LCOV - code coverage report
Current view: top level - libavfilter - af_firequalizer.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 283 529 53.5 %
Date: 2017-12-12 11:08:38 Functions: 12 17 70.6 %

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

Generated by: LCOV version 1.13