# HG changeset patch # User Chris Cannam # Date 1400068150 -3600 # Node ID f5325762ff6dee0223473a212887956b464c4666 # Parent e034798ab1107c26bdc6164a039564e6f2f7ffe6 Make CQVamp implement two plugins, one with MIDI pitch range and one with Hz diff -r e034798ab110 -r f5325762ff6d vamp/CQVamp.cpp --- a/vamp/CQVamp.cpp Wed May 14 11:40:18 2014 +0100 +++ b/vamp/CQVamp.cpp Wed May 14 12:49:10 2014 +0100 @@ -41,16 +41,28 @@ using std::cerr; using std::endl; -CQVamp::CQVamp(float inputSampleRate) : +// The plugin offers either MIDI pitch or frequency range parameters, +// depending on the midiPitchParameters option given to the +// constructor. It never offers both. So they can have different +// defaults; if we're using MIDI pitch, the min and max frequencies +// will come from those rather than from the m_minFrequency and +// m_maxFrequency members. +static const int defaultMinMIDIPitch = 36; +static const int defaultMaxMIDIPitch = 96; +static const int defaultBPO = 36; +static const float defaultTuningFrequency = 440.f; + +CQVamp::CQVamp(float inputSampleRate, bool midiPitchParameters) : Vamp::Plugin(inputSampleRate), - m_minMIDIPitch(36), - m_maxMIDIPitch(84), - m_tuningFrequency(440), - m_bpo(24), + m_midiPitchParameters(midiPitchParameters), + m_minMIDIPitch(defaultMinMIDIPitch), + m_maxMIDIPitch(defaultMaxMIDIPitch), + m_tuningFrequency(defaultTuningFrequency), + m_bpo(defaultBPO), m_interpolation(CQSpectrogram::InterpolateLinear), m_cq(0), - m_maxFrequency(inputSampleRate/2), - m_minFrequency(46), + m_maxFrequency(14080), + m_minFrequency(100), m_haveStartTime(false), m_columnCount(0) { @@ -64,19 +76,31 @@ string CQVamp::getIdentifier() const { - return "cqvamp"; + if (m_midiPitchParameters) { + return "cqvampmidi"; + } else { + return "cqvamp"; + } } string CQVamp::getName() const { - return "Constant-Q Spectrogram"; + if (m_midiPitchParameters) { + return "Constant-Q Spectrogram (MIDI pitch range)"; + } else { + return "Constant-Q Spectrogram (Hz range)"; + } } string CQVamp::getDescription() const { - return "Extract a spectrogram with constant ratio of centre frequency to resolution from the input audio"; + if (m_midiPitchParameters) { + return "Extract a spectrogram with constant ratio of centre frequency to resolution from the input audio, specifying the frequency range in MIDI pitch units."; + } else { + return "Extract a spectrogram with constant ratio of centre frequency to resolution from the input audio, specifying the frequency range in Hz."; + } } string @@ -103,37 +127,63 @@ ParameterList list; ParameterDescriptor desc; - desc.identifier = "minpitch"; - desc.name = "Minimum Pitch"; - desc.unit = "MIDI units"; - desc.description = "MIDI pitch corresponding to the lowest frequency to be included in the constant-Q transform"; - desc.minValue = 0; - desc.maxValue = 127; - desc.defaultValue = 36; - desc.isQuantized = true; - desc.quantizeStep = 1; - list.push_back(desc); - desc.identifier = "maxpitch"; - desc.name = "Maximum Pitch"; - desc.unit = "MIDI units"; - desc.description = "MIDI pitch corresponding to the highest frequency to be included in the constant-Q transform"; - desc.minValue = 0; - desc.maxValue = 127; - desc.defaultValue = 84; - desc.isQuantized = true; - desc.quantizeStep = 1; - list.push_back(desc); + if (m_midiPitchParameters) { - desc.identifier = "tuning"; - desc.name = "Tuning Frequency"; - desc.unit = "Hz"; - desc.description = "Frequency of concert A"; - desc.minValue = 360; - desc.maxValue = 500; - desc.defaultValue = 440; - desc.isQuantized = false; - list.push_back(desc); + desc.identifier = "minpitch"; + desc.name = "Minimum Pitch"; + desc.unit = "MIDI units"; + desc.description = "MIDI pitch corresponding to the lowest frequency to be included in the constant-Q transform. (The actual minimum frequency may be lower, as the range always covers an integral number of octaves below the highest frequency.)"; + desc.minValue = 0; + desc.maxValue = 127; + desc.defaultValue = 36; + desc.isQuantized = true; + desc.quantizeStep = 1; + list.push_back(desc); + + desc.identifier = "maxpitch"; + desc.name = "Maximum Pitch"; + desc.unit = "MIDI units"; + desc.description = "MIDI pitch corresponding to the highest frequency to be included in the constant-Q transform"; + desc.minValue = 0; + desc.maxValue = 127; + desc.defaultValue = 84; + desc.isQuantized = true; + desc.quantizeStep = 1; + list.push_back(desc); + + desc.identifier = "tuning"; + desc.name = "Tuning Frequency"; + desc.unit = "Hz"; + desc.description = "Frequency of concert A"; + desc.minValue = 360; + desc.maxValue = 500; + desc.defaultValue = 440; + desc.isQuantized = false; + list.push_back(desc); + + } else { + + desc.identifier = "minfreq"; + desc.name = "Minimum Frequency"; + desc.unit = "Hz"; + desc.description = "Lowest frequency to be included in the constant-Q transform. (The actual minimum frequency may be lower, as the range always covers an integral number of octaves below the highest frequency.)"; + desc.minValue = 1; + desc.maxValue = m_inputSampleRate / 2; + desc.defaultValue = 100; + desc.isQuantized = false; + list.push_back(desc); + + desc.identifier = "maxfreq"; + desc.name = "Maximum Frequency"; + desc.unit = "Hz"; + desc.description = "MIDI pitch corresponding to the highest frequency to be included in the constant-Q transform"; + desc.minValue = 1; + desc.maxValue = m_inputSampleRate / 2; + desc.defaultValue = 14080; + desc.isQuantized = false; + list.push_back(desc); + } desc.identifier = "bpo"; desc.name = "Bins per Octave"; @@ -141,7 +191,7 @@ desc.description = "Number of constant-Q transform bins per octave"; desc.minValue = 2; desc.maxValue = 480; - desc.defaultValue = 24; + desc.defaultValue = 60; desc.isQuantized = true; desc.quantizeStep = 1; list.push_back(desc); @@ -166,13 +216,13 @@ float CQVamp::getParameter(std::string param) const { - if (param == "minpitch") { + if (param == "minpitch" && m_midiPitchParameters) { return m_minMIDIPitch; } - if (param == "maxpitch") { + if (param == "maxpitch" && m_midiPitchParameters) { return m_maxMIDIPitch; } - if (param == "tuning") { + if (param == "tuning" && m_midiPitchParameters) { return m_tuningFrequency; } if (param == "bpo") { @@ -181,6 +231,12 @@ if (param == "interpolation") { return (float)m_interpolation; } + if (param == "minfreq" && !m_midiPitchParameters) { + return m_minFrequency; + } + if (param == "maxfreq" && !m_midiPitchParameters) { + return m_maxFrequency; + } std::cerr << "WARNING: CQVamp::getParameter: unknown parameter \"" << param << "\"" << std::endl; return 0.0; @@ -189,16 +245,20 @@ void CQVamp::setParameter(std::string param, float value) { - if (param == "minpitch") { + if (param == "minpitch" && m_midiPitchParameters) { m_minMIDIPitch = lrintf(value); - } else if (param == "maxpitch") { + } else if (param == "maxpitch" && m_midiPitchParameters) { m_maxMIDIPitch = lrintf(value); - } else if (param == "tuning") { + } else if (param == "tuning" && m_midiPitchParameters) { m_tuningFrequency = value; } else if (param == "bpo") { m_bpo = lrintf(value); } else if (param == "interpolation") { m_interpolation = (CQSpectrogram::Interpolation)lrintf(value); + } else if (param == "minfreq" && !m_midiPitchParameters) { + m_minFrequency = value; + } else if (param == "maxfreq" && !m_midiPitchParameters) { + m_maxFrequency = value; } else { std::cerr << "WARNING: CQVamp::setParameter: unknown parameter \"" << param << "\"" << std::endl; @@ -219,10 +279,12 @@ m_stepSize = stepSize; m_blockSize = blockSize; - m_minFrequency = Pitch::getFrequencyForPitch - (m_minMIDIPitch, 0, m_tuningFrequency); - m_maxFrequency = Pitch::getFrequencyForPitch - (m_maxMIDIPitch, 0, m_tuningFrequency); + if (m_midiPitchParameters) { + m_minFrequency = Pitch::getFrequencyForPitch + (m_minMIDIPitch, 0, m_tuningFrequency); + m_maxFrequency = Pitch::getFrequencyForPitch + (m_maxMIDIPitch, 0, m_tuningFrequency); + } m_cq = new CQSpectrogram (m_inputSampleRate, m_minFrequency, m_maxFrequency, m_bpo, @@ -257,6 +319,33 @@ return 0; } +std::string +CQVamp::noteName(int i) const +{ + static const char *names[] = { + "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" + }; + + const char *n = names[i % 12]; + int oct = i / 12 - 1; + char buf[20]; + sprintf(buf, "%s%d", n, oct); + + return buf; +} + +float +CQVamp::noteFrequency(int note) const +{ + return m_tuningFrequency * pow(2.0, (note - 69) / 12.0); +} + +int +CQVamp::noteNumber(float freq) const +{ + return int(round(57.0 + (12.0 * log(freq / (m_tuningFrequency / 2.0)) / log(2.0)))); +} + CQVamp::OutputList CQVamp::getOutputDescriptors() const { @@ -275,7 +364,12 @@ for (int i = 0; i < (int)d.binCount; ++i) { float freq = m_cq->getBinFrequency(i); sprintf(name, "%.1f Hz", freq); - d.binNames.push_back(name); + if (fabs(noteFrequency(noteNumber(freq)) - freq) < 0.01) { + d.binNames.push_back(name + std::string(": ") + + noteName(noteNumber(freq))); + } else { + d.binNames.push_back(name); + } } } diff -r e034798ab110 -r f5325762ff6d vamp/CQVamp.h --- a/vamp/CQVamp.h Wed May 14 11:40:18 2014 +0100 +++ b/vamp/CQVamp.h Wed May 14 12:49:10 2014 +0100 @@ -41,7 +41,7 @@ class CQVamp : public Vamp::Plugin { public: - CQVamp(float inputSampleRate); + CQVamp(float inputSampleRate, bool midiPitchParameters); virtual ~CQVamp(); bool initialise(size_t channels, size_t stepSize, size_t blockSize); @@ -71,6 +71,7 @@ FeatureSet getRemainingFeatures(); protected: + bool m_midiPitchParameters; int m_minMIDIPitch; int m_maxMIDIPitch; float m_tuningFrequency; @@ -87,6 +88,10 @@ bool m_haveStartTime; int m_columnCount; + std::string noteName(int i) const; + float noteFrequency(int i) const; + int noteNumber(float freq) const; + std::vector m_prevFeature; FeatureSet convertToFeatures(const std::vector > &); }; diff -r e034798ab110 -r f5325762ff6d vamp/libmain.cpp --- a/vamp/libmain.cpp Wed May 14 11:40:18 2014 +0100 +++ b/vamp/libmain.cpp Wed May 14 12:49:10 2014 +0100 @@ -34,7 +34,26 @@ #include "CQVamp.h" -static Vamp::PluginAdapter cqPluginAdapter; +class CQVampPluginAdapter : public Vamp::PluginAdapterBase +{ +public: + CQVampPluginAdapter(bool midiPitchParameters) : + PluginAdapterBase(), + m_midiPitchParameters(midiPitchParameters) + { } + + virtual ~CQVampPluginAdapter() { } + +protected: + bool m_midiPitchParameters; + + Vamp::Plugin *createPlugin(float inputSampleRate) { + return new CQVamp(inputSampleRate, m_midiPitchParameters); + } +}; + +static CQVampPluginAdapter midiAdapter(true); +static CQVampPluginAdapter hzAdapter(false); const VampPluginDescriptor * vampGetPluginDescriptor(unsigned int version, unsigned int index) @@ -42,7 +61,8 @@ if (version < 1) return 0; switch (index) { - case 0: return cqPluginAdapter.getDescriptor(); + case 0: return hzAdapter.getDescriptor(); + case 1: return midiAdapter.getDescriptor(); default: return 0; } }