annotate constant-q-cpp/vamp/CQChromaVamp.cpp @ 372:af71cbdab621 tip

Update bqvec code
author Chris Cannam
date Tue, 19 Nov 2019 10:13:32 +0000
parents 5d0a2ebb4d17
children
rev   line source
Chris@366 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@366 2 /*
Chris@366 3 Constant-Q library
Chris@366 4 Copyright (c) 2013-2014 Queen Mary, University of London
Chris@366 5
Chris@366 6 Permission is hereby granted, free of charge, to any person
Chris@366 7 obtaining a copy of this software and associated documentation
Chris@366 8 files (the "Software"), to deal in the Software without
Chris@366 9 restriction, including without limitation the rights to use, copy,
Chris@366 10 modify, merge, publish, distribute, sublicense, and/or sell copies
Chris@366 11 of the Software, and to permit persons to whom the Software is
Chris@366 12 furnished to do so, subject to the following conditions:
Chris@366 13
Chris@366 14 The above copyright notice and this permission notice shall be
Chris@366 15 included in all copies or substantial portions of the Software.
Chris@366 16
Chris@366 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@366 18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@366 19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Chris@366 20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
Chris@366 21 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@366 22 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@366 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@366 24
Chris@366 25 Except as contained in this notice, the names of the Centre for
Chris@366 26 Digital Music; Queen Mary, University of London; and Chris Cannam
Chris@366 27 shall not be used in advertising or otherwise to promote the sale,
Chris@366 28 use or other dealings in this Software without prior written
Chris@366 29 authorization.
Chris@366 30 */
Chris@366 31
Chris@366 32 #include "CQChromaVamp.h"
Chris@366 33
Chris@366 34 #include "cq/Chromagram.h"
Chris@366 35
Chris@366 36 #include <algorithm>
Chris@366 37
Chris@366 38 using std::string;
Chris@366 39 using std::vector;
Chris@366 40 using std::cerr;
Chris@366 41 using std::endl;
Chris@366 42
Chris@366 43 static const int defaultLowestOctave = 0;
Chris@366 44 static const int defaultOctaveCount = 7;
Chris@366 45 static const int defaultBPO = 36;
Chris@366 46 static const float defaultTuningFrequency = 440.f;
Chris@366 47
Chris@366 48 CQChromaVamp::CQChromaVamp(float inputSampleRate) :
Chris@366 49 Vamp::Plugin(inputSampleRate),
Chris@366 50 m_lowestOctave(defaultLowestOctave),
Chris@366 51 m_octaveCount(defaultOctaveCount),
Chris@366 52 m_tuningFrequency(defaultTuningFrequency),
Chris@366 53 m_bpo(defaultBPO),
Chris@366 54 m_chroma(0),
Chris@366 55 m_haveStartTime(false),
Chris@366 56 m_columnCount(0)
Chris@366 57 {
Chris@366 58 }
Chris@366 59
Chris@366 60 CQChromaVamp::~CQChromaVamp()
Chris@366 61 {
Chris@366 62 delete m_chroma;
Chris@366 63 }
Chris@366 64
Chris@366 65 string
Chris@366 66 CQChromaVamp::getIdentifier() const
Chris@366 67 {
Chris@366 68 return "cqchromavamp";
Chris@366 69 }
Chris@366 70
Chris@366 71 string
Chris@366 72 CQChromaVamp::getName() const
Chris@366 73 {
Chris@366 74 return "CQ Chromagram";
Chris@366 75 }
Chris@366 76
Chris@366 77 string
Chris@366 78 CQChromaVamp::getDescription() const
Chris@366 79 {
Chris@366 80 return "Extract a Constant-Q spectrogram with constant ratio of centre frequency to resolution from the audio, then wrap it around into a single-octave chromagram.";
Chris@366 81 }
Chris@366 82
Chris@366 83 string
Chris@366 84 CQChromaVamp::getMaker() const
Chris@366 85 {
Chris@366 86 return "Queen Mary, University of London";
Chris@366 87 }
Chris@366 88
Chris@366 89 int
Chris@366 90 CQChromaVamp::getPluginVersion() const
Chris@366 91 {
Chris@366 92 return 2;
Chris@366 93 }
Chris@366 94
Chris@366 95 string
Chris@366 96 CQChromaVamp::getCopyright() const
Chris@366 97 {
Chris@366 98 return "Plugin by Chris Cannam. Method by Christian Schörkhuber and Anssi Klapuri. Copyright (c) 2015 QMUL. BSD/MIT licence.";
Chris@366 99 }
Chris@366 100
Chris@366 101 CQChromaVamp::ParameterList
Chris@366 102 CQChromaVamp::getParameterDescriptors() const
Chris@366 103 {
Chris@366 104 ParameterList list;
Chris@366 105
Chris@366 106 ParameterDescriptor desc;
Chris@366 107
Chris@366 108 desc.identifier = "lowestoct";
Chris@366 109 desc.name = "Lowest Contributing Octave";
Chris@366 110 desc.unit = "";
Chris@366 111 desc.description = "Octave number of the lowest octave to include in the chromagram. Octave numbering is ASA standard, with -1 as the first octave in the MIDI range and middle-C being C4. The octave starts at C.";
Chris@366 112 desc.minValue = -1;
Chris@366 113 desc.maxValue = 12;
Chris@366 114 desc.defaultValue = defaultLowestOctave;
Chris@366 115 desc.isQuantized = true;
Chris@366 116 desc.quantizeStep = 1;
Chris@366 117 list.push_back(desc);
Chris@366 118
Chris@366 119 desc.identifier = "octaves";
Chris@366 120 desc.name = "Contributing Octave Count";
Chris@366 121 desc.unit = "octaves";
Chris@366 122 desc.description = "Number of octaves to use when generating the Constant-Q transform. All octaves are wrapped around and summed to produce a single octave chromagram as output.";
Chris@366 123 desc.minValue = 1;
Chris@366 124 desc.maxValue = 12;
Chris@366 125 desc.defaultValue = defaultOctaveCount;
Chris@366 126 desc.isQuantized = true;
Chris@366 127 desc.quantizeStep = 1;
Chris@366 128 list.push_back(desc);
Chris@366 129
Chris@366 130 desc.identifier = "tuning";
Chris@366 131 desc.name = "Tuning Frequency";
Chris@366 132 desc.unit = "Hz";
Chris@366 133 desc.description = "Frequency of concert A";
Chris@366 134 desc.minValue = 360;
Chris@366 135 desc.maxValue = 500;
Chris@366 136 desc.defaultValue = defaultTuningFrequency;
Chris@366 137 desc.isQuantized = false;
Chris@366 138 list.push_back(desc);
Chris@366 139
Chris@366 140 desc.identifier = "bpo";
Chris@366 141 desc.name = "Bins per Octave";
Chris@366 142 desc.unit = "bins";
Chris@366 143 desc.description = "Number of constant-Q transform bins per octave";
Chris@366 144 desc.minValue = 2;
Chris@366 145 desc.maxValue = 480;
Chris@366 146 desc.defaultValue = defaultBPO;
Chris@366 147 desc.isQuantized = true;
Chris@366 148 desc.quantizeStep = 1;
Chris@366 149 list.push_back(desc);
Chris@366 150
Chris@366 151 return list;
Chris@366 152 }
Chris@366 153
Chris@366 154 float
Chris@366 155 CQChromaVamp::getParameter(std::string param) const
Chris@366 156 {
Chris@366 157 if (param == "lowestoct") {
Chris@366 158 return m_lowestOctave;
Chris@366 159 }
Chris@366 160 if (param == "octaves") {
Chris@366 161 return m_octaveCount;
Chris@366 162 }
Chris@366 163 if (param == "tuning") {
Chris@366 164 return m_tuningFrequency;
Chris@366 165 }
Chris@366 166 if (param == "bpo") {
Chris@366 167 return m_bpo;
Chris@366 168 }
Chris@366 169 std::cerr << "WARNING: CQChromaVamp::getParameter: unknown parameter \""
Chris@366 170 << param << "\"" << std::endl;
Chris@366 171 return 0.0;
Chris@366 172 }
Chris@366 173
Chris@366 174 void
Chris@366 175 CQChromaVamp::setParameter(std::string param, float value)
Chris@366 176 {
Chris@366 177 if (param == "lowestoct") {
Chris@366 178 m_lowestOctave = int(value + 0.5f);
Chris@366 179 } else if (param == "octaves") {
Chris@366 180 m_octaveCount = int(value + 0.5f);
Chris@366 181 } else if (param == "tuning") {
Chris@366 182 m_tuningFrequency = value;
Chris@366 183 } else if (param == "bpo") {
Chris@366 184 m_bpo = int(value + 0.5f);
Chris@366 185 } else {
Chris@366 186 std::cerr << "WARNING: CQChromaVamp::setParameter: unknown parameter \""
Chris@366 187 << param << "\"" << std::endl;
Chris@366 188 }
Chris@366 189 }
Chris@366 190
Chris@366 191 bool
Chris@366 192 CQChromaVamp::initialise(size_t channels, size_t stepSize, size_t blockSize)
Chris@366 193 {
Chris@366 194 if (m_chroma) {
Chris@366 195 delete m_chroma;
Chris@366 196 m_chroma = 0;
Chris@366 197 }
Chris@366 198
Chris@366 199 if (channels < getMinChannelCount() ||
Chris@366 200 channels > getMaxChannelCount()) return false;
Chris@366 201
Chris@366 202 m_stepSize = stepSize;
Chris@366 203 m_blockSize = blockSize;
Chris@366 204
Chris@366 205 reset();
Chris@366 206
Chris@366 207 if (!m_chroma || !m_chroma->isValid()) {
Chris@366 208 cerr << "CQVamp::initialise: Constant-Q parameters not valid! Not initialising" << endl;
Chris@366 209 return false;
Chris@366 210 }
Chris@366 211
Chris@366 212 return true;
Chris@366 213 }
Chris@366 214
Chris@366 215 void
Chris@366 216 CQChromaVamp::reset()
Chris@366 217 {
Chris@366 218 delete m_chroma;
Chris@366 219 Chromagram::Parameters p(m_inputSampleRate);
Chris@366 220 p.lowestOctave = m_lowestOctave;
Chris@366 221 p.octaveCount = m_octaveCount;
Chris@366 222 p.binsPerOctave = m_bpo;
Chris@366 223 p.tuningFrequency = m_tuningFrequency;
Chris@366 224
Chris@366 225 m_chroma = new Chromagram(p);
Chris@366 226
Chris@366 227 m_haveStartTime = false;
Chris@366 228 m_startTime = Vamp::RealTime::zeroTime;
Chris@366 229 m_columnCount = 0;
Chris@366 230 }
Chris@366 231
Chris@366 232 size_t
Chris@366 233 CQChromaVamp::getPreferredStepSize() const
Chris@366 234 {
Chris@366 235 return 0;
Chris@366 236 }
Chris@366 237
Chris@366 238 size_t
Chris@366 239 CQChromaVamp::getPreferredBlockSize() const
Chris@366 240 {
Chris@366 241 return 0;
Chris@366 242 }
Chris@366 243
Chris@366 244 CQChromaVamp::OutputList
Chris@366 245 CQChromaVamp::getOutputDescriptors() const
Chris@366 246 {
Chris@366 247 OutputList list;
Chris@366 248
Chris@366 249 OutputDescriptor d;
Chris@366 250 d.identifier = "chromagram";
Chris@366 251 d.name = "Chromagram";
Chris@366 252 d.unit = "";
Chris@366 253 d.description = "Chromagram obtained from output of constant-Q transform, folding over each process block into a single-octave vector";
Chris@366 254 d.hasFixedBinCount = true;
Chris@366 255 d.binCount = m_bpo;
Chris@366 256
Chris@366 257 if (m_chroma) {
Chris@366 258 for (int i = 0; i < (int)d.binCount; ++i) {
Chris@366 259 d.binNames.push_back(m_chroma->getBinName(i));
Chris@366 260 }
Chris@366 261 }
Chris@366 262
Chris@366 263 d.hasKnownExtents = false;
Chris@366 264 d.isQuantized = false;
Chris@366 265 d.sampleType = OutputDescriptor::FixedSampleRate;
Chris@366 266 d.sampleRate = m_inputSampleRate / (m_chroma ? m_chroma->getColumnHop() : 256);
Chris@366 267 list.push_back(d);
Chris@366 268
Chris@366 269 return list;
Chris@366 270 }
Chris@366 271
Chris@366 272 CQChromaVamp::FeatureSet
Chris@366 273 CQChromaVamp::process(const float *const *inputBuffers,
Chris@366 274 Vamp::RealTime timestamp)
Chris@366 275 {
Chris@366 276 if (!m_chroma) {
Chris@366 277 cerr << "ERROR: CQChromaVamp::process: "
Chris@366 278 << "Plugin has not been initialised"
Chris@366 279 << endl;
Chris@366 280 return FeatureSet();
Chris@366 281 }
Chris@366 282
Chris@366 283 if (!m_haveStartTime) {
Chris@366 284 m_startTime = timestamp;
Chris@366 285 m_haveStartTime = true;
Chris@366 286 }
Chris@366 287
Chris@366 288 vector<double> data;
Chris@366 289 for (int i = 0; i < m_blockSize; ++i) data.push_back(inputBuffers[0][i]);
Chris@366 290
Chris@366 291 vector<vector<double> > chromaout = m_chroma->process(data);
Chris@366 292 return convertToFeatures(chromaout);
Chris@366 293 }
Chris@366 294
Chris@366 295 CQChromaVamp::FeatureSet
Chris@366 296 CQChromaVamp::getRemainingFeatures()
Chris@366 297 {
Chris@366 298 vector<vector<double> > chromaout = m_chroma->getRemainingOutput();
Chris@366 299 return convertToFeatures(chromaout);
Chris@366 300 }
Chris@366 301
Chris@366 302 CQChromaVamp::FeatureSet
Chris@366 303 CQChromaVamp::convertToFeatures(const vector<vector<double> > &chromaout)
Chris@366 304 {
Chris@366 305 FeatureSet returnFeatures;
Chris@366 306
Chris@366 307 int width = chromaout.size();
Chris@366 308
Chris@366 309 for (int i = 0; i < width; ++i) {
Chris@366 310
Chris@366 311 vector<float> column(chromaout[i].begin(), chromaout[i].end());
Chris@366 312
Chris@366 313 Feature feature;
Chris@366 314 feature.hasTimestamp = true;
Chris@366 315 feature.timestamp = m_startTime + Vamp::RealTime::frame2RealTime
Chris@366 316 (m_columnCount * m_chroma->getColumnHop() - m_chroma->getLatency(),
Chris@366 317 m_inputSampleRate);
Chris@366 318 feature.values = column;
Chris@366 319 feature.label = "";
Chris@366 320
Chris@366 321 if (feature.timestamp >= m_startTime) {
Chris@366 322 returnFeatures[0].push_back(feature);
Chris@366 323 }
Chris@366 324
Chris@366 325 ++m_columnCount;
Chris@366 326 }
Chris@366 327
Chris@366 328 return returnFeatures;
Chris@366 329 }
Chris@366 330