Mercurial > hg > qm-vamp-plugins
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 |