diff --git a/doc/filters.texi b/doc/filters.texi index 05a9ca3684..4dd1a5de85 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -1308,9 +1308,16 @@ Shorter signals than the chosen attack time will be left untouched. Set input level before filtering. 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 Set the level of gain reduction when the signal is below the threshold. 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 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. 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 Set the level of gain reduction when the signal is below the threshold. 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 If a signal rises above this level the gain reduction is released. diff --git a/libavfilter/af_agate.c b/libavfilter/af_agate.c index ba96863a68..0609dc222e 100644 --- a/libavfilter/af_agate.c +++ b/libavfilter/af_agate.c @@ -47,11 +47,13 @@ typedef struct AudioGateContext { double range; int link; int detection; + int mode; double thres; double knee_start; - double lin_knee_stop; double knee_stop; + double lin_knee_start; + double lin_knee_stop; double lin_slope; double attack_coeff; double release_coeff; @@ -65,6 +67,9 @@ typedef struct AudioGateContext { static const AVOption options[] = { { "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 }, { "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 }, @@ -88,7 +93,6 @@ static int agate_config_input(AVFilterLink *inlink) AudioGateContext *s = ctx->priv; double lin_threshold = s->threshold; double lin_knee_sqrt = sqrt(s->knee); - double lin_knee_start; if (s->detection) 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->release_coeff = FFMIN(1., 1. / (s->release * inlink->sample_rate / 4000.)); 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->knee_start = log(lin_knee_start); + s->knee_start = log(s->lin_knee_start); s->knee_stop = log(s->lin_knee_stop); return 0; @@ -112,26 +116,26 @@ static int agate_config_input(AVFilterLink *inlink) static double output_gain(double lin_slope, double ratio, double thres, 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 tratio = ratio; - double gain = 0.; - double delta = 0.; + double slope = log(lin_slope); + double tratio = ratio; + double gain = 0.; + double delta = 0.; - if (IS_FAKE_INFINITY(ratio)) - tratio = 1000.; - gain = (slope - thres) * tratio + thres; - delta = tratio; + if (IS_FAKE_INFINITY(ratio)) + tratio = 1000.; + gain = (slope - thres) * tratio + thres; + 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.); - } - return FFMAX(range, exp(gain - slope)); } - - return 1.; + return FFMAX(range, exp(gain - slope)); } 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) { double abs_sample = fabs(scsrc[0] * level_sc), gain = 1.0; + int detected; if (s->link == 1) { for (c = 1; c < sclink->channels; c++) @@ -161,10 +166,16 @@ static void gate(AudioGateContext *s, abs_sample *= abs_sample; 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, 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++) dst[c] = src[c] * level_in * gain * makeup;