Mercurial > hg > constant-q-cpp
changeset 127:8996465e39fc
Expose some more processing parameters, use a single parameter class
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Fri, 16 May 2014 10:12:03 +0100 |
parents | b87290781071 |
children | ca3620c9a763 |
files | Makefile.linux cq/CQInverse.h cq/CQKernel.h cq/CQParameters.h cq/CQSpectrogram.h cq/ConstantQ.h src/CQInverse.cpp src/CQKernel.cpp src/CQSpectrogram.cpp src/ConstantQ.cpp test/processfile.cpp test/test.cpp vamp/CQChromaVamp.cpp vamp/CQVamp.cpp |
diffstat | 14 files changed, 188 insertions(+), 81 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.linux Fri May 16 09:06:34 2014 +0100 +++ b/Makefile.linux Fri May 16 10:12:03 2014 +0100 @@ -4,7 +4,7 @@ CXXFLAGS := $(CFLAGS) -VAMPSDK_DIR := ../vamp-plugin-sdk +VAMPSDK_DIR := ../../vamp-plugin-sdk PLUGIN_LDFLAGS := -shared -Wl,--version-script=vamp/vamp-plugin.map PLUGIN_EXT := .so
--- a/cq/CQInverse.h Fri May 16 09:06:34 2014 +0100 +++ b/cq/CQInverse.h Fri May 16 10:12:03 2014 +0100 @@ -41,9 +41,7 @@ class CQInverse : public CQBase { public: - CQInverse(double sampleRate, - double minFreq, double maxFreq, - int binsPerOctave); + CQInverse(CQParameters params); virtual ~CQInverse(); virtual double getSampleRate() const { return m_sampleRate; } @@ -64,12 +62,13 @@ RealSequence getRemainingOutput(); private: - double m_sampleRate; - double m_maxFrequency; - double m_minFrequency; - int m_binsPerOctave; + const CQParameters m_inparams; + const double m_sampleRate; + const double m_maxFrequency; + const double m_minFrequency; + const int m_binsPerOctave; + int m_octaves; - CQKernel *m_kernel; CQKernel::Properties m_p;
--- a/cq/CQKernel.h Fri May 16 09:06:34 2014 +0100 +++ b/cq/CQKernel.h Fri May 16 10:12:03 2014 +0100 @@ -32,6 +32,8 @@ #ifndef CQ_KERNEL_H #define CQ_KERNEL_H +#include "CQParameters.h" + #include <vector> #include <complex> @@ -40,7 +42,7 @@ class CQKernel { public: - CQKernel(double sampleRate, double maxFreq, int binsPerOctave); + CQKernel(CQParameters params); ~CQKernel(); struct Properties { @@ -66,6 +68,7 @@ (const std::vector<std::complex<double> > &); private: + const CQParameters m_inparams; Properties m_p; FFT *m_fft; @@ -75,6 +78,7 @@ }; KernelMatrix m_kernel; + std::vector<double> makeWindow(int len) const; void generateKernel(); void finaliseKernel(); };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cq/CQParameters.h Fri May 16 10:12:03 2014 +0100 @@ -0,0 +1,75 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ +/* + Constant-Q library + Copyright (c) 2013-2014 Queen Mary, University of London + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#ifndef CQ_PARAMETERS_H +#define CQ_PARAMETERS_H + +class CQParameters +{ +public: + enum WindowType { + SqrtBlackmanHarris, + SqrtBlackman, + SqrtHann, + BlackmanHarris, + Blackman, + Hann, + }; + + CQParameters(double _sampleRate, + double _minFrequency, + double _maxFrequency, + int _binsPerOctave) : + sampleRate(_sampleRate), + minFrequency(_minFrequency), + maxFrequency(_maxFrequency), + binsPerOctave(_binsPerOctave), + q(1.0), // Q scaling factor + atomHopFactor(0.25), // hop size of shortest temporal atom + threshold(0.0005), // sparsity threshold for resulting kernel + window(SqrtBlackmanHarris) // window shape + { } + + double sampleRate; + double minFrequency; + double maxFrequency; + int binsPerOctave; + + double q; + double atomHopFactor; + double threshold; + WindowType window; +}; + +#endif + + +
--- a/cq/CQSpectrogram.h Fri May 16 09:06:34 2014 +0100 +++ b/cq/CQSpectrogram.h Fri May 16 10:12:03 2014 +0100 @@ -43,10 +43,7 @@ InterpolateLinear, // linear interpolation between consecutive time cells }; - CQSpectrogram(double sampleRate, - double minFreq, double maxFreq, - int binsPerOctave, - Interpolation interpolation); + CQSpectrogram(CQParameters params, Interpolation interpolation); virtual ~CQSpectrogram(); virtual double getSampleRate() const { return m_cq.getSampleRate(); }
--- a/cq/ConstantQ.h Fri May 16 09:06:34 2014 +0100 +++ b/cq/ConstantQ.h Fri May 16 10:12:03 2014 +0100 @@ -33,6 +33,7 @@ #define CONSTANTQ_H #include "CQBase.h" +#include "CQParameters.h" #include "CQKernel.h" class Resampler; @@ -48,9 +49,7 @@ class ConstantQ : public CQBase { public: - ConstantQ(double sampleRate, - double minFreq, double maxFreq, - int binsPerOctave); + ConstantQ(CQParameters params); virtual ~ConstantQ(); virtual double getSampleRate() const { return m_sampleRate; } @@ -92,12 +91,13 @@ ComplexBlock getRemainingOutput(); private: - double m_sampleRate; - double m_maxFrequency; - double m_minFrequency; - int m_binsPerOctave; + const CQParameters m_inparams; + const double m_sampleRate; + const double m_maxFrequency; + const double m_minFrequency; + const int m_binsPerOctave; + int m_octaves; - CQKernel *m_kernel; CQKernel::Properties m_p; int m_bigBlockSize;
--- a/src/CQInverse.cpp Fri May 16 09:06:34 2014 +0100 +++ b/src/CQInverse.cpp Fri May 16 10:12:03 2014 +0100 @@ -45,17 +45,15 @@ //#define DEBUG_CQ 1 -CQInverse::CQInverse(double sampleRate, - double minFreq, - double maxFreq, - int binsPerOctave) : - m_sampleRate(sampleRate), - m_maxFrequency(maxFreq), - m_minFrequency(minFreq), - m_binsPerOctave(binsPerOctave), +CQInverse::CQInverse(CQParameters params) : + m_inparams(params), + m_sampleRate(params.sampleRate), + m_maxFrequency(params.maxFrequency), + m_minFrequency(params.minFrequency), + m_binsPerOctave(params.binsPerOctave), m_fft(0) { - if (minFreq <= 0.0 || maxFreq <= 0.0) { + if (m_minFrequency <= 0.0 || m_maxFrequency <= 0.0) { throw std::invalid_argument("Frequency extents must be positive"); } @@ -87,7 +85,7 @@ CQInverse::initialise() { m_octaves = int(ceil(log2(m_maxFrequency / m_minFrequency))); - m_kernel = new CQKernel(m_sampleRate, m_maxFrequency, m_binsPerOctave); + m_kernel = new CQKernel(m_inparams); m_p = m_kernel->getProperties(); // Use exact powers of two for resampling rates. They don't have
--- a/src/CQKernel.cpp Fri May 16 09:06:34 2014 +0100 +++ b/src/CQKernel.cpp Fri May 16 10:12:03 2014 +0100 @@ -48,12 +48,13 @@ typedef std::complex<double> C; -CQKernel::CQKernel(double sampleRate, double maxFreq, int binsPerOctave) : +CQKernel::CQKernel(CQParameters params) : + m_inparams(params), m_fft(0) { - m_p.sampleRate = sampleRate; - m_p.maxFrequency = maxFreq; - m_p.binsPerOctave = binsPerOctave; + m_p.sampleRate = params.sampleRate; + m_p.maxFrequency = params.maxFrequency; + m_p.binsPerOctave = params.binsPerOctave; generateKernel(); } @@ -62,12 +63,60 @@ delete m_fft; } +vector<double> +CQKernel::makeWindow(int len) const +{ + // The MATLAB version uses a symmetric window, but our windows + // are periodic. A symmetric window of size N is a periodic + // one of size N-1 with the first element stuck on the end. + + WindowType wt(BlackmanHarrisWindow); + + switch (m_inparams.window) { + case CQParameters::SqrtBlackmanHarris: + case CQParameters::BlackmanHarris: + wt = BlackmanHarrisWindow; + break; + case CQParameters::SqrtBlackman: + case CQParameters::Blackman: + wt = BlackmanWindow; + break; + case CQParameters::SqrtHann: + case CQParameters::Hann: + wt = HanningWindow; + break; + } + + Window<double> w(wt, len-1); + vector<double> win = w.getWindowData(); + win.push_back(win[0]); + + switch (m_inparams.window) { + case CQParameters::SqrtBlackmanHarris: + case CQParameters::SqrtBlackman: + case CQParameters::SqrtHann: + for (int i = 0; i < (int)win.size(); ++i) { + win[i] = sqrt(win[i]) / len; + } + break; + case CQParameters::BlackmanHarris: + case CQParameters::Blackman: + case CQParameters::Hann: + for (int i = 0; i < (int)win.size(); ++i) { + win[i] = win[i] / len; + } + break; + } + + return win; +} + void CQKernel::generateKernel() { - double q = 1; - double atomHopFactor = 0.25; - double thresh = 0.0005; + double q = m_inparams.q; + double atomHopFactor = m_inparams.atomHopFactor; + double thresh = m_inparams.threshold; double bpo = m_p.binsPerOctave; @@ -99,7 +148,7 @@ m_p.atomsPerFrame = floor (1.0 + (m_p.fftSize - ceil(maxNK / 2.0) - m_p.firstCentre) / m_p.atomSpacing); - cerr << "atomsPerFrame = " << m_p.atomsPerFrame << " (atomHopFactor = " << atomHopFactor << ", atomSpacing = " << m_p.atomSpacing << ", fftSize = " << m_p.fftSize << ", maxNK = " << maxNK << ", firstCentre = " << m_p.firstCentre << ")" << endl; + cerr << "atomsPerFrame = " << m_p.atomsPerFrame << " (q = " << q << ", Q = " << m_p.Q << ", atomHopFactor = " << atomHopFactor << ", atomSpacing = " << m_p.atomSpacing << ", fftSize = " << m_p.fftSize << ", maxNK = " << maxNK << ", firstCentre = " << m_p.firstCentre << ")" << endl; m_p.lastCentre = m_p.firstCentre + (m_p.atomsPerFrame - 1) * m_p.atomSpacing; @@ -114,16 +163,7 @@ int nk = round(m_p.Q * m_p.sampleRate / (m_p.minFrequency * pow(2, ((k-1.0) / bpo)))); - // The MATLAB version uses a symmetric window, but our windows - // are periodic. A symmetric window of size N is a periodic - // one of size N-1 with the first element stuck on the end - Window<double> w(BlackmanHarrisWindow, nk-1); - vector<double> win = w.getWindowData(); - win.push_back(win[0]); - - for (int i = 0; i < (int)win.size(); ++i) { - win[i] = sqrt(win[i]) / nk; - } + vector<double> win = makeWindow(nk); double fk = m_p.minFrequency * pow(2, ((k-1.0) / bpo)); @@ -242,7 +282,7 @@ } vector<double> wK; - double q = 1; //!!! duplicated from constructor + double q = m_inparams.q; for (int i = round(1.0/q); i < ncols - round(1.0/q) - 2; ++i) { wK.push_back(abs(square[i][i])); }
--- a/src/CQSpectrogram.cpp Fri May 16 09:06:34 2014 +0100 +++ b/src/CQSpectrogram.cpp Fri May 16 10:12:03 2014 +0100 @@ -37,11 +37,9 @@ using std::cerr; using std::endl; -CQSpectrogram::CQSpectrogram(double sampleRate, - double minFreq, double maxFreq, - int binsPerOctave, - Interpolation interpolation) : - m_cq(sampleRate, minFreq, maxFreq, binsPerOctave), +CQSpectrogram::CQSpectrogram(CQParameters params, + Interpolation interpolation) : + m_cq(params), m_interpolation(interpolation) { }
--- a/src/ConstantQ.cpp Fri May 16 09:06:34 2014 +0100 +++ b/src/ConstantQ.cpp Fri May 16 10:12:03 2014 +0100 @@ -47,17 +47,15 @@ //#define DEBUG_CQ 1 -ConstantQ::ConstantQ(double sampleRate, - double minFreq, - double maxFreq, - int binsPerOctave) : - m_sampleRate(sampleRate), - m_maxFrequency(maxFreq), - m_minFrequency(minFreq), - m_binsPerOctave(binsPerOctave), +ConstantQ::ConstantQ(CQParameters params) : + m_inparams(params), + m_sampleRate(params.sampleRate), + m_maxFrequency(params.maxFrequency), + m_minFrequency(params.minFrequency), + m_binsPerOctave(params.binsPerOctave), m_fft(0) { - if (minFreq <= 0.0 || maxFreq <= 0.0) { + if (m_minFrequency <= 0.0 || m_maxFrequency <= 0.0) { throw std::invalid_argument("Frequency extents must be positive"); } @@ -89,7 +87,7 @@ ConstantQ::initialise() { m_octaves = int(ceil(log2(m_maxFrequency / m_minFrequency))); - m_kernel = new CQKernel(m_sampleRate, m_maxFrequency, m_binsPerOctave); + m_kernel = new CQKernel(m_inparams); m_p = m_kernel->getProperties(); // Use exact powers of two for resampling rates. They don't have
--- a/test/processfile.cpp Fri May 16 09:06:34 2014 +0100 +++ b/test/processfile.cpp Fri May 16 10:12:03 2014 +0100 @@ -125,8 +125,9 @@ if (minFreq == 0.0) minFreq = 100; if (bpo == 0) bpo = 60; - ConstantQ cq(sfinfo.samplerate, minFreq, maxFreq, bpo); - CQInverse cqi(sfinfo.samplerate, minFreq, maxFreq, bpo); + CQParameters params(sfinfo.samplerate, minFreq, maxFreq, bpo); + ConstantQ cq(params); + CQInverse cqi(params); cerr << "max freq = " << cq.getMaxFrequency() << ", min freq = " << cq.getMinFrequency() << ", octaves = " << cq.getOctaves() << endl;
--- a/test/test.cpp Fri May 16 09:06:34 2014 +0100 +++ b/test/test.cpp Fri May 16 10:12:03 2014 +0100 @@ -50,7 +50,8 @@ in.push_back(sin(i * M_PI / 2.0)); } - CQSpectrogram k(8, 1, 4, 4, CQSpectrogram::InterpolateZeros); + CQParameters params(8, 1, 4, 4); + CQSpectrogram k(params, CQSpectrogram::InterpolateZeros); vector<vector<double> > out = k.process(in); vector<vector<double> > rest = k.getRemainingOutput();
--- a/vamp/CQChromaVamp.cpp Fri May 16 09:06:34 2014 +0100 +++ b/vamp/CQChromaVamp.cpp Fri May 16 10:12:03 2014 +0100 @@ -228,9 +228,8 @@ << ", min freq " << m_minFrequency << ", max freq " << m_maxFrequency << endl; - m_cq = new CQSpectrogram - (m_inputSampleRate, m_minFrequency, m_maxFrequency, m_bpo, - CQSpectrogram::InterpolateLinear); + CQParameters p(m_inputSampleRate, m_minFrequency, m_maxFrequency, m_bpo); + m_cq = new CQSpectrogram(p, CQSpectrogram::InterpolateLinear); return true; } @@ -240,9 +239,8 @@ { if (m_cq) { delete m_cq; - m_cq = new CQSpectrogram - (m_inputSampleRate, m_minFrequency, m_maxFrequency, m_bpo, - CQSpectrogram::InterpolateLinear); + CQParameters p(m_inputSampleRate, m_minFrequency, m_maxFrequency, m_bpo); + m_cq = new CQSpectrogram(p, CQSpectrogram::InterpolateLinear); } m_haveStartTime = false; m_columnCount = 0;
--- a/vamp/CQVamp.cpp Fri May 16 09:06:34 2014 +0100 +++ b/vamp/CQVamp.cpp Fri May 16 10:12:03 2014 +0100 @@ -286,9 +286,8 @@ (m_maxMIDIPitch, 0, m_tuningFrequency); } - m_cq = new CQSpectrogram - (m_inputSampleRate, m_minFrequency, m_maxFrequency, m_bpo, - m_interpolation); + CQParameters p(m_inputSampleRate, m_minFrequency, m_maxFrequency, m_bpo); + m_cq = new CQSpectrogram(p, m_interpolation); return true; } @@ -298,9 +297,8 @@ { if (m_cq) { delete m_cq; - m_cq = new CQSpectrogram - (m_inputSampleRate, m_minFrequency, m_maxFrequency, m_bpo, - m_interpolation); + CQParameters p(m_inputSampleRate, m_minFrequency, m_maxFrequency, m_bpo); + m_cq = new CQSpectrogram(p, m_interpolation); } m_haveStartTime = false; m_columnCount = 0;