changeset 33:fa527df85c2c

Added the JNMR code which now features chopping after loading all events, easier that way
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Mon, 12 Dec 2011 12:46:17 +0000
parents f91b7b019350
children 9d2a651a87b2
files jnmr/BayesianArrayStructure.cpp jnmr/BayesianArrayStructure.h jnmr/CannamMidiFileLoader.cpp jnmr/CannamMidiFileLoader.h jnmr/DynamicVector.cpp jnmr/DynamicVector.h jnmr/MidiInputStream.cpp jnmr/MidiInputStream.h jnmr/drawMidiNotes.cpp jnmr/drawMidiNotes.h jnmr/hackday_notes.txt jnmr/main.cpp jnmr/midiEventHolder.cpp jnmr/midiEventHolder.h jnmr/testApp.cpp jnmr/testApp.h
diffstat 16 files changed, 3941 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/BayesianArrayStructure.cpp	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,592 @@
+/*
+ *  BayesianArrayStructure.cpp
+ *  midiCannamReader
+ *
+ *  Created by Andrew on 17/07/2011.
+ *  Copyright 2011 QMUL. All rights reserved.
+ *
+ */
+
+//look at reset speed to one - what does this do? - get rid of?
+
+
+#include "BayesianArrayStructure.h"
+
+BayesianArrayStructure::BayesianArrayStructure(){
+	printf("Bayesian structure: DeFault constructor called");
+	usingIntegratedTempoEstimate = true;// use max index
+	
+	relativeSpeedLikelihoodStdDev = 5.0;
+	
+	prior.createVector(1);
+	likelihood.createVector(1);
+	posterior.createVector(1);
+
+	
+	speedPriorValue = 1.0;
+	speedEstimate = speedPriorValue;
+	
+	lastEventTime = 0;//ofGetElapsedTimeMillis();
+
+	tmpBestEstimate = 0;
+	crossUpdateTimeThreshold = 60;
+	priorWidth = 50;
+	
+}
+
+BayesianArrayStructure::BayesianArrayStructure(int length){
+	printf("BAYESIAN STURTUCRE CREATED LENGTH: %i\n", length);
+	//this constructor isnt called  it seems
+	prior.createVector(length);
+	likelihood.createVector(length);
+	posterior.createVector(length);
+	
+	lastEventTime = 0;
+	
+
+}
+
+
+
+void BayesianArrayStructure::resetSize(int length){
+	printf("BAYESIAN STRUCTURE size is : %i\n", length);
+	
+	prior.createVector(length);
+	likelihood.createVector(length);
+	posterior.createVector(length);
+	
+	acceleration.createVector(length);
+	
+}
+
+
+
+void BayesianArrayStructure::resetSpeedToOne(){
+	relativeSpeedPrior.zero();
+	relativeSpeedPosterior.zero();
+	relativeSpeedLikelihood.zero();
+	
+	
+	relativeSpeedPosterior.addGaussianShape(100, 20, 0.8);
+	relativeSpeedPosterior.renormalise();
+	relativeSpeedPosterior.getMaximum();
+	
+	setSpeedPrior(speedPriorValue);
+	speedEstimate = speedPriorValue;
+	
+	prior.zero();
+	posterior.zero();
+
+	posterior.addToIndex(0, 1);
+	posterior.renormalise();
+	
+
+	//acceleration.addGaussianShape(2000, 20, 0.8);
+	
+}
+
+void BayesianArrayStructure::setSpeedPrior(double f){	
+	speedPriorValue = f;
+	int index = relativeSpeedPosterior.getRealTermsAsIndex(speedPriorValue);
+	relativeSpeedPosterior.zero();
+	relativeSpeedPosterior.addGaussianShape(index, priorWidth, 0.8);
+	relativeSpeedPosterior.renormalise();
+	relativeSpeedPosterior.getMaximum();
+	relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior);
+	printf("BAYES STRUCTU ' SPEED PRIOR %f . index %i\n", speedPriorValue, index);
+	
+}
+
+void BayesianArrayStructure::resetSpeedSize(int length){
+	printf("BAYESIAN SPEED size is : %i\n", length);
+	
+	relativeSpeedPrior.createVector(length);
+	relativeSpeedLikelihood.createVector(length);
+	relativeSpeedPosterior.createVector(length);
+	tmpPosteriorForStorage.createVector(length);
+	
+	
+
+}
+
+void BayesianArrayStructure::setRelativeSpeedScalar(double f){
+	relativeSpeedPrior.scalar = f;
+	relativeSpeedPosterior.scalar = f;
+	relativeSpeedLikelihood.scalar = f;
+}
+
+
+void BayesianArrayStructure::setPositionDistributionScalar(double f){
+	if (f > 0){
+	prior.scalar = f;
+	posterior.scalar = f;
+	likelihood.scalar = f;
+	}
+}
+
+void BayesianArrayStructure::simpleExample(){
+	relativeSpeedPosterior.getMaximum();
+	relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior);
+}
+
+void BayesianArrayStructure::copyPriorToPosterior(){
+
+	for (int i = 0;i < prior.arraySize;i++){
+		posterior.array[i] = prior.array[i];
+	}
+}
+
+void BayesianArrayStructure::setStartPlaying(){
+	
+	lastEventTime = 0;
+	bestEstimate = 0;
+	lastBestEstimateUpdateTime = 0;
+	if (*realTimeMode)
+		lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
+	//cannot just be zero - offline bug
+	printf("start playing - best estimate %f\n", lastBestEstimateUpdateTime);
+	
+	resetArrays();
+}
+
+void BayesianArrayStructure::resetArrays(){
+	//called when we start playing
+	
+	prior.zero();
+	likelihood.zero();
+	posterior.zero();
+	
+	updateCounter = 0;
+	
+	posterior.offset = -1000;
+	setNewDistributionOffsets(0);
+	
+	int zeroIndex = posterior.getRealTermsAsIndex(0);
+	
+	posterior.addGaussianShape(zeroIndex, 500, 1);
+	//	posterior.addToIndex(0, 1);
+	likelihood.addConstant(1);
+	
+	updateCounter = 0;
+	
+
+	printf("bayes reset arrays - best estimate %f\n", lastBestEstimateUpdateTime);
+	
+	setSpeedPrior(speedPriorValue);
+}
+
+
+void BayesianArrayStructure::zeroArrays(){
+	prior.zero();
+	likelihood.zero();
+	posterior.zero();
+	
+	relativeSpeedPrior.zero();
+	relativeSpeedPosterior.zero();
+	relativeSpeedLikelihood.zero();
+
+}
+
+
+void BayesianArrayStructure::updateTmpBestEstimate(const double& timeDifference){
+	//input is the time since the start of playing
+	
+//	double timeDiff = ofGetElapsedTimeMillis() - lastEventTime;//lastBestEstimateUpdateTime;
+	
+	tmpBestEstimate = posterior.getIndexInRealTerms(posterior.MAPestimate) + timeDifference*relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.integratedEstimate);
+	// 
+	//printf("tmp best %f and best %f time diff %f posterior MAP %f at speed %f\n", tmpBestEstimate, bestEstimate, timeDifference, posterior.getIndexInRealTerms(posterior.MAPestimate), relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.integratedEstimate));
+	//lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
+}
+	
+void BayesianArrayStructure::updateBestEstimate(const double& timeDifference){
+//	double timeDiff = ofGetElapsedTimeMillis() - lastEventTime;//
+	
+	double timeDiff = timeDifference;
+	
+	//Using timedifferencfe here will make it go wrong. Is time since beginning of playing
+	
+	if (*realTimeMode)
+		timeDiff = ofGetElapsedTimeMillis() - lastBestEstimateUpdateTime;
+	
+	double speedEstimate;
+	if (usingIntegratedTempoEstimate)
+		speedEstimate = relativeSpeedPosterior.getIntegratedEstimate();
+	else
+		speedEstimate = relativeSpeedPosterior.MAPestimate;
+	
+	
+	speedEstimate = relativeSpeedPosterior.getIndexInRealTerms(speedEstimate);
+	//relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.MAPestimate)
+	bestEstimate = posterior.getIndexInRealTerms(posterior.MAPestimate) + timeDiff*speedEstimate;
+	
+//	bestEstimate = tmpBestEstimate;
+}
+
+void BayesianArrayStructure::calculatePosterior(){
+	//posterior.doProduct(prior, likelihood);
+	
+	int i;
+	for (i = 0;i < posterior.length;i++){
+		posterior.array[i] = likelihood.array[i] * prior.array[i];
+	}
+	
+	
+	posterior.renormalise();
+	
+
+
+	 
+}
+
+
+
+
+void BayesianArrayStructure::setNewDistributionOffsets(const double& newOffset){
+	prior.offset = newOffset;
+	likelihood.offset = newOffset;
+	//posterior.offset = newOffset;
+}
+
+
+void BayesianArrayStructure::crossUpdateArrays(DynamicVector& position, DynamicVector& speed, double timeDifference){
+	//set the cutoff for offset of position first! XXX
+	
+//	printf("time difference %f, ", timeDifference);
+	
+	double timeDifferenceInPositionVectorUnits = timeDifference / prior.scalar;
+	
+
+	prior.zero();//kill prior
+	calculateNewPriorOffset(timeDifference);//set new prior offset here
+	
+	if (timeDifferenceInPositionVectorUnits > crossUpdateTimeThreshold)
+		complexCrossUpdate(timeDifferenceInPositionVectorUnits);
+	else
+		translateByMaximumSpeed(timeDifferenceInPositionVectorUnits);	
+			
+
+	updateCounter++;
+	prior.renormalise();
+
+}
+
+void BayesianArrayStructure::complexCrossUpdate(const double& timeDifferenceInPositionVectorUnits){
+	int distanceMoved, newPriorIndex;
+	
+	double speedValue = relativeSpeedPosterior.offset;
+	
+	for (int i = 0;i < relativeSpeedPosterior.arraySize;i++){
+		
+	//	double speedValue = relativeSpeedPosterior.getIndexInRealTerms(i);//so for scalar 0.01, 50 -> speed value of 0.5
+		
+		//so we have moved 
+		distanceMoved = round(timeDifferenceInPositionVectorUnits * speedValue);//round the value
+	
+		if (relativeSpeedPosterior.array[i] != 0){
+			double speedContribution = relativeSpeedPosterior.array[i];
+			//	printf("speed [%i] gives %f moved %i in %f units \n", i, speedValue, distanceMoved, timeDifferenceInPositionVectorUnits);
+			
+			newPriorIndex = posterior.offset - prior.offset + distanceMoved;
+			
+			for (int postIndex = 0;postIndex < posterior.arraySize;postIndex++){
+				//old posterior contributing to new prior
+			//	newPriorIndex = postIndex + posterior.offset - prior.offset + distanceMoved;
+				
+				if (newPriorIndex >= 0 && newPriorIndex < prior.arraySize){
+					prior.addToIndex(newPriorIndex, posterior.array[postIndex]*speedContribution);
+				}
+				
+				newPriorIndex++;//optimised code - the commented line above explains how this works
+			}//end for
+			
+			
+		}//if not zero
+		speedValue += relativeSpeedPosterior.scalar;
+		//optimised line
+		//as we wanted:
+		//	double speedValue = relativeSpeedPosterior.getIndexInRealTerms(i);//so for scalar 0.01, 50 -> speed value of 0.5
+	}//end speed
+}
+
+
+
+void BayesianArrayStructure::translateByMaximumSpeed(const double& timeDifferenceInPositionVectorUnits){
+
+	int distanceMoved, newPriorIndex;
+	
+	double speedValue = relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.integratedEstimate);
+	//so for scalar 0.01, 50 -> speed value of 0.5
+	double speedContribution = relativeSpeedPosterior.array[relativeSpeedPosterior.integratedEstimate];
+		//so we have moved 
+		distanceMoved = round(timeDifferenceInPositionVectorUnits * speedValue);//round the value
+					//	printf("speed [%i] gives %f moved %i in %f units \n", i, speedValue, distanceMoved, timeDifferenceInPositionVectorUnits);
+			
+			for (int postIndex = 0;postIndex < posterior.arraySize;postIndex++){
+				//old posterior contributing to new prior
+				newPriorIndex = postIndex + posterior.offset - prior.offset + distanceMoved;
+				if (newPriorIndex >= 0 && newPriorIndex < prior.arraySize){
+					prior.addToIndex(newPriorIndex, posterior.array[postIndex]*speedContribution);
+				}
+				
+			}
+	
+}
+
+void BayesianArrayStructure::addGaussianNoiseToSpeedPosterior(const double& std_dev){
+	tmpPosteriorForStorage.copyFromDynamicVector(relativeSpeedPosterior);
+	
+	for (int i = 0;i < relativeSpeedPosterior.length;i++){
+		tmpPosteriorForStorage.addGaussianShape(i, std_dev, relativeSpeedPosterior.array[i]);
+		}
+												
+	tmpPosteriorForStorage.renormalise();
+	
+	relativeSpeedPosterior.copyFromDynamicVector(tmpPosteriorForStorage);											
+}
+
+
+void BayesianArrayStructure::addTriangularNoiseToSpeedPosterior(const double& std_dev){
+	tmpPosteriorForStorage.copyFromDynamicVector(relativeSpeedPosterior);
+	
+	for (int i = 0;i < relativeSpeedPosterior.length;i++){
+		//adding a linear amount depending on distance
+		tmpPosteriorForStorage.addTriangularShape(i, std_dev*2.0, relativeSpeedPosterior.array[i]);
+	}
+	
+	tmpPosteriorForStorage.renormalise();
+	
+	relativeSpeedPosterior.copyFromDynamicVector(tmpPosteriorForStorage);											
+}
+
+void BayesianArrayStructure::calculateNewPriorOffset(const double& timeDifference){
+	
+	double maxSpeed = relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.integratedEstimate);
+	//	printf("Maxspeed is %f\n", maxSpeed);
+	
+	double priorMax = posterior.getMaximum();
+	double distanceTravelled = maxSpeed * (timeDifference / prior.scalar);
+	double newMaxLocation = posterior.MAPestimate + distanceTravelled;
+	//	printf("MAP: %i, tim df %f, distance %f, new location %f\n", posterior.MAPestimate, timeDifference, distanceTravelled, newMaxLocation);
+	
+}
+
+
+void BayesianArrayStructure::decaySpeedDistribution(double timeDifference){
+	
+	// commented for the moment
+	 double relativeAmount = max(1.0, timeDifference/1000.);
+//	printf("decay %f around %i \n", timeDifference, relativeSpeedPosterior.MAPestimate);
+	relativeAmount *= speedDecayAmount;
+	relativeSpeedPosterior.renormalise();
+	relativeSpeedPosterior.addGaussianShape(relativeSpeedPosterior.MAPestimate, speedDecayWidth, relativeAmount);
+	
+	relativeSpeedPosterior.renormalise();
+	double newMax = relativeSpeedPosterior.getMaximum();
+	
+	//old code
+//	relativeSpeedPosterior.addGaussianShape(relativeSpeedPosterior.MAPestimate, speedDecayWidth, 10);
+	//relativeSpeedPosterior.addConstant(1);
+	
+	/*
+	relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior);
+	relativeSpeedLikelihood.zero();
+	relativeSpeedLikelihood.addConstant(0.2);
+	relativeSpeedLikelihood.addGaussianShape(relativeSpeedPosterior.maximumValue, speedDecayWidth, relativeAmount);
+	relativeSpeedPosterior.doProduct(relativeSpeedPrior, relativeSpeedLikelihood);
+	relativeSpeedPosterior.renormalise();
+	 */
+	
+
+	
+}
+
+void BayesianArrayStructure::setLikelihoodToConstant(){
+	//set new likelihood
+	relativeSpeedLikelihood.zero();
+	relativeSpeedLikelihood.addConstant(speedLikelihoodNoise);
+}
+
+
+void BayesianArrayStructure::updateTempoLikelihood(const double& speedRatio, const double& matchFactor){
+	
+	//speedratio is speed of played relative to the recording
+	
+	double index = relativeSpeedLikelihood.getRealTermsAsIndex(speedRatio);
+	//	printf("index of likelihood would be %f for ratio %f\n", index, speedRatio);
+	if (index >= 0 && index < relativeSpeedPrior.length){	
+		relativeSpeedLikelihood.addGaussianShape(index , relativeSpeedLikelihoodStdDev, matchFactor);
+	}
+}
+	
+
+
+void BayesianArrayStructure::updateTempoDistribution(){
+
+	//copy posterior to prior
+	relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior);
+
+	//update
+	relativeSpeedPosterior.doProduct(relativeSpeedPrior, relativeSpeedLikelihood);
+
+	//normalise
+	relativeSpeedPosterior.renormalise();
+		
+	relativeSpeedPosterior.getMaximum();	
+	
+//	relativeSpeedPosterior.updateIntegratedEstimate();
+	relativeSpeedPosterior.updateLimitedIntegratedEstimate();
+	
+	speedEstimate = relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.integratedEstimate);
+}
+
+
+void BayesianArrayStructure::calculateTempoUpdate(){
+	//copy posterior to prior
+	relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior);
+	
+	//update
+	relativeSpeedPosterior.doProduct(relativeSpeedPrior, relativeSpeedLikelihood);
+	
+	//normalise
+	relativeSpeedPosterior.renormalise();
+	
+	relativeSpeedPosterior.getMaximum();	
+	
+}
+
+
+void BayesianArrayStructure::drawArrays(){
+	
+	//bayesArray.drawFloatArray(&bayesArray.prior[0], 0, 200);
+	//bayesArray.drawFloatArray(&bayesArray.prior[0], 0, 200);
+	
+	int displaySize = prior.arraySize;
+	ofSetColor(0,0,255);
+	prior.drawVector(0, displaySize);
+	ofSetColor(0,255,0);
+	likelihood.drawVector(0, displaySize);
+	ofSetColor(255,0,255);
+	posterior.drawVector(0, displaySize);
+	
+	
+	
+}
+
+
+void BayesianArrayStructure::drawTempoArrays(){
+	ofSetColor(0,0,255);
+//	relativeSpeedPrior.drawVector(0, relativeSpeedPrior.arraySize);
+	
+	ofSetColor(0,150,255);
+	relativeSpeedLikelihood.drawVector(0, relativeSpeedLikelihood.arraySize);
+	
+//	relativeSpeedLikelihood.drawConstrainedVector(0, 199, 0, 1000);// relativeSpeedLikelihood.arraySize);	
+	ofSetColor(255,0,0);
+	relativeSpeedPosterior.drawVector(0, relativeSpeedPosterior.arraySize);
+	
+//	ofSetColor(0,0,255);
+//	tmpPosteriorForStorage.drawVector(0, tmpPosteriorForStorage.arraySize);
+	
+	ofSetColor(255,255, 255);
+	ofLine(screenWidth/2, 0, screenWidth/2, ofGetHeight());//middle of screen
+	
+	ofSetColor(25, 0, 250);
+	double fractionOfScreen = ((double)relativeSpeedPosterior.integratedEstimate / relativeSpeedPosterior.length);
+	ofLine(screenWidth * fractionOfScreen, 0, screenWidth * fractionOfScreen, ofGetHeight());
+	
+	ofSetColor(255, 0, 20);
+	fractionOfScreen = ((double)relativeSpeedPosterior.MAPestimate / relativeSpeedPosterior.length);
+	ofLine(screenWidth * fractionOfScreen, 0, screenWidth * fractionOfScreen, ofGetHeight());
+	 
+	
+}
+
+
+void BayesianArrayStructure::drawArraysRelativeToTimeframe(const double& startTimeMillis, const double& endTimeMillis){
+
+	screenWidth = ofGetWidth();
+	
+	int startArrayIndex = 0;
+	
+	if (prior.getIndexInRealTerms(prior.arraySize-1) > startTimeMillis){
+		//i.e. the array is on the page
+	
+	while (prior.getIndexInRealTerms(startArrayIndex) < startTimeMillis){
+		startArrayIndex++;
+	}
+	int endArrayIndex = prior.arraySize-1;
+	//could find constraints here
+	if (prior.getIndexInRealTerms(prior.arraySize-1) > endTimeMillis)
+		endArrayIndex = (floor)((endTimeMillis - prior.offset)/prior.scalar);
+	
+	//so we need to figure where start and end array are on screen
+	int startScreenPosition, endScreenPosition;
+	double screenWidthMillis = endTimeMillis - startTimeMillis;
+		
+	startScreenPosition = (prior.getIndexInRealTerms(startArrayIndex) - startTimeMillis)*screenWidth/screenWidthMillis;
+	endScreenPosition = (double)(prior.getIndexInRealTerms(endArrayIndex) - startTimeMillis)*screenWidth/screenWidthMillis;
+		
+	ofSetColor(0,0,100);
+	string relativeString = " offset "+ofToString(prior.offset, 1);//starttimes("+ofToString(startTimeMillis)+", "+ofToString(endTimeMillis);
+	relativeString += ": index "+ofToString(startArrayIndex)+" , "+ofToString(endArrayIndex)+" [";
+//	relativeString += ofToString(prior.getIndexInRealTerms(endArrayIndex), 3)+"] (sc-width:"+ofToString(screenWidthMillis, 1)+")  ";
+	relativeString += " mapped to screen "+ofToString(startScreenPosition)+" , "+ofToString(endScreenPosition);
+//	ofDrawBitmapString(relativeString, 100, 180);
+	
+		
+		
+	ofSetColor(100,100,100);//255, 255, 0);
+	likelihood.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition);
+
+//	ofSetColor(0,0,200);
+	ofSetColor(170,170,170);//00,200);
+	prior.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition);
+		
+		ofSetColor(0,0,150);	
+//	ofSetColor(200, 0, 0);
+	posterior.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition);
+		
+		
+//	ofSetColor(0, 200, 255);
+//	acceleration.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition);
+		
+		
+	}
+
+}
+
+
+/*
+ 
+ void BayesianArrayStructure::updateTempoDistribution(const double& speedRatio, const double& matchFactor){
+ //speedratio is speed of played relative to the recording
+ 
+ double index = relativeSpeedLikelihood.getRealTermsAsIndex(speedRatio);
+ //	printf("\nindex of likelihood would be %f\n", index);
+ if (index >= 0 && index < relativeSpeedPrior.length){
+ //then we can do update
+ 
+ //set new likelihood
+ relativeSpeedLikelihood.zero();
+ relativeSpeedLikelihood.addConstant(speedLikelihoodNoise);
+ 
+ relativeSpeedLikelihood.addGaussianShape(index , 5, 0.5*matchFactor);
+ 
+ 
+ //copy posterior to prior
+ relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior);
+ 
+ //update
+ relativeSpeedPosterior.doProduct(relativeSpeedPrior, relativeSpeedLikelihood);
+ 
+ //normalise
+ relativeSpeedPosterior.renormalise();
+ 
+ relativeSpeedPosterior.getMaximum();	
+ }//end if within range
+ 
+ 
+ }
+ 
+ */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/BayesianArrayStructure.h	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,99 @@
+/*
+ *  BayesianArrayStructure.h
+ *  midiCannamReader
+ *
+ *  Created by Andrew on 17/07/2011.
+ *  Copyright 2011 QMUL. All rights reserved.
+ *
+ */
+#ifndef BAYESIAN_ARRAY_STRUCTURE
+#define BAYESIAN_ARRAY_STRUCTURE
+
+
+#include "ofMain.h"
+//#include "DynamicBayesianArray.h"
+#include "DynamicVector.h"
+
+class BayesianArrayStructure {
+	
+public:
+//	BayesianArrayStructure();
+	BayesianArrayStructure();
+	BayesianArrayStructure(int length);
+	
+	void calculatePosterior();
+	void drawArrays();
+	void drawArraysRelativeToTimeframe(const double& startTimeMillis, const double& endTimeMillis);
+
+	void drawTempoArrays();
+	
+	void resetSize(int length);
+	void resetArrays();
+	void simpleExample();
+	void setStartPlaying();
+	void zeroArrays();
+	
+	double screenWidth;
+	
+	void copyPriorToPosterior();
+//	DynamicBayesianArray bayesArray;
+	
+	double lastEventTime;
+	double likelihoodNoise;
+	double speedLikelihoodNoise;
+	
+	//DynamicVector tmpPrior;
+	DynamicVector tmpPosteriorForStorage;
+	DynamicVector prior;
+	DynamicVector posterior;
+	DynamicVector likelihood;
+	
+	DynamicVector relativeSpeedPrior;
+	DynamicVector relativeSpeedLikelihood;
+	DynamicVector relativeSpeedPosterior;
+	DynamicVector acceleration;
+	
+	double tmpBestEstimate;
+	void updateTmpBestEstimate(const double& timeDifference);
+	
+	int updateCounter;
+	
+	void setPositionDistributionScalar(double f);
+	
+	void resetSpeedToOne();
+	void addGaussianNoiseToSpeedPosterior(const double& std_dev);
+	void addTriangularNoiseToSpeedPosterior(const double& std_dev);
+	
+	double bestEstimate;
+	void updateBestEstimate(const double& timeDifference);
+	double lastBestEstimateUpdateTime;
+	double speedEstimate;
+	
+	double speedDecayWidth, speedDecayAmount;
+	void decaySpeedDistribution(double timeDifference);
+	
+	void resetSpeedSize(int length);
+	void setRelativeSpeedScalar(double f);
+	void setSpeedPrior(double f);
+	void calculateNewPriorOffset(const double& timeDifference);
+	void setNewDistributionOffsets(const double& newOffset);
+	
+	void setLikelihoodToConstant();
+	void updateTempoLikelihood(const double& speedRatio, const double& matchFactor);
+	void updateTempoDistribution();
+	
+	void calculateTempoUpdate();
+	
+	void crossUpdateArrays(DynamicVector& position, DynamicVector& speed, double timeDifference);
+	void complexCrossUpdate(const double& timeDifferenceInPositionVectorUnits);
+	void translateByMaximumSpeed(const double& timeDifferenceInPositionVectorUnits);
+	double crossUpdateTimeThreshold;//time after which we do complex update of multiple speeds
+	
+	double speedPriorValue;
+	int priorWidth;
+	bool* realTimeMode;
+	bool usingIntegratedTempoEstimate;
+	double relativeSpeedLikelihoodStdDev;
+	
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/CannamMidiFileLoader.cpp	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,397 @@
+/*
+ *  CannamMidiFileLoader.cpp
+ *  midi-score-follower
+ *
+ *  Created by Andrew on 19/08/2011.
+ *  Copyright 2011 QMUL. All rights reserved.
+ *
+ */
+
+#include "MIDIFileReader.h"
+#include "CannamMidiFileLoader.h"
+
+CannamMidiFileLoader::CannamMidiFileLoader(){
+	chopBeginning = true;
+	firstTickTime = 0;
+}
+
+int CannamMidiFileLoader::loadFile(std::string& filename, midiEventHolder& myMidiEvents){
+		
+		noteOnIndex = 0;
+		firstTickTime = 0;
+		myMidiEvents.clearAllEvents();
+		
+		
+		setTempoFromMidiValue(500000, myMidiEvents);//default is 120bpm
+		myMidiEvents.pulsesPerQuarternote = 240;//default
+		//myMidiEvents.measureVector.push_back(0);
+		//int main(int argc, char **argv)
+		//{
+		//	if (argc != 2) {
+		//		cerr << "Usage: midifile <file.mid>" << endl;
+		//		return 1;
+		//	}
+		
+	//	std::string filename = midiFileName;//argv[1];
+		
+		MIDIFileReader fr(filename);
+	
+		if (!fr.isOK()) {
+			std::cerr << "Error: " << fr.getError().c_str() << std::endl;
+			return 1;
+		}
+		
+		MIDIComposition c = fr.load();
+		
+		switch (fr.getFormat()) {
+			case MIDI_SINGLE_TRACK_FILE: cout << "Format: MIDI Single Track File" << endl; break;
+			case MIDI_SIMULTANEOUS_TRACK_FILE: cout << "Format: MIDI Simultaneous Track File" << endl; break;
+			case MIDI_SEQUENTIAL_TRACK_FILE: cout << "Format: MIDI Sequential Track File" << endl; break;
+			default: cout << "Format: Unknown MIDI file format?" << endl; break;
+		}
+		
+		cout << "Tracks: " << c.size() << endl;
+		
+		int td = fr.getTimingDivision();
+		if (td < 32768) {
+				if (printMidiInfo)
+					cout << "Timing division: " << fr.getTimingDivision() << " ppq" << endl;
+			myMidiEvents.pulsesPerQuarternote = fr.getTimingDivision();
+			ticksPerMeasure = myMidiEvents.pulsesPerQuarternote * 4;//default setting
+			
+		} else {
+			int frames = 256 - (td >> 8);
+			int subframes = td & 0xff;
+				if (printMidiInfo)
+					cout << "SMPTE timing: " << frames << " fps, " << subframes << " subframes" << endl;
+		}
+		
+		for (MIDIComposition::const_iterator i = c.begin(); i != c.end(); ++i) {
+				if (printMidiInfo)
+					cout << "Start of track: " << i->first+1 << endl;
+			
+			for (MIDITrack::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
+				
+				unsigned int t = j->getTime();
+				int ch = j->getChannelNumber();
+				
+				if (j->isMeta()) {
+					int code = j->getMetaEventCode();
+					string name;
+					bool printable = true;
+					switch (code) {
+							
+						case MIDI_END_OF_TRACK:
+							cout << t << ": End of track" << endl;
+							break;
+							
+						case MIDI_TEXT_EVENT: name = "Text"; break;
+						case MIDI_COPYRIGHT_NOTICE: name = "Copyright"; break;
+						case MIDI_TRACK_NAME: name = "Track name"; break;
+						case MIDI_INSTRUMENT_NAME: name = "Instrument name"; break;
+						case MIDI_LYRIC: name = "Lyric"; break;
+						case MIDI_TEXT_MARKER: name = "Text marker"; break;
+						case MIDI_SEQUENCE_NUMBER: name = "Sequence number"; printable = false; break;
+						case MIDI_CHANNEL_PREFIX_OR_PORT: name = "Channel prefix or port"; printable = false; break;
+						case MIDI_CUE_POINT: name = "Cue point"; break;
+						case MIDI_CHANNEL_PREFIX: name = "Channel prefix"; printable = false; break;
+						case MIDI_SEQUENCER_SPECIFIC: name = "Sequencer specific"; printable = false; break;
+						case MIDI_SMPTE_OFFSET: name = "SMPTE offset"; printable = false; break;
+							
+						case MIDI_SET_TEMPO:
+						{
+							int m0 = j->getMetaMessage()[0];
+							int m1 = j->getMetaMessage()[1];
+							int m2 = j->getMetaMessage()[2];
+							long tempo = (((m0 << 8) + m1) << 8) + m2;
+								//if (printMidiInfo)
+								cout << t << ": Tempo: " << 60000000.0 / double(tempo) << endl;
+							setTempoFromMidiValue(tempo, myMidiEvents);
+							DoubleVector tmp;
+
+							
+							double lastTickInMillis = 0;
+							double millisTimeNow = lastTickInMillis;
+							int tickInterval = 0;
+							if (myMidiEvents.periodValues.size() > 0){
+								lastTickInMillis = myMidiEvents.periodValues[myMidiEvents.periodValues.size()-1][2];
+								tickInterval = (t - firstTickTime) - myMidiEvents.periodValues[myMidiEvents.periodValues.size()-1][0];
+								millisTimeNow = lastTickInMillis + (myMidiEvents.periodValues[myMidiEvents.periodValues.size()-1][1]*tickInterval);
+								
+							}
+							
+							if (!chopBeginning)
+								tmp.push_back(t);
+							else
+								tmp.push_back(t - firstTickTime);
+							
+							tmp.push_back(60000000.0 / double(tempo));	
+							tmp.push_back(millisTimeNow);
+							myMidiEvents.periodValues.push_back(tmp);
+							
+							printf("tick[%i]: TEMPO period %f : time now %f\n", t, 60000000.0 / double(tempo), millisTimeNow);
+							//printf("period double is %f\n", myMidiEvents.period);
+						
+						}
+							break;
+							
+						case MIDI_TIME_SIGNATURE:
+						{
+							int numerator = j->getMetaMessage()[0];
+							int denominator = 1 << (int)j->getMetaMessage()[1];
+							
+							newTimeSignature(t, numerator, denominator, myMidiEvents);
+							
+							//if (printMidiInfo)
+							cout << t << ": Time signature: " << numerator << "/" << denominator << endl;
+							printf(" ticks %i Time signature: %i by %i \n", t,  numerator , denominator );
+						}
+							
+						case MIDI_KEY_SIGNATURE:
+						{
+							int accidentals = j->getMetaMessage()[0];
+							int isMinor = j->getMetaMessage()[1];
+							bool isSharp = accidentals < 0 ? false : true;
+							accidentals = accidentals < 0 ? -accidentals : accidentals;
+							if (printMidiInfo)
+								cout << t << ": Key signature: " << accidentals << " "
+								<< (isSharp ?
+								(accidentals > 1 ? "sharps" : "sharp") :
+								(accidentals > 1 ? "flats" : "flat"))
+								<< (isMinor ? ", minor" : ", major") << endl;
+						}
+							
+					}
+					
+					
+					if (name != "") {
+						if (printable) {
+							cout << t << ": File meta event: code " << code
+							<< ": " << name << ": \"" << j->getMetaMessage()
+							<< "\"" << endl;
+						} else {
+							cout << t << ": File meta event: code " << code
+							<< ": " << name << ": ";
+							for (int k = 0; k < j->getMetaMessage().length(); ++k) {
+								cout << (int)j->getMetaMessage()[k] << " ";
+							}
+						}
+					}
+					continue;
+				}
+				
+				switch (j->getMessageType()) {
+						
+					case MIDI_NOTE_ON:
+						if (printMidiInfo)
+						cout << t << ": Note: channel " << ch
+						<< " duration " << j->getDuration()
+						<< " pitch " << j->getPitch()
+						<< " velocity " << j->getVelocity() 
+						<< "event time " << myMidiEvents.getEventTimeMillis(t) << endl;
+				
+						
+						if (noteOnIndex == 0  || t < firstTickTime){
+							//easier just to pick the minimum
+							firstTickTime = t;
+							printf("FIRST TICK TIME %i\n", firstTickTime);
+						}
+						
+						noteOnIndex++;
+						
+						v.clear();
+						
+					//	printf("note on at %i\n", t);
+						
+						if (!chopBeginning)
+							v.push_back(t);
+						else
+							v.push_back(t - firstTickTime);
+						
+						v.push_back(j->getPitch());
+						v.push_back(j->getVelocity());
+						v.push_back(j->getDuration());
+						myMidiEvents.recordedNoteOnMatrix.push_back(v);
+						
+						myMidiEvents.noteOnMatches.push_back(false);
+						
+						break;
+						
+					case MIDI_POLY_AFTERTOUCH:
+						if (printMidiInfo)
+						cout << t << ": Polyphonic aftertouch: channel " << ch
+						<< " pitch " << j->getPitch()
+						<< " pressure " << j->getData2() << endl;
+						break;
+						
+					case MIDI_CTRL_CHANGE:
+					{
+						int controller = j->getData1();
+						string name;
+						switch (controller) {
+							case MIDI_CONTROLLER_BANK_MSB: name = "Bank select MSB"; break;
+							case MIDI_CONTROLLER_VOLUME: name = "Volume"; break;
+							case MIDI_CONTROLLER_BANK_LSB: name = "Bank select LSB"; break;
+							case MIDI_CONTROLLER_MODULATION: name = "Modulation wheel"; break;
+							case MIDI_CONTROLLER_PAN: name = "Pan"; break;
+							case MIDI_CONTROLLER_SUSTAIN: name = "Sustain"; break;
+							case MIDI_CONTROLLER_RESONANCE: name = "Resonance"; break;
+							case MIDI_CONTROLLER_RELEASE: name = "Release"; break;
+							case MIDI_CONTROLLER_ATTACK: name = "Attack"; break;
+							case MIDI_CONTROLLER_FILTER: name = "Filter"; break;
+							case MIDI_CONTROLLER_REVERB: name = "Reverb"; break;
+							case MIDI_CONTROLLER_CHORUS: name = "Chorus"; break;
+							case MIDI_CONTROLLER_NRPN_1: name = "NRPN 1"; break;
+							case MIDI_CONTROLLER_NRPN_2: name = "NRPN 2"; break;
+							case MIDI_CONTROLLER_RPN_1: name = "RPN 1"; break;
+							case MIDI_CONTROLLER_RPN_2: name = "RPN 2"; break;
+							case MIDI_CONTROLLER_SOUNDS_OFF: name = "All sounds off"; break;
+							case MIDI_CONTROLLER_RESET: name = "Reset"; break;
+							case MIDI_CONTROLLER_LOCAL: name = "Local"; break;
+							case MIDI_CONTROLLER_ALL_NOTES_OFF: name = "All notes off"; break;
+						}
+						if (printMidiInfo)
+						cout << t << ": Controller change: channel " << ch
+						<< " controller " << j->getData1();
+						if (name != "") cout << " (" << name << ")";
+						cout << " value " << j->getData2() << endl;
+					}
+						break;
+						
+					case MIDI_PROG_CHANGE:
+						if (printMidiInfo)
+						cout << t << ": Program change: channel " << ch
+						<< " program " << j->getData1() << endl;
+						break;
+						
+					case MIDI_CHNL_AFTERTOUCH:
+						if (printMidiInfo)
+						cout << t << ": Channel aftertouch: channel " << ch
+						<< " pressure " << j->getData1() << endl;
+						break;
+						
+					case MIDI_PITCH_BEND:
+						if (printMidiInfo)
+						cout << t << ": Pitch bend: channel " << ch
+						<< " value " << (int)j->getData2() * 128 + (int)j->getData1() << endl;
+						break;
+						
+					case MIDI_SYSTEM_EXCLUSIVE:
+						if (printMidiInfo)
+						cout << t << ": System exclusive: code "
+						<< (int)j->getMessageType() << " message length " <<
+						j->getMetaMessage().length() << endl;
+						break;
+						
+						
+				}
+				
+				
+			}
+			
+			
+		}
+	if (printMidiInfo)
+	myMidiEvents.printRecordedEvents();
+	
+	//printMeasuresSoFar(myMidiEvents);
+	
+	if (myMidiEvents.recordedNoteOnMatrix.size() > 0){
+		
+		printf("END FILE MEASURE UPDATE\n");
+		updateMeasureToTickPosition(myMidiEvents.recordedNoteOnMatrix[myMidiEvents.recordedNoteOnMatrix.size()-1][0], myMidiEvents);
+	//	printMeasuresSoFar(myMidiEvents);
+	}
+	
+//	printf("|||||||||||||||||||||| \n\n\n\n\n\n\n");
+	myMidiEvents.reorderMatrixFromNoteTimes(myMidiEvents.recordedNoteOnMatrix);
+	myMidiEvents.correctTiming(myMidiEvents.recordedNoteOnMatrix);
+	myMidiEvents.doublecheckOrder(myMidiEvents.recordedNoteOnMatrix);
+
+	createEventTiming(myMidiEvents);
+	
+	printf("BEFORE DOING MEASURE UPDATE\n first tick pos is %i\n", firstTickTime);
+//	printMeasuresSoFar(myMidiEvents);
+	if (chopBeginning)
+		correctMeasuresTiming(myMidiEvents);
+	
+	if (printMidiInfo)
+	myMidiEvents.printRecordedEvents();	
+	
+	printf("Duration of MIDI file is %f \n", myMidiEvents.recordedEventTimes[myMidiEvents.recordedEventTimes.size()-1]);
+	
+	//printMeasuresSoFar(myMidiEvents);
+	
+}//end cannam midi main
+	
+
+void CannamMidiFileLoader::createEventTiming( midiEventHolder& myMidiEvents){
+	
+	long t;
+	t = myMidiEvents.recordedNoteOnMatrix[0][0];
+	firstNoteTime = myMidiEvents.getEventTimeMillis(t);
+	
+	for (int i = 0; i < myMidiEvents.recordedNoteOnMatrix.size();i++){
+		t = myMidiEvents.recordedNoteOnMatrix[i][0];
+		
+		if (!chopBeginning)
+			myMidiEvents.recordedEventTimes.push_back(myMidiEvents.getEventTimeMillis(t));
+		else {
+			myMidiEvents.recordedEventTimes.push_back(myMidiEvents.getEventTimeMillis(t) - firstNoteTime);
+			
+		}
+	}
+	
+}
+
+void CannamMidiFileLoader::setTempoFromMidiValue(long tempo,  midiEventHolder& myMidiEvents){
+	myMidiEvents.tempo = 60000000.0 / double(tempo);
+	myMidiEvents.period = double(tempo)/1000.0;
+	myMidiEvents.ticksFactor = myMidiEvents.pulsesPerQuarternote / myMidiEvents.period;
+}
+	
+
+void CannamMidiFileLoader::newTimeSignature(int ticks, int numerator, int denominator, midiEventHolder& myMidiEvents){
+
+	updateMeasureToTickPosition(ticks, myMidiEvents);
+	
+	ticksPerMeasure = myMidiEvents.pulsesPerQuarternote * 4 * numerator / denominator;
+	
+}
+
+void CannamMidiFileLoader::updateMeasureToTickPosition(int ticks,  midiEventHolder& myMidiEvents){
+	printf("update measure at tick pos %i at tpm %i\n", ticks, ticksPerMeasure);
+	
+	int measureVectorSize = myMidiEvents.measureVector.size();
+	int lastMeasurePosition = 0;
+//	if (chopBeginning)
+//		lastMeasurePosition = -1*firstTickTime;
+	
+	if (measureVectorSize > 0)
+		lastMeasurePosition = myMidiEvents.measureVector[measureVectorSize-1];
+
+	
+while (lastMeasurePosition < ticks){
+	//update
+	lastMeasurePosition += ticksPerMeasure;
+	myMidiEvents.measureVector.push_back(lastMeasurePosition);
+//	cout << "MEASURE " << myMidiEvents.measureVector.size()-1 << " is " << lastMeasurePosition << endl;
+//	printf("MEASURE %i is %i \n", (int)myMidiEvents.measureVector.size()-1 , lastMeasurePosition);
+	}
+}
+
+
+void CannamMidiFileLoader::correctMeasuresTiming(midiEventHolder& myMidiEvents){
+	//correct measures
+	for (int i = 0;i <myMidiEvents.measureVector.size();i++){
+		myMidiEvents.measureVector[i] -= firstTickTime;
+	}
+	printf("AFTER DOING MEASURE UPDATE\n");
+	printMeasuresSoFar(myMidiEvents);
+}
+
+void CannamMidiFileLoader::printMeasuresSoFar(midiEventHolder& myMidiEvents){
+	for (int i = 0;i < myMidiEvents.measureVector.size();i++){
+		printf("measure [%i] at %i\n", i, myMidiEvents.measureVector[i]);
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/CannamMidiFileLoader.h	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,45 @@
+/*
+ *  CannamMidiFileLoader.h
+ *  midi-score-follower
+ *
+ *  Created by Chris Cannam on 19/08/2011.
+ *  Copyright 2011 QMUL. All rights reserved.
+ *
+ */
+
+#ifndef CANNAM_MIDI_FILE_LOADER
+#define  CANNAM_MIDI_FILE_LOADER
+
+#include "MIDIFileReader.h"
+//#include "MIDIEvent.h"
+#include "midiEventHolder.h"
+using namespace MIDIConstants;
+
+class CannamMidiFileLoader{
+	
+public:
+	CannamMidiFileLoader();
+	
+	typedef std::vector<double> DoubleVector;
+	
+	int loadFile(std::string& filename, midiEventHolder& myMidiEvents);
+
+	void createEventTiming( midiEventHolder& myMidiEvents);
+	void setTempoFromMidiValue(long tempo,  midiEventHolder& myMidiEvents);
+	double firstNoteTime;
+	int firstTickTime;
+	bool chopBeginning;
+	
+	typedef std::vector<int> IntVector;
+	IntVector v;
+	int noteOnIndex;
+	
+	int ticksPerMeasure;
+	void newTimeSignature(int ticks, int numerator, int denominator, midiEventHolder& myMidiEvents);
+	void updateMeasureToTickPosition(int ticks,  midiEventHolder& myMidiEvents);
+	bool printMidiInfo;
+	void printMeasuresSoFar(midiEventHolder& myMidiEvents);
+	void correctMeasuresTiming(midiEventHolder& myMidiEvents);
+	
+};
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/DynamicVector.cpp	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,293 @@
+/*
+ *  DynamicVector.cpp
+ *  midiCannamReader
+ *
+ *  Created by Andrew on 18/07/2011.
+ *  Copyright 2011 QMUL. All rights reserved.
+ *
+ */
+
+
+#include "DynamicVector.h"
+
+DynamicVector::DynamicVector(){
+	length = 0;
+	arraySize = 0;
+	maximumValue = 0;
+	MAPestimate = 0;
+	offset = 0;
+	scalar = 1;
+	integratedEstimate = length/2;
+	
+	gaussianLookupMean = (double) GAUSSIAN_LOOKUP_LENGTH/2;
+	gaussianLookupStdDev = (double)(GAUSSIAN_LOOKUP_LENGTH/16);
+	double factor = 1.0;//(1.0 / (gaussianLookupStdDev*sqrt(2*PI)) );//1.0;//-1.0/(2*PI*sqrt(gaussianLookupStdDev));
+	for (int i = 0;i < GAUSSIAN_LOOKUP_LENGTH;i++){
+	gaussianLookupTable[i] = factor*exp(-1.0*(i-gaussianLookupMean)*(i-gaussianLookupMean)/(2.0*gaussianLookupStdDev*gaussianLookupStdDev));
+	}
+	
+}
+
+void DynamicVector::copyFromDynamicVector(const DynamicVector& dynamicVec){
+	if (dynamicVec.length == length){
+		for (int i = 0;i < length;i++)
+			array[i] = dynamicVec.array[i];
+	}
+	else{
+		printf("CANNOT COPY VECTORS OF NON SAME LENGTH!!\n");
+	}
+}
+
+void DynamicVector::createVector(int len){
+	array.clear();
+	for (int i = 0; i < len;i++){
+		array.push_back(0);
+	}
+	length = len;
+	arraySize = array.size();
+	integratedEstimate = length/2;
+}
+
+
+double DynamicVector::getMaximum(){
+	int i;
+	double max = 0;
+	for (i=0;i < length;i++){	
+		if (array[i] > max){
+			max = array[i];
+			MAPestimate = i;
+		}
+	}
+	maximumValue = max;
+	return max;
+}
+
+double DynamicVector::getIntegratedEstimate(){
+	//returns the index of the integrated average - where the probability distribution is centred
+	integratedEstimate = 0;
+	double integratedTotal = 0;
+	for (int i = 0;i < length;i++){
+		integratedEstimate += array[i]*i;
+		integratedTotal += array[i];
+	}
+	if (integratedTotal > 0){
+		integratedEstimate /= integratedTotal;
+	}
+	return integratedEstimate;
+}
+
+void DynamicVector::updateIntegratedEstimate(){
+	//returns the index of the integrated average - where the probability distribution is centred
+	integratedEstimate = 0;
+	double integratedTotal = 0;
+	for (int i = 0;i < length;i++){
+		integratedEstimate += array[i]*i;
+		integratedTotal += array[i];
+	}
+	if (integratedTotal > 0){
+		integratedEstimate /= integratedTotal;
+	}
+
+}
+
+void DynamicVector::updateLimitedIntegratedEstimate(){
+	//returns the index of the integrated average - where the probability distribution is centred
+	//but limited round the MAP estimate
+	double tmp = getMaximum();
+	int limit = min(MAPestimate, length - MAPestimate);
+	int start = max(0, MAPestimate - limit);
+	int end = min(MAPestimate + limit, length-1);
+	
+	integratedEstimate = 0;
+	double integratedTotal = 0;
+	for (int i = start;i <= end;i++){
+		integratedEstimate += array[i]*i;
+		integratedTotal += array[i];
+	}
+	if (integratedTotal > 0){
+		integratedEstimate /= integratedTotal;
+	}
+	
+}
+
+
+void DynamicVector::zero(){
+	for (int i = 0;i < array.size();i++)
+		array[i] = 0;
+}
+
+void DynamicVector::renormalise(){
+	double tmpMax = getMaximum();
+	if (tmpMax > 0){
+//	printf("renormalise : max is %f and size is %i\n", tmpMax, arraySize);		
+		for (int i = 0;i < array.size();i++)
+			array[i] /= tmpMax;
+
+	}
+	//printArray();
+}
+
+void DynamicVector::doProduct(DynamicVector& arrayOne, DynamicVector& arrayTwo){
+
+	for (int i = 0;i < arrayOne.length;i++)
+		array[i] = arrayOne.array[i] * arrayTwo.array[i];
+}
+
+
+void DynamicVector::printArray(){
+	for (int i = 0;i < arraySize;i++){
+		printf("[%i] = %f\n", i, array[i]);
+	}
+}
+
+void DynamicVector::translateDistribution(int translationIndex){
+	int tmpIndex;
+	DoubleVector tmpArray;
+	int i;
+
+	for (i=0;i < arraySize;i++){
+		tmpArray.push_back(array[i]);
+	}
+	//translate values
+	for (i=0;i < arraySize;i++){
+		tmpIndex = (i + translationIndex + arraySize)%arraySize;
+		array[tmpIndex] = tmpArray[i]; 
+	}
+	tmpArray.clear();
+	//now delete tmp array
+}
+
+void DynamicVector::addGaussianShape(const double& mean, const double& StdDev, double factor){
+	
+	int i;
+	double std_dev_factor = (2*StdDev*StdDev);
+	factor *= (1/(StdDev*sqrt(2*PI)));
+	int maxVal = min((int) array.size(), (int)(mean + 4.8*StdDev));
+	int minVal = max(0, (int)(mean - 4.8*StdDev));
+	
+	for (i=minVal;i < maxVal;i++){
+		array[i] += factor*exp(-1*(i-mean)*(i-mean)/(std_dev_factor));
+	}
+	
+//	addGaussianShapeByLookupTable(mean, StdDev, factor);
+}
+
+void DynamicVector::addGaussianShapeByLookupTable(double& mean, double& StdDev, double factor){
+	int i;
+	int lookupIndex ;
+	factor *= (1/(StdDev*sqrt(2*PI)));
+	for (i=0;i<array.size()-1;i++){
+		lookupIndex = round(getLookupIndex(i, mean, StdDev));
+		array[i] += factor*gaussianLookupTable[lookupIndex];
+	}
+	//printf("ADDED GAUSSIAN SHAPE %i\n", (int)array.size());
+}
+
+double DynamicVector::getLookupIndex(const int& i, const double& mean, const double& StdDev){
+	
+	double Z = ((double)i - mean)/StdDev;
+	double lookupIndex = Z*gaussianLookupStdDev + gaussianLookupMean;
+	
+	if (lookupIndex < 0)
+		lookupIndex = 0;
+	
+	if (lookupIndex >= GAUSSIAN_LOOKUP_LENGTH)
+		lookupIndex = GAUSSIAN_LOOKUP_LENGTH-1;
+	
+//	(i - mean)*(i-mean)*(GAUSSIAN_LOOKUP_LENGTH*GAUSSIAN_LOOKUP_LENGTH/16.0)/(StdDev*StdDev);
+	return lookupIndex;
+}
+
+void DynamicVector::addTriangularShape(double mean, double width, double factor){
+	int i;
+
+	for (i= max(0., (double)(mean - width));i < min((mean+width), (double)array.size());i++){
+		array[i] += factor * abs(i - mean) / mean;		
+	}
+
+}
+
+void DynamicVector::addConstant(const double& value){
+	for (int i=0;i<array.size();i++){
+		array[i] += value;
+	}
+}
+
+
+void DynamicVector::addToIndex(const int& index, const double& constant){
+	array[index] += constant;
+}
+
+
+double DynamicVector::getIndexInRealTerms(const int& index){
+	if (index < arraySize)
+		return (offset + scalar*index);
+	else
+		return 0;
+}
+
+double DynamicVector::getRealTermsAsIndex(double value){
+	value -= offset;
+	value /= scalar;
+	
+	return value;
+	
+}
+
+double DynamicVector::getValueAtMillis(const double& millis){
+	
+	int index = round(getRealTermsAsIndex(millis));
+		if (index >= 0 && index < length)
+			return array[index];
+		else
+			return 0;
+}
+
+void DynamicVector::drawVector(const int& minIndex, const int& maxIndex){
+
+		
+		double stepSize = ofGetWidth() / (double)(maxIndex - minIndex);
+		double screenHeight = (double) ofGetHeight();
+		double maxVal = getMaximum();
+	
+		int startInt = max(1,minIndex+1);
+		int endInt = min(maxIndex, (int)array.size());
+		double heightConstant = screenHeight / maxVal;
+		int lastHeightPixel = heightConstant * (maxVal - array[startInt-1]);
+		int newHeightPixel;
+		for (int i = startInt;i < endInt;i++){
+			newHeightPixel = (int) heightConstant * (maxVal - array[i]);
+			ofLine (stepSize*(i-1), lastHeightPixel, stepSize*i, newHeightPixel);
+			lastHeightPixel = newHeightPixel;
+		}
+	
+}
+
+
+void DynamicVector::drawConstrainedVector(const int& minIndex, const int& maxIndex, const int& minScreenIndex, const int& maxScreenIndex){
+	//constrain the height and width
+	
+	double stepSize = (maxScreenIndex - minScreenIndex) / (double)(maxIndex - minIndex);//step size in pixels per array bin 
+	double screenHeight = ofGetHeight();
+	double maxVal = getMaximum();
+
+	//OPTIMIZE!! XXX could just add stepsize each time
+	//not add minindex each time
+	int i = max(1,minIndex+1);
+//	ofDrawBitmapString("i = "+ofToString(i)+"  :: screen min: "+ofToString(minScreenIndex + stepSize*(i-minIndex-1)), 20, 640);
+	
+	while ((minScreenIndex + stepSize*(i-minIndex)) < 0)
+		i++;//only draw what is on the screen
+	
+	for ( ; i < min(maxIndex+1, (int)array.size());i++){
+		ofLine (minScreenIndex + (stepSize*(i-minIndex-1)), screenHeight * (1 - array[i-1] / maxVal), 
+				minScreenIndex + (stepSize*(i-minIndex)),	 screenHeight * (1 - array[i] / maxVal) );
+		
+	}
+	
+	ofLine(minScreenIndex, screenHeight, minScreenIndex, screenHeight/2);
+	ofLine(maxScreenIndex, screenHeight, maxScreenIndex, screenHeight/2);
+	
+//	ofDrawBitmapString(ofToString(stepSize, 2)+"  "+ofToString(maxScreenIndex - minScreenIndex, 0), 20, 600);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/DynamicVector.h	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,68 @@
+/*
+ *  DynamicVector.h
+ *  midiCannamReader
+ *
+ *  Created by Andrew on 18/07/2011.
+ *  Copyright 2011 QMUL. All rights reserved.
+ *
+ */
+
+//OPTIMIZE CONSTRAINED VECTOR
+
+#include "stdlib.h"
+#include "ofMain.h"
+
+#ifndef _DYNAMIC_VECTOR
+#define _DYNAMIC_VECTOR
+#define GAUSSIAN_LOOKUP_LENGTH 1000000
+
+class DynamicVector{
+public:
+	DynamicVector();
+
+	void createVector(int len);
+	void renormalise();
+	void translateDistribution(int translationIndex);
+	typedef std::vector<double> DoubleVector;
+	DoubleVector array;
+	double getMaximum();
+	double getIntegratedEstimate();
+	double getLookupIndex(const int& i, const double& mean, const double& StdDev);
+	void addGaussianShapeByLookupTable(double& mean, double& StdDev, double factor);
+	double gaussianLookupTable[GAUSSIAN_LOOKUP_LENGTH];
+	double gaussianLookupMean, gaussianLookupStdDev;
+	double integratedEstimate;
+	void updateIntegratedEstimate();
+	void updateLimitedIntegratedEstimate();
+	
+	void drawVector(const int& minIndex, const int& maxIndex);
+	void drawConstrainedVector(const int& minIndex, const int& maxIndex, const int& minScreenIndex, const int& maxScreenIndex);
+
+	void addConstant(const double& value);
+	void addGaussianShape(const double& mean, const double& stddev, double factor);
+	void addTriangularShape(double mean, double width, double factor);
+	void addToIndex(const int& index, const double& constant);
+	
+	void doProduct(DynamicVector& arrayOne, DynamicVector& arrayTwo);
+		
+	double getIndexInRealTerms(const int& index);
+	double getRealTermsAsIndex(double value);
+	double getValueAtMillis(const double& millis);
+	
+	void printArray();
+	void zero();
+	
+	void copyFromDynamicVector(const DynamicVector& dynamicVec);
+	
+	//variables
+	int length, arraySize;
+	double maximumValue;
+	int MAPestimate;
+	
+	double offset;
+	double scalar;//each array point is this much of the quantity
+	//i.e. array[index] contributes to (offset + scalar*index) in real terms
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/MidiInputStream.cpp	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,108 @@
+/*
+ *  MidiInputStream.cpp
+ *  MuseScoreMidiFollower
+ *
+ *  Created by Andrew on 03/12/2011.
+ *  Copyright 2011 QMUL. All rights reserved.
+ *
+ */
+
+#include "MidiInputStream.h"
+
+
+MidiInputStream::MidiInputStream(){
+	reset();
+}
+
+
+void MidiInputStream::reset(){
+
+	midiInputEvents.clear();
+	midiInputTimes.clear();
+	
+	eventTimesForNote.clear();
+	eventTimesForNote.assign (127, 0.0);
+
+	
+	totalNotesRecievedByPitch.clear();
+	totalNotesRecievedByPitch.assign (127, 0);
+	
+}
+
+bool MidiInputStream::noteInReceived(ofxMidiEventArgs &args){
+//	printf("midi input received port %i, channel %i status %i, byteOne %i, byteTwo %i\n", args.port,args.channel, args.status, newPitch, args.byteTwo);
+	bool noteOn = false;
+	int newPitch;
+	switch (args.status) {
+		
+		case 144:
+			newPitch = (int)args.byteOne;
+			newPitch += (*transposeVal);
+			
+	//		printf("note on %i", args.byteOne);
+			if (args.byteTwo){
+			//	printf("volume is %i\n", args.byteTwo);
+				double time = ofGetElapsedTimeMillis();
+				eventTimesForNote[newPitch] = time;
+				noteOn = true;
+				newNoteCounted(newPitch);
+				
+			}else{
+				double time = ofGetElapsedTimeMillis();
+				time -= eventTimesForNote[newPitch];
+			//	printf(", NOTE OFF after %f millis %f ticks\n", time, time * (*factor));
+				
+				int index = endNote(newPitch);
+				//correct the length of note time
+				if (midiInputEvents[index].size() > 2)
+				midiInputEvents[index][3] = (time * (*factor));
+			}
+			
+			break;
+		default:
+			break;
+	}
+	
+	return noteOn;
+	//cout << "MIDI message [port: " << args.port << ", channel: " << args.channel << ", status: " << args.status << ", byteOne: " << newPitch << ", byteTwo: " << args.byteTwo << ", timestamp: " << args.timestamp << "]" << endl;
+}
+
+void  MidiInputStream::newNoteCounted(const int& pitch){
+	totalNotesRecievedByPitch[pitch] += 1;
+}
+
+int MidiInputStream::endNote(int notePitch){
+	int index = midiInputEvents.size()-1;
+	while (index > 0 && midiInputEvents[index][1] != notePitch){
+		index--;
+	}
+//	printf("found index %i\n", index);
+	return index;
+}
+
+double MidiInputStream::calculateTotalScore(midiEventHolder& midiEvents){
+	double gameScore = 1.0;
+	double totalNotes = 1.0;
+	if (totalNotesRecievedByPitch.size() > 100){
+		for (int i = 30;i < 90;i++){
+			gameScore += abs(totalNotesRecievedByPitch[i] - midiEvents.recordedTotalNoteCounterByPitch[i]);
+			totalNotes += midiEvents.recordedTotalNoteCounterByPitch[i];
+		}
+	}
+	return 1.0 - (gameScore / totalNotes);
+
+}
+
+void MidiInputStream::printNotes(){
+	printf("live input \n");
+	for (int i = 0;i < midiInputEvents.size();i++){
+		printf("ticktime %i :: pitch %i @ millis %f\n",  midiInputEvents[i][0],  midiInputEvents[i][1],  midiInputTimes[i]);
+	}
+}
+
+void MidiInputStream::printTotalCount(){
+	for (int i = 0;i < totalNotesRecievedByPitch.size();i++){
+		printf("LIVE PLAYED TOTAL[%i] := %i\n", i, totalNotesRecievedByPitch[i]);
+	}
+}
+	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/MidiInputStream.h	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,52 @@
+/*
+ *  MidiInputStream.h
+ *  MuseScoreMidiFollower
+ *
+ *  Created by Andrew on 03/12/2011.
+ *  Copyright 2011 QMUL. All rights reserved.
+ *
+ */
+
+#ifndef MIDI_INPUT_STREAM
+#define MIDI_INPUT_STREAM
+
+#include "ofMain.h"
+#include "ofxMidi.h"
+#include "midiEventHolder.h"
+//WOULD BE GOOD TO USE STD CONSTANTS here
+//#include "MIDIFileReader.h"
+//using namespace MIDIConstants;
+
+class MidiInputStream{
+	
+public:
+	MidiInputStream();
+	bool noteInReceived(ofxMidiEventArgs &args);
+	void reset();
+	void printNotes();
+	int endNote(int notePitch);	
+	
+	typedef std::vector<int> IntVector;
+	typedef std::vector<IntVector> IntMatrix;
+
+	typedef std::vector<double> DoubleVector;
+	DoubleVector eventTimesForNote;
+	
+	double calculateTotalScore(midiEventHolder& midiEvents);
+	
+	IntMatrix midiInputEvents;
+	DoubleVector midiInputTimes;
+	IntVector v;
+	IntVector totalNotesRecievedByPitch;
+	void newNoteCounted(const int& pitch);
+	void printTotalCount();
+	
+	double* startTime;
+	midiEventHolder* eventHolder;
+	
+	int* transposeVal;
+	
+	double* factor;
+	
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/drawMidiNotes.cpp	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,87 @@
+/*
+ *  drawMidiNotes.cpp
+ *  midiCannamReader
+ *
+ *  Created by Andrew on 17/07/2011.
+ *  Copyright 2011 QMUL. All rights reserved.
+ *
+ */
+
+#include "drawMidiNotes.h"
+
+drawMidiNotes::drawMidiNotes(){
+
+	
+	ticksPerScreen = 8000;
+	tickLocation = 0;
+	pulsesPerQuarternote = 240;
+	noteArrayIndex = 0;
+	noteMinimum = 30;
+	noteMaximum = 96;
+	screenWidth = ofGetWidth();
+	screenHeight = ofGetHeight();
+	noteHeight = screenHeight / (float)(noteMaximum - noteMinimum);
+}
+
+void drawMidiNotes::reset(){
+	noteArrayIndex = 0;
+	tickLocation = 0;
+	lastPeriodUpdateTime = ofGetElapsedTimeMillis();
+	
+}
+
+void drawMidiNotes::updatePlayPosition(){
+	double timeDifference = ofGetElapsedTimeMillis() - lastPeriodUpdateTime;
+	//this is time diff in milliseconds
+	//then we have 
+	double quarterNoteIntervals = (timeDifference / period);
+	tickLocation = quarterNoteIntervals * pulsesPerQuarternote; 
+
+}
+
+void drawMidiNotes::drawFile(const IntMatrix& noteOnMatrix){
+	int size = noteOnMatrix.size();
+	if (size > 0){
+
+		int numberOfScreensIn = tickLocation / ticksPerScreen;
+		
+	while (noteArrayIndex < noteOnMatrix.size() && tickLocation > noteOnMatrix[noteArrayIndex][0] )
+		noteArrayIndex++;
+	
+	while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < noteOnMatrix[noteArrayIndex][0])
+		noteArrayIndex--;
+		
+		//need to start where we currently are in file
+		int maxNoteIndexToPrint	= noteArrayIndex;
+		int minNoteIndexToPrint = noteArrayIndex;
+		
+		
+		while (maxNoteIndexToPrint < noteOnMatrix.size() && noteOnMatrix[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen )
+			maxNoteIndexToPrint++;
+		
+		while (minNoteIndexToPrint > 0 && minNoteIndexToPrint < size && noteOnMatrix[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen)
+			minNoteIndexToPrint--;
+		
+		
+		for (int tmpIndex = minNoteIndexToPrint;tmpIndex < maxNoteIndexToPrint;tmpIndex++){
+		int xLocation = (float)(noteOnMatrix[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*screenWidth/(float)ticksPerScreen;
+			int duration = (float)(noteOnMatrix[tmpIndex][3]*screenWidth)/(float)ticksPerScreen;
+			
+			
+		int yLocation = screenHeight - ((noteOnMatrix[tmpIndex][1] - noteMinimum )*screenHeight/ (float)(noteMaximum - noteMinimum));						 
+		ofRect(xLocation,yLocation, duration,  noteHeight);
+		
+		}
+		
+			int xLocation = (float)(tickLocation - numberOfScreensIn*ticksPerScreen)*screenWidth/(float)ticksPerScreen;
+		ofLine(xLocation, 0, xLocation, screenHeight);
+	
+	//	if (noteArrayIndex < size )
+	//		printf("tick %i :: note array :%i: %i\n", tickLocation, noteArrayIndex, noteOnMatrix[noteArrayIndex][0]);
+	//	else
+	//		printf("end of file\n");
+
+		
+	}	
+		
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/drawMidiNotes.h	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,42 @@
+/*
+ *  drawMidiNotes.h
+ *  midiCannamReader
+ *
+ *  Created by Andrew on 17/07/2011.
+ *  Copyright 2011 QMUL. All rights reserved.
+ *
+ */
+
+
+#include "ofMain.h"
+
+class drawMidiNotes{
+public:
+	drawMidiNotes();
+	void updatePlayPosition();
+	
+	typedef std::vector<double> DoubleVector;
+	typedef std::vector<DoubleVector> DoubleMatrix;
+	
+	DoubleMatrix beatPeriodMatrix;
+	
+	typedef std::vector<int> IntVector;
+	typedef std::vector<IntVector> IntMatrix;
+	
+	void drawFile(const IntMatrix& noteOnMatrix);
+	void reset();
+	
+	int ticksPerScreen;
+	int tickLocation;
+	int noteArrayIndex;
+	
+	int noteMinimum, noteMaximum;
+	int screenWidth, screenHeight;
+	float noteHeight;
+	float tempo;
+	double period;
+	int pulsesPerQuarternote;
+	double lastPeriodUpdateTime;
+					 
+	
+};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/hackday_notes.txt	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,36 @@
+hackney wiki - london hacks link for full list
+
+the matrix
+
+ctrl
+
+beat tracking
+
+musochackday app - spotifyle system
+
+dylanjones.info - Facebook music taste game
+
+drivetime - code on github
+
+scotd.herokuapp.com
+
+mmsm.herokuapp.com - yves' monster mashup
+
+ethicsgirls.com/pitchforkeffect
+
+github for "guess the intro" app in spiffy
+
+owl octave!
+
+
+gig out iphone app: share test flight - foursquare venue data - gigs around you - at export?? on twitter
+
+chordify spotify app and pretentiometer
+
+alarm clock app
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/main.cpp	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,25 @@
+#include "ofMain.h"
+#include "testApp.h"
+#include "ofAppGlutWindow.h"
+#include "ofxArgs.h"
+
+//========================================================================
+int main(int argc, char *argv[]){
+	ofxArgs* args = new ofxArgs(argc, argv);
+	
+	if (argc > 0){
+		cout << "MIDI FOLLOW (" << argc << ")  arg[1] is " << argv[1] << endl;
+	}
+	
+    ofAppGlutWindow window;
+	ofSetupOpenGL(&window, 1024,768, OF_WINDOW);			// <-------- setup the GL context
+
+	// this kicks off the running of my app
+	// can be OF_WINDOW or OF_FULLSCREEN
+	// pass in width and height too:
+	
+	ofRunApp(new testApp(args));
+	delete args;
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/midiEventHolder.cpp	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,1216 @@
+/*
+ *  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"
+
+midiEventHolder::midiEventHolder(){
+//	recordedNoteOnIndex = 0;
+	
+	useTempoPrior = false;//puts sine wave round tempo
+	confidenceWeightingUsed = true;
+	newOptimalMethod = true;
+	
+	matchWindowWidth = 8000;//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
+	speedPriorValue = 1.0;
+	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;
+	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;
+	
+	recordedTotalNoteCounterByPitch.clear();
+	recordedTotalNoteCounterByPitch.assign(127,0);
+	totalNoteCounterIndex = 0;
+	
+	interNoteIntervals.clear();
+	
+	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();
+	measureVector.clear();
+	//played events:
+	playedEventTimes.clear();
+	playedNoteOnMatrix.clear();
+	matchMatrix.clear();
+	bestMatchFound.clear();
+	periodValues.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 (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);
+	
+//	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();
+	}
+	 
+}
+
+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::findLocalTempoPairsWeightedForConfidence(){
+	bool needToUpdate = false;
+	
+	//adapted this to just use the best match for each note
+	
+	int currentPlayedIndex = playedNoteOnMatrix.size()-1;
+	//	printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]);
+	//	printMatchesFound();
+	//	printMatchMatrix();
+	//	printf("possible notes \n");
+	
+	bayesStruct.setLikelihoodToConstant();
+	
+	for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){
+		
+		//iterate through the recently matched events - even dodgy matches included
+		//size, index of match0, index of match1, ....
+		int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1];
+		
+		double currentMatchConfidence = matchConfidence[currentPlayedIndex][i+1];//new confidence
+		
+		int previousIndex = currentPlayedIndex-1;
+		
+		while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) {
+			double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
+			
+			//			for (int k = 0;k < matchMatrix[previousIndex][0];k++)
+			int recordedPreviousIndex = bestMatchFound[previousIndex];//matchMatrix[previousIndex][k+1];
+			
+			//double previousMatchConfidence = matchConfidence[previousIndex][k+1];
+			
+			
+			double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex];
+			
+			
+			//we want the speed of the recording relative to that of the playing live
+			
+			double speedRatio = recordedTimeDifference / playedTimeDifference;
+			if (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){
+				
+				printf("(%i)", matchMatrix[currentPlayedIndex][i+1]);
+				printf("[%i] :: ", recordedPreviousIndex);
+				//	printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence);
+				printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference);
+				printf("update on speed ratio %f\n", speedRatio);
+				
+				//	matchString += " speed: "+ofToString(speedRatio, 3);
+				//	commented for debug
+				
+				
+				double priorWeighting = 1;
+				
+				if (useTempoPrior)
+					priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed
+				
+				
+				//	double weighting = previousMatchConfidence * currentMatchConfidence ;
+				double amount =	(1-bayesStruct.speedLikelihoodNoise)*priorWeighting/10;
+				bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match
+				tempoSpeedString += ofToString(recordedPreviousIndex) + "  " + ofToString(speedRatio, 2) + "  "+ofToString(amount, 2) += " \n";
+				
+				needToUpdate = true;
+			}
+			//		printf("\n");	
+			
+			
+			previousIndex--;
+		}//end while previousindex countdown
+	}//end for loop through possible current matches
+	
+	if (needToUpdate)
+		bayesStruct.updateTempoDistribution();
+	//printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
+}
+*/
+
+
+void midiEventHolder::updatePlayPosition(){
+	
+	//in actual fact if we are changing the speed of the play position 
+	//we will need to update this via the file
+	
+	//actually time since beginning of file i think
+	
+	double timeDifference = 0;
+	if (runningInRealTime)
+		timeDifference = ofGetElapsedTimeMillis() - lastPeriodUpdateTime;//elpased - lastperiodupdatetime
+	
+	//this is time diff in milliseconds
+	//then we have 
+	double quarterNoteIntervals = (timeDifference / period);
+	tickLocation = quarterNoteIntervals * pulsesPerQuarternote; 
+	
+	playPositionInMillis = timeDifference;//based on updating from when we change period
+	//this to be added
+	
+	if (runningInRealTime)
+	bayesStruct.updateBestEstimate(timeDifference);
+	
+	updateNoteCounter();
+	
+}
+
+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(80,80,80);//250,100,0);
+		ofLine(xLocation, 0, xLocation, (*screenHeight));
+		
+		xLocation = getLocationFromMillis(bayesStruct.tmpBestEstimate);
+		ofSetColor(150,150,150);//250,100,0);
+		ofLine(xLocation, 0, xLocation, (*screenHeight));
+		
+		
+		//lines where matching window start and end are 
+		ofSetColor(0);//0,100,255);
+		xLocation = getLocationFromMillis(windowStartTime);
+		ofLine(xLocation, 0, xLocation, (*screenHeight));
+		xLocation = getLocationFromMillis(windowStartTime+matchWindowWidth);
+		ofLine(xLocation, 0, xLocation, (*screenHeight));
+		
+		
+		int maxSize = recordedNoteOnMatrix[size-1][0];
+		
+		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();
+		
+	
+//	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 (int)((float)(tickPosition - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen);
+}
+
+int midiEventHolder::getLocationFromMillis(double millisPosition){
+	//(getEventTimeTicks(windowStartTime+matchWindowWidth) - numberOfScreensIn*ticksPerScreen)*(*screenWidth) / (double)ticksPerScreen
+	return (millisPosition - timeOffsetForScreen)*(*screenWidth)/getEventTimeMillis(ticksPerScreen);
+}
+
+
+void midiEventHolder::exampleCrossUpdate(){
+	
+	bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, 200);
+	
+}
+
+
+void midiEventHolder::setStartPlayingTimes(){
+	lastPeriodUpdateTime = getTimeNow(0);//ofGetElapsedTimeMillis();
+	startTime = lastPeriodUpdateTime;
+	
+/*	
+ 	bayesStruct.lastEventTime = 0;//ofGetElapsedTimeMillis();
+	bayesStruct.bestEstimate = 0;
+	bayesStruct.resetArrays();
+	bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
+*/
+	bayesStruct.setStartPlaying();
+	matchString = "";
+}
+
+
+void midiEventHolder::printMatchMatrix(){
+	printf("match matrix:\n");
+	for (int i = 0;i < matchMatrix.size();i++){
+		for (int k = 0;k < matchMatrix[i].size();k++){
+			printf("%i , ", matchMatrix[i][k]);
+		}
+		printf("\n");
+	}
+	
+}
+
+
+
+void midiEventHolder::printRecordedEvents(){
+	printf("Recorded Events:\n");
+	for (int i = 0;i < recordedNoteOnMatrix.size();i++){
+		for (int k = 0;k < recordedNoteOnMatrix[i].size();k++){
+			printf("[%i] = %i ,", i, recordedNoteOnMatrix[i][k]);
+		}
+		if (i < recordedEventTimes.size())
+			printf("time %f \n", recordedEventTimes[i]);
+		else
+			printf("\n");
+	}
+	
+}
+
+
+
+void midiEventHolder::reorderMatrixFromNoteTimes(IntMatrix& noteOnMatrix){
+	double currentTime = -19999.;
+	for (int i = 0;i < noteOnMatrix.size();i++){
+		int nextIndex = getIndexOfMinimumAboveTime(currentTime, noteOnMatrix);
+	//	cout << "index of min time " << currentTime << " is " << nextIndex << " at time " <<  noteOnMatrix[nextIndex][0] << endl;
+	
+		if (nextIndex >= 0 && nextIndex > i &&	noteOnMatrix[nextIndex][0] < noteOnMatrix[i][0] ){
+			//which it should be
+	//		cout << " index " << nextIndex << " at time " << noteOnMatrix[nextIndex][0] << " swaps with inex " << i << " at time  " << noteOnMatrix[i][0] << endl; 
+			noteOnMatrix[i].swap(noteOnMatrix[nextIndex]);
+			currentTime = noteOnMatrix[i][0];
+		}
+		
+	}	
+	//printRecordedEvents();
+
+}
+
+
+
+
+void midiEventHolder::doublecheckOrder(IntMatrix& noteOnMatrix){
+
+	for (int i = 0;i < noteOnMatrix.size();i++){
+		int nextIndex = getIndexOfMinimumAboveIndex(i, noteOnMatrix);
+		if (nextIndex > i){
+			noteOnMatrix[i].swap(noteOnMatrix[nextIndex]);
+		}
+	}	
+}
+
+int midiEventHolder::getIndexOfMinimumAboveIndex(const int& index, IntMatrix& noteOnMatrix){
+	int returnIndex = index;
+	int min = noteOnMatrix[index][0];
+	for (int i = index;i < noteOnMatrix.size();i++){
+		if (noteOnMatrix[i][0] < min){
+			returnIndex = i;
+			min = noteOnMatrix[i][0];
+		}
+	}
+	return returnIndex;
+}
+
+
+int midiEventHolder::getIndexOfMinimumAboveTime(const double& time, IntMatrix& noteOnMatrix){
+	int index = 0;
+	double minimumTime = 100000000.;
+	int bestIndex = -1;
+	while (index < noteOnMatrix.size()){
+	
+		if (noteOnMatrix[index][0] > time && noteOnMatrix[index][0] < minimumTime){
+			bestIndex = index;
+			minimumTime = noteOnMatrix[index][0];
+		}
+			index++;
+	}
+	return bestIndex;
+}
+
+
+
+
+void midiEventHolder::correctTiming(IntMatrix& noteOnMatrix){
+	
+	if (noteOnMatrix.size() > 0 && noteOnMatrix[0][0] < 0) {
+		int offset = noteOnMatrix[0][0];
+		for (int i = 0;i < noteOnMatrix.size();i++){
+			noteOnMatrix[i][0] -= offset;
+		}	
+	}
+
+}
+
+
+void midiEventHolder::printNoteCounter(){
+	for (int i = 0;i < recordedTotalNoteCounterByPitch.size();i++){
+		printf("RECORDED TOTAL[%i] := %i", i, recordedTotalNoteCounterByPitch[i]);
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/midiEventHolder.h	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,169 @@
+/*
+ *  midiEventHolder.h
+ *  midiCannamReader3
+ *
+ *  Created by Andrew on 19/07/2011.
+ *  Copyright 2011 QMUL. All rights reserved.
+ *
+ */
+#ifndef MIDI_EVENT_HOLDER
+#define MIDI_EVENT_HOLDER
+ 
+#include "ofMain.h"
+#include "BayesianArrayStructure.h"
+
+class midiEventHolder{
+
+public:
+	
+	midiEventHolder();
+	void printNotes();
+	
+	typedef std::vector<int> IntVector;
+	typedef std::vector<IntVector> IntMatrix;
+	
+	typedef std::vector<bool> BoolVector;
+	
+	typedef std::vector<double> DoubleVector;
+	typedef std::vector<DoubleVector> DoubleMatrix;
+	
+	//the rehearsal version
+	IntMatrix recordedNoteOnMatrix;//note, velocity, duration
+	DoubleVector recordedEventTimes;
+	
+	IntVector matchesFound;
+	BoolVector noteOnMatches;
+	
+	void drawMidiFile(IntMatrix& midiFileToDraw);
+	
+//	int recordedNoteOnIndex;
+	
+	
+	IntMatrix playedNoteOnMatrix;
+	DoubleVector playedEventTimes;
+	int playedNoteIndex;
+	IntMatrix matchMatrix;
+	IntVector bestMatchFound;
+	IntVector measureVector;
+	
+	IntVector recordedTotalNoteCounterByPitch;
+	int totalNoteCounterIndex;
+	
+	DoubleMatrix matchConfidence;
+	double totalConfidence;
+	
+	double mouseX;
+	
+	void clearAllEvents();
+	bool drawTempoMode, drawPhaseMode;
+	
+	double minimumMatchSpeed , maximumMatchSpeed;
+	
+	double period, pulsesPerQuarternote;
+	double getEventTimeMillis(double ticks);
+	double getEventTimeTicks(double millis);
+	
+	int getLocationFromTicks(double tickPosition);
+	int getLocationFromMillis(double millisPosition);
+	
+	double getTimeNow(double eventTime);
+	bool runningInRealTime;
+	
+	double windowStartTime;
+	
+	//functions for finding match to incoming note
+	void newNoteOnEvent(int pitch, int velocity, double timePlayed);
+	int findLocalMatches(int notePitch);
+	bool checkIfMatchedNote(const int& tmpIndex);
+	int findMatch(const int& notePitch, const int& startTime, const int& endTime);
+	
+	void updateTempo();
+	void findLocalTempoPairs();
+	void findLocalTempoPairsWeightedForConfidence();
+	void findOptimumTempoPairsToCurrentBestMatch();
+	double getBestSpeedEstimate(const int& currentPlayedIndex, const int& equivalentRecordedIndex);
+	
+	
+	void 	calcuateNewInterNoteIntervals();
+	
+	double likelihoodWidth;
+	double likelihoodToNoiseRatio;
+	
+	void printMatchMatrix();
+	void printRecordedEvents();
+	void printNoteCounter();
+	void updateNoteCounter();
+	
+	void setMatchLikelihoods(int numberOfMatches);
+	
+	void setStartPlayingTimes();
+	void setSpeedPrior(double speedPriorValue);
+	
+	int width, height;
+	/////
+	string matchString;
+	void updatePlayPosition();
+	
+	DoubleMatrix beatPeriodMatrix;
+	
+	void drawFile();
+	void drawMidiFile();
+	void reset();
+	void setMatchedNotesBackToFalse();
+	
+	int ticksPerScreen;
+	int tickLocation;
+	int numberOfScreensIn;
+	int noteArrayIndex;
+	
+	int matchWindowWidth;
+	
+	int noteMinimum, noteMaximum;
+	int* screenWidth;
+	int* screenHeight;
+	float noteHeight;
+	float tempo;
+	double lastPeriodUpdateTime;
+	int lastPlayedPitch;
+	
+	double playPositionInMillis;
+	
+	double timeOffsetForScreen;
+	
+	double recentNoteOnTime;
+	
+	void exampleCrossUpdate();
+	BayesianArrayStructure bayesStruct;
+
+	double speedPriorValue;
+	int bestMatchIndex;
+	string timeString;
+	double startTime;
+	int speedWindowWidthMillis;
+	
+	bool confidenceWeightingUsed;
+	
+	double minimumMatchError;//recent best error between observed note and aligned midi file
+	
+	void reorderMatrixFromNoteTimes(IntMatrix& noteOnMatrix);
+	int getIndexOfMinimumAboveTime(const double& time, IntMatrix& noteOnMatrix);
+	void correctTiming(IntMatrix& noteOnMatrix);
+	void doublecheckOrder(IntMatrix& noteOnMatrix);
+	int getIndexOfMinimumAboveIndex(const int& index, IntMatrix& noteOnMatrix);
+	bool useTempoPrior;
+	string	tempoSpeedString;
+	int minimumTimeIntervalForTempoUpdate;
+	
+	double ticksFactor;
+	
+	bool newOptimalMethod;
+	DoubleMatrix interNoteIntervals;
+	IntVector intervalsToCheck;
+	void checkForCorrectInterval(const double& playedTimeDifference, DoubleVector* v);
+	void drawInterNoteIntervals();
+	void printInterNoteIntervals();
+	int interNoteRange;
+	DoubleMatrix periodValues;
+	
+};
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/testApp.cpp	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,584 @@
+#include "testApp.h"
+
+
+testApp::testApp(ofxArgs* args){
+	this->args = args;
+}
+
+//--------------------------------------------------------------
+void testApp::setup(){
+	
+
+ this->args->printArgs();
+	this->args->printOpts();
+	midiFileName = "../../../data/frerejacques.mid";
+	
+	if (this->args->getCount() > 0){
+		museScoreFilename = this->args->getString(1);
+	//printf("MUSESCORE FILENAME IS %s\n", museScoreFilename);
+	cout << "running!! " << museScoreFilename << endl;
+	midiFileName = museScoreFilename;
+	}
+
+	int retVal = cannamMainFunction();
+	
+	ofSetVerticalSync(true);
+	//ofBackground(255,255,255);
+	midiPort = 2;
+	midiIn.listPorts();
+	midiIn.openPort(midiPort);
+	midiPortName = "";
+	//midiPortName = midiIn.portNames(midiPort);
+	
+	transpose = 0;
+	noteInStream.transposeVal = &transpose;
+	
+	noteInStream.startTime = &midiEvents.startTime;//point start time of note in stream to the same time in MIDI events
+
+	noteInStream.factor = &midiEvents.ticksFactor;
+	printf("TICKS FACTOR %f \n", midiEvents.ticksFactor);//noteInStream->factor)
+	
+//	portName = "hello";//midiIn.portNames[2];
+//	printf("MIDI PORT %c\n", portName);
+	cout << "MIDI PORT " << endl;//portName << endl;
+	
+	
+	//midiIn.addListener(this);	
+	ofAddListener(midiIn.newMessageEvent, this, &testApp::newMessage);
+
+	
+	verdana30.loadFont("verdana.ttf", 50, true, true);
+	verdana30.setLineHeight(48.0f);
+	verdana30.setLetterSpacing(1.035);
+	
+	playing = false;
+	readyToStart = true;
+	
+	receiver.setup( PORT );
+
+	sender.setup( HOST, SEND_PORT );
+	
+	screenWidth = ofGetWidth();
+	screenHeight = ofGetHeight();
+	midiEvents.screenWidth = &screenWidth;
+	midiEvents.screenHeight = &screenHeight;
+	midiEvents.drawTempoMode = true;
+	ofSetFrameRate(30);
+	
+	midiEvents.ticksPerScreen += 4000;
+	lastScoreIndexSent = 0;
+	performanceRating = 0.0;
+
+	liveInputPlaying = false;
+	lastScoreIndexSent = 0;
+	midiEvents.bestMatchIndex = 0;
+	
+}
+
+//--------------------------------------------------------------
+void testApp::update(){
+	if (playing){
+		midiEvents.updatePlayPosition();//this fn calls	midiEvents.bayesStruct.updateBestEstimate();
+	}
+//	drawer.tickLocation+=20;
+	
+	// check for waiting messages
+	while( receiver.hasWaitingMessages() )
+	{
+		ofxOscMessage m;
+		receiver.getNextMessage( &m );
+		
+		if ( m.getAddress() == "/midinoteon" )
+		{
+			int newMidiOnPitch = m.getArgAsInt32(0) + transpose;
+			int velocity = m.getArgAsInt32(1);
+			double time = m.getArgAsFloat(2);
+			
+			if (velocity != 0){
+				if (readyToStart){
+					startPlaying();
+					printf("starting to PLAY!!!");
+				}
+				printf("MIDI NOTE %i \n", newMidiOnPitch);
+				midiEvents.newNoteOnEvent(newMidiOnPitch, velocity, time);
+				noteInStream.newNoteCounted(newMidiOnPitch);
+			}
+
+		}
+		
+		if ( m.getAddress() == "/setSpeedPrior" )
+		{
+			float speedPrior = m.getArgAsFloat(0);
+			printf("speed prior set to %f\n", speedPrior);
+			midiEvents.speedPriorValue = speedPrior;
+			midiEvents.bayesStruct.speedPriorValue = speedPrior;
+		}
+		
+		if ( m.getAddress() == "/startplaying" )
+		{
+			prepareToStartOnNextNote();
+		}
+		
+		if ( m.getAddress() == "/stopplaying" )
+		{
+			stopPlaying();
+		}
+		
+		
+		if ( m.getAddress() == "/integratedEstimate" )
+		{
+			midiEvents.bayesStruct.usingIntegratedTempoEstimate = true;
+		}
+	
+		if ( m.getAddress() == "/MAPestimate" )
+		{
+			midiEvents.bayesStruct.usingIntegratedTempoEstimate = false;
+		}
+		
+		
+		if ( m.getAddress() == "/realtime" )
+		{
+			midiEvents.runningInRealTime = true;
+		}
+		
+		
+		if ( m.getAddress() == "/offline" )
+		{
+			midiEvents.runningInRealTime = false;
+		}
+		
+		if ( m.getAddress() == "/minimumSpeedRatio" )
+		{
+				
+			float minSpeed = m.getArgAsFloat(0);
+			//printf("minimum speed received is  %f and max is %f\n", minSpeed, midiEvents.bayesStruct.relativeSpeedLikelihood.getIndexInRealTerms(midiEvents.bayesStruct.relativeSpeedLikelihood.length-1));
+			if (minSpeed > 0 && minSpeed < midiEvents.bayesStruct.relativeSpeedLikelihood.getIndexInRealTerms(midiEvents.bayesStruct.relativeSpeedLikelihood.length-1)){
+			printf("minimum speed accepted is %f\n", minSpeed);
+				midiEvents.minimumMatchSpeed = minSpeed;
+			}
+		}
+
+		if ( m.getAddress() == "/maximumSpeedRatio" )
+		{
+			
+			float maxSpeed = m.getArgAsFloat(0);
+			//printf("minimum speed received is  %f and max is %f\n", minSpeed, midiEvents.bayesStruct.relativeSpeedLikelihood.getIndexInRealTerms(midiEvents.bayesStruct.relativeSpeedLikelihood.length-1));
+			if (maxSpeed > midiEvents.minimumMatchSpeed && maxSpeed <= midiEvents.bayesStruct.relativeSpeedLikelihood.getIndexInRealTerms(midiEvents.bayesStruct.relativeSpeedLikelihood.length-1)){
+				printf("maximum speed accepted is %f\n", maxSpeed);
+				midiEvents.maximumMatchSpeed = maxSpeed;
+			}
+		}
+		
+		if ( m.getAddress() == "/likelihoodToNoiseRatio" )
+		{
+			
+			float ratio = m.getArgAsFloat(0);
+			
+			if (ratio > 0.001 && ratio < 0.6){
+				midiEvents.likelihoodToNoiseRatio = ratio;
+				printf("likelihood for events relative to noise uses ratio %f\n", ratio);
+			}
+		
+		}
+		
+	}//end while osc
+	if (midiEvents.recordedEventTimes.size() > 0)
+	checkNewScoreNote();
+	
+}
+
+
+void testApp::checkNewScoreNote(){
+	if (lastScoreIndexSent != midiEvents.bestMatchIndex){
+	//then we send out new note
+		sendNoteToMuseScore();
+		lastScoreIndexSent = midiEvents.bestMatchIndex;
+		findMeasure();
+	}
+}
+
+void testApp::findMeasure(){
+	int ticks = midiEvents.recordedNoteOnMatrix[midiEvents.bestMatchIndex][0];
+	int tmpMeasure = lastMeasureSent;
+	
+	while (lastMeasureSent > 0 && midiEvents.measureVector[lastMeasureSent] > ticks) {
+		lastMeasureSent--;
+	}
+	
+	while (lastMeasureSent < midiEvents.measureVector.size() && midiEvents.measureVector[lastMeasureSent] < ticks) {
+		lastMeasureSent++;
+	}
+	if (lastMeasureSent != tmpMeasure){
+	//sendMeasureToMuseScore();
+	performanceRating =	noteInStream.calculateTotalScore(midiEvents);
+	}
+	
+
+}
+
+void testApp::sendBlackNotes(){
+	ofxOscMessage m;
+	m.setAddress( "/plugin" );
+	string noteString;	
+	noteString = "blacknotes.js";
+	m.addStringArg( noteString);
+	sender.sendMessage( m ); 
+}
+
+void testApp::sendNoteToMuseScore(){
+	if (midiEvents.recordedNoteOnMatrix.size() > 0){
+	int ticks = midiEvents.recordedNoteOnMatrix[midiEvents.bestMatchIndex][0];
+	int pitch = midiEvents.recordedNoteOnMatrix[midiEvents.bestMatchIndex][1];
+//	printf("sending to muse score %i, %i \n", ticks, pitch);
+	sendNoteDataByOsc(pitch, ticks);
+	}
+	/*
+		ofxOscMessage m;
+		m.setAddress( "/plugin" );
+		string noteString;	
+		noteString = "blackNotes.js";
+		m.addStringArg( noteString);
+		sender.sendMessage( m ); 
+	*/
+
+	
+//	/color-note 60,3440
+	
+	//crappy javascript message
+	/*
+			ofxOscMessage m;
+			m.setAddress( "/plugin" );
+			string noteString;	
+			noteString = "coloronenote.js";
+			noteString += ",myTick,"+ofToString(ticks)+",myPitch,"+ofToString(pitch);
+		//	printf("%s\n", noteString);
+			m.addStringArg( noteString);
+			sender.sendMessage( m ); */
+
+		   
+	//	   /plugin coloronenote.js mytick 100 mypitch 56;
+}
+
+void testApp::sendNoteDataByOsc(const int& pitch, const int& ticks){
+	ofxOscMessage m;
+	m.setAddress( "/color-note" );
+	string noteString;	
+	noteString = ofToString(ticks);
+	noteString += ","+ofToString(pitch);
+	m.addStringArg( noteString);
+	sender.sendMessage( m );
+}
+
+void testApp::sendMeasureToMuseScore(){
+
+	printf("sending measure to muse score %i \n", lastMeasureSent);
+	
+	ofxOscMessage m;
+	m.setAddress( "/select-measure" );
+	m.addIntArg(lastMeasureSent);
+	sender.sendMessage( m );  
+	
+	//		/select-measure 6
+	//	   /plugin coloronenote.js mytick 100 mypitch 56;
+}
+
+
+void testApp::newMessage(ofxMidiEventArgs &args){
+
+	int pitch;
+	if (noteInStream.noteInReceived(args)){
+	double timeNow = ofGetElapsedTimeMillis();
+		
+		if (!liveInputPlaying){
+			firstNoteTime = timeNow;
+			liveInputPlaying = true;
+			startPlaying();
+			printf("FIRST LIVE NOTE IS NOW AT TIME %f\n", timeNow);
+		}
+		
+		pitch = args.byteOne + transpose;
+		
+		midiEvents.newNoteOnEvent(pitch, args.byteTwo, timeNow - firstNoteTime);
+		
+		
+		int tickTime = midiEvents.getEventTimeTicks(timeNow-firstNoteTime);
+		IntVector v;
+		v.push_back(tickTime);
+		v.push_back(pitch);
+		v.push_back(args.byteTwo);
+		v.push_back(200);//tmp time til note off happens
+		noteInStream.midiInputEvents.push_back(v);
+		noteInStream.midiInputTimes.push_back(timeNow - firstNoteTime);
+		//printf("NOTE %i at time %f at tick time %i\n", pitch, (timeNow - firstNoteTime), tickTime);
+	}
+	
+//	cout << "MIDI message [port: " << args.port << ", channel: " << args.channel << ", status: " << args.status << ", byteOne: " << pitch << ", byteTwo: " << args.byteTwo << ", timestamp: " << args.timestamp << "]" << endl;
+}
+
+//--------------------------------------------------------------
+void testApp::draw(){
+
+	midiEvents.drawFile();
+	
+	string info = "Measure ";
+	info += ofToString(lastMeasureSent);
+	info += "  Last note ";
+	info += ofToString(lastScoreIndexSent);
+	
+	ofSetHexColor(0xFF0000);
+//	ofDrawBitmapString(info, 20, 20);
+	midiEvents.drawMidiFile(noteInStream.midiInputEvents);
+
+//	ofDrawBitmapString("Rating "+ofToString(performanceRating*100), 60, 50);
+	//ofDrawBitmapString("filename "+museScoreFilename, 20, 80);
+	string ratingString = ofToString(performanceRating*100,0)+"%";
+						   if (performanceRating > 0.84)
+						   ratingString += "!* *";
+						   string extraText = "";
+						   if (performanceRating > 0.9){
+						   extraText += " pretty good, huh?";
+						   }
+						   if (performanceRating > 0.95)
+						   extraText = " blimey! ";
+						   if (performanceRating > 0.97)
+						   extraText = " maestro!";
+						   
+						   ratingString += extraText;  
+	verdana30.drawString(ratingString, 20, 60);
+	
+	ofSetHexColor(0x000000);
+	ofDrawBitmapString(midiPortName, 20, ofGetHeight() - 20);
+	
+}
+
+//--------------------------------------------------------------
+void testApp::keyPressed(int key){
+
+	if (key == '.'){
+		midiPort++;
+		midiIn.openPort(midiPort);
+	}
+
+	if (key == ',' && midiPort > 0){
+		midiPort--;
+		midiIn.openPort(midiPort);
+	}
+
+	if (key == '-')
+		transpose -= 12;
+	
+	if (key == '=')
+		transpose += 12;
+	
+	if (key == 'c'){
+		double timenow = ofGetElapsedTimeMillis();
+		midiEvents.exampleCrossUpdate();
+		timenow *= -1;
+		timenow += ofGetElapsedTimeMillis();
+		printf("CROSS UPDATE TOOK %f", timenow);
+	}
+
+	if (key == 'x')
+		sendNoteDataByOsc(60, 0);
+	
+	if (key == OF_KEY_LEFT){
+		
+	}
+	
+	if (key == OF_KEY_RIGHT)
+	
+	if (key == OF_KEY_RETURN)
+		stopPlaying();
+	
+	if (key == OF_KEY_UP){
+		if (midiEvents.ticksPerScreen >= 4000)
+		midiEvents.ticksPerScreen += 2000;
+		else 
+			midiEvents.ticksPerScreen += 500;
+	}
+	
+	if (key == 'm'){
+//		midiEvents.findMatch(84, 0, 10000);
+	}
+	
+	if (key == 'b'){
+		sendBlackNotes();
+	}
+	
+	
+	if (key == 'n'){
+		midiEvents.printInterNoteIntervals();
+	}
+	
+	if (key == OF_KEY_DOWN){
+		if (midiEvents.ticksPerScreen >= 4000)
+		midiEvents.ticksPerScreen -= 2000;
+	else if (midiEvents.ticksPerScreen > 500)
+		midiEvents.ticksPerScreen -= 500;
+	}
+	
+	if (key == 'w')
+		midiEvents.printMatchMatrix();
+	
+	if (key == 'k'){
+		noteInStream.printNotes();
+	}
+	
+	if (key == 'p'){
+		midiEvents.printNotes();
+	}
+
+	if (key == 'l')
+		
+		
+		//midiEvents.bayesStruct.decaySpeedDistribution(100);
+	
+	if (key == 't')
+		midiEvents.drawTempoMode = !midiEvents.drawTempoMode;
+	
+	if (key == 'y')
+		midiEvents.drawPhaseMode = !midiEvents.drawPhaseMode;
+	
+	if (key == 'r'){
+		noteInStream.reset();
+		liveInputPlaying = false;
+		stopPlaying();
+		lastMeasureSent = 0;
+		sendMeasureToMuseScore();
+		sendBlackNotes();
+		lastScoreIndexSent = 0;
+		performanceRating = 0;
+		
+	}
+	
+	if (key == 'o' || key == 'O'){
+		loadRecordedMidiFile();
+	}
+
+	
+	
+}
+
+void testApp::loadRecordedMidiFile(){
+	//open audio file
+	string *filePtr;
+	filePtr = &midiFileName;	
+	
+	if (getFilenameFromDialogBox(filePtr)){
+		printf("Midifile: Loaded name okay :\n'%s' \n", midiFileName.c_str());	
+		cannamMainFunction();
+	}
+}
+
+//--------------------------------------------------------------
+void testApp::keyReleased(int key){
+
+}
+
+//--------------------------------------------------------------
+void testApp::mouseMoved(int x, int y ){
+	midiEvents.mouseX = midiEvents.getEventTimeMillis((x * midiEvents.ticksPerScreen)/ screenWidth);
+}
+
+//--------------------------------------------------------------
+void testApp::mouseDragged(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void testApp::mousePressed(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void testApp::mouseReleased(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void testApp::windowResized(int w, int h){
+	screenWidth = w;
+	screenHeight = h;
+	midiEvents.noteHeight = screenHeight / (float)(midiEvents.noteMaximum - midiEvents.noteMinimum);
+	
+}
+
+void testApp::prepareToStartOnNextNote(){
+	readyToStart = true;
+}
+
+
+void testApp::startPlaying(){
+	playing = !playing;
+	midiEvents.reset();
+	noteInStream.reset();
+	midiEvents.setStartPlayingTimes();
+	sendBlackNotes();
+	readyToStart = false;
+	//this is where we stop and start playing
+}
+
+void testApp::stopPlaying(){
+	//midiEvents.printNoteCounter();
+	//noteInStream.printTotalCount();
+	
+	noteInStream.calculateTotalScore(midiEvents);
+	
+	
+	playing = false;
+	liveInputPlaying = false;
+	lastScoreIndexSent = 0;
+	midiEvents.bestMatchIndex = 0;
+	sendNoteToMuseScore();
+	
+}
+
+bool testApp::getFilenameFromDialogBox(string* fileNameToSave){
+	//this uses a pointer structure within the loader and returns true if the dialogue box was used successfully
+	// first, create a string that will hold the URL
+	string URL;
+	
+	// openFile(string& URL) returns 1 if a file was picked
+	// returns 0 when something went wrong or the user pressed 'cancel'
+	int response = ofxFileDialogOSX::openFile(URL);
+	if(response){
+		// now you can use the URL 
+		*fileNameToSave = URL;
+		//printf("\n filename is %s \n", soundFileName.c_str());
+		return true;
+	}
+	else {
+		//	soundFileName = "OPEN canceled. ";
+		printf("\n open file cancelled \n");
+		return false;
+	}
+	
+	
+	
+}
+
+
+
+
+int testApp::cannamMainFunction(){
+
+
+	midiEvents.clearAllEvents();
+	
+	//int main(int argc, char **argv)
+	//{
+	//	if (argc != 2) {
+	//		cerr << "Usage: midifile <file.mid>" << endl;
+	//		return 1;
+	//	}
+		
+	std::string filename = midiFileName;//argv[1];
+	
+//	fileLoader.chopBeginning = true;
+	fileLoader.loadFile(filename, midiEvents);
+	
+}//new end of load function
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jnmr/testApp.h	Mon Dec 12 12:46:17 2011 +0000
@@ -0,0 +1,128 @@
+#ifndef _TEST_APP
+#define _TEST_APP
+
+
+//midieventholder - newMidiEvents() sent there
+//create cannamMidiLoader for cannamMainfunction
+
+
+//check new prior offset function - how is used?
+
+
+
+//check the widening function - adding decay noise
+//ticksperscreen could be better as millis per screen
+
+
+
+//uses ftmMidiPlay in max5 via osc to communicate notes in
+
+#include "ofMain.h"
+
+#include "MIDIFileReader.h"
+#include "ofxFileDialogOSX.h"
+#include "drawMidiNotes.h"
+#include "DynamicBayesianArray.h"
+#include "CannamMidiFileLoader.h"
+#include <iostream>
+#include "midiEventHolder.h"
+#include "ofxMidiIn.h"
+#include "ofxOsc.h"
+#include "MidiInputStream.h"
+#include "ofxArgs.h"
+
+#define PORT 12121
+#define SEND_PORT 5282
+#define HOST "localhost"
+
+
+using namespace std;
+using namespace MIDIConstants;
+
+class testApp : public ofBaseApp{
+private:
+	ofxArgs* args;
+	string option1, option2;
+	bool flag1;
+	ofxOscReceiver	receiver;
+	ofxOscSender	sender;
+	
+public:
+		testApp(ofxArgs* args);
+
+		void setup();
+		void update();
+		void draw();
+
+		void keyPressed  (int key);
+		void keyReleased(int key);
+		void mouseMoved(int x, int y );
+		void mouseDragged(int x, int y, int button);
+		void mousePressed(int x, int y, int button);
+		void mouseReleased(int x, int y, int button);
+		void windowResized(int w, int h);
+
+	void startPlaying();
+	void stopPlaying();
+	bool getFilenameFromDialogBox(string* fileNameToSave);
+
+	typedef std::vector<int> IntVector;
+	typedef std::vector<double> DoubleVector;
+//	typedef std::vector<IntVector> IntMatrix;	
+	IntVector v;
+
+	midiEventHolder midiEvents;
+	
+	int cannamMainFunction();
+	string midiFileName;
+	std::string museScoreFilename;
+	
+	bool playing;
+	//drawMidiNotes drawer;
+	
+//	BayesianArrayStructure bayesStruct;
+	
+	int screenWidth, screenHeight;
+	CannamMidiFileLoader fileLoader;
+
+	//MIDI INPUT
+	// vars
+	int port;
+	int id;
+	int value;
+	double timestamp;
+	char msg[255];
+	string portName;
+	
+	void checkNewScoreNote();
+	void sendNoteToMuseScore();
+	void sendMeasureToMuseScore();
+	void sendBlackNotes();
+	void findMeasure();
+	
+	// midi addon
+	ofxMidiIn	midiIn;
+	// this is your listener function
+	void newMessage(ofxMidiEventArgs &args);
+	
+	MidiInputStream noteInStream;
+
+	double firstNoteTime;
+	bool liveInputPlaying;
+	double timePlayed;	
+	int transpose;
+	int lastScoreIndexSent;
+	int lastMeasureSent;
+	double performanceRating;
+	void sendNoteDataByOsc(const int& pitch, const int& ticks);
+
+	ofTrueTypeFont verdana30;
+	int midiPort;
+	std::string midiPortName;
+	void loadRecordedMidiFile();
+	
+	bool readyToStart;
+	void prepareToStartOnNextNote();
+};
+
+#endif