annotate src/AudioEventMatcher.cpp @ 36:eb43b2a007ea

changed newMatchOnset to have different way to calculate onsets vs noise, using the onsetLikelihoodNoise factor
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Tue, 24 Apr 2012 01:19:24 +0100
parents 6fb77b20413c
children 9806a4f22fd0
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@0 12
andrew@36 13 const int matchWindowWidth = 8000;
andrew@32 14 const float pitchCutOff = 16;//within which pitches are even considered
andrew@0 15
andrew@0 16 AudioEventMatcher::AudioEventMatcher(){
andrew@7 17
andrew@35 18 useChromaDotProduct = false;
andrew@15 19
andrew@23 20 pitchLikelihoodToNoise = 0.6;//more noise
andrew@32 21 chromaLikelihoodToNoise = 0.5;//lower => more noise, higher more weight for events
andrew@32 22 chromaLikelihoodWidth = 50;//ms round onset event
andrew@16 23
andrew@36 24 onsetLikelihoodToNoise = 0.1;
andrew@17 25 onsetLikelihoodWidth = 10;//in ms
andrew@15 26
andrew@0 27 setArraySizes();
andrew@3 28
andrew@3 29 usingRealTime = false;
andrew@3 30 bayesianStruct.realTimeMode = &usingRealTime;
andrew@7 31 recentPitch = 0;
andrew@8 32 currentAlignmentPosition = 0;
andrew@14 33
andrew@9 34 followingLiveInput = true;
andrew@15 35 startedPlaying = false;
andrew@20 36 recordedTempoIndex = 0;
andrew@20 37 // temporal.setUpEventTimeMatrix();
andrew@20 38 // recordedTempoData.setUpEventTimeMatrix();
andrew@0 39 }
andrew@0 40
andrew@14 41
andrew@19 42
andrew@19 43
andrew@7 44 void AudioEventMatcher::setWindowDimensions(){
andrew@7 45 double startHeight = recordedTracks.numberOfAudioTracks * recordedTracks.trackScreenHeight;
andrew@7 46 double heightAvailable = 1 - startHeight;
andrew@32 47 heightAvailable /= numberOfChannels;
andrew@7 48
andrew@7 49 bayesPositionWindow.setToRelativeSize(0, startHeight, 1, heightAvailable);
andrew@7 50 bayesLikelihoodWindow.setToRelativeSize(0, startHeight + 1*heightAvailable, 1, heightAvailable);
andrew@7 51 bayesTempoWindow.setToRelativeSize(0, startHeight + 2*heightAvailable, 1, heightAvailable);
andrew@7 52
andrew@7 53
andrew@7 54 }
andrew@0 55
andrew@0 56 void AudioEventMatcher::setArraySizes(){
andrew@0 57 bayesianStruct.resetSpeedSize(200);
andrew@0 58 bayesianStruct.setRelativeSpeedScalar(0.01);
andrew@0 59 bayesianStruct.setSpeedPrior(1.0);
andrew@0 60 bayesianStruct.relativeSpeedPrior.getMaximum();
andrew@0 61
andrew@36 62 float scalarForBayesianDistribution = 2;
andrew@36 63
andrew@36 64 bayesianStruct.resetSize(matchWindowWidth / scalarForBayesianDistribution);
andrew@36 65 bayesianStruct.setPositionDistributionScalar(2);
andrew@0 66
andrew@0 67 }
andrew@0 68
andrew@16 69 void AudioEventMatcher::loadAudioFiles(){
andrew@16 70 recordedTracks.loadTestAudio();
andrew@16 71 synchroniser.fileLengthSamples = recordedTracks.loadedAudioFiles[0].fileLoader.totalNumberOfSamples;
andrew@16 72 printf("synchroniser has %f samples\n", synchroniser.fileLengthSamples);
andrew@20 73
andrew@20 74 calculateRecordedTempoData();
andrew@20 75 printf("\n\nFIRST PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo);
andrew@20 76 setTempoPrior(recordedTempoData.playingTempo);
andrew@20 77 calculateRecordedTempoData();//now calculate again using better prior
andrew@20 78
andrew@20 79 printf("\n\nSECOND PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo);
andrew@20 80 printf("GLOBAL TEMPO of RECORDED FILES\n");
andrew@20 81 recordedTempoData.printTempoTimes();
andrew@20 82 }
andrew@20 83
andrew@20 84 void AudioEventMatcher::setTempoPrior(double tempo){
andrew@20 85 recordedTempoData.zero();
andrew@20 86 recordedTempoData.tempoPosterior.zero();
andrew@20 87 recordedTempoData.tempoPosterior.addGaussianShapeFromRealTime(tempo, 3, 1);
andrew@20 88
andrew@20 89 }
andrew@20 90
andrew@20 91 void AudioEventMatcher::calculateRecordedTempoData(){
andrew@20 92 int indexForOnsets[3];
andrew@20 93 indexForOnsets[0] = 0;
andrew@20 94 indexForOnsets[1] = 0;
andrew@20 95 indexForOnsets[2] = 0;
andrew@20 96 int kickTime, snareTime;
andrew@20 97 while (indexForOnsets[0] < recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.chromaOnsets.size() ||
andrew@20 98 indexForOnsets[2] < recordedTracks.loadedAudioFiles[2].fileLoader.onsetDetect.chromaOnsets.size()) {
andrew@20 99
andrew@20 100 setNextOnsetTime(0, kickTime, &indexForOnsets[0]);
andrew@20 101 setNextOnsetTime(2, snareTime, &indexForOnsets[0]);
andrew@20 102
andrew@20 103 if (kickTime < snareTime){
andrew@20 104 printf("update kick at %i\n", kickTime);
andrew@20 105 recordedTempoData.updateTempo(0, kickTime);
andrew@20 106 printf("recorded tempo is %f\n", recordedTempoData.playingTempo);
andrew@20 107 indexForOnsets[0]++;
andrew@20 108 }else {
andrew@20 109 printf("update snare at %i\n", snareTime);
andrew@20 110 recordedTempoData.updateTempo(2, snareTime);
andrew@20 111 printf("recorded tempo is %f\n", recordedTempoData.playingTempo);
andrew@20 112 indexForOnsets[2]++;
andrew@20 113 }
andrew@20 114 }//end while
andrew@20 115
andrew@20 116
andrew@20 117 }
andrew@20 118
andrew@20 119 void AudioEventMatcher::setNextOnsetTime(const int& channel, int& time, int* indexForOnsets){
andrew@20 120 if (indexForOnsets[channel] < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){
andrew@20 121 time = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[indexForOnsets[channel]].millisTime;
andrew@20 122 }
andrew@20 123 else {
andrew@20 124 time = 2147483647;//infinity
andrew@20 125 }
andrew@16 126 }
andrew@16 127
andrew@9 128 void AudioEventMatcher::startPlaying(){
andrew@3 129 bayesianStruct.setStartPlaying();
andrew@8 130 currentAlignmentPosition = 0;
andrew@8 131 startTime = ofGetElapsedTimeMillis();
andrew@11 132
andrew@11 133 projectedPrior = bayesianStruct.prior;
andrew@15 134 startedPlaying = true;
andrew@17 135 synchroniser.reset();
andrew@19 136 temporal.reset();
andrew@17 137
andrew@20 138 recordedTempoIndex = 0;
andrew@20 139 recordedTempo = recordedTempoData.globalTempo[recordedTempoIndex];
andrew@20 140
andrew@20 141 currentSpeedRatio = 1;
andrew@20 142
andrew@21 143 temporal.tempoPosterior.zero();
andrew@36 144 temporal.tempoPosterior.addGaussianShapeFromRealTime(recordedTempo, 2000, 1);
andrew@21 145
andrew@20 146 //SET TEMPO PRIOR for Speed Ratio
andrew@20 147 //the update this
andrew@20 148 setSpeedRatioDistribution(currentSpeedRatio);
andrew@3 149 //bayesianStruct.posterior.printArray();
andrew@3 150 }
andrew@3 151
andrew@9 152
andrew@20 153 void AudioEventMatcher::setSpeedRatioDistribution(const double& speedRatio){
andrew@20 154 bayesianStruct.relativeSpeedPosterior.zero();
andrew@20 155 bayesianStruct.relativeSpeedPosterior.addToIndex(bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(speedRatio), 1);
andrew@22 156 bayesianStruct.relativeSpeedPosterior.addGaussianShapeFromRealTime(1, 0.06, 0.8);
andrew@20 157 }
andrew@20 158
andrew@15 159 void AudioEventMatcher::stopPlaying(){
andrew@15 160 startedPlaying = false;
andrew@19 161 temporal.printEventTimes();
andrew@15 162 }
andrew@15 163
andrew@22 164 void AudioEventMatcher::rescue(){
andrew@22 165 bayesianStruct.posterior.zero();
andrew@22 166 bayesianStruct.posterior.addConstant(1);
andrew@22 167 bayesianStruct.prior.zero();
andrew@22 168 bayesianStruct.prior.addConstant(1);
andrew@22 169 }
andrew@22 170
andrew@9 171 void AudioEventMatcher::updatePosition(){
andrew@19 172
andrew@19 173 if (startedPlaying){
andrew@9 174 if (!followingLiveInput)
andrew@9 175 recordedTracks.updatePosition();
andrew@19 176 else
andrew@9 177 recordedTracks.updatePositionToMillis(currentAlignmentPosition);
andrew@9 178
andrew@20 179 updateBestAlignmentPosition();
andrew@19 180 }
andrew@19 181
andrew@20 182 updateRecordedTempo();
andrew@20 183
andrew@19 184 temporal.tempoPosterior.addGaussianShape(temporal.tempoPosterior.MAPestimate, temporal.tempoArraySize / 4, 0.5 );
andrew@9 185 }
andrew@9 186
andrew@20 187 void AudioEventMatcher::updateRecordedTempo(){
andrew@20 188 //tempo of equivalent recorded position is updated
andrew@20 189 while(currentAlignmentPosition > recordedTempoData.globalTempoTimes[recordedTempoIndex]){
andrew@20 190 recordedTempoIndex++;
andrew@20 191 }
andrew@20 192 recordedTempo = recordedTempoData.globalTempo[recordedTempoIndex];
andrew@20 193 double tmpRatio = currentSpeedRatio;
andrew@20 194 currentSpeedRatio = temporal.playingTempo / recordedTempo;
andrew@20 195 if (currentSpeedRatio != tmpRatio)
andrew@20 196 setSpeedRatioDistribution(currentSpeedRatio);
andrew@20 197 }
andrew@20 198
andrew@8 199 void AudioEventMatcher::updateBestAlignmentPosition(){
andrew@10 200 //THIS DEALS WITH WHERE WE ARE NOW! ON THE SCREEN
andrew@10 201 //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 202
andrew@10 203 int newTime = ofGetElapsedTimeMillis() - startTime;
andrew@10 204 // double tmp = bayesianStruct.posterior.getIndexInRealTerms(bayesianStruct.posterior.MAPestimate);;
andrew@10 205 // double timetmp = (newTime - lastAlignmentTime);
andrew@10 206 // double speedtmp = bayesianStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesianStruct.relativeSpeedPosterior.MAPestimate);
andrew@11 207 // currentAlignmentTime = newTime;
andrew@9 208 currentAlignmentPosition = bayesianStruct.posterior.getIndexInRealTerms(bayesianStruct.posterior.MAPestimate);
andrew@10 209 currentAlignmentPosition += (newTime - lastAlignmentTime) * bayesianStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesianStruct.relativeSpeedPosterior.MAPestimate);
andrew@10 210
andrew@16 211
andrew@17 212 synchroniser.updateRecordedPosition(currentAlignmentPosition, newTime);
andrew@16 213
andrew@16 214 synchroniser.updateOutputSpeed();
andrew@16 215
andrew@11 216 bayesianStruct.projectDistribution(newTime, currentAlignmentPosition, projectedPrior);//prior gets updated to where we are now
andrew@32 217
andrew@32 218 // printf("updateBestAlignment:: alignment %i:: %i\n", newTime, (int) currentAlignmentPosition);
andrew@11 219
andrew@10 220 // 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 221 }
andrew@8 222
andrew@0 223 void AudioEventMatcher::draw(){
andrew@32 224
andrew@32 225 //MAIN DRAW FUNCTION FOR ALL
andrew@32 226
andrew@6 227 //draw some outlines in blue
andrew@3 228 ofSetColor(20,200,200);
andrew@3 229 bayesPositionWindow.drawOutline();
andrew@3 230 bayesTempoWindow.drawOutline();
andrew@0 231
andrew@6 232 //draw the scrolling audio tracks
andrew@1 233 recordedTracks.drawTracks();
andrew@7 234
andrew@2 235 ofSetColor(255);
andrew@2 236 // bayesianStruct.relativeSpeedPrior.drawVector(0, 200, bayesTempoWindow);
andrew@9 237
andrew@9 238 setScreenDisplayTimes();
andrew@6 239 drawBayesianDistributions();
andrew@8 240
andrew@11 241 //bayesianStruct.posterior.drawVector(0, bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow);
andrew@6 242 //bayesianStruct.posterior.drawVector(bayesianStruct.posterior.getRealTermsAsIndex(0), bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow);
andrew@11 243 //bayesianStruct.relativeSpeedPosterior.drawVector(0, bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(2), bayesTempoWindow);
andrew@9 244
andrew@20 245 temporal.drawTempoArray(bayesLikelihoodWindow);
andrew@20 246
andrew@20 247 drawRecordedTempo();
andrew@20 248 drawPlayingTempo();
andrew@20 249
andrew@20 250
andrew@6 251 }
andrew@20 252
andrew@20 253 void AudioEventMatcher::drawRecordedTempo(){
andrew@6 254
andrew@21 255 int xTempoIndex = ofGetWidth() * (double)(recordedTempo - recordedTempoData.minimumTempoInterval)/(double)(recordedTempoData.maximumTempoInterval - recordedTempoData.minimumTempoInterval);
andrew@20 256 ofSetColor(0, 200, 0);
andrew@20 257 ofLine(xTempoIndex, bayesLikelihoodWindow.y, xTempoIndex, bayesLikelihoodWindow.y + bayesLikelihoodWindow.height);
andrew@20 258 ofDrawBitmapString(ofToString(recordedTempo), xTempoIndex, bayesLikelihoodWindow.y + 10);
andrew@20 259 }
andrew@20 260
andrew@20 261 void AudioEventMatcher::drawPlayingTempo(){
andrew@21 262 //purple line for MAP estimate of new intervals
andrew@21 263 int xTempoIndex = (double)(ofGetWidth() * (temporal.playingTempo - temporal.minimumTempoInterval))/(double)(temporal.maximumTempoInterval - temporal.minimumTempoInterval);
andrew@20 264 ofSetColor(200, 0, 200);
andrew@20 265 ofLine(xTempoIndex, bayesLikelihoodWindow.y, xTempoIndex, bayesLikelihoodWindow.y + bayesLikelihoodWindow.height);
andrew@21 266 ofDrawBitmapString(ofToString(temporal.playingTempo), xTempoIndex, bayesLikelihoodWindow.y + 10);
andrew@20 267
andrew@21 268 //red line where the ratio is between playing tempo and recorded one
andrew@20 269 int xSpeedRatioIndex = (double)(temporal.tempoPosterior.getIndexInRealTerms(currentSpeedRatio)*ofGetWidth())/(double)temporal.tempoPosterior.arraySize;
andrew@20 270 ofSetColor(200,0,0);
andrew@20 271 ofLine(xSpeedRatioIndex, bayesTempoWindow.y, xSpeedRatioIndex, bayesTempoWindow.y + bayesTempoWindow.height);
andrew@21 272 string tmpString = "playing "+ofToString(temporal.playingTempo);
andrew@21 273 tmpString += ", recorded "+ofToString(recordedTempo);
andrew@21 274 tmpString += " ratio "+ofToString(currentSpeedRatio);
andrew@21 275 ofSetColor(155,155,155);
andrew@21 276 ofDrawBitmapString(tmpString, 20, bayesTempoWindow.y+10);
andrew@20 277
andrew@20 278 }
andrew@20 279
andrew@20 280
andrew@9 281 void AudioEventMatcher::setScreenDisplayTimes(){
andrew@9 282 screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber);
andrew@9 283 // if (!followingLiveInput){
andrew@9 284
andrew@9 285 screenStartTimeMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.drawParams.windowStartFrame);
andrew@9 286 screenEndTimeMillis = screenStartTimeMillis + screenWidthMillis;
andrew@9 287
andrew@9 288 //need PRECISION in this alignment
andrew@9 289
andrew@9 290
andrew@9 291 /*}else{
andrew@9 292
andrew@9 293 screenStartTimeMillis = (int)(currentAlignmentPosition/screenWidthMillis) * screenWidthMillis;
andrew@9 294 screenEndTimeMillis = screenStartTimeMillis + screenWidthMillis;
andrew@9 295 }*/
andrew@9 296 }
andrew@9 297
andrew@6 298 void AudioEventMatcher::drawBayesianDistributions(){
andrew@6 299
andrew@32 300
andrew@32 301 drawPositionWindow();
andrew@4 302
andrew@8 303 // bayesianStruct.likelihood.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesLikelihoodWindow);
andrew@2 304
andrew@6 305 bayesianStruct.relativeSpeedPosterior.drawConstrainedVector(0, bayesianStruct.relativeSpeedPosterior.arraySize, 0, ofGetWidth(), bayesTempoWindow);
andrew@32 306
andrew@6 307
andrew@32 308 drawTrackLikelihoods();
andrew@32 309
andrew@32 310 // int priorStartIndex = bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis);
andrew@32 311 // int priorEndIndex = bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis);
andrew@32 312 // ofSetColor(0,200,200);//recent prior
andrew@32 313 // recentPrior.drawConstrainedVector(priorStartIndex, priorEndIndex, 0, ofGetWidth(), bayesPositionWindow);
andrew@32 314
andrew@32 315 drawInfo();
andrew@32 316
andrew@3 317
andrew@32 318 }
andrew@32 319
andrew@32 320 void AudioEventMatcher::drawPositionWindow(){
andrew@32 321 int startIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenStartTimeMillis);
andrew@32 322 int endIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenEndTimeMillis);
andrew@32 323 string tmpString = "start "+ofToString(screenStartTimeMillis)+" (index "+ofToString(startIndex)+"), end "+ofToString(screenEndTimeMillis);
andrew@32 324 ofDrawBitmapString(tmpString, bayesPositionWindow.x+20, bayesPositionWindow.y+20);
andrew@32 325
andrew@32 326 //draw posterior in the bayes position window
andrew@32 327 ofSetColor(255,0,255);
andrew@32 328 bayesianStruct.posterior.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesPositionWindow);
andrew@3 329
andrew@9 330 //green line at current best estimate
andrew@13 331 ofSetColor(0,255,0);//green scrolling line best position
andrew@8 332 double currentEstimateIndex = (currentAlignmentPosition - screenStartTimeMillis)*ofGetWidth()/screenWidthMillis;
andrew@8 333 ofLine(currentEstimateIndex, bayesPositionWindow.y, currentEstimateIndex, bayesPositionWindow.y + bayesPositionWindow.height);
andrew@7 334
andrew@32 335
andrew@16 336 ofSetColor(0,255,255);//synchroniser position
andrew@16 337 currentEstimateIndex = (synchroniser.playingPositionMillis - screenStartTimeMillis)*ofGetWidth()/screenWidthMillis;
andrew@16 338 ofLine(currentEstimateIndex, bayesLikelihoodWindow.y, currentEstimateIndex, bayesLikelihoodWindow.y + bayesPositionWindow.height);
andrew@32 339
andrew@32 340 ofSetColor(255,0,100);//purple prior
andrew@32 341 bayesianStruct.prior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesPositionWindow);
andrew@16 342
andrew@32 343 ofSetColor(255,0,0);//projected prior in red
andrew@32 344 projectedPrior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesPositionWindow);
andrew@16 345
andrew@16 346
andrew@32 347
andrew@32 348 }
andrew@32 349
andrew@32 350 void AudioEventMatcher::drawTrackLikelihoods(){
andrew@7 351 //draw track by track likelihoods
andrew@7 352 for (int i = 0; i <recordedTracks.numberOfAudioTracks;i++){
andrew@13 353 ofSetColor(200,255,50);//channel likelihoods in yellow
andrew@8 354 likelihoodVisualisation[i].drawConstrainedVector(likelihoodVisualisation[i].getRealTermsAsIndex(screenStartTimeMillis), likelihoodVisualisation[i].getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), recordedTracks.loadedAudioFiles[i].fileLoader.onsetDetect.window);
andrew@11 355
andrew@13 356 ofSetColor(0,255,150);//channel priors
andrew@11 357 recentPriors[i].drawConstrainedVector(recentPriors[i].getRealTermsAsIndex(screenStartTimeMillis), recentPriors[i].getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), recordedTracks.loadedAudioFiles[i].fileLoader.onsetDetect.window);
andrew@11 358
andrew@11 359
andrew@8 360 ofSetColor(255);
andrew@8 361 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@7 362 }
andrew@32 363 }
andrew@8 364
andrew@8 365
andrew@32 366 void AudioEventMatcher::drawInfo(){
andrew@32 367 string tmpStr = "zero is "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(0));
andrew@32 368 tmpStr += " offsetis "+ofToString(bayesianStruct.posterior.offset);
andrew@32 369 tmpStr += " screenWidth = "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis));
andrew@32 370 ofDrawBitmapString(tmpStr, 20,140);
andrew@32 371 tmpStr = "best est "+ofToString(bayesianStruct.bestEstimate);
andrew@32 372 ofDrawBitmapString(tmpStr, 20, 180);
andrew@32 373 ofDrawBitmapString("screenwidth "+ofToString(screenWidthMillis), 20, 800);
andrew@11 374
andrew@32 375 ofSetColor(255);
andrew@32 376 tmpStr = "pitch "+ofToString(recentPitch, 2);
andrew@32 377 tmpStr += " Nearest "+ofToString(pitchOfNearestMatch,2);
andrew@32 378 tmpStr += " dist "+ofToString(distanceOfNearestMatch, 2);
andrew@32 379 tmpStr += ", Time "+ofToString(recentTime, 0);
andrew@32 380 ofDrawBitmapString(tmpStr, 20, 20);
andrew@7 381
andrew@32 382 string alignString = " align "+ofToString(currentAlignmentPosition, 2);
andrew@32 383 alignString += " playing "+ofToString(synchroniser.playingPositionRatio, 5);
andrew@32 384 alignString += " pos "+ofToString(synchroniser.playingPositionMillis,0)+" ms";
andrew@32 385 alignString += " rec pos "+ofToString(synchroniser.recordedPositionMillis,0)+" ms";
andrew@32 386 ofDrawBitmapString(alignString, 20, 50);
andrew@20 387
andrew@32 388 ofDrawBitmapString("pos "+ofToString(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.playPosition), 200,600);
andrew@19 389
andrew@1 390 }
andrew@1 391
andrew@6 392 void AudioEventMatcher::newPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){
andrew@7 393 if (pitchIn > 0){
andrew@1 394 liveInput.addPitchEvent(pitchIn, timeIn);
andrew@4 395
andrew@10 396 //printPosteriorMAPinfo();
andrew@11 397
andrew@7 398 matchNewPitchEvent(channel, pitchIn, timeIn);//main pitch matching fn
andrew@7 399
andrew@7 400 likelihoodVisualisation[1] = bayesianStruct.likelihood;
andrew@7 401
andrew@7 402 recentPitch = pitchIn;//for drawing
andrew@7 403 recentTime = timeIn;
andrew@7 404 }
andrew@32 405 }
andrew@32 406
andrew@32 407
andrew@32 408 void AudioEventMatcher::newChromaEvent(const int& channel, float* chromaIn, const double& timeIn){
andrew@32 409
andrew@32 410 // could add event to the liveInput list? as in pitch event
andrew@34 411 printf("match chroma channel %i\n", channel);
andrew@34 412 for (int i = 0;i < 12;i++){
andrew@34 413 printf("chroma in[%i] = %f\n", i, chromaIn[i]);
andrew@34 414 }
andrew@34 415
andrew@32 416 matchNewChromaEvent(channel, chromaIn, timeIn);//main pitch matching fn
andrew@32 417
andrew@32 418 likelihoodVisualisation[channel] = bayesianStruct.likelihood;
andrew@32 419
andrew@8 420
andrew@2 421 }
andrew@2 422
andrew@32 423
andrew@6 424 void AudioEventMatcher::newKickEvent(const double& timeIn){
andrew@6 425 // liveInput.addKickEvent(timeIn);
andrew@2 426 matchNewOnsetEvent(0, timeIn);
andrew@7 427 likelihoodVisualisation[0] = bayesianStruct.likelihood;
andrew@2 428 }
andrew@2 429
andrew@6 430 void AudioEventMatcher::newKickEvent(const int& channel, const double& timeIn){
andrew@6 431 // liveInput.addKickEvent(timeIn);
andrew@6 432 matchNewOnsetEvent(channel, timeIn);
andrew@7 433 likelihoodVisualisation[0] = bayesianStruct.likelihood;
andrew@6 434 }
andrew@6 435
andrew@2 436
andrew@2 437 void AudioEventMatcher::newSnareEvent(const double& timeIn){
andrew@6 438 matchNewOnsetEvent(2, timeIn);
andrew@7 439 likelihoodVisualisation[2] = bayesianStruct.likelihood;
andrew@7 440 }
andrew@7 441
andrew@7 442
andrew@7 443 void AudioEventMatcher::newSnareEvent(const int& channel, const double& timeIn){
andrew@7 444 matchNewOnsetEvent(channel, timeIn);
andrew@7 445 likelihoodVisualisation[2] = bayesianStruct.likelihood;
andrew@2 446 }
andrew@2 447
andrew@2 448 //Needs just to set bounds for the matching process, not have TimeIn
andrew@2 449 void AudioEventMatcher::matchNewOnsetEvent(const int& channel, const double& timeIn){
andrew@3 450
andrew@6 451 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
andrew@10 452
andrew@2 453 //start at beginning but OPTIMISE later
andrew@2 454 bayesianStruct.likelihood.offset = bayesianStruct.prior.offset;
andrew@2 455 bayesianStruct.likelihood.zero();//set to zero
andrew@36 456 //double quantity = 1;//
andrew@36 457 double quantity = 1*onsetLikelihoodToNoise;//BETTER CHANGE THIS BACK TOO..see below//likelihoodToNoiseRatio / numberOfMatches;
andrew@2 458 int numberOfMatchesFound = 0;
andrew@2 459
andrew@10 460 double startMatchingTime = bayesianStruct.likelihood.offset;
andrew@10 461 double endMatchingTime = bayesianStruct.likelihood.offset + matchWindowWidth;
andrew@32 462 double millisTime = -1*INFINITY;//or 0 is fine
andrew@32 463 int checkIndex = 0;
andrew@36 464 if (channel <= recordedTracks.numberOfAudioTracks && checkIndex < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){
andrew@32 465 while (millisTime < startMatchingTime) {
andrew@32 466 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[checkIndex].millisTime;
andrew@32 467 checkIndex++;
andrew@32 468 }
andrew@32 469 for (int i = checkIndex;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size() && millisTime <= endMatchingTime;i++){
andrew@32 470 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
andrew@10 471 if (millisTime >= startMatchingTime && millisTime <= endMatchingTime){
andrew@14 472 bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, onsetLikelihoodWidth, quantity);
andrew@2 473 numberOfMatchesFound++;
andrew@6 474 // printf("Adding Gaussian for onset at time %f offset %f\n", millisTime, bayesianStruct.likelihood.offset);
andrew@2 475
andrew@32 476 }//end if within limits (changed so it now is 4 sure)
andrew@2 477 }
andrew@2 478 }
andrew@2 479
andrew@11 480 if (numberOfMatchesFound > 0){
andrew@3 481 // bayesianStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesianStruct.likelihood.length);
andrew@36 482 // bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-onsetLikelihoodToNoise)/(onsetLikelihoodToNoise*bayesianStruct.likelihood.length));
andrew@36 483 bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-onsetLikelihoodToNoise)/(bayesianStruct.likelihood.length));//BETTER CHANGE THIS BACK...
andrew@2 484 bayesianStruct.likelihood.renormalise();
andrew@2 485
andrew@8 486 bayesianStruct.calculatePosterior();
andrew@10 487 lastAlignmentTime = timeIn;//use TIMESTAMP
andrew@10 488 recentEventTime[channel] = timeIn;//ofGetElapsedTimeMillis() - startTime;
andrew@11 489
andrew@11 490 recentPriors[channel] = bayesianStruct.prior;
andrew@13 491 projectedPrior = bayesianStruct.prior;
andrew@19 492
andrew@19 493
andrew@19 494 temporal.updateTempo(channel, timeIn);
andrew@11 495 }
andrew@11 496
andrew@3 497 }
andrew@3 498
andrew@3 499
andrew@3 500
andrew@3 501 void AudioEventMatcher::matchNewPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){
andrew@3 502 //start at beginning but OPTIMISE later
andrew@10 503 /*printf("TIME %i\n", ofGetElapsedTimeMillis());
andrew@10 504 //tmp debug
andrew@10 505 updateBestAlignmentPosition();
andrew@10 506 printf("current alignment best estimate %f\n", currentAlignmentPosition);
andrew@10 507 */
andrew@6 508 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
andrew@8 509
andrew@7 510 //set the lielihoods by matching the pitched note
andrew@7 511
andrew@15 512
andrew@3 513 int numberOfMatches = 0;
andrew@3 514 bayesianStruct.likelihood.zero();//set to zero
andrew@18 515 double newOnsetTime;
andrew@18 516 double closestDistance = INFINITY;
andrew@3 517
andrew@3 518 double quantity = 0;
andrew@32 519 double totalLikelihoodAdded = 0;
andrew@3 520 if (channel <= recordedTracks.numberOfAudioTracks){
andrew@3 521 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){
andrew@3 522
andrew@3 523 if (checkMatch(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn)) {
andrew@32 524 quantity = getPitchDistance(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn, 12);
andrew@18 525
andrew@3 526 bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, 30, quantity);
andrew@3 527 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = true;
andrew@3 528 numberOfMatches++;
andrew@32 529 totalLikelihoodAdded += quantity;
andrew@3 530 }
andrew@3 531 else{
andrew@3 532 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = false;
andrew@3 533 }
andrew@18 534 //checking nearest pitch
andrew@18 535 newOnsetTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
andrew@18 536 if (abs(newOnsetTime - currentAlignmentPosition) < closestDistance){
andrew@18 537 closestDistance = abs(newOnsetTime - currentAlignmentPosition);
andrew@18 538 pitchOfNearestMatch = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch;
andrew@18 539 distanceOfNearestMatch = quantity;
andrew@18 540 }
andrew@3 541
andrew@3 542 }
andrew@3 543 }
andrew@6 544
andrew@8 545
andrew@8 546
andrew@6 547 if (numberOfMatches > 0){//no point updating unless there is a match
andrew@32 548 //replacing numberOfMatches with totalLike below...
andrew@32 549 bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-pitchLikelihoodToNoise)/(pitchLikelihoodToNoise*bayesianStruct.likelihood.length));
andrew@4 550
andrew@4 551 //tmp set likelihood constant and calculate using that
andrew@6 552 //bayesianStruct.likelihood.zero();
andrew@6 553 //bayesianStruct.likelihood.addConstant(1);
andrew@7 554
andrew@6 555 bayesianStruct.calculatePosterior();
andrew@11 556 lastAlignmentTime = timeIn;//has to use the STAMPED time
andrew@11 557 recentEventTime[channel] = timeIn;
andrew@11 558
andrew@11 559 recentPriors[channel] = bayesianStruct.prior;
andrew@13 560 projectedPrior = bayesianStruct.prior;
andrew@19 561
andrew@19 562 temporal.eventTimes[channel].push_back(timeIn);
andrew@6 563 }
andrew@4 564
andrew@11 565
andrew@1 566 }
andrew@1 567
andrew@3 568 double AudioEventMatcher::getPitchDistance(const double& pitchOne, const double& pitchTwo, const double& scale){
andrew@3 569
andrew@18 570 double scaleFactor = scale * pitchOne / 110.0;
andrew@16 571
andrew@18 572 int multiplicationFactor = 1;
andrew@18 573 if (pitchTwo > 0){
andrew@32 574 multiplicationFactor = round(pitchOne/pitchTwo);
andrew@18 575 }
andrew@16 576
andrew@18 577 double distance = abs(pitchOne - pitchTwo*multiplicationFactor);
andrew@16 578 if (distance < scaleFactor)
andrew@16 579 distance = 1 - (distance/scaleFactor);
andrew@3 580 else
andrew@3 581 distance = 0;
andrew@3 582
andrew@32 583 //printf("[pitch distance %f vs %f, factor %i = %f\n", pitchOne, pitchTwo, multiplicationFactor, distance);
andrew@3 584 return distance;
andrew@3 585
andrew@3 586 }
andrew@3 587
andrew@3 588
andrew@3 589 bool AudioEventMatcher::checkMatch(const double& recordedPitch, const double& livePitch){
andrew@18 590
andrew@18 591 if (livePitch > 0){
andrew@18 592 int multiplicationFactor = (int)(round(recordedPitch/livePitch));
andrew@18 593
andrew@32 594 if (abs(recordedPitch - livePitch * multiplicationFactor) < pitchCutOff)
andrew@3 595 return true;
andrew@3 596 else
andrew@3 597 return false;
andrew@18 598 }else {
andrew@18 599 return false;
andrew@18 600 }
andrew@18 601
andrew@3 602 }
andrew@3 603
andrew@3 604
andrew@32 605 void AudioEventMatcher::matchNewChromaEvent(const int& channel, float* chromaIn, const double& timeIn){
andrew@32 606 //start at beginning but OPTIMISE later
andrew@32 607
andrew@32 608 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
andrew@32 609
andrew@32 610 //set the likelihoods by matching the pitched note
andrew@32 611
andrew@32 612 int numberOfMatches = 0;
andrew@32 613 bayesianStruct.likelihood.zero();//set to zero
andrew@32 614 double newOnsetTime;
andrew@32 615 double closestDistance = INFINITY;
andrew@32 616
andrew@32 617 double quantity = 1;
andrew@32 618 double totalLikelihoodAdded = 0;
andrew@32 619
andrew@32 620 double startMatchingTime = bayesianStruct.likelihood.offset;
andrew@32 621 double endMatchingTime = bayesianStruct.likelihood.offset + matchWindowWidth;
andrew@32 622 double millisTime = -1*INFINITY;//or 0 is fine
andrew@32 623
andrew@32 624 int checkIndex = 0;
andrew@32 625 if (channel <= recordedTracks.numberOfAudioTracks){
andrew@32 626 while (millisTime < startMatchingTime) {
andrew@32 627 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[checkIndex].millisTime;
andrew@32 628 checkIndex++;
andrew@32 629 }//go up to where we need to check from fast
andrew@32 630
andrew@32 631 for (int i = checkIndex;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size() && millisTime <= endMatchingTime;i++){
andrew@32 632 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
andrew@32 633
andrew@32 634 if (millisTime >= startMatchingTime && millisTime <= endMatchingTime){
andrew@35 635
andrew@35 636 if (useChromaDotProduct)
andrew@35 637 quantity = getChromaDotProductDistance(chromaIn, &recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].chromaValues[0]);
andrew@35 638 else
andrew@35 639 quantity = getChromaEuclideanDistance(chromaIn, &recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].chromaValues[0]);
andrew@35 640
andrew@35 641
andrew@32 642 bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, chromaLikelihoodWidth, quantity);
andrew@32 643
andrew@32 644 // bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, onsetLikelihoodWidth, quantity);
andrew@32 645 numberOfMatches++;
andrew@32 646 totalLikelihoodAdded += quantity;
andrew@32 647 printf("Adding CHROMA Gaussian for onset at time %.1f dist %.3f\n", millisTime, quantity);
andrew@32 648
andrew@32 649 }//end if within limits (changed so it now is 4 sure)
andrew@32 650 }
andrew@32 651 }
andrew@32 652
andrew@32 653
andrew@32 654 if (numberOfMatches > 0){//no point updating unless there is a match
andrew@32 655 //replacing numberOfMatches with totalLike below...
andrew@32 656
andrew@32 657 printf("CHROMA HAS %i MATCHES\n", numberOfMatches);
andrew@32 658
andrew@32 659 bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-chromaLikelihoodToNoise)/(chromaLikelihoodToNoise*bayesianStruct.likelihood.length));
andrew@32 660
andrew@32 661 bayesianStruct.calculatePosterior();
andrew@32 662 lastAlignmentTime = timeIn;//has to use the STAMPED time
andrew@32 663 recentEventTime[channel] = timeIn;
andrew@32 664
andrew@32 665 recentPriors[channel] = bayesianStruct.prior;
andrew@32 666 projectedPrior = bayesianStruct.prior;
andrew@32 667
andrew@32 668 temporal.eventTimes[channel].push_back(timeIn);
andrew@32 669 }
andrew@32 670
andrew@32 671 }
andrew@32 672
andrew@32 673
andrew@35 674 double AudioEventMatcher::getChromaDotProductDistance(float* chromaOne, float* chromaTwo){
andrew@32 675 double distance = 0;
andrew@32 676 double total = 0;
andrew@32 677 for (int i = 0;i < 12;i++){
andrew@32 678 distance += chromaOne[i]*chromaTwo[i];
andrew@32 679 total += chromaOne[i]*chromaOne[i] + (chromaTwo[i]*chromaTwo[i]);
andrew@32 680 }
andrew@32 681
andrew@35 682 if (total > 0)
andrew@35 683 distance /= sqrt(total);
andrew@35 684
andrew@35 685 return distance;
andrew@35 686 }
andrew@35 687
andrew@35 688 double AudioEventMatcher::getChromaEuclideanDistance(float* chromaOne, float* chromaTwo){
andrew@35 689 double distance = 0;
andrew@35 690 double total = 0;
andrew@35 691 // printf("\n");
andrew@35 692 for (int i = 0;i < 12;i++){
andrew@35 693 total += (chromaOne[i] - chromaTwo[i])*(chromaOne[i] - chromaTwo[i]);
andrew@35 694 // printf("chroma1: %.2f; chroma2: %.2f\n", chromaOne[i], chromaTwo[i]);
andrew@35 695 // total += chromaOne[i]*chromaOne[i] + (chromaTwo[i]*chromaTwo[i]);
andrew@35 696 }
andrew@35 697
andrew@35 698 if (total > 0)
andrew@35 699 distance = 1.0/sqrt(total);
andrew@35 700 // printf("DISTANCE : %.3f\n", distance);
andrew@32 701 return distance;
andrew@32 702 }
andrew@1 703
andrew@1 704 void AudioEventMatcher::windowResized(const int& w, const int& h){
andrew@1 705 recordedTracks.windowResized(w,h);
andrew@3 706 bayesTempoWindow.resized(w,h);
andrew@3 707 bayesPositionWindow.resized(w,h);
andrew@3 708 }
andrew@3 709
andrew@10 710 /*
andrew@10 711
andrew@10 712 void printPosteriorMAPinfo(){ //tmp print stuff
andrew@10 713 printf("New pitch MAP post estimate now %i, ", bayesianStruct.posterior.MAPestimate);
andrew@10 714 double tmp = bayesianStruct.posterior.getMAPestimate();
andrew@10 715 printf(" getting it %f and offset %f == %f ms\n", tmp, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(tmp));
andrew@10 716
andrew@10 717 }
andrew@10 718 */
andrew@3 719