diff --git a/doc/filters.texi b/doc/filters.texi index a52f6ff578..618eb28e28 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -1084,8 +1084,17 @@ Set output gain. @item f Set coefficients format. -Can be @code{tf} - transfer function or @code{zp} - Z-plane zeros/poles. -Default is @code{zp}. + +@table @samp +@item tf +transfer function +@item zp +Z-plane zeros/poles, cartesian (default) +@item zpr +Z-plane zeros/poles, polar radians +@item zpd +Z-plane zeros/poles, polar degrees +@end table @item r Set kind of processing. @@ -1094,7 +1103,7 @@ Can be @code{d} - direct or @code{s} - serial cascading. Defauls is @code{s}. @item e Set filtering precision. -@table @option +@table @samp @item dbl double-precision floating-point (default) @item flt diff --git a/libavfilter/af_aiir.c b/libavfilter/af_aiir.c index 46b1c7e698..1f2a568c1d 100644 --- a/libavfilter/af_aiir.c +++ b/libavfilter/af_aiir.c @@ -283,7 +283,7 @@ static int read_tf_coefficients(AVFilterContext *ctx, char *item_str, int nb_ite return 0; } -static int read_zp_coefficients(AVFilterContext *ctx, char *item_str, int nb_items, double *dst) +static int read_zp_coefficients(AVFilterContext *ctx, char *item_str, int nb_items, double *dst, const char *format) { char *p, *arg, *old_str, *saveptr = NULL; int i; @@ -296,7 +296,7 @@ static int read_zp_coefficients(AVFilterContext *ctx, char *item_str, int nb_ite break; p = NULL; - if (sscanf(arg, "%lf %lfi", &dst[i*2], &dst[i*2+1]) != 2) { + if (sscanf(arg, format, &dst[i*2], &dst[i*2+1]) != 2) { av_log(ctx, AV_LOG_ERROR, "Invalid coefficients supplied: %s\n", arg); av_freep(&old_str); return AVERROR(EINVAL); @@ -308,6 +308,8 @@ static int read_zp_coefficients(AVFilterContext *ctx, char *item_str, int nb_ite return 0; } +static const char *format[] = { "%lf", "%lf %lfi", "%lf %lfr", "%lf %lfd" }; + static int read_channels(AVFilterContext *ctx, int channels, uint8_t *item_str, int ab) { AudioIIRContext *s = ctx->priv; @@ -332,14 +334,14 @@ static int read_channels(AVFilterContext *ctx, int channels, uint8_t *item_str, p = NULL; iir->cache[ab] = av_calloc(iir->nb_ab[ab] + 1, sizeof(double)); - iir->ab[ab] = av_calloc(iir->nb_ab[ab] * (s->format + 1), sizeof(double)); + iir->ab[ab] = av_calloc(iir->nb_ab[ab] * (!!s->format + 1), sizeof(double)); if (!iir->ab[ab] || !iir->cache[ab]) { av_freep(&old_str); return AVERROR(ENOMEM); } if (s->format) { - ret = read_zp_coefficients(ctx, arg, iir->nb_ab[ab], iir->ab[ab]); + ret = read_zp_coefficients(ctx, arg, iir->nb_ab[ab], iir->ab[ab], format[s->format]); } else { ret = read_tf_coefficients(ctx, arg, iir->nb_ab[ab], iir->ab[ab]); } @@ -586,6 +588,60 @@ static int decompose_zp2biquads(AVFilterContext *ctx, int channels) return 0; } +static void convert_pr2zp(AVFilterContext *ctx, int channels) +{ + AudioIIRContext *s = ctx->priv; + int ch; + + for (ch = 0; ch < channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + int n; + + for (n = 0; n < iir->nb_ab[0]; n++) { + double r = iir->ab[0][2*n]; + double angle = iir->ab[0][2*n+1]; + + iir->ab[0][2*n] = r * cos(angle); + iir->ab[0][2*n+1] = r * sin(angle); + } + + for (n = 0; n < iir->nb_ab[1]; n++) { + double r = iir->ab[1][2*n]; + double angle = iir->ab[1][2*n+1]; + + iir->ab[1][2*n] = r * cos(angle); + iir->ab[1][2*n+1] = r * sin(angle); + } + } +} + +static void convert_pd2zp(AVFilterContext *ctx, int channels) +{ + AudioIIRContext *s = ctx->priv; + int ch; + + for (ch = 0; ch < channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + int n; + + for (n = 0; n < iir->nb_ab[0]; n++) { + double r = iir->ab[0][2*n]; + double angle = M_PI*iir->ab[0][2*n+1]/180.; + + iir->ab[0][2*n] = r * cos(angle); + iir->ab[0][2*n+1] = r * sin(angle); + } + + for (n = 0; n < iir->nb_ab[1]; n++) { + double r = iir->ab[1][2*n]; + double angle = M_PI*iir->ab[1][2*n+1]/180.; + + iir->ab[1][2*n] = r * cos(angle); + iir->ab[1][2*n+1] = r * sin(angle); + } + } +} + static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; @@ -610,10 +666,16 @@ static int config_output(AVFilterLink *outlink) if (ret < 0) return ret; + if (s->format == 2) { + convert_pr2zp(ctx, inlink->channels); + } else if (s->format == 3) { + convert_pd2zp(ctx, inlink->channels); + } + if (s->format == 0) av_log(ctx, AV_LOG_WARNING, "tf coefficients format is not recommended for too high number of zeros/poles.\n"); - if (s->format == 1 && s->process == 0) { + if (s->format > 0 && s->process == 0) { av_log(ctx, AV_LOG_WARNING, "Direct processsing is not recommended for zp coefficients format.\n"); ret = convert_zp2tf(ctx, inlink->channels); @@ -622,7 +684,7 @@ static int config_output(AVFilterLink *outlink) } else if (s->format == 0 && s->process == 1) { av_log(ctx, AV_LOG_ERROR, "Serial cascading is not implemented for transfer function.\n"); return AVERROR_PATCHWELCOME; - } else if (s->format == 1 && s->process == 1) { + } else if (s->format > 0 && s->process == 1) { if (inlink->format == AV_SAMPLE_FMT_S16P) av_log(ctx, AV_LOG_WARNING, "Serial cascading is not recommended for i16 precision.\n"); @@ -755,9 +817,11 @@ static const AVOption aiir_options[] = { { "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 }, { "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=1}, 0, 1, AF, "format" }, + { "f", "set coefficients format", OFFSET(format), AV_OPT_TYPE_INT, {.i64=1}, 0, 3, AF, "format" }, { "tf", "transfer function", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "format" }, { "zp", "Z-plane zeros/poles", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "format" }, + { "pr", "Z-plane zeros/poles (polar radians)", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "format" }, + { "pd", "Z-plane zeros/poles (polar degrees)", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "format" }, { "r", "set kind of processing", OFFSET(process), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AF, "process" }, { "d", "direct", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "process" }, { "s", "serial cascading", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "process" },