annotate examples/FixedTempoEstimator.cpp @ 246:5bfed156b45d

* 3 * lag is not related in 4/4, is it?
author cannam
date Tue, 11 Nov 2008 09:49:12 +0000
parents 8042ab66f707
children 88ef5ffdbe8d
rev   line source
cannam@198 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@198 2
cannam@198 3 /*
cannam@198 4 Vamp
cannam@198 5
cannam@198 6 An API for audio analysis and feature extraction plugins.
cannam@198 7
cannam@198 8 Centre for Digital Music, Queen Mary, University of London.
cannam@198 9 Copyright 2006-2008 Chris Cannam and QMUL.
cannam@198 10
cannam@198 11 Permission is hereby granted, free of charge, to any person
cannam@198 12 obtaining a copy of this software and associated documentation
cannam@198 13 files (the "Software"), to deal in the Software without
cannam@198 14 restriction, including without limitation the rights to use, copy,
cannam@198 15 modify, merge, publish, distribute, sublicense, and/or sell copies
cannam@198 16 of the Software, and to permit persons to whom the Software is
cannam@198 17 furnished to do so, subject to the following conditions:
cannam@198 18
cannam@198 19 The above copyright notice and this permission notice shall be
cannam@198 20 included in all copies or substantial portions of the Software.
cannam@198 21
cannam@198 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@198 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@198 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
cannam@198 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
cannam@198 26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@198 27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@198 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@198 29
cannam@198 30 Except as contained in this notice, the names of the Centre for
cannam@198 31 Digital Music; Queen Mary, University of London; and Chris Cannam
cannam@198 32 shall not be used in advertising or otherwise to promote the sale,
cannam@198 33 use or other dealings in this Software without prior written
cannam@198 34 authorization.
cannam@198 35 */
cannam@198 36
cannam@198 37 #include "FixedTempoEstimator.h"
cannam@198 38
cannam@198 39 using std::string;
cannam@198 40 using std::vector;
cannam@198 41 using std::cerr;
cannam@198 42 using std::endl;
cannam@198 43
cannam@198 44 using Vamp::RealTime;
cannam@198 45
cannam@198 46 #include <cmath>
cannam@198 47
cannam@198 48
cannam@243 49 class FixedTempoEstimator::D
cannam@243 50 {
cannam@243 51 public:
cannam@243 52 D(float inputSampleRate);
cannam@243 53 ~D();
cannam@243 54
cannam@243 55 size_t getPreferredStepSize() const { return 64; }
cannam@243 56 size_t getPreferredBlockSize() const { return 256; }
cannam@243 57
cannam@243 58 ParameterList getParameterDescriptors() const;
cannam@243 59 float getParameter(string id) const;
cannam@243 60 void setParameter(string id, float value);
cannam@243 61
cannam@243 62 OutputList getOutputDescriptors() const;
cannam@243 63
cannam@243 64 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
cannam@243 65 void reset();
cannam@243 66 FeatureSet process(const float *const *, RealTime);
cannam@243 67 FeatureSet getRemainingFeatures();
cannam@243 68
cannam@243 69 private:
cannam@243 70 void calculate();
cannam@243 71 FeatureSet assembleFeatures();
cannam@243 72
cannam@243 73 float lag2tempo(int);
cannam@243 74 int tempo2lag(float);
cannam@243 75
cannam@243 76 float m_inputSampleRate;
cannam@243 77 size_t m_stepSize;
cannam@243 78 size_t m_blockSize;
cannam@243 79
cannam@243 80 float m_minbpm;
cannam@243 81 float m_maxbpm;
cannam@243 82 float m_maxdflen;
cannam@243 83
cannam@243 84 float *m_priorMagnitudes;
cannam@243 85
cannam@243 86 size_t m_dfsize;
cannam@243 87 float *m_df;
cannam@243 88 float *m_r;
cannam@243 89 float *m_fr;
cannam@243 90 float *m_t;
cannam@243 91 size_t m_n;
cannam@243 92
cannam@243 93 Vamp::RealTime m_start;
cannam@243 94 Vamp::RealTime m_lasttime;
cannam@243 95 };
cannam@243 96
cannam@243 97 FixedTempoEstimator::D::D(float inputSampleRate) :
cannam@243 98 m_inputSampleRate(inputSampleRate),
cannam@198 99 m_stepSize(0),
cannam@198 100 m_blockSize(0),
cannam@243 101 m_minbpm(50),
cannam@243 102 m_maxbpm(190),
cannam@243 103 m_maxdflen(10),
cannam@198 104 m_priorMagnitudes(0),
cannam@200 105 m_df(0),
cannam@200 106 m_r(0),
cannam@200 107 m_fr(0),
cannam@204 108 m_t(0),
cannam@200 109 m_n(0)
cannam@198 110 {
cannam@198 111 }
cannam@198 112
cannam@243 113 FixedTempoEstimator::D::~D()
cannam@198 114 {
cannam@198 115 delete[] m_priorMagnitudes;
cannam@198 116 delete[] m_df;
cannam@200 117 delete[] m_r;
cannam@200 118 delete[] m_fr;
cannam@204 119 delete[] m_t;
cannam@198 120 }
cannam@198 121
cannam@198 122 FixedTempoEstimator::ParameterList
cannam@243 123 FixedTempoEstimator::D::getParameterDescriptors() const
cannam@198 124 {
cannam@198 125 ParameterList list;
cannam@243 126
cannam@243 127 ParameterDescriptor d;
cannam@243 128 d.identifier = "minbpm";
cannam@243 129 d.name = "Minimum estimated tempo";
cannam@243 130 d.description = "Minimum beat-per-minute value which the tempo estimator is able to return";
cannam@243 131 d.unit = "bpm";
cannam@243 132 d.minValue = 10;
cannam@243 133 d.maxValue = 360;
cannam@243 134 d.defaultValue = 50;
cannam@243 135 d.isQuantized = false;
cannam@243 136 list.push_back(d);
cannam@243 137
cannam@243 138 d.identifier = "maxbpm";
cannam@243 139 d.name = "Maximum estimated tempo";
cannam@243 140 d.description = "Maximum beat-per-minute value which the tempo estimator is able to return";
cannam@243 141 d.defaultValue = 190;
cannam@243 142 list.push_back(d);
cannam@243 143
cannam@243 144 d.identifier = "maxdflen";
cannam@243 145 d.name = "Input duration to study";
cannam@243 146 d.description = "Length of audio input, in seconds, which should be taken into account when estimating tempo. There is no need to supply the plugin with any further input once this time has elapsed since the start of the audio. The tempo estimator may use only the first part of this, up to eight times the slowest beat duration: increasing this value further than that is unlikely to improve results.";
cannam@243 147 d.unit = "s";
cannam@243 148 d.minValue = 2;
cannam@243 149 d.maxValue = 40;
cannam@243 150 d.defaultValue = 10;
cannam@243 151 list.push_back(d);
cannam@243 152
cannam@198 153 return list;
cannam@198 154 }
cannam@198 155
cannam@198 156 float
cannam@243 157 FixedTempoEstimator::D::getParameter(string id) const
cannam@198 158 {
cannam@243 159 if (id == "minbpm") {
cannam@243 160 return m_minbpm;
cannam@243 161 } else if (id == "maxbpm") {
cannam@243 162 return m_maxbpm;
cannam@243 163 } else if (id == "maxdflen") {
cannam@243 164 return m_maxdflen;
cannam@243 165 }
cannam@198 166 return 0.f;
cannam@198 167 }
cannam@198 168
cannam@198 169 void
cannam@243 170 FixedTempoEstimator::D::setParameter(string id, float value)
cannam@198 171 {
cannam@243 172 if (id == "minbpm") {
cannam@243 173 m_minbpm = value;
cannam@243 174 } else if (id == "maxbpm") {
cannam@243 175 m_maxbpm = value;
cannam@243 176 } else if (id == "maxdflen") {
cannam@243 177 m_maxdflen = value;
cannam@243 178 }
cannam@198 179 }
cannam@198 180
cannam@200 181 static int TempoOutput = 0;
cannam@200 182 static int CandidatesOutput = 1;
cannam@200 183 static int DFOutput = 2;
cannam@200 184 static int ACFOutput = 3;
cannam@200 185 static int FilteredACFOutput = 4;
cannam@200 186
cannam@198 187 FixedTempoEstimator::OutputList
cannam@243 188 FixedTempoEstimator::D::getOutputDescriptors() const
cannam@198 189 {
cannam@198 190 OutputList list;
cannam@198 191
cannam@198 192 OutputDescriptor d;
cannam@198 193 d.identifier = "tempo";
cannam@198 194 d.name = "Tempo";
cannam@198 195 d.description = "Estimated tempo";
cannam@198 196 d.unit = "bpm";
cannam@198 197 d.hasFixedBinCount = true;
cannam@198 198 d.binCount = 1;
cannam@198 199 d.hasKnownExtents = false;
cannam@198 200 d.isQuantized = false;
cannam@198 201 d.sampleType = OutputDescriptor::VariableSampleRate;
cannam@198 202 d.sampleRate = m_inputSampleRate;
cannam@198 203 d.hasDuration = true; // our returned tempo spans a certain range
cannam@198 204 list.push_back(d);
cannam@198 205
cannam@200 206 d.identifier = "candidates";
cannam@200 207 d.name = "Tempo candidates";
cannam@200 208 d.description = "Possible tempo estimates, one per bin with the most likely in the first bin";
cannam@200 209 d.unit = "bpm";
cannam@200 210 d.hasFixedBinCount = false;
cannam@200 211 list.push_back(d);
cannam@200 212
cannam@198 213 d.identifier = "detectionfunction";
cannam@198 214 d.name = "Detection Function";
cannam@198 215 d.description = "Onset detection function";
cannam@198 216 d.unit = "";
cannam@198 217 d.hasFixedBinCount = 1;
cannam@198 218 d.binCount = 1;
cannam@198 219 d.hasKnownExtents = true;
cannam@198 220 d.minValue = 0.0;
cannam@198 221 d.maxValue = 1.0;
cannam@198 222 d.isQuantized = false;
cannam@198 223 d.quantizeStep = 0.0;
cannam@198 224 d.sampleType = OutputDescriptor::FixedSampleRate;
cannam@198 225 if (m_stepSize) {
cannam@198 226 d.sampleRate = m_inputSampleRate / m_stepSize;
cannam@198 227 } else {
cannam@198 228 d.sampleRate = m_inputSampleRate / (getPreferredBlockSize()/2);
cannam@198 229 }
cannam@198 230 d.hasDuration = false;
cannam@198 231 list.push_back(d);
cannam@198 232
cannam@198 233 d.identifier = "acf";
cannam@198 234 d.name = "Autocorrelation Function";
cannam@198 235 d.description = "Autocorrelation of onset detection function";
cannam@198 236 d.hasKnownExtents = false;
cannam@201 237 d.unit = "r";
cannam@198 238 list.push_back(d);
cannam@198 239
cannam@198 240 d.identifier = "filtered_acf";
cannam@198 241 d.name = "Filtered Autocorrelation";
cannam@198 242 d.description = "Filtered autocorrelation of onset detection function";
cannam@201 243 d.unit = "r";
cannam@198 244 list.push_back(d);
cannam@198 245
cannam@198 246 return list;
cannam@198 247 }
cannam@198 248
cannam@243 249 bool
cannam@243 250 FixedTempoEstimator::D::initialise(size_t channels,
cannam@243 251 size_t stepSize, size_t blockSize)
cannam@243 252 {
cannam@243 253 m_stepSize = stepSize;
cannam@243 254 m_blockSize = blockSize;
cannam@243 255
cannam@243 256 float dfLengthSecs = m_maxdflen;
cannam@243 257 m_dfsize = (dfLengthSecs * m_inputSampleRate) / m_stepSize;
cannam@243 258
cannam@243 259 m_priorMagnitudes = new float[m_blockSize/2];
cannam@243 260 m_df = new float[m_dfsize];
cannam@243 261
cannam@243 262 for (size_t i = 0; i < m_blockSize/2; ++i) {
cannam@243 263 m_priorMagnitudes[i] = 0.f;
cannam@243 264 }
cannam@243 265 for (size_t i = 0; i < m_dfsize; ++i) {
cannam@243 266 m_df[i] = 0.f;
cannam@243 267 }
cannam@243 268
cannam@243 269 m_n = 0;
cannam@243 270
cannam@243 271 return true;
cannam@243 272 }
cannam@243 273
cannam@243 274 void
cannam@243 275 FixedTempoEstimator::D::reset()
cannam@243 276 {
cannam@243 277 if (!m_priorMagnitudes) return;
cannam@243 278
cannam@243 279 for (size_t i = 0; i < m_blockSize/2; ++i) {
cannam@243 280 m_priorMagnitudes[i] = 0.f;
cannam@243 281 }
cannam@243 282 for (size_t i = 0; i < m_dfsize; ++i) {
cannam@243 283 m_df[i] = 0.f;
cannam@243 284 }
cannam@243 285
cannam@243 286 delete[] m_r;
cannam@243 287 m_r = 0;
cannam@243 288
cannam@243 289 delete[] m_fr;
cannam@243 290 m_fr = 0;
cannam@243 291
cannam@243 292 delete[] m_t;
cannam@243 293 m_t = 0;
cannam@243 294
cannam@243 295 m_n = 0;
cannam@243 296
cannam@243 297 m_start = RealTime::zeroTime;
cannam@243 298 m_lasttime = RealTime::zeroTime;
cannam@243 299 }
cannam@243 300
cannam@198 301 FixedTempoEstimator::FeatureSet
cannam@243 302 FixedTempoEstimator::D::process(const float *const *inputBuffers, RealTime ts)
cannam@198 303 {
cannam@198 304 FeatureSet fs;
cannam@198 305
cannam@198 306 if (m_stepSize == 0) {
cannam@198 307 cerr << "ERROR: FixedTempoEstimator::process: "
cannam@198 308 << "FixedTempoEstimator has not been initialised"
cannam@198 309 << endl;
cannam@198 310 return fs;
cannam@198 311 }
cannam@198 312
cannam@198 313 if (m_n == 0) m_start = ts;
cannam@198 314 m_lasttime = ts;
cannam@198 315
cannam@198 316 if (m_n == m_dfsize) {
cannam@200 317 calculate();
cannam@200 318 fs = assembleFeatures();
cannam@198 319 ++m_n;
cannam@198 320 return fs;
cannam@198 321 }
cannam@198 322
cannam@198 323 if (m_n > m_dfsize) return FeatureSet();
cannam@198 324
cannam@207 325 float value = 0.f;
cannam@207 326
cannam@198 327 for (size_t i = 1; i < m_blockSize/2; ++i) {
cannam@198 328
cannam@198 329 float real = inputBuffers[0][i*2];
cannam@198 330 float imag = inputBuffers[0][i*2 + 1];
cannam@198 331
cannam@198 332 float sqrmag = real * real + imag * imag;
cannam@207 333 value += fabsf(sqrmag - m_priorMagnitudes[i]);
cannam@198 334
cannam@198 335 m_priorMagnitudes[i] = sqrmag;
cannam@198 336 }
cannam@198 337
cannam@207 338 m_df[m_n] = value;
cannam@207 339
cannam@198 340 ++m_n;
cannam@198 341 return fs;
cannam@243 342 }
cannam@198 343
cannam@198 344 FixedTempoEstimator::FeatureSet
cannam@243 345 FixedTempoEstimator::D::getRemainingFeatures()
cannam@198 346 {
cannam@198 347 FeatureSet fs;
cannam@198 348 if (m_n > m_dfsize) return fs;
cannam@200 349 calculate();
cannam@200 350 fs = assembleFeatures();
cannam@198 351 ++m_n;
cannam@198 352 return fs;
cannam@198 353 }
cannam@198 354
cannam@198 355 float
cannam@243 356 FixedTempoEstimator::D::lag2tempo(int lag)
cannam@199 357 {
cannam@198 358 return 60.f / ((lag * m_stepSize) / m_inputSampleRate);
cannam@198 359 }
cannam@198 360
cannam@207 361 int
cannam@243 362 FixedTempoEstimator::D::tempo2lag(float tempo)
cannam@207 363 {
cannam@207 364 return ((60.f / tempo) * m_inputSampleRate) / m_stepSize;
cannam@207 365 }
cannam@207 366
cannam@200 367 void
cannam@243 368 FixedTempoEstimator::D::calculate()
cannam@200 369 {
cannam@200 370 if (m_r) {
cannam@207 371 cerr << "FixedTempoEstimator::calculate: calculation already happened?" << endl;
cannam@200 372 return;
cannam@200 373 }
cannam@200 374
cannam@243 375 if (m_n < m_dfsize / 9 &&
cannam@243 376 m_n < (1.0 * m_inputSampleRate) / m_stepSize) { // 1 second
cannam@243 377 cerr << "FixedTempoEstimator::calculate: Input is too short" << endl;
cannam@243 378 return;
cannam@200 379 }
cannam@200 380
cannam@200 381 int n = m_n;
cannam@200 382
cannam@200 383 m_r = new float[n/2];
cannam@200 384 m_fr = new float[n/2];
cannam@204 385 m_t = new float[n/2];
cannam@200 386
cannam@200 387 for (int i = 0; i < n/2; ++i) {
cannam@200 388 m_r[i] = 0.f;
cannam@200 389 m_fr[i] = 0.f;
cannam@207 390 m_t[i] = lag2tempo(i);
cannam@200 391 }
cannam@200 392
cannam@200 393 for (int i = 0; i < n/2; ++i) {
cannam@200 394
cannam@200 395 for (int j = i; j < n-1; ++j) {
cannam@200 396 m_r[i] += m_df[j] * m_df[j - i];
cannam@200 397 }
cannam@200 398
cannam@200 399 m_r[i] /= n - i - 1;
cannam@200 400 }
cannam@200 401
cannam@246 402 float related[] = { 0.5, 2, 4, 8 };
cannam@208 403
cannam@209 404 for (int i = 1; i < n/2-1; ++i) {
cannam@204 405
cannam@209 406 float weight = 1.f - fabsf(128.f - lag2tempo(i)) * 0.005;
cannam@209 407 if (weight < 0.f) weight = 0.f;
cannam@215 408 weight = weight * weight * weight;
cannam@209 409
cannam@209 410 m_fr[i] = m_r[i];
cannam@204 411
cannam@200 412 int div = 1;
cannam@200 413
cannam@215 414 for (int j = 0; j < int(sizeof(related)/sizeof(related[0])); ++j) {
cannam@204 415
cannam@215 416 int k0 = int(i * related[j] + 0.5);
cannam@209 417
cannam@215 418 if (k0 >= 0 && k0 < int(n/2)) {
cannam@204 419
cannam@207 420 int kmax = 0, kmin = 0;
cannam@207 421 float kvmax = 0, kvmin = 0;
cannam@209 422 bool have = false;
cannam@204 423
cannam@209 424 for (int k = k0 - 1; k <= k0 + 1; ++k) {
cannam@204 425
cannam@209 426 if (k < 0 || k >= n/2) continue;
cannam@209 427
cannam@215 428 if (!have || (m_r[k] > kvmax)) { kmax = k; kvmax = m_r[k]; }
cannam@215 429 if (!have || (m_r[k] < kvmin)) { kmin = k; kvmin = m_r[k]; }
cannam@209 430
cannam@209 431 have = true;
cannam@204 432 }
cannam@209 433
cannam@215 434 m_fr[i] += m_r[kmax] / 5;
cannam@209 435
cannam@209 436 if ((kmax == 0 || m_r[kmax] > m_r[kmax-1]) &&
cannam@209 437 (kmax == n/2-1 || m_r[kmax] > m_r[kmax+1]) &&
cannam@207 438 kvmax > kvmin * 1.05) {
cannam@209 439
cannam@207 440 m_t[i] = m_t[i] + lag2tempo(kmax) * related[j];
cannam@207 441 ++div;
cannam@207 442 }
cannam@204 443 }
cannam@204 444 }
cannam@209 445
cannam@204 446 m_t[i] /= div;
cannam@204 447
cannam@215 448 m_fr[i] += m_fr[i] * (weight / 3);
cannam@207 449 }
cannam@200 450 }
cannam@200 451
cannam@198 452 FixedTempoEstimator::FeatureSet
cannam@243 453 FixedTempoEstimator::D::assembleFeatures()
cannam@198 454 {
cannam@198 455 FeatureSet fs;
cannam@200 456 if (!m_r) return fs; // No results
cannam@200 457
cannam@198 458 Feature feature;
cannam@198 459 feature.hasTimestamp = true;
cannam@198 460 feature.hasDuration = false;
cannam@198 461 feature.label = "";
cannam@198 462 feature.values.clear();
cannam@198 463 feature.values.push_back(0.f);
cannam@198 464
cannam@200 465 char buffer[40];
cannam@198 466
cannam@198 467 int n = m_n;
cannam@198 468
cannam@198 469 for (int i = 0; i < n; ++i) {
cannam@208 470 feature.timestamp = m_start +
cannam@208 471 RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate);
cannam@200 472 feature.values[0] = m_df[i];
cannam@198 473 feature.label = "";
cannam@200 474 fs[DFOutput].push_back(feature);
cannam@198 475 }
cannam@198 476
cannam@199 477 for (int i = 1; i < n/2; ++i) {
cannam@208 478 feature.timestamp = m_start +
cannam@208 479 RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate);
cannam@200 480 feature.values[0] = m_r[i];
cannam@199 481 sprintf(buffer, "%.1f bpm", lag2tempo(i));
cannam@200 482 if (i == n/2-1) feature.label = "";
cannam@200 483 else feature.label = buffer;
cannam@200 484 fs[ACFOutput].push_back(feature);
cannam@198 485 }
cannam@198 486
cannam@243 487 float t0 = m_minbpm; // our minimum detected tempo
cannam@243 488 float t1 = m_maxbpm; // our maximum detected tempo
cannam@216 489
cannam@207 490 int p0 = tempo2lag(t1);
cannam@207 491 int p1 = tempo2lag(t0);
cannam@198 492
cannam@200 493 std::map<float, int> candidates;
cannam@198 494
cannam@200 495 for (int i = p0; i <= p1 && i < n/2-1; ++i) {
cannam@198 496
cannam@209 497 if (m_fr[i] > m_fr[i-1] &&
cannam@209 498 m_fr[i] > m_fr[i+1]) {
cannam@209 499 candidates[m_fr[i]] = i;
cannam@209 500 }
cannam@198 501
cannam@208 502 feature.timestamp = m_start +
cannam@208 503 RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate);
cannam@200 504 feature.values[0] = m_fr[i];
cannam@199 505 sprintf(buffer, "%.1f bpm", lag2tempo(i));
cannam@200 506 if (i == p1 || i == n/2-2) feature.label = "";
cannam@200 507 else feature.label = buffer;
cannam@200 508 fs[FilteredACFOutput].push_back(feature);
cannam@198 509 }
cannam@198 510
cannam@200 511 if (candidates.empty()) {
cannam@207 512 cerr << "No tempo candidates!" << endl;
cannam@200 513 return fs;
cannam@200 514 }
cannam@198 515
cannam@198 516 feature.hasTimestamp = true;
cannam@198 517 feature.timestamp = m_start;
cannam@198 518
cannam@198 519 feature.hasDuration = true;
cannam@198 520 feature.duration = m_lasttime - m_start;
cannam@198 521
cannam@200 522 std::map<float, int>::const_iterator ci = candidates.end();
cannam@200 523 --ci;
cannam@200 524 int maxpi = ci->second;
cannam@198 525
cannam@204 526 if (m_t[maxpi] > 0) {
cannam@207 527 cerr << "*** Using adjusted tempo " << m_t[maxpi] << " instead of lag tempo " << lag2tempo(maxpi) << endl;
cannam@204 528 feature.values[0] = m_t[maxpi];
cannam@204 529 } else {
cannam@204 530 // shouldn't happen -- it would imply that this high value was not a peak!
cannam@204 531 feature.values[0] = lag2tempo(maxpi);
cannam@207 532 cerr << "WARNING: No stored tempo for index " << maxpi << endl;
cannam@204 533 }
cannam@204 534
cannam@204 535 sprintf(buffer, "%.1f bpm", feature.values[0]);
cannam@199 536 feature.label = buffer;
cannam@199 537
cannam@200 538 fs[TempoOutput].push_back(feature);
cannam@198 539
cannam@200 540 feature.values.clear();
cannam@200 541 feature.label = "";
cannam@200 542
cannam@200 543 while (feature.values.size() < 8) {
cannam@207 544 if (m_t[ci->second] > 0) {
cannam@207 545 feature.values.push_back(m_t[ci->second]);
cannam@207 546 } else {
cannam@207 547 feature.values.push_back(lag2tempo(ci->second));
cannam@207 548 }
cannam@200 549 if (ci == candidates.begin()) break;
cannam@200 550 --ci;
cannam@200 551 }
cannam@200 552
cannam@200 553 fs[CandidatesOutput].push_back(feature);
cannam@200 554
cannam@198 555 return fs;
cannam@198 556 }
cannam@243 557
cannam@243 558
cannam@243 559
cannam@243 560 FixedTempoEstimator::FixedTempoEstimator(float inputSampleRate) :
cannam@243 561 Plugin(inputSampleRate),
cannam@243 562 m_d(new D(inputSampleRate))
cannam@243 563 {
cannam@243 564 }
cannam@243 565
cannam@243 566 FixedTempoEstimator::~FixedTempoEstimator()
cannam@243 567 {
cannam@243 568 }
cannam@243 569
cannam@243 570 string
cannam@243 571 FixedTempoEstimator::getIdentifier() const
cannam@243 572 {
cannam@243 573 return "fixedtempo";
cannam@243 574 }
cannam@243 575
cannam@243 576 string
cannam@243 577 FixedTempoEstimator::getName() const
cannam@243 578 {
cannam@243 579 return "Simple Fixed Tempo Estimator";
cannam@243 580 }
cannam@243 581
cannam@243 582 string
cannam@243 583 FixedTempoEstimator::getDescription() const
cannam@243 584 {
cannam@243 585 return "Study a short section of audio and estimate its tempo, assuming the tempo is constant";
cannam@243 586 }
cannam@243 587
cannam@243 588 string
cannam@243 589 FixedTempoEstimator::getMaker() const
cannam@243 590 {
cannam@243 591 return "Vamp SDK Example Plugins";
cannam@243 592 }
cannam@243 593
cannam@243 594 int
cannam@243 595 FixedTempoEstimator::getPluginVersion() const
cannam@243 596 {
cannam@243 597 return 1;
cannam@243 598 }
cannam@243 599
cannam@243 600 string
cannam@243 601 FixedTempoEstimator::getCopyright() const
cannam@243 602 {
cannam@243 603 return "Code copyright 2008 Queen Mary, University of London. Freely redistributable (BSD license)";
cannam@243 604 }
cannam@243 605
cannam@243 606 size_t
cannam@243 607 FixedTempoEstimator::getPreferredStepSize() const
cannam@243 608 {
cannam@243 609 return m_d->getPreferredStepSize();
cannam@243 610 }
cannam@243 611
cannam@243 612 size_t
cannam@243 613 FixedTempoEstimator::getPreferredBlockSize() const
cannam@243 614 {
cannam@243 615 return m_d->getPreferredBlockSize();
cannam@243 616 }
cannam@243 617
cannam@243 618 bool
cannam@243 619 FixedTempoEstimator::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@243 620 {
cannam@243 621 if (channels < getMinChannelCount() ||
cannam@243 622 channels > getMaxChannelCount()) return false;
cannam@243 623
cannam@243 624 return m_d->initialise(channels, stepSize, blockSize);
cannam@243 625 }
cannam@243 626
cannam@243 627 void
cannam@243 628 FixedTempoEstimator::reset()
cannam@243 629 {
cannam@243 630 return m_d->reset();
cannam@243 631 }
cannam@243 632
cannam@243 633 FixedTempoEstimator::ParameterList
cannam@243 634 FixedTempoEstimator::getParameterDescriptors() const
cannam@243 635 {
cannam@243 636 return m_d->getParameterDescriptors();
cannam@243 637 }
cannam@243 638
cannam@243 639 float
cannam@243 640 FixedTempoEstimator::getParameter(std::string id) const
cannam@243 641 {
cannam@243 642 return m_d->getParameter(id);
cannam@243 643 }
cannam@243 644
cannam@243 645 void
cannam@243 646 FixedTempoEstimator::setParameter(std::string id, float value)
cannam@243 647 {
cannam@243 648 m_d->setParameter(id, value);
cannam@243 649 }
cannam@243 650
cannam@243 651 FixedTempoEstimator::OutputList
cannam@243 652 FixedTempoEstimator::getOutputDescriptors() const
cannam@243 653 {
cannam@243 654 return m_d->getOutputDescriptors();
cannam@243 655 }
cannam@243 656
cannam@243 657 FixedTempoEstimator::FeatureSet
cannam@243 658 FixedTempoEstimator::process(const float *const *inputBuffers, RealTime ts)
cannam@243 659 {
cannam@243 660 return m_d->process(inputBuffers, ts);
cannam@243 661 }
cannam@243 662
cannam@243 663 FixedTempoEstimator::FeatureSet
cannam@243 664 FixedTempoEstimator::getRemainingFeatures()
cannam@243 665 {
cannam@243 666 return m_d->getRemainingFeatures();
cannam@243 667 }