Mercurial > hg > midi-score-follower
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 + + + +