blob: 328e25ba84ebbcae2cf17df23db7d5256b53f26a
1 | /* |
2 | * Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen, Damien Zammit |
3 | * |
4 | * This file is part of FFmpeg. |
5 | * |
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. |
10 | * |
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. |
15 | * |
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 |
19 | */ |
20 | |
21 | /** |
22 | * @file |
23 | * Audio (Sidechain) Gate filter |
24 | */ |
25 | |
26 | #include "libavutil/audio_fifo.h" |
27 | #include "libavutil/avassert.h" |
28 | #include "libavutil/channel_layout.h" |
29 | #include "libavutil/opt.h" |
30 | #include "avfilter.h" |
31 | #include "audio.h" |
32 | #include "formats.h" |
33 | #include "hermite.h" |
34 | |
35 | typedef struct AudioGateContext { |
36 | const AVClass *class; |
37 | |
38 | double level_in; |
39 | double level_sc; |
40 | double attack; |
41 | double release; |
42 | double threshold; |
43 | double ratio; |
44 | double knee; |
45 | double makeup; |
46 | double range; |
47 | int link; |
48 | int detection; |
49 | |
50 | double thres; |
51 | double knee_start; |
52 | double lin_knee_stop; |
53 | double knee_stop; |
54 | double lin_slope; |
55 | double attack_coeff; |
56 | double release_coeff; |
57 | |
58 | AVAudioFifo *fifo[2]; |
59 | int64_t pts; |
60 | } AudioGateContext; |
61 | |
62 | #define OFFSET(x) offsetof(AudioGateContext, x) |
63 | #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM |
64 | |
65 | static const AVOption options[] = { |
66 | { "level_in", "set input level", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A }, |
67 | { "range", "set max gain reduction", OFFSET(range), AV_OPT_TYPE_DOUBLE, {.dbl=0.06125}, 0, 1, A }, |
68 | { "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0.125}, 0, 1, A }, |
69 | { "ratio", "set ratio", OFFSET(ratio), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 1, 9000, A }, |
70 | { "attack", "set attack", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=20}, 0.01, 9000, A }, |
71 | { "release", "set release", OFFSET(release), AV_OPT_TYPE_DOUBLE, {.dbl=250}, 0.01, 9000, A }, |
72 | { "makeup", "set makeup gain", OFFSET(makeup), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 1, 64, A }, |
73 | { "knee", "set knee", OFFSET(knee), AV_OPT_TYPE_DOUBLE, {.dbl=2.828427125}, 1, 8, A }, |
74 | { "detection", "set detection", OFFSET(detection), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, A, "detection" }, |
75 | { "peak", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A, "detection" }, |
76 | { "rms", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A, "detection" }, |
77 | { "link", "set link", OFFSET(link), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, A, "link" }, |
78 | { "average", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A, "link" }, |
79 | { "maximum", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A, "link" }, |
80 | { "level_sc", "set sidechain gain", OFFSET(level_sc), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A }, |
81 | { NULL } |
82 | }; |
83 | |
84 | static int agate_config_input(AVFilterLink *inlink) |
85 | { |
86 | AVFilterContext *ctx = inlink->dst; |
87 | AudioGateContext *s = ctx->priv; |
88 | double lin_threshold = s->threshold; |
89 | double lin_knee_sqrt = sqrt(s->knee); |
90 | double lin_knee_start; |
91 | |
92 | if (s->detection) |
93 | lin_threshold *= lin_threshold; |
94 | |
95 | s->attack_coeff = FFMIN(1., 1. / (s->attack * inlink->sample_rate / 4000.)); |
96 | s->release_coeff = FFMIN(1., 1. / (s->release * inlink->sample_rate / 4000.)); |
97 | s->lin_knee_stop = lin_threshold * lin_knee_sqrt; |
98 | lin_knee_start = lin_threshold / lin_knee_sqrt; |
99 | s->thres = log(lin_threshold); |
100 | s->knee_start = log(lin_knee_start); |
101 | s->knee_stop = log(s->lin_knee_stop); |
102 | |
103 | return 0; |
104 | } |
105 | |
106 | // A fake infinity value (because real infinity may break some hosts) |
107 | #define FAKE_INFINITY (65536.0 * 65536.0) |
108 | |
109 | // Check for infinity (with appropriate-ish tolerance) |
110 | #define IS_FAKE_INFINITY(value) (fabs(value-FAKE_INFINITY) < 1.0) |
111 | |
112 | static double output_gain(double lin_slope, double ratio, double thres, |
113 | double knee, double knee_start, double knee_stop, |
114 | double lin_knee_stop, double range) |
115 | { |
116 | if (lin_slope < lin_knee_stop) { |
117 | double slope = log(lin_slope); |
118 | double tratio = ratio; |
119 | double gain = 0.; |
120 | double delta = 0.; |
121 | |
122 | if (IS_FAKE_INFINITY(ratio)) |
123 | tratio = 1000.; |
124 | gain = (slope - thres) * tratio + thres; |
125 | delta = tratio; |
126 | |
127 | if (knee > 1. && slope > knee_start) { |
128 | gain = hermite_interpolation(slope, knee_start, knee_stop, ((knee_start - thres) * tratio + thres), knee_stop, delta, 1.); |
129 | } |
130 | return FFMAX(range, exp(gain - slope)); |
131 | } |
132 | |
133 | return 1.; |
134 | } |
135 | |
136 | static void gate(AudioGateContext *s, |
137 | const double *src, double *dst, const double *scsrc, |
138 | int nb_samples, double level_in, double level_sc, |
139 | AVFilterLink *inlink, AVFilterLink *sclink) |
140 | { |
141 | const double makeup = s->makeup; |
142 | const double attack_coeff = s->attack_coeff; |
143 | const double release_coeff = s->release_coeff; |
144 | int n, c; |
145 | |
146 | for (n = 0; n < nb_samples; n++, src += inlink->channels, dst += inlink->channels, scsrc += sclink->channels) { |
147 | double abs_sample = fabs(scsrc[0] * level_sc), gain = 1.0; |
148 | |
149 | if (s->link == 1) { |
150 | for (c = 1; c < sclink->channels; c++) |
151 | abs_sample = FFMAX(fabs(scsrc[c] * level_sc), abs_sample); |
152 | } else { |
153 | for (c = 1; c < sclink->channels; c++) |
154 | abs_sample += fabs(scsrc[c] * level_sc); |
155 | |
156 | abs_sample /= sclink->channels; |
157 | } |
158 | |
159 | if (s->detection) |
160 | abs_sample *= abs_sample; |
161 | |
162 | s->lin_slope += (abs_sample - s->lin_slope) * (abs_sample > s->lin_slope ? attack_coeff : release_coeff); |
163 | if (s->lin_slope > 0.0) |
164 | gain = output_gain(s->lin_slope, s->ratio, s->thres, |
165 | s->knee, s->knee_start, s->knee_stop, |
166 | s->lin_knee_stop, s->range); |
167 | |
168 | for (c = 0; c < inlink->channels; c++) |
169 | dst[c] = src[c] * level_in * gain * makeup; |
170 | } |
171 | } |
172 | |
173 | #if CONFIG_AGATE_FILTER |
174 | |
175 | #define agate_options options |
176 | AVFILTER_DEFINE_CLASS(agate); |
177 | |
178 | static int query_formats(AVFilterContext *ctx) |
179 | { |
180 | AVFilterFormats *formats = NULL; |
181 | AVFilterChannelLayouts *layouts; |
182 | int ret; |
183 | |
184 | if ((ret = ff_add_format(&formats, AV_SAMPLE_FMT_DBL)) < 0) |
185 | return ret; |
186 | ret = ff_set_common_formats(ctx, formats); |
187 | if (ret < 0) |
188 | return ret; |
189 | |
190 | layouts = ff_all_channel_counts(); |
191 | if (!layouts) |
192 | return AVERROR(ENOMEM); |
193 | ret = ff_set_common_channel_layouts(ctx, layouts); |
194 | if (ret < 0) |
195 | return ret; |
196 | |
197 | formats = ff_all_samplerates(); |
198 | if (!formats) |
199 | return AVERROR(ENOMEM); |
200 | |
201 | return ff_set_common_samplerates(ctx, formats); |
202 | } |
203 | |
204 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
205 | { |
206 | const double *src = (const double *)in->data[0]; |
207 | AVFilterContext *ctx = inlink->dst; |
208 | AVFilterLink *outlink = ctx->outputs[0]; |
209 | AudioGateContext *s = ctx->priv; |
210 | AVFrame *out; |
211 | double *dst; |
212 | |
213 | if (av_frame_is_writable(in)) { |
214 | out = in; |
215 | } else { |
216 | out = ff_get_audio_buffer(inlink, in->nb_samples); |
217 | if (!out) { |
218 | av_frame_free(&in); |
219 | return AVERROR(ENOMEM); |
220 | } |
221 | av_frame_copy_props(out, in); |
222 | } |
223 | dst = (double *)out->data[0]; |
224 | |
225 | gate(s, src, dst, src, in->nb_samples, |
226 | s->level_in, s->level_in, inlink, inlink); |
227 | |
228 | if (out != in) |
229 | av_frame_free(&in); |
230 | return ff_filter_frame(outlink, out); |
231 | } |
232 | |
233 | static const AVFilterPad inputs[] = { |
234 | { |
235 | .name = "default", |
236 | .type = AVMEDIA_TYPE_AUDIO, |
237 | .filter_frame = filter_frame, |
238 | .config_props = agate_config_input, |
239 | }, |
240 | { NULL } |
241 | }; |
242 | |
243 | static const AVFilterPad outputs[] = { |
244 | { |
245 | .name = "default", |
246 | .type = AVMEDIA_TYPE_AUDIO, |
247 | }, |
248 | { NULL } |
249 | }; |
250 | |
251 | AVFilter ff_af_agate = { |
252 | .name = "agate", |
253 | .description = NULL_IF_CONFIG_SMALL("Audio gate."), |
254 | .query_formats = query_formats, |
255 | .priv_size = sizeof(AudioGateContext), |
256 | .priv_class = &agate_class, |
257 | .inputs = inputs, |
258 | .outputs = outputs, |
259 | }; |
260 | |
261 | #endif /* CONFIG_AGATE_FILTER */ |
262 | |
263 | #if CONFIG_SIDECHAINGATE_FILTER |
264 | |
265 | #define sidechaingate_options options |
266 | AVFILTER_DEFINE_CLASS(sidechaingate); |
267 | |
268 | static int scfilter_frame(AVFilterLink *link, AVFrame *frame) |
269 | { |
270 | AVFilterContext *ctx = link->dst; |
271 | AudioGateContext *s = ctx->priv; |
272 | AVFilterLink *outlink = ctx->outputs[0]; |
273 | AVFrame *out, *in[2] = { NULL }; |
274 | double *dst; |
275 | int nb_samples; |
276 | int i; |
277 | |
278 | for (i = 0; i < 2; i++) |
279 | if (link == ctx->inputs[i]) |
280 | break; |
281 | av_assert0(i < 2); |
282 | av_audio_fifo_write(s->fifo[i], (void **)frame->extended_data, |
283 | frame->nb_samples); |
284 | av_frame_free(&frame); |
285 | |
286 | nb_samples = FFMIN(av_audio_fifo_size(s->fifo[0]), av_audio_fifo_size(s->fifo[1])); |
287 | if (!nb_samples) |
288 | return 0; |
289 | |
290 | out = ff_get_audio_buffer(outlink, nb_samples); |
291 | if (!out) |
292 | return AVERROR(ENOMEM); |
293 | for (i = 0; i < 2; i++) { |
294 | in[i] = ff_get_audio_buffer(ctx->inputs[i], nb_samples); |
295 | if (!in[i]) { |
296 | av_frame_free(&in[0]); |
297 | av_frame_free(&in[1]); |
298 | av_frame_free(&out); |
299 | return AVERROR(ENOMEM); |
300 | } |
301 | av_audio_fifo_read(s->fifo[i], (void **)in[i]->data, nb_samples); |
302 | } |
303 | |
304 | dst = (double *)out->data[0]; |
305 | out->pts = s->pts; |
306 | s->pts += nb_samples; |
307 | |
308 | gate(s, (double *)in[0]->data[0], dst, |
309 | (double *)in[1]->data[0], nb_samples, |
310 | s->level_in, s->level_sc, |
311 | ctx->inputs[0], ctx->inputs[1]); |
312 | |
313 | av_frame_free(&in[0]); |
314 | av_frame_free(&in[1]); |
315 | |
316 | return ff_filter_frame(outlink, out); |
317 | } |
318 | |
319 | static int screquest_frame(AVFilterLink *outlink) |
320 | { |
321 | AVFilterContext *ctx = outlink->src; |
322 | AudioGateContext *s = ctx->priv; |
323 | int i; |
324 | |
325 | /* get a frame on each input */ |
326 | for (i = 0; i < 2; i++) { |
327 | AVFilterLink *inlink = ctx->inputs[i]; |
328 | if (!av_audio_fifo_size(s->fifo[i])) |
329 | return ff_request_frame(inlink); |
330 | } |
331 | |
332 | return 0; |
333 | } |
334 | |
335 | static int scquery_formats(AVFilterContext *ctx) |
336 | { |
337 | AVFilterFormats *formats; |
338 | AVFilterChannelLayouts *layouts = NULL; |
339 | static const enum AVSampleFormat sample_fmts[] = { |
340 | AV_SAMPLE_FMT_DBL, |
341 | AV_SAMPLE_FMT_NONE |
342 | }; |
343 | int ret, i; |
344 | |
345 | if (!ctx->inputs[0]->in_channel_layouts || |
346 | !ctx->inputs[0]->in_channel_layouts->nb_channel_layouts) { |
347 | av_log(ctx, AV_LOG_WARNING, |
348 | "No channel layout for input 1\n"); |
349 | return AVERROR(EAGAIN); |
350 | } |
351 | |
352 | if ((ret = ff_add_channel_layout(&layouts, ctx->inputs[0]->in_channel_layouts->channel_layouts[0])) < 0 || |
353 | (ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts)) < 0) |
354 | return ret; |
355 | |
356 | for (i = 0; i < 2; i++) { |
357 | layouts = ff_all_channel_counts(); |
358 | if ((ret = ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts)) < 0) |
359 | return ret; |
360 | } |
361 | |
362 | formats = ff_make_format_list(sample_fmts); |
363 | if ((ret = ff_set_common_formats(ctx, formats)) < 0) |
364 | return ret; |
365 | |
366 | formats = ff_all_samplerates(); |
367 | return ff_set_common_samplerates(ctx, formats); |
368 | } |
369 | |
370 | static int scconfig_output(AVFilterLink *outlink) |
371 | { |
372 | AVFilterContext *ctx = outlink->src; |
373 | AudioGateContext *s = ctx->priv; |
374 | |
375 | if (ctx->inputs[0]->sample_rate != ctx->inputs[1]->sample_rate) { |
376 | av_log(ctx, AV_LOG_ERROR, |
377 | "Inputs must have the same sample rate " |
378 | "%d for in0 vs %d for in1\n", |
379 | ctx->inputs[0]->sample_rate, ctx->inputs[1]->sample_rate); |
380 | return AVERROR(EINVAL); |
381 | } |
382 | |
383 | outlink->sample_rate = ctx->inputs[0]->sample_rate; |
384 | outlink->time_base = ctx->inputs[0]->time_base; |
385 | outlink->channel_layout = ctx->inputs[0]->channel_layout; |
386 | outlink->channels = ctx->inputs[0]->channels; |
387 | |
388 | s->fifo[0] = av_audio_fifo_alloc(ctx->inputs[0]->format, ctx->inputs[0]->channels, 1024); |
389 | s->fifo[1] = av_audio_fifo_alloc(ctx->inputs[1]->format, ctx->inputs[1]->channels, 1024); |
390 | if (!s->fifo[0] || !s->fifo[1]) |
391 | return AVERROR(ENOMEM); |
392 | |
393 | |
394 | agate_config_input(ctx->inputs[0]); |
395 | |
396 | return 0; |
397 | } |
398 | |
399 | static av_cold void uninit(AVFilterContext *ctx) |
400 | { |
401 | AudioGateContext *s = ctx->priv; |
402 | |
403 | av_audio_fifo_free(s->fifo[0]); |
404 | av_audio_fifo_free(s->fifo[1]); |
405 | } |
406 | |
407 | static const AVFilterPad sidechaingate_inputs[] = { |
408 | { |
409 | .name = "main", |
410 | .type = AVMEDIA_TYPE_AUDIO, |
411 | .filter_frame = scfilter_frame, |
412 | },{ |
413 | .name = "sidechain", |
414 | .type = AVMEDIA_TYPE_AUDIO, |
415 | .filter_frame = scfilter_frame, |
416 | }, |
417 | { NULL } |
418 | }; |
419 | |
420 | static const AVFilterPad sidechaingate_outputs[] = { |
421 | { |
422 | .name = "default", |
423 | .type = AVMEDIA_TYPE_AUDIO, |
424 | .config_props = scconfig_output, |
425 | .request_frame = screquest_frame, |
426 | }, |
427 | { NULL } |
428 | }; |
429 | |
430 | AVFilter ff_af_sidechaingate = { |
431 | .name = "sidechaingate", |
432 | .description = NULL_IF_CONFIG_SMALL("Audio sidechain gate."), |
433 | .priv_size = sizeof(AudioGateContext), |
434 | .priv_class = &sidechaingate_class, |
435 | .query_formats = scquery_formats, |
436 | .uninit = uninit, |
437 | .inputs = sidechaingate_inputs, |
438 | .outputs = sidechaingate_outputs, |
439 | }; |
440 | #endif /* CONFIG_SIDECHAINGATE_FILTER */ |
441 |