annotate src/midiEventHolder.cpp @ 9:75dcd1308658

looked at tempo process, likelihood function changed and improved. Now drawing using constrained vector function. Good working version.
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Tue, 23 Aug 2011 11:20:44 +0100
parents 6f5836d432ca
children 2ab6f4670cf5
rev   line source
andrew@0 1 /*
andrew@0 2 * midiEventHolder.cpp
andrew@0 3 * midiCannamReader3
andrew@0 4 *
andrew@0 5 * Created by Andrew on 19/07/2011.
andrew@0 6 * Copyright 2011 QMUL. All rights reserved.
andrew@0 7 *
andrew@0 8 */
andrew@0 9 //hello
andrew@0 10
andrew@0 11 #include "midiEventHolder.h"
andrew@0 12
andrew@0 13 midiEventHolder::midiEventHolder(){
andrew@0 14 // recordedNoteOnIndex = 0;
andrew@0 15
andrew@0 16 width = ofGetWidth();
andrew@0 17 height = ofGetHeight();
andrew@0 18 screenWidth= &width;
andrew@0 19 screenHeight = &height;
andrew@0 20
andrew@0 21 ticksPerScreen = 4000;
andrew@0 22 tickLocation = 0;
andrew@0 23 pulsesPerQuarternote = 240;
andrew@0 24 noteArrayIndex = 0;
andrew@0 25 noteMinimum = 30;
andrew@0 26 noteMaximum = 96;
andrew@0 27
andrew@4 28 minimumMatchSpeed = 0.0;
andrew@4 29 maximumMatchSpeed = 2.0;
andrew@2 30
andrew@0 31 likelihoodWidth = 100;
andrew@2 32 likelihoodToNoiseRatio = 0.02;
andrew@0 33
andrew@9 34 bayesStruct.speedLikelihoodNoise = 0.1;//was 0.05
andrew@2 35 bayesStruct.speedDecayWidth = 20;
andrew@2 36 bayesStruct.speedDecayAmount = 10;
andrew@2 37
andrew@3 38 speedPriorValue = 1.0;
andrew@2 39
andrew@2 40 matchWindowWidth = 8000;//window size for matching in ms
andrew@0 41
andrew@1 42 bayesStruct.resetSize(matchWindowWidth);
andrew@2 43 bayesStruct.setPositionDistributionScalar(1);
andrew@2 44
andrew@0 45 bayesStruct.resetSpeedSize(200);
andrew@0 46 bayesStruct.setRelativeSpeedScalar(0.01);
andrew@0 47 bayesStruct.relativeSpeedPrior.getMaximum();
andrew@2 48 //bayesStruct.simpleExample();
andrew@2 49
andrew@6 50
andrew@6 51 speedWindowWidthMillis = 4000;
andrew@3 52 speedPriorValue = 1.0;
andrew@0 53 noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum);
andrew@4 54
andrew@6 55 confidenceWeightingUsed = false;
andrew@6 56
andrew@9 57 drawPhaseMode = true;
andrew@9 58
andrew@4 59 printf("lookup index %f value %f\n", bayesStruct.prior.getLookupIndex(100, 30., 10.0), bayesStruct.prior.gaussianLookupTable[(int)bayesStruct.prior.getLookupIndex(100, 30., 10.0)]);
andrew@0 60 }
andrew@0 61
andrew@0 62
andrew@0 63
andrew@0 64 void midiEventHolder::reset(){
andrew@2 65 //called when we start playing
andrew@2 66
andrew@0 67 noteArrayIndex = 0;
andrew@0 68 tickLocation = 0;
andrew@0 69 lastPeriodUpdateTime = ofGetElapsedTimeMillis();
andrew@0 70 bayesStruct.lastEventTime = ofGetElapsedTimeMillis();
andrew@0 71 numberOfScreensIn = 0;
andrew@0 72 // recordedNoteOnIndex = 0;
andrew@0 73 bayesStruct.setNewDistributionOffsets(0);
andrew@0 74 bayesStruct.posterior.offset = 0;
andrew@0 75
andrew@0 76 playedEventTimes.clear();
andrew@0 77 playedNoteOnMatrix.clear();
andrew@0 78 matchMatrix.clear();
andrew@5 79 bestMatchIndex = 0;
andrew@0 80
andrew@0 81 bayesStruct.resetSpeedToOne();
andrew@3 82 bayesStruct.setSpeedPrior(speedPriorValue);
andrew@5 83 setMatchedNotesBackToFalse();
andrew@5 84 }
andrew@5 85
andrew@5 86 void midiEventHolder::setMatchedNotesBackToFalse(){
andrew@5 87 for (int i = 0;i < noteOnMatches.size();i++)
andrew@5 88 noteOnMatches[i] = false;
andrew@0 89 }
andrew@0 90
andrew@1 91 void midiEventHolder::clearAllEvents(){
andrew@1 92 recordedNoteOnMatrix.clear();
andrew@1 93 matchesFound.clear();
andrew@1 94 noteOnMatches.clear();
andrew@1 95 recordedEventTimes.clear();
andrew@1 96
andrew@1 97 //played events:
andrew@1 98 playedEventTimes.clear();
andrew@1 99 playedNoteOnMatrix.clear();
andrew@1 100 matchMatrix.clear();
andrew@1 101 }
andrew@1 102
andrew@0 103 void midiEventHolder::printNotes(){
andrew@0 104 printf("RECORDED MATRIX");
andrew@0 105 for (int i = 0;i < recordedNoteOnMatrix.size();i++){
andrew@0 106 printf("%i :: %i @ %f\n", recordedNoteOnMatrix[i][0], recordedNoteOnMatrix[i][1], recordedEventTimes[i]);
andrew@0 107 }
andrew@0 108 }
andrew@0 109
andrew@0 110
andrew@0 111 double midiEventHolder::getEventTimeTicks(double millis){
andrew@0 112 return (millis * pulsesPerQuarternote / period);
andrew@0 113 }
andrew@0 114
andrew@0 115 double midiEventHolder::getEventTimeMillis(double ticks){
andrew@0 116 return (period * ticks / (double) pulsesPerQuarternote);
andrew@0 117 }
andrew@0 118
andrew@0 119 void midiEventHolder::newNoteOnEvent(int pitch, int velocity, double timePlayed){
andrew@0 120
andrew@0 121 //MOVE INTO BAYESSTRUCT?? XXX
andrew@0 122 //bayesStruct.copyPriorToPosterior();
andrew@0 123 //why was this here??
andrew@0 124 bayesStruct.prior.copyFromDynamicVector(bayesStruct.posterior);//try the otehr way
andrew@0 125 //bayesStruct.copyPriorToPosterior();
andrew@0 126 //need to get new MAP position and set the offset of the arrays
andrew@0 127 //currently bestEstimate is the approx for the new MAP position
andrew@0 128
andrew@0 129
andrew@0 130 //add the new event to our played information matrix
andrew@0 131 IntVector v;
andrew@0 132 v.push_back(pitch);
andrew@0 133 v.push_back(velocity);
andrew@0 134 playedNoteOnMatrix.push_back(v);
andrew@0 135
andrew@0 136
andrew@0 137 //would update the arrays at this point to show where out current location (phase) and tempo is.
andrew@2 138 // double timeNow = ofGetElapsedTimeMillis() - startTime;
andrew@2 139 double timeNow = timePlayed;// - startTime;
andrew@2 140 recentNoteOnTime = timePlayed;
andrew@0 141
andrew@2 142 // printf("Max time %f OF time %f \n", timePlayed, timeNow);
andrew@0 143
andrew@0 144 playedEventTimes.push_back(timePlayed);
andrew@0 145
andrew@2 146 // double timeDifference = ofGetElapsedTimeMillis() - bayesStruct.lastEventTime;
andrew@2 147 double timeDifference = timePlayed - bayesStruct.lastEventTime;
andrew@0 148
andrew@9 149 // printf("note %i played at %f and last event %f\n", pitch, timePlayed, bayesStruct.lastEventTime);
andrew@0 150 //addnoise to the tempo distribution
andrew@2 151 //bayesStruct.decaySpeedDistribution(timeDifference);
andrew@2 152 if (timeDifference > 50){
andrew@2 153 bayesStruct.addGaussianNoiseToSpeedPosterior(timeDifference * 10 / 100.);
andrew@2 154 // bayesStruct.addTriangularNoiseToSpeedPosterior(timeDifference * 10 / 100.);
andrew@2 155 }
andrew@2 156
andrew@2 157 bayesStruct.updateTmpBestEstimate(timeDifference);// debug - didnt work bayesStruct.bestEstimate = bayesStruct.tmpBestEstimate;
andrew@2 158 bayesStruct.updateBestEstimate();
andrew@2 159 bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
andrew@0 160
andrew@0 161 // double newMAPestimateTime = bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate);
andrew@0 162 //was offset + bayesStruct.posterior.MAPestimate; but this doesnt include scalar to convert to millis
andrew@0 163
andrew@0 164 timeString = "Pitch:"+ofToString(pitch);
andrew@0 165 timeString += ", time now:"+ofToString(timeNow, 1);
andrew@0 166 timeString += " TD "+ofToString(timeDifference, 1);
andrew@0 167 timeString += " offset "+ofToString(bayesStruct.posterior.offset , 0);
andrew@0 168 timeString += " map Est: "+ofToString(bayesStruct.posterior.MAPestimate, 0);
andrew@0 169 // timeString += " Previous time" + ofToString(newMAPestimateTime,0);
andrew@9 170 timeString += " speedMap "+ofToString(bayesStruct.relativeSpeedPosterior.integratedEstimate, 2);
andrew@9 171 timeString += " :: "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.integratedEstimate), 2);
andrew@0 172
andrew@0 173 // newMAPestimateTime += (timeDifference * bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
andrew@0 174 // timeString += " : Predicted MAP time" + ofToString(newMAPestimateTime,0);
andrew@0 175
andrew@0 176 //then we recalculate the window start based on MAP being central
andrew@0 177 //then we do the matches on these and the likelihood on these.
andrew@0 178
andrew@0 179 bayesStruct.setNewDistributionOffsets(max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)));
andrew@0 180 // bayesStruct.prior.offset = max(0.,newMAPestimateTime - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));
andrew@0 181
andrew@0 182 timeString += " \n : new offset " + ofToString(bayesStruct.prior.offset , 0);
andrew@0 183 timeString += " \n best estimate "+ofToString(bayesStruct.bestEstimate, 1);
andrew@9 184 timeString += " map "+ofToString(bayesStruct.relativeSpeedPosterior.integratedEstimate, 1);
andrew@9 185 timeString += " rel speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.integratedEstimate), 1);
andrew@0 186
andrew@0 187
andrew@0 188 //be able to draw the prior in correct location relative to the midi notes
andrew@2 189 //this calculates the cross update of all possible speeds and all possible positions
andrew@0 190 bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, timeDifference);
andrew@0 191
andrew@0 192
andrew@0 193 timeString += " new OFF "+ofToString(bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2), 1);
andrew@0 194 timeString += " notearrayindex "+ofToString(noteArrayIndex, 0);
andrew@0 195 //when this is off teh screen there is a problem somehow XXX
andrew@0 196 bayesStruct.posterior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));
andrew@0 197 // bayesStruct.prior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));
andrew@0 198 //trying to switch to prior
andrew@0 199
andrew@2 200 //bayesStruct.lastEventTime = ofGetElapsedTimeMillis();
andrew@2 201 bayesStruct.lastEventTime = timePlayed;
andrew@0 202
andrew@0 203 //do the cross update to find current posterior for location
andrew@1 204 // totalConfidence= 0;
andrew@0 205 int numberOfMatchesFound = findLocalMatches(pitch);
andrew@0 206 setMatchLikelihoods(numberOfMatchesFound);
andrew@0 207 bayesStruct.calculatePosterior();
andrew@0 208
andrew@0 209 //having found matches we have matches for new note and matches for previous notes
andrew@6 210 if (!confidenceWeightingUsed)
andrew@0 211 findLocalTempoPairs();
andrew@6 212 else
andrew@6 213 findLocalTempoPairsWeightedForConfidence();
andrew@0 214
andrew@2 215 //bayesStruct.addGaussianNoiseToSpeedPosterior(10);
andrew@0 216
andrew@0 217 }
andrew@0 218
andrew@0 219 int midiEventHolder::findLocalMatches(int notePitch){
andrew@0 220
andrew@0 221 //here we find the matches to the new note within appropriate range
andrew@0 222
andrew@1 223 matchString = "";
andrew@0 224
andrew@0 225 windowStartTime = max(0.0,(bayesStruct.bestEstimate - matchWindowWidth/2));//was playPositionInMillis
andrew@0 226 int numberOfMatches = findMatch(notePitch, windowStartTime, windowStartTime + matchWindowWidth);
andrew@5 227
andrew@0 228
andrew@1 229 matchString += " pitch: "+ofToString(notePitch)+" matches "+ofToString(numberOfMatches)+" win start "+ofToString(windowStartTime);
andrew@1 230
andrew@0 231 return numberOfMatches;
andrew@0 232
andrew@0 233
andrew@0 234 }
andrew@0 235
andrew@0 236
andrew@0 237 void midiEventHolder::setMatchLikelihoods(int numberOfMatches){
andrew@0 238 //reset the offset to match the prior
andrew@0 239 bayesStruct.likelihood.offset = bayesStruct.prior.offset;
andrew@0 240 bayesStruct.likelihood.zero();//set to zero
andrew@0 241
andrew@2 242 double quantity = likelihoodToNoiseRatio / numberOfMatches;
andrew@0 243
andrew@0 244 for (int i = 0;i < numberOfMatches && matchesFound[i] >= 0 && matchesFound[i] < recordedEventTimes.size();i++){
andrew@0 245 // printf("match times %i of %i::%f adding likelihood to %f\n", i, numberOfMatches, recordedEventTimes[matchesFound[i]], recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset);
andrew@0 246 //this is the vent time since start of file
andrew@0 247 if (recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset < bayesStruct.likelihood.arraySize){
andrew@1 248 // double confidenceMeasure = 0;
andrew@1 249 // if (totalConfidence > 0)
andrew@6 250 // confidenceMeasure = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[matchesFound[i]])/totalConfidence;
andrew@2 251
andrew@2 252 bayesStruct.likelihood.addGaussianShape(recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset, likelihoodWidth, quantity);//* confidenceMeasure
andrew@0 253 }//end if
andrew@0 254 }
andrew@2 255 bayesStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesStruct.likelihood.length);
andrew@0 256 }
andrew@0 257
andrew@0 258 int midiEventHolder::findMatch(const int& notePitch, const int& startTime, const int& endTime){
andrew@0 259
andrew@0 260 matchesFound.clear();
andrew@0 261 int startIndex = 0;
andrew@0 262
andrew@0 263 if (recordedEventTimes.size() > 0){
andrew@0 264
andrew@0 265 //get to the right range of events to check in
andrew@0 266 while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < startTime)
andrew@0 267 startIndex++;
andrew@0 268
andrew@0 269 }
andrew@0 270
andrew@6 271 IntVector v;
andrew@6 272 DoubleVector d;
andrew@6 273
andrew@5 274 double minimumConfidence = 0;
andrew@0 275 while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < endTime){
andrew@0 276 if (recordedNoteOnMatrix[startIndex][1] == notePitch){
andrew@6 277
andrew@0 278 matchesFound.push_back(startIndex);
andrew@6 279 v.push_back(startIndex);
andrew@5 280 double eventConfidence = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[startIndex]);
andrew@5 281 if (eventConfidence > minimumConfidence){
andrew@5 282 minimumConfidence = eventConfidence;
andrew@5 283 bestMatchIndex = startIndex;
andrew@5 284 }
andrew@6 285 d.push_back(eventConfidence);
andrew@5 286
andrew@6 287 double confidence = eventConfidence;//bayesStruct.posterior.getValueAtMillis(mouseX);
andrew@1 288 // recordedEventTimes[startIndex]);
andrew@1 289 matchString += "["+ofToString(startIndex)+"] = "+ofToString(confidence, 3)+" .";
andrew@0 290 }
andrew@0 291 startIndex++;
andrew@0 292 }
andrew@5 293
andrew@5 294
andrew@0 295 // printf("%i MATCHES TO Note %i found\n", (int)matchesFound.size(), notePitch);
andrew@0 296 int size = matchesFound.size();
andrew@5 297 if (size > 0)
andrew@5 298 noteOnMatches[bestMatchIndex] = true;
andrew@5 299
andrew@6 300 v.insert(v.begin() , (int)size);
andrew@6 301 d.insert(d.begin() , (double)size);
andrew@6 302
andrew@6 303 //v.push_back(size);
andrew@6 304 //d.push_back(size);
andrew@6 305 //for (int i = 0;i < matchesFound.size()+1;i++){
andrew@6 306 // v.push_back(matchesFound[i]);
andrew@6 307 // printf("match %i,[%i] is %i\n", startIndex, i, v[i]);
andrew@6 308 //}
andrew@6 309
andrew@0 310
andrew@0 311 matchMatrix.push_back(v);
andrew@6 312 matchConfidence.push_back(d);
andrew@0 313
andrew@0 314 return size;
andrew@0 315 }
andrew@0 316
andrew@0 317 bool midiEventHolder::checkIfMatchedNote(const int& tmpIndex){
andrew@0 318 for (int i = 0;i < matchesFound.size();i++){
andrew@0 319 if (matchesFound[i] == tmpIndex)
andrew@0 320 return true;
andrew@0 321 }
andrew@0 322 return false;
andrew@0 323 }
andrew@0 324
andrew@0 325
andrew@0 326
andrew@0 327 void midiEventHolder::findLocalTempoPairs(){
andrew@6 328
andrew@0 329 int currentPlayedIndex = playedNoteOnMatrix.size()-1;
andrew@6 330 // printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]);
andrew@6 331 // printMatchesFound();
andrew@6 332 // printMatchMatrix();
andrew@6 333 // printf("possible notes \n");
andrew@9 334 bool needToUpdate = false;
andrew@9 335 bayesStruct.setLikelihoodToConstant();
andrew@0 336
andrew@0 337
andrew@0 338 for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){
andrew@6 339 //iterate through the recently matched events - even dodgy matches included
andrew@6 340 //size, index of match0, index of match1, ....
andrew@9 341
andrew@9 342
andrew@0 343 int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1];
andrew@0 344
andrew@0 345 int previousIndex = currentPlayedIndex-1;
andrew@9 346
andrew@0 347
andrew@6 348 while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) {
andrew@0 349 double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
andrew@6 350
andrew@0 351 for (int k = 0;k < matchMatrix[previousIndex][0];k++){
andrew@0 352 int recordedPreviousIndex = matchMatrix[previousIndex][k+1];
andrew@0 353
andrew@6 354
andrew@0 355 double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex];
andrew@6 356
andrew@0 357
andrew@0 358 //we want the speed of the recording relative to that of the playing live
andrew@0 359
andrew@0 360 double speedRatio = recordedTimeDifference / playedTimeDifference;
andrew@0 361 if (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){
andrew@6 362 /*
andrew@6 363 printf("(%i)", matchMatrix[currentPlayedIndex][i+1]);
andrew@6 364 printf("[%i] :: ", recordedPreviousIndex);
andrew@6 365 printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference);
andrew@6 366 printf("update on speed ratio %f\n", speedRatio);
andrew@6 367 */
andrew@1 368 // matchString += " speed: "+ofToString(speedRatio, 3);
andrew@6 369 // commented for debug
andrew@2 370
andrew@9 371 //bayesStruct.updateTempoDistribution(speedRatio, 0.1);//second paramter is confidence in the match
andrew@9 372 double amount = (1-bayesStruct.speedLikelihoodNoise)/10;
andrew@9 373 bayesStruct.updateTempoLikelihood(speedRatio, amount);
andrew@9 374 needToUpdate = true;
andrew@0 375 }
andrew@6 376 // printf("\n");
andrew@0 377 }
andrew@0 378
andrew@0 379 previousIndex--;
andrew@0 380 }//end while previousindex countdown
andrew@0 381 }//end for loop through possible current matches
andrew@0 382
andrew@9 383 if (needToUpdate)
andrew@9 384 bayesStruct.updateTempoDistribution();
andrew@9 385
andrew@2 386 //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
andrew@0 387 }
andrew@0 388
andrew@0 389
andrew@6 390 void midiEventHolder::findLocalTempoPairsWeightedForConfidence(){
andrew@9 391 bool needToUpdate = false;
andrew@6 392
andrew@6 393 int currentPlayedIndex = playedNoteOnMatrix.size()-1;
andrew@6 394 // printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]);
andrew@6 395 // printMatchesFound();
andrew@6 396 // printMatchMatrix();
andrew@6 397 // printf("possible notes \n");
andrew@6 398
andrew@9 399 bayesStruct.setLikelihoodToConstant();
andrew@6 400
andrew@6 401 for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){
andrew@6 402 //iterate through the recently matched events - even dodgy matches included
andrew@6 403 //size, index of match0, index of match1, ....
andrew@6 404 int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1];
andrew@6 405
andrew@6 406 double currentMatchConfidence = matchConfidence[currentPlayedIndex][i+1];//new confidence
andrew@6 407
andrew@6 408 int previousIndex = currentPlayedIndex-1;
andrew@6 409
andrew@6 410 while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) {
andrew@6 411 double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
andrew@6 412
andrew@6 413 for (int k = 0;k < matchMatrix[previousIndex][0];k++){
andrew@6 414 int recordedPreviousIndex = matchMatrix[previousIndex][k+1];
andrew@6 415
andrew@6 416 double previousMatchConfidence = matchConfidence[previousIndex][k+1];
andrew@6 417
andrew@6 418
andrew@6 419 double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex];
andrew@6 420
andrew@6 421
andrew@6 422 //we want the speed of the recording relative to that of the playing live
andrew@6 423
andrew@6 424 double speedRatio = recordedTimeDifference / playedTimeDifference;
andrew@6 425 if (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){
andrew@6 426
andrew@6 427 printf("(%i)", matchMatrix[currentPlayedIndex][i+1]);
andrew@6 428 printf("[%i] :: ", recordedPreviousIndex);
andrew@6 429 printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence);
andrew@6 430 printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference);
andrew@6 431 printf("update on speed ratio %f\n", speedRatio);
andrew@6 432
andrew@6 433 // matchString += " speed: "+ofToString(speedRatio, 3);
andrew@6 434 // commented for debug
andrew@9 435 double weighting = previousMatchConfidence * currentMatchConfidence ;
andrew@9 436 double amount = (1-bayesStruct.speedLikelihoodNoise)*weighting/10;
andrew@9 437 bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match
andrew@9 438 needToUpdate = true;
andrew@6 439 }
andrew@6 440 // printf("\n");
andrew@6 441 }
andrew@6 442
andrew@6 443 previousIndex--;
andrew@6 444 }//end while previousindex countdown
andrew@6 445 }//end for loop through possible current matches
andrew@6 446
andrew@9 447 if (needToUpdate)
andrew@9 448 bayesStruct.updateTempoDistribution();
andrew@6 449 //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
andrew@6 450 }
andrew@6 451
andrew@6 452
andrew@6 453
andrew@0 454 void midiEventHolder::updatePlayPosition(){
andrew@0 455
andrew@0 456 //in actual fact if we are changing the speed of the play position
andrew@0 457 //we will need to update this via the file
andrew@0 458
andrew@0 459 double timeDifference = ofGetElapsedTimeMillis() - lastPeriodUpdateTime;
andrew@0 460 //this is time diff in milliseconds
andrew@0 461 //then we have
andrew@0 462 double quarterNoteIntervals = (timeDifference / period);
andrew@0 463 tickLocation = quarterNoteIntervals * pulsesPerQuarternote;
andrew@0 464
andrew@0 465 playPositionInMillis = timeDifference;//based on updating from when we change period
andrew@0 466 //this to be added
andrew@0 467
andrew@0 468 bayesStruct.updateBestEstimate();
andrew@0 469
andrew@0 470 }
andrew@0 471
andrew@0 472
andrew@9 473 void midiEventHolder::drawMidiFile(){
andrew@9 474
andrew@0 475 //draws midi file on scrolling screen
andrew@0 476 int size = recordedNoteOnMatrix.size();
andrew@0 477 if (size > 0){
andrew@0 478
andrew@0 479 numberOfScreensIn = floor(bayesStruct.bestEstimate / getEventTimeMillis(ticksPerScreen));//rpounds down on no screens in
andrew@0 480
andrew@9 481 // numberOfScreensIn = tickLocation / ticksPerScreen;//rounds down
andrew@0 482 timeOffsetForScreen = getEventTimeMillis(numberOfScreensIn * ticksPerScreen);
andrew@0 483
andrew@0 484 while (noteArrayIndex < recordedNoteOnMatrix.size() && tickLocation > recordedNoteOnMatrix[noteArrayIndex][0] )
andrew@0 485 noteArrayIndex++;
andrew@0 486
andrew@0 487
andrew@0 488 while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < recordedNoteOnMatrix[noteArrayIndex][0])
andrew@0 489 noteArrayIndex--;
andrew@0 490
andrew@0 491 //need to start where we currently are in file
andrew@0 492 int maxNoteIndexToPrint = noteArrayIndex;
andrew@0 493 int minNoteIndexToPrint = noteArrayIndex;
andrew@0 494
andrew@0 495 while (maxNoteIndexToPrint < recordedNoteOnMatrix.size() && recordedNoteOnMatrix[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen )
andrew@0 496 maxNoteIndexToPrint++;
andrew@0 497
andrew@0 498 while (minNoteIndexToPrint > 0 && minNoteIndexToPrint < size && recordedNoteOnMatrix[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen)
andrew@0 499 minNoteIndexToPrint--;
andrew@0 500
andrew@0 501 for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)recordedNoteOnMatrix.size());tmpIndex++){
andrew@0 502
andrew@0 503 if (checkIfMatchedNote(tmpIndex))
andrew@0 504 ofSetColor(0,0,255);
andrew@5 505 else if(noteOnMatches[tmpIndex]){
andrew@9 506 ofSetColor(255,0,255);
andrew@5 507 }else{
andrew@0 508 ofSetColor(255,255,255);
andrew@5 509 }
andrew@5 510
andrew@9 511
andrew@9 512
andrew@9 513 // XXX replace ofgetwidth below
andrew@0 514 //if (tmpIndex >= 0 && tmpIndex < size)
andrew@0 515 int xLocation = (float)(recordedNoteOnMatrix[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen;
andrew@0 516 int duration = (float)(recordedNoteOnMatrix[tmpIndex][3]*(*screenWidth))/(float)ticksPerScreen;
andrew@0 517
andrew@0 518
andrew@0 519 int yLocation = (*screenHeight) - ((recordedNoteOnMatrix[tmpIndex][1] - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum));
andrew@0 520 ofRect(xLocation,yLocation, duration, noteHeight);
andrew@0 521
andrew@0 522 }
andrew@0 523
andrew@0 524
andrew@0 525 int xLocation;// = getLocationFromTicks(tickLocation);
andrew@9 526 // ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@0 527
andrew@0 528 //orange line at best estimate
andrew@0 529 xLocation = getLocationFromMillis(bayesStruct.bestEstimate);
andrew@0 530 ofSetColor(250,100,0);
andrew@0 531 ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@0 532
andrew@2 533 xLocation = getLocationFromMillis(bayesStruct.tmpBestEstimate);
andrew@2 534 ofSetColor(250,100,0);
andrew@2 535 ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@2 536
andrew@0 537
andrew@0 538 //lines where matching window start and end are
andrew@0 539 ofSetColor(0,100,255);
andrew@0 540 xLocation = getLocationFromMillis(windowStartTime);
andrew@0 541 ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@0 542 xLocation = getLocationFromMillis(windowStartTime+matchWindowWidth);
andrew@0 543 ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@9 544
andrew@0 545
andrew@0 546 }
andrew@0 547
andrew@0 548 ofDrawBitmapString(ofToString(timeOffsetForScreen, 1), 20,20);
andrew@0 549
andrew@0 550 ofDrawBitmapString(timeString, 20, 60);
andrew@0 551
andrew@9 552
andrew@9 553 }
andrew@9 554
andrew@9 555 void midiEventHolder::drawFile(){
andrew@9 556 drawMidiFile();
andrew@9 557
andrew@9 558
andrew@0 559 // bayesStruct.drawArrays();
andrew@0 560
andrew@0 561 // ofSetColor(200,200,0);
andrew@0 562 // bayesStruct.prior.drawConstrainedVector(0, bayesStruct.prior.arraySize, 400, 800);
andrew@0 563
andrew@0 564 //need to draw arrays within correct timescope
andrew@9 565 if (drawPhaseMode)
andrew@0 566 bayesStruct.drawArraysRelativeToTimeframe(timeOffsetForScreen, timeOffsetForScreen + getEventTimeMillis(ticksPerScreen));
andrew@0 567
andrew@1 568 if (drawTempoMode)
andrew@1 569 bayesStruct.drawTempoArrays();
andrew@0 570
andrew@1 571
andrew@1 572 ofSetColor(0, 0, 0);
andrew@0 573 ofDrawBitmapString(matchString, 20, ofGetHeight() - 20);
andrew@0 574
andrew@1 575 double confidence = bayesStruct.posterior.getValueAtMillis(mouseX);
andrew@2 576 /*
andrew@2 577 string mouseString = "mouseX "+ofToString(confidence, 3)+" .";
andrew@1 578 ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40);
andrew@2 579 */
andrew@2 580 string mouseString = "updateCounter "+ofToString(bayesStruct.updateCounter);
andrew@2 581 ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40);
andrew@2 582
andrew@2 583 string infostring = "speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 3);
andrew@2 584 ofDrawBitmapString(infostring, 20 , ofGetHeight() - 60);
andrew@0 585 }
andrew@0 586
andrew@0 587 int midiEventHolder::getLocationFromTicks(double tickPosition){
andrew@0 588 return (int)((float)(tickPosition - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen);
andrew@0 589 }
andrew@0 590
andrew@0 591 int midiEventHolder::getLocationFromMillis(double millisPosition){
andrew@0 592 //(getEventTimeTicks(windowStartTime+matchWindowWidth) - numberOfScreensIn*ticksPerScreen)*(*screenWidth) / (double)ticksPerScreen
andrew@0 593 return (millisPosition - timeOffsetForScreen)*(*screenWidth)/getEventTimeMillis(ticksPerScreen);
andrew@0 594 }
andrew@0 595
andrew@0 596
andrew@0 597 void midiEventHolder::exampleCrossUpdate(){
andrew@0 598
andrew@0 599 bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, 200);
andrew@0 600
andrew@0 601 }
andrew@0 602
andrew@0 603
andrew@0 604 void midiEventHolder::setStartPlayingTimes(){
andrew@0 605 lastPeriodUpdateTime = ofGetElapsedTimeMillis();
andrew@0 606 startTime = lastPeriodUpdateTime;
andrew@0 607
andrew@2 608 /*
andrew@2 609 bayesStruct.lastEventTime = 0;//ofGetElapsedTimeMillis();
andrew@2 610 bayesStruct.bestEstimate = 0;
andrew@0 611 bayesStruct.resetArrays();
andrew@2 612 bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
andrew@2 613 */
andrew@2 614 bayesStruct.setStartPlaying();
andrew@0 615 matchString = "";
andrew@0 616 }
andrew@0 617
andrew@0 618
andrew@0 619 void midiEventHolder::printMatchMatrix(){
andrew@0 620 printf("match matrix:\n");
andrew@0 621 for (int i = 0;i < matchMatrix.size();i++){
andrew@0 622 for (int k = 0;k < matchMatrix[i].size();k++){
andrew@0 623 printf("%i , ", matchMatrix[i][k]);
andrew@0 624 }
andrew@0 625 printf("\n");
andrew@0 626 }
andrew@0 627
andrew@0 628
andrew@0 629 }