Commit 8a3ed5a3 authored by Paul B Mahol's avatar Paul B Mahol

avfilter/af_agate: implement mode option

parent a0559fcd
...@@ -1308,9 +1308,16 @@ Shorter signals than the chosen attack time will be left untouched. ...@@ -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: ...@@ -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.
......
...@@ -47,11 +47,13 @@ typedef struct AudioGateContext { ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 (mode) {
if (knee > 1. && slope > knee_start) { 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, ...@@ -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, ...@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment