Mercurial > hg > vamp-tempogram
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 } |