view bayesianArraySrc/midiEventHolder.cpp @ 56:4394c9490716 tip

minor changes
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Mon, 24 Dec 2012 18:58:39 +0000
parents 45b5cf9be377
children
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>
#include <assert.h>

midiEventHolder::midiEventHolder(){
	

	
//	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;
	
	drawTempoMode = false;
	//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

	//why was this here??
	bayesStruct.prior.copyFromDynamicVector(bayesStruct.posterior);//try the otehr way

	//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){
	//smooth play position was where we last outputted notes from.
	//checking index is there to make sense.
	while (smoothIndex > 0 && recordedEventTimes[smoothIndex] > smoothPlayPosition){
		smoothIndex--;
		//printf("going backewaers on smooth, ");
	}
	while (smoothIndex < recordedEventTimes.size()-1 && recordedEventTimes[smoothIndex] < smoothPlayPosition){
		smoothIndex++;
		//printf("outputting  smooth\n ");
	}
	

	double playingTime = ofGetElapsedTimeMillis();
	playingTime -= startPlayingTime;
	//now at the last one
	
	float smoothLocation = beatPositions[smoothIndex];
	int currentNote = recordedNoteOnMatrix[smoothIndex][1];
	
	while (smoothIndex < recordedEventTimes.size() && recordedEventTimes[smoothIndex] < newPosition){
		float annotationTime = 0;
		float annotationLocation = 0;
		int annotationTick = 0;
		int annotationNote = 0;
		float difference = 10000;//very big
		float currentLocationDifference = 1.0;
		float range = 1.0;
/*		if (smoothIndex < myNotation.rwcAnnotations.size()){
			//add in test here to find closest matching note
			
		
			annotationTime = myNotation.rwcAnnotations[smoothIndex].eventTime;
			annotationNote = myNotation.rwcAnnotations[smoothIndex].midiNote;
			annotationLocation = myNotation.rwcAnnotations[smoothIndex].beatLocation;
			annotationTick = round(annotationLocation*480.0);
		}else{
			printf("No annotaion size %i\n", (int)myNotation.rwcAnnotations.size());
		}
		*/
		difference = playingTime - (annotationTime*1000.0);
		/*
		if ((*fileOutput).is_open()){
			(*fileOutput) << fixed << beatPositions[smoothIndex] <<",\t" <<  recordedNoteOnMatrix[smoothIndex][1] << ",\t";
			(*fileOutput) << playingTime ;
			
				if ( recordedNoteOnMatrix[smoothIndex][1] == annotationNote){
					(*fileOutput) << " corresponds to " << annotationTime;
				}
			(*fileOutput) << " \n";

		}
		 */
	
		printf("annotaions: rec tick time %i vs %i midi %i beat pos %f playing time now at %f :: annotaion %i loc % f time %f diff \t%f ms\n",  
			   recordedNoteOnMatrix[smoothIndex][0], annotationTick, recordedNoteOnMatrix[smoothIndex][1], 
			   beatPositions[smoothIndex], playingTime, 
			   annotationNote, annotationLocation, annotationTime, difference);
		
//		assert(annotationNote == recordedNoteOnMatrix[smoothIndex][1]);
	assert(annotationTick == recordedNoteOnMatrix[smoothIndex][0]);
	
	/*	
		if ((*differenceOutput).is_open()){
			(*differenceOutput) << beatPositions[smoothIndex] << "," << difference << "\n";
		//	printf("midi %i beat pos %f playing time now at %f :: annotaion %i loc % f time %f diff \t%f ms\n",  
		//		   recordedNoteOnMatrix[smoothIndex][1], 
		//		   beatPositions[smoothIndex], playingTime, 
		//		   annotationNote, annotationLocation, annotationTime, difference);
		}else{
			printf("file not open\n");
		}
	*/	
		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;
	printf("starting playing at time %f\n", 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]);
	}
}