Mercurial > hg > midi-score-follower
comparison src/midiEventHolder.cpp @ 2:5581023e0de4
Added separate CannamMidiFileLoader class to handle the loading in.
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Fri, 19 Aug 2011 01:26:40 +0100 |
parents | 1a32ce016bb9 |
children | de86d77f2612 |
comparison
equal
deleted
inserted
replaced
1:1a32ce016bb9 | 2:5581023e0de4 |
---|---|
25 noteMinimum = 30; | 25 noteMinimum = 30; |
26 noteMaximum = 96; | 26 noteMaximum = 96; |
27 | 27 |
28 minimumMatchSpeed = 0.7; | 28 minimumMatchSpeed = 0.7; |
29 maximumMatchSpeed = 1.3; | 29 maximumMatchSpeed = 1.3; |
30 | |
30 likelihoodWidth = 100; | 31 likelihoodWidth = 100; |
31 likelihoodToNoiseRatio = 50; | 32 likelihoodToNoiseRatio = 0.02; |
32 | 33 |
33 matchWindowWidth = 4000;//window size for matching in ms | 34 bayesStruct.speedLikelihoodNoise = 0.05;//was 0.05 |
35 bayesStruct.speedDecayWidth = 20; | |
36 bayesStruct.speedDecayAmount = 10; | |
37 | |
38 | |
39 matchWindowWidth = 8000;//window size for matching in ms | |
34 | 40 |
35 bayesStruct.resetSize(matchWindowWidth); | 41 bayesStruct.resetSize(matchWindowWidth); |
42 bayesStruct.setPositionDistributionScalar(1); | |
43 | |
36 bayesStruct.resetSpeedSize(200); | 44 bayesStruct.resetSpeedSize(200); |
37 bayesStruct.setRelativeSpeedScalar(0.01); | 45 bayesStruct.setRelativeSpeedScalar(0.01); |
38 bayesStruct.relativeSpeedPrior.getMaximum(); | 46 bayesStruct.relativeSpeedPrior.getMaximum(); |
39 bayesStruct.simpleExample(); | 47 //bayesStruct.simpleExample(); |
48 | |
40 | 49 |
41 noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum); | 50 noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum); |
42 } | 51 } |
43 | 52 |
44 | 53 |
45 | 54 |
46 void midiEventHolder::reset(){ | 55 void midiEventHolder::reset(){ |
56 //called when we start playing | |
57 | |
47 noteArrayIndex = 0; | 58 noteArrayIndex = 0; |
48 tickLocation = 0; | 59 tickLocation = 0; |
49 lastPeriodUpdateTime = ofGetElapsedTimeMillis(); | 60 lastPeriodUpdateTime = ofGetElapsedTimeMillis(); |
50 bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); | 61 bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); |
51 numberOfScreensIn = 0; | 62 numberOfScreensIn = 0; |
106 v.push_back(velocity); | 117 v.push_back(velocity); |
107 playedNoteOnMatrix.push_back(v); | 118 playedNoteOnMatrix.push_back(v); |
108 | 119 |
109 | 120 |
110 //would update the arrays at this point to show where out current location (phase) and tempo is. | 121 //would update the arrays at this point to show where out current location (phase) and tempo is. |
111 double timeNow = ofGetElapsedTimeMillis() - startTime; | 122 // double timeNow = ofGetElapsedTimeMillis() - startTime; |
112 recentNoteOnTime = timeNow; | 123 double timeNow = timePlayed;// - startTime; |
113 | 124 recentNoteOnTime = timePlayed; |
114 printf("Max time %f OF time %f \n", timePlayed, timeNow); | 125 |
126 // printf("Max time %f OF time %f \n", timePlayed, timeNow); | |
115 | 127 |
116 playedEventTimes.push_back(timePlayed); | 128 playedEventTimes.push_back(timePlayed); |
117 | 129 |
118 double timeDifference = ofGetElapsedTimeMillis() - bayesStruct.lastEventTime; | 130 // double timeDifference = ofGetElapsedTimeMillis() - bayesStruct.lastEventTime; |
119 | 131 double timeDifference = timePlayed - bayesStruct.lastEventTime; |
132 | |
133 printf("note %i played at %f and last event %f\n", pitch, timePlayed, bayesStruct.lastEventTime); | |
120 //addnoise to the tempo distribution | 134 //addnoise to the tempo distribution |
121 bayesStruct.decaySpeedDistribution(timeDifference); | 135 //bayesStruct.decaySpeedDistribution(timeDifference); |
122 | 136 if (timeDifference > 50){ |
137 bayesStruct.addGaussianNoiseToSpeedPosterior(timeDifference * 10 / 100.); | |
138 // bayesStruct.addTriangularNoiseToSpeedPosterior(timeDifference * 10 / 100.); | |
139 } | |
140 | |
141 bayesStruct.updateTmpBestEstimate(timeDifference);// debug - didnt work bayesStruct.bestEstimate = bayesStruct.tmpBestEstimate; | |
142 bayesStruct.updateBestEstimate(); | |
143 bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); | |
123 | 144 |
124 // double newMAPestimateTime = bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate); | 145 // double newMAPestimateTime = bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate); |
125 //was offset + bayesStruct.posterior.MAPestimate; but this doesnt include scalar to convert to millis | 146 //was offset + bayesStruct.posterior.MAPestimate; but this doesnt include scalar to convert to millis |
126 | 147 |
127 timeString = "Pitch:"+ofToString(pitch); | 148 timeString = "Pitch:"+ofToString(pitch); |
147 timeString += " map "+ofToString(bayesStruct.relativeSpeedPosterior.MAPestimate, 1); | 168 timeString += " map "+ofToString(bayesStruct.relativeSpeedPosterior.MAPestimate, 1); |
148 timeString += " rel speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 1); | 169 timeString += " rel speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 1); |
149 | 170 |
150 | 171 |
151 //be able to draw the prior in correct location relative to the midi notes | 172 //be able to draw the prior in correct location relative to the midi notes |
173 //this calculates the cross update of all possible speeds and all possible positions | |
152 bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, timeDifference); | 174 bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, timeDifference); |
153 // bayesStruct.crossUpdateArrays(bayesStruct.prior, bayesStruct.relativeSpeedPosterior, timeDifference); | |
154 | 175 |
155 | 176 |
156 timeString += " new OFF "+ofToString(bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2), 1); | 177 timeString += " new OFF "+ofToString(bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2), 1); |
157 timeString += " notearrayindex "+ofToString(noteArrayIndex, 0); | 178 timeString += " notearrayindex "+ofToString(noteArrayIndex, 0); |
158 //when this is off teh screen there is a problem somehow XXX | 179 //when this is off teh screen there is a problem somehow XXX |
159 bayesStruct.posterior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)); | 180 bayesStruct.posterior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)); |
160 // bayesStruct.prior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)); | 181 // bayesStruct.prior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)); |
161 //trying to switch to prior | 182 //trying to switch to prior |
162 | 183 |
163 bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); | 184 //bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); |
185 bayesStruct.lastEventTime = timePlayed; | |
164 | 186 |
165 //do the cross update to find current posterior for location | 187 //do the cross update to find current posterior for location |
166 // totalConfidence= 0; | 188 // totalConfidence= 0; |
167 int numberOfMatchesFound = findLocalMatches(pitch); | 189 int numberOfMatchesFound = findLocalMatches(pitch); |
168 setMatchLikelihoods(numberOfMatchesFound); | 190 setMatchLikelihoods(numberOfMatchesFound); |
169 bayesStruct.calculatePosterior(); | 191 bayesStruct.calculatePosterior(); |
170 | 192 |
171 //having found matches we have matches for new note and matches for previous notes | 193 //having found matches we have matches for new note and matches for previous notes |
172 findLocalTempoPairs(); | 194 findLocalTempoPairs(); |
173 | 195 |
174 | 196 //bayesStruct.addGaussianNoiseToSpeedPosterior(10); |
175 | 197 |
176 } | 198 } |
177 | 199 |
178 int midiEventHolder::findLocalMatches(int notePitch){ | 200 int midiEventHolder::findLocalMatches(int notePitch){ |
179 | 201 |
195 void midiEventHolder::setMatchLikelihoods(int numberOfMatches){ | 217 void midiEventHolder::setMatchLikelihoods(int numberOfMatches){ |
196 //reset the offset to match the prior | 218 //reset the offset to match the prior |
197 bayesStruct.likelihood.offset = bayesStruct.prior.offset; | 219 bayesStruct.likelihood.offset = bayesStruct.prior.offset; |
198 bayesStruct.likelihood.zero();//set to zero | 220 bayesStruct.likelihood.zero();//set to zero |
199 | 221 |
200 | 222 double quantity = likelihoodToNoiseRatio / numberOfMatches; |
201 | 223 |
202 for (int i = 0;i < numberOfMatches && matchesFound[i] >= 0 && matchesFound[i] < recordedEventTimes.size();i++){ | 224 for (int i = 0;i < numberOfMatches && matchesFound[i] >= 0 && matchesFound[i] < recordedEventTimes.size();i++){ |
203 // printf("match times %i of %i::%f adding likelihood to %f\n", i, numberOfMatches, recordedEventTimes[matchesFound[i]], recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset); | 225 // printf("match times %i of %i::%f adding likelihood to %f\n", i, numberOfMatches, recordedEventTimes[matchesFound[i]], recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset); |
204 //this is the vent time since start of file | 226 //this is the vent time since start of file |
205 if (recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset < bayesStruct.likelihood.arraySize){ | 227 if (recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset < bayesStruct.likelihood.arraySize){ |
206 // double confidenceMeasure = 0; | 228 // double confidenceMeasure = 0; |
207 // if (totalConfidence > 0) | 229 // if (totalConfidence > 0) |
208 // confidenceMeasure = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[matchesFound[i]])/totalConfidence; | 230 // confidenceMeasure = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[matchesFound[i]])/totalConfidence; |
209 | 231 |
210 bayesStruct.likelihood.addGaussianShape(recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset, likelihoodWidth, 0.5 * likelihoodToNoiseRatio );//* confidenceMeasure | 232 bayesStruct.likelihood.addGaussianShape(recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset, likelihoodWidth, quantity);//* confidenceMeasure |
211 }//end if | 233 }//end if |
212 } | 234 } |
213 bayesStruct.likelihood.addConstant(0.01); | 235 bayesStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesStruct.likelihood.length); |
214 } | 236 } |
215 | 237 |
216 int midiEventHolder::findMatch(const int& notePitch, const int& startTime, const int& endTime){ | 238 int midiEventHolder::findMatch(const int& notePitch, const int& startTime, const int& endTime){ |
217 | 239 |
218 matchesFound.clear(); | 240 matchesFound.clear(); |
288 | 310 |
289 //we want the speed of the recording relative to that of the playing live | 311 //we want the speed of the recording relative to that of the playing live |
290 | 312 |
291 double speedRatio = recordedTimeDifference / playedTimeDifference; | 313 double speedRatio = recordedTimeDifference / playedTimeDifference; |
292 if (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){ | 314 if (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){ |
293 printf("(%i)", matchMatrix[currentPlayedIndex][i+1]); | 315 /* |
316 printf("(%i)", matchMatrix[currentPlayedIndex][i+1]); | |
294 printf("[%i] :: ", recordedPreviousIndex); | 317 printf("[%i] :: ", recordedPreviousIndex); |
295 printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference); | 318 printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference); |
296 printf("update on speed ratio %f\n", speedRatio); | 319 printf("update on speed ratio %f\n", speedRatio); |
320 */ | |
297 // matchString += " speed: "+ofToString(speedRatio, 3); | 321 // matchString += " speed: "+ofToString(speedRatio, 3); |
298 // commented for debug | 322 // commented for debug |
299 bayesStruct.updateTempoDistribution(speedRatio, 0.1);//second paramter is confidence in the match | 323 |
324 bayesStruct.updateTempoDistribution(speedRatio, 0.1);//second paramter is confidence in the match | |
300 | 325 |
301 } | 326 } |
302 // printf("\n"); | 327 // printf("\n"); |
303 } | 328 } |
304 | 329 |
305 previousIndex--; | 330 previousIndex--; |
306 }//end while previousindex countdown | 331 }//end while previousindex countdown |
307 }//end for loop through possible current matches | 332 }//end for loop through possible current matches |
308 | 333 |
309 | 334 //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); |
310 } | 335 } |
311 | 336 |
312 | 337 |
313 void midiEventHolder::updatePlayPosition(){ | 338 void midiEventHolder::updatePlayPosition(){ |
314 | 339 |
378 int xLocation;// = getLocationFromTicks(tickLocation); | 403 int xLocation;// = getLocationFromTicks(tickLocation); |
379 // ofLine(xLocation, 0, xLocation, (*screenHeight)); | 404 // ofLine(xLocation, 0, xLocation, (*screenHeight)); |
380 | 405 |
381 //orange line at best estimate | 406 //orange line at best estimate |
382 xLocation = getLocationFromMillis(bayesStruct.bestEstimate); | 407 xLocation = getLocationFromMillis(bayesStruct.bestEstimate); |
408 ofSetColor(250,100,0); | |
409 ofLine(xLocation, 0, xLocation, (*screenHeight)); | |
410 | |
411 xLocation = getLocationFromMillis(bayesStruct.tmpBestEstimate); | |
383 ofSetColor(250,100,0); | 412 ofSetColor(250,100,0); |
384 ofLine(xLocation, 0, xLocation, (*screenHeight)); | 413 ofLine(xLocation, 0, xLocation, (*screenHeight)); |
385 | 414 |
386 | 415 |
387 //lines where matching window start and end are | 416 //lines where matching window start and end are |
414 | 443 |
415 ofSetColor(0, 0, 0); | 444 ofSetColor(0, 0, 0); |
416 ofDrawBitmapString(matchString, 20, ofGetHeight() - 20); | 445 ofDrawBitmapString(matchString, 20, ofGetHeight() - 20); |
417 | 446 |
418 double confidence = bayesStruct.posterior.getValueAtMillis(mouseX); | 447 double confidence = bayesStruct.posterior.getValueAtMillis(mouseX); |
419 string mouseString = "mouseX "+ofToString(confidence, 3)+" ."; | 448 /* |
449 string mouseString = "mouseX "+ofToString(confidence, 3)+" ."; | |
420 ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40); | 450 ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40); |
451 */ | |
452 string mouseString = "updateCounter "+ofToString(bayesStruct.updateCounter); | |
453 ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40); | |
454 | |
455 string infostring = "speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 3); | |
456 ofDrawBitmapString(infostring, 20 , ofGetHeight() - 60); | |
421 } | 457 } |
422 | 458 |
423 int midiEventHolder::getLocationFromTicks(double tickPosition){ | 459 int midiEventHolder::getLocationFromTicks(double tickPosition){ |
424 return (int)((float)(tickPosition - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen); | 460 return (int)((float)(tickPosition - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen); |
425 } | 461 } |
437 } | 473 } |
438 | 474 |
439 | 475 |
440 void midiEventHolder::setStartPlayingTimes(){ | 476 void midiEventHolder::setStartPlayingTimes(){ |
441 lastPeriodUpdateTime = ofGetElapsedTimeMillis(); | 477 lastPeriodUpdateTime = ofGetElapsedTimeMillis(); |
442 bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); | |
443 startTime = lastPeriodUpdateTime; | 478 startTime = lastPeriodUpdateTime; |
444 | 479 |
480 /* | |
481 bayesStruct.lastEventTime = 0;//ofGetElapsedTimeMillis(); | |
482 bayesStruct.bestEstimate = 0; | |
445 bayesStruct.resetArrays(); | 483 bayesStruct.resetArrays(); |
446 // bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); | 484 bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); |
485 */ | |
486 bayesStruct.setStartPlaying(); | |
447 matchString = ""; | 487 matchString = ""; |
448 } | 488 } |
449 | 489 |
450 | 490 |
451 void midiEventHolder::printMatchMatrix(){ | 491 void midiEventHolder::printMatchMatrix(){ |