comparison TempogramPlugin.cpp @ 22:99380ba63be6

* Changed input of NoveltyCurve::spectrogramToNoveltyCurve() from transposed spe ctrogram to spectrogram * Collect spectrogram from process(), not transposed spectrogram * allowed OctaveDivider parameter to be any value in range, despite number of binumber of values in the range
author Carl Bussey <c.bussey@se10.qmul.ac.uk>
date Tue, 19 Aug 2014 16:52:19 +0100
parents 12b952286959
children 7d36c742a183
comparison
equal deleted inserted replaced
21:12b952286959 22:99380ba63be6
310 void 310 void
311 TempogramPlugin::selectProgram(string name) 311 TempogramPlugin::selectProgram(string name)
312 { 312 {
313 } 313 }
314 314
315 string TempogramPlugin::floatToString(float value) const
316 {
317 ostringstream ss;
318
319 if(!(ss << value)) throw runtime_error("TempogramPlugin::floatToString(): invalid conversion from float to string");
320 return ss.str();
321 }
322
323 TempogramPlugin::OutputList 315 TempogramPlugin::OutputList
324 TempogramPlugin::getOutputDescriptors() const 316 TempogramPlugin::getOutputDescriptors() const
325 { 317 {
326 OutputList list; 318 OutputList list;
327 319
381 list.push_back(d2); 373 list.push_back(d2);
382 374
383 return list; 375 return list;
384 } 376 }
385 377
386 bool TempogramPlugin::handleParameterValues(){
387
388 if (m_tempogramHopSize <= 0) return false;
389 if (m_tempogramLog2FftLength <= 0) return false;
390
391 if (m_tempogramFftLength < m_tempogramWindowLength){
392 m_tempogramFftLength = m_tempogramWindowLength;
393 }
394 if (m_tempogramMinBPM > m_tempogramMaxBPM){
395 m_tempogramMinBPM = 30;
396 m_tempogramMaxBPM = 480;
397 }
398
399 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize;
400 m_tempogramMinBin = (max(floor(((m_tempogramMinBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)0.0));
401 m_tempogramMaxBin = (min(ceil(((m_tempogramMaxBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)m_tempogramFftLength/2));
402
403 if (m_tempogramMinBPM > m_cyclicTempogramMinBPM) m_cyclicTempogramMinBPM = m_tempogramMinBPM;
404 float cyclicTempogramMaxBPM = 480;
405 if (m_tempogramMaxBPM < cyclicTempogramMaxBPM) cyclicTempogramMaxBPM = m_tempogramMaxBPM;
406
407 m_cyclicTempogramNumberOfOctaves = floor(log2(cyclicTempogramMaxBPM/m_cyclicTempogramMinBPM));
408 int numberOfBinsInFirstOctave = bpmToBin(m_cyclicTempogramMinBPM);
409 if (m_cyclicTempogramOctaveDivider > numberOfBinsInFirstOctave) m_cyclicTempogramOctaveDivider = numberOfBinsInFirstOctave;
410
411 return true;
412 }
413
414 bool 378 bool
415 TempogramPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) 379 TempogramPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
416 { 380 {
417 if (channels < getMinChannelCount() || 381 if (channels < getMinChannelCount() ||
418 channels > getMaxChannelCount()) return false; 382 channels > getMaxChannelCount()) return false;
419 383
420 // Real initialisation work goes here! 384 // Real initialisation work goes here!
421 m_inputBlockSize = blockSize; 385 m_inputBlockSize = blockSize;
422 m_inputStepSize = stepSize; 386 m_inputStepSize = stepSize;
423 387
424 m_spectrogram = SpectrogramTransposed(m_inputBlockSize/2.0f + 1);
425 if (!handleParameterValues()) return false; 388 if (!handleParameterValues()) return false;
426 //cout << m_cyclicTempogramOctaveDivider << endl; 389 //cout << m_cyclicTempogramOctaveDivider << endl;
427 390
428 return true; 391 return true;
429 } 392 }
431 void 394 void
432 TempogramPlugin::reset() 395 TempogramPlugin::reset()
433 { 396 {
434 // Clear buffers, reset stored values, etc 397 // Clear buffers, reset stored values, etc
435 m_spectrogram.clear(); 398 m_spectrogram.clear();
436 m_spectrogram = SpectrogramTransposed(m_inputBlockSize/2.0f + 1);
437 handleParameterValues(); 399 handleParameterValues();
438 } 400 }
439 401
440 TempogramPlugin::FeatureSet 402 TempogramPlugin::FeatureSet
441 TempogramPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp) 403 TempogramPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
448 Feature feature; 410 Feature feature;
449 411
450 const float *in = inputBuffers[0]; 412 const float *in = inputBuffers[0];
451 413
452 //calculate magnitude of FrequencyDomain input 414 //calculate magnitude of FrequencyDomain input
415 vector<float> fftCoefficients;
453 for (int i = 0; i < (int)n; i++){ 416 for (int i = 0; i < (int)n; i++){
454 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]); 417 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]);
455 magnitude = magnitude > m_noveltyCurveMinDB ? magnitude : m_noveltyCurveMinDB; 418 magnitude = magnitude > m_noveltyCurveMinDB ? magnitude : m_noveltyCurveMinDB;
456 m_spectrogram[i].push_back(magnitude); 419 fftCoefficients.push_back(magnitude);
457 } 420 }
421 m_spectrogram.push_back(fftCoefficients);
458 422
459 return featureSet; 423 return featureSet;
460 }
461
462 vector<unsigned int> TempogramPlugin::calculateTempogramNearestNeighbourLogBins() const
463 {
464 vector<unsigned int> logBins;
465
466 for (int i = 0; i < (int)ceil(m_cyclicTempogramNumberOfOctaves*m_cyclicTempogramOctaveDivider); i++){
467 float bpm = m_cyclicTempogramMinBPM*pow(2.0f, (float)i/m_cyclicTempogramOctaveDivider);
468 int bin = bpmToBin(bpm);
469
470 logBins.push_back(bin);
471 //cerr << bin << endl;
472 }
473
474 //cerr << logBins.size() << endl;
475
476 return logBins;
477 }
478
479 int TempogramPlugin::bpmToBin(const float &bpm) const
480 {
481 float w = (float)bpm/60;
482 float sampleRate = m_inputSampleRate/m_inputStepSize;
483 int bin = floor((float)m_tempogramFftLength*w/sampleRate + 0.5);
484
485 if(bin < 0) bin = 0;
486 else if(bin > m_tempogramFftLength/2.0f) bin = m_tempogramFftLength;
487
488 return bin;
489 }
490
491 float TempogramPlugin::binToBPM(const int &bin) const
492 {
493 float sampleRate = m_inputSampleRate/m_inputStepSize;
494
495 return (bin*sampleRate/m_tempogramFftLength)*60;
496 } 424 }
497 425
498 TempogramPlugin::FeatureSet 426 TempogramPlugin::FeatureSet
499 TempogramPlugin::getRemainingFeatures() 427 TempogramPlugin::getRemainingFeatures()
500 { 428 {
505 } 433 }
506 434
507 FeatureSet featureSet; 435 FeatureSet featureSet;
508 436
509 //initialise novelty curve processor 437 //initialise novelty curve processor
510 size_t numberOfBlocks = m_spectrogram[0].size(); 438 size_t numberOfBlocks = m_spectrogram.size();
511 //cerr << numberOfBlocks << endl; 439 //cerr << numberOfBlocks << endl;
512 NoveltyCurveProcessor nc(m_inputSampleRate, m_inputBlockSize, numberOfBlocks, m_noveltyCurveCompressionConstant); 440 NoveltyCurveProcessor nc(m_inputSampleRate, m_inputBlockSize, m_noveltyCurveCompressionConstant);
513 vector<float> noveltyCurve = nc.spectrogramToNoveltyCurve(m_spectrogram); //calculate novelty curvefrom magnitude data 441 vector<float> noveltyCurve = nc.spectrogramToNoveltyCurve(m_spectrogram); //calculate novelty curvefrom magnitude data
514 //if(noveltyCurve.size() > 50) for (int i = 0; i < 50; i++) cerr << noveltyCurve[i] << endl; 442 //if(noveltyCurve.size() > 50) for (int i = 0; i < 50; i++) cerr << noveltyCurve[i] << endl;
515 443
516 //push novelty curve data to featureset 1 and set timestamps 444 //push novelty curve data to featureset 1 and set timestamps
517 for (int i = 0; i < (int)numberOfBlocks; i++){ 445 for (int i = 0; i < (int)numberOfBlocks; i++){
546 tempogramFeature.hasTimestamp = false; 474 tempogramFeature.hasTimestamp = false;
547 featureSet[1].push_back(tempogramFeature); 475 featureSet[1].push_back(tempogramFeature);
548 } 476 }
549 477
550 //Calculate cyclic tempogram 478 //Calculate cyclic tempogram
551 vector<unsigned int> logBins = calculateTempogramNearestNeighbourLogBins(); 479 vector< vector<unsigned int> > logBins = calculateTempogramNearestNeighbourLogBins();
552 480
553 assert(logBins.back() <= m_tempogramFftLength/2.0f); 481 //assert((int)logBins.size() == m_cyclicTempogramOctaveDivider*m_cyclicTempogramNumberOfOctaves);
554 assert((int)logBins.size() == m_cyclicTempogramOctaveDivider*m_cyclicTempogramNumberOfOctaves);
555 for (int block = 0; block < tempogramLength; block++){ 482 for (int block = 0; block < tempogramLength; block++){
556 Feature cyclicTempogramFeature; 483 Feature cyclicTempogramFeature;
557 484
558 for (int i = 0; i < (int)m_cyclicTempogramOctaveDivider; i++){ 485 for (int i = 0; i < (int)m_cyclicTempogramOctaveDivider; i++){
559 float sum = 0; 486 float sum = 0;
560 487
561 //mcerr << floor(binToBPM(logBins[i]) + 0.5) << " " << floor(binToBPM(logBins[i + m_cyclicTempogramOctaveDivider]) + 0.5) << endl;
562
563 for (int j = 0; j < (int)m_cyclicTempogramNumberOfOctaves; j++){ 488 for (int j = 0; j < (int)m_cyclicTempogramNumberOfOctaves; j++){
564 sum += tempogram[block][logBins[i+j*m_cyclicTempogramOctaveDivider]]; 489 sum += tempogram[block][logBins[j][i]];
565 } 490 }
566 cyclicTempogramFeature.values.push_back(sum/m_cyclicTempogramNumberOfOctaves); 491 cyclicTempogramFeature.values.push_back(sum/m_cyclicTempogramNumberOfOctaves);
567 assert(!isnan(cyclicTempogramFeature.values.back())); 492 assert(!isnan(cyclicTempogramFeature.values.back()));
568 } 493 }
569 494
571 featureSet[0].push_back(cyclicTempogramFeature); 496 featureSet[0].push_back(cyclicTempogramFeature);
572 } 497 }
573 498
574 return featureSet; 499 return featureSet;
575 } 500 }
501
502 vector< vector<unsigned int> > TempogramPlugin::calculateTempogramNearestNeighbourLogBins() const
503 {
504 vector< vector<unsigned int> > logBins;
505
506 for (int octave = 0; octave < (int)m_cyclicTempogramNumberOfOctaves; octave++){
507 vector<unsigned int> octaveBins;
508
509 for (int bin = 0; bin < (int)m_cyclicTempogramOctaveDivider; bin++){
510 float bpm = m_cyclicTempogramMinBPM*pow(2.0f, octave+(float)bin/m_cyclicTempogramOctaveDivider);
511
512 octaveBins.push_back(bpmToBin(bpm));
513 }
514 logBins.push_back(octaveBins);
515 }
516
517 //cerr << logBins.size() << endl;
518
519 return logBins;
520 }
521
522 unsigned int TempogramPlugin::bpmToBin(const float &bpm) const
523 {
524 float w = (float)bpm/60;
525 float sampleRate = m_inputSampleRate/m_inputStepSize;
526 int bin = floor((float)m_tempogramFftLength*w/sampleRate + 0.5);
527
528 if(bin < 0) bin = 0;
529 else if(bin > m_tempogramFftLength/2.0f) bin = m_tempogramFftLength;
530
531 return bin;
532 }
533
534 float TempogramPlugin::binToBPM(const int &bin) const
535 {
536 float sampleRate = m_inputSampleRate/m_inputStepSize;
537
538 return (bin*sampleRate/m_tempogramFftLength)*60;
539 }
540
541 bool TempogramPlugin::handleParameterValues(){
542
543 if (m_tempogramHopSize <= 0) return false;
544 if (m_tempogramLog2FftLength <= 0) return false;
545
546 if (m_tempogramFftLength < m_tempogramWindowLength){
547 m_tempogramFftLength = m_tempogramWindowLength;
548 }
549 if (m_tempogramMinBPM >= m_tempogramMaxBPM){
550 m_tempogramMinBPM = 30;
551 m_tempogramMaxBPM = 480;
552 }
553
554 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize;
555 m_tempogramMinBin = (max(floor(((m_tempogramMinBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)0.0));
556 m_tempogramMaxBin = (min(ceil(((m_tempogramMaxBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)m_tempogramFftLength/2));
557
558 if (m_tempogramMinBPM > m_cyclicTempogramMinBPM) m_cyclicTempogramMinBPM = m_tempogramMinBPM;
559 float cyclicTempogramMaxBPM = 480;
560 if (m_tempogramMaxBPM < cyclicTempogramMaxBPM) cyclicTempogramMaxBPM = m_tempogramMaxBPM;
561
562 m_cyclicTempogramNumberOfOctaves = floor(log2(cyclicTempogramMaxBPM/m_cyclicTempogramMinBPM));
563
564 return true;
565 }
566
567 string TempogramPlugin::floatToString(float value) const
568 {
569 ostringstream ss;
570
571 if(!(ss << value)) throw runtime_error("TempogramPlugin::floatToString(): invalid conversion from float to string");
572 return ss.str();
573 }