annotate src/AudioEventMatcher.cpp @ 6:746a5af43c02

windowed bayesian distributions - drawn within constrained portion of the screen
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Thu, 02 Feb 2012 17:52:08 +0000
parents 5ef00d1dfe68
children 33dedfe32893
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@6 44 //draw some outlines in blue
andrew@3 45 ofSetColor(20,200,200);
andrew@3 46 bayesPositionWindow.drawOutline();
andrew@3 47 bayesTempoWindow.drawOutline();
andrew@0 48
andrew@6 49 //draw the scrolling audio tracks
andrew@1 50 recordedTracks.drawTracks();
andrew@2 51
andrew@2 52 ofSetColor(255);
andrew@2 53 // bayesianStruct.relativeSpeedPrior.drawVector(0, 200, bayesTempoWindow);
andrew@2 54
andrew@6 55 drawBayesianDistributions();
andrew@6 56 // bayesianStruct.posterior.drawVector(0, bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow);
andrew@6 57
andrew@6 58 //bayesianStruct.posterior.drawVector(bayesianStruct.posterior.getRealTermsAsIndex(0), bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow);
andrew@6 59
andrew@6 60 // bayesianStruct.relativeSpeedPosterior.drawVector(0, bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(2), bayesTempoWindow);
andrew@6 61
andrew@6 62 }
andrew@6 63
andrew@6 64 void AudioEventMatcher::drawBayesianDistributions(){
andrew@6 65
andrew@6 66
andrew@2 67 double screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber);
andrew@2 68
andrew@6 69
andrew@6 70 double screenStartTimeMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.drawParams.windowStartFrame);
andrew@6 71 double screenEndTimeMillis = screenStartTimeMillis + screenWidthMillis;
andrew@6 72 int startIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenStartTimeMillis);
andrew@6 73 int endIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenEndTimeMillis);
andrew@4 74
andrew@6 75 bayesianStruct.posterior.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesPositionWindow);
andrew@6 76
andrew@6 77 string tmpString = "start "+ofToString(screenStartTimeMillis)+" (index "+ofToString(startIndex)+"), end "+ofToString(screenEndTimeMillis);
andrew@6 78 ofDrawBitmapString(tmpString, bayesPositionWindow.x+20, bayesPositionWindow.y+20);
andrew@4 79
andrew@4 80
andrew@2 81
andrew@6 82 bayesianStruct.likelihood.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesLikelihoodWindow);
andrew@3 83
andrew@6 84
andrew@6 85 //bayesianStruct.likelihood.drawVector(bayesianStruct.likelihood.getRealTermsAsIndex(0), bayesianStruct.likelihood.getRealTermsAsIndex(screenWidthMillis), bayesLikelihoodWindow);
andrew@6 86
andrew@6 87 bayesianStruct.relativeSpeedPosterior.drawConstrainedVector(0, bayesianStruct.relativeSpeedPosterior.arraySize, 0, ofGetWidth(), bayesTempoWindow);
andrew@6 88
andrew@3 89 string tmpStr = "zero is "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(0));
andrew@3 90 tmpStr += " offsetis "+ofToString(bayesianStruct.posterior.offset);
andrew@3 91 tmpStr += " screenWidth = "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis));
andrew@3 92 ofDrawBitmapString(tmpStr, 20,140);
andrew@3 93 tmpStr = "best est "+ofToString(bayesianStruct.bestEstimate);
andrew@3 94 ofDrawBitmapString(tmpStr, 20, 180);
andrew@3 95
andrew@3 96 ofDrawBitmapString("screenamp "+ofToString(screenWidthMillis), 20, 100);
andrew@3 97
andrew@0 98
andrew@1 99 }
andrew@1 100
andrew@6 101 void AudioEventMatcher::newPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){
andrew@1 102 liveInput.addPitchEvent(pitchIn, timeIn);
andrew@4 103
andrew@4 104 //tmp print stuff
andrew@4 105 printf("New pitch MAP post estimate now %i, ", bayesianStruct.posterior.MAPestimate);
andrew@4 106 double tmp = bayesianStruct.posterior.getMAPestimate();
andrew@4 107 printf(" getting it %f and offset %f == %f ms\n", tmp, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(tmp));
andrew@4 108
andrew@6 109 matchNewPitchEvent(channel, pitchIn, timeIn);
andrew@2 110 }
andrew@2 111
andrew@6 112 void AudioEventMatcher::newKickEvent(const double& timeIn){
andrew@6 113 // liveInput.addKickEvent(timeIn);
andrew@2 114 matchNewOnsetEvent(0, timeIn);
andrew@2 115 }
andrew@2 116
andrew@6 117 void AudioEventMatcher::newKickEvent(const int& channel, const double& timeIn){
andrew@6 118 // liveInput.addKickEvent(timeIn);
andrew@6 119 matchNewOnsetEvent(channel, timeIn);
andrew@6 120 }
andrew@6 121
andrew@2 122
andrew@2 123 void AudioEventMatcher::newSnareEvent(const double& timeIn){
andrew@6 124 matchNewOnsetEvent(2, timeIn);
andrew@2 125 }
andrew@2 126
andrew@2 127 //Needs just to set bounds for the matching process, not have TimeIn
andrew@2 128 void AudioEventMatcher::matchNewOnsetEvent(const int& channel, const double& timeIn){
andrew@3 129
andrew@3 130
andrew@6 131 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
andrew@6 132
andrew@2 133 //start at beginning but OPTIMISE later
andrew@6 134 double onsetLikelihoodToNoise = 0.3;
andrew@2 135
andrew@2 136 double likelihoodWidth = 40;
andrew@2 137
andrew@2 138 bayesianStruct.likelihood.offset = bayesianStruct.prior.offset;
andrew@2 139 bayesianStruct.likelihood.zero();//set to zero
andrew@2 140
andrew@2 141 double quantity = 1;//likelihoodToNoiseRatio / numberOfMatches;
andrew@2 142 int numberOfMatchesFound = 0;
andrew@2 143
andrew@2 144
andrew@2 145 double startTime = bayesianStruct.likelihood.offset;
andrew@2 146 double endTime = bayesianStruct.likelihood.offset + matchWindowWidth;
andrew@2 147
andrew@2 148 if (channel <= recordedTracks.numberOfAudioTracks){
andrew@2 149 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){
andrew@2 150 double millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
andrew@2 151 if (millisTime >= startTime && millisTime <= endTime){
andrew@2 152 bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, likelihoodWidth, quantity);
andrew@2 153 numberOfMatchesFound++;
andrew@6 154 // printf("Adding Gaussian for onset at time %f offset %f\n", millisTime, bayesianStruct.likelihood.offset);
andrew@2 155
andrew@2 156 }
andrew@2 157 }
andrew@2 158 }
andrew@2 159
andrew@3 160 // bayesianStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesianStruct.likelihood.length);
andrew@3 161 bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-onsetLikelihoodToNoise)/(onsetLikelihoodToNoise*bayesianStruct.likelihood.length));
andrew@3 162
andrew@2 163 bayesianStruct.likelihood.renormalise();
andrew@2 164
andrew@3 165
andrew@6 166
andrew@3 167 }
andrew@3 168
andrew@3 169
andrew@3 170
andrew@3 171 void AudioEventMatcher::matchNewPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){
andrew@3 172 //start at beginning but OPTIMISE later
andrew@2 173
andrew@2 174
andrew@6 175 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
andrew@3 176
andrew@3 177 ///set offsets
andrew@3 178 // bayesianStruct.likelihood.offset = bayesianStruct.prior.offset;
andrew@6 179 double pitchLikelihoodToNoise = 0.2;//more noise
andrew@3 180 int numberOfMatches = 0;
andrew@3 181 bayesianStruct.likelihood.zero();//set to zero
andrew@3 182
andrew@3 183 double quantity = 0;
andrew@3 184 if (channel <= recordedTracks.numberOfAudioTracks){
andrew@3 185 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){
andrew@3 186
andrew@3 187 if (checkMatch(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn)) {
andrew@6 188 quantity = getPitchDistance(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn, 20);
andrew@3 189 bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, 30, quantity);
andrew@3 190 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = true;
andrew@3 191 numberOfMatches++;
andrew@3 192 }
andrew@3 193 else{
andrew@3 194 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = false;
andrew@3 195 }
andrew@3 196
andrew@3 197 }
andrew@3 198 }
andrew@6 199
andrew@6 200 if (numberOfMatches > 0){//no point updating unless there is a match
andrew@6 201 bayesianStruct.likelihood.addConstant(numberOfMatches*(1-pitchLikelihoodToNoise)/(pitchLikelihoodToNoise*bayesianStruct.likelihood.length));
andrew@4 202
andrew@4 203 //tmp set likelihood constant and calculate using that
andrew@6 204 //bayesianStruct.likelihood.zero();
andrew@6 205 //bayesianStruct.likelihood.addConstant(1);
andrew@4 206
andrew@6 207 bayesianStruct.calculatePosterior();
andrew@6 208 }
andrew@4 209
andrew@1 210 }
andrew@1 211
andrew@3 212 double AudioEventMatcher::getPitchDistance(const double& pitchOne, const double& pitchTwo, const double& scale){
andrew@3 213
andrew@3 214 double distance = abs(pitchOne - pitchTwo);
andrew@3 215 if (distance < scale)
andrew@3 216 distance = 1 - (distance/scale);
andrew@3 217 else
andrew@3 218 distance = 0;
andrew@3 219
andrew@3 220 // printf("[pitch distance %f vs %f = %f\n", pitchOne, pitchTwo, distance);
andrew@3 221 return distance;
andrew@3 222
andrew@3 223 }
andrew@3 224
andrew@3 225
andrew@3 226 bool AudioEventMatcher::checkMatch(const double& recordedPitch, const double& livePitch){
andrew@3 227 if (abs(recordedPitch - livePitch) < 40)
andrew@3 228 return true;
andrew@3 229 else
andrew@3 230 return false;
andrew@3 231 }
andrew@3 232
andrew@3 233
andrew@1 234
andrew@1 235 void AudioEventMatcher::windowResized(const int& w, const int& h){
andrew@1 236 recordedTracks.windowResized(w,h);
andrew@3 237 bayesTempoWindow.resized(w,h);
andrew@3 238 bayesPositionWindow.resized(w,h);
andrew@3 239 }
andrew@3 240
andrew@3 241
andrew@3 242