Browse code

avfilter: add audio compressor filter

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2015/11/25 19:36:45
Showing 6 changed files
... ...
@@ -35,6 +35,7 @@ version <next>:
35 35
 - anoisesrc audio filter source
36 36
 - IVR demuxer
37 37
 - compensationdelay filter
38
+- acompressor filter
38 39
 
39 40
 
40 41
 version 2.8:
... ...
@@ -318,6 +318,78 @@ build.
318 318
 
319 319
 Below is a description of the currently available audio filters.
320 320
 
321
+@section acompressor
322
+
323
+A compressor is mainly used to reduce the dynamic range of a signal.
324
+Especially modern music is mostly compressed at a high ratio to
325
+improve the overall loudness. It's done to get the highest attention
326
+of a listener, "fatten" the sound and bring more "power" to the track.
327
+If a signal is compressed too much it may sound dull or "dead"
328
+afterwards or it may start to "pump" (which could be a powerful effect
329
+but can also destroy a track completely).
330
+The right compression is the key to reach a professional sound and is
331
+the high art of mixing and mastering. Because of its complex settings
332
+it may take a long time to get the right feeling for this kind of effect.
333
+
334
+Compression is done by detecting the volume above a chosen level
335
+@code{threshold} and dividing it by the factor set with @code{ratio}.
336
+So if you set the threshold to -12dB and your signal reaches -6dB a ratio
337
+of 2:1 will result in a signal at -9dB. Because an exact manipulation of
338
+the signal would cause distortion of the waveform the reduction can be
339
+levelled over the time. This is done by setting "Attack" and "Release".
340
+@code{attack} determines how long the signal has to rise above the threshold
341
+before any reduction will occur and @code{release} sets the time the signal
342
+has to fall below the threshold to reduce the reduction again. Shorter signals
343
+than the chosen attack time will be left untouched.
344
+The overall reduction of the signal can be made up afterwards with the
345
+@code{makeup} setting. So compressing the peaks of a signal about 6dB and
346
+raising the makeup to this level results in a signal twice as loud than the
347
+source. To gain a softer entry in the compression the @code{knee} flattens the
348
+hard edge at the threshold in the range of the chosen decibels.
349
+
350
+The filter accepts the following options:
351
+
352
+@table @option
353
+@item threshold
354
+If a signal of second stream rises above this level it will affect the gain
355
+reduction of the first stream.
356
+By default it is 0.125. Range is between 0.00097563 and 1.
357
+
358
+@item ratio
359
+Set a ratio by which the signal is reduced. 1:2 means that if the level
360
+rose 4dB above the threshold, it will be only 2dB above after the reduction.
361
+Default is 2. Range is between 1 and 20.
362
+
363
+@item attack
364
+Amount of milliseconds the signal has to rise above the threshold before gain
365
+reduction starts. Default is 20. Range is between 0.01 and 2000.
366
+
367
+@item release
368
+Amount of milliseconds the signal has to fall below the threshold before
369
+reduction is decreased again. Default is 250. Range is between 0.01 and 9000.
370
+
371
+@item makeup
372
+Set the amount by how much signal will be amplified after processing.
373
+Default is 2. Range is from 1 and 64.
374
+
375
+@item knee
376
+Curve the sharp knee around the threshold to enter gain reduction more softly.
377
+Default is 2.82843. Range is between 1 and 8.
378
+
379
+@item link
380
+Choose if the @code{average} level between all channels of input stream
381
+or the louder(@code{maximum}) channel of input stream affects the
382
+reduction. Default is @code{average}.
383
+
384
+@item detection
385
+Should the exact signal be taken in case of @code{peak} or an RMS one in case
386
+of @code{rms}. Default is @code{rms} which is mostly smoother.
387
+
388
+@item mix
389
+How much to use compressed signal in output. Default is 1.
390
+Range is between 0 and 1.
391
+@end table
392
+
321 393
 @section acrossfade
322 394
 
323 395
 Apply cross fade from one input audio stream to another input audio stream.
... ...
@@ -23,6 +23,7 @@ OBJS = allfilters.o                                                     \
23 23
        transform.o                                                      \
24 24
        video.o                                                          \
25 25
 
26
+OBJS-$(CONFIG_ACOMPRESSOR_FILTER)            += af_sidechaincompress.o
26 27
 OBJS-$(CONFIG_ACROSSFADE_FILTER)             += af_afade.o
27 28
 OBJS-$(CONFIG_ADELAY_FILTER)                 += af_adelay.o
28 29
 OBJS-$(CONFIG_AECHO_FILTER)                  += af_aecho.o
... ...
@@ -21,7 +21,7 @@
21 21
 
22 22
 /**
23 23
  * @file
24
- * Sidechain compressor filter
24
+ * Audio (Sidechain) Compressor filter
25 25
  */
26 26
 
27 27
 #include "libavutil/avassert.h"
... ...
@@ -61,7 +61,7 @@ typedef struct SidechainCompressContext {
61 61
 #define A AV_OPT_FLAG_AUDIO_PARAM
62 62
 #define F AV_OPT_FLAG_FILTERING_PARAM
63 63
 
64
-static const AVOption sidechaincompress_options[] = {
64
+static const AVOption options[] = {
65 65
     { "threshold", "set threshold",    OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0.125}, 0.000976563,    1, A|F },
66 66
     { "ratio",     "set ratio",        OFFSET(ratio),     AV_OPT_TYPE_DOUBLE, {.dbl=2},               1,   20, A|F },
67 67
     { "attack",    "set attack",       OFFSET(attack),    AV_OPT_TYPE_DOUBLE, {.dbl=20},           0.01, 2000, A|F },
... ...
@@ -78,6 +78,7 @@ static const AVOption sidechaincompress_options[] = {
78 78
     { NULL }
79 79
 };
80 80
 
81
+#define sidechaincompress_options options
81 82
 AVFILTER_DEFINE_CLASS(sidechaincompress);
82 83
 
83 84
 static av_cold int init(AVFilterContext *ctx)
... ...
@@ -126,33 +127,24 @@ static double output_gain(double lin_slope, double ratio, double thres,
126 126
     return exp(gain - slope);
127 127
 }
128 128
 
129
-static int filter_frame(AVFilterLink *link, AVFrame *frame)
129
+static int compressor_config_output(AVFilterLink *outlink)
130 130
 {
131
-    AVFilterContext *ctx = link->dst;
131
+    AVFilterContext *ctx = outlink->src;
132 132
     SidechainCompressContext *s = ctx->priv;
133
-    AVFilterLink *sclink = ctx->inputs[1];
134
-    AVFilterLink *outlink = ctx->outputs[0];
135
-    const double makeup = s->makeup;
136
-    const double mix = s->mix;
137
-    const double *scsrc;
138
-    double *sample;
139
-    int nb_samples;
140
-    int ret, i, c;
141 133
 
142
-    for (i = 0; i < 2; i++)
143
-        if (link == ctx->inputs[i])
144
-            break;
145
-    av_assert0(i < 2 && !s->input_frame[i]);
146
-    s->input_frame[i] = frame;
147
-
148
-    if (!s->input_frame[0] || !s->input_frame[1])
149
-        return 0;
134
+    s->attack_coeff = FFMIN(1., 1. / (s->attack * outlink->sample_rate / 4000.));
135
+    s->release_coeff = FFMIN(1., 1. / (s->release * outlink->sample_rate / 4000.));
150 136
 
151
-    nb_samples = FFMIN(s->input_frame[0]->nb_samples,
152
-                       s->input_frame[1]->nb_samples);
137
+    return 0;
138
+}
153 139
 
154
-    sample = (double *)s->input_frame[0]->data[0];
155
-    scsrc = (const double *)s->input_frame[1]->data[0];
140
+static void compressor(SidechainCompressContext *s,
141
+                       double *sample, const double *scsrc, int nb_samples,
142
+                       AVFilterLink *inlink, AVFilterLink *sclink)
143
+{
144
+    const double makeup = s->makeup;
145
+    const double mix = s->mix;
146
+    int i, c;
156 147
 
157 148
     for (i = 0; i < nb_samples; i++) {
158 149
         double abs_sample, gain = 1.0;
... ...
@@ -179,13 +171,42 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame)
179 179
                                s->knee_start, s->knee_stop,
180 180
                                s->compressed_knee_stop, s->detection);
181 181
 
182
-        for (c = 0; c < outlink->channels; c++)
182
+        for (c = 0; c < inlink->channels; c++)
183 183
             sample[c] *= (gain * makeup * mix + (1. - mix));
184 184
 
185
-        sample += outlink->channels;
185
+        sample += inlink->channels;
186 186
         scsrc += sclink->channels;
187 187
     }
188
+}
189
+
190
+#if CONFIG_SIDECHAINCOMPRESS_FILTER
191
+static int filter_frame(AVFilterLink *link, AVFrame *frame)
192
+{
193
+    AVFilterContext *ctx = link->dst;
194
+    SidechainCompressContext *s = ctx->priv;
195
+    AVFilterLink *outlink = ctx->outputs[0];
196
+    const double *scsrc;
197
+    double *sample;
198
+    int nb_samples;
199
+    int ret, i;
200
+
201
+    for (i = 0; i < 2; i++)
202
+        if (link == ctx->inputs[i])
203
+            break;
204
+    av_assert0(i < 2 && !s->input_frame[i]);
205
+    s->input_frame[i] = frame;
206
+
207
+    if (!s->input_frame[0] || !s->input_frame[1])
208
+        return 0;
209
+
210
+    nb_samples = FFMIN(s->input_frame[0]->nb_samples,
211
+                       s->input_frame[1]->nb_samples);
212
+
213
+    sample = (double *)s->input_frame[0]->data[0];
214
+    scsrc = (const double *)s->input_frame[1]->data[0];
188 215
 
216
+    compressor(s, sample, scsrc, nb_samples,
217
+               ctx->inputs[0], ctx->inputs[1]);
189 218
     ret = ff_filter_frame(outlink, s->input_frame[0]);
190 219
 
191 220
     s->input_frame[0] = NULL;
... ...
@@ -253,7 +274,6 @@ static int query_formats(AVFilterContext *ctx)
253 253
 static int config_output(AVFilterLink *outlink)
254 254
 {
255 255
     AVFilterContext *ctx = outlink->src;
256
-    SidechainCompressContext *s = ctx->priv;
257 256
 
258 257
     if (ctx->inputs[0]->sample_rate != ctx->inputs[1]->sample_rate) {
259 258
         av_log(ctx, AV_LOG_ERROR,
... ...
@@ -268,8 +288,7 @@ static int config_output(AVFilterLink *outlink)
268 268
     outlink->channel_layout = ctx->inputs[0]->channel_layout;
269 269
     outlink->channels = ctx->inputs[0]->channels;
270 270
 
271
-    s->attack_coeff = FFMIN(1., 1. / (s->attack * outlink->sample_rate / 4000.));
272
-    s->release_coeff = FFMIN(1., 1. / (s->release * outlink->sample_rate / 4000.));
271
+    compressor_config_output(outlink);
273 272
 
274 273
     return 0;
275 274
 }
... ...
@@ -310,3 +329,83 @@ AVFilter ff_af_sidechaincompress = {
310 310
     .inputs         = sidechaincompress_inputs,
311 311
     .outputs        = sidechaincompress_outputs,
312 312
 };
313
+#endif  /* CONFIG_SIDECHAINCOMPRESS_FILTER */
314
+
315
+#if CONFIG_ACOMPRESSOR_FILTER
316
+static int acompressor_filter_frame(AVFilterLink *inlink, AVFrame *frame)
317
+{
318
+    AVFilterContext *ctx = inlink->dst;
319
+    SidechainCompressContext *s = ctx->priv;
320
+    AVFilterLink *outlink = ctx->outputs[0];
321
+    double *sample;
322
+
323
+    sample = (double *)frame->data[0];
324
+    compressor(s, sample, sample, frame->nb_samples,
325
+               inlink, inlink);
326
+
327
+    return ff_filter_frame(outlink, frame);
328
+}
329
+
330
+static int acompressor_query_formats(AVFilterContext *ctx)
331
+{
332
+    AVFilterFormats *formats;
333
+    AVFilterChannelLayouts *layouts;
334
+    static const enum AVSampleFormat sample_fmts[] = {
335
+        AV_SAMPLE_FMT_DBL,
336
+        AV_SAMPLE_FMT_NONE
337
+    };
338
+    int ret;
339
+
340
+    layouts = ff_all_channel_counts();
341
+    if (!layouts)
342
+        return AVERROR(ENOMEM);
343
+    ret = ff_set_common_channel_layouts(ctx, layouts);
344
+    if (ret < 0)
345
+        return ret;
346
+
347
+    formats = ff_make_format_list(sample_fmts);
348
+    if (!formats)
349
+        return AVERROR(ENOMEM);
350
+    ret = ff_set_common_formats(ctx, formats);
351
+    if (ret < 0)
352
+        return ret;
353
+
354
+    formats = ff_all_samplerates();
355
+    if (!formats)
356
+        return AVERROR(ENOMEM);
357
+    return ff_set_common_samplerates(ctx, formats);
358
+}
359
+
360
+#define acompressor_options options
361
+AVFILTER_DEFINE_CLASS(acompressor);
362
+
363
+static const AVFilterPad acompressor_inputs[] = {
364
+    {
365
+        .name           = "default",
366
+        .type           = AVMEDIA_TYPE_AUDIO,
367
+        .filter_frame   = acompressor_filter_frame,
368
+        .needs_writable = 1,
369
+    },
370
+    { NULL }
371
+};
372
+
373
+static const AVFilterPad acompressor_outputs[] = {
374
+    {
375
+        .name          = "default",
376
+        .type          = AVMEDIA_TYPE_AUDIO,
377
+        .config_props  = compressor_config_output,
378
+    },
379
+    { NULL }
380
+};
381
+
382
+AVFilter ff_af_acompressor = {
383
+    .name           = "acompressor",
384
+    .description    = NULL_IF_CONFIG_SMALL("Audio compressor."),
385
+    .priv_size      = sizeof(SidechainCompressContext),
386
+    .priv_class     = &acompressor_class,
387
+    .init           = init,
388
+    .query_formats  = acompressor_query_formats,
389
+    .inputs         = acompressor_inputs,
390
+    .outputs        = acompressor_outputs,
391
+};
392
+#endif  /* CONFIG_ACOMPRESSOR_FILTER */
... ...
@@ -45,6 +45,7 @@ void avfilter_register_all(void)
45 45
         return;
46 46
     initialized = 1;
47 47
 
48
+    REGISTER_FILTER(ACOMPRESSOR,    acompressor,    af);
48 49
     REGISTER_FILTER(ACROSSFADE,     acrossfade,     af);
49 50
     REGISTER_FILTER(ADELAY,         adelay,         af);
50 51
     REGISTER_FILTER(AECHO,          aecho,          af);
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFILTER_VERSION_MAJOR   6
33
-#define LIBAVFILTER_VERSION_MINOR  16
33
+#define LIBAVFILTER_VERSION_MINOR  17
34 34
 #define LIBAVFILTER_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \