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