view jnmr/midiEventHolder.cpp @ 36:5a1b0c6fa1fb

Added class to read in the csv Annotation file, then write out the respective difference between the performed piece as followed here, and the annotation of RWC by Ewert and Muller
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Thu, 15 Dec 2011 02:28:49 +0000
parents 6cd3e0075adf
children 795a99987875
line wrap: on
line source
/*
 *  midiEventHolder.cpp
 *  midiCannamReader3
 *
 *  Created by Andrew on 19/07/2011.
 *  Copyright 2011 QMUL. All rights reserved.
 *
 */


//Main file to look at here is newNoteEvent() - this calls everything else to update the Bayesian array

#include "midiEventHolder.h"

//#include <iostream>
//#include <fstream>

midiEventHolder::midiEventHolder(){
	
	myNotation.readInSomeValues();
	
//	recordedNoteOnIndex = 0;
	alignmentPosition = 0;
	
	useTempoPrior = false;//puts sine wave round tempo
	confidenceWeightingUsed = true;
	newOptimalMethod = true;
	
	matchWindowWidth = 16000;//window size for matching in ms 
	interNoteRange = 1600;//preferred duration
	//so max here is really four
	
	
	likelihoodWidth = 100;//using 100 is good
	likelihoodToNoiseRatio = 0.20;//was 0.02 on 18/11/11, changing to give more weight to observations
									//was 0.08 on 11/12/11 but need more for tempo varn in rwc database
	
	bayesStruct.speedLikelihoodNoise = 0.1;//was 0.05
	bayesStruct.speedDecayWidth = 40;
	bayesStruct.speedDecayAmount = 10;
	
	
	//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;




	
	speedPriorValue = 1.0;
	
	
	bayesStruct.resetSize(matchWindowWidth);
	bayesStruct.setPositionDistributionScalar(1);
	
	bayesStruct.resetSpeedSize(200);
	bayesStruct.setRelativeSpeedScalar(0.01);
	bayesStruct.relativeSpeedPrior.getMaximum();
	//bayesStruct.simpleExample();
	
	
	speedWindowWidthMillis =  1600;//4000

	noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum);
	

	intervalsToCheck.push_back(1);
	intervalsToCheck.push_back(2);
	//intervalsToCheck.push_back(3);
	intervalsToCheck.push_back(4);
	intervalsToCheck.push_back(6);
	intervalsToCheck.push_back(8);
	intervalsToCheck.push_back(16);

	
	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;
	startPlayingTime = 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;
	
	recordedTotalNoteCounterByPitch.clear();
	recordedTotalNoteCounterByPitch.assign(127,0);
	totalNoteCounterIndex = 0;

	interNoteIntervals.clear();
	
	smoothIndex = 0;
	smoothPlayPosition = 0.0;
//	relativeSpeedForSmooth = 1.0;
//	storedSmoothPlayPosition = smoothPlayPosition;
//	lastSmoothUpdateTime = getTimeNow(0);
	
	printf("reset speed prior is %f\n", speedPriorValue);
	bayesStruct.resetSpeedToOne();
	bayesStruct.setSpeedPrior(speedPriorValue);
	setMatchedNotesBackToFalse();

	periodCounter = 0;
	for (int i = 0;i < periodValues.size();i++){
	//	printf("period at %f is %f\n", periodValues[i][2], periodValues[i][1]);
	}
/*	if (periodValues.size() > 0){
		updatePeriodValue(0);// periodValues[0][2];
		printf("Resetting period to %f , size is %i\n", period,  (int)periodValues.size());
	}
*/
	//period = 500.0;
}

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();
	measureVector.clear();
	//played events:
	playedEventTimes.clear();
	playedNoteOnMatrix.clear();
	matchMatrix.clear();
	bestMatchFound.clear();
	periodValues.clear();
	
	beatPositions.clear();
	
	recordedTotalNoteCounterByPitch.clear();
	recordedTotalNoteCounterByPitch.assign(127, 0);
	totalNoteCounterIndex = 0;
}

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 0.0;
	//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
	
	lastPlayedPitch = pitch;
	//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.0 / 100.);
//	bayesStruct.addTriangularNoiseToSpeedPosterior(timeDifference * 10 / 100.);
	}
	
//	bayesStruct.updateTmpBestEstimate(timeDifference);// debug - didnt work	bayesStruct.bestEstimate = bayesStruct.tmpBestEstimate;
	bayesStruct.updateBestEstimate(timeDifference);

	bayesStruct.lastBestEstimateUpdateTime = getTimeNow(timePlayed);
	//updatePeriodValue(bayesStruct.lastBestEstimateUpdateTime);

//	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();
	
	if (recordedEventTimes.size() > 0){
	updateTempo();
	//calcuateNewInterNoteIntervals();
	}
	
	//storedSmoothPlayPosition = smoothPlayPosition;
	 
}

void midiEventHolder::updateTempo(){
	//having found matches we have matches for new note and matches for previous notes
	if (newOptimalMethod)
		findOptimumTempoPairsToCurrentBestMatch();
	else 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));
}

double midiEventHolder::getBestSpeedEstimate(const int& currentPlayedIndex, const int& equivalentRecordedIndex){
	double estimate = 1.0;
	if (bestMatchIndex > 0){
	double accordingToFileLengthEstimate = recordedEventTimes[equivalentRecordedIndex] - recordedEventTimes[0];
		double playedEquivalent = (playedEventTimes[currentPlayedIndex] - playedEventTimes[0]);
		if (accordingToFileLengthEstimate > 0 && playedEquivalent > 0)
		accordingToFileLengthEstimate /= playedEquivalent;
		estimate = accordingToFileLengthEstimate;
	}
	return estimate;
}

void midiEventHolder::findOptimumTempoPairsToCurrentBestMatch(){
	bool needToUpdate = false;
	
	DoubleVector speedIntervalsFound;
	
	double currentSpeedEstimate = bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate);
	
	int currentPlayedIndex = playedNoteOnMatrix.size()-1;

	bayesStruct.setLikelihoodToConstant();
	
	int recordedCurrentIndex = bestMatchFound[currentPlayedIndex];
	//we only look at intervals between the current best match and other recent best matched notes
	
	//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;
		
		//now check if this can be closer the observed value
		int checkRecordedCurrentIndex = recordedCurrentIndex;
		int checkRecordedPreviousIndex ;//= recordedCurrentIndex;
		int currentPlayedPitch = playedNoteOnMatrix[currentPlayedIndex][1];
		int previousPlayedPitch = playedNoteOnMatrix[previousIndex][1];
		
		double recordedTimeOfBestMatch = recordedEventTimes[recordedCurrentIndex];
		
		//change this so we start first in window and go to end
		
		while (checkRecordedCurrentIndex >= 0 && recordedEventTimes[checkRecordedCurrentIndex] > recordedTimeOfBestMatch - matchWindowWidth){
			
			checkRecordedCurrentIndex--;
		}
		
		double bestSpeedEstimate = getBestSpeedEstimate(currentPlayedIndex, bestMatchIndex);
		
		while (checkRecordedCurrentIndex < recordedEventTimes.size() && recordedEventTimes[checkRecordedCurrentIndex] <  recordedTimeOfBestMatch + matchWindowWidth ){
			if (recordedNoteOnMatrix[checkRecordedCurrentIndex][1] == currentPlayedPitch ){
				checkRecordedPreviousIndex = checkRecordedCurrentIndex;
				double recordedTimeCurrent = recordedEventTimes[checkRecordedCurrentIndex] ;
				while (checkRecordedPreviousIndex >= 0 && recordedEventTimes[checkRecordedPreviousIndex] + maximumMatchSpeed*playedTimeDifference > recordedTimeCurrent ) {
					if (recordedNoteOnMatrix[checkRecordedPreviousIndex][1] == previousPlayedPitch){
					//we have a candidate
						double speedToTest = recordedEventTimes[checkRecordedCurrentIndex]  - recordedEventTimes[checkRecordedPreviousIndex];
						speedToTest /= playedTimeDifference;
						if (abs(speedToTest-currentSpeedEstimate) < abs(speedRatio - currentSpeedEstimate) ){
							speedRatio = speedToTest;
						}
					}
					checkRecordedPreviousIndex--;
				}
			}
			checkRecordedCurrentIndex++;
		}
		
		
		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::calcuateNewInterNoteIntervals(){
	DoubleVector v;
	
	int currentPlayedIndex = playedNoteOnMatrix.size()-1;
//	int recordedCurrentIndex = bestMatchFound[currentPlayedIndex];
	int previousIndex = currentPlayedIndex-1;
	
	//withing speedwindow i.e. 4 seconds
	while (previousIndex >= 0 && playedEventTimes[previousIndex] + interNoteRange > playedEventTimes[currentPlayedIndex]) {
		
		double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
		
		checkForCorrectInterval(playedTimeDifference, &v);
			
		previousIndex--;
	}
	
	if (v.size() > 0)
		interNoteIntervals.push_back(v);
	//printf("\n");
}

void midiEventHolder::checkForCorrectInterval(const double& playedTimeDifference, DoubleVector* v){
	double intervalDuration = 0.0;

	for (int intervalIndex = 0;intervalIndex < 3;intervalIndex++){
		//on;y check 1,2 and 4
		double possibleDuration = playedTimeDifference / intervalsToCheck[intervalIndex];
		if (possibleDuration >= 200 && possibleDuration < 400){
			v->push_back(possibleDuration);
		//	printf("int %f / %i :: %f  ", playedTimeDifference,  intervalsToCheck[intervalIndex], possibleDuration);
		}
	}
}


void midiEventHolder::updatePlayPosition(){
	//timeDifference = ofGetElapsedTimeMillis() - startPlayingTime;//elpased 
	
	//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){
		
		bayesStruct.updateBestEstimate(timeDifference);
		//	bayesStruct.updateTmpBestEstimate(timeDifference);
	}
	
	
	
	if (smoothPlayPosition < bayesStruct.bestEstimate){
		updateSmoothPositionTo(bayesStruct.bestEstimate);
		//smoothPlayPosition = bayesStruct.bestEstimate;
	}
	
//	playPositionInMillis = timeDifference;//based on updating from when we change period
	//this to be added

	
	//this is time diff in milliseconds
	//then we have 
	double quarterNoteIntervals = (timeDifference / period);
	tickLocation = quarterNoteIntervals * pulsesPerQuarternote; 
	
	updateNoteCounter();
	
}

void midiEventHolder::updateSmoothPositionTo(const double& newPosition){
	while (smoothIndex > 0 && recordedEventTimes[smoothIndex] > smoothPlayPosition){
		smoothIndex--;
	}
	while (smoothIndex < recordedEventTimes.size()-1 && recordedEventTimes[smoothIndex] < smoothPlayPosition){
		smoothIndex++;
	}
	

	double playingTime = ofGetElapsedTimeMillis();
	playingTime -= startPlayingTime;
	//now at the last one
	

	
	while (smoothIndex < recordedEventTimes.size() && recordedEventTimes[smoothIndex] < newPosition){
		float annotationTime = 0;
		int annotationNote = 0;
		if (smoothIndex < myNotation.rwcAnnotations.size()){
			annotationTime = myNotation.rwcAnnotations[smoothIndex].eventTime;
			annotationNote = myNotation.rwcAnnotations[smoothIndex].midiNote;
		}
		
		
		if ((*fileOutput).is_open()){
			(*fileOutput) << fixed << beatPositions[smoothIndex] <<",\t" <<  recordedNoteOnMatrix[smoothIndex][1] << ",\t";
			(*fileOutput) << playingTime ;
			float difference = playingTime - (annotationTime*1000.0);
				if ( recordedNoteOnMatrix[smoothIndex][1] == annotationNote){
					(*fileOutput) << " corresponds to " << annotationTime;
				}
			(*fileOutput) << " \n";
			
			printf("midi %i beat pos %f now at %f :: annotaion %i time %f diff \t%f ms\n",  recordedNoteOnMatrix[smoothIndex][1], 
				   beatPositions[smoothIndex], playingTime, annotationNote, annotationTime, difference);
		}
		
		smoothIndex++;
	}
	
		
	smoothPlayPosition = newPosition;
		
}


void midiEventHolder::updatePeriodValue(const double& millis){

	double tmp = period;
/*	
	while (periodCounter >= 0 && periodCounter < periodValues.size()-1 && periodValues[periodCounter][2] < millis){
		periodCounter++;
	}
	while (periodCounter > 0 && periodValues[periodCounter][2] > millis){
		periodCounter--;
	}
 */
	//period = periodValues[periodCounter][1];
	
	if (period != tmp){
		printf("new period at %f of %f\n", millis, period);
	}
}

void  midiEventHolder::updateNoteCounter(){
	while (totalNoteCounterIndex < bestMatchIndex){
		int tmpPitch = recordedNoteOnMatrix[totalNoteCounterIndex][1];
		recordedTotalNoteCounterByPitch[tmpPitch] += 1;
		totalNoteCounterIndex++;
	}
}


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(250,250,20);//250,100,0);
		ofLine(xLocation, 0, xLocation, (*screenHeight));
		
		xLocation = getLocationFromMillis(smoothPlayPosition);//bayesStruct.tmpBestEstimate
		ofSetColor(0,250,0);//250,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];
		
		int tmpIndex = 0;
		while (tmpIndex < measureVector.size() && measureVector[tmpIndex] < (numberOfScreensIn+1)*ticksPerScreen){
			int measureLocation = measureVector[tmpIndex];
		int xLocation = (float)(measureLocation - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen;
			ofSetColor(155,155,0);
			ofLine(xLocation, 0, xLocation, (*screenHeight));
			tmpIndex++;
		}
		
		
	//	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);
	
//last played piutch
	ofSetColor(0,200,0,50);
	int yLocation = (*screenHeight) - ((lastPlayedPitch - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum));						 
	ofRect(0,yLocation, 100,  noteHeight);
	
	
	
}



void midiEventHolder::drawMidiFile(IntMatrix& midiFileToDraw){
	
	//using this to draw the live input
	
	//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(0,0,255, 200);

			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();
		
	ofSetColor(0,0,255);
	ofDrawBitmapString("period"+ofToString(period, 2), ofGetWidth() - 180, 20);
	
//	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);							   
*/
	
	//drawInterNoteIntervals();
	
 }

void midiEventHolder::drawInterNoteIntervals(){
	
	ofSetColor(0,0,150);
	int size = interNoteIntervals.size();
	int numberToShow = min(100, size);
	double x ;
	for (int y = 1;y < numberToShow;y++){
		for (int point = 0;point < interNoteIntervals[y].size();point++){
			double interval = interNoteIntervals[size - y][point];
			x = interval - 200;
			x *= (*screenWidth) / 200.0;
		}
		double h = (double)(y * (*screenHeight)) / numberToShow;
		ofCircle(x, h, 5);
	}
	
}


void midiEventHolder::printInterNoteIntervals(){

	int size = interNoteIntervals.size();
	int numberToShow = 20;
	double x ;
	for (int y = max(0, size - numberToShow);y < interNoteIntervals.size();y++){
		for (int point = 0;point < interNoteIntervals[y].size();point++){
			printf("[%i][%i] : %f", y, point, interNoteIntervals[y][point]);
			}
				   printf("\n");
	}			   
	
}

int midiEventHolder::getLocationFromTicks(double tickPosition){
	return 0;
//	return (int)((float)(tickPosition - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen);
//not used
}

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(){
	startPlayingTime = getTimeNow(0);//ofGetElapsedTimeMillis();
	//startTime = startPlayingTime;
	
/*	
 	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]);
		//	double tmp = beatPositions[i];
		//	beatPositions[i] = beatPositions[nextIndex];
		//	 = tmp; 
		
				swap (beatPositions[i], beatPositions[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]);
			swap (beatPositions[i], beatPositions[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;
		}	
	}

}


void midiEventHolder::printNoteCounter(){
	for (int i = 0;i < recordedTotalNoteCounterByPitch.size();i++){
		printf("RECORDED TOTAL[%i] := %i", i, recordedTotalNoteCounterByPitch[i]);
	}
}

/*	double timeDiff = 0;//timeDifference;
 if (runningInRealTime)
 timeDiff = ofGetElapsedTimeMillis() - lastSmoothUpdateTime;
 //		bayesStruct.lastBestEstimateUpdateTime;
 
 //smoothPlayPosition = bayesStruct.bestEstimate + 100;
 //relativeSpeedForSmooth = 0.1;
 //bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate);
 //   speedEstimate*2;
 
 smoothPlayPosition = storedSmoothPlayPosition + timeDiff * relativeSpeedForSmooth;// * bayesStruct.speedEstimate;
 storedSmoothPlayPosition = smoothPlayPosition;
 lastSmoothUpdateTime = getTimeNow(bayesStruct.lastBestEstimateUpdateTime);
 updateSmoothPlaySpeed();
 //bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate) 
 
 }
 
 void  midiEventHolder::updateSmoothPlaySpeed(){
 //project where current play pos will be in two seconds and aim for it.
 double timeToAimForMillis = 2000.0;
 //double timeDiff = ofGetElapsedTimeMillis() - bayesStruct.lastBestEstimateUpdateTime;//since the update need to get to where we are
 double projection = bayesStruct.bestEstimate + bayesStruct.speedEstimate*timeToAimForMillis;//
 double timeDifferenceFromSmooth = projection - smoothPlayPosition;
 relativeSpeedForSmooth = timeDifferenceFromSmooth / timeToAimForMillis;
 
 }
*/ 


/*
 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));
 }
 */