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@55
|
12 //whi are there two Tempo Follower class objects?
|
andrew@55
|
13
|
andrew@0
|
14
|
andrew@39
|
15 const int matchWindowWidth = 8000;//ms in which to match
|
andrew@39
|
16
|
andrew@32
|
17 const float pitchCutOff = 16;//within which pitches are even considered
|
andrew@56
|
18 const double pitchWidth = 12;
|
andrew@0
|
19
|
andrew@55
|
20 bool printInfo = false;
|
andrew@50
|
21
|
andrew@0
|
22 AudioEventMatcher::AudioEventMatcher(){
|
andrew@7
|
23
|
andrew@55
|
24 ofBackground(0);
|
andrew@50
|
25 useChromaDotProduct = false;//false for most tests
|
andrew@37
|
26 printingData = false;
|
andrew@56
|
27 updateTempoMethodOn = false;
|
andrew@37
|
28
|
andrew@23
|
29 pitchLikelihoodToNoise = 0.6;//more noise
|
andrew@56
|
30 pitchLikelihoodWidth = 30;
|
andrew@56
|
31
|
andrew@32
|
32 chromaLikelihoodToNoise = 0.5;//lower => more noise, higher more weight for events
|
andrew@32
|
33 chromaLikelihoodWidth = 50;//ms round onset event
|
andrew@16
|
34
|
andrew@56
|
35 //onsetLikelihoodToNoise = 0.2;//0.1 and 10 as to 9/5/12
|
andrew@53
|
36 kickLikelihoodToNoise = 0.3;
|
andrew@53
|
37 snareLikelihoodToNoise = 0.1;
|
andrew@53
|
38
|
andrew@53
|
39
|
andrew@48
|
40 onsetLikelihoodWidth = 6;//in ms
|
andrew@15
|
41
|
andrew@0
|
42 setArraySizes();
|
andrew@3
|
43
|
andrew@3
|
44 usingRealTime = false;
|
andrew@3
|
45 bayesianStruct.realTimeMode = &usingRealTime;
|
andrew@7
|
46 recentPitch = 0;
|
andrew@8
|
47 currentAlignmentPosition = 0;
|
andrew@14
|
48
|
andrew@9
|
49 followingLiveInput = true;
|
andrew@15
|
50 startedPlaying = false;
|
andrew@20
|
51 recordedTempoIndex = 0;
|
andrew@39
|
52
|
andrew@42
|
53 bayesianStruct.startingWindowWidth = 100;//matchWindowWidth / 8;
|
andrew@42
|
54 bayesianStruct.matchWindowWidth = matchWindowWidth;
|
andrew@50
|
55
|
andrew@51
|
56 drawLikelihoods = true;
|
andrew@50
|
57 drawPosterior = false;
|
andrew@50
|
58
|
andrew@53
|
59 temporal.printOutput = true;//printInfo;
|
andrew@50
|
60
|
andrew@52
|
61
|
andrew@20
|
62 // temporal.setUpEventTimeMatrix();
|
andrew@20
|
63 // recordedTempoData.setUpEventTimeMatrix();
|
andrew@0
|
64 }
|
andrew@0
|
65
|
andrew@14
|
66
|
andrew@19
|
67
|
andrew@19
|
68
|
andrew@7
|
69 void AudioEventMatcher::setWindowDimensions(){
|
andrew@53
|
70
|
andrew@7
|
71 double startHeight = recordedTracks.numberOfAudioTracks * recordedTracks.trackScreenHeight;
|
andrew@7
|
72 double heightAvailable = 1 - startHeight;
|
andrew@32
|
73 heightAvailable /= numberOfChannels;
|
andrew@7
|
74
|
andrew@7
|
75 bayesPositionWindow.setToRelativeSize(0, startHeight, 1, heightAvailable);
|
andrew@7
|
76 bayesLikelihoodWindow.setToRelativeSize(0, startHeight + 1*heightAvailable, 1, heightAvailable);
|
andrew@7
|
77 bayesTempoWindow.setToRelativeSize(0, startHeight + 2*heightAvailable, 1, heightAvailable);
|
andrew@7
|
78
|
andrew@7
|
79
|
andrew@7
|
80 }
|
andrew@0
|
81
|
andrew@0
|
82 void AudioEventMatcher::setArraySizes(){
|
andrew@0
|
83 bayesianStruct.resetSpeedSize(200);
|
andrew@0
|
84 bayesianStruct.setRelativeSpeedScalar(0.01);
|
andrew@0
|
85 bayesianStruct.setSpeedPrior(1.0);
|
andrew@0
|
86 bayesianStruct.relativeSpeedPrior.getMaximum();
|
andrew@0
|
87
|
andrew@36
|
88 float scalarForBayesianDistribution = 2;
|
andrew@36
|
89
|
andrew@36
|
90 bayesianStruct.resetSize(matchWindowWidth / scalarForBayesianDistribution);
|
andrew@36
|
91 bayesianStruct.setPositionDistributionScalar(2);
|
andrew@0
|
92
|
andrew@0
|
93 }
|
andrew@0
|
94
|
andrew@16
|
95 void AudioEventMatcher::loadAudioFiles(){
|
andrew@16
|
96 recordedTracks.loadTestAudio();
|
andrew@16
|
97 synchroniser.fileLengthSamples = recordedTracks.loadedAudioFiles[0].fileLoader.totalNumberOfSamples;
|
andrew@16
|
98 printf("synchroniser has %f samples\n", synchroniser.fileLengthSamples);
|
andrew@55
|
99 printf("First PASS\n");
|
andrew@20
|
100
|
andrew@20
|
101 calculateRecordedTempoData();
|
andrew@55
|
102 recordedTempoData.printTempoTimes();
|
andrew@53
|
103 printf("\n audioeventmatcher\nFIRST PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo);
|
andrew@55
|
104
|
andrew@55
|
105 printf("SECOND PASS\n");
|
andrew@20
|
106 setTempoPrior(recordedTempoData.playingTempo);
|
andrew@20
|
107 calculateRecordedTempoData();//now calculate again using better prior
|
andrew@20
|
108
|
andrew@53
|
109 printf("\n audioeventmatcher\nSECOND PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo);
|
andrew@20
|
110 printf("GLOBAL TEMPO of RECORDED FILES\n");
|
andrew@20
|
111 recordedTempoData.printTempoTimes();
|
andrew@20
|
112 }
|
andrew@20
|
113
|
andrew@20
|
114 void AudioEventMatcher::setTempoPrior(double tempo){
|
andrew@20
|
115 recordedTempoData.zero();
|
andrew@20
|
116 recordedTempoData.tempoPosterior.zero();
|
andrew@20
|
117 recordedTempoData.tempoPosterior.addGaussianShapeFromRealTime(tempo, 3, 1);
|
andrew@20
|
118
|
andrew@20
|
119 }
|
andrew@20
|
120
|
andrew@20
|
121 void AudioEventMatcher::calculateRecordedTempoData(){
|
andrew@20
|
122 int indexForOnsets[3];
|
andrew@20
|
123 indexForOnsets[0] = 0;
|
andrew@20
|
124 indexForOnsets[1] = 0;
|
andrew@20
|
125 indexForOnsets[2] = 0;
|
andrew@53
|
126
|
andrew@55
|
127 int kickTime = 0;
|
andrew@55
|
128 int snareTime = 0;
|
andrew@53
|
129
|
andrew@20
|
130 while (indexForOnsets[0] < recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.chromaOnsets.size() ||
|
andrew@20
|
131 indexForOnsets[2] < recordedTracks.loadedAudioFiles[2].fileLoader.onsetDetect.chromaOnsets.size()) {
|
andrew@20
|
132
|
andrew@20
|
133 setNextOnsetTime(0, kickTime, &indexForOnsets[0]);
|
andrew@20
|
134 setNextOnsetTime(2, snareTime, &indexForOnsets[0]);
|
andrew@20
|
135
|
andrew@20
|
136 if (kickTime < snareTime){
|
andrew@53
|
137 printf("kick(%i) at %i\n", indexForOnsets[0], kickTime);
|
andrew@20
|
138 recordedTempoData.updateTempo(0, kickTime);
|
andrew@53
|
139 // printf("recorded tempo is %f\n", recordedTempoData.playingTempo);
|
andrew@20
|
140 indexForOnsets[0]++;
|
andrew@20
|
141 }else {
|
andrew@53
|
142 printf("snare(%i) at %i\n", indexForOnsets[2], snareTime);
|
andrew@20
|
143 recordedTempoData.updateTempo(2, snareTime);
|
andrew@53
|
144 // printf("recorded tempo is %f\n", recordedTempoData.playingTempo);
|
andrew@20
|
145 indexForOnsets[2]++;
|
andrew@20
|
146 }
|
andrew@20
|
147 }//end while
|
andrew@20
|
148
|
andrew@20
|
149 }
|
andrew@20
|
150
|
andrew@20
|
151 void AudioEventMatcher::setNextOnsetTime(const int& channel, int& time, int* indexForOnsets){
|
andrew@20
|
152 if (indexForOnsets[channel] < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){
|
andrew@20
|
153 time = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[indexForOnsets[channel]].millisTime;
|
andrew@20
|
154 }
|
andrew@20
|
155 else {
|
andrew@20
|
156 time = 2147483647;//infinity
|
andrew@20
|
157 }
|
andrew@16
|
158 }
|
andrew@16
|
159
|
andrew@9
|
160 void AudioEventMatcher::startPlaying(){
|
andrew@3
|
161 bayesianStruct.setStartPlaying();
|
andrew@8
|
162 currentAlignmentPosition = 0;
|
andrew@8
|
163 startTime = ofGetElapsedTimeMillis();
|
andrew@11
|
164
|
andrew@11
|
165 projectedPrior = bayesianStruct.prior;
|
andrew@15
|
166 startedPlaying = true;
|
andrew@17
|
167 synchroniser.reset();
|
andrew@19
|
168 temporal.reset();
|
andrew@17
|
169
|
andrew@20
|
170 recordedTempoIndex = 0;
|
andrew@20
|
171 recordedTempo = recordedTempoData.globalTempo[recordedTempoIndex];
|
andrew@20
|
172
|
andrew@55
|
173 printf("recorded tempo is %f\n", recordedTempo);
|
andrew@20
|
174 currentSpeedRatio = 1;
|
andrew@53
|
175 relativeTempo = 1;
|
andrew@20
|
176
|
andrew@55
|
177 temporal.reset();
|
andrew@55
|
178 // temporal.tempoPosterior.zero();
|
andrew@55
|
179 // temporal.tempoPosterior.addGaussianShapeFromRealTime(recordedTempo, 2000, 1);
|
andrew@21
|
180
|
andrew@20
|
181 //SET TEMPO PRIOR for Speed Ratio
|
andrew@20
|
182 //the update this
|
andrew@20
|
183 setSpeedRatioDistribution(currentSpeedRatio);
|
andrew@37
|
184
|
andrew@37
|
185 euclideanMaximumDistance = 0;
|
andrew@37
|
186
|
andrew@3
|
187 //bayesianStruct.posterior.printArray();
|
andrew@3
|
188 }
|
andrew@3
|
189
|
andrew@9
|
190
|
andrew@20
|
191 void AudioEventMatcher::setSpeedRatioDistribution(const double& speedRatio){
|
andrew@39
|
192 //here is the speed combo actually used
|
andrew@20
|
193 bayesianStruct.relativeSpeedPosterior.zero();
|
andrew@39
|
194 // bayesianStruct.relativeSpeedPosterior.addToIndex(bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(speedRatio), 1);
|
andrew@53
|
195 bayesianStruct.relativeSpeedPosterior.addGaussianShapeFromRealTime(speedRatio, 0.1, 3);
|
andrew@53
|
196 bayesianStruct.relativeSpeedPosterior.addGaussianShapeFromRealTime(speedRatio, 0.02, 2);
|
andrew@20
|
197 }
|
andrew@20
|
198
|
andrew@15
|
199 void AudioEventMatcher::stopPlaying(){
|
andrew@15
|
200 startedPlaying = false;
|
andrew@52
|
201 testDistributionOutput.closeFile();
|
andrew@37
|
202 //temporal.printEventTimes();
|
andrew@15
|
203 }
|
andrew@15
|
204
|
andrew@22
|
205 void AudioEventMatcher::rescue(){
|
andrew@22
|
206 bayesianStruct.posterior.zero();
|
andrew@22
|
207 bayesianStruct.posterior.addConstant(1);
|
andrew@22
|
208 bayesianStruct.prior.zero();
|
andrew@22
|
209 bayesianStruct.prior.addConstant(1);
|
andrew@22
|
210 }
|
andrew@22
|
211
|
andrew@50
|
212 #pragma mark -update
|
andrew@9
|
213 void AudioEventMatcher::updatePosition(){
|
andrew@19
|
214
|
andrew@19
|
215 if (startedPlaying){
|
andrew@50
|
216 /* if (!followingLiveInput)
|
andrew@9
|
217 recordedTracks.updatePosition();
|
andrew@19
|
218 else
|
andrew@50
|
219 */
|
andrew@9
|
220 recordedTracks.updatePositionToMillis(currentAlignmentPosition);
|
andrew@53
|
221 updateBestAlignmentPosition();
|
andrew@9
|
222
|
andrew@53
|
223 } else {
|
andrew@50
|
224 recordedTracks.updatePosition();
|
andrew@50
|
225 markerPlaybackPosition = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.playPositionFrames);
|
andrew@50
|
226 currentAlignmentPosition = markerPlaybackPosition;
|
andrew@19
|
227 }
|
andrew@19
|
228
|
andrew@56
|
229 if (updateTempoMethodOn){
|
andrew@56
|
230 updateRecordedTempo();
|
andrew@56
|
231 }
|
andrew@9
|
232 }
|
andrew@9
|
233
|
andrew@20
|
234 void AudioEventMatcher::updateRecordedTempo(){
|
andrew@20
|
235 //tempo of equivalent recorded position is updated
|
andrew@56
|
236
|
andrew@56
|
237 if (recordedTempoIndex < recordedTempoData.globalTempoTimes.size()){//if for debug
|
andrew@56
|
238 recordedTempo = getRecordedTempoAtMillis(currentAlignmentPosition);
|
andrew@55
|
239
|
andrew@56
|
240 double tmpRatio = currentSpeedRatio;
|
andrew@56
|
241
|
andrew@56
|
242 currentSpeedRatio = temporal.playingTempo / recordedTempo;
|
andrew@56
|
243 if (currentSpeedRatio != tmpRatio)
|
andrew@56
|
244 setSpeedRatioDistribution(currentSpeedRatio);
|
andrew@56
|
245
|
andrew@37
|
246 }//end if to prevent debug crash
|
andrew@56
|
247
|
andrew@56
|
248 temporal.tempoPosterior.addGaussianShape(temporal.tempoPosterior.MAPestimate, temporal.tempoArraySize / 4, 0.5 );
|
andrew@56
|
249
|
andrew@20
|
250 }
|
andrew@56
|
251
|
andrew@55
|
252 double AudioEventMatcher::getRecordedTempoAtMillis(const double& millisPosition){
|
andrew@56
|
253
|
andrew@55
|
254 while(currentAlignmentPosition < recordedTempoData.globalTempoTimes[recordedTempoIndex] && recordedTempoIndex > 0){
|
andrew@56
|
255 //this loop never used as sequential, so we expect the alignment time to be ahead of the last recorded tempo point
|
andrew@55
|
256 //but just in case
|
andrew@55
|
257 recordedTempoIndex--;
|
andrew@55
|
258 }
|
andrew@55
|
259
|
andrew@55
|
260 while(currentAlignmentPosition > recordedTempoData.globalTempoTimes[recordedTempoIndex]){
|
andrew@55
|
261 recordedTempoIndex++;
|
andrew@55
|
262 }
|
andrew@55
|
263
|
andrew@55
|
264 return recordedTempoData.globalTempo[recordedTempoIndex];
|
andrew@55
|
265 }
|
andrew@55
|
266
|
andrew@8
|
267 void AudioEventMatcher::updateBestAlignmentPosition(){
|
andrew@10
|
268 //THIS DEALS WITH WHERE WE ARE NOW! ON THE SCREEN
|
andrew@10
|
269 //DIFFERENT TO WHEN EVENTS COME IN AS THEY ARE TIMESTAMPED - SO EG A PITCH EVENT MAY ARRIVE 16 CHROMA FRAMES LATER - BIG DIFFERENCE
|
andrew@10
|
270
|
andrew@45
|
271 int newTime = getTimeNow();
|
andrew@10
|
272 // double tmp = bayesianStruct.posterior.getIndexInRealTerms(bayesianStruct.posterior.MAPestimate);;
|
andrew@10
|
273 // double timetmp = (newTime - lastAlignmentTime);
|
andrew@10
|
274 // double speedtmp = bayesianStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesianStruct.relativeSpeedPosterior.MAPestimate);
|
andrew@11
|
275 // currentAlignmentTime = newTime;
|
andrew@9
|
276 currentAlignmentPosition = bayesianStruct.posterior.getIndexInRealTerms(bayesianStruct.posterior.MAPestimate);
|
andrew@10
|
277 currentAlignmentPosition += (newTime - lastAlignmentTime) * bayesianStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesianStruct.relativeSpeedPosterior.MAPestimate);
|
andrew@10
|
278
|
andrew@16
|
279
|
andrew@17
|
280 synchroniser.updateRecordedPosition(currentAlignmentPosition, newTime);
|
andrew@16
|
281
|
andrew@16
|
282 synchroniser.updateOutputSpeed();
|
andrew@16
|
283
|
andrew@11
|
284 bayesianStruct.projectDistribution(newTime, currentAlignmentPosition, projectedPrior);//prior gets updated to where we are now
|
andrew@32
|
285
|
andrew@50
|
286 // printf("updateBestAlignment:: alignment %i:: %i\n", newTime, (int) currentAlignmentPosition);
|
andrew@10
|
287 // printf("ALIGN pos %f time diff %f (now %f , last %f)speed %f :: ALIGN BEST %f\n", tmp, timetmp, (double)ofGetElapsedTimeMillis(), lastAlignmentTime, speedtmp, currentAlignmentPosition);
|
andrew@8
|
288 }
|
andrew@8
|
289
|
andrew@45
|
290 int AudioEventMatcher::getTimeNow(){
|
andrew@45
|
291 return ofGetElapsedTimeMillis() - startTime;
|
andrew@45
|
292 }
|
andrew@45
|
293
|
andrew@50
|
294 #pragma mark -markers
|
andrew@50
|
295 void AudioEventMatcher::addMarkerNow(){
|
andrew@50
|
296 if (!startedPlaying)
|
andrew@50
|
297 markedPoints.addMarker(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.playPositionFrames));
|
andrew@50
|
298 }
|
andrew@50
|
299
|
andrew@50
|
300 void AudioEventMatcher::deleteMarkers(){
|
andrew@50
|
301 markedPoints.markers.clear();
|
andrew@50
|
302 }
|
andrew@50
|
303
|
andrew@50
|
304 void AudioEventMatcher::moveToNextMarker(){
|
andrew@50
|
305 int m = 0;
|
andrew@50
|
306 while (m < markedPoints.markers.size() && markedPoints.markers[m] < currentAlignmentPosition)
|
andrew@50
|
307 m++;
|
andrew@50
|
308
|
andrew@50
|
309
|
andrew@50
|
310 if (markedPoints.markers[m] > currentAlignmentPosition){
|
andrew@50
|
311 setPlaybackPosition(markedPoints.markers[m]);
|
andrew@50
|
312 printf("move to marker %f from current pos %f\n", markedPoints.markers[m], currentAlignmentPosition);
|
andrew@50
|
313 }
|
andrew@50
|
314
|
andrew@50
|
315 }
|
andrew@50
|
316
|
andrew@50
|
317 void AudioEventMatcher::moveToPreviousMarker(){
|
andrew@50
|
318 int m = 0;
|
andrew@50
|
319 while (m < markedPoints.markers.size() && markedPoints.markers[m] < currentAlignmentPosition)
|
andrew@50
|
320 m++;
|
andrew@50
|
321
|
andrew@51
|
322 if (m > 1 && markedPoints.markers[m-1] + 300 > currentAlignmentPosition)
|
andrew@51
|
323 setPlaybackPosition(markedPoints.markers[m-2]);
|
andrew@51
|
324 else if (m > 0 && markedPoints.markers[m-1] < currentAlignmentPosition){
|
andrew@50
|
325 setPlaybackPosition(markedPoints.markers[m-1]);
|
andrew@50
|
326 printf("move to marker %f from current pos %f\n", markedPoints.markers[m], currentAlignmentPosition);
|
andrew@50
|
327 }
|
andrew@51
|
328
|
andrew@51
|
329
|
andrew@50
|
330 }
|
andrew@50
|
331
|
andrew@50
|
332 void AudioEventMatcher::deleteNearestMarker(){
|
andrew@50
|
333 int m = 0;
|
andrew@50
|
334 while (m < markedPoints.markers.size() && markedPoints.markers[m] < currentAlignmentPosition)
|
andrew@50
|
335 m++;
|
andrew@50
|
336
|
andrew@50
|
337 int markerToDelete = m;
|
andrew@50
|
338 if (m >= 0 && fabs(markedPoints.markers[m] - currentAlignmentPosition) < fabs(markedPoints.markers[m-1] - currentAlignmentPosition)){
|
andrew@50
|
339 markerToDelete = m-1;
|
andrew@50
|
340 }
|
andrew@50
|
341
|
andrew@50
|
342 markedPoints.deleteMarker(markerToDelete);
|
andrew@50
|
343
|
andrew@50
|
344
|
andrew@50
|
345 }
|
andrew@50
|
346
|
andrew@50
|
347
|
andrew@50
|
348 void AudioEventMatcher::setPlaybackPosition(const double& millis){
|
andrew@50
|
349 if (!startedPlaying)
|
andrew@50
|
350 recordedTracks.updatePlaybackPositionToMillis(millis);
|
andrew@50
|
351 }
|
andrew@50
|
352
|
andrew@50
|
353 void AudioEventMatcher::goToMarker(const int& markerID){
|
andrew@50
|
354 if (startedPlaying && markerID >= 0 && markerID < markedPoints.markers.size()){
|
andrew@50
|
355 double markPosition = markedPoints.markers[markerID];
|
andrew@50
|
356 setToPosition(markPosition);
|
andrew@50
|
357 }
|
andrew@50
|
358
|
andrew@50
|
359 }
|
andrew@50
|
360
|
andrew@50
|
361 void AudioEventMatcher::mousePressed(const int& x){
|
andrew@50
|
362 if (!startedPlaying){
|
andrew@50
|
363 double position = (float) x * screenWidthMillis / ofGetWidth();
|
andrew@50
|
364 position += screenStartTimeMillis;
|
andrew@50
|
365 setPlaybackPosition(position);
|
andrew@50
|
366 }
|
andrew@50
|
367 }
|
andrew@50
|
368
|
andrew@50
|
369 void AudioEventMatcher::setToPosition(const double& position){
|
andrew@55
|
370 setNewLimits(position);
|
andrew@55
|
371
|
andrew@50
|
372 bayesianStruct.posterior.zero();
|
andrew@53
|
373 bayesianStruct.zeroDistributionAtPosition(bayesianStruct.posterior, position);
|
andrew@50
|
374 bayesianStruct.posterior.addGaussianShapeFromRealTime(position, 100, 1);
|
andrew@53
|
375
|
andrew@53
|
376 bayesianStruct.prior.zero();
|
andrew@53
|
377 bayesianStruct.zeroDistributionAtPosition(bayesianStruct.prior, position);
|
andrew@53
|
378 bayesianStruct.prior.addGaussianShapeFromRealTime(position, 100, 1);
|
andrew@53
|
379
|
andrew@50
|
380 // bayesianStruct.posterior.addConstant(0.1);
|
andrew@50
|
381 // bayesianStruct.prior.zero();
|
andrew@50
|
382 // bayesianStruct.prior.addConstant(1);
|
andrew@50
|
383 }
|
andrew@50
|
384
|
andrew@55
|
385
|
andrew@55
|
386 void AudioEventMatcher::setNewLimits(const double& position){
|
andrew@55
|
387 //update the distribution to the new limits
|
andrew@55
|
388 double difference = position - (bayesianStruct.prior.getIndexInRealTerms(bayesianStruct.prior.length/2));
|
andrew@55
|
389 bayesianStruct.prior.offset += difference;
|
andrew@55
|
390 bayesianStruct.likelihood.offset += difference;
|
andrew@55
|
391 bayesianStruct.posterior.offset += difference;
|
andrew@55
|
392
|
andrew@55
|
393 bayesianStruct.prior.zero();
|
andrew@55
|
394 bayesianStruct.posterior.zero();
|
andrew@55
|
395 bayesianStruct.likelihood.zero();
|
andrew@55
|
396 }
|
andrew@55
|
397
|
andrew@50
|
398 #pragma mark -draw
|
andrew@45
|
399
|
andrew@0
|
400 void AudioEventMatcher::draw(){
|
andrew@32
|
401
|
andrew@32
|
402 //MAIN DRAW FUNCTION FOR ALL
|
andrew@55
|
403
|
andrew@55
|
404 //ofBackground(255,255,255);
|
andrew@32
|
405
|
andrew@6
|
406 //draw some outlines in blue
|
andrew@3
|
407 ofSetColor(20,200,200);
|
andrew@39
|
408 // bayesPositionWindow.drawOutline();
|
andrew@39
|
409 // bayesTempoWindow.drawOutline();
|
andrew@0
|
410
|
andrew@6
|
411 //draw the scrolling audio tracks
|
andrew@1
|
412 recordedTracks.drawTracks();
|
andrew@7
|
413
|
andrew@2
|
414 ofSetColor(255);
|
andrew@2
|
415 // bayesianStruct.relativeSpeedPrior.drawVector(0, 200, bayesTempoWindow);
|
andrew@9
|
416
|
andrew@9
|
417 setScreenDisplayTimes();
|
andrew@6
|
418 drawBayesianDistributions();
|
andrew@8
|
419
|
andrew@11
|
420 //bayesianStruct.posterior.drawVector(0, bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow);
|
andrew@6
|
421 //bayesianStruct.posterior.drawVector(bayesianStruct.posterior.getRealTermsAsIndex(0), bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow);
|
andrew@11
|
422 //bayesianStruct.relativeSpeedPosterior.drawVector(0, bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(2), bayesTempoWindow);
|
andrew@9
|
423
|
andrew@55
|
424 //tempo
|
andrew@55
|
425 //temporal.drawTempoArray(bayesLikelihoodWindow);
|
andrew@50
|
426
|
andrew@50
|
427 if (printInfo){
|
andrew@55
|
428 drawRecordedTempo();
|
andrew@55
|
429 drawPlayingTempo();
|
andrew@55
|
430 drawAlignmentTimes();
|
andrew@50
|
431 }
|
andrew@20
|
432
|
andrew@50
|
433 drawMarkers();
|
andrew@20
|
434
|
andrew@6
|
435 }
|
andrew@20
|
436
|
andrew@20
|
437 void AudioEventMatcher::drawRecordedTempo(){
|
andrew@6
|
438
|
andrew@21
|
439 int xTempoIndex = ofGetWidth() * (double)(recordedTempo - recordedTempoData.minimumTempoInterval)/(double)(recordedTempoData.maximumTempoInterval - recordedTempoData.minimumTempoInterval);
|
andrew@20
|
440 ofSetColor(0, 200, 0);
|
andrew@20
|
441 ofLine(xTempoIndex, bayesLikelihoodWindow.y, xTempoIndex, bayesLikelihoodWindow.y + bayesLikelihoodWindow.height);
|
andrew@20
|
442 ofDrawBitmapString(ofToString(recordedTempo), xTempoIndex, bayesLikelihoodWindow.y + 10);
|
andrew@20
|
443 }
|
andrew@20
|
444
|
andrew@20
|
445 void AudioEventMatcher::drawPlayingTempo(){
|
andrew@21
|
446 //purple line for MAP estimate of new intervals
|
andrew@21
|
447 int xTempoIndex = (double)(ofGetWidth() * (temporal.playingTempo - temporal.minimumTempoInterval))/(double)(temporal.maximumTempoInterval - temporal.minimumTempoInterval);
|
andrew@20
|
448 ofSetColor(200, 0, 200);
|
andrew@20
|
449 ofLine(xTempoIndex, bayesLikelihoodWindow.y, xTempoIndex, bayesLikelihoodWindow.y + bayesLikelihoodWindow.height);
|
andrew@21
|
450 ofDrawBitmapString(ofToString(temporal.playingTempo), xTempoIndex, bayesLikelihoodWindow.y + 10);
|
andrew@20
|
451
|
andrew@21
|
452 //red line where the ratio is between playing tempo and recorded one
|
andrew@20
|
453 int xSpeedRatioIndex = (double)(temporal.tempoPosterior.getIndexInRealTerms(currentSpeedRatio)*ofGetWidth())/(double)temporal.tempoPosterior.arraySize;
|
andrew@20
|
454 ofSetColor(200,0,0);
|
andrew@20
|
455 ofLine(xSpeedRatioIndex, bayesTempoWindow.y, xSpeedRatioIndex, bayesTempoWindow.y + bayesTempoWindow.height);
|
andrew@50
|
456
|
andrew@50
|
457 if (printInfo){
|
andrew@21
|
458 string tmpString = "playing "+ofToString(temporal.playingTempo);
|
andrew@21
|
459 tmpString += ", recorded "+ofToString(recordedTempo);
|
andrew@21
|
460 tmpString += " ratio "+ofToString(currentSpeedRatio);
|
andrew@21
|
461 ofSetColor(155,155,155);
|
andrew@21
|
462 ofDrawBitmapString(tmpString, 20, bayesTempoWindow.y+10);
|
andrew@50
|
463 }
|
andrew@20
|
464 }
|
andrew@20
|
465
|
andrew@20
|
466
|
andrew@9
|
467 void AudioEventMatcher::setScreenDisplayTimes(){
|
andrew@9
|
468 screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber);
|
andrew@9
|
469 // if (!followingLiveInput){
|
andrew@9
|
470
|
andrew@9
|
471 screenStartTimeMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.drawParams.windowStartFrame);
|
andrew@9
|
472 screenEndTimeMillis = screenStartTimeMillis + screenWidthMillis;
|
andrew@9
|
473
|
andrew@9
|
474 //need PRECISION in this alignment
|
andrew@9
|
475
|
andrew@9
|
476
|
andrew@9
|
477 /*}else{
|
andrew@9
|
478
|
andrew@9
|
479 screenStartTimeMillis = (int)(currentAlignmentPosition/screenWidthMillis) * screenWidthMillis;
|
andrew@9
|
480 screenEndTimeMillis = screenStartTimeMillis + screenWidthMillis;
|
andrew@9
|
481 }*/
|
andrew@9
|
482 }
|
andrew@9
|
483
|
andrew@6
|
484 void AudioEventMatcher::drawBayesianDistributions(){
|
andrew@6
|
485
|
andrew@32
|
486
|
andrew@32
|
487 drawPositionWindow();
|
andrew@4
|
488
|
andrew@8
|
489 // bayesianStruct.likelihood.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesLikelihoodWindow);
|
andrew@2
|
490
|
andrew@6
|
491 bayesianStruct.relativeSpeedPosterior.drawConstrainedVector(0, bayesianStruct.relativeSpeedPosterior.arraySize, 0, ofGetWidth(), bayesTempoWindow);
|
andrew@32
|
492
|
andrew@50
|
493 if (drawLikelihoods)
|
andrew@55
|
494 drawTrackLikelihoods();
|
andrew@6
|
495
|
andrew@50
|
496
|
andrew@32
|
497
|
andrew@32
|
498 // int priorStartIndex = bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis);
|
andrew@32
|
499 // int priorEndIndex = bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis);
|
andrew@32
|
500 // ofSetColor(0,200,200);//recent prior
|
andrew@32
|
501 // recentPrior.drawConstrainedVector(priorStartIndex, priorEndIndex, 0, ofGetWidth(), bayesPositionWindow);
|
andrew@32
|
502
|
andrew@50
|
503 if (printInfo)
|
andrew@50
|
504 drawInfo();
|
andrew@32
|
505
|
andrew@3
|
506
|
andrew@32
|
507 }
|
andrew@32
|
508
|
andrew@32
|
509 void AudioEventMatcher::drawPositionWindow(){
|
andrew@32
|
510 int startIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenStartTimeMillis);
|
andrew@32
|
511 int endIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenEndTimeMillis);
|
andrew@32
|
512 string tmpString = "start "+ofToString(screenStartTimeMillis)+" (index "+ofToString(startIndex)+"), end "+ofToString(screenEndTimeMillis);
|
andrew@32
|
513 ofDrawBitmapString(tmpString, bayesPositionWindow.x+20, bayesPositionWindow.y+20);
|
andrew@32
|
514
|
andrew@32
|
515 //draw posterior in the bayes position window
|
andrew@32
|
516 ofSetColor(255,0,255);
|
andrew@32
|
517 bayesianStruct.posterior.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesPositionWindow);
|
andrew@3
|
518
|
andrew@9
|
519 //green line at current best estimate
|
andrew@13
|
520 ofSetColor(0,255,0);//green scrolling line best position
|
andrew@8
|
521 double currentEstimateIndex = (currentAlignmentPosition - screenStartTimeMillis)*ofGetWidth()/screenWidthMillis;
|
andrew@8
|
522 ofLine(currentEstimateIndex, bayesPositionWindow.y, currentEstimateIndex, bayesPositionWindow.y + bayesPositionWindow.height);
|
andrew@7
|
523
|
andrew@32
|
524
|
andrew@16
|
525 ofSetColor(0,255,255);//synchroniser position
|
andrew@16
|
526 currentEstimateIndex = (synchroniser.playingPositionMillis - screenStartTimeMillis)*ofGetWidth()/screenWidthMillis;
|
andrew@16
|
527 ofLine(currentEstimateIndex, bayesLikelihoodWindow.y, currentEstimateIndex, bayesLikelihoodWindow.y + bayesPositionWindow.height);
|
andrew@32
|
528
|
andrew@32
|
529 ofSetColor(255,0,100);//purple prior
|
andrew@32
|
530 bayesianStruct.prior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesPositionWindow);
|
andrew@16
|
531
|
andrew@32
|
532 ofSetColor(255,0,0);//projected prior in red
|
andrew@32
|
533 projectedPrior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesPositionWindow);
|
andrew@16
|
534
|
andrew@37
|
535 //draw pitch
|
andrew@37
|
536 ofSetColor(0,100,255);
|
andrew@37
|
537 int index = getScreenWidthIndexOfEventTime(recentPitchEventTime);
|
andrew@37
|
538 //this window would be used (recordedTracks.loadedAudioFiles[1].fileLoader.onsetDetect.window);
|
andrew@16
|
539
|
andrew@53
|
540 ofSetColor(255, 255, 255);
|
andrew@53
|
541 ofDrawBitmapString("curr.speed "+ofToString(synchroniser.smoothedSpeedOutput, 3), 20, ofGetHeight() - 10);
|
andrew@53
|
542
|
andrew@32
|
543 }
|
andrew@32
|
544
|
andrew@37
|
545 int AudioEventMatcher::getScreenWidthIndexOfEventTime(const double& time){
|
andrew@53
|
546 return (time - screenStartTimeMillis
|
andrew@53
|
547 )*ofGetWidth()/screenWidthMillis;
|
andrew@37
|
548 }
|
andrew@37
|
549
|
andrew@32
|
550 void AudioEventMatcher::drawTrackLikelihoods(){
|
andrew@7
|
551 //draw track by track likelihoods
|
andrew@7
|
552 for (int i = 0; i <recordedTracks.numberOfAudioTracks;i++){
|
andrew@13
|
553 ofSetColor(200,255,50);//channel likelihoods in yellow
|
andrew@8
|
554 likelihoodVisualisation[i].drawConstrainedVector(likelihoodVisualisation[i].getRealTermsAsIndex(screenStartTimeMillis), likelihoodVisualisation[i].getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), recordedTracks.loadedAudioFiles[i].fileLoader.onsetDetect.window);
|
andrew@11
|
555
|
andrew@13
|
556 ofSetColor(0,255,150);//channel priors
|
andrew@11
|
557 recentPriors[i].drawConstrainedVector(recentPriors[i].getRealTermsAsIndex(screenStartTimeMillis), recentPriors[i].getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), recordedTracks.loadedAudioFiles[i].fileLoader.onsetDetect.window);
|
andrew@11
|
558
|
andrew@50
|
559 if (printInfo){
|
andrew@8
|
560 ofSetColor(255);
|
andrew@8
|
561 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@50
|
562 }
|
andrew@7
|
563 }
|
andrew@32
|
564 }
|
andrew@8
|
565
|
andrew@8
|
566
|
andrew@32
|
567 void AudioEventMatcher::drawInfo(){
|
andrew@32
|
568 string tmpStr = "zero is "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(0));
|
andrew@32
|
569 tmpStr += " offsetis "+ofToString(bayesianStruct.posterior.offset);
|
andrew@32
|
570 tmpStr += " screenWidth = "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis));
|
andrew@32
|
571 ofDrawBitmapString(tmpStr, 20,140);
|
andrew@32
|
572 tmpStr = "best est "+ofToString(bayesianStruct.bestEstimate);
|
andrew@32
|
573 ofDrawBitmapString(tmpStr, 20, 180);
|
andrew@45
|
574 //ofDrawBitmapString("screenwidth "+ofToString(screenWidthMillis), 20, 800);
|
andrew@11
|
575
|
andrew@32
|
576 ofSetColor(255);
|
andrew@32
|
577 tmpStr = "pitch "+ofToString(recentPitch, 2);
|
andrew@32
|
578 tmpStr += " Nearest "+ofToString(pitchOfNearestMatch,2);
|
andrew@32
|
579 tmpStr += " dist "+ofToString(distanceOfNearestMatch, 2);
|
andrew@37
|
580 tmpStr += ", Time "+ofToString(recentPitchEventTime, 0);
|
andrew@32
|
581 ofDrawBitmapString(tmpStr, 20, 20);
|
andrew@7
|
582
|
andrew@39
|
583 string alignString = "align "+ofToString(currentAlignmentPosition, 2);//same as synchroniser-recordedposition
|
andrew@32
|
584 alignString += " playing "+ofToString(synchroniser.playingPositionRatio, 5);
|
andrew@39
|
585 alignString += " pos "+ofToString(synchroniser.playingPositionMillis,0)+" ms";//playing position in file - causal correction
|
andrew@39
|
586 alignString += " rec pos "+ofToString(synchroniser.recordedPositionMillis,0)+" ms";//currentAlignmentPosition in rehearsal
|
andrew@39
|
587 alignString += "playing time "+ofToString(synchroniser.recordedPositionTimeSent, 0)+" ms";//playing time since begining of live take
|
andrew@32
|
588 ofDrawBitmapString(alignString, 20, 50);
|
andrew@32
|
589 ofDrawBitmapString("pos "+ofToString(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.playPosition), 200,600);
|
andrew@19
|
590
|
andrew@1
|
591 }
|
andrew@1
|
592
|
andrew@45
|
593
|
andrew@45
|
594 void AudioEventMatcher::drawAlignmentTimes(){
|
andrew@45
|
595 ofSetColor(255);
|
andrew@45
|
596 std::string dataString = "Live time "+ofToString(synchroniser.recordedPositionTimeSent);
|
andrew@45
|
597 dataString += ", Reh time "+ofToString(synchroniser.recordedPositionMillis);
|
andrew@53
|
598 ofDrawBitmapString(dataString, 10, ofGetHeight() - 40);
|
andrew@45
|
599
|
andrew@45
|
600 }
|
andrew@45
|
601
|
andrew@45
|
602
|
andrew@50
|
603 void AudioEventMatcher::drawMarkers(){
|
andrew@50
|
604 int i = 0;
|
andrew@50
|
605 while (i < markedPoints.markers.size() && markedPoints.markers[i] < screenStartTimeMillis)
|
andrew@50
|
606 i++;
|
andrew@50
|
607
|
andrew@50
|
608 while (i < markedPoints.markers.size() && markedPoints.markers[i] < screenStartTimeMillis + screenWidthMillis) {
|
andrew@50
|
609 ofSetColor(255,255,60);
|
andrew@50
|
610 double markerPosition = (markedPoints.markers[i] - screenStartTimeMillis)*ofGetWidth()/screenWidthMillis;
|
andrew@50
|
611 ofLine(markerPosition, bayesPositionWindow.y, markerPosition, bayesPositionWindow.y + bayesPositionWindow.height);
|
andrew@50
|
612 //printf("marker %f pos %f\n", markedPoints.markers[i], markerPosition);
|
andrew@50
|
613 i++;
|
andrew@50
|
614
|
andrew@52
|
615 ofDrawBitmapString(ofToString(i), markerPosition, bayesPositionWindow.y);
|
andrew@52
|
616
|
andrew@50
|
617 }
|
andrew@50
|
618 }
|
andrew@50
|
619
|
andrew@50
|
620 #pragma mark -newEvents
|
andrew@50
|
621
|
andrew@6
|
622 void AudioEventMatcher::newPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){
|
andrew@7
|
623 if (pitchIn > 0){
|
andrew@1
|
624 liveInput.addPitchEvent(pitchIn, timeIn);
|
andrew@4
|
625
|
andrew@10
|
626 //printPosteriorMAPinfo();
|
andrew@11
|
627
|
andrew@7
|
628 matchNewPitchEvent(channel, pitchIn, timeIn);//main pitch matching fn
|
andrew@7
|
629
|
andrew@7
|
630 likelihoodVisualisation[1] = bayesianStruct.likelihood;
|
andrew@7
|
631
|
andrew@7
|
632 recentPitch = pitchIn;//for drawing
|
andrew@37
|
633 recentPitchEventTime = timeIn;
|
andrew@7
|
634 }
|
andrew@53
|
635 checkTempo();
|
andrew@32
|
636 }
|
andrew@32
|
637
|
andrew@32
|
638
|
andrew@32
|
639 void AudioEventMatcher::newChromaEvent(const int& channel, float* chromaIn, const double& timeIn){
|
andrew@32
|
640
|
andrew@32
|
641 // could add event to the liveInput list? as in pitch event
|
andrew@37
|
642 if (printingData){
|
andrew@37
|
643 printf("match chroma channel %i\n", channel);
|
andrew@37
|
644 for (int i = 0;i < 12;i++){
|
andrew@34
|
645 printf("chroma in[%i] = %f\n", i, chromaIn[i]);
|
andrew@37
|
646 }
|
andrew@34
|
647 }
|
andrew@34
|
648
|
andrew@32
|
649 matchNewChromaEvent(channel, chromaIn, timeIn);//main pitch matching fn
|
andrew@32
|
650
|
andrew@32
|
651 likelihoodVisualisation[channel] = bayesianStruct.likelihood;
|
andrew@32
|
652
|
andrew@53
|
653 checkTempo();
|
andrew@2
|
654 }
|
andrew@2
|
655
|
andrew@32
|
656
|
andrew@6
|
657 void AudioEventMatcher::newKickEvent(const double& timeIn){
|
andrew@6
|
658 // liveInput.addKickEvent(timeIn);
|
andrew@53
|
659 newKickEvent(0, timeIn);
|
andrew@53
|
660 // matchNewOnsetEvent(0, timeIn);
|
andrew@53
|
661 // likelihoodVisualisation[0] = bayesianStruct.likelihood;
|
andrew@2
|
662 }
|
andrew@2
|
663
|
andrew@6
|
664 void AudioEventMatcher::newKickEvent(const int& channel, const double& timeIn){
|
andrew@6
|
665 // liveInput.addKickEvent(timeIn);
|
andrew@6
|
666 matchNewOnsetEvent(channel, timeIn);
|
andrew@7
|
667 likelihoodVisualisation[0] = bayesianStruct.likelihood;
|
andrew@53
|
668 checkTempo();
|
andrew@6
|
669 }
|
andrew@6
|
670
|
andrew@2
|
671
|
andrew@2
|
672 void AudioEventMatcher::newSnareEvent(const double& timeIn){
|
andrew@53
|
673 newSnareEvent(2, timeIn);
|
andrew@53
|
674
|
andrew@53
|
675 // matchNewOnsetEvent(2, timeIn);
|
andrew@53
|
676 // likelihoodVisualisation[2] = bayesianStruct.likelihood;
|
andrew@7
|
677 }
|
andrew@7
|
678
|
andrew@7
|
679 void AudioEventMatcher::newSnareEvent(const int& channel, const double& timeIn){
|
andrew@7
|
680 matchNewOnsetEvent(channel, timeIn);
|
andrew@7
|
681 likelihoodVisualisation[2] = bayesianStruct.likelihood;
|
andrew@53
|
682 checkTempo();
|
andrew@2
|
683 }
|
andrew@2
|
684
|
andrew@53
|
685 void AudioEventMatcher::checkTempo(){
|
andrew@53
|
686
|
andrew@53
|
687 if (synchroniser.speed > 0.92 && synchroniser.speed < 1.08){
|
andrew@53
|
688 // double relativeTempo = 1 +
|
andrew@53
|
689 // relativeTempo += 0.4 * (synchroniser.speed - relativeTempo);
|
andrew@53
|
690 printf("Speed %f new tempo %f\n\n", synchroniser.speed, synchroniser.smoothedSpeedOutput);
|
andrew@53
|
691 setSpeedRatioDistribution(synchroniser.smoothedSpeedOutput);
|
andrew@53
|
692 }
|
andrew@53
|
693
|
andrew@53
|
694 }
|
andrew@53
|
695
|
andrew@53
|
696
|
andrew@50
|
697 #pragma mark -EventMatching
|
andrew@2
|
698 //Needs just to set bounds for the matching process, not have TimeIn
|
andrew@2
|
699 void AudioEventMatcher::matchNewOnsetEvent(const int& channel, const double& timeIn){
|
andrew@3
|
700
|
andrew@6
|
701 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
|
andrew@10
|
702
|
andrew@2
|
703 //start at beginning but OPTIMISE later
|
andrew@2
|
704 bayesianStruct.likelihood.offset = bayesianStruct.prior.offset;
|
andrew@2
|
705 bayesianStruct.likelihood.zero();//set to zero
|
andrew@36
|
706 //double quantity = 1;//
|
andrew@53
|
707 double quantity;
|
andrew@53
|
708
|
andrew@53
|
709 switch (channel) {
|
andrew@53
|
710 case 0:
|
andrew@53
|
711 quantity = kickLikelihoodToNoise;// onsetLikelihoodToNoise;
|
andrew@53
|
712 //BETTER CHANGE THIS BACK TOO..see below//likelihoodToNoiseRatio / numberOfMatches;
|
andrew@53
|
713 break;
|
andrew@53
|
714 case 2:
|
andrew@53
|
715 quantity = snareLikelihoodToNoise;// onsetLikelihoodToNoise;
|
andrew@53
|
716 //BETTER CHANGE THIS BACK TOO..see below//likelihoodToNoiseRatio / numberOfMatches;
|
andrew@53
|
717 break;
|
andrew@53
|
718 }
|
andrew@53
|
719
|
andrew@53
|
720
|
andrew@53
|
721
|
andrew@2
|
722 int numberOfMatchesFound = 0;
|
andrew@45
|
723 double nearestOnsetDistance = 1000;
|
andrew@10
|
724 double startMatchingTime = bayesianStruct.likelihood.offset;
|
andrew@10
|
725 double endMatchingTime = bayesianStruct.likelihood.offset + matchWindowWidth;
|
andrew@32
|
726 double millisTime = -1*INFINITY;//or 0 is fine
|
andrew@32
|
727 int checkIndex = 0;
|
andrew@36
|
728 if (channel <= recordedTracks.numberOfAudioTracks && checkIndex < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){
|
andrew@32
|
729 while (millisTime < startMatchingTime) {
|
andrew@32
|
730 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[checkIndex].millisTime;
|
andrew@32
|
731 checkIndex++;
|
andrew@32
|
732 }
|
andrew@32
|
733 for (int i = checkIndex;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size() && millisTime <= endMatchingTime;i++){
|
andrew@32
|
734 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
|
andrew@10
|
735 if (millisTime >= startMatchingTime && millisTime <= endMatchingTime){
|
andrew@14
|
736 bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, onsetLikelihoodWidth, quantity);
|
andrew@2
|
737 numberOfMatchesFound++;
|
andrew@6
|
738 // printf("Adding Gaussian for onset at time %f offset %f\n", millisTime, bayesianStruct.likelihood.offset);
|
andrew@45
|
739 if (fabs(currentAlignmentPosition - millisTime) < nearestOnsetDistance)
|
andrew@45
|
740 nearestOnsetDistance = currentAlignmentPosition - millisTime;
|
andrew@32
|
741 }//end if within limits (changed so it now is 4 sure)
|
andrew@2
|
742 }
|
andrew@2
|
743 }
|
andrew@2
|
744
|
andrew@11
|
745 if (numberOfMatchesFound > 0){
|
andrew@3
|
746 // bayesianStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesianStruct.likelihood.length);
|
andrew@36
|
747 // bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-onsetLikelihoodToNoise)/(onsetLikelihoodToNoise*bayesianStruct.likelihood.length));
|
andrew@53
|
748 bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-quantity)/(bayesianStruct.likelihood.length));//BETTER CHANGE THIS BACK...
|
andrew@2
|
749 bayesianStruct.likelihood.renormalise();
|
andrew@2
|
750
|
andrew@8
|
751 bayesianStruct.calculatePosterior();
|
andrew@10
|
752 lastAlignmentTime = timeIn;//use TIMESTAMP
|
andrew@10
|
753 recentEventTime[channel] = timeIn;//ofGetElapsedTimeMillis() - startTime;
|
andrew@11
|
754
|
andrew@11
|
755 recentPriors[channel] = bayesianStruct.prior;
|
andrew@13
|
756 projectedPrior = bayesianStruct.prior;
|
andrew@19
|
757
|
andrew@19
|
758
|
andrew@19
|
759 temporal.updateTempo(channel, timeIn);
|
andrew@11
|
760 }
|
andrew@45
|
761 int timeNow = getTimeNow();
|
andrew@11
|
762
|
andrew@45
|
763 printf("Nearest onset is %.1f time is %i and alignemnt %i time now %i\n", nearestOnsetDistance, (int) timeIn, (int)currentAlignmentPosition, timeNow);
|
andrew@3
|
764 }
|
andrew@3
|
765
|
andrew@3
|
766
|
andrew@3
|
767
|
andrew@3
|
768 void AudioEventMatcher::matchNewPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){
|
andrew@3
|
769 //start at beginning but OPTIMISE later
|
andrew@10
|
770 /*printf("TIME %i\n", ofGetElapsedTimeMillis());
|
andrew@10
|
771 //tmp debug
|
andrew@10
|
772 updateBestAlignmentPosition();
|
andrew@10
|
773 printf("current alignment best estimate %f\n", currentAlignmentPosition);
|
andrew@10
|
774 */
|
andrew@6
|
775 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
|
andrew@8
|
776
|
andrew@7
|
777 //set the lielihoods by matching the pitched note
|
andrew@7
|
778
|
andrew@15
|
779
|
andrew@3
|
780 int numberOfMatches = 0;
|
andrew@3
|
781 bayesianStruct.likelihood.zero();//set to zero
|
andrew@18
|
782 double newOnsetTime;
|
andrew@18
|
783 double closestDistance = INFINITY;
|
andrew@3
|
784
|
andrew@3
|
785 double quantity = 0;
|
andrew@32
|
786 double totalLikelihoodAdded = 0;
|
andrew@3
|
787 if (channel <= recordedTracks.numberOfAudioTracks){
|
andrew@3
|
788 for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){
|
andrew@3
|
789
|
andrew@3
|
790 if (checkMatch(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn)) {
|
andrew@56
|
791 quantity = getPitchDistance(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn, pitchWidth);
|
andrew@18
|
792
|
andrew@56
|
793 bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, pitchLikelihoodWidth, quantity);
|
andrew@3
|
794 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = true;
|
andrew@3
|
795 numberOfMatches++;
|
andrew@32
|
796 totalLikelihoodAdded += quantity;
|
andrew@3
|
797 }
|
andrew@3
|
798 else{
|
andrew@3
|
799 recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = false;
|
andrew@3
|
800 }
|
andrew@18
|
801 //checking nearest pitch
|
andrew@18
|
802 newOnsetTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
|
andrew@18
|
803 if (abs(newOnsetTime - currentAlignmentPosition) < closestDistance){
|
andrew@18
|
804 closestDistance = abs(newOnsetTime - currentAlignmentPosition);
|
andrew@18
|
805 pitchOfNearestMatch = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch;
|
andrew@18
|
806 distanceOfNearestMatch = quantity;
|
andrew@18
|
807 }
|
andrew@3
|
808
|
andrew@3
|
809 }
|
andrew@3
|
810 }
|
andrew@6
|
811
|
andrew@8
|
812
|
andrew@8
|
813
|
andrew@37
|
814 if (numberOfMatches > 0 && totalLikelihoodAdded > 0){//no point updating unless there is a match
|
andrew@32
|
815 //replacing numberOfMatches with totalLike below...
|
andrew@37
|
816 //bug here was that if totaladded = 0, we add then zero likelihood
|
andrew@37
|
817 bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-pitchLikelihoodToNoise)/(bayesianStruct.likelihood.length));
|
andrew@37
|
818 // bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-pitchLikelihoodToNoise)/(pitchLikelihoodToNoise*bayesianStruct.likelihood.length));
|
andrew@4
|
819
|
andrew@4
|
820 //tmp set likelihood constant and calculate using that
|
andrew@6
|
821 //bayesianStruct.likelihood.zero();
|
andrew@6
|
822 //bayesianStruct.likelihood.addConstant(1);
|
andrew@7
|
823
|
andrew@6
|
824 bayesianStruct.calculatePosterior();
|
andrew@11
|
825 lastAlignmentTime = timeIn;//has to use the STAMPED time
|
andrew@11
|
826 recentEventTime[channel] = timeIn;
|
andrew@11
|
827
|
andrew@11
|
828 recentPriors[channel] = bayesianStruct.prior;
|
andrew@13
|
829 projectedPrior = bayesianStruct.prior;
|
andrew@19
|
830
|
andrew@19
|
831 temporal.eventTimes[channel].push_back(timeIn);
|
andrew@6
|
832 }
|
andrew@4
|
833
|
andrew@11
|
834
|
andrew@1
|
835 }
|
andrew@1
|
836
|
andrew@3
|
837 double AudioEventMatcher::getPitchDistance(const double& pitchOne, const double& pitchTwo, const double& scale){
|
andrew@3
|
838
|
andrew@18
|
839 double scaleFactor = scale * pitchOne / 110.0;
|
andrew@16
|
840
|
andrew@18
|
841 int multiplicationFactor = 1;
|
andrew@18
|
842 if (pitchTwo > 0){
|
andrew@32
|
843 multiplicationFactor = round(pitchOne/pitchTwo);
|
andrew@18
|
844 }
|
andrew@16
|
845
|
andrew@18
|
846 double distance = abs(pitchOne - pitchTwo*multiplicationFactor);
|
andrew@16
|
847 if (distance < scaleFactor)
|
andrew@16
|
848 distance = 1 - (distance/scaleFactor);
|
andrew@3
|
849 else
|
andrew@3
|
850 distance = 0;
|
andrew@3
|
851
|
andrew@32
|
852 //printf("[pitch distance %f vs %f, factor %i = %f\n", pitchOne, pitchTwo, multiplicationFactor, distance);
|
andrew@3
|
853 return distance;
|
andrew@3
|
854
|
andrew@3
|
855 }
|
andrew@3
|
856
|
andrew@3
|
857
|
andrew@3
|
858 bool AudioEventMatcher::checkMatch(const double& recordedPitch, const double& livePitch){
|
andrew@18
|
859
|
andrew@18
|
860 if (livePitch > 0){
|
andrew@18
|
861 int multiplicationFactor = (int)(round(recordedPitch/livePitch));
|
andrew@18
|
862
|
andrew@32
|
863 if (abs(recordedPitch - livePitch * multiplicationFactor) < pitchCutOff)
|
andrew@3
|
864 return true;
|
andrew@3
|
865 else
|
andrew@3
|
866 return false;
|
andrew@18
|
867 }else {
|
andrew@18
|
868 return false;
|
andrew@18
|
869 }
|
andrew@18
|
870
|
andrew@3
|
871 }
|
andrew@3
|
872
|
andrew@3
|
873
|
andrew@32
|
874 void AudioEventMatcher::matchNewChromaEvent(const int& channel, float* chromaIn, const double& timeIn){
|
andrew@32
|
875 //start at beginning but OPTIMISE later
|
andrew@32
|
876
|
andrew@52
|
877 makeQuantisedChroma(chromaIn);
|
andrew@52
|
878
|
andrew@32
|
879 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets
|
andrew@32
|
880
|
andrew@32
|
881 //set the likelihoods by matching the pitched note
|
andrew@32
|
882
|
andrew@32
|
883 int numberOfMatches = 0;
|
andrew@32
|
884 bayesianStruct.likelihood.zero();//set to zero
|
andrew@32
|
885 double newOnsetTime;
|
andrew@32
|
886 double closestDistance = INFINITY;
|
andrew@32
|
887
|
andrew@32
|
888 double quantity = 1;
|
andrew@32
|
889 double totalLikelihoodAdded = 0;
|
andrew@32
|
890
|
andrew@32
|
891 double startMatchingTime = bayesianStruct.likelihood.offset;
|
andrew@32
|
892 double endMatchingTime = bayesianStruct.likelihood.offset + matchWindowWidth;
|
andrew@32
|
893 double millisTime = -1*INFINITY;//or 0 is fine
|
andrew@32
|
894
|
andrew@32
|
895 int checkIndex = 0;
|
andrew@37
|
896 if (channel <= recordedTracks.numberOfAudioTracks && checkIndex < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){
|
andrew@37
|
897
|
andrew@32
|
898 while (millisTime < startMatchingTime) {
|
andrew@32
|
899 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[checkIndex].millisTime;
|
andrew@32
|
900 checkIndex++;
|
andrew@32
|
901 }//go up to where we need to check from fast
|
andrew@32
|
902
|
andrew@32
|
903 for (int i = checkIndex;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size() && millisTime <= endMatchingTime;i++){
|
andrew@32
|
904 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
|
andrew@32
|
905
|
andrew@32
|
906 if (millisTime >= startMatchingTime && millisTime <= endMatchingTime){
|
andrew@35
|
907
|
andrew@52
|
908 //for cts chroma
|
andrew@52
|
909 /*
|
andrew@35
|
910 if (useChromaDotProduct)
|
andrew@35
|
911 quantity = getChromaDotProductDistance(chromaIn, &recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].chromaValues[0]);
|
andrew@35
|
912 else
|
andrew@35
|
913 quantity = getChromaEuclideanDistance(chromaIn, &recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].chromaValues[0]);
|
andrew@52
|
914 */
|
andrew@52
|
915 // printf("Distance old way %f", quantity);
|
andrew@35
|
916
|
andrew@52
|
917 //for quantised chroma
|
andrew@52
|
918 quantity = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].getChromaQuantisedDistance(&quantisedChromagramReceived[0]);
|
andrew@52
|
919
|
andrew@52
|
920 // printf(" quantised %f\n", quantity);
|
andrew@35
|
921
|
andrew@32
|
922 bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, chromaLikelihoodWidth, quantity);
|
andrew@32
|
923
|
andrew@32
|
924 // bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, onsetLikelihoodWidth, quantity);
|
andrew@32
|
925 numberOfMatches++;
|
andrew@32
|
926 totalLikelihoodAdded += quantity;
|
andrew@37
|
927
|
andrew@37
|
928 //printf("Adding CHROMA Gaussian for onset at time %.1f dist %.3f\n", millisTime, quantity);
|
andrew@32
|
929
|
andrew@32
|
930 }//end if within limits (changed so it now is 4 sure)
|
andrew@32
|
931 }
|
andrew@32
|
932 }
|
andrew@32
|
933
|
andrew@32
|
934
|
andrew@37
|
935 if (numberOfMatches > 0 && totalLikelihoodAdded > 0){//no point updating unless there is a match
|
andrew@32
|
936 //replacing numberOfMatches with totalLike below...
|
andrew@32
|
937
|
andrew@32
|
938 printf("CHROMA HAS %i MATCHES\n", numberOfMatches);
|
andrew@32
|
939
|
andrew@37
|
940 bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-chromaLikelihoodToNoise)/(bayesianStruct.likelihood.length));
|
andrew@37
|
941 //previous way
|
andrew@37
|
942 // bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-chromaLikelihoodToNoise)/(chromaLikelihoodToNoise*bayesianStruct.likelihood.length));
|
andrew@32
|
943
|
andrew@32
|
944 bayesianStruct.calculatePosterior();
|
andrew@32
|
945 lastAlignmentTime = timeIn;//has to use the STAMPED time
|
andrew@32
|
946 recentEventTime[channel] = timeIn;
|
andrew@32
|
947
|
andrew@32
|
948 recentPriors[channel] = bayesianStruct.prior;
|
andrew@32
|
949 projectedPrior = bayesianStruct.prior;
|
andrew@32
|
950
|
andrew@32
|
951 temporal.eventTimes[channel].push_back(timeIn);
|
andrew@32
|
952 }
|
andrew@32
|
953
|
andrew@32
|
954 }
|
andrew@32
|
955
|
andrew@52
|
956 void AudioEventMatcher::makeQuantisedChroma(float* chromaIn){
|
andrew@52
|
957 double L_norm = 0;
|
andrew@52
|
958
|
andrew@52
|
959 for (int i = 0;i < 12;i++){
|
andrew@52
|
960 L_norm += chromaIn[i];
|
andrew@52
|
961 }
|
andrew@52
|
962
|
andrew@52
|
963 if (L_norm > 0){
|
andrew@52
|
964 for (int i = 0;i < 12;i++){
|
andrew@52
|
965 chromaIn[i] /= L_norm;//NB not const fn!
|
andrew@52
|
966 quantisedChromagramReceived[i] = 0;
|
andrew@52
|
967
|
andrew@52
|
968 if (chromaIn[i] > 0.05)
|
andrew@52
|
969 quantisedChromagramReceived[i]++;
|
andrew@52
|
970
|
andrew@52
|
971 if (chromaIn[i] > 0.1)
|
andrew@52
|
972 quantisedChromagramReceived[i]++;
|
andrew@52
|
973
|
andrew@52
|
974 if (chromaIn[i] > 0.2)
|
andrew@52
|
975 quantisedChromagramReceived[i]++;
|
andrew@52
|
976
|
andrew@52
|
977 if (chromaIn[i] > 0.4)
|
andrew@52
|
978 quantisedChromagramReceived[i]++;
|
andrew@52
|
979
|
andrew@52
|
980 }
|
andrew@52
|
981 }
|
andrew@52
|
982 }
|
andrew@32
|
983
|
andrew@35
|
984 double AudioEventMatcher::getChromaDotProductDistance(float* chromaOne, float* chromaTwo){
|
andrew@32
|
985 double distance = 0;
|
andrew@32
|
986 double total = 0;
|
andrew@32
|
987 for (int i = 0;i < 12;i++){
|
andrew@32
|
988 distance += chromaOne[i]*chromaTwo[i];
|
andrew@32
|
989 total += chromaOne[i]*chromaOne[i] + (chromaTwo[i]*chromaTwo[i]);
|
andrew@32
|
990 }
|
andrew@32
|
991
|
andrew@35
|
992 if (total > 0)
|
andrew@35
|
993 distance /= sqrt(total);
|
andrew@35
|
994
|
andrew@35
|
995 return distance;
|
andrew@35
|
996 }
|
andrew@35
|
997
|
andrew@35
|
998 double AudioEventMatcher::getChromaEuclideanDistance(float* chromaOne, float* chromaTwo){
|
andrew@35
|
999 double distance = 0;
|
andrew@35
|
1000 double total = 0;
|
andrew@37
|
1001
|
andrew@35
|
1002 // printf("\n");
|
andrew@35
|
1003 for (int i = 0;i < 12;i++){
|
andrew@35
|
1004 total += (chromaOne[i] - chromaTwo[i])*(chromaOne[i] - chromaTwo[i]);
|
andrew@35
|
1005 // printf("chroma1: %.2f; chroma2: %.2f\n", chromaOne[i], chromaTwo[i]);
|
andrew@35
|
1006 // total += chromaOne[i]*chromaOne[i] + (chromaTwo[i]*chromaTwo[i]);
|
andrew@35
|
1007 }
|
andrew@35
|
1008
|
andrew@37
|
1009 if (total > euclideanMaximumDistance)
|
andrew@37
|
1010 euclideanMaximumDistance = total;
|
andrew@37
|
1011
|
andrew@37
|
1012 distance = ((euclideanMaximumDistance - total)/ euclideanMaximumDistance);//i.e. 1 is
|
andrew@37
|
1013
|
andrew@37
|
1014 // if (total > 0)
|
andrew@37
|
1015
|
andrew@37
|
1016
|
andrew@37
|
1017 // distance = 1.0/sqrt(total);
|
andrew@35
|
1018 // printf("DISTANCE : %.3f\n", distance);
|
andrew@32
|
1019 return distance;
|
andrew@32
|
1020 }
|
andrew@1
|
1021
|
andrew@1
|
1022 void AudioEventMatcher::windowResized(const int& w, const int& h){
|
andrew@1
|
1023 recordedTracks.windowResized(w,h);
|
andrew@3
|
1024 bayesTempoWindow.resized(w,h);
|
andrew@3
|
1025 bayesPositionWindow.resized(w,h);
|
andrew@50
|
1026 bayesLikelihoodWindow.resized(w, h);
|
andrew@3
|
1027 }
|
andrew@3
|
1028
|
andrew@52
|
1029 void AudioEventMatcher::writeAllDistributions(){
|
andrew@55
|
1030 std::string filepath = "../../../data/distributions/priorDistbnOutput.txt";
|
andrew@53
|
1031 writeDistribution(bayesianStruct.prior, filepath);
|
andrew@55
|
1032 filepath = "../../../data/distributions/likelihoodDistbnOutput.txt";
|
andrew@53
|
1033 writeDistribution(bayesianStruct.likelihood, filepath);
|
andrew@55
|
1034 filepath = "../../../data/distributions/posteriorDistbnOutput.txt";
|
andrew@53
|
1035 writeDistribution(bayesianStruct.posterior, filepath);
|
andrew@52
|
1036
|
andrew@55
|
1037 //write kick events
|
andrew@55
|
1038 filepath = "../../../data/distributions/kickEvents.txt";
|
andrew@55
|
1039 writeKickEvent(screenStartTimeMillis, screenEndTimeMillis, filepath);
|
andrew@55
|
1040
|
andrew@55
|
1041 ofBackground(255);
|
andrew@52
|
1042 recordedTracks.drawTracks();
|
andrew@55
|
1043 filepath = "../../../data/distributions/screenGraphics.png";
|
andrew@52
|
1044 img.grabScreen(0, 0, ofGetWidth(), ofGetHeight());
|
andrew@52
|
1045 img.saveImage(filepath);
|
andrew@55
|
1046
|
andrew@55
|
1047 ofBackground(0);
|
andrew@52
|
1048 }
|
andrew@52
|
1049
|
andrew@52
|
1050 void AudioEventMatcher::writeDistribution(DynamicVector& distribution, std::string filename){
|
andrew@52
|
1051 testDistributionOutput.openFile(filename);
|
andrew@52
|
1052
|
andrew@52
|
1053 int minIndex = distribution.getRealTermsAsIndex(screenStartTimeMillis);
|
andrew@52
|
1054 int maxIndex = distribution.getRealTermsAsIndex(screenEndTimeMillis);
|
andrew@52
|
1055 int minScreenIndex = 0;
|
andrew@52
|
1056 int maxScreenIndex = ofGetWidth();
|
andrew@52
|
1057
|
andrew@52
|
1058 double stepSize = (maxScreenIndex - minScreenIndex) / (double)(maxIndex - minIndex);//step size in pixels per array bin
|
andrew@52
|
1059 double screenHeight = ofGetHeight();
|
andrew@52
|
1060 double maxVal = distribution.getMaximum();
|
andrew@52
|
1061
|
andrew@52
|
1062 //OPTIMIZE!! XXX could just add stepsize each time
|
andrew@52
|
1063 //not add minindex each time
|
andrew@52
|
1064 int i = max(1,minIndex+1);
|
andrew@52
|
1065 // ofDrawBitmapString("i = "+ofToString(i)+" :: screen min: "+ofToString(minScreenIndex + stepSize*(i-minIndex-1)), 20, 640);
|
andrew@52
|
1066
|
andrew@52
|
1067 while ((minScreenIndex + stepSize*(i-minIndex)) < 0)
|
andrew@52
|
1068 i++;//only draw what is on the screen
|
andrew@52
|
1069
|
andrew@52
|
1070 for ( ; i < min(maxIndex+1, (int)distribution.array.size());i++){
|
andrew@52
|
1071
|
andrew@55
|
1072 //as array indices
|
andrew@55
|
1073 // testDistributionOutput.writeValue(minScreenIndex + (stepSize*(i-minIndex-1)), distribution.array[i-1]);
|
andrew@55
|
1074
|
andrew@55
|
1075 //as millis:
|
andrew@55
|
1076 testDistributionOutput.writeValue(distribution.getIndexInRealTerms(i), distribution.array[i-1]);
|
andrew@52
|
1077 }
|
andrew@52
|
1078 testDistributionOutput.closeFile();
|
andrew@52
|
1079 }
|
andrew@52
|
1080
|
andrew@55
|
1081 void AudioEventMatcher::writeKickEvent(const int& startMatchingTime, const int& endMatchingTime, std::string filepath){
|
andrew@55
|
1082
|
andrew@55
|
1083 int channel = 0;//i.e. kick
|
andrew@55
|
1084
|
andrew@55
|
1085 if (!testDistributionOutput.outputFile.is_open())
|
andrew@55
|
1086 testDistributionOutput.closeFile();
|
andrew@55
|
1087
|
andrew@55
|
1088 testDistributionOutput.outputFile.open(filepath.c_str());
|
andrew@55
|
1089
|
andrew@55
|
1090 testDistributionOutput.outputFile << startMatchingTime << "\t" << 0 << endl;
|
andrew@55
|
1091 int checkIndex = 0;
|
andrew@55
|
1092 double millisTime = 0;
|
andrew@55
|
1093 if (channel <= recordedTracks.numberOfAudioTracks && checkIndex < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){
|
andrew@55
|
1094 while (millisTime < startMatchingTime) {
|
andrew@55
|
1095 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[checkIndex].millisTime;
|
andrew@55
|
1096 checkIndex++;
|
andrew@55
|
1097 }
|
andrew@55
|
1098 for (int i = checkIndex;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size() && millisTime <= endMatchingTime;i++){
|
andrew@55
|
1099 millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime;
|
andrew@55
|
1100 if (millisTime >= startMatchingTime && millisTime <= endMatchingTime){
|
andrew@55
|
1101
|
andrew@55
|
1102 testDistributionOutput.outputFile << (int) millisTime - 1 << "\t" << 0 << endl;
|
andrew@55
|
1103 testDistributionOutput.outputFile << (int) millisTime << "\t" << 1 << endl;
|
andrew@55
|
1104 testDistributionOutput.outputFile << (int) millisTime + 1 << "\t" << 0 << endl;
|
andrew@55
|
1105 }//end if within limits (changed so it now is 4 sure)
|
andrew@55
|
1106 }
|
andrew@55
|
1107 }
|
andrew@55
|
1108
|
andrew@55
|
1109 testDistributionOutput.outputFile << endMatchingTime << "\t" << 0 << endl;
|
andrew@55
|
1110
|
andrew@55
|
1111 testDistributionOutput.closeFile();
|
andrew@55
|
1112
|
andrew@55
|
1113 }
|
andrew@55
|
1114
|
andrew@10
|
1115 /*
|
andrew@10
|
1116
|
andrew@10
|
1117 void printPosteriorMAPinfo(){ //tmp print stuff
|
andrew@10
|
1118 printf("New pitch MAP post estimate now %i, ", bayesianStruct.posterior.MAPestimate);
|
andrew@10
|
1119 double tmp = bayesianStruct.posterior.getMAPestimate();
|
andrew@10
|
1120 printf(" getting it %f and offset %f == %f ms\n", tmp, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(tmp));
|
andrew@10
|
1121
|
andrew@10
|
1122 }
|
andrew@10
|
1123 */
|
andrew@3
|
1124
|