changeset 35:6cd3e0075adf

now writing out alignment data - correct beat positions for the MIDI file so alignment can be done via iostream over RWV database
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Wed, 14 Dec 2011 17:28:17 +0000
parents 9d2a651a87b2
children 5a1b0c6fa1fb
files jnmr/CannamMidiFileLoader.cpp jnmr/CannamMidiFileLoader.h jnmr/MidiInputStream.cpp jnmr/MidiInputStream.h jnmr/midiEventHolder.cpp jnmr/midiEventHolder.h jnmr/testApp.cpp
diffstat 7 files changed, 191 insertions(+), 92 deletions(-) [+]
line wrap: on
line diff
--- a/jnmr/CannamMidiFileLoader.cpp	Wed Dec 14 11:35:31 2011 +0000
+++ b/jnmr/CannamMidiFileLoader.cpp	Wed Dec 14 17:28:17 2011 +0000
@@ -11,7 +11,7 @@
 #include "CannamMidiFileLoader.h"
 
 CannamMidiFileLoader::CannamMidiFileLoader(){
-	chopBeginning = true;
+	chopBeginning = false;
 	firstTickTime = 0;
 	printMidiInfo = false;
 }
@@ -21,8 +21,10 @@
 		noteOnIndex = 0;
 		firstTickTime = 0;
 		myMidiEvents.clearAllEvents();
-		
-		
+		beatsPerMeasure = 4;
+		numberOfBeatsAtLastPosition = 0;
+		lastBeatPosition = 0;
+	
 		setTempoFromMidiValue(500000, myMidiEvents);//default is 120bpm
 	
 		myMidiEvents.pulsesPerQuarternote = 240;//default
@@ -201,7 +203,7 @@
 					}
 					continue;
 				}
-				
+				double newBeatLocation = 0;
 				switch (j->getMessageType()) {
 						
 					case MIDI_NOTE_ON:
@@ -212,7 +214,14 @@
 						<< " velocity " << j->getVelocity() 
 						<< "event time " << myMidiEvents.getEventTimeMillis(t) << endl;
 						
-						printf("%i channel %i durn %i pitch %i vel %i event time %f\n", t, ch, j->getDuration(), j->getPitch(), j->getVelocity(), myMidiEvents.getEventTimeMillis(t));
+						newBeatLocation = getBeatPositionForTickCount(t, myMidiEvents);
+						
+					//	printf("%i channel %i durn %i pitch %i vel %i event time %f beat pos %f\n", t, ch, (int)j->getDuration(), (int)j->getPitch(), (int)j->getVelocity(), myMidiEvents.getEventTimeMillis(t)
+					//		   , newBeatLocation);
+						
+						
+						
+					//	printf("Beat location %3.2f\n", newBeatLocation);
 						
 						/*
 						if (noteOnIndex == 0  || t < firstTickTime){
@@ -236,8 +245,9 @@
 						v.push_back(j->getVelocity());
 						v.push_back(j->getDuration());
 						myMidiEvents.recordedNoteOnMatrix.push_back(v);
+						myMidiEvents.noteOnMatches.push_back(false);
+						myMidiEvents.beatPositions.push_back(newBeatLocation);
 						
-						myMidiEvents.noteOnMatches.push_back(false);
 						
 						break;
 						
@@ -347,6 +357,7 @@
 	
 	printf("Duration of MIDI file is %f \n", myMidiEvents.recordedEventTimes[myMidiEvents.recordedEventTimes.size()-1]);
 	printf("And first note offset is %i ticks == %f msec \n", firstTickTime, firstNoteTime);
+	printUpToIndex(50, myMidiEvents);
 	//printMeasuresSoFar(myMidiEvents);
 	
 }//end cannam midi main
@@ -373,7 +384,8 @@
 	}
 	
 	printf("\n\n\nAFTER chop - \n");
-//	myMidiEvents.printRecordedEvents();
+
+//myMidiEvents.printRecordedEvents();
 	
 }
 
@@ -409,6 +421,7 @@
 
 	updateMeasureToTickPosition(ticks, myMidiEvents);
 	
+	beatsPerMeasure = 4.0 * (float)numerator / denominator;
 	ticksPerMeasure = myMidiEvents.pulsesPerQuarternote * 4 * numerator / denominator;
 	
 }
@@ -428,7 +441,10 @@
 while (lastMeasurePosition < ticks){
 	//update
 	lastMeasurePosition += ticksPerMeasure;
+	numberOfBeatsAtLastPosition += beatsPerMeasure;
+	lastBeatPosition = lastMeasurePosition;
 	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);
 	}
@@ -448,4 +464,23 @@
 	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
+}
+
+double CannamMidiFileLoader::getBeatPositionForTickCount(long t, midiEventHolder& myMidiEvents){
+	int lastMeasurePosition = 0;
+	if (myMidiEvents.measureVector.size() > 0)
+		lastMeasurePosition = myMidiEvents.measureVector[myMidiEvents.measureVector.size()-1];
+	
+	int ticksSinceBeatCounted = t - lastMeasurePosition;
+	double beats = numberOfBeatsAtLastPosition;
+	beats += ticksSinceBeatCounted * beatsPerMeasure / ticksPerMeasure;
+//	printf("ticks since %i, beat per measure %f at %i tick per measure :: %f beats\n", ticksSinceBeatCounted, beatsPerMeasure, ticksPerMeasure, beats);
+	return beats;
+}
+
+
+void  CannamMidiFileLoader::printUpToIndex(const int& index, midiEventHolder& myMidiEvents){
+	for (int i = 0;i < index;i++){
+		printf("Beat pos %f MIIDI %i event time %f\n", myMidiEvents.beatPositions[i], myMidiEvents.recordedNoteOnMatrix[i][1], myMidiEvents.recordedEventTimes[i]);
+	}
+}
--- a/jnmr/CannamMidiFileLoader.h	Wed Dec 14 11:35:31 2011 +0000
+++ b/jnmr/CannamMidiFileLoader.h	Wed Dec 14 17:28:17 2011 +0000
@@ -42,5 +42,10 @@
 	void printMeasuresSoFar(midiEventHolder& myMidiEvents);
 	void correctMeasuresTiming(midiEventHolder& myMidiEvents);
 	double fileDuration;
+	float beatsPerMeasure;
+	float numberOfBeatsAtLastPosition;
+	int lastBeatPosition;
+	double getBeatPositionForTickCount(long t, midiEventHolder& myMidiEvents);
+	void printUpToIndex(const int& index, midiEventHolder& midiEvents);
 };
 #endif
\ No newline at end of file
--- a/jnmr/MidiInputStream.cpp	Wed Dec 14 11:35:31 2011 +0000
+++ b/jnmr/MidiInputStream.cpp	Wed Dec 14 17:28:17 2011 +0000
@@ -106,3 +106,4 @@
 	}
 }
 	
+
--- a/jnmr/MidiInputStream.h	Wed Dec 14 11:35:31 2011 +0000
+++ b/jnmr/MidiInputStream.h	Wed Dec 14 17:28:17 2011 +0000
@@ -47,6 +47,7 @@
 	int* transposeVal;
 	
 	double* factor;
+	void printUpToIndex(const int& index, midiEventHolder& midiEvents);
 
 	
 };
--- a/jnmr/midiEventHolder.cpp	Wed Dec 14 11:35:31 2011 +0000
+++ b/jnmr/midiEventHolder.cpp	Wed Dec 14 17:28:17 2011 +0000
@@ -11,6 +11,8 @@
 //Main file to look at here is newNoteEvent() - this calls everything else to update the Bayesian array
 
 #include "midiEventHolder.h"
+#include <iostream>
+#include <fstream>
 
 midiEventHolder::midiEventHolder(){
 //	recordedNoteOnIndex = 0;
@@ -115,6 +117,7 @@
 
 	interNoteIntervals.clear();
 	
+	smoothIndex = 0;
 	smoothPlayPosition = 0.0;
 //	relativeSpeedForSmooth = 1.0;
 //	storedSmoothPlayPosition = smoothPlayPosition;
@@ -155,6 +158,8 @@
 	bestMatchFound.clear();
 	periodValues.clear();
 	
+	beatPositions.clear();
+	
 	recordedTotalNoteCounterByPitch.clear();
 	recordedTotalNoteCounterByPitch.assign(127, 0);
 	totalNoteCounterIndex = 0;
@@ -748,83 +753,6 @@
 	}
 }
 
-/*
-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(){
 	//timeDifference = ofGetElapsedTimeMillis() - startPlayingTime;//elpased 
@@ -842,8 +770,12 @@
 		//	bayesStruct.updateTmpBestEstimate(timeDifference);
 	}
 	
-	if (smoothPlayPosition < bayesStruct.bestEstimate)
-		smoothPlayPosition = bayesStruct.bestEstimate;
+	
+	
+	if (smoothPlayPosition < bayesStruct.bestEstimate){
+		updateSmoothPositionTo(bayesStruct.bestEstimate);
+		//smoothPlayPosition = bayesStruct.bestEstimate;
+	}
 	
 //	playPositionInMillis = timeDifference;//based on updating from when we change period
 	//this to be added
@@ -858,6 +790,33 @@
 	
 }
 
+void midiEventHolder::updateSmoothPositionTo(const double& newPosition){
+	while (smoothIndex > 0 && recordedEventTimes[smoothIndex] > smoothPlayPosition){
+		smoothIndex--;
+	}
+	while (smoothIndex < recordedEventTimes.size()-1 && recordedEventTimes[smoothIndex] < smoothPlayPosition){
+		smoothIndex++;
+	}
+	
+
+	double playingTime = ofGetElapsedTimeMillis();
+	playingTime -= startPlayingTime;
+	//now at the last one
+	
+	while (smoothIndex < recordedEventTimes.size() && recordedEventTimes[smoothIndex] < newPosition){
+		if ((*fileOutput).is_open()){
+			(*fileOutput) << beatPositions[smoothIndex] <<",  " <<  recordedNoteOnMatrix[smoothIndex][1] << ",  ";
+			(*fileOutput) << playingTime << "\n";
+		}
+		
+		smoothIndex++;
+	}
+	
+		
+	smoothPlayPosition = newPosition;
+		
+}
+
 
 void midiEventHolder::updatePeriodValue(const double& millis){
 
@@ -1194,6 +1153,13 @@
 			//which it should be
 	//		cout << " index " << nextIndex << " at time " << noteOnMatrix[nextIndex][0] << " swaps with inex " << i << " at time  " << noteOnMatrix[i][0] << endl; 
 			noteOnMatrix[i].swap(noteOnMatrix[nextIndex]);
+		//	double tmp = beatPositions[i];
+		//	beatPositions[i] = beatPositions[nextIndex];
+		//	 = tmp; 
+		
+				swap (beatPositions[i], beatPositions[nextIndex]);
+			
+			
 			currentTime = noteOnMatrix[i][0];
 		}
 		
@@ -1211,6 +1177,8 @@
 		int nextIndex = getIndexOfMinimumAboveIndex(i, noteOnMatrix);
 		if (nextIndex > i){
 			noteOnMatrix[i].swap(noteOnMatrix[nextIndex]);
+			swap (beatPositions[i], beatPositions[nextIndex]);
+			
 		}
 	}	
 }
@@ -1292,3 +1260,82 @@
  
  }
 */ 
+
+
+/*
+ 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));
+ }
+ */
+
--- a/jnmr/midiEventHolder.h	Wed Dec 14 11:35:31 2011 +0000
+++ b/jnmr/midiEventHolder.h	Wed Dec 14 17:28:17 2011 +0000
@@ -165,7 +165,7 @@
 	int interNoteRange;
 	DoubleMatrix periodValues;
 	int 	periodCounter;
-	void updatePeriodValue(const double& millis);
+	void updatePeriodValue(const double& miupdatesllis);
 	
 	double smoothPlayPosition;
 //	double storedSmoothPlayPosition;
@@ -175,5 +175,11 @@
 	//best alignment
 	double alignmentPosition;
 	double firstEventOffsetTimeMillis;
+	
+	void updateSmoothPositionTo(const double& newPosition);
+	int smoothIndex;
+	DoubleVector beatPositions;
+
+	ofstream *fileOutput;
 };
 #endif
\ No newline at end of file
--- a/jnmr/testApp.cpp	Wed Dec 14 11:35:31 2011 +0000
+++ b/jnmr/testApp.cpp	Wed Dec 14 17:28:17 2011 +0000
@@ -8,13 +8,15 @@
 //--------------------------------------------------------------
 void testApp::setup(){
 	
+	midiEvents.fileOutput = &myfile;
 	
+	string root = "../../../data/FilesOut/exampletest.txt";
 	myfile.open("../../../data/FilesOut/exampletest.txt");
 	if (myfile.is_open())
 	{
-		myfile << "This is a line.\n";
-		myfile << "This is another line.\n";
-		myfile.close();
+	//	myfile << "This is a line.\n";
+	//	myfile << "This is another line.\n";
+//		myfile.close();
 		printf("WRITING TO TEXT FILE\n");
 	}
 	else cout << "Unable to open file";
@@ -127,12 +129,14 @@
 		
 		if ( m.getAddress() == "/startplaying" )
 		{
-			prepareToStartOnNextNote();
+//			prepareToStartOnNextNote();
+			startPlaying();
 		}
 		
 		if ( m.getAddress() == "/stopplaying" )
 		{
 			stopPlaying();
+			myfile.close();
 		}