changeset 446:d132b92ec65d vampipe

Add FFTComplex class by analogy to FFTReal
author Chris Cannam
date Thu, 18 Aug 2016 16:04:25 +0100
parents 7f7a10bcaff1
children 80b46389aab0
files src/vamp-sdk/FFT.cpp vamp-sdk/FFT.h
diffstat 2 files changed, 144 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/vamp-sdk/FFT.cpp	Thu Aug 18 15:06:23 2016 +0100
+++ b/src/vamp-sdk/FFT.cpp	Thu Aug 18 16:04:25 2016 +0100
@@ -108,21 +108,92 @@
     delete[] out;
 }
 
+class FFTComplex::D
+{
+public:
+    D(int n) :
+        m_n(n),
+        m_fconf(Kiss::kiss_fft_alloc(n, false, 0, 0)),
+        m_iconf(Kiss::kiss_fft_alloc(n, true, 0, 0)),
+        m_ci(new Kiss::kiss_fft_cpx[m_n]),
+        m_co(new Kiss::kiss_fft_cpx[m_n]) { }
+
+    ~D() {
+        Kiss::kiss_fftr_free(m_fconf);
+        Kiss::kiss_fftr_free(m_iconf);
+        delete[] m_ci;
+        delete[] m_co;
+    }
+
+    void forward(const double *ci, double *co) {
+        for (int i = 0; i < m_n; ++i) {
+            m_ci[i].r = ci[i*2];
+            m_ci[i].i = ci[i*2+1];
+        }
+        Kiss::kiss_fft(m_fconf, m_ci, m_co);
+        for (int i = 0; i < m_n; ++i) {
+            co[i*2] = m_co[i].r;
+            co[i*2+1] = m_co[i].i;
+        }
+    }
+
+    void inverse(const double *ci, double *co) {
+        for (int i = 0; i < m_n; ++i) {
+            m_ci[i].r = ci[i*2];
+            m_ci[i].i = ci[i*2+1];
+        }
+        Kiss::kiss_fft(m_iconf, m_ci, m_co);
+        double scale = 1.0 / double(m_n);
+        for (int i = 0; i < m_n; ++i) {
+            co[i*2] = m_co[i].r * scale;
+            co[i*2+1] = m_co[i].i * scale;
+        }
+    }
+    
+private:
+    int m_n;
+    Kiss::kiss_fft_cfg m_fconf;
+    Kiss::kiss_fft_cfg m_iconf;
+    Kiss::kiss_fft_cpx *m_ci;
+    Kiss::kiss_fft_cpx *m_co;
+};
+
+FFTComplex::FFTComplex(unsigned int n) :
+    m_d(new D(n))
+{
+}
+
+FFTComplex::~FFTComplex()
+{
+    delete m_d;
+}
+
+void
+FFTComplex::forward(const double *ci, double *co)
+{
+    m_d->forward(ci, co);
+}
+
+void
+FFTComplex::inverse(const double *ci, double *co)
+{
+    m_d->inverse(ci, co);
+}
+
 class FFTReal::D
 {
 public:
-    
     D(int n) :
         m_n(n),
-        m_cf(Kiss::kiss_fftr_alloc(n, false, 0, 0)),
-        m_ci(Kiss::kiss_fftr_alloc(n, true, 0, 0)),
+        m_fconf(Kiss::kiss_fftr_alloc(n, false, 0, 0)),
+        m_iconf(Kiss::kiss_fftr_alloc(n, true, 0, 0)),
         m_ri(new Kiss::kiss_fft_scalar[m_n]),
         m_ro(new Kiss::kiss_fft_scalar[m_n]),
         m_freq(new Kiss::kiss_fft_cpx[n/2+1]) { }
 
     ~D() {
-        Kiss::kiss_fftr_free(m_cf);
-        Kiss::kiss_fftr_free(m_ci);
+        Kiss::kiss_fftr_free(m_fconf);
+        Kiss::kiss_fftr_free(m_iconf);
         delete[] m_ri;
         delete[] m_ro;
         delete[] m_freq;
@@ -133,7 +204,7 @@
             // in case kiss_fft_scalar is float
             m_ri[i] = ri[i];
         }
-        Kiss::kiss_fftr(m_cf, m_ri, m_freq);
+        Kiss::kiss_fftr(m_fconf, m_ri, m_freq);
         int hs = m_n/2 + 1;
         for (int i = 0; i < hs; ++i) {
             co[i*2] = m_freq[i].r;
@@ -147,7 +218,7 @@
             m_freq[i].r = ci[i*2];
             m_freq[i].i = ci[i*2+1];
         }
-        Kiss::kiss_fftri(m_ci, m_freq, m_ro);
+        Kiss::kiss_fftri(m_iconf, m_freq, m_ro);
         double scale = 1.0 / double(m_n);
         for (int i = 0; i < m_n; ++i) {
             ro[i] = m_ro[i] * scale;
@@ -156,8 +227,8 @@
     
 private:
     int m_n;
-    Kiss::kiss_fftr_cfg m_cf;
-    Kiss::kiss_fftr_cfg m_ci;
+    Kiss::kiss_fftr_cfg m_fconf;
+    Kiss::kiss_fftr_cfg m_iconf;
     Kiss::kiss_fft_scalar *m_ri;
     Kiss::kiss_fft_scalar *m_ro;
     Kiss::kiss_fft_cpx *m_freq;
--- a/vamp-sdk/FFT.h	Thu Aug 18 15:06:23 2016 +0100
+++ b/vamp-sdk/FFT.h	Thu Aug 18 16:04:25 2016 +0100
@@ -47,7 +47,11 @@
  * authors. This class provides one-shot (i.e. fixed table state is
  * recalculated every time) double-precision complex-complex
  * transforms. For repeated transforms from real time-domain data, use
- * an FFTReal object instead.
+ * an FFTComplex or FFTReal object instead.
+ *
+ * Note: If the SDK has been compiled with the SINGLE_PRECISION_FFT
+ * flag, then all FFTs will use single precision internally. The
+ * default is double precision. The API uses doubles in either case.
  *
  * The forward transform is unscaled; the inverse transform is scaled
  * by 1/n.
@@ -57,7 +61,7 @@
 public:
     /**
      * Calculate a one-shot forward transform of size n.
-     * n must be a power of 2, greater than 1.
+     * n must be a multiple of 2.
      *
      * ri and ii must point to the real and imaginary component arrays
      * of the input. For real input, ii may be NULL.
@@ -92,10 +96,64 @@
 
 /**
  * A simple FFT implementation provided for convenience of plugin
+ * authors. This class provides double-precision complex-complex
+ * transforms.
+ *
+ * Note: If the SDK has been compiled with the SINGLE_PRECISION_FFT
+ * flag, then all FFTs will use single precision internally. The
+ * default is double precision. The API uses doubles in either case.
+ *
+ * The forward transform is unscaled; the inverse transform is scaled
+ * by 1/n.
+ */
+class FFTComplex
+{
+    /**
+     * Prepare to calculate transforms of size n.
+     * n must be a multiple of 2.
+     */
+    FFTComplex(unsigned int n);
+
+    ~FFTComplex();
+
+    /**
+     * Calculate a forward transform of size n.
+     *
+     * ci must point to the interleaved complex input data of size n
+     * (that is, 2n doubles in total).
+     *
+     * co must point to enough space to receive an interleaved complex
+     * output array of size n (that is, 2n doubles in total).
+     */
+    void forward(const double *ci, double *co);
+
+    /**
+     * Calculate an inverse transform of size n.
+     *
+     * ci must point to an interleaved complex input array of size n
+     * (that is, 2n doubles in total).
+     *
+     * co must point to enough space to receive the interleaved
+     * complex output data of size n (that is, 2n doubles in
+     * total). The output is scaled by 1/n.
+     */
+    void inverse(const double *ci, double *co);
+
+private:
+    class D;
+    D *m_d;
+};
+
+/**
+ * A simple FFT implementation provided for convenience of plugin
  * authors. This class provides transforms between double-precision
  * real time-domain and double-precision complex frequency-domain
  * data.
  *
+ * Note: If the SDK has been compiled with the SINGLE_PRECISION_FFT
+ * flag, then all FFTs will use single precision internally. The
+ * default is double precision. The API uses doubles in either case.
+ *
  * The forward transform is unscaled; the inverse transform is scaled
  * by 1/n.
  */
@@ -103,7 +161,7 @@
 {
     /**
      * Prepare to calculate transforms of size n.
-     * n must be a power of 2, greater than 1.
+     * n must be a multiple of 2.
      */
     FFTReal(unsigned int n);
 
@@ -115,14 +173,15 @@
      * ri must point to the real input data of size n.
      *
      * co must point to enough space to receive an interleaved complex
-     * output array of size n/2+1.
+     * output array of size n/2+1 (that is, n+2 doubles in total).
      */
     void forward(const double *ri, double *co);
 
     /**
      * Calculate an inverse transform of size n.
      *
-     * ci must point to an interleaved complex input array of size n/2+1.
+     * ci must point to an interleaved complex input array of size
+     * n/2+1 (that is, n+2 doubles in total).
      *
      * ro must point to enough space to receive the real output data
      * of size n. The output is scaled by 1/n and only the real part