diff jnmr/midiEventHolder.cpp @ 50:158f5f38e9d3

outputting exact difference for annotations, comparison with match annotations is now working over all rwc files
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Thu, 29 Mar 2012 13:41:59 +0100
parents 3ce6dadd8167
children 13194a9dca77
line wrap: on
line diff
--- a/jnmr/midiEventHolder.cpp	Fri Mar 23 10:53:57 2012 +0000
+++ b/jnmr/midiEventHolder.cpp	Thu Mar 29 13:41:59 2012 +0100
@@ -35,7 +35,7 @@
 	confidenceWeightingUsed = true;
 	newOptimalMethod = true;
 	
-	matchWindowWidth = 16000;//window size for matching in ms 
+	matchWindowWidth = 20000;//window size for matching in ms 
 	interNoteRange = 1600;//preferred duration
 	//so max here is really four
 	
@@ -44,7 +44,7 @@
 	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.speedLikelihoodNoise = 0.2;//changed from 0.1, was 0.05
 	bayesStruct.speedDecayWidth = 40;
 	bayesStruct.speedDecayAmount = 10;
 	
@@ -131,7 +131,7 @@
 
 	interNoteIntervals.clear();
 	
-	smoothIndex = 0;
+	outputIndex = 0;
 	smoothPlayPosition = 0.0;
 	causalPlayPosition = 0;
 	lastCausalUpdateTime = getTimeNow(0);
@@ -157,6 +157,21 @@
 	//period = 500.0;
 }
 
+void midiEventHolder::testSpeedPriorSetting(){
+	if (speedPriorValue > 2){
+		bayesStruct.resetSpeedSize(speedPriorValue * 200);
+		bayesStruct.setRelativeSpeedScalar(0.01);
+		bayesStruct.relativeSpeedPrior.getMaximum();
+		printf("SPEED SIZE EXCEEDS MAXIMUM!!! RESETTING TO SIXE %i\n", (int)(speedPriorValue * 200));
+	}
+	else{
+		bayesStruct.resetSpeedSize(200);
+		bayesStruct.setRelativeSpeedScalar(0.01);
+		bayesStruct.relativeSpeedPrior.getMaximum();
+	}
+
+}
+
 void midiEventHolder::setMatchedNotesBackToFalse(){
 	for (int i = 0;i < noteOnMatches.size();i++)
 		noteOnMatches[i] = false;
@@ -309,14 +324,13 @@
 
 void midiEventHolder::updateTempo(){
 	//having found matches we have matches for new note and matches for previous notes
-	if (newOptimalMethod)
+	if (newOptimalMethod)//now true
 		findOptimumTempoPairsToCurrentBestMatch();
 	else if (!confidenceWeightingUsed)
 		findLocalTempoPairs();
 	else
 		findLocalTempoPairsWeightedForConfidence();
 	
-	
 	//bayesStruct.addGaussianNoiseToSpeedPosterior(10);
 }
 
@@ -376,6 +390,7 @@
 	if (recordedEventTimes.size() > 0){
 	
 		//get to the right range of events to check in
+		//OPTIMIZE!
 		while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < startTime)
 			startIndex++;
 		   
@@ -396,7 +411,7 @@
 			double eventConfidence = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[startIndex]);
 				if (eventConfidence > minimumConfidence){
 					minimumConfidence = eventConfidence;
-					bestMatchIndex = startIndex;
+					bestMatchIndex = startIndex;//could change this to minimumMatchError below
 				}
 			d.push_back(eventConfidence);
 			
@@ -408,6 +423,7 @@
 				//record the error between expected and observed times
 				tmpError = abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate);
 				minimumMatchError = tmpError;//recordedEventTimes[startIndex] - bayesStruct.bestEstimate;
+			//	bestMatchIndex = startIndex;
 			}
 			
 		}
@@ -794,15 +810,22 @@
 	//did just update smooth to current if it was less
 	
 	if (smoothPlayPosition < bayesStruct.bestEstimate){
-		updateSmoothPositionTo(bayesStruct.bestEstimate);
-		//smoothPlayPosition = bayesStruct.bestEstimate;
+	//	updateOutputPositionTo(bayesStruct.bestEstimate);
+		smoothPlayPosition = bayesStruct.bestEstimate;
 	}
 	
+	updateOutputPositionTo(causalPlayPosition);	//need it outputting before the update
+	
+	updateCausalPlayPosition(getTimeNow(bayesStruct.lastBestEstimateUpdateTime));
+
 
 	
-	updateCausalPlayPosition(getTimeNow(bayesStruct.lastBestEstimateUpdateTime));
+	//can choose to output either the smooth position (i.e. forwards)
+	//or causal play position which aims toward our current smooth position in near future
 	
-/*
+	
+
+	/*
 	//now we try updating it to a causal path that tries to match into the future	
  if (smoothPlayPosition < causalPlayPosition){
 		updateSmoothPositionTo(causalPlayPosition);
@@ -822,101 +845,134 @@
 	
 }
 
-void midiEventHolder::updateSmoothPositionTo(const double& newPosition){
+void midiEventHolder::updateOutputPositionTo(const double& newPosition){
 	//smooth play position was where we last outputted notes from.
 	//checking index is there to make sense.
-	while (smoothIndex > 0 && recordedEventTimes[smoothIndex] > smoothPlayPosition){
-		smoothIndex--;
-		//printf("going backewaers on smooth, ");
+//	double checkPosition = smoothPlayPosition;
+	double checkPosition = lastUpdatePosition;
+	
+	
+	while (outputIndex > 0 && recordedEventTimes[outputIndex] > checkPosition){
+		outputIndex--;
+//		printf("going backewards, smooth time %f, ", recordedEventTimes[outputIndex]);
 	}
-	while (smoothIndex < recordedEventTimes.size()-1 && recordedEventTimes[smoothIndex] < smoothPlayPosition){
-		smoothIndex++;
-		//printf("outputting  smooth\n ");
+	while (outputIndex < recordedEventTimes.size()-1 && recordedEventTimes[outputIndex] < checkPosition){
+		outputIndex++;
+//		printf("outputting smooth forwards time %f\n ", recordedEventTimes[outputIndex], checkPosition);
 	}
 	
+//	printf("last output position %f, new position %f\n", checkPosition, newPosition);	
+//	printf("causal pos %.0f, smooth pos %.0f, best est %.0f\n", causalPlayPosition, smoothPlayPosition, bayesStruct.bestEstimate);
+	
+	outputPosition = recordedEventTimes[outputIndex];
 
 	double playingTime = ofGetElapsedTimeMillis();
 	playingTime -= startPlayingTime;
 	//now at the last one
 	
-	float smoothLocation = beatPositions[smoothIndex];
-	int currentNote = recordedNoteOnMatrix[smoothIndex][1];
+	float smoothLocation = beatPositions[outputIndex];
+	int currentNote = recordedNoteOnMatrix[outputIndex][1];
 	
-	while (smoothIndex < recordedEventTimes.size() && recordedEventTimes[smoothIndex] < newPosition){
+	while (outputIndex < recordedEventTimes.size() && recordedEventTimes[outputIndex] < newPosition){
 		float annotationTime = 0;
 		float annotationLocation = 0;
 		int annotationTick = 0;
 		int annotationNote = 0;
 		float difference = 10000;//very big
-		float currentLocationDifference = 1.0;
+		//float currentLocationDifference = 1.0;
+		
+		double amountSinceLastUpdate = 0.0;//between 0 and 1, the exact position of this event since last update
+			if (newPosition  > lastUpdatePosition){
+				amountSinceLastUpdate = (recordedEventTimes[outputIndex] - lastUpdatePosition)/(newPosition - lastUpdatePosition);
+			}
+		
 		float range = 1.0;
-		if (smoothIndex < myNotation.rwcAnnotations.size()){
+		if (outputIndex < myNotation.rwcAnnotations.size()){
 			//add in test here to find closest matching note
 			
 		
-			annotationTime = myNotation.rwcAnnotations[smoothIndex].eventTime;
-			annotationNote = myNotation.rwcAnnotations[smoothIndex].midiNote;
-			annotationLocation = myNotation.rwcAnnotations[smoothIndex].beatLocation;
+			annotationTime = myNotation.rwcAnnotations[outputIndex].eventTime;
+			annotationNote = myNotation.rwcAnnotations[outputIndex].midiNote;
+			annotationLocation = myNotation.rwcAnnotations[outputIndex].beatLocation;
 			annotationTick = round(annotationLocation*480.0);
 		}else{
 			printf("No annotaion size %i\n", (int)myNotation.rwcAnnotations.size());
 		}
 		
+		double exactPlayingTime = amountSinceLastUpdate*playingTime + ((1 - amountSinceLastUpdate)*lastUpdatePlayingTime);
 		difference = playingTime - (annotationTime*1000.0);
-		
-		if ((*fileOutput).is_open()){
-			(*fileOutput) << fixed << beatPositions[smoothIndex] <<",\t" <<  recordedNoteOnMatrix[smoothIndex][1] << ",\t";
+		double exactDifference = exactPlayingTime - (annotationTime*1000.0);
+	/*
+	 //NO LONGER NEEDED ALLO
+	 if ((*fileOutput).is_open()){
+			(*fileOutput) << fixed << beatPositions[outputIndex] <<",\t" <<  recordedNoteOnMatrix[outputIndex][1] << ",\t";
 			(*fileOutput) << playingTime ;
 			
-				if ( recordedNoteOnMatrix[smoothIndex][1] == annotationNote){
+				if ( recordedNoteOnMatrix[outputIndex][1] == annotationNote){
 					(*fileOutput) << " corresponds to " << annotationTime;
 				}
 			(*fileOutput) << " \n";
 				
 		}
-	
-		printf("annotations: rec tick time %i vs %i midi %i beat pos %f playing time now at %f :: annotaion %i loc % f time %f diff \t%f ms\n",  
-			   recordedNoteOnMatrix[smoothIndex][0], annotationTick, recordedNoteOnMatrix[smoothIndex][1], 
-			   beatPositions[smoothIndex], playingTime, 
-			   annotationNote, annotationLocation, annotationTime, difference);
+	 */
 		
-//		assert(annotationNote == recordedNoteOnMatrix[smoothIndex][1]);
-	assert(annotationTick == recordedNoteOnMatrix[smoothIndex][0]);
+	//useful printing stuff
+//		printf("playing time %.1f, annotation time %.1f, diff %.1f\n", playingTime, (annotationTime*1000.0), difference);
+		
+//		printf("last posn %.1f, amount since %.2f \n" lastUpdatePosition, amountSinceLastUpdate);
+		
+//		printf("annotations:Diff %f rec tick time %i vs %i midi %i beat pos %f playing time now at %f :: annotaion %i loc % f time %f diff \t%f ms\n",  
+//			   difference, recordedNoteOnMatrix[outputIndex][0], annotationTick, recordedNoteOnMatrix[outputIndex][1], 
+//			   beatPositions[outputIndex], playingTime, 
+//			   annotationNote, annotationLocation, annotationTime, difference);
+
+	// we use exact difference as it more accurately predicts where we scheduled the note
+//		printf("diff %.1f, exact diff %.1f\n", difference, exactDifference);
+		
+		
+		//assert(annotationNote == recordedNoteOnMatrix[outputIndex][1]);
+		assert(annotationTick == recordedNoteOnMatrix[outputIndex][0]);
 	
 		smoothDifference = difference;
 		
 		if ((*differenceOutput).is_open()){
-			(*differenceOutput) << beatPositions[smoothIndex] << "," << difference << "," << playingTime << "," << (annotationTime*1000.0) << "\n";
+			(*differenceOutput) << beatPositions[outputIndex] << "," << exactDifference << "," << playingTime << "," << (annotationTime*1000.0) << annotationNote << difference <<  "\n";
 		//	printf("midi %i beat pos %f playing time now at %f :: annotaion %i loc % f time %f diff \t%f ms\n",  
-		//		   recordedNoteOnMatrix[smoothIndex][1], 
-		//		   beatPositions[smoothIndex], playingTime, 
+		//		   recordedNoteOnMatrix[outputIndex][1], 
+		//		   beatPositions[outputIndex], playingTime, 
 		//		   annotationNote, annotationLocation, annotationTime, difference);
 		}else{
 			printf("file not open\n");
 		}
 		
-		smoothIndex++;
+		outputIndex++;
 	}
 	
-		
-	smoothPlayPosition = newPosition;
-		
+	lastUpdatePosition = newPosition;
+	lastUpdatePlayingTime = playingTime;
 }
 
 void midiEventHolder::updateCausalPlayPosition(const double& timeNow){
 	//projected position
 	
+	//first update the speed
+	updateCausalSpeed();
+	
+	causalPlayPosition += causalSpeed * (timeNow - lastCausalUpdateTime);
+	lastCausalUpdateTime = timeNow;
+	
+}
+
+void midiEventHolder::updateCausalSpeed(){
 	double difference =	bayesStruct.bestEstimate - causalPlayPosition;
 	causalSpeed = bayesStruct.speedEstimate;
 	causalSpeed += (difference/timeProjectionToMeet);
 	
 	if (causalSpeed < 0)
 		causalSpeed = 0;
-	
-	causalPlayPosition += causalSpeed * (timeNow - lastCausalUpdateTime);
-	lastCausalUpdateTime = timeNow;
-	
+
 }
+
 /*
 void midiEventHolder::updatePeriodValue(const double& millis){
 
@@ -981,7 +1037,7 @@
 			if (checkIfMatchedNote(tmpIndex))
 				ofSetColor(100,100,100);//0,0,255);
 			else if(noteOnMatches[tmpIndex]){
-				ofSetColor(255,0,255);//dark grey
+				ofSetColor(255,0,255);//pink
 			}
 			else{
 				ofSetColor(255,255,255);//255,255,255);
@@ -1011,10 +1067,14 @@
 		ofSetColor(250,250,20);//250,100,0);
 		ofLine(xLocation, 0, xLocation, (*screenHeight));
 		
+		
+/*		
+		//cyan blue - smooth position
 		xLocation = getLocationFromMillis(smoothPlayPosition);//bayesStruct.tmpBestEstimate
-		ofSetColor(0,250,0);//250,150, 250,100,0);
-	//	ofLine(xLocation, 0, xLocation, (*screenHeight));
-		
+		ofSetColor(0,250,250);//250,150, 250,100,0);
+		ofLine(xLocation, 0, xLocation, (*screenHeight));
+*/		
+		//bright green is the causal play position
 		xLocation = getLocationFromMillis(causalPlayPosition);//bayesStruct.tmpBestEstimate
 		ofSetColor(0,250,0);//250,150, 250,100,0);
 		ofLine(xLocation, 0, xLocation, (*screenHeight));
@@ -1049,9 +1109,16 @@
 	//ofDrawBitmapString(ofToString(timeOffsetForScreen, 1), 20,20);
 	ofSetColor(255,255,255);
 	ofDrawBitmapString(timeString, 20, 60);
-	ofDrawBitmapString("diff "+ofToString(smoothDifference), 20, 140);
+	string diffString = "diff "+ofToString(smoothDifference);
+	diffString += "\ncausal posn: "+ofToString(causalPlayPosition, 0);
+	diffString += "\nsmooth posn: "+ofToString(smoothPlayPosition, 0);
+	diffString += "\noutput posn: "+ofToString(outputPosition, 0);
+	diffString += "\nbest est: "+ofToString(bayesStruct.bestEstimate, 0);
+	diffString += "\nlast best est: "+ofToString(bayesStruct.lastBestEstimateUpdateTime, 0);
 	
-//last played piutch
+	ofDrawBitmapString(diffString, 20, 140);
+	
+	//last played pitch
 	ofSetColor(0,200,0,50);
 	int yLocation = (*screenHeight) - ((lastPlayedPitch - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum));						 
 	ofRect(0,yLocation, 100,  noteHeight);
@@ -1448,7 +1515,7 @@
 /*
 JUNK SMOOTH StuffHex
  /*
- int testIndex = smoothIndex;
+ int testIndex = outputIndex;
  while (testIndex >= 0 && abs(smoothLocation - myNotation.rwcAnnotations[testIndex].beatLocation) < range){
  
  if (myNotation.rwcAnnotations[testIndex].midiNote == currentNote){
@@ -1463,7 +1530,7 @@
  testIndex--;
  }
  
- testIndex = smoothIndex;
+ testIndex = outputIndex;
  while (testIndex >= 0 && testIndex < myNotation.rwcAnnotations.size() && abs(smoothLocation - myNotation.rwcAnnotations[testIndex].beatLocation) < range){
  
  if (myNotation.rwcAnnotations[testIndex].midiNote == currentNote){