FFmpeg
af_firequalizer.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Muhammad Faiz <mfcc64@gmail.com>
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 
22 #include "libavutil/opt.h"
23 #include "libavutil/eval.h"
24 #include "libavutil/avassert.h"
25 #include "libavcodec/avfft.h"
26 #include "avfilter.h"
27 #include "internal.h"
28 #include "audio.h"
29 
30 #define RDFT_BITS_MIN 4
31 #define RDFT_BITS_MAX 16
32 
33 enum WindowFunc {
45 };
46 
47 enum Scale {
53 };
54 
55 #define NB_GAIN_ENTRY_MAX 4096
56 typedef struct GainEntry {
57  double freq;
58  double gain;
59 } GainEntry;
60 
61 typedef struct OverlapIndex {
62  int buf_idx;
64 } OverlapIndex;
65 
66 typedef struct FIREqualizerContext {
67  const AVClass *class;
68 
77  int rdft_len;
79 
80  float *analysis_buf;
81  float *dump_buf;
83  float *kernel_buf;
84  float *cepstrum_buf;
85  float *conv_buf;
87  int fir_len;
89  int64_t next_pts;
91  int remaining;
92 
93  char *gain_cmd;
95  const char *gain;
96  const char *gain_entry;
97  double delay;
98  double accuracy;
99  int wfunc;
100  int fixed;
101  int multi;
103  int scale;
104  char *dumpfile;
106  int fft2;
108 
113 
114 #define OFFSET(x) offsetof(FIREqualizerContext, x)
115 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
116 #define TFLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
117 
118 static const AVOption firequalizer_options[] = {
119  { "gain", "set gain curve", OFFSET(gain), AV_OPT_TYPE_STRING, { .str = "gain_interpolate(f)" }, 0, 0, TFLAGS },
120  { "gain_entry", "set gain entry", OFFSET(gain_entry), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, TFLAGS },
121  { "delay", "set delay", OFFSET(delay), AV_OPT_TYPE_DOUBLE, { .dbl = 0.01 }, 0.0, 1e10, FLAGS },
122  { "accuracy", "set accuracy", OFFSET(accuracy), AV_OPT_TYPE_DOUBLE, { .dbl = 5.0 }, 0.0, 1e10, FLAGS },
123  { "wfunc", "set window function", OFFSET(wfunc), AV_OPT_TYPE_INT, { .i64 = WFUNC_HANN }, 0, NB_WFUNC-1, FLAGS, "wfunc" },
124  { "rectangular", "rectangular window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_RECTANGULAR }, 0, 0, FLAGS, "wfunc" },
125  { "hann", "hann window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_HANN }, 0, 0, FLAGS, "wfunc" },
126  { "hamming", "hamming window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_HAMMING }, 0, 0, FLAGS, "wfunc" },
127  { "blackman", "blackman window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_BLACKMAN }, 0, 0, FLAGS, "wfunc" },
128  { "nuttall3", "3-term nuttall window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_NUTTALL3 }, 0, 0, FLAGS, "wfunc" },
129  { "mnuttall3", "minimum 3-term nuttall window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_MNUTTALL3 }, 0, 0, FLAGS, "wfunc" },
130  { "nuttall", "nuttall window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_NUTTALL }, 0, 0, FLAGS, "wfunc" },
131  { "bnuttall", "blackman-nuttall window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_BNUTTALL }, 0, 0, FLAGS, "wfunc" },
132  { "bharris", "blackman-harris window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_BHARRIS }, 0, 0, FLAGS, "wfunc" },
133  { "tukey", "tukey window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_TUKEY }, 0, 0, FLAGS, "wfunc" },
134  { "fixed", "set fixed frame samples", OFFSET(fixed), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
135  { "multi", "set multi channels mode", OFFSET(multi), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
136  { "zero_phase", "set zero phase mode", OFFSET(zero_phase), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
137  { "scale", "set gain scale", OFFSET(scale), AV_OPT_TYPE_INT, { .i64 = SCALE_LINLOG }, 0, NB_SCALE-1, FLAGS, "scale" },
138  { "linlin", "linear-freq linear-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LINLIN }, 0, 0, FLAGS, "scale" },
139  { "linlog", "linear-freq logarithmic-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LINLOG }, 0, 0, FLAGS, "scale" },
140  { "loglin", "logarithmic-freq linear-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LOGLIN }, 0, 0, FLAGS, "scale" },
141  { "loglog", "logarithmic-freq logarithmic-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LOGLOG }, 0, 0, FLAGS, "scale" },
142  { "dumpfile", "set dump file", OFFSET(dumpfile), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },
143  { "dumpscale", "set dump scale", OFFSET(dumpscale), AV_OPT_TYPE_INT, { .i64 = SCALE_LINLOG }, 0, NB_SCALE-1, FLAGS, "scale" },
144  { "fft2", "set 2-channels fft", OFFSET(fft2), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
145  { "min_phase", "set minimum phase mode", OFFSET(min_phase), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
146  { NULL }
147 };
148 
149 AVFILTER_DEFINE_CLASS(firequalizer);
150 
152 {
153  av_rdft_end(s->analysis_rdft);
154  av_rdft_end(s->analysis_irdft);
155  av_rdft_end(s->rdft);
156  av_rdft_end(s->irdft);
157  av_fft_end(s->fft_ctx);
158  av_rdft_end(s->cepstrum_rdft);
159  av_rdft_end(s->cepstrum_irdft);
160  s->analysis_rdft = s->analysis_irdft = s->rdft = s->irdft = NULL;
161  s->fft_ctx = NULL;
162  s->cepstrum_rdft = NULL;
163  s->cepstrum_irdft = NULL;
164 
165  av_freep(&s->analysis_buf);
166  av_freep(&s->dump_buf);
167  av_freep(&s->kernel_tmp_buf);
168  av_freep(&s->kernel_buf);
169  av_freep(&s->cepstrum_buf);
170  av_freep(&s->conv_buf);
171  av_freep(&s->conv_idx);
172 }
173 
175 {
176  FIREqualizerContext *s = ctx->priv;
177 
178  common_uninit(s);
179  av_freep(&s->gain_cmd);
180  av_freep(&s->gain_entry_cmd);
181 }
182 
183 static void fast_convolute(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf, float *av_restrict conv_buf,
184  OverlapIndex *av_restrict idx, float *av_restrict data, int nsamples)
185 {
186  if (nsamples <= s->nsamples_max) {
187  float *buf = conv_buf + idx->buf_idx * s->rdft_len;
188  float *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx;
189  int center = s->fir_len/2;
190  int k;
191 
192  memset(buf, 0, center * sizeof(*data));
193  memcpy(buf + center, data, nsamples * sizeof(*data));
194  memset(buf + center + nsamples, 0, (s->rdft_len - nsamples - center) * sizeof(*data));
195  av_rdft_calc(s->rdft, buf);
196 
197  buf[0] *= kernel_buf[0];
198  buf[1] *= kernel_buf[s->rdft_len/2];
199  for (k = 1; k < s->rdft_len/2; k++) {
200  buf[2*k] *= kernel_buf[k];
201  buf[2*k+1] *= kernel_buf[k];
202  }
203 
204  av_rdft_calc(s->irdft, buf);
205  for (k = 0; k < s->rdft_len - idx->overlap_idx; k++)
206  buf[k] += obuf[k];
207  memcpy(data, buf, nsamples * sizeof(*data));
208  idx->buf_idx = !idx->buf_idx;
209  idx->overlap_idx = nsamples;
210  } else {
211  while (nsamples > s->nsamples_max * 2) {
212  fast_convolute(s, kernel_buf, conv_buf, idx, data, s->nsamples_max);
213  data += s->nsamples_max;
214  nsamples -= s->nsamples_max;
215  }
216  fast_convolute(s, kernel_buf, conv_buf, idx, data, nsamples/2);
217  fast_convolute(s, kernel_buf, conv_buf, idx, data + nsamples/2, nsamples - nsamples/2);
218  }
219 }
220 
221 static void fast_convolute_nonlinear(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf,
222  float *av_restrict conv_buf, OverlapIndex *av_restrict idx,
223  float *av_restrict data, int nsamples)
224 {
225  if (nsamples <= s->nsamples_max) {
226  float *buf = conv_buf + idx->buf_idx * s->rdft_len;
227  float *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx;
228  int k;
229 
230  memcpy(buf, data, nsamples * sizeof(*data));
231  memset(buf + nsamples, 0, (s->rdft_len - nsamples) * sizeof(*data));
232  av_rdft_calc(s->rdft, buf);
233 
234  buf[0] *= kernel_buf[0];
235  buf[1] *= kernel_buf[1];
236  for (k = 2; k < s->rdft_len; k += 2) {
237  float re, im;
238  re = buf[k] * kernel_buf[k] - buf[k+1] * kernel_buf[k+1];
239  im = buf[k] * kernel_buf[k+1] + buf[k+1] * kernel_buf[k];
240  buf[k] = re;
241  buf[k+1] = im;
242  }
243 
244  av_rdft_calc(s->irdft, buf);
245  for (k = 0; k < s->rdft_len - idx->overlap_idx; k++)
246  buf[k] += obuf[k];
247  memcpy(data, buf, nsamples * sizeof(*data));
248  idx->buf_idx = !idx->buf_idx;
249  idx->overlap_idx = nsamples;
250  } else {
251  while (nsamples > s->nsamples_max * 2) {
252  fast_convolute_nonlinear(s, kernel_buf, conv_buf, idx, data, s->nsamples_max);
253  data += s->nsamples_max;
254  nsamples -= s->nsamples_max;
255  }
256  fast_convolute_nonlinear(s, kernel_buf, conv_buf, idx, data, nsamples/2);
257  fast_convolute_nonlinear(s, kernel_buf, conv_buf, idx, data + nsamples/2, nsamples - nsamples/2);
258  }
259 }
260 
261 static void fast_convolute2(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf, FFTComplex *av_restrict conv_buf,
262  OverlapIndex *av_restrict idx, float *av_restrict data0, float *av_restrict data1, int nsamples)
263 {
264  if (nsamples <= s->nsamples_max) {
265  FFTComplex *buf = conv_buf + idx->buf_idx * s->rdft_len;
266  FFTComplex *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx;
267  int center = s->fir_len/2;
268  int k;
269  float tmp;
270 
271  memset(buf, 0, center * sizeof(*buf));
272  for (k = 0; k < nsamples; k++) {
273  buf[center+k].re = data0[k];
274  buf[center+k].im = data1[k];
275  }
276  memset(buf + center + nsamples, 0, (s->rdft_len - nsamples - center) * sizeof(*buf));
277  av_fft_permute(s->fft_ctx, buf);
278  av_fft_calc(s->fft_ctx, buf);
279 
280  /* swap re <-> im, do backward fft using forward fft_ctx */
281  /* normalize with 0.5f */
282  tmp = buf[0].re;
283  buf[0].re = 0.5f * kernel_buf[0] * buf[0].im;
284  buf[0].im = 0.5f * kernel_buf[0] * tmp;
285  for (k = 1; k < s->rdft_len/2; k++) {
286  int m = s->rdft_len - k;
287  tmp = buf[k].re;
288  buf[k].re = 0.5f * kernel_buf[k] * buf[k].im;
289  buf[k].im = 0.5f * kernel_buf[k] * tmp;
290  tmp = buf[m].re;
291  buf[m].re = 0.5f * kernel_buf[k] * buf[m].im;
292  buf[m].im = 0.5f * kernel_buf[k] * tmp;
293  }
294  tmp = buf[k].re;
295  buf[k].re = 0.5f * kernel_buf[k] * buf[k].im;
296  buf[k].im = 0.5f * kernel_buf[k] * tmp;
297 
298  av_fft_permute(s->fft_ctx, buf);
299  av_fft_calc(s->fft_ctx, buf);
300 
301  for (k = 0; k < s->rdft_len - idx->overlap_idx; k++) {
302  buf[k].re += obuf[k].re;
303  buf[k].im += obuf[k].im;
304  }
305 
306  /* swapped re <-> im */
307  for (k = 0; k < nsamples; k++) {
308  data0[k] = buf[k].im;
309  data1[k] = buf[k].re;
310  }
311  idx->buf_idx = !idx->buf_idx;
312  idx->overlap_idx = nsamples;
313  } else {
314  while (nsamples > s->nsamples_max * 2) {
315  fast_convolute2(s, kernel_buf, conv_buf, idx, data0, data1, s->nsamples_max);
316  data0 += s->nsamples_max;
317  data1 += s->nsamples_max;
318  nsamples -= s->nsamples_max;
319  }
320  fast_convolute2(s, kernel_buf, conv_buf, idx, data0, data1, nsamples/2);
321  fast_convolute2(s, kernel_buf, conv_buf, idx, data0 + nsamples/2, data1 + nsamples/2, nsamples - nsamples/2);
322  }
323 }
324 
325 static void dump_fir(AVFilterContext *ctx, FILE *fp, int ch)
326 {
327  FIREqualizerContext *s = ctx->priv;
328  int rate = ctx->inputs[0]->sample_rate;
329  int xlog = s->dumpscale == SCALE_LOGLIN || s->dumpscale == SCALE_LOGLOG;
330  int ylog = s->dumpscale == SCALE_LINLOG || s->dumpscale == SCALE_LOGLOG;
331  int x;
332  int center = s->fir_len / 2;
333  double delay = s->zero_phase ? 0.0 : (double) center / rate;
334  double vx, ya, yb;
335 
336  if (!s->min_phase) {
337  s->analysis_buf[0] *= s->rdft_len/2;
338  for (x = 1; x <= center; x++) {
339  s->analysis_buf[x] *= s->rdft_len/2;
340  s->analysis_buf[s->analysis_rdft_len - x] *= s->rdft_len/2;
341  }
342  } else {
343  for (x = 0; x < s->fir_len; x++)
344  s->analysis_buf[x] *= s->rdft_len/2;
345  }
346 
347  if (ch)
348  fprintf(fp, "\n\n");
349 
350  fprintf(fp, "# time[%d] (time amplitude)\n", ch);
351 
352  if (!s->min_phase) {
353  for (x = center; x > 0; x--)
354  fprintf(fp, "%15.10f %15.10f\n", delay - (double) x / rate, (double) s->analysis_buf[s->analysis_rdft_len - x]);
355 
356  for (x = 0; x <= center; x++)
357  fprintf(fp, "%15.10f %15.10f\n", delay + (double)x / rate , (double) s->analysis_buf[x]);
358  } else {
359  for (x = 0; x < s->fir_len; x++)
360  fprintf(fp, "%15.10f %15.10f\n", (double)x / rate, (double) s->analysis_buf[x]);
361  }
362 
363  av_rdft_calc(s->analysis_rdft, s->analysis_buf);
364 
365  fprintf(fp, "\n\n# freq[%d] (frequency desired_gain actual_gain)\n", ch);
366 
367  for (x = 0; x <= s->analysis_rdft_len/2; x++) {
368  int i = (x == s->analysis_rdft_len/2) ? 1 : 2 * x;
369  vx = (double)x * rate / s->analysis_rdft_len;
370  if (xlog)
371  vx = log2(0.05*vx);
372  ya = s->dump_buf[i];
373  yb = s->min_phase && (i > 1) ? hypotf(s->analysis_buf[i], s->analysis_buf[i+1]) : s->analysis_buf[i];
374  if (s->min_phase)
375  yb = fabs(yb);
376  if (ylog) {
377  ya = 20.0 * log10(fabs(ya));
378  yb = 20.0 * log10(fabs(yb));
379  }
380  fprintf(fp, "%17.10f %17.10f %17.10f\n", vx, ya, yb);
381  }
382 }
383 
384 static double entry_func(void *p, double freq, double gain)
385 {
386  AVFilterContext *ctx = p;
387  FIREqualizerContext *s = ctx->priv;
388 
389  if (s->nb_gain_entry >= NB_GAIN_ENTRY_MAX) {
390  av_log(ctx, AV_LOG_ERROR, "entry table overflow.\n");
391  s->gain_entry_err = AVERROR(EINVAL);
392  return 0;
393  }
394 
395  if (isnan(freq)) {
396  av_log(ctx, AV_LOG_ERROR, "nan frequency (%g, %g).\n", freq, gain);
397  s->gain_entry_err = AVERROR(EINVAL);
398  return 0;
399  }
400 
401  if (s->nb_gain_entry > 0 && freq <= s->gain_entry_tbl[s->nb_gain_entry - 1].freq) {
402  av_log(ctx, AV_LOG_ERROR, "unsorted frequency (%g, %g).\n", freq, gain);
403  s->gain_entry_err = AVERROR(EINVAL);
404  return 0;
405  }
406 
407  s->gain_entry_tbl[s->nb_gain_entry].freq = freq;
408  s->gain_entry_tbl[s->nb_gain_entry].gain = gain;
409  s->nb_gain_entry++;
410  return 0;
411 }
412 
413 static int gain_entry_compare(const void *key, const void *memb)
414 {
415  const double *freq = key;
416  const GainEntry *entry = memb;
417 
418  if (*freq < entry[0].freq)
419  return -1;
420  if (*freq > entry[1].freq)
421  return 1;
422  return 0;
423 }
424 
425 static double gain_interpolate_func(void *p, double freq)
426 {
427  AVFilterContext *ctx = p;
428  FIREqualizerContext *s = ctx->priv;
429  GainEntry *res;
430  double d0, d1, d;
431 
432  if (isnan(freq))
433  return freq;
434 
435  if (!s->nb_gain_entry)
436  return 0;
437 
438  if (freq <= s->gain_entry_tbl[0].freq)
439  return s->gain_entry_tbl[0].gain;
440 
441  if (freq >= s->gain_entry_tbl[s->nb_gain_entry-1].freq)
442  return s->gain_entry_tbl[s->nb_gain_entry-1].gain;
443 
444  res = bsearch(&freq, &s->gain_entry_tbl, s->nb_gain_entry - 1, sizeof(*res), gain_entry_compare);
445  av_assert0(res);
446 
447  d = res[1].freq - res[0].freq;
448  d0 = freq - res[0].freq;
449  d1 = res[1].freq - freq;
450 
451  if (d0 && d1)
452  return (d0 * res[1].gain + d1 * res[0].gain) / d;
453 
454  if (d0)
455  return res[1].gain;
456 
457  return res[0].gain;
458 }
459 
460 static double cubic_interpolate_func(void *p, double freq)
461 {
462  AVFilterContext *ctx = p;
463  FIREqualizerContext *s = ctx->priv;
464  GainEntry *res;
465  double x, x2, x3;
466  double a, b, c, d;
467  double m0, m1, m2, msum, unit;
468 
469  if (!s->nb_gain_entry)
470  return 0;
471 
472  if (freq <= s->gain_entry_tbl[0].freq)
473  return s->gain_entry_tbl[0].gain;
474 
475  if (freq >= s->gain_entry_tbl[s->nb_gain_entry-1].freq)
476  return s->gain_entry_tbl[s->nb_gain_entry-1].gain;
477 
478  res = bsearch(&freq, &s->gain_entry_tbl, s->nb_gain_entry - 1, sizeof(*res), gain_entry_compare);
479  av_assert0(res);
480 
481  unit = res[1].freq - res[0].freq;
482  m0 = res != s->gain_entry_tbl ?
483  unit * (res[0].gain - res[-1].gain) / (res[0].freq - res[-1].freq) : 0;
484  m1 = res[1].gain - res[0].gain;
485  m2 = res != s->gain_entry_tbl + s->nb_gain_entry - 2 ?
486  unit * (res[2].gain - res[1].gain) / (res[2].freq - res[1].freq) : 0;
487 
488  msum = fabs(m0) + fabs(m1);
489  m0 = msum > 0 ? (fabs(m0) * m1 + fabs(m1) * m0) / msum : 0;
490  msum = fabs(m1) + fabs(m2);
491  m1 = msum > 0 ? (fabs(m1) * m2 + fabs(m2) * m1) / msum : 0;
492 
493  d = res[0].gain;
494  c = m0;
495  b = 3 * res[1].gain - m1 - 2 * c - 3 * d;
496  a = res[1].gain - b - c - d;
497 
498  x = (freq - res[0].freq) / unit;
499  x2 = x * x;
500  x3 = x2 * x;
501 
502  return a * x3 + b * x2 + c * x + d;
503 }
504 
505 static const char *const var_names[] = {
506  "f",
507  "sr",
508  "ch",
509  "chid",
510  "chs",
511  "chlayout",
512  NULL
513 };
514 
515 enum VarOffset {
523 };
524 
525 static void generate_min_phase_kernel(FIREqualizerContext *s, float *rdft_buf)
526 {
527  int k, cepstrum_len = s->cepstrum_len, rdft_len = s->rdft_len;
528  double norm = 2.0 / cepstrum_len;
529  double minval = 1e-7 / rdft_len;
530 
531  memset(s->cepstrum_buf, 0, cepstrum_len * sizeof(*s->cepstrum_buf));
532  memcpy(s->cepstrum_buf, rdft_buf, rdft_len/2 * sizeof(*rdft_buf));
533  memcpy(s->cepstrum_buf + cepstrum_len - rdft_len/2, rdft_buf + rdft_len/2, rdft_len/2 * sizeof(*rdft_buf));
534 
535  av_rdft_calc(s->cepstrum_rdft, s->cepstrum_buf);
536 
537  s->cepstrum_buf[0] = log(FFMAX(s->cepstrum_buf[0], minval));
538  s->cepstrum_buf[1] = log(FFMAX(s->cepstrum_buf[1], minval));
539 
540  for (k = 2; k < cepstrum_len; k += 2) {
541  s->cepstrum_buf[k] = log(FFMAX(s->cepstrum_buf[k], minval));
542  s->cepstrum_buf[k+1] = 0;
543  }
544 
545  av_rdft_calc(s->cepstrum_irdft, s->cepstrum_buf);
546 
547  memset(s->cepstrum_buf + cepstrum_len/2 + 1, 0, (cepstrum_len/2 - 1) * sizeof(*s->cepstrum_buf));
548  for (k = 1; k < cepstrum_len/2; k++)
549  s->cepstrum_buf[k] *= 2;
550 
551  av_rdft_calc(s->cepstrum_rdft, s->cepstrum_buf);
552 
553  s->cepstrum_buf[0] = exp(s->cepstrum_buf[0] * norm) * norm;
554  s->cepstrum_buf[1] = exp(s->cepstrum_buf[1] * norm) * norm;
555  for (k = 2; k < cepstrum_len; k += 2) {
556  double mag = exp(s->cepstrum_buf[k] * norm) * norm;
557  double ph = s->cepstrum_buf[k+1] * norm;
558  s->cepstrum_buf[k] = mag * cos(ph);
559  s->cepstrum_buf[k+1] = mag * sin(ph);
560  }
561 
562  av_rdft_calc(s->cepstrum_irdft, s->cepstrum_buf);
563  memset(rdft_buf, 0, s->rdft_len * sizeof(*rdft_buf));
564  memcpy(rdft_buf, s->cepstrum_buf, s->fir_len * sizeof(*rdft_buf));
565 
566  if (s->dumpfile) {
567  memset(s->analysis_buf, 0, s->analysis_rdft_len * sizeof(*s->analysis_buf));
568  memcpy(s->analysis_buf, s->cepstrum_buf, s->fir_len * sizeof(*s->analysis_buf));
569  }
570 
571 }
572 
573 static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *gain_entry)
574 {
575  FIREqualizerContext *s = ctx->priv;
576  AVFilterLink *inlink = ctx->inputs[0];
577  const char *gain_entry_func_names[] = { "entry", NULL };
578  const char *gain_func_names[] = { "gain_interpolate", "cubic_interpolate", NULL };
579  double (*gain_entry_funcs[])(void *, double, double) = { entry_func, NULL };
580  double (*gain_funcs[])(void *, double) = { gain_interpolate_func, cubic_interpolate_func, NULL };
581  double vars[VAR_NB];
582  AVExpr *gain_expr;
583  int ret, k, center, ch;
584  int xlog = s->scale == SCALE_LOGLIN || s->scale == SCALE_LOGLOG;
585  int ylog = s->scale == SCALE_LINLOG || s->scale == SCALE_LOGLOG;
586  FILE *dump_fp = NULL;
587 
588  s->nb_gain_entry = 0;
589  s->gain_entry_err = 0;
590  if (gain_entry) {
591  double result = 0.0;
592  ret = av_expr_parse_and_eval(&result, gain_entry, NULL, NULL, NULL, NULL,
593  gain_entry_func_names, gain_entry_funcs, ctx, 0, ctx);
594  if (ret < 0)
595  return ret;
596  if (s->gain_entry_err < 0)
597  return s->gain_entry_err;
598  }
599 
600  av_log(ctx, AV_LOG_DEBUG, "nb_gain_entry = %d.\n", s->nb_gain_entry);
601 
602  ret = av_expr_parse(&gain_expr, gain, var_names,
603  gain_func_names, gain_funcs, NULL, NULL, 0, ctx);
604  if (ret < 0)
605  return ret;
606 
607  if (s->dumpfile && (!s->dump_buf || !s->analysis_rdft || !(dump_fp = fopen(s->dumpfile, "w"))))
608  av_log(ctx, AV_LOG_WARNING, "dumping failed.\n");
609 
610  vars[VAR_CHS] = inlink->channels;
611  vars[VAR_CHLAYOUT] = inlink->channel_layout;
612  vars[VAR_SR] = inlink->sample_rate;
613  for (ch = 0; ch < inlink->channels; ch++) {
614  float *rdft_buf = s->kernel_tmp_buf + ch * s->rdft_len;
615  double result;
616  vars[VAR_CH] = ch;
617  vars[VAR_CHID] = av_channel_layout_extract_channel(inlink->channel_layout, ch);
618  vars[VAR_F] = 0.0;
619  if (xlog)
620  vars[VAR_F] = log2(0.05 * vars[VAR_F]);
621  result = av_expr_eval(gain_expr, vars, ctx);
622  s->analysis_buf[0] = ylog ? pow(10.0, 0.05 * result) : result;
623 
624  vars[VAR_F] = 0.5 * inlink->sample_rate;
625  if (xlog)
626  vars[VAR_F] = log2(0.05 * vars[VAR_F]);
627  result = av_expr_eval(gain_expr, vars, ctx);
628  s->analysis_buf[1] = ylog ? pow(10.0, 0.05 * result) : result;
629 
630  for (k = 1; k < s->analysis_rdft_len/2; k++) {
631  vars[VAR_F] = k * ((double)inlink->sample_rate /(double)s->analysis_rdft_len);
632  if (xlog)
633  vars[VAR_F] = log2(0.05 * vars[VAR_F]);
634  result = av_expr_eval(gain_expr, vars, ctx);
635  s->analysis_buf[2*k] = ylog ? pow(10.0, 0.05 * result) : s->min_phase ? fabs(result) : result;
636  s->analysis_buf[2*k+1] = 0.0;
637  }
638 
639  if (s->dump_buf)
640  memcpy(s->dump_buf, s->analysis_buf, s->analysis_rdft_len * sizeof(*s->analysis_buf));
641 
642  av_rdft_calc(s->analysis_irdft, s->analysis_buf);
643  center = s->fir_len / 2;
644 
645  for (k = 0; k <= center; k++) {
646  double u = k * (M_PI/center);
647  double win;
648  switch (s->wfunc) {
649  case WFUNC_RECTANGULAR:
650  win = 1.0;
651  break;
652  case WFUNC_HANN:
653  win = 0.5 + 0.5 * cos(u);
654  break;
655  case WFUNC_HAMMING:
656  win = 0.53836 + 0.46164 * cos(u);
657  break;
658  case WFUNC_BLACKMAN:
659  win = 0.42 + 0.5 * cos(u) + 0.08 * cos(2*u);
660  break;
661  case WFUNC_NUTTALL3:
662  win = 0.40897 + 0.5 * cos(u) + 0.09103 * cos(2*u);
663  break;
664  case WFUNC_MNUTTALL3:
665  win = 0.4243801 + 0.4973406 * cos(u) + 0.0782793 * cos(2*u);
666  break;
667  case WFUNC_NUTTALL:
668  win = 0.355768 + 0.487396 * cos(u) + 0.144232 * cos(2*u) + 0.012604 * cos(3*u);
669  break;
670  case WFUNC_BNUTTALL:
671  win = 0.3635819 + 0.4891775 * cos(u) + 0.1365995 * cos(2*u) + 0.0106411 * cos(3*u);
672  break;
673  case WFUNC_BHARRIS:
674  win = 0.35875 + 0.48829 * cos(u) + 0.14128 * cos(2*u) + 0.01168 * cos(3*u);
675  break;
676  case WFUNC_TUKEY:
677  win = (u <= 0.5 * M_PI) ? 1.0 : (0.5 + 0.5 * cos(2*u - M_PI));
678  break;
679  default:
680  av_assert0(0);
681  }
682  s->analysis_buf[k] *= (2.0/s->analysis_rdft_len) * (2.0/s->rdft_len) * win;
683  if (k)
684  s->analysis_buf[s->analysis_rdft_len - k] = s->analysis_buf[k];
685  }
686 
687  memset(s->analysis_buf + center + 1, 0, (s->analysis_rdft_len - s->fir_len) * sizeof(*s->analysis_buf));
688  memcpy(rdft_buf, s->analysis_buf, s->rdft_len/2 * sizeof(*s->analysis_buf));
689  memcpy(rdft_buf + s->rdft_len/2, s->analysis_buf + s->analysis_rdft_len - s->rdft_len/2, s->rdft_len/2 * sizeof(*s->analysis_buf));
690  if (s->min_phase)
691  generate_min_phase_kernel(s, rdft_buf);
692  av_rdft_calc(s->rdft, rdft_buf);
693 
694  for (k = 0; k < s->rdft_len; k++) {
695  if (isnan(rdft_buf[k]) || isinf(rdft_buf[k])) {
696  av_log(ctx, AV_LOG_ERROR, "filter kernel contains nan or infinity.\n");
697  av_expr_free(gain_expr);
698  if (dump_fp)
699  fclose(dump_fp);
700  return AVERROR(EINVAL);
701  }
702  }
703 
704  if (!s->min_phase) {
705  rdft_buf[s->rdft_len-1] = rdft_buf[1];
706  for (k = 0; k < s->rdft_len/2; k++)
707  rdft_buf[k] = rdft_buf[2*k];
708  rdft_buf[s->rdft_len/2] = rdft_buf[s->rdft_len-1];
709  }
710 
711  if (dump_fp)
712  dump_fir(ctx, dump_fp, ch);
713 
714  if (!s->multi)
715  break;
716  }
717 
718  memcpy(s->kernel_buf, s->kernel_tmp_buf, (s->multi ? inlink->channels : 1) * s->rdft_len * sizeof(*s->kernel_buf));
719  av_expr_free(gain_expr);
720  if (dump_fp)
721  fclose(dump_fp);
722  return 0;
723 }
724 
725 #define SELECT_GAIN(s) (s->gain_cmd ? s->gain_cmd : s->gain)
726 #define SELECT_GAIN_ENTRY(s) (s->gain_entry_cmd ? s->gain_entry_cmd : s->gain_entry)
727 
729 {
730  AVFilterContext *ctx = inlink->dst;
731  FIREqualizerContext *s = ctx->priv;
732  int rdft_bits;
733 
734  common_uninit(s);
735 
736  s->next_pts = 0;
737  s->frame_nsamples_max = 0;
738 
739  s->fir_len = FFMAX(2 * (int)(inlink->sample_rate * s->delay) + 1, 3);
740  s->remaining = s->fir_len - 1;
741 
742  for (rdft_bits = RDFT_BITS_MIN; rdft_bits <= RDFT_BITS_MAX; rdft_bits++) {
743  s->rdft_len = 1 << rdft_bits;
744  s->nsamples_max = s->rdft_len - s->fir_len + 1;
745  if (s->nsamples_max * 2 >= s->fir_len)
746  break;
747  }
748 
749  if (rdft_bits > RDFT_BITS_MAX) {
750  av_log(ctx, AV_LOG_ERROR, "too large delay, please decrease it.\n");
751  return AVERROR(EINVAL);
752  }
753 
754  if (!(s->rdft = av_rdft_init(rdft_bits, DFT_R2C)) || !(s->irdft = av_rdft_init(rdft_bits, IDFT_C2R)))
755  return AVERROR(ENOMEM);
756 
757  if (s->fft2 && !s->multi && inlink->channels > 1 && !(s->fft_ctx = av_fft_init(rdft_bits, 0)))
758  return AVERROR(ENOMEM);
759 
760  if (s->min_phase) {
761  int cepstrum_bits = rdft_bits + 2;
762  if (cepstrum_bits > RDFT_BITS_MAX) {
763  av_log(ctx, AV_LOG_ERROR, "too large delay, please decrease it.\n");
764  return AVERROR(EINVAL);
765  }
766 
767  cepstrum_bits = FFMIN(RDFT_BITS_MAX, cepstrum_bits + 1);
768  s->cepstrum_rdft = av_rdft_init(cepstrum_bits, DFT_R2C);
769  s->cepstrum_irdft = av_rdft_init(cepstrum_bits, IDFT_C2R);
770  if (!s->cepstrum_rdft || !s->cepstrum_irdft)
771  return AVERROR(ENOMEM);
772 
773  s->cepstrum_len = 1 << cepstrum_bits;
774  s->cepstrum_buf = av_malloc_array(s->cepstrum_len, sizeof(*s->cepstrum_buf));
775  if (!s->cepstrum_buf)
776  return AVERROR(ENOMEM);
777  }
778 
779  for ( ; rdft_bits <= RDFT_BITS_MAX; rdft_bits++) {
780  s->analysis_rdft_len = 1 << rdft_bits;
781  if (inlink->sample_rate <= s->accuracy * s->analysis_rdft_len)
782  break;
783  }
784 
785  if (rdft_bits > RDFT_BITS_MAX) {
786  av_log(ctx, AV_LOG_ERROR, "too small accuracy, please increase it.\n");
787  return AVERROR(EINVAL);
788  }
789 
790  if (!(s->analysis_irdft = av_rdft_init(rdft_bits, IDFT_C2R)))
791  return AVERROR(ENOMEM);
792 
793  if (s->dumpfile) {
794  s->analysis_rdft = av_rdft_init(rdft_bits, DFT_R2C);
795  s->dump_buf = av_malloc_array(s->analysis_rdft_len, sizeof(*s->dump_buf));
796  }
797 
798  s->analysis_buf = av_malloc_array(s->analysis_rdft_len, sizeof(*s->analysis_buf));
799  s->kernel_tmp_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->channels : 1), sizeof(*s->kernel_tmp_buf));
800  s->kernel_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->channels : 1), sizeof(*s->kernel_buf));
801  s->conv_buf = av_calloc(2 * s->rdft_len * inlink->channels, sizeof(*s->conv_buf));
802  s->conv_idx = av_calloc(inlink->channels, sizeof(*s->conv_idx));
803  if (!s->analysis_buf || !s->kernel_tmp_buf || !s->kernel_buf || !s->conv_buf || !s->conv_idx)
804  return AVERROR(ENOMEM);
805 
806  av_log(ctx, AV_LOG_DEBUG, "sample_rate = %d, channels = %d, analysis_rdft_len = %d, rdft_len = %d, fir_len = %d, nsamples_max = %d.\n",
807  inlink->sample_rate, inlink->channels, s->analysis_rdft_len, s->rdft_len, s->fir_len, s->nsamples_max);
808 
809  if (s->fixed)
810  inlink->min_samples = inlink->max_samples = s->nsamples_max;
811 
813 }
814 
816 {
817  AVFilterContext *ctx = inlink->dst;
818  FIREqualizerContext *s = ctx->priv;
819  int ch;
820 
821  if (!s->min_phase) {
822  for (ch = 0; ch + 1 < inlink->channels && s->fft_ctx; ch += 2) {
823  fast_convolute2(s, s->kernel_buf, (FFTComplex *)(s->conv_buf + 2 * ch * s->rdft_len),
824  s->conv_idx + ch, (float *) frame->extended_data[ch],
825  (float *) frame->extended_data[ch+1], frame->nb_samples);
826  }
827 
828  for ( ; ch < inlink->channels; ch++) {
829  fast_convolute(s, s->kernel_buf + (s->multi ? ch * s->rdft_len : 0),
830  s->conv_buf + 2 * ch * s->rdft_len, s->conv_idx + ch,
831  (float *) frame->extended_data[ch], frame->nb_samples);
832  }
833  } else {
834  for (ch = 0; ch < inlink->channels; ch++) {
835  fast_convolute_nonlinear(s, s->kernel_buf + (s->multi ? ch * s->rdft_len : 0),
836  s->conv_buf + 2 * ch * s->rdft_len, s->conv_idx + ch,
837  (float *) frame->extended_data[ch], frame->nb_samples);
838  }
839  }
840 
841  s->next_pts = AV_NOPTS_VALUE;
842  if (frame->pts != AV_NOPTS_VALUE) {
843  s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, av_make_q(1, inlink->sample_rate), inlink->time_base);
844  if (s->zero_phase && !s->min_phase)
845  frame->pts -= av_rescale_q(s->fir_len/2, av_make_q(1, inlink->sample_rate), inlink->time_base);
846  }
847  s->frame_nsamples_max = FFMAX(s->frame_nsamples_max, frame->nb_samples);
848  return ff_filter_frame(ctx->outputs[0], frame);
849 }
850 
851 static int request_frame(AVFilterLink *outlink)
852 {
853  AVFilterContext *ctx = outlink->src;
854  FIREqualizerContext *s= ctx->priv;
855  int ret;
856 
857  ret = ff_request_frame(ctx->inputs[0]);
858  if (ret == AVERROR_EOF && s->remaining > 0 && s->frame_nsamples_max > 0) {
859  AVFrame *frame = ff_get_audio_buffer(outlink, FFMIN(s->remaining, s->frame_nsamples_max));
860 
861  if (!frame)
862  return AVERROR(ENOMEM);
863 
864  av_samples_set_silence(frame->extended_data, 0, frame->nb_samples, outlink->channels, frame->format);
865  frame->pts = s->next_pts;
866  s->remaining -= frame->nb_samples;
867  ret = filter_frame(ctx->inputs[0], frame);
868  }
869 
870  return ret;
871 }
872 
873 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
874  char *res, int res_len, int flags)
875 {
876  FIREqualizerContext *s = ctx->priv;
877  int ret = AVERROR(ENOSYS);
878 
879  if (!strcmp(cmd, "gain")) {
880  char *gain_cmd;
881 
882  if (SELECT_GAIN(s) && !strcmp(SELECT_GAIN(s), args)) {
883  av_log(ctx, AV_LOG_DEBUG, "equal gain, do not rebuild.\n");
884  return 0;
885  }
886 
887  gain_cmd = av_strdup(args);
888  if (!gain_cmd)
889  return AVERROR(ENOMEM);
890 
891  ret = generate_kernel(ctx, gain_cmd, SELECT_GAIN_ENTRY(s));
892  if (ret >= 0) {
893  av_freep(&s->gain_cmd);
894  s->gain_cmd = gain_cmd;
895  } else {
896  av_freep(&gain_cmd);
897  }
898  } else if (!strcmp(cmd, "gain_entry")) {
899  char *gain_entry_cmd;
900 
901  if (SELECT_GAIN_ENTRY(s) && !strcmp(SELECT_GAIN_ENTRY(s), args)) {
902  av_log(ctx, AV_LOG_DEBUG, "equal gain_entry, do not rebuild.\n");
903  return 0;
904  }
905 
906  gain_entry_cmd = av_strdup(args);
907  if (!gain_entry_cmd)
908  return AVERROR(ENOMEM);
909 
910  ret = generate_kernel(ctx, SELECT_GAIN(s), gain_entry_cmd);
911  if (ret >= 0) {
912  av_freep(&s->gain_entry_cmd);
913  s->gain_entry_cmd = gain_entry_cmd;
914  } else {
915  av_freep(&gain_entry_cmd);
916  }
917  }
918 
919  return ret;
920 }
921 
923  {
924  .name = "default",
926  .config_props = config_input,
927  .filter_frame = filter_frame,
928  .type = AVMEDIA_TYPE_AUDIO,
929  },
930 };
931 
933  {
934  .name = "default",
935  .request_frame = request_frame,
936  .type = AVMEDIA_TYPE_AUDIO,
937  },
938 };
939 
941  .name = "firequalizer",
942  .description = NULL_IF_CONFIG_SMALL("Finite Impulse Response Equalizer."),
943  .uninit = uninit,
944  .process_command = process_command,
945  .priv_size = sizeof(FIREqualizerContext),
949  .priv_class = &firequalizer_class,
950 };
FIREqualizerContext::cepstrum_len
int cepstrum_len
Definition: af_firequalizer.c:78
av_fft_end
av_cold void av_fft_end(FFTContext *s)
Definition: avfft.c:48
ff_get_audio_buffer
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition: audio.c:88
AV_SAMPLE_FMT_FLTP
@ AV_SAMPLE_FMT_FLTP
float, planar
Definition: samplefmt.h:69
GainEntry::freq
double freq
Definition: af_firequalizer.c:57
FIREqualizerContext::gain_cmd
char * gain_cmd
Definition: af_firequalizer.c:93
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
generate_kernel
static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *gain_entry)
Definition: af_firequalizer.c:573
u
#define u(width, name, range_min, range_max)
Definition: cbs_h2645.c:264
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1018
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
fft2
static void fft2(FFTComplex *z)
Definition: tx_template.c:505
FILTER_SINGLE_SAMPLEFMT
#define FILTER_SINGLE_SAMPLEFMT(sample_fmt_)
Definition: internal.h:184
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
gain_interpolate_func
static double gain_interpolate_func(void *p, double freq)
Definition: af_firequalizer.c:425
FIREqualizerContext::analysis_irdft
RDFTContext * analysis_irdft
Definition: af_firequalizer.c:70
im
float im
Definition: fft.c:78
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:317
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:26
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: af_firequalizer.c:815
AVOption
AVOption.
Definition: opt.h:247
b
#define b
Definition: input.c:40
FIREqualizerContext::frame_nsamples_max
int frame_nsamples_max
Definition: af_firequalizer.c:90
data
const char data[16]
Definition: mxf.c:143
OverlapIndex::buf_idx
int buf_idx
Definition: af_firequalizer.c:62
ff_request_frame
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition: avfilter.c:420
av_fft_permute
void av_fft_permute(FFTContext *s, FFTComplex *z)
Do the permutation needed BEFORE calling ff_fft_calc().
Definition: avfft.c:38
FIREqualizerContext::rdft_len
int rdft_len
Definition: af_firequalizer.c:77
VarOffset
VarOffset
Definition: af_firequalizer.c:515
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:169
SCALE_LOGLOG
@ SCALE_LOGLOG
Definition: af_firequalizer.c:51
FIREqualizerContext::wfunc
int wfunc
Definition: af_firequalizer.c:99
FIREqualizerContext::cepstrum_irdft
RDFTContext * cepstrum_irdft
Definition: af_firequalizer.c:75
SELECT_GAIN_ENTRY
#define SELECT_GAIN_ENTRY(s)
Definition: af_firequalizer.c:726
FIREqualizerContext::nb_gain_entry
int nb_gain_entry
Definition: af_firequalizer.c:109
FIREqualizerContext
Definition: af_firequalizer.c:66
WFUNC_RECTANGULAR
@ WFUNC_RECTANGULAR
Definition: af_firequalizer.c:34
win
static float win(SuperEqualizerContext *s, float n, int N)
Definition: af_superequalizer.c:119
av_expr_parse
int av_expr_parse(AVExpr **expr, const char *s, const char *const *const_names, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), int log_offset, void *log_ctx)
Parse an expression.
Definition: eval.c:685
NB_GAIN_ENTRY_MAX
#define NB_GAIN_ENTRY_MAX
Definition: af_firequalizer.c:55
VAR_CHLAYOUT
@ VAR_CHLAYOUT
Definition: af_firequalizer.c:521
WFUNC_BLACKMAN
@ WFUNC_BLACKMAN
Definition: af_firequalizer.c:37
generate_min_phase_kernel
static void generate_min_phase_kernel(FIREqualizerContext *s, float *rdft_buf)
Definition: af_firequalizer.c:525
firequalizer_outputs
static const AVFilterPad firequalizer_outputs[]
Definition: af_firequalizer.c:932
ff_af_firequalizer
const AVFilter ff_af_firequalizer
Definition: af_firequalizer.c:940
firequalizer_inputs
static const AVFilterPad firequalizer_inputs[]
Definition: af_firequalizer.c:922
WindowFunc
WindowFunc
Definition: af_firequalizer.c:33
VAR_SR
@ VAR_SR
Definition: af_firequalizer.c:517
GainEntry::gain
double gain
Definition: af_firequalizer.c:58
RDFT_BITS_MAX
#define RDFT_BITS_MAX
Definition: af_firequalizer.c:31
request_frame
static int request_frame(AVFilterLink *outlink)
Definition: af_firequalizer.c:851
IDFT_C2R
@ IDFT_C2R
Definition: avfft.h:73
FIREqualizerContext::conv_idx
OverlapIndex * conv_idx
Definition: af_firequalizer.c:86
cubic_interpolate_func
static double cubic_interpolate_func(void *p, double freq)
Definition: af_firequalizer.c:460
scale
static av_always_inline float scale(float x, float s)
Definition: vf_v360.c:1388
av_expr_free
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:336
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:50
SELECT_GAIN
#define SELECT_GAIN(s)
Definition: af_firequalizer.c:725
avassert.h
FIREqualizerContext::scale
int scale
Definition: af_firequalizer.c:103
VAR_CHID
@ VAR_CHID
Definition: af_firequalizer.c:519
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
WFUNC_NUTTALL
@ WFUNC_NUTTALL
Definition: af_firequalizer.c:40
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: af_firequalizer.c:174
s
#define s(width, name)
Definition: cbs_vp9.c:257
AV_OPT_TYPE_DOUBLE
@ AV_OPT_TYPE_DOUBLE
Definition: opt.h:226
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
WFUNC_NUTTALL3
@ WFUNC_NUTTALL3
Definition: af_firequalizer.c:38
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
FIREqualizerContext::min_phase
int min_phase
Definition: af_firequalizer.c:107
ctx
AVFormatContext * ctx
Definition: movenc.c:48
av_expr_eval
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:766
WFUNC_BHARRIS
@ WFUNC_BHARRIS
Definition: af_firequalizer.c:42
OverlapIndex::overlap_idx
int overlap_idx
Definition: af_firequalizer.c:63
av_rescale_q
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:141
AVExpr
Definition: eval.c:157
key
const char * key
Definition: hwcontext_opencl.c:168
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:191
av_rdft_calc
void av_rdft_calc(RDFTContext *s, FFTSample *data)
if
if(ret)
Definition: filter_design.txt:179
SCALE_LINLIN
@ SCALE_LINLIN
Definition: af_firequalizer.c:48
FIREqualizerContext::analysis_rdft_len
int analysis_rdft_len
Definition: af_firequalizer.c:76
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
result
and forward the result(frame or status change) to the corresponding input. If nothing is possible
fabs
static __device__ float fabs(float a)
Definition: cuda_runtime.h:182
NULL
#define NULL
Definition: coverity.c:32
FIREqualizerContext::gain_entry_err
int gain_entry_err
Definition: af_firequalizer.c:110
vars
static const uint8_t vars[2][12]
Definition: camellia.c:179
FLAGS
#define FLAGS
Definition: af_firequalizer.c:115
WFUNC_HAMMING
@ WFUNC_HAMMING
Definition: af_firequalizer.c:36
isnan
#define isnan(x)
Definition: libm.h:340
FIREqualizerContext::fft_ctx
FFTContext * fft_ctx
Definition: af_firequalizer.c:73
GainEntry
Definition: af_firequalizer.c:56
FIREqualizerContext::zero_phase
int zero_phase
Definition: af_firequalizer.c:102
entry_func
static double entry_func(void *p, double freq, double gain)
Definition: af_firequalizer.c:384
FIREqualizerContext::gain
const char * gain
Definition: af_firequalizer.c:95
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(firequalizer)
isinf
#define isinf(x)
Definition: libm.h:317
DFT_R2C
@ DFT_R2C
Definition: avfft.h:72
avfft.h
OFFSET
#define OFFSET(x)
Definition: af_firequalizer.c:114
fp
#define fp
Definition: regdef.h:44
exp
int8_t exp
Definition: eval.c:72
var_names
static const char *const var_names[]
Definition: af_firequalizer.c:505
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
VAR_CHS
@ VAR_CHS
Definition: af_firequalizer.c:520
FIREqualizerContext::gain_entry_cmd
char * gain_entry_cmd
Definition: af_firequalizer.c:94
eval.h
RDFT_BITS_MIN
#define RDFT_BITS_MIN
Definition: af_firequalizer.c:30
TFLAGS
#define TFLAGS
Definition: af_firequalizer.c:116
av_rdft_init
RDFTContext * av_rdft_init(int nbits, enum RDFTransformType trans)
Set up a real FFT.
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
av_expr_parse_and_eval
int av_expr_parse_and_eval(double *d, const char *s, const char *const *const_names, const double *const_values, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), void *opaque, int log_offset, void *log_ctx)
Parse and evaluate an expression.
Definition: eval.c:776
FIREqualizerContext::analysis_buf
float * analysis_buf
Definition: af_firequalizer.c:80
fast_convolute2
static void fast_convolute2(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf, FFTComplex *av_restrict conv_buf, OverlapIndex *av_restrict idx, float *av_restrict data0, float *av_restrict data1, int nsamples)
Definition: af_firequalizer.c:261
av_make_q
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition: rational.h:71
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
WFUNC_TUKEY
@ WFUNC_TUKEY
Definition: af_firequalizer.c:43
FIREqualizerContext::fir_len
int fir_len
Definition: af_firequalizer.c:87
FFTComplex::im
FFTSample im
Definition: avfft.h:38
FFTComplex::re
FFTSample re
Definition: avfft.h:38
firequalizer_options
static const AVOption firequalizer_options[]
Definition: af_firequalizer.c:118
VAR_NB
@ VAR_NB
Definition: af_firequalizer.c:522
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
FIREqualizerContext::kernel_tmp_buf
float * kernel_tmp_buf
Definition: af_firequalizer.c:82
FIREqualizerContext::cepstrum_rdft
RDFTContext * cepstrum_rdft
Definition: af_firequalizer.c:74
M_PI
#define M_PI
Definition: mathematics.h:52
internal.h
FIREqualizerContext::cepstrum_buf
float * cepstrum_buf
Definition: af_firequalizer.c:84
FIREqualizerContext::remaining
int remaining
Definition: af_firequalizer.c:91
VAR_CH
@ VAR_CH
Definition: af_firequalizer.c:518
WFUNC_HANN
@ WFUNC_HANN
Definition: af_firequalizer.c:35
FFTContext
Definition: fft.h:75
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:271
av_channel_layout_extract_channel
uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index)
Get the channel with the given index in channel_layout.
Definition: channel_layout.c:271
FIREqualizerContext::conv_buf
float * conv_buf
Definition: af_firequalizer.c:85
SCALE_LINLOG
@ SCALE_LINLOG
Definition: af_firequalizer.c:49
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:32
RDFTContext
Definition: rdft.h:28
FIREqualizerContext::dump_buf
float * dump_buf
Definition: af_firequalizer.c:81
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
FIREqualizerContext::gain_entry_tbl
GainEntry gain_entry_tbl[NB_GAIN_ENTRY_MAX]
Definition: af_firequalizer.c:111
Scale
Scale
Definition: af_firequalizer.c:47
VAR_F
@ VAR_F
Definition: af_firequalizer.c:516
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:56
process_command
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: af_firequalizer.c:873
fast_convolute
static void fast_convolute(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf, float *av_restrict conv_buf, OverlapIndex *av_restrict idx, float *av_restrict data, int nsamples)
Definition: af_firequalizer.c:183
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:271
FIREqualizerContext::kernel_buf
float * kernel_buf
Definition: af_firequalizer.c:83
log2
#define log2(x)
Definition: libm.h:404
av_samples_set_silence
int av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples, int nb_channels, enum AVSampleFormat sample_fmt)
Fill an audio buffer with silence.
Definition: samplefmt.c:244
FIREqualizerContext::next_pts
int64_t next_pts
Definition: af_firequalizer.c:89
AVFilter
Filter definition.
Definition: avfilter.h:165
ret
ret
Definition: filter_design.txt:187
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
SCALE_LOGLIN
@ SCALE_LOGLIN
Definition: af_firequalizer.c:50
FIREqualizerContext::accuracy
double accuracy
Definition: af_firequalizer.c:98
av_fft_init
FFTContext * av_fft_init(int nbits, int inverse)
Set up a complex FFT.
Definition: avfft.c:28
NB_WFUNC
@ NB_WFUNC
Definition: af_firequalizer.c:44
channel_layout.h
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:224
avfilter.h
FIREqualizerContext::fixed
int fixed
Definition: af_firequalizer.c:100
FIREqualizerContext::dumpscale
int dumpscale
Definition: af_firequalizer.c:105
FIREqualizerContext::nsamples_max
int nsamples_max
Definition: af_firequalizer.c:88
AVFilterContext
An instance of a filter.
Definition: avfilter.h:402
FIREqualizerContext::rdft
RDFTContext * rdft
Definition: af_firequalizer.c:71
common_uninit
static void common_uninit(FIREqualizerContext *s)
Definition: af_firequalizer.c:151
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:279
WFUNC_BNUTTALL
@ WFUNC_BNUTTALL
Definition: af_firequalizer.c:41
audio.h
fast_convolute_nonlinear
static void fast_convolute_nonlinear(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf, float *av_restrict conv_buf, OverlapIndex *av_restrict idx, float *av_restrict data, int nsamples)
Definition: af_firequalizer.c:221
gain_entry_compare
static int gain_entry_compare(const void *key, const void *memb)
Definition: af_firequalizer.c:413
FIREqualizerContext::gain_entry
const char * gain_entry
Definition: af_firequalizer.c:96
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:241
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:192
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
FIREqualizerContext::analysis_rdft
RDFTContext * analysis_rdft
Definition: af_firequalizer.c:69
d
d
Definition: ffmpeg_filter.c:153
fixed
#define fixed(width, name, value)
Definition: cbs_av1.c:566
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
av_rdft_end
void av_rdft_end(RDFTContext *s)
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
FIREqualizerContext::fft2
int fft2
Definition: af_firequalizer.c:106
NB_SCALE
@ NB_SCALE
Definition: af_firequalizer.c:52
config_input
static int config_input(AVFilterLink *inlink)
Definition: af_firequalizer.c:728
OverlapIndex
Definition: af_firequalizer.c:61
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:228
FIREqualizerContext::delay
double delay
Definition: af_firequalizer.c:97
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:233
av_fft_calc
void av_fft_calc(FFTContext *s, FFTComplex *z)
Do a complex FFT with the parameters defined in av_fft_init().
Definition: avfft.c:43
dump_fir
static void dump_fir(AVFilterContext *ctx, FILE *fp, int ch)
Definition: af_firequalizer.c:325
FFTComplex
Definition: avfft.h:37
re
float re
Definition: fft.c:78
FIREqualizerContext::irdft
RDFTContext * irdft
Definition: af_firequalizer.c:72
FIREqualizerContext::multi
int multi
Definition: af_firequalizer.c:101
WFUNC_MNUTTALL3
@ WFUNC_MNUTTALL3
Definition: af_firequalizer.c:39
FIREqualizerContext::dumpfile
char * dumpfile
Definition: af_firequalizer.c:104
AVFILTERPAD_FLAG_NEEDS_WRITABLE
#define AVFILTERPAD_FLAG_NEEDS_WRITABLE
The filter expects writable frames from its input link, duplicating data buffers if needed.
Definition: internal.h:69