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> </head>
<body class="normal"> <body class="normal">
<hr> <hr>
<h1>SoundTouch audio processing library v1.5.0 <h1>SoundTouch audio processing library v1.5.1pre
</h1> </h1>
<p class="normal">SoundTouch library Copyright &copy; Olli <p class="normal">SoundTouch library Copyright &copy; Olli
Parviainen 2001-2009 </p> Parviainen 2001-2009 </p>
@ -536,6 +536,13 @@ estimates the BPM rate:</p>
<h2>5. Change History</h2> <h2>5. Change History</h2>
<h3>5.1. SoundTouch library Change History </h3> <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> <p><strong>1.5.0:</strong></p>
<ul> <ul>
<li>Added normalization to correlation calculation and improvement automatic seek/sequence parameter calculation to improve sound quality</li> <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 <h3>5.2. SoundStretch application Change
History </h3> 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> <ul>
<li>Moved BPM detection routines from SoundStretch application into SoundTouch <li>Moved BPM detection routines from SoundStretch application into SoundTouch
library</li> library</li>

View File

@ -78,10 +78,19 @@ protected:
float *xcorr; float *xcorr;
/// Amplitude envelope sliding average approximation level accumulator /// Amplitude envelope sliding average approximation level accumulator
float envelopeAccu; double envelopeAccu;
/// RMS volume sliding average approximation level accumulator /// 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. /// Sample average counter.
int decimateCount; int decimateCount;

View File

@ -79,10 +79,10 @@ namespace soundtouch
{ {
/// Soundtouch library version string /// Soundtouch library version string
#define SOUNDTOUCH_VERSION "1.5.0" #define SOUNDTOUCH_VERSION "1.5.1pre"
/// SoundTouch library version id /// SoundTouch library version id
#define SOUNDTOUCH_VERSION_ID (10500) #define SOUNDTOUCH_VERSION_ID (10509)
// //
// Available setting IDs for the 'setSetting' & 'get_setting' functions: // 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; RMSVolumeAccu = (0.092f * 0.092f) / avgnorm;
#endif #endif
cutCoeff = 1.75;
aboveCutAccu = 0;
totalAccu = 0;
// choose decimation factor so that result is approx. 500 Hz // choose decimation factor so that result is approx. 500 Hz
decimateBy = sampleRate / 500; decimateBy = sampleRate / 500;
assert(decimateBy > 0); assert(decimateBy > 0);
@ -215,16 +219,15 @@ void BPMDetect::updateXCorr(int process_samples)
} }
// Calculates envelope of the sample data // Calculates envelope of the sample data
void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples) void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples)
{ {
const float decay = 0.7f; // decay constant for smoothing the envelope const static double decay = 0.7f; // decay constant for smoothing the envelope
const float norm = (1 - decay); const static double norm = (1 - decay);
int i; int i;
LONG_SAMPLETYPE out; LONG_SAMPLETYPE out;
float val; double val;
for (i = 0; i < numsamples; i ++) for (i = 0; i < numsamples; i ++)
{ {
@ -233,10 +236,32 @@ void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples)
val = (float)fabs((float)samples[i]); val = (float)fabs((float)samples[i]);
RMSVolumeAccu += val * val; 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) // (we're interested in peak values, not the silent moments)
val -= 2 * (float)sqrt(RMSVolumeAccu * avgnorm); val -= cutCoeff * sqrt(RMSVolumeAccu * avgnorm);
val = (val > 0) ? val : 0; 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 // smooth amplitude envelope
envelopeAccu *= decay; envelopeAccu *= decay;
@ -249,6 +274,12 @@ void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples)
#endif // INTEGER_SAMPLES #endif // 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;
}
} }