lavfi/dynaudnorm: rename pow2 to pow_2
[ffmpeg.git] / libavfilter / af_firequalizer.c
index e799e34..4243d66 100644 (file)
@@ -69,6 +69,7 @@ typedef struct {
     RDFTContext   *analysis_irdft;
     RDFTContext   *rdft;
     RDFTContext   *irdft;
+    FFTContext    *fft_ctx;
     int           analysis_rdft_len;
     int           rdft_len;
 
@@ -97,6 +98,7 @@ typedef struct {
     int           scale;
     char          *dumpfile;
     int           dumpscale;
+    int           fft2;
 
     int           nb_gain_entry;
     int           gain_entry_err;
@@ -132,6 +134,7 @@ static const AVOption firequalizer_options[] = {
         { "loglog", "logarithmic-freq logarithmic-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LOGLOG }, 0, 0, FLAGS, "scale" },
     { "dumpfile", "set dump file", OFFSET(dumpfile), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },
     { "dumpscale", "set dump scale", OFFSET(dumpscale), AV_OPT_TYPE_INT, { .i64 = SCALE_LINLOG }, 0, NB_SCALE-1, FLAGS, "scale" },
+    { "fft2", "set 2-channels fft", OFFSET(fft2), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
     { NULL }
 };
 
@@ -143,7 +146,9 @@ static void common_uninit(FIREqualizerContext *s)
     av_rdft_end(s->analysis_irdft);
     av_rdft_end(s->rdft);
     av_rdft_end(s->irdft);
+    av_fft_end(s->fft_ctx);
     s->analysis_rdft = s->analysis_irdft = s->rdft = s->irdft = NULL;
+    s->fft_ctx = NULL;
 
     av_freep(&s->analysis_buf);
     av_freep(&s->dump_buf);
@@ -192,26 +197,25 @@ static int query_formats(AVFilterContext *ctx)
     return ff_set_common_samplerates(ctx, formats);
 }
 
-static void fast_convolute(FIREqualizerContext *s, const float *kernel_buf, float *conv_buf,
-                           OverlapIndex *idx, float *data, int nsamples)
+static void fast_convolute(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf, float *av_restrict conv_buf,
+                           OverlapIndex *av_restrict idx, float *av_restrict data, int nsamples)
 {
     if (nsamples <= s->nsamples_max) {
         float *buf = conv_buf + idx->buf_idx * s->rdft_len;
         float *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx;
+        int center = s->fir_len/2;
         int k;
 
-        memcpy(buf, data, nsamples * sizeof(*data));
-        memset(buf + nsamples, 0, (s->rdft_len - nsamples) * sizeof(*data));
+        memset(buf, 0, center * sizeof(*data));
+        memcpy(buf + center, data, nsamples * sizeof(*data));
+        memset(buf + center + nsamples, 0, (s->rdft_len - nsamples - center) * sizeof(*data));
         av_rdft_calc(s->rdft, buf);
 
         buf[0] *= kernel_buf[0];
-        buf[1] *= kernel_buf[1];
-        for (k = 2; k < s->rdft_len; k += 2) {
-            float re, im;
-            re = buf[k] * kernel_buf[k] - buf[k+1] * kernel_buf[k+1];
-            im = buf[k] * kernel_buf[k+1] + buf[k+1] * kernel_buf[k];
-            buf[k] = re;
-            buf[k+1] = im;
+        buf[1] *= kernel_buf[s->rdft_len/2];
+        for (k = 1; k < s->rdft_len/2; k++) {
+            buf[2*k] *= kernel_buf[k];
+            buf[2*k+1] *= kernel_buf[k];
         }
 
         av_rdft_calc(s->irdft, buf);
@@ -231,6 +235,70 @@ static void fast_convolute(FIREqualizerContext *s, const float *kernel_buf, floa
     }
 }
 
+static void fast_convolute2(FIREqualizerContext *av_restrict s, const float *av_restrict kernel_buf, FFTComplex *av_restrict conv_buf,
+                            OverlapIndex *av_restrict idx, float *av_restrict data0, float *av_restrict data1, int nsamples)
+{
+    if (nsamples <= s->nsamples_max) {
+        FFTComplex *buf = conv_buf + idx->buf_idx * s->rdft_len;
+        FFTComplex *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx;
+        int center = s->fir_len/2;
+        int k;
+        float tmp;
+
+        memset(buf, 0, center * sizeof(*buf));
+        for (k = 0; k < nsamples; k++) {
+            buf[center+k].re = data0[k];
+            buf[center+k].im = data1[k];
+        }
+        memset(buf + center + nsamples, 0, (s->rdft_len - nsamples - center) * sizeof(*buf));
+        av_fft_permute(s->fft_ctx, buf);
+        av_fft_calc(s->fft_ctx, buf);
+
+        /* swap re <-> im, do backward fft using forward fft_ctx */
+        /* normalize with 0.5f */
+        tmp = buf[0].re;
+        buf[0].re = 0.5f * kernel_buf[0] * buf[0].im;
+        buf[0].im = 0.5f * kernel_buf[0] * tmp;
+        for (k = 1; k < s->rdft_len/2; k++) {
+            int m = s->rdft_len - k;
+            tmp = buf[k].re;
+            buf[k].re = 0.5f * kernel_buf[k] * buf[k].im;
+            buf[k].im = 0.5f * kernel_buf[k] * tmp;
+            tmp = buf[m].re;
+            buf[m].re = 0.5f * kernel_buf[k] * buf[m].im;
+            buf[m].im = 0.5f * kernel_buf[k] * tmp;
+        }
+        tmp = buf[k].re;
+        buf[k].re = 0.5f * kernel_buf[k] * buf[k].im;
+        buf[k].im = 0.5f * kernel_buf[k] * tmp;
+
+        av_fft_permute(s->fft_ctx, buf);
+        av_fft_calc(s->fft_ctx, buf);
+
+        for (k = 0; k < s->rdft_len - idx->overlap_idx; k++) {
+            buf[k].re += obuf[k].re;
+            buf[k].im += obuf[k].im;
+        }
+
+        /* swapped re <-> im */
+        for (k = 0; k < nsamples; k++) {
+            data0[k] = buf[k].im;
+            data1[k] = buf[k].re;
+        }
+        idx->buf_idx = !idx->buf_idx;
+        idx->overlap_idx = nsamples;
+    } else {
+        while (nsamples > s->nsamples_max * 2) {
+            fast_convolute2(s, kernel_buf, conv_buf, idx, data0, data1, s->nsamples_max);
+            data0 += s->nsamples_max;
+            data1 += s->nsamples_max;
+            nsamples -= s->nsamples_max;
+        }
+        fast_convolute2(s, kernel_buf, conv_buf, idx, data0, data1, nsamples/2);
+        fast_convolute2(s, kernel_buf, conv_buf, idx, data0 + nsamples/2, data1 + nsamples/2, nsamples - nsamples/2);
+    }
+}
+
 static void dump_fir(AVFilterContext *ctx, FILE *fp, int ch)
 {
     FIREqualizerContext *s = ctx->priv;
@@ -534,8 +602,8 @@ static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *g
         }
 
         memset(s->analysis_buf + center + 1, 0, (s->analysis_rdft_len - s->fir_len) * sizeof(*s->analysis_buf));
-        memcpy(rdft_buf, s->analysis_buf + s->analysis_rdft_len - center, center * sizeof(*s->analysis_buf));
-        memcpy(rdft_buf + center, s->analysis_buf, (s->rdft_len - center) * sizeof(*s->analysis_buf));
+        memcpy(rdft_buf, s->analysis_buf, s->rdft_len/2 * sizeof(*s->analysis_buf));
+        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));
         av_rdft_calc(s->rdft, rdft_buf);
 
         for (k = 0; k < s->rdft_len; k++) {
@@ -548,6 +616,11 @@ static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *g
             }
         }
 
+        rdft_buf[s->rdft_len-1] = rdft_buf[1];
+        for (k = 0; k < s->rdft_len/2; k++)
+            rdft_buf[k] = rdft_buf[2*k];
+        rdft_buf[s->rdft_len/2] = rdft_buf[s->rdft_len-1];
+
         if (dump_fp)
             dump_fir(ctx, dump_fp, ch);
 
@@ -594,6 +667,9 @@ static int config_input(AVFilterLink *inlink)
     if (!(s->rdft = av_rdft_init(rdft_bits, DFT_R2C)) || !(s->irdft = av_rdft_init(rdft_bits, IDFT_C2R)))
         return AVERROR(ENOMEM);
 
+    if (s->fft2 && !s->multi && inlink->channels > 1 && !(s->fft_ctx = av_fft_init(rdft_bits, 0)))
+        return AVERROR(ENOMEM);
+
     for ( ; rdft_bits <= RDFT_BITS_MAX; rdft_bits++) {
         s->analysis_rdft_len = 1 << rdft_bits;
         if (inlink->sample_rate <= s->accuracy * s->analysis_rdft_len)
@@ -636,7 +712,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     FIREqualizerContext *s = ctx->priv;
     int ch;
 
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch + 1 < inlink->channels && s->fft_ctx; ch += 2) {
+        fast_convolute2(s, s->kernel_buf, (FFTComplex *)(s->conv_buf + 2 * ch * s->rdft_len),
+                        s->conv_idx + ch, (float *) frame->extended_data[ch],
+                        (float *) frame->extended_data[ch+1], frame->nb_samples);
+    }
+
+    for ( ; ch < inlink->channels; ch++) {
         fast_convolute(s, s->kernel_buf + (s->multi ? ch * s->rdft_len : 0),
                        s->conv_buf + 2 * ch * s->rdft_len, s->conv_idx + ch,
                        (float *) frame->extended_data[ch], frame->nb_samples);