Mercurial > hg > constant-q-cpp
changeset 89:25947630486b
More toward inverse CQ
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Fri, 09 May 2014 08:25:24 +0100 |
parents | c3e1a08c97f0 |
children | bfc7cf71f2ef |
files | Makefile.inc cpp-qm-dsp/CQInverse.cpp cpp-qm-dsp/CQInverse.h cpp-qm-dsp/ConstantQ.h |
diffstat | 4 files changed, 71 insertions(+), 57 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.inc Thu May 08 19:01:15 2014 +0100 +++ b/Makefile.inc Fri May 09 08:25:24 2014 +0100 @@ -20,8 +20,8 @@ PLUGIN := cqvamp$(PLUGIN_EXT) TEST := $(LIB_DIR)/test -LIB_HEADERS := $(LIB_DIR)/CQKernel.h $(LIB_DIR)/ConstantQ.h $(LIB_DIR)/CQInterpolated.h -LIB_SOURCES := $(LIB_DIR)/CQKernel.cpp $(LIB_DIR)/ConstantQ.cpp $(LIB_DIR)/CQInterpolated.cpp +LIB_HEADERS := $(LIB_DIR)/CQKernel.h $(LIB_DIR)/ConstantQ.h $(LIB_DIR)/CQInterpolated.h $(LIB_DIR)/CQInverse.h +LIB_SOURCES := $(LIB_DIR)/CQKernel.cpp $(LIB_DIR)/ConstantQ.cpp $(LIB_DIR)/CQInterpolated.cpp $(LIB_DIR)/CQInverse.cpp VAMP_HEADERS := $(VAMP_DIR)/CQVamp.h VAMP_SOURCES := $(VAMP_DIR)/CQVamp.cpp $(VAMP_DIR)/libmain.cpp
--- a/cpp-qm-dsp/CQInverse.cpp Thu May 08 19:01:15 2014 +0100 +++ b/cpp-qm-dsp/CQInverse.cpp Fri May 09 08:25:24 2014 +0100 @@ -37,6 +37,11 @@ #include "maths/MathUtilities.h" #include "dsp/transforms/FFT.h" +#include <algorithm> +#include <complex> +#include <iostream> +#include <stdexcept> + using std::vector; using std::complex; using std::cerr; @@ -119,71 +124,52 @@ m_bigBlockSize = m_p.fftSize * pow(2, m_octaves - 1); - -//!!! GOT HERE! -#error continue from here please! -/* - // Now add in the extra padding and compensate for hops that must - // be dropped in order to align the atom centres across - // octaves. Again this is a bit trickier because we are doing it - // at input rather than output and so must work in per-octave - // sample rates rather than output blocks - - int emptyHops = m_p.firstCentre / m_p.atomSpacing; - - vector<int> drops; + //!!! review this later for the hops-dropped stuff + int maxLatency = 0; for (int i = 0; i < m_octaves; ++i) { - int factor = pow(2, i); - int dropHops = emptyHops * pow(2, m_octaves - i - 1) - emptyHops; - int drop = ((dropHops * m_p.fftHop) * factor) / m_p.atomsPerFrame; - drops.push_back(drop); + if (latencies[i] > maxLatency) maxLatency = latencies[i]; } - int maxLatPlusDrop = 0; - for (int i = 0; i < m_octaves; ++i) { - int latPlusDrop = latencies[i] + drops[i]; - if (latPlusDrop > maxLatPlusDrop) maxLatPlusDrop = latPlusDrop; - } - - // we want to design totalLatency such that totalLatency - - // latencies[0] - drops[0] is a multiple of m_p.fftHop, so that we - // can get identical results in octave 0 to our reference - // implementation, making for easier testing (though other octaves - // will differ because of different resampler implementations) - - int totalLatency = maxLatPlusDrop; - int lat0 = totalLatency - latencies[0] - drops[0]; - totalLatency = ceil(double(lat0 / m_p.fftHop) * m_p.fftHop) - + latencies[0] + drops[0]; - -// cerr << "total latency = " << totalLatency << endl; - - // Padding as in the reference (will be introduced with the - // latency compensation in the loop below) - m_outputLatency = totalLatency + m_bigBlockSize - - m_p.firstCentre * pow(2, m_octaves-1); - -// cerr << "m_bigBlockSize = " << m_bigBlockSize << ", firstCentre = " -// << m_p.firstCentre << ", m_octaves = " << m_octaves << ", so m_outputLatency = " << m_outputLatency << endl; + m_outputLatency = maxLatency; //!!! for now for (int i = 0; i < m_octaves; ++i) { - double factor = pow(2, i); - // Calculate the difference between the total latency applied // across all octaves, and the existing latency due to the - // decimator for this octave, and then convert it back into - // the sample rate appropriate for the output latency of this - // decimator -- including one additional big block of padding - // (as in the reference). - - double octaveLatency = - double(totalLatency - latencies[i] - drops[i] - + m_bigBlockSize) / factor; + // upsampler for this octave m_buffers.push_back - (vector<double>(int(round(octaveLatency)), 0.0)); + (vector<double>(m_outputLatency - latencies[i], 0.0)); } -*/ + m_fft = new FFTReal(m_p.fftSize); } + +std::vector<double> process(const std::vector<std::vector<double> > &blocks) +{ + // The input data is of the form produced by ConstantQ::process -- + // an unknown number N of columns of varying height. We assert + // that N is a multiple of atomsPerFrame * 2^(octaves-1). + // + // Our procedure: + // + // 1. Slice the list of columns into a set of lists of columns, + // one per octave, each of width N / (2^octave-1) and height + // binsPerOctave, containing the values present in that octave + // + // 2. Group each octave list by atomsPerFrame columns at a time, + // 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 + // + // 4. Overlap-add each octave's resynthesised blocks (unwindowed) + // + // 5. Resample each octave's overlap-add stream to the original + // rate, and sum + +} + +
--- a/cpp-qm-dsp/CQInverse.h Thu May 08 19:01:15 2014 +0100 +++ b/cpp-qm-dsp/CQInverse.h Fri May 09 08:25:24 2014 +0100 @@ -60,6 +60,9 @@ // Input is the format produced by ConstantQ class, not // CQInterpolated (or can we make this support either?) + //!!! no, we need complex not magnitudes! CQ should probably + //!!! produce totally raw output and something like CQInterpolated + //!!! do the magnitude stuff as well as interpolation std::vector<double> process(const std::vector<std::vector<double> > &); std::vector<double> getRemainingOutput();
--- a/cpp-qm-dsp/ConstantQ.h Thu May 08 19:01:15 2014 +0100 +++ b/cpp-qm-dsp/ConstantQ.h Fri May 09 08:25:24 2014 +0100 @@ -57,7 +57,32 @@ double getMinFrequency() const; // actual min, not that passed to ctor double getBinFrequency(int bin) const; + /** + * Given a series of time-domain samples, return a series of + * constant-Q columns. Any samples left over (that did not fit + * into a constant-Q processing block) are saved for the next call + * to process or getRemainingBlocks. + * + * Each column contains a series of constant-Q bin values ordered + * from highest to lowest frequency. + * + * Columns are of variable height: each will contain at least + * getBinsPerOctave() values, because the highest-frequency octave + * is always present, but a second octave (if requested) will + * appear only in alternate columns, a third octave only in every + * fourth column, and so on. + * + * If you need a format in which all columns are of equal height + * and every bin contains a value, use CQInterpolated instead of + * ConstantQ. + */ std::vector<std::vector<double> > process(const std::vector<double> &); + + /** + * Return the remaining constant-Q columns following the end of + * processing. Any buffered input is padded so as to ensure that + * all input provided to process() will have been returned. + */ std::vector<std::vector<double> > getRemainingBlocks(); private: