comparison plugins/BeatTrack.cpp @ 86:e377296d01b2

* First cut at including Matthew's newer beat tracker
author Chris Cannam <c.cannam@qmul.ac.uk>
date Tue, 20 Jan 2009 15:01:31 +0000
parents 2631d0b3d7eb
children 790e051896a9
comparison
equal deleted inserted replaced
85:2631d0b3d7eb 86:e377296d01b2
10 #include "BeatTrack.h" 10 #include "BeatTrack.h"
11 11
12 #include <dsp/onsets/DetectionFunction.h> 12 #include <dsp/onsets/DetectionFunction.h>
13 #include <dsp/onsets/PeakPicking.h> 13 #include <dsp/onsets/PeakPicking.h>
14 #include <dsp/tempotracking/TempoTrack.h> 14 #include <dsp/tempotracking/TempoTrack.h>
15 #include <dsp/tempotracking/TempoTrackV2.h>
15 16
16 using std::string; 17 using std::string;
17 using std::vector; 18 using std::vector;
18 using std::cerr; 19 using std::cerr;
19 using std::endl; 20 using std::endl;
20 21
21 float BeatTracker::m_stepSecs = 0.01161; 22 float BeatTracker::m_stepSecs = 0.01161; // 512 samples at 44100
23
24 #define METHOD_OLD 0
25 #define METHOD_NEW 1
22 26
23 class BeatTrackerData 27 class BeatTrackerData
24 { 28 {
25 public: 29 public:
26 BeatTrackerData(const DFConfig &config) : dfConfig(config) { 30 BeatTrackerData(const DFConfig &config) : dfConfig(config) {
44 48
45 49
46 BeatTracker::BeatTracker(float inputSampleRate) : 50 BeatTracker::BeatTracker(float inputSampleRate) :
47 Vamp::Plugin(inputSampleRate), 51 Vamp::Plugin(inputSampleRate),
48 m_d(0), 52 m_d(0),
53 m_method(METHOD_NEW),
49 m_dfType(DF_COMPLEXSD), 54 m_dfType(DF_COMPLEXSD),
50 m_whiten(false) 55 m_whiten(false)
51 { 56 {
52 } 57 }
53 58
96 BeatTracker::getParameterDescriptors() const 101 BeatTracker::getParameterDescriptors() const
97 { 102 {
98 ParameterList list; 103 ParameterList list;
99 104
100 ParameterDescriptor desc; 105 ParameterDescriptor desc;
106
107 desc.identifier = "method";
108 desc.name = "Beat Tracking Method";
109 desc.description = ""; //!!!
110 desc.minValue = 0;
111 desc.maxValue = 1;
112 desc.defaultValue = METHOD_NEW;
113 desc.isQuantized = true;
114 desc.quantizeStep = 1;
115 desc.valueNames.push_back("Old");
116 desc.valueNames.push_back("New");
117 list.push_back(desc);
118
101 desc.identifier = "dftype"; 119 desc.identifier = "dftype";
102 desc.name = "Onset Detection Function Type"; 120 desc.name = "Onset Detection Function Type";
103 desc.description = "Method used to calculate the onset detection function"; 121 desc.description = "Method used to calculate the onset detection function";
104 desc.minValue = 0; 122 desc.minValue = 0;
105 desc.maxValue = 4; 123 desc.maxValue = 4;
106 desc.defaultValue = 3; 124 desc.defaultValue = 3;
107 desc.isQuantized = true; 125 desc.valueNames.clear();
108 desc.quantizeStep = 1;
109 desc.valueNames.push_back("High-Frequency Content"); 126 desc.valueNames.push_back("High-Frequency Content");
110 desc.valueNames.push_back("Spectral Difference"); 127 desc.valueNames.push_back("Spectral Difference");
111 desc.valueNames.push_back("Phase Deviation"); 128 desc.valueNames.push_back("Phase Deviation");
112 desc.valueNames.push_back("Complex Domain"); 129 desc.valueNames.push_back("Complex Domain");
113 desc.valueNames.push_back("Broadband Energy Rise"); 130 desc.valueNames.push_back("Broadband Energy Rise");
137 case DF_SPECDIFF: return 1; 154 case DF_SPECDIFF: return 1;
138 case DF_PHASEDEV: return 2; 155 case DF_PHASEDEV: return 2;
139 default: case DF_COMPLEXSD: return 3; 156 default: case DF_COMPLEXSD: return 3;
140 case DF_BROADBAND: return 4; 157 case DF_BROADBAND: return 4;
141 } 158 }
159 } else if (name == "method") {
160 return m_method;
142 } else if (name == "whiten") { 161 } else if (name == "whiten") {
143 return m_whiten ? 1.0 : 0.0; 162 return m_whiten ? 1.0 : 0.0;
144 } 163 }
145 return 0.0; 164 return 0.0;
146 } 165 }
154 case 1: m_dfType = DF_SPECDIFF; break; 173 case 1: m_dfType = DF_SPECDIFF; break;
155 case 2: m_dfType = DF_PHASEDEV; break; 174 case 2: m_dfType = DF_PHASEDEV; break;
156 default: case 3: m_dfType = DF_COMPLEXSD; break; 175 default: case 3: m_dfType = DF_COMPLEXSD; break;
157 case 4: m_dfType = DF_BROADBAND; break; 176 case 4: m_dfType = DF_BROADBAND; break;
158 } 177 }
178 } else if (name == "method") {
179 m_method = lrintf(value);
159 } else if (name == "whiten") { 180 } else if (name == "whiten") {
160 m_whiten = (value > 0.5); 181 m_whiten = (value > 0.5);
161 } 182 }
162 } 183 }
163 184
325 << "BeatTracker has not been initialised" 346 << "BeatTracker has not been initialised"
326 << endl; 347 << endl;
327 return FeatureSet(); 348 return FeatureSet();
328 } 349 }
329 350
351 if (m_method == METHOD_OLD) return beatTrackOld();
352 else return beatTrackNew();
353 }
354
355 BeatTracker::FeatureSet
356 BeatTracker::beatTrackOld()
357 {
330 double aCoeffs[] = { 1.0000, -0.5949, 0.2348 }; 358 double aCoeffs[] = { 1.0000, -0.5949, 0.2348 };
331 double bCoeffs[] = { 0.1600, 0.3200, 0.1600 }; 359 double bCoeffs[] = { 0.1600, 0.3200, 0.1600 };
332 360
333 TTParams ttParams; 361 TTParams ttParams;
334 ttParams.winLength = 512; 362 ttParams.winLength = 512;
401 } 429 }
402 430
403 return returnFeatures; 431 return returnFeatures;
404 } 432 }
405 433
434 BeatTracker::FeatureSet
435 BeatTracker::beatTrackNew()
436 {
437 vector<double> df;
438 vector<double> beatPeriod;
439
440 for (size_t i = 2; i < m_d->dfOutput.size(); ++i) { // discard first two elts
441 df.push_back(m_d->dfOutput[i]);
442 beatPeriod.push_back(0.0);
443 }
444 if (df.empty()) return FeatureSet();
445
446 TempoTrackV2 tt;
447
448 tt.calculateBeatPeriod(df, beatPeriod);
449
450 vector<double> beats;
451 tt.calculateBeats(df, beatPeriod, beats);
452
453 FeatureSet returnFeatures;
454
455 char label[100];
456
457 for (size_t i = 0; i < beats.size(); ++i) {
458
459 // beats are returned in reverse order?
460
461 size_t index = beats.size() - i - 1;
462
463 size_t frame = beats[index] * m_d->dfConfig.stepSize;
464
465 Feature feature;
466 feature.hasTimestamp = true;
467 feature.timestamp = m_d->origin + Vamp::RealTime::frame2RealTime
468 (frame, lrintf(m_inputSampleRate));
469
470 float bpm = 0.0;
471 int frameIncrement = 0;
472
473 if (index > 0) {
474
475 frameIncrement = (beats[index - 1] - beats[index]) * m_d->dfConfig.stepSize;
476
477 // one beat is frameIncrement frames, so there are
478 // samplerate/frameIncrement bps, so
479 // 60*samplerate/frameIncrement bpm
480
481 if (frameIncrement > 0) {
482 bpm = (60.0 * m_inputSampleRate) / frameIncrement;
483 bpm = int(bpm * 100.0 + 0.5) / 100.0;
484 sprintf(label, "%.2f bpm", bpm);
485 feature.label = label;
486 }
487 }
488
489 returnFeatures[0].push_back(feature); // beats are output 0
490 }
491
492 return returnFeatures;
493 }
494