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/file_open.h"
23 #include "libavutil/mem.h"
24 #include "libavutil/opt.h"
25 #include "libavutil/eval.h"
26 #include "libavutil/avassert.h"
27 #include "libavutil/tx.h"
28 #include "avfilter.h"
29 #include "filters.h"
30 #include "audio.h"
31 
32 #define RDFT_BITS_MIN 4
33 #define RDFT_BITS_MAX 16
34 
35 enum WindowFunc {
47 };
48 
49 enum Scale {
55 };
56 
57 #define NB_GAIN_ENTRY_MAX 4096
58 typedef struct GainEntry {
59  double freq;
60  double gain;
61 } GainEntry;
62 
63 typedef struct OverlapIndex {
64  int buf_idx;
66 } OverlapIndex;
67 
68 typedef struct FIREqualizerContext {
69  const AVClass *class;
70 
86  int rdft_len;
88 
89  float *analysis_buf;
90  float *analysis_tbuf;
91  float *dump_buf;
94  float *kernel_buf;
95  float *tx_buf;
96  float *cepstrum_buf;
97  float *cepstrum_tbuf;
98  float *conv_buf;
100  int fir_len;
105 
106  char *gain_cmd;
108  const char *gain;
109  const char *gain_entry;
110  double delay;
111  double accuracy;
112  int wfunc;
113  int fixed;
114  int multi;
116  int scale;
117  char *dumpfile;
119  int fft2;
121 
126 
127 #define OFFSET(x) offsetof(FIREqualizerContext, x)
128 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
129 #define TFLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
130 
131 static const AVOption firequalizer_options[] = {
132  { "gain", "set gain curve", OFFSET(gain), AV_OPT_TYPE_STRING, { .str = "gain_interpolate(f)" }, 0, 0, TFLAGS },
133  { "gain_entry", "set gain entry", OFFSET(gain_entry), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, TFLAGS },
134  { "delay", "set delay", OFFSET(delay), AV_OPT_TYPE_DOUBLE, { .dbl = 0.01 }, 0.0, 1e10, FLAGS },
135  { "accuracy", "set accuracy", OFFSET(accuracy), AV_OPT_TYPE_DOUBLE, { .dbl = 5.0 }, 0.0, 1e10, FLAGS },
136  { "wfunc", "set window function", OFFSET(wfunc), AV_OPT_TYPE_INT, { .i64 = WFUNC_HANN }, 0, NB_WFUNC-1, FLAGS, .unit = "wfunc" },
137  { "rectangular", "rectangular window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_RECTANGULAR }, 0, 0, FLAGS, .unit = "wfunc" },
138  { "hann", "hann window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_HANN }, 0, 0, FLAGS, .unit = "wfunc" },
139  { "hamming", "hamming window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_HAMMING }, 0, 0, FLAGS, .unit = "wfunc" },
140  { "blackman", "blackman window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_BLACKMAN }, 0, 0, FLAGS, .unit = "wfunc" },
141  { "nuttall3", "3-term nuttall window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_NUTTALL3 }, 0, 0, FLAGS, .unit = "wfunc" },
142  { "mnuttall3", "minimum 3-term nuttall window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_MNUTTALL3 }, 0, 0, FLAGS, .unit = "wfunc" },
143  { "nuttall", "nuttall window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_NUTTALL }, 0, 0, FLAGS, .unit = "wfunc" },
144  { "bnuttall", "blackman-nuttall window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_BNUTTALL }, 0, 0, FLAGS, .unit = "wfunc" },
145  { "bharris", "blackman-harris window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_BHARRIS }, 0, 0, FLAGS, .unit = "wfunc" },
146  { "tukey", "tukey window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_TUKEY }, 0, 0, FLAGS, .unit = "wfunc" },
147  { "fixed", "set fixed frame samples", OFFSET(fixed), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
148  { "multi", "set multi channels mode", OFFSET(multi), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
149  { "zero_phase", "set zero phase mode", OFFSET(zero_phase), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
150  { "scale", "set gain scale", OFFSET(scale), AV_OPT_TYPE_INT, { .i64 = SCALE_LINLOG }, 0, NB_SCALE-1, FLAGS, .unit = "scale" },
151  { "linlin", "linear-freq linear-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LINLIN }, 0, 0, FLAGS, .unit = "scale" },
152  { "linlog", "linear-freq logarithmic-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LINLOG }, 0, 0, FLAGS, .unit = "scale" },
153  { "loglin", "logarithmic-freq linear-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LOGLIN }, 0, 0, FLAGS, .unit = "scale" },
154  { "loglog", "logarithmic-freq logarithmic-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LOGLOG }, 0, 0, FLAGS, .unit = "scale" },
155  { "dumpfile", "set dump file", OFFSET(dumpfile), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },
156  { "dumpscale", "set dump scale", OFFSET(dumpscale), AV_OPT_TYPE_INT, { .i64 = SCALE_LINLOG }, 0, NB_SCALE-1, FLAGS, .unit = "scale" },
157  { "fft2", "set 2-channels fft", OFFSET(fft2), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
158  { "min_phase", "set minimum phase mode", OFFSET(min_phase), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
159  { NULL }
160 };
161 
162 AVFILTER_DEFINE_CLASS(firequalizer);
163 
165 {
166  av_tx_uninit(&s->analysis_rdft);
167  av_tx_uninit(&s->analysis_irdft);
168  av_tx_uninit(&s->rdft);
169  av_tx_uninit(&s->irdft);
170  av_tx_uninit(&s->fft_ctx);
171  av_tx_uninit(&s->cepstrum_rdft);
172  av_tx_uninit(&s->cepstrum_irdft);
173  s->analysis_rdft = s->analysis_irdft = s->rdft = s->irdft = NULL;
174  s->fft_ctx = NULL;
175  s->cepstrum_rdft = NULL;
176  s->cepstrum_irdft = NULL;
177 
178  av_freep(&s->analysis_buf);
179  av_freep(&s->analysis_tbuf);
180  av_freep(&s->dump_buf);
181  av_freep(&s->kernel_tmp_buf);
182  av_freep(&s->kernel_tmp_tbuf);
183  av_freep(&s->kernel_buf);
184  av_freep(&s->tx_buf);
185  av_freep(&s->cepstrum_buf);
186  av_freep(&s->cepstrum_tbuf);
187  av_freep(&s->conv_buf);
188  av_freep(&s->conv_idx);
189 }
190 
192 {
193  FIREqualizerContext *s = ctx->priv;
194 
195  common_uninit(s);
196  av_freep(&s->gain_cmd);
197  av_freep(&s->gain_entry_cmd);
198 }
199 
200 static void fast_convolute(FIREqualizerContext *restrict s, const float *restrict kernel_buf, float *restrict conv_buf,
201  OverlapIndex *restrict idx, float *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  float *tbuf = s->tx_buf;
207  int center = s->fir_len/2;
208  int k;
209 
210  memset(buf, 0, center * sizeof(*data));
211  memcpy(buf + center, data, nsamples * sizeof(*data));
212  memset(buf + center + nsamples, 0, (s->rdft_len - nsamples - center) * sizeof(*data));
213  s->rdft_fn(s->rdft, tbuf, buf, sizeof(float));
214 
215  for (k = 0; k <= s->rdft_len/2; k++) {
216  tbuf[2*k] *= kernel_buf[k];
217  tbuf[2*k+1] *= kernel_buf[k];
218  }
219 
220  s->irdft_fn(s->irdft, buf, tbuf, sizeof(AVComplexFloat));
221  for (k = 0; k < s->rdft_len - idx->overlap_idx; k++)
222  buf[k] += obuf[k];
223  memcpy(data, buf, nsamples * sizeof(*data));
224  idx->buf_idx = !idx->buf_idx;
225  idx->overlap_idx = nsamples;
226  } else {
227  while (nsamples > s->nsamples_max * 2) {
228  fast_convolute(s, kernel_buf, conv_buf, idx, data, s->nsamples_max);
229  data += s->nsamples_max;
230  nsamples -= s->nsamples_max;
231  }
232  fast_convolute(s, kernel_buf, conv_buf, idx, data, nsamples/2);
233  fast_convolute(s, kernel_buf, conv_buf, idx, data + nsamples/2, nsamples - nsamples/2);
234  }
235 }
236 
237 static void fast_convolute_nonlinear(FIREqualizerContext *restrict s, const float *restrict kernel_buf,
238  float *restrict conv_buf, OverlapIndex *restrict idx,
239  float *restrict data, int nsamples)
240 {
241  if (nsamples <= s->nsamples_max) {
242  float *buf = conv_buf + idx->buf_idx * s->rdft_len;
243  float *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx;
244  float *tbuf = s->tx_buf;
245  int k;
246 
247  memcpy(buf, data, nsamples * sizeof(*data));
248  memset(buf + nsamples, 0, (s->rdft_len - nsamples) * sizeof(*data));
249  s->rdft_fn(s->rdft, tbuf, buf, sizeof(float));
250 
251  for (k = 0; k < s->rdft_len + 2; k += 2) {
252  float re, im;
253  re = tbuf[k] * kernel_buf[k] - tbuf[k+1] * kernel_buf[k+1];
254  im = tbuf[k] * kernel_buf[k+1] + tbuf[k+1] * kernel_buf[k];
255  tbuf[k] = re;
256  tbuf[k+1] = im;
257  }
258 
259  s->irdft_fn(s->irdft, buf, tbuf, sizeof(AVComplexFloat));
260  for (k = 0; k < s->rdft_len - idx->overlap_idx; k++)
261  buf[k] += obuf[k];
262  memcpy(data, buf, nsamples * sizeof(*data));
263  idx->buf_idx = !idx->buf_idx;
264  idx->overlap_idx = nsamples;
265  } else {
266  while (nsamples > s->nsamples_max * 2) {
267  fast_convolute_nonlinear(s, kernel_buf, conv_buf, idx, data, s->nsamples_max);
268  data += s->nsamples_max;
269  nsamples -= s->nsamples_max;
270  }
271  fast_convolute_nonlinear(s, kernel_buf, conv_buf, idx, data, nsamples/2);
272  fast_convolute_nonlinear(s, kernel_buf, conv_buf, idx, data + nsamples/2, nsamples - nsamples/2);
273  }
274 }
275 
276 static void fast_convolute2(FIREqualizerContext *restrict s, const float *restrict kernel_buf, AVComplexFloat *restrict conv_buf,
277  OverlapIndex *restrict idx, float *restrict data0, float *restrict data1, int nsamples)
278 {
279  if (nsamples <= s->nsamples_max) {
280  AVComplexFloat *buf = conv_buf + idx->buf_idx * s->rdft_len;
281  AVComplexFloat *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx;
282  AVComplexFloat *tbuf = (AVComplexFloat *)s->tx_buf;
283  int center = s->fir_len/2;
284  int k;
285  float tmp;
286 
287  memset(buf, 0, center * sizeof(*buf));
288  for (k = 0; k < nsamples; k++) {
289  buf[center+k].re = data0[k];
290  buf[center+k].im = data1[k];
291  }
292  memset(buf + center + nsamples, 0, (s->rdft_len - nsamples - center) * sizeof(*buf));
293  s->fft_fn(s->fft_ctx, tbuf, buf, sizeof(AVComplexFloat));
294 
295  /* swap re <-> im, do backward fft using forward fft_ctx */
296  /* normalize with 0.5f */
297  tmp = tbuf[0].re;
298  tbuf[0].re = 0.5f * kernel_buf[0] * tbuf[0].im;
299  tbuf[0].im = 0.5f * kernel_buf[0] * tmp;
300  for (k = 1; k < s->rdft_len/2; k++) {
301  int m = s->rdft_len - k;
302  tmp = tbuf[k].re;
303  tbuf[k].re = 0.5f * kernel_buf[k] * tbuf[k].im;
304  tbuf[k].im = 0.5f * kernel_buf[k] * tmp;
305  tmp = tbuf[m].re;
306  tbuf[m].re = 0.5f * kernel_buf[k] * tbuf[m].im;
307  tbuf[m].im = 0.5f * kernel_buf[k] * tmp;
308  }
309  tmp = tbuf[k].re;
310  tbuf[k].re = 0.5f * kernel_buf[k] * tbuf[k].im;
311  tbuf[k].im = 0.5f * kernel_buf[k] * tmp;
312 
313  s->fft_fn(s->fft_ctx, buf, tbuf, sizeof(AVComplexFloat));
314 
315  for (k = 0; k < s->rdft_len - idx->overlap_idx; k++) {
316  buf[k].re += obuf[k].re;
317  buf[k].im += obuf[k].im;
318  }
319 
320  /* swapped re <-> im */
321  for (k = 0; k < nsamples; k++) {
322  data0[k] = buf[k].im;
323  data1[k] = buf[k].re;
324  }
325  idx->buf_idx = !idx->buf_idx;
326  idx->overlap_idx = nsamples;
327  } else {
328  while (nsamples > s->nsamples_max * 2) {
329  fast_convolute2(s, kernel_buf, conv_buf, idx, data0, data1, s->nsamples_max);
330  data0 += s->nsamples_max;
331  data1 += s->nsamples_max;
332  nsamples -= s->nsamples_max;
333  }
334  fast_convolute2(s, kernel_buf, conv_buf, idx, data0, data1, nsamples/2);
335  fast_convolute2(s, kernel_buf, conv_buf, idx, data0 + nsamples/2, data1 + nsamples/2, nsamples - nsamples/2);
336  }
337 }
338 
339 static void dump_fir(AVFilterContext *ctx, FILE *fp, int ch)
340 {
341  FIREqualizerContext *s = ctx->priv;
342  int rate = ctx->inputs[0]->sample_rate;
343  int xlog = s->dumpscale == SCALE_LOGLIN || s->dumpscale == SCALE_LOGLOG;
344  int ylog = s->dumpscale == SCALE_LINLOG || s->dumpscale == SCALE_LOGLOG;
345  int x;
346  int center = s->fir_len / 2;
347  double delay = s->zero_phase ? 0.0 : (double) center / rate;
348  double vx, ya, yb;
349 
350  if (!s->min_phase) {
351  s->analysis_buf[0] *= s->rdft_len/2;
352  for (x = 1; x <= center; x++) {
353  s->analysis_buf[x] *= s->rdft_len/2;
354  s->analysis_buf[s->analysis_rdft_len - x] *= s->rdft_len/2;
355  }
356  } else {
357  for (x = 0; x < s->fir_len; x++)
358  s->analysis_buf[x] *= s->rdft_len/2;
359  }
360 
361  if (ch)
362  fprintf(fp, "\n\n");
363 
364  fprintf(fp, "# time[%d] (time amplitude)\n", ch);
365 
366  if (!s->min_phase) {
367  for (x = center; x > 0; x--)
368  fprintf(fp, "%15.10f %15.10f\n", delay - (double) x / rate, (double) s->analysis_buf[s->analysis_rdft_len - x]);
369 
370  for (x = 0; x <= center; x++)
371  fprintf(fp, "%15.10f %15.10f\n", delay + (double)x / rate , (double) s->analysis_buf[x]);
372  } else {
373  for (x = 0; x < s->fir_len; x++)
374  fprintf(fp, "%15.10f %15.10f\n", (double)x / rate, (double) s->analysis_buf[x]);
375  }
376 
377  s->analysis_rdft_fn(s->analysis_rdft, s->analysis_tbuf, s->analysis_buf, sizeof(float));
378 
379  fprintf(fp, "\n\n# freq[%d] (frequency desired_gain actual_gain)\n", ch);
380 
381  for (x = 0; x <= s->analysis_rdft_len/2; x++) {
382  int i = 2 * x;
383  vx = (double)x * rate / s->analysis_rdft_len;
384  if (xlog)
385  vx = log2(0.05*vx);
386  ya = s->dump_buf[i];
387  yb = s->min_phase ? hypotf(s->analysis_tbuf[i], s->analysis_tbuf[i+1]) : s->analysis_tbuf[i];
388  if (s->min_phase)
389  yb = fabs(yb);
390  if (ylog) {
391  ya = 20.0 * log10(fabs(ya));
392  yb = 20.0 * log10(fabs(yb));
393  }
394  fprintf(fp, "%17.10f %17.10f %17.10f\n", vx, ya, yb);
395  }
396 }
397 
398 static double entry_func(void *p, double freq, double gain)
399 {
400  AVFilterContext *ctx = p;
401  FIREqualizerContext *s = ctx->priv;
402 
403  if (s->nb_gain_entry >= NB_GAIN_ENTRY_MAX) {
404  av_log(ctx, AV_LOG_ERROR, "entry table overflow.\n");
405  s->gain_entry_err = AVERROR(EINVAL);
406  return 0;
407  }
408 
409  if (isnan(freq)) {
410  av_log(ctx, AV_LOG_ERROR, "nan frequency (%g, %g).\n", freq, gain);
411  s->gain_entry_err = AVERROR(EINVAL);
412  return 0;
413  }
414 
415  if (s->nb_gain_entry > 0 && freq <= s->gain_entry_tbl[s->nb_gain_entry - 1].freq) {
416  av_log(ctx, AV_LOG_ERROR, "unsorted frequency (%g, %g).\n", freq, gain);
417  s->gain_entry_err = AVERROR(EINVAL);
418  return 0;
419  }
420 
421  s->gain_entry_tbl[s->nb_gain_entry].freq = freq;
422  s->gain_entry_tbl[s->nb_gain_entry].gain = gain;
423  s->nb_gain_entry++;
424  return 0;
425 }
426 
427 static int gain_entry_compare(const void *key, const void *memb)
428 {
429  const double *freq = key;
430  const GainEntry *entry = memb;
431 
432  if (*freq < entry[0].freq)
433  return -1;
434  if (*freq > entry[1].freq)
435  return 1;
436  return 0;
437 }
438 
439 static double gain_interpolate_func(void *p, double freq)
440 {
441  AVFilterContext *ctx = p;
442  FIREqualizerContext *s = ctx->priv;
443  GainEntry *res;
444  double d0, d1, d;
445 
446  if (isnan(freq))
447  return freq;
448 
449  if (!s->nb_gain_entry)
450  return 0;
451 
452  if (freq <= s->gain_entry_tbl[0].freq)
453  return s->gain_entry_tbl[0].gain;
454 
455  if (freq >= s->gain_entry_tbl[s->nb_gain_entry-1].freq)
456  return s->gain_entry_tbl[s->nb_gain_entry-1].gain;
457 
458  res = bsearch(&freq, &s->gain_entry_tbl, s->nb_gain_entry - 1, sizeof(*res), gain_entry_compare);
459  av_assert0(res);
460 
461  d = res[1].freq - res[0].freq;
462  d0 = freq - res[0].freq;
463  d1 = res[1].freq - freq;
464 
465  if (d0 && d1)
466  return (d0 * res[1].gain + d1 * res[0].gain) / d;
467 
468  if (d0)
469  return res[1].gain;
470 
471  return res[0].gain;
472 }
473 
474 static double cubic_interpolate_func(void *p, double freq)
475 {
476  AVFilterContext *ctx = p;
477  FIREqualizerContext *s = ctx->priv;
478  GainEntry *res;
479  double x, x2, x3;
480  double a, b, c, d;
481  double m0, m1, m2, msum, unit;
482 
483  if (!s->nb_gain_entry)
484  return 0;
485 
486  if (freq <= s->gain_entry_tbl[0].freq)
487  return s->gain_entry_tbl[0].gain;
488 
489  if (freq >= s->gain_entry_tbl[s->nb_gain_entry-1].freq)
490  return s->gain_entry_tbl[s->nb_gain_entry-1].gain;
491 
492  res = bsearch(&freq, &s->gain_entry_tbl, s->nb_gain_entry - 1, sizeof(*res), gain_entry_compare);
493  av_assert0(res);
494 
495  unit = res[1].freq - res[0].freq;
496  m0 = res != s->gain_entry_tbl ?
497  unit * (res[0].gain - res[-1].gain) / (res[0].freq - res[-1].freq) : 0;
498  m1 = res[1].gain - res[0].gain;
499  m2 = res != s->gain_entry_tbl + s->nb_gain_entry - 2 ?
500  unit * (res[2].gain - res[1].gain) / (res[2].freq - res[1].freq) : 0;
501 
502  msum = fabs(m0) + fabs(m1);
503  m0 = msum > 0 ? (fabs(m0) * m1 + fabs(m1) * m0) / msum : 0;
504  msum = fabs(m1) + fabs(m2);
505  m1 = msum > 0 ? (fabs(m1) * m2 + fabs(m2) * m1) / msum : 0;
506 
507  d = res[0].gain;
508  c = m0;
509  b = 3 * res[1].gain - m1 - 2 * c - 3 * d;
510  a = res[1].gain - b - c - d;
511 
512  x = (freq - res[0].freq) / unit;
513  x2 = x * x;
514  x3 = x2 * x;
515 
516  return a * x3 + b * x2 + c * x + d;
517 }
518 
519 static const char *const var_names[] = {
520  "f",
521  "sr",
522  "ch",
523  "chid",
524  "chs",
525  "chlayout",
526  NULL
527 };
528 
529 enum VarOffset {
537 };
538 
539 static void generate_min_phase_kernel(FIREqualizerContext *s, float *rdft_buf)
540 {
541  int k, cepstrum_len = s->cepstrum_len, rdft_len = s->rdft_len;
542  double norm = 2.0 / cepstrum_len;
543  double minval = 1e-7 / rdft_len;
544 
545  memset(s->cepstrum_buf, 0, cepstrum_len * sizeof(*s->cepstrum_buf));
546  memset(s->cepstrum_tbuf, 0, (cepstrum_len + 2) * sizeof(*s->cepstrum_tbuf));
547  memcpy(s->cepstrum_buf, rdft_buf, rdft_len/2 * sizeof(*rdft_buf));
548  memcpy(s->cepstrum_buf + cepstrum_len - rdft_len/2, rdft_buf + rdft_len/2, rdft_len/2 * sizeof(*rdft_buf));
549 
550  s->cepstrum_rdft_fn(s->cepstrum_rdft, s->cepstrum_tbuf, s->cepstrum_buf, sizeof(float));
551 
552  for (k = 0; k < cepstrum_len + 2; k += 2) {
553  s->cepstrum_tbuf[k] = log(FFMAX(s->cepstrum_tbuf[k], minval));
554  s->cepstrum_tbuf[k+1] = 0;
555  }
556 
557  s->cepstrum_irdft_fn(s->cepstrum_irdft, s->cepstrum_buf, s->cepstrum_tbuf, sizeof(AVComplexFloat));
558 
559  memset(s->cepstrum_buf + cepstrum_len/2 + 1, 0, (cepstrum_len/2 - 1) * sizeof(*s->cepstrum_buf));
560  for (k = 1; k <= cepstrum_len/2; k++)
561  s->cepstrum_buf[k] *= 2;
562 
563  s->cepstrum_rdft_fn(s->cepstrum_rdft, s->cepstrum_tbuf, s->cepstrum_buf, sizeof(float));
564 
565  for (k = 0; k < cepstrum_len + 2; k += 2) {
566  double mag = exp(s->cepstrum_tbuf[k] * norm) * norm;
567  double ph = s->cepstrum_tbuf[k+1] * norm;
568  s->cepstrum_tbuf[k] = mag * cos(ph);
569  s->cepstrum_tbuf[k+1] = mag * sin(ph);
570  }
571 
572  s->cepstrum_irdft_fn(s->cepstrum_irdft, s->cepstrum_buf, s->cepstrum_tbuf, sizeof(AVComplexFloat));
573  memset(rdft_buf, 0, s->rdft_len * sizeof(*rdft_buf));
574  memcpy(rdft_buf, s->cepstrum_buf, s->fir_len * sizeof(*rdft_buf));
575 
576  if (s->dumpfile) {
577  memset(s->analysis_buf, 0, (s->analysis_rdft_len + 2) * sizeof(*s->analysis_buf));
578  memcpy(s->analysis_buf, s->cepstrum_buf, s->fir_len * sizeof(*s->analysis_buf));
579  }
580 }
581 
582 static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *gain_entry)
583 {
584  FIREqualizerContext *s = ctx->priv;
585  AVFilterLink *inlink = ctx->inputs[0];
586  const char *gain_entry_func_names[] = { "entry", NULL };
587  const char *gain_func_names[] = { "gain_interpolate", "cubic_interpolate", NULL };
588  double (*gain_entry_funcs[])(void *, double, double) = { entry_func, NULL };
589  double (*gain_funcs[])(void *, double) = { gain_interpolate_func, cubic_interpolate_func, NULL };
590  double vars[VAR_NB];
591  AVExpr *gain_expr;
592  int ret, k, center, ch;
593  int xlog = s->scale == SCALE_LOGLIN || s->scale == SCALE_LOGLOG;
594  int ylog = s->scale == SCALE_LINLOG || s->scale == SCALE_LOGLOG;
595  FILE *dump_fp = NULL;
596 
597  s->nb_gain_entry = 0;
598  s->gain_entry_err = 0;
599  if (gain_entry) {
600  double result = 0.0;
601  ret = av_expr_parse_and_eval(&result, gain_entry, NULL, NULL, NULL, NULL,
602  gain_entry_func_names, gain_entry_funcs, ctx, 0, ctx);
603  if (ret < 0)
604  return ret;
605  if (s->gain_entry_err < 0)
606  return s->gain_entry_err;
607  }
608 
609  av_log(ctx, AV_LOG_DEBUG, "nb_gain_entry = %d.\n", s->nb_gain_entry);
610 
611  ret = av_expr_parse(&gain_expr, gain, var_names,
612  gain_func_names, gain_funcs, NULL, NULL, 0, ctx);
613  if (ret < 0)
614  return ret;
615 
616  if (s->dumpfile && (!s->dump_buf || !s->analysis_rdft || !(dump_fp = avpriv_fopen_utf8(s->dumpfile, "w"))))
617  av_log(ctx, AV_LOG_WARNING, "dumping failed.\n");
618 
619  vars[VAR_CHS] = inlink->ch_layout.nb_channels;
620  vars[VAR_CHLAYOUT] = inlink->ch_layout.order == AV_CHANNEL_ORDER_NATIVE ?
621  inlink->ch_layout.u.mask : 0;
622  vars[VAR_SR] = inlink->sample_rate;
623  for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
624  float *rdft_buf = s->kernel_tmp_buf + ch * (s->rdft_len * 2);
625  float *rdft_tbuf = s->kernel_tmp_tbuf;
626  double result;
627  vars[VAR_CH] = ch;
629 
630  for (k = 0; 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_tbuf[2*k] = ylog ? pow(10.0, 0.05 * result) : s->min_phase ? fabs(result) : result;
636  s->analysis_tbuf[2*k+1] = 0.0;
637  }
638 
639  if (s->dump_buf)
640  memcpy(s->dump_buf, s->analysis_tbuf, (s->analysis_rdft_len + 2) * sizeof(*s->analysis_tbuf));
641 
642  s->analysis_irdft_fn(s->analysis_irdft, s->analysis_buf, s->analysis_tbuf, sizeof(AVComplexFloat));
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_tbuf, s->analysis_buf, s->rdft_len/2 * sizeof(*s->analysis_buf));
689  memcpy(rdft_tbuf + 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_tbuf);
692  s->rdft_fn(s->rdft, rdft_buf, rdft_tbuf, sizeof(float));
693 
694  for (k = 0; k < s->rdft_len + 2; 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  for (k = 0; k <= s->rdft_len/2; k++)
706  rdft_buf[k] = rdft_buf[2*k];
707  }
708 
709  if (dump_fp)
710  dump_fir(ctx, dump_fp, ch);
711 
712  if (!s->multi)
713  break;
714  }
715 
716  memcpy(s->kernel_buf, s->kernel_tmp_buf, (s->multi ? inlink->ch_layout.nb_channels : 1) * (s->rdft_len * 2) * sizeof(*s->kernel_buf));
717  av_expr_free(gain_expr);
718  if (dump_fp)
719  fclose(dump_fp);
720  return 0;
721 }
722 
723 #define SELECT_GAIN(s) (s->gain_cmd ? s->gain_cmd : s->gain)
724 #define SELECT_GAIN_ENTRY(s) (s->gain_entry_cmd ? s->gain_entry_cmd : s->gain_entry)
725 
727 {
729  AVFilterContext *ctx = inlink->dst;
730  FIREqualizerContext *s = ctx->priv;
731  float iscale, scale = 1.f;
732  int rdft_bits, ret;
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  iscale = 0.5f;
755  if (((ret = av_tx_init(&s->rdft, &s->rdft_fn, AV_TX_FLOAT_RDFT, 0, 1 << rdft_bits, &scale, 0)) < 0) ||
756  ((ret = av_tx_init(&s->irdft, &s->irdft_fn, AV_TX_FLOAT_RDFT, 1, 1 << rdft_bits, &iscale, 0)) < 0))
757  return ret;
758 
759  scale = 1.f;
760  if (s->fft2 && !s->multi && inlink->ch_layout.nb_channels > 1 &&
761  ((ret = av_tx_init(&s->fft_ctx, &s->fft_fn, AV_TX_FLOAT_FFT, 0, 1 << rdft_bits, &scale, 0)) < 0))
762  return ret;
763 
764  if (s->min_phase) {
765  int cepstrum_bits = rdft_bits + 2;
766  if (cepstrum_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  cepstrum_bits = FFMIN(RDFT_BITS_MAX, cepstrum_bits + 1);
772  scale = 1.f;
773  ret = av_tx_init(&s->cepstrum_rdft, &s->cepstrum_rdft_fn, AV_TX_FLOAT_RDFT, 0, 1 << cepstrum_bits, &scale, 0);
774  if (ret < 0)
775  return ret;
776 
777  iscale = 0.5f;
778  ret = av_tx_init(&s->cepstrum_irdft, &s->cepstrum_irdft_fn, AV_TX_FLOAT_RDFT, 1, 1 << cepstrum_bits, &iscale, 0);
779  if (ret < 0)
780  return ret;
781 
782  s->cepstrum_len = 1 << cepstrum_bits;
783  s->cepstrum_buf = av_malloc_array(s->cepstrum_len, sizeof(*s->cepstrum_buf));
784  if (!s->cepstrum_buf)
785  return AVERROR(ENOMEM);
786  s->cepstrum_tbuf = av_malloc_array(s->cepstrum_len + 2, sizeof(*s->cepstrum_tbuf));
787  if (!s->cepstrum_tbuf)
788  return AVERROR(ENOMEM);
789  }
790 
791  for ( ; rdft_bits <= RDFT_BITS_MAX; rdft_bits++) {
792  s->analysis_rdft_len = 1 << rdft_bits;
793  if (inlink->sample_rate <= s->accuracy * s->analysis_rdft_len)
794  break;
795  }
796 
797  if (rdft_bits > RDFT_BITS_MAX) {
798  av_log(ctx, AV_LOG_ERROR, "too small accuracy, please increase it.\n");
799  return AVERROR(EINVAL);
800  }
801 
802  iscale = 0.5f;
803  if ((ret = av_tx_init(&s->analysis_irdft, &s->analysis_irdft_fn, AV_TX_FLOAT_RDFT, 1, 1 << rdft_bits, &iscale, 0)) < 0)
804  return ret;
805 
806  if (s->dumpfile) {
807  scale = 1.f;
808  if ((ret = av_tx_init(&s->analysis_rdft, &s->analysis_rdft_fn, AV_TX_FLOAT_RDFT, 0, 1 << rdft_bits, &scale, 0)) < 0)
809  return ret;
810  s->dump_buf = av_malloc_array(s->analysis_rdft_len + 2, sizeof(*s->dump_buf));
811  }
812 
813  s->analysis_buf = av_malloc_array((s->analysis_rdft_len + 2), sizeof(*s->analysis_buf));
814  s->analysis_tbuf = av_malloc_array(s->analysis_rdft_len + 2, sizeof(*s->analysis_tbuf));
815  s->kernel_tmp_buf = av_malloc_array((s->rdft_len * 2) * (s->multi ? inlink->ch_layout.nb_channels : 1), sizeof(*s->kernel_tmp_buf));
816  s->kernel_tmp_tbuf = av_malloc_array(s->rdft_len, sizeof(*s->kernel_tmp_tbuf));
817  s->kernel_buf = av_malloc_array((s->rdft_len * 2) * (s->multi ? inlink->ch_layout.nb_channels : 1), sizeof(*s->kernel_buf));
818  s->tx_buf = av_malloc_array(2 * (s->rdft_len + 2), sizeof(*s->kernel_buf));
819  s->conv_buf = av_calloc(2 * s->rdft_len * inlink->ch_layout.nb_channels, sizeof(*s->conv_buf));
820  s->conv_idx = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->conv_idx));
821  if (!s->analysis_buf || !s->analysis_tbuf || !s->kernel_tmp_buf || !s->kernel_buf || !s->conv_buf || !s->conv_idx || !s->kernel_tmp_tbuf || !s->tx_buf)
822  return AVERROR(ENOMEM);
823 
824  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",
825  inlink->sample_rate, inlink->ch_layout.nb_channels, s->analysis_rdft_len, s->rdft_len, s->fir_len, s->nsamples_max);
826 
827  if (s->fixed)
828  l->min_samples = l->max_samples = s->nsamples_max;
829 
831 }
832 
834 {
835  AVFilterContext *ctx = inlink->dst;
836  FIREqualizerContext *s = ctx->priv;
837  int ch;
838 
839  if (!s->min_phase) {
840  for (ch = 0; ch + 1 < inlink->ch_layout.nb_channels && s->fft_ctx; ch += 2) {
841  fast_convolute2(s, s->kernel_buf, (AVComplexFloat *)(s->conv_buf + 2 * ch * s->rdft_len),
842  s->conv_idx + ch, (float *) frame->extended_data[ch],
843  (float *) frame->extended_data[ch+1], frame->nb_samples);
844  }
845 
846  for ( ; ch < inlink->ch_layout.nb_channels; ch++) {
847  fast_convolute(s, s->kernel_buf + (s->multi ? ch * (s->rdft_len * 2) : 0),
848  s->conv_buf + 2 * ch * s->rdft_len, s->conv_idx + ch,
849  (float *) frame->extended_data[ch], frame->nb_samples);
850  }
851  } else {
852  for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
853  fast_convolute_nonlinear(s, s->kernel_buf + (s->multi ? ch * (s->rdft_len * 2) : 0),
854  s->conv_buf + 2 * ch * s->rdft_len, s->conv_idx + ch,
855  (float *) frame->extended_data[ch], frame->nb_samples);
856  }
857  }
858 
859  s->next_pts = AV_NOPTS_VALUE;
860  if (frame->pts != AV_NOPTS_VALUE) {
861  s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, av_make_q(1, inlink->sample_rate), inlink->time_base);
862  if (s->zero_phase && !s->min_phase)
863  frame->pts -= av_rescale_q(s->fir_len/2, av_make_q(1, inlink->sample_rate), inlink->time_base);
864  }
865  s->frame_nsamples_max = FFMAX(s->frame_nsamples_max, frame->nb_samples);
866  return ff_filter_frame(ctx->outputs[0], frame);
867 }
868 
869 static int request_frame(AVFilterLink *outlink)
870 {
871  AVFilterContext *ctx = outlink->src;
872  FIREqualizerContext *s= ctx->priv;
873  int ret;
874 
875  ret = ff_request_frame(ctx->inputs[0]);
876  if (ret == AVERROR_EOF && s->remaining > 0 && s->frame_nsamples_max > 0) {
877  AVFrame *frame = ff_get_audio_buffer(outlink, FFMIN(s->remaining, s->frame_nsamples_max));
878 
879  if (!frame)
880  return AVERROR(ENOMEM);
881 
882  av_samples_set_silence(frame->extended_data, 0, frame->nb_samples, outlink->ch_layout.nb_channels, frame->format);
883  frame->pts = s->next_pts;
884  s->remaining -= frame->nb_samples;
885  ret = filter_frame(ctx->inputs[0], frame);
886  }
887 
888  return ret;
889 }
890 
891 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
892  char *res, int res_len, int flags)
893 {
894  FIREqualizerContext *s = ctx->priv;
895  int ret = AVERROR(ENOSYS);
896 
897  if (!strcmp(cmd, "gain")) {
898  char *gain_cmd;
899 
900  if (SELECT_GAIN(s) && !strcmp(SELECT_GAIN(s), args)) {
901  av_log(ctx, AV_LOG_DEBUG, "equal gain, do not rebuild.\n");
902  return 0;
903  }
904 
905  gain_cmd = av_strdup(args);
906  if (!gain_cmd)
907  return AVERROR(ENOMEM);
908 
909  ret = generate_kernel(ctx, gain_cmd, SELECT_GAIN_ENTRY(s));
910  if (ret >= 0) {
911  av_freep(&s->gain_cmd);
912  s->gain_cmd = gain_cmd;
913  } else {
914  av_freep(&gain_cmd);
915  }
916  } else if (!strcmp(cmd, "gain_entry")) {
917  char *gain_entry_cmd;
918 
919  if (SELECT_GAIN_ENTRY(s) && !strcmp(SELECT_GAIN_ENTRY(s), args)) {
920  av_log(ctx, AV_LOG_DEBUG, "equal gain_entry, do not rebuild.\n");
921  return 0;
922  }
923 
924  gain_entry_cmd = av_strdup(args);
925  if (!gain_entry_cmd)
926  return AVERROR(ENOMEM);
927 
928  ret = generate_kernel(ctx, SELECT_GAIN(s), gain_entry_cmd);
929  if (ret >= 0) {
930  av_freep(&s->gain_entry_cmd);
931  s->gain_entry_cmd = gain_entry_cmd;
932  } else {
933  av_freep(&gain_entry_cmd);
934  }
935  }
936 
937  return ret;
938 }
939 
941  {
942  .name = "default",
944  .config_props = config_input,
945  .filter_frame = filter_frame,
946  .type = AVMEDIA_TYPE_AUDIO,
947  },
948 };
949 
951  {
952  .name = "default",
953  .request_frame = request_frame,
954  .type = AVMEDIA_TYPE_AUDIO,
955  },
956 };
957 
959  .name = "firequalizer",
960  .description = NULL_IF_CONFIG_SMALL("Finite Impulse Response Equalizer."),
961  .uninit = uninit,
962  .process_command = process_command,
963  .priv_size = sizeof(FIREqualizerContext),
967  .priv_class = &firequalizer_class,
968 };
FIREqualizerContext::cepstrum_len
int cepstrum_len
Definition: af_firequalizer.c:87
FIREqualizerContext::kernel_tmp_tbuf
float * kernel_tmp_tbuf
Definition: af_firequalizer.c:93
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:98
AV_SAMPLE_FMT_FLTP
@ AV_SAMPLE_FMT_FLTP
float, planar
Definition: samplefmt.h:66
GainEntry::freq
double freq
Definition: af_firequalizer.c:59
FIREqualizerContext::gain_cmd
char * gain_cmd
Definition: af_firequalizer.c:106
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
entry
#define entry
Definition: aom_film_grain_template.c:66
FIREqualizerContext::fft_ctx
AVTXContext * fft_ctx
Definition: af_firequalizer.c:79
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:582
u
#define u(width, name, range_min, range_max)
Definition: cbs_h2645.c:251
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1061
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
FIREqualizerContext::analysis_irdft_fn
av_tx_fn analysis_irdft_fn
Definition: af_firequalizer.c:74
AVTXContext
Definition: tx_priv.h:235
int64_t
long long int64_t
Definition: coverity.c:34
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:439
normalize.log
log
Definition: normalize.py:21
FIREqualizerContext::irdft
AVTXContext * irdft
Definition: af_firequalizer.c:77
FIREqualizerContext::analysis_tbuf
float * analysis_tbuf
Definition: af_firequalizer.c:90
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: filters.h:262
ph
static int FUNC() ph(CodedBitstreamContext *ctx, RWContext *rw, H266RawPH *current)
Definition: cbs_h266_syntax_template.c:3043
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:389
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:28
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: af_firequalizer.c:833
av_channel_layout_channel_from_index
enum AVChannel av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout, unsigned int idx)
Get the channel with the given index in a channel layout.
Definition: channel_layout.c:671
av_samples_set_silence
int av_samples_set_silence(uint8_t *const *audio_data, int offset, int nb_samples, int nb_channels, enum AVSampleFormat sample_fmt)
Fill an audio buffer with silence.
Definition: samplefmt.c:246
AVOption
AVOption.
Definition: opt.h:429
b
#define b
Definition: input.c:41
FIREqualizerContext::frame_nsamples_max
int frame_nsamples_max
Definition: af_firequalizer.c:103
data
const char data[16]
Definition: mxf.c:149
OverlapIndex::buf_idx
int buf_idx
Definition: af_firequalizer.c:64
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:475
FIREqualizerContext::rdft_fn
av_tx_fn rdft_fn
Definition: af_firequalizer.c:76
FIREqualizerContext::rdft_len
int rdft_len
Definition: af_firequalizer.c:86
AVComplexFloat
Definition: tx.h:27
FIREqualizerContext::analysis_rdft_fn
av_tx_fn analysis_rdft_fn
Definition: af_firequalizer.c:72
VarOffset
VarOffset
Definition: af_firequalizer.c:529
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:205
AVChannelLayout::nb_channels
int nb_channels
Number of channels in this layout.
Definition: channel_layout.h:327
SCALE_LOGLOG
@ SCALE_LOGLOG
Definition: af_firequalizer.c:53
FIREqualizerContext::wfunc
int wfunc
Definition: af_firequalizer.c:112
av_tx_init
av_cold int av_tx_init(AVTXContext **ctx, av_tx_fn *tx, enum AVTXType type, int inv, int len, const void *scale, uint64_t flags)
Initialize a transform context with the given configuration (i)MDCTs with an odd length are currently...
Definition: tx.c:903
SELECT_GAIN_ENTRY
#define SELECT_GAIN_ENTRY(s)
Definition: af_firequalizer.c:724
FIREqualizerContext::nb_gain_entry
int nb_gain_entry
Definition: af_firequalizer.c:122
FIREqualizerContext
Definition: af_firequalizer.c:68
WFUNC_RECTANGULAR
@ WFUNC_RECTANGULAR
Definition: af_firequalizer.c:36
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:710
NB_GAIN_ENTRY_MAX
#define NB_GAIN_ENTRY_MAX
Definition: af_firequalizer.c:57
VAR_CHLAYOUT
@ VAR_CHLAYOUT
Definition: af_firequalizer.c:535
FIREqualizerContext::fft_fn
av_tx_fn fft_fn
Definition: af_firequalizer.c:80
WFUNC_BLACKMAN
@ WFUNC_BLACKMAN
Definition: af_firequalizer.c:39
AVComplexFloat::im
float im
Definition: tx.h:28
generate_min_phase_kernel
static void generate_min_phase_kernel(FIREqualizerContext *s, float *rdft_buf)
Definition: af_firequalizer.c:539
firequalizer_outputs
static const AVFilterPad firequalizer_outputs[]
Definition: af_firequalizer.c:950
ff_af_firequalizer
const AVFilter ff_af_firequalizer
Definition: af_firequalizer.c:958
firequalizer_inputs
static const AVFilterPad firequalizer_inputs[]
Definition: af_firequalizer.c:940
FIREqualizerContext::tx_buf
float * tx_buf
Definition: af_firequalizer.c:95
WindowFunc
WindowFunc
Definition: af_firequalizer.c:35
VAR_SR
@ VAR_SR
Definition: af_firequalizer.c:531
GainEntry::gain
double gain
Definition: af_firequalizer.c:60
RDFT_BITS_MAX
#define RDFT_BITS_MAX
Definition: af_firequalizer.c:33
request_frame
static int request_frame(AVFilterLink *outlink)
Definition: af_firequalizer.c:869
FIREqualizerContext::conv_idx
OverlapIndex * conv_idx
Definition: af_firequalizer.c:99
cubic_interpolate_func
static double cubic_interpolate_func(void *p, double freq)
Definition: af_firequalizer.c:474
av_expr_free
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:358
FIREqualizerContext::cepstrum_rdft_fn
av_tx_fn cepstrum_rdft_fn
Definition: af_firequalizer.c:82
AVFilterPad
A filter pad used for either input or output.
Definition: filters.h:38
SELECT_GAIN
#define SELECT_GAIN(s)
Definition: af_firequalizer.c:723
FIREqualizerContext::cepstrum_irdft
AVTXContext * cepstrum_irdft
Definition: af_firequalizer.c:83
avassert.h
FIREqualizerContext::scale
int scale
Definition: af_firequalizer.c:116
VAR_CHID
@ VAR_CHID
Definition: af_firequalizer.c:533
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
av_cold
#define av_cold
Definition: attributes.h:90
av_tx_fn
void(* av_tx_fn)(AVTXContext *s, void *out, void *in, ptrdiff_t stride)
Function pointer to a function to perform the transform.
Definition: tx.h:151
WFUNC_NUTTALL
@ WFUNC_NUTTALL
Definition: af_firequalizer.c:42
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: af_firequalizer.c:191
s
#define s(width, name)
Definition: cbs_vp9.c:198
AV_OPT_TYPE_DOUBLE
@ AV_OPT_TYPE_DOUBLE
Underlying C type is double.
Definition: opt.h:267
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:40
WFUNC_NUTTALL3
@ WFUNC_NUTTALL3
Definition: af_firequalizer.c:40
filters.h
AV_TX_FLOAT_FFT
@ AV_TX_FLOAT_FFT
Standard complex to complex FFT with sample data type of AVComplexFloat, AVComplexDouble or AVComplex...
Definition: tx.h:47
fast_convolute_nonlinear
static void fast_convolute_nonlinear(FIREqualizerContext *restrict s, const float *restrict kernel_buf, float *restrict conv_buf, OverlapIndex *restrict idx, float *restrict data, int nsamples)
Definition: af_firequalizer.c:237
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:230
FIREqualizerContext::min_phase
int min_phase
Definition: af_firequalizer.c:120
ctx
AVFormatContext * ctx
Definition: movenc.c:49
av_expr_eval
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:792
WFUNC_BHARRIS
@ WFUNC_BHARRIS
Definition: af_firequalizer.c:44
OverlapIndex::overlap_idx
int overlap_idx
Definition: af_firequalizer.c:65
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:142
AVExpr
Definition: eval.c:158
key
const char * key
Definition: hwcontext_opencl.c:189
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: filters.h:263
file_open.h
if
if(ret)
Definition: filter_design.txt:179
SCALE_LINLIN
@ SCALE_LINLIN
Definition: af_firequalizer.c:50
FIREqualizerContext::analysis_rdft_len
int analysis_rdft_len
Definition: af_firequalizer.c:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:75
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:123
vars
static const uint8_t vars[2][12]
Definition: camellia.c:183
FLAGS
#define FLAGS
Definition: af_firequalizer.c:128
WFUNC_HAMMING
@ WFUNC_HAMMING
Definition: af_firequalizer.c:38
isnan
#define isnan(x)
Definition: libm.h:340
GainEntry
Definition: af_firequalizer.c:58
fast_convolute2
static void fast_convolute2(FIREqualizerContext *restrict s, const float *restrict kernel_buf, AVComplexFloat *restrict conv_buf, OverlapIndex *restrict idx, float *restrict data0, float *restrict data1, int nsamples)
Definition: af_firequalizer.c:276
FIREqualizerContext::zero_phase
int zero_phase
Definition: af_firequalizer.c:115
entry_func
static double entry_func(void *p, double freq, double gain)
Definition: af_firequalizer.c:398
FIREqualizerContext::gain
const char * gain
Definition: af_firequalizer.c:108
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(firequalizer)
isinf
#define isinf(x)
Definition: libm.h:317
FIREqualizerContext::cepstrum_irdft_fn
av_tx_fn cepstrum_irdft_fn
Definition: af_firequalizer.c:84
double
double
Definition: af_crystalizer.c:132
OFFSET
#define OFFSET(x)
Definition: af_firequalizer.c:127
exp
int8_t exp
Definition: eval.c:73
var_names
static const char *const var_names[]
Definition: af_firequalizer.c:519
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
ff_filter_link
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition: filters.h:197
VAR_CHS
@ VAR_CHS
Definition: af_firequalizer.c:534
FIREqualizerContext::gain_entry_cmd
char * gain_entry_cmd
Definition: af_firequalizer.c:107
FIREqualizerContext::irdft_fn
av_tx_fn irdft_fn
Definition: af_firequalizer.c:78
eval.h
AVFILTERPAD_FLAG_NEEDS_WRITABLE
#define AVFILTERPAD_FLAG_NEEDS_WRITABLE
The filter expects writable frames from its input link, duplicating data buffers if needed.
Definition: filters.h:57
FILTER_SINGLE_SAMPLEFMT
#define FILTER_SINGLE_SAMPLEFMT(sample_fmt_)
Definition: filters.h:255
RDFT_BITS_MIN
#define RDFT_BITS_MIN
Definition: af_firequalizer.c:32
TFLAGS
#define TFLAGS
Definition: af_firequalizer.c:129
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:94
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:803
FIREqualizerContext::analysis_buf
float * analysis_buf
Definition: af_firequalizer.c:89
av_make_q
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition: rational.h:71
AVComplexFloat::re
float re
Definition: tx.h:28
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
WFUNC_TUKEY
@ WFUNC_TUKEY
Definition: af_firequalizer.c:45
FIREqualizerContext::fir_len
int fir_len
Definition: af_firequalizer.c:100
firequalizer_options
static const AVOption firequalizer_options[]
Definition: af_firequalizer.c:131
VAR_NB
@ VAR_NB
Definition: af_firequalizer.c:536
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:92
AV_CHANNEL_ORDER_NATIVE
@ AV_CHANNEL_ORDER_NATIVE
The native channel order, i.e.
Definition: channel_layout.h:125
M_PI
#define M_PI
Definition: mathematics.h:67
av_tx_uninit
av_cold void av_tx_uninit(AVTXContext **ctx)
Frees a context and sets *ctx to NULL, does nothing when *ctx == NULL.
Definition: tx.c:295
FIREqualizerContext::cepstrum_buf
float * cepstrum_buf
Definition: af_firequalizer.c:96
FIREqualizerContext::remaining
int remaining
Definition: af_firequalizer.c:104
VAR_CH
@ VAR_CH
Definition: af_firequalizer.c:532
WFUNC_HANN
@ WFUNC_HANN
Definition: af_firequalizer.c:37
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
FIREqualizerContext::conv_buf
float * conv_buf
Definition: af_firequalizer.c:98
SCALE_LINLOG
@ SCALE_LINLOG
Definition: af_firequalizer.c:51
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:31
FIREqualizerContext::rdft
AVTXContext * rdft
Definition: af_firequalizer.c:75
FIREqualizerContext::dump_buf
float * dump_buf
Definition: af_firequalizer.c:91
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:124
Scale
Scale
Definition: af_firequalizer.c:49
VAR_F
@ VAR_F
Definition: af_firequalizer.c:530
AVFilterPad::name
const char * name
Pad name.
Definition: filters.h:44
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:891
avpriv_fopen_utf8
FILE * avpriv_fopen_utf8(const char *path, const char *mode)
Open a file using a UTF-8 filename.
Definition: file_open.c:161
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
FIREqualizerContext::kernel_buf
float * kernel_buf
Definition: af_firequalizer.c:94
log2
#define log2(x)
Definition: libm.h:404
FIREqualizerContext::next_pts
int64_t next_pts
Definition: af_firequalizer.c:102
AVFilter
Filter definition.
Definition: avfilter.h:201
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:52
FIREqualizerContext::accuracy
double accuracy
Definition: af_firequalizer.c:111
FIREqualizerContext::analysis_irdft
AVTXContext * analysis_irdft
Definition: af_firequalizer.c:73
AV_TX_FLOAT_RDFT
@ AV_TX_FLOAT_RDFT
Real to complex and complex to real DFTs.
Definition: tx.h:90
FIREqualizerContext::cepstrum_rdft
AVTXContext * cepstrum_rdft
Definition: af_firequalizer.c:81
NB_WFUNC
@ NB_WFUNC
Definition: af_firequalizer.c:46
FIREqualizerContext::analysis_rdft
AVTXContext * analysis_rdft
Definition: af_firequalizer.c:71
channel_layout.h
FIREqualizerContext::cepstrum_tbuf
float * cepstrum_tbuf
Definition: af_firequalizer.c:97
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:259
avfilter.h
FIREqualizerContext::fixed
int fixed
Definition: af_firequalizer.c:113
FIREqualizerContext::dumpscale
int dumpscale
Definition: af_firequalizer.c:118
FIREqualizerContext::nsamples_max
int nsamples_max
Definition: af_firequalizer.c:101
AVFilterContext
An instance of a filter.
Definition: avfilter.h:457
common_uninit
static void common_uninit(FIREqualizerContext *s)
Definition: af_firequalizer.c:164
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:272
WFUNC_BNUTTALL
@ WFUNC_BNUTTALL
Definition: af_firequalizer.c:43
mem.h
audio.h
gain_entry_compare
static int gain_entry_compare(const void *key, const void *memb)
Definition: af_firequalizer.c:427
scale
static void scale(int *out, const int *in, const int w, const int h, const int shift)
Definition: intra.c:291
FIREqualizerContext::gain_entry
const char * gain_entry
Definition: af_firequalizer.c:109
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:327
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
fixed
#define fixed(width, name, value)
Definition: cbs_av1.c:487
fast_convolute
static void fast_convolute(FIREqualizerContext *restrict s, const float *restrict kernel_buf, float *restrict conv_buf, OverlapIndex *restrict idx, float *restrict data, int nsamples)
Definition: af_firequalizer.c:200
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:482
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
FIREqualizerContext::fft2
int fft2
Definition: af_firequalizer.c:119
NB_SCALE
@ NB_SCALE
Definition: af_firequalizer.c:54
config_input
static int config_input(AVFilterLink *inlink)
Definition: af_firequalizer.c:726
OverlapIndex
Definition: af_firequalizer.c:63
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:276
FIREqualizerContext::delay
double delay
Definition: af_firequalizer.c:110
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition: opt.h:299
dump_fir
static void dump_fir(AVFilterContext *ctx, FILE *fp, int ch)
Definition: af_firequalizer.c:339
tx.h
FIREqualizerContext::multi
int multi
Definition: af_firequalizer.c:114
WFUNC_MNUTTALL3
@ WFUNC_MNUTTALL3
Definition: af_firequalizer.c:41
FIREqualizerContext::dumpfile
char * dumpfile
Definition: af_firequalizer.c:117