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 
184 {
185  static const enum AVSampleFormat sample_fmts[] = {
188  };
190  if (ret < 0)
191  return ret;
192 
194  if (ret < 0)
195  return ret;
196 
198 }
199 
200 static void fast_convolute(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf, float *av_restrict conv_buf,
201  OverlapIndex *av_restrict idx, float *av_restrict data, int nsamples)
202 {
203  if (nsamples <= s->nsamples_max) {
204  float *buf = conv_buf + idx->buf_idx * s->rdft_len;
205  float *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx;
206  int center = s->fir_len/2;
207  int k;
208 
209  memset(buf, 0, center * sizeof(*data));
210  memcpy(buf + center, data, nsamples * sizeof(*data));
211  memset(buf + center + nsamples, 0, (s->rdft_len - nsamples - center) * sizeof(*data));
212  av_rdft_calc(s->rdft, buf);
213 
214  buf[0] *= kernel_buf[0];
215  buf[1] *= kernel_buf[s->rdft_len/2];
216  for (k = 1; k < s->rdft_len/2; k++) {
217  buf[2*k] *= kernel_buf[k];
218  buf[2*k+1] *= kernel_buf[k];
219  }
220 
221  av_rdft_calc(s->irdft, buf);
222  for (k = 0; k < s->rdft_len - idx->overlap_idx; k++)
223  buf[k] += obuf[k];
224  memcpy(data, buf, nsamples * sizeof(*data));
225  idx->buf_idx = !idx->buf_idx;
226  idx->overlap_idx = nsamples;
227  } else {
228  while (nsamples > s->nsamples_max * 2) {
229  fast_convolute(s, kernel_buf, conv_buf, idx, data, s->nsamples_max);
230  data += s->nsamples_max;
231  nsamples -= s->nsamples_max;
232  }
233  fast_convolute(s, kernel_buf, conv_buf, idx, data, nsamples/2);
234  fast_convolute(s, kernel_buf, conv_buf, idx, data + nsamples/2, nsamples - nsamples/2);
235  }
236 }
237 
238 static void fast_convolute_nonlinear(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf,
239  float *av_restrict conv_buf, OverlapIndex *av_restrict idx,
240  float *av_restrict data, int nsamples)
241 {
242  if (nsamples <= s->nsamples_max) {
243  float *buf = conv_buf + idx->buf_idx * s->rdft_len;
244  float *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx;
245  int k;
246 
247  memcpy(buf, data, nsamples * sizeof(*data));
248  memset(buf + nsamples, 0, (s->rdft_len - nsamples) * sizeof(*data));
249  av_rdft_calc(s->rdft, buf);
250 
251  buf[0] *= kernel_buf[0];
252  buf[1] *= kernel_buf[1];
253  for (k = 2; k < s->rdft_len; k += 2) {
254  float re, im;
255  re = buf[k] * kernel_buf[k] - buf[k+1] * kernel_buf[k+1];
256  im = buf[k] * kernel_buf[k+1] + buf[k+1] * kernel_buf[k];
257  buf[k] = re;
258  buf[k+1] = im;
259  }
260 
261  av_rdft_calc(s->irdft, buf);
262  for (k = 0; k < s->rdft_len - idx->overlap_idx; k++)
263  buf[k] += obuf[k];
264  memcpy(data, buf, nsamples * sizeof(*data));
265  idx->buf_idx = !idx->buf_idx;
266  idx->overlap_idx = nsamples;
267  } else {
268  while (nsamples > s->nsamples_max * 2) {
269  fast_convolute_nonlinear(s, kernel_buf, conv_buf, idx, data, s->nsamples_max);
270  data += s->nsamples_max;
271  nsamples -= s->nsamples_max;
272  }
273  fast_convolute_nonlinear(s, kernel_buf, conv_buf, idx, data, nsamples/2);
274  fast_convolute_nonlinear(s, kernel_buf, conv_buf, idx, data + nsamples/2, nsamples - nsamples/2);
275  }
276 }
277 
278 static void fast_convolute2(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf, FFTComplex *av_restrict conv_buf,
279  OverlapIndex *av_restrict idx, float *av_restrict data0, float *av_restrict data1, int nsamples)
280 {
281  if (nsamples <= s->nsamples_max) {
282  FFTComplex *buf = conv_buf + idx->buf_idx * s->rdft_len;
283  FFTComplex *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx;
284  int center = s->fir_len/2;
285  int k;
286  float tmp;
287 
288  memset(buf, 0, center * sizeof(*buf));
289  for (k = 0; k < nsamples; k++) {
290  buf[center+k].re = data0[k];
291  buf[center+k].im = data1[k];
292  }
293  memset(buf + center + nsamples, 0, (s->rdft_len - nsamples - center) * sizeof(*buf));
294  av_fft_permute(s->fft_ctx, buf);
295  av_fft_calc(s->fft_ctx, buf);
296 
297  /* swap re <-> im, do backward fft using forward fft_ctx */
298  /* normalize with 0.5f */
299  tmp = buf[0].re;
300  buf[0].re = 0.5f * kernel_buf[0] * buf[0].im;
301  buf[0].im = 0.5f * kernel_buf[0] * tmp;
302  for (k = 1; k < s->rdft_len/2; k++) {
303  int m = s->rdft_len - k;
304  tmp = buf[k].re;
305  buf[k].re = 0.5f * kernel_buf[k] * buf[k].im;
306  buf[k].im = 0.5f * kernel_buf[k] * tmp;
307  tmp = buf[m].re;
308  buf[m].re = 0.5f * kernel_buf[k] * buf[m].im;
309  buf[m].im = 0.5f * kernel_buf[k] * tmp;
310  }
311  tmp = buf[k].re;
312  buf[k].re = 0.5f * kernel_buf[k] * buf[k].im;
313  buf[k].im = 0.5f * kernel_buf[k] * tmp;
314 
315  av_fft_permute(s->fft_ctx, buf);
316  av_fft_calc(s->fft_ctx, buf);
317 
318  for (k = 0; k < s->rdft_len - idx->overlap_idx; k++) {
319  buf[k].re += obuf[k].re;
320  buf[k].im += obuf[k].im;
321  }
322 
323  /* swapped re <-> im */
324  for (k = 0; k < nsamples; k++) {
325  data0[k] = buf[k].im;
326  data1[k] = buf[k].re;
327  }
328  idx->buf_idx = !idx->buf_idx;
329  idx->overlap_idx = nsamples;
330  } else {
331  while (nsamples > s->nsamples_max * 2) {
332  fast_convolute2(s, kernel_buf, conv_buf, idx, data0, data1, s->nsamples_max);
333  data0 += s->nsamples_max;
334  data1 += s->nsamples_max;
335  nsamples -= s->nsamples_max;
336  }
337  fast_convolute2(s, kernel_buf, conv_buf, idx, data0, data1, nsamples/2);
338  fast_convolute2(s, kernel_buf, conv_buf, idx, data0 + nsamples/2, data1 + nsamples/2, nsamples - nsamples/2);
339  }
340 }
341 
342 static void dump_fir(AVFilterContext *ctx, FILE *fp, int ch)
343 {
344  FIREqualizerContext *s = ctx->priv;
345  int rate = ctx->inputs[0]->sample_rate;
346  int xlog = s->dumpscale == SCALE_LOGLIN || s->dumpscale == SCALE_LOGLOG;
347  int ylog = s->dumpscale == SCALE_LINLOG || s->dumpscale == SCALE_LOGLOG;
348  int x;
349  int center = s->fir_len / 2;
350  double delay = s->zero_phase ? 0.0 : (double) center / rate;
351  double vx, ya, yb;
352 
353  if (!s->min_phase) {
354  s->analysis_buf[0] *= s->rdft_len/2;
355  for (x = 1; x <= center; x++) {
356  s->analysis_buf[x] *= s->rdft_len/2;
357  s->analysis_buf[s->analysis_rdft_len - x] *= s->rdft_len/2;
358  }
359  } else {
360  for (x = 0; x < s->fir_len; x++)
361  s->analysis_buf[x] *= s->rdft_len/2;
362  }
363 
364  if (ch)
365  fprintf(fp, "\n\n");
366 
367  fprintf(fp, "# time[%d] (time amplitude)\n", ch);
368 
369  if (!s->min_phase) {
370  for (x = center; x > 0; x--)
371  fprintf(fp, "%15.10f %15.10f\n", delay - (double) x / rate, (double) s->analysis_buf[s->analysis_rdft_len - x]);
372 
373  for (x = 0; x <= center; x++)
374  fprintf(fp, "%15.10f %15.10f\n", delay + (double)x / rate , (double) s->analysis_buf[x]);
375  } else {
376  for (x = 0; x < s->fir_len; x++)
377  fprintf(fp, "%15.10f %15.10f\n", (double)x / rate, (double) s->analysis_buf[x]);
378  }
379 
380  av_rdft_calc(s->analysis_rdft, s->analysis_buf);
381 
382  fprintf(fp, "\n\n# freq[%d] (frequency desired_gain actual_gain)\n", ch);
383 
384  for (x = 0; x <= s->analysis_rdft_len/2; x++) {
385  int i = (x == s->analysis_rdft_len/2) ? 1 : 2 * x;
386  vx = (double)x * rate / s->analysis_rdft_len;
387  if (xlog)
388  vx = log2(0.05*vx);
389  ya = s->dump_buf[i];
390  yb = s->min_phase && (i > 1) ? hypotf(s->analysis_buf[i], s->analysis_buf[i+1]) : s->analysis_buf[i];
391  if (s->min_phase)
392  yb = fabs(yb);
393  if (ylog) {
394  ya = 20.0 * log10(fabs(ya));
395  yb = 20.0 * log10(fabs(yb));
396  }
397  fprintf(fp, "%17.10f %17.10f %17.10f\n", vx, ya, yb);
398  }
399 }
400 
401 static double entry_func(void *p, double freq, double gain)
402 {
403  AVFilterContext *ctx = p;
404  FIREqualizerContext *s = ctx->priv;
405 
406  if (s->nb_gain_entry >= NB_GAIN_ENTRY_MAX) {
407  av_log(ctx, AV_LOG_ERROR, "entry table overflow.\n");
408  s->gain_entry_err = AVERROR(EINVAL);
409  return 0;
410  }
411 
412  if (isnan(freq)) {
413  av_log(ctx, AV_LOG_ERROR, "nan frequency (%g, %g).\n", freq, gain);
414  s->gain_entry_err = AVERROR(EINVAL);
415  return 0;
416  }
417 
418  if (s->nb_gain_entry > 0 && freq <= s->gain_entry_tbl[s->nb_gain_entry - 1].freq) {
419  av_log(ctx, AV_LOG_ERROR, "unsorted frequency (%g, %g).\n", freq, gain);
420  s->gain_entry_err = AVERROR(EINVAL);
421  return 0;
422  }
423 
424  s->gain_entry_tbl[s->nb_gain_entry].freq = freq;
425  s->gain_entry_tbl[s->nb_gain_entry].gain = gain;
426  s->nb_gain_entry++;
427  return 0;
428 }
429 
430 static int gain_entry_compare(const void *key, const void *memb)
431 {
432  const double *freq = key;
433  const GainEntry *entry = memb;
434 
435  if (*freq < entry[0].freq)
436  return -1;
437  if (*freq > entry[1].freq)
438  return 1;
439  return 0;
440 }
441 
442 static double gain_interpolate_func(void *p, double freq)
443 {
444  AVFilterContext *ctx = p;
445  FIREqualizerContext *s = ctx->priv;
446  GainEntry *res;
447  double d0, d1, d;
448 
449  if (isnan(freq))
450  return freq;
451 
452  if (!s->nb_gain_entry)
453  return 0;
454 
455  if (freq <= s->gain_entry_tbl[0].freq)
456  return s->gain_entry_tbl[0].gain;
457 
458  if (freq >= s->gain_entry_tbl[s->nb_gain_entry-1].freq)
459  return s->gain_entry_tbl[s->nb_gain_entry-1].gain;
460 
461  res = bsearch(&freq, &s->gain_entry_tbl, s->nb_gain_entry - 1, sizeof(*res), gain_entry_compare);
462  av_assert0(res);
463 
464  d = res[1].freq - res[0].freq;
465  d0 = freq - res[0].freq;
466  d1 = res[1].freq - freq;
467 
468  if (d0 && d1)
469  return (d0 * res[1].gain + d1 * res[0].gain) / d;
470 
471  if (d0)
472  return res[1].gain;
473 
474  return res[0].gain;
475 }
476 
477 static double cubic_interpolate_func(void *p, double freq)
478 {
479  AVFilterContext *ctx = p;
480  FIREqualizerContext *s = ctx->priv;
481  GainEntry *res;
482  double x, x2, x3;
483  double a, b, c, d;
484  double m0, m1, m2, msum, unit;
485 
486  if (!s->nb_gain_entry)
487  return 0;
488 
489  if (freq <= s->gain_entry_tbl[0].freq)
490  return s->gain_entry_tbl[0].gain;
491 
492  if (freq >= s->gain_entry_tbl[s->nb_gain_entry-1].freq)
493  return s->gain_entry_tbl[s->nb_gain_entry-1].gain;
494 
495  res = bsearch(&freq, &s->gain_entry_tbl, s->nb_gain_entry - 1, sizeof(*res), gain_entry_compare);
496  av_assert0(res);
497 
498  unit = res[1].freq - res[0].freq;
499  m0 = res != s->gain_entry_tbl ?
500  unit * (res[0].gain - res[-1].gain) / (res[0].freq - res[-1].freq) : 0;
501  m1 = res[1].gain - res[0].gain;
502  m2 = res != s->gain_entry_tbl + s->nb_gain_entry - 2 ?
503  unit * (res[2].gain - res[1].gain) / (res[2].freq - res[1].freq) : 0;
504 
505  msum = fabs(m0) + fabs(m1);
506  m0 = msum > 0 ? (fabs(m0) * m1 + fabs(m1) * m0) / msum : 0;
507  msum = fabs(m1) + fabs(m2);
508  m1 = msum > 0 ? (fabs(m1) * m2 + fabs(m2) * m1) / msum : 0;
509 
510  d = res[0].gain;
511  c = m0;
512  b = 3 * res[1].gain - m1 - 2 * c - 3 * d;
513  a = res[1].gain - b - c - d;
514 
515  x = (freq - res[0].freq) / unit;
516  x2 = x * x;
517  x3 = x2 * x;
518 
519  return a * x3 + b * x2 + c * x + d;
520 }
521 
522 static const char *const var_names[] = {
523  "f",
524  "sr",
525  "ch",
526  "chid",
527  "chs",
528  "chlayout",
529  NULL
530 };
531 
532 enum VarOffset {
540 };
541 
542 static void generate_min_phase_kernel(FIREqualizerContext *s, float *rdft_buf)
543 {
544  int k, cepstrum_len = s->cepstrum_len, rdft_len = s->rdft_len;
545  double norm = 2.0 / cepstrum_len;
546  double minval = 1e-7 / rdft_len;
547 
548  memset(s->cepstrum_buf, 0, cepstrum_len * sizeof(*s->cepstrum_buf));
549  memcpy(s->cepstrum_buf, rdft_buf, rdft_len/2 * sizeof(*rdft_buf));
550  memcpy(s->cepstrum_buf + cepstrum_len - rdft_len/2, rdft_buf + rdft_len/2, rdft_len/2 * sizeof(*rdft_buf));
551 
552  av_rdft_calc(s->cepstrum_rdft, s->cepstrum_buf);
553 
554  s->cepstrum_buf[0] = log(FFMAX(s->cepstrum_buf[0], minval));
555  s->cepstrum_buf[1] = log(FFMAX(s->cepstrum_buf[1], minval));
556 
557  for (k = 2; k < cepstrum_len; k += 2) {
558  s->cepstrum_buf[k] = log(FFMAX(s->cepstrum_buf[k], minval));
559  s->cepstrum_buf[k+1] = 0;
560  }
561 
562  av_rdft_calc(s->cepstrum_irdft, s->cepstrum_buf);
563 
564  memset(s->cepstrum_buf + cepstrum_len/2 + 1, 0, (cepstrum_len/2 - 1) * sizeof(*s->cepstrum_buf));
565  for (k = 1; k < cepstrum_len/2; k++)
566  s->cepstrum_buf[k] *= 2;
567 
568  av_rdft_calc(s->cepstrum_rdft, s->cepstrum_buf);
569 
570  s->cepstrum_buf[0] = exp(s->cepstrum_buf[0] * norm) * norm;
571  s->cepstrum_buf[1] = exp(s->cepstrum_buf[1] * norm) * norm;
572  for (k = 2; k < cepstrum_len; k += 2) {
573  double mag = exp(s->cepstrum_buf[k] * norm) * norm;
574  double ph = s->cepstrum_buf[k+1] * norm;
575  s->cepstrum_buf[k] = mag * cos(ph);
576  s->cepstrum_buf[k+1] = mag * sin(ph);
577  }
578 
579  av_rdft_calc(s->cepstrum_irdft, s->cepstrum_buf);
580  memset(rdft_buf, 0, s->rdft_len * sizeof(*rdft_buf));
581  memcpy(rdft_buf, s->cepstrum_buf, s->fir_len * sizeof(*rdft_buf));
582 
583  if (s->dumpfile) {
584  memset(s->analysis_buf, 0, s->analysis_rdft_len * sizeof(*s->analysis_buf));
585  memcpy(s->analysis_buf, s->cepstrum_buf, s->fir_len * sizeof(*s->analysis_buf));
586  }
587 
588 }
589 
590 static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *gain_entry)
591 {
592  FIREqualizerContext *s = ctx->priv;
593  AVFilterLink *inlink = ctx->inputs[0];
594  const char *gain_entry_func_names[] = { "entry", NULL };
595  const char *gain_func_names[] = { "gain_interpolate", "cubic_interpolate", NULL };
596  double (*gain_entry_funcs[])(void *, double, double) = { entry_func, NULL };
597  double (*gain_funcs[])(void *, double) = { gain_interpolate_func, cubic_interpolate_func, NULL };
598  double vars[VAR_NB];
599  AVExpr *gain_expr;
600  int ret, k, center, ch;
601  int xlog = s->scale == SCALE_LOGLIN || s->scale == SCALE_LOGLOG;
602  int ylog = s->scale == SCALE_LINLOG || s->scale == SCALE_LOGLOG;
603  FILE *dump_fp = NULL;
604 
605  s->nb_gain_entry = 0;
606  s->gain_entry_err = 0;
607  if (gain_entry) {
608  double result = 0.0;
609  ret = av_expr_parse_and_eval(&result, gain_entry, NULL, NULL, NULL, NULL,
610  gain_entry_func_names, gain_entry_funcs, ctx, 0, ctx);
611  if (ret < 0)
612  return ret;
613  if (s->gain_entry_err < 0)
614  return s->gain_entry_err;
615  }
616 
617  av_log(ctx, AV_LOG_DEBUG, "nb_gain_entry = %d.\n", s->nb_gain_entry);
618 
619  ret = av_expr_parse(&gain_expr, gain, var_names,
620  gain_func_names, gain_funcs, NULL, NULL, 0, ctx);
621  if (ret < 0)
622  return ret;
623 
624  if (s->dumpfile && (!s->dump_buf || !s->analysis_rdft || !(dump_fp = fopen(s->dumpfile, "w"))))
625  av_log(ctx, AV_LOG_WARNING, "dumping failed.\n");
626 
627  vars[VAR_CHS] = inlink->channels;
628  vars[VAR_CHLAYOUT] = inlink->channel_layout;
629  vars[VAR_SR] = inlink->sample_rate;
630  for (ch = 0; ch < inlink->channels; ch++) {
631  float *rdft_buf = s->kernel_tmp_buf + ch * s->rdft_len;
632  double result;
633  vars[VAR_CH] = ch;
634  vars[VAR_CHID] = av_channel_layout_extract_channel(inlink->channel_layout, ch);
635  vars[VAR_F] = 0.0;
636  if (xlog)
637  vars[VAR_F] = log2(0.05 * vars[VAR_F]);
638  result = av_expr_eval(gain_expr, vars, ctx);
639  s->analysis_buf[0] = ylog ? pow(10.0, 0.05 * result) : result;
640 
641  vars[VAR_F] = 0.5 * inlink->sample_rate;
642  if (xlog)
643  vars[VAR_F] = log2(0.05 * vars[VAR_F]);
644  result = av_expr_eval(gain_expr, vars, ctx);
645  s->analysis_buf[1] = ylog ? pow(10.0, 0.05 * result) : result;
646 
647  for (k = 1; k < s->analysis_rdft_len/2; k++) {
648  vars[VAR_F] = k * ((double)inlink->sample_rate /(double)s->analysis_rdft_len);
649  if (xlog)
650  vars[VAR_F] = log2(0.05 * vars[VAR_F]);
651  result = av_expr_eval(gain_expr, vars, ctx);
652  s->analysis_buf[2*k] = ylog ? pow(10.0, 0.05 * result) : s->min_phase ? fabs(result) : result;
653  s->analysis_buf[2*k+1] = 0.0;
654  }
655 
656  if (s->dump_buf)
657  memcpy(s->dump_buf, s->analysis_buf, s->analysis_rdft_len * sizeof(*s->analysis_buf));
658 
659  av_rdft_calc(s->analysis_irdft, s->analysis_buf);
660  center = s->fir_len / 2;
661 
662  for (k = 0; k <= center; k++) {
663  double u = k * (M_PI/center);
664  double win;
665  switch (s->wfunc) {
666  case WFUNC_RECTANGULAR:
667  win = 1.0;
668  break;
669  case WFUNC_HANN:
670  win = 0.5 + 0.5 * cos(u);
671  break;
672  case WFUNC_HAMMING:
673  win = 0.53836 + 0.46164 * cos(u);
674  break;
675  case WFUNC_BLACKMAN:
676  win = 0.42 + 0.5 * cos(u) + 0.08 * cos(2*u);
677  break;
678  case WFUNC_NUTTALL3:
679  win = 0.40897 + 0.5 * cos(u) + 0.09103 * cos(2*u);
680  break;
681  case WFUNC_MNUTTALL3:
682  win = 0.4243801 + 0.4973406 * cos(u) + 0.0782793 * cos(2*u);
683  break;
684  case WFUNC_NUTTALL:
685  win = 0.355768 + 0.487396 * cos(u) + 0.144232 * cos(2*u) + 0.012604 * cos(3*u);
686  break;
687  case WFUNC_BNUTTALL:
688  win = 0.3635819 + 0.4891775 * cos(u) + 0.1365995 * cos(2*u) + 0.0106411 * cos(3*u);
689  break;
690  case WFUNC_BHARRIS:
691  win = 0.35875 + 0.48829 * cos(u) + 0.14128 * cos(2*u) + 0.01168 * cos(3*u);
692  break;
693  case WFUNC_TUKEY:
694  win = (u <= 0.5 * M_PI) ? 1.0 : (0.5 + 0.5 * cos(2*u - M_PI));
695  break;
696  default:
697  av_assert0(0);
698  }
699  s->analysis_buf[k] *= (2.0/s->analysis_rdft_len) * (2.0/s->rdft_len) * win;
700  if (k)
701  s->analysis_buf[s->analysis_rdft_len - k] = s->analysis_buf[k];
702  }
703 
704  memset(s->analysis_buf + center + 1, 0, (s->analysis_rdft_len - s->fir_len) * sizeof(*s->analysis_buf));
705  memcpy(rdft_buf, s->analysis_buf, s->rdft_len/2 * sizeof(*s->analysis_buf));
706  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));
707  if (s->min_phase)
708  generate_min_phase_kernel(s, rdft_buf);
709  av_rdft_calc(s->rdft, rdft_buf);
710 
711  for (k = 0; k < s->rdft_len; k++) {
712  if (isnan(rdft_buf[k]) || isinf(rdft_buf[k])) {
713  av_log(ctx, AV_LOG_ERROR, "filter kernel contains nan or infinity.\n");
714  av_expr_free(gain_expr);
715  if (dump_fp)
716  fclose(dump_fp);
717  return AVERROR(EINVAL);
718  }
719  }
720 
721  if (!s->min_phase) {
722  rdft_buf[s->rdft_len-1] = rdft_buf[1];
723  for (k = 0; k < s->rdft_len/2; k++)
724  rdft_buf[k] = rdft_buf[2*k];
725  rdft_buf[s->rdft_len/2] = rdft_buf[s->rdft_len-1];
726  }
727 
728  if (dump_fp)
729  dump_fir(ctx, dump_fp, ch);
730 
731  if (!s->multi)
732  break;
733  }
734 
735  memcpy(s->kernel_buf, s->kernel_tmp_buf, (s->multi ? inlink->channels : 1) * s->rdft_len * sizeof(*s->kernel_buf));
736  av_expr_free(gain_expr);
737  if (dump_fp)
738  fclose(dump_fp);
739  return 0;
740 }
741 
742 #define SELECT_GAIN(s) (s->gain_cmd ? s->gain_cmd : s->gain)
743 #define SELECT_GAIN_ENTRY(s) (s->gain_entry_cmd ? s->gain_entry_cmd : s->gain_entry)
744 
746 {
747  AVFilterContext *ctx = inlink->dst;
748  FIREqualizerContext *s = ctx->priv;
749  int rdft_bits;
750 
751  common_uninit(s);
752 
753  s->next_pts = 0;
754  s->frame_nsamples_max = 0;
755 
756  s->fir_len = FFMAX(2 * (int)(inlink->sample_rate * s->delay) + 1, 3);
757  s->remaining = s->fir_len - 1;
758 
759  for (rdft_bits = RDFT_BITS_MIN; rdft_bits <= RDFT_BITS_MAX; rdft_bits++) {
760  s->rdft_len = 1 << rdft_bits;
761  s->nsamples_max = s->rdft_len - s->fir_len + 1;
762  if (s->nsamples_max * 2 >= s->fir_len)
763  break;
764  }
765 
766  if (rdft_bits > RDFT_BITS_MAX) {
767  av_log(ctx, AV_LOG_ERROR, "too large delay, please decrease it.\n");
768  return AVERROR(EINVAL);
769  }
770 
771  if (!(s->rdft = av_rdft_init(rdft_bits, DFT_R2C)) || !(s->irdft = av_rdft_init(rdft_bits, IDFT_C2R)))
772  return AVERROR(ENOMEM);
773 
774  if (s->fft2 && !s->multi && inlink->channels > 1 && !(s->fft_ctx = av_fft_init(rdft_bits, 0)))
775  return AVERROR(ENOMEM);
776 
777  if (s->min_phase) {
778  int cepstrum_bits = rdft_bits + 2;
779  if (cepstrum_bits > RDFT_BITS_MAX) {
780  av_log(ctx, AV_LOG_ERROR, "too large delay, please decrease it.\n");
781  return AVERROR(EINVAL);
782  }
783 
784  cepstrum_bits = FFMIN(RDFT_BITS_MAX, cepstrum_bits + 1);
785  s->cepstrum_rdft = av_rdft_init(cepstrum_bits, DFT_R2C);
786  s->cepstrum_irdft = av_rdft_init(cepstrum_bits, IDFT_C2R);
787  if (!s->cepstrum_rdft || !s->cepstrum_irdft)
788  return AVERROR(ENOMEM);
789 
790  s->cepstrum_len = 1 << cepstrum_bits;
791  s->cepstrum_buf = av_malloc_array(s->cepstrum_len, sizeof(*s->cepstrum_buf));
792  if (!s->cepstrum_buf)
793  return AVERROR(ENOMEM);
794  }
795 
796  for ( ; rdft_bits <= RDFT_BITS_MAX; rdft_bits++) {
797  s->analysis_rdft_len = 1 << rdft_bits;
798  if (inlink->sample_rate <= s->accuracy * s->analysis_rdft_len)
799  break;
800  }
801 
802  if (rdft_bits > RDFT_BITS_MAX) {
803  av_log(ctx, AV_LOG_ERROR, "too small accuracy, please increase it.\n");
804  return AVERROR(EINVAL);
805  }
806 
807  if (!(s->analysis_irdft = av_rdft_init(rdft_bits, IDFT_C2R)))
808  return AVERROR(ENOMEM);
809 
810  if (s->dumpfile) {
811  s->analysis_rdft = av_rdft_init(rdft_bits, DFT_R2C);
812  s->dump_buf = av_malloc_array(s->analysis_rdft_len, sizeof(*s->dump_buf));
813  }
814 
815  s->analysis_buf = av_malloc_array(s->analysis_rdft_len, sizeof(*s->analysis_buf));
816  s->kernel_tmp_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->channels : 1), sizeof(*s->kernel_tmp_buf));
817  s->kernel_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->channels : 1), sizeof(*s->kernel_buf));
818  s->conv_buf = av_calloc(2 * s->rdft_len * inlink->channels, sizeof(*s->conv_buf));
819  s->conv_idx = av_calloc(inlink->channels, sizeof(*s->conv_idx));
820  if (!s->analysis_buf || !s->kernel_tmp_buf || !s->kernel_buf || !s->conv_buf || !s->conv_idx)
821  return AVERROR(ENOMEM);
822 
823  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",
824  inlink->sample_rate, inlink->channels, s->analysis_rdft_len, s->rdft_len, s->fir_len, s->nsamples_max);
825 
826  if (s->fixed)
827  inlink->min_samples = inlink->max_samples = s->nsamples_max;
828 
830 }
831 
833 {
834  AVFilterContext *ctx = inlink->dst;
835  FIREqualizerContext *s = ctx->priv;
836  int ch;
837 
838  if (!s->min_phase) {
839  for (ch = 0; ch + 1 < inlink->channels && s->fft_ctx; ch += 2) {
840  fast_convolute2(s, s->kernel_buf, (FFTComplex *)(s->conv_buf + 2 * ch * s->rdft_len),
841  s->conv_idx + ch, (float *) frame->extended_data[ch],
842  (float *) frame->extended_data[ch+1], frame->nb_samples);
843  }
844 
845  for ( ; ch < inlink->channels; ch++) {
846  fast_convolute(s, s->kernel_buf + (s->multi ? ch * s->rdft_len : 0),
847  s->conv_buf + 2 * ch * s->rdft_len, s->conv_idx + ch,
848  (float *) frame->extended_data[ch], frame->nb_samples);
849  }
850  } else {
851  for (ch = 0; ch < inlink->channels; ch++) {
852  fast_convolute_nonlinear(s, s->kernel_buf + (s->multi ? ch * s->rdft_len : 0),
853  s->conv_buf + 2 * ch * s->rdft_len, s->conv_idx + ch,
854  (float *) frame->extended_data[ch], frame->nb_samples);
855  }
856  }
857 
858  s->next_pts = AV_NOPTS_VALUE;
859  if (frame->pts != AV_NOPTS_VALUE) {
860  s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, av_make_q(1, inlink->sample_rate), inlink->time_base);
861  if (s->zero_phase && !s->min_phase)
862  frame->pts -= av_rescale_q(s->fir_len/2, av_make_q(1, inlink->sample_rate), inlink->time_base);
863  }
864  s->frame_nsamples_max = FFMAX(s->frame_nsamples_max, frame->nb_samples);
865  return ff_filter_frame(ctx->outputs[0], frame);
866 }
867 
868 static int request_frame(AVFilterLink *outlink)
869 {
870  AVFilterContext *ctx = outlink->src;
871  FIREqualizerContext *s= ctx->priv;
872  int ret;
873 
874  ret = ff_request_frame(ctx->inputs[0]);
875  if (ret == AVERROR_EOF && s->remaining > 0 && s->frame_nsamples_max > 0) {
876  AVFrame *frame = ff_get_audio_buffer(outlink, FFMIN(s->remaining, s->frame_nsamples_max));
877 
878  if (!frame)
879  return AVERROR(ENOMEM);
880 
881  av_samples_set_silence(frame->extended_data, 0, frame->nb_samples, outlink->channels, frame->format);
882  frame->pts = s->next_pts;
883  s->remaining -= frame->nb_samples;
884  ret = filter_frame(ctx->inputs[0], frame);
885  }
886 
887  return ret;
888 }
889 
890 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
891  char *res, int res_len, int flags)
892 {
893  FIREqualizerContext *s = ctx->priv;
894  int ret = AVERROR(ENOSYS);
895 
896  if (!strcmp(cmd, "gain")) {
897  char *gain_cmd;
898 
899  if (SELECT_GAIN(s) && !strcmp(SELECT_GAIN(s), args)) {
900  av_log(ctx, AV_LOG_DEBUG, "equal gain, do not rebuild.\n");
901  return 0;
902  }
903 
904  gain_cmd = av_strdup(args);
905  if (!gain_cmd)
906  return AVERROR(ENOMEM);
907 
908  ret = generate_kernel(ctx, gain_cmd, SELECT_GAIN_ENTRY(s));
909  if (ret >= 0) {
910  av_freep(&s->gain_cmd);
911  s->gain_cmd = gain_cmd;
912  } else {
913  av_freep(&gain_cmd);
914  }
915  } else if (!strcmp(cmd, "gain_entry")) {
916  char *gain_entry_cmd;
917 
918  if (SELECT_GAIN_ENTRY(s) && !strcmp(SELECT_GAIN_ENTRY(s), args)) {
919  av_log(ctx, AV_LOG_DEBUG, "equal gain_entry, do not rebuild.\n");
920  return 0;
921  }
922 
923  gain_entry_cmd = av_strdup(args);
924  if (!gain_entry_cmd)
925  return AVERROR(ENOMEM);
926 
927  ret = generate_kernel(ctx, SELECT_GAIN(s), gain_entry_cmd);
928  if (ret >= 0) {
929  av_freep(&s->gain_entry_cmd);
930  s->gain_entry_cmd = gain_entry_cmd;
931  } else {
932  av_freep(&gain_entry_cmd);
933  }
934  }
935 
936  return ret;
937 }
938 
940  {
941  .name = "default",
943  .config_props = config_input,
944  .filter_frame = filter_frame,
945  .type = AVMEDIA_TYPE_AUDIO,
946  },
947 };
948 
950  {
951  .name = "default",
952  .request_frame = request_frame,
953  .type = AVMEDIA_TYPE_AUDIO,
954  },
955 };
956 
958  .name = "firequalizer",
959  .description = NULL_IF_CONFIG_SMALL("Finite Impulse Response Equalizer."),
960  .uninit = uninit,
961  .query_formats = query_formats,
962  .process_command = process_command,
963  .priv_size = sizeof(FIREqualizerContext),
966  .priv_class = &firequalizer_class,
967 };
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:590
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:1019
sample_fmts
static enum AVSampleFormat sample_fmts[]
Definition: adpcmenc.c:948
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
fft2
static void fft2(FFTComplex *z)
Definition: tx_template.c:505
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:442
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:303
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:832
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:421
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
ff_set_common_all_samplerates
int ff_set_common_all_samplerates(AVFilterContext *ctx)
Equivalent to ff_set_common_samplerates(ctx, ff_all_samplerates())
Definition: formats.c:687
VarOffset
VarOffset
Definition: af_firequalizer.c:532
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:153
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: af_firequalizer.c:183
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:743
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:538
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:542
firequalizer_outputs
static const AVFilterPad firequalizer_outputs[]
Definition: af_firequalizer.c:949
ff_af_firequalizer
const AVFilter ff_af_firequalizer
Definition: af_firequalizer.c:957
firequalizer_inputs
static const AVFilterPad firequalizer_inputs[]
Definition: af_firequalizer.c:939
WindowFunc
WindowFunc
Definition: af_firequalizer.c:33
VAR_SR
@ VAR_SR
Definition: af_firequalizer.c:534
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:868
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:477
scale
static av_always_inline float scale(float x, float s)
Definition: vf_v360.c:1376
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:742
avassert.h
FIREqualizerContext::scale
int scale
Definition: af_firequalizer.c:103
VAR_CHID
@ VAR_CHID
Definition: af_firequalizer.c:536
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
ff_set_common_formats_from_list
int ff_set_common_formats_from_list(AVFilterContext *ctx, const int *fmts)
Equivalent to ff_set_common_formats(ctx, ff_make_format_list(fmts))
Definition: formats.c:703
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:152
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:401
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
ff_set_common_all_channel_counts
int ff_set_common_all_channel_counts(AVFilterContext *ctx)
Equivalent to ff_set_common_channel_layouts(ctx, ff_all_channel_counts())
Definition: formats.c:669
exp
int8_t exp
Definition: eval.c:72
var_names
static const char *const var_names[]
Definition: af_firequalizer.c:522
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:537
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:278
AV_SAMPLE_FMT_NONE
@ AV_SAMPLE_FMT_NONE
Definition: samplefmt.h:59
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:539
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:535
WFUNC_HANN
@ WFUNC_HANN
Definition: af_firequalizer.c:35
FFTContext
Definition: fft.h:75
i
int i
Definition: input.c:406
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
AVSampleFormat
AVSampleFormat
Audio sample formats.
Definition: samplefmt.h:58
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:533
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:890
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:200
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:149
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:346
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:238
gain_entry_compare
static int gain_entry_compare(const void *key, const void *memb)
Definition: af_firequalizer.c:430
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:153
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:156
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:745
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:342
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