avfilter/af_asupercut: add order option

This commit is contained in:
Paul B Mahol
2020-11-29 14:06:44 +01:00
parent f194cedfe6
commit bebea78755
2 changed files with 34 additions and 12 deletions

View File

@@ -2645,6 +2645,10 @@ The filter accepts the following options:
@item cutoff @item cutoff
Set cutoff frequency in Hertz. Allowed range is 20000 to 192000. Set cutoff frequency in Hertz. Allowed range is 20000 to 192000.
Default value is 20000. Default value is 20000.
@item order
Set filter order. Available values are from 3 to 20.
Default value is 10.
@end table @end table
@subsection Commands @subsection Commands

View File

@@ -32,10 +32,12 @@ typedef struct ASuperCutContext {
const AVClass *class; const AVClass *class;
double cutoff; double cutoff;
int order;
int filter_count;
int bypass; int bypass;
BiquadCoeffs coeffs[5]; BiquadCoeffs coeffs[10];
AVFrame *w; AVFrame *w;
} ASuperCutContext; } ASuperCutContext;
@@ -69,33 +71,48 @@ static int query_formats(AVFilterContext *ctx)
return ff_set_common_samplerates(ctx, formats); return ff_set_common_samplerates(ctx, formats);
} }
static void calc_q_factors(int n, double *q)
{
for (int i = 0; i < n / 2; i++)
q[i] = 1. / (-2. * cos(M_PI * (2. * (i + 1) + n - 1.) / (2. * n)));
}
static int get_coeffs(AVFilterContext *ctx) static int get_coeffs(AVFilterContext *ctx)
{ {
ASuperCutContext *s = ctx->priv; ASuperCutContext *s = ctx->priv;
AVFilterLink *inlink = ctx->inputs[0]; AVFilterLink *inlink = ctx->inputs[0];
double w0 = s->cutoff / inlink->sample_rate; double w0 = s->cutoff / inlink->sample_rate;
double K = tan(M_PI * w0); double K = tan(M_PI * w0);
double q[5]; double q[10];
s->bypass = w0 >= 0.5; s->bypass = w0 >= 0.5;
if (s->bypass) if (s->bypass)
return 0; return 0;
q[0] = 0.50623256; s->filter_count = s->order / 2 + (s->order & 1);
q[1] = 0.56116312; calc_q_factors(s->order, q);
q[2] = 0.70710678;
q[3] = 1.10134463;
q[4] = 3.19622661;
for (int b = 0; b < 5; b++) { if (s->order & 1) {
BiquadCoeffs *coeffs = &s->coeffs[0];
double omega = 2. * tan(M_PI * w0);
coeffs->b0 = omega / (2. + omega);
coeffs->b1 = coeffs->b0;
coeffs->b2 = 0.;
coeffs->a1 = -(omega - 2.) / (2. + omega);
coeffs->a2 = 0.;
}
for (int b = (s->order & 1); b < s->filter_count; b++) {
BiquadCoeffs *coeffs = &s->coeffs[b]; BiquadCoeffs *coeffs = &s->coeffs[b];
double norm = 1.0 / (1.0 + K / q[b] + K * K); const int idx = b - (s->order & 1);
double norm = 1.0 / (1.0 + K / q[idx] + K * K);
coeffs->b0 = K * K * norm; coeffs->b0 = K * K * norm;
coeffs->b1 = 2.0 * coeffs->b0; coeffs->b1 = 2.0 * coeffs->b0;
coeffs->b2 = coeffs->b0; coeffs->b2 = coeffs->b0;
coeffs->a1 = -2.0 * (K * K - 1.0) * norm; coeffs->a1 = -2.0 * (K * K - 1.0) * norm;
coeffs->a2 = -(1.0 - K / q[b] + K * K) * norm; coeffs->a2 = -(1.0 - K / q[idx] + K * K) * norm;
} }
return 0; return 0;
@@ -106,7 +123,7 @@ static int config_input(AVFilterLink *inlink)
AVFilterContext *ctx = inlink->dst; AVFilterContext *ctx = inlink->dst;
ASuperCutContext *s = ctx->priv; ASuperCutContext *s = ctx->priv;
s->w = ff_get_audio_buffer(inlink, 2 * 5); s->w = ff_get_audio_buffer(inlink, 2 * 10);
if (!s->w) if (!s->w)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
@@ -130,7 +147,7 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
const double *src = (const double *)in->extended_data[ch]; const double *src = (const double *)in->extended_data[ch];
double *dst = (double *)out->extended_data[ch]; double *dst = (double *)out->extended_data[ch];
for (int b = 0; b < 5; b++) { for (int b = 0; b < s->filter_count; b++) {
BiquadCoeffs *coeffs = &s->coeffs[b]; BiquadCoeffs *coeffs = &s->coeffs[b];
const double a1 = coeffs->a1; const double a1 = coeffs->a1;
const double a2 = coeffs->a2; const double a2 = coeffs->a2;
@@ -209,6 +226,7 @@ static av_cold void uninit(AVFilterContext *ctx)
static const AVOption asupercut_options[] = { static const AVOption asupercut_options[] = {
{ "cutoff", "set cutoff frequency", OFFSET(cutoff), AV_OPT_TYPE_DOUBLE, {.dbl=20000}, 20000, 192000, FLAGS }, { "cutoff", "set cutoff frequency", OFFSET(cutoff), AV_OPT_TYPE_DOUBLE, {.dbl=20000}, 20000, 192000, FLAGS },
{ "order", "set filter order", OFFSET(order), AV_OPT_TYPE_INT, {.i64=10}, 3, 20, FLAGS },
{ NULL } { NULL }
}; };