view jnmr/testApp.cpp @ 36:5a1b0c6fa1fb

Added class to read in the csv Annotation file, then write out the respective difference between the performed piece as followed here, and the annotation of RWC by Ewert and Muller
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Thu, 15 Dec 2011 02:28:49 +0000
parents 6cd3e0075adf
children 795a99987875
line wrap: on
line source
#include "testApp.h"


testApp::testApp(ofxArgs* args){
	this->args = args;
}

//--------------------------------------------------------------
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();
		printf("WRITING TO TEXT FILE\n");
	}
	else cout << "Unable to open file";
	
	
 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.startPlayingTime;//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();
			startPlaying();
		}
		
		if ( m.getAddress() == "/stopplaying" )
		{
			stopPlaying();
			myfile.close();
		}
		
		
		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);
			}
		
		}
		
		if ( m.getAddress() == "/duration" )
		{
			
			float playedDuration = m.getArgAsFloat(0);
			double recordedDuration =	midiEvents.recordedEventTimes[midiEvents.recordedEventTimes.size()-1];
			midiEvents.speedPriorValue = recordedDuration/playedDuration;
			printf("played duration %f, recorded %f\n", playedDuration, recordedDuration);
			printf("speed prior set to %f\n", midiEvents.bayesStruct.speedPriorValue);
			
		}
		
		
	}//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);

	drawMuseScoreText();
	
	ofSetHexColor(0x000000);
	ofDrawBitmapString(midiPortName, 20, ofGetHeight() - 20);
	
}

void testApp::drawMuseScoreText(){
	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);
}

//--------------------------------------------------------------
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

/*
void testApp::readInSomeValues(){
	

	printf("READ FILE\n");
	ifstream file ( "/Users/andrew/Documents/work/MuseScore/RWC/ANNOTATION/RM-C002_annotation+WavPos.csv" ); // declare file stream: http://www.cplusplus.com/reference/iostream/ifstream/
	string value;
	int count = 0;
	while ( file.good() )
	{
		getline ( file, value, ',' ); // read a string until next comma: http://www.cplusplus.com/reference/string/getline/
		cout << string( value, 1, value.length()-2 ); // display value removing the first and the last character from it
		
		string::size_type start = value.find_first_not_of(" \t\v");
		string part = value.substr(start, string::npos);
		//printf("%s (%i)\n", part.c_str(), count);
		float my_float;
		int my_int;
		switch (count%6) {
			case 1:
				printf("reading %s\n", part.c_str());
				my_float = atof(part.c_str());
				printf("float is %f\n", my_float);
				break;
			case 2:
				printf("reading %s\n", part.c_str());
				my_int = atoi(part.c_str());
				printf("float is %i\n", i);
				break;	
				
			default:
				break;
		}
		count++;
	}
	
}

 */