annotate examples/FixedTempoEstimator.cpp @ 243:3cf5bd155e5b

* Some build improvements * Make parameterisable values in tempo estimator into parameters
author cannam
date Mon, 10 Nov 2008 22:04:40 +0000
parents 6b30e064cab7
children 8042ab66f707
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@207 370 cerr << "FixedTempoEstimator::calculate: m_n = " << m_n << endl;
cannam@200 371
cannam@200 372 if (m_r) {
cannam@207 373 cerr << "FixedTempoEstimator::calculate: calculation already happened?" << endl;
cannam@200 374 return;
cannam@200 375 }
cannam@200 376
cannam@243 377 if (m_n < m_dfsize / 9 &&
cannam@243 378 m_n < (1.0 * m_inputSampleRate) / m_stepSize) { // 1 second
cannam@243 379 cerr << "FixedTempoEstimator::calculate: Input is too short" << endl;
cannam@243 380 return;
cannam@200 381 }
cannam@200 382
cannam@200 383 int n = m_n;
cannam@200 384
cannam@200 385 m_r = new float[n/2];
cannam@200 386 m_fr = new float[n/2];
cannam@204 387 m_t = new float[n/2];
cannam@200 388
cannam@200 389 for (int i = 0; i < n/2; ++i) {
cannam@200 390 m_r[i] = 0.f;
cannam@200 391 m_fr[i] = 0.f;
cannam@207 392 m_t[i] = lag2tempo(i);
cannam@200 393 }
cannam@200 394
cannam@200 395 for (int i = 0; i < n/2; ++i) {
cannam@200 396
cannam@200 397 for (int j = i; j < n-1; ++j) {
cannam@200 398 m_r[i] += m_df[j] * m_df[j - i];
cannam@200 399 }
cannam@200 400
cannam@200 401 m_r[i] /= n - i - 1;
cannam@200 402 }
cannam@200 403
cannam@215 404 float related[] = { 0.5, 2, 3, 4 };
cannam@208 405
cannam@209 406 for (int i = 1; i < n/2-1; ++i) {
cannam@204 407
cannam@209 408 float weight = 1.f - fabsf(128.f - lag2tempo(i)) * 0.005;
cannam@209 409 if (weight < 0.f) weight = 0.f;
cannam@215 410 weight = weight * weight * weight;
cannam@209 411
cannam@209 412 m_fr[i] = m_r[i];
cannam@204 413
cannam@200 414 int div = 1;
cannam@200 415
cannam@215 416 for (int j = 0; j < int(sizeof(related)/sizeof(related[0])); ++j) {
cannam@204 417
cannam@215 418 int k0 = int(i * related[j] + 0.5);
cannam@209 419
cannam@215 420 if (k0 >= 0 && k0 < int(n/2)) {
cannam@204 421
cannam@207 422 int kmax = 0, kmin = 0;
cannam@207 423 float kvmax = 0, kvmin = 0;
cannam@209 424 bool have = false;
cannam@204 425
cannam@209 426 for (int k = k0 - 1; k <= k0 + 1; ++k) {
cannam@204 427
cannam@209 428 if (k < 0 || k >= n/2) continue;
cannam@209 429
cannam@215 430 if (!have || (m_r[k] > kvmax)) { kmax = k; kvmax = m_r[k]; }
cannam@215 431 if (!have || (m_r[k] < kvmin)) { kmin = k; kvmin = m_r[k]; }
cannam@209 432
cannam@209 433 have = true;
cannam@204 434 }
cannam@209 435
cannam@215 436 m_fr[i] += m_r[kmax] / 5;
cannam@209 437
cannam@209 438 if ((kmax == 0 || m_r[kmax] > m_r[kmax-1]) &&
cannam@209 439 (kmax == n/2-1 || m_r[kmax] > m_r[kmax+1]) &&
cannam@207 440 kvmax > kvmin * 1.05) {
cannam@209 441
cannam@207 442 m_t[i] = m_t[i] + lag2tempo(kmax) * related[j];
cannam@207 443 ++div;
cannam@207 444 }
cannam@204 445 }
cannam@204 446 }
cannam@209 447
cannam@204 448 m_t[i] /= div;
cannam@204 449
cannam@215 450 // if (div > 1) {
cannam@215 451 // cerr << "adjusting tempo from " << lag2tempo(i) << " to "
cannam@215 452 // << m_t[i] << " for fr = " << m_fr[i] << " (div = " << div << ")" << endl;
cannam@215 453 // }
cannam@209 454
cannam@215 455 m_fr[i] += m_fr[i] * (weight / 3);
cannam@207 456 }
cannam@200 457 }
cannam@200 458
cannam@198 459 FixedTempoEstimator::FeatureSet
cannam@243 460 FixedTempoEstimator::D::assembleFeatures()
cannam@198 461 {
cannam@198 462 FeatureSet fs;
cannam@200 463 if (!m_r) return fs; // No results
cannam@200 464
cannam@198 465 Feature feature;
cannam@198 466 feature.hasTimestamp = true;
cannam@198 467 feature.hasDuration = false;
cannam@198 468 feature.label = "";
cannam@198 469 feature.values.clear();
cannam@198 470 feature.values.push_back(0.f);
cannam@198 471
cannam@200 472 char buffer[40];
cannam@198 473
cannam@198 474 int n = m_n;
cannam@198 475
cannam@198 476 for (int i = 0; i < n; ++i) {
cannam@208 477 feature.timestamp = m_start +
cannam@208 478 RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate);
cannam@200 479 feature.values[0] = m_df[i];
cannam@198 480 feature.label = "";
cannam@200 481 fs[DFOutput].push_back(feature);
cannam@198 482 }
cannam@198 483
cannam@199 484 for (int i = 1; i < n/2; ++i) {
cannam@208 485 feature.timestamp = m_start +
cannam@208 486 RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate);
cannam@200 487 feature.values[0] = m_r[i];
cannam@199 488 sprintf(buffer, "%.1f bpm", lag2tempo(i));
cannam@200 489 if (i == n/2-1) feature.label = "";
cannam@200 490 else feature.label = buffer;
cannam@200 491 fs[ACFOutput].push_back(feature);
cannam@198 492 }
cannam@198 493
cannam@243 494 float t0 = m_minbpm; // our minimum detected tempo
cannam@243 495 float t1 = m_maxbpm; // our maximum detected tempo
cannam@216 496
cannam@207 497 int p0 = tempo2lag(t1);
cannam@207 498 int p1 = tempo2lag(t0);
cannam@198 499
cannam@200 500 std::map<float, int> candidates;
cannam@198 501
cannam@243 502 std::cerr << "minbpm = " << m_minbpm << ", p0 = " << p0 << ", p1 = " << p1 << std::endl;
cannam@243 503
cannam@200 504 for (int i = p0; i <= p1 && i < n/2-1; ++i) {
cannam@198 505
cannam@209 506 if (m_fr[i] > m_fr[i-1] &&
cannam@209 507 m_fr[i] > m_fr[i+1]) {
cannam@209 508 candidates[m_fr[i]] = i;
cannam@209 509 }
cannam@198 510
cannam@208 511 feature.timestamp = m_start +
cannam@208 512 RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate);
cannam@200 513 feature.values[0] = m_fr[i];
cannam@199 514 sprintf(buffer, "%.1f bpm", lag2tempo(i));
cannam@200 515 if (i == p1 || i == n/2-2) feature.label = "";
cannam@200 516 else feature.label = buffer;
cannam@200 517 fs[FilteredACFOutput].push_back(feature);
cannam@198 518 }
cannam@198 519
cannam@207 520 // cerr << "maxpi = " << maxpi << " for tempo " << lag2tempo(maxpi) << " (value = " << maxp << ")" << endl;
cannam@198 521
cannam@200 522 if (candidates.empty()) {
cannam@207 523 cerr << "No tempo candidates!" << endl;
cannam@200 524 return fs;
cannam@200 525 }
cannam@198 526
cannam@198 527 feature.hasTimestamp = true;
cannam@198 528 feature.timestamp = m_start;
cannam@198 529
cannam@198 530 feature.hasDuration = true;
cannam@198 531 feature.duration = m_lasttime - m_start;
cannam@198 532
cannam@200 533 std::map<float, int>::const_iterator ci = candidates.end();
cannam@200 534 --ci;
cannam@200 535 int maxpi = ci->second;
cannam@198 536
cannam@204 537 if (m_t[maxpi] > 0) {
cannam@207 538 cerr << "*** Using adjusted tempo " << m_t[maxpi] << " instead of lag tempo " << lag2tempo(maxpi) << endl;
cannam@204 539 feature.values[0] = m_t[maxpi];
cannam@204 540 } else {
cannam@204 541 // shouldn't happen -- it would imply that this high value was not a peak!
cannam@204 542 feature.values[0] = lag2tempo(maxpi);
cannam@207 543 cerr << "WARNING: No stored tempo for index " << maxpi << endl;
cannam@204 544 }
cannam@204 545
cannam@204 546 sprintf(buffer, "%.1f bpm", feature.values[0]);
cannam@199 547 feature.label = buffer;
cannam@199 548
cannam@200 549 fs[TempoOutput].push_back(feature);
cannam@198 550
cannam@200 551 feature.values.clear();
cannam@200 552 feature.label = "";
cannam@200 553
cannam@200 554 while (feature.values.size() < 8) {
cannam@213 555 // cerr << "adding tempo value from lag " << ci->second << endl;
cannam@207 556 if (m_t[ci->second] > 0) {
cannam@207 557 feature.values.push_back(m_t[ci->second]);
cannam@207 558 } else {
cannam@207 559 feature.values.push_back(lag2tempo(ci->second));
cannam@207 560 }
cannam@200 561 if (ci == candidates.begin()) break;
cannam@200 562 --ci;
cannam@200 563 }
cannam@200 564
cannam@200 565 fs[CandidatesOutput].push_back(feature);
cannam@200 566
cannam@198 567 return fs;
cannam@198 568 }
cannam@243 569
cannam@243 570
cannam@243 571
cannam@243 572 FixedTempoEstimator::FixedTempoEstimator(float inputSampleRate) :
cannam@243 573 Plugin(inputSampleRate),
cannam@243 574 m_d(new D(inputSampleRate))
cannam@243 575 {
cannam@243 576 }
cannam@243 577
cannam@243 578 FixedTempoEstimator::~FixedTempoEstimator()
cannam@243 579 {
cannam@243 580 }
cannam@243 581
cannam@243 582 string
cannam@243 583 FixedTempoEstimator::getIdentifier() const
cannam@243 584 {
cannam@243 585 return "fixedtempo";
cannam@243 586 }
cannam@243 587
cannam@243 588 string
cannam@243 589 FixedTempoEstimator::getName() const
cannam@243 590 {
cannam@243 591 return "Simple Fixed Tempo Estimator";
cannam@243 592 }
cannam@243 593
cannam@243 594 string
cannam@243 595 FixedTempoEstimator::getDescription() const
cannam@243 596 {
cannam@243 597 return "Study a short section of audio and estimate its tempo, assuming the tempo is constant";
cannam@243 598 }
cannam@243 599
cannam@243 600 string
cannam@243 601 FixedTempoEstimator::getMaker() const
cannam@243 602 {
cannam@243 603 return "Vamp SDK Example Plugins";
cannam@243 604 }
cannam@243 605
cannam@243 606 int
cannam@243 607 FixedTempoEstimator::getPluginVersion() const
cannam@243 608 {
cannam@243 609 return 1;
cannam@243 610 }
cannam@243 611
cannam@243 612 string
cannam@243 613 FixedTempoEstimator::getCopyright() const
cannam@243 614 {
cannam@243 615 return "Code copyright 2008 Queen Mary, University of London. Freely redistributable (BSD license)";
cannam@243 616 }
cannam@243 617
cannam@243 618 size_t
cannam@243 619 FixedTempoEstimator::getPreferredStepSize() const
cannam@243 620 {
cannam@243 621 return m_d->getPreferredStepSize();
cannam@243 622 }
cannam@243 623
cannam@243 624 size_t
cannam@243 625 FixedTempoEstimator::getPreferredBlockSize() const
cannam@243 626 {
cannam@243 627 return m_d->getPreferredBlockSize();
cannam@243 628 }
cannam@243 629
cannam@243 630 bool
cannam@243 631 FixedTempoEstimator::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@243 632 {
cannam@243 633 if (channels < getMinChannelCount() ||
cannam@243 634 channels > getMaxChannelCount()) return false;
cannam@243 635
cannam@243 636 return m_d->initialise(channels, stepSize, blockSize);
cannam@243 637 }
cannam@243 638
cannam@243 639 void
cannam@243 640 FixedTempoEstimator::reset()
cannam@243 641 {
cannam@243 642 return m_d->reset();
cannam@243 643 }
cannam@243 644
cannam@243 645 FixedTempoEstimator::ParameterList
cannam@243 646 FixedTempoEstimator::getParameterDescriptors() const
cannam@243 647 {
cannam@243 648 return m_d->getParameterDescriptors();
cannam@243 649 }
cannam@243 650
cannam@243 651 float
cannam@243 652 FixedTempoEstimator::getParameter(std::string id) const
cannam@243 653 {
cannam@243 654 return m_d->getParameter(id);
cannam@243 655 }
cannam@243 656
cannam@243 657 void
cannam@243 658 FixedTempoEstimator::setParameter(std::string id, float value)
cannam@243 659 {
cannam@243 660 m_d->setParameter(id, value);
cannam@243 661 }
cannam@243 662
cannam@243 663 FixedTempoEstimator::OutputList
cannam@243 664 FixedTempoEstimator::getOutputDescriptors() const
cannam@243 665 {
cannam@243 666 return m_d->getOutputDescriptors();
cannam@243 667 }
cannam@243 668
cannam@243 669 FixedTempoEstimator::FeatureSet
cannam@243 670 FixedTempoEstimator::process(const float *const *inputBuffers, RealTime ts)
cannam@243 671 {
cannam@243 672 return m_d->process(inputBuffers, ts);
cannam@243 673 }
cannam@243 674
cannam@243 675 FixedTempoEstimator::FeatureSet
cannam@243 676 FixedTempoEstimator::getRemainingFeatures()
cannam@243 677 {
cannam@243 678 return m_d->getRemainingFeatures();
cannam@243 679 }