Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 1998 Juergen Mueller And Sundry Contributors | ||
3 | * This source code is freely redistributable and may be used for | ||
4 | * any purpose. This copyright notice must be maintained. | ||
5 | * Juergen Mueller And Sundry Contributors are not responsible for | ||
6 | * the consequences of using this software. | ||
7 | * | ||
8 | * Copyright (c) 2015 Paul B Mahol | ||
9 | * | ||
10 | * This file is part of FFmpeg. | ||
11 | * | ||
12 | * FFmpeg is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU Lesser General Public | ||
14 | * License as published by the Free Software Foundation; either | ||
15 | * version 2.1 of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * FFmpeg is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
20 | * Lesser General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU Lesser General Public | ||
23 | * License along with FFmpeg; if not, write to the Free Software | ||
24 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
25 | */ | ||
26 | |||
27 | /** | ||
28 | * @file | ||
29 | * chorus audio filter | ||
30 | */ | ||
31 | |||
32 | #include "libavutil/avstring.h" | ||
33 | #include "libavutil/mem.h" | ||
34 | #include "libavutil/opt.h" | ||
35 | #include "audio.h" | ||
36 | #include "avfilter.h" | ||
37 | #include "filters.h" | ||
38 | #include "generate_wave_table.h" | ||
39 | |||
40 | typedef struct ChorusContext { | ||
41 | const AVClass *class; | ||
42 | float in_gain, out_gain; | ||
43 | char *delays_str; | ||
44 | char *decays_str; | ||
45 | char *speeds_str; | ||
46 | char *depths_str; | ||
47 | float *delays; | ||
48 | float *decays; | ||
49 | float *speeds; | ||
50 | float *depths; | ||
51 | uint8_t **chorusbuf; | ||
52 | int **phase; | ||
53 | int *length; | ||
54 | int32_t **lookup_table; | ||
55 | int *counter; | ||
56 | int num_chorus; | ||
57 | int max_samples; | ||
58 | int channels; | ||
59 | int modulation; | ||
60 | int fade_out; | ||
61 | int64_t next_pts; | ||
62 | } ChorusContext; | ||
63 | |||
64 | #define OFFSET(x) offsetof(ChorusContext, x) | ||
65 | #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM | ||
66 | |||
67 | static const AVOption chorus_options[] = { | ||
68 | { "in_gain", "set input gain", OFFSET(in_gain), AV_OPT_TYPE_FLOAT, {.dbl=.4}, 0, 1, A }, | ||
69 | { "out_gain", "set output gain", OFFSET(out_gain), AV_OPT_TYPE_FLOAT, {.dbl=.4}, 0, 1, A }, | ||
70 | { "delays", "set delays", OFFSET(delays_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A }, | ||
71 | { "decays", "set decays", OFFSET(decays_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A }, | ||
72 | { "speeds", "set speeds", OFFSET(speeds_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A }, | ||
73 | { "depths", "set depths", OFFSET(depths_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A }, | ||
74 | { NULL } | ||
75 | }; | ||
76 | |||
77 | AVFILTER_DEFINE_CLASS(chorus); | ||
78 | |||
79 | 8 | static void count_items(char *item_str, int *nb_items) | |
80 | { | ||
81 | char *p; | ||
82 | |||
83 | 8 | *nb_items = 1; | |
84 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 8 times.
|
58 | for (p = item_str; *p; p++) { |
85 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
|
50 | if (*p == '|') |
86 | ✗ | (*nb_items)++; | |
87 | } | ||
88 | |||
89 | 8 | } | |
90 | |||
91 | 8 | static void fill_items(char *item_str, int *nb_items, float *items) | |
92 | { | ||
93 | 8 | char *p, *saveptr = NULL; | |
94 | 8 | int i, new_nb_items = 0; | |
95 | |||
96 | 8 | p = item_str; | |
97 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | for (i = 0; i < *nb_items; i++) { |
98 | 8 | char *tstr = av_strtok(p, "|", &saveptr); | |
99 | 8 | p = NULL; | |
100 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (tstr) |
101 | 8 | new_nb_items += sscanf(tstr, "%f", &items[new_nb_items]) == 1; | |
102 | } | ||
103 | |||
104 | 8 | *nb_items = new_nb_items; | |
105 | 8 | } | |
106 | |||
107 | 2 | static av_cold int init(AVFilterContext *ctx) | |
108 | { | ||
109 | 2 | ChorusContext *s = ctx->priv; | |
110 | int nb_delays, nb_decays, nb_speeds, nb_depths; | ||
111 | |||
112 |
4/8✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
|
2 | if (!s->delays_str || !s->decays_str || !s->speeds_str || !s->depths_str) { |
113 | ✗ | av_log(ctx, AV_LOG_ERROR, "Both delays & decays & speeds & depths must be set.\n"); | |
114 | ✗ | return AVERROR(EINVAL); | |
115 | } | ||
116 | |||
117 | 2 | count_items(s->delays_str, &nb_delays); | |
118 | 2 | count_items(s->decays_str, &nb_decays); | |
119 | 2 | count_items(s->speeds_str, &nb_speeds); | |
120 | 2 | count_items(s->depths_str, &nb_depths); | |
121 | |||
122 | 2 | s->delays = av_realloc_f(s->delays, nb_delays, sizeof(*s->delays)); | |
123 | 2 | s->decays = av_realloc_f(s->decays, nb_decays, sizeof(*s->decays)); | |
124 | 2 | s->speeds = av_realloc_f(s->speeds, nb_speeds, sizeof(*s->speeds)); | |
125 | 2 | s->depths = av_realloc_f(s->depths, nb_depths, sizeof(*s->depths)); | |
126 | |||
127 |
4/8✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
|
2 | if (!s->delays || !s->decays || !s->speeds || !s->depths) |
128 | ✗ | return AVERROR(ENOMEM); | |
129 | |||
130 | 2 | fill_items(s->delays_str, &nb_delays, s->delays); | |
131 | 2 | fill_items(s->decays_str, &nb_decays, s->decays); | |
132 | 2 | fill_items(s->speeds_str, &nb_speeds, s->speeds); | |
133 | 2 | fill_items(s->depths_str, &nb_depths, s->depths); | |
134 | |||
135 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
2 | if (nb_delays != nb_decays && nb_delays != nb_speeds && nb_delays != nb_depths) { |
136 | ✗ | av_log(ctx, AV_LOG_ERROR, "Number of delays & decays & speeds & depths given must be same.\n"); | |
137 | ✗ | return AVERROR(EINVAL); | |
138 | } | ||
139 | |||
140 | 2 | s->num_chorus = nb_delays; | |
141 | |||
142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (s->num_chorus < 1) { |
143 | ✗ | av_log(ctx, AV_LOG_ERROR, "At least one delay & decay & speed & depth must be set.\n"); | |
144 | ✗ | return AVERROR(EINVAL); | |
145 | } | ||
146 | |||
147 | 2 | s->length = av_calloc(s->num_chorus, sizeof(*s->length)); | |
148 | 2 | s->lookup_table = av_calloc(s->num_chorus, sizeof(*s->lookup_table)); | |
149 | |||
150 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (!s->length || !s->lookup_table) |
151 | ✗ | return AVERROR(ENOMEM); | |
152 | |||
153 | 2 | s->next_pts = AV_NOPTS_VALUE; | |
154 | |||
155 | 2 | return 0; | |
156 | } | ||
157 | |||
158 | 1 | static int config_output(AVFilterLink *outlink) | |
159 | { | ||
160 | 1 | AVFilterContext *ctx = outlink->src; | |
161 | 1 | ChorusContext *s = ctx->priv; | |
162 | 1 | float sum_in_volume = 1.0; | |
163 | int n; | ||
164 | |||
165 | 1 | s->channels = outlink->ch_layout.nb_channels; | |
166 | |||
167 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (n = 0; n < s->num_chorus; n++) { |
168 | 1 | int samples = (int) ((s->delays[n] + s->depths[n]) * outlink->sample_rate / 1000.0); | |
169 | 1 | int depth_samples = (int) (s->depths[n] * outlink->sample_rate / 1000.0); | |
170 | |||
171 | 1 | s->length[n] = outlink->sample_rate / s->speeds[n]; | |
172 | |||
173 | 1 | s->lookup_table[n] = av_malloc(sizeof(int32_t) * s->length[n]); | |
174 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!s->lookup_table[n]) |
175 | ✗ | return AVERROR(ENOMEM); | |
176 | |||
177 | 1 | ff_generate_wave_table(WAVE_SIN, AV_SAMPLE_FMT_S32, s->lookup_table[n], | |
178 | 1 | s->length[n], 0., depth_samples, 0); | |
179 | 1 | s->max_samples = FFMAX(s->max_samples, samples); | |
180 | } | ||
181 | |||
182 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (n = 0; n < s->num_chorus; n++) |
183 | 1 | sum_in_volume += s->decays[n]; | |
184 | |||
185 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (s->in_gain * (sum_in_volume) > 1.0 / s->out_gain) |
186 | ✗ | av_log(ctx, AV_LOG_WARNING, "output gain can cause saturation or clipping of output\n"); | |
187 | |||
188 | 1 | s->counter = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->counter)); | |
189 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!s->counter) |
190 | ✗ | return AVERROR(ENOMEM); | |
191 | |||
192 | 1 | s->phase = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->phase)); | |
193 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!s->phase) |
194 | ✗ | return AVERROR(ENOMEM); | |
195 | |||
196 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (n = 0; n < outlink->ch_layout.nb_channels; n++) { |
197 | 1 | s->phase[n] = av_calloc(s->num_chorus, sizeof(int)); | |
198 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!s->phase[n]) |
199 | ✗ | return AVERROR(ENOMEM); | |
200 | } | ||
201 | |||
202 | 1 | s->fade_out = s->max_samples; | |
203 | |||
204 | 1 | return av_samples_alloc_array_and_samples(&s->chorusbuf, NULL, | |
205 | outlink->ch_layout.nb_channels, | ||
206 | s->max_samples, | ||
207 | 1 | outlink->format, 0); | |
208 | } | ||
209 | |||
210 | #define MOD(a, b) (((a) >= (b)) ? (a) - (b) : (a)) | ||
211 | |||
212 | 10 | static int filter_frame(AVFilterLink *inlink, AVFrame *frame) | |
213 | { | ||
214 | 10 | AVFilterContext *ctx = inlink->dst; | |
215 | 10 | ChorusContext *s = ctx->priv; | |
216 | AVFrame *out_frame; | ||
217 | int c, i, n; | ||
218 | |||
219 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | if (av_frame_is_writable(frame)) { |
220 | 10 | out_frame = frame; | |
221 | } else { | ||
222 | ✗ | out_frame = ff_get_audio_buffer(ctx->outputs[0], frame->nb_samples); | |
223 | ✗ | if (!out_frame) { | |
224 | ✗ | av_frame_free(&frame); | |
225 | ✗ | return AVERROR(ENOMEM); | |
226 | } | ||
227 | ✗ | av_frame_copy_props(out_frame, frame); | |
228 | } | ||
229 | |||
230 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
|
20 | for (c = 0; c < inlink->ch_layout.nb_channels; c++) { |
231 | 10 | const float *src = (const float *)frame->extended_data[c]; | |
232 | 10 | float *dst = (float *)out_frame->extended_data[c]; | |
233 | 10 | float *chorusbuf = (float *)s->chorusbuf[c]; | |
234 | 10 | int *phase = s->phase[c]; | |
235 | |||
236 |
2/2✓ Branch 0 taken 20480 times.
✓ Branch 1 taken 10 times.
|
20490 | for (i = 0; i < frame->nb_samples; i++) { |
237 | 20480 | float out, in = src[i]; | |
238 | |||
239 | 20480 | out = in * s->in_gain; | |
240 | |||
241 |
2/2✓ Branch 0 taken 20480 times.
✓ Branch 1 taken 20480 times.
|
40960 | for (n = 0; n < s->num_chorus; n++) { |
242 |
2/2✓ Branch 0 taken 20126 times.
✓ Branch 1 taken 354 times.
|
20480 | out += chorusbuf[MOD(s->max_samples + s->counter[c] - |
243 | s->lookup_table[n][phase[n]], | ||
244 | 20480 | s->max_samples)] * s->decays[n]; | |
245 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20480 times.
|
20480 | phase[n] = MOD(phase[n] + 1, s->length[n]); |
246 | } | ||
247 | |||
248 | 20480 | out *= s->out_gain; | |
249 | |||
250 | 20480 | dst[i] = out; | |
251 | |||
252 | 20480 | chorusbuf[s->counter[c]] = in; | |
253 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 20466 times.
|
20480 | s->counter[c] = MOD(s->counter[c] + 1, s->max_samples); |
254 | } | ||
255 | } | ||
256 | |||
257 | 10 | s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base); | |
258 | |||
259 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (frame != out_frame) |
260 | ✗ | av_frame_free(&frame); | |
261 | |||
262 | 10 | return ff_filter_frame(ctx->outputs[0], out_frame); | |
263 | } | ||
264 | |||
265 | 9 | static int request_frame(AVFilterLink *outlink) | |
266 | { | ||
267 | 9 | AVFilterContext *ctx = outlink->src; | |
268 | 9 | ChorusContext *s = ctx->priv; | |
269 | int ret; | ||
270 | |||
271 | 9 | ret = ff_request_frame(ctx->inputs[0]); | |
272 | |||
273 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
9 | if (ret == AVERROR_EOF && !ctx->is_disabled && s->fade_out) { |
274 | ✗ | int nb_samples = FFMIN(s->fade_out, 2048); | |
275 | AVFrame *frame; | ||
276 | |||
277 | ✗ | frame = ff_get_audio_buffer(outlink, nb_samples); | |
278 | ✗ | if (!frame) | |
279 | ✗ | return AVERROR(ENOMEM); | |
280 | ✗ | s->fade_out -= nb_samples; | |
281 | |||
282 | ✗ | av_samples_set_silence(frame->extended_data, 0, | |
283 | frame->nb_samples, | ||
284 | outlink->ch_layout.nb_channels, | ||
285 | ✗ | frame->format); | |
286 | |||
287 | ✗ | frame->pts = s->next_pts; | |
288 | ✗ | if (s->next_pts != AV_NOPTS_VALUE) | |
289 | ✗ | s->next_pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); | |
290 | |||
291 | ✗ | ret = filter_frame(ctx->inputs[0], frame); | |
292 | } | ||
293 | |||
294 | 9 | return ret; | |
295 | } | ||
296 | |||
297 | 2 | static av_cold void uninit(AVFilterContext *ctx) | |
298 | { | ||
299 | 2 | ChorusContext *s = ctx->priv; | |
300 | int n; | ||
301 | |||
302 | 2 | av_freep(&s->delays); | |
303 | 2 | av_freep(&s->decays); | |
304 | 2 | av_freep(&s->speeds); | |
305 | 2 | av_freep(&s->depths); | |
306 | |||
307 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (s->chorusbuf) |
308 | 1 | av_freep(&s->chorusbuf[0]); | |
309 | 2 | av_freep(&s->chorusbuf); | |
310 | |||
311 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (s->phase) |
312 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (n = 0; n < s->channels; n++) |
313 | 1 | av_freep(&s->phase[n]); | |
314 | 2 | av_freep(&s->phase); | |
315 | |||
316 | 2 | av_freep(&s->counter); | |
317 | 2 | av_freep(&s->length); | |
318 | |||
319 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (s->lookup_table) |
320 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | for (n = 0; n < s->num_chorus; n++) |
321 | 2 | av_freep(&s->lookup_table[n]); | |
322 | 2 | av_freep(&s->lookup_table); | |
323 | 2 | } | |
324 | |||
325 | static const AVFilterPad chorus_inputs[] = { | ||
326 | { | ||
327 | .name = "default", | ||
328 | .type = AVMEDIA_TYPE_AUDIO, | ||
329 | .filter_frame = filter_frame, | ||
330 | }, | ||
331 | }; | ||
332 | |||
333 | static const AVFilterPad chorus_outputs[] = { | ||
334 | { | ||
335 | .name = "default", | ||
336 | .type = AVMEDIA_TYPE_AUDIO, | ||
337 | .request_frame = request_frame, | ||
338 | .config_props = config_output, | ||
339 | }, | ||
340 | }; | ||
341 | |||
342 | const AVFilter ff_af_chorus = { | ||
343 | .name = "chorus", | ||
344 | .description = NULL_IF_CONFIG_SMALL("Add a chorus effect to the audio."), | ||
345 | .priv_size = sizeof(ChorusContext), | ||
346 | .priv_class = &chorus_class, | ||
347 | .init = init, | ||
348 | .uninit = uninit, | ||
349 | FILTER_INPUTS(chorus_inputs), | ||
350 | FILTER_OUTPUTS(chorus_outputs), | ||
351 | FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), | ||
352 | }; | ||
353 |