[FFmpeg-cvslog] avfilter/af_afir: add irnorm and irlink options
Paul B Mahol
git at videolan.org
Sat Nov 18 18:10:10 EET 2023
ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Sat Nov 18 00:36:18 2023 +0100| [5452cbdc150f0fcff736cd3897a2c41fec77fb79] | committer: Paul B Mahol
avfilter/af_afir: add irnorm and irlink options
Deprecate gtype option.
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=5452cbdc150f0fcff736cd3897a2c41fec77fb79
---
doc/filters.texi | 37 ++++++---------
libavfilter/af_afir.c | 57 ++++++++++++++++++----
libavfilter/af_afir.h | 3 ++
libavfilter/afir_template.c | 113 +++++++++++---------------------------------
4 files changed, 91 insertions(+), 119 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index d83a3fb91e..ffe9a424a8 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -1794,33 +1794,24 @@ Set wet gain. This sets final output gain.
Set Impulse Response filter length. Default is 1, which means whole IR is processed.
@item gtype
-Enable applying gain measured from power of IR.
+This option is deprecated, and does nothing.
-Set which approach to use for auto gain measurement.
+ at item irnorm
+Set norm to be applied to IR coefficients before filtering.
+Allowed range is from @var{-1} to @var{2}.
+IR coefficients are normalized with calculated vector norm set by this option.
+For negative values, no norm is calculated, and IR coefficients are not modified at all.
+Default is @var{1}.
- at table @option
- at item none
-Do not apply any gain.
-
- at item peak
-select peak gain, very conservative approach. This is default value.
-
- at item dc
-select DC gain, limited application.
-
- at item gn
-select gain to noise approach, this is most popular one.
-
- at item ac
-select AC gain.
-
- at item rms
-select RMS gain.
- at end table
+ at item irlink
+For multichannel IR if this option is set to @var{true}. All IR channels will be
+normalized with maximal measured gain of all IR channels coefficients as set by @code{irnorm} option.
+When disabled, all IR coefficients in each IR channel will be normalized independently.
+Default is @var{true}.
@item irgain
Set gain to be applied to IR coefficients before filtering.
-Allowed range is 0 to 1. This gain is applied after any gain applied with @var{gtype} option.
+Allowed range is 0 to 1. This gain is applied after any gain applied with @var{irnorm} option.
@item irfmt
Set format of IR stream. Can be @code{mono} or @code{input}.
@@ -1899,7 +1890,7 @@ ffmpeg -i input.wav -i middle_tunnel_1way_mono.wav -lavfi afir output.wav
Apply true stereo processing given input stereo stream, and two stereo impulse responses for left and right channel,
the impulse response files are files with names l_ir.wav and r_ir.wav:
@example
-"pan=4C|c0=FL|c1=FL|c2=FR|c3=FR[a];amovie=l_ir.wav[LIR];amovie=r_ir.wav[RIR];[LIR][RIR]amerge[ir];[a][ir]afir=irfmt=input:gtype=gn:irgain=-5dB,pan=stereo|FL<c0+c2|FR<c1+c3"
+"pan=4C|c0=FL|c1=FL|c2=FR|c3=FR[a];amovie=l_ir.wav[LIR];amovie=r_ir.wav[RIR];[LIR][RIR]amerge[ir];[a][ir]afir=irfmt=input:irgain=-5dB,pan=stereo|FL<c0+c2|FR<c1+c3"
@end example
@end itemize
diff --git a/libavfilter/af_afir.c b/libavfilter/af_afir.c
index 5d3f4070a7..ca4b585afd 100644
--- a/libavfilter/af_afir.c
+++ b/libavfilter/af_afir.c
@@ -393,6 +393,22 @@ skip:
switch (s->format) {
case AV_SAMPLE_FMT_FLTP:
+ for (int ch = 0; ch < s->nb_channels; ch++) {
+ const float *tsrc = (const float *)s->ir[selir]->extended_data[!s->one2many * ch];
+
+ s->ch_gain[ch] = ir_gain_float(ctx, s, nb_taps, tsrc);
+ }
+
+ if (s->ir_link) {
+ float gain = +INFINITY;
+
+ for (int ch = 0; ch < s->nb_channels; ch++)
+ gain = fminf(gain, s->ch_gain[ch]);
+
+ for (int ch = 0; ch < s->nb_channels; ch++)
+ s->ch_gain[ch] = gain;
+ }
+
for (int ch = 0; ch < s->nb_channels; ch++) {
const float *tsrc = (const float *)s->ir[selir]->extended_data[!s->one2many * ch];
float *time = (float *)s->norm_ir[selir]->extended_data[ch];
@@ -401,7 +417,7 @@ skip:
for (int i = FFMAX(1, s->length * nb_taps); i < nb_taps; i++)
time[i] = 0;
- get_power_float(ctx, s, nb_taps, ch, time);
+ ir_scale_float(ctx, s, nb_taps, ch, time, s->ch_gain[ch]);
for (int n = 0; n < s->nb_segments[selir]; n++) {
AudioFIRSegment *seg = &s->seg[selir][n];
@@ -417,6 +433,22 @@ skip:
}
break;
case AV_SAMPLE_FMT_DBLP:
+ for (int ch = 0; ch < s->nb_channels; ch++) {
+ const double *tsrc = (const double *)s->ir[selir]->extended_data[!s->one2many * ch];
+
+ s->ch_gain[ch] = ir_gain_double(ctx, s, nb_taps, tsrc);
+ }
+
+ if (s->ir_link) {
+ double gain = +INFINITY;
+
+ for (int ch = 0; ch < s->nb_channels; ch++)
+ gain = fmin(gain, s->ch_gain[ch]);
+
+ for (int ch = 0; ch < s->nb_channels; ch++)
+ s->ch_gain[ch] = gain;
+ }
+
for (int ch = 0; ch < s->nb_channels; ch++) {
const double *tsrc = (const double *)s->ir[selir]->extended_data[!s->one2many * ch];
double *time = (double *)s->norm_ir[selir]->extended_data[ch];
@@ -425,7 +457,8 @@ skip:
for (int i = FFMAX(1, s->length * nb_taps); i < nb_taps; i++)
time[i] = 0;
- get_power_double(ctx, s, nb_taps, ch, time);
+ ir_scale_double(ctx, s, nb_taps, ch, time, s->ch_gain[ch]);
+
for (int n = 0; n < s->nb_segments[selir]; n++) {
AudioFIRSegment *seg = &s->seg[selir][n];
@@ -627,8 +660,9 @@ FF_ENABLE_DEPRECATION_WARNINGS
s->format = outlink->format;
s->nb_channels = outlink->ch_layout.nb_channels;
+ s->ch_gain = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*s->ch_gain));
s->loading = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*s->loading));
- if (!s->loading)
+ if (!s->loading || !s->ch_gain)
return AVERROR(ENOMEM);
s->fadein[0] = ff_get_audio_buffer(outlink, s->min_part_size);
@@ -674,6 +708,7 @@ static av_cold void uninit(AVFilterContext *ctx)
AudioFIRContext *s = ctx->priv;
av_freep(&s->fdsp);
+ av_freep(&s->ch_gain);
av_freep(&s->loading);
for (int i = 0; i < s->nb_irs; i++) {
@@ -812,13 +847,15 @@ static const AVOption afir_options[] = {
{ "dry", "set dry gain", OFFSET(dry_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, AFR },
{ "wet", "set wet gain", OFFSET(wet_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, AFR },
{ "length", "set IR length", OFFSET(length), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },
- { "gtype", "set IR auto gain type",OFFSET(gtype), AV_OPT_TYPE_INT, {.i64=0}, -1, 4, AF, "gtype" },
- { "none", "without auto gain", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, AF, "gtype" },
- { "peak", "peak gain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "gtype" },
- { "dc", "DC gain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "gtype" },
- { "gn", "gain to noise", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "gtype" },
- { "ac", "AC gain", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "gtype" },
- { "rms", "RMS gain", 0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, AF, "gtype" },
+ { "gtype", "set IR auto gain type",OFFSET(gtype), AV_OPT_TYPE_INT, {.i64=0}, -1, 4, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+ { "none", "without auto gain", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+ { "peak", "peak gain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+ { "dc", "DC gain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+ { "gn", "gain to noise", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+ { "ac", "AC gain", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+ { "rms", "RMS gain", 0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+ { "irnorm", "set IR norm", OFFSET(ir_norm), AV_OPT_TYPE_FLOAT, {.dbl=1}, -1, 2, AF },
+ { "irlink", "set IR link", OFFSET(ir_link), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, AF },
{ "irgain", "set IR gain", OFFSET(ir_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },
{ "irfmt", "set IR format", OFFSET(ir_format), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AF, "irfmt" },
{ "mono", "single channel", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "irfmt" },
diff --git a/libavfilter/af_afir.h b/libavfilter/af_afir.h
index 7c9a3b3e31..5c39aa10b9 100644
--- a/libavfilter/af_afir.h
+++ b/libavfilter/af_afir.h
@@ -63,6 +63,8 @@ typedef struct AudioFIRContext {
float dry_gain;
float length;
int gtype;
+ float ir_norm;
+ float ir_link;
float ir_gain;
int ir_format;
int ir_load;
@@ -87,6 +89,7 @@ typedef struct AudioFIRContext {
int nb_channels;
int one2many;
int *loading;
+ double *ch_gain;
AudioFIRSegment seg[MAX_IR_STREAMS][1024];
diff --git a/libavfilter/afir_template.c b/libavfilter/afir_template.c
index 9a11ec2fa6..676cec6dde 100644
--- a/libavfilter/afir_template.c
+++ b/libavfilter/afir_template.c
@@ -29,6 +29,8 @@
#undef HYPOT
#undef SAMPLE_FORMAT
#undef TX_TYPE
+#undef FABS
+#undef POW
#if DEPTH == 32
#define SAMPLE_FORMAT float
#define SQRT sqrtf
@@ -36,6 +38,8 @@
#define ctype AVComplexFloat
#define ftype float
#define TX_TYPE AV_TX_FLOAT_RDFT
+#define FABS fabsf
+#define POW powf
#else
#define SAMPLE_FORMAT double
#define SQRT sqrt
@@ -43,6 +47,8 @@
#define ctype AVComplexDouble
#define ftype double
#define TX_TYPE AV_TX_DOUBLE_RDFT
+#define FABS fabs
+#define POW pow
#endif
#define fn3(a,b) a##_##b
@@ -139,95 +145,32 @@ end:
av_free(mag);
}
-static int fn(get_power)(AVFilterContext *ctx, AudioFIRContext *s,
- int cur_nb_taps, int ch,
- ftype *time)
+static ftype fn(ir_gain)(AVFilterContext *ctx, AudioFIRContext *s,
+ int cur_nb_taps, const ftype *time)
{
- ftype ch_gain = 1;
+ ftype ch_gain, sum = 0;
- switch (s->gtype) {
- case -1:
+ if (s->ir_norm < 0.f) {
ch_gain = 1;
- break;
- case 0:
- {
- ftype sum = 0;
-
- for (int i = 0; i < cur_nb_taps; i++)
- sum += FFABS(time[i]);
- ch_gain = 1. / sum;
- }
- break;
- case 1:
- {
- ftype sum = 0;
-
- for (int i = 0; i < cur_nb_taps; i++)
- sum += time[i];
- ch_gain = 1. / sum;
- }
- break;
- case 2:
- {
- ftype sum = 0;
-
- for (int i = 0; i < cur_nb_taps; i++)
- sum += time[i] * time[i];
- ch_gain = 1. / SQRT(sum);
- }
- break;
- case 3:
- case 4:
- {
- ftype *inc, *outc, scale, power;
- AVTXContext *tx;
- av_tx_fn tx_fn;
- int ret, size;
-
- size = 1 << av_ceil_log2_c(cur_nb_taps);
- inc = av_calloc(size + 2, sizeof(SAMPLE_FORMAT));
- outc = av_calloc(size + 2, sizeof(SAMPLE_FORMAT));
- if (!inc || !outc) {
- av_free(outc);
- av_free(inc);
- break;
- }
-
- scale = 1.;
- ret = av_tx_init(&tx, &tx_fn, TX_TYPE, 0, size, &scale, 0);
- if (ret < 0) {
- av_free(outc);
- av_free(inc);
- break;
- }
-
- {
- memcpy(inc, time, cur_nb_taps * sizeof(SAMPLE_FORMAT));
- tx_fn(tx, outc, inc, sizeof(SAMPLE_FORMAT));
-
- power = 0;
- if (s->gtype == 3) {
- for (int i = 0; i < size / 2 + 1; i++)
- power = FFMAX(power, HYPOT(outc[i * 2], outc[i * 2 + 1]));
- } else {
- ftype sum = 0;
- for (int i = 0; i < size / 2 + 1; i++)
- sum += HYPOT(outc[i * 2], outc[i * 2 + 1]);
- power = SQRT(sum / (size / 2 + 1));
- }
-
- ch_gain = 1. / power;
- }
-
- av_tx_uninit(&tx);
- av_free(outc);
- av_free(inc);
- }
- break;
- default:
- return AVERROR_BUG;
+ } else if (s->ir_norm == 0.f) {
+ for (int i = 0; i < cur_nb_taps; i++)
+ sum += time[i];
+ ch_gain = 1. / sum;
+ } else {
+ ftype ir_norm = s->ir_norm;
+
+ for (int i = 0; i < cur_nb_taps; i++)
+ sum += POW(FABS(time[i]), ir_norm);
+ ch_gain = 1. / POW(sum, 1. / ir_norm);
}
+ return ch_gain;
+}
+
+static void fn(ir_scale)(AVFilterContext *ctx, AudioFIRContext *s,
+ int cur_nb_taps, int ch,
+ ftype *time, ftype ch_gain)
+{
if (ch_gain != 1. || s->ir_gain != 1.) {
ftype gain = ch_gain * s->ir_gain;
@@ -238,8 +181,6 @@ static int fn(get_power)(AVFilterContext *ctx, AudioFIRContext *s,
s->fdsp->vector_dmul_scalar(time, time, gain, FFALIGN(cur_nb_taps, 8));
#endif
}
-
- return 0;
}
static void fn(convert_channel)(AVFilterContext *ctx, AudioFIRContext *s, int ch,
More information about the ffmpeg-cvslog
mailing list