annotate src/midiEventHolder.cpp @ 14:3f103cf78148

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