comparison plugins/BeatTrack.cpp @ 146:c4837ed2eeb1

Merge mepd_new_params branch
author Chris Cannam <c.cannam@qmul.ac.uk>
date Mon, 02 Sep 2013 09:29:34 +0100
parents edad8a88a074
children d169df0c0cbc
comparison
equal deleted inserted replaced
143:592ac92002a8 146:c4837ed2eeb1
31 31
32 class BeatTrackerData 32 class BeatTrackerData
33 { 33 {
34 public: 34 public:
35 BeatTrackerData(const DFConfig &config) : dfConfig(config) { 35 BeatTrackerData(const DFConfig &config) : dfConfig(config) {
36 df = new DetectionFunction(config); 36 df = new DetectionFunction(config);
37 } 37 }
38 ~BeatTrackerData() { 38 ~BeatTrackerData() {
39 delete df; 39 delete df;
40 } 40 }
41 void reset() { 41 void reset() {
42 delete df; 42 delete df;
43 df = new DetectionFunction(dfConfig); 43 df = new DetectionFunction(dfConfig);
44 dfOutput.clear(); 44 dfOutput.clear();
45 origin = Vamp::RealTime::zeroTime; 45 origin = Vamp::RealTime::zeroTime;
46 } 46 }
47 47
48 DFConfig dfConfig; 48 DFConfig dfConfig;
49 DetectionFunction *df; 49 DetectionFunction *df;
50 vector<double> dfOutput; 50 vector<double> dfOutput;
51 Vamp::RealTime origin; 51 Vamp::RealTime origin;
52 }; 52 };
53 53
54 54
55 BeatTracker::BeatTracker(float inputSampleRate) : 55 BeatTracker::BeatTracker(float inputSampleRate) :
56 Vamp::Plugin(inputSampleRate), 56 Vamp::Plugin(inputSampleRate),
57 m_d(0), 57 m_d(0),
58 m_method(METHOD_NEW), 58 m_method(METHOD_NEW),
59 m_dfType(DF_COMPLEXSD), 59 m_dfType(DF_COMPLEXSD),
60 m_whiten(false) 60 m_whiten(false),
61 m_alpha(0.9), // MEPD new exposed parameter for beat tracker, default value = 0.9 (as old version)
62 m_tightness(4.), // MEPD new exposed parameter for beat tracker, default value = 4. (as old version)
63 m_inputtempo(120.), // MEPD new exposed parameter for beat tracker, default value = 120. (as old version)
64 m_constraintempo(false) // MEPD new exposed parameter for beat tracker, default value = false (as old version)
65 // calling the beat tracker with these default parameters will give the same output as the previous existing version
66
61 { 67 {
62 } 68 }
63 69
64 BeatTracker::~BeatTracker() 70 BeatTracker::~BeatTracker()
65 { 71 {
91 } 97 }
92 98
93 int 99 int
94 BeatTracker::getPluginVersion() const 100 BeatTracker::getPluginVersion() const
95 { 101 {
96 return 5; 102 return 6;
97 } 103 }
98 104
99 string 105 string
100 BeatTracker::getCopyright() const 106 BeatTracker::getCopyright() const
101 { 107 {
102 return "Plugin by Christian Landone and Matthew Davies. Copyright (c) 2006-2009 QMUL - All Rights Reserved"; 108 return "Plugin by Christian Landone and Matthew Davies. Copyright (c) 2006-2012 QMUL - All Rights Reserved";
103 } 109 }
104 110
105 BeatTracker::ParameterList 111 BeatTracker::ParameterList
106 BeatTracker::getParameterDescriptors() const 112 BeatTracker::getParameterDescriptors() const
107 { 113 {
145 desc.quantizeStep = 1; 151 desc.quantizeStep = 1;
146 desc.unit = ""; 152 desc.unit = "";
147 desc.valueNames.clear(); 153 desc.valueNames.clear();
148 list.push_back(desc); 154 list.push_back(desc);
149 155
156 // MEPD new exposed parameter - used in the dynamic programming part of the beat tracker
157 //Alpha Parameter of Beat Tracker
158 desc.identifier = "alpha";
159 desc.name = "Alpha";
160 desc.description = "Inertia - Flexibility Trade Off";
161 desc.minValue = 0.1;
162 desc.maxValue = 0.99;
163 desc.defaultValue = 0.90;
164 desc.unit = "";
165 desc.isQuantized = false;
166 list.push_back(desc);
167
168
169 // MEPD new exposed parameter - used in the dynamic programming part of the beat tracker
170 //Tightness Parameter of Beat Tracker
171 desc.identifier = "tightness";
172 desc.name = "Tightness";
173 desc.description = "Inertia - Flexibility Trade Off 2";
174 desc.minValue = 3;
175 desc.maxValue = 7;
176 desc.defaultValue = 4;
177 desc.unit = "";
178 desc.isQuantized = true;
179 list.push_back(desc);
180
181 // MEPD new exposed parameter - used in the periodicity estimation
182 //User input tempo
183 desc.identifier = "inputtempo";
184 desc.name = "InputTempo";
185 desc.description = "User defined Tempo";
186 desc.minValue = 50;
187 desc.maxValue = 250;
188 desc.defaultValue = 120;
189 desc.unit = "BPM";
190 desc.isQuantized = true;
191 list.push_back(desc);
192
193 // MEPD new exposed parameter - used in periodicity estimation
194 desc.identifier = "constraintempo";
195 desc.name = "Constrain Tempo";
196 desc.description = "Constrain tempo to use Gaussian weighting";
197 desc.minValue = 0;
198 desc.maxValue = 1;
199 desc.defaultValue = 0;
200 desc.isQuantized = true;
201 desc.quantizeStep = 1;
202 desc.unit = "";
203 desc.valueNames.clear();
204 list.push_back(desc);
205
206
207
150 return list; 208 return list;
151 } 209 }
152 210
153 float 211 float
154 BeatTracker::getParameter(std::string name) const 212 BeatTracker::getParameter(std::string name) const
162 case DF_BROADBAND: return 4; 220 case DF_BROADBAND: return 4;
163 } 221 }
164 } else if (name == "method") { 222 } else if (name == "method") {
165 return m_method; 223 return m_method;
166 } else if (name == "whiten") { 224 } else if (name == "whiten") {
167 return m_whiten ? 1.0 : 0.0; 225 return m_whiten ? 1.0 : 0.0;
226 } else if (name == "alpha") {
227 return m_alpha;
228 } else if (name == "tightness") {
229 return m_tightness;
230 } else if (name == "inputtempo") {
231 return m_inputtempo;
232 } else if (name == "constraintempo") {
233 return m_constraintempo ? 1.0 : 0.0;
168 } 234 }
169 return 0.0; 235 return 0.0;
170 } 236 }
171 237
172 void 238 void
182 } 248 }
183 } else if (name == "method") { 249 } else if (name == "method") {
184 m_method = lrintf(value); 250 m_method = lrintf(value);
185 } else if (name == "whiten") { 251 } else if (name == "whiten") {
186 m_whiten = (value > 0.5); 252 m_whiten = (value > 0.5);
253 } else if (name == "alpha") {
254 m_alpha = value;
255 } else if (name == "tightness") {
256 m_tightness = value;
257 } else if (name == "inputtempo") {
258 m_inputtempo = value;
259 } else if (name == "constraintempo") {
260 m_constraintempo = (value > 0.5);
187 } 261 }
188 } 262 }
189 263
190 bool 264 bool
191 BeatTracker::initialise(size_t channels, size_t stepSize, size_t blockSize) 265 BeatTracker::initialise(size_t channels, size_t stepSize, size_t blockSize)
192 { 266 {
193 if (m_d) { 267 if (m_d) {
194 delete m_d; 268 delete m_d;
195 m_d = 0; 269 m_d = 0;
196 } 270 }
197 271
198 if (channels < getMinChannelCount() || 272 if (channels < getMinChannelCount() ||
199 channels > getMaxChannelCount()) { 273 channels > getMaxChannelCount()) {
200 std::cerr << "BeatTracker::initialise: Unsupported channel count: " 274 std::cerr << "BeatTracker::initialise: Unsupported channel count: "
201 << channels << std::endl; 275 << channels << std::endl;
202 return false; 276 return false;
203 } 277 }
204 278
220 dfConfig.frameLength = blockSize; 294 dfConfig.frameLength = blockSize;
221 dfConfig.dbRise = 3; 295 dfConfig.dbRise = 3;
222 dfConfig.adaptiveWhitening = m_whiten; 296 dfConfig.adaptiveWhitening = m_whiten;
223 dfConfig.whiteningRelaxCoeff = -1; 297 dfConfig.whiteningRelaxCoeff = -1;
224 dfConfig.whiteningFloor = -1; 298 dfConfig.whiteningFloor = -1;
225 299
226 m_d = new BeatTrackerData(dfConfig); 300 m_d = new BeatTrackerData(dfConfig);
227 return true; 301 return true;
228 } 302 }
229 303
230 void 304 void
300 BeatTracker::FeatureSet 374 BeatTracker::FeatureSet
301 BeatTracker::process(const float *const *inputBuffers, 375 BeatTracker::process(const float *const *inputBuffers,
302 Vamp::RealTime timestamp) 376 Vamp::RealTime timestamp)
303 { 377 {
304 if (!m_d) { 378 if (!m_d) {
305 cerr << "ERROR: BeatTracker::process: " 379 cerr << "ERROR: BeatTracker::process: "
306 << "BeatTracker has not been initialised" 380 << "BeatTracker has not been initialised"
307 << endl; 381 << endl;
308 return FeatureSet(); 382 return FeatureSet();
309 } 383 }
310 384
311 size_t len = m_d->dfConfig.frameLength / 2; 385 size_t len = m_d->dfConfig.frameLength / 2;
312 386
313 double *magnitudes = new double[len]; 387 double *magnitudes = new double[len];
318 for (size_t i = 0; i < len; ++i) { 392 for (size_t i = 0; i < len; ++i) {
319 393
320 magnitudes[i] = sqrt(inputBuffers[0][i*2 ] * inputBuffers[0][i*2 ] + 394 magnitudes[i] = sqrt(inputBuffers[0][i*2 ] * inputBuffers[0][i*2 ] +
321 inputBuffers[0][i*2+1] * inputBuffers[0][i*2+1]); 395 inputBuffers[0][i*2+1] * inputBuffers[0][i*2+1]);
322 396
323 phases[i] = atan2(-inputBuffers[0][i*2+1], inputBuffers[0][i*2]); 397 phases[i] = atan2(-inputBuffers[0][i*2+1], inputBuffers[0][i*2]);
324 } 398 }
325 399
326 double output = m_d->df->process(magnitudes, phases); 400 double output = m_d->df->process(magnitudes, phases);
327 401
328 delete[] magnitudes; 402 delete[] magnitudes;
344 418
345 BeatTracker::FeatureSet 419 BeatTracker::FeatureSet
346 BeatTracker::getRemainingFeatures() 420 BeatTracker::getRemainingFeatures()
347 { 421 {
348 if (!m_d) { 422 if (!m_d) {
349 cerr << "ERROR: BeatTracker::getRemainingFeatures: " 423 cerr << "ERROR: BeatTracker::getRemainingFeatures: "
350 << "BeatTracker has not been initialised" 424 << "BeatTracker has not been initialised"
351 << endl; 425 << endl;
352 return FeatureSet(); 426 return FeatureSet();
353 } 427 }
354 428
355 if (m_method == METHOD_OLD) return beatTrackOld(); 429 if (m_method == METHOD_OLD) return beatTrackOld();
356 else return beatTrackNew(); 430 else return beatTrackNew();
357 } 431 }
381 455
382 char label[100]; 456 char label[100];
383 457
384 for (size_t i = 0; i < beats.size(); ++i) { 458 for (size_t i = 0; i < beats.size(); ++i) {
385 459
386 size_t frame = beats[i] * m_d->dfConfig.stepSize; 460 size_t frame = beats[i] * m_d->dfConfig.stepSize;
387 461
388 Feature feature; 462 Feature feature;
389 feature.hasTimestamp = true; 463 feature.hasTimestamp = true;
390 feature.timestamp = m_d->origin + Vamp::RealTime::frame2RealTime 464 feature.timestamp = m_d->origin + Vamp::RealTime::frame2RealTime
391 (frame, lrintf(m_inputSampleRate)); 465 (frame, lrintf(m_inputSampleRate));
392 466
393 float bpm = 0.0; 467 float bpm = 0.0;
394 int frameIncrement = 0; 468 int frameIncrement = 0;
395 469
396 if (i < beats.size() - 1) { 470 if (i < beats.size() - 1) {
397 471
398 frameIncrement = (beats[i+1] - beats[i]) * m_d->dfConfig.stepSize; 472 frameIncrement = (beats[i+1] - beats[i]) * m_d->dfConfig.stepSize;
399 473
400 // one beat is frameIncrement frames, so there are 474 // one beat is frameIncrement frames, so there are
401 // samplerate/frameIncrement bps, so 475 // samplerate/frameIncrement bps, so
402 // 60*samplerate/frameIncrement bpm 476 // 60*samplerate/frameIncrement bpm
403 477
404 if (frameIncrement > 0) { 478 if (frameIncrement > 0) {
405 bpm = (60.0 * m_inputSampleRate) / frameIncrement; 479 bpm = (60.0 * m_inputSampleRate) / frameIncrement;
406 bpm = int(bpm * 100.0 + 0.5) / 100.0; 480 bpm = int(bpm * 100.0 + 0.5) / 100.0;
407 sprintf(label, "%.2f bpm", bpm); 481 sprintf(label, "%.2f bpm", bpm);
408 feature.label = label; 482 feature.label = label;
409 } 483 }
410 } 484 }
411 485
412 returnFeatures[0].push_back(feature); // beats are output 0 486 returnFeatures[0].push_back(feature); // beats are output 0
413 } 487 }
414 488
415 double prevTempo = 0.0; 489 double prevTempo = 0.0;
416 490
417 for (size_t i = 0; i < tempi.size(); ++i) { 491 for (size_t i = 0; i < tempi.size(); ++i) {
418 492
419 size_t frame = i * m_d->dfConfig.stepSize * ttParams.lagLength; 493 size_t frame = i * m_d->dfConfig.stepSize * ttParams.lagLength;
420 494
421 // std::cerr << "unit " << i << ", step size " << m_d->dfConfig.stepSize << ", hop " << ttParams.lagLength << ", frame = " << frame << std::endl; 495 // std::cerr << "unit " << i << ", step size " << m_d->dfConfig.stepSize << ", hop " << ttParams.lagLength << ", frame = " << frame << std::endl;
422 496
423 if (tempi[i] > 1 && int(tempi[i] * 100) != int(prevTempo * 100)) { 497 if (tempi[i] > 1 && int(tempi[i] * 100) != int(prevTempo * 100)) {
424 Feature feature; 498 Feature feature;
425 feature.hasTimestamp = true; 499 feature.hasTimestamp = true;
426 feature.timestamp = m_d->origin + Vamp::RealTime::frame2RealTime 500 feature.timestamp = m_d->origin + Vamp::RealTime::frame2RealTime
427 (frame, lrintf(m_inputSampleRate)); 501 (frame, lrintf(m_inputSampleRate));
459 } 533 }
460 if (df.empty()) return FeatureSet(); 534 if (df.empty()) return FeatureSet();
461 535
462 TempoTrackV2 tt(m_inputSampleRate, m_d->dfConfig.stepSize); 536 TempoTrackV2 tt(m_inputSampleRate, m_d->dfConfig.stepSize);
463 537
464 tt.calculateBeatPeriod(df, beatPeriod, tempi); 538
539 // MEPD - note this function is now passed 2 new parameters, m_inputtempo and m_constraintempo
540 tt.calculateBeatPeriod(df, beatPeriod, tempi, m_inputtempo, m_constraintempo);
465 541
466 vector<double> beats; 542 vector<double> beats;
467 tt.calculateBeats(df, beatPeriod, beats); 543
468 544 // MEPD - note this function is now passed 2 new parameters, m_alpha and m_tightness
545 tt.calculateBeats(df, beatPeriod, beats, m_alpha, m_tightness);
546
469 FeatureSet returnFeatures; 547 FeatureSet returnFeatures;
470 548
471 char label[100]; 549 char label[100];
472 550
473 for (size_t i = 0; i < beats.size(); ++i) { 551 for (size_t i = 0; i < beats.size(); ++i) {
474 552
475 size_t frame = beats[i] * m_d->dfConfig.stepSize; 553 size_t frame = beats[i] * m_d->dfConfig.stepSize;
476 554
477 Feature feature; 555 Feature feature;
478 feature.hasTimestamp = true; 556 feature.hasTimestamp = true;
479 feature.timestamp = m_d->origin + Vamp::RealTime::frame2RealTime 557 feature.timestamp = m_d->origin + Vamp::RealTime::frame2RealTime
480 (frame, lrintf(m_inputSampleRate)); 558 (frame, lrintf(m_inputSampleRate));
481 559
482 float bpm = 0.0; 560 float bpm = 0.0;
483 int frameIncrement = 0; 561 int frameIncrement = 0;
484 562
485 if (i+1 < beats.size()) { 563 if (i+1 < beats.size()) {
486 564
487 frameIncrement = (beats[i+1] - beats[i]) * m_d->dfConfig.stepSize; 565 frameIncrement = (beats[i+1] - beats[i]) * m_d->dfConfig.stepSize;
488 566
489 // one beat is frameIncrement frames, so there are 567 // one beat is frameIncrement frames, so there are
490 // samplerate/frameIncrement bps, so 568 // samplerate/frameIncrement bps, so
491 // 60*samplerate/frameIncrement bpm 569 // 60*samplerate/frameIncrement bpm
492 570
493 if (frameIncrement > 0) { 571 if (frameIncrement > 0) {
494 bpm = (60.0 * m_inputSampleRate) / frameIncrement; 572 bpm = (60.0 * m_inputSampleRate) / frameIncrement;
495 bpm = int(bpm * 100.0 + 0.5) / 100.0; 573 bpm = int(bpm * 100.0 + 0.5) / 100.0;
496 sprintf(label, "%.2f bpm", bpm); 574 sprintf(label, "%.2f bpm", bpm);
497 feature.label = label; 575 feature.label = label;
498 } 576 }
499 } 577 }
500 578
501 returnFeatures[0].push_back(feature); // beats are output 0 579 returnFeatures[0].push_back(feature); // beats are output 0
502 } 580 }
503 581
504 double prevTempo = 0.0; 582 double prevTempo = 0.0;
505 583
506 for (size_t i = 0; i < tempi.size(); ++i) { 584 for (size_t i = 0; i < tempi.size(); ++i) {
507 585
508 size_t frame = i * m_d->dfConfig.stepSize; 586 size_t frame = i * m_d->dfConfig.stepSize;
509 587
510 if (tempi[i] > 1 && int(tempi[i] * 100) != int(prevTempo * 100)) { 588 if (tempi[i] > 1 && int(tempi[i] * 100) != int(prevTempo * 100)) {
511 Feature feature; 589 Feature feature;
512 feature.hasTimestamp = true; 590 feature.hasTimestamp = true;
513 feature.timestamp = m_d->origin + Vamp::RealTime::frame2RealTime 591 feature.timestamp = m_d->origin + Vamp::RealTime::frame2RealTime
514 (frame, lrintf(m_inputSampleRate)); 592 (frame, lrintf(m_inputSampleRate));
520 } 598 }
521 } 599 }
522 600
523 return returnFeatures; 601 return returnFeatures;
524 } 602 }
525