annotate src/midiEventHolder.cpp @ 22:9860abc92a30

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