annotate src/AudioEventMatcher.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 2eca10a31ae2
children
rev   line source
andrew@0 1 /*
andrew@0 2 * AudioEventMatcher.cpp
andrew@0 3 * MultipleAudioMathcher
andrew@0 4 *
andrew@0 5 * Created by Andrew on 31/01/2012.
andrew@0 6 * Copyright 2012 QMUL. All rights reserved.
andrew@0 7 *
andrew@0 8 */
andrew@0 9
andrew@0 10 #include "AudioEventMatcher.h"
andrew@0 11
andrew@55 12 //whi are there two Tempo Follower class objects?
andrew@55 13
andrew@0 14
andrew@39 15 const int matchWindowWidth = 8000;//ms in which to match
andrew@39 16
andrew@32 17 const float pitchCutOff = 16;//within which pitches are even considered
andrew@56 18 const double pitchWidth = 12;
andrew@0 19
andrew@55 20 bool printInfo = false;
andrew@50 21
andrew@0 22 AudioEventMatcher::AudioEventMatcher(){
andrew@7 23
andrew@55 24 ofBackground(0);
andrew@50 25 useChromaDotProduct = false;//false for most tests
andrew@37 26 printingData = false;
andrew@56 27 updateTempoMethodOn = false;
andrew@37 28
andrew@23 29 pitchLikelihoodToNoise = 0.6;//more noise
andrew@56 30 pitchLikelihoodWidth = 30;
andrew@56 31
andrew@32 32 chromaLikelihoodToNoise = 0.5;//lower => more noise, higher more weight for events
andrew@32 33 chromaLikelihoodWidth = 50;//ms round onset event
andrew@16 34
andrew@56 35 //onsetLikelihoodToNoise = 0.2;//0.1 and 10 as to 9/5/12
andrew@53 36 kickLikelihoodToNoise = 0.3;
andrew@53 37 snareLikelihoodToNoise = 0.1;
andrew@53 38
andrew@53 39
andrew@48 40 onsetLikelihoodWidth = 6;//in ms
andrew@15 41
andrew@0 42 setArraySizes();
andrew@3 43
andrew@3 44 usingRealTime = false;
andrew@3 45 bayesianStruct.realTimeMode = &usingRealTime;
andrew@7 46 recentPitch = 0;
andrew@8 47 currentAlignmentPosition = 0;
andrew@14 48
andrew@9 49 followingLiveInput = true;
andrew@15 50 startedPlaying = false;
andrew@20 51 recordedTempoIndex = 0;
andrew@39 52
andrew@42 53 bayesianStruct.startingWindowWidth = 100;//matchWindowWidth / 8;
andrew@42 54 bayesianStruct.matchWindowWidth = matchWindowWidth;
andrew@50 55
andrew@51 56 drawLikelihoods = true;
andrew@50 57 drawPosterior = false;
andrew@50 58
andrew@53 59 temporal.printOutput = true;//printInfo;
andrew@50 60
andrew@52 61
andrew@20 62 // temporal.setUpEventTimeMatrix();
andrew@20 63 // recordedTempoData.setUpEventTimeMatrix();
andrew@0 64 }
andrew@0 65
andrew@14 66
andrew@19 67
andrew@19 68
andrew@7 69 void AudioEventMatcher::setWindowDimensions(){
andrew@53 70
andrew@7 71 double startHeight = recordedTracks.numberOfAudioTracks * recordedTracks.trackScreenHeight;
andrew@7 72 double heightAvailable = 1 - startHeight;
andrew@32 73 heightAvailable /= numberOfChannels;
andrew@7 74
andrew@7 75 bayesPositionWindow.setToRelativeSize(0, startHeight, 1, heightAvailable);
andrew@7 76 bayesLikelihoodWindow.setToRelativeSize(0, startHeight + 1*heightAvailable, 1, heightAvailable);
andrew@7 77 bayesTempoWindow.setToRelativeSize(0, startHeight + 2*heightAvailable, 1, heightAvailable);
andrew@7 78
andrew@7 79
andrew@7 80 }
andrew@0 81
andrew@0 82 void AudioEventMatcher::setArraySizes(){
andrew@0 83 bayesianStruct.resetSpeedSize(200);
andrew@0 84 bayesianStruct.setRelativeSpeedScalar(0.01);
andrew@0 85 bayesianStruct.setSpeedPrior(1.0);
andrew@0 86 bayesianStruct.relativeSpeedPrior.getMaximum();
andrew@0 87
andrew@36 88 float scalarForBayesianDistribution = 2;
andrew@36 89
andrew@36 90 bayesianStruct.resetSize(matchWindowWidth / scalarForBayesianDistribution);
andrew@36 91 bayesianStruct.setPositionDistributionScalar(2);
andrew@0 92
andrew@0 93 }
andrew@0 94
andrew@16 95 void AudioEventMatcher::loadAudioFiles(){
andrew@16 96 recordedTracks.loadTestAudio();
andrew@16 97 synchroniser.fileLengthSamples = recordedTracks.loadedAudioFiles[0].fileLoader.totalNumberOfSamples;
andrew@16 98 printf("synchroniser has %f samples\n", synchroniser.fileLengthSamples);
andrew@55 99 printf("First PASS\n");
andrew@20 100
andrew@20 101 calculateRecordedTempoData();
andrew@55 102 recordedTempoData.printTempoTimes();
andrew@53 103 printf("\n audioeventmatcher\nFIRST PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo);
andrew@55 104
andrew@55 105 printf("SECOND PASS\n");
andrew@20 106 setTempoPrior(recordedTempoData.playingTempo);
andrew@20 107 calculateRecordedTempoData();//now calculate again using better prior
andrew@20 108
andrew@53 109 printf("\n audioeventmatcher\nSECOND PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo);
andrew@20 110 printf("GLOBAL TEMPO of RECORDED FILES\n");
andrew@20 111 recordedTempoData.printTempoTimes();
andrew@20 112 }
andrew@20 113
andrew@20 114 void AudioEventMatcher::setTempoPrior(double tempo){
andrew@20 115 recordedTempoData.zero();
andrew@20 116 recordedTempoData.tempoPosterior.zero();
andrew@20 117 recordedTempoData.tempoPosterior.addGaussianShapeFromRealTime(tempo, 3, 1);
andrew@20 118
andrew@20 119 }
andrew@20 120
andrew@20 121 void AudioEventMatcher::calculateRecordedTempoData(){
andrew@20 122 int indexForOnsets[3];
andrew@20 123 indexForOnsets[0] = 0;
andrew@20 124 indexForOnsets[1] = 0;
andrew@20 125 indexForOnsets[2] = 0;
andrew@53 126
andrew@55 127 int kickTime = 0;
andrew@55 128 int snareTime = 0;
andrew@53 129
andrew@20 130 while (indexForOnsets[0] < recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.chromaOnsets.size() ||
andrew@20 131 indexForOnsets[2] < recordedTracks.loadedAudioFiles[2].fileLoader.onsetDetect.chromaOnsets.size()) {
andrew@20 132
andrew@20 133 setNextOnsetTime(0, kickTime, &indexForOnsets[0]);
andrew@20 134 setNextOnsetTime(2, snareTime, &indexForOnsets[0]);
andrew@20 135
andrew@20 136 if (kickTime < snareTime){
andrew@53 137 printf("kick(%i) at %i\n", indexForOnsets[0], kickTime);
andrew@20 138 recordedTempoData.updateTempo(0, kickTime);
andrew@53 139 // printf("recorded tempo is %f\n", recordedTempoData.playingTempo);
andrew@20 140 indexForOnsets[0]++;
andrew@20 141 }else {
andrew@53 142 printf("snare(%i) at %i\n", indexForOnsets[2], snareTime);
andrew@20 143 recordedTempoData.updateTempo(2, snareTime);
andrew@53 144 // printf("recorded tempo is %f\n", recordedTempoData.playingTempo);
andrew@20 145 indexForOnsets[2]++;
andrew@20 146 }
andrew@20 147 }//end while
andrew@20 148
andrew@20 149 }
andrew@20 150
andrew@20 151 void AudioEventMatcher::setNextOnsetTime(const int& channel, int& time, int* indexForOnsets){
andrew@20 152 if (indexForOnsets[channel] < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){
andrew@20 153 time = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[indexForOnsets[channel]].millisTime;
andrew@20 154 }
andrew@20 155 else {
andrew@20 156 time = 2147483647;//infinity
andrew@20 157 }
andrew@16 158 }
andrew@16 159
andrew@9 160 void AudioEventMatcher::startPlaying(){
andrew@3 161 bayesianStruct.setStartPlaying();
andrew@8 162 currentAlignmentPosition = 0;
andrew@8 163 startTime = ofGetElapsedTimeMillis();
andrew@11 164
andrew@11 165 projectedPrior = bayesianStruct.prior;
andrew@15 166 startedPlaying = true;
andrew@17 167 synchroniser.reset();
andrew@19 168 temporal.reset();
andrew@17 169
andrew@20 170 recordedTempoIndex = 0;
andrew@20 171 recordedTempo = recordedTempoData.globalTempo[recordedTempoIndex];
andrew@20 172
andrew@55 173 printf("recorded tempo is %f\n", recordedTempo);
andrew@20 174 currentSpeedRatio = 1;
andrew@53 175 relativeTempo = 1;
andrew@20 176
andrew@55 177 temporal.reset();
andrew@55 178 // temporal.tempoPosterior.zero();
andrew@55 179 // temporal.tempoPosterior.addGaussianShapeFromRealTime(recordedTempo, 2000, 1);
andrew@21 180
andrew@20 181 //SET TEMPO PRIOR for Speed Ratio
andrew@20 182 //the update this
andrew@20 183 setSpeedRatioDistribution(currentSpeedRatio);
andrew@37 184
andrew@37 185 euclideanMaximumDistance = 0;
andrew@37 186
andrew@3 187 //bayesianStruct.posterior.printArray();
andrew@3 188 }
andrew@3 189
andrew@9 190
andrew@20 191 void AudioEventMatcher::setSpeedRatioDistribution(const double& speedRatio){
andrew@39 192 //here is the speed combo actually used
andrew@20 193 bayesianStruct.relativeSpeedPosterior.zero();
andrew@39 194 // bayesianStruct.relativeSpeedPosterior.addToIndex(bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(speedRatio), 1);
andrew@53 195 bayesianStruct.relativeSpeedPosterior.addGaussianShapeFromRealTime(speedRatio, 0.1, 3);
andrew@53 196 bayesianStruct.relativeSpeedPosterior.addGaussianShapeFromRealTime(speedRatio, 0.02, 2);
andrew@20 197 }
andrew@20 198
andrew@15 199 void AudioEventMatcher::stopPlaying(){
andrew@15 200 startedPlaying = false;
andrew@52 201 testDistributionOutput.closeFile();
andrew@37 202 //temporal.printEventTimes();
andrew@15 203 }
andrew@15 204
andrew@22 205 void AudioEventMatcher::rescue(){
andrew@22 206 bayesianStruct.posterior.zero();
andrew@22 207 bayesianStruct.posterior.addConstant(1);
andrew@22 208 bayesianStruct.prior.zero();
andrew@22 209 bayesianStruct.prior.addConstant(1);
andrew@22 210 }
andrew@22 211
andrew@50 212 #pragma mark -update
andrew@9 213 void AudioEventMatcher::updatePosition(){
andrew@19 214
andrew@19 215 if (startedPlaying){
andrew@50 216 /* if (!followingLiveInput)
andrew@9 217 recordedTracks.updatePosition();
andrew@19 218 else
andrew@50 219 */
andrew@9 220 recordedTracks.updatePositionToMillis(currentAlignmentPosition);
andrew@53 221 updateBestAlignmentPosition();
andrew@9 222
andrew@53 223 } else {
andrew@50 224 recordedTracks.updatePosition();
andrew@50 225 markerPlaybackPosition = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.playPositionFrames);
andrew@50 226 currentAlignmentPosition = markerPlaybackPosition;
andrew@19 227 }
andrew@19 228
andrew@56 229 if (updateTempoMethodOn){
andrew@56 230 updateRecordedTempo();
andrew@56 231 }
andrew@9 232 }
andrew@9 233
andrew@20 234 void AudioEventMatcher::updateRecordedTempo(){
andrew@20 235 //tempo of equivalent recorded position is updated
andrew@56 236
andrew@56 237 if (recordedTempoIndex < recordedTempoData.globalTempoTimes.size()){//if for debug
andrew@56 238 recordedTempo = getRecordedTempoAtMillis(currentAlignmentPosition);
andrew@55 239
andrew@56 240 double tmpRatio = currentSpeedRatio;
andrew@56 241
andrew@56 242 currentSpeedRatio = temporal.playingTempo / recordedTempo;
andrew@56 243 if (currentSpeedRatio != tmpRatio)
andrew@56 244 setSpeedRatioDistribution(currentSpeedRatio);
andrew@56 245
andrew@37 246 }//end if to prevent debug crash
andrew@56 247
andrew@56 248 temporal.tempoPosterior.addGaussianShape(temporal.tempoPosterior.MAPestimate, temporal.tempoArraySize / 4, 0.5 );
andrew@56 249
andrew@20 250 }
andrew@56 251
andrew@55 252 double AudioEventMatcher::getRecordedTempoAtMillis(const double& millisPosition){
andrew@56 253
andrew@55 254 while(currentAlignmentPosition < recordedTempoData.globalTempoTimes[recordedTempoIndex] && recordedTempoIndex > 0){
andrew@56 255 //this loop never used as sequential, so we expect the alignment time to be ahead of the last recorded tempo point
andrew@55 256 //but just in case
andrew@55 257 recordedTempoIndex--;
andrew@55 258 }
andrew@55 259
andrew@55 260 while(currentAlignmentPosition > recordedTempoData.globalTempoTimes[recordedTempoIndex]){
andrew@55 261 recordedTempoIndex++;
andrew@55 262 }
andrew@55 263
andrew@55 264 return recordedTempoData.globalTempo[recordedTempoIndex];
andrew@55 265 }
andrew@55 266
andrew@8 267 void AudioEventMatcher::updateBestAlignmentPosition(){
andrew@10 268 //THIS DEALS WITH WHERE WE ARE NOW! ON THE SCREEN
andrew@10 269 //DIFFERENT TO WHEN EVENTS COME IN AS THEY ARE TIMESTAMPED - SO EG A PITCH EVENT MAY ARRIVE 16 CHROMA FRAMES LATER - BIG DIFFERENCE
andrew@10 270
andrew@45 271 int newTime = getTimeNow();
andrew@10 272 // double tmp = bayesianStruct.posterior.getIndexInRealTerms(bayesianStruct.posterior.MAPestimate);;
andrew@10 273 // double timetmp = (newTime - lastAlignmentTime);
andrew@10 274 // double speedtmp = bayesianStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesianStruct.relativeSpeedPosterior.MAPestimate);
andrew@11 275 // currentAlignmentTime = newTime;
andrew@9 276 currentAlignmentPosition = bayesianStruct.posterior.getIndexInRealTerms(bayesianStruct.posterior.MAPestimate);
andrew@10 277 currentAlignmentPosition += (newTime - lastAlignmentTime) * bayesianStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesianStruct.relativeSpeedPosterior.MAPestimate);
andrew@10 278
andrew@16 279
andrew@17 280 synchroniser.updateRecordedPosition(currentAlignmentPosition, newTime);
andrew@16 281
andrew@16 282 synchroniser.updateOutputSpeed();
andrew@16 283
andrew@11 284 bayesianStruct.projectDistribution(newTime, currentAlignmentPosition, projectedPrior);//prior gets updated to where we are now
andrew@32 285
andrew@50 286 // printf("updateBestAlignment:: alignment %i:: %i\n", newTime, (int) currentAlignmentPosition);
andrew@10 287 // printf("ALIGN pos %f time diff %f (now %f , last %f)speed %f :: ALIGN BEST %f\n", tmp, timetmp, (double)ofGetElapsedTimeMillis(), lastAlignmentTime, speedtmp, currentAlignmentPosition);
andrew@8 288 }
andrew@8 289
andrew@45 290 int AudioEventMatcher::getTimeNow(){
andrew@45 291 return ofGetElapsedTimeMillis() - startTime;
andrew@45 292 }
andrew@45 293
andrew@50 294 #pragma mark -markers
andrew@50 295 void AudioEventMatcher::addMarkerNow(){
andrew@50 296 if (!startedPlaying)
andrew@50 297 markedPoints.addMarker(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.playPositionFrames));
andrew@50 298 }
andrew@50 299
andrew@50 300 void AudioEventMatcher::deleteMarkers(){
andrew@50 301 markedPoints.markers.clear();
andrew@50 302 }
andrew@50 303
andrew@50 304 void AudioEventMatcher::moveToNextMarker(){
andrew@50 305 int m = 0;
andrew@50 306 while (m < markedPoints.markers.size() && markedPoints.markers[m] < currentAlignmentPosition)
andrew@50 307 m++;
andrew@50 308
andrew@50 309
andrew@50 310 if (markedPoints.markers[m] > currentAlignmentPosition){
andrew@50 311 setPlaybackPosition(markedPoints.markers[m]);
andrew@50 312 printf("move to marker %f from current pos %f\n", markedPoints.markers[m], currentAlignmentPosition);
andrew@50 313 }
andrew@50 314
andrew@50 315 }
andrew@50 316
andrew@50 317 void AudioEventMatcher::moveToPreviousMarker(){
andrew@50 318 int m = 0;
andrew@50 319 while (m < markedPoints.markers.size() && markedPoints.markers[m] < currentAlignmentPosition)
andrew@50 320 m++;
andrew@50 321
andrew@51 322 if (m > 1 && markedPoints.markers[m-1] + 300 > currentAlignmentPosition)
andrew@51 323 setPlaybackPosition(markedPoints.markers[m-2]);
andrew@51 324 else if (m > 0 && markedPoints.markers[m-1] < currentAlignmentPosition){
andrew@50 325 setPlaybackPosition(markedPoints.markers[m-1]);
andrew@50 326 printf("move to marker %f from current pos %f\n", markedPoints.markers[m], currentAlignmentPosition);
andrew@50 327 }
andrew@51 328
andrew@51 329
andrew@50 330 }
andrew@50 331
andrew@50 332 void AudioEventMatcher::deleteNearestMarker(){
andrew@50 333 int m = 0;
andrew@50 334 while (m < markedPoints.markers.size() && markedPoints.markers[m] < currentAlignmentPosition)
andrew@50 335 m++;
andrew@50 336
andrew@50 337 int markerToDelete = m;
andrew@50 338 if (m >= 0 && fabs(markedPoints.markers[m] - currentAlignmentPosition) < fabs(markedPoints.markers[m-1] - currentAlignmentPosition)){
andrew@50 339 markerToDelete = m-1;
andrew@50 340 }
andrew@50 341
andrew@50 342 markedPoints.deleteMarker(markerToDelete);
andrew@50 343
andrew@50 344
andrew@50 345 }
andrew@50 346
andrew@50 347
andrew@50 348 void AudioEventMatcher::setPlaybackPosition(const double& millis){
andrew@50 349 if (!startedPlaying)
andrew@50 350 recordedTracks.updatePlaybackPositionToMillis(millis);
andrew@50 351 }
andrew@50 352
andrew@50 353 void AudioEventMatcher::goToMarker(const int& markerID){
andrew@50 354 if (startedPlaying && markerID >= 0 && markerID < markedPoints.markers.size()){
andrew@50 355 double markPosition = markedPoints.markers[markerID];
andrew@50 356 setToPosition(markPosition);
andrew@50 357 }
andrew@50 358
andrew@50 359 }
andrew@50 360
andrew@50 361 void AudioEventMatcher::mousePressed(const int& x){
andrew@50 362 if (!startedPlaying){
andrew@50 363 double position = (float) x * screenWidthMillis / ofGetWidth();
andrew@50 364 position += screenStartTimeMillis;
andrew@50 365 setPlaybackPosition(position);
andrew@50 366 }
andrew@50 367 }
andrew@50 368
andrew@50 369 void AudioEventMatcher::setToPosition(const double& position){
andrew@55 370 setNewLimits(position);
andrew@55 371
andrew@50 372 bayesianStruct.posterior.zero();
andrew@53 373 bayesianStruct.zeroDistributionAtPosition(bayesianStruct.posterior, position);
andrew@50 374 bayesianStruct.posterior.addGaussianShapeFromRealTime(position, 100, 1);
andrew@53 375
andrew@53 376 bayesianStruct.prior.zero();
andrew@53 377 bayesianStruct.zeroDistributionAtPosition(bayesianStruct.prior, position);
andrew@53 378 bayesianStruct.prior.addGaussianShapeFromRealTime(position, 100, 1);
andrew@53 379
andrew@50 380 // bayesianStruct.posterior.addConstant(0.1);
andrew@50 381 // bayesianStruct.prior.zero();
andrew@50 382 // bayesianStruct.prior.addConstant(1);
andrew@50 383 }
andrew@50 384
andrew@55 385
andrew@55 386 void AudioEventMatcher::setNewLimits(const double& position){
andrew@55 387 //update the distribution to the new limits
andrew@55 388 double difference = position - (bayesianStruct.prior.getIndexInRealTerms(bayesianStruct.prior.length/2));
andrew@55 389 bayesianStruct.prior.offset += difference;
andrew@55 390 bayesianStruct.likelihood.offset += difference;
andrew@55 391 bayesianStruct.posterior.offset += difference;
andrew@55 392
andrew@55 393 bayesianStruct.prior.zero();
andrew@55 394 bayesianStruct.posterior.zero();
andrew@55 395 bayesianStruct.likelihood.zero();
andrew@55 396 }
andrew@55 397
andrew@50 398 #pragma mark -draw
andrew@45 399
andrew@0 400 void AudioEventMatcher::draw(){
andrew@32 401
andrew@32 402 //MAIN DRAW FUNCTION FOR ALL
andrew@55 403
andrew@55 404 //ofBackground(255,255,255);
andrew@32 405
andrew@6 406 //draw some outlines in blue
andrew@3 407 ofSetColor(20,200,200);
andrew@39 408 // bayesPositionWindow.drawOutline();
andrew@39 409 // bayesTempoWindow.drawOutline();
andrew@0 410
andrew@6 411 //draw the scrolling audio tracks
andrew@1 412 recordedTracks.drawTracks();
andrew@7 413
andrew@2 414 ofSetColor(255);
andrew@2 415 // bayesianStruct.relativeSpeedPrior.drawVector(0, 200, bayesTempoWindow);
andrew@9 416
andrew@9 417 setScreenDisplayTimes();
andrew@6 418 drawBayesianDistributions();
andrew@8 419
andrew@11 420 //bayesianStruct.posterior.drawVector(0, bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow);
andrew@6 421 //bayesianStruct.posterior.drawVector(bayesianStruct.posterior.getRealTermsAsIndex(0), bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow);
andrew@11 422 //bayesianStruct.relativeSpeedPosterior.drawVector(0, bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(2), bayesTempoWindow);
andrew@9 423
andrew@55 424 //tempo
andrew@55 425 //temporal.drawTempoArray(bayesLikelihoodWindow);
andrew@50 426
andrew@50 427 if (printInfo){
andrew@55 428 drawRecordedTempo();
andrew@55 429 drawPlayingTempo();
andrew@55 430 drawAlignmentTimes();
andrew@50 431 }
andrew@20 432
andrew@50 433 drawMarkers();
andrew@20 434
andrew@6 435 }
andrew@20 436
andrew@20 437 void AudioEventMatcher::drawRecordedTempo(){
andrew@6 438
andrew@21 439 int xTempoIndex = ofGetWidth() * (double)(recordedTempo - recordedTempoData.minimumTempoInterval)/(double)(recordedTempoData.maximumTempoInterval - recordedTempoData.minimumTempoInterval);
andrew@20 440 ofSetColor(0, 200, 0);
andrew@20 441 ofLine(xTempoIndex, bayesLikelihoodWindow.y, xTempoIndex, bayesLikelihoodWindow.y + bayesLikelihoodWindow.height);
andrew@20 442 ofDrawBitmapString(ofToString(recordedTempo), xTempoIndex, bayesLikelihoodWindow.y + 10);
andrew@20 443 }
andrew@20 444
andrew@20 445 void AudioEventMatcher::drawPlayingTempo(){
andrew@21 446 //purple line for MAP estimate of new intervals
andrew@21 447 int xTempoIndex = (double)(ofGetWidth() * (temporal.playingTempo - temporal.minimumTempoInterval))/(double)(temporal.maximumTempoInterval - temporal.minimumTempoInterval);
andrew@20 448 ofSetColor(200, 0, 200);
andrew@20 449 ofLine(xTempoIndex, bayesLikelihoodWindow.y, xTempoIndex, bayesLikelihoodWindow.y + bayesLikelihoodWindow.height);
andrew@21 450 ofDrawBitmapString(ofToString(temporal.playingTempo), xTempoIndex, bayesLikelihoodWindow.y + 10);
andrew@20 451
andrew@21 452 //red line where the ratio is between playing tempo and recorded one
andrew@20 453 int xSpeedRatioIndex = (double)(temporal.tempoPosterior.getIndexInRealTerms(currentSpeedRatio)*ofGetWidth())/(double)temporal.tempoPosterior.arraySize;
andrew@20 454 ofSetColor(200,0,0);
andrew@20 455 ofLine(xSpeedRatioIndex, bayesTempoWindow.y, xSpeedRatioIndex, bayesTempoWindow.y + bayesTempoWindow.height);
andrew@50 456
andrew@50 457 if (printInfo){
andrew@21 458 string tmpString = "playing "+ofToString(temporal.playingTempo);
andrew@21 459 tmpString += ", recorded "+ofToString(recordedTempo);
andrew@21 460 tmpString += " ratio "+ofToString(currentSpeedRatio);
andrew@21 461 ofSetColor(155,155,155);
andrew@21 462 ofDrawBitmapString(tmpString, 20, bayesTempoWindow.y+10);
andrew@50 463 }
andrew@20 464 }
andrew@20 465
andrew@20 466
andrew@9 467 void AudioEventMatcher::setScreenDisplayTimes(){
andrew@9 468 screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber);
andrew@9 469 // if (!followingLiveInput){
andrew@9 470
andrew@9 471 screenStartTimeMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.drawParams.windowStartFrame);
andrew@9 472 screenEndTimeMillis = screenStartTimeMillis + screenWidthMillis;
andrew@9 473
andrew@9 474 //need PRECISION in this alignment
andrew@9 475
andrew@9 476
andrew@9 477 /*}else{
andrew@9 478
andrew@9 479 screenStartTimeMillis = (int)(currentAlignmentPosition/screenWidthMillis) * screenWidthMillis;
andrew@9 480 screenEndTimeMillis = screenStartTimeMillis + screenWidthMillis;
andrew@9 481 }*/
andrew@9 482 }
andrew@9 483
andrew@6 484 void AudioEventMatcher::drawBayesianDistributions(){
andrew@6 485
andrew@32 486
andrew@32 487 drawPositionWindow();
andrew@4 488
andrew@8 489 // bayesianStruct.likelihood.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesLikelihoodWindow);
andrew@2 490
andrew@6 491 bayesianStruct.relativeSpeedPosterior.drawConstrainedVector(0, bayesianStruct.relativeSpeedPosterior.arraySize, 0, ofGetWidth(), bayesTempoWindow);
andrew@32 492
andrew@50 493 if (drawLikelihoods)
andrew@55 494 drawTrackLikelihoods();
andrew@6 495
andrew@50 496
andrew@32 497
andrew@32 498 // int priorStartIndex = bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis);
andrew@32 499 // int priorEndIndex = bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis);
andrew@32 500 // ofSetColor(0,200,200);//recent prior
andrew@32 501 // recentPrior.drawConstrainedVector(priorStartIndex, priorEndIndex, 0, ofGetWidth(), bayesPositionWindow);
andrew@32 502
andrew@50 503 if (printInfo)
andrew@50 504 drawInfo();
andrew@32 505
andrew@3 506
andrew@32 507 }
andrew@32 508
andrew@32 509 void AudioEventMatcher::drawPositionWindow(){
andrew@32 510 int startIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenStartTimeMillis);
andrew@32 511 int endIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenEndTimeMillis);
andrew@32 512 string tmpString = "start "+ofToString(screenStartTimeMillis)+" (index "+ofToString(startIndex)+"), end "+ofToString(screenEndTimeMillis);
andrew@32 513 ofDrawBitmapString(tmpString, bayesPositionWindow.x+20, bayesPositionWindow.y+20);
andrew@32 514
andrew@32 515 //draw posterior in the bayes position window
andrew@32 516 ofSetColor(255,0,255);
andrew@32 517 bayesianStruct.posterior.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesPositionWindow);
andrew@3 518
andrew@9 519 //green line at current best estimate
andrew@13 520 ofSetColor(0,255,0);//green scrolling line best position
andrew@8 521 double currentEstimateIndex = (currentAlignmentPosition - screenStartTimeMillis)*ofGetWidth()/screenWidthMillis;
andrew@8 522 ofLine(currentEstimateIndex, bayesPositionWindow.y, currentEstimateIndex, bayesPositionWindow.y + bayesPositionWindow.height);
andrew@7 523
andrew@32 524
andrew@16 525 ofSetColor(0,255,255);//synchroniser position
andrew@16 526 currentEstimateIndex = (synchroniser.playingPositionMillis - screenStartTimeMillis)*ofGetWidth()/screenWidthMillis;
andrew@16 527 ofLine(currentEstimateIndex, bayesLikelihoodWindow.y, currentEstimateIndex, bayesLikelihoodWindow.y + bayesPositionWindow.height);
andrew@32 528
andrew@32 529 ofSetColor(255,0,100);//purple prior
andrew@32 530 bayesianStruct.prior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesPositionWindow);
andrew@16 531
andrew@32 532 ofSetColor(255,0,0);//projected prior in red
andrew@32 533 projectedPrior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesPositionWindow);
andrew@16 534
andrew@37 535 //draw pitch
andrew@37 536 ofSetColor(0,100,255);
andrew@37 537 int index = getScreenWidthIndexOfEventTime(recentPitchEventTime);
andrew@37 538 //this window would be used (recordedTracks.loadedAudioFiles[1].fileLoader.onsetDetect.window);
andrew@16 539
andrew@53 540 ofSetColor(255, 255, 255);
andrew@53 541 ofDrawBitmapString("curr.speed "+ofToString(synchroniser.smoothedSpeedOutput, 3), 20, ofGetHeight() - 10);
andrew@53 542
andrew@32 543 }
andrew@32 544
andrew@37 545 int AudioEventMatcher::getScreenWidthIndexOfEventTime(const double& time){
andrew@53 546 return (time - screenStartTimeMillis
andrew@53 547 )*ofGetWidth()/screenWidthMillis;
andrew@37 548 }
andrew@37 549
andrew@32 550 void AudioEventMatcher::drawTrackLikelihoods(){
andrew@7 551 //draw track by track likelihoods
andrew@7 552 for (int i = 0; i <recordedTracks.numberOfAudioTracks;i++){
andrew@13 553 ofSetColor(200,255,50);//channel likelihoods in yellow
andrew@8 554 likelihoodVisualisation[i].drawConstrainedVector(likelihoodVisualisation[i].getRealTermsAsIndex(screenStartTimeMillis), likelihoodVisualisation[i].getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), recordedTracks.loadedAudioFiles[i].fileLoader.onsetDetect.window);
andrew@11 555
andrew@13 556 ofSetColor(0,255,150);//channel priors
andrew@11 557 recentPriors[i].drawConstrainedVector(recentPriors[i].getRealTermsAsIndex(screenStartTimeMillis), recentPriors[i].getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), recordedTracks.loadedAudioFiles[i].fileLoader.onsetDetect.window);
andrew@11 558
andrew@50 559 if (printInfo){
andrew@8 560 ofSetColor(255);
andrew@8 561 ofDrawBitmapString("recent event "+ofToString(recentEventTime[i]), recordedTracks.loadedAudioFiles[i].fileLoader.onsetDetect.window.x + 20, recordedTracks.loadedAudioFiles[i].fileLoader.onsetDetect.window.y + recordedTracks.loadedAudioFiles[i].fileLoader.onsetDetect.window.height - 10);
andrew@50 562 }
andrew@7 563 }
andrew@32 564 }
andrew@8 565
andrew@8 566
andrew@32 567 void AudioEventMatcher::drawInfo(){
andrew@32 568 string tmpStr = "zero is "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(0));
andrew@32 569 tmpStr += " offsetis "+ofToString(bayesianStruct.posterior.offset);
andrew@32 570 tmpStr += " screenWidth = "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis));
andrew@32 571 ofDrawBitmapString(tmpStr, 20,140);
andrew@32 572 tmpStr = "best est "+ofToString(bayesianStruct.bestEstimate);
andrew@32 573 ofDrawBitmapString(tmpStr, 20, 180);
andrew@45 574 //ofDrawBitmapString("screenwidth "+ofToString(screenWidthMillis), 20, 800);
andrew@11 575
andrew@32 576 ofSetColor(255);
andrew@32 577 tmpStr = "pitch "+ofToString(recentPitch, 2);
andrew@32 578 tmpStr += " Nearest "+ofToString(pitchOfNearestMatch,2);
andrew@32 579 tmpStr += " dist "+ofToString(distanceOfNearestMatch, 2);
andrew@37 580 tmpStr += ", Time "+ofToString(recentPitchEventTime, 0);
andrew@32 581 ofDrawBitmapString(tmpStr, 20, 20);
andrew@7 582
andrew@39 583 string alignString = "align "+ofToString(currentAlignmentPosition, 2);//same as synchroniser-recordedposition
andrew@32 584 alignString += " playing "+ofToString(synchroniser.playingPositionRatio, 5);
andrew@39 585 alignString += " pos "+ofToString(synchroniser.playingPositionMillis,0)+" ms";//playing position in file - causal correction
andrew@39 586 alignString += " rec pos "+ofToString(synchroniser.recordedPositionMillis,0)+" ms";//currentAlignmentPosition in rehearsal
andrew@39 587 alignString += "playing time "+ofToString(synchroniser.recordedPositionTimeSent, 0)+" ms";//playing time since begining of live take
andrew@32 588 ofDrawBitmapString(alignString, 20, 50);
andrew@32 589 ofDrawBitmapString("pos "+ofToString(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.playPosition), 200,600);
andrew@19 590
andrew@1 591 }
andrew@1 592
andrew@45 593
andrew@45 594 void AudioEventMatcher::drawAlignmentTimes(){
andrew@45 595 ofSetColor(255);
andrew@45 596 std::string dataString = "Live time "+ofToString(synchroniser.recordedPositionTimeSent);
andrew@45 597 dataString += ", Reh time "+ofToString(synchroniser.recordedPositionMillis);
andrew@53 598 ofDrawBitmapString(dataString, 10, ofGetHeight() - 40);
andrew@45 599
andrew@45 600 }
andrew@45 601
andrew@45 602
andrew@50 603 void AudioEventMatcher::drawMarkers(){
andrew@50 604 int i = 0;
andrew@50 605 while (i < markedPoints.markers.size() && markedPoints.markers[i] < screenStartTimeMillis)
andrew@50 606 i++;
andrew@50 607
andrew@50 608 while (i < markedPoints.markers.size() && markedPoints.markers[i] < screenStartTimeMillis + screenWidthMillis) {
andrew@50 609 ofSetColor(255,255,60);
andrew@50 610 double markerPosition = (markedPoints.markers[i] - screenStartTimeMillis)*ofGetWidth()/screenWidthMillis;
andrew@50 611 ofLine(markerPosition, bayesPositionWindow.y, markerPosition, bayesPositionWindow.y + bayesPositionWindow.height);
andrew@50 612 //printf("marker %f pos %f\n", markedPoints.markers[i], markerPosition);
andrew@50 613 i++;
andrew@50 614
andrew@52 615 ofDrawBitmapString(ofToString(i), markerPosition, bayesPositionWindow.y);
andrew@52 616
andrew@50 617 }
andrew@50 618 }
andrew@50 619
andrew@50 620 #pragma mark -newEvents
andrew@50 621
andrew@6 622 void AudioEventMatcher::newPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){
andrew@7 623 if (pitchIn > 0){
andrew@1 624 liveInput.addPitchEvent(pitchIn, timeIn);
andrew@4 625
andrew@10 626 //printPosteriorMAPinfo();
andrew@11 627
andrew@7 628 matchNewPitchEvent(channel, pitchIn, timeIn);//main pitch matching fn
andrew@7 629
andrew@7 630 likelihoodVisualisation[1] = bayesianStruct.likelihood;
andrew@7 631
andrew@7 632 recentPitch = pitchIn;//for drawing
andrew@37 633 recentPitchEventTime = timeIn;
andrew@7 634 }
andrew@53 635 checkTempo();
andrew@32 636 }
andrew@32 637
andrew@32 638
andrew@32 639 void AudioEventMatcher::newChromaEvent(const int& channel, float* chromaIn, const double& timeIn){
andrew@32 640
andrew@32 641 // could add event to the liveInput list? as in pitch event
andrew@37 642 if (printingData){
andrew@37 643 printf("match chroma channel %i\n", channel);
andrew@37 644 for (int i = 0;i < 12;i++){
andrew@34 645 printf("chroma in[%i] = %f\n", i, chromaIn[i]);
andrew@37 646 }
andrew@34 647 }
andrew@34 648
andrew@32 649 matchNewChromaEvent(channel, chromaIn, timeIn);//main pitch matching fn
andrew@32 650
andrew@32 651 likelihoodVisualisation[channel] = bayesianStruct.likelihood;
andrew@32 652
andrew@53 653 checkTempo();
andrew@2 654 }
andrew@2 655
andrew@32 656
andrew@6 657 void AudioEventMatcher::newKickEvent(const double& timeIn){
andrew@6 658 // liveInput.addKickEvent(timeIn);
andrew@53 659 newKickEvent(0, timeIn);
andrew@53 660 // matchNewOnsetEvent(0, timeIn);
andrew@53 661 // likelihoodVisualisation[0] = bayesianStruct.likelihood;
andrew@2 662 }
andrew@2 663
andrew@6 664 void AudioEventMatcher::newKickEvent(const int& channel, const double& timeIn){
andrew@6 665 // liveInput.addKickEvent(timeIn);
andrew@6 666 matchNewOnsetEvent(channel, timeIn);
andrew@7 667 likelihoodVisualisation[0] = bayesianStruct.likelihood;
andrew@53 668 checkTempo();
andrew@6 669 }
andrew@6 670
andrew@2 671
andrew@2 672 void AudioEventMatcher::newSnareEvent(const double& timeIn){
andrew@53 673 newSnareEvent(2, timeIn);
andrew@53 674
andrew@53 675 // matchNewOnsetEvent(2, timeIn);
andrew@53 676 // likelihoodVisualisation[2] = bayesianStruct.likelihood;
andrew@7 677 }
andrew@7 678
andrew@7 679 void AudioEventMatcher::newSnareEvent(const int& channel, const double& timeIn){
andrew@7 680 matchNewOnsetEvent(channel, timeIn);
andrew@7 681 likelihoodVisualisation[2] = bayesianStruct.likelihood;
andrew@53 682 checkTempo();
andrew@2 683 }
andrew@2 684
andrew@53 685 void AudioEventMatcher::checkTempo(){
andrew@53 686
andrew@53 687 if (synchroniser.speed > 0.92 && synchroniser.speed < 1.08){
andrew@53 688 // double relativeTempo = 1 +
andrew@53 689 // relativeTempo += 0.4 * (synchroniser.speed - relativeTempo);
andrew@53 690 printf("Speed %f new tempo %f\n\n", synchroniser.speed, synchroniser.smoothedSpeedOutput);
andrew@53 691 setSpeedRatioDistribution(synchroniser.smoothedSpeedOutput);
andrew@53 692 }
andrew@53 693
andrew@53 694 }
andrew@53 695
andrew@53 696
andrew@50 697 #pragma mark -EventMatching
andrew@2 698 //Needs just to set bounds for the matching process, not have TimeIn
andrew@2 699 void AudioEventMatcher::matchNewOnsetEvent(const int& channel, const double& timeIn){
andrew@3 700
andrew@6 701 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
andrew@10 702
andrew@2 703 //start at beginning but OPTIMISE later
andrew@2 704 bayesianStruct.likelihood.offset = bayesianStruct.prior.offset;
andrew@2 705 bayesianStruct.likelihood.zero();//set to zero
andrew@36 706 //double quantity = 1;//
andrew@53 707 double quantity;
andrew@53 708
andrew@53 709 switch (channel) {
andrew@53 710 case 0:
andrew@53 711 quantity = kickLikelihoodToNoise;// onsetLikelihoodToNoise;
andrew@53 712 //BETTER CHANGE THIS BACK TOO..see below//likelihoodToNoiseRatio / numberOfMatches;
andrew@53 713 break;
andrew@53 714 case 2:
andrew@53 715 quantity = snareLikelihoodToNoise;// onsetLikelihoodToNoise;
andrew@53 716 //BETTER CHANGE THIS BACK TOO..see below//likelihoodToNoiseRatio / numberOfMatches;
andrew@53 717 break;
andrew@53 718 }
andrew@53 719
andrew@53 720
andrew@53 721
andrew@2 722 int numberOfMatchesFound = 0;
andrew@45 723 double nearestOnsetDistance = 1000;
andrew@10 724 double startMatchingTime = bayesianStruct.likelihood.offset;
andrew@10 725 double endMatchingTime = bayesianStruct.likelihood.offset + matchWindowWidth;
andrew@32 726 double millisTime = -1*INFINITY;//or 0 is fine
andrew@32 727 int checkIndex = 0;
andrew@36 728 if (channel <= recordedTracks.numberOfAudioTracks && checkIndex < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){
andrew@32 729 while (millisTime < startMatchingTime) {
andrew@32 730 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[checkIndex].millisTime;
andrew@32 731 checkIndex++;
andrew@32 732 }
andrew@32 733 for (int i = checkIndex;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size() && millisTime <= endMatchingTime;i++){
andrew@32 734 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
andrew@10 735 if (millisTime >= startMatchingTime && millisTime <= endMatchingTime){
andrew@14 736 bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, onsetLikelihoodWidth, quantity);
andrew@2 737 numberOfMatchesFound++;
andrew@6 738 // printf("Adding Gaussian for onset at time %f offset %f\n", millisTime, bayesianStruct.likelihood.offset);
andrew@45 739 if (fabs(currentAlignmentPosition - millisTime) < nearestOnsetDistance)
andrew@45 740 nearestOnsetDistance = currentAlignmentPosition - millisTime;
andrew@32 741 }//end if within limits (changed so it now is 4 sure)
andrew@2 742 }
andrew@2 743 }
andrew@2 744
andrew@11 745 if (numberOfMatchesFound > 0){
andrew@3 746 // bayesianStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesianStruct.likelihood.length);
andrew@36 747 // bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-onsetLikelihoodToNoise)/(onsetLikelihoodToNoise*bayesianStruct.likelihood.length));
andrew@53 748 bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-quantity)/(bayesianStruct.likelihood.length));//BETTER CHANGE THIS BACK...
andrew@2 749 bayesianStruct.likelihood.renormalise();
andrew@2 750
andrew@8 751 bayesianStruct.calculatePosterior();
andrew@10 752 lastAlignmentTime = timeIn;//use TIMESTAMP
andrew@10 753 recentEventTime[channel] = timeIn;//ofGetElapsedTimeMillis() - startTime;
andrew@11 754
andrew@11 755 recentPriors[channel] = bayesianStruct.prior;
andrew@13 756 projectedPrior = bayesianStruct.prior;
andrew@19 757
andrew@19 758
andrew@19 759 temporal.updateTempo(channel, timeIn);
andrew@11 760 }
andrew@45 761 int timeNow = getTimeNow();
andrew@11 762
andrew@45 763 printf("Nearest onset is %.1f time is %i and alignemnt %i time now %i\n", nearestOnsetDistance, (int) timeIn, (int)currentAlignmentPosition, timeNow);
andrew@3 764 }
andrew@3 765
andrew@3 766
andrew@3 767
andrew@3 768 void AudioEventMatcher::matchNewPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){
andrew@3 769 //start at beginning but OPTIMISE later
andrew@10 770 /*printf("TIME %i\n", ofGetElapsedTimeMillis());
andrew@10 771 //tmp debug
andrew@10 772 updateBestAlignmentPosition();
andrew@10 773 printf("current alignment best estimate %f\n", currentAlignmentPosition);
andrew@10 774 */
andrew@6 775 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
andrew@8 776
andrew@7 777 //set the lielihoods by matching the pitched note
andrew@7 778
andrew@15 779
andrew@3 780 int numberOfMatches = 0;
andrew@3 781 bayesianStruct.likelihood.zero();//set to zero
andrew@18 782 double newOnsetTime;
andrew@18 783 double closestDistance = INFINITY;
andrew@3 784
andrew@3 785 double quantity = 0;
andrew@32 786 double totalLikelihoodAdded = 0;
andrew@3 787 if (channel <= recordedTracks.numberOfAudioTracks){
andrew@3 788 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){
andrew@3 789
andrew@3 790 if (checkMatch(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn)) {
andrew@56 791 quantity = getPitchDistance(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn, pitchWidth);
andrew@18 792
andrew@56 793 bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, pitchLikelihoodWidth, quantity);
andrew@3 794 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = true;
andrew@3 795 numberOfMatches++;
andrew@32 796 totalLikelihoodAdded += quantity;
andrew@3 797 }
andrew@3 798 else{
andrew@3 799 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = false;
andrew@3 800 }
andrew@18 801 //checking nearest pitch
andrew@18 802 newOnsetTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
andrew@18 803 if (abs(newOnsetTime - currentAlignmentPosition) < closestDistance){
andrew@18 804 closestDistance = abs(newOnsetTime - currentAlignmentPosition);
andrew@18 805 pitchOfNearestMatch = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch;
andrew@18 806 distanceOfNearestMatch = quantity;
andrew@18 807 }
andrew@3 808
andrew@3 809 }
andrew@3 810 }
andrew@6 811
andrew@8 812
andrew@8 813
andrew@37 814 if (numberOfMatches > 0 && totalLikelihoodAdded > 0){//no point updating unless there is a match
andrew@32 815 //replacing numberOfMatches with totalLike below...
andrew@37 816 //bug here was that if totaladded = 0, we add then zero likelihood
andrew@37 817 bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-pitchLikelihoodToNoise)/(bayesianStruct.likelihood.length));
andrew@37 818 // bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-pitchLikelihoodToNoise)/(pitchLikelihoodToNoise*bayesianStruct.likelihood.length));
andrew@4 819
andrew@4 820 //tmp set likelihood constant and calculate using that
andrew@6 821 //bayesianStruct.likelihood.zero();
andrew@6 822 //bayesianStruct.likelihood.addConstant(1);
andrew@7 823
andrew@6 824 bayesianStruct.calculatePosterior();
andrew@11 825 lastAlignmentTime = timeIn;//has to use the STAMPED time
andrew@11 826 recentEventTime[channel] = timeIn;
andrew@11 827
andrew@11 828 recentPriors[channel] = bayesianStruct.prior;
andrew@13 829 projectedPrior = bayesianStruct.prior;
andrew@19 830
andrew@19 831 temporal.eventTimes[channel].push_back(timeIn);
andrew@6 832 }
andrew@4 833
andrew@11 834
andrew@1 835 }
andrew@1 836
andrew@3 837 double AudioEventMatcher::getPitchDistance(const double& pitchOne, const double& pitchTwo, const double& scale){
andrew@3 838
andrew@18 839 double scaleFactor = scale * pitchOne / 110.0;
andrew@16 840
andrew@18 841 int multiplicationFactor = 1;
andrew@18 842 if (pitchTwo > 0){
andrew@32 843 multiplicationFactor = round(pitchOne/pitchTwo);
andrew@18 844 }
andrew@16 845
andrew@18 846 double distance = abs(pitchOne - pitchTwo*multiplicationFactor);
andrew@16 847 if (distance < scaleFactor)
andrew@16 848 distance = 1 - (distance/scaleFactor);
andrew@3 849 else
andrew@3 850 distance = 0;
andrew@3 851
andrew@32 852 //printf("[pitch distance %f vs %f, factor %i = %f\n", pitchOne, pitchTwo, multiplicationFactor, distance);
andrew@3 853 return distance;
andrew@3 854
andrew@3 855 }
andrew@3 856
andrew@3 857
andrew@3 858 bool AudioEventMatcher::checkMatch(const double& recordedPitch, const double& livePitch){
andrew@18 859
andrew@18 860 if (livePitch > 0){
andrew@18 861 int multiplicationFactor = (int)(round(recordedPitch/livePitch));
andrew@18 862
andrew@32 863 if (abs(recordedPitch - livePitch * multiplicationFactor) < pitchCutOff)
andrew@3 864 return true;
andrew@3 865 else
andrew@3 866 return false;
andrew@18 867 }else {
andrew@18 868 return false;
andrew@18 869 }
andrew@18 870
andrew@3 871 }
andrew@3 872
andrew@3 873
andrew@32 874 void AudioEventMatcher::matchNewChromaEvent(const int& channel, float* chromaIn, const double& timeIn){
andrew@32 875 //start at beginning but OPTIMISE later
andrew@32 876
andrew@52 877 makeQuantisedChroma(chromaIn);
andrew@52 878
andrew@32 879 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
andrew@32 880
andrew@32 881 //set the likelihoods by matching the pitched note
andrew@32 882
andrew@32 883 int numberOfMatches = 0;
andrew@32 884 bayesianStruct.likelihood.zero();//set to zero
andrew@32 885 double newOnsetTime;
andrew@32 886 double closestDistance = INFINITY;
andrew@32 887
andrew@32 888 double quantity = 1;
andrew@32 889 double totalLikelihoodAdded = 0;
andrew@32 890
andrew@32 891 double startMatchingTime = bayesianStruct.likelihood.offset;
andrew@32 892 double endMatchingTime = bayesianStruct.likelihood.offset + matchWindowWidth;
andrew@32 893 double millisTime = -1*INFINITY;//or 0 is fine
andrew@32 894
andrew@32 895 int checkIndex = 0;
andrew@37 896 if (channel <= recordedTracks.numberOfAudioTracks && checkIndex < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){
andrew@37 897
andrew@32 898 while (millisTime < startMatchingTime) {
andrew@32 899 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[checkIndex].millisTime;
andrew@32 900 checkIndex++;
andrew@32 901 }//go up to where we need to check from fast
andrew@32 902
andrew@32 903 for (int i = checkIndex;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size() && millisTime <= endMatchingTime;i++){
andrew@32 904 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
andrew@32 905
andrew@32 906 if (millisTime >= startMatchingTime && millisTime <= endMatchingTime){
andrew@35 907
andrew@52 908 //for cts chroma
andrew@52 909 /*
andrew@35 910 if (useChromaDotProduct)
andrew@35 911 quantity = getChromaDotProductDistance(chromaIn, &recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].chromaValues[0]);
andrew@35 912 else
andrew@35 913 quantity = getChromaEuclideanDistance(chromaIn, &recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].chromaValues[0]);
andrew@52 914 */
andrew@52 915 // printf("Distance old way %f", quantity);
andrew@35 916
andrew@52 917 //for quantised chroma
andrew@52 918 quantity = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].getChromaQuantisedDistance(&quantisedChromagramReceived[0]);
andrew@52 919
andrew@52 920 // printf(" quantised %f\n", quantity);
andrew@35 921
andrew@32 922 bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, chromaLikelihoodWidth, quantity);
andrew@32 923
andrew@32 924 // bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, onsetLikelihoodWidth, quantity);
andrew@32 925 numberOfMatches++;
andrew@32 926 totalLikelihoodAdded += quantity;
andrew@37 927
andrew@37 928 //printf("Adding CHROMA Gaussian for onset at time %.1f dist %.3f\n", millisTime, quantity);
andrew@32 929
andrew@32 930 }//end if within limits (changed so it now is 4 sure)
andrew@32 931 }
andrew@32 932 }
andrew@32 933
andrew@32 934
andrew@37 935 if (numberOfMatches > 0 && totalLikelihoodAdded > 0){//no point updating unless there is a match
andrew@32 936 //replacing numberOfMatches with totalLike below...
andrew@32 937
andrew@32 938 printf("CHROMA HAS %i MATCHES\n", numberOfMatches);
andrew@32 939
andrew@37 940 bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-chromaLikelihoodToNoise)/(bayesianStruct.likelihood.length));
andrew@37 941 //previous way
andrew@37 942 // bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-chromaLikelihoodToNoise)/(chromaLikelihoodToNoise*bayesianStruct.likelihood.length));
andrew@32 943
andrew@32 944 bayesianStruct.calculatePosterior();
andrew@32 945 lastAlignmentTime = timeIn;//has to use the STAMPED time
andrew@32 946 recentEventTime[channel] = timeIn;
andrew@32 947
andrew@32 948 recentPriors[channel] = bayesianStruct.prior;
andrew@32 949 projectedPrior = bayesianStruct.prior;
andrew@32 950
andrew@32 951 temporal.eventTimes[channel].push_back(timeIn);
andrew@32 952 }
andrew@32 953
andrew@32 954 }
andrew@32 955
andrew@52 956 void AudioEventMatcher::makeQuantisedChroma(float* chromaIn){
andrew@52 957 double L_norm = 0;
andrew@52 958
andrew@52 959 for (int i = 0;i < 12;i++){
andrew@52 960 L_norm += chromaIn[i];
andrew@52 961 }
andrew@52 962
andrew@52 963 if (L_norm > 0){
andrew@52 964 for (int i = 0;i < 12;i++){
andrew@52 965 chromaIn[i] /= L_norm;//NB not const fn!
andrew@52 966 quantisedChromagramReceived[i] = 0;
andrew@52 967
andrew@52 968 if (chromaIn[i] > 0.05)
andrew@52 969 quantisedChromagramReceived[i]++;
andrew@52 970
andrew@52 971 if (chromaIn[i] > 0.1)
andrew@52 972 quantisedChromagramReceived[i]++;
andrew@52 973
andrew@52 974 if (chromaIn[i] > 0.2)
andrew@52 975 quantisedChromagramReceived[i]++;
andrew@52 976
andrew@52 977 if (chromaIn[i] > 0.4)
andrew@52 978 quantisedChromagramReceived[i]++;
andrew@52 979
andrew@52 980 }
andrew@52 981 }
andrew@52 982 }
andrew@32 983
andrew@35 984 double AudioEventMatcher::getChromaDotProductDistance(float* chromaOne, float* chromaTwo){
andrew@32 985 double distance = 0;
andrew@32 986 double total = 0;
andrew@32 987 for (int i = 0;i < 12;i++){
andrew@32 988 distance += chromaOne[i]*chromaTwo[i];
andrew@32 989 total += chromaOne[i]*chromaOne[i] + (chromaTwo[i]*chromaTwo[i]);
andrew@32 990 }
andrew@32 991
andrew@35 992 if (total > 0)
andrew@35 993 distance /= sqrt(total);
andrew@35 994
andrew@35 995 return distance;
andrew@35 996 }
andrew@35 997
andrew@35 998 double AudioEventMatcher::getChromaEuclideanDistance(float* chromaOne, float* chromaTwo){
andrew@35 999 double distance = 0;
andrew@35 1000 double total = 0;
andrew@37 1001
andrew@35 1002 // printf("\n");
andrew@35 1003 for (int i = 0;i < 12;i++){
andrew@35 1004 total += (chromaOne[i] - chromaTwo[i])*(chromaOne[i] - chromaTwo[i]);
andrew@35 1005 // printf("chroma1: %.2f; chroma2: %.2f\n", chromaOne[i], chromaTwo[i]);
andrew@35 1006 // total += chromaOne[i]*chromaOne[i] + (chromaTwo[i]*chromaTwo[i]);
andrew@35 1007 }
andrew@35 1008
andrew@37 1009 if (total > euclideanMaximumDistance)
andrew@37 1010 euclideanMaximumDistance = total;
andrew@37 1011
andrew@37 1012 distance = ((euclideanMaximumDistance - total)/ euclideanMaximumDistance);//i.e. 1 is
andrew@37 1013
andrew@37 1014 // if (total > 0)
andrew@37 1015
andrew@37 1016
andrew@37 1017 // distance = 1.0/sqrt(total);
andrew@35 1018 // printf("DISTANCE : %.3f\n", distance);
andrew@32 1019 return distance;
andrew@32 1020 }
andrew@1 1021
andrew@1 1022 void AudioEventMatcher::windowResized(const int& w, const int& h){
andrew@1 1023 recordedTracks.windowResized(w,h);
andrew@3 1024 bayesTempoWindow.resized(w,h);
andrew@3 1025 bayesPositionWindow.resized(w,h);
andrew@50 1026 bayesLikelihoodWindow.resized(w, h);
andrew@3 1027 }
andrew@3 1028
andrew@52 1029 void AudioEventMatcher::writeAllDistributions(){
andrew@55 1030 std::string filepath = "../../../data/distributions/priorDistbnOutput.txt";
andrew@53 1031 writeDistribution(bayesianStruct.prior, filepath);
andrew@55 1032 filepath = "../../../data/distributions/likelihoodDistbnOutput.txt";
andrew@53 1033 writeDistribution(bayesianStruct.likelihood, filepath);
andrew@55 1034 filepath = "../../../data/distributions/posteriorDistbnOutput.txt";
andrew@53 1035 writeDistribution(bayesianStruct.posterior, filepath);
andrew@52 1036
andrew@55 1037 //write kick events
andrew@55 1038 filepath = "../../../data/distributions/kickEvents.txt";
andrew@55 1039 writeKickEvent(screenStartTimeMillis, screenEndTimeMillis, filepath);
andrew@55 1040
andrew@55 1041 ofBackground(255);
andrew@52 1042 recordedTracks.drawTracks();
andrew@55 1043 filepath = "../../../data/distributions/screenGraphics.png";
andrew@52 1044 img.grabScreen(0, 0, ofGetWidth(), ofGetHeight());
andrew@52 1045 img.saveImage(filepath);
andrew@55 1046
andrew@55 1047 ofBackground(0);
andrew@52 1048 }
andrew@52 1049
andrew@52 1050 void AudioEventMatcher::writeDistribution(DynamicVector& distribution, std::string filename){
andrew@52 1051 testDistributionOutput.openFile(filename);
andrew@52 1052
andrew@52 1053 int minIndex = distribution.getRealTermsAsIndex(screenStartTimeMillis);
andrew@52 1054 int maxIndex = distribution.getRealTermsAsIndex(screenEndTimeMillis);
andrew@52 1055 int minScreenIndex = 0;
andrew@52 1056 int maxScreenIndex = ofGetWidth();
andrew@52 1057
andrew@52 1058 double stepSize = (maxScreenIndex - minScreenIndex) / (double)(maxIndex - minIndex);//step size in pixels per array bin
andrew@52 1059 double screenHeight = ofGetHeight();
andrew@52 1060 double maxVal = distribution.getMaximum();
andrew@52 1061
andrew@52 1062 //OPTIMIZE!! XXX could just add stepsize each time
andrew@52 1063 //not add minindex each time
andrew@52 1064 int i = max(1,minIndex+1);
andrew@52 1065 // ofDrawBitmapString("i = "+ofToString(i)+" :: screen min: "+ofToString(minScreenIndex + stepSize*(i-minIndex-1)), 20, 640);
andrew@52 1066
andrew@52 1067 while ((minScreenIndex + stepSize*(i-minIndex)) < 0)
andrew@52 1068 i++;//only draw what is on the screen
andrew@52 1069
andrew@52 1070 for ( ; i < min(maxIndex+1, (int)distribution.array.size());i++){
andrew@52 1071
andrew@55 1072 //as array indices
andrew@55 1073 // testDistributionOutput.writeValue(minScreenIndex + (stepSize*(i-minIndex-1)), distribution.array[i-1]);
andrew@55 1074
andrew@55 1075 //as millis:
andrew@55 1076 testDistributionOutput.writeValue(distribution.getIndexInRealTerms(i), distribution.array[i-1]);
andrew@52 1077 }
andrew@52 1078 testDistributionOutput.closeFile();
andrew@52 1079 }
andrew@52 1080
andrew@55 1081 void AudioEventMatcher::writeKickEvent(const int& startMatchingTime, const int& endMatchingTime, std::string filepath){
andrew@55 1082
andrew@55 1083 int channel = 0;//i.e. kick
andrew@55 1084
andrew@55 1085 if (!testDistributionOutput.outputFile.is_open())
andrew@55 1086 testDistributionOutput.closeFile();
andrew@55 1087
andrew@55 1088 testDistributionOutput.outputFile.open(filepath.c_str());
andrew@55 1089
andrew@55 1090 testDistributionOutput.outputFile << startMatchingTime << "\t" << 0 << endl;
andrew@55 1091 int checkIndex = 0;
andrew@55 1092 double millisTime = 0;
andrew@55 1093 if (channel <= recordedTracks.numberOfAudioTracks && checkIndex < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){
andrew@55 1094 while (millisTime < startMatchingTime) {
andrew@55 1095 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[checkIndex].millisTime;
andrew@55 1096 checkIndex++;
andrew@55 1097 }
andrew@55 1098 for (int i = checkIndex;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size() && millisTime <= endMatchingTime;i++){
andrew@55 1099 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
andrew@55 1100 if (millisTime >= startMatchingTime && millisTime <= endMatchingTime){
andrew@55 1101
andrew@55 1102 testDistributionOutput.outputFile << (int) millisTime - 1 << "\t" << 0 << endl;
andrew@55 1103 testDistributionOutput.outputFile << (int) millisTime << "\t" << 1 << endl;
andrew@55 1104 testDistributionOutput.outputFile << (int) millisTime + 1 << "\t" << 0 << endl;
andrew@55 1105 }//end if within limits (changed so it now is 4 sure)
andrew@55 1106 }
andrew@55 1107 }
andrew@55 1108
andrew@55 1109 testDistributionOutput.outputFile << endMatchingTime << "\t" << 0 << endl;
andrew@55 1110
andrew@55 1111 testDistributionOutput.closeFile();
andrew@55 1112
andrew@55 1113 }
andrew@55 1114
andrew@10 1115 /*
andrew@10 1116
andrew@10 1117 void printPosteriorMAPinfo(){ //tmp print stuff
andrew@10 1118 printf("New pitch MAP post estimate now %i, ", bayesianStruct.posterior.MAPestimate);
andrew@10 1119 double tmp = bayesianStruct.posterior.getMAPestimate();
andrew@10 1120 printf(" getting it %f and offset %f == %f ms\n", tmp, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(tmp));
andrew@10 1121
andrew@10 1122 }
andrew@10 1123 */
andrew@3 1124