Added automatic cutoff threshold adaptation to beat detection routine to better adapt BPM calculation to different types of music

This commit is contained in:
oparviai 2010-01-06 18:59:23 +00:00
parent 3dbc7209bd
commit ff06c88fd5
4 changed files with 68 additions and 13 deletions

View File

@ -18,7 +18,7 @@
</head>
<body class="normal">
<hr>
<h1>SoundTouch audio processing library v1.5.0
<h1>SoundTouch audio processing library v1.5.1pre
</h1>
<p class="normal">SoundTouch library Copyright &copy; Olli
Parviainen 2001-2009 </p>
@ -536,6 +536,13 @@ estimates the BPM rate:</p>
<h2>5. Change History</h2>
<h3>5.1. SoundTouch library Change History </h3>
<p><b>1.5.1pre:</b></p>
<ul>
<li>Added automatic cutoff threshold adaptation to beat detection routine to
better adapt BPM calculation&nbsp; to different types of music</li>
</ul>
<p><strong>1.5.0:</strong></p>
<ul>
<li>Added normalization to correlation calculation and improvement automatic seek/sequence parameter calculation to improve sound quality</li>
@ -657,7 +664,15 @@ files. </li>
<h3>5.2. SoundStretch application Change
History </h3>
<p><strong>1.4.0:</strong></p>
<p><b>v1.5.0:</b></p>
<ul>
<li>Added &quot;-speech&quot; switch to activate algorithm parameters more
suitable for speech processing than the default parameters tuned for music
processing.</li>
</ul>
<p><strong>v1.4.0:</strong></p>
<ul>
<li>Moved BPM detection routines from SoundStretch application into SoundTouch
library</li>

View File

@ -78,10 +78,19 @@ protected:
float *xcorr;
/// Amplitude envelope sliding average approximation level accumulator
float envelopeAccu;
double envelopeAccu;
/// RMS volume sliding average approximation level accumulator
float RMSVolumeAccu;
double RMSVolumeAccu;
/// Level below which to cut off signals
double cutCoeff;
/// Accumulator for accounting what proportion of samples exceed cutCoeff level
double aboveCutAccu;
/// Accumulator for total samples to calculate proportion of samples that exceed cutCoeff level
double totalAccu;
/// Sample average counter.
int decimateCount;

View File

@ -79,10 +79,10 @@ namespace soundtouch
{
/// Soundtouch library version string
#define SOUNDTOUCH_VERSION "1.5.0"
#define SOUNDTOUCH_VERSION "1.5.1pre"
/// SoundTouch library version id
#define SOUNDTOUCH_VERSION_ID (10500)
#define SOUNDTOUCH_VERSION_ID (10509)
//
// Available setting IDs for the 'setSetting' & 'get_setting' functions:

View File

@ -96,6 +96,10 @@ BPMDetect::BPMDetect(int numChannels, int aSampleRate)
RMSVolumeAccu = (0.092f * 0.092f) / avgnorm;
#endif
cutCoeff = 1.75;
aboveCutAccu = 0;
totalAccu = 0;
// choose decimation factor so that result is approx. 500 Hz
decimateBy = sampleRate / 500;
assert(decimateBy > 0);
@ -215,16 +219,15 @@ void BPMDetect::updateXCorr(int process_samples)
}
// Calculates envelope of the sample data
void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples)
{
const float decay = 0.7f; // decay constant for smoothing the envelope
const float norm = (1 - decay);
const static double decay = 0.7f; // decay constant for smoothing the envelope
const static double norm = (1 - decay);
int i;
LONG_SAMPLETYPE out;
float val;
double val;
for (i = 0; i < numsamples; i ++)
{
@ -233,10 +236,32 @@ void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples)
val = (float)fabs((float)samples[i]);
RMSVolumeAccu += val * val;
// cut amplitudes that are below 2 times average RMS volume
// cut amplitudes that are below cutoff ~2 times RMS volume
// (we're interested in peak values, not the silent moments)
val -= 2 * (float)sqrt(RMSVolumeAccu * avgnorm);
val = (val > 0) ? val : 0;
val -= cutCoeff * sqrt(RMSVolumeAccu * avgnorm);
if (val > 0)
{
aboveCutAccu += 1.0; // sample above threshold
}
else
{
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;
@ -249,6 +274,12 @@ void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples)
#endif // 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;
}
}