changeset 56:a0f987c06bec

* Make it possible to retrieve beat spectral difference function from bar detector * Avoid crashes when bar detector is run with very short input
author cannam
date Fri, 27 Feb 2009 10:23:08 +0000
parents 7fe29d8a7eaf
children d241e7701c0c
files dsp/tempotracking/DownBeat.cpp dsp/tempotracking/DownBeat.h dsp/tempotracking/TempoTrackV2.cpp
diffstat 3 files changed, 42 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/dsp/tempotracking/DownBeat.cpp	Tue Feb 10 16:37:11 2009 +0000
+++ b/dsp/tempotracking/DownBeat.cpp	Fri Feb 27 10:23:08 2009 +0000
@@ -140,7 +140,8 @@
 
     d_vec_t newspec(m_beatframesize / 2); // magnitude spectrum of current beat
     d_vec_t oldspec(m_beatframesize / 2); // magnitude spectrum of previous beat
-    d_vec_t specdiff;
+
+    m_beatsd.clear();
 
     if (audioLength == 0) return;
 
@@ -191,10 +192,10 @@
 
         // Calculate JS divergence between new and old spectral frames
 
-        specdiff.push_back(measureSpecDiff(oldspec, newspec));
-//        specdiff.push_back(KLDivergence().distanceDistribution(oldspec, newspec, false));
-
-        std::cerr << "specdiff: " << specdiff[specdiff.size()-1] << std::endl;
+        if (i > 0) { // otherwise we have no previous frame
+            m_beatsd.push_back(measureSpecDiff(oldspec, newspec));
+            std::cerr << "specdiff: " << m_beatsd[m_beatsd.size()-1] << std::endl;
+        }
 
         // Copy newspec across to old
 
@@ -216,9 +217,13 @@
 
     // look for beat transition which leads to greatest spectral change
     for (int beat = 0; beat < timesig; ++beat) {
-        for (int example = beat; example < specdiff.size(); example += timesig) {
-            dbcand[beat] += (specdiff[example]) / timesig;
+        int count = 0;
+        for (int example = beat - 1; example < m_beatsd.size(); example += timesig) {
+            if (example < 0) continue;
+            dbcand[beat] += (m_beatsd[example]) / timesig;
+            ++count;
         }
+        if (count > 0) m_beatsd[beat] /= count;
         std::cerr << "dbcand[" << beat << "] = " << dbcand[beat] << std::endl;
     }
 
@@ -280,3 +285,9 @@
     return SD;
 }
 
+void
+DownBeat::getBeatSD(vector<double> &beatsd) const
+{
+    for (int i = 0; i < m_beatsd.size(); ++i) beatsd.push_back(m_beatsd[i]);
+}
+
--- a/dsp/tempotracking/DownBeat.h	Tue Feb 10 16:37:11 2009 +0000
+++ b/dsp/tempotracking/DownBeat.h	Fri Feb 27 10:23:08 2009 +0000
@@ -65,6 +65,17 @@
                        size_t audioLength, // after downsampling
                        const vector<double> &beats,
                        vector<int> &downbeats);
+
+    /**
+     * Return the beat spectral difference function.  This is
+     * calculated during findDownBeats, so this function can only be
+     * meaningfully called after that has completed.  The returned
+     * vector contains one value for each of the beat times passed in
+     * to findDownBeats, less one.  Each value contains the spectral
+     * difference between region prior to the beat's nominal position
+     * and the region following it.
+     */
+    void getBeatSD(vector<double> &beatsd) const;
     
     /**
      * For your downsampling convenience: call this function
@@ -110,6 +121,7 @@
     double *m_beatframe;
     double *m_fftRealOut;
     double *m_fftImagOut;
+    d_vec_t m_beatsd;
 };
 
 #endif
--- a/dsp/tempotracking/TempoTrackV2.cpp	Tue Feb 10 16:37:11 2009 +0000
+++ b/dsp/tempotracking/TempoTrackV2.cpp	Fri Feb 27 10:23:08 2009 +0000
@@ -115,7 +115,7 @@
     int col_counter = -1;
 
     // main loop for beat period calculation
-    for (uint i=0; i<(df.size()-winlen); i+=step)
+    for (uint i=0; i+winlen<df.size(); i+=step)
     {
         // get dfframe
         d_vec_t dfframe(winlen);
@@ -248,6 +248,9 @@
 
 
     uint T = delta.size();
+
+    if (T < 2) return; // can't do anything at all meaningful
+
     uint Q = delta[0].size();
 
     // initialize first column of delta
@@ -392,6 +395,8 @@
 TempoTrackV2::calculateBeats(const d_vec_t &df, const d_vec_t &beat_period,
                              d_vec_t &beats)
 {
+    if (df.empty() || beat_period.empty()) return;
+
     d_vec_t cumscore(df.size()); // store cumulative score
     i_vec_t backlink(df.size()); // backlink (stores best beat locations at each time instant)
     d_vec_t localscore(df.size()); // localscore, for now this is the same as the detection function
@@ -449,6 +454,9 @@
 
     int startpoint = get_max_ind(tmp_vec) + cumscore.size() - beat_period[beat_period.size()-1] ;
 
+    // can happen if no results obtained earlier (e.g. input too short)
+    if (startpoint >= backlink.size()) startpoint = backlink.size()-1;
+
     // USE BACKLINK TO GET EACH NEW BEAT (TOWARDS THE BEGINNING OF THE FILE)
     //  BACKTRACKING FROM THE END TO THE BEGINNING.. MAKING SURE NOT TO GO BEFORE SAMPLE 0
     i_vec_t ibeats;
@@ -457,7 +465,9 @@
     while (backlink[ibeats.back()] > 0)
     {
         std::cerr << "backlink[" << ibeats.back() << "] = " << backlink[ibeats.back()] << std::endl;
-        ibeats.push_back(backlink[ibeats.back()]);
+        int b = ibeats.back();
+        if (backlink[b] == b) break; // shouldn't happen... haha
+        ibeats.push_back(backlink[b]);
     }
   
     // REVERSE SEQUENCE OF IBEATS AND STORE AS BEATS