annotate src/AudioEventMatcher.cpp @ 8:572564b7cb85

added calculation posterior into both onset and pitch processes
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Fri, 03 Feb 2012 13:28:59 +0000
parents 33dedfe32893
children bc62266af280
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@2 13 const int matchWindowWidth = 6000;
andrew@0 14
andrew@0 15 AudioEventMatcher::AudioEventMatcher(){
andrew@7 16
andrew@0 17 setArraySizes();
andrew@3 18
andrew@3 19 usingRealTime = false;
andrew@3 20 bayesianStruct.realTimeMode = &usingRealTime;
andrew@7 21 recentPitch = 0;
andrew@8 22 currentAlignmentPosition = 0;
andrew@0 23 }
andrew@0 24
andrew@7 25 void AudioEventMatcher::setWindowDimensions(){
andrew@7 26 double startHeight = recordedTracks.numberOfAudioTracks * recordedTracks.trackScreenHeight;
andrew@7 27 double heightAvailable = 1 - startHeight;
andrew@7 28 heightAvailable /= 3.0;
andrew@7 29
andrew@7 30 bayesPositionWindow.setToRelativeSize(0, startHeight, 1, heightAvailable);
andrew@7 31 bayesLikelihoodWindow.setToRelativeSize(0, startHeight + 1*heightAvailable, 1, heightAvailable);
andrew@7 32 bayesTempoWindow.setToRelativeSize(0, startHeight + 2*heightAvailable, 1, heightAvailable);
andrew@7 33
andrew@7 34
andrew@7 35 }
andrew@0 36
andrew@0 37 void AudioEventMatcher::setArraySizes(){
andrew@0 38 bayesianStruct.resetSpeedSize(200);
andrew@0 39 bayesianStruct.setRelativeSpeedScalar(0.01);
andrew@0 40 bayesianStruct.setSpeedPrior(1.0);
andrew@0 41 bayesianStruct.relativeSpeedPrior.getMaximum();
andrew@0 42
andrew@0 43 bayesianStruct.resetSize(matchWindowWidth);
andrew@0 44 bayesianStruct.setPositionDistributionScalar(1);
andrew@0 45
andrew@0 46 }
andrew@0 47
andrew@3 48 void AudioEventMatcher::startPlaying(){
andrew@3 49 bayesianStruct.setStartPlaying();
andrew@8 50 currentAlignmentPosition = 0;
andrew@8 51 startTime = ofGetElapsedTimeMillis();
andrew@3 52 //bayesianStruct.posterior.printArray();
andrew@3 53 }
andrew@3 54
andrew@8 55 void AudioEventMatcher::updateBestAlignmentPosition(){
andrew@8 56 currentAlignmentPosition = bayesianStruct.posterior.offset + bayesianStruct.posterior.getIndexInRealTerms(bayesianStruct.posterior.MAPestimate);
andrew@8 57 currentAlignmentPosition += (ofGetElapsedTimeMillis() - lastAlignmentTime) * bayesianStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesianStruct.relativeSpeedPosterior.MAPestimate);
andrew@8 58 }
andrew@8 59
andrew@0 60 void AudioEventMatcher::draw(){
andrew@6 61 //draw some outlines in blue
andrew@3 62 ofSetColor(20,200,200);
andrew@3 63 bayesPositionWindow.drawOutline();
andrew@3 64 bayesTempoWindow.drawOutline();
andrew@0 65
andrew@6 66 //draw the scrolling audio tracks
andrew@1 67 recordedTracks.drawTracks();
andrew@7 68
andrew@7 69
andrew@2 70
andrew@2 71 ofSetColor(255);
andrew@2 72 // bayesianStruct.relativeSpeedPrior.drawVector(0, 200, bayesTempoWindow);
andrew@2 73
andrew@6 74 drawBayesianDistributions();
andrew@8 75
andrew@6 76 // bayesianStruct.posterior.drawVector(0, bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow);
andrew@6 77
andrew@6 78 //bayesianStruct.posterior.drawVector(bayesianStruct.posterior.getRealTermsAsIndex(0), bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow);
andrew@6 79
andrew@6 80 // bayesianStruct.relativeSpeedPosterior.drawVector(0, bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(2), bayesTempoWindow);
andrew@6 81
andrew@7 82 ofDrawBitmapString("pitch "+ofToString(recentPitch, 2)+", Time "+ofToString(recentTime, 0), 20, 20);
andrew@6 83 }
andrew@6 84
andrew@6 85 void AudioEventMatcher::drawBayesianDistributions(){
andrew@6 86
andrew@6 87
andrew@2 88 double screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber);
andrew@2 89
andrew@6 90
andrew@6 91 double screenStartTimeMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.drawParams.windowStartFrame);
andrew@6 92 double screenEndTimeMillis = screenStartTimeMillis + screenWidthMillis;
andrew@6 93 int startIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenStartTimeMillis);
andrew@6 94 int endIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenEndTimeMillis);
andrew@4 95
andrew@6 96 bayesianStruct.posterior.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesPositionWindow);
andrew@6 97
andrew@6 98 string tmpString = "start "+ofToString(screenStartTimeMillis)+" (index "+ofToString(startIndex)+"), end "+ofToString(screenEndTimeMillis);
andrew@6 99 ofDrawBitmapString(tmpString, bayesPositionWindow.x+20, bayesPositionWindow.y+20);
andrew@4 100
andrew@8 101 // bayesianStruct.likelihood.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesLikelihoodWindow);
andrew@2 102
andrew@6 103 bayesianStruct.relativeSpeedPosterior.drawConstrainedVector(0, bayesianStruct.relativeSpeedPosterior.arraySize, 0, ofGetWidth(), bayesTempoWindow);
andrew@6 104
andrew@3 105 string tmpStr = "zero is "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(0));
andrew@3 106 tmpStr += " offsetis "+ofToString(bayesianStruct.posterior.offset);
andrew@3 107 tmpStr += " screenWidth = "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis));
andrew@3 108 ofDrawBitmapString(tmpStr, 20,140);
andrew@3 109 tmpStr = "best est "+ofToString(bayesianStruct.bestEstimate);
andrew@3 110 ofDrawBitmapString(tmpStr, 20, 180);
andrew@3 111
andrew@8 112 ofDrawBitmapString("screenwidth "+ofToString(screenWidthMillis), 20, 800);
andrew@3 113
andrew@8 114 ofSetColor(0,255,0);
andrew@8 115 double currentEstimateIndex = (currentAlignmentPosition - screenStartTimeMillis)*ofGetWidth()/screenWidthMillis;
andrew@8 116 ofLine(currentEstimateIndex, bayesPositionWindow.y, currentEstimateIndex, bayesPositionWindow.y + bayesPositionWindow.height);
andrew@7 117
andrew@7 118 //draw track by track likelihoods
andrew@7 119 for (int i = 0; i <recordedTracks.numberOfAudioTracks;i++){
andrew@7 120 ofSetColor(200,255,50);
andrew@8 121 likelihoodVisualisation[i].drawConstrainedVector(likelihoodVisualisation[i].getRealTermsAsIndex(screenStartTimeMillis), likelihoodVisualisation[i].getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), recordedTracks.loadedAudioFiles[i].fileLoader.onsetDetect.window);
andrew@8 122 ofSetColor(255);
andrew@8 123 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 124 }
andrew@8 125
andrew@8 126 int priorStartIndex = recentPrior.getRealTermsAsIndex(screenStartTimeMillis);
andrew@8 127 int priorEndIndex = recentPrior.getRealTermsAsIndex(screenEndTimeMillis);
andrew@8 128 ofSetColor(0,200,200);
andrew@8 129 recentPrior.drawConstrainedVector(priorStartIndex, priorEndIndex, 0, ofGetWidth(), bayesPositionWindow);
andrew@8 130
andrew@8 131 // bayesianStruct.prior.addTriangularShape(100, 20, 0.4);
andrew@8 132 ofSetColor(255,0,100);
andrew@8 133 bayesianStruct.prior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesLikelihoodWindow);
andrew@7 134
andrew@1 135 }
andrew@1 136
andrew@6 137 void AudioEventMatcher::newPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){
andrew@7 138 if (pitchIn > 0){
andrew@1 139 liveInput.addPitchEvent(pitchIn, timeIn);
andrew@4 140
andrew@4 141 //tmp print stuff
andrew@4 142 printf("New pitch MAP post estimate now %i, ", bayesianStruct.posterior.MAPestimate);
andrew@4 143 double tmp = bayesianStruct.posterior.getMAPestimate();
andrew@4 144 printf(" getting it %f and offset %f == %f ms\n", tmp, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(tmp));
andrew@4 145
andrew@7 146 matchNewPitchEvent(channel, pitchIn, timeIn);//main pitch matching fn
andrew@7 147
andrew@7 148 likelihoodVisualisation[1] = bayesianStruct.likelihood;
andrew@7 149
andrew@7 150 recentPitch = pitchIn;//for drawing
andrew@7 151 recentTime = timeIn;
andrew@7 152 }
andrew@8 153
andrew@8 154
andrew@2 155 }
andrew@2 156
andrew@6 157 void AudioEventMatcher::newKickEvent(const double& timeIn){
andrew@6 158 // liveInput.addKickEvent(timeIn);
andrew@2 159 matchNewOnsetEvent(0, timeIn);
andrew@7 160 likelihoodVisualisation[0] = bayesianStruct.likelihood;
andrew@2 161 }
andrew@2 162
andrew@6 163 void AudioEventMatcher::newKickEvent(const int& channel, const double& timeIn){
andrew@6 164 // liveInput.addKickEvent(timeIn);
andrew@6 165 matchNewOnsetEvent(channel, timeIn);
andrew@7 166 likelihoodVisualisation[0] = bayesianStruct.likelihood;
andrew@6 167 }
andrew@6 168
andrew@2 169
andrew@2 170 void AudioEventMatcher::newSnareEvent(const double& timeIn){
andrew@6 171 matchNewOnsetEvent(2, timeIn);
andrew@7 172 likelihoodVisualisation[2] = bayesianStruct.likelihood;
andrew@7 173 }
andrew@7 174
andrew@7 175
andrew@7 176 void AudioEventMatcher::newSnareEvent(const int& channel, const double& timeIn){
andrew@7 177 matchNewOnsetEvent(channel, timeIn);
andrew@7 178 likelihoodVisualisation[2] = bayesianStruct.likelihood;
andrew@2 179 }
andrew@2 180
andrew@2 181 //Needs just to set bounds for the matching process, not have TimeIn
andrew@2 182 void AudioEventMatcher::matchNewOnsetEvent(const int& channel, const double& timeIn){
andrew@3 183
andrew@3 184
andrew@6 185 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
andrew@6 186
andrew@2 187 //start at beginning but OPTIMISE later
andrew@8 188 double onsetLikelihoodToNoise = 0.5;
andrew@2 189
andrew@2 190 double likelihoodWidth = 40;
andrew@2 191
andrew@2 192 bayesianStruct.likelihood.offset = bayesianStruct.prior.offset;
andrew@2 193 bayesianStruct.likelihood.zero();//set to zero
andrew@2 194
andrew@2 195 double quantity = 1;//likelihoodToNoiseRatio / numberOfMatches;
andrew@2 196 int numberOfMatchesFound = 0;
andrew@2 197
andrew@2 198
andrew@2 199 double startTime = bayesianStruct.likelihood.offset;
andrew@2 200 double endTime = bayesianStruct.likelihood.offset + matchWindowWidth;
andrew@2 201
andrew@2 202 if (channel <= recordedTracks.numberOfAudioTracks){
andrew@2 203 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){
andrew@2 204 double millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
andrew@2 205 if (millisTime >= startTime && millisTime <= endTime){
andrew@2 206 bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, likelihoodWidth, quantity);
andrew@2 207 numberOfMatchesFound++;
andrew@6 208 // printf("Adding Gaussian for onset at time %f offset %f\n", millisTime, bayesianStruct.likelihood.offset);
andrew@2 209
andrew@2 210 }
andrew@2 211 }
andrew@2 212 }
andrew@2 213
andrew@3 214 // bayesianStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesianStruct.likelihood.length);
andrew@3 215 bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-onsetLikelihoodToNoise)/(onsetLikelihoodToNoise*bayesianStruct.likelihood.length));
andrew@2 216 bayesianStruct.likelihood.renormalise();
andrew@2 217
andrew@8 218 bayesianStruct.calculatePosterior();
andrew@8 219
andrew@8 220 lastAlignmentTime = ofGetElapsedTimeMillis();
andrew@8 221 recentEventTime[channel] = ofGetElapsedTimeMillis() - startTime;
andrew@6 222
andrew@3 223 }
andrew@3 224
andrew@3 225
andrew@3 226
andrew@3 227 void AudioEventMatcher::matchNewPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){
andrew@3 228 //start at beginning but OPTIMISE later
andrew@2 229
andrew@2 230
andrew@6 231 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
andrew@8 232
andrew@7 233 //set the lielihoods by matching the pitched note
andrew@7 234
andrew@8 235 double pitchLikelihoodToNoise = 0.5;//more noise
andrew@3 236 int numberOfMatches = 0;
andrew@3 237 bayesianStruct.likelihood.zero();//set to zero
andrew@3 238
andrew@3 239 double quantity = 0;
andrew@3 240 if (channel <= recordedTracks.numberOfAudioTracks){
andrew@3 241 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){
andrew@3 242
andrew@3 243 if (checkMatch(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn)) {
andrew@7 244 quantity = getPitchDistance(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn, 10);
andrew@3 245 bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, 30, quantity);
andrew@3 246 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = true;
andrew@3 247 numberOfMatches++;
andrew@3 248 }
andrew@3 249 else{
andrew@3 250 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = false;
andrew@3 251 }
andrew@3 252
andrew@3 253 }
andrew@3 254 }
andrew@6 255
andrew@8 256 recentPrior = bayesianStruct.prior;
andrew@8 257
andrew@8 258
andrew@6 259 if (numberOfMatches > 0){//no point updating unless there is a match
andrew@7 260
andrew@6 261 bayesianStruct.likelihood.addConstant(numberOfMatches*(1-pitchLikelihoodToNoise)/(pitchLikelihoodToNoise*bayesianStruct.likelihood.length));
andrew@4 262
andrew@4 263 //tmp set likelihood constant and calculate using that
andrew@6 264 //bayesianStruct.likelihood.zero();
andrew@6 265 //bayesianStruct.likelihood.addConstant(1);
andrew@7 266
andrew@6 267 bayesianStruct.calculatePosterior();
andrew@6 268 }
andrew@4 269
andrew@8 270 lastAlignmentTime = ofGetElapsedTimeMillis();
andrew@8 271 recentEventTime[channel] = ofGetElapsedTimeMillis() - startTime;
andrew@1 272 }
andrew@1 273
andrew@3 274 double AudioEventMatcher::getPitchDistance(const double& pitchOne, const double& pitchTwo, const double& scale){
andrew@3 275
andrew@3 276 double distance = abs(pitchOne - pitchTwo);
andrew@3 277 if (distance < scale)
andrew@3 278 distance = 1 - (distance/scale);
andrew@3 279 else
andrew@3 280 distance = 0;
andrew@3 281
andrew@3 282 // printf("[pitch distance %f vs %f = %f\n", pitchOne, pitchTwo, distance);
andrew@3 283 return distance;
andrew@3 284
andrew@3 285 }
andrew@3 286
andrew@3 287
andrew@3 288 bool AudioEventMatcher::checkMatch(const double& recordedPitch, const double& livePitch){
andrew@3 289 if (abs(recordedPitch - livePitch) < 40)
andrew@3 290 return true;
andrew@3 291 else
andrew@3 292 return false;
andrew@3 293 }
andrew@3 294
andrew@3 295
andrew@1 296
andrew@1 297 void AudioEventMatcher::windowResized(const int& w, const int& h){
andrew@1 298 recordedTracks.windowResized(w,h);
andrew@3 299 bayesTempoWindow.resized(w,h);
andrew@3 300 bayesPositionWindow.resized(w,h);
andrew@3 301 }
andrew@3 302
andrew@3 303
andrew@3 304