annotate src/AudioEventMatcher.cpp @ 7:33dedfe32893

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