LCOV - code coverage report
Current view: top level - src/libavfilter - af_firequalizer.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 274 435 63.0 %
Date: 2017-07-24 01:16:58 Functions: 12 15 80.0 %

          Line data    Source code
       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             : 
      21             : #include "libavutil/opt.h"
      22             : #include "libavutil/eval.h"
      23             : #include "libavutil/avassert.h"
      24             : #include "libavcodec/avfft.h"
      25             : #include "avfilter.h"
      26             : #include "internal.h"
      27             : #include "audio.h"
      28             : 
      29             : #define RDFT_BITS_MIN 4
      30             : #define RDFT_BITS_MAX 16
      31             : 
      32             : enum WindowFunc {
      33             :     WFUNC_RECTANGULAR,
      34             :     WFUNC_HANN,
      35             :     WFUNC_HAMMING,
      36             :     WFUNC_BLACKMAN,
      37             :     WFUNC_NUTTALL3,
      38             :     WFUNC_MNUTTALL3,
      39             :     WFUNC_NUTTALL,
      40             :     WFUNC_BNUTTALL,
      41             :     WFUNC_BHARRIS,
      42             :     WFUNC_TUKEY,
      43             :     NB_WFUNC
      44             : };
      45             : 
      46             : enum Scale {
      47             :     SCALE_LINLIN,
      48             :     SCALE_LINLOG,
      49             :     SCALE_LOGLIN,
      50             :     SCALE_LOGLOG,
      51             :     NB_SCALE
      52             : };
      53             : 
      54             : #define NB_GAIN_ENTRY_MAX 4096
      55             : typedef struct GainEntry {
      56             :     double  freq;
      57             :     double  gain;
      58             : } GainEntry;
      59             : 
      60             : typedef struct OverlapIndex {
      61             :     int buf_idx;
      62             :     int overlap_idx;
      63             : } OverlapIndex;
      64             : 
      65             : typedef struct FIREqualizerContext {
      66             :     const AVClass *class;
      67             : 
      68             :     RDFTContext   *analysis_rdft;
      69             :     RDFTContext   *analysis_irdft;
      70             :     RDFTContext   *rdft;
      71             :     RDFTContext   *irdft;
      72             :     FFTContext    *fft_ctx;
      73             :     int           analysis_rdft_len;
      74             :     int           rdft_len;
      75             : 
      76             :     float         *analysis_buf;
      77             :     float         *dump_buf;
      78             :     float         *kernel_tmp_buf;
      79             :     float         *kernel_buf;
      80             :     float         *conv_buf;
      81             :     OverlapIndex  *conv_idx;
      82             :     int           fir_len;
      83             :     int           nsamples_max;
      84             :     int64_t       next_pts;
      85             :     int           frame_nsamples_max;
      86             :     int           remaining;
      87             : 
      88             :     char          *gain_cmd;
      89             :     char          *gain_entry_cmd;
      90             :     const char    *gain;
      91             :     const char    *gain_entry;
      92             :     double        delay;
      93             :     double        accuracy;
      94             :     int           wfunc;
      95             :     int           fixed;
      96             :     int           multi;
      97             :     int           zero_phase;
      98             :     int           scale;
      99             :     char          *dumpfile;
     100             :     int           dumpscale;
     101             :     int           fft2;
     102             : 
     103             :     int           nb_gain_entry;
     104             :     int           gain_entry_err;
     105             :     GainEntry     gain_entry_tbl[NB_GAIN_ENTRY_MAX];
     106             : } FIREqualizerContext;
     107             : 
     108             : #define OFFSET(x) offsetof(FIREqualizerContext, x)
     109             : #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
     110             : 
     111             : static const AVOption firequalizer_options[] = {
     112             :     { "gain", "set gain curve", OFFSET(gain), AV_OPT_TYPE_STRING, { .str = "gain_interpolate(f)" }, 0, 0, FLAGS },
     113             :     { "gain_entry", "set gain entry", OFFSET(gain_entry), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },
     114             :     { "delay", "set delay", OFFSET(delay), AV_OPT_TYPE_DOUBLE, { .dbl = 0.01 }, 0.0, 1e10, FLAGS },
     115             :     { "accuracy", "set accuracy", OFFSET(accuracy), AV_OPT_TYPE_DOUBLE, { .dbl = 5.0 }, 0.0, 1e10, FLAGS },
     116             :     { "wfunc", "set window function", OFFSET(wfunc), AV_OPT_TYPE_INT, { .i64 = WFUNC_HANN }, 0, NB_WFUNC-1, FLAGS, "wfunc" },
     117             :         { "rectangular", "rectangular window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_RECTANGULAR }, 0, 0, FLAGS, "wfunc" },
     118             :         { "hann", "hann window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_HANN }, 0, 0, FLAGS, "wfunc" },
     119             :         { "hamming", "hamming window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_HAMMING }, 0, 0, FLAGS, "wfunc" },
     120             :         { "blackman", "blackman window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_BLACKMAN }, 0, 0, FLAGS, "wfunc" },
     121             :         { "nuttall3", "3-term nuttall window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_NUTTALL3 }, 0, 0, FLAGS, "wfunc" },
     122             :         { "mnuttall3", "minimum 3-term nuttall window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_MNUTTALL3 }, 0, 0, FLAGS, "wfunc" },
     123             :         { "nuttall", "nuttall window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_NUTTALL }, 0, 0, FLAGS, "wfunc" },
     124             :         { "bnuttall", "blackman-nuttall window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_BNUTTALL }, 0, 0, FLAGS, "wfunc" },
     125             :         { "bharris", "blackman-harris window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_BHARRIS }, 0, 0, FLAGS, "wfunc" },
     126             :         { "tukey", "tukey window", 0, AV_OPT_TYPE_CONST, { .i64 = WFUNC_TUKEY }, 0, 0, FLAGS, "wfunc" },
     127             :     { "fixed", "set fixed frame samples", OFFSET(fixed), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
     128             :     { "multi", "set multi channels mode", OFFSET(multi), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
     129             :     { "zero_phase", "set zero phase mode", OFFSET(zero_phase), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
     130             :     { "scale", "set gain scale", OFFSET(scale), AV_OPT_TYPE_INT, { .i64 = SCALE_LINLOG }, 0, NB_SCALE-1, FLAGS, "scale" },
     131             :         { "linlin", "linear-freq linear-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LINLIN }, 0, 0, FLAGS, "scale" },
     132             :         { "linlog", "linear-freq logarithmic-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LINLOG }, 0, 0, FLAGS, "scale" },
     133             :         { "loglin", "logarithmic-freq linear-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LOGLIN }, 0, 0, FLAGS, "scale" },
     134             :         { "loglog", "logarithmic-freq logarithmic-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LOGLOG }, 0, 0, FLAGS, "scale" },
     135             :     { "dumpfile", "set dump file", OFFSET(dumpfile), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },
     136             :     { "dumpscale", "set dump scale", OFFSET(dumpscale), AV_OPT_TYPE_INT, { .i64 = SCALE_LINLOG }, 0, NB_SCALE-1, FLAGS, "scale" },
     137             :     { "fft2", "set 2-channels fft", OFFSET(fft2), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
     138             :     { NULL }
     139             : };
     140             : 
     141             : AVFILTER_DEFINE_CLASS(firequalizer);
     142             : 
     143          10 : static void common_uninit(FIREqualizerContext *s)
     144             : {
     145          10 :     av_rdft_end(s->analysis_rdft);
     146          10 :     av_rdft_end(s->analysis_irdft);
     147          10 :     av_rdft_end(s->rdft);
     148          10 :     av_rdft_end(s->irdft);
     149          10 :     av_fft_end(s->fft_ctx);
     150          10 :     s->analysis_rdft = s->analysis_irdft = s->rdft = s->irdft = NULL;
     151          10 :     s->fft_ctx = NULL;
     152             : 
     153          10 :     av_freep(&s->analysis_buf);
     154          10 :     av_freep(&s->dump_buf);
     155          10 :     av_freep(&s->kernel_tmp_buf);
     156          10 :     av_freep(&s->kernel_buf);
     157          10 :     av_freep(&s->conv_buf);
     158          10 :     av_freep(&s->conv_idx);
     159          10 : }
     160             : 
     161           5 : static av_cold void uninit(AVFilterContext *ctx)
     162             : {
     163           5 :     FIREqualizerContext *s = ctx->priv;
     164             : 
     165           5 :     common_uninit(s);
     166           5 :     av_freep(&s->gain_cmd);
     167           5 :     av_freep(&s->gain_entry_cmd);
     168           5 : }
     169             : 
     170           5 : static int query_formats(AVFilterContext *ctx)
     171             : {
     172             :     AVFilterChannelLayouts *layouts;
     173             :     AVFilterFormats *formats;
     174             :     static const enum AVSampleFormat sample_fmts[] = {
     175             :         AV_SAMPLE_FMT_FLTP,
     176             :         AV_SAMPLE_FMT_NONE
     177             :     };
     178             :     int ret;
     179             : 
     180           5 :     layouts = ff_all_channel_counts();
     181           5 :     if (!layouts)
     182           0 :         return AVERROR(ENOMEM);
     183           5 :     ret = ff_set_common_channel_layouts(ctx, layouts);
     184           5 :     if (ret < 0)
     185           0 :         return ret;
     186             : 
     187           5 :     formats = ff_make_format_list(sample_fmts);
     188           5 :     if (!formats)
     189           0 :         return AVERROR(ENOMEM);
     190           5 :     ret = ff_set_common_formats(ctx, formats);
     191           5 :     if (ret < 0)
     192           0 :         return ret;
     193             : 
     194           5 :     formats = ff_all_samplerates();
     195           5 :     if (!formats)
     196           0 :         return AVERROR(ENOMEM);
     197           5 :     return ff_set_common_samplerates(ctx, formats);
     198             : }
     199             : 
     200         914 : static void fast_convolute(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf, float *av_restrict conv_buf,
     201             :                            OverlapIndex *av_restrict idx, float *av_restrict data, int nsamples)
     202             : {
     203         914 :     if (nsamples <= s->nsamples_max) {
     204         760 :         float *buf = conv_buf + idx->buf_idx * s->rdft_len;
     205         760 :         float *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx;
     206         760 :         int center = s->fir_len/2;
     207             :         int k;
     208             : 
     209         760 :         memset(buf, 0, center * sizeof(*data));
     210         760 :         memcpy(buf + center, data, nsamples * sizeof(*data));
     211         760 :         memset(buf + center + nsamples, 0, (s->rdft_len - nsamples - center) * sizeof(*data));
     212         760 :         av_rdft_calc(s->rdft, buf);
     213             : 
     214         760 :         buf[0] *= kernel_buf[0];
     215         760 :         buf[1] *= kernel_buf[s->rdft_len/2];
     216     1802240 :         for (k = 1; k < s->rdft_len/2; k++) {
     217     1801480 :             buf[2*k] *= kernel_buf[k];
     218     1801480 :             buf[2*k+1] *= kernel_buf[k];
     219             :         }
     220             : 
     221         760 :         av_rdft_calc(s->irdft, buf);
     222     1924014 :         for (k = 0; k < s->rdft_len - idx->overlap_idx; k++)
     223     1923254 :             buf[k] += obuf[k];
     224         760 :         memcpy(data, buf, nsamples * sizeof(*data));
     225         760 :         idx->buf_idx = !idx->buf_idx;
     226         760 :         idx->overlap_idx = nsamples;
     227             :     } else {
     228         676 :         while (nsamples > s->nsamples_max * 2) {
     229         368 :             fast_convolute(s, kernel_buf, conv_buf, idx, data, s->nsamples_max);
     230         368 :             data += s->nsamples_max;
     231         368 :             nsamples -= s->nsamples_max;
     232             :         }
     233         154 :         fast_convolute(s, kernel_buf, conv_buf, idx, data, nsamples/2);
     234         154 :         fast_convolute(s, kernel_buf, conv_buf, idx, data + nsamples/2, nsamples - nsamples/2);
     235             :     }
     236         914 : }
     237             : 
     238         561 : static void fast_convolute2(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf, FFTComplex *av_restrict conv_buf,
     239             :                             OverlapIndex *av_restrict idx, float *av_restrict data0, float *av_restrict data1, int nsamples)
     240             : {
     241         561 :     if (nsamples <= s->nsamples_max) {
     242         523 :         FFTComplex *buf = conv_buf + idx->buf_idx * s->rdft_len;
     243         523 :         FFTComplex *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx;
     244         523 :         int center = s->fir_len/2;
     245             :         int k;
     246             :         float tmp;
     247             : 
     248         523 :         memset(buf, 0, center * sizeof(*buf));
     249      548245 :         for (k = 0; k < nsamples; k++) {
     250      547722 :             buf[center+k].re = data0[k];
     251      547722 :             buf[center+k].im = data1[k];
     252             :         }
     253         523 :         memset(buf + center + nsamples, 0, (s->rdft_len - nsamples - center) * sizeof(*buf));
     254         523 :         av_fft_permute(s->fft_ctx, buf);
     255         523 :         av_fft_calc(s->fft_ctx, buf);
     256             : 
     257             :         /* swap re <-> im, do backward fft using forward fft_ctx */
     258             :         /* normalize with 0.5f */
     259         523 :         tmp = buf[0].re;
     260         523 :         buf[0].re = 0.5f * kernel_buf[0] * buf[0].im;
     261         523 :         buf[0].im = 0.5f * kernel_buf[0] * tmp;
     262     1346560 :         for (k = 1; k < s->rdft_len/2; k++) {
     263     1346037 :             int m = s->rdft_len - k;
     264     1346037 :             tmp = buf[k].re;
     265     1346037 :             buf[k].re = 0.5f * kernel_buf[k] * buf[k].im;
     266     1346037 :             buf[k].im = 0.5f * kernel_buf[k] * tmp;
     267     1346037 :             tmp = buf[m].re;
     268     1346037 :             buf[m].re = 0.5f * kernel_buf[k] * buf[m].im;
     269     1346037 :             buf[m].im = 0.5f * kernel_buf[k] * tmp;
     270             :         }
     271         523 :         tmp = buf[k].re;
     272         523 :         buf[k].re = 0.5f * kernel_buf[k] * buf[k].im;
     273         523 :         buf[k].im = 0.5f * kernel_buf[k] * tmp;
     274             : 
     275         523 :         av_fft_permute(s->fft_ctx, buf);
     276         523 :         av_fft_calc(s->fft_ctx, buf);
     277             : 
     278     2147117 :         for (k = 0; k < s->rdft_len - idx->overlap_idx; k++) {
     279     2146594 :             buf[k].re += obuf[k].re;
     280     2146594 :             buf[k].im += obuf[k].im;
     281             :         }
     282             : 
     283             :         /* swapped re <-> im */
     284      548245 :         for (k = 0; k < nsamples; k++) {
     285      547722 :             data0[k] = buf[k].im;
     286      547722 :             data1[k] = buf[k].re;
     287             :         }
     288         523 :         idx->buf_idx = !idx->buf_idx;
     289         523 :         idx->overlap_idx = nsamples;
     290             :     } else {
     291         258 :         while (nsamples > s->nsamples_max * 2) {
     292         182 :             fast_convolute2(s, kernel_buf, conv_buf, idx, data0, data1, s->nsamples_max);
     293         182 :             data0 += s->nsamples_max;
     294         182 :             data1 += s->nsamples_max;
     295         182 :             nsamples -= s->nsamples_max;
     296             :         }
     297          38 :         fast_convolute2(s, kernel_buf, conv_buf, idx, data0, data1, nsamples/2);
     298          38 :         fast_convolute2(s, kernel_buf, conv_buf, idx, data0 + nsamples/2, data1 + nsamples/2, nsamples - nsamples/2);
     299             :     }
     300         561 : }
     301             : 
     302           0 : static void dump_fir(AVFilterContext *ctx, FILE *fp, int ch)
     303             : {
     304           0 :     FIREqualizerContext *s = ctx->priv;
     305           0 :     int rate = ctx->inputs[0]->sample_rate;
     306           0 :     int xlog = s->dumpscale == SCALE_LOGLIN || s->dumpscale == SCALE_LOGLOG;
     307           0 :     int ylog = s->dumpscale == SCALE_LINLOG || s->dumpscale == SCALE_LOGLOG;
     308             :     int x;
     309           0 :     int center = s->fir_len / 2;
     310           0 :     double delay = s->zero_phase ? 0.0 : (double) center / rate;
     311             :     double vx, ya, yb;
     312             : 
     313           0 :     s->analysis_buf[0] *= s->rdft_len/2;
     314           0 :     for (x = 1; x <= center; x++) {
     315           0 :         s->analysis_buf[x] *= s->rdft_len/2;
     316           0 :         s->analysis_buf[s->analysis_rdft_len - x] *= s->rdft_len/2;
     317             :     }
     318             : 
     319           0 :     if (ch)
     320           0 :         fprintf(fp, "\n\n");
     321             : 
     322           0 :     fprintf(fp, "# time[%d] (time amplitude)\n", ch);
     323             : 
     324           0 :     for (x = center; x > 0; x--)
     325           0 :         fprintf(fp, "%15.10f %15.10f\n", delay - (double) x / rate, (double) s->analysis_buf[s->analysis_rdft_len - x]);
     326             : 
     327           0 :     for (x = 0; x <= center; x++)
     328           0 :         fprintf(fp, "%15.10f %15.10f\n", delay + (double)x / rate , (double) s->analysis_buf[x]);
     329             : 
     330           0 :     av_rdft_calc(s->analysis_rdft, s->analysis_buf);
     331             : 
     332           0 :     fprintf(fp, "\n\n# freq[%d] (frequency desired_gain actual_gain)\n", ch);
     333             : 
     334           0 :     for (x = 0; x <= s->analysis_rdft_len/2; x++) {
     335           0 :         int i = (x == s->analysis_rdft_len/2) ? 1 : 2 * x;
     336           0 :         vx = (double)x * rate / s->analysis_rdft_len;
     337           0 :         if (xlog)
     338           0 :             vx = log2(0.05*vx);
     339           0 :         ya = s->dump_buf[i];
     340           0 :         yb = s->analysis_buf[i];
     341           0 :         if (ylog) {
     342           0 :             ya = 20.0 * log10(fabs(ya));
     343           0 :             yb = 20.0 * log10(fabs(yb));
     344             :         }
     345           0 :         fprintf(fp, "%17.10f %17.10f %17.10f\n", vx, ya, yb);
     346             :     }
     347           0 : }
     348             : 
     349           6 : static double entry_func(void *p, double freq, double gain)
     350             : {
     351           6 :     AVFilterContext *ctx = p;
     352           6 :     FIREqualizerContext *s = ctx->priv;
     353             : 
     354           6 :     if (s->nb_gain_entry >= NB_GAIN_ENTRY_MAX) {
     355           0 :         av_log(ctx, AV_LOG_ERROR, "entry table overflow.\n");
     356           0 :         s->gain_entry_err = AVERROR(EINVAL);
     357           0 :         return 0;
     358             :     }
     359             : 
     360           6 :     if (isnan(freq)) {
     361           0 :         av_log(ctx, AV_LOG_ERROR, "nan frequency (%g, %g).\n", freq, gain);
     362           0 :         s->gain_entry_err = AVERROR(EINVAL);
     363           0 :         return 0;
     364             :     }
     365             : 
     366           6 :     if (s->nb_gain_entry > 0 && freq <= s->gain_entry_tbl[s->nb_gain_entry - 1].freq) {
     367           0 :         av_log(ctx, AV_LOG_ERROR, "unsorted frequency (%g, %g).\n", freq, gain);
     368           0 :         s->gain_entry_err = AVERROR(EINVAL);
     369           0 :         return 0;
     370             :     }
     371             : 
     372           6 :     s->gain_entry_tbl[s->nb_gain_entry].freq = freq;
     373           6 :     s->gain_entry_tbl[s->nb_gain_entry].gain = gain;
     374           6 :     s->nb_gain_entry++;
     375           6 :     return 0;
     376             : }
     377             : 
     378        9660 : static int gain_entry_compare(const void *key, const void *memb)
     379             : {
     380        9660 :     const double *freq = key;
     381        9660 :     const GainEntry *entry = memb;
     382             : 
     383        9660 :     if (*freq < entry[0].freq)
     384        2972 :         return -1;
     385        6688 :     if (*freq > entry[1].freq)
     386           0 :         return 1;
     387        6688 :     return 0;
     388             : }
     389             : 
     390       16386 : static double gain_interpolate_func(void *p, double freq)
     391             : {
     392       16386 :     AVFilterContext *ctx = p;
     393       16386 :     FIREqualizerContext *s = ctx->priv;
     394             :     GainEntry *res;
     395             :     double d0, d1, d;
     396             : 
     397       16386 :     if (isnan(freq))
     398           0 :         return freq;
     399             : 
     400       16386 :     if (!s->nb_gain_entry)
     401           0 :         return 0;
     402             : 
     403       16386 :     if (freq <= s->gain_entry_tbl[0].freq)
     404         744 :         return s->gain_entry_tbl[0].gain;
     405             : 
     406       15642 :     if (freq >= s->gain_entry_tbl[s->nb_gain_entry-1].freq)
     407        8954 :         return s->gain_entry_tbl[s->nb_gain_entry-1].gain;
     408             : 
     409        6688 :     res = bsearch(&freq, &s->gain_entry_tbl, s->nb_gain_entry - 1, sizeof(*res), gain_entry_compare);
     410        6688 :     av_assert0(res);
     411             : 
     412        6688 :     d  = res[1].freq - res[0].freq;
     413        6688 :     d0 = freq - res[0].freq;
     414        6688 :     d1 = res[1].freq - freq;
     415             : 
     416        6688 :     if (d0 && d1)
     417        6688 :         return (d0 * res[1].gain + d1 * res[0].gain) / d;
     418             : 
     419           0 :     if (d0)
     420           0 :         return res[1].gain;
     421             : 
     422           0 :     return res[0].gain;
     423             : }
     424             : 
     425           0 : static double cubic_interpolate_func(void *p, double freq)
     426             : {
     427           0 :     AVFilterContext *ctx = p;
     428           0 :     FIREqualizerContext *s = ctx->priv;
     429             :     GainEntry *res;
     430             :     double x, x2, x3;
     431             :     double a, b, c, d;
     432             :     double m0, m1, m2, msum, unit;
     433             : 
     434           0 :     if (!s->nb_gain_entry)
     435           0 :         return 0;
     436             : 
     437           0 :     if (freq <= s->gain_entry_tbl[0].freq)
     438           0 :         return s->gain_entry_tbl[0].gain;
     439             : 
     440           0 :     if (freq >= s->gain_entry_tbl[s->nb_gain_entry-1].freq)
     441           0 :         return s->gain_entry_tbl[s->nb_gain_entry-1].gain;
     442             : 
     443           0 :     res = bsearch(&freq, &s->gain_entry_tbl, s->nb_gain_entry - 1, sizeof(*res), gain_entry_compare);
     444           0 :     av_assert0(res);
     445             : 
     446           0 :     unit = res[1].freq - res[0].freq;
     447           0 :     m0 = res != s->gain_entry_tbl ?
     448           0 :          unit * (res[0].gain - res[-1].gain) / (res[0].freq - res[-1].freq) : 0;
     449           0 :     m1 = res[1].gain - res[0].gain;
     450           0 :     m2 = res != s->gain_entry_tbl + s->nb_gain_entry - 2 ?
     451           0 :          unit * (res[2].gain - res[1].gain) / (res[2].freq - res[1].freq) : 0;
     452             : 
     453           0 :     msum = fabs(m0) + fabs(m1);
     454           0 :     m0 = msum > 0 ? (fabs(m0) * m1 + fabs(m1) * m0) / msum : 0;
     455           0 :     msum = fabs(m1) + fabs(m2);
     456           0 :     m1 = msum > 0 ? (fabs(m1) * m2 + fabs(m2) * m1) / msum : 0;
     457             : 
     458           0 :     d = res[0].gain;
     459           0 :     c = m0;
     460           0 :     b = 3 * res[1].gain - m1 - 2 * c - 3 * d;
     461           0 :     a = res[1].gain - b - c - d;
     462             : 
     463           0 :     x = (freq - res[0].freq) / unit;
     464           0 :     x2 = x * x;
     465           0 :     x3 = x2 * x;
     466             : 
     467           0 :     return a * x3 + b * x2 + c * x + d;
     468             : }
     469             : 
     470             : static const char *const var_names[] = {
     471             :     "f",
     472             :     "sr",
     473             :     "ch",
     474             :     "chid",
     475             :     "chs",
     476             :     "chlayout",
     477             :     NULL
     478             : };
     479             : 
     480             : enum VarOffset {
     481             :     VAR_F,
     482             :     VAR_SR,
     483             :     VAR_CH,
     484             :     VAR_CHID,
     485             :     VAR_CHS,
     486             :     VAR_CHLAYOUT,
     487             :     VAR_NB
     488             : };
     489             : 
     490           5 : static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *gain_entry)
     491             : {
     492           5 :     FIREqualizerContext *s = ctx->priv;
     493           5 :     AVFilterLink *inlink = ctx->inputs[0];
     494           5 :     const char *gain_entry_func_names[] = { "entry", NULL };
     495           5 :     const char *gain_func_names[] = { "gain_interpolate", "cubic_interpolate", NULL };
     496           5 :     double (*gain_entry_funcs[])(void *, double, double) = { entry_func, NULL };
     497           5 :     double (*gain_funcs[])(void *, double) = { gain_interpolate_func, cubic_interpolate_func, NULL };
     498             :     double vars[VAR_NB];
     499             :     AVExpr *gain_expr;
     500             :     int ret, k, center, ch;
     501           5 :     int xlog = s->scale == SCALE_LOGLIN || s->scale == SCALE_LOGLOG;
     502           5 :     int ylog = s->scale == SCALE_LINLOG || s->scale == SCALE_LOGLOG;
     503           5 :     FILE *dump_fp = NULL;
     504             : 
     505           5 :     s->nb_gain_entry = 0;
     506           5 :     s->gain_entry_err = 0;
     507           5 :     if (gain_entry) {
     508           2 :         double result = 0.0;
     509           2 :         ret = av_expr_parse_and_eval(&result, gain_entry, NULL, NULL, NULL, NULL,
     510             :                                      gain_entry_func_names, gain_entry_funcs, ctx, 0, ctx);
     511           2 :         if (ret < 0)
     512           0 :             return ret;
     513           2 :         if (s->gain_entry_err < 0)
     514           0 :             return s->gain_entry_err;
     515             :     }
     516             : 
     517           5 :     av_log(ctx, AV_LOG_DEBUG, "nb_gain_entry = %d.\n", s->nb_gain_entry);
     518             : 
     519           5 :     ret = av_expr_parse(&gain_expr, gain, var_names,
     520             :                         gain_func_names, gain_funcs, NULL, NULL, 0, ctx);
     521           5 :     if (ret < 0)
     522           0 :         return ret;
     523             : 
     524           5 :     if (s->dumpfile && (!s->dump_buf || !s->analysis_rdft || !(dump_fp = fopen(s->dumpfile, "w"))))
     525           0 :         av_log(ctx, AV_LOG_WARNING, "dumping failed.\n");
     526             : 
     527           5 :     vars[VAR_CHS] = inlink->channels;
     528           5 :     vars[VAR_CHLAYOUT] = inlink->channel_layout;
     529           5 :     vars[VAR_SR] = inlink->sample_rate;
     530           9 :     for (ch = 0; ch < inlink->channels; ch++) {
     531           7 :         float *rdft_buf = s->kernel_tmp_buf + ch * s->rdft_len;
     532             :         double result;
     533           7 :         vars[VAR_CH] = ch;
     534           7 :         vars[VAR_CHID] = av_channel_layout_extract_channel(inlink->channel_layout, ch);
     535           7 :         vars[VAR_F] = 0.0;
     536           7 :         if (xlog)
     537           0 :             vars[VAR_F] = log2(0.05 * vars[VAR_F]);
     538           7 :         result = av_expr_eval(gain_expr, vars, ctx);
     539           7 :         s->analysis_buf[0] = ylog ? pow(10.0, 0.05 * result) : result;
     540             : 
     541           7 :         vars[VAR_F] = 0.5 * inlink->sample_rate;
     542           7 :         if (xlog)
     543           0 :             vars[VAR_F] = log2(0.05 * vars[VAR_F]);
     544           7 :         result = av_expr_eval(gain_expr, vars, ctx);
     545           7 :         s->analysis_buf[1] = ylog ? pow(10.0, 0.05 * result) : result;
     546             : 
     547       57344 :         for (k = 1; k < s->analysis_rdft_len/2; k++) {
     548       57337 :             vars[VAR_F] = k * ((double)inlink->sample_rate /(double)s->analysis_rdft_len);
     549       57337 :             if (xlog)
     550           0 :                 vars[VAR_F] = log2(0.05 * vars[VAR_F]);
     551       57337 :             result = av_expr_eval(gain_expr, vars, ctx);
     552       57337 :             s->analysis_buf[2*k] = ylog ? pow(10.0, 0.05 * result) : result;
     553       57337 :             s->analysis_buf[2*k+1] = 0.0;
     554             :         }
     555             : 
     556           7 :         if (s->dump_buf)
     557           0 :             memcpy(s->dump_buf, s->analysis_buf, s->analysis_rdft_len * sizeof(*s->analysis_buf));
     558             : 
     559           7 :         av_rdft_calc(s->analysis_irdft, s->analysis_buf);
     560           7 :         center = s->fir_len / 2;
     561             : 
     562       16331 :         for (k = 0; k <= center; k++) {
     563       16324 :             double u = k * (M_PI/center);
     564             :             double win;
     565       16324 :             switch (s->wfunc) {
     566           0 :             case WFUNC_RECTANGULAR:
     567           0 :                 win = 1.0;
     568           0 :                 break;
     569        7502 :             case WFUNC_HANN:
     570        7502 :                 win = 0.5 + 0.5 * cos(u);
     571        7502 :                 break;
     572           0 :             case WFUNC_HAMMING:
     573           0 :                 win = 0.53836 + 0.46164 * cos(u);
     574           0 :                 break;
     575           0 :             case WFUNC_BLACKMAN:
     576           0 :                 win = 0.42 + 0.5 * cos(u) + 0.08 * cos(2*u);
     577           0 :                 break;
     578           0 :             case WFUNC_NUTTALL3:
     579           0 :                 win = 0.40897 + 0.5 * cos(u) + 0.09103 * cos(2*u);
     580           0 :                 break;
     581           0 :             case WFUNC_MNUTTALL3:
     582           0 :                 win = 0.4243801 + 0.4973406 * cos(u) + 0.0782793 * cos(2*u);
     583           0 :                 break;
     584        8822 :             case WFUNC_NUTTALL:
     585        8822 :                 win = 0.355768 + 0.487396 * cos(u) + 0.144232 * cos(2*u) + 0.012604 * cos(3*u);
     586        8822 :                 break;
     587           0 :             case WFUNC_BNUTTALL:
     588           0 :                 win = 0.3635819 + 0.4891775 * cos(u) + 0.1365995 * cos(2*u) + 0.0106411 * cos(3*u);
     589           0 :                 break;
     590           0 :             case WFUNC_BHARRIS:
     591           0 :                 win = 0.35875 + 0.48829 * cos(u) + 0.14128 * cos(2*u) + 0.01168 * cos(3*u);
     592           0 :                 break;
     593           0 :             case WFUNC_TUKEY:
     594           0 :                 win = (u <= 0.5 * M_PI) ? 1.0 : (0.5 + 0.5 * cos(2*u - M_PI));
     595           0 :                 break;
     596           0 :             default:
     597           0 :                 av_assert0(0);
     598             :             }
     599       16324 :             s->analysis_buf[k] *= (2.0/s->analysis_rdft_len) * (2.0/s->rdft_len) * win;
     600       16324 :             if (k)
     601       16317 :                 s->analysis_buf[s->analysis_rdft_len - k] = s->analysis_buf[k];
     602             :         }
     603             : 
     604           7 :         memset(s->analysis_buf + center + 1, 0, (s->analysis_rdft_len - s->fir_len) * sizeof(*s->analysis_buf));
     605           7 :         memcpy(rdft_buf, s->analysis_buf, s->rdft_len/2 * sizeof(*s->analysis_buf));
     606           7 :         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));
     607           7 :         av_rdft_calc(s->rdft, rdft_buf);
     608             : 
     609       61447 :         for (k = 0; k < s->rdft_len; k++) {
     610       61440 :             if (isnan(rdft_buf[k]) || isinf(rdft_buf[k])) {
     611           0 :                 av_log(ctx, AV_LOG_ERROR, "filter kernel contains nan or infinity.\n");
     612           0 :                 av_expr_free(gain_expr);
     613           0 :                 if (dump_fp)
     614           0 :                     fclose(dump_fp);
     615           0 :                 return AVERROR(EINVAL);
     616             :             }
     617             :         }
     618             : 
     619           7 :         rdft_buf[s->rdft_len-1] = rdft_buf[1];
     620       30727 :         for (k = 0; k < s->rdft_len/2; k++)
     621       30720 :             rdft_buf[k] = rdft_buf[2*k];
     622           7 :         rdft_buf[s->rdft_len/2] = rdft_buf[s->rdft_len-1];
     623             : 
     624           7 :         if (dump_fp)
     625           0 :             dump_fir(ctx, dump_fp, ch);
     626             : 
     627           7 :         if (!s->multi)
     628           3 :             break;
     629             :     }
     630             : 
     631           5 :     memcpy(s->kernel_buf, s->kernel_tmp_buf, (s->multi ? inlink->channels : 1) * s->rdft_len * sizeof(*s->kernel_buf));
     632           5 :     av_expr_free(gain_expr);
     633           5 :     if (dump_fp)
     634           0 :         fclose(dump_fp);
     635           5 :     return 0;
     636             : }
     637             : 
     638             : #define SELECT_GAIN(s) (s->gain_cmd ? s->gain_cmd : s->gain)
     639             : #define SELECT_GAIN_ENTRY(s) (s->gain_entry_cmd ? s->gain_entry_cmd : s->gain_entry)
     640             : 
     641           5 : static int config_input(AVFilterLink *inlink)
     642             : {
     643           5 :     AVFilterContext *ctx = inlink->dst;
     644           5 :     FIREqualizerContext *s = ctx->priv;
     645             :     int rdft_bits;
     646             : 
     647           5 :     common_uninit(s);
     648             : 
     649           5 :     s->next_pts = 0;
     650           5 :     s->frame_nsamples_max = 0;
     651             : 
     652           5 :     s->fir_len = FFMAX(2 * (int)(inlink->sample_rate * s->delay) + 1, 3);
     653           5 :     s->remaining = s->fir_len - 1;
     654             : 
     655          47 :     for (rdft_bits = RDFT_BITS_MIN; rdft_bits <= RDFT_BITS_MAX; rdft_bits++) {
     656          47 :         s->rdft_len = 1 << rdft_bits;
     657          47 :         s->nsamples_max = s->rdft_len - s->fir_len + 1;
     658          47 :         if (s->nsamples_max * 2 >= s->fir_len)
     659           5 :             break;
     660             :     }
     661             : 
     662           5 :     if (rdft_bits > RDFT_BITS_MAX) {
     663           0 :         av_log(ctx, AV_LOG_ERROR, "too large delay, please decrease it.\n");
     664           0 :         return AVERROR(EINVAL);
     665             :     }
     666             : 
     667           5 :     if (!(s->rdft = av_rdft_init(rdft_bits, DFT_R2C)) || !(s->irdft = av_rdft_init(rdft_bits, IDFT_C2R)))
     668           0 :         return AVERROR(ENOMEM);
     669             : 
     670           5 :     if (s->fft2 && !s->multi && inlink->channels > 1 && !(s->fft_ctx = av_fft_init(rdft_bits, 0)))
     671           0 :         return AVERROR(ENOMEM);
     672             : 
     673          13 :     for ( ; rdft_bits <= RDFT_BITS_MAX; rdft_bits++) {
     674          13 :         s->analysis_rdft_len = 1 << rdft_bits;
     675          13 :         if (inlink->sample_rate <= s->accuracy * s->analysis_rdft_len)
     676           5 :             break;
     677             :     }
     678             : 
     679           5 :     if (rdft_bits > RDFT_BITS_MAX) {
     680           0 :         av_log(ctx, AV_LOG_ERROR, "too small accuracy, please increase it.\n");
     681           0 :         return AVERROR(EINVAL);
     682             :     }
     683             : 
     684           5 :     if (!(s->analysis_irdft = av_rdft_init(rdft_bits, IDFT_C2R)))
     685           0 :         return AVERROR(ENOMEM);
     686             : 
     687           5 :     if (s->dumpfile) {
     688           0 :         s->analysis_rdft = av_rdft_init(rdft_bits, DFT_R2C);
     689           0 :         s->dump_buf = av_malloc_array(s->analysis_rdft_len, sizeof(*s->dump_buf));
     690             :     }
     691             : 
     692           5 :     s->analysis_buf = av_malloc_array(s->analysis_rdft_len, sizeof(*s->analysis_buf));
     693           5 :     s->kernel_tmp_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->channels : 1), sizeof(*s->kernel_tmp_buf));
     694           5 :     s->kernel_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->channels : 1), sizeof(*s->kernel_buf));
     695           5 :     s->conv_buf   = av_calloc(2 * s->rdft_len * inlink->channels, sizeof(*s->conv_buf));
     696           5 :     s->conv_idx   = av_calloc(inlink->channels, sizeof(*s->conv_idx));
     697           5 :     if (!s->analysis_buf || !s->kernel_tmp_buf || !s->kernel_buf || !s->conv_buf || !s->conv_idx)
     698           0 :         return AVERROR(ENOMEM);
     699             : 
     700           5 :     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",
     701             :            inlink->sample_rate, inlink->channels, s->analysis_rdft_len, s->rdft_len, s->fir_len, s->nsamples_max);
     702             : 
     703           5 :     if (s->fixed)
     704           1 :         inlink->min_samples = inlink->max_samples = inlink->partial_buf_size = s->nsamples_max;
     705             : 
     706           5 :     return generate_kernel(ctx, SELECT_GAIN(s), SELECT_GAIN_ENTRY(s));
     707             : }
     708             : 
     709         422 : static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     710             : {
     711         422 :     AVFilterContext *ctx = inlink->dst;
     712         422 :     FIREqualizerContext *s = ctx->priv;
     713             :     int ch;
     714             : 
     715         725 :     for (ch = 0; ch + 1 < inlink->channels && s->fft_ctx; ch += 2) {
     716        1212 :         fast_convolute2(s, s->kernel_buf, (FFTComplex *)(s->conv_buf + 2 * ch * s->rdft_len),
     717         606 :                         s->conv_idx + ch, (float *) frame->extended_data[ch],
     718         303 :                         (float *) frame->extended_data[ch+1], frame->nb_samples);
     719             :     }
     720             : 
     721         660 :     for ( ; ch < inlink->channels; ch++) {
     722        1190 :         fast_convolute(s, s->kernel_buf + (s->multi ? ch * s->rdft_len : 0),
     723         714 :                        s->conv_buf + 2 * ch * s->rdft_len, s->conv_idx + ch,
     724         238 :                        (float *) frame->extended_data[ch], frame->nb_samples);
     725             :     }
     726             : 
     727         422 :     s->next_pts = AV_NOPTS_VALUE;
     728         422 :     if (frame->pts != AV_NOPTS_VALUE) {
     729         422 :         s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, av_make_q(1, inlink->sample_rate), inlink->time_base);
     730         422 :         if (s->zero_phase)
     731          38 :             frame->pts -= av_rescale_q(s->fir_len/2, av_make_q(1, inlink->sample_rate), inlink->time_base);
     732             :     }
     733         422 :     s->frame_nsamples_max = FFMAX(s->frame_nsamples_max, frame->nb_samples);
     734         422 :     return ff_filter_frame(ctx->outputs[0], frame);
     735             : }
     736             : 
     737         655 : static int request_frame(AVFilterLink *outlink)
     738             : {
     739         655 :     AVFilterContext *ctx = outlink->src;
     740         655 :     FIREqualizerContext *s= ctx->priv;
     741             :     int ret;
     742             : 
     743         655 :     ret = ff_request_frame(ctx->inputs[0]);
     744         655 :     if (ret == AVERROR_EOF && s->remaining > 0 && s->frame_nsamples_max > 0) {
     745          10 :         AVFrame *frame = ff_get_audio_buffer(outlink, FFMIN(s->remaining, s->frame_nsamples_max));
     746             : 
     747          10 :         if (!frame)
     748           0 :             return AVERROR(ENOMEM);
     749             : 
     750          10 :         av_samples_set_silence(frame->extended_data, 0, frame->nb_samples, outlink->channels, frame->format);
     751          10 :         frame->pts = s->next_pts;
     752          10 :         s->remaining -= frame->nb_samples;
     753          10 :         ret = filter_frame(ctx->inputs[0], frame);
     754             :     }
     755             : 
     756         655 :     return ret;
     757             : }
     758             : 
     759           0 : static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
     760             :                            char *res, int res_len, int flags)
     761             : {
     762           0 :     FIREqualizerContext *s = ctx->priv;
     763           0 :     int ret = AVERROR(ENOSYS);
     764             : 
     765           0 :     if (!strcmp(cmd, "gain")) {
     766             :         char *gain_cmd;
     767             : 
     768           0 :         if (SELECT_GAIN(s) && !strcmp(SELECT_GAIN(s), args)) {
     769           0 :             av_log(ctx, AV_LOG_DEBUG, "equal gain, do not rebuild.\n");
     770           0 :             return 0;
     771             :         }
     772             : 
     773           0 :         gain_cmd = av_strdup(args);
     774           0 :         if (!gain_cmd)
     775           0 :             return AVERROR(ENOMEM);
     776             : 
     777           0 :         ret = generate_kernel(ctx, gain_cmd, SELECT_GAIN_ENTRY(s));
     778           0 :         if (ret >= 0) {
     779           0 :             av_freep(&s->gain_cmd);
     780           0 :             s->gain_cmd = gain_cmd;
     781             :         } else {
     782           0 :             av_freep(&gain_cmd);
     783             :         }
     784           0 :     } else if (!strcmp(cmd, "gain_entry")) {
     785             :         char *gain_entry_cmd;
     786             : 
     787           0 :         if (SELECT_GAIN_ENTRY(s) && !strcmp(SELECT_GAIN_ENTRY(s), args)) {
     788           0 :             av_log(ctx, AV_LOG_DEBUG, "equal gain_entry, do not rebuild.\n");
     789           0 :             return 0;
     790             :         }
     791             : 
     792           0 :         gain_entry_cmd = av_strdup(args);
     793           0 :         if (!gain_entry_cmd)
     794           0 :             return AVERROR(ENOMEM);
     795             : 
     796           0 :         ret = generate_kernel(ctx, SELECT_GAIN(s), gain_entry_cmd);
     797           0 :         if (ret >= 0) {
     798           0 :             av_freep(&s->gain_entry_cmd);
     799           0 :             s->gain_entry_cmd = gain_entry_cmd;
     800             :         } else {
     801           0 :             av_freep(&gain_entry_cmd);
     802             :         }
     803             :     }
     804             : 
     805           0 :     return ret;
     806             : }
     807             : 
     808             : static const AVFilterPad firequalizer_inputs[] = {
     809             :     {
     810             :         .name           = "default",
     811             :         .config_props   = config_input,
     812             :         .filter_frame   = filter_frame,
     813             :         .type           = AVMEDIA_TYPE_AUDIO,
     814             :         .needs_writable = 1,
     815             :     },
     816             :     { NULL }
     817             : };
     818             : 
     819             : static const AVFilterPad firequalizer_outputs[] = {
     820             :     {
     821             :         .name           = "default",
     822             :         .request_frame  = request_frame,
     823             :         .type           = AVMEDIA_TYPE_AUDIO,
     824             :     },
     825             :     { NULL }
     826             : };
     827             : 
     828             : AVFilter ff_af_firequalizer = {
     829             :     .name               = "firequalizer",
     830             :     .description        = NULL_IF_CONFIG_SMALL("Finite Impulse Response Equalizer."),
     831             :     .uninit             = uninit,
     832             :     .query_formats      = query_formats,
     833             :     .process_command    = process_command,
     834             :     .priv_size          = sizeof(FIREqualizerContext),
     835             :     .inputs             = firequalizer_inputs,
     836             :     .outputs            = firequalizer_outputs,
     837             :     .priv_class         = &firequalizer_class,
     838             : };

Generated by: LCOV version 1.13