avfilter/af_aiir: rename options, provide gains in separate option

This way it can be also used for other format.

Signed-off-by: Paul B Mahol <onemda@gmail.com>
pull/303/head
Paul B Mahol 7 years ago
parent 6c65de3db0
commit 2d3df8e2e9
  1. 20
      doc/filters.texi
  2. 95
      libavfilter/af_aiir.c

@ -1067,11 +1067,14 @@ Apply an arbitrary Infinite Impulse Response filter.
It accepts the following parameters: It accepts the following parameters:
@table @option @table @option
@item a @item z
Set numerator/zeros coefficients.
@item p
Set denominator/poles coefficients. Set denominator/poles coefficients.
@item b @item k
Set numerator/zeros coefficients. Set channels gains.
@item dry_gain @item dry_gain
Set input gain. Set input gain.
@ -1089,11 +1092,10 @@ order.
Coefficients in @code{zp} format are separated by spaces and order of coefficients Coefficients in @code{zp} format are separated by spaces and order of coefficients
doesn't matter. Coefficients in @code{zp} format are complex numbers with @var{i} doesn't matter. Coefficients in @code{zp} format are complex numbers with @var{i}
imaginary unit, also first number in numerator, option @var{b}, is not complex but imaginary unit.
real number and sets overall gain for channel.
Different coefficients can be provided for every channel, in such case Different coefficients and gains can be provided for every channel, in such case
use '|' to separate coefficients. Last provided coefficients will be use '|' to separate coefficients or gains. Last provided coefficients will be
used for all remaining channels. used for all remaining channels.
@subsection Examples @subsection Examples
@ -1102,13 +1104,13 @@ used for all remaining channels.
@item @item
Apply 2 pole elliptic notch at arround 5000Hz for 48000 Hz sample rate: Apply 2 pole elliptic notch at arround 5000Hz for 48000 Hz sample rate:
@example @example
aiir=b=7.957584807809675810E-1 -2.575128568908332300 3.674839853930788710 -2.57512875289799137 7.957586296317130880E-1:a=1 -2.86950072432325953 3.63022088054647218 -2.28075678147272232 6.361362326477423500E-1:f=tf aiir=k=1:z=7.957584807809675810E-1 -2.575128568908332300 3.674839853930788710 -2.57512875289799137 7.957586296317130880E-1:p=1 -2.86950072432325953 3.63022088054647218 -2.28075678147272232 6.361362326477423500E-1:f=tf
@end example @end example
@item @item
Same as above but in @code{zp} format: Same as above but in @code{zp} format:
@example @example
aiir=b=0.79575848078096756 0.80918701+0.58773007i 0.80918701-0.58773007i 0.80884700+0.58784055i 0.80884700-0.58784055i:a=0.63892345+0.59951235i 0.63892345-0.59951235i 0.79582691+0.44198673i 0.79582691-0.44198673i:f=zp aiir=k=0.79575848078096756:z=0.80918701+0.58773007i 0.80918701-0.58773007i 0.80884700+0.58784055i 0.80884700-0.58784055i:p=0.63892345+0.59951235i 0.63892345-0.59951235i 0.79582691+0.44198673i 0.79582691-0.44198673i:f=zp
@end example @end example
@end itemize @end itemize

@ -29,12 +29,13 @@
typedef struct AudioIIRContext { typedef struct AudioIIRContext {
const AVClass *class; const AVClass *class;
char *a_str, *b_str; char *a_str, *b_str, *g_str;
double dry_gain, wet_gain; double dry_gain, wet_gain;
int format; int format;
int *nb_a, *nb_b; int *nb_a, *nb_b;
double **a, **b; double **a, **b;
double *g;
double **input, **output; double **input, **output;
int clippings; int clippings;
int channels; int channels;
@ -140,6 +141,38 @@ static void count_coefficients(char *item_str, int *nb_items)
} }
} }
static int read_gains(AVFilterContext *ctx, char *item_str, int nb_items, double *dst)
{
char *p, *arg, *old_str, *prev_arg = NULL, *saveptr = NULL;
int i;
p = old_str = av_strdup(item_str);
if (!p)
return AVERROR(ENOMEM);
for (i = 0; i < nb_items; i++) {
if (!(arg = av_strtok(p, "|", &saveptr)))
arg = prev_arg;
if (!arg) {
av_freep(&old_str);
return AVERROR(EINVAL);
}
p = NULL;
if (sscanf(arg, "%lf", &dst[i]) != 1) {
av_log(ctx, AV_LOG_ERROR, "Invalid gains supplied: %s\n", arg);
av_freep(&old_str);
return AVERROR(EINVAL);
}
prev_arg = arg;
}
av_freep(&old_str);
return 0;
}
static int read_tf_coefficients(AVFilterContext *ctx, char *item_str, int nb_items, double *dst) static int read_tf_coefficients(AVFilterContext *ctx, char *item_str, int nb_items, double *dst)
{ {
char *p, *arg, *old_str, *saveptr = NULL; char *p, *arg, *old_str, *saveptr = NULL;
@ -155,6 +188,7 @@ static int read_tf_coefficients(AVFilterContext *ctx, char *item_str, int nb_ite
p = NULL; p = NULL;
if (sscanf(arg, "%lf", &dst[i]) != 1) { if (sscanf(arg, "%lf", &dst[i]) != 1) {
av_log(ctx, AV_LOG_ERROR, "Invalid coefficients supplied: %s\n", arg); av_log(ctx, AV_LOG_ERROR, "Invalid coefficients supplied: %s\n", arg);
av_freep(&old_str);
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
} }
@ -164,7 +198,7 @@ static int read_tf_coefficients(AVFilterContext *ctx, char *item_str, int nb_ite
return 0; return 0;
} }
static int read_zp_coefficients(AVFilterContext *ctx, char *item_str, int nb_items, double *dst, int is_zeros) static int read_zp_coefficients(AVFilterContext *ctx, char *item_str, int nb_items, double *dst)
{ {
char *p, *arg, *old_str, *saveptr = NULL; char *p, *arg, *old_str, *saveptr = NULL;
int i; int i;
@ -177,16 +211,10 @@ static int read_zp_coefficients(AVFilterContext *ctx, char *item_str, int nb_ite
break; break;
p = NULL; p = NULL;
if (i == 0 && is_zeros) { if (sscanf(arg, "%lf %lfi", &dst[i*2], &dst[i*2+1]) != 2) {
if (sscanf(arg, "%lf", &dst[i]) != 1) { av_log(ctx, AV_LOG_ERROR, "Invalid coefficients supplied: %s\n", arg);
av_log(ctx, AV_LOG_ERROR, "Invalid gain supplied: %s\n", arg); av_freep(&old_str);
return AVERROR(EINVAL); return AVERROR(EINVAL);
}
} else {
if (sscanf(arg, "%lf %lfi", &dst[i*2], &dst[i*2+1]) != 2) {
av_log(ctx, AV_LOG_ERROR, "Invalid coefficients supplied: %s\n", arg);
return AVERROR(EINVAL);
}
} }
} }
@ -195,7 +223,7 @@ static int read_zp_coefficients(AVFilterContext *ctx, char *item_str, int nb_ite
return 0; return 0;
} }
static int read_channels(AVFilterContext *ctx, int channels, uint8_t *item_str, int *nb, double **c, double **cache, int is_zeros) static int read_channels(AVFilterContext *ctx, int channels, uint8_t *item_str, int *nb, double **c, double **cache)
{ {
AudioIIRContext *s = ctx->priv; AudioIIRContext *s = ctx->priv;
char *p, *arg, *old_str, *prev_arg = NULL, *saveptr = NULL; char *p, *arg, *old_str, *prev_arg = NULL, *saveptr = NULL;
@ -208,26 +236,30 @@ static int read_channels(AVFilterContext *ctx, int channels, uint8_t *item_str,
if (!(arg = av_strtok(p, "|", &saveptr))) if (!(arg = av_strtok(p, "|", &saveptr)))
arg = prev_arg; arg = prev_arg;
if (!arg) if (!arg) {
av_freep(&old_str);
return AVERROR(EINVAL); return AVERROR(EINVAL);
}
count_coefficients(arg, &nb[i]); count_coefficients(arg, &nb[i]);
p = NULL; p = NULL;
cache[i] = av_calloc(nb[i] + 1, sizeof(double)); cache[i] = av_calloc(nb[i] + 1, sizeof(double));
c[i] = av_calloc(nb[i] * (s->format + 1), sizeof(double)); c[i] = av_calloc(nb[i] * (s->format + 1), sizeof(double));
if (!c[i] || !cache[i]) if (!c[i] || !cache[i]) {
av_freep(&old_str);
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
}
if (s->format) { if (s->format) {
ret = read_zp_coefficients(ctx, arg, nb[i], c[i], is_zeros); ret = read_zp_coefficients(ctx, arg, nb[i], c[i]);
if (is_zeros)
nb[i]--;
} else { } else {
ret = read_tf_coefficients(ctx, arg, nb[i], c[i]); ret = read_tf_coefficients(ctx, arg, nb[i], c[i]);
} }
if (ret < 0) if (ret < 0) {
av_freep(&old_str);
return ret; return ret;
}
prev_arg = arg; prev_arg = arg;
} }
@ -288,7 +320,7 @@ static int convert_zp2tf(AVFilterContext *ctx, int channels)
int ch, i, j, ret; int ch, i, j, ret;
for (ch = 0; ch < channels; ch++) { for (ch = 0; ch < channels; ch++) {
double *topc, *botc, gain; double *topc, *botc;
topc = av_calloc((s->nb_b[ch] + 1) * 2, sizeof(*topc)); topc = av_calloc((s->nb_b[ch] + 1) * 2, sizeof(*topc));
botc = av_calloc((s->nb_a[ch] + 1) * 2, sizeof(*botc)); botc = av_calloc((s->nb_a[ch] + 1) * 2, sizeof(*botc));
@ -302,16 +334,15 @@ static int convert_zp2tf(AVFilterContext *ctx, int channels)
return ret; return ret;
} }
ret = expand(ctx, &s->b[ch][2], s->nb_b[ch], topc); ret = expand(ctx, s->b[ch], s->nb_b[ch], topc);
if (ret < 0) { if (ret < 0) {
av_free(topc); av_free(topc);
av_free(botc); av_free(botc);
return ret; return ret;
} }
gain = s->b[ch][0];
for (j = 0, i = s->nb_b[ch]; i >= 0; j++, i--) { for (j = 0, i = s->nb_b[ch]; i >= 0; j++, i--) {
s->b[ch][j] = topc[2 * i] * gain; s->b[ch][j] = topc[2 * i];
} }
s->nb_b[ch]++; s->nb_b[ch]++;
@ -337,6 +368,7 @@ static int config_output(AVFilterLink *outlink)
s->channels = inlink->channels; s->channels = inlink->channels;
s->a = av_calloc(inlink->channels, sizeof(*s->a)); s->a = av_calloc(inlink->channels, sizeof(*s->a));
s->b = av_calloc(inlink->channels, sizeof(*s->b)); s->b = av_calloc(inlink->channels, sizeof(*s->b));
s->g = av_calloc(inlink->channels, sizeof(*s->g));
s->nb_a = av_calloc(inlink->channels, sizeof(*s->nb_a)); s->nb_a = av_calloc(inlink->channels, sizeof(*s->nb_a));
s->nb_b = av_calloc(inlink->channels, sizeof(*s->nb_b)); s->nb_b = av_calloc(inlink->channels, sizeof(*s->nb_b));
s->input = av_calloc(inlink->channels, sizeof(*s->input)); s->input = av_calloc(inlink->channels, sizeof(*s->input));
@ -344,11 +376,15 @@ static int config_output(AVFilterLink *outlink)
if (!s->a || !s->b || !s->nb_a || !s->nb_b || !s->input || !s->output) if (!s->a || !s->b || !s->nb_a || !s->nb_b || !s->input || !s->output)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
ret = read_channels(ctx, inlink->channels, s->a_str, s->nb_a, s->a, s->output, 0); ret = read_gains(ctx, s->g_str, inlink->channels, s->g);
if (ret < 0)
return ret;
ret = read_channels(ctx, inlink->channels, s->a_str, s->nb_a, s->a, s->output);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = read_channels(ctx, inlink->channels, s->b_str, s->nb_b, s->b, s->input, 1); ret = read_channels(ctx, inlink->channels, s->b_str, s->nb_b, s->b, s->input);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -364,7 +400,7 @@ static int config_output(AVFilterLink *outlink)
} }
for (i = 0; i < s->nb_b[ch]; i++) { for (i = 0; i < s->nb_b[ch]; i++) {
s->b[ch][i] /= s->a[ch][0]; s->b[ch][i] *= s->g[ch] / s->a[ch][0];
} }
} }
@ -412,7 +448,7 @@ static av_cold int init(AVFilterContext *ctx)
{ {
AudioIIRContext *s = ctx->priv; AudioIIRContext *s = ctx->priv;
if (!s->a_str || !s->b_str) { if (!s->a_str || !s->b_str || !s->g_str) {
av_log(ctx, AV_LOG_ERROR, "Valid coefficients are mandatory.\n"); av_log(ctx, AV_LOG_ERROR, "Valid coefficients are mandatory.\n");
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
@ -470,8 +506,9 @@ static const AVFilterPad outputs[] = {
#define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM #define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption aiir_options[] = { static const AVOption aiir_options[] = {
{ "a", "set A/denominator/poles coefficients", OFFSET(a_str), AV_OPT_TYPE_STRING, {.str="1 1"}, 0, 0, AF }, { "z", "set B/numerator/zeros coefficients", OFFSET(b_str), AV_OPT_TYPE_STRING, {.str="1 1"}, 0, 0, AF },
{ "b", "set B/numerator/zeros coefficients", OFFSET(b_str), AV_OPT_TYPE_STRING, {.str="1 1"}, 0, 0, AF }, { "p", "set A/denominator/poles coefficients", OFFSET(a_str), AV_OPT_TYPE_STRING, {.str="1 1"}, 0, 0, AF },
{ "k", "set channels gains", OFFSET(g_str), AV_OPT_TYPE_STRING, {.str="1|1"}, 0, 0, AF },
{ "dry", "set dry gain", OFFSET(dry_gain), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, AF }, { "dry", "set dry gain", OFFSET(dry_gain), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, AF },
{ "wet", "set wet gain", OFFSET(wet_gain), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, AF }, { "wet", "set wet gain", OFFSET(wet_gain), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, AF },
{ "f", "set coefficients format", OFFSET(format), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AF, "format" }, { "f", "set coefficients format", OFFSET(format), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AF, "format" },

Loading…
Cancel
Save