Mercurial > hg > vamp-tempogram
comparison TempogramPlugin.cpp @ 21:12b952286959
* Debugging 1Hz freeze using vamp-plugin-tester
author | Carl Bussey <c.bussey@se10.qmul.ac.uk> |
---|---|
date | Mon, 18 Aug 2014 15:22:44 +0100 |
parents | de7213b35755 |
children | 99380ba63be6 |
comparison
equal
deleted
inserted
replaced
20:de7213b35755 | 21:12b952286959 |
---|---|
326 OutputList list; | 326 OutputList list; |
327 | 327 |
328 // See OutputDescriptor documentation for the possibilities here. | 328 // See OutputDescriptor documentation for the possibilities here. |
329 // Every plugin must have at least one output. | 329 // Every plugin must have at least one output. |
330 | 330 |
331 OutputDescriptor d1; | |
332 float d_sampleRate; | 331 float d_sampleRate; |
333 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize; | 332 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize; |
334 | 333 |
334 OutputDescriptor d3; | |
335 d3.identifier = "cyclicTempogram"; | |
336 d3.name = "Cyclic Tempogram"; | |
337 d3.description = "Cyclic Tempogram"; | |
338 d3.unit = ""; | |
339 d3.hasFixedBinCount = true; | |
340 d3.binCount = m_cyclicTempogramOctaveDivider > 0 && !isnan(m_cyclicTempogramOctaveDivider) ? m_cyclicTempogramOctaveDivider : 0; | |
341 d3.hasKnownExtents = false; | |
342 d3.isQuantized = false; | |
343 d3.sampleType = OutputDescriptor::FixedSampleRate; | |
344 d_sampleRate = tempogramInputSampleRate/m_tempogramHopSize; | |
345 d3.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0; | |
346 d3.hasDuration = false; | |
347 list.push_back(d3); | |
348 | |
349 OutputDescriptor d1; | |
335 d1.identifier = "tempogram"; | 350 d1.identifier = "tempogram"; |
336 d1.name = "Tempogram"; | 351 d1.name = "Tempogram"; |
337 d1.description = "Tempogram"; | 352 d1.description = "Tempogram"; |
338 d1.unit = "BPM"; | 353 d1.unit = "BPM"; |
339 d1.hasFixedBinCount = true; | 354 d1.hasFixedBinCount = true; |
363 d_sampleRate = tempogramInputSampleRate; | 378 d_sampleRate = tempogramInputSampleRate; |
364 d2.sampleRate = d_sampleRate > 0 && !isnan(d_sampleRate) ? d_sampleRate : 0; | 379 d2.sampleRate = d_sampleRate > 0 && !isnan(d_sampleRate) ? d_sampleRate : 0; |
365 d2.hasDuration = false; | 380 d2.hasDuration = false; |
366 list.push_back(d2); | 381 list.push_back(d2); |
367 | 382 |
368 OutputDescriptor d3; | |
369 d3.identifier = "cyclicTempogram"; | |
370 d3.name = "Cyclic Tempogram"; | |
371 d3.description = "Cyclic Tempogram"; | |
372 d3.unit = ""; | |
373 d3.hasFixedBinCount = true; | |
374 d3.binCount = m_cyclicTempogramOctaveDivider > 0 && !isnan(m_cyclicTempogramOctaveDivider) ? m_cyclicTempogramOctaveDivider : 0; | |
375 d3.hasKnownExtents = false; | |
376 d3.isQuantized = false; | |
377 d3.sampleType = OutputDescriptor::FixedSampleRate; | |
378 d_sampleRate = tempogramInputSampleRate/m_tempogramHopSize; | |
379 d3.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0; | |
380 d3.hasDuration = false; | |
381 list.push_back(d3); | |
382 | |
383 return list; | 383 return list; |
384 } | 384 } |
385 | 385 |
386 void TempogramPlugin::checkParameterValues(){ | 386 bool TempogramPlugin::handleParameterValues(){ |
387 | |
388 if (m_tempogramHopSize <= 0) return false; | |
389 if (m_tempogramLog2FftLength <= 0) return false; | |
387 | 390 |
388 if (m_tempogramFftLength < m_tempogramWindowLength){ | 391 if (m_tempogramFftLength < m_tempogramWindowLength){ |
389 m_tempogramFftLength = m_tempogramWindowLength; | 392 m_tempogramFftLength = m_tempogramWindowLength; |
390 } | 393 } |
391 if (m_tempogramMinBPM > m_tempogramMaxBPM){ | 394 if (m_tempogramMinBPM > m_tempogramMaxBPM){ |
392 m_tempogramMinBPM = 30; | 395 m_tempogramMinBPM = 30; |
393 m_tempogramMaxBPM = 480; | 396 m_tempogramMaxBPM = 480; |
394 } | 397 } |
395 | 398 |
396 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize; | 399 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize; |
397 m_tempogramMinBin = (unsigned int)(max(floor(((m_tempogramMinBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)0.0)); | 400 m_tempogramMinBin = (max(floor(((m_tempogramMinBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)0.0)); |
398 m_tempogramMaxBin = (unsigned int)(min(ceil(((m_tempogramMaxBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)m_tempogramFftLength/2)); | 401 m_tempogramMaxBin = (min(ceil(((m_tempogramMaxBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)m_tempogramFftLength/2)); |
399 | 402 |
400 if (m_tempogramMinBPM > m_cyclicTempogramMinBPM) m_cyclicTempogramMinBPM = m_tempogramMinBPM; | 403 if (m_tempogramMinBPM > m_cyclicTempogramMinBPM) m_cyclicTempogramMinBPM = m_tempogramMinBPM; |
401 float cyclicTempogramMaxBPM = 480; | 404 float cyclicTempogramMaxBPM = 480; |
402 if (m_tempogramMaxBPM < cyclicTempogramMaxBPM) cyclicTempogramMaxBPM = m_tempogramMaxBPM; | 405 if (m_tempogramMaxBPM < cyclicTempogramMaxBPM) cyclicTempogramMaxBPM = m_tempogramMaxBPM; |
403 | 406 |
404 m_cyclicTempogramNumberOfOctaves = floor(log2(cyclicTempogramMaxBPM/m_cyclicTempogramMinBPM)); | 407 m_cyclicTempogramNumberOfOctaves = floor(log2(cyclicTempogramMaxBPM/m_cyclicTempogramMinBPM)); |
405 int numberOfBinsInFirstOctave = bpmToBin(m_cyclicTempogramMinBPM); | 408 int numberOfBinsInFirstOctave = bpmToBin(m_cyclicTempogramMinBPM); |
406 if (m_cyclicTempogramOctaveDivider > numberOfBinsInFirstOctave) m_cyclicTempogramOctaveDivider = numberOfBinsInFirstOctave; | 409 if (m_cyclicTempogramOctaveDivider > numberOfBinsInFirstOctave) m_cyclicTempogramOctaveDivider = numberOfBinsInFirstOctave; |
407 | 410 |
411 return true; | |
408 } | 412 } |
409 | 413 |
410 bool | 414 bool |
411 TempogramPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) | 415 TempogramPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) |
412 { | 416 { |
416 // Real initialisation work goes here! | 420 // Real initialisation work goes here! |
417 m_inputBlockSize = blockSize; | 421 m_inputBlockSize = blockSize; |
418 m_inputStepSize = stepSize; | 422 m_inputStepSize = stepSize; |
419 | 423 |
420 m_spectrogram = SpectrogramTransposed(m_inputBlockSize/2.0f + 1); | 424 m_spectrogram = SpectrogramTransposed(m_inputBlockSize/2.0f + 1); |
421 checkParameterValues(); | 425 if (!handleParameterValues()) return false; |
422 //cout << m_cyclicTempogramOctaveDivider << endl; | 426 //cout << m_cyclicTempogramOctaveDivider << endl; |
423 | 427 |
424 return true; | 428 return true; |
425 } | 429 } |
426 | 430 |
428 TempogramPlugin::reset() | 432 TempogramPlugin::reset() |
429 { | 433 { |
430 // Clear buffers, reset stored values, etc | 434 // Clear buffers, reset stored values, etc |
431 m_spectrogram.clear(); | 435 m_spectrogram.clear(); |
432 m_spectrogram = SpectrogramTransposed(m_inputBlockSize/2.0f + 1); | 436 m_spectrogram = SpectrogramTransposed(m_inputBlockSize/2.0f + 1); |
433 checkParameterValues(); | 437 handleParameterValues(); |
434 } | 438 } |
435 | 439 |
436 TempogramPlugin::FeatureSet | 440 TempogramPlugin::FeatureSet |
437 TempogramPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp) | 441 TempogramPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp) |
438 { | 442 { |
443 //cerr << "Here" << endl; | |
444 | |
439 size_t n = m_inputBlockSize/2 + 1; | 445 size_t n = m_inputBlockSize/2 + 1; |
440 | 446 |
441 FeatureSet featureSet; | 447 FeatureSet featureSet; |
442 Feature feature; | 448 Feature feature; |
443 | 449 |
447 for (int i = 0; i < (int)n; i++){ | 453 for (int i = 0; i < (int)n; i++){ |
448 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]); | 454 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]); |
449 magnitude = magnitude > m_noveltyCurveMinDB ? magnitude : m_noveltyCurveMinDB; | 455 magnitude = magnitude > m_noveltyCurveMinDB ? magnitude : m_noveltyCurveMinDB; |
450 m_spectrogram[i].push_back(magnitude); | 456 m_spectrogram[i].push_back(magnitude); |
451 } | 457 } |
452 | 458 |
453 return featureSet; | 459 return featureSet; |
454 } | 460 } |
455 | 461 |
456 vector<unsigned int> TempogramPlugin::calculateTempogramNearestNeighbourLogBins() const | 462 vector<unsigned int> TempogramPlugin::calculateTempogramNearestNeighbourLogBins() const |
457 { | 463 { |
480 else if(bin > m_tempogramFftLength/2.0f) bin = m_tempogramFftLength; | 486 else if(bin > m_tempogramFftLength/2.0f) bin = m_tempogramFftLength; |
481 | 487 |
482 return bin; | 488 return bin; |
483 } | 489 } |
484 | 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 } | |
497 | |
485 TempogramPlugin::FeatureSet | 498 TempogramPlugin::FeatureSet |
486 TempogramPlugin::getRemainingFeatures() | 499 TempogramPlugin::getRemainingFeatures() |
487 { | 500 { |
488 | 501 |
489 float * hannWindow = new float[m_tempogramWindowLength]; | 502 float * hannWindow = new float[m_tempogramWindowLength]; |
495 | 508 |
496 //initialise novelty curve processor | 509 //initialise novelty curve processor |
497 size_t numberOfBlocks = m_spectrogram[0].size(); | 510 size_t numberOfBlocks = m_spectrogram[0].size(); |
498 //cerr << numberOfBlocks << endl; | 511 //cerr << numberOfBlocks << endl; |
499 NoveltyCurveProcessor nc(m_inputSampleRate, m_inputBlockSize, numberOfBlocks, m_noveltyCurveCompressionConstant); | 512 NoveltyCurveProcessor nc(m_inputSampleRate, m_inputBlockSize, numberOfBlocks, m_noveltyCurveCompressionConstant); |
500 vector<float> noveltyCurve = nc.spectrogramToNoveltyCurve(m_spectrogram); //calculate novelty curve from magnitude data | 513 vector<float> noveltyCurve = nc.spectrogramToNoveltyCurve(m_spectrogram); //calculate novelty curvefrom magnitude data |
501 //if(noveltyCurve.size() > 50) for (int i = 0; i < 50; i++) cerr << noveltyCurve[i] << endl; | 514 //if(noveltyCurve.size() > 50) for (int i = 0; i < 50; i++) cerr << noveltyCurve[i] << endl; |
502 | 515 |
503 //push novelty curve data to featureset 1 and set timestamps | 516 //push novelty curve data to featureset 1 and set timestamps |
504 for (int i = 0; i < (int)numberOfBlocks; i++){ | 517 for (int i = 0; i < (int)numberOfBlocks; i++){ |
505 Feature noveltyCurveFeature; | 518 Feature noveltyCurveFeature; |
506 noveltyCurveFeature.values.push_back(noveltyCurve[i]); | 519 noveltyCurveFeature.values.push_back(noveltyCurve[i]); |
507 noveltyCurveFeature.hasTimestamp = false; | 520 noveltyCurveFeature.hasTimestamp = false; |
508 featureSet[1].push_back(noveltyCurveFeature); | 521 featureSet[2].push_back(noveltyCurveFeature); |
522 assert(!isnan(noveltyCurveFeature.values.back())); | |
509 } | 523 } |
510 | 524 |
511 //window function for spectrogram | 525 //window function for spectrogram |
512 WindowFunction::hanning(hannWindow, m_tempogramWindowLength); | 526 WindowFunction::hanning(hannWindow, m_tempogramWindowLength); |
513 | 527 |
525 Feature tempogramFeature; | 539 Feature tempogramFeature; |
526 | 540 |
527 assert(tempogram[block].size() == (m_tempogramFftLength/2 + 1)); | 541 assert(tempogram[block].size() == (m_tempogramFftLength/2 + 1)); |
528 for(int k = m_tempogramMinBin; k < (int)m_tempogramMaxBin; k++){ | 542 for(int k = m_tempogramMinBin; k < (int)m_tempogramMaxBin; k++){ |
529 tempogramFeature.values.push_back(tempogram[block][k]); | 543 tempogramFeature.values.push_back(tempogram[block][k]); |
544 assert(!isnan(tempogramFeature.values.back())); | |
530 } | 545 } |
531 tempogramFeature.hasTimestamp = false; | 546 tempogramFeature.hasTimestamp = false; |
532 featureSet[0].push_back(tempogramFeature); | 547 featureSet[1].push_back(tempogramFeature); |
533 } | 548 } |
534 | 549 |
535 //Calculate cyclic tempogram | 550 //Calculate cyclic tempogram |
536 vector<unsigned int> logBins = calculateTempogramNearestNeighbourLogBins(); | 551 vector<unsigned int> logBins = calculateTempogramNearestNeighbourLogBins(); |
537 | 552 |
540 for (int block = 0; block < tempogramLength; block++){ | 555 for (int block = 0; block < tempogramLength; block++){ |
541 Feature cyclicTempogramFeature; | 556 Feature cyclicTempogramFeature; |
542 | 557 |
543 for (int i = 0; i < (int)m_cyclicTempogramOctaveDivider; i++){ | 558 for (int i = 0; i < (int)m_cyclicTempogramOctaveDivider; i++){ |
544 float sum = 0; | 559 float sum = 0; |
560 | |
561 //mcerr << floor(binToBPM(logBins[i]) + 0.5) << " " << floor(binToBPM(logBins[i + m_cyclicTempogramOctaveDivider]) + 0.5) << endl; | |
562 | |
545 for (int j = 0; j < (int)m_cyclicTempogramNumberOfOctaves; j++){ | 563 for (int j = 0; j < (int)m_cyclicTempogramNumberOfOctaves; j++){ |
546 sum += tempogram[block][logBins[i+j*m_cyclicTempogramOctaveDivider]]; | 564 sum += tempogram[block][logBins[i+j*m_cyclicTempogramOctaveDivider]]; |
547 } | 565 } |
548 cyclicTempogramFeature.values.push_back(sum/m_cyclicTempogramNumberOfOctaves); | 566 cyclicTempogramFeature.values.push_back(sum/m_cyclicTempogramNumberOfOctaves); |
567 assert(!isnan(cyclicTempogramFeature.values.back())); | |
549 } | 568 } |
550 | 569 |
551 cyclicTempogramFeature.hasTimestamp = false; | 570 cyclicTempogramFeature.hasTimestamp = false; |
552 featureSet[2].push_back(cyclicTempogramFeature); | 571 featureSet[0].push_back(cyclicTempogramFeature); |
553 } | 572 } |
554 | 573 |
555 return featureSet; | 574 return featureSet; |
556 } | 575 } |