annotate hackday/midiEventHolder.cpp @ 36:5a1b0c6fa1fb

Added class to read in the csv Annotation file, then write out the respective difference between the performed piece as followed here, and the annotation of RWC by Ewert and Muller
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Thu, 15 Dec 2011 02:28:49 +0000
parents f91b7b019350
children
rev   line source
andrew@24 1 /*
andrew@24 2 * midiEventHolder.cpp
andrew@24 3 * midiCannamReader3
andrew@24 4 *
andrew@24 5 * Created by Andrew on 19/07/2011.
andrew@24 6 * Copyright 2011 QMUL. All rights reserved.
andrew@24 7 *
andrew@24 8 */
andrew@24 9
andrew@29 10
andrew@29 11 //Main file to look at here is newNoteEvent() - this calls everything else to update the Bayesian array
andrew@29 12
andrew@24 13 #include "midiEventHolder.h"
andrew@24 14
andrew@24 15 midiEventHolder::midiEventHolder(){
andrew@24 16 // recordedNoteOnIndex = 0;
andrew@24 17
andrew@24 18 useTempoPrior = false;//puts sine wave round tempo
andrew@24 19 confidenceWeightingUsed = true;
andrew@30 20 newOptimalMethod = true;
andrew@30 21
andrew@31 22 matchWindowWidth = 8000;//window size for matching in ms
andrew@30 23 interNoteRange = 1600;//preferred duration
andrew@30 24 //so max here is really four
andrew@24 25
andrew@32 26
andrew@32 27 likelihoodWidth = 100;//using 100 is good
andrew@32 28 likelihoodToNoiseRatio = 0.20;//was 0.02 on 18/11/11, changing to give more weight to observations
andrew@32 29 //was 0.08 on 11/12/11 but need more for tempo varn in rwc database
andrew@32 30
andrew@32 31 bayesStruct.speedLikelihoodNoise = 0.1;//was 0.05
andrew@32 32 bayesStruct.speedDecayWidth = 40;
andrew@32 33 bayesStruct.speedDecayAmount = 10;
andrew@32 34
andrew@32 35
andrew@24 36 //there is option to use MAP estinate or integral in beayesianarraystricture class
andrew@24 37
andrew@24 38 runningInRealTime = true;
andrew@24 39 bayesStruct.realTimeMode = &runningInRealTime;
andrew@24 40
andrew@31 41 minimumMatchSpeed = 0.0;
andrew@24 42 maximumMatchSpeed = 2.0;
andrew@24 43 minimumTimeIntervalForTempoUpdate = 150;
andrew@24 44
andrew@24 45 width = ofGetWidth();
andrew@24 46 height = ofGetHeight();
andrew@24 47 screenWidth= &width;
andrew@24 48 screenHeight = &height;
andrew@24 49
andrew@24 50 ticksPerScreen = 4000;
andrew@24 51 tickLocation = 0;
andrew@24 52 pulsesPerQuarternote = 240;
andrew@24 53 noteArrayIndex = 0;
andrew@24 54 noteMinimum = 30;
andrew@24 55 noteMaximum = 96;
andrew@24 56
andrew@24 57
andrew@24 58
andrew@24 59
andrew@24 60
andrew@24 61 speedPriorValue = 1.0;
andrew@24 62
andrew@24 63
andrew@24 64 bayesStruct.resetSize(matchWindowWidth);
andrew@24 65 bayesStruct.setPositionDistributionScalar(1);
andrew@24 66
andrew@24 67 bayesStruct.resetSpeedSize(200);
andrew@24 68 bayesStruct.setRelativeSpeedScalar(0.01);
andrew@24 69 bayesStruct.relativeSpeedPrior.getMaximum();
andrew@24 70 //bayesStruct.simpleExample();
andrew@24 71
andrew@24 72
andrew@31 73 speedWindowWidthMillis = 1600;//4000
andrew@24 74 speedPriorValue = 1.0;
andrew@24 75 noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum);
andrew@24 76
andrew@24 77
andrew@30 78 intervalsToCheck.push_back(1);
andrew@30 79 intervalsToCheck.push_back(2);
andrew@30 80 //intervalsToCheck.push_back(3);
andrew@30 81 intervalsToCheck.push_back(4);
andrew@30 82 intervalsToCheck.push_back(6);
andrew@30 83 intervalsToCheck.push_back(8);
andrew@30 84 intervalsToCheck.push_back(16);
andrew@30 85
andrew@24 86
andrew@24 87 drawPhaseMode = true;
andrew@24 88
andrew@24 89 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@24 90 }
andrew@24 91
andrew@24 92
andrew@24 93
andrew@24 94 void midiEventHolder::reset(){
andrew@24 95 //called when we start playing
andrew@24 96
andrew@24 97 noteArrayIndex = 0;
andrew@24 98 tickLocation = 0;
andrew@24 99 lastPeriodUpdateTime = getTimeNow(0);//ofGetElapsedTimeMillis();
andrew@24 100 bayesStruct.lastEventTime = getTimeNow(0);//ofGetElapsedTimeMillis();
andrew@24 101 numberOfScreensIn = 0;
andrew@24 102 // recordedNoteOnIndex = 0;
andrew@24 103 bayesStruct.setNewDistributionOffsets(0);
andrew@24 104 bayesStruct.posterior.offset = 0;
andrew@24 105
andrew@24 106 playedEventTimes.clear();
andrew@24 107 playedNoteOnMatrix.clear();
andrew@24 108 matchMatrix.clear();
andrew@24 109 bestMatchIndex = 0;
andrew@24 110
andrew@26 111 recordedTotalNoteCounterByPitch.clear();
andrew@26 112 recordedTotalNoteCounterByPitch.assign(127,0);
andrew@26 113 totalNoteCounterIndex = 0;
andrew@26 114
andrew@30 115 interNoteIntervals.clear();
andrew@26 116
andrew@24 117 bayesStruct.resetSpeedToOne();
andrew@24 118 bayesStruct.setSpeedPrior(speedPriorValue);
andrew@24 119 setMatchedNotesBackToFalse();
andrew@30 120
andrew@24 121 }
andrew@24 122
andrew@24 123 void midiEventHolder::setMatchedNotesBackToFalse(){
andrew@24 124 for (int i = 0;i < noteOnMatches.size();i++)
andrew@24 125 noteOnMatches[i] = false;
andrew@24 126 }
andrew@24 127
andrew@24 128 void midiEventHolder::clearAllEvents(){
andrew@24 129 recordedNoteOnMatrix.clear();
andrew@24 130 matchesFound.clear();
andrew@24 131 noteOnMatches.clear();
andrew@24 132 recordedEventTimes.clear();
andrew@25 133 measureVector.clear();
andrew@24 134 //played events:
andrew@24 135 playedEventTimes.clear();
andrew@24 136 playedNoteOnMatrix.clear();
andrew@24 137 matchMatrix.clear();
andrew@24 138 bestMatchFound.clear();
andrew@31 139 periodValues.clear();
andrew@26 140
andrew@26 141 recordedTotalNoteCounterByPitch.clear();
andrew@26 142 recordedTotalNoteCounterByPitch.assign(127, 0);
andrew@26 143 totalNoteCounterIndex = 0;
andrew@24 144 }
andrew@24 145
andrew@24 146 void midiEventHolder::printNotes(){
andrew@24 147 printf("RECORDED MATRIX\n");
andrew@24 148 for (int i = 0;i < recordedNoteOnMatrix.size();i++){
andrew@24 149 printf("ticktime %i :: pitch %i @ millis %f\n", recordedNoteOnMatrix[i][0], recordedNoteOnMatrix[i][1], recordedEventTimes[i]);
andrew@24 150 }
andrew@24 151 }
andrew@24 152
andrew@24 153
andrew@24 154 double midiEventHolder::getEventTimeTicks(double millis){
andrew@24 155 return (millis * pulsesPerQuarternote / period);
andrew@24 156 }
andrew@24 157
andrew@24 158 double midiEventHolder::getEventTimeMillis(double ticks){
andrew@24 159 return (period * ticks / (double) pulsesPerQuarternote);
andrew@24 160 }
andrew@24 161
andrew@24 162 void midiEventHolder::newNoteOnEvent(int pitch, int velocity, double timePlayed){
andrew@24 163 // tempoSpeedString = "";
andrew@24 164
andrew@24 165 //MOVE INTO BAYESSTRUCT?? XXX
andrew@24 166 //bayesStruct.copyPriorToPosterior();
andrew@24 167 //why was this here??
andrew@24 168 bayesStruct.prior.copyFromDynamicVector(bayesStruct.posterior);//try the otehr way
andrew@24 169 //bayesStruct.copyPriorToPosterior();
andrew@24 170 //need to get new MAP position and set the offset of the arrays
andrew@24 171 //currently bestEstimate is the approx for the new MAP position
andrew@24 172
andrew@25 173 lastPlayedPitch = pitch;
andrew@24 174 //add the new event to our played information matrix
andrew@24 175 IntVector v;
andrew@24 176 v.push_back(pitch);
andrew@24 177 v.push_back(velocity);
andrew@24 178 playedNoteOnMatrix.push_back(v);
andrew@24 179
andrew@24 180
andrew@24 181 //would update the arrays at this point to show where out current location (phase) and tempo is.
andrew@24 182 // double timeNow = ofGetElapsedTimeMillis() - startTime;
andrew@24 183 double timeNow = timePlayed;// - startTime;
andrew@24 184 recentNoteOnTime = timePlayed;
andrew@24 185
andrew@24 186 // printf("Max time %f OF time %f \n", timePlayed, timeNow);
andrew@24 187
andrew@24 188 playedEventTimes.push_back(timePlayed);
andrew@24 189
andrew@24 190 // double timeDifference = ofGetElapsedTimeMillis() - bayesStruct.lastEventTime;
andrew@24 191 double timeDifference = timePlayed - bayesStruct.lastEventTime;
andrew@24 192
andrew@24 193
andrew@24 194
andrew@24 195 //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 196
andrew@24 197 //addnoise to the tempo distribution
andrew@24 198 //bayesStruct.decaySpeedDistribution(timeDifference);
andrew@31 199
andrew@24 200 if (timeDifference > 50){
andrew@31 201 bayesStruct.addGaussianNoiseToSpeedPosterior(timeDifference * 10.0 / 100.);
andrew@24 202 // bayesStruct.addTriangularNoiseToSpeedPosterior(timeDifference * 10 / 100.);
andrew@24 203 }
andrew@24 204
andrew@24 205 bayesStruct.updateTmpBestEstimate(timeDifference);// debug - didnt work bayesStruct.bestEstimate = bayesStruct.tmpBestEstimate;
andrew@24 206 bayesStruct.updateBestEstimate(timeDifference);
andrew@24 207 bayesStruct.lastBestEstimateUpdateTime = getTimeNow(timePlayed);
andrew@24 208
andrew@24 209 // double newMAPestimateTime = bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate);
andrew@24 210 //was offset + bayesStruct.posterior.MAPestimate; but this doesnt include scalar to convert to millis
andrew@24 211
andrew@24 212 timeString = "Pitch:"+ofToString(pitch);
andrew@24 213 timeString += ", time now:"+ofToString(timeNow, 1);
andrew@24 214 timeString += " TD "+ofToString(timeDifference, 1);
andrew@24 215 timeString += " offset "+ofToString(bayesStruct.posterior.offset , 0);
andrew@24 216 timeString += " map Est: "+ofToString(bayesStruct.posterior.MAPestimate, 0);
andrew@24 217 // timeString += " Previous time" + ofToString(newMAPestimateTime,0);
andrew@24 218 timeString += " speedMap "+ofToString(bayesStruct.relativeSpeedPosterior.integratedEstimate, 2);
andrew@24 219 timeString += " :: "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.integratedEstimate), 2);
andrew@24 220
andrew@24 221 // newMAPestimateTime += (timeDifference * bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
andrew@24 222 // timeString += " : Predicted MAP time" + ofToString(newMAPestimateTime,0);
andrew@24 223
andrew@24 224 //then we recalculate the window start based on MAP being central
andrew@24 225 //then we do the matches on these and the likelihood on these.
andrew@24 226
andrew@24 227 bayesStruct.setNewDistributionOffsets(max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)));
andrew@24 228 // bayesStruct.prior.offset = max(0.,newMAPestimateTime - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));
andrew@24 229
andrew@24 230 timeString += " \n : new offset " + ofToString(bayesStruct.prior.offset , 0);
andrew@24 231 timeString += " \n best estimate "+ofToString(bayesStruct.bestEstimate, 1);
andrew@24 232 timeString += " error "+ofToString(minimumMatchError, 0);
andrew@24 233 timeString += " map "+ofToString(bayesStruct.relativeSpeedPosterior.integratedEstimate, 1);
andrew@24 234 timeString += " rel speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.integratedEstimate), 2);
andrew@24 235
andrew@24 236
andrew@24 237 //be able to draw the prior in correct location relative to the midi notes
andrew@24 238 //this calculates the cross update of all possible speeds and all possible positions
andrew@24 239 bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, timeDifference);
andrew@24 240
andrew@24 241
andrew@24 242 timeString += " new OFF "+ofToString(bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2), 1);
andrew@24 243 timeString += " notearrayindex "+ofToString(noteArrayIndex, 0);
andrew@24 244 //when this is off teh screen there is a problem somehow XXX
andrew@24 245
andrew@24 246 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@24 247
andrew@24 248 //trying to switch to prior
andrew@24 249
andrew@24 250
andrew@24 251 bayesStruct.lastEventTime = timePlayed;//bayesStruct.lastEventTime = ofGetElapsedTimeMillis();
andrew@24 252
andrew@24 253 //do the cross update to find current posterior for location
andrew@24 254 // totalConfidence= 0;
andrew@24 255 int numberOfMatchesFound = findLocalMatches(pitch);
andrew@24 256 setMatchLikelihoods(numberOfMatchesFound);
andrew@24 257 bayesStruct.calculatePosterior();
andrew@24 258
andrew@30 259 if (recordedEventTimes.size() > 0){
andrew@29 260 updateTempo();
andrew@30 261 //calcuateNewInterNoteIntervals();
andrew@30 262 }
andrew@29 263
andrew@29 264 }
andrew@29 265
andrew@29 266 void midiEventHolder::updateTempo(){
andrew@24 267 //having found matches we have matches for new note and matches for previous notes
andrew@30 268 if (newOptimalMethod)
andrew@30 269 findOptimumTempoPairsToCurrentBestMatch();
andrew@30 270 else if (!confidenceWeightingUsed)
andrew@29 271 findLocalTempoPairs();
andrew@24 272 else
andrew@29 273 findLocalTempoPairsWeightedForConfidence();
andrew@30 274
andrew@24 275
andrew@24 276 //bayesStruct.addGaussianNoiseToSpeedPosterior(10);
andrew@24 277 }
andrew@24 278
andrew@24 279 double midiEventHolder::getTimeNow(double eventTime){
andrew@24 280 double timeNow = eventTime;
andrew@24 281 if (runningInRealTime)
andrew@24 282 timeNow = ofGetElapsedTimeMillis();
andrew@24 283 return timeNow;
andrew@24 284 }
andrew@24 285
andrew@24 286 int midiEventHolder::findLocalMatches(int notePitch){
andrew@24 287
andrew@24 288 //here we find the matches to the new note within appropriate range
andrew@24 289
andrew@24 290 matchString = "";
andrew@24 291
andrew@24 292 windowStartTime = max(0.0,(bayesStruct.bestEstimate - matchWindowWidth/2));//was playPositionInMillis
andrew@24 293 // cout << "best estimate is " << bayesStruct.bestEstimate << endl;
andrew@24 294 int numberOfMatches = findMatch(notePitch, windowStartTime, windowStartTime + matchWindowWidth);
andrew@24 295
andrew@24 296
andrew@24 297 //matchString += " pitch: "+ofToString(notePitch)+" matches "+ofToString(numberOfMatches)+" win start "+ofToString(windowStartTime);
andrew@24 298
andrew@24 299 return numberOfMatches;
andrew@24 300
andrew@24 301
andrew@24 302 }
andrew@24 303
andrew@24 304
andrew@24 305 void midiEventHolder::setMatchLikelihoods(int numberOfMatches){
andrew@24 306 //reset the offset to match the prior
andrew@24 307 bayesStruct.likelihood.offset = bayesStruct.prior.offset;
andrew@24 308 bayesStruct.likelihood.zero();//set to zero
andrew@24 309
andrew@24 310 double quantity = likelihoodToNoiseRatio / numberOfMatches;
andrew@24 311
andrew@24 312 for (int i = 0;i < numberOfMatches && matchesFound[i] >= 0 && matchesFound[i] < recordedEventTimes.size();i++){
andrew@24 313 // printf("match times %i of %i::%f adding likelihood to %f\n", i, numberOfMatches, recordedEventTimes[matchesFound[i]], recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset);
andrew@24 314 //this is the vent time since start of file
andrew@24 315 if (recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset < bayesStruct.likelihood.arraySize){
andrew@24 316 // double confidenceMeasure = 0;
andrew@24 317 // if (totalConfidence > 0)
andrew@24 318 // confidenceMeasure = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[matchesFound[i]])/totalConfidence;
andrew@24 319
andrew@24 320 bayesStruct.likelihood.addGaussianShape(recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset, likelihoodWidth, quantity);//* confidenceMeasure
andrew@24 321 }//end if
andrew@24 322 }
andrew@24 323 bayesStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesStruct.likelihood.length);
andrew@24 324 }
andrew@24 325
andrew@24 326 int midiEventHolder::findMatch(const int& notePitch, const int& startTime, const int& endTime){
andrew@24 327
andrew@24 328 matchesFound.clear();
andrew@24 329 int startIndex = 0;
andrew@24 330
andrew@24 331 if (recordedEventTimes.size() > 0){
andrew@24 332
andrew@24 333 //get to the right range of events to check in
andrew@24 334 while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < startTime)
andrew@24 335 startIndex++;
andrew@24 336
andrew@24 337 }
andrew@24 338
andrew@24 339 IntVector v;
andrew@24 340 DoubleVector d;
andrew@24 341 double tmpError = 100000.;//v high error
andrew@24 342
andrew@24 343 double minimumConfidence = 0;
andrew@24 344 while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < endTime){
andrew@24 345 if (recordedNoteOnMatrix[startIndex][1] == notePitch){
andrew@24 346
andrew@24 347 matchesFound.push_back(startIndex);
andrew@24 348 v.push_back(startIndex);
andrew@24 349 //so startIndex is registered as a match
andrew@24 350
andrew@24 351 double eventConfidence = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[startIndex]);
andrew@24 352 if (eventConfidence > minimumConfidence){
andrew@24 353 minimumConfidence = eventConfidence;
andrew@24 354 bestMatchIndex = startIndex;
andrew@24 355 }
andrew@24 356 d.push_back(eventConfidence);
andrew@24 357
andrew@24 358 double confidence = eventConfidence;//bayesStruct.posterior.getValueAtMillis(mouseX);
andrew@24 359 // recordedEventTimes[startIndex]);
andrew@24 360 // matchString += "["+ofToString(startIndex)+"] = "+ofToString(confidence, 3)+" .";
andrew@24 361
andrew@24 362 if (abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate) < tmpError){
andrew@24 363 //record the error between expected and observed times
andrew@24 364 tmpError = abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate);
andrew@24 365 minimumMatchError = tmpError;//recordedEventTimes[startIndex] - bayesStruct.bestEstimate;
andrew@24 366 }
andrew@24 367
andrew@24 368 }
andrew@24 369 startIndex++;
andrew@24 370 }
andrew@24 371
andrew@24 372
andrew@24 373 // printf("%i MATCHES TO Note %i found\n", (int)matchesFound.size(), notePitch);
andrew@24 374 int size = matchesFound.size();
andrew@24 375 if (size > 0)
andrew@24 376 noteOnMatches[bestMatchIndex] = true;
andrew@24 377
andrew@24 378 v.insert(v.begin() , (int)size);//at beginning, we list how many matches there are that we have found
andrew@24 379 d.insert(d.begin() , (double)size);
andrew@24 380
andrew@24 381 //v.push_back(size);
andrew@24 382 //d.push_back(size);
andrew@24 383 //for (int i = 0;i < matchesFound.size()+1;i++){
andrew@24 384 // v.push_back(matchesFound[i]);
andrew@24 385 // printf("match %i,[%i] is %i\n", startIndex, i, v[i]);
andrew@24 386 //}
andrew@24 387
andrew@24 388
andrew@24 389 matchMatrix.push_back(v);
andrew@24 390 matchConfidence.push_back(d);
andrew@24 391
andrew@24 392 //bringing in way to list only the best matches and use these in tempo process
andrew@24 393 bestMatchFound.push_back(bestMatchIndex);
andrew@24 394
andrew@24 395 // 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@24 396
andrew@24 397 return size;
andrew@24 398 }
andrew@24 399
andrew@24 400 bool midiEventHolder::checkIfMatchedNote(const int& tmpIndex){
andrew@24 401 for (int i = 0;i < matchesFound.size();i++){
andrew@24 402 if (matchesFound[i] == tmpIndex)
andrew@24 403 return true;
andrew@24 404 }
andrew@24 405 return false;
andrew@24 406 }
andrew@24 407
andrew@24 408
andrew@24 409
andrew@24 410 void midiEventHolder::findLocalTempoPairs(){
andrew@24 411
andrew@24 412 int currentPlayedIndex = playedNoteOnMatrix.size()-1;
andrew@24 413 // printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]);
andrew@24 414 // printMatchesFound();
andrew@24 415 // printMatchMatrix();
andrew@24 416 // printf("possible notes \n");
andrew@24 417 bool needToUpdate = false;
andrew@24 418 bayesStruct.setLikelihoodToConstant();
andrew@24 419
andrew@24 420
andrew@24 421 for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){
andrew@24 422 //iterate through the recently matched events - even dodgy matches included
andrew@24 423 //size, index of match0, index of match1, ....
andrew@24 424
andrew@24 425
andrew@24 426 int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1];
andrew@24 427
andrew@24 428 int previousIndex = currentPlayedIndex-1;
andrew@24 429
andrew@24 430
andrew@24 431 while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) {
andrew@24 432 double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
andrew@24 433
andrew@24 434 for (int k = 0;k < matchMatrix[previousIndex][0];k++){
andrew@24 435
andrew@24 436 int recordedPreviousIndex = matchMatrix[previousIndex][k+1];
andrew@24 437
andrew@24 438 double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex];
andrew@24 439
andrew@24 440
andrew@24 441 //we want the speed of the recording relative to that of the playing live
andrew@24 442
andrew@24 443 double speedRatio = recordedTimeDifference / playedTimeDifference;
andrew@24 444 if (recordedTimeDifference > minimumTimeIntervalForTempoUpdate &&
andrew@24 445 speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){
andrew@24 446
andrew@24 447 //adding in a prior that prefers 1
andrew@24 448 double priorWeighting = 1;
andrew@24 449 if (useTempoPrior)
andrew@24 450 priorWeighting = sin(speedRatio * PI/2);
andrew@24 451
andrew@24 452
andrew@24 453
andrew@24 454 /*
andrew@24 455 printf("(%i)", matchMatrix[currentPlayedIndex][i+1]);
andrew@24 456 printf("[%i] :: ", recordedPreviousIndex);
andrew@24 457 printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference);
andrew@24 458 printf("update on speed ratio %f\n", speedRatio);
andrew@24 459 */
andrew@24 460 // matchString += " speed: "+ofToString(speedRatio, 3);
andrew@24 461 // commented for debug
andrew@24 462
andrew@24 463 //bayesStruct.updateTempoDistribution(speedRatio, 0.1);//second paramter is confidence in the match
andrew@24 464 double amount = (1-bayesStruct.speedLikelihoodNoise)/10;
andrew@24 465 amount *= priorWeighting;
andrew@24 466 bayesStruct.updateTempoLikelihood(speedRatio, amount);
andrew@24 467 // tempoSpeedString += ofToString(recordedPreviousIndex) + " "+ ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n";
andrew@24 468 needToUpdate = true;
andrew@24 469 }
andrew@24 470 // printf("\n");
andrew@24 471 }
andrew@24 472
andrew@24 473 previousIndex--;
andrew@24 474 }//end while previousindex countdown
andrew@24 475 }//end for loop through possible current matches
andrew@24 476
andrew@24 477 if (needToUpdate)
andrew@24 478 bayesStruct.updateTempoDistribution();
andrew@24 479
andrew@24 480 //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
andrew@24 481 }
andrew@24 482
andrew@24 483
andrew@24 484 void midiEventHolder::findLocalTempoPairsWeightedForConfidence(){
andrew@24 485 bool needToUpdate = false;
andrew@24 486
andrew@24 487 DoubleVector speedIntervalsFound;
andrew@24 488
andrew@24 489 //adapted this to just use the best match for each note
andrew@24 490
andrew@24 491 int currentPlayedIndex = playedNoteOnMatrix.size()-1;
andrew@24 492 // printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]);
andrew@24 493 // printMatchesFound();
andrew@24 494 // printMatchMatrix();
andrew@24 495 // printf("possible notes \n");
andrew@24 496
andrew@24 497 bayesStruct.setLikelihoodToConstant();
andrew@24 498
andrew@24 499 int recordedCurrentIndex = bestMatchFound[currentPlayedIndex];
andrew@24 500 //we only look at intervals between the current best match and other recent best matched notes
andrew@24 501 //that is the difference in confidence method
andrew@24 502
andrew@24 503
andrew@24 504 //printf("BEST MATCH FOUND for index %i is %i ", currentPlayedIndex, bestMatchFound[currentPlayedIndex]);
andrew@24 505
andrew@24 506 int previousIndex = currentPlayedIndex-1;
andrew@24 507
andrew@24 508 //withing speedwindow i.e. 4 seconds
andrew@24 509 while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) {
andrew@24 510 double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
andrew@24 511
andrew@24 512 int recordedPreviousIndex = bestMatchFound[previousIndex];
andrew@24 513
andrew@24 514 double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex];
andrew@24 515
andrew@24 516
andrew@24 517 //we want the speed of the recording relative to that of the playing live
andrew@24 518
andrew@24 519 double speedRatio = recordedTimeDifference / playedTimeDifference;
andrew@24 520 if (recordedTimeDifference > minimumTimeIntervalForTempoUpdate
andrew@24 521 && speedRatio < maximumMatchSpeed && speedRatio > minimumMatchSpeed){
andrew@24 522
andrew@24 523 /* printf("(%i)", previousIndex);
andrew@24 524 printf("[%i] :: ", recordedPreviousIndex);
andrew@24 525 // printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence);
andrew@24 526 printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference);
andrew@24 527 printf("update on speed ratio %f\n", speedRatio);
andrew@24 528 */
andrew@24 529 // matchString += " speed: "+ofToString(speedRatio, 3);
andrew@24 530 // commented for debug
andrew@24 531
andrew@24 532
andrew@24 533 double priorWeighting = 1;
andrew@24 534
andrew@24 535 if (useTempoPrior)
andrew@24 536 priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed
andrew@24 537
andrew@24 538
andrew@24 539 // double weighting = previousMatchConfidence * currentMatchConfidence ;
andrew@24 540 double amount = (1-bayesStruct.speedLikelihoodNoise)*priorWeighting/16;//was 9
andrew@24 541
andrew@24 542 speedIntervalsFound.push_back(speedRatio);
andrew@24 543 // bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match
andrew@24 544
andrew@24 545 // tempoSpeedString += ofToString(recordedCurrentIndex) + " :: " + ofToString(recordedPreviousIndex);
andrew@24 546 // tempoSpeedString += " " + ofToString(recordedTimeDifference)+ " " + ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n";
andrew@24 547
andrew@24 548 needToUpdate = true;
andrew@24 549 }
andrew@24 550 // printf("\n");
andrew@24 551
andrew@24 552
andrew@24 553 previousIndex--;
andrew@24 554 }//end while previousindex countdown
andrew@24 555
andrew@24 556 if (speedIntervalsFound.size() > 0){
andrew@24 557 double amount = (1 - bayesStruct.speedLikelihoodNoise) / speedIntervalsFound.size();
andrew@24 558 for (int i = 0;i < speedIntervalsFound.size();i++)
andrew@24 559 bayesStruct.updateTempoLikelihood(speedIntervalsFound[i], amount);
andrew@24 560 }
andrew@24 561
andrew@24 562
andrew@24 563 if (needToUpdate)
andrew@24 564 bayesStruct.updateTempoDistribution();
andrew@24 565 //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
andrew@24 566 }
andrew@24 567
andrew@29 568 double midiEventHolder::getBestSpeedEstimate(const int& currentPlayedIndex, const int& equivalentRecordedIndex){
andrew@29 569 double estimate = 1.0;
andrew@29 570 if (bestMatchIndex > 0){
andrew@29 571 double accordingToFileLengthEstimate = recordedEventTimes[equivalentRecordedIndex] - recordedEventTimes[0];
andrew@29 572 double playedEquivalent = (playedEventTimes[currentPlayedIndex] - playedEventTimes[0]);
andrew@29 573 if (accordingToFileLengthEstimate > 0 && playedEquivalent > 0)
andrew@29 574 accordingToFileLengthEstimate /= playedEquivalent;
andrew@29 575 estimate = accordingToFileLengthEstimate;
andrew@29 576 }
andrew@29 577 return estimate;
andrew@29 578 }
andrew@29 579
andrew@29 580 void midiEventHolder::findOptimumTempoPairsToCurrentBestMatch(){
andrew@29 581 bool needToUpdate = false;
andrew@29 582
andrew@29 583 DoubleVector speedIntervalsFound;
andrew@29 584
andrew@31 585 double currentSpeedEstimate = bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate);
andrew@29 586
andrew@29 587 int currentPlayedIndex = playedNoteOnMatrix.size()-1;
andrew@29 588
andrew@29 589 bayesStruct.setLikelihoodToConstant();
andrew@29 590
andrew@29 591 int recordedCurrentIndex = bestMatchFound[currentPlayedIndex];
andrew@29 592 //we only look at intervals between the current best match and other recent best matched notes
andrew@29 593
andrew@29 594 //printf("BEST MATCH FOUND for index %i is %i ", currentPlayedIndex, bestMatchFound[currentPlayedIndex]);
andrew@29 595
andrew@29 596 int previousIndex = currentPlayedIndex-1;
andrew@29 597
andrew@29 598 //withing speedwindow i.e. 4 seconds
andrew@29 599 while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) {
andrew@29 600
andrew@29 601 double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
andrew@29 602
andrew@29 603 int recordedPreviousIndex = bestMatchFound[previousIndex];
andrew@29 604
andrew@29 605 double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex];
andrew@29 606
andrew@29 607 //we want the speed of the recording relative to that of the playing live
andrew@29 608 double speedRatio = recordedTimeDifference / playedTimeDifference;
andrew@29 609
andrew@29 610 //now check if this can be closer the observed value
andrew@29 611 int checkRecordedCurrentIndex = recordedCurrentIndex;
andrew@29 612 int checkRecordedPreviousIndex ;//= recordedCurrentIndex;
andrew@29 613 int currentPlayedPitch = playedNoteOnMatrix[currentPlayedIndex][1];
andrew@29 614 int previousPlayedPitch = playedNoteOnMatrix[previousIndex][1];
andrew@29 615
andrew@29 616 double recordedTimeOfBestMatch = recordedEventTimes[recordedCurrentIndex];
andrew@29 617
andrew@29 618 //change this so we start first in window and go to end
andrew@29 619
andrew@30 620 while (checkRecordedCurrentIndex >= 0 && recordedEventTimes[checkRecordedCurrentIndex] > recordedTimeOfBestMatch - matchWindowWidth){
andrew@29 621
andrew@29 622 checkRecordedCurrentIndex--;
andrew@29 623 }
andrew@29 624
andrew@29 625 double bestSpeedEstimate = getBestSpeedEstimate(currentPlayedIndex, bestMatchIndex);
andrew@29 626
andrew@30 627 while (checkRecordedCurrentIndex < recordedEventTimes.size() && recordedEventTimes[checkRecordedCurrentIndex] < recordedTimeOfBestMatch + matchWindowWidth ){
andrew@29 628 if (recordedNoteOnMatrix[checkRecordedCurrentIndex][1] == currentPlayedPitch ){
andrew@29 629 checkRecordedPreviousIndex = checkRecordedCurrentIndex;
andrew@29 630 double recordedTimeCurrent = recordedEventTimes[checkRecordedCurrentIndex] ;
andrew@29 631 while (checkRecordedPreviousIndex >= 0 && recordedEventTimes[checkRecordedPreviousIndex] + maximumMatchSpeed*playedTimeDifference > recordedTimeCurrent ) {
andrew@29 632 if (recordedNoteOnMatrix[checkRecordedPreviousIndex][1] == previousPlayedPitch){
andrew@29 633 //we have a candidate
andrew@29 634 double speedToTest = recordedEventTimes[checkRecordedCurrentIndex] - recordedEventTimes[checkRecordedPreviousIndex];
andrew@29 635 speedToTest /= playedTimeDifference;
andrew@31 636 if (abs(speedToTest-currentSpeedEstimate) < abs(speedRatio - currentSpeedEstimate) ){
andrew@29 637 speedRatio = speedToTest;
andrew@29 638 }
andrew@29 639 }
andrew@29 640 checkRecordedPreviousIndex--;
andrew@29 641 }
andrew@29 642 }
andrew@29 643 checkRecordedCurrentIndex++;
andrew@29 644 }
andrew@29 645
andrew@29 646
andrew@29 647 if (recordedTimeDifference > minimumTimeIntervalForTempoUpdate
andrew@29 648 && speedRatio < maximumMatchSpeed && speedRatio > minimumMatchSpeed){
andrew@29 649
andrew@29 650 /* printf("(%i)", previousIndex);
andrew@29 651 printf("[%i] :: ", recordedPreviousIndex);
andrew@29 652 // printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence);
andrew@29 653 printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference);
andrew@29 654 printf("update on speed ratio %f\n", speedRatio);
andrew@29 655 */
andrew@29 656 // matchString += " speed: "+ofToString(speedRatio, 3);
andrew@29 657 // commented for debug
andrew@29 658
andrew@29 659
andrew@29 660 double priorWeighting = 1;
andrew@29 661
andrew@29 662 if (useTempoPrior)
andrew@29 663 priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed
andrew@29 664
andrew@29 665
andrew@29 666 // double weighting = previousMatchConfidence * currentMatchConfidence ;
andrew@29 667 double amount = (1-bayesStruct.speedLikelihoodNoise)*priorWeighting/16;//was 9
andrew@29 668
andrew@29 669 speedIntervalsFound.push_back(speedRatio);
andrew@29 670 // bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match
andrew@29 671
andrew@29 672 // tempoSpeedString += ofToString(recordedCurrentIndex) + " :: " + ofToString(recordedPreviousIndex);
andrew@29 673 // tempoSpeedString += " " + ofToString(recordedTimeDifference)+ " " + ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n";
andrew@29 674
andrew@29 675 needToUpdate = true;
andrew@29 676 }
andrew@29 677 // printf("\n");
andrew@29 678
andrew@29 679
andrew@29 680 previousIndex--;
andrew@29 681 }//end while previousindex countdown
andrew@29 682
andrew@29 683 if (speedIntervalsFound.size() > 0){
andrew@29 684 double amount = (1 - bayesStruct.speedLikelihoodNoise) / speedIntervalsFound.size();
andrew@29 685 for (int i = 0;i < speedIntervalsFound.size();i++)
andrew@29 686 bayesStruct.updateTempoLikelihood(speedIntervalsFound[i], amount);
andrew@29 687 }
andrew@29 688
andrew@29 689
andrew@29 690 if (needToUpdate)
andrew@29 691 bayesStruct.updateTempoDistribution();
andrew@29 692 //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
andrew@29 693 }
andrew@29 694
andrew@29 695
andrew@30 696 void midiEventHolder::calcuateNewInterNoteIntervals(){
andrew@30 697 DoubleVector v;
andrew@30 698
andrew@30 699 int currentPlayedIndex = playedNoteOnMatrix.size()-1;
andrew@30 700 // int recordedCurrentIndex = bestMatchFound[currentPlayedIndex];
andrew@30 701 int previousIndex = currentPlayedIndex-1;
andrew@30 702
andrew@30 703 //withing speedwindow i.e. 4 seconds
andrew@30 704 while (previousIndex >= 0 && playedEventTimes[previousIndex] + interNoteRange > playedEventTimes[currentPlayedIndex]) {
andrew@30 705
andrew@30 706 double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
andrew@30 707
andrew@30 708 checkForCorrectInterval(playedTimeDifference, &v);
andrew@30 709
andrew@30 710 previousIndex--;
andrew@30 711 }
andrew@30 712
andrew@30 713 if (v.size() > 0)
andrew@30 714 interNoteIntervals.push_back(v);
andrew@30 715 //printf("\n");
andrew@30 716 }
andrew@30 717
andrew@30 718 void midiEventHolder::checkForCorrectInterval(const double& playedTimeDifference, DoubleVector* v){
andrew@30 719 double intervalDuration = 0.0;
andrew@30 720
andrew@30 721 for (int intervalIndex = 0;intervalIndex < 3;intervalIndex++){
andrew@30 722 //on;y check 1,2 and 4
andrew@30 723 double possibleDuration = playedTimeDifference / intervalsToCheck[intervalIndex];
andrew@30 724 if (possibleDuration >= 200 && possibleDuration < 400){
andrew@30 725 v->push_back(possibleDuration);
andrew@30 726 // printf("int %f / %i :: %f ", playedTimeDifference, intervalsToCheck[intervalIndex], possibleDuration);
andrew@30 727 }
andrew@30 728 }
andrew@30 729 }
andrew@29 730
andrew@24 731 /*
andrew@24 732 void midiEventHolder::findLocalTempoPairsWeightedForConfidence(){
andrew@24 733 bool needToUpdate = false;
andrew@24 734
andrew@24 735 //adapted this to just use the best match for each note
andrew@24 736
andrew@24 737 int currentPlayedIndex = playedNoteOnMatrix.size()-1;
andrew@24 738 // printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]);
andrew@24 739 // printMatchesFound();
andrew@24 740 // printMatchMatrix();
andrew@24 741 // printf("possible notes \n");
andrew@24 742
andrew@24 743 bayesStruct.setLikelihoodToConstant();
andrew@24 744
andrew@24 745 for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){
andrew@24 746
andrew@24 747 //iterate through the recently matched events - even dodgy matches included
andrew@24 748 //size, index of match0, index of match1, ....
andrew@24 749 int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1];
andrew@24 750
andrew@24 751 double currentMatchConfidence = matchConfidence[currentPlayedIndex][i+1];//new confidence
andrew@24 752
andrew@24 753 int previousIndex = currentPlayedIndex-1;
andrew@24 754
andrew@24 755 while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) {
andrew@24 756 double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
andrew@24 757
andrew@24 758 // for (int k = 0;k < matchMatrix[previousIndex][0];k++)
andrew@24 759 int recordedPreviousIndex = bestMatchFound[previousIndex];//matchMatrix[previousIndex][k+1];
andrew@24 760
andrew@24 761 //double previousMatchConfidence = matchConfidence[previousIndex][k+1];
andrew@24 762
andrew@24 763
andrew@24 764 double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex];
andrew@24 765
andrew@24 766
andrew@24 767 //we want the speed of the recording relative to that of the playing live
andrew@24 768
andrew@24 769 double speedRatio = recordedTimeDifference / playedTimeDifference;
andrew@24 770 if (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){
andrew@24 771
andrew@24 772 printf("(%i)", matchMatrix[currentPlayedIndex][i+1]);
andrew@24 773 printf("[%i] :: ", recordedPreviousIndex);
andrew@24 774 // printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence);
andrew@24 775 printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference);
andrew@24 776 printf("update on speed ratio %f\n", speedRatio);
andrew@24 777
andrew@24 778 // matchString += " speed: "+ofToString(speedRatio, 3);
andrew@24 779 // commented for debug
andrew@24 780
andrew@24 781
andrew@24 782 double priorWeighting = 1;
andrew@24 783
andrew@24 784 if (useTempoPrior)
andrew@24 785 priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed
andrew@24 786
andrew@24 787
andrew@24 788 // double weighting = previousMatchConfidence * currentMatchConfidence ;
andrew@24 789 double amount = (1-bayesStruct.speedLikelihoodNoise)*priorWeighting/10;
andrew@24 790 bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match
andrew@24 791 tempoSpeedString += ofToString(recordedPreviousIndex) + " " + ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n";
andrew@24 792
andrew@24 793 needToUpdate = true;
andrew@24 794 }
andrew@24 795 // printf("\n");
andrew@24 796
andrew@24 797
andrew@24 798 previousIndex--;
andrew@24 799 }//end while previousindex countdown
andrew@24 800 }//end for loop through possible current matches
andrew@24 801
andrew@24 802 if (needToUpdate)
andrew@24 803 bayesStruct.updateTempoDistribution();
andrew@24 804 //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
andrew@24 805 }
andrew@24 806 */
andrew@24 807
andrew@24 808
andrew@24 809 void midiEventHolder::updatePlayPosition(){
andrew@24 810
andrew@24 811 //in actual fact if we are changing the speed of the play position
andrew@24 812 //we will need to update this via the file
andrew@24 813
andrew@24 814 //actually time since beginning of file i think
andrew@24 815
andrew@24 816 double timeDifference = 0;
andrew@24 817 if (runningInRealTime)
andrew@24 818 timeDifference = ofGetElapsedTimeMillis() - lastPeriodUpdateTime;//elpased - lastperiodupdatetime
andrew@24 819
andrew@24 820 //this is time diff in milliseconds
andrew@24 821 //then we have
andrew@24 822 double quarterNoteIntervals = (timeDifference / period);
andrew@24 823 tickLocation = quarterNoteIntervals * pulsesPerQuarternote;
andrew@24 824
andrew@24 825 playPositionInMillis = timeDifference;//based on updating from when we change period
andrew@24 826 //this to be added
andrew@24 827
andrew@24 828 if (runningInRealTime)
andrew@24 829 bayesStruct.updateBestEstimate(timeDifference);
andrew@24 830
andrew@26 831 updateNoteCounter();
andrew@26 832
andrew@26 833 }
andrew@26 834
andrew@26 835 void midiEventHolder::updateNoteCounter(){
andrew@26 836 while (totalNoteCounterIndex < bestMatchIndex){
andrew@26 837 int tmpPitch = recordedNoteOnMatrix[totalNoteCounterIndex][1];
andrew@26 838 recordedTotalNoteCounterByPitch[tmpPitch] += 1;
andrew@26 839 totalNoteCounterIndex++;
andrew@26 840 }
andrew@24 841 }
andrew@24 842
andrew@24 843
andrew@24 844 void midiEventHolder::drawMidiFile(){
andrew@24 845
andrew@24 846 //draws midi file on scrolling screen
andrew@24 847 int size = recordedNoteOnMatrix.size();
andrew@24 848 if (size > 0){
andrew@24 849
andrew@24 850 numberOfScreensIn = floor(bayesStruct.bestEstimate / getEventTimeMillis(ticksPerScreen));//rpounds down on no screens in
andrew@24 851
andrew@24 852 // numberOfScreensIn = tickLocation / ticksPerScreen;//rounds down
andrew@24 853 timeOffsetForScreen = getEventTimeMillis(numberOfScreensIn * ticksPerScreen);
andrew@24 854
andrew@24 855 while (noteArrayIndex < recordedNoteOnMatrix.size()-1 && tickLocation > recordedNoteOnMatrix[noteArrayIndex][0] )
andrew@24 856 noteArrayIndex++;
andrew@24 857
andrew@24 858
andrew@24 859 while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < recordedNoteOnMatrix[noteArrayIndex][0])
andrew@24 860 noteArrayIndex--;
andrew@24 861
andrew@24 862 //need to start where we currently are in file
andrew@24 863 int maxNoteIndexToPrint = noteArrayIndex;
andrew@24 864 int minNoteIndexToPrint = min(size-1,noteArrayIndex);//not needed as changed above
andrew@24 865
andrew@24 866 while (maxNoteIndexToPrint < recordedNoteOnMatrix.size() && recordedNoteOnMatrix[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen )
andrew@24 867 maxNoteIndexToPrint++;
andrew@24 868
andrew@24 869 while (minNoteIndexToPrint > 0 && recordedNoteOnMatrix[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen)//&& minNoteIndexToPrint < size
andrew@24 870 minNoteIndexToPrint--;
andrew@24 871
andrew@24 872 for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)recordedNoteOnMatrix.size());tmpIndex++){
andrew@24 873
andrew@24 874 ofSetColor(255,255,255);
andrew@24 875 if (checkIfMatchedNote(tmpIndex))
andrew@24 876 ofSetColor(100,100,100);//0,0,255);
andrew@24 877 else if(noteOnMatches[tmpIndex]){
andrew@24 878 ofSetColor(255,0,255);//dark grey
andrew@24 879 }
andrew@24 880 else{
andrew@24 881 ofSetColor(255,255,255);//255,255,255);
andrew@24 882 }
andrew@24 883
andrew@24 884 //ofSetColor(255,255,255);
andrew@24 885 if (tmpIndex == bestMatchIndex)
andrew@24 886 ofSetColor(255,0,0);//best recent match is in red
andrew@24 887
andrew@24 888 // XXX replace ofgetwidth below
andrew@24 889 //if (tmpIndex >= 0 && tmpIndex < size)
andrew@24 890 int xLocation = (float)(recordedNoteOnMatrix[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen;
andrew@24 891 int duration = (float)(recordedNoteOnMatrix[tmpIndex][3]*(*screenWidth))/(float)ticksPerScreen;
andrew@24 892
andrew@24 893
andrew@24 894 int yLocation = (*screenHeight) - ((recordedNoteOnMatrix[tmpIndex][1] - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum));
andrew@24 895 ofRect(xLocation,yLocation, duration, noteHeight);
andrew@24 896
andrew@24 897 }
andrew@24 898
andrew@24 899
andrew@24 900 int xLocation;// = getLocationFromTicks(tickLocation);
andrew@24 901 // ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@24 902
andrew@24 903 //orange line at best estimate
andrew@24 904 xLocation = getLocationFromMillis(bayesStruct.bestEstimate);
andrew@24 905 ofSetColor(80,80,80);//250,100,0);
andrew@24 906 ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@24 907
andrew@24 908 xLocation = getLocationFromMillis(bayesStruct.tmpBestEstimate);
andrew@24 909 ofSetColor(150,150,150);//250,100,0);
andrew@24 910 ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@24 911
andrew@24 912
andrew@24 913 //lines where matching window start and end are
andrew@24 914 ofSetColor(0);//0,100,255);
andrew@24 915 xLocation = getLocationFromMillis(windowStartTime);
andrew@24 916 ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@24 917 xLocation = getLocationFromMillis(windowStartTime+matchWindowWidth);
andrew@24 918 ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@24 919
andrew@24 920
andrew@24 921 int maxSize = recordedNoteOnMatrix[size-1][0];
andrew@24 922
andrew@25 923 int tmpIndex = 0;
andrew@25 924 while (tmpIndex < measureVector.size() && measureVector[tmpIndex] < (numberOfScreensIn+1)*ticksPerScreen){
andrew@25 925 int measureLocation = measureVector[tmpIndex];
andrew@25 926 int xLocation = (float)(measureLocation - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen;
andrew@25 927 ofSetColor(155,155,0);
andrew@25 928 ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@25 929 tmpIndex++;
andrew@25 930 }
andrew@25 931
andrew@25 932
andrew@24 933 // ofDrawBitmapString(tempoSpeedString, 20, 20);
andrew@24 934 /* string indexString = "num screens in "+ofToString(numberOfScreensIn)+"; min index to print "+ofToString(minNoteIndexToPrint)+", max index to print "+ofToString(maxNoteIndexToPrint);
andrew@24 935 indexString += " size "+ofToString(size)+" tick loc "+ofToString(tickLocation)+" max size "+ofToString(maxSize);
andrew@24 936 ofDrawBitmapString(indexString, 20, 40);
andrew@24 937 */
andrew@24 938 }
andrew@24 939
andrew@24 940 //ofDrawBitmapString(ofToString(timeOffsetForScreen, 1), 20,20);
andrew@24 941
andrew@24 942 //ofDrawBitmapString(timeString, 20, 60);
andrew@24 943
andrew@25 944 //last played piutch
andrew@25 945 ofSetColor(0,200,0,50);
andrew@25 946 int yLocation = (*screenHeight) - ((lastPlayedPitch - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum));
andrew@25 947 ofRect(0,yLocation, 100, noteHeight);
andrew@25 948
andrew@25 949
andrew@25 950
andrew@24 951 }
andrew@24 952
andrew@24 953
andrew@24 954
andrew@24 955 void midiEventHolder::drawMidiFile(IntMatrix& midiFileToDraw){
andrew@24 956
andrew@25 957 //using this to draw the live input
andrew@25 958
andrew@24 959 //draws midi file on scrolling screen
andrew@24 960 int size = midiFileToDraw.size();
andrew@24 961 if (size > 0){
andrew@24 962
andrew@24 963 numberOfScreensIn = floor(bayesStruct.bestEstimate / getEventTimeMillis(ticksPerScreen));//rpounds down on no screens in
andrew@24 964
andrew@24 965 // numberOfScreensIn = tickLocation / ticksPerScreen;//rounds down
andrew@24 966 timeOffsetForScreen = getEventTimeMillis(numberOfScreensIn * ticksPerScreen);
andrew@24 967
andrew@24 968 while (noteArrayIndex < midiFileToDraw.size()-1 && tickLocation > midiFileToDraw[noteArrayIndex][0] )
andrew@24 969 noteArrayIndex++;
andrew@24 970
andrew@24 971
andrew@24 972 while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < midiFileToDraw[noteArrayIndex][0])
andrew@24 973 noteArrayIndex--;
andrew@24 974
andrew@24 975 //need to start where we currently are in file
andrew@24 976 int maxNoteIndexToPrint = noteArrayIndex;
andrew@24 977 int minNoteIndexToPrint = min(size-1,noteArrayIndex);//not needed as changed above
andrew@24 978
andrew@24 979 while (maxNoteIndexToPrint < midiFileToDraw.size() && midiFileToDraw[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen )
andrew@24 980 maxNoteIndexToPrint++;
andrew@24 981
andrew@24 982 while (minNoteIndexToPrint > 0 && midiFileToDraw[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen)//&& minNoteIndexToPrint < size
andrew@24 983 minNoteIndexToPrint--;
andrew@24 984
andrew@24 985 for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)midiFileToDraw.size());tmpIndex++){
andrew@24 986
andrew@25 987 ofSetColor(0,0,255, 200);
andrew@25 988
andrew@24 989 int xLocation = (float)(midiFileToDraw[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen;
andrew@24 990 int duration = (float)(midiFileToDraw[tmpIndex][3]*(*screenWidth))/(float)ticksPerScreen;
andrew@24 991
andrew@24 992
andrew@24 993 int yLocation = (*screenHeight) - ((midiFileToDraw[tmpIndex][1] - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum));
andrew@24 994 ofRect(xLocation,yLocation, duration, noteHeight);
andrew@24 995
andrew@24 996 }
andrew@24 997
andrew@24 998
andrew@24 999
andrew@24 1000 }
andrew@24 1001
andrew@24 1002
andrew@24 1003
andrew@24 1004 }
andrew@24 1005
andrew@24 1006
andrew@24 1007
andrew@24 1008 void midiEventHolder::drawFile(){
andrew@24 1009 drawMidiFile();
andrew@24 1010
andrew@24 1011
andrew@24 1012 // bayesStruct.drawArrays();
andrew@24 1013
andrew@24 1014 // ofSetColor(200,200,0);
andrew@24 1015 // bayesStruct.prior.drawConstrainedVector(0, bayesStruct.prior.arraySize, 400, 800);
andrew@24 1016
andrew@24 1017 //need to draw arrays within correct timescope
andrew@24 1018 if (drawPhaseMode)
andrew@24 1019 bayesStruct.drawArraysRelativeToTimeframe(timeOffsetForScreen, timeOffsetForScreen + getEventTimeMillis(ticksPerScreen));
andrew@24 1020
andrew@24 1021 if (drawTempoMode)
andrew@24 1022 bayesStruct.drawTempoArrays();
andrew@24 1023
andrew@24 1024
andrew@24 1025 ofSetColor(0, 0, 0);
andrew@24 1026 //ofDrawBitmapString(matchString, 20, ofGetHeight() - 20);
andrew@24 1027
andrew@24 1028 double confidence = bayesStruct.posterior.getValueAtMillis(mouseX);
andrew@24 1029 /*
andrew@24 1030 string mouseString = "mouseX "+ofToString(confidence, 3)+" .";
andrew@24 1031 ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40);
andrew@24 1032
andrew@24 1033 string mouseString = "updateCounter "+ofToString(bayesStruct.updateCounter);
andrew@24 1034 ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40);
andrew@24 1035
andrew@24 1036 string infostring = "speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 3);
andrew@24 1037 ofDrawBitmapString(infostring, 20 , ofGetHeight() - 60);
andrew@24 1038 */
andrew@30 1039
andrew@30 1040 //drawInterNoteIntervals();
andrew@30 1041
andrew@24 1042 }
andrew@24 1043
andrew@30 1044 void midiEventHolder::drawInterNoteIntervals(){
andrew@30 1045
andrew@30 1046 ofSetColor(0,0,150);
andrew@30 1047 int size = interNoteIntervals.size();
andrew@30 1048 int numberToShow = min(100, size);
andrew@30 1049 double x ;
andrew@30 1050 for (int y = 1;y < numberToShow;y++){
andrew@30 1051 for (int point = 0;point < interNoteIntervals[y].size();point++){
andrew@30 1052 double interval = interNoteIntervals[size - y][point];
andrew@30 1053 x = interval - 200;
andrew@30 1054 x *= (*screenWidth) / 200.0;
andrew@30 1055 }
andrew@30 1056 double h = (double)(y * (*screenHeight)) / numberToShow;
andrew@30 1057 ofCircle(x, h, 5);
andrew@30 1058 }
andrew@30 1059
andrew@30 1060 }
andrew@30 1061
andrew@30 1062
andrew@30 1063 void midiEventHolder::printInterNoteIntervals(){
andrew@30 1064
andrew@30 1065 int size = interNoteIntervals.size();
andrew@30 1066 int numberToShow = 20;
andrew@30 1067 double x ;
andrew@30 1068 for (int y = max(0, size - numberToShow);y < interNoteIntervals.size();y++){
andrew@30 1069 for (int point = 0;point < interNoteIntervals[y].size();point++){
andrew@30 1070 printf("[%i][%i] : %f", y, point, interNoteIntervals[y][point]);
andrew@30 1071 }
andrew@30 1072 printf("\n");
andrew@30 1073 }
andrew@30 1074
andrew@30 1075 }
andrew@30 1076
andrew@24 1077 int midiEventHolder::getLocationFromTicks(double tickPosition){
andrew@24 1078 return (int)((float)(tickPosition - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen);
andrew@24 1079 }
andrew@24 1080
andrew@24 1081 int midiEventHolder::getLocationFromMillis(double millisPosition){
andrew@24 1082 //(getEventTimeTicks(windowStartTime+matchWindowWidth) - numberOfScreensIn*ticksPerScreen)*(*screenWidth) / (double)ticksPerScreen
andrew@24 1083 return (millisPosition - timeOffsetForScreen)*(*screenWidth)/getEventTimeMillis(ticksPerScreen);
andrew@24 1084 }
andrew@24 1085
andrew@24 1086
andrew@24 1087 void midiEventHolder::exampleCrossUpdate(){
andrew@24 1088
andrew@24 1089 bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, 200);
andrew@24 1090
andrew@24 1091 }
andrew@24 1092
andrew@24 1093
andrew@24 1094 void midiEventHolder::setStartPlayingTimes(){
andrew@24 1095 lastPeriodUpdateTime = getTimeNow(0);//ofGetElapsedTimeMillis();
andrew@24 1096 startTime = lastPeriodUpdateTime;
andrew@24 1097
andrew@24 1098 /*
andrew@24 1099 bayesStruct.lastEventTime = 0;//ofGetElapsedTimeMillis();
andrew@24 1100 bayesStruct.bestEstimate = 0;
andrew@24 1101 bayesStruct.resetArrays();
andrew@24 1102 bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
andrew@24 1103 */
andrew@24 1104 bayesStruct.setStartPlaying();
andrew@24 1105 matchString = "";
andrew@24 1106 }
andrew@24 1107
andrew@24 1108
andrew@24 1109 void midiEventHolder::printMatchMatrix(){
andrew@24 1110 printf("match matrix:\n");
andrew@24 1111 for (int i = 0;i < matchMatrix.size();i++){
andrew@24 1112 for (int k = 0;k < matchMatrix[i].size();k++){
andrew@24 1113 printf("%i , ", matchMatrix[i][k]);
andrew@24 1114 }
andrew@24 1115 printf("\n");
andrew@24 1116 }
andrew@24 1117
andrew@24 1118 }
andrew@24 1119
andrew@24 1120
andrew@24 1121
andrew@24 1122 void midiEventHolder::printRecordedEvents(){
andrew@24 1123 printf("Recorded Events:\n");
andrew@24 1124 for (int i = 0;i < recordedNoteOnMatrix.size();i++){
andrew@24 1125 for (int k = 0;k < recordedNoteOnMatrix[i].size();k++){
andrew@24 1126 printf("[%i] = %i ,", i, recordedNoteOnMatrix[i][k]);
andrew@24 1127 }
andrew@24 1128 if (i < recordedEventTimes.size())
andrew@24 1129 printf("time %f \n", recordedEventTimes[i]);
andrew@24 1130 else
andrew@24 1131 printf("\n");
andrew@24 1132 }
andrew@24 1133
andrew@24 1134 }
andrew@24 1135
andrew@24 1136
andrew@24 1137
andrew@24 1138 void midiEventHolder::reorderMatrixFromNoteTimes(IntMatrix& noteOnMatrix){
andrew@24 1139 double currentTime = -19999.;
andrew@24 1140 for (int i = 0;i < noteOnMatrix.size();i++){
andrew@24 1141 int nextIndex = getIndexOfMinimumAboveTime(currentTime, noteOnMatrix);
andrew@24 1142 // cout << "index of min time " << currentTime << " is " << nextIndex << " at time " << noteOnMatrix[nextIndex][0] << endl;
andrew@24 1143
andrew@24 1144 if (nextIndex >= 0 && nextIndex > i && noteOnMatrix[nextIndex][0] < noteOnMatrix[i][0] ){
andrew@24 1145 //which it should be
andrew@24 1146 // cout << " index " << nextIndex << " at time " << noteOnMatrix[nextIndex][0] << " swaps with inex " << i << " at time " << noteOnMatrix[i][0] << endl;
andrew@24 1147 noteOnMatrix[i].swap(noteOnMatrix[nextIndex]);
andrew@24 1148 currentTime = noteOnMatrix[i][0];
andrew@24 1149 }
andrew@24 1150
andrew@24 1151 }
andrew@24 1152 //printRecordedEvents();
andrew@24 1153
andrew@24 1154 }
andrew@24 1155
andrew@24 1156
andrew@24 1157
andrew@24 1158
andrew@24 1159 void midiEventHolder::doublecheckOrder(IntMatrix& noteOnMatrix){
andrew@24 1160
andrew@24 1161 for (int i = 0;i < noteOnMatrix.size();i++){
andrew@24 1162 int nextIndex = getIndexOfMinimumAboveIndex(i, noteOnMatrix);
andrew@24 1163 if (nextIndex > i){
andrew@24 1164 noteOnMatrix[i].swap(noteOnMatrix[nextIndex]);
andrew@24 1165 }
andrew@24 1166 }
andrew@24 1167 }
andrew@24 1168
andrew@24 1169 int midiEventHolder::getIndexOfMinimumAboveIndex(const int& index, IntMatrix& noteOnMatrix){
andrew@24 1170 int returnIndex = index;
andrew@24 1171 int min = noteOnMatrix[index][0];
andrew@24 1172 for (int i = index;i < noteOnMatrix.size();i++){
andrew@24 1173 if (noteOnMatrix[i][0] < min){
andrew@24 1174 returnIndex = i;
andrew@24 1175 min = noteOnMatrix[i][0];
andrew@24 1176 }
andrew@24 1177 }
andrew@24 1178 return returnIndex;
andrew@24 1179 }
andrew@24 1180
andrew@24 1181
andrew@24 1182 int midiEventHolder::getIndexOfMinimumAboveTime(const double& time, IntMatrix& noteOnMatrix){
andrew@24 1183 int index = 0;
andrew@24 1184 double minimumTime = 100000000.;
andrew@24 1185 int bestIndex = -1;
andrew@24 1186 while (index < noteOnMatrix.size()){
andrew@24 1187
andrew@24 1188 if (noteOnMatrix[index][0] > time && noteOnMatrix[index][0] < minimumTime){
andrew@24 1189 bestIndex = index;
andrew@24 1190 minimumTime = noteOnMatrix[index][0];
andrew@24 1191 }
andrew@24 1192 index++;
andrew@24 1193 }
andrew@24 1194 return bestIndex;
andrew@24 1195 }
andrew@24 1196
andrew@24 1197
andrew@26 1198
andrew@26 1199
andrew@24 1200 void midiEventHolder::correctTiming(IntMatrix& noteOnMatrix){
andrew@24 1201
andrew@24 1202 if (noteOnMatrix.size() > 0 && noteOnMatrix[0][0] < 0) {
andrew@24 1203 int offset = noteOnMatrix[0][0];
andrew@24 1204 for (int i = 0;i < noteOnMatrix.size();i++){
andrew@24 1205 noteOnMatrix[i][0] -= offset;
andrew@24 1206 }
andrew@24 1207 }
andrew@24 1208
andrew@24 1209 }
andrew@26 1210
andrew@26 1211
andrew@26 1212 void midiEventHolder::printNoteCounter(){
andrew@26 1213 for (int i = 0;i < recordedTotalNoteCounterByPitch.size();i++){
andrew@26 1214 printf("RECORDED TOTAL[%i] := %i", i, recordedTotalNoteCounterByPitch[i]);
andrew@26 1215 }
andrew@26 1216 }