avfilter/af_agate: implement mode option

This commit is contained in:
Paul B Mahol 2019-04-17 23:33:51 +02:00
parent a0559fcd81
commit 8a3ed5a313
2 changed files with 46 additions and 21 deletions

View File

@ -1308,9 +1308,16 @@ Shorter signals than the chosen attack time will be left untouched.
Set input level before filtering. Set input level before filtering.
Default is 1. Allowed range is from 0.015625 to 64. Default is 1. Allowed range is from 0.015625 to 64.
@item mode
Set the mode of operation. Can be @code{upward} or @code{downward}.
Default is @code{downward}. If set to @code{upward} mode, higher parts of signal
will be amplified, expanding dynamic range in upward direction.
Otherwise, in case of @code{downward} lower parts of signal will be reduced.
@item range @item range
Set the level of gain reduction when the signal is below the threshold. Set the level of gain reduction when the signal is below the threshold.
Default is 0.06125. Allowed range is from 0 to 1. Default is 0.06125. Allowed range is from 0 to 1.
Setting this to 0 disables reduction and then filter behaves like expander.
@item threshold @item threshold
If a signal rises above this level the gain reduction is released. If a signal rises above this level the gain reduction is released.
@ -4331,9 +4338,16 @@ The filter accepts the following options:
Set input level before filtering. Set input level before filtering.
Default is 1. Allowed range is from 0.015625 to 64. Default is 1. Allowed range is from 0.015625 to 64.
@item mode
Set the mode of operation. Can be @code{upward} or @code{downward}.
Default is @code{downward}. If set to @code{upward} mode, higher parts of signal
will be amplified, expanding dynamic range in upward direction.
Otherwise, in case of @code{downward} lower parts of signal will be reduced.
@item range @item range
Set the level of gain reduction when the signal is below the threshold. Set the level of gain reduction when the signal is below the threshold.
Default is 0.06125. Allowed range is from 0 to 1. Default is 0.06125. Allowed range is from 0 to 1.
Setting this to 0 disables reduction and then filter behaves like expander.
@item threshold @item threshold
If a signal rises above this level the gain reduction is released. If a signal rises above this level the gain reduction is released.

View File

@ -47,11 +47,13 @@ typedef struct AudioGateContext {
double range; double range;
int link; int link;
int detection; int detection;
int mode;
double thres; double thres;
double knee_start; double knee_start;
double lin_knee_stop;
double knee_stop; double knee_stop;
double lin_knee_start;
double lin_knee_stop;
double lin_slope; double lin_slope;
double attack_coeff; double attack_coeff;
double release_coeff; double release_coeff;
@ -65,6 +67,9 @@ typedef struct AudioGateContext {
static const AVOption options[] = { static const AVOption options[] = {
{ "level_in", "set input level", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A }, { "level_in", "set input level", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A },
{ "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, A, "mode" },
{ "downward",0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A, "mode" },
{ "upward", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A, "mode" },
{ "range", "set max gain reduction", OFFSET(range), AV_OPT_TYPE_DOUBLE, {.dbl=0.06125}, 0, 1, A }, { "range", "set max gain reduction", OFFSET(range), AV_OPT_TYPE_DOUBLE, {.dbl=0.06125}, 0, 1, A },
{ "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0.125}, 0, 1, A }, { "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0.125}, 0, 1, A },
{ "ratio", "set ratio", OFFSET(ratio), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 1, 9000, A }, { "ratio", "set ratio", OFFSET(ratio), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 1, 9000, A },
@ -88,7 +93,6 @@ static int agate_config_input(AVFilterLink *inlink)
AudioGateContext *s = ctx->priv; AudioGateContext *s = ctx->priv;
double lin_threshold = s->threshold; double lin_threshold = s->threshold;
double lin_knee_sqrt = sqrt(s->knee); double lin_knee_sqrt = sqrt(s->knee);
double lin_knee_start;
if (s->detection) if (s->detection)
lin_threshold *= lin_threshold; lin_threshold *= lin_threshold;
@ -96,9 +100,9 @@ static int agate_config_input(AVFilterLink *inlink)
s->attack_coeff = FFMIN(1., 1. / (s->attack * inlink->sample_rate / 4000.)); s->attack_coeff = FFMIN(1., 1. / (s->attack * inlink->sample_rate / 4000.));
s->release_coeff = FFMIN(1., 1. / (s->release * inlink->sample_rate / 4000.)); s->release_coeff = FFMIN(1., 1. / (s->release * inlink->sample_rate / 4000.));
s->lin_knee_stop = lin_threshold * lin_knee_sqrt; s->lin_knee_stop = lin_threshold * lin_knee_sqrt;
lin_knee_start = lin_threshold / lin_knee_sqrt; s->lin_knee_start = lin_threshold / lin_knee_sqrt;
s->thres = log(lin_threshold); s->thres = log(lin_threshold);
s->knee_start = log(lin_knee_start); s->knee_start = log(s->lin_knee_start);
s->knee_stop = log(s->lin_knee_stop); s->knee_stop = log(s->lin_knee_stop);
return 0; return 0;
@ -112,26 +116,26 @@ static int agate_config_input(AVFilterLink *inlink)
static double output_gain(double lin_slope, double ratio, double thres, static double output_gain(double lin_slope, double ratio, double thres,
double knee, double knee_start, double knee_stop, double knee, double knee_start, double knee_stop,
double lin_knee_stop, double range) double range, int mode)
{ {
if (lin_slope < lin_knee_stop) { double slope = log(lin_slope);
double slope = log(lin_slope); double tratio = ratio;
double tratio = ratio; double gain = 0.;
double gain = 0.; double delta = 0.;
double delta = 0.;
if (IS_FAKE_INFINITY(ratio)) if (IS_FAKE_INFINITY(ratio))
tratio = 1000.; tratio = 1000.;
gain = (slope - thres) * tratio + thres; gain = (slope - thres) * tratio + thres;
delta = tratio; delta = tratio;
if (knee > 1. && slope > knee_start) { if (mode) {
if (knee > 1. && slope < knee_stop)
gain = hermite_interpolation(slope, knee_stop, knee_start, ((knee_stop - thres) * tratio + thres), knee_start, delta, 1.);
} else {
if (knee > 1. && slope > knee_start)
gain = hermite_interpolation(slope, knee_start, knee_stop, ((knee_start - thres) * tratio + thres), knee_stop, delta, 1.); gain = hermite_interpolation(slope, knee_start, knee_stop, ((knee_start - thres) * tratio + thres), knee_stop, delta, 1.);
}
return FFMAX(range, exp(gain - slope));
} }
return FFMAX(range, exp(gain - slope));
return 1.;
} }
static void gate(AudioGateContext *s, static void gate(AudioGateContext *s,
@ -146,6 +150,7 @@ static void gate(AudioGateContext *s,
for (n = 0; n < nb_samples; n++, src += inlink->channels, dst += inlink->channels, scsrc += sclink->channels) { for (n = 0; n < nb_samples; n++, src += inlink->channels, dst += inlink->channels, scsrc += sclink->channels) {
double abs_sample = fabs(scsrc[0] * level_sc), gain = 1.0; double abs_sample = fabs(scsrc[0] * level_sc), gain = 1.0;
int detected;
if (s->link == 1) { if (s->link == 1) {
for (c = 1; c < sclink->channels; c++) for (c = 1; c < sclink->channels; c++)
@ -161,10 +166,16 @@ static void gate(AudioGateContext *s,
abs_sample *= abs_sample; abs_sample *= abs_sample;
s->lin_slope += (abs_sample - s->lin_slope) * (abs_sample > s->lin_slope ? attack_coeff : release_coeff); s->lin_slope += (abs_sample - s->lin_slope) * (abs_sample > s->lin_slope ? attack_coeff : release_coeff);
if (s->lin_slope > 0.0)
if (s->mode)
detected = s->lin_slope > s->lin_knee_start;
else
detected = s->lin_slope < s->lin_knee_stop;
if (s->lin_slope > 0.0 && detected)
gain = output_gain(s->lin_slope, s->ratio, s->thres, gain = output_gain(s->lin_slope, s->ratio, s->thres,
s->knee, s->knee_start, s->knee_stop, s->knee, s->knee_start, s->knee_stop,
s->lin_knee_stop, s->range); s->range, s->mode);
for (c = 0; c < inlink->channels; c++) for (c = 0; c < inlink->channels; c++)
dst[c] = src[c] * level_in * gain * makeup; dst[c] = src[c] * level_in * gain * makeup;