Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/alexmarsev/soundtouch.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authoroparviai <oparviai@f3a24b6a-cf45-0410-b55a-8c22e2698227>2012-08-30 23:45:25 +0400
committeroparviai <oparviai@f3a24b6a-cf45-0410-b55a-8c22e2698227>2012-08-30 23:45:25 +0400
commite67e04bc5b3ca3c42a6508303ff0b11bba1c69b1 (patch)
treef479ec292155fbaa734e0a3141a04f96d1c9f885 /source
parenta6267e14c1f429f42bad35f01bc60f7403b19428 (diff)
Adjustments in beat detection
Diffstat (limited to 'source')
-rw-r--r--source/SoundTouch/BPMDetect.cpp67
-rw-r--r--source/SoundTouch/PeakFinder.cpp11
2 files changed, 34 insertions, 44 deletions
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