[FFmpeg-devel] [PATCH] avfilter: add aringmodulator filter
Paul B Mahol
onemda at gmail.com
Sat May 2 13:51:15 EEST 2020
Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
doc/filters.texi | 78 +++++++++++++
libavfilter/Makefile | 1 +
libavfilter/af_apulsator.c | 224 +++++++++++++++++++++++++++++++++++++
libavfilter/allfilters.c | 1 +
4 files changed, 304 insertions(+)
diff --git a/doc/filters.texi b/doc/filters.texi
index d19fd346ae..a8987a56c7 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -2141,6 +2141,84 @@ atrim=end=5,areverse
@end example
@end itemize
+ at section aringmodulator
+Apply ring modulator to input audio stream.
+
+Ring Modulator distorts the original signal with a LFO-generated signal -
+the so called "modulator". The modulator can be altered in frequency even
+by another LFO which adds some kind of modulating distortion to the signal.
+A third LFO is used to modulate different aspects of the ring modulator to
+create even more strange effects.
+
+This filter accepts the following options:
+ at table @option
+ at item level_in
+Set the input gain before signal is processed.
+
+ at item level_out
+Set the output gain after signal is processed.
+
+ at item mod_mode
+Set waveform of the modulator.
+
+ at item mod_freq
+Set frequency of the modulator.
+
+ at item mod_amount
+Set amount by how much original signal is modulated.
+
+ at item mod_phase
+Shift the phase of the right channels modulator against the left channel.
+
+ at item mod_detune
+Detune the modulators frequency between left and right channel.
+
+ at item mod_listen
+Only output modulator signal. By default is disabled.
+
+ at item lfo1_mode
+Set waveform of the LFO1 modulator.
+
+ at item lfo1_freq
+Set frequency of the LFO1 modulator.
+
+ at item lfo1_mod_freq_lo
+Set the minimal modulators frequency to reach at lowest point.
+
+ at item lfo1_mod_freq_hi
+Set the maximal modulators frequency to reach at highest point.
+
+ at item lfo1_mod_freq
+Enable modulating modulators frequency by LFO1. By defauls is disabled.
+
+ at item lfo1_mod_detune_lo
+Set the minimal modulators frequency to reach at lowest point.
+
+ at item lfo1_mod_detune_hi
+Set the maximal modulators frequency to reach at highest point.
+
+ at item lfo1_mod_detune
+Enable modulating modulators frequency by LFO1. By default is disabled.
+
+ at item lfo2_mode
+Set waveform of the LFO2 modulator.
+
+ at item lfo2_freq
+Set frequency of the LFO2 modulator.
+
+ at item lfo2_lfo1_freq
+Enable modulating LFO1's frequency by LFO2. By defauls is disabled.
+
+ at item lfo2_mod_amount
+Enable modulating modulators amount by LFO2. By defauls is disabled.
+
+ at item lfo2_mod_amount_lo
+Set the minimal modulators amount to reach at LFO2 lowest point.
+
+ at item lfo2_mod_amount_hi
+Set the maximal modulators amount to reach at LFO2 highest point.
+ at end table
+
@section arnndn
Reduce noise from speech using Recurrent Neural Networks.
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index f982afe15f..dc512fe4b2 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -72,6 +72,7 @@ OBJS-$(CONFIG_APULSATOR_FILTER) += af_apulsator.o
OBJS-$(CONFIG_AREALTIME_FILTER) += f_realtime.o
OBJS-$(CONFIG_ARESAMPLE_FILTER) += af_aresample.o
OBJS-$(CONFIG_AREVERSE_FILTER) += f_reverse.o
+OBJS-$(CONFIG_ARINGMODULATOR_FILTER) += af_apulsator.o
OBJS-$(CONFIG_ARNNDN_FILTER) += af_arnndn.o
OBJS-$(CONFIG_ASELECT_FILTER) += f_select.o
OBJS-$(CONFIG_ASENDCMD_FILTER) += f_sendcmd.o
diff --git a/libavfilter/af_apulsator.c b/libavfilter/af_apulsator.c
index 67711a28ce..9ba1d48341 100644
--- a/libavfilter/af_apulsator.c
+++ b/libavfilter/af_apulsator.c
@@ -255,3 +255,227 @@ AVFilter ff_af_apulsator = {
.inputs = inputs,
.outputs = outputs,
};
+
+#if CONFIG_ARINGMODULATOR_FILTER
+typedef struct AudioRingModulatorContext {
+ const AVClass *class;
+ double level_in;
+ double level_out;
+ int mod_mode;
+ double mod_freq;
+ double mod_amount;
+ double mod_phase;
+ double mod_detune;
+ int mod_listen;
+ int lfo1_mode;
+ double lfo1_freq;
+ double lfo1_mod_freq_lo;
+ double lfo1_mod_freq_hi;
+ int lfo1_mod_freq_active;
+ int lfo2_lfo1_freq_active;
+ int lfo1_mod_detune_active;
+ double lfo1_mod_detune_lo;
+ double lfo1_mod_detune_hi;
+ int lfo2_mode;
+ double lfo2_freq;
+ double lfo2_lfo1_freq_lo;
+ double lfo2_lfo1_freq_hi;
+ int lfo2_mod_amount_active;
+ double lfo2_mod_amount_lo;
+ double lfo2_mod_amount_hi;
+
+ SimpleLFO lfo1, lfo2, modL, modR;
+} AudioRingModulatorContext;
+
+static int ringmodulator_config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AudioRingModulatorContext *s = ctx->priv;
+
+ s->modL.freq = s->mod_freq * pow(pow(2, 1.0 / 1200.0), s->mod_detune / 2);
+ s->modR.freq = s->mod_freq * pow(pow(2, 1.0 / 1200.0), s->mod_detune / 2);
+ s->modL.mode = s->mod_mode;
+ s->modR.mode = s->mod_mode;
+ s->modL.offset = 0;
+ s->modR.offset = s->mod_phase;
+ s->modL.srate = inlink->sample_rate;
+ s->modR.srate = inlink->sample_rate;
+ s->modL.amount = s->mod_amount;
+ s->modR.amount = s->mod_amount;
+ s->modL.pwidth = 1;
+ s->modR.pwidth = 1;
+ s->lfo1.freq = s->lfo1_freq;
+ s->lfo2.freq = s->lfo2_freq;
+ s->lfo1.mode = s->lfo1_mode;
+ s->lfo2.mode = s->lfo2_mode;
+ s->lfo1.srate = inlink->sample_rate;
+ s->lfo2.srate = inlink->sample_rate;
+ s->lfo1.amount = 1;
+ s->lfo2.amount = 1;
+ s->lfo1.pwidth = 1;
+ s->lfo2.pwidth = 1;
+
+ return 0;
+}
+
+static int ringmodulator_filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AudioRingModulatorContext *s = ctx->priv;
+ const double *src = (const double *)in->data[0];
+ const int nb_samples = in->nb_samples;
+ const double level_out = s->level_out;
+ const double level_in = s->level_in;
+ AVFrame *out;
+ double *dst;
+ int n;
+
+ if (av_frame_is_writable(in)) {
+ out = in;
+ } else {
+ out = ff_get_audio_buffer(inlink, in->nb_samples);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+ dst = (double *)out->data[0];
+
+ for (n = 0; n < nb_samples; n++) {
+ double mod_amount = s->mod_amount;
+ double freq = 0.;
+ double outL = 0.;
+ double outR = 0.;
+ double inL = src[0] * level_in;
+ double inR = src[1] * level_in;
+ double procL;
+ double procR;
+ double modulL;
+ double modulR;
+
+ if (s->lfo1_mod_freq_active) {
+ freq = (s->lfo1_mod_freq_hi - s->lfo1_mod_freq_lo) *
+ ((lfo_get_value(&s->lfo1) + 1) / 2.) +
+ s->lfo1_mod_freq_lo;
+ s->modL.freq = freq;
+ s->modR.freq = freq;
+ }
+
+ if (s->lfo1_mod_detune_active) {
+ double detune = (s->lfo1_mod_detune_hi - s->lfo1_mod_detune_lo) *
+ ((lfo_get_value(&s->lfo1) + 1) / 2.) + s->lfo1_mod_detune_lo;
+
+ s->modL.freq = freq ? freq : s->mod_freq * pow(pow(2, 1.0 / 1200.0), detune / 2);
+ s->modR.freq = freq ? freq : s->mod_freq * pow(pow(2, 1.0 / 1200.0), detune / -2);
+ }
+
+ if (s->lfo2_lfo1_freq_active) {
+ s->lfo1.freq = (s->lfo2_lfo1_freq_hi - s->lfo2_lfo1_freq_lo) *
+ ((lfo_get_value(&s->lfo2) + 1) / 2.) +
+ s->lfo2_lfo1_freq_lo;
+ }
+
+ if (s->lfo2_mod_amount_active) {
+ mod_amount = (s->lfo2_mod_amount_hi - s->lfo2_mod_amount_lo) *
+ ((lfo_get_value(&s->lfo2) + 1) / 2.) +
+ s->lfo2_mod_amount_lo;
+ }
+
+ modulL = lfo_get_value(&s->modL) * mod_amount;
+ modulR = lfo_get_value(&s->modR) * mod_amount;
+
+ procL = inL * modulL;
+ procR = inR * modulR;
+
+ outL = s->mod_listen ? modulL : procL + inL * (1 - mod_amount);
+ outR = s->mod_listen ? modulR : procR + inR * (1 - mod_amount);
+
+ outL *= level_out;
+ outR *= level_out;
+
+ dst[0] = outL;
+ dst[1] = outR;
+
+ lfo_advance(&s->lfo1, 1);
+ lfo_advance(&s->lfo2, 1);
+ lfo_advance(&s->modL, 1);
+ lfo_advance(&s->modR, 1);
+
+ dst += 2;
+ src += 2;
+ }
+
+ if (in != out)
+ av_frame_free(&in);
+
+ return ff_filter_frame(outlink, out);
+}
+
+#undef OFFSET
+#undef FLAGS
+#define OFFSET(x) offsetof(AudioRingModulatorContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption aringmodulator_options[] = {
+ { "level_in", "set input gain", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, FLAGS, },
+ { "level_out", "set output gain", OFFSET(level_out), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, FLAGS, },
+ { "mod_mode", "set modulation mode", OFFSET(mod_mode), AV_OPT_TYPE_INT, {.i64=SINE}, SINE, NB_MODES-1, FLAGS, "mode" },
+ { "sine", NULL, 0, AV_OPT_TYPE_CONST, {.i64=SINE}, 0, 0, FLAGS, "mode" },
+ { "triangle", NULL, 0, AV_OPT_TYPE_CONST, {.i64=TRIANGLE}, 0, 0, FLAGS, "mode" },
+ { "square", NULL, 0, AV_OPT_TYPE_CONST, {.i64=SQUARE}, 0, 0, FLAGS, "mode" },
+ { "sawup", NULL, 0, AV_OPT_TYPE_CONST, {.i64=SAWUP}, 0, 0, FLAGS, "mode" },
+ { "sawdown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=SAWDOWN}, 0, 0, FLAGS, "mode" },
+ { "mod_freq", NULL, OFFSET(mod_freq), AV_OPT_TYPE_DOUBLE, {.dbl=1000}, 1, 20000, FLAGS },
+ { "mod_amount", NULL, OFFSET(mod_amount), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 1, FLAGS },
+ { "mod_phase", NULL, OFFSET(mod_phase), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 1, FLAGS },
+ { "mod_detune", NULL, OFFSET(mod_detune), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -200, 200, FLAGS },
+ { "mod_listen", NULL, OFFSET(mod_listen), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
+ { "lfo1_mode", NULL, OFFSET(lfo1_mode), AV_OPT_TYPE_INT, {.i64=SINE}, SINE, NB_MODES-1, FLAGS, "mode" },
+ { "lfo1_freq", NULL, OFFSET(lfo1_freq), AV_OPT_TYPE_DOUBLE, {.dbl=0.1}, 0.01, 10, FLAGS },
+ { "lfo1_mod_freq_lo", NULL, OFFSET(lfo1_mod_freq_lo), AV_OPT_TYPE_DOUBLE, {.dbl=100}, 1,20000, FLAGS },
+ { "lfo1_mod_freq_hi", NULL, OFFSET(lfo1_mod_freq_hi), AV_OPT_TYPE_DOUBLE, {.dbl=1000}, 1,20000, FLAGS },
+ { "lfo1_mod_freq", NULL, OFFSET(lfo1_mod_freq_active), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
+ { "lfo1_mod_detune_lo", NULL, OFFSET(lfo1_mod_detune_lo), AV_OPT_TYPE_DOUBLE, {.dbl=-100}, -200, 200, FLAGS },
+ { "lfo1_mod_detune_hi", NULL, OFFSET(lfo1_mod_detune_hi), AV_OPT_TYPE_DOUBLE, {.dbl=100}, -200, 200, FLAGS },
+ { "lfo1_mod_detune", NULL, OFFSET(lfo1_mod_detune_active), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
+ { "lfo2_mode", NULL, OFFSET(lfo2_mode), AV_OPT_TYPE_INT, {.i64=SINE}, SINE, NB_MODES-1, FLAGS, "mode" },
+ { "lfo2_freq", NULL, OFFSET(lfo2_freq), AV_OPT_TYPE_DOUBLE, {.dbl=0.2}, 0.01, 10, FLAGS },
+ { "lfo2_lfo1_freq", NULL, OFFSET(lfo2_lfo1_freq_active), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
+ { "lfo2_mod_amount", NULL, OFFSET(lfo2_mod_amount_active), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
+ { "lfo2_mod_amount_lo", NULL, OFFSET(lfo2_mod_amount_lo), AV_OPT_TYPE_DOUBLE, {.dbl=0.3}, 0, 1, FLAGS },
+ { "lfo2_mod_amount_hi", NULL, OFFSET(lfo2_mod_amount_hi), AV_OPT_TYPE_DOUBLE, {.dbl=0.6}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(aringmodulator);
+
+static const AVFilterPad ringmodulator_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = ringmodulator_config_input,
+ .filter_frame = ringmodulator_filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad ringmodulator_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_aringmodulator = {
+ .name = "aringmodulator",
+ .description = NULL_IF_CONFIG_SMALL("Audio Ring Modulator."),
+ .priv_size = sizeof(AudioRingModulatorContext),
+ .priv_class = åmodulator_class,
+ .query_formats = query_formats,
+ .inputs = ringmodulator_inputs,
+ .outputs = ringmodulator_outputs,
+};
+#endif /* CONFIG_ARINGMODULATOR_FILTER */
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 1b94501da0..6ec92181f3 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -65,6 +65,7 @@ extern AVFilter ff_af_apulsator;
extern AVFilter ff_af_arealtime;
extern AVFilter ff_af_aresample;
extern AVFilter ff_af_areverse;
+extern AVFilter ff_af_aringmodulator;
extern AVFilter ff_af_arnndn;
extern AVFilter ff_af_aselect;
extern AVFilter ff_af_asendcmd;
--
2.17.1
More information about the ffmpeg-devel
mailing list