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:
parent
b4e22218e6
commit
0462e450a6
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user