diff --git a/source/SoundTouch/BPMDetect.cpp b/source/SoundTouch/BPMDetect.cpp index 8b3d1c6..c36661f 100644 --- a/source/SoundTouch/BPMDetect.cpp +++ b/source/SoundTouch/BPMDetect.cpp @@ -117,23 +117,19 @@ BPMDetect::BPMDetect(int numChannels, int aSampleRate) envelopeAccu = 0; - // Initialize RMS volume accumulator to RMS level of 3000 (out of 32768) that's - // a typical RMS signal level value for song data. This value is then adapted + // Initialize RMS volume accumulator to RMS level of 1500 (out of 32768) that's + // safe initial RMS signal level value for song data. This value is then adapted // to the actual level during processing. #ifdef SOUNDTOUCH_INTEGER_SAMPLES // integer samples - RMSVolumeAccu = (3000 * 3000) / avgnorm; + RMSVolumeAccu = (1500 * 1500) / avgnorm; #else // float samples, scaled to range [-1..+1[ - RMSVolumeAccu = (0.092f * 0.092f) / avgnorm; + RMSVolumeAccu = (0.045f * 0.045f) / avgnorm; #endif - cutCoeff = 1.75; - aboveCutAccu = 0; - totalAccu = 0; - - // choose decimation factor so that result is approx. 500 Hz - decimateBy = sampleRate / 500; + // choose decimation factor so that result is approx. 1000 Hz + decimateBy = sampleRate / 1000; assert(decimateBy > 0); assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES); @@ -270,31 +266,11 @@ void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples) // cut amplitudes that are below cutoff ~2 times RMS volume // (we're interested in peak values, not the silent moments) - val -= cutCoeff * sqrt(RMSVolumeAccu * avgnorm); - if (val > 0) - { - aboveCutAccu += 1.0; // sample above threshold - } - else + if (val < 0.5 * sqrt(RMSVolumeAccu * avgnorm)) { val = 0; } - totalAccu += 1.0; - - // maintain sliding statistic what proportion of 'val' samples is - // above cutoff threshold - aboveCutAccu *= 0.99931; // 2 sec time constant - totalAccu *= 0.99931; - - if (totalAccu > 500) - { - // after initial settling, auto-adjust cutoff level so that ~8% of - // values are above the threshold - double d = (aboveCutAccu / totalAccu) - 0.08; - cutCoeff += 0.001 * d; - } - // smooth amplitude envelope envelopeAccu *= decay; envelopeAccu += val; @@ -306,12 +282,6 @@ void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples) #endif // SOUNDTOUCH_INTEGER_SAMPLES samples[i] = (SAMPLETYPE)out; } - - // check that cutoff doesn't get too small - it can be just silent sequence! - if (cutCoeff < 1.5) - { - cutCoeff = 1.5; - } } @@ -355,6 +325,26 @@ void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples) +void BPMDetect::removeBias() +{ + int i; + float minval = 1e12f; // arbitrary large number + + for (i = windowStart; i < windowLen; i ++) + { + if (xcorr[i] < minval) + { + minval = xcorr[i]; + } + } + + for (i = windowStart; i < windowLen; i ++) + { + xcorr[i] -= minval; + } +} + + float BPMDetect::getBpm() { double peakPos; @@ -366,6 +356,9 @@ float BPMDetect::getBpm() // save bpm debug analysis data if debug data enabled _SaveDebugData(xcorr, windowStart, windowLen, coeff); + // remove bias from xcorr data + removeBias(); + // find peak position peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen); diff --git a/source/SoundTouch/PeakFinder.cpp b/source/SoundTouch/PeakFinder.cpp index 7f70c3c..c5123f0 100644 --- a/source/SoundTouch/PeakFinder.cpp +++ b/source/SoundTouch/PeakFinder.cpp @@ -103,7 +103,7 @@ int PeakFinder::findGround(const float *data, int peakpos, int direction) const pos = peakpos; - while ((pos > minPos) && (pos < maxPos)) + while ((pos > minPos+1) && (pos < maxPos-1)) { int prevpos; @@ -132,7 +132,7 @@ int PeakFinder::findGround(const float *data, int peakpos, int direction) const { // going uphill, increase climbing counter climb_count ++; - if (climb_count >= 10) break; // we've been climbing too long => it's next uphill => quit + if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit } } return lowpos; @@ -192,12 +192,9 @@ double PeakFinder::getPeakCenter(const float *data, int peakpos) const gp1 = findGround(data, peakpos, -1); gp2 = findGround(data, peakpos, 1); - groundLevel = max(data[gp1], data[gp2]); + groundLevel = 0.5 * (data[gp1] + data[gp2]); peakLevel = data[peakpos]; - if (groundLevel < 1e-9) return 0; // ground level too small => detection failed - if ((peakLevel / groundLevel) < 1.3) return 0; // peak less than 30% of the ground level => no good peak detected - // calculate 70%-level of the peak cutLevel = 0.70f * peakLevel + 0.30f * groundLevel; // find mid-level crossings @@ -269,7 +266,7 @@ double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos) // now compare to highest detected peak i1 = (int)(highPeak + 0.5); i2 = (int)(peaktmp + 0.5); - if (data[i2] >= 0.5*data[i1]) + if (data[i2] >= 0.4*data[i1]) { // The harmonic is at least half as high primary peak, // thus use the harmonic peak instead