avfilter/af_afir: make IR gain control more flexible
authorPaul B Mahol <onemda@gmail.com>
Wed, 3 Oct 2018 19:43:40 +0000 (21:43 +0200)
committerPaul B Mahol <onemda@gmail.com>
Wed, 3 Oct 2018 19:43:40 +0000 (21:43 +0200)
For this reason introduce two more options.

doc/filters.texi
libavfilter/af_afir.c
libavfilter/af_afir.h

index 6d38333..1c51e42 100644 (file)
@@ -1147,7 +1147,7 @@ afftfilt="1-clip((b/nb)*b,0,1)"
 Apply an arbitrary Frequency Impulse Response filter.
 
 This filter is designed for applying long FIR filters,
-up to 30 seconds long.
+up to 60 seconds long.
 
 It can be used as component for digital crossover filters,
 room equalization, cross talk cancellation, wavefield synthesis,
@@ -1172,7 +1172,26 @@ Set wet gain. This sets final output gain.
 Set Impulse Response filter length. Default is 1, which means whole IR is processed.
 
 @item again
-Enable applying gain measured from power of IR.
+Enable applying gain measured from power of IR. For approach to use for measuring power
+of IR see next option.
+
+@item gtype
+Set which approach to use for auto gain measurement.
+
+@table @option
+@item peak
+select peak gain, very conservative approach. This is default value.
+
+@item dc
+select DC gain, limited application.
+
+@item gn
+select gain to noise approach, this is most popular one.
+@end table
+
+@item irgain
+Set gain to be applied to IR coefficients before filtering.
+Allowed range is 0 to 1. This can be set even with @var{again} used.
 
 @item maxir
 Set max allowed Impulse Response filter duration in seconds. Default is 30 seconds.
index bdca903..770b8be 100644 (file)
@@ -280,6 +280,7 @@ static int convert_coeffs(AVFilterContext *ctx)
 {
     AudioFIRContext *s = ctx->priv;
     int i, ch, n, N;
+    float power = 0;
 
     s->nb_taps = av_audio_fifo_size(s->fifo);
     if (s->nb_taps <= 0)
@@ -333,22 +334,48 @@ static int convert_coeffs(AVFilterContext *ctx)
     if (s->response)
         draw_response(ctx, s->video);
 
+    s->gain = 1;
+
     if (s->again) {
-        float power = 0;
+        switch (s->gtype) {
+        case 0:
+            for (ch = 0; ch < ctx->inputs[1]->channels; ch++) {
+                float *time = (float *)s->in[1]->extended_data[!s->one2many * ch];
+
+                for (i = 0; i < s->nb_taps; i++)
+                    power += FFABS(time[i]);
+            }
+            s->gain = ctx->inputs[1]->channels / power;
+            break;
+        case 1:
+            for (ch = 0; ch < ctx->inputs[1]->channels; ch++) {
+                float *time = (float *)s->in[1]->extended_data[!s->one2many * ch];
 
-        for (ch = 0; ch < ctx->inputs[1]->channels; ch++) {
-            float *time = (float *)s->in[1]->extended_data[!s->one2many * ch];
+                for (i = 0; i < s->nb_taps; i++)
+                    power += time[i];
+            }
+            s->gain = ctx->inputs[1]->channels / power;
+            break;
+        case 2:
+            for (ch = 0; ch < ctx->inputs[1]->channels; ch++) {
+                float *time = (float *)s->in[1]->extended_data[!s->one2many * ch];
 
-            for (i = 0; i < s->nb_taps; i++)
-                power += FFABS(time[i]);
+                for (i = 0; i < s->nb_taps; i++)
+                    power += time[i] * time[i];
+            }
+            s->gain = sqrtf(ch / power);
+            break;
+        default:
+            return AVERROR_BUG;
         }
+    }
 
-        s->gain = sqrtf(1.f / (ctx->inputs[1]->channels * power)) / (sqrtf(ctx->inputs[1]->channels));
-        for (ch = 0; ch < ctx->inputs[1]->channels; ch++) {
-            float *time = (float *)s->in[1]->extended_data[!s->one2many * ch];
+    s->gain = FFMIN(s->gain * s->ir_gain, 1.f);
+    av_log(ctx, AV_LOG_DEBUG, "power %f, gain %f\n", power, s->gain);
+    for (ch = 0; ch < ctx->inputs[1]->channels; ch++) {
+        float *time = (float *)s->in[1]->extended_data[!s->one2many * ch];
 
-            s->fdsp->vector_fmul_scalar(time, time, s->gain, FFALIGN(s->nb_taps, 4));
-        }
+        s->fdsp->vector_fmul_scalar(time, time, s->gain, FFALIGN(s->nb_taps, 4));
     }
 
     for (ch = 0; ch < ctx->inputs[1]->channels; ch++) {
@@ -727,6 +754,11 @@ static const AVOption afir_options[] = {
     { "wet",    "set wet gain",      OFFSET(wet_gain),   AV_OPT_TYPE_FLOAT, {.dbl=1},    0, 10, AF },
     { "length", "set IR length",     OFFSET(length),     AV_OPT_TYPE_FLOAT, {.dbl=1},    0,  1, AF },
     { "again",  "enable auto gain",  OFFSET(again),      AV_OPT_TYPE_BOOL,  {.i64=1},    0,  1, AF },
+    { "gtype",  "set auto gain type",OFFSET(gtype),      AV_OPT_TYPE_INT,   {.i64=0},    0,  2, 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" },
+    { "irgain", "set IR gain",       OFFSET(ir_gain),    AV_OPT_TYPE_FLOAT, {.dbl=1},    0,  1, AF },
     { "maxir",  "set max IR length", OFFSET(max_ir_len), AV_OPT_TYPE_FLOAT, {.dbl=30}, 0.1, 60, AF },
     { "response", "show IR frequency response", OFFSET(response), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, VF },
     { "channel", "set IR channel to display frequency response", OFFSET(ir_channel), AV_OPT_TYPE_INT, {.i64=0}, 0, 1024, VF },
index 9489ad0..9e6f957 100644 (file)
@@ -39,6 +39,8 @@ typedef struct AudioFIRContext {
     float dry_gain;
     float length;
     int again;
+    int gtype;
+    float ir_gain;
     float max_ir_len;
     int response;
     int w, h;