changeset 93:908be1d06bd2

More work on inverse
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 09 May 2014 11:41:44 +0100
parents 5a3163eff37a
children fa1709ed4a3c
files cpp-qm-dsp/CQInverse.cpp cpp-qm-dsp/CQInverse.h cpp-qm-dsp/CQKernel.cpp cpp-qm-dsp/CQKernel.h cpp-qm-dsp/ConstantQ.cpp
diffstat 5 files changed, 69 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/cpp-qm-dsp/CQInverse.cpp	Fri May 09 11:15:56 2014 +0100
+++ b/cpp-qm-dsp/CQInverse.cpp	Fri May 09 11:41:44 2014 +0100
@@ -173,9 +173,9 @@
     // and stack these so as to achieve a list, for each octave, of
     // taller columns of height binsPerOctave * atomsPerFrame
     //
-    // 3. For each column, take the product with the inverse CQ kernel
-    // (which is the conjugate of the forward kernel) and perform an
-    // inverse FFT
+    // 3. For each taller column, take the product with the inverse CQ
+    // kernel (which is the conjugate of the forward kernel) and
+    // perform an inverse FFT
     //
     // 4. Overlap-add each octave's resynthesised blocks (unwindowed)
     //
@@ -225,19 +225,43 @@
             ("Columns in octave must be a multiple of atoms per frame");
     }
 
-    ComplexBlock reshaped;
     for (int i = 0; i < ncols; i += m_p.atomsPerFrame) {
+
         ComplexColumn tallcol;
         for (int b = 0; b < m_binsPerOctave; ++b) {
             for (int a = 0; a < m_p.atomsPerFrame; ++a) {
                 tallcol.push_back(columns[i + a][b]);
             }
         }
-        reshaped.push_back(tallcol);
+        
+        processOctaveColumn(octave, tallcol);
+    }
+}
+
+void
+CQInverse::processOctaveColumn(int octave, const ComplexColumn &column)
+{
+    // 3. For each taller column, take the product with the inverse CQ
+    // kernel (which is the conjugate of the forward kernel) and
+    // perform an inverse FFT
+
+    ComplexSequence transformed = m_kernel->processInverse(column);
+
+    int halfLen = m_p.fftSize/2 + 1;
+
+    RealSequence ri(halfLen, 0);
+    RealSequence ii(halfLen, 0);
+
+    for (int i = 0; i < halfLen; ++i) {
+        ri[i] = transformed[i].real();
+        ii[i] = transformed[i].imag();
     }
 
-    
+    RealSequence timeDomain(m_p.fftSize, 0);
 
+    m_fft->inverse(ri.data(), ii.data(), timeDomain.data());
+
+
+    //...
 }
 
-
--- a/cpp-qm-dsp/CQInverse.h	Fri May 09 11:15:56 2014 +0100
+++ b/cpp-qm-dsp/CQInverse.h	Fri May 09 11:41:44 2014 +0100
@@ -83,6 +83,7 @@
     
     void initialise();
     void processOctave(int octave, const ComplexBlock &block);
+    void processOctaveColumn(int octave, const ComplexColumn &column);
 };
 
 #endif
--- a/cpp-qm-dsp/CQKernel.cpp	Fri May 09 11:15:56 2014 +0100
+++ b/cpp-qm-dsp/CQKernel.cpp	Fri May 09 11:41:44 2014 +0100
@@ -241,9 +241,10 @@
     
     cerr << "weight = " << weight << endl;
 
-    // apply normalisation weight, make sparse, and store conjugates
-    // (our multiplication order means we will effectively be using
-    // the adjoint or conjugate transpose of the kernel matrix)
+    // apply normalisation weight, make sparse, and store conjugate
+    // (we use the adjoint or conjugate transpose of the kernel matrix
+    // for the forward transform, the plain kernel for the inverse
+    // which we expect to be less common)
 
     KernelMatrix sk;
 
@@ -274,14 +275,14 @@
 }
 
 vector<C>
-CQKernel::process(const vector<C> &cv)
+CQKernel::processForward(const vector<C> &cv)
 {
-    // matrix multiply m_kernel.data by in, converting in to complex
-    // as we go
+    // straightforward matrix multiply (taking into account m_kernel's
+    // slightly-sparse representation)
 
     int nrows = m_p.binsPerOctave * m_p.atomsPerFrame;
 
-    vector<C> rv(nrows, C(0, 0));
+    vector<C> rv(nrows, C());
 
     for (int i = 0; i < nrows; ++i) {
         for (int j = 0; j < (int)m_kernel.data[i].size(); ++j) {
@@ -292,4 +293,28 @@
     return rv;
 }
 
+vector<C>
+CQKernel::processInverse(const vector<C> &cv)
+{
+    // matrix multiply by conjugate transpose of m_kernel. This is
+    // actually the original kernel as calculated, we just stored the
+    // conjugate-transpose of the kernel because we expect to be doing
+    // more forward transforms than inverse ones.
 
+    int ncols = m_p.binsPerOctave * m_p.atomsPerFrame;
+    int nrows = m_p.fftSize;
+
+    vector<C> rv(nrows, C());
+
+    for (int j = 0; j < ncols; ++j) {
+        int i0 = m_kernel.origin[j];
+        int i1 = i0 + m_kernel.data[j].size();
+        for (int i = i0; i < i1; ++i) {
+            rv[i] += cv[j] * conj(m_kernel.data[j][i - i0]);
+        }
+    }
+
+    return rv;
+}
+
+
--- a/cpp-qm-dsp/CQKernel.h	Fri May 09 11:15:56 2014 +0100
+++ b/cpp-qm-dsp/CQKernel.h	Fri May 09 11:41:44 2014 +0100
@@ -59,7 +59,10 @@
 
     Properties getProperties() const { return m_p; }
 
-    std::vector<std::complex<double> > process
+    std::vector<std::complex<double> > processForward
+        (const std::vector<std::complex<double> > &);
+
+    std::vector<std::complex<double> > processInverse
         (const std::vector<std::complex<double> > &);
 
 private:
--- a/cpp-qm-dsp/ConstantQ.cpp	Fri May 09 11:15:56 2014 +0100
+++ b/cpp-qm-dsp/ConstantQ.cpp	Fri May 09 11:41:44 2014 +0100
@@ -305,7 +305,7 @@
         cv.push_back(Complex(ro[i], io[i]));
     }
 
-    ComplexSequence cqrowvec = m_kernel->process(cv);
+    ComplexSequence cqrowvec = m_kernel->processForward(cv);
 
     // Reform into a column matrix
     ComplexBlock cqblock;