Mercurial > hg > constant-q-cpp
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; + }