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,
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.
{
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)
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++) {
{ "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 },