diff src/BTrack.cpp @ 102:0a99d93955bb

Tidied up predictBeat() function, and removed an unnecessary overloaded function for calculating beat times in seconds
author Adam Stark <adamstark.uk@gmail.com>
date Sun, 03 Sep 2017 12:21:25 +0100
parents 1fcc06afd9cb
children 6b522d568ba4
line wrap: on
line diff
--- a/src/BTrack.cpp	Sun Sep 03 11:34:04 2017 +0100
+++ b/src/BTrack.cpp	Sun Sep 03 12:21:25 2017 +0100
@@ -77,14 +77,6 @@
 }
 
 //=======================================================================
-double BTrack::getBeatTimeInSeconds (int frameNumber, int hopSize, int fs)
-{
-    long frameNum = (long) frameNumber;
-    
-    return getBeatTimeInSeconds (frameNum, hopSize, fs);
-}
-
-//=======================================================================
 void BTrack::initialise (int hopSize_, int frameSize_)
 {
     // set vector sizes
@@ -507,7 +499,7 @@
 		{
 			for (int b = 1 - a; b <= a - 1; b++) // general state using normalisation of comb elements
 			{
-				combFilterBankOutput[i-1] = combFilterBankOutput[i-1] + (acf[(a*i+b)-1]*weightingVector[i-1])/(2*a-1);	// calculate value for comb filter row
+				combFilterBankOutput[i-1] += (acf[(a * i + b) - 1] * weightingVector[i - 1]) / (2 * a - 1);	// calculate value for comb filter row
 			}
 		}
 	}
@@ -638,7 +630,6 @@
 	
 	double w1[windowSize];
 	double v = -2. * beatPeriod;
-	double weightedCumulativeScore;
 	
 	// create window
 	for (int i = 0; i < windowSize; i++)
@@ -653,7 +644,7 @@
 	int n = 0;
 	for (int i = windowStart; i <= windowEnd; i++)
 	{
-        weightedCumulativeScore = cumulativeScore[i] * w1[n];
+        double weightedCumulativeScore = cumulativeScore[i] * w1[n];
 		
         if (weightedCumulativeScore > maxValue)
             maxValue = weightedCumulativeScore;
@@ -668,73 +659,79 @@
 //=======================================================================
 void BTrack::predictBeat()
 {	 
-	int windowSize = (int) beatPeriod;
-	double futureCumulativeScore[onsetDFBufferSize + windowSize];
-	double w2[windowSize];
+	int beatExpectationWindowSize = (int) beatPeriod;
+	double futureCumulativeScore[onsetDFBufferSize + beatExpectationWindowSize];
+	double beatExpectationWindow[beatExpectationWindowSize];
     
-	// copy cumscore to first part of fcumscore
+	// copy cumulativeScore to first part of futureCumulativeScore
 	for (int i = 0;i < onsetDFBufferSize;i++)
+        futureCumulativeScore[i] = cumulativeScore[i];
+	
+	// Create a beat expectation window for predicting future beats from the "future" of the cumulative score.
+    // We are making this beat prediction at the midpoint between beats, and so we make a Gaussian
+    // weighting centred on the most likely beat position (half a beat period into the future)
+    // This is W2 in Adam Stark's PhD thesis, equation 3.6, page 62
+    
+	double v = 1;
+	for (int i = 0; i < beatExpectationWindowSize; i++)
 	{
-		futureCumulativeScore[i] = cumulativeScore[i];
-	}
-	
-	// create future window
-	double v = 1;
-	for (int i = 0; i < windowSize; i++)
-	{
-		w2[i] = exp((-1*pow((v - (beatPeriod/2)),2))   /  (2*pow((beatPeriod/2) ,2)));
+		beatExpectationWindow[i] = exp((-1 * pow ((v - (beatPeriod / 2)), 2))   /  (2 * pow (beatPeriod / 2, 2)));
 		v++;
 	}
 	
-	// create past window
-	v = -2*beatPeriod;
-	int start = onsetDFBufferSize - round(2*beatPeriod);
-	int end = onsetDFBufferSize - round(beatPeriod/2);
-	int pastwinsize = end-start+1;
-	double w1[pastwinsize];
+	// Create window for "synthesizing" the cumulative score into the future
+    // It is a log-Gaussian transition weighting running from from 2 beat periods
+    // in the past to half a beat period in the past. It favours the time exactly
+    // one beat period in the past
+    // This is W1 in Adam Stark's PhD thesis, equation 3.2, page 60
+    
+	v = -2 * beatPeriod;
+	int startIndex = onsetDFBufferSize - round (2 * beatPeriod);
+	int endIndex = onsetDFBufferSize - round (beatPeriod / 2);
+	int pastWindowSize = endIndex - startIndex + 1;
+	double logGaussianTransitionWeighting[pastWindowSize];
 
-	for (int i = 0;i < pastwinsize;i++)
+	for (int i = 0; i < pastWindowSize; i++)
 	{
-		w1[i] = exp((-1*pow(tightness*log(-v/beatPeriod),2))/2);
-		v = v+1;
+		logGaussianTransitionWeighting[i] = exp((-1 * pow (tightness * log (-v / beatPeriod), 2) ) / 2);
+		v = v + 1;
 	}
 
-	// calculate future cumulative score
-	double max;
-	int n;
-	double wcumscore;
-	for (int i = onsetDFBufferSize; i < (onsetDFBufferSize + windowSize); i++)
+	// Calculate the future cumulative score, using the log Gaussian transition weighting
+    
+	for (int i = onsetDFBufferSize; i < (onsetDFBufferSize + beatExpectationWindowSize); i++)
 	{
-		start = i - round (2*beatPeriod);
-		end = i - round (beatPeriod/2);
+		startIndex = i - round (2 * beatPeriod);
+		endIndex = i - round (beatPeriod / 2);
 		
-		max = 0;
-		n = 0;
-		for (int k=start;k <= end;k++)
+		double maxValue = 0;
+		int n = 0;
+		for (int k = startIndex; k <= endIndex; k++)
 		{
-			wcumscore = futureCumulativeScore[k]*w1[n];
+			double weightedCumulativeScore = futureCumulativeScore[k] * logGaussianTransitionWeighting[n];
 			
-			if (wcumscore > max)
-			{
-				max = wcumscore;
-			}
+			if (weightedCumulativeScore > maxValue)
+                maxValue = weightedCumulativeScore;
+
 			n++;
 		}
 		
-		futureCumulativeScore[i] = max;
+		futureCumulativeScore[i] = maxValue;
 	}
 	
-	// predict beat
-	max = 0;
-	n = 0;
+	// Predict the next beat, finding the maximum point of the future cumulative score
+    // over the next beat, after being weighted by the beat expectation window
+    
+	double maxValue = 0;
+	int n = 0;
 	
-	for (int i = onsetDFBufferSize; i < (onsetDFBufferSize + windowSize); i++)
+	for (int i = onsetDFBufferSize; i < (onsetDFBufferSize + beatExpectationWindowSize); i++)
 	{
-		wcumscore = futureCumulativeScore[i]*w2[n];
+		double weightedCumulativeScore = futureCumulativeScore[i] * beatExpectationWindow[n];
 		
-		if (wcumscore > max)
+		if (weightedCumulativeScore > maxValue)
 		{
-			max = wcumscore;
+			maxValue = weightedCumulativeScore;
 			beatCounter = n;
 		}