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