Commit 9e45364a authored by Paul B Mahol's avatar Paul B Mahol

avfilter/af_afir: make IR gain control more flexible

For this reason introduce two more options.
parent 4c514edc
......@@ -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.
......
......@@ -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 },
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment