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
diff options
context:
space:
mode:
authoroparviai <oparviai@f3a24b6a-cf45-0410-b55a-8c22e2698227>2011-12-31 00:33:46 +0400
committeroparviai <oparviai@f3a24b6a-cf45-0410-b55a-8c22e2698227>2011-12-31 00:33:46 +0400
commit10dc06227db2fd5ec9ed872f7fba4ac974f9ec64 (patch)
tree22161243f98ebecf962693cd47909095968b7e11
parentc723240152c75c7f3dc40fa3e32a2289411f57b0 (diff)
Improved BPM detection routine to better spot harmonics for the strongest beat pattern.
-rw-r--r--include/BPMDetect.h2
-rw-r--r--source/SoundTouch/PeakFinder.cpp64
-rw-r--r--source/SoundTouch/PeakFinder.h4
3 files changed, 58 insertions, 12 deletions
diff --git a/include/BPMDetect.h b/include/BPMDetect.h
index ff1d3c4..c5989cf 100644
--- a/include/BPMDetect.h
+++ b/include/BPMDetect.h
@@ -67,7 +67,7 @@ namespace soundtouch
#define MIN_BPM 29
/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit.
-#define MAX_BPM 230
+#define MAX_BPM 200
/// Class for calculating BPM rate for audio data.
diff --git a/source/SoundTouch/PeakFinder.cpp b/source/SoundTouch/PeakFinder.cpp
index 9ad601c..cc2113b 100644
--- a/source/SoundTouch/PeakFinder.cpp
+++ b/source/SoundTouch/PeakFinder.cpp
@@ -55,15 +55,46 @@ PeakFinder::PeakFinder()
}
+// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.
+int PeakFinder::findTop(const float *data, int peakpos) const
+{
+ int i;
+ int start, end;
+ float refvalue;
+
+ refvalue = data[peakpos];
+
+ // seek within ±10 points
+ start = peakpos - 10;
+ if (start < minPos) start = minPos;
+ end = peakpos + 10;
+ if (end > maxPos) end = maxPos;
+
+ for (i = start; i <= end; i ++)
+ {
+ if (data[i] > refvalue)
+ {
+ peakpos = i;
+ refvalue = data[i];
+ }
+ }
+
+ // failure if max value is at edges of seek range => it's not peak, it's at slope.
+ if ((peakpos == start) || (peakpos == end)) return 0;
+
+ return peakpos;
+}
+
+
// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding
// to direction defined by 'direction' until next 'hump' after minimum value will
// begin
int PeakFinder::findGround(const float *data, int peakpos, int direction) const
{
- float refvalue;
int lowpos;
int pos;
int climb_count;
+ float refvalue;
float delta;
climb_count = 0;
@@ -210,30 +241,41 @@ double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
// Now check if the highest peak were in fact harmonic of the true base beat peak
// - sometimes the highest peak can be Nth harmonic of the true base peak yet
// just a slightly higher than the true base
- for (i = 2; i < 10; i ++)
+
+ int hp = (int)(highPeak + 0.5);
+
+ for (i = 3; i < 10; i ++)
{
- double peaktmp, tmp;
+ double peaktmp, harmonic;
int i1,i2;
- peakpos = (int)(highPeak / (double)i + 0.5f);
+ harmonic = (double)i * 0.5;
+ peakpos = (int)(highPeak / harmonic + 0.5f);
if (peakpos < minPos) break;
+ peakpos = findTop(data, peakpos); // seek true local maximum index
+ if (peakpos == 0) continue; // no local max here
- // calculate mass-center of possible base peak
+ // calculate mass-center of possible harmonic peak
peaktmp = getPeakCenter(data, peakpos);
+ // accept harmonic peak if
+ // (a) it is found
+ // (b) is within ±4% of the expected harmonic interval
+ // (c) has at least half x-corr value of the max. peak
+
+ double diff = harmonic * peaktmp / highPeak;
+ if ((diff < 0.96) || (diff > 1.04)) continue; // peak too afar from expected
+
// now compare to highest detected peak
i1 = (int)(highPeak + 0.5);
i2 = (int)(peaktmp + 0.5);
- tmp = 2 * (data[i2] - data[i1]) / (data[i2] + data[i1]);
- if (fabs(tmp) < 0.1)
+ if (data[i2] >= 0.5*data[i1])
{
- // The highest peak is harmonic of almost as high base peak,
- // thus use the base peak instead
+ // The harmonic is at least half as high primary peak,
+ // thus use the harmonic peak instead
peak = peaktmp;
}
}
return peak;
}
-
-
diff --git a/source/SoundTouch/PeakFinder.h b/source/SoundTouch/PeakFinder.h
index a72b24f..fce4dc1 100644
--- a/source/SoundTouch/PeakFinder.h
+++ b/source/SoundTouch/PeakFinder.h
@@ -63,6 +63,10 @@ protected:
int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
) const;
+ // Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.
+ int findTop(const float *data, int peakpos) const;
+
+
/// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right-
/// or left-hand side of the given peak position.
int findGround(const float *data, /// Data vector.