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
4587when framelen option is set to smaller value, if framelen option value is4587when framelen option is set to smaller value, if framelen option value is
4588compensated for non-zero overlap then gain adjustments will be smoother across time4588compensated for non-zero overlap then gain adjustments will be smoother across time
4589compared to zero overlap case.4589compared to zero overlap case.
4590
4591@item curve, v
4592Specify the peak mapping curve expression which is going to be used when calculating
4593gain applied to frames. The max output frame gain will still be limited by other
4594options mentioned previously for this filter.
4595
4596The expression can contain the following constants:
4597
4598@table @option
4599@item ch
4600current channel number
4601
4602@item sn
4603current sample number
4604
4605@item nb_channels
4606number of channels
4607
4608@item t
4609timestamp expressed in seconds
4610
4611@item sr
4612sample rate
4613
4614@item p
4615current frame peak value
4616@end table
4590@end table4617@end table
4591 4618
4592@subsection Commands4619@subsection Commands
libavfilter/af_dynaudnorm.c+61−5
@@ -28,6 +28,7 @@ · 27 unmodified lines
28 28
29#include "libavutil/avassert.h"29#include "libavutil/avassert.h"
30#include "libavutil/channel_layout.h"30#include "libavutil/channel_layout.h"
31#include "libavutil/eval.h"
31#include "libavutil/opt.h"32#include "libavutil/opt.h"
32 33
33#define MIN_FILTER_SIZE 334#define MIN_FILTER_SIZE 3
@@ -41,6 +42,26 @@ · 7 unmodified lines
41#include "filters.h"42#include "filters.h"
42#include "internal.h"43#include "internal.h"
43 44
45static 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
55enum 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
44typedef struct local_gain {65typedef struct local_gain {
45 double max_gain;66 double max_gain;
46 double threshold;67 double threshold;
@@ -65,6 +86,7 @@ typedef struct DynamicAudioNormalizerContext { · 18 unmodified lines
65 int channels_coupled;86 int channels_coupled;
66 int alt_boundary_mode;87 int alt_boundary_mode;
67 double overlap;88 double overlap;
89 char *expr_str;
68 90
69 double peak_value;91 double peak_value;
70 double max_amplification;92 double max_amplification;
@@ -91,6 +113,9 @@ typedef struct DynamicAudioNormalizerContext { · 20 unmodified lines
91 cqueue *is_enabled;113 cqueue *is_enabled;
92 114
93 AVFrame *window;115 AVFrame *window;
116
117 AVExpr *expr;
118 double var_values[VAR_VARS_NB];
94} DynamicAudioNormalizerContext;119} DynamicAudioNormalizerContext;
95 120
96typedef struct ThreadData {121typedef struct ThreadData {
@@ -122,10 +147,12 @@ static const AVOption dynaudnorm_options[] = { · 25 unmodified lines
122 { "s", "set the compress factor", OFFSET(compress_factor), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 30.0, FLAGS },147 { "s", "set the compress factor", OFFSET(compress_factor), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 30.0, FLAGS },
123 { "threshold", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },148 { "threshold", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },
124 { "t", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },149 { "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 },150 { "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 },151 { "h", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },
127 { "overlap", "set the frame overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=.0}, 0.0, 1.0, FLAGS },152 { "overlap", "set the frame overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=.0}, 0.0, 1.0, FLAGS },
128 { "o", "set the frame overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=.0}, 0.0, 1.0, FLAGS },153 { "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 },
129 { NULL }156 { NULL }
130};157};
131 158
@@ -309,12 +336,15 @@ static av_cold void uninit(AVFilterContext *ctx) · 177 unmodified lines
309 ff_bufqueue_discard_all(&s->queue);336 ff_bufqueue_discard_all(&s->queue);
310 337
311 av_frame_free(&s->window);338 av_frame_free(&s->window);
339 av_expr_free(s->expr);
340 s->expr = NULL;
312}341}
313 342
314static int config_input(AVFilterLink *inlink)343static int config_input(AVFilterLink *inlink)
315{344{
316 AVFilterContext *ctx = inlink->dst;345 AVFilterContext *ctx = inlink->dst;
317 DynamicAudioNormalizerContext *s = ctx->priv;346 DynamicAudioNormalizerContext *s = ctx->priv;
347 int ret = 0;
318 348
319 uninit(ctx);349 uninit(ctx);
320 350
@@ -358,7 +388,13 @@ static int config_input(AVFilterLink *inlink) · 37 unmodified lines
358 return AVERROR(ENOMEM);388 return AVERROR(ENOMEM);
359 s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));389 s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));
360 390
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;
362}398}
363 399
364static inline double fade(double prev, double next, int pos, int length)400static 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
433 const double peak_magnitude = find_peak_magnitude(frame, channel);469 const double peak_magnitude = find_peak_magnitude(frame, channel);
434 const double maximum_gain = s->peak_value / peak_magnitude;470 const double maximum_gain = s->peak_value / peak_magnitude;
435 const double rms_gain = s->target_rms > DBL_EPSILON ? (s->target_rms / compute_frame_rms(frame, channel)) : DBL_MAX;471 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;
436 local_gain gain;473 local_gain gain;
437 474
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
438 gain.threshold = peak_magnitude > s->threshold;486 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)));
440 488
441 return gain;489 return gain;
442}490}
@@ -731,6 +779,9 @@ static int analyze_frame(AVFilterContext *ctx, AVFilterLink *outlink, AVFrame ** · 288 unmodified lines
731 analyze_frame = *frame;779 analyze_frame = *frame;
732 }780 }
733 781
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
734 if (s->channels_coupled) {785 if (s->channels_coupled) {
735 const local_gain gain = get_max_local_gain(s, analyze_frame, -1);786 const local_gain gain = get_max_local_gain(s, analyze_frame, -1);
736 for (int c = 0; c < s->channels; c++)787 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
951 1002
952 s->frame_len = frame_size(inlink->sample_rate, s->frame_len_msec);1003 s->frame_len = frame_size(inlink->sample_rate, s->frame_len_msec);
953 s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));1004 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 }
955 return 0;1011 return 0;
956}1012}
957 1013

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