Mercurial > hg > vamp-tempogram
comparison TempogramPlugin.cpp @ 25:fe23998968b4
* Added tempogram via autocorrelation feature, using AutocorrelationProcessor
* Moved calculateMax() from NoveltyCurveProcessor to SpectrogramProcessor
author | Carl Bussey <c.bussey@se10.qmul.ac.uk> |
---|---|
date | Wed, 20 Aug 2014 16:00:37 +0100 |
parents | 957b83524c06 |
children | ff6110f1144b |
comparison
equal
deleted
inserted
replaced
24:957b83524c06 | 25:fe23998968b4 |
---|---|
3 // libraries. Replace MyPlugin and myPlugin throughout with the name | 3 // libraries. Replace MyPlugin and myPlugin throughout with the name |
4 // of your first plugin class, and fill in the gaps as appropriate. | 4 // of your first plugin class, and fill in the gaps as appropriate. |
5 | 5 |
6 | 6 |
7 #include "TempogramPlugin.h" | 7 #include "TempogramPlugin.h" |
8 #include <sstream> | 8 |
9 #include <stdexcept> | |
10 | 9 |
11 using Vamp::FFT; | 10 using Vamp::FFT; |
12 using Vamp::RealTime; | 11 using Vamp::RealTime; |
13 using namespace std; | 12 using namespace std; |
14 | 13 |
321 // Every plugin must have at least one output. | 320 // Every plugin must have at least one output. |
322 | 321 |
323 float d_sampleRate; | 322 float d_sampleRate; |
324 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize; | 323 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize; |
325 | 324 |
325 OutputDescriptor d1; | |
326 d1.identifier = "cyclicTempogram"; | |
327 d1.name = "Cyclic Tempogram"; | |
328 d1.description = "Cyclic Tempogram"; | |
329 d1.unit = ""; | |
330 d1.hasFixedBinCount = true; | |
331 d1.binCount = m_cyclicTempogramOctaveDivider > 0 && !isnan(m_cyclicTempogramOctaveDivider) ? m_cyclicTempogramOctaveDivider : 0; | |
332 d1.hasKnownExtents = false; | |
333 d1.isQuantized = false; | |
334 d1.sampleType = OutputDescriptor::FixedSampleRate; | |
335 d_sampleRate = tempogramInputSampleRate/m_tempogramHopSize; | |
336 d1.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0; | |
337 d1.hasDuration = false; | |
338 list.push_back(d1); | |
339 | |
340 OutputDescriptor d2; | |
341 d2.identifier = "tempogramDFT"; | |
342 d2.name = "Tempogram via DFT"; | |
343 d2.description = "Tempogram via DFT"; | |
344 d2.unit = "BPM"; | |
345 d2.hasFixedBinCount = true; | |
346 d2.binCount = m_tempogramMaxBin - m_tempogramMinBin + 1; | |
347 d2.hasKnownExtents = false; | |
348 d2.isQuantized = false; | |
349 d2.sampleType = OutputDescriptor::FixedSampleRate; | |
350 d_sampleRate = tempogramInputSampleRate/m_tempogramHopSize; | |
351 d2.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0; | |
352 for(int i = m_tempogramMinBin; i <= (int)m_tempogramMaxBin; i++){ | |
353 float w = ((float)i/m_tempogramFftLength)*(tempogramInputSampleRate); | |
354 d2.binNames.push_back(floatToString(w*60)); | |
355 } | |
356 d2.hasDuration = false; | |
357 list.push_back(d2); | |
358 | |
326 OutputDescriptor d3; | 359 OutputDescriptor d3; |
327 d3.identifier = "cyclicTempogram"; | 360 d3.identifier = "tempogramACT"; |
328 d3.name = "Cyclic Tempogram"; | 361 d3.name = "Tempogram via ACT"; |
329 d3.description = "Cyclic Tempogram"; | 362 d3.description = "Tempogram via ACT"; |
330 d3.unit = ""; | 363 d3.unit = "BPM"; |
331 d3.hasFixedBinCount = true; | 364 d3.hasFixedBinCount = true; |
332 d3.binCount = m_cyclicTempogramOctaveDivider > 0 && !isnan(m_cyclicTempogramOctaveDivider) ? m_cyclicTempogramOctaveDivider : 0; | 365 d3.binCount = m_tempogramMaxBin - m_tempogramMinBin + 1; |
333 d3.hasKnownExtents = false; | 366 d3.hasKnownExtents = false; |
334 d3.isQuantized = false; | 367 d3.isQuantized = false; |
335 d3.sampleType = OutputDescriptor::FixedSampleRate; | 368 d3.sampleType = OutputDescriptor::FixedSampleRate; |
336 d_sampleRate = tempogramInputSampleRate/m_tempogramHopSize; | 369 d_sampleRate = tempogramInputSampleRate/m_tempogramHopSize; |
337 d3.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0; | 370 d3.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0; |
371 for(int i = m_tempogramMinBin; i <= (int)m_tempogramMaxBin; i++){ | |
372 float w = ((float)i/m_tempogramFftLength)*(tempogramInputSampleRate); | |
373 d3.binNames.push_back(floatToString(w*60)); | |
374 } | |
338 d3.hasDuration = false; | 375 d3.hasDuration = false; |
339 list.push_back(d3); | 376 list.push_back(d3); |
340 | 377 |
341 OutputDescriptor d1; | 378 OutputDescriptor d4; |
342 d1.identifier = "tempogram"; | 379 d4.identifier = "nc"; |
343 d1.name = "Tempogram"; | 380 d4.name = "Novelty Curve"; |
344 d1.description = "Tempogram"; | 381 d4.description = "Novelty Curve"; |
345 d1.unit = "BPM"; | 382 d4.unit = ""; |
346 d1.hasFixedBinCount = true; | 383 d4.hasFixedBinCount = true; |
347 d1.binCount = m_tempogramMaxBin - m_tempogramMinBin + 1; | 384 d4.binCount = 1; |
348 d1.hasKnownExtents = false; | 385 d4.hasKnownExtents = false; |
349 d1.isQuantized = false; | 386 d4.isQuantized = false; |
350 d1.sampleType = OutputDescriptor::FixedSampleRate; | 387 d4.sampleType = OutputDescriptor::FixedSampleRate; |
351 d_sampleRate = tempogramInputSampleRate/m_tempogramHopSize; | |
352 d1.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0; | |
353 for(int i = m_tempogramMinBin; i <= (int)m_tempogramMaxBin; i++){ | |
354 float w = ((float)i/m_tempogramFftLength)*(tempogramInputSampleRate); | |
355 d1.binNames.push_back(floatToString(w*60)); | |
356 } | |
357 d1.hasDuration = false; | |
358 list.push_back(d1); | |
359 | |
360 OutputDescriptor d2; | |
361 d2.identifier = "nc"; | |
362 d2.name = "Novelty Curve"; | |
363 d2.description = "Novelty Curve"; | |
364 d2.unit = ""; | |
365 d2.hasFixedBinCount = true; | |
366 d2.binCount = 1; | |
367 d2.hasKnownExtents = false; | |
368 d2.isQuantized = false; | |
369 d2.sampleType = OutputDescriptor::FixedSampleRate; | |
370 d_sampleRate = tempogramInputSampleRate; | 388 d_sampleRate = tempogramInputSampleRate; |
371 d2.sampleRate = d_sampleRate > 0 && !isnan(d_sampleRate) ? d_sampleRate : 0; | 389 d4.sampleRate = d_sampleRate > 0 && !isnan(d_sampleRate) ? d_sampleRate : 0; |
372 d2.hasDuration = false; | 390 d4.hasDuration = false; |
373 list.push_back(d2); | 391 list.push_back(d4); |
374 | 392 |
375 return list; | 393 return list; |
376 } | 394 } |
377 | 395 |
378 bool | 396 bool |
440 //push novelty curve data to featureset 1 and set timestamps | 458 //push novelty curve data to featureset 1 and set timestamps |
441 for (int i = 0; i < numberOfBlocks; i++){ | 459 for (int i = 0; i < numberOfBlocks; i++){ |
442 Feature noveltyCurveFeature; | 460 Feature noveltyCurveFeature; |
443 noveltyCurveFeature.values.push_back(noveltyCurve[i]); | 461 noveltyCurveFeature.values.push_back(noveltyCurve[i]); |
444 noveltyCurveFeature.hasTimestamp = false; | 462 noveltyCurveFeature.hasTimestamp = false; |
445 featureSet[2].push_back(noveltyCurveFeature); | 463 featureSet[3].push_back(noveltyCurveFeature); |
446 assert(!isnan(noveltyCurveFeature.values.back())); | 464 assert(!isnan(noveltyCurveFeature.values.back())); |
447 } | 465 } |
448 | 466 |
449 //window function for spectrogram | 467 //window function for spectrogram |
450 WindowFunction::hanning(hannWindow, m_tempogramWindowLength); | 468 WindowFunction::hanning(hannWindow, m_tempogramWindowLength); |
451 | 469 |
452 //initialise spectrogram processor | 470 //initialise spectrogram processor |
453 SpectrogramProcessor spectrogramProcessor(m_tempogramWindowLength, m_tempogramFftLength, m_tempogramHopSize); | 471 SpectrogramProcessor spectrogramProcessor(m_tempogramWindowLength, m_tempogramFftLength, m_tempogramHopSize); |
454 //compute spectrogram from novelty curve data (i.e., tempogram) | 472 //compute spectrogram from novelty curve data (i.e., tempogram) |
455 Tempogram tempogram = spectrogramProcessor.process(&noveltyCurve[0], numberOfBlocks, hannWindow); | 473 Tempogram tempogramDFT = spectrogramProcessor.process(&noveltyCurve[0], numberOfBlocks, hannWindow); |
456 delete []hannWindow; | 474 delete []hannWindow; |
457 hannWindow = 0; | 475 hannWindow = 0; |
458 | 476 |
459 int tempogramLength = tempogram.size(); | 477 int tempogramLag = 1; |
478 AutocorrelationProcessor autocorrelationProcessor(m_tempogramWindowLength, m_tempogramHopSize, tempogramLag); | |
479 Tempogram tempogramACT = autocorrelationProcessor.process(&noveltyCurve[0], numberOfBlocks); | |
480 | |
481 int tempogramLength = tempogramDFT.size(); | |
460 | 482 |
461 //push tempogram data to featureset 0 and set timestamps. | 483 //push tempogram data to featureset 0 and set timestamps. |
462 for (int block = 0; block < tempogramLength; block++){ | 484 for (int block = 0; block < tempogramLength; block++){ |
463 Feature tempogramFeature; | 485 Feature tempogramDFTFeature; |
486 Feature tempogramACTFeature; | |
464 | 487 |
465 assert(tempogram[block].size() == (m_tempogramFftLength/2 + 1)); | 488 assert(tempogramDFT[block].size() == (m_tempogramFftLength/2 + 1)); |
466 for(int k = m_tempogramMinBin; k < (int)m_tempogramMaxBin; k++){ | 489 for(int k = m_tempogramMinBin; k < (int)m_tempogramMaxBin; k++){ |
467 tempogramFeature.values.push_back(tempogram[block][k]); | 490 tempogramDFTFeature.values.push_back(tempogramDFT[block][k]); |
468 assert(!isnan(tempogramFeature.values.back())); | 491 tempogramACTFeature.values.push_back(tempogramACT[block][k]); |
469 } | 492 } |
470 tempogramFeature.hasTimestamp = false; | 493 tempogramDFTFeature.hasTimestamp = false; |
471 featureSet[1].push_back(tempogramFeature); | 494 tempogramACTFeature.hasTimestamp = false; |
495 featureSet[1].push_back(tempogramDFTFeature); | |
496 featureSet[2].push_back(tempogramACTFeature); | |
472 } | 497 } |
473 | 498 |
474 //Calculate cyclic tempogram | 499 //Calculate cyclic tempogram |
475 vector< vector<unsigned int> > logBins = calculateTempogramNearestNeighbourLogBins(); | 500 vector< vector<unsigned int> > logBins = calculateTempogramNearestNeighbourLogBins(); |
476 | 501 |
480 | 505 |
481 for (int i = 0; i < m_cyclicTempogramOctaveDivider; i++){ | 506 for (int i = 0; i < m_cyclicTempogramOctaveDivider; i++){ |
482 float sum = 0; | 507 float sum = 0; |
483 | 508 |
484 for (int j = 0; j < m_cyclicTempogramNumberOfOctaves; j++){ | 509 for (int j = 0; j < m_cyclicTempogramNumberOfOctaves; j++){ |
485 sum += tempogram[block][logBins[j][i]]; | 510 sum += tempogramDFT[block][logBins[j][i]]; |
486 } | 511 } |
487 cyclicTempogramFeature.values.push_back(sum/m_cyclicTempogramNumberOfOctaves); | 512 cyclicTempogramFeature.values.push_back(sum/m_cyclicTempogramNumberOfOctaves); |
488 assert(!isnan(cyclicTempogramFeature.values.back())); | 513 assert(!isnan(cyclicTempogramFeature.values.back())); |
489 } | 514 } |
490 | 515 |
549 | 574 |
550 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize; | 575 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize; |
551 m_tempogramMinBin = (max(floor(((m_tempogramMinBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)0.0)); | 576 m_tempogramMinBin = (max(floor(((m_tempogramMinBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)0.0)); |
552 m_tempogramMaxBin = (min(ceil(((m_tempogramMaxBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)m_tempogramFftLength/2)); | 577 m_tempogramMaxBin = (min(ceil(((m_tempogramMaxBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)m_tempogramFftLength/2)); |
553 | 578 |
554 if (m_tempogramMinBPM > m_cyclicTempogramMinBPM) m_cyclicTempogramMinBPM = m_tempogramMinBPM; | 579 if (m_tempogramMinBPM > m_cyclicTempogramMinBPM) m_cyclicTempogramMinBPM = m_tempogramMinBPM; //m_cyclicTempogram can't be less than default = 30 |
555 float cyclicTempogramMaxBPM = 480; | 580 float cyclicTempogramMaxBPM = 480; |
556 if (m_tempogramMaxBPM < cyclicTempogramMaxBPM) cyclicTempogramMaxBPM = m_tempogramMaxBPM; | 581 if (m_tempogramMaxBPM < cyclicTempogramMaxBPM) cyclicTempogramMaxBPM = m_tempogramMaxBPM; |
557 | 582 |
558 m_cyclicTempogramNumberOfOctaves = floor(log2(cyclicTempogramMaxBPM/m_cyclicTempogramMinBPM)); | 583 m_cyclicTempogramNumberOfOctaves = floor(log2(cyclicTempogramMaxBPM/m_cyclicTempogramMinBPM)); |
559 | 584 |