Mercurial > hg > multitrack-audio-matcher
comparison 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 |
comparison
equal
deleted
inserted
replaced
5:5ef00d1dfe68 | 6:746a5af43c02 |
---|---|
39 bayesianStruct.setStartPlaying(); | 39 bayesianStruct.setStartPlaying(); |
40 //bayesianStruct.posterior.printArray(); | 40 //bayesianStruct.posterior.printArray(); |
41 } | 41 } |
42 | 42 |
43 void AudioEventMatcher::draw(){ | 43 void AudioEventMatcher::draw(){ |
44 //draw some outlines in blue | |
44 ofSetColor(20,200,200); | 45 ofSetColor(20,200,200); |
45 bayesPositionWindow.drawOutline(); | 46 bayesPositionWindow.drawOutline(); |
46 bayesTempoWindow.drawOutline(); | 47 bayesTempoWindow.drawOutline(); |
47 | 48 |
49 //draw the scrolling audio tracks | |
48 recordedTracks.drawTracks(); | 50 recordedTracks.drawTracks(); |
49 | 51 |
50 ofSetColor(255); | 52 ofSetColor(255); |
51 // bayesianStruct.relativeSpeedPrior.drawVector(0, 200, bayesTempoWindow); | 53 // bayesianStruct.relativeSpeedPrior.drawVector(0, 200, bayesTempoWindow); |
52 | 54 |
55 drawBayesianDistributions(); | |
56 // bayesianStruct.posterior.drawVector(0, bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow); | |
57 | |
58 //bayesianStruct.posterior.drawVector(bayesianStruct.posterior.getRealTermsAsIndex(0), bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow); | |
59 | |
60 // bayesianStruct.relativeSpeedPosterior.drawVector(0, bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(2), bayesTempoWindow); | |
61 | |
62 } | |
63 | |
64 void AudioEventMatcher::drawBayesianDistributions(){ | |
65 | |
66 | |
53 double screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber); | 67 double screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber); |
54 | 68 |
55 bayesianStruct.posterior.drawVector(0, bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow); | 69 |
56 | 70 double screenStartTimeMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.drawParams.windowStartFrame); |
57 // bayesianStruct.posterior.drawVector(bayesianStruct.posterior.getRealTermsAsIndex(0), bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow); | 71 double screenEndTimeMillis = screenStartTimeMillis + screenWidthMillis; |
58 | 72 int startIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenStartTimeMillis); |
59 | 73 int endIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenEndTimeMillis); |
60 bayesianStruct.likelihood.drawVector(bayesianStruct.likelihood.getRealTermsAsIndex(0), bayesianStruct.likelihood.getRealTermsAsIndex(screenWidthMillis), bayesLikelihoodWindow); | 74 |
61 | 75 bayesianStruct.posterior.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesPositionWindow); |
62 bayesianStruct.relativeSpeedPosterior.drawVector(0, bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(2), bayesTempoWindow); | 76 |
63 | 77 string tmpString = "start "+ofToString(screenStartTimeMillis)+" (index "+ofToString(startIndex)+"), end "+ofToString(screenEndTimeMillis); |
64 | 78 ofDrawBitmapString(tmpString, bayesPositionWindow.x+20, bayesPositionWindow.y+20); |
79 | |
80 | |
81 | |
82 bayesianStruct.likelihood.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesLikelihoodWindow); | |
83 | |
84 | |
85 //bayesianStruct.likelihood.drawVector(bayesianStruct.likelihood.getRealTermsAsIndex(0), bayesianStruct.likelihood.getRealTermsAsIndex(screenWidthMillis), bayesLikelihoodWindow); | |
86 | |
87 bayesianStruct.relativeSpeedPosterior.drawConstrainedVector(0, bayesianStruct.relativeSpeedPosterior.arraySize, 0, ofGetWidth(), bayesTempoWindow); | |
88 | |
65 string tmpStr = "zero is "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(0)); | 89 string tmpStr = "zero is "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(0)); |
66 tmpStr += " offsetis "+ofToString(bayesianStruct.posterior.offset); | 90 tmpStr += " offsetis "+ofToString(bayesianStruct.posterior.offset); |
67 tmpStr += " screenWidth = "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis)); | 91 tmpStr += " screenWidth = "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis)); |
68 ofDrawBitmapString(tmpStr, 20,140); | 92 ofDrawBitmapString(tmpStr, 20,140); |
69 tmpStr = "best est "+ofToString(bayesianStruct.bestEstimate); | 93 tmpStr = "best est "+ofToString(bayesianStruct.bestEstimate); |
72 ofDrawBitmapString("screenamp "+ofToString(screenWidthMillis), 20, 100); | 96 ofDrawBitmapString("screenamp "+ofToString(screenWidthMillis), 20, 100); |
73 | 97 |
74 | 98 |
75 } | 99 } |
76 | 100 |
77 | 101 void AudioEventMatcher::newPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){ |
78 void AudioEventMatcher::newPitchEvent(const double& pitchIn, const double& timeIn){ | |
79 liveInput.addPitchEvent(pitchIn, timeIn); | 102 liveInput.addPitchEvent(pitchIn, timeIn); |
80 | 103 |
81 //tmp print stuff | 104 //tmp print stuff |
82 printf("New pitch MAP post estimate now %i, ", bayesianStruct.posterior.MAPestimate); | 105 printf("New pitch MAP post estimate now %i, ", bayesianStruct.posterior.MAPestimate); |
83 double tmp = bayesianStruct.posterior.getMAPestimate(); | 106 double tmp = bayesianStruct.posterior.getMAPestimate(); |
84 printf(" getting it %f and offset %f == %f ms\n", tmp, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(tmp)); | 107 printf(" getting it %f and offset %f == %f ms\n", tmp, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(tmp)); |
85 | 108 |
86 matchNewPitchEvent(0, pitchIn, timeIn); | 109 matchNewPitchEvent(channel, pitchIn, timeIn); |
87 } | 110 } |
88 | 111 |
89 void AudioEventMatcher::newKickEvent(const double& timeIn){ | 112 void AudioEventMatcher::newKickEvent(const double& timeIn){ |
90 // liveInput.addKickEvent(time); | 113 // liveInput.addKickEvent(timeIn); |
91 matchNewOnsetEvent(0, timeIn); | 114 matchNewOnsetEvent(0, timeIn); |
92 } | 115 } |
93 | 116 |
117 void AudioEventMatcher::newKickEvent(const int& channel, const double& timeIn){ | |
118 // liveInput.addKickEvent(timeIn); | |
119 matchNewOnsetEvent(channel, timeIn); | |
120 } | |
121 | |
94 | 122 |
95 void AudioEventMatcher::newSnareEvent(const double& timeIn){ | 123 void AudioEventMatcher::newSnareEvent(const double& timeIn){ |
96 matchNewOnsetEvent(0, timeIn); | 124 matchNewOnsetEvent(2, timeIn); |
97 } | 125 } |
98 | 126 |
99 //Needs just to set bounds for the matching process, not have TimeIn | 127 //Needs just to set bounds for the matching process, not have TimeIn |
100 void AudioEventMatcher::matchNewOnsetEvent(const int& channel, const double& timeIn){ | 128 void AudioEventMatcher::matchNewOnsetEvent(const int& channel, const double& timeIn){ |
101 | 129 |
102 | 130 |
131 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets | |
132 | |
103 //start at beginning but OPTIMISE later | 133 //start at beginning but OPTIMISE later |
104 double onsetLikelihoodToNoise = 0.5; | 134 double onsetLikelihoodToNoise = 0.3; |
105 | 135 |
106 double likelihoodWidth = 40; | 136 double likelihoodWidth = 40; |
107 | 137 |
108 bayesianStruct.likelihood.offset = bayesianStruct.prior.offset; | 138 bayesianStruct.likelihood.offset = bayesianStruct.prior.offset; |
109 bayesianStruct.likelihood.zero();//set to zero | 139 bayesianStruct.likelihood.zero();//set to zero |
119 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){ | 149 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){ |
120 double millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime; | 150 double millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime; |
121 if (millisTime >= startTime && millisTime <= endTime){ | 151 if (millisTime >= startTime && millisTime <= endTime){ |
122 bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, likelihoodWidth, quantity); | 152 bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, likelihoodWidth, quantity); |
123 numberOfMatchesFound++; | 153 numberOfMatchesFound++; |
124 printf("Adding Gaussian for onset at time %f offset %f\n", millisTime, bayesianStruct.likelihood.offset); | 154 // printf("Adding Gaussian for onset at time %f offset %f\n", millisTime, bayesianStruct.likelihood.offset); |
125 | 155 |
126 } | 156 } |
127 } | 157 } |
128 } | 158 } |
129 | 159 |
131 bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-onsetLikelihoodToNoise)/(onsetLikelihoodToNoise*bayesianStruct.likelihood.length)); | 161 bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-onsetLikelihoodToNoise)/(onsetLikelihoodToNoise*bayesianStruct.likelihood.length)); |
132 | 162 |
133 bayesianStruct.likelihood.renormalise(); | 163 bayesianStruct.likelihood.renormalise(); |
134 | 164 |
135 | 165 |
166 | |
136 } | 167 } |
137 | 168 |
138 | 169 |
139 | 170 |
140 void AudioEventMatcher::matchNewPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){ | 171 void AudioEventMatcher::matchNewPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){ |
141 //start at beginning but OPTIMISE later | 172 //start at beginning but OPTIMISE later |
142 | 173 |
143 | 174 |
144 updateBayesianDistributions(timeIn); | 175 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets |
145 | 176 |
146 ///set offsets | 177 ///set offsets |
147 // bayesianStruct.likelihood.offset = bayesianStruct.prior.offset; | 178 // bayesianStruct.likelihood.offset = bayesianStruct.prior.offset; |
148 double pitchLikelihoodToNoise = 0.5; | 179 double pitchLikelihoodToNoise = 0.2;//more noise |
149 int numberOfMatches = 0; | 180 int numberOfMatches = 0; |
150 bayesianStruct.likelihood.zero();//set to zero | 181 bayesianStruct.likelihood.zero();//set to zero |
151 | 182 |
152 double quantity = 0; | 183 double quantity = 0; |
153 if (channel <= recordedTracks.numberOfAudioTracks){ | 184 if (channel <= recordedTracks.numberOfAudioTracks){ |
154 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){ | 185 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){ |
155 | 186 |
156 if (checkMatch(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn)) { | 187 if (checkMatch(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn)) { |
157 quantity = getPitchDistance(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn, 40); | 188 quantity = getPitchDistance(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn, 20); |
158 bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, 30, quantity); | 189 bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, 30, quantity); |
159 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = true; | 190 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = true; |
160 numberOfMatches++; | 191 numberOfMatches++; |
161 } | 192 } |
162 else{ | 193 else{ |
163 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = false; | 194 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = false; |
164 } | 195 } |
165 | 196 |
166 } | 197 } |
167 } | 198 } |
168 | 199 |
169 bayesianStruct.likelihood.addConstant(numberOfMatches*(1-pitchLikelihoodToNoise)/(pitchLikelihoodToNoise*bayesianStruct.likelihood.length)); | 200 if (numberOfMatches > 0){//no point updating unless there is a match |
170 | 201 bayesianStruct.likelihood.addConstant(numberOfMatches*(1-pitchLikelihoodToNoise)/(pitchLikelihoodToNoise*bayesianStruct.likelihood.length)); |
171 recordedTracks.recentPitch = pitchIn; | |
172 | |
173 | 202 |
174 //tmp set likelihood constant and calculate using that | 203 //tmp set likelihood constant and calculate using that |
175 bayesianStruct.likelihood.zero(); | 204 //bayesianStruct.likelihood.zero(); |
176 bayesianStruct.likelihood.addConstant(1); | 205 //bayesianStruct.likelihood.addConstant(1); |
177 | 206 |
178 bayesianStruct.calculatePosterior(); | 207 bayesianStruct.calculatePosterior(); |
179 | 208 } |
180 //tmp print stuff | |
181 printf("After CALC"); | |
182 printPostOffset(); | |
183 | 209 |
184 } | 210 } |
185 | 211 |
186 double AudioEventMatcher::getPitchDistance(const double& pitchOne, const double& pitchTwo, const double& scale){ | 212 double AudioEventMatcher::getPitchDistance(const double& pitchOne, const double& pitchTwo, const double& scale){ |
187 | 213 |
212 bayesPositionWindow.resized(w,h); | 238 bayesPositionWindow.resized(w,h); |
213 } | 239 } |
214 | 240 |
215 | 241 |
216 | 242 |
217 void AudioEventMatcher::updateBayesianDistributions(const double& newEventTime){ | |
218 //MOVE INTO bayesianStruct?? XX | |
219 | |
220 //NEED TO CHECK HERE THAT THEY HAVE THE SAME OFFSETS | |
221 bayesianStruct.prior.copyFromDynamicVector(bayesianStruct.posterior);//try the otehr way | |
222 | |
223 //bayesianStruct.copyPriorToPosterior(); | |
224 //need to get new MAP position and set the offset of the arrays | |
225 //currently bestEstimate is the approx for the new MAP position | |
226 int tmpMap = bayesianStruct.posterior.getMAPestimate(); | |
227 | |
228 double timeDifference = newEventTime - bayesianStruct.lastEventTime; | |
229 printf("updating distributions at time %f diff %f offset %f tmpmap est %i\n", newEventTime, timeDifference, bayesianStruct.posterior.offset, tmpMap); | |
230 | |
231 //addnoise to the tempo distribution | |
232 //bayesianStruct.decaySpeedDistribution(timeDifference); | |
233 | |
234 if (timeDifference > 50){ | |
235 bayesianStruct.addGaussianNoiseToSpeedPosterior(timeDifference * 10.0 / 100.); | |
236 } | |
237 | |
238 bayesianStruct.updateBestEstimate(timeDifference); | |
239 bayesianStruct.lastBestEstimateUpdateTime = newEventTime;//getTimeNow(timePlayed); | |
240 | |
241 // printf("set new distrb max 0 or %f\n", bayesianStruct.bestEstimate - (bayesianStruct.prior.scalar*bayesianStruct.prior.arraySize/2)); | |
242 | |
243 //tmp print stuff | |
244 | |
245 printf("HALFWAY BEST "); | |
246 printPostOffset(); | |
247 | |
248 bayesianStruct.setNewDistributionOffsets(max(0., bayesianStruct.bestEstimate - (bayesianStruct.prior.scalar*bayesianStruct.prior.arraySize/2))); | |
249 bayesianStruct.crossUpdateArrays(bayesianStruct.posterior, bayesianStruct.relativeSpeedPosterior, timeDifference); | |
250 | |
251 //i.e. using the same offset as prior | |
252 bayesianStruct.posterior.offset = bayesianStruct.prior.offset;// | |
253 | |
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)); | |
255 // printf("Using prior offset of %f not %f\n", tmpPrior, bayesianStruct.prior.offset); | |
256 | |
257 bayesianStruct.lastEventTime = newEventTime;//bayesianStruct.lastEventTime = ofGetElapsedTimeMillis(); | |
258 | |
259 } | |
260 | |
261 void AudioEventMatcher::printPostOffset(){ | |
262 double tmp = bayesianStruct.posterior.getMAPestimate(); | |
263 printf(" MAP index %i post offset %f == %f ms\n", bayesianStruct.posterior.MAPestimate, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(bayesianStruct.posterior.MAPestimate)); | |
264 } |