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
34
37
50
59
63
64 #define OFFSET(x) offsetof(AudioGateContext, x)
65 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
66
87 };
88
90
92 {
95 double lin_threshold =
s->threshold;
96 double lin_knee_sqrt = sqrt(
s->knee);
97
99 lin_threshold *= lin_threshold;
100
101 s->attack_coeff =
FFMIN(1., 1. / (
s->attack *
inlink->sample_rate / 4000.));
102 s->release_coeff =
FFMIN(1., 1. / (
s->release *
inlink->sample_rate / 4000.));
103 s->lin_knee_stop = lin_threshold * lin_knee_sqrt;
104 s->lin_knee_start = lin_threshold / lin_knee_sqrt;
105 s->thres = log(lin_threshold);
106 s->knee_start = log(
s->lin_knee_start);
107 s->knee_stop = log(
s->lin_knee_stop);
108
109 return 0;
110 }
111
112 // A fake infinity value (because real infinity may break some hosts)
113 #define FAKE_INFINITY (65536.0 * 65536.0)
114
115 // Check for infinity (with appropriate-ish tolerance)
116 #define IS_FAKE_INFINITY(value) (fabs(value-FAKE_INFINITY) < 1.0)
117
118 static double output_gain(
double lin_slope,
double ratio,
double thres,
119 double knee, double knee_start, double knee_stop,
120 double range,
int mode)
121 {
122 double slope = log(lin_slope);
123 double tratio = ratio;
124 double gain = 0.;
126
128 tratio = 1000.;
129 gain = (slope - thres) * tratio + thres;
131
133 if (knee > 1. && slope < knee_stop)
135 } else {
136 if (knee > 1. && slope > knee_start)
138 }
139 return FFMAX(range,
exp(gain - slope));
140 }
141
143 const double *
src,
double *dst,
const double *scsrc,
144 int nb_samples, double level_in, double level_sc,
146 {
148 const double makeup =
s->makeup;
149 const double attack_coeff =
s->attack_coeff;
150 const double release_coeff =
s->release_coeff;
152
153 for (n = 0; n < nb_samples; n++,
src +=
inlink->channels, dst +=
inlink->channels, scsrc += sclink->
channels) {
154 double abs_sample =
fabs(scsrc[0] * level_sc), gain = 1.0;
156 int detected;
157
160 abs_sample =
FFMAX(
fabs(scsrc[
c] * level_sc), abs_sample);
161 } else {
163 abs_sample +=
fabs(scsrc[
c] * level_sc);
164
166 }
167
169 abs_sample *= abs_sample;
170
171 s->lin_slope += (abs_sample -
s->lin_slope) * (abs_sample >
s->lin_slope ? attack_coeff : release_coeff);
172
174 detected =
s->lin_slope >
s->lin_knee_start;
175 else
176 detected =
s->lin_slope <
s->lin_knee_stop;
177
178 if (
s->lin_slope > 0.0 && detected)
180 s->knee,
s->knee_start,
s->knee_stop,
182
183 factor =
ctx->is_disabled ? 1.f : level_in * gain * makeup;
186 }
187 }
188
189 #if CONFIG_AGATE_FILTER
190
192 {
193 const double *
src = (
const double *)in->
data[0];
198 double *dst;
199
202 } else {
207 }
209 }
210 dst = (
double *)
out->data[0];
211
214
218 }
219
221 {
222 .name = "default",
226 },
227 };
228
230 {
233 },
234 };
235
239 .priv_class = &agate_sidechaingate_class,
246 };
247
248 #endif /* CONFIG_AGATE_FILTER */
249
250 #if CONFIG_SIDECHAINGATE_FILTER
251
253 {
256 int ret,
i, nb_samples;
257 double *dst;
258
262 in[0]->nb_samples);
264 }
269 in[1]->nb_samples);
271 }
274
276 if (nb_samples) {
280 for (
i = 0;
i < 2;
i++) {
287 }
289 }
290
291 dst = (
double *)
out->data[0];
294
296 (
double *)in[1]->
data[0], nb_samples,
297 s->level_in,
s->level_sc,
298 ctx->inputs[0],
ctx->inputs[1]);
299
302
306 }
314 }
315 return 0;
316 }
317
319 {
323 };
325 &
ctx->inputs[1]->outcfg.channel_layouts);
328
329 /* This will link the channel properties of the main input and the output;
330 * it won't touch the second input as its channel_layouts is already set. */
333
336
338 }
339
341 {
344
346
349 if (!
s->fifo[0] || !
s->fifo[1])
351
352
354
355 return 0;
356 }
357
359 {
361
364 }
365
366 static const AVFilterPad sidechaingate_inputs[] = {
367 {
370 },{
371 .name = "sidechain",
373 },
374 };
375
376 static const AVFilterPad sidechaingate_outputs[] = {
377 {
380 .config_props = scconfig_output,
381 },
382 };
383
385 .
name =
"sidechaingate",
387 .priv_class = &agate_sidechaingate_class,
396 };
397 #endif /* CONFIG_SIDECHAINGATE_FILTER */