]> git.sesse.net Git - ffmpeg/blob - libavfilter/af_acrossover.c
avfilter: Constify all AVFilters
[ffmpeg] / libavfilter / af_acrossover.c
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 /**
20  * @file
21  * Crossover filter
22  *
23  * Split an audio stream into several bands.
24  */
25
26 #include "libavutil/attributes.h"
27 #include "libavutil/avstring.h"
28 #include "libavutil/channel_layout.h"
29 #include "libavutil/eval.h"
30 #include "libavutil/float_dsp.h"
31 #include "libavutil/internal.h"
32 #include "libavutil/opt.h"
33
34 #include "audio.h"
35 #include "avfilter.h"
36 #include "formats.h"
37 #include "internal.h"
38
39 #define MAX_SPLITS 16
40 #define MAX_BANDS MAX_SPLITS + 1
41
42 #define B0 0
43 #define B1 1
44 #define B2 2
45 #define A1 3
46 #define A2 4
47
48 typedef struct BiquadCoeffs {
49     double cd[5];
50     float cf[5];
51 } BiquadCoeffs;
52
53 typedef struct AudioCrossoverContext {
54     const AVClass *class;
55
56     char *splits_str;
57     char *gains_str;
58     int order_opt;
59     float level_in;
60
61     int order;
62     int filter_count;
63     int first_order;
64     int ap_filter_count;
65     int nb_splits;
66     float splits[MAX_SPLITS];
67
68     float gains[MAX_BANDS];
69
70     BiquadCoeffs lp[MAX_BANDS][20];
71     BiquadCoeffs hp[MAX_BANDS][20];
72     BiquadCoeffs ap[MAX_BANDS][20];
73
74     AVFrame *xover;
75
76     AVFrame *input_frame;
77     AVFrame *frames[MAX_BANDS];
78
79     int (*filter_channels)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
80
81     AVFloatDSPContext *fdsp;
82 } AudioCrossoverContext;
83
84 #define OFFSET(x) offsetof(AudioCrossoverContext, x)
85 #define AF AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
86
87 static const AVOption acrossover_options[] = {
88     { "split", "set split frequencies", OFFSET(splits_str), AV_OPT_TYPE_STRING, {.str="500"}, 0, 0, AF },
89     { "order", "set filter order",      OFFSET(order_opt),  AV_OPT_TYPE_INT,    {.i64=1},     0, 9, AF, "m" },
90     { "2nd",   "2nd order (12 dB/8ve)", 0,                  AV_OPT_TYPE_CONST,  {.i64=0},     0, 0, AF, "m" },
91     { "4th",   "4th order (24 dB/8ve)", 0,                  AV_OPT_TYPE_CONST,  {.i64=1},     0, 0, AF, "m" },
92     { "6th",   "6th order (36 dB/8ve)", 0,                  AV_OPT_TYPE_CONST,  {.i64=2},     0, 0, AF, "m" },
93     { "8th",   "8th order (48 dB/8ve)", 0,                  AV_OPT_TYPE_CONST,  {.i64=3},     0, 0, AF, "m" },
94     { "10th",  "10th order (60 dB/8ve)",0,                  AV_OPT_TYPE_CONST,  {.i64=4},     0, 0, AF, "m" },
95     { "12th",  "12th order (72 dB/8ve)",0,                  AV_OPT_TYPE_CONST,  {.i64=5},     0, 0, AF, "m" },
96     { "14th",  "14th order (84 dB/8ve)",0,                  AV_OPT_TYPE_CONST,  {.i64=6},     0, 0, AF, "m" },
97     { "16th",  "16th order (96 dB/8ve)",0,                  AV_OPT_TYPE_CONST,  {.i64=7},     0, 0, AF, "m" },
98     { "18th",  "18th order (108 dB/8ve)",0,                 AV_OPT_TYPE_CONST,  {.i64=8},     0, 0, AF, "m" },
99     { "20th",  "20th order (120 dB/8ve)",0,                 AV_OPT_TYPE_CONST,  {.i64=9},     0, 0, AF, "m" },
100     { "level", "set input gain",        OFFSET(level_in),   AV_OPT_TYPE_FLOAT,  {.dbl=1},     0, 1, AF },
101     { "gain",  "set output bands gain", OFFSET(gains_str),  AV_OPT_TYPE_STRING, {.str="1.f"}, 0, 0, AF },
102     { NULL }
103 };
104
105 AVFILTER_DEFINE_CLASS(acrossover);
106
107 static int parse_gains(AVFilterContext *ctx)
108 {
109     AudioCrossoverContext *s = ctx->priv;
110     char *p, *arg, *saveptr = NULL;
111     int i, ret = 0;
112
113     saveptr = NULL;
114     p = s->gains_str;
115     for (i = 0; i < MAX_BANDS; i++) {
116         float gain;
117         char c[3] = { 0 };
118
119         if (!(arg = av_strtok(p, " |", &saveptr)))
120             break;
121
122         p = NULL;
123
124         if (av_sscanf(arg, "%f%2s", &gain, c) < 1) {
125             av_log(ctx, AV_LOG_ERROR, "Invalid syntax for gain[%d].\n", i);
126             ret = AVERROR(EINVAL);
127             break;
128         }
129
130         if (c[0] == 'd' && c[1] == 'B')
131             s->gains[i] = expf(gain * M_LN10 / 20.f);
132         else
133             s->gains[i] = gain;
134     }
135
136     for (; i < MAX_BANDS; i++)
137         s->gains[i] = 1.f;
138
139     return ret;
140 }
141
142 static av_cold int init(AVFilterContext *ctx)
143 {
144     AudioCrossoverContext *s = ctx->priv;
145     char *p, *arg, *saveptr = NULL;
146     int i, ret = 0;
147
148     s->fdsp = avpriv_float_dsp_alloc(0);
149     if (!s->fdsp)
150         return AVERROR(ENOMEM);
151
152     p = s->splits_str;
153     for (i = 0; i < MAX_SPLITS; i++) {
154         float freq;
155
156         if (!(arg = av_strtok(p, " |", &saveptr)))
157             break;
158
159         p = NULL;
160
161         if (av_sscanf(arg, "%f", &freq) != 1) {
162             av_log(ctx, AV_LOG_ERROR, "Invalid syntax for frequency[%d].\n", i);
163             return AVERROR(EINVAL);
164         }
165         if (freq <= 0) {
166             av_log(ctx, AV_LOG_ERROR, "Frequency %f must be positive number.\n", freq);
167             return AVERROR(EINVAL);
168         }
169
170         if (i > 0 && freq <= s->splits[i-1]) {
171             av_log(ctx, AV_LOG_ERROR, "Frequency %f must be in increasing order.\n", freq);
172             return AVERROR(EINVAL);
173         }
174
175         s->splits[i] = freq;
176     }
177
178     s->nb_splits = i;
179
180     ret = parse_gains(ctx);
181     if (ret < 0)
182         return ret;
183
184     for (i = 0; i <= s->nb_splits; i++) {
185         AVFilterPad pad  = { 0 };
186         char *name;
187
188         pad.type = AVMEDIA_TYPE_AUDIO;
189         name = av_asprintf("out%d", ctx->nb_outputs);
190         if (!name)
191             return AVERROR(ENOMEM);
192         pad.name = name;
193
194         if ((ret = ff_insert_outpad(ctx, i, &pad)) < 0) {
195             av_freep(&pad.name);
196             return ret;
197         }
198     }
199
200     return ret;
201 }
202
203 static void set_lp(BiquadCoeffs *b, double fc, double q, double sr)
204 {
205     double omega = 2. * M_PI * fc / sr;
206     double cosine = cos(omega);
207     double alpha = sin(omega) / (2. * q);
208
209     double b0 = (1. - cosine) / 2.;
210     double b1 = 1. - cosine;
211     double b2 = (1. - cosine) / 2.;
212     double a0 = 1. + alpha;
213     double a1 = -2. * cosine;
214     double a2 = 1. - alpha;
215
216     b->cd[B0] =  b0 / a0;
217     b->cd[B1] =  b1 / a0;
218     b->cd[B2] =  b2 / a0;
219     b->cd[A1] = -a1 / a0;
220     b->cd[A2] = -a2 / a0;
221
222     b->cf[B0] = b->cd[B0];
223     b->cf[B1] = b->cd[B1];
224     b->cf[B2] = b->cd[B2];
225     b->cf[A1] = b->cd[A1];
226     b->cf[A2] = b->cd[A2];
227 }
228
229 static void set_hp(BiquadCoeffs *b, double fc, double q, double sr)
230 {
231     double omega = 2. * M_PI * fc / sr;
232     double cosine = cos(omega);
233     double alpha = sin(omega) / (2. * q);
234
235     double b0 = (1. + cosine) / 2.;
236     double b1 = -1. - cosine;
237     double b2 = (1. + cosine) / 2.;
238     double a0 = 1. + alpha;
239     double a1 = -2. * cosine;
240     double a2 = 1. - alpha;
241
242     b->cd[B0] =  b0 / a0;
243     b->cd[B1] =  b1 / a0;
244     b->cd[B2] =  b2 / a0;
245     b->cd[A1] = -a1 / a0;
246     b->cd[A2] = -a2 / a0;
247
248     b->cf[B0] = b->cd[B0];
249     b->cf[B1] = b->cd[B1];
250     b->cf[B2] = b->cd[B2];
251     b->cf[A1] = b->cd[A1];
252     b->cf[A2] = b->cd[A2];
253 }
254
255 static void set_ap(BiquadCoeffs *b, double fc, double q, double sr)
256 {
257     double omega = 2. * M_PI * fc / sr;
258     double cosine = cos(omega);
259     double alpha = sin(omega) / (2. * q);
260
261     double a0 = 1. + alpha;
262     double a1 = -2. * cosine;
263     double a2 = 1. - alpha;
264     double b0 = a2;
265     double b1 = a1;
266     double b2 = a0;
267
268     b->cd[B0] =  b0 / a0;
269     b->cd[B1] =  b1 / a0;
270     b->cd[B2] =  b2 / a0;
271     b->cd[A1] = -a1 / a0;
272     b->cd[A2] = -a2 / a0;
273
274     b->cf[B0] = b->cd[B0];
275     b->cf[B1] = b->cd[B1];
276     b->cf[B2] = b->cd[B2];
277     b->cf[A1] = b->cd[A1];
278     b->cf[A2] = b->cd[A2];
279 }
280
281 static void set_ap1(BiquadCoeffs *b, double fc, double sr)
282 {
283     double omega = 2. * M_PI * fc / sr;
284
285     b->cd[A1] = exp(-omega);
286     b->cd[A2] = 0.;
287     b->cd[B0] = -b->cd[A1];
288     b->cd[B1] = 1.;
289     b->cd[B2] = 0.;
290
291     b->cf[B0] = b->cd[B0];
292     b->cf[B1] = b->cd[B1];
293     b->cf[B2] = b->cd[B2];
294     b->cf[A1] = b->cd[A1];
295     b->cf[A2] = b->cd[A2];
296 }
297
298 static void calc_q_factors(int order, double *q)
299 {
300     double n = order / 2.;
301
302     for (int i = 0; i < n / 2; i++)
303         q[i] = 1. / (-2. * cos(M_PI * (2. * (i + 1) + n - 1.) / (2. * n)));
304 }
305
306 static int query_formats(AVFilterContext *ctx)
307 {
308     AVFilterFormats *formats;
309     AVFilterChannelLayouts *layouts;
310     static const enum AVSampleFormat sample_fmts[] = {
311         AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP,
312         AV_SAMPLE_FMT_NONE
313     };
314     int ret;
315
316     layouts = ff_all_channel_counts();
317     if (!layouts)
318         return AVERROR(ENOMEM);
319     ret = ff_set_common_channel_layouts(ctx, layouts);
320     if (ret < 0)
321         return ret;
322
323     formats = ff_make_format_list(sample_fmts);
324     if (!formats)
325         return AVERROR(ENOMEM);
326     ret = ff_set_common_formats(ctx, formats);
327     if (ret < 0)
328         return ret;
329
330     formats = ff_all_samplerates();
331     if (!formats)
332         return AVERROR(ENOMEM);
333     return ff_set_common_samplerates(ctx, formats);
334 }
335
336 #define BIQUAD_PROCESS(name, type)                             \
337 static void biquad_process_## name(const type *const c,        \
338                                    type *b,                    \
339                                    type *dst, const type *src, \
340                                    int nb_samples)             \
341 {                                                              \
342     const type b0 = c[B0];                                     \
343     const type b1 = c[B1];                                     \
344     const type b2 = c[B2];                                     \
345     const type a1 = c[A1];                                     \
346     const type a2 = c[A2];                                     \
347     type z1 = b[0];                                            \
348     type z2 = b[1];                                            \
349                                                                \
350     for (int n = 0; n + 1 < nb_samples; n++) {                 \
351         type in = src[n];                                      \
352         type out;                                              \
353                                                                \
354         out = in * b0 + z1;                                    \
355         z1 = b1 * in + z2 + a1 * out;                          \
356         z2 = b2 * in + a2 * out;                               \
357         dst[n] = out;                                          \
358                                                                \
359         n++;                                                   \
360         in = src[n];                                           \
361         out = in * b0 + z1;                                    \
362         z1 = b1 * in + z2 + a1 * out;                          \
363         z2 = b2 * in + a2 * out;                               \
364         dst[n] = out;                                          \
365     }                                                          \
366                                                                \
367     if (nb_samples & 1) {                                      \
368         const int n = nb_samples - 1;                          \
369         const type in = src[n];                                \
370         type out;                                              \
371                                                                \
372         out = in * b0 + z1;                                    \
373         z1 = b1 * in + z2 + a1 * out;                          \
374         z2 = b2 * in + a2 * out;                               \
375         dst[n] = out;                                          \
376     }                                                          \
377                                                                \
378     b[0] = z1;                                                 \
379     b[1] = z2;                                                 \
380 }
381
382 BIQUAD_PROCESS(fltp, float)
383 BIQUAD_PROCESS(dblp, double)
384
385 #define XOVER_PROCESS(name, type, one, ff)                                                  \
386 static int filter_channels_## name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
387 {                                                                                           \
388     AudioCrossoverContext *s = ctx->priv;                                                   \
389     AVFrame *in = s->input_frame;                                                           \
390     AVFrame **frames = s->frames;                                                           \
391     const int start = (in->channels * jobnr) / nb_jobs;                                     \
392     const int end = (in->channels * (jobnr+1)) / nb_jobs;                                   \
393     const int nb_samples = in->nb_samples;                                                  \
394     const int nb_outs = ctx->nb_outputs;                                                    \
395     const int first_order = s->first_order;                                                 \
396                                                                                             \
397     for (int ch = start; ch < end; ch++) {                                                  \
398         const type *src = (const type *)in->extended_data[ch];                              \
399         type *xover = (type *)s->xover->extended_data[ch];                                  \
400                                                                                             \
401         s->fdsp->vector_## ff ##mul_scalar((type *)frames[0]->extended_data[ch], src,       \
402                                     s->level_in, FFALIGN(nb_samples, sizeof(type)));        \
403                                                                                             \
404         for (int band = 0; band < nb_outs; band++) {                                        \
405             for (int f = 0; band + 1 < nb_outs && f < s->filter_count; f++) {               \
406                 const type *prv = (const type *)frames[band]->extended_data[ch];            \
407                 type *dst = (type *)frames[band + 1]->extended_data[ch];                    \
408                 const type *hsrc = f == 0 ? prv : dst;                                      \
409                 type *hp = xover + nb_outs * 20 + band * 20 + f * 2;                        \
410                 const type *const hpc = (type *)&s->hp[band][f].c ## ff;                    \
411                                                                                             \
412                 biquad_process_## name(hpc, hp, dst, hsrc, nb_samples);                     \
413             }                                                                               \
414                                                                                             \
415             for (int f = 0; band + 1 < nb_outs && f < s->filter_count; f++) {               \
416                 type *dst = (type *)frames[band]->extended_data[ch];                        \
417                 const type *lsrc = dst;                                                     \
418                 type *lp = xover + band * 20 + f * 2;                                       \
419                 const type *const lpc = (type *)&s->lp[band][f].c ## ff;                    \
420                                                                                             \
421                 biquad_process_## name(lpc, lp, dst, lsrc, nb_samples);                     \
422             }                                                                               \
423                                                                                             \
424             for (int aband = band + 1; aband + 1 < nb_outs; aband++) {                      \
425                 if (first_order) {                                                          \
426                     const type *asrc = (const type *)frames[band]->extended_data[ch];       \
427                     type *dst = (type *)frames[band]->extended_data[ch];                    \
428                     type *ap = xover + nb_outs * 40 + (aband * nb_outs + band) * 20;        \
429                     const type *const apc = (type *)&s->ap[aband][0].c ## ff;               \
430                                                                                             \
431                     biquad_process_## name(apc, ap, dst, asrc, nb_samples);                 \
432                 }                                                                           \
433                                                                                             \
434                 for (int f = first_order; f < s->ap_filter_count; f++) {                    \
435                     const type *asrc = (const type *)frames[band]->extended_data[ch];       \
436                     type *dst = (type *)frames[band]->extended_data[ch];                    \
437                     type *ap = xover + nb_outs * 40 + (aband * nb_outs + band) * 20 + f * 2;\
438                     const type *const apc = (type *)&s->ap[aband][f].c ## ff;               \
439                                                                                             \
440                     biquad_process_## name(apc, ap, dst, asrc, nb_samples);                 \
441                 }                                                                           \
442             }                                                                               \
443         }                                                                                   \
444                                                                                             \
445         for (int band = 0; band < nb_outs; band++) {                                        \
446             const type gain = s->gains[band] * ((band & 1 && first_order) ? -one : one);    \
447             type *dst = (type *)frames[band]->extended_data[ch];                            \
448                                                                                             \
449             s->fdsp->vector_## ff ##mul_scalar(dst, dst, gain,                              \
450                                                FFALIGN(nb_samples, sizeof(type)));          \
451         }                                                                                   \
452     }                                                                                       \
453                                                                                             \
454     return 0;                                                                               \
455 }
456
457 XOVER_PROCESS(fltp, float, 1.f, f)
458 XOVER_PROCESS(dblp, double, 1.0, d)
459
460 static int config_input(AVFilterLink *inlink)
461 {
462     AVFilterContext *ctx = inlink->dst;
463     AudioCrossoverContext *s = ctx->priv;
464     int sample_rate = inlink->sample_rate;
465     double q[16];
466
467     s->order = (s->order_opt + 1) * 2;
468     s->filter_count = s->order / 2;
469     s->first_order = s->filter_count & 1;
470     s->ap_filter_count = s->filter_count / 2 + s->first_order;
471     calc_q_factors(s->order, q);
472
473     for (int band = 0; band <= s->nb_splits; band++) {
474         if (s->first_order) {
475             set_lp(&s->lp[band][0], s->splits[band], 0.5, sample_rate);
476             set_hp(&s->hp[band][0], s->splits[band], 0.5, sample_rate);
477         }
478
479         for (int n = s->first_order; n < s->filter_count; n++) {
480             const int idx = s->filter_count / 2 - ((n + s->first_order) / 2 - s->first_order) - 1;
481
482             set_lp(&s->lp[band][n], s->splits[band], q[idx], sample_rate);
483             set_hp(&s->hp[band][n], s->splits[band], q[idx], sample_rate);
484         }
485
486         if (s->first_order)
487             set_ap1(&s->ap[band][0], s->splits[band], sample_rate);
488
489         for (int n = s->first_order; n < s->ap_filter_count; n++) {
490             const int idx = (s->filter_count / 2 - ((n * 2 + s->first_order) / 2 - s->first_order) - 1);
491
492             set_ap(&s->ap[band][n], s->splits[band], q[idx], sample_rate);
493         }
494     }
495
496     switch (inlink->format) {
497     case AV_SAMPLE_FMT_FLTP: s->filter_channels = filter_channels_fltp; break;
498     case AV_SAMPLE_FMT_DBLP: s->filter_channels = filter_channels_dblp; break;
499     }
500
501     s->xover = ff_get_audio_buffer(inlink, 2 * (ctx->nb_outputs * 10 + ctx->nb_outputs * 10 +
502                                                 ctx->nb_outputs * ctx->nb_outputs * 10));
503     if (!s->xover)
504         return AVERROR(ENOMEM);
505
506     return 0;
507 }
508
509 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
510 {
511     AVFilterContext *ctx = inlink->dst;
512     AudioCrossoverContext *s = ctx->priv;
513     AVFrame **frames = s->frames;
514     int i, ret = 0;
515
516     for (i = 0; i < ctx->nb_outputs; i++) {
517         frames[i] = ff_get_audio_buffer(ctx->outputs[i], in->nb_samples);
518
519         if (!frames[i]) {
520             ret = AVERROR(ENOMEM);
521             break;
522         }
523
524         frames[i]->pts = in->pts;
525     }
526
527     if (ret < 0)
528         goto fail;
529
530     s->input_frame = in;
531     ctx->internal->execute(ctx, s->filter_channels, NULL, NULL, FFMIN(inlink->channels,
532                                                                       ff_filter_get_nb_threads(ctx)));
533
534     for (i = 0; i < ctx->nb_outputs; i++) {
535         ret = ff_filter_frame(ctx->outputs[i], frames[i]);
536         frames[i] = NULL;
537         if (ret < 0)
538             break;
539     }
540
541 fail:
542     for (i = 0; i < ctx->nb_outputs; i++)
543         av_frame_free(&frames[i]);
544     av_frame_free(&in);
545     s->input_frame = NULL;
546
547     return ret;
548 }
549
550 static av_cold void uninit(AVFilterContext *ctx)
551 {
552     AudioCrossoverContext *s = ctx->priv;
553     int i;
554
555     av_freep(&s->fdsp);
556     av_frame_free(&s->xover);
557
558     for (i = 0; i < ctx->nb_outputs; i++)
559         av_freep(&ctx->output_pads[i].name);
560 }
561
562 static const AVFilterPad inputs[] = {
563     {
564         .name         = "default",
565         .type         = AVMEDIA_TYPE_AUDIO,
566         .filter_frame = filter_frame,
567         .config_props = config_input,
568     },
569     { NULL }
570 };
571
572 const AVFilter ff_af_acrossover = {
573     .name           = "acrossover",
574     .description    = NULL_IF_CONFIG_SMALL("Split audio into per-bands streams."),
575     .priv_size      = sizeof(AudioCrossoverContext),
576     .priv_class     = &acrossover_class,
577     .init           = init,
578     .uninit         = uninit,
579     .query_formats  = query_formats,
580     .inputs         = inputs,
581     .outputs        = NULL,
582     .flags          = AVFILTER_FLAG_DYNAMIC_OUTPUTS |
583                       AVFILTER_FLAG_SLICE_THREADS,
584 };