annotate src/midiEventHolder.cpp @ 52:13194a9dca77 tip

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