Mercurial > hg > midi-score-follower
changeset 25:2a025ea7c793
hackday work to get live midi input, follow the notes, output measure, read measure in with midi file
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Sat, 03 Dec 2011 21:09:13 +0000 |
parents | 5a11b19906c7 |
children | 179365726f07 |
files | hackday/CannamMidiFileLoader.cpp hackday/CannamMidiFileLoader.h hackday/MidiInputStream.cpp hackday/midiEventHolder.cpp hackday/midiEventHolder.h hackday/testApp.cpp hackday/testApp.h |
diffstat | 7 files changed, 184 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/hackday/CannamMidiFileLoader.cpp Sat Dec 03 17:19:43 2011 +0000 +++ b/hackday/CannamMidiFileLoader.cpp Sat Dec 03 21:09:13 2011 +0000 @@ -21,7 +21,7 @@ setTempoFromMidiValue(500000, myMidiEvents);//default is 120bpm myMidiEvents.pulsesPerQuarternote = 240;//default - + myMidiEvents.measureVector.push_back(0); //int main(int argc, char **argv) //{ // if (argc != 2) { @@ -54,6 +54,8 @@ if (printMidiInfo) cout << "Timing division: " << fr.getTimingDivision() << " ppq" << endl; myMidiEvents.pulsesPerQuarternote = fr.getTimingDivision(); + ticksPerMeasure = myMidiEvents.pulsesPerQuarternote * 4;//default setting + } else { int frames = 256 - (td >> 8); int subframes = td & 0xff; @@ -102,9 +104,9 @@ if (printMidiInfo) cout << t << ": Tempo: " << 60000000.0 / double(tempo) << endl; setTempoFromMidiValue(tempo, myMidiEvents); - - + printf("period double is %f\n", myMidiEvents.period); + } break; @@ -112,8 +114,12 @@ { int numerator = j->getMetaMessage()[0]; int denominator = 1 << (int)j->getMetaMessage()[1]; - if (printMidiInfo) + + newTimeSignature(t, numerator, denominator, myMidiEvents); + + //if (printMidiInfo) cout << t << ": Time signature: " << numerator << "/" << denominator << endl; + printf(" ticks %i Time signature: %i by %i ", t, numerator , denominator ); } case MIDI_KEY_SIGNATURE: @@ -259,15 +265,26 @@ if (printMidiInfo) myMidiEvents.printRecordedEvents(); + //printMeasuresSoFar(myMidiEvents); + + if (myMidiEvents.recordedNoteOnMatrix.size() > 0){ + + printf("END FILE MEASURE UPDATE\n"); + updateMeasureToTickPosition(myMidiEvents.recordedNoteOnMatrix[myMidiEvents.recordedNoteOnMatrix.size()-1][0], myMidiEvents); + // printMeasuresSoFar(myMidiEvents); + } + // printf("|||||||||||||||||||||| \n\n\n\n\n\n\n"); myMidiEvents.reorderMatrixFromNoteTimes(myMidiEvents.recordedNoteOnMatrix); myMidiEvents.correctTiming(myMidiEvents.recordedNoteOnMatrix); myMidiEvents.doublecheckOrder(myMidiEvents.recordedNoteOnMatrix); createEventTiming(myMidiEvents); - + if (printMidiInfo) - myMidiEvents.printRecordedEvents(); + myMidiEvents.printRecordedEvents(); + + //printMeasuresSoFar(myMidiEvents); }//end cannam midi main @@ -298,4 +315,35 @@ } +void CannamMidiFileLoader::newTimeSignature(int ticks, int numerator, int denominator, midiEventHolder& myMidiEvents){ + updateMeasureToTickPosition(ticks, myMidiEvents); + + ticksPerMeasure = myMidiEvents.pulsesPerQuarternote * 4 * numerator / denominator; + +} + +void CannamMidiFileLoader::updateMeasureToTickPosition(int ticks, midiEventHolder& myMidiEvents){ + printf("update measure at tick pos %i at tpm %i\n", ticks, ticksPerMeasure); + + int measureVectorSize = myMidiEvents.measureVector.size(); + int lastMeasurePosition = 0; + + if (measureVectorSize > 0) + lastMeasurePosition = myMidiEvents.measureVector[measureVectorSize-1]; + +while (lastMeasurePosition < ticks){ + //update + lastMeasurePosition += ticksPerMeasure; + 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); + } +} + + +void CannamMidiFileLoader::printMeasuresSoFar(midiEventHolder& myMidiEvents){ + 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
--- a/hackday/CannamMidiFileLoader.h Sat Dec 03 17:19:43 2011 +0000 +++ b/hackday/CannamMidiFileLoader.h Sat Dec 03 21:09:13 2011 +0000 @@ -32,8 +32,11 @@ IntVector v; int noteOnIndex; - + int ticksPerMeasure; + void newTimeSignature(int ticks, int numerator, int denominator, midiEventHolder& myMidiEvents); + void updateMeasureToTickPosition(int ticks, midiEventHolder& myMidiEvents); bool printMidiInfo; + void printMeasuresSoFar(midiEventHolder& myMidiEvents); }; #endif \ No newline at end of file
--- a/hackday/MidiInputStream.cpp Sat Dec 03 17:19:43 2011 +0000 +++ b/hackday/MidiInputStream.cpp Sat Dec 03 21:09:13 2011 +0000 @@ -32,9 +32,9 @@ newPitch = (int)args.byteOne; newPitch += (*transposeVal); - printf("note on %i", args.byteOne); + // printf("note on %i", args.byteOne); if (args.byteTwo){ - printf("volume is %i\n", args.byteTwo); + // printf("volume is %i\n", args.byteTwo); double time = ofGetElapsedTimeMillis(); eventTimesForNote[newPitch] = time; @@ -43,10 +43,12 @@ }else{ double time = ofGetElapsedTimeMillis(); time -= eventTimesForNote[newPitch]; - printf(", OFF after %f millis %f ticks\n", time, time * (*factor)); + // printf(", OFF after %f millis %f ticks\n", time, time * (*factor)); int index = endNote(newPitch); - midiInputEvents[index].push_back(time * (*factor)); + //correct the length of note time + if (midiInputEvents[index].size() > 2) + midiInputEvents[index][3] = (time * (*factor)); } break; @@ -64,7 +66,7 @@ while (index > 0 && midiInputEvents[index][1] != notePitch){ index--; } - printf("found index %i\n", index); +// printf("found index %i\n", index); return index; }
--- a/hackday/midiEventHolder.cpp Sat Dec 03 17:19:43 2011 +0000 +++ b/hackday/midiEventHolder.cpp Sat Dec 03 21:09:13 2011 +0000 @@ -20,7 +20,7 @@ runningInRealTime = true; bayesStruct.realTimeMode = &runningInRealTime; - minimumMatchSpeed = 0.0; + minimumMatchSpeed = 0.5; maximumMatchSpeed = 2.0; minimumTimeIntervalForTempoUpdate = 150; @@ -105,7 +105,7 @@ matchesFound.clear(); noteOnMatches.clear(); recordedEventTimes.clear(); - + measureVector.clear(); //played events: playedEventTimes.clear(); playedNoteOnMatrix.clear(); @@ -140,7 +140,7 @@ //need to get new MAP position and set the offset of the arrays //currently bestEstimate is the approx for the new MAP position - + lastPlayedPitch = pitch; //add the new event to our played information matrix IntVector v; v.push_back(pitch); @@ -706,6 +706,16 @@ int maxSize = recordedNoteOnMatrix[size-1][0]; + int tmpIndex = 0; + while (tmpIndex < measureVector.size() && measureVector[tmpIndex] < (numberOfScreensIn+1)*ticksPerScreen){ + int measureLocation = measureVector[tmpIndex]; + int xLocation = (float)(measureLocation - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen; + ofSetColor(155,155,0); + ofLine(xLocation, 0, xLocation, (*screenHeight)); + tmpIndex++; + } + + // ofDrawBitmapString(tempoSpeedString, 20, 20); /* string indexString = "num screens in "+ofToString(numberOfScreensIn)+"; min index to print "+ofToString(minNoteIndexToPrint)+", max index to print "+ofToString(maxNoteIndexToPrint); indexString += " size "+ofToString(size)+" tick loc "+ofToString(tickLocation)+" max size "+ofToString(maxSize); @@ -717,13 +727,21 @@ //ofDrawBitmapString(timeString, 20, 60); - +//last played piutch + ofSetColor(0,200,0,50); + int yLocation = (*screenHeight) - ((lastPlayedPitch - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum)); + ofRect(0,yLocation, 100, noteHeight); + + + } void midiEventHolder::drawMidiFile(IntMatrix& midiFileToDraw){ + //using this to draw the live input + //draws midi file on scrolling screen int size = midiFileToDraw.size(); if (size > 0){ @@ -752,23 +770,8 @@ for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)midiFileToDraw.size());tmpIndex++){ - ofSetColor(255,0,255); - /* - if (checkIfMatchedNote(tmpIndex)) - ofSetColor(100,100,100);//0,0,255); - else if(noteOnMatches[tmpIndex]){ - ofSetColor(255,0,255);//dark grey - } - else{ - ofSetColor(255,255,255);//255,255,255); - } - */ - //ofSetColor(255,255,255); - if (tmpIndex == bestMatchIndex) - ofSetColor(255,0,0);//best recent match is in red - - // XXX replace ofgetwidth below - //if (tmpIndex >= 0 && tmpIndex < size) + ofSetColor(0,0,255, 200); + int xLocation = (float)(midiFileToDraw[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen; int duration = (float)(midiFileToDraw[tmpIndex][3]*(*screenWidth))/(float)ticksPerScreen;
--- a/hackday/midiEventHolder.h Sat Dec 03 17:19:43 2011 +0000 +++ b/hackday/midiEventHolder.h Sat Dec 03 21:09:13 2011 +0000 @@ -44,6 +44,7 @@ int playedNoteIndex; IntMatrix matchMatrix; IntVector bestMatchFound; + IntVector measureVector; DoubleMatrix matchConfidence; double totalConfidence; @@ -113,6 +114,7 @@ float noteHeight; float tempo; double lastPeriodUpdateTime; + int lastPlayedPitch; double playPositionInMillis;
--- a/hackday/testApp.cpp Sat Dec 03 17:19:43 2011 +0000 +++ b/hackday/testApp.cpp Sat Dec 03 21:09:13 2011 +0000 @@ -13,7 +13,7 @@ midiIn.listPorts(); midiIn.openPort(2); - transpose = 12; + transpose = 24; noteInStream.transposeVal = &transpose; noteInStream.startTime = &midiEvents.startTime;//point start time of note in stream to the same time in MIDI events @@ -35,6 +35,8 @@ receiver.setup( PORT ); + + sender.setup( HOST, SEND_PORT ); screenWidth = ofGetWidth(); screenHeight = ofGetHeight(); @@ -42,13 +44,16 @@ midiEvents.screenHeight = &screenHeight; midiEvents.drawTempoMode = false; ofSetFrameRate(30); + + midiEvents.ticksPerScreen += 4000; + lastScoreIndexSent = 0; + } //-------------------------------------------------------------- void testApp::update(){ if (playing){ - midiEvents.updatePlayPosition(); - // midiEvents.bayesStruct.updateBestEstimate(); + midiEvents.updatePlayPosition();//this fn calls midiEvents.bayesStruct.updateBestEstimate(); } // drawer.tickLocation+=20; @@ -122,9 +127,72 @@ } }//end while osc + + 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(); + } + + +} + +void testApp::sendNoteToMuseScore(){ + int ticks = midiEvents.recordedNoteOnMatrix[midiEvents.bestMatchIndex][0]; + int pitch = midiEvents.recordedNoteOnMatrix[midiEvents.bestMatchIndex][1]; + printf("sending to muse score %i, %i \n", ticks, pitch); + + ofxOscMessage m; + m.setAddress( "/plugin" ); + m.addStringArg( "coloronenote.js" ); + m.addStringArg("mytick"); + m.addIntArg( ticks ); + m.addStringArg("mypitch"); + m.addIntArg( pitch); + sender.sendMessage( m ); + + // /plugin coloronenote.js mytick 100 mypitch 56; +} + + + +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; @@ -148,9 +216,10 @@ 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); + //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; @@ -161,6 +230,13 @@ midiEvents.drawFile(); + string info = "Measure "; + info += ofToString(lastMeasureSent); + info += " Last note "; + info += ofToString(lastScoreIndexSent); + + ofSetHexColor(0x000000); + ofDrawBitmapString(info, 20, 20); midiEvents.drawMidiFile(noteInStream.midiInputEvents); } @@ -294,6 +370,9 @@ void testApp::stopPlaying(){ playing = false; liveInputPlaying = false; + lastScoreIndexSent = 0; + midiEvents.bestMatchIndex = 0; + sendNoteToMuseScore(); } bool testApp::getFilenameFromDialogBox(string* fileNameToSave){
--- a/hackday/testApp.h Sat Dec 03 17:19:43 2011 +0000 +++ b/hackday/testApp.h Sat Dec 03 21:09:13 2011 +0000 @@ -32,6 +32,9 @@ #define PORT 12121 +#define SEND_PORT 5282 +#define HOST "localhost" + using namespace std; using namespace MIDIConstants; @@ -82,6 +85,10 @@ char msg[255]; string portName; + void checkNewScoreNote(); + void sendNoteToMuseScore(); + void sendMeasureToMuseScore(); + void findMeasure(); // midi addon ofxMidiIn midiIn; // this is your listener function @@ -93,9 +100,11 @@ bool liveInputPlaying; double timePlayed; int transpose; + int lastScoreIndexSent; + int lastMeasureSent; private: ofxOscReceiver receiver; - + ofxOscSender sender; };