annotate src/midiEventHolder.cpp @ 21:11e3119ce6b4

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