[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