diff --git a/doc/filters.texi b/doc/filters.texi index 1aa6841682..4b8e8de81b 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -833,9 +833,14 @@ that the delay it produces is the attack time you set. The filter accepts the following options: @table @option +@item level_in +Set input gain. Default is 1. + +@item level_out +Set output gain. Default is 1. + @item limit -Don't let signals above this level pass the limiter. The removed amplitude is -added automatically. Default is 1. +Don't let signals above this level pass the limiter. Default is 1. @item attack The limiter will reach its attenuation level in this amount of time in @@ -853,6 +858,10 @@ time. @item asc_level Select how much the release time is affected by ASC, 0 means nearly no changes in release time while 1 produces higher release times. + +@item level +Auto level output signal. Default is enabled. +This normalizes audio back to 0dB if enabled. @end table Depending on picked setting it is recommended to upsample input 2x or 4x times diff --git a/libavfilter/af_alimiter.c b/libavfilter/af_alimiter.c index c3e3ff2942..46211a710a 100644 --- a/libavfilter/af_alimiter.c +++ b/libavfilter/af_alimiter.c @@ -41,7 +41,10 @@ typedef struct AudioLimiterContext { double attack; double release; double att; + double level_in; + double level_out; int auto_release; + int auto_level; double asc; int asc_c; int asc_pos; @@ -64,11 +67,14 @@ typedef struct AudioLimiterContext { #define F AV_OPT_FLAG_FILTERING_PARAM static const AVOption alimiter_options[] = { - { "limit", "set limit", OFFSET(limit), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0625, 1, A|F }, - { "attack", "set attack", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=5}, 0.1, 80, A|F }, - { "release", "set release", OFFSET(release), AV_OPT_TYPE_DOUBLE, {.dbl=50}, 1, 8000, A|F }, - { "asc", "enable asc", OFFSET(auto_release), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, A|F }, - { "asc_level", "set asc level", OFFSET(asc_coeff), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 1, A|F }, + { "level_in", "set input level", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1},.015625, 64, A|F }, + { "level_out", "set output level", OFFSET(level_out), AV_OPT_TYPE_DOUBLE, {.dbl=1},.015625, 64, A|F }, + { "limit", "set limit", OFFSET(limit), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0625, 1, A|F }, + { "attack", "set attack", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=5}, 0.1, 80, A|F }, + { "release", "set release", OFFSET(release), AV_OPT_TYPE_DOUBLE, {.dbl=50}, 1, 8000, A|F }, + { "asc", "enable asc", OFFSET(auto_release), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, A|F }, + { "asc_level", "set asc level", OFFSET(asc_coeff), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 1, A|F }, + { "level", "auto level", OFFSET(auto_level), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, A|F }, { NULL } }; @@ -118,6 +124,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) const double release = s->release; const double limit = s->limit; double *nextdelta = s->nextdelta; + double level = s->auto_level ? 1 / limit : 1; + const double level_out = s->level_out; + const double level_in = s->level_in; int *nextpos = s->nextpos; AVFrame *out; double *buf; @@ -139,7 +148,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) double peak = 0; for (c = 0; c < channels; c++) { - double sample = src[c]; + double sample = src[c] * level_in; buffer[s->pos + c] = sample; peak = FFMAX(peak, fabs(sample)); @@ -255,7 +264,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) s->delta = 0.; for (c = 0; c < channels; c++) - dst[c] = av_clipd(dst[c], -limit, limit); + dst[c] = av_clipd(dst[c], -limit, limit) * level * level_out; s->pos = (s->pos + channels) % buffer_size; src += channels;