mirror of https://git.ffmpeg.org/ffmpeg.git
avfilter/af_aiir: add polar zeros/poles format variant
Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
parent
de5b12c93f
commit
de8a1d8d4d
|
@ -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
|
||||
|
|
|
@ -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" },
|
||||
|
|
Loading…
Reference in New Issue