History

avfilter/af_dynaudnorm: add curve option

Paul B Mahol committed 4 years ago

Commit 8e963191 parent a0c7c9d2 files · +88 −5Browse files

Unified · Split

2 files
  1. doc/filters.texi +27 −0
  2. libavfilter/af_dynaudnorm.c +61 −5
doc/filters.texi+27−0
@@ -4587,6 +4587,33 @@ Using >0 and <1 values will make less conservative gain adjustments, like · 4586 unmodified lines
45874587 when framelen option is set to smaller value, if framelen option value is
45884588 compensated for non-zero overlap then gain adjustments will be smoother across time
45894589 compared to zero overlap case.
4590+
4591+@item curve, v
4592+Specify the peak mapping curve expression which is going to be used when calculating
4593+gain applied to frames. The max output frame gain will still be limited by other
4594+options mentioned previously for this filter.
4595+
4596+The expression can contain the following constants:
4597+
4598+@table @option
4599+@item ch
4600+current channel number
4601+
4602+@item sn
4603+current sample number
4604+
4605+@item nb_channels
4606+number of channels
4607+
4608+@item t
4609+timestamp expressed in seconds
4610+
4611+@item sr
4612+sample rate
4613+
4614+@item p
4615+current frame peak value
4616+@end table
45904617 @end table
45914618
45924619 @subsection Commands
libavfilter/af_dynaudnorm.c+61−5
@@ -28,6 +28,7 @@ · 27 unmodified lines
2828
2929 #include "libavutil/avassert.h"
3030 #include "libavutil/channel_layout.h"
31+#include "libavutil/eval.h"
3132 #include "libavutil/opt.h"
3233
3334 #define MIN_FILTER_SIZE 3
@@ -41,6 +42,26 @@ · 7 unmodified lines
4142 #include "filters.h"
4243 #include "internal.h"
4344
45+static const char * const var_names[] = {
46+ "ch", ///< the value of the current channel
47+ "sn", ///< number of samples
48+ "nb_channels",
49+ "t", ///< timestamp expressed in seconds
50+ "sr", ///< sample rate
51+ "p", ///< peak value
52+ NULL
53+};
54+
55+enum var_name {
56+ VAR_CH,
57+ VAR_SN,
58+ VAR_NB_CHANNELS,
59+ VAR_T,
60+ VAR_SR,
61+ VAR_P,
62+ VAR_VARS_NB
63+};
64+
4465 typedef struct local_gain {
4566 double max_gain;
4667 double threshold;
@@ -65,6 +86,7 @@ typedef struct DynamicAudioNormalizerContext { · 18 unmodified lines
6586 int channels_coupled;
6687 int alt_boundary_mode;
6788 double overlap;
89+ char *expr_str;
6890
6991 double peak_value;
7092 double max_amplification;
@@ -91,6 +113,9 @@ typedef struct DynamicAudioNormalizerContext { · 20 unmodified lines
91113 cqueue *is_enabled;
92114
93115 AVFrame *window;
116+
117+ AVExpr *expr;
118+ double var_values[VAR_VARS_NB];
94119 } DynamicAudioNormalizerContext;
95120
96121 typedef struct ThreadData {
@@ -122,10 +147,12 @@ static const AVOption dynaudnorm_options[] = { · 25 unmodified lines
122147 { "s", "set the compress factor", OFFSET(compress_factor), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 30.0, FLAGS },
123148 { "threshold", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },
124149 { "t", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },
125− { "channels", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },
126− { "h", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },
150+ { "channels", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },
151+ { "h", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },
127152 { "overlap", "set the frame overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=.0}, 0.0, 1.0, FLAGS },
128153 { "o", "set the frame overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=.0}, 0.0, 1.0, FLAGS },
154+ { "curve", "set the custom peak mapping curve",OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
155+ { "v", "set the custom peak mapping curve",OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
129156 { NULL }
130157 };
131158
@@ -309,12 +336,15 @@ static av_cold void uninit(AVFilterContext *ctx) · 177 unmodified lines
309336 ff_bufqueue_discard_all(&s->queue);
310337
311338 av_frame_free(&s->window);
339+ av_expr_free(s->expr);
340+ s->expr = NULL;
312341 }
313342
314343 static int config_input(AVFilterLink *inlink)
315344 {
316345 AVFilterContext *ctx = inlink->dst;
317346 DynamicAudioNormalizerContext *s = ctx->priv;
347+ int ret = 0;
318348
319349 uninit(ctx);
320350
@@ -358,7 +388,13 @@ static int config_input(AVFilterLink *inlink) · 37 unmodified lines
358388 return AVERROR(ENOMEM);
359389 s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));
360390
361− return 0;
391+ s->var_values[VAR_SR] = inlink->sample_rate;
392+ s->var_values[VAR_NB_CHANNELS] = s->channels;
393+
394+ if (s->expr_str)
395+ ret = av_expr_parse(&s->expr, s->expr_str, var_names, NULL, NULL,
396+ NULL, NULL, 0, ctx);
397+ return ret;
362398 }
363399
364400 static inline double fade(double prev, double next, int pos, int length)
@@ -433,10 +469,22 @@ static local_gain get_max_local_gain(DynamicAudioNormalizerContext *s, AVFrame * · 68 unmodified lines
433469 const double peak_magnitude = find_peak_magnitude(frame, channel);
434470 const double maximum_gain = s->peak_value / peak_magnitude;
435471 const double rms_gain = s->target_rms > DBL_EPSILON ? (s->target_rms / compute_frame_rms(frame, channel)) : DBL_MAX;
472+ double target_gain = DBL_MAX;
436473 local_gain gain;
437474
475+ if (s->expr_str) {
476+ double var_values[VAR_VARS_NB];
477+
478+ memcpy(var_values, s->var_values, sizeof(var_values));
479+
480+ var_values[VAR_CH] = channel;
481+ var_values[VAR_P] = peak_magnitude;
482+
483+ target_gain = av_expr_eval(s->expr, var_values, s) / peak_magnitude;
484+ }
485+
438486 gain.threshold = peak_magnitude > s->threshold;
439− gain.max_gain = bound(s->max_amplification, fmin(maximum_gain, rms_gain));
487+ gain.max_gain = bound(s->max_amplification, fmin(target_gain, fmin(maximum_gain, rms_gain)));
440488
441489 return gain;
442490 }
@@ -731,6 +779,9 @@ static int analyze_frame(AVFilterContext *ctx, AVFilterLink *outlink, AVFrame ** · 288 unmodified lines
731779 analyze_frame = *frame;
732780 }
733781
782+ s->var_values[VAR_SN] = outlink->sample_count_in;
783+ s->var_values[VAR_T] = s->var_values[VAR_SN] * (double)1/outlink->sample_rate;
784+
734785 if (s->channels_coupled) {
735786 const local_gain gain = get_max_local_gain(s, analyze_frame, -1);
736787 for (int c = 0; c < s->channels; c++)
@@ -951,7 +1002,12 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar · 214 unmodified lines
9511002
9521003 s->frame_len = frame_size(inlink->sample_rate, s->frame_len_msec);
9531004 s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));
954−
1005+ if (s->expr_str) {
1006+ ret = av_expr_parse(&s->expr, s->expr_str, var_names, NULL, NULL,
1007+ NULL, NULL, 0, ctx);
1008+ if (ret < 0)
1009+ return ret;
1010+ }
9551011 return 0;
9561012 }
9571013

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t