Mercurial > hg > midi-score-follower
changeset 22:9860abc92a30
follower has confidence measure now just using best match. Difficulty in visualising the speed likelihood fn
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Wed, 30 Nov 2011 11:48:35 +0000 |
parents | 11e3119ce6b4 |
children | 032edf186a68 |
files | .DS_Store src/BayesianArrayStructure.cpp src/BayesianArrayStructure.h src/DynamicVector.cpp src/DynamicVector.h src/midiEventHolder.cpp src/midiEventHolder.h src/testApp.cpp |
diffstat | 8 files changed, 201 insertions(+), 71 deletions(-) [+] |
line wrap: on
line diff
--- a/src/BayesianArrayStructure.cpp Sun Nov 27 21:56:19 2011 +0000 +++ b/src/BayesianArrayStructure.cpp Wed Nov 30 11:48:35 2011 +0000 @@ -15,17 +15,20 @@ BayesianArrayStructure::BayesianArrayStructure(){ printf("Bayesian structure: DeFault constructor called"); + relativeSpeedLikelihoodStdDev = 5.0; + prior.createVector(1); likelihood.createVector(1); posterior.createVector(1); - + tmpPrior.createVector(1); + speedPriorValue = 1.0; speedEstimate = speedPriorValue; lastEventTime = 0;//ofGetElapsedTimeMillis(); tmpBestEstimate = 0; - crossUpdateTimeThreshold = 100; + crossUpdateTimeThreshold = 60; priorWidth = 50; } @@ -35,9 +38,10 @@ prior.createVector(length); likelihood.createVector(length); posterior.createVector(length); + tmpPrior.createVector(length); lastEventTime = 0; - usingIntegratedTempoEstimate = false;//use max index + usingIntegratedTempoEstimate = true;//use max index } @@ -50,7 +54,6 @@ likelihood.createVector(length); posterior.createVector(length); - acceleration.createVector(length); } @@ -76,6 +79,7 @@ posterior.addToIndex(0, 1); posterior.renormalise(); + //acceleration.addGaussianShape(2000, 20, 0.8); } @@ -100,6 +104,13 @@ relativeSpeedPosterior.createVector(length); tmpPosteriorForStorage.createVector(length); + tmpPrior.createVector(length); + tmpPrior.zero(); + tmpPrior.addConstant(0.1); + tmpPrior.addGaussianShape(130, 10, 0.2); + printf("TMP PRIOR TEST VECTOR\n"); + tmpPrior.printArray(); + } @@ -409,11 +420,12 @@ double index = relativeSpeedLikelihood.getRealTermsAsIndex(speedRatio); // printf("index of likelihood would be %f for ratio %f\n", index, speedRatio); if (index >= 0 && index < relativeSpeedPrior.length){ - relativeSpeedLikelihood.addGaussianShape(index , 5, matchFactor); + relativeSpeedLikelihood.addGaussianShape(index , relativeSpeedLikelihoodStdDev, matchFactor); } } - + + void BayesianArrayStructure::updateTempoDistribution(){ //copy posterior to prior @@ -461,8 +473,6 @@ posterior.drawVector(0, displaySize); -// ofSetColor(255,255,255); -// tmpPrior.drawVector(0,300); } @@ -471,8 +481,9 @@ ofSetColor(0,0,255); // relativeSpeedPrior.drawVector(0, relativeSpeedPrior.arraySize); - ofSetColor(255,0,255); + ofSetColor(0,150,255); relativeSpeedLikelihood.drawVector(0, relativeSpeedLikelihood.arraySize); + // relativeSpeedLikelihood.drawConstrainedVector(0, 199, 0, 1000);// relativeSpeedLikelihood.arraySize); ofSetColor(255,0,0); relativeSpeedPosterior.drawVector(0, relativeSpeedPosterior.arraySize); @@ -483,13 +494,14 @@ ofSetColor(255,255, 255); ofLine(screenWidth/2, 0, screenWidth/2, ofGetHeight());//middle of screen - ofSetColor(155,255, 0); + ofSetColor(25, 0, 250); double fractionOfScreen = ((double)relativeSpeedPosterior.integratedEstimate / relativeSpeedPosterior.length); ofLine(screenWidth * fractionOfScreen, 0, screenWidth * fractionOfScreen, ofGetHeight()); - ofSetColor(0,255, 255); + ofSetColor(255, 0, 20); fractionOfScreen = ((double)relativeSpeedPosterior.MAPestimate / relativeSpeedPosterior.length); ofLine(screenWidth * fractionOfScreen, 0, screenWidth * fractionOfScreen, ofGetHeight()); + } @@ -524,14 +536,18 @@ // relativeString += ofToString(prior.getIndexInRealTerms(endArrayIndex), 3)+"] (sc-width:"+ofToString(screenWidthMillis, 1)+") "; relativeString += " mapped to screen "+ofToString(startScreenPosition)+" , "+ofToString(endScreenPosition); // ofDrawBitmapString(relativeString, 100, 180); + - ofSetColor(255, 255, 0); + + ofSetColor(100,100,100);//255, 255, 0); likelihood.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition); - ofSetColor(0,0,200); +// ofSetColor(0,0,200); + ofSetColor(170,170,170);//00,200); prior.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition); - ofSetColor(200, 0, 0); + ofSetColor(0,0,150); +// ofSetColor(200, 0, 0); posterior.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition);
--- a/src/BayesianArrayStructure.h Sun Nov 27 21:56:19 2011 +0000 +++ b/src/BayesianArrayStructure.h Wed Nov 30 11:48:35 2011 +0000 @@ -93,6 +93,7 @@ int priorWidth; bool* realTimeMode; bool usingIntegratedTempoEstimate; + double relativeSpeedLikelihoodStdDev; }; #endif
--- a/src/DynamicVector.cpp Sun Nov 27 21:56:19 2011 +0000 +++ b/src/DynamicVector.cpp Wed Nov 30 11:48:35 2011 +0000 @@ -137,7 +137,7 @@ //now delete tmp array } -void DynamicVector::addGaussianShape(double mean, double StdDev, double factor){ +void DynamicVector::addGaussianShape(const double& mean, const double& StdDev, double factor){ int i; double std_dev_factor = (2*StdDev*StdDev); @@ -152,7 +152,7 @@ // addGaussianShapeByLookupTable(mean, StdDev, factor); } -void DynamicVector::addGaussianShapeByLookupTable(double& mean, double& StdDev, double& factor){ +void DynamicVector::addGaussianShapeByLookupTable(double& mean, double& StdDev, double factor){ int i; int lookupIndex ; factor *= (1/(StdDev*sqrt(2*PI))); @@ -187,14 +187,14 @@ } -void DynamicVector::addConstant(double value){ +void DynamicVector::addConstant(const double& value){ for (int i=0;i<array.size();i++){ array[i] += value; } } -void DynamicVector::addToIndex(int index, double constant){ +void DynamicVector::addToIndex(const int& index, const double& constant){ array[index] += constant; }
--- a/src/DynamicVector.h Sun Nov 27 21:56:19 2011 +0000 +++ b/src/DynamicVector.h Wed Nov 30 11:48:35 2011 +0000 @@ -28,7 +28,7 @@ double getMaximum(); double getIntegratedEstimate(); double getLookupIndex(const int& i, const double& mean, const double& StdDev); - void addGaussianShapeByLookupTable(double& mean, double& StdDev, double& factor); + void addGaussianShapeByLookupTable(double& mean, double& StdDev, double factor); double gaussianLookupTable[GAUSSIAN_LOOKUP_LENGTH]; double gaussianLookupMean, gaussianLookupStdDev; double integratedEstimate; @@ -37,10 +37,10 @@ void drawVector(const int& minIndex, const int& maxIndex); void drawConstrainedVector(const int& minIndex, const int& maxIndex, const int& minScreenIndex, const int& maxScreenIndex); - void addConstant(double value); - void addGaussianShape(double mean, double stddev, double factor); + void addConstant(const double& value); + void addGaussianShape(const double& mean, const double& stddev, double factor); void addTriangularShape(double mean, double width, double factor); - void addToIndex(int index, double constant); + void addToIndex(const int& index, const double& constant); void doProduct(DynamicVector& arrayOne, DynamicVector& arrayTwo);
--- a/src/midiEventHolder.cpp Sun Nov 27 21:56:19 2011 +0000 +++ b/src/midiEventHolder.cpp Wed Nov 30 11:48:35 2011 +0000 @@ -12,11 +12,18 @@ midiEventHolder::midiEventHolder(){ // recordedNoteOnIndex = 0; - useTempoPrior = true;//puts sine wave round tempo + useTempoPrior = false;//puts sine wave round tempo + confidenceWeightingUsed = true; - runningInRealTime = false; + //there is option to use MAP estinate or integral in beayesianarraystricture class + + runningInRealTime = true; bayesStruct.realTimeMode = &runningInRealTime; + minimumMatchSpeed = 0.0; + maximumMatchSpeed = 2.0; + minimumTimeIntervalForTempoUpdate = 150; + width = ofGetWidth(); height = ofGetHeight(); screenWidth= &width; @@ -28,9 +35,8 @@ noteArrayIndex = 0; noteMinimum = 30; noteMaximum = 96; - - minimumMatchSpeed = 0.0; - maximumMatchSpeed = 2.0; + + likelihoodWidth = 100;//using 100 is good likelihoodToNoiseRatio = 0.08;//was 0.02 on 18/11/11, changing to give more weight to observations @@ -43,7 +49,7 @@ speedPriorValue = 1.0; - matchWindowWidth = 8000;//window size for matching in ms + matchWindowWidth = 12000;//window size for matching in ms bayesStruct.resetSize(matchWindowWidth); bayesStruct.setPositionDistributionScalar(1); @@ -58,7 +64,7 @@ speedPriorValue = 1.0; noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum); - confidenceWeightingUsed = false; + drawPhaseMode = true; @@ -104,6 +110,7 @@ playedEventTimes.clear(); playedNoteOnMatrix.clear(); matchMatrix.clear(); + bestMatchFound.clear(); } void midiEventHolder::printNotes(){ @@ -123,6 +130,7 @@ } void midiEventHolder::newNoteOnEvent(int pitch, int velocity, double timePlayed){ + tempoSpeedString = ""; //MOVE INTO BAYESSTRUCT?? XXX //bayesStruct.copyPriorToPosterior(); @@ -217,10 +225,10 @@ bayesStruct.calculatePosterior(); //having found matches we have matches for new note and matches for previous notes - //if (!confidenceWeightingUsed) + if (!confidenceWeightingUsed) findLocalTempoPairs(); - //else - //findLocalTempoPairsWeightedForConfidence(); + else + findLocalTempoPairsWeightedForConfidence(); //bayesStruct.addGaussianNoiseToSpeedPosterior(10); @@ -296,6 +304,8 @@ matchesFound.push_back(startIndex); v.push_back(startIndex); + //so startIndex is registered as a match + double eventConfidence = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[startIndex]); if (eventConfidence > minimumConfidence){ minimumConfidence = eventConfidence; @@ -323,7 +333,7 @@ if (size > 0) noteOnMatches[bestMatchIndex] = true; - v.insert(v.begin() , (int)size); + v.insert(v.begin() , (int)size);//at beginning, we list how many matches there are that we have found d.insert(d.begin() , (double)size); //v.push_back(size); @@ -337,6 +347,9 @@ matchMatrix.push_back(v); matchConfidence.push_back(d); + //bringing in way to list only the best matches and use these in tempo process + bestMatchFound.push_back(bestMatchIndex); + printf("BEST MATCH TO note %i, start time %i, endtime %i, time %i is recorded time %i, confidence %0.2f\n", notePitch, startTime, endTime, (int) recordedEventTimes[bestMatchIndex], minimumConfidence); return size; @@ -377,16 +390,18 @@ double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; for (int k = 0;k < matchMatrix[previousIndex][0];k++){ + int recordedPreviousIndex = matchMatrix[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){ + if (recordedTimeDifference > minimumTimeIntervalForTempoUpdate && + speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){ + //adding in a prior that prefers 1 double priorWeighting = 1; if (useTempoPrior) @@ -407,6 +422,7 @@ double amount = (1-bayesStruct.speedLikelihoodNoise)/10; amount *= priorWeighting; bayesStruct.updateTempoLikelihood(speedRatio, amount); + tempoSpeedString += ofToString(recordedPreviousIndex) + " "+ ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n"; needToUpdate = true; } // printf("\n"); @@ -426,6 +442,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(); + + int recordedCurrentIndex = bestMatchFound[currentPlayedIndex]; + //we only look at intervals between the current best match and other recent best matched notes + //that is the difference in confidence method + + + printf("BEST MATCH FOUND for index %i is %i ", currentPlayedIndex, bestMatchFound[currentPlayedIndex]); + + int previousIndex = currentPlayedIndex-1; + + //withing speedwindow i.e. 4 seconds + while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) { + double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; + + int recordedPreviousIndex = bestMatchFound[previousIndex]; + + 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 (recordedTimeDifference > minimumTimeIntervalForTempoUpdate + && speedRatio < maximumMatchSpeed && speedRatio > minimumMatchSpeed){ + + printf("(%i)", previousIndex); + 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/16;//was 9 + bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match + + tempoSpeedString += ofToString(recordedCurrentIndex) + " :: " + ofToString(recordedPreviousIndex); + tempoSpeedString += " " + ofToString(recordedTimeDifference)+ " " + ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n"; + + needToUpdate = true; + } + // printf("\n"); + + + previousIndex--; + }//end while previousindex countdown + + if (needToUpdate) + bayesStruct.updateTempoDistribution(); + //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); +} + +/* +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(); @@ -435,6 +527,7 @@ 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]; @@ -446,35 +539,45 @@ 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 = matchMatrix[previousIndex][k+1]; + // 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){ - double previousMatchConfidence = matchConfidence[previousIndex][k+1]; + 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 recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex]; + double priorWeighting = 1; - //we want the speed of the recording relative to that of the playing live + if (useTempoPrior) + priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed - 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 weighting = previousMatchConfidence * currentMatchConfidence ; - double amount = (1-bayesStruct.speedLikelihoodNoise)*weighting/10; - bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match - needToUpdate = true; - } - // printf("\n"); + + // 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 @@ -484,7 +587,7 @@ bayesStruct.updateTempoDistribution(); //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); } - +*/ void midiEventHolder::updatePlayPosition(){ @@ -542,14 +645,17 @@ for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)recordedNoteOnMatrix.size());tmpIndex++){ + ofSetColor(255,255,255); if (checkIfMatchedNote(tmpIndex)) - ofSetColor(0,0,255); + ofSetColor(100,100,100);//0,0,255); else if(noteOnMatches[tmpIndex]){ - ofSetColor(255,0,255); - }else{ - ofSetColor(255,255,255); + 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 @@ -570,16 +676,16 @@ //orange line at best estimate xLocation = getLocationFromMillis(bayesStruct.bestEstimate); - ofSetColor(250,100,0); + ofSetColor(80,80,80);//250,100,0); ofLine(xLocation, 0, xLocation, (*screenHeight)); xLocation = getLocationFromMillis(bayesStruct.tmpBestEstimate); - ofSetColor(250,100,0); + ofSetColor(150,150,150);//250,100,0); ofLine(xLocation, 0, xLocation, (*screenHeight)); //lines where matching window start and end are - ofSetColor(0,100,255); + ofSetColor(0);//0,100,255); xLocation = getLocationFromMillis(windowStartTime); ofLine(xLocation, 0, xLocation, (*screenHeight)); xLocation = getLocationFromMillis(windowStartTime+matchWindowWidth); @@ -588,6 +694,7 @@ int maxSize = recordedNoteOnMatrix[size-1][0]; + 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); ofDrawBitmapString(indexString, 20, 40);
--- a/src/midiEventHolder.h Sun Nov 27 21:56:19 2011 +0000 +++ b/src/midiEventHolder.h Wed Nov 30 11:48:35 2011 +0000 @@ -41,6 +41,8 @@ DoubleVector playedEventTimes; int playedNoteIndex; IntMatrix matchMatrix; + IntVector bestMatchFound; + DoubleMatrix matchConfidence; double totalConfidence; @@ -135,5 +137,7 @@ void doublecheckOrder(IntMatrix& noteOnMatrix); int getIndexOfMinimumAboveIndex(const int& index, IntMatrix& noteOnMatrix); bool useTempoPrior; + string tempoSpeedString; + int minimumTimeIntervalForTempoUpdate; }; #endif \ No newline at end of file
--- a/src/testApp.cpp Sun Nov 27 21:56:19 2011 +0000 +++ b/src/testApp.cpp Wed Nov 30 11:48:35 2011 +0000 @@ -87,16 +87,17 @@ void testApp::draw(){ midiEvents.drawFile(); - + ofSetColor(0,255,0); + midiEvents.bayesStruct.tmpPrior.drawVector(0, 200); } //-------------------------------------------------------------- void testApp::keyPressed(int key){ - if (key == ' '){ - startPlaying(); - } +// if (key == ' '){ +// startPlaying(); +// } if (key == 'c'){ double timenow = ofGetElapsedTimeMillis(); @@ -151,10 +152,11 @@ if (getFilenameFromDialogBox(filePtr)){ printf("Midifile: Loaded name okay :\n'%s' \n", midiFileName.c_str()); cannamMainFunction(); - } + } + - } + } //--------------------------------------------------------------