diff src/TempoFollower.cpp @ 19:1a62561bd72d

Added in tempo follower class that models the tempo of played events
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Thu, 09 Feb 2012 18:09:34 +0000
parents
children 4f6006cac9de
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/TempoFollower.cpp	Thu Feb 09 18:09:34 2012 +0000
@@ -0,0 +1,134 @@
+/*
+ *  TempoFollower.cpp
+ *  MultipleAudioMathcher
+ *
+ *  Created by Andrew on 09/02/2012.
+ *  Copyright 2012 QMUL. All rights reserved.
+ *
+ */
+
+#include "TempoFollower.h"
+
+TempoFollower::TempoFollower(){
+	maximumTempoInterval = 600;
+	minimumTempoInterval = 200;
+	tempoArraySize = maximumTempoInterval - minimumTempoInterval;;
+	
+	tempoPrior.createVector(tempoArraySize);
+	tempoPosterior.createVector(tempoArraySize);
+	tempoLikelihood.createVector(tempoArraySize);
+	
+	tempoPosterior.addConstant(1);
+	
+	tempoPrior.offset = minimumTempoInterval;
+	tempoPosterior.offset = minimumTempoInterval;
+	tempoLikelihood.offset = minimumTempoInterval;
+	
+	tempoPrior.scalar = 1;
+	tempoPosterior.scalar = 1;
+	tempoLikelihood.scalar = 1;
+}
+
+
+void TempoFollower::reset(){
+
+	tempoPrior.zero();
+	tempoPosterior.addConstant(1);
+}
+
+
+void TempoFollower::setUpEventTimeMatrix(){
+	for (int i = 0;i < NUMBER_OF_CHANNELS;i++){
+		IntVector v;
+		eventTimes.push_back(v);
+		
+		DoubleMatrix m;	
+		tempoIntervals.push_back(m);
+	}
+	
+	//[channel][index]
+}
+
+
+
+void TempoFollower::printEventTimes(){
+	for (int i = 0;i < NUMBER_OF_CHANNELS;i++){
+		printf("CHANNEL %i EVENT TIMES...\n", i);
+		for (int j = 0;j < eventTimes[i].size();j++)
+			printf("%i\n", eventTimes[i][j]);
+	}
+}
+
+
+void TempoFollower::updateTempo(const int& channel, const int& timeIn){
+	
+	eventTimes[channel].push_back(timeIn);
+	
+	int interval = 0;
+	int intervalLimit = 3600;
+	
+	int recentIndex = eventTimes[channel].size()-1;
+	
+	DoubleVector d;
+	
+	int recentEvent = eventTimes[channel][recentIndex];
+	
+	for (int i = 1;i < eventTimes[channel].size() && interval < intervalLimit;i++){
+		interval = eventTimes[channel][recentIndex] - eventTimes[channel][recentIndex - i];
+		
+		if (testTempoInterval(channel, interval, d))
+			printf("channel %i interval %i at division 1 == tempo update %i\n", channel, interval, interval);
+		
+		for (double divisionInEighthNotes = 2.0;divisionInEighthNotes < 9.0;divisionInEighthNotes+=2){
+			
+			double testInterval = interval / divisionInEighthNotes;
+			if (testTempoInterval(channel, testInterval, d))
+				printf("channel %i interval %i at division %.0f == tempo update %f\n", channel, interval, divisionInEighthNotes, testInterval);
+			
+		}
+	}
+	
+	(tempoIntervals[channel]).push_back(d);
+	updateTempoDistribution(d);
+	
+}
+
+
+bool TempoFollower::testTempoInterval(const int& channel, const double& testInterval, DoubleVector& d){
+
+	bool updated = false;
+	if (testInterval >= minimumTempoInterval && testInterval <= maximumTempoInterval){
+		d.push_back(testInterval);
+		updated = true;
+	}
+	return updated;
+}
+
+void TempoFollower::updateTempoDistribution(const DoubleVector& d){
+	double tempoLikelihoodToNoiseRatio = 0.8;
+	tempoLikelihood.zero();
+	double amount = tempoLikelihoodToNoiseRatio/d.size();
+	for (int i = 0;i < d.size();i++){
+		tempoLikelihood.addGaussianShapeFromRealTime(d[i], 10, amount);
+	}
+	tempoLikelihood.addConstant(0.1*(1-tempoLikelihoodToNoiseRatio));
+	calculatePosterior();
+	
+	tempoPosterior.renormalise();
+	playingTempo = tempoPosterior.getIndexInRealTerms(tempoPosterior.getMAPestimate());
+}
+
+
+
+void TempoFollower::calculatePosterior(){
+	tempoPrior.copyFromDynamicVector(tempoPosterior);
+	for (int i = 0;i < tempoArraySize;i++){
+		tempoPosterior.array[i] = tempoLikelihood.array[i] * tempoPrior.array[i];
+	}
+}
+
+void TempoFollower::drawTempoArray(ofxWindowRegion& window){
+	ofSetColor(150,0,250);
+	tempoPosterior.drawConstrainedVector(0, tempoArraySize, 0, ofGetWidth(), window);
+	ofDrawBitmapString("tempo "+ofToString(playingTempo), window.x+ 20, window.y + 40);
+}