view src/midiEventHolder.cpp @ 15:9e972948d654

looking at offline version - need to do updateBestEstimate routine which presently only works for realtime
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Tue, 15 Nov 2011 13:10:12 +0000
parents 3f103cf78148
children f0abb0e414ec
line wrap: on
line source
/*
 *  midiEventHolder.cpp
 *  midiCannamReader3
 *
 *  Created by Andrew on 19/07/2011.
 *  Copyright 2011 QMUL. All rights reserved.
 *
 */

#include "midiEventHolder.h"

midiEventHolder::midiEventHolder(){
//	recordedNoteOnIndex = 0;
	
	width = ofGetWidth();
	height = ofGetHeight();
	screenWidth= &width;
	screenHeight = &height;
	
	ticksPerScreen = 4000;
	tickLocation = 0;
	pulsesPerQuarternote = 240;
	noteArrayIndex = 0;
	noteMinimum = 30;
	noteMaximum = 96;
	
	minimumMatchSpeed = 0.0;
	maximumMatchSpeed = 2.0;

	likelihoodWidth = 100;
	likelihoodToNoiseRatio = 0.02;
	
	bayesStruct.speedLikelihoodNoise = 0.1;//was 0.05
	bayesStruct.speedDecayWidth = 20;
	bayesStruct.speedDecayAmount = 10;
	
	runningInRealTime = true;
	
	speedPriorValue = 1.0;
	
	matchWindowWidth = 8000;//window size for matching in ms 
	
	bayesStruct.resetSize(matchWindowWidth);
	bayesStruct.setPositionDistributionScalar(1);
	
	bayesStruct.resetSpeedSize(200);
	bayesStruct.setRelativeSpeedScalar(0.01);
	bayesStruct.relativeSpeedPrior.getMaximum();
	//bayesStruct.simpleExample();
	
	
	speedWindowWidthMillis = 4000;
	speedPriorValue = 1.0;
	noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum);
	
	confidenceWeightingUsed = false;
	
	drawPhaseMode = true;
	
	printf("lookup index %f value %f\n", bayesStruct.prior.getLookupIndex(100, 30., 10.0), bayesStruct.prior.gaussianLookupTable[(int)bayesStruct.prior.getLookupIndex(100, 30., 10.0)]);
}



void midiEventHolder::reset(){
	//called when we start playing
	
	noteArrayIndex = 0;
	tickLocation = 0;
	lastPeriodUpdateTime = getTimeNow(0);//ofGetElapsedTimeMillis();
	bayesStruct.lastEventTime = getTimeNow(0);//ofGetElapsedTimeMillis();
	numberOfScreensIn = 0;
//	recordedNoteOnIndex = 0;
	bayesStruct.setNewDistributionOffsets(0);
	bayesStruct.posterior.offset = 0;
	
	playedEventTimes.clear();
	playedNoteOnMatrix.clear();
	matchMatrix.clear();
	bestMatchIndex = 0;
	
	bayesStruct.resetSpeedToOne();
	bayesStruct.setSpeedPrior(speedPriorValue);
	setMatchedNotesBackToFalse();
}

void midiEventHolder::setMatchedNotesBackToFalse(){
	for (int i = 0;i < noteOnMatches.size();i++)
		noteOnMatches[i] = false;
}

void midiEventHolder::clearAllEvents(){
	recordedNoteOnMatrix.clear();
	matchesFound.clear();
	noteOnMatches.clear();
	recordedEventTimes.clear();
	
	//played events:
	playedEventTimes.clear();
	playedNoteOnMatrix.clear();
	matchMatrix.clear();
}

void midiEventHolder::printNotes(){
	printf("RECORDED MATRIX\n");
	for (int i = 0;i < recordedNoteOnMatrix.size();i++){
		printf("ticktime %i :: pitch %i @ millis %f\n", recordedNoteOnMatrix[i][0], recordedNoteOnMatrix[i][1], recordedEventTimes[i]);
	}
}


double midiEventHolder::getEventTimeTicks(double millis){
	return (millis * pulsesPerQuarternote / period);
}

double midiEventHolder::getEventTimeMillis(double ticks){
	return (period * ticks / (double) pulsesPerQuarternote);
}

void midiEventHolder::newNoteOnEvent(int pitch, int velocity, double timePlayed){
	
	//MOVE INTO BAYESSTRUCT?? XXX
	//bayesStruct.copyPriorToPosterior();
	//why was this here??
	bayesStruct.prior.copyFromDynamicVector(bayesStruct.posterior);//try the otehr way
	//bayesStruct.copyPriorToPosterior();
	//need to get new MAP position and set the offset of the arrays
	//currently bestEstimate is the approx for the new MAP position
	
	
	//add the new event to our played information matrix
	IntVector v;
	v.push_back(pitch);
	v.push_back(velocity);
	playedNoteOnMatrix.push_back(v);

	
	//would update the arrays at this point to show where out current location (phase) and tempo is.
//	double timeNow = ofGetElapsedTimeMillis() - startTime;
	double timeNow = timePlayed;// - startTime;
	recentNoteOnTime = timePlayed;
	
//	printf("Max time %f OF time %f \n", timePlayed, timeNow);
	
	playedEventTimes.push_back(timePlayed);
	
//	double timeDifference = ofGetElapsedTimeMillis() - bayesStruct.lastEventTime; 
	double timeDifference = timePlayed - bayesStruct.lastEventTime; 
	
	
	
	printf("note %i played at %f and last event %f time difference %f and current best estmate %f\n", pitch, timePlayed, bayesStruct.lastEventTime, timeDifference, bayesStruct.bestEstimate);
	//addnoise to the tempo distribution
	//bayesStruct.decaySpeedDistribution(timeDifference);
	if (timeDifference > 50){
	bayesStruct.addGaussianNoiseToSpeedPosterior(timeDifference * 10 / 100.);
//	bayesStruct.addTriangularNoiseToSpeedPosterior(timeDifference * 10 / 100.);
	}
	
	bayesStruct.updateTmpBestEstimate(timeDifference);// debug - didnt work	bayesStruct.bestEstimate = bayesStruct.tmpBestEstimate;
	bayesStruct.updateBestEstimate(timeDifference);
	bayesStruct.lastBestEstimateUpdateTime = getTimeNow(timePlayed);
	
//	double newMAPestimateTime = bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate);
	//was offset + bayesStruct.posterior.MAPestimate; but this doesnt include scalar to convert to millis

	timeString = "Pitch:"+ofToString(pitch);
	timeString += ", time now:"+ofToString(timeNow, 1);
	timeString += "  TD "+ofToString(timeDifference, 1);
	timeString += "  offset "+ofToString(bayesStruct.posterior.offset , 0);
	timeString += " map Est: "+ofToString(bayesStruct.posterior.MAPestimate, 0); 
//	timeString += " Previous time" + ofToString(newMAPestimateTime,0);
	timeString += " speedMap "+ofToString(bayesStruct.relativeSpeedPosterior.integratedEstimate, 2);
	timeString += " :: "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.integratedEstimate), 2);
	
//	newMAPestimateTime += (timeDifference * bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
//	timeString += " :  Predicted MAP time" + ofToString(newMAPestimateTime,0);

	//then we recalculate the window start based on MAP being central
	//then we do the matches on these and the likelihood on these.
	
	bayesStruct.setNewDistributionOffsets(max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)));
//	bayesStruct.prior.offset = max(0.,newMAPestimateTime - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));
	
	timeString += " \n :  new offset " + ofToString(bayesStruct.prior.offset , 0);
	timeString += " \n best estimate "+ofToString(bayesStruct.bestEstimate, 1);
	timeString += " error "+ofToString(minimumMatchError, 0);
	timeString += " map "+ofToString(bayesStruct.relativeSpeedPosterior.integratedEstimate, 1);
	timeString += " rel speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.integratedEstimate), 2);
	
	
	//be able to draw the prior in correct location relative to the midi notes
	//this calculates the cross update of all possible speeds and all possible positions
	bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, timeDifference);

	
	timeString += " new OFF "+ofToString(bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2), 1);
	timeString += " notearrayindex "+ofToString(noteArrayIndex, 0);
	//when this is off teh screen there is a problem somehow XXX
	bayesStruct.posterior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));
//	bayesStruct.prior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));
	//trying to switch to prior
	
	//bayesStruct.lastEventTime = ofGetElapsedTimeMillis();
	bayesStruct.lastEventTime = timePlayed;
	
	//do the cross update to find current posterior for location
//	totalConfidence= 0;
	int numberOfMatchesFound = findLocalMatches(pitch);
	setMatchLikelihoods(numberOfMatchesFound);
	bayesStruct.calculatePosterior();
	
	//having found matches we have matches for new note and matches for previous notes
	//if (!confidenceWeightingUsed)
	findLocalTempoPairs();
	//else
	//findLocalTempoPairsWeightedForConfidence();
	
	//bayesStruct.addGaussianNoiseToSpeedPosterior(10);
	 
}

double midiEventHolder::getTimeNow(double eventTime){
	double timeNow = eventTime;
	if (runningInRealTime)
		timeNow = ofGetElapsedTimeMillis();
	return timeNow;
}

int midiEventHolder::findLocalMatches(int notePitch){

	//here we find the matches to the new note within appropriate range
		
	matchString = "";
	
	windowStartTime = max(0.0,(bayesStruct.bestEstimate - matchWindowWidth/2));//was playPositionInMillis
	cout << "best estimate is " << bayesStruct.bestEstimate << endl;
	int numberOfMatches = findMatch(notePitch, windowStartTime, windowStartTime + matchWindowWidth);

	
	matchString += " pitch: "+ofToString(notePitch)+" matches "+ofToString(numberOfMatches)+" win start "+ofToString(windowStartTime);	
	
	return numberOfMatches;
	
	
}


void midiEventHolder::setMatchLikelihoods(int numberOfMatches){
//reset the offset to match the prior
	bayesStruct.likelihood.offset = bayesStruct.prior.offset;
	bayesStruct.likelihood.zero();//set to zero
	
	double quantity = likelihoodToNoiseRatio / numberOfMatches;
	
	for (int i = 0;i < numberOfMatches && matchesFound[i] >= 0 && matchesFound[i] < recordedEventTimes.size();i++){
	//	printf("match times %i of %i::%f adding likelihood to %f\n", i, numberOfMatches, recordedEventTimes[matchesFound[i]], recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset);
		//this is the vent time since start of file
		if (recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset < bayesStruct.likelihood.arraySize){
	//		double confidenceMeasure = 0;
	//		if (totalConfidence > 0)
	//			confidenceMeasure =	bayesStruct.posterior.getValueAtMillis(recordedEventTimes[matchesFound[i]])/totalConfidence;
			
			bayesStruct.likelihood.addGaussianShape(recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset, likelihoodWidth,  quantity);//* confidenceMeasure
		}//end if
	}
	bayesStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesStruct.likelihood.length);
}

int midiEventHolder::findMatch(const int& notePitch, const int& startTime, const int& endTime){

	matchesFound.clear();
	int startIndex = 0;

	if (recordedEventTimes.size() > 0){
	
		//get to the right range of events to check in
		while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < startTime)
			startIndex++;
		   
		}

	IntVector v;
	DoubleVector d;
	double tmpError = 100000.;//v high error
	
	double minimumConfidence = 0;
	while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < endTime){
		if (recordedNoteOnMatrix[startIndex][1] == notePitch){
			
			matchesFound.push_back(startIndex);
			v.push_back(startIndex);
			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);
	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);
	
	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 (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){
					//adding in a prior that prefers 1
					double 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);
					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;
	
	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 = 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 weighting = previousMatchConfidence * currentMatchConfidence ;
					double amount =	(1-bayesStruct.speedLikelihoodNoise)*weighting/10;
					bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match
					needToUpdate = true;
				}
				//		printf("\n");	
			}
			
			previousIndex--;
		}//end while previousindex countdown
	}//end for loop through possible current matches
	
	if (needToUpdate)
		bayesStruct.updateTempoDistribution();
	//printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
}



void midiEventHolder::updatePlayPosition(){
	
	//in actual fact if we are changing the speed of the play position 
	//we will need to update this via the file
	
	//actually time since beginning of file i think
	
	double timeDifference = 0;
	if (runningInRealTime)
		timeDifference = ofGetElapsedTimeMillis() - lastPeriodUpdateTime;//elpased - lastperiodupdatetime
	
	//this is time diff in milliseconds
	//then we have 
	double quarterNoteIntervals = (timeDifference / period);
	tickLocation = quarterNoteIntervals * pulsesPerQuarternote; 
	
	playPositionInMillis = timeDifference;//based on updating from when we change period
	//this to be added
	
	if (runningInRealTime)
	bayesStruct.updateBestEstimate(timeDifference);
	
}


void midiEventHolder::drawMidiFile(){
	
	//draws midi file on scrolling screen
	int size = recordedNoteOnMatrix.size();
	if (size > 0){
		
		numberOfScreensIn = floor(bayesStruct.bestEstimate / getEventTimeMillis(ticksPerScreen));//rpounds down on no screens in
		
		//	numberOfScreensIn = tickLocation / ticksPerScreen;//rounds down
		timeOffsetForScreen = getEventTimeMillis(numberOfScreensIn * ticksPerScreen);
		
		while (noteArrayIndex < recordedNoteOnMatrix.size()-1 && tickLocation > recordedNoteOnMatrix[noteArrayIndex][0] )
			noteArrayIndex++;
		
		
		while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < recordedNoteOnMatrix[noteArrayIndex][0])
			noteArrayIndex--;
		
		//need to start where we currently are in file
		int maxNoteIndexToPrint	= noteArrayIndex;
		int minNoteIndexToPrint = min(size-1,noteArrayIndex);//not needed as changed above
		
		while (maxNoteIndexToPrint < recordedNoteOnMatrix.size() && recordedNoteOnMatrix[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen )
			maxNoteIndexToPrint++;
		
		while (minNoteIndexToPrint > 0 && recordedNoteOnMatrix[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen)//&& minNoteIndexToPrint < size 
			minNoteIndexToPrint--;
		
		for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)recordedNoteOnMatrix.size());tmpIndex++){
			
			if (checkIfMatchedNote(tmpIndex))
				ofSetColor(0,0,255);
			else if(noteOnMatches[tmpIndex]){
				ofSetColor(255,0,255);
			}else{
				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,100,0);
		ofLine(xLocation, 0, xLocation, (*screenHeight));
		
		xLocation = getLocationFromMillis(bayesStruct.tmpBestEstimate);
		ofSetColor(250,100,0);
		ofLine(xLocation, 0, xLocation, (*screenHeight));
		
		
		//lines where matching window start and end are 
		ofSetColor(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];
		
		string indexString = "num screens in "+ofToString(numberOfScreensIn)+"; min index to print "+ofToString(minNoteIndexToPrint)+", max index to print "+ofToString(maxNoteIndexToPrint);
		indexString += " size "+ofToString(size)+" tick loc "+ofToString(tickLocation)+" max size "+ofToString(maxSize);
		ofDrawBitmapString(indexString, 20, 40);

	}	
	
	ofDrawBitmapString(ofToString(timeOffsetForScreen, 1), 20,20);
	
	ofDrawBitmapString(timeString, 20, 60);
	

}

void midiEventHolder::drawFile(){	
		drawMidiFile();
		
	
//	bayesStruct.drawArrays();
	
//	ofSetColor(200,200,0);
//	bayesStruct.prior.drawConstrainedVector(0, bayesStruct.prior.arraySize, 400, 800);
	
	//need to draw arrays within correct timescope
	if (drawPhaseMode)
	bayesStruct.drawArraysRelativeToTimeframe(timeOffsetForScreen, timeOffsetForScreen + getEventTimeMillis(ticksPerScreen));
	
	if (drawTempoMode)
	bayesStruct.drawTempoArrays();
	
	
	ofSetColor(0, 0, 0);
	ofDrawBitmapString(matchString, 20, ofGetHeight() - 20);
	
	double confidence = bayesStruct.posterior.getValueAtMillis(mouseX);
/*
 string mouseString = "mouseX "+ofToString(confidence, 3)+" .";
	ofDrawBitmapString(mouseString, 20 ,  ofGetHeight() - 40);
*/	
	string mouseString = "updateCounter "+ofToString(bayesStruct.updateCounter);
	ofDrawBitmapString(mouseString, 20 ,  ofGetHeight() - 40);
	
	string infostring = "speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 3);
	ofDrawBitmapString(infostring, 20 ,  ofGetHeight() - 60);							   
}

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

int midiEventHolder::getLocationFromMillis(double millisPosition){
	//(getEventTimeTicks(windowStartTime+matchWindowWidth) - numberOfScreensIn*ticksPerScreen)*(*screenWidth) / (double)ticksPerScreen
	return (millisPosition - timeOffsetForScreen)*(*screenWidth)/getEventTimeMillis(ticksPerScreen);
}


void midiEventHolder::exampleCrossUpdate(){
	
	bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, 200);
	
}


void midiEventHolder::setStartPlayingTimes(){
	lastPeriodUpdateTime = getTimeNow(0);//ofGetElapsedTimeMillis();
	startTime = lastPeriodUpdateTime;
	
/*	
 	bayesStruct.lastEventTime = 0;//ofGetElapsedTimeMillis();
	bayesStruct.bestEstimate = 0;
	bayesStruct.resetArrays();
	bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
*/
	bayesStruct.setStartPlaying();
	matchString = "";
}


void midiEventHolder::printMatchMatrix(){
	printf("match matrix:\n");
	for (int i = 0;i < matchMatrix.size();i++){
		for (int k = 0;k < matchMatrix[i].size();k++){
			printf("%i , ", matchMatrix[i][k]);
		}
		printf("\n");
	}
	
	
}