diff jnmr/testApp.cpp @ 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
children 9d2a651a87b2
line wrap: on
line diff
--- /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
+
+
+
+