1
0
mirror of https://github.com/RPCS3/soundtouch.git synced 2024-11-10 04:42:50 +01:00

Adjustments in beat detection

This commit is contained in:
oparviai 2012-08-30 19:45:25 +00:00
parent b4e22218e6
commit 0462e450a6
2 changed files with 34 additions and 44 deletions

View File

@ -117,23 +117,19 @@ BPMDetect::BPMDetect(int numChannels, int aSampleRate)
envelopeAccu = 0; envelopeAccu = 0;
// Initialize RMS volume accumulator to RMS level of 3000 (out of 32768) that's // Initialize RMS volume accumulator to RMS level of 1500 (out of 32768) that's
// a typical RMS signal level value for song data. This value is then adapted // safe initial RMS signal level value for song data. This value is then adapted
// to the actual level during processing. // to the actual level during processing.
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
// integer samples // integer samples
RMSVolumeAccu = (3000 * 3000) / avgnorm; RMSVolumeAccu = (1500 * 1500) / avgnorm;
#else #else
// float samples, scaled to range [-1..+1[ // float samples, scaled to range [-1..+1[
RMSVolumeAccu = (0.092f * 0.092f) / avgnorm; RMSVolumeAccu = (0.045f * 0.045f) / avgnorm;
#endif #endif
cutCoeff = 1.75; // choose decimation factor so that result is approx. 1000 Hz
aboveCutAccu = 0; decimateBy = sampleRate / 1000;
totalAccu = 0;
// choose decimation factor so that result is approx. 500 Hz
decimateBy = sampleRate / 500;
assert(decimateBy > 0); assert(decimateBy > 0);
assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES); 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 // cut amplitudes that are below cutoff ~2 times RMS volume
// (we're interested in peak values, not the silent moments) // (we're interested in peak values, not the silent moments)
val -= cutCoeff * sqrt(RMSVolumeAccu * avgnorm); if (val < 0.5 * sqrt(RMSVolumeAccu * avgnorm))
if (val > 0)
{
aboveCutAccu += 1.0; // sample above threshold
}
else
{ {
val = 0; 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 // smooth amplitude envelope
envelopeAccu *= decay; envelopeAccu *= decay;
envelopeAccu += val; envelopeAccu += val;
@ -306,12 +282,6 @@ void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples)
#endif // SOUNDTOUCH_INTEGER_SAMPLES #endif // SOUNDTOUCH_INTEGER_SAMPLES
samples[i] = (SAMPLETYPE)out; 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() float BPMDetect::getBpm()
{ {
double peakPos; double peakPos;
@ -366,6 +356,9 @@ float BPMDetect::getBpm()
// save bpm debug analysis data if debug data enabled // save bpm debug analysis data if debug data enabled
_SaveDebugData(xcorr, windowStart, windowLen, coeff); _SaveDebugData(xcorr, windowStart, windowLen, coeff);
// remove bias from xcorr data
removeBias();
// find peak position // find peak position
peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen); peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen);

View File

@ -103,7 +103,7 @@ int PeakFinder::findGround(const float *data, int peakpos, int direction) const
pos = peakpos; pos = peakpos;
while ((pos > minPos) && (pos < maxPos)) while ((pos > minPos+1) && (pos < maxPos-1))
{ {
int prevpos; int prevpos;
@ -132,7 +132,7 @@ int PeakFinder::findGround(const float *data, int peakpos, int direction) const
{ {
// going uphill, increase climbing counter // going uphill, increase climbing counter
climb_count ++; 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; return lowpos;
@ -192,12 +192,9 @@ double PeakFinder::getPeakCenter(const float *data, int peakpos) const
gp1 = findGround(data, peakpos, -1); gp1 = findGround(data, peakpos, -1);
gp2 = 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]; 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 // calculate 70%-level of the peak
cutLevel = 0.70f * peakLevel + 0.30f * groundLevel; cutLevel = 0.70f * peakLevel + 0.30f * groundLevel;
// find mid-level crossings // find mid-level crossings
@ -269,7 +266,7 @@ double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
// now compare to highest detected peak // now compare to highest detected peak
i1 = (int)(highPeak + 0.5); i1 = (int)(highPeak + 0.5);
i2 = (int)(peaktmp + 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, // The harmonic is at least half as high primary peak,
// thus use the harmonic peak instead // thus use the harmonic peak instead