annotate vamp/CQVamp.cpp @ 69:27007f8302f4

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