2 * Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen, Damien Zammit
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * Audio (Sidechain) Gate filter
26 #include "config_components.h"
28 #include "libavutil/audio_fifo.h"
29 #include "libavutil/channel_layout.h"
30 #include "libavutil/opt.h"
37 typedef struct AudioGateContext
{
56 double lin_knee_start
;
66 #define OFFSET(x) offsetof(AudioGateContext, x)
67 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
69 static const AVOption options
[] = {
70 { "level_in", "set input level", OFFSET(level_in
), AV_OPT_TYPE_DOUBLE
, {.dbl
=1}, 0.015625, 64, A
},
71 { "mode", "set mode", OFFSET(mode
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, A
, .unit
= "mode" },
72 { "downward",0, 0, AV_OPT_TYPE_CONST
, {.i64
=0}, 0, 0, A
, .unit
= "mode" },
73 { "upward", 0, 0, AV_OPT_TYPE_CONST
, {.i64
=1}, 0, 0, A
, .unit
= "mode" },
74 { "range", "set max gain reduction", OFFSET(range
), AV_OPT_TYPE_DOUBLE
, {.dbl
=0.06125}, 0, 1, A
},
75 { "threshold", "set threshold", OFFSET(threshold
), AV_OPT_TYPE_DOUBLE
, {.dbl
=0.125}, 0, 1, A
},
76 { "ratio", "set ratio", OFFSET(ratio
), AV_OPT_TYPE_DOUBLE
, {.dbl
=2}, 1, 9000, A
},
77 { "attack", "set attack", OFFSET(attack
), AV_OPT_TYPE_DOUBLE
, {.dbl
=20}, 0.01, 9000, A
},
78 { "release", "set release", OFFSET(release
), AV_OPT_TYPE_DOUBLE
, {.dbl
=250}, 0.01, 9000, A
},
79 { "makeup", "set makeup gain", OFFSET(makeup
), AV_OPT_TYPE_DOUBLE
, {.dbl
=1}, 1, 64, A
},
80 { "knee", "set knee", OFFSET(knee
), AV_OPT_TYPE_DOUBLE
, {.dbl
=2.828427125}, 1, 8, A
},
81 { "detection", "set detection", OFFSET(detection
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1, A
, .unit
= "detection" },
82 { "peak", 0, 0, AV_OPT_TYPE_CONST
, {.i64
=0}, 0, 0, A
, .unit
= "detection" },
83 { "rms", 0, 0, AV_OPT_TYPE_CONST
, {.i64
=1}, 0, 0, A
, .unit
= "detection" },
84 { "link", "set link", OFFSET(link
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, A
, .unit
= "link" },
85 { "average", 0, 0, AV_OPT_TYPE_CONST
, {.i64
=0}, 0, 0, A
, .unit
= "link" },
86 { "maximum", 0, 0, AV_OPT_TYPE_CONST
, {.i64
=1}, 0, 0, A
, .unit
= "link" },
87 { "level_sc", "set sidechain gain", OFFSET(level_sc
), AV_OPT_TYPE_DOUBLE
, {.dbl
=1}, 0.015625, 64, A
},
91 AVFILTER_DEFINE_CLASS_EXT(agate_sidechaingate
, "agate/sidechaingate", options
);
93 static int agate_config_input(AVFilterLink
*inlink
)
95 AVFilterContext
*ctx
= inlink
->dst
;
96 AudioGateContext
*s
= ctx
->priv
;
97 double lin_threshold
= s
->threshold
;
98 double lin_knee_sqrt
= sqrt(s
->knee
);
101 lin_threshold
*= lin_threshold
;
103 s
->attack_coeff
= FFMIN(1., 1. / (s
->attack
* inlink
->sample_rate
/ 4000.));
104 s
->release_coeff
= FFMIN(1., 1. / (s
->release
* inlink
->sample_rate
/ 4000.));
105 s
->lin_knee_stop
= lin_threshold
* lin_knee_sqrt
;
106 s
->lin_knee_start
= lin_threshold
/ lin_knee_sqrt
;
107 s
->thres
= log(lin_threshold
);
108 s
->knee_start
= log(s
->lin_knee_start
);
109 s
->knee_stop
= log(s
->lin_knee_stop
);
114 // A fake infinity value (because real infinity may break some hosts)
115 #define FAKE_INFINITY (65536.0 * 65536.0)
117 // Check for infinity (with appropriate-ish tolerance)
118 #define IS_FAKE_INFINITY(value) (fabs(value-FAKE_INFINITY) < 1.0)
120 static double output_gain(double lin_slope
, double ratio
, double thres
,
121 double knee
, double knee_start
, double knee_stop
,
122 double range
, int mode
)
124 double slope
= log(lin_slope
);
125 double tratio
= ratio
;
129 if (IS_FAKE_INFINITY(ratio
))
131 gain
= (slope
- thres
) * tratio
+ thres
;
135 if (knee
> 1. && slope
< knee_stop
)
136 gain
= hermite_interpolation(slope
, knee_stop
, knee_start
, ((knee_stop
- thres
) * tratio
+ thres
), knee_start
, delta
, 1.);
138 if (knee
> 1. && slope
> knee_start
)
139 gain
= hermite_interpolation(slope
, knee_start
, knee_stop
, ((knee_start
- thres
) * tratio
+ thres
), knee_stop
, delta
, 1.);
141 return FFMAX(range
, exp(gain
- slope
));
144 static void gate(AudioGateContext
*s
,
145 const double *src
, double *dst
, const double *scsrc
,
146 int nb_samples
, double level_in
, double level_sc
,
147 AVFilterLink
*inlink
, AVFilterLink
*sclink
)
149 AVFilterContext
*ctx
= inlink
->dst
;
150 const double makeup
= s
->makeup
;
151 const double attack_coeff
= s
->attack_coeff
;
152 const double release_coeff
= s
->release_coeff
;
155 for (n
= 0; n
< nb_samples
; n
++, src
+= inlink
->ch_layout
.nb_channels
, dst
+= inlink
->ch_layout
.nb_channels
, scsrc
+= sclink
->ch_layout
.nb_channels
) {
156 double abs_sample
= fabs(scsrc
[0] * level_sc
), gain
= 1.0;
161 for (c
= 1; c
< sclink
->ch_layout
.nb_channels
; c
++)
162 abs_sample
= FFMAX(fabs(scsrc
[c
] * level_sc
), abs_sample
);
164 for (c
= 1; c
< sclink
->ch_layout
.nb_channels
; c
++)
165 abs_sample
+= fabs(scsrc
[c
] * level_sc
);
167 abs_sample
/= sclink
->ch_layout
.nb_channels
;
171 abs_sample
*= abs_sample
;
173 s
->lin_slope
+= (abs_sample
- s
->lin_slope
) * (abs_sample
> s
->lin_slope
? attack_coeff
: release_coeff
);
176 detected
= s
->lin_slope
> s
->lin_knee_start
;
178 detected
= s
->lin_slope
< s
->lin_knee_stop
;
180 if (s
->lin_slope
> 0.0 && detected
)
181 gain
= output_gain(s
->lin_slope
, s
->ratio
, s
->thres
,
182 s
->knee
, s
->knee_start
, s
->knee_stop
,
185 factor
= ctx
->is_disabled
? 1.f
: level_in
* gain
* makeup
;
186 for (c
= 0; c
< inlink
->ch_layout
.nb_channels
; c
++)
187 dst
[c
] = src
[c
] * factor
;
191 #if CONFIG_AGATE_FILTER
193 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*in
)
195 const double *src
= (const double *)in
->data
[0];
196 AVFilterContext
*ctx
= inlink
->dst
;
197 AVFilterLink
*outlink
= ctx
->outputs
[0];
198 AudioGateContext
*s
= ctx
->priv
;
202 if (av_frame_is_writable(in
)) {
205 out
= ff_get_audio_buffer(outlink
, in
->nb_samples
);
208 return AVERROR(ENOMEM
);
210 av_frame_copy_props(out
, in
);
212 dst
= (double *)out
->data
[0];
214 gate(s
, src
, dst
, src
, in
->nb_samples
,
215 s
->level_in
, s
->level_in
, inlink
, inlink
);
219 return ff_filter_frame(outlink
, out
);
222 static const AVFilterPad inputs
[] = {
225 .type
= AVMEDIA_TYPE_AUDIO
,
226 .filter_frame
= filter_frame
,
227 .config_props
= agate_config_input
,
231 const FFFilter ff_af_agate
= {
233 .p
.description
= NULL_IF_CONFIG_SMALL("Audio gate."),
234 .p
.priv_class
= &agate_sidechaingate_class
,
235 .p
.flags
= AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
,
236 .priv_size
= sizeof(AudioGateContext
),
237 FILTER_INPUTS(inputs
),
238 FILTER_OUTPUTS(ff_audio_default_filterpad
),
239 FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL
),
240 .process_command
= ff_filter_process_command
,
243 #endif /* CONFIG_AGATE_FILTER */
245 #if CONFIG_SIDECHAINGATE_FILTER
247 static int activate(AVFilterContext
*ctx
)
249 AudioGateContext
*s
= ctx
->priv
;
250 AVFrame
*out
= NULL
, *in
[2] = { NULL
};
251 int ret
, i
, nb_samples
;
254 FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx
->outputs
[0], ctx
);
255 if ((ret
= ff_inlink_consume_frame(ctx
->inputs
[0], &in
[0])) > 0) {
256 av_audio_fifo_write(s
->fifo
[0], (void **)in
[0]->extended_data
,
258 av_frame_free(&in
[0]);
262 if ((ret
= ff_inlink_consume_frame(ctx
->inputs
[1], &in
[1])) > 0) {
263 av_audio_fifo_write(s
->fifo
[1], (void **)in
[1]->extended_data
,
265 av_frame_free(&in
[1]);
270 nb_samples
= FFMIN(av_audio_fifo_size(s
->fifo
[0]), av_audio_fifo_size(s
->fifo
[1]));
272 out
= ff_get_audio_buffer(ctx
->outputs
[0], nb_samples
);
274 return AVERROR(ENOMEM
);
275 for (i
= 0; i
< 2; i
++) {
276 in
[i
] = ff_get_audio_buffer(ctx
->inputs
[i
], nb_samples
);
278 av_frame_free(&in
[0]);
279 av_frame_free(&in
[1]);
281 return AVERROR(ENOMEM
);
283 av_audio_fifo_read(s
->fifo
[i
], (void **)in
[i
]->data
, nb_samples
);
286 dst
= (double *)out
->data
[0];
288 s
->pts
+= av_rescale_q(nb_samples
, (AVRational
){1, ctx
->outputs
[0]->sample_rate
}, ctx
->outputs
[0]->time_base
);
290 gate(s
, (double *)in
[0]->data
[0], dst
,
291 (double *)in
[1]->data
[0], nb_samples
,
292 s
->level_in
, s
->level_sc
,
293 ctx
->inputs
[0], ctx
->inputs
[1]);
295 av_frame_free(&in
[0]);
296 av_frame_free(&in
[1]);
298 ret
= ff_filter_frame(ctx
->outputs
[0], out
);
302 FF_FILTER_FORWARD_STATUS(ctx
->inputs
[0], ctx
->outputs
[0]);
303 FF_FILTER_FORWARD_STATUS(ctx
->inputs
[1], ctx
->outputs
[0]);
304 if (ff_outlink_frame_wanted(ctx
->outputs
[0])) {
305 if (!av_audio_fifo_size(s
->fifo
[0]))
306 ff_inlink_request_frame(ctx
->inputs
[0]);
307 if (!av_audio_fifo_size(s
->fifo
[1]))
308 ff_inlink_request_frame(ctx
->inputs
[1]);
313 static int scquery_formats(const AVFilterContext
*ctx
,
314 AVFilterFormatsConfig
**cfg_in
,
315 AVFilterFormatsConfig
**cfg_out
)
317 static const enum AVSampleFormat sample_fmts
[] = {
323 /* Generic code will link the channel properties of the main input and the
324 * output; it won't touch the second input as its channel_layouts is already
326 ret
= ff_channel_layouts_ref(ff_all_channel_counts(),
327 &cfg_in
[1]->channel_layouts
);
331 if ((ret
= ff_set_common_formats_from_list2(ctx
, cfg_in
, cfg_out
, sample_fmts
)) < 0)
337 static int scconfig_output(AVFilterLink
*outlink
)
339 AVFilterContext
*ctx
= outlink
->src
;
340 AudioGateContext
*s
= ctx
->priv
;
342 outlink
->time_base
= ctx
->inputs
[0]->time_base
;
344 s
->fifo
[0] = av_audio_fifo_alloc(ctx
->inputs
[0]->format
, ctx
->inputs
[0]->ch_layout
.nb_channels
, 1024);
345 s
->fifo
[1] = av_audio_fifo_alloc(ctx
->inputs
[1]->format
, ctx
->inputs
[1]->ch_layout
.nb_channels
, 1024);
346 if (!s
->fifo
[0] || !s
->fifo
[1])
347 return AVERROR(ENOMEM
);
350 agate_config_input(ctx
->inputs
[0]);
355 static av_cold
void uninit(AVFilterContext
*ctx
)
357 AudioGateContext
*s
= ctx
->priv
;
359 av_audio_fifo_free(s
->fifo
[0]);
360 av_audio_fifo_free(s
->fifo
[1]);
363 static const AVFilterPad sidechaingate_inputs
[] = {
366 .type
= AVMEDIA_TYPE_AUDIO
,
369 .type
= AVMEDIA_TYPE_AUDIO
,
373 static const AVFilterPad sidechaingate_outputs
[] = {
376 .type
= AVMEDIA_TYPE_AUDIO
,
377 .config_props
= scconfig_output
,
381 const FFFilter ff_af_sidechaingate
= {
382 .p
.name
= "sidechaingate",
383 .p
.description
= NULL_IF_CONFIG_SMALL("Audio sidechain gate."),
384 .p
.priv_class
= &agate_sidechaingate_class
,
385 .p
.flags
= AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
,
386 .priv_size
= sizeof(AudioGateContext
),
387 .activate
= activate
,
389 FILTER_INPUTS(sidechaingate_inputs
),
390 FILTER_OUTPUTS(sidechaingate_outputs
),
391 FILTER_QUERY_FUNC2(scquery_formats
),
392 .process_command
= ff_filter_process_command
,
394 #endif /* CONFIG_SIDECHAINGATE_FILTER */