changeset 30:39dddbb78d8b

Start on CQ process implementation
author Chris Cannam <c.cannam@qmul.ac.uk>
date Tue, 05 Nov 2013 16:44:12 +0000
parents b62bb8789b1a
children 01a3e110bf8d
files cpp-qm-dsp/CQKernel.cpp cpp-qm-dsp/CQKernel.h cpp-qm-dsp/ConstantQ.cpp cpp-qm-dsp/ConstantQ.h cpp-qm-dsp/Makefile cpp-qm-dsp/test.cpp
diffstat 6 files changed, 150 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/cpp-qm-dsp/CQKernel.cpp	Tue Nov 05 08:41:00 2013 +0000
+++ b/cpp-qm-dsp/CQKernel.cpp	Tue Nov 05 16:44:12 2013 +0000
@@ -19,7 +19,8 @@
 
 typedef std::complex<double> C;
 
-CQKernel::CQKernel(double sampleRate, double maxFreq, int binsPerOctave)
+CQKernel::CQKernel(double sampleRate, double maxFreq, int binsPerOctave) :
+    m_fft(0)
 {
     m_p.sampleRate = sampleRate;
     m_p.maxFrequency = maxFreq;
@@ -144,7 +145,7 @@
 
     cerr << "density = " << double(nnz) / double(m_p.binsPerOctave * m_p.atomsPerFrame * m_p.fftSize) << " (" << nnz << " of " << m_p.binsPerOctave * m_p.atomsPerFrame * m_p.fftSize << ")" << endl;
 
-    normaliseKernel();
+    finaliseKernel();
 }
 
 static bool ccomparator(C &c1, C &c2)
@@ -158,9 +159,9 @@
 }
 
 void
-CQKernel::normaliseKernel()
+CQKernel::finaliseKernel()
 {
-    // and normalise
+    // calculate weight for normalisation
 
     int wx1 = maxidx(m_kernel.data[0]);
     int wx2 = maxidx(m_kernel.data[m_kernel.data.size()-1]);
@@ -202,6 +203,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)
+
     KernelMatrix sk;
 
     for (int i = 0; i < m_kernel.data.size(); ++i) {
@@ -222,7 +227,7 @@
             if (haveNZ || abs(m_kernel.data[i][j]) != 0.0) {
                 if (!haveNZ) sk.origin[i] = j;
                 haveNZ = true;
-                sk.data[i].push_back(m_kernel.data[i][j] * weight);
+                sk.data[i].push_back(conj(m_kernel.data[i][j]) * weight);
             }
         }
     }
--- a/cpp-qm-dsp/CQKernel.h	Tue Nov 05 08:41:00 2013 +0000
+++ b/cpp-qm-dsp/CQKernel.h	Tue Nov 05 16:44:12 2013 +0000
@@ -40,7 +40,7 @@
     KernelMatrix m_kernel;
 
     void generateKernel();
-    void normaliseKernel();
+    void finaliseKernel();
 };
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cpp-qm-dsp/ConstantQ.cpp	Tue Nov 05 16:44:12 2013 +0000
@@ -0,0 +1,98 @@
+
+#include "ConstantQ.h"
+
+#include "CQKernel.h"
+
+#include "qm-dsp/dsp/rateconversion/Resampler.h"
+#include "qm-dsp/maths/MathUtilities.h"
+#include "qm-dsp/dsp/transforms/FFT.h"
+
+#include <algorithm>
+#include <complex>
+#include <iostream>
+#include <stdexcept>
+
+using std::vector;
+using std::complex;
+using std::cerr;
+using std::endl;
+
+ConstantQ::ConstantQ(double sampleRate,
+		     double minFreq,
+		     double maxFreq,
+		     int binsPerOctave) :
+    m_sampleRate(sampleRate),
+    m_maxFrequency(maxFreq),
+    m_minFrequency(minFreq),
+    m_binsPerOctave(binsPerOctave),
+    m_fft(0)
+{
+    if (minFreq <= 0.0 || maxFreq <= 0.0) {
+	throw std::invalid_argument("Frequency extents must be positive");
+    }
+
+    initialise();
+}
+
+ConstantQ::~ConstantQ()
+{
+    delete m_fft;
+    for (int i = 0; i < m_decimators.size(); ++i) {
+	delete m_decimators[i];
+    }
+}
+
+void
+ConstantQ::initialise()
+{
+    m_octaves = int(ceil(log2(m_maxFrequency / m_minFrequency)));
+    double actualMinFreq =
+	(m_maxFrequency / pow(2.0, m_octaves)) * pow(2.0, 1.0/m_binsPerOctave);
+
+    cerr << "actual min freq = " << actualMinFreq << endl;
+
+    m_kernel = new CQKernel(m_sampleRate, m_maxFrequency, m_binsPerOctave);
+    m_p = m_kernel->getProperties();
+    
+    // use exact powers of two for resampling rates. They don't have
+    // to be related to our actual samplerate, the resampler only
+    // cares about the ratio
+
+    int sourceRate = pow(2, m_octaves);
+    vector<int> latencies;
+    for (int oct = 1; oct < m_octaves; ++oct) {
+	Resampler *r = new Resampler(sourceRate, sourceRate / pow(2, oct));
+	latencies.push_back(r->getLatency());
+	m_decimators.push_back(r);
+    }
+
+    //!!! should be multiple of the kernel fft size?
+    int maxLatency = *std::max_element(latencies.begin(), latencies.end());
+    m_totalLatency = MathUtilities::nextPowerOfTwo(maxLatency);
+    cerr << "total latency = " << m_totalLatency << endl;
+    for (int i = 0; i < latencies.size(); ++i) {
+	m_extraLatencies.push_back(m_totalLatency - latencies[i]);
+	cerr << "extra latency " << i << " = " << m_extraLatencies[i] << endl;
+	m_octaveBuffers.push_back(new vector<double>(m_extraLatencies[i], 0.0));
+    }
+
+    m_fft = new FFT(m_p.fftSize);
+    m_bigBlockSize = m_p.fftSize * pow(2, m_octaves) / 2;
+
+    cerr << "m_bigBlockSize = " << m_bigBlockSize << " for " << m_octaves << " octaves" << endl;
+}
+
+vector<vector<double> > 
+ConstantQ::process(vector<double> td)
+{
+    for (int i = 1; i < m_octaves; ++i) {
+	vector<double> dec = m_decimators[i]->process(td.data(), td.size());
+	m_octaveBuffers[i].insert(m_octaveBuffers[i].end(), dec);
+    }
+
+    //!!! do the work!
+
+    vector<vector<double> > out;
+    return out;
+}
+
--- a/cpp-qm-dsp/ConstantQ.h	Tue Nov 05 08:41:00 2013 +0000
+++ b/cpp-qm-dsp/ConstantQ.h	Tue Nov 05 16:44:12 2013 +0000
@@ -3,17 +3,44 @@
 #ifndef CONSTANTQ_H
 #define CONSTANTQ_H
 
+#include "CQKernel.h"
+
+#include <vector>
+
+class Resampler;
+class FFT;
+
 class ConstantQ
 {
 public:
     ConstantQ(double sampleRate, 
 	      double minFreq, double maxFreq, 
 	      int binsPerOctave);
+    ~ConstantQ();
 
-    
+    std::vector<std::vector<double> > process(std::vector<double>);
 
+private:
+    double m_sampleRate;
+    double m_maxFrequency;
+    double m_minFrequency;
+    int m_binsPerOctave;
+    int m_octaves;
 
-}
+    CQKernel *m_kernel;
+    CQKernel::Properties m_p;
+    int m_bigBlockSize;
+
+    std::vector<Resampler *> m_decimators;
+    std::vector<std::vector<double> > m_octaveBuffers;
+
+    int m_totalLatency;
+    std::vector<int> m_extraLatencies; // per resampler, to make up to total
+
+    FFT *m_fft;
+
+    void initialise();
+};
 
 #endif
 
--- a/cpp-qm-dsp/Makefile	Tue Nov 05 08:41:00 2013 +0000
+++ b/cpp-qm-dsp/Makefile	Tue Nov 05 16:44:12 2013 +0000
@@ -13,7 +13,7 @@
 LIBS 		:= ../../qm-dsp/libqm-dsp.a -lpthread
 PROGRAM_LIBS	:= -lsndfile
 
-SOURCES	:= CQKernel.cpp test.cpp
+SOURCES	:= CQKernel.cpp ConstantQ.cpp test.cpp
 
 OBJECTS := $(SOURCES:.cpp=.o)
 OBJECTS := $(OBJECTS:.c=.o)
@@ -28,3 +28,11 @@
 clean: 
 	rm -f *.o 
 
+depend:
+	makedepend -Y $(SOURCES)
+
+# DO NOT DELETE
+
+CQKernel.o: CQKernel.h
+ConstantQ.o: ConstantQ.h CQKernel.h
+test.o: ConstantQ.h CQKernel.h
--- a/cpp-qm-dsp/test.cpp	Tue Nov 05 08:41:00 2013 +0000
+++ b/cpp-qm-dsp/test.cpp	Tue Nov 05 16:44:12 2013 +0000
@@ -1,13 +1,13 @@
 
-#include "CQKernel.h"
+#include "ConstantQ.h"
 
 #include <iostream>
 
 int main(int argc, char **argv)
 {
-    CQKernel k(48000, 24000, 24);
+    ConstantQ k(48000, 50, 24000, 24);
 
-    std::cerr << "Q = " << k.getProperties().Q << std::endl;
+
 
 }