[FFmpeg-devel] [PATCH] chorus filter

Michael Niedermayer michaelni at gmx.at
Mon Apr 6 00:52:28 CEST 2015


On Sun, Apr 05, 2015 at 05:50:47PM +0000, Paul B Mahol wrote:
> Signed-off-by: Paul B Mahol <onemda at gmail.com>
> ---
>  doc/filters.texi         |  32 ++++
>  libavfilter/Makefile     |   1 +
>  libavfilter/af_chorus.c  | 370 +++++++++++++++++++++++++++++++++++++++++++++++
>  libavfilter/allfilters.c |   1 +
>  4 files changed, 404 insertions(+)
>  create mode 100644 libavfilter/af_chorus.c
> 
> diff --git a/doc/filters.texi b/doc/filters.texi
> index b75ce5a..4926d1c 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -1320,6 +1320,38 @@ front_center.wav -map '[LFE]' lfe.wav -map '[SL]' side_left.wav -map '[SR]'
>  side_right.wav
>  @end example
>  
> + at section chorus
> +Add a chorus effect to the audio.
> +Can make a single vocal sound like a chorus, but can also be applied to instrumentation.
> +
> +Chorus resembles an echo effect with a short delay, but whereas with echo the delay is
> +constant, with chorus, it is varied using using sinusoidal or triangular modulation.
> +The modulation depth defines the range the modulated delay is played before or after
> +the delay. Hence the delayed sound will sound slower or faster, that is the delayed
> +sound tuned around the original one, like in a chorus where some vocals are slightly
> +off key.
> +
> +It accepts the following parameters:
> + at table @option
> + at item in_gain
> +Set input gain. Default is 0.4.
> +
> + at item out_gain
> +Set output gain. Default is 0.4.
> +
> + at item delays
> +Set delays.
> +
> + at item decays
> +Set decays.
> +
> + at item speeds
> +Set speeds.
> +
> + at item depths
> +Set depths.
> + at end table
> +

please add an example to the documentation


>  @section compand
>  Compress or expand the audio's dynamic range.
>  
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index 73e7adf..48cee50 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -64,6 +64,7 @@ OBJS-$(CONFIG_BIQUAD_FILTER)                 += af_biquads.o
>  OBJS-$(CONFIG_BS2B_FILTER)                   += af_bs2b.o
>  OBJS-$(CONFIG_CHANNELMAP_FILTER)             += af_channelmap.o
>  OBJS-$(CONFIG_CHANNELSPLIT_FILTER)           += af_channelsplit.o
> +OBJS-$(CONFIG_CHORUS_FILTER)                 += af_chorus.o generate_wave_table.o
>  OBJS-$(CONFIG_COMPAND_FILTER)                += af_compand.o
>  OBJS-$(CONFIG_DCSHIFT_FILTER)                += af_dcshift.o
>  OBJS-$(CONFIG_EARWAX_FILTER)                 += af_earwax.o
> diff --git a/libavfilter/af_chorus.c b/libavfilter/af_chorus.c
> new file mode 100644
> index 0000000..6daf571
> --- /dev/null
> +++ b/libavfilter/af_chorus.c
> @@ -0,0 +1,370 @@
> +/*
> + * Copyright (c) 1998 Juergen Mueller And Sundry Contributors
> + * This source code is freely redistributable and may be used for
> + * any purpose.  This copyright notice must be maintained.
> + * Juergen Mueller And Sundry Contributors are not responsible for
> + * the consequences of using this software.
> + *
> + * Copyright (c) 2015 Paul B Mahol
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +/**
> + * @file
> + * chorus audio filter
> + */
> +
> +#include "libavutil/avstring.h"
> +#include "libavutil/opt.h"
> +#include "audio.h"
> +#include "avfilter.h"
> +#include "internal.h"
> +#include "generate_wave_table.h"
> +
> +typedef struct ChorusContext {
> +    const AVClass *class;
> +    float in_gain, out_gain;
> +    char *delays_str;
> +    char *decays_str;
> +    char *speeds_str;
> +    char *depths_str;
> +    float *delays;
> +    float *decays;
> +    float *speeds;
> +    float *depths;
> +    uint8_t **chorusbuf;
> +    int **phase;
> +    int *length;
> +    int32_t **lookup_table;
> +    int *counter;
> +    int num_chorus;
> +    int max_samples;
> +    int channels;
> +    int modulation;
> +    int fade_out;
> +    int64_t next_pts;
> +} ChorusContext;
> +
> +#define OFFSET(x) offsetof(ChorusContext, x)
> +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
> +
> +static const AVOption chorus_options[] = {
> +    { "in_gain",  "set input gain",  OFFSET(in_gain),    AV_OPT_TYPE_FLOAT,  {.dbl=.4}, 0, 1, A },
> +    { "out_gain", "set output gain", OFFSET(out_gain),   AV_OPT_TYPE_FLOAT,  {.dbl=.4}, 0, 1, A },
> +    { "delays",   "set delays",      OFFSET(delays_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A },
> +    { "decays",   "set decays",      OFFSET(decays_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A },
> +    { "speeds",   "set speeds",      OFFSET(speeds_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A },
> +    { "depths",   "set depths",      OFFSET(depths_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A },
> +    { NULL }
> +};
> +
> +AVFILTER_DEFINE_CLASS(chorus);
> +
> +static void count_items(char *item_str, int *nb_items)
> +{
> +    char *p;
> +
> +    *nb_items = 1;
> +    for (p = item_str; *p; p++) {
> +        if (*p == '|')
> +            (*nb_items)++;
> +    }
> +
> +}
> +
> +static void fill_items(char *item_str, int *nb_items, float *items)
> +{
> +    char *p, *saveptr = NULL;
> +    int i, new_nb_items = 0;
> +
> +    p = item_str;
> +    for (i = 0; i < *nb_items; i++) {
> +        char *tstr = av_strtok(p, "|", &saveptr);
> +        p = NULL;
> +        new_nb_items += sscanf(tstr, "%f", &items[i]) == 1;
> +    }
> +
> +    *nb_items = new_nb_items;
> +}
> +

> +static av_cold int init(AVFilterContext *ctx)
> +{
> +    ChorusContext *s = ctx->priv;
> +    int nb_delays, nb_decays, nb_speeds, nb_depths;
> +
> +    if (!s->delays_str || !s->decays_str || !s->speeds_str || !s->depths_str)
> +        return AVERROR(EINVAL);
> +
> +    count_items(s->delays_str, &nb_delays);
> +    count_items(s->decays_str, &nb_decays);
> +    count_items(s->speeds_str, &nb_speeds);
> +    count_items(s->depths_str, &nb_depths);
> +
> +    s->delays = av_realloc_f(s->delays, nb_delays, sizeof(*s->delays));
> +    s->decays = av_realloc_f(s->decays, nb_decays, sizeof(*s->decays));
> +    s->speeds = av_realloc_f(s->speeds, nb_speeds, sizeof(*s->speeds));
> +    s->depths = av_realloc_f(s->depths, nb_depths, sizeof(*s->depths));
> +
> +    if (!s->delays || !s->decays || !s->speeds || !s->depths)
> +        return AVERROR(ENOMEM);
> +
> +    fill_items(s->delays_str, &nb_delays, s->delays);
> +    fill_items(s->decays_str, &nb_decays, s->decays);
> +    fill_items(s->speeds_str, &nb_speeds, s->speeds);
> +    fill_items(s->depths_str, &nb_depths, s->depths);
> +
> +    if (nb_delays != nb_decays && nb_delays != nb_speeds && nb_delays != nb_depths)
> +        return AVERROR(EINVAL);

please add error messages to the cases where the user has provided
invalid parameters so that she knows what is wrong


[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

If you think the mosad wants you dead since a long time then you are either
wrong or dead since a long time.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20150406/eade05f1/attachment.asc>


More information about the ffmpeg-devel mailing list