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