Mercurial > hg > qm-vamp-plugins
changeset 9:507f923a93e8
* Add Constant-Q Spectrogram plugin
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Mon, 15 May 2006 19:56:21 +0000 |
parents | a8215973f030 |
children | 6ab46726a653 |
files | libmain.cpp plugins/ChromagramPlugin.cpp plugins/ConstantQSpectrogram.cpp plugins/ConstantQSpectrogram.h plugins/TonalChangeDetect.cpp qm-vamp-plugins.pro |
diffstat | 6 files changed, 431 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/libmain.cpp Mon May 15 15:12:46 2006 +0000 +++ b/libmain.cpp Mon May 15 19:56:21 2006 +0000 @@ -12,10 +12,12 @@ #include "plugins/BeatDetect.h" #include "plugins/ChromagramPlugin.h" +#include "plugins/ConstantQSpectrogram.h" #include "plugins/TonalChangeDetect.h" static Vamp::PluginAdapter<BeatDetector> beatDetectorAdapter; static Vamp::PluginAdapter<ChromagramPlugin> chromagramPluginAdapter; +static Vamp::PluginAdapter<ConstantQSpectrogram> constantQAdapter; static Vamp::PluginAdapter<TonalChangeDetect> tonalChangeDetectorAdapter; const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int index) @@ -23,7 +25,8 @@ switch (index) { case 0: return beatDetectorAdapter.getDescriptor(); case 1: return chromagramPluginAdapter.getDescriptor(); - case 2: return tonalChangeDetectorAdapter.getDescriptor(); + case 2: return constantQAdapter.getDescriptor(); + case 3: return tonalChangeDetectorAdapter.getDescriptor(); default: return 0; } }
--- a/plugins/ChromagramPlugin.cpp Mon May 15 15:12:46 2006 +0000 +++ b/plugins/ChromagramPlugin.cpp Mon May 15 19:56:21 2006 +0000 @@ -56,7 +56,7 @@ string ChromagramPlugin::getName() const { - return "chromagram"; + return "qm-chromagram"; } string @@ -265,7 +265,7 @@ } } } else { - d.binNames.push_back("C"); + d.binNames.push_back(names[m_minMIDIPitch % 12]); } d.hasKnownExtents = m_normalized; @@ -274,13 +274,7 @@ d.isQuantized = false; d.sampleType = OutputDescriptor::OneSamplePerStep; list.push_back(d); -/* - d.name = "normalized"; - d.description = "Normalized Chromagram"; - d.hasKnownExtents = true; - d.maxValue = 1.0; - list.push_back(d); -*/ + return list; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/ConstantQSpectrogram.cpp Mon May 15 19:56:21 2006 +0000 @@ -0,0 +1,354 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + QM Vamp Plugin Set + + Centre for Digital Music, Queen Mary, University of London. + All rights reserved. +*/ + +#include "ConstantQSpectrogram.h" + +#include <base/Pitch.h> +#include <dsp/chromagram/ConstantQ.h> + +using std::string; +using std::vector; +using std::cerr; +using std::endl; + +ConstantQSpectrogram::ConstantQSpectrogram(float inputSampleRate) : + Vamp::Plugin(inputSampleRate), + m_cq(0), + m_step(0), + m_block(0), + m_bins(1) +{ + m_minMIDIPitch = 12; + m_maxMIDIPitch = 96; + m_tuningFrequency = 440; + m_normalized = true; + m_bpo = 12; + + setupConfig(); +} + +void +ConstantQSpectrogram::setupConfig() +{ + m_config.FS = lrintf(m_inputSampleRate); + m_config.min = Pitch::getFrequencyForPitch + (m_minMIDIPitch, 0, m_tuningFrequency); + m_config.max = Pitch::getFrequencyForPitch + (m_maxMIDIPitch, 0, m_tuningFrequency); + m_config.BPO = m_bpo; + m_config.CQThresh = 0.0054; + + m_step = 0; + m_block = 0; +} + +ConstantQSpectrogram::~ConstantQSpectrogram() +{ + delete m_cq; +} + +string +ConstantQSpectrogram::getName() const +{ + return "qm-constantq"; +} + +string +ConstantQSpectrogram::getDescription() const +{ + return "Constant-Q Spectrogram"; +} + +string +ConstantQSpectrogram::getMaker() const +{ + return "Queen Mary, University of London"; +} + +int +ConstantQSpectrogram::getPluginVersion() const +{ + return 1; +} + +string +ConstantQSpectrogram::getCopyright() const +{ + return "Copyright (c) 2006 - All Rights Reserved"; +} + +ConstantQSpectrogram::ParameterList +ConstantQSpectrogram::getParameterDescriptors() const +{ + ParameterList list; + + ParameterDescriptor desc; + desc.name = "minpitch"; + desc.description = "Minimum Pitch"; + desc.unit = "MIDI units"; + desc.minValue = 0; + desc.maxValue = 127; + desc.defaultValue = 36; + desc.isQuantized = true; + desc.quantizeStep = 1; + list.push_back(desc); + + desc.name = "maxpitch"; + desc.description = "Maximum Pitch"; + desc.unit = "MIDI units"; + desc.minValue = 0; + desc.maxValue = 127; + desc.defaultValue = 84; + desc.isQuantized = true; + desc.quantizeStep = 1; + list.push_back(desc); + + desc.name = "tuning"; + desc.description = "Tuning Frequency"; + desc.unit = "Hz"; + desc.minValue = 420; + desc.maxValue = 460; + desc.defaultValue = 440; + desc.isQuantized = false; + list.push_back(desc); + + desc.name = "bpo"; + desc.description = "Bins per Octave"; + desc.unit = "bins"; + desc.minValue = 2; + desc.maxValue = 36; + desc.defaultValue = 12; + desc.isQuantized = true; + desc.quantizeStep = 1; + list.push_back(desc); + + desc.name = "normalized"; + desc.description = "Normalized"; + desc.unit = ""; + desc.minValue = 0; + desc.maxValue = 1; + desc.defaultValue = 1; + desc.isQuantized = true; + desc.quantizeStep = 1; + list.push_back(desc); + + return list; +} + +float +ConstantQSpectrogram::getParameter(std::string param) const +{ + if (param == "minpitch") { + return m_minMIDIPitch; + } + if (param == "maxpitch") { + return m_maxMIDIPitch; + } + if (param == "tuning") { + return m_tuningFrequency; + } + if (param == "bpo") { + return m_bpo; + } + if (param == "normalized") { + return m_normalized; + } + std::cerr << "WARNING: ConstantQSpectrogram::getParameter: unknown parameter \"" + << param << "\"" << std::endl; + return 0.0; +} + +void +ConstantQSpectrogram::setParameter(std::string param, float value) +{ + if (param == "minpitch") { + m_minMIDIPitch = lrintf(value); + } else if (param == "maxpitch") { + m_maxMIDIPitch = lrintf(value); + } else if (param == "tuning") { + m_tuningFrequency = value; + } else if (param == "bpo") { + m_bpo = lrintf(value); + } else if (param == "normalized") { + m_normalized = (value > 0.0001); + } else { + std::cerr << "WARNING: ConstantQSpectrogram::setParameter: unknown parameter \"" + << param << "\"" << std::endl; + } + + setupConfig(); +} + + +bool +ConstantQSpectrogram::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (m_cq) { + delete m_cq; + m_cq = 0; + } + + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + if (stepSize != m_step) return false; + if (blockSize != m_block) return false; + + std::cerr << "ConstantQSpectrogram::initialise: step " << stepSize << ", block " + << blockSize << std::endl; + + m_cq = new ConstantQ(m_config); + m_bins = (int)ceil(m_bpo * log(m_config.max / m_config.min) / log(2.0)); + m_cq->sparsekernel(); + + return true; +} + +void +ConstantQSpectrogram::reset() +{ + if (m_cq) { + delete m_cq; + m_cq = new ConstantQ(m_config); + } +} + +size_t +ConstantQSpectrogram::getPreferredStepSize() const +{ + if (!m_step) { + ConstantQ cq(m_config); + m_step = cq.gethop(); + m_block = cq.getfftlength(); + } + + return m_step; +} + +size_t +ConstantQSpectrogram::getPreferredBlockSize() const +{ + if (!m_block) { + ConstantQ cq(m_config); + m_step = cq.gethop(); + m_block = cq.getfftlength(); + } + + return m_block; +} + +ConstantQSpectrogram::OutputList +ConstantQSpectrogram::getOutputDescriptors() const +{ + OutputList list; + + OutputDescriptor d; + d.name = "constantq"; + d.unit = ""; + d.description = "Constant-Q Spectrogram"; + d.hasFixedBinCount = true; + d.binCount = m_bins; + + std::cerr << "Bin count " << d.binCount << std::endl; + + const char *names[] = + { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; + + if (m_bpo == 12) { + for (int i = 0; i < d.binCount; ++i) { + int ipc = m_minMIDIPitch % 12; + int index = (i + ipc) % 12; + d.binNames.push_back(names[index]); + } + } else { + d.binNames.push_back(names[m_minMIDIPitch % 12]); + } + + d.hasKnownExtents = m_normalized; + d.minValue = 0.0; + d.maxValue = (m_normalized ? 1.0 : 0.0); + d.isQuantized = false; + d.sampleType = OutputDescriptor::OneSamplePerStep; + list.push_back(d); + + return list; +} + +ConstantQSpectrogram::Feature +ConstantQSpectrogram::normalize(const Feature &feature) +{ + float min = 0.0, max = 0.0; + + for (size_t i = 0; i < feature.values.size(); ++i) { + if (i == 0 || feature.values[i] < min) min = feature.values[i]; + if (i == 0 || feature.values[i] > max) max = feature.values[i]; + } + + if (max == 0.0 || max == min) return feature; + + Feature normalized; + normalized.hasTimestamp = false; + + for (size_t i = 0; i < feature.values.size(); ++i) { + normalized.values.push_back((feature.values[i] - min) / (max - min)); + } + + return normalized; +} + +ConstantQSpectrogram::FeatureSet +ConstantQSpectrogram::process(float **inputBuffers, Vamp::RealTime /* timestamp */) +{ + if (!m_cq) { + cerr << "ERROR: ConstantQSpectrogram::process: " + << "Constant-Q has not been initialised" + << endl; + return FeatureSet(); + } + + double *real = new double[m_block]; + double *imag = new double[m_block]; + double *cqre = new double[m_bins]; + double *cqim = new double[m_bins]; + + for (size_t i = 0; i < m_block/2; ++i) { + real[i] = inputBuffers[0][i*2]; + real[m_block - i] = real[i]; + imag[i] = inputBuffers[0][i*2+1]; + imag[m_block - i] = imag[i]; + } + + m_cq->process(real, imag, cqre, cqim); + + delete[] real; + delete[] imag; + + Feature feature; + feature.hasTimestamp = false; + for (size_t i = 0; i < m_bins; ++i) { + feature.values.push_back(sqrt(cqre[i] * cqre[i] + + cqim[i] * cqim[i])); + } + feature.label = ""; + + delete[] cqre; + delete[] cqim; + + FeatureSet returnFeatures; + if (m_normalized) returnFeatures[0].push_back(normalize(feature)); + else returnFeatures[0].push_back(feature); + return returnFeatures; +} + +ConstantQSpectrogram::FeatureSet +ConstantQSpectrogram::getRemainingFeatures() +{ + return FeatureSet(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/ConstantQSpectrogram.h Mon May 15 19:56:21 2006 +0000 @@ -0,0 +1,67 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + QM Vamp Plugin Set + + Centre for Digital Music, Queen Mary, University of London. + All rights reserved. +*/ + +#ifndef _CONSTANT_Q_SPECTROGRAM_PLUGIN_H_ +#define _CONSTANT_Q_SPECTROGRAM_PLUGIN_H_ + +#include <vamp-sdk/Plugin.h> +#include <dsp/chromagram/ConstantQ.h> + +#include <queue> + +class ConstantQSpectrogram : public Vamp::Plugin +{ +public: + ConstantQSpectrogram(float inputSampleRate); + virtual ~ConstantQSpectrogram(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + void reset(); + + InputDomain getInputDomain() const { return FrequencyDomain; } + + std::string getName() const; + std::string getDescription() const; + std::string getMaker() const; + int getPluginVersion() const; + std::string getCopyright() const; + + ParameterList getParameterDescriptors() const; + float getParameter(std::string) const; + void setParameter(std::string, float); + + size_t getPreferredStepSize() const; + size_t getPreferredBlockSize() const; + + OutputList getOutputDescriptors() const; + + FeatureSet process(float **inputBuffers, Vamp::RealTime timestamp); + + FeatureSet getRemainingFeatures(); + +protected: + int m_minMIDIPitch; + int m_maxMIDIPitch; + float m_tuningFrequency; + bool m_normalized; + int m_bpo; + int m_bins; + + void setupConfig(); + + CQConfig m_config; + ConstantQ *m_cq; + mutable size_t m_step; + mutable size_t m_block; + + Feature normalize(const Feature &); +}; + + +#endif
--- a/plugins/TonalChangeDetect.cpp Mon May 15 15:12:46 2006 +0000 +++ b/plugins/TonalChangeDetect.cpp Mon May 15 19:56:21 2006 +0000 @@ -71,7 +71,7 @@ std::string TonalChangeDetect::getName() const { - return "TonalChange"; + return "qm-tonalchange"; } std::string TonalChangeDetect::getDescription() const
--- a/qm-vamp-plugins.pro Mon May 15 15:12:46 2006 +0000 +++ b/qm-vamp-plugins.pro Mon May 15 19:56:21 2006 +0000 @@ -18,8 +18,10 @@ # Input HEADERS += plugins/BeatDetect.h \ plugins/ChromagramPlugin.h \ + plugins/ConstantQSpectrogram.h \ plugins/TonalChangeDetect.h SOURCES += plugins/BeatDetect.cpp \ plugins/ChromagramPlugin.cpp \ + plugins/ConstantQSpectrogram.cpp \ plugins/TonalChangeDetect.cpp \ ./libmain.cpp