diff hackday/midiEventHolder.cpp @ 24:5a11b19906c7

hackday code is added.
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Sat, 03 Dec 2011 17:19:43 +0000
parents
children 2a025ea7c793
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hackday/midiEventHolder.cpp	Sat Dec 03 17:19:43 2011 +0000
@@ -0,0 +1,955 @@
+/*
+ *  midiEventHolder.cpp
+ *  midiCannamReader3
+ *
+ *  Created by Andrew on 19/07/2011.
+ *  Copyright 2011 QMUL. All rights reserved.
+ *
+ */
+
+#include "midiEventHolder.h"
+
+midiEventHolder::midiEventHolder(){
+//	recordedNoteOnIndex = 0;
+	
+	useTempoPrior = false;//puts sine wave round tempo
+	confidenceWeightingUsed = true;
+	
+	//there is option to use MAP estinate or integral in beayesianarraystricture class
+	
+	runningInRealTime = true;
+	bayesStruct.realTimeMode = &runningInRealTime;
+	
+	minimumMatchSpeed = 0.0;
+	maximumMatchSpeed = 2.0;
+	minimumTimeIntervalForTempoUpdate = 150;
+	
+	width = ofGetWidth();
+	height = ofGetHeight();
+	screenWidth= &width;
+	screenHeight = &height;
+	
+	ticksPerScreen = 4000;
+	tickLocation = 0;
+	pulsesPerQuarternote = 240;
+	noteArrayIndex = 0;
+	noteMinimum = 30;
+	noteMaximum = 96;
+
+
+
+	likelihoodWidth = 100;//using 100 is good
+	likelihoodToNoiseRatio = 0.08;//was 0.02 on 18/11/11, changing to give more weight to observations
+	
+	bayesStruct.speedLikelihoodNoise = 0.1;//was 0.05
+	bayesStruct.speedDecayWidth = 20;
+	bayesStruct.speedDecayAmount = 10;
+	
+
+	
+	speedPriorValue = 1.0;
+	
+	matchWindowWidth = 12000;//window size for matching in ms 
+	
+	bayesStruct.resetSize(matchWindowWidth);
+	bayesStruct.setPositionDistributionScalar(1);
+	
+	bayesStruct.resetSpeedSize(200);
+	bayesStruct.setRelativeSpeedScalar(0.01);
+	bayesStruct.relativeSpeedPrior.getMaximum();
+	//bayesStruct.simpleExample();
+	
+	
+	speedWindowWidthMillis = 4000;
+	speedPriorValue = 1.0;
+	noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum);
+	
+
+	
+	drawPhaseMode = true;
+	
+	printf("lookup index %f value %f\n", bayesStruct.prior.getLookupIndex(100, 30., 10.0), bayesStruct.prior.gaussianLookupTable[(int)bayesStruct.prior.getLookupIndex(100, 30., 10.0)]);
+}
+
+
+
+void midiEventHolder::reset(){
+	//called when we start playing
+	
+	noteArrayIndex = 0;
+	tickLocation = 0;
+	lastPeriodUpdateTime = getTimeNow(0);//ofGetElapsedTimeMillis();
+	bayesStruct.lastEventTime = getTimeNow(0);//ofGetElapsedTimeMillis();
+	numberOfScreensIn = 0;
+//	recordedNoteOnIndex = 0;
+	bayesStruct.setNewDistributionOffsets(0);
+	bayesStruct.posterior.offset = 0;
+	
+	playedEventTimes.clear();
+	playedNoteOnMatrix.clear();
+	matchMatrix.clear();
+	bestMatchIndex = 0;
+	
+	bayesStruct.resetSpeedToOne();
+	bayesStruct.setSpeedPrior(speedPriorValue);
+	setMatchedNotesBackToFalse();
+}
+
+void midiEventHolder::setMatchedNotesBackToFalse(){
+	for (int i = 0;i < noteOnMatches.size();i++)
+		noteOnMatches[i] = false;
+}
+
+void midiEventHolder::clearAllEvents(){
+	recordedNoteOnMatrix.clear();
+	matchesFound.clear();
+	noteOnMatches.clear();
+	recordedEventTimes.clear();
+	
+	//played events:
+	playedEventTimes.clear();
+	playedNoteOnMatrix.clear();
+	matchMatrix.clear();
+	bestMatchFound.clear();
+}
+
+void midiEventHolder::printNotes(){
+	printf("RECORDED MATRIX\n");
+	for (int i = 0;i < recordedNoteOnMatrix.size();i++){
+		printf("ticktime %i :: pitch %i @ millis %f\n", recordedNoteOnMatrix[i][0], recordedNoteOnMatrix[i][1], recordedEventTimes[i]);
+	}
+}
+
+
+double midiEventHolder::getEventTimeTicks(double millis){
+	return (millis * pulsesPerQuarternote / period);
+}
+
+double midiEventHolder::getEventTimeMillis(double ticks){
+	return (period * ticks / (double) pulsesPerQuarternote);
+}
+
+void midiEventHolder::newNoteOnEvent(int pitch, int velocity, double timePlayed){
+//	tempoSpeedString = "";
+	
+	//MOVE INTO BAYESSTRUCT?? XXX
+	//bayesStruct.copyPriorToPosterior();
+	//why was this here??
+	bayesStruct.prior.copyFromDynamicVector(bayesStruct.posterior);//try the otehr way
+	//bayesStruct.copyPriorToPosterior();
+	//need to get new MAP position and set the offset of the arrays
+	//currently bestEstimate is the approx for the new MAP position
+	
+	
+	//add the new event to our played information matrix
+	IntVector v;
+	v.push_back(pitch);
+	v.push_back(velocity);
+	playedNoteOnMatrix.push_back(v);
+
+	
+	//would update the arrays at this point to show where out current location (phase) and tempo is.
+//	double timeNow = ofGetElapsedTimeMillis() - startTime;
+	double timeNow = timePlayed;// - startTime;
+	recentNoteOnTime = timePlayed;
+	
+//	printf("Max time %f OF time %f \n", timePlayed, timeNow);
+	
+	playedEventTimes.push_back(timePlayed);
+	
+//	double timeDifference = ofGetElapsedTimeMillis() - bayesStruct.lastEventTime; 
+	double timeDifference = timePlayed - bayesStruct.lastEventTime; 
+	
+	
+	
+	//printf("note %i played at %f and last event %f time difference %f and current best estmate %f\n", pitch, timePlayed, bayesStruct.lastEventTime, timeDifference, bayesStruct.bestEstimate);
+
+	//addnoise to the tempo distribution
+	//bayesStruct.decaySpeedDistribution(timeDifference);
+	if (timeDifference > 50){
+	bayesStruct.addGaussianNoiseToSpeedPosterior(timeDifference * 10 / 100.);
+//	bayesStruct.addTriangularNoiseToSpeedPosterior(timeDifference * 10 / 100.);
+	}
+	
+	bayesStruct.updateTmpBestEstimate(timeDifference);// debug - didnt work	bayesStruct.bestEstimate = bayesStruct.tmpBestEstimate;
+	bayesStruct.updateBestEstimate(timeDifference);
+	bayesStruct.lastBestEstimateUpdateTime = getTimeNow(timePlayed);
+	
+//	double newMAPestimateTime = bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate);
+	//was offset + bayesStruct.posterior.MAPestimate; but this doesnt include scalar to convert to millis
+
+	timeString = "Pitch:"+ofToString(pitch);
+	timeString += ", time now:"+ofToString(timeNow, 1);
+	timeString += "  TD "+ofToString(timeDifference, 1);
+	timeString += "  offset "+ofToString(bayesStruct.posterior.offset , 0);
+	timeString += " map Est: "+ofToString(bayesStruct.posterior.MAPestimate, 0); 
+//	timeString += " Previous time" + ofToString(newMAPestimateTime,0);
+	timeString += " speedMap "+ofToString(bayesStruct.relativeSpeedPosterior.integratedEstimate, 2);
+	timeString += " :: "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.integratedEstimate), 2);
+	
+//	newMAPestimateTime += (timeDifference * bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
+//	timeString += " :  Predicted MAP time" + ofToString(newMAPestimateTime,0);
+
+	//then we recalculate the window start based on MAP being central
+	//then we do the matches on these and the likelihood on these.
+	
+	bayesStruct.setNewDistributionOffsets(max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)));
+//	bayesStruct.prior.offset = max(0.,newMAPestimateTime - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));
+	
+	timeString += " \n :  new offset " + ofToString(bayesStruct.prior.offset , 0);
+	timeString += " \n best estimate "+ofToString(bayesStruct.bestEstimate, 1);
+	timeString += " error "+ofToString(minimumMatchError, 0);
+	timeString += " map "+ofToString(bayesStruct.relativeSpeedPosterior.integratedEstimate, 1);
+	timeString += " rel speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.integratedEstimate), 2);
+	
+	
+	//be able to draw the prior in correct location relative to the midi notes
+	//this calculates the cross update of all possible speeds and all possible positions
+	bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, timeDifference);
+
+	
+	timeString += " new OFF "+ofToString(bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2), 1);
+	timeString += " notearrayindex "+ofToString(noteArrayIndex, 0);
+	//when this is off teh screen there is a problem somehow XXX
+	
+	bayesStruct.posterior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));//	bayesStruct.prior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));
+
+	//trying to switch to prior
+	
+	
+	bayesStruct.lastEventTime = timePlayed;//bayesStruct.lastEventTime = ofGetElapsedTimeMillis();
+	
+	//do the cross update to find current posterior for location
+//	totalConfidence= 0;
+	int numberOfMatchesFound = findLocalMatches(pitch);
+	setMatchLikelihoods(numberOfMatchesFound);
+	bayesStruct.calculatePosterior();
+	
+	//having found matches we have matches for new note and matches for previous notes
+	if (!confidenceWeightingUsed)
+	findLocalTempoPairs();
+	else
+	findLocalTempoPairsWeightedForConfidence();
+	
+	//bayesStruct.addGaussianNoiseToSpeedPosterior(10);
+	 
+}
+
+double midiEventHolder::getTimeNow(double eventTime){
+	double timeNow = eventTime;
+	if (runningInRealTime)
+		timeNow = ofGetElapsedTimeMillis();
+	return timeNow;
+}
+
+int midiEventHolder::findLocalMatches(int notePitch){
+
+	//here we find the matches to the new note within appropriate range
+		
+	matchString = "";
+	
+	windowStartTime = max(0.0,(bayesStruct.bestEstimate - matchWindowWidth/2));//was playPositionInMillis
+//	cout << "best estimate is " << bayesStruct.bestEstimate << endl;
+	int numberOfMatches = findMatch(notePitch, windowStartTime, windowStartTime + matchWindowWidth);
+
+	
+	//matchString += " pitch: "+ofToString(notePitch)+" matches "+ofToString(numberOfMatches)+" win start "+ofToString(windowStartTime);	
+	
+	return numberOfMatches;
+	
+	
+}
+
+
+void midiEventHolder::setMatchLikelihoods(int numberOfMatches){
+//reset the offset to match the prior
+	bayesStruct.likelihood.offset = bayesStruct.prior.offset;
+	bayesStruct.likelihood.zero();//set to zero
+	
+	double quantity = likelihoodToNoiseRatio / numberOfMatches;
+	
+	for (int i = 0;i < numberOfMatches && matchesFound[i] >= 0 && matchesFound[i] < recordedEventTimes.size();i++){
+	//	printf("match times %i of %i::%f adding likelihood to %f\n", i, numberOfMatches, recordedEventTimes[matchesFound[i]], recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset);
+		//this is the vent time since start of file
+		if (recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset < bayesStruct.likelihood.arraySize){
+	//		double confidenceMeasure = 0;
+	//		if (totalConfidence > 0)
+	//			confidenceMeasure =	bayesStruct.posterior.getValueAtMillis(recordedEventTimes[matchesFound[i]])/totalConfidence;
+			
+			bayesStruct.likelihood.addGaussianShape(recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset, likelihoodWidth,  quantity);//* confidenceMeasure
+		}//end if
+	}
+	bayesStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesStruct.likelihood.length);
+}
+
+int midiEventHolder::findMatch(const int& notePitch, const int& startTime, const int& endTime){
+
+	matchesFound.clear();
+	int startIndex = 0;
+
+	if (recordedEventTimes.size() > 0){
+	
+		//get to the right range of events to check in
+		while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < startTime)
+			startIndex++;
+		   
+		}
+
+	IntVector v;
+	DoubleVector d;
+	double tmpError = 100000.;//v high error
+	
+	double minimumConfidence = 0;
+	while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < endTime){
+		if (recordedNoteOnMatrix[startIndex][1] == notePitch){
+			
+			matchesFound.push_back(startIndex);
+			v.push_back(startIndex);
+			//so startIndex is registered as a match
+			
+			double eventConfidence = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[startIndex]);
+				if (eventConfidence > minimumConfidence){
+					minimumConfidence = eventConfidence;
+					bestMatchIndex = startIndex;
+				}
+			d.push_back(eventConfidence);
+			
+			double confidence = eventConfidence;//bayesStruct.posterior.getValueAtMillis(mouseX);
+	//																   recordedEventTimes[startIndex]);
+	//		matchString += "["+ofToString(startIndex)+"] = "+ofToString(confidence, 3)+" .";
+			
+			if (abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate) < tmpError){
+				//record the error between expected and observed times
+				tmpError = abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate);
+				minimumMatchError = tmpError;//recordedEventTimes[startIndex] - bayesStruct.bestEstimate;
+			}
+			
+		}
+		startIndex++;
+	}
+	
+
+//	printf("%i MATCHES TO Note %i found\n", (int)matchesFound.size(), notePitch);
+	int size = matchesFound.size();
+		if (size > 0)
+		noteOnMatches[bestMatchIndex] = true;
+	
+	v.insert(v.begin() , (int)size);//at beginning, we list how many matches there are that we have found
+	d.insert(d.begin() , (double)size);
+	
+	//v.push_back(size);
+	//d.push_back(size);
+	//for (int i = 0;i < matchesFound.size()+1;i++){
+	//	v.push_back(matchesFound[i]);
+	//	printf("match %i,[%i] is %i\n", startIndex, i, v[i]);	
+	//}
+	 
+	
+	matchMatrix.push_back(v);
+	matchConfidence.push_back(d);
+	
+	//bringing in way to list only the best matches and use these in tempo process
+	bestMatchFound.push_back(bestMatchIndex);
+	
+//	printf("BEST MATCH TO note %i, start time %i, endtime %i, time %i is recorded time %i, confidence %0.2f\n", notePitch, startTime, endTime, (int) recordedEventTimes[bestMatchIndex], minimumConfidence);
+	
+	return size;
+}
+
+bool midiEventHolder::checkIfMatchedNote(const int& tmpIndex){
+	for (int i = 0;i < matchesFound.size();i++){
+	if (matchesFound[i] == tmpIndex)
+		return true;
+	}
+	return false;
+}
+
+
+
+void midiEventHolder::findLocalTempoPairs(){
+	
+	int currentPlayedIndex = playedNoteOnMatrix.size()-1;
+	//	printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]);
+	//	printMatchesFound();
+	//	printMatchMatrix();
+	//	printf("possible notes \n");
+	bool needToUpdate = false;
+	bayesStruct.setLikelihoodToConstant();
+	
+	
+	for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){
+		//iterate through the recently matched events - even dodgy matches included
+		//size, index of match0, index of match1, ....
+		
+		
+		int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1];
+		
+		int previousIndex = currentPlayedIndex-1;
+
+		
+		while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) {
+			double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
+			
+			for (int k = 0;k < matchMatrix[previousIndex][0];k++){
+				
+				int recordedPreviousIndex = matchMatrix[previousIndex][k+1];
+				
+				double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex];
+				
+				
+				//we want the speed of the recording relative to that of the playing live
+				
+				double speedRatio = recordedTimeDifference / playedTimeDifference;
+				if (recordedTimeDifference > minimumTimeIntervalForTempoUpdate &&
+					speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){
+					
+					//adding in a prior that prefers 1
+					double priorWeighting = 1;
+					if (useTempoPrior)
+						priorWeighting = sin(speedRatio * PI/2);
+					
+					
+					
+					/*
+					 printf("(%i)", matchMatrix[currentPlayedIndex][i+1]);
+					 printf("[%i] :: ", recordedPreviousIndex);
+					 printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference);
+					 printf("update on speed ratio %f\n", speedRatio);
+					 */
+					//	matchString += " speed: "+ofToString(speedRatio, 3);
+					//	commented for debug
+					
+					//bayesStruct.updateTempoDistribution(speedRatio, 0.1);//second paramter is confidence in the match
+					double amount =	(1-bayesStruct.speedLikelihoodNoise)/10;
+					amount *= priorWeighting;
+					bayesStruct.updateTempoLikelihood(speedRatio, amount);
+				//	tempoSpeedString += ofToString(recordedPreviousIndex) + "  "+ ofToString(speedRatio, 2) + "  "+ofToString(amount, 2) += " \n";
+					needToUpdate = true;
+				}
+				//		printf("\n");	
+			}
+			
+			previousIndex--;
+		}//end while previousindex countdown
+	}//end for loop through possible current matches
+	
+	if (needToUpdate)
+		bayesStruct.updateTempoDistribution();
+	
+	//printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
+}
+
+
+void midiEventHolder::findLocalTempoPairsWeightedForConfidence(){
+	bool needToUpdate = false;
+	
+	DoubleVector speedIntervalsFound;
+	
+	//adapted this to just use the best match for each note
+	
+	int currentPlayedIndex = playedNoteOnMatrix.size()-1;
+	//	printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]);
+	//	printMatchesFound();
+	//	printMatchMatrix();
+	//	printf("possible notes \n");
+	
+	bayesStruct.setLikelihoodToConstant();
+	
+	int recordedCurrentIndex = bestMatchFound[currentPlayedIndex];
+	//we only look at intervals between the current best match and other recent best matched notes
+	//that is the difference in confidence method
+	
+	
+		//printf("BEST MATCH FOUND for index %i is %i ", currentPlayedIndex, bestMatchFound[currentPlayedIndex]);
+	
+		int previousIndex = currentPlayedIndex-1;
+		
+		//withing speedwindow i.e. 4 seconds
+		while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) {
+			double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
+
+			int recordedPreviousIndex = bestMatchFound[previousIndex];
+			
+			double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex];
+				
+				
+				//we want the speed of the recording relative to that of the playing live
+				
+				double speedRatio = recordedTimeDifference / playedTimeDifference;
+				if (recordedTimeDifference > minimumTimeIntervalForTempoUpdate
+					&& speedRatio < maximumMatchSpeed && speedRatio > minimumMatchSpeed){
+					
+			/*		 printf("(%i)", previousIndex);
+					 printf("[%i] :: ", recordedPreviousIndex);
+				//	printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence);
+					printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference);
+					 printf("update on speed ratio %f\n", speedRatio);
+				*/	 
+					//	matchString += " speed: "+ofToString(speedRatio, 3);
+					//	commented for debug
+					
+					
+					double priorWeighting = 1;
+					
+					if (useTempoPrior)
+						priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed
+					
+					
+				//	double weighting = previousMatchConfidence * currentMatchConfidence ;
+					double amount =	(1-bayesStruct.speedLikelihoodNoise)*priorWeighting/16;//was 9
+					
+					speedIntervalsFound.push_back(speedRatio);
+		//			bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match
+					
+			//		tempoSpeedString += ofToString(recordedCurrentIndex) + " :: " + ofToString(recordedPreviousIndex);
+			//		tempoSpeedString += "  " + ofToString(recordedTimeDifference)+ "  " + ofToString(speedRatio, 2) + "  "+ofToString(amount, 2) += " \n";
+					
+					needToUpdate = true;
+				}
+				//		printf("\n");	
+			
+			
+			previousIndex--;
+		}//end while previousindex countdown
+	
+	if (speedIntervalsFound.size() > 0){
+		double amount = (1 - bayesStruct.speedLikelihoodNoise) / speedIntervalsFound.size();
+		for (int i = 0;i < speedIntervalsFound.size();i++)
+		bayesStruct.updateTempoLikelihood(speedIntervalsFound[i], amount);
+	}
+	
+	
+	if (needToUpdate)
+		bayesStruct.updateTempoDistribution();
+	//printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
+}
+
+/*
+void midiEventHolder::findLocalTempoPairsWeightedForConfidence(){
+	bool needToUpdate = false;
+	
+	//adapted this to just use the best match for each note
+	
+	int currentPlayedIndex = playedNoteOnMatrix.size()-1;
+	//	printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]);
+	//	printMatchesFound();
+	//	printMatchMatrix();
+	//	printf("possible notes \n");
+	
+	bayesStruct.setLikelihoodToConstant();
+	
+	for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){
+		
+		//iterate through the recently matched events - even dodgy matches included
+		//size, index of match0, index of match1, ....
+		int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1];
+		
+		double currentMatchConfidence = matchConfidence[currentPlayedIndex][i+1];//new confidence
+		
+		int previousIndex = currentPlayedIndex-1;
+		
+		while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) {
+			double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
+			
+			//			for (int k = 0;k < matchMatrix[previousIndex][0];k++)
+			int recordedPreviousIndex = bestMatchFound[previousIndex];//matchMatrix[previousIndex][k+1];
+			
+			//double previousMatchConfidence = matchConfidence[previousIndex][k+1];
+			
+			
+			double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex];
+			
+			
+			//we want the speed of the recording relative to that of the playing live
+			
+			double speedRatio = recordedTimeDifference / playedTimeDifference;
+			if (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){
+				
+				printf("(%i)", matchMatrix[currentPlayedIndex][i+1]);
+				printf("[%i] :: ", recordedPreviousIndex);
+				//	printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence);
+				printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference);
+				printf("update on speed ratio %f\n", speedRatio);
+				
+				//	matchString += " speed: "+ofToString(speedRatio, 3);
+				//	commented for debug
+				
+				
+				double priorWeighting = 1;
+				
+				if (useTempoPrior)
+					priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed
+				
+				
+				//	double weighting = previousMatchConfidence * currentMatchConfidence ;
+				double amount =	(1-bayesStruct.speedLikelihoodNoise)*priorWeighting/10;
+				bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match
+				tempoSpeedString += ofToString(recordedPreviousIndex) + "  " + ofToString(speedRatio, 2) + "  "+ofToString(amount, 2) += " \n";
+				
+				needToUpdate = true;
+			}
+			//		printf("\n");	
+			
+			
+			previousIndex--;
+		}//end while previousindex countdown
+	}//end for loop through possible current matches
+	
+	if (needToUpdate)
+		bayesStruct.updateTempoDistribution();
+	//printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
+}
+*/
+
+
+void midiEventHolder::updatePlayPosition(){
+	
+	//in actual fact if we are changing the speed of the play position 
+	//we will need to update this via the file
+	
+	//actually time since beginning of file i think
+	
+	double timeDifference = 0;
+	if (runningInRealTime)
+		timeDifference = ofGetElapsedTimeMillis() - lastPeriodUpdateTime;//elpased - lastperiodupdatetime
+	
+	//this is time diff in milliseconds
+	//then we have 
+	double quarterNoteIntervals = (timeDifference / period);
+	tickLocation = quarterNoteIntervals * pulsesPerQuarternote; 
+	
+	playPositionInMillis = timeDifference;//based on updating from when we change period
+	//this to be added
+	
+	if (runningInRealTime)
+	bayesStruct.updateBestEstimate(timeDifference);
+	
+}
+
+
+void midiEventHolder::drawMidiFile(){
+	
+	//draws midi file on scrolling screen
+	int size = recordedNoteOnMatrix.size();
+	if (size > 0){
+		
+		numberOfScreensIn = floor(bayesStruct.bestEstimate / getEventTimeMillis(ticksPerScreen));//rpounds down on no screens in
+		
+		//	numberOfScreensIn = tickLocation / ticksPerScreen;//rounds down
+		timeOffsetForScreen = getEventTimeMillis(numberOfScreensIn * ticksPerScreen);
+		
+		while (noteArrayIndex < recordedNoteOnMatrix.size()-1 && tickLocation > recordedNoteOnMatrix[noteArrayIndex][0] )
+			noteArrayIndex++;
+		
+		
+		while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < recordedNoteOnMatrix[noteArrayIndex][0])
+			noteArrayIndex--;
+		
+		//need to start where we currently are in file
+		int maxNoteIndexToPrint	= noteArrayIndex;
+		int minNoteIndexToPrint = min(size-1,noteArrayIndex);//not needed as changed above
+		
+		while (maxNoteIndexToPrint < recordedNoteOnMatrix.size() && recordedNoteOnMatrix[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen )
+			maxNoteIndexToPrint++;
+		
+		while (minNoteIndexToPrint > 0 && recordedNoteOnMatrix[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen)//&& minNoteIndexToPrint < size 
+			minNoteIndexToPrint--;
+		
+		for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)recordedNoteOnMatrix.size());tmpIndex++){
+			
+			ofSetColor(255,255,255);
+			if (checkIfMatchedNote(tmpIndex))
+				ofSetColor(100,100,100);//0,0,255);
+			else if(noteOnMatches[tmpIndex]){
+				ofSetColor(255,0,255);//dark grey
+			}
+			else{
+				ofSetColor(255,255,255);//255,255,255);
+			}
+			
+			//ofSetColor(255,255,255);
+			if (tmpIndex == bestMatchIndex)
+				ofSetColor(255,0,0);//best recent match is in red
+			
+			//		 XXX replace ofgetwidth below
+			//if (tmpIndex >= 0 && tmpIndex < size)
+			int xLocation = (float)(recordedNoteOnMatrix[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen;
+			int duration = (float)(recordedNoteOnMatrix[tmpIndex][3]*(*screenWidth))/(float)ticksPerScreen;
+			
+			
+			int yLocation = (*screenHeight) - ((recordedNoteOnMatrix[tmpIndex][1] - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum));						 
+			ofRect(xLocation,yLocation, duration,  noteHeight);
+			
+		}
+		
+		
+		int xLocation;// = getLocationFromTicks(tickLocation);
+		//	ofLine(xLocation, 0, xLocation, (*screenHeight));
+		
+		//orange line at best estimate
+		xLocation = getLocationFromMillis(bayesStruct.bestEstimate);
+		ofSetColor(80,80,80);//250,100,0);
+		ofLine(xLocation, 0, xLocation, (*screenHeight));
+		
+		xLocation = getLocationFromMillis(bayesStruct.tmpBestEstimate);
+		ofSetColor(150,150,150);//250,100,0);
+		ofLine(xLocation, 0, xLocation, (*screenHeight));
+		
+		
+		//lines where matching window start and end are 
+		ofSetColor(0);//0,100,255);
+		xLocation = getLocationFromMillis(windowStartTime);
+		ofLine(xLocation, 0, xLocation, (*screenHeight));
+		xLocation = getLocationFromMillis(windowStartTime+matchWindowWidth);
+		ofLine(xLocation, 0, xLocation, (*screenHeight));
+		
+		
+		int maxSize = recordedNoteOnMatrix[size-1][0];
+		
+	//	ofDrawBitmapString(tempoSpeedString, 20, 20);
+	/*	string indexString = "num screens in "+ofToString(numberOfScreensIn)+"; min index to print "+ofToString(minNoteIndexToPrint)+", max index to print "+ofToString(maxNoteIndexToPrint);
+		indexString += " size "+ofToString(size)+" tick loc "+ofToString(tickLocation)+" max size "+ofToString(maxSize);
+		ofDrawBitmapString(indexString, 20, 40);
+	 */
+	}	
+	
+	//ofDrawBitmapString(ofToString(timeOffsetForScreen, 1), 20,20);
+	
+	//ofDrawBitmapString(timeString, 20, 60);
+	
+
+}
+
+
+
+void midiEventHolder::drawMidiFile(IntMatrix& midiFileToDraw){
+	
+	//draws midi file on scrolling screen
+	int size = midiFileToDraw.size();
+	if (size > 0){
+		
+		numberOfScreensIn = floor(bayesStruct.bestEstimate / getEventTimeMillis(ticksPerScreen));//rpounds down on no screens in
+		
+		//	numberOfScreensIn = tickLocation / ticksPerScreen;//rounds down
+		timeOffsetForScreen = getEventTimeMillis(numberOfScreensIn * ticksPerScreen);
+		
+		while (noteArrayIndex < midiFileToDraw.size()-1 && tickLocation > midiFileToDraw[noteArrayIndex][0] )
+			noteArrayIndex++;
+		
+		
+		while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < midiFileToDraw[noteArrayIndex][0])
+			noteArrayIndex--;
+		
+		//need to start where we currently are in file
+		int maxNoteIndexToPrint	= noteArrayIndex;
+		int minNoteIndexToPrint = min(size-1,noteArrayIndex);//not needed as changed above
+		
+		while (maxNoteIndexToPrint < midiFileToDraw.size() && midiFileToDraw[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen )
+			maxNoteIndexToPrint++;
+		
+		while (minNoteIndexToPrint > 0 && midiFileToDraw[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen)//&& minNoteIndexToPrint < size 
+			minNoteIndexToPrint--;
+		
+		for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)midiFileToDraw.size());tmpIndex++){
+			
+			ofSetColor(255,0,255);
+	/*
+	 if (checkIfMatchedNote(tmpIndex))
+				ofSetColor(100,100,100);//0,0,255);
+			else if(noteOnMatches[tmpIndex]){
+				ofSetColor(255,0,255);//dark grey
+			}
+			else{
+				ofSetColor(255,255,255);//255,255,255);
+			}
+			*/
+			//ofSetColor(255,255,255);
+			if (tmpIndex == bestMatchIndex)
+				ofSetColor(255,0,0);//best recent match is in red
+			
+			//		 XXX replace ofgetwidth below
+			//if (tmpIndex >= 0 && tmpIndex < size)
+			int xLocation = (float)(midiFileToDraw[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen;
+			int duration = (float)(midiFileToDraw[tmpIndex][3]*(*screenWidth))/(float)ticksPerScreen;
+			
+			
+			int yLocation = (*screenHeight) - ((midiFileToDraw[tmpIndex][1] - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum));						 
+			ofRect(xLocation,yLocation, duration,  noteHeight);
+			
+		}
+		
+		
+
+	}	
+	
+	
+	
+}
+
+
+
+void midiEventHolder::drawFile(){	
+		drawMidiFile();
+		
+	
+//	bayesStruct.drawArrays();
+	
+//	ofSetColor(200,200,0);
+//	bayesStruct.prior.drawConstrainedVector(0, bayesStruct.prior.arraySize, 400, 800);
+	
+	//need to draw arrays within correct timescope
+	if (drawPhaseMode)
+	bayesStruct.drawArraysRelativeToTimeframe(timeOffsetForScreen, timeOffsetForScreen + getEventTimeMillis(ticksPerScreen));
+	
+	if (drawTempoMode)
+	bayesStruct.drawTempoArrays();
+	
+	
+	ofSetColor(0, 0, 0);
+	//ofDrawBitmapString(matchString, 20, ofGetHeight() - 20);
+	
+	double confidence = bayesStruct.posterior.getValueAtMillis(mouseX);
+/*
+ string mouseString = "mouseX "+ofToString(confidence, 3)+" .";
+	ofDrawBitmapString(mouseString, 20 ,  ofGetHeight() - 40);
+	
+	string mouseString = "updateCounter "+ofToString(bayesStruct.updateCounter);
+	ofDrawBitmapString(mouseString, 20 ,  ofGetHeight() - 40);
+	
+	string infostring = "speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 3);
+	ofDrawBitmapString(infostring, 20 ,  ofGetHeight() - 60);							   
+*/
+ }
+
+int midiEventHolder::getLocationFromTicks(double tickPosition){
+	return (int)((float)(tickPosition - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen);
+}
+
+int midiEventHolder::getLocationFromMillis(double millisPosition){
+	//(getEventTimeTicks(windowStartTime+matchWindowWidth) - numberOfScreensIn*ticksPerScreen)*(*screenWidth) / (double)ticksPerScreen
+	return (millisPosition - timeOffsetForScreen)*(*screenWidth)/getEventTimeMillis(ticksPerScreen);
+}
+
+
+void midiEventHolder::exampleCrossUpdate(){
+	
+	bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, 200);
+	
+}
+
+
+void midiEventHolder::setStartPlayingTimes(){
+	lastPeriodUpdateTime = getTimeNow(0);//ofGetElapsedTimeMillis();
+	startTime = lastPeriodUpdateTime;
+	
+/*	
+ 	bayesStruct.lastEventTime = 0;//ofGetElapsedTimeMillis();
+	bayesStruct.bestEstimate = 0;
+	bayesStruct.resetArrays();
+	bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
+*/
+	bayesStruct.setStartPlaying();
+	matchString = "";
+}
+
+
+void midiEventHolder::printMatchMatrix(){
+	printf("match matrix:\n");
+	for (int i = 0;i < matchMatrix.size();i++){
+		for (int k = 0;k < matchMatrix[i].size();k++){
+			printf("%i , ", matchMatrix[i][k]);
+		}
+		printf("\n");
+	}
+	
+}
+
+
+
+void midiEventHolder::printRecordedEvents(){
+	printf("Recorded Events:\n");
+	for (int i = 0;i < recordedNoteOnMatrix.size();i++){
+		for (int k = 0;k < recordedNoteOnMatrix[i].size();k++){
+			printf("[%i] = %i ,", i, recordedNoteOnMatrix[i][k]);
+		}
+		if (i < recordedEventTimes.size())
+			printf("time %f \n", recordedEventTimes[i]);
+		else
+			printf("\n");
+	}
+	
+}
+
+
+
+void midiEventHolder::reorderMatrixFromNoteTimes(IntMatrix& noteOnMatrix){
+	double currentTime = -19999.;
+	for (int i = 0;i < noteOnMatrix.size();i++){
+		int nextIndex = getIndexOfMinimumAboveTime(currentTime, noteOnMatrix);
+	//	cout << "index of min time " << currentTime << " is " << nextIndex << " at time " <<  noteOnMatrix[nextIndex][0] << endl;
+	
+		if (nextIndex >= 0 && nextIndex > i &&	noteOnMatrix[nextIndex][0] < noteOnMatrix[i][0] ){
+			//which it should be
+	//		cout << " index " << nextIndex << " at time " << noteOnMatrix[nextIndex][0] << " swaps with inex " << i << " at time  " << noteOnMatrix[i][0] << endl; 
+			noteOnMatrix[i].swap(noteOnMatrix[nextIndex]);
+			currentTime = noteOnMatrix[i][0];
+		}
+		
+	}	
+		
+	//printRecordedEvents();
+
+}
+
+
+
+
+void midiEventHolder::doublecheckOrder(IntMatrix& noteOnMatrix){
+
+	for (int i = 0;i < noteOnMatrix.size();i++){
+		int nextIndex = getIndexOfMinimumAboveIndex(i, noteOnMatrix);
+		if (nextIndex > i){
+			noteOnMatrix[i].swap(noteOnMatrix[nextIndex]);
+		}
+	}	
+}
+
+int midiEventHolder::getIndexOfMinimumAboveIndex(const int& index, IntMatrix& noteOnMatrix){
+	int returnIndex = index;
+	int min = noteOnMatrix[index][0];
+	for (int i = index;i < noteOnMatrix.size();i++){
+		if (noteOnMatrix[i][0] < min){
+			returnIndex = i;
+			min = noteOnMatrix[i][0];
+		}
+	}
+	return returnIndex;
+}
+
+
+int midiEventHolder::getIndexOfMinimumAboveTime(const double& time, IntMatrix& noteOnMatrix){
+	int index = 0;
+	double minimumTime = 100000000.;
+	int bestIndex = -1;
+	while (index < noteOnMatrix.size()){
+	
+		if (noteOnMatrix[index][0] > time && noteOnMatrix[index][0] < minimumTime){
+			bestIndex = index;
+			minimumTime = noteOnMatrix[index][0];
+		}
+			index++;
+	}
+	return bestIndex;
+}
+
+
+void midiEventHolder::correctTiming(IntMatrix& noteOnMatrix){
+	
+	if (noteOnMatrix.size() > 0 && noteOnMatrix[0][0] < 0) {
+		int offset = noteOnMatrix[0][0];
+		for (int i = 0;i < noteOnMatrix.size();i++){
+			noteOnMatrix[i][0] -= offset;
+		}	
+	}
+
+}