Mercurial > hg > midi-score-follower
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(); }