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 "config_components.h"
27
36
39
52
61
65
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
68
81 {
"detection",
"set detection",
OFFSET(detection),
AV_OPT_TYPE_INT, {.i64=1}, 0, 1,
A, .unit =
"detection" },
89 };
90
92
94 {
97 double lin_threshold =
s->threshold;
98 double lin_knee_sqrt = sqrt(
s->knee);
99
101 lin_threshold *= lin_threshold;
102
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);
110
111 return 0;
112 }
113
114 // A fake infinity value (because real infinity may break some hosts)
115 #define FAKE_INFINITY (65536.0 * 65536.0)
116
117 // Check for infinity (with appropriate-ish tolerance)
118 #define IS_FAKE_INFINITY(value) (fabs(value-FAKE_INFINITY) < 1.0)
119
120 static double output_gain(
double lin_slope,
double ratio,
double thres,
121 double knee, double knee_start, double knee_stop,
123 {
124 double slope =
log(lin_slope);
125 double tratio = ratio;
126 double gain = 0.;
128
130 tratio = 1000.;
131 gain = (slope - thres) * tratio + thres;
133
135 if (knee > 1. && slope < knee_stop)
137 } else {
138 if (knee > 1. && slope > knee_start)
140 }
142 }
143
145 const double *
src,
double *
dst,
const double *scsrc,
146 int nb_samples, double level_in, double level_sc,
148 {
150 const double makeup =
s->makeup;
151 const double attack_coeff =
s->attack_coeff;
152 const double release_coeff =
s->release_coeff;
154
156 double abs_sample =
fabs(scsrc[0] * level_sc), gain = 1.0;
158 int detected;
159
162 abs_sample =
FFMAX(
fabs(scsrc[
c] * level_sc), abs_sample);
163 } else {
165 abs_sample +=
fabs(scsrc[
c] * level_sc);
166
168 }
169
171 abs_sample *= abs_sample;
172
173 s->lin_slope += (abs_sample -
s->lin_slope) * (abs_sample >
s->lin_slope ? attack_coeff : release_coeff);
174
176 detected =
s->lin_slope >
s->lin_knee_start;
177 else
178 detected =
s->lin_slope <
s->lin_knee_stop;
179
180 if (
s->lin_slope > 0.0 && detected)
182 s->knee,
s->knee_start,
s->knee_stop,
184
185 factor =
ctx->is_disabled ? 1.f : level_in * gain * makeup;
186 for (
c = 0;
c <
inlink->ch_layout.nb_channels;
c++)
188 }
189 }
190
191 #if CONFIG_AGATE_FILTER
192
194 {
195 const double *
src = (
const double *)in->
data[0];
201
204 } else {
209 }
211 }
212 dst = (
double *)
out->data[0];
213
216
220 }
221
223 {
224 .name = "default",
228 },
229 };
230
234 .priv_class = &agate_sidechaingate_class,
241 };
242
243 #endif /* CONFIG_AGATE_FILTER */
244
245 #if CONFIG_SIDECHAINGATE_FILTER
246
248 {
251 int ret,
i, nb_samples;
253
257 in[0]->nb_samples);
259 }
264 in[1]->nb_samples);
266 }
269
271 if (nb_samples) {
275 for (
i = 0;
i < 2;
i++) {
282 }
284 }
285
286 dst = (
double *)
out->data[0];
289
291 (
double *)in[1]->
data[0], nb_samples,
292 s->level_in,
s->level_sc,
293 ctx->inputs[0],
ctx->inputs[1]);
294
297
301 }
309 }
310 return 0;
311 }
312
316 {
320 };
322
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
325 * set. */
330
333
334 return 0;
335 }
336
338 {
341
343
346 if (!
s->fifo[0] || !
s->fifo[1])
348
349
351
352 return 0;
353 }
354
356 {
358
361 }
362
363 static const AVFilterPad sidechaingate_inputs[] = {
364 {
367 },{
368 .name = "sidechain",
370 },
371 };
372
373 static const AVFilterPad sidechaingate_outputs[] = {
374 {
377 .config_props = scconfig_output,
378 },
379 };
380
382 .
name =
"sidechaingate",
384 .priv_class = &agate_sidechaingate_class,
393 };
394 #endif /* CONFIG_SIDECHAINGATE_FILTER */