diff options
Diffstat (limited to 'libavfilter/af_sidechaincompress.c')
-rw-r--r-- | libavfilter/af_sidechaincompress.c | 47 |
1 files changed, 39 insertions, 8 deletions
diff --git a/libavfilter/af_sidechaincompress.c b/libavfilter/af_sidechaincompress.c index 888049eaf0..219643acb6 100644 --- a/libavfilter/af_sidechaincompress.c +++ b/libavfilter/af_sidechaincompress.c @@ -54,10 +54,14 @@ typedef struct SidechainCompressContext { double knee_start; double knee_stop; double lin_knee_start; + double lin_knee_stop; double adj_knee_start; + double adj_knee_stop; + double compressed_knee_start; double compressed_knee_stop; int link; int detection; + int mode; AVAudioFifo *fifo[2]; int64_t pts; @@ -69,6 +73,9 @@ typedef struct SidechainCompressContext { static const AVOption options[] = { { "level_in", "set input gain", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A|F }, + { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, A|F, "mode" }, + { "downward",0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A|F, "mode" }, + { "upward", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A|F, "mode" }, { "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0.125}, 0.000976563, 1, A|F }, { "ratio", "set ratio", OFFSET(ratio), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 1, 20, A|F }, { "attack", "set attack", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=20}, 0.01, 2000, A|F }, @@ -97,7 +104,9 @@ AVFILTER_DEFINE_CLASS(sidechaincompress); static double output_gain(double lin_slope, double ratio, double thres, double knee, double knee_start, double knee_stop, - double compressed_knee_stop, int detection) + double compressed_knee_start, + double compressed_knee_stop, + int detection, int mode) { double slope = log(lin_slope); double gain = 0.0; @@ -114,10 +123,17 @@ static double output_gain(double lin_slope, double ratio, double thres, delta = 1.0 / ratio; } - if (knee > 1.0 && slope < knee_stop) - gain = hermite_interpolation(slope, knee_start, knee_stop, - knee_start, compressed_knee_stop, - 1.0, delta); + if (mode) { + if (knee > 1.0 && slope > knee_start) + gain = hermite_interpolation(slope, knee_stop, knee_start, + knee_stop, compressed_knee_start, + 1.0, delta); + } else { + if (knee > 1.0 && slope < knee_stop) + gain = hermite_interpolation(slope, knee_start, knee_stop, + knee_start, compressed_knee_stop, + 1.0, delta); + } return exp(gain - slope); } @@ -129,9 +145,12 @@ static int compressor_config_output(AVFilterLink *outlink) s->thres = log(s->threshold); s->lin_knee_start = s->threshold / sqrt(s->knee); + s->lin_knee_stop = s->threshold * sqrt(s->knee); s->adj_knee_start = s->lin_knee_start * s->lin_knee_start; + s->adj_knee_stop = s->lin_knee_stop * s->lin_knee_stop; s->knee_start = log(s->lin_knee_start); - s->knee_stop = log(s->threshold * sqrt(s->knee)); + s->knee_stop = log(s->lin_knee_stop); + s->compressed_knee_start = (s->knee_start - s->thres) / s->ratio + s->thres; s->compressed_knee_stop = (s->knee_stop - s->thres) / s->ratio + s->thres; s->attack_coeff = FFMIN(1., 1. / (s->attack * outlink->sample_rate / 4000.)); @@ -151,6 +170,8 @@ static void compressor(SidechainCompressContext *s, for (i = 0; i < nb_samples; i++) { double abs_sample, gain = 1.0; + double detector; + int detected; abs_sample = fabs(scsrc[0] * level_sc); @@ -169,10 +190,20 @@ static void compressor(SidechainCompressContext *s, s->lin_slope += (abs_sample - s->lin_slope) * (abs_sample > s->lin_slope ? s->attack_coeff : s->release_coeff); - if (s->lin_slope > 0.0 && s->lin_slope > (s->detection ? s->adj_knee_start : s->lin_knee_start)) + if (s->mode) { + detector = (s->detection ? s->adj_knee_stop : s->lin_knee_stop); + detected = s->lin_slope < detector; + } else { + detector = (s->detection ? s->adj_knee_start : s->lin_knee_start); + detected = s->lin_slope > detector; + } + + 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->compressed_knee_stop, s->detection); + s->compressed_knee_start, + s->compressed_knee_stop, + s->detection, s->mode); for (c = 0; c < inlink->channels; c++) dst[c] = src[c] * level_in * (gain * makeup * mix + (1. - mix)); |