annotate src/AudioEventMatcher.cpp @ 4:45b5cf9be377

checking through Bayesian update procedure - working without cross update method.
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Thu, 02 Feb 2012 12:13:44 +0000
parents 5e188c0035b6
children 5ef00d1dfe68
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@3 16 bayesPositionWindow.setToRelativeSize(0, 0.4, 1, 0.2);
andrew@3 17 bayesTempoWindow.setToRelativeSize(0, 0.8, 1, 0.2);
andrew@3 18 bayesLikelihoodWindow.setToRelativeSize(0, 0.6, 1, 0.2);
andrew@3 19
andrew@0 20 setArraySizes();
andrew@3 21
andrew@3 22 usingRealTime = false;
andrew@3 23 bayesianStruct.realTimeMode = &usingRealTime;
andrew@0 24 }
andrew@0 25
andrew@0 26
andrew@0 27 void AudioEventMatcher::setArraySizes(){
andrew@0 28 bayesianStruct.resetSpeedSize(200);
andrew@0 29 bayesianStruct.setRelativeSpeedScalar(0.01);
andrew@0 30 bayesianStruct.setSpeedPrior(1.0);
andrew@0 31 bayesianStruct.relativeSpeedPrior.getMaximum();
andrew@0 32
andrew@0 33 bayesianStruct.resetSize(matchWindowWidth);
andrew@0 34 bayesianStruct.setPositionDistributionScalar(1);
andrew@0 35
andrew@0 36 }
andrew@0 37
andrew@3 38 void AudioEventMatcher::startPlaying(){
andrew@3 39 bayesianStruct.setStartPlaying();
andrew@3 40 //bayesianStruct.posterior.printArray();
andrew@3 41 }
andrew@3 42
andrew@0 43 void AudioEventMatcher::draw(){
andrew@3 44 ofSetColor(20,200,200);
andrew@3 45 bayesPositionWindow.drawOutline();
andrew@3 46 bayesTempoWindow.drawOutline();
andrew@0 47
andrew@1 48 recordedTracks.drawTracks();
andrew@2 49
andrew@2 50 ofSetColor(255);
andrew@2 51 // bayesianStruct.relativeSpeedPrior.drawVector(0, 200, bayesTempoWindow);
andrew@2 52
andrew@2 53 double screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber);
andrew@2 54
andrew@4 55 bayesianStruct.posterior.drawVector(0, bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow);
andrew@4 56
andrew@4 57 // bayesianStruct.posterior.drawVector(bayesianStruct.posterior.getRealTermsAsIndex(0), bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow);
andrew@4 58
andrew@4 59
andrew@3 60 bayesianStruct.likelihood.drawVector(bayesianStruct.likelihood.getRealTermsAsIndex(0), bayesianStruct.likelihood.getRealTermsAsIndex(screenWidthMillis), bayesLikelihoodWindow);
andrew@2 61
andrew@3 62 bayesianStruct.relativeSpeedPosterior.drawVector(0, bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(2), bayesTempoWindow);
andrew@3 63
andrew@4 64
andrew@3 65 string tmpStr = "zero is "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(0));
andrew@3 66 tmpStr += " offsetis "+ofToString(bayesianStruct.posterior.offset);
andrew@3 67 tmpStr += " screenWidth = "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis));
andrew@3 68 ofDrawBitmapString(tmpStr, 20,140);
andrew@3 69 tmpStr = "best est "+ofToString(bayesianStruct.bestEstimate);
andrew@3 70 ofDrawBitmapString(tmpStr, 20, 180);
andrew@3 71
andrew@3 72 ofDrawBitmapString("screenamp "+ofToString(screenWidthMillis), 20, 100);
andrew@3 73
andrew@0 74
andrew@1 75 }
andrew@1 76
andrew@1 77
andrew@1 78 void AudioEventMatcher::newPitchEvent(const double& pitchIn, const double& timeIn){
andrew@1 79 liveInput.addPitchEvent(pitchIn, timeIn);
andrew@4 80
andrew@4 81 //tmp print stuff
andrew@4 82 printf("New pitch MAP post estimate now %i, ", bayesianStruct.posterior.MAPestimate);
andrew@4 83 double tmp = bayesianStruct.posterior.getMAPestimate();
andrew@4 84 printf(" getting it %f and offset %f == %f ms\n", tmp, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(tmp));
andrew@4 85
andrew@3 86 matchNewPitchEvent(0, pitchIn, timeIn);
andrew@2 87 }
andrew@2 88
andrew@2 89 void AudioEventMatcher::newKickEvent(const double& timeIn){
andrew@3 90 // liveInput.addKickEvent(time);
andrew@2 91 matchNewOnsetEvent(0, timeIn);
andrew@2 92 }
andrew@2 93
andrew@2 94
andrew@2 95 void AudioEventMatcher::newSnareEvent(const double& timeIn){
andrew@2 96 matchNewOnsetEvent(0, timeIn);
andrew@2 97 }
andrew@2 98
andrew@2 99 //Needs just to set bounds for the matching process, not have TimeIn
andrew@2 100 void AudioEventMatcher::matchNewOnsetEvent(const int& channel, const double& timeIn){
andrew@3 101
andrew@3 102
andrew@2 103 //start at beginning but OPTIMISE later
andrew@3 104 double onsetLikelihoodToNoise = 0.5;
andrew@2 105
andrew@2 106 double likelihoodWidth = 40;
andrew@2 107
andrew@2 108 bayesianStruct.likelihood.offset = bayesianStruct.prior.offset;
andrew@2 109 bayesianStruct.likelihood.zero();//set to zero
andrew@2 110
andrew@2 111 double quantity = 1;//likelihoodToNoiseRatio / numberOfMatches;
andrew@2 112 int numberOfMatchesFound = 0;
andrew@2 113
andrew@2 114
andrew@2 115 double startTime = bayesianStruct.likelihood.offset;
andrew@2 116 double endTime = bayesianStruct.likelihood.offset + matchWindowWidth;
andrew@2 117
andrew@2 118 if (channel <= recordedTracks.numberOfAudioTracks){
andrew@2 119 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){
andrew@2 120 double millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
andrew@2 121 if (millisTime >= startTime && millisTime <= endTime){
andrew@2 122 bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, likelihoodWidth, quantity);
andrew@2 123 numberOfMatchesFound++;
andrew@2 124 printf("Adding Gaussian for onset at time %f offset %f\n", millisTime, bayesianStruct.likelihood.offset);
andrew@2 125
andrew@2 126 }
andrew@2 127 }
andrew@2 128 }
andrew@2 129
andrew@3 130 // bayesianStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesianStruct.likelihood.length);
andrew@3 131 bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-onsetLikelihoodToNoise)/(onsetLikelihoodToNoise*bayesianStruct.likelihood.length));
andrew@3 132
andrew@2 133 bayesianStruct.likelihood.renormalise();
andrew@2 134
andrew@3 135
andrew@3 136 }
andrew@3 137
andrew@3 138
andrew@3 139
andrew@3 140 void AudioEventMatcher::matchNewPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){
andrew@3 141 //start at beginning but OPTIMISE later
andrew@2 142
andrew@2 143
andrew@3 144 updateBayesianDistributions(timeIn);
andrew@3 145
andrew@3 146 ///set offsets
andrew@3 147 // bayesianStruct.likelihood.offset = bayesianStruct.prior.offset;
andrew@3 148 double pitchLikelihoodToNoise = 0.5;
andrew@3 149 int numberOfMatches = 0;
andrew@3 150 bayesianStruct.likelihood.zero();//set to zero
andrew@3 151
andrew@3 152 double quantity = 0;
andrew@3 153 if (channel <= recordedTracks.numberOfAudioTracks){
andrew@3 154 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){
andrew@3 155
andrew@3 156 if (checkMatch(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn)) {
andrew@3 157 quantity = getPitchDistance(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn, 40);
andrew@3 158 bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, 30, quantity);
andrew@3 159 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = true;
andrew@3 160 numberOfMatches++;
andrew@3 161 }
andrew@3 162 else{
andrew@3 163 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = false;
andrew@3 164 }
andrew@3 165
andrew@3 166 }
andrew@3 167 }
andrew@3 168
andrew@3 169 bayesianStruct.likelihood.addConstant(numberOfMatches*(1-pitchLikelihoodToNoise)/(pitchLikelihoodToNoise*bayesianStruct.likelihood.length));
andrew@3 170
andrew@3 171 recordedTracks.recentPitch = pitchIn;
andrew@4 172
andrew@4 173
andrew@4 174 //tmp set likelihood constant and calculate using that
andrew@4 175 bayesianStruct.likelihood.zero();
andrew@4 176 bayesianStruct.likelihood.addConstant(1);
andrew@4 177
andrew@4 178 bayesianStruct.calculatePosterior();
andrew@4 179
andrew@4 180 //tmp print stuff
andrew@4 181 printf("After CALC");
andrew@4 182 printPostOffset();
andrew@4 183
andrew@1 184 }
andrew@1 185
andrew@3 186 double AudioEventMatcher::getPitchDistance(const double& pitchOne, const double& pitchTwo, const double& scale){
andrew@3 187
andrew@3 188 double distance = abs(pitchOne - pitchTwo);
andrew@3 189 if (distance < scale)
andrew@3 190 distance = 1 - (distance/scale);
andrew@3 191 else
andrew@3 192 distance = 0;
andrew@3 193
andrew@3 194 // printf("[pitch distance %f vs %f = %f\n", pitchOne, pitchTwo, distance);
andrew@3 195 return distance;
andrew@3 196
andrew@3 197 }
andrew@3 198
andrew@3 199
andrew@3 200 bool AudioEventMatcher::checkMatch(const double& recordedPitch, const double& livePitch){
andrew@3 201 if (abs(recordedPitch - livePitch) < 40)
andrew@3 202 return true;
andrew@3 203 else
andrew@3 204 return false;
andrew@3 205 }
andrew@3 206
andrew@3 207
andrew@1 208
andrew@1 209 void AudioEventMatcher::windowResized(const int& w, const int& h){
andrew@1 210 recordedTracks.windowResized(w,h);
andrew@3 211 bayesTempoWindow.resized(w,h);
andrew@3 212 bayesPositionWindow.resized(w,h);
andrew@3 213 }
andrew@3 214
andrew@3 215
andrew@3 216
andrew@3 217 void AudioEventMatcher::updateBayesianDistributions(const double& newEventTime){
andrew@3 218 //MOVE INTO bayesianStruct?? XX
andrew@3 219
andrew@3 220 //NEED TO CHECK HERE THAT THEY HAVE THE SAME OFFSETS
andrew@3 221 bayesianStruct.prior.copyFromDynamicVector(bayesianStruct.posterior);//try the otehr way
andrew@3 222
andrew@3 223 //bayesianStruct.copyPriorToPosterior();
andrew@3 224 //need to get new MAP position and set the offset of the arrays
andrew@3 225 //currently bestEstimate is the approx for the new MAP position
andrew@4 226 int tmpMap = bayesianStruct.posterior.getMAPestimate();
andrew@4 227
andrew@3 228 double timeDifference = newEventTime - bayesianStruct.lastEventTime;
andrew@4 229 printf("updating distributions at time %f diff %f offset %f tmpmap est %i\n", newEventTime, timeDifference, bayesianStruct.posterior.offset, tmpMap);
andrew@3 230
andrew@3 231 //addnoise to the tempo distribution
andrew@3 232 //bayesianStruct.decaySpeedDistribution(timeDifference);
andrew@4 233
andrew@3 234 if (timeDifference > 50){
andrew@3 235 bayesianStruct.addGaussianNoiseToSpeedPosterior(timeDifference * 10.0 / 100.);
andrew@3 236 }
andrew@3 237
andrew@3 238 bayesianStruct.updateBestEstimate(timeDifference);
andrew@3 239 bayesianStruct.lastBestEstimateUpdateTime = newEventTime;//getTimeNow(timePlayed);
andrew@3 240
andrew@4 241 // printf("set new distrb max 0 or %f\n", bayesianStruct.bestEstimate - (bayesianStruct.prior.scalar*bayesianStruct.prior.arraySize/2));
andrew@4 242
andrew@4 243 //tmp print stuff
andrew@4 244
andrew@4 245 printf("HALFWAY BEST ");
andrew@4 246 printPostOffset();
andrew@4 247
andrew@3 248 bayesianStruct.setNewDistributionOffsets(max(0., bayesianStruct.bestEstimate - (bayesianStruct.prior.scalar*bayesianStruct.prior.arraySize/2)));
andrew@3 249 bayesianStruct.crossUpdateArrays(bayesianStruct.posterior, bayesianStruct.relativeSpeedPosterior, timeDifference);
andrew@3 250
andrew@4 251 //i.e. using the same offset as prior
andrew@4 252 bayesianStruct.posterior.offset = bayesianStruct.prior.offset;//
andrew@4 253
andrew@4 254 // float tmpPrior = max(0., bayesianStruct.bestEstimate - (bayesianStruct.prior.scalar*bayesianStruct.prior.arraySize/2));// bayesianStruct.prior.offset = max(0., bayesianStruct.bestEstimate - (bayesianStruct.prior.scalar*bayesianStruct.prior.arraySize/2));
andrew@4 255 // printf("Using prior offset of %f not %f\n", tmpPrior, bayesianStruct.prior.offset);
andrew@4 256
andrew@3 257 bayesianStruct.lastEventTime = newEventTime;//bayesianStruct.lastEventTime = ofGetElapsedTimeMillis();
andrew@4 258
andrew@4 259
andrew@3 260 }
andrew@4 261
andrew@4 262 void AudioEventMatcher::printPostOffset(){
andrew@4 263 double tmp = bayesianStruct.posterior.getMAPestimate();
andrew@4 264 printf(" MAP index %i post offset %f == %f ms\n", bayesianStruct.posterior.MAPestimate, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(bayesianStruct.posterior.MAPestimate));
andrew@4 265 }