annotate bayesianArraySrc/midiEventHolder.cpp @ 56:4394c9490716 tip

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