Mercurial > hg > qm-vamp-plugins
comparison plugins/BarBeatTrack.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 | 88c05c0ac438 |
comparison
equal
deleted
inserted
replaced
143:592ac92002a8 | 146:c4837ed2eeb1 |
---|---|
33 | 33 |
34 class BarBeatTrackerData | 34 class BarBeatTrackerData |
35 { | 35 { |
36 public: | 36 public: |
37 BarBeatTrackerData(float rate, const DFConfig &config) : dfConfig(config) { | 37 BarBeatTrackerData(float rate, const DFConfig &config) : dfConfig(config) { |
38 df = new DetectionFunction(config); | 38 df = new DetectionFunction(config); |
39 // decimation factor aims at resampling to c. 3KHz; must be power of 2 | 39 // decimation factor aims at resampling to c. 3KHz; must be power of 2 |
40 int factor = MathUtilities::nextPowerOfTwo(rate / 3000); | 40 int factor = MathUtilities::nextPowerOfTwo(rate / 3000); |
41 // std::cerr << "BarBeatTrackerData: factor = " << factor << std::endl; | 41 // std::cerr << "BarBeatTrackerData: factor = " << factor << std::endl; |
42 downBeat = new DownBeat(rate, factor, config.stepSize); | 42 downBeat = new DownBeat(rate, factor, config.stepSize); |
43 } | 43 } |
44 ~BarBeatTrackerData() { | 44 ~BarBeatTrackerData() { |
45 delete df; | 45 delete df; |
46 delete downBeat; | 46 delete downBeat; |
47 } | 47 } |
48 void reset() { | 48 void reset() { |
49 delete df; | 49 delete df; |
50 df = new DetectionFunction(dfConfig); | 50 df = new DetectionFunction(dfConfig); |
51 dfOutput.clear(); | 51 dfOutput.clear(); |
52 downBeat->resetAudioBuffer(); | 52 downBeat->resetAudioBuffer(); |
53 origin = Vamp::RealTime::zeroTime; | 53 origin = Vamp::RealTime::zeroTime; |
54 } | 54 } |
55 | 55 |
56 DFConfig dfConfig; | 56 DFConfig dfConfig; |
57 DetectionFunction *df; | 57 DetectionFunction *df; |
58 DownBeat *downBeat; | 58 DownBeat *downBeat; |
59 vector<double> dfOutput; | 59 vector<double> dfOutput; |
60 Vamp::RealTime origin; | 60 Vamp::RealTime origin; |
61 }; | 61 }; |
62 | 62 |
63 | 63 |
64 BarBeatTracker::BarBeatTracker(float inputSampleRate) : | 64 BarBeatTracker::BarBeatTracker(float inputSampleRate) : |
65 Vamp::Plugin(inputSampleRate), | 65 Vamp::Plugin(inputSampleRate), |
66 m_d(0), | 66 m_d(0), |
67 m_bpb(4) | 67 m_bpb(4), |
68 m_alpha(0.9), // changes are as per the BeatTrack.cpp | |
69 m_tightness(4.), // changes are as per the BeatTrack.cpp | |
70 m_inputtempo(120.), // changes are as per the BeatTrack.cpp | |
71 m_constraintempo(false) // changes are as per the BeatTrack.cpp | |
68 { | 72 { |
69 } | 73 } |
70 | 74 |
71 BarBeatTracker::~BarBeatTracker() | 75 BarBeatTracker::~BarBeatTracker() |
72 { | 76 { |
98 } | 102 } |
99 | 103 |
100 int | 104 int |
101 BarBeatTracker::getPluginVersion() const | 105 BarBeatTracker::getPluginVersion() const |
102 { | 106 { |
103 return 2; | 107 return 3; |
104 } | 108 } |
105 | 109 |
106 string | 110 string |
107 BarBeatTracker::getCopyright() const | 111 BarBeatTracker::getCopyright() const |
108 { | 112 { |
124 desc.defaultValue = 4; | 128 desc.defaultValue = 4; |
125 desc.isQuantized = true; | 129 desc.isQuantized = true; |
126 desc.quantizeStep = 1; | 130 desc.quantizeStep = 1; |
127 list.push_back(desc); | 131 list.push_back(desc); |
128 | 132 |
133 // changes are as per the BeatTrack.cpp | |
134 //Alpha Parameter of Beat Tracker | |
135 desc.identifier = "alpha"; | |
136 desc.name = "Alpha"; | |
137 desc.description = "Inertia - Flexibility Trade Off"; | |
138 desc.minValue = 0.1; | |
139 desc.maxValue = 0.99; | |
140 desc.defaultValue = 0.90; | |
141 desc.unit = ""; | |
142 desc.isQuantized = false; | |
143 list.push_back(desc); | |
144 | |
145 | |
146 // changes are as per the BeatTrack.cpp | |
147 //Tightness Parameter of Beat Tracker | |
148 desc.identifier = "tightness"; | |
149 desc.name = "Tightness"; | |
150 desc.description = "Inertia - Flexibility Trade Off 2"; | |
151 desc.minValue = 3; | |
152 desc.maxValue = 7; | |
153 desc.defaultValue = 4; | |
154 desc.unit = ""; | |
155 desc.isQuantized = true; | |
156 list.push_back(desc); | |
157 | |
158 // changes are as per the BeatTrack.cpp | |
159 //User input tempo | |
160 desc.identifier = "inputtempo"; | |
161 desc.name = "InputTempo"; | |
162 desc.description = "User defined Tempo"; | |
163 desc.minValue = 50; | |
164 desc.maxValue = 250; | |
165 desc.defaultValue = 120; | |
166 desc.unit = "BPM"; | |
167 desc.isQuantized = true; | |
168 list.push_back(desc); | |
169 | |
170 // changes are as per the BeatTrack.cpp | |
171 desc.identifier = "constraintempo"; | |
172 desc.name = "Constrain Tempo"; | |
173 desc.description = "Constrain tempo to use Gaussian weighting"; | |
174 desc.minValue = 0; | |
175 desc.maxValue = 1; | |
176 desc.defaultValue = 0; | |
177 desc.isQuantized = true; | |
178 desc.quantizeStep = 1; | |
179 desc.unit = ""; | |
180 desc.valueNames.clear(); | |
181 list.push_back(desc); | |
182 | |
183 | |
129 return list; | 184 return list; |
130 } | 185 } |
131 | 186 |
132 float | 187 float |
133 BarBeatTracker::getParameter(std::string name) const | 188 BarBeatTracker::getParameter(std::string name) const |
134 { | 189 { |
135 if (name == "bpb") return m_bpb; | 190 if (name == "bpb") { |
191 return m_bpb; | |
192 } else if (name == "alpha") { | |
193 return m_alpha; | |
194 } else if (name == "tightness") { | |
195 return m_tightness; | |
196 } else if (name == "inputtempo") { | |
197 return m_inputtempo; | |
198 } else if (name == "constraintempo") { | |
199 return m_constraintempo ? 1.0 : 0.0; | |
200 } | |
136 return 0.0; | 201 return 0.0; |
137 } | 202 } |
138 | 203 |
139 void | 204 void |
140 BarBeatTracker::setParameter(std::string name, float value) | 205 BarBeatTracker::setParameter(std::string name, float value) |
141 { | 206 { |
142 if (name == "bpb") m_bpb = lrintf(value); | 207 if (name == "bpb") { |
208 m_bpb = lrintf(value); | |
209 } else if (name == "alpha") { | |
210 m_alpha = value; | |
211 } else if (name == "tightness") { | |
212 m_tightness = value; | |
213 } else if (name == "inputtempo") { | |
214 m_inputtempo = value; | |
215 } else if (name == "constraintempo") { | |
216 m_constraintempo = (value > 0.5); | |
217 } | |
143 } | 218 } |
144 | 219 |
145 bool | 220 bool |
146 BarBeatTracker::initialise(size_t channels, size_t stepSize, size_t blockSize) | 221 BarBeatTracker::initialise(size_t channels, size_t stepSize, size_t blockSize) |
147 { | 222 { |
148 if (m_d) { | 223 if (m_d) { |
149 delete m_d; | 224 delete m_d; |
150 m_d = 0; | 225 m_d = 0; |
151 } | 226 } |
152 | 227 |
153 if (channels < getMinChannelCount() || | 228 if (channels < getMinChannelCount() || |
154 channels > getMaxChannelCount()) { | 229 channels > getMaxChannelCount()) { |
155 std::cerr << "BarBeatTracker::initialise: Unsupported channel count: " | 230 std::cerr << "BarBeatTracker::initialise: Unsupported channel count: " |
156 << channels << std::endl; | 231 << channels << std::endl; |
157 return false; | 232 return false; |
158 } | 233 } |
159 | 234 |
175 dfConfig.frameLength = blockSize; | 250 dfConfig.frameLength = blockSize; |
176 dfConfig.dbRise = 3; | 251 dfConfig.dbRise = 3; |
177 dfConfig.adaptiveWhitening = false; | 252 dfConfig.adaptiveWhitening = false; |
178 dfConfig.whiteningRelaxCoeff = -1; | 253 dfConfig.whiteningRelaxCoeff = -1; |
179 dfConfig.whiteningFloor = -1; | 254 dfConfig.whiteningFloor = -1; |
180 | 255 |
181 m_d = new BarBeatTrackerData(m_inputSampleRate, dfConfig); | 256 m_d = new BarBeatTrackerData(m_inputSampleRate, dfConfig); |
182 m_d->downBeat->setBeatsPerBar(m_bpb); | 257 m_d->downBeat->setBeatsPerBar(m_bpb); |
183 return true; | 258 return true; |
184 } | 259 } |
185 | 260 |
265 BarBeatTracker::FeatureSet | 340 BarBeatTracker::FeatureSet |
266 BarBeatTracker::process(const float *const *inputBuffers, | 341 BarBeatTracker::process(const float *const *inputBuffers, |
267 Vamp::RealTime timestamp) | 342 Vamp::RealTime timestamp) |
268 { | 343 { |
269 if (!m_d) { | 344 if (!m_d) { |
270 cerr << "ERROR: BarBeatTracker::process: " | 345 cerr << "ERROR: BarBeatTracker::process: " |
271 << "BarBeatTracker has not been initialised" | 346 << "BarBeatTracker has not been initialised" |
272 << endl; | 347 << endl; |
273 return FeatureSet(); | 348 return FeatureSet(); |
274 } | 349 } |
275 | 350 |
276 // We use time domain input, because DownBeat requires it -- so we | 351 // We use time domain input, because DownBeat requires it -- so we |
277 // use the time-domain version of DetectionFunction::process which | 352 // use the time-domain version of DetectionFunction::process which |
278 // does its own FFT. It requires doubles as input, so we need to | 353 // does its own FFT. It requires doubles as input, so we need to |
309 | 384 |
310 BarBeatTracker::FeatureSet | 385 BarBeatTracker::FeatureSet |
311 BarBeatTracker::getRemainingFeatures() | 386 BarBeatTracker::getRemainingFeatures() |
312 { | 387 { |
313 if (!m_d) { | 388 if (!m_d) { |
314 cerr << "ERROR: BarBeatTracker::getRemainingFeatures: " | 389 cerr << "ERROR: BarBeatTracker::getRemainingFeatures: " |
315 << "BarBeatTracker has not been initialised" | 390 << "BarBeatTracker has not been initialised" |
316 << endl; | 391 << endl; |
317 return FeatureSet(); | 392 return FeatureSet(); |
318 } | 393 } |
319 | 394 |
320 return barBeatTrack(); | 395 return barBeatTrack(); |
321 } | 396 } |
322 | 397 |
332 beatPeriod.push_back(0.0); | 407 beatPeriod.push_back(0.0); |
333 } | 408 } |
334 if (df.empty()) return FeatureSet(); | 409 if (df.empty()) return FeatureSet(); |
335 | 410 |
336 TempoTrackV2 tt(m_inputSampleRate, m_d->dfConfig.stepSize); | 411 TempoTrackV2 tt(m_inputSampleRate, m_d->dfConfig.stepSize); |
337 tt.calculateBeatPeriod(df, beatPeriod, tempi); | 412 |
413 // changes are as per the BeatTrack.cpp - allow m_inputtempo and m_constraintempo to be set be the user | |
414 tt.calculateBeatPeriod(df, beatPeriod, tempi, m_inputtempo, m_constraintempo); | |
338 | 415 |
339 vector<double> beats; | 416 vector<double> beats; |
340 tt.calculateBeats(df, beatPeriod, beats); | 417 // changes are as per the BeatTrack.cpp - allow m_alpha and m_tightness to be set be the user |
418 tt.calculateBeats(df, beatPeriod, beats, m_alpha, m_tightness); | |
419 | |
420 // tt.calculateBeatPeriod(df, beatPeriod, tempi, 0., 0); // use default parameters | |
421 | |
422 // vector<double> beats; | |
423 // tt.calculateBeats(df, beatPeriod, beats, 0.9, 4.); // use default parameters until i fix this plugin too | |
341 | 424 |
342 vector<int> downbeats; | 425 vector<int> downbeats; |
343 size_t downLength = 0; | 426 size_t downLength = 0; |
344 const float *downsampled = m_d->downBeat->getBufferedAudio(downLength); | 427 const float *downsampled = m_d->downBeat->getBufferedAudio(downLength); |
345 m_d->downBeat->findDownBeats(downsampled, downLength, beats, downbeats); | 428 m_d->downBeat->findDownBeats(downsampled, downLength, beats, downbeats); |
347 vector<double> beatsd; | 430 vector<double> beatsd; |
348 m_d->downBeat->getBeatSD(beatsd); | 431 m_d->downBeat->getBeatSD(beatsd); |
349 | 432 |
350 // std::cerr << "BarBeatTracker: found downbeats at: "; | 433 // std::cerr << "BarBeatTracker: found downbeats at: "; |
351 // for (int i = 0; i < downbeats.size(); ++i) std::cerr << downbeats[i] << " " << std::endl; | 434 // for (int i = 0; i < downbeats.size(); ++i) std::cerr << downbeats[i] << " " << std::endl; |
352 | 435 |
353 FeatureSet returnFeatures; | 436 FeatureSet returnFeatures; |
354 | 437 |
355 char label[20]; | 438 char label[20]; |
356 | 439 |
357 int dbi = 0; | 440 int dbi = 0; |
366 if (beat == m_bpb) beat = 0; | 449 if (beat == m_bpb) beat = 0; |
367 } | 450 } |
368 | 451 |
369 for (size_t i = 0; i < beats.size(); ++i) { | 452 for (size_t i = 0; i < beats.size(); ++i) { |
370 | 453 |
371 size_t frame = beats[i] * m_d->dfConfig.stepSize; | 454 size_t frame = beats[i] * m_d->dfConfig.stepSize; |
372 | 455 |
373 if (dbi < downbeats.size() && i == downbeats[dbi]) { | 456 if (dbi < downbeats.size() && i == downbeats[dbi]) { |
374 beat = 0; | 457 beat = 0; |
375 ++bar; | 458 ++bar; |
376 ++dbi; | 459 ++dbi; |
381 // outputs are: | 464 // outputs are: |
382 // | 465 // |
383 // 0 -> beats | 466 // 0 -> beats |
384 // 1 -> bars | 467 // 1 -> bars |
385 // 2 -> beat counter function | 468 // 2 -> beat counter function |
386 | 469 |
387 Feature feature; | 470 Feature feature; |
388 feature.hasTimestamp = true; | 471 feature.hasTimestamp = true; |
389 feature.timestamp = m_d->origin + Vamp::RealTime::frame2RealTime | 472 feature.timestamp = m_d->origin + Vamp::RealTime::frame2RealTime |
390 (frame, lrintf(m_inputSampleRate)); | 473 (frame, lrintf(m_inputSampleRate)); |
391 | 474 |
392 sprintf(label, "%d", beat + 1); | 475 sprintf(label, "%d", beat + 1); |
393 feature.label = label; | 476 feature.label = label; |
394 returnFeatures[0].push_back(feature); // labelled beats | 477 returnFeatures[0].push_back(feature); // labelled beats |
395 | 478 |
396 feature.values.push_back(beat + 1); | 479 feature.values.push_back(beat + 1); |
397 returnFeatures[2].push_back(feature); // beat function | 480 returnFeatures[2].push_back(feature); // beat function |
398 | 481 |
399 if (i > 0 && i <= beatsd.size()) { | 482 if (i > 0 && i <= beatsd.size()) { |