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
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,
122 double range,
int mode)
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 }
141 return FFMAX(range,
exp(gain - slope));
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];
200 double *dst;
201
204 } else {
209 }
211 }
212 dst = (
double *)
out->data[0];
213
216
220 }
221
223 {
224 .name = "default",
228 },
229 };
230
232 {
235 },
236 };
237
241 .priv_class = &agate_sidechaingate_class,
248 };
249
250 #endif /* CONFIG_AGATE_FILTER */
251
252 #if CONFIG_SIDECHAINGATE_FILTER
253
255 {
258 int ret,
i, nb_samples;
259 double *dst;
260
264 in[0]->nb_samples);
266 }
271 in[1]->nb_samples);
273 }
276
278 if (nb_samples) {
282 for (
i = 0;
i < 2;
i++) {
289 }
291 }
292
293 dst = (
double *)
out->data[0];
296
298 (
double *)in[1]->
data[0], nb_samples,
299 s->level_in,
s->level_sc,
300 ctx->inputs[0],
ctx->inputs[1]);
301
304
308 }
316 }
317 return 0;
318 }
319
321 {
325 };
327 &
ctx->inputs[1]->outcfg.channel_layouts);
330
331 /* This will link the channel properties of the main input and the output;
332 * it won't touch the second input as its channel_layouts is already set. */
335
338
340 }
341
343 {
346
348
351 if (!
s->fifo[0] || !
s->fifo[1])
353
354
356
357 return 0;
358 }
359
361 {
363
366 }
367
368 static const AVFilterPad sidechaingate_inputs[] = {
369 {
372 },{
373 .name = "sidechain",
375 },
376 };
377
378 static const AVFilterPad sidechaingate_outputs[] = {
379 {
382 .config_props = scconfig_output,
383 },
384 };
385
387 .
name =
"sidechaingate",
389 .priv_class = &agate_sidechaingate_class,
398 };
399 #endif /* CONFIG_SIDECHAINGATE_FILTER */