andrew@0
|
1 /*
|
andrew@0
|
2 * BayesDrumTracker.cpp
|
andrew@0
|
3 * bayesianTempoInitialiser5
|
andrew@0
|
4 *
|
andrew@0
|
5 * Created by Andrew on 14/07/2011.
|
andrew@0
|
6 * Copyright 2011 QMUL. All rights reserved.
|
andrew@0
|
7 *
|
andrew@0
|
8 */
|
andrew@0
|
9
|
andrew@0
|
10 #include "BayesDrumTracker.h"
|
andrew@0
|
11 #define OUTPORT 12346
|
andrew@0
|
12 #define HOST "localhost"
|
andrew@0
|
13
|
andrew@0
|
14
|
andrew@0
|
15 //beatCorrection process indicates how the phase is changing from max
|
andrew@0
|
16
|
andrew@0
|
17
|
andrew@0
|
18 BayesDrumTracker::BayesDrumTracker(){
|
andrew@0
|
19
|
andrew@0
|
20 initialiseTracker();
|
andrew@0
|
21 sender.setup( HOST, OUTPORT );
|
andrew@0
|
22 }
|
andrew@0
|
23
|
andrew@0
|
24
|
andrew@0
|
25 BayesDrumTracker::~BayesDrumTracker(){}
|
andrew@0
|
26
|
andrew@0
|
27 void BayesDrumTracker::initialiseTracker(){
|
andrew@0
|
28
|
andrew@0
|
29 beatDistribution.initialiseArray();
|
andrew@0
|
30 tempoDistribution.initialiseArray();
|
andrew@0
|
31 beatTimes.lastBeatTime = 0;
|
andrew@0
|
32 correctionFactor = 0.5;
|
andrew@0
|
33
|
andrew@0
|
34 tempoDistribution.likelihoodStdDev = ARRAY_SIZE / 32;
|
andrew@0
|
35 // tempoDistribution.likelihoodNoise = 0.96;
|
andrew@0
|
36 tempoDistribution.likelihoodNoise = 0.7;
|
andrew@0
|
37 tempoDistribution.setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/1);//wide
|
andrew@0
|
38
|
andrew@0
|
39 beatDistribution.likelihoodStdDev = ARRAY_SIZE / 32;
|
andrew@0
|
40 beatDistribution.likelihoodNoise = 0.56;
|
andrew@0
|
41 beatDistribution.setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/1);
|
andrew@0
|
42
|
andrew@0
|
43
|
andrew@0
|
44 tempoMinimum = 180;
|
andrew@0
|
45 tempoMaximum = 400;
|
andrew@0
|
46 posteriorMaximum = 0.1;
|
andrew@0
|
47
|
andrew@0
|
48 adaptiveStandardDeviationMode = false;
|
andrew@0
|
49 setDistributionOnStartTempo = true;
|
andrew@0
|
50
|
andrew@0
|
51 setBeatToNowTime = ofGetElapsedTimeMillis();
|
andrew@0
|
52 recentClickTime = ofGetElapsedTimeMillis();
|
andrew@0
|
53
|
andrew@0
|
54 resetParameters();
|
andrew@0
|
55 //check what we can delete above SINCE RESET CALLED
|
andrew@0
|
56
|
andrew@0
|
57 }
|
andrew@0
|
58
|
andrew@0
|
59
|
andrew@0
|
60 void BayesDrumTracker::resetParameters(){
|
andrew@0
|
61
|
andrew@0
|
62 beatTimes.startIndex = 0;
|
andrew@0
|
63 beatTimes.lastBeatTime = 0;
|
andrew@0
|
64 maxPhase = 0;
|
andrew@0
|
65 posteriorMaximum = 0.1;
|
andrew@0
|
66
|
andrew@0
|
67 accompanimentStarted = false;
|
andrew@0
|
68
|
andrew@0
|
69 tempoDistribution.likelihoodNoise = 0.8;
|
andrew@0
|
70 tempoDistribution.setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/2);//wide
|
andrew@0
|
71
|
andrew@0
|
72 beatDistribution.initialiseArray();
|
andrew@0
|
73 tempoDistribution.initialiseArray();
|
andrew@0
|
74
|
andrew@0
|
75 tempoDistribution.calculateStandardDeviation();
|
andrew@0
|
76 beatDistribution.calculateStandardDeviation();
|
andrew@0
|
77
|
andrew@0
|
78 tempoStdDev = tempoDistribution.standardDeviation;
|
andrew@0
|
79
|
andrew@0
|
80 beatTimes.resetBeatTimeArray();
|
andrew@0
|
81
|
andrew@0
|
82 }
|
andrew@0
|
83
|
andrew@0
|
84
|
andrew@0
|
85
|
andrew@0
|
86 void BayesDrumTracker::decayDistributions(){
|
andrew@0
|
87
|
andrew@0
|
88 if (accompanimentStarted){
|
andrew@0
|
89 tempoDistribution.decayPosteriorWithGaussianNoise ();
|
andrew@0
|
90 beatDistribution.decayPosteriorWithGaussianNoise();
|
andrew@0
|
91 }
|
andrew@0
|
92 else{
|
andrew@0
|
93 if (tempoStdDev < 0.8 && beatDistribution.standardDeviation < 5)
|
andrew@0
|
94 accompanimentStarted = true;
|
andrew@0
|
95
|
andrew@0
|
96 }
|
andrew@0
|
97 }
|
andrew@0
|
98
|
andrew@0
|
99
|
andrew@0
|
100 void BayesDrumTracker::setBeatDistribution(int beatPosition){
|
andrew@0
|
101 switch (beatPosition){
|
andrew@0
|
102 //early sixteenth is that the beat is a sixteenth earlier
|
andrew@0
|
103 case 0:
|
andrew@0
|
104 case 1:
|
andrew@0
|
105 case 11:
|
andrew@0
|
106 //i.e. these zones are interpreted as "on the beat"
|
andrew@0
|
107 beatDistribution.eighthNoteProportion = 0;
|
andrew@0
|
108 beatDistribution.earlySixteenthNoteProportion = 0;
|
andrew@0
|
109 beatDistribution.lateSixteenthNoteProportion = 0;
|
andrew@0
|
110 break;
|
andrew@0
|
111 //10 and 2 were here
|
andrew@0
|
112
|
andrew@0
|
113 case 2:
|
andrew@0
|
114 beatDistribution.eighthNoteProportion = 0;
|
andrew@0
|
115 beatDistribution.earlySixteenthNoteProportion = 0.25;//was 0.3 in Bayesian8
|
andrew@0
|
116 //i.e. a 25% chance it is early sixteenth - 75% that the beat actually lies here
|
andrew@0
|
117 beatDistribution.lateSixteenthNoteProportion = 0;
|
andrew@0
|
118 break;
|
andrew@0
|
119
|
andrew@0
|
120 case 3:
|
andrew@0
|
121 beatDistribution.eighthNoteProportion = 0;
|
andrew@0
|
122 beatDistribution.earlySixteenthNoteProportion = 0.3;//was 0.4 in Bayesian8 //half chance it is early
|
andrew@0
|
123 beatDistribution.lateSixteenthNoteProportion = 0;
|
andrew@0
|
124 break;
|
andrew@0
|
125
|
andrew@0
|
126 case 5:
|
andrew@0
|
127 case 6:
|
andrew@0
|
128 case 7:
|
andrew@0
|
129 beatDistribution.eighthNoteProportion = 0.3;//i.e. nearly half a chance we are on the 8th note
|
andrew@0
|
130 beatDistribution.earlySixteenthNoteProportion = 0;
|
andrew@0
|
131 beatDistribution.lateSixteenthNoteProportion = 0;
|
andrew@0
|
132 break;
|
andrew@0
|
133
|
andrew@0
|
134 case 4:
|
andrew@0
|
135 beatDistribution.eighthNoteProportion = 0;
|
andrew@0
|
136 beatDistribution.earlySixteenthNoteProportion = 0.25;//was 0.3 in Bayesian8
|
andrew@0
|
137 beatDistribution.lateSixteenthNoteProportion = 0.05;//was 0.2 in Bayesian8
|
andrew@0
|
138 //chsanged to 0.2 and 0.1 then back
|
andrew@0
|
139 break;
|
andrew@0
|
140
|
andrew@0
|
141 case 8:
|
andrew@0
|
142 beatDistribution.eighthNoteProportion = 0;
|
andrew@0
|
143 beatDistribution.earlySixteenthNoteProportion = 0.05;//was 0.2 in Bayesian8
|
andrew@0
|
144 beatDistribution.lateSixteenthNoteProportion = 0.25;//was 0.3 in Bayesian8
|
andrew@0
|
145 break;
|
andrew@0
|
146
|
andrew@0
|
147 case 9:
|
andrew@0
|
148 beatDistribution.eighthNoteProportion = 0;
|
andrew@0
|
149 beatDistribution.earlySixteenthNoteProportion = 0;
|
andrew@0
|
150 beatDistribution.lateSixteenthNoteProportion = 0.35;//was 0.4 in Bayesian8
|
andrew@0
|
151 break;
|
andrew@0
|
152
|
andrew@0
|
153 case 10:
|
andrew@0
|
154 beatDistribution.eighthNoteProportion = 0;
|
andrew@0
|
155 beatDistribution.earlySixteenthNoteProportion = 0;
|
andrew@0
|
156 beatDistribution.lateSixteenthNoteProportion = 0.25;//was 0.2 in Bayesian8
|
andrew@0
|
157 break;
|
andrew@0
|
158
|
andrew@0
|
159 }
|
andrew@0
|
160
|
andrew@0
|
161 }
|
andrew@0
|
162
|
andrew@0
|
163 void BayesDrumTracker::newKickError(const float& error, const double& cpuEventTime, const string& onsetTypeString){
|
andrew@0
|
164
|
andrew@0
|
165 onsetType = onsetTypeString;
|
andrew@0
|
166 cpuBeatTime = cpuEventTime;
|
andrew@0
|
167 kickError = error;
|
andrew@0
|
168
|
andrew@0
|
169 //printf("beat errror %f time %f\n", kickError, cpuBeatTime);
|
andrew@0
|
170
|
andrew@0
|
171 while (kickError > 0.5){
|
andrew@0
|
172 kickError -= 1;
|
andrew@0
|
173 }
|
andrew@0
|
174
|
andrew@0
|
175 if (paused != true){
|
andrew@0
|
176 updateTempoProcess(cpuBeatTime, onsetType);
|
andrew@0
|
177 //this also cross updates the distributions
|
andrew@0
|
178 beatTimes.beatMapTimeDifferences[beatTimes.beatSegment] = kickError*beatTimes.tatum;
|
andrew@0
|
179 }//end if paused
|
andrew@0
|
180
|
andrew@0
|
181
|
andrew@0
|
182
|
andrew@0
|
183 if (onsetType == "kick"){
|
andrew@0
|
184 if (accompanimentStarted)
|
andrew@0
|
185 beatDistribution.likelihoodNoise = 0.5;
|
andrew@0
|
186 else
|
andrew@0
|
187 beatDistribution.likelihoodNoise = 0.5;
|
andrew@0
|
188 // printf("kick %f ", cpuBeatTime);
|
andrew@0
|
189 }
|
andrew@0
|
190 else{
|
andrew@0
|
191 //snare
|
andrew@0
|
192 if (accompanimentStarted)
|
andrew@0
|
193 beatDistribution.likelihoodNoise = 0.7;
|
andrew@0
|
194 else
|
andrew@0
|
195 beatDistribution.likelihoodNoise = 0.85;
|
andrew@0
|
196 // printf("snare %f ", cpuBeatTime);
|
andrew@0
|
197 }
|
andrew@0
|
198
|
andrew@0
|
199
|
andrew@0
|
200 setBeatDistribution(beatTimes.beatSegment%12);
|
andrew@0
|
201
|
andrew@0
|
202 if (kickError <= 0.5 && kickError >= -0.5)
|
andrew@0
|
203 {
|
andrew@0
|
204 float beatStandardDeviation;
|
andrew@0
|
205 if (adaptiveStandardDeviationMode)
|
andrew@0
|
206 beatStandardDeviation = min((double)beatDistribution.likelihoodStdDev, beatDistribution.standardDeviation);
|
andrew@0
|
207 else
|
andrew@0
|
208 beatStandardDeviation = beatDistribution.likelihoodStdDev;
|
andrew@0
|
209
|
andrew@0
|
210
|
andrew@0
|
211 beatDistribution.resetPrior();
|
andrew@0
|
212 beatDistribution.setGaussianLikelihoodForBeats((ARRAY_SIZE/2)+(kickError*ARRAY_SIZE), beatStandardDeviation);
|
andrew@0
|
213 beatDistribution.calculatePosterior();
|
andrew@0
|
214 beatDistribution.renormalisePosterior();
|
andrew@0
|
215
|
andrew@0
|
216 sendMaxPhase();
|
andrew@0
|
217
|
andrew@0
|
218 beatDistribution.calculateStandardDeviation();
|
andrew@0
|
219
|
andrew@0
|
220 }//end if error < 0.5
|
andrew@0
|
221
|
andrew@0
|
222
|
andrew@0
|
223
|
andrew@0
|
224 if (beatTimes.beatSegment % 12 == 6){
|
andrew@0
|
225 kickString = "Kick ";
|
andrew@0
|
226 kickString += ofToString(kickError);
|
andrew@0
|
227 kickString += " ERROR ";
|
andrew@0
|
228 kickString += ofToString(kickError, 2);
|
andrew@0
|
229 kickString += " at time diff ";
|
andrew@0
|
230 kickString += ofToString(cpuBeatTime - beatTimes.lastClickTime, 2);
|
andrew@0
|
231 kickString += " index ";
|
andrew@0
|
232 kickString += ofToString(beatTimes.lastClickIndex, 2);
|
andrew@0
|
233 kickString += " TYPE ";
|
andrew@0
|
234 kickString += ofToString(beatTimes.beatSegment%12);
|
andrew@0
|
235 kickString += " Time diff ";
|
andrew@0
|
236 kickString += ofToString(beatTimes.timeDifference, 2);
|
andrew@0
|
237 }
|
andrew@0
|
238
|
andrew@0
|
239
|
andrew@0
|
240 }
|
andrew@0
|
241
|
andrew@0
|
242
|
andrew@0
|
243
|
andrew@0
|
244 void BayesDrumTracker::startTatum(const float& startTatum){
|
andrew@0
|
245 beatTimes.tatum = startTatum;
|
andrew@0
|
246
|
andrew@0
|
247 if (setDistributionOnStartTempo){
|
andrew@0
|
248 beatDistribution.setGaussianPosterior(ARRAY_SIZE/2, 8);
|
andrew@0
|
249 tempoDistribution.setGaussianPosterior(ARRAY_SIZE/2, 12);
|
andrew@0
|
250 float tmpIndex;
|
andrew@0
|
251 tmpIndex = ( (beatTimes.tatum - ((tempoMinimum+tempoMaximum)/2) ) * ARRAY_SIZE)/(tempoMaximum - tempoMinimum);
|
andrew@0
|
252 tempoDistribution.translateDistribution(tmpIndex);
|
andrew@0
|
253
|
andrew@0
|
254 sendMaxTempo();
|
andrew@0
|
255 }
|
andrew@0
|
256 }
|
andrew@0
|
257
|
andrew@0
|
258
|
andrew@0
|
259 void BayesDrumTracker::setUniformTempo(){
|
andrew@0
|
260 for (int i = 0;i < ARRAY_SIZE;i++)
|
andrew@0
|
261 tempoDistribution.posterior[i] = (float)1/ARRAY_SIZE;
|
andrew@0
|
262 }
|
andrew@0
|
263
|
andrew@0
|
264
|
andrew@0
|
265 void BayesDrumTracker::setUniformPhase(){
|
andrew@0
|
266 for (int i = 0;i < ARRAY_SIZE;i++)
|
andrew@0
|
267 beatDistribution.posterior[i] = (float)1/ARRAY_SIZE;
|
andrew@0
|
268 }
|
andrew@0
|
269
|
andrew@0
|
270 void BayesDrumTracker::setBeatNow(const double& beatTime){
|
andrew@0
|
271 for (int i = 0;i < ARRAY_SIZE;i++)
|
andrew@0
|
272 beatDistribution.prior[i] = (float)1/ARRAY_SIZE;
|
andrew@0
|
273
|
andrew@0
|
274 setBeatToNowTime = ofGetElapsedTimeMillis();
|
andrew@0
|
275 double difference = (setBeatToNowTime - recentClickTime);
|
andrew@0
|
276 printf("SET BEAT TO NOW %f vs %f :: diff %f tatum %f :: ", setBeatToNowTime, recentClickTime, difference, beatTimes.tatum );
|
andrew@0
|
277
|
andrew@0
|
278 double beatTimeToUse = 0;
|
andrew@0
|
279
|
andrew@0
|
280 if (difference < beatTimes.tatum)//tatum is the eighth note time
|
andrew@0
|
281 beatTimeToUse = difference/ (2*beatTimes.tatum);
|
andrew@0
|
282 else
|
andrew@0
|
283 beatTimeToUse = -1*(2*beatTimes.tatum - difference) / (2*beatTimes.tatum);
|
andrew@0
|
284
|
andrew@0
|
285 printf("sending %f \n", beatTimeToUse);
|
andrew@0
|
286
|
andrew@0
|
287 beatDistribution.setGaussianLikelihoodForBeats((ARRAY_SIZE/2)+(beatTimeToUse*ARRAY_SIZE), 2);
|
andrew@0
|
288 beatDistribution.calculatePosterior();
|
andrew@0
|
289 beatDistribution.renormalisePosterior();
|
andrew@0
|
290
|
andrew@0
|
291 sendMaxPhase();
|
andrew@0
|
292
|
andrew@0
|
293
|
andrew@0
|
294 }
|
andrew@0
|
295
|
andrew@0
|
296
|
andrew@0
|
297 void BayesDrumTracker::newBeat(int& beatIndex){
|
andrew@0
|
298 ofxOscMessage m;
|
andrew@0
|
299 m.setAddress( "/beatInfo" );
|
andrew@0
|
300
|
andrew@0
|
301 m.addFloatArg(beatTimes.tatum);
|
andrew@0
|
302 m.addFloatArg(maxPhase);
|
andrew@0
|
303
|
andrew@0
|
304 beatTimes.tatum = maxTempo;
|
andrew@0
|
305 printf("BEAT INFO %f, %f\n", beatTimes.tatum, maxPhase);
|
andrew@0
|
306
|
andrew@0
|
307 sender.sendMessage( m );
|
andrew@0
|
308
|
andrew@0
|
309 }
|
andrew@0
|
310
|
andrew@0
|
311 void BayesDrumTracker::sendMaxTempo(){
|
andrew@0
|
312 ofxOscMessage m;
|
andrew@0
|
313 m.setAddress( "/tempo" );
|
andrew@0
|
314
|
andrew@0
|
315 //maxTempo = tempoDistribution.maximumIndex * (tempoMaximum - tempoMinimum) / ARRAY_SIZE;
|
andrew@0
|
316 //would be introduced new in bayesian8
|
andrew@0
|
317 maxTempo = tempoDistribution.getIntegratedEstimateIndex() * (tempoMaximum - tempoMinimum) / ARRAY_SIZE;
|
andrew@0
|
318 maxTempo += tempoMinimum;
|
andrew@0
|
319
|
andrew@0
|
320 beatTimes.tatum = maxTempo;
|
andrew@0
|
321 printf("SEND TATUM %f\n", beatTimes.tatum);
|
andrew@0
|
322
|
andrew@0
|
323 m.addFloatArg( maxTempo );
|
andrew@0
|
324 sender.sendMessage( m );
|
andrew@0
|
325
|
andrew@0
|
326 //printf("max tempo %f\n", maxTempo);
|
andrew@0
|
327
|
andrew@0
|
328 }
|
andrew@0
|
329
|
andrew@0
|
330 void BayesDrumTracker::sendMaxPhase(){
|
andrew@0
|
331
|
andrew@0
|
332
|
andrew@0
|
333 // maxPhase = (beatDistribution.maximumIndex - (ARRAY_SIZE/2)) / ARRAY_SIZE;
|
andrew@0
|
334 maxPhase = (beatDistribution.getIntegratedEstimateIndex() - (ARRAY_SIZE/2)) / ARRAY_SIZE;
|
andrew@0
|
335 // printf("\nphase index %f :: %f\n", (float) beatDistribution.integratedEstimate , maxPhase);
|
andrew@0
|
336 ofxOscMessage m;
|
andrew@0
|
337 m.setAddress( "/phase" );
|
andrew@0
|
338 m.addFloatArg( maxPhase );
|
andrew@0
|
339 sender.sendMessage( m );
|
andrew@0
|
340
|
andrew@0
|
341 //beatCorrection = maxPhase * beatTimes.tatum / 4;
|
andrew@0
|
342 }
|
andrew@0
|
343
|
andrew@0
|
344
|
andrew@0
|
345 void BayesDrumTracker::setNewClickIndex(const int& clickIndex, const float& clickTime){
|
andrew@0
|
346
|
andrew@0
|
347 beatTimes.lastClickIndex = clickIndex;
|
andrew@0
|
348 beatTimes.lastClickTime = clickTime;
|
andrew@0
|
349
|
andrew@0
|
350 int clickIndexToUse = clickIndex % 16;
|
andrew@0
|
351 beatTimes.clickIndex = clickIndex;
|
andrew@0
|
352 beatTimes.clickNumber[clickIndexToUse] = clickIndex;
|
andrew@0
|
353 beatTimes.clickTimes[clickIndexToUse] = clickTime;
|
andrew@0
|
354
|
andrew@0
|
355 recentClickTime = ofGetElapsedTimeMillis();
|
andrew@0
|
356
|
andrew@0
|
357 }
|
andrew@0
|
358
|
andrew@0
|
359
|
andrew@0
|
360 void BayesDrumTracker::doBeatCorrection(const float& beatCorrFloat){
|
andrew@0
|
361 beatCorrection = beatCorrFloat;
|
andrew@0
|
362 correctBeatBy = round(correctionFactor * beatCorrection * ARRAY_SIZE / (2 * beatTimes.tatum));
|
andrew@0
|
363 beatDistribution.translateDistribution(-1 * correctBeatBy);
|
andrew@0
|
364 }
|
andrew@0
|
365
|
andrew@0
|
366
|
andrew@0
|
367 bool BayesDrumTracker::filterBeatTime(double newBeatTime){
|
andrew@0
|
368 bool newBeatFound = false;
|
andrew@0
|
369 if ((newBeatTime - beatTimes.lastBeatTime) > 20 || beatTimes.lastBeatTime == 0){
|
andrew@0
|
370
|
andrew@0
|
371 crossUpdateArrays((float)(newBeatTime - beatTimes.lastBeatTime));
|
andrew@0
|
372 beatTimes.lastBeatTime = newBeatTime;
|
andrew@0
|
373 newBeatFound = true;
|
andrew@0
|
374 }
|
andrew@0
|
375 return newBeatFound;
|
andrew@0
|
376 }
|
andrew@0
|
377
|
andrew@0
|
378 void BayesDrumTracker::crossUpdateArrays(float timeInterval){
|
andrew@0
|
379
|
andrew@0
|
380 int finalBeatIndex, tmpTempoIndex, startBeatIndex;
|
andrew@0
|
381 //finalBeat has contribution from BEAT[finalBeat + INT.k] * TEMPO[Max_tempo + k] where INT = INTERVAL
|
andrew@0
|
382 float interval;
|
andrew@0
|
383 interval = timeInterval / maxTempo;//beatTimes.tatum;
|
andrew@0
|
384 tempoDistribution.resetMaximumPosterior();
|
andrew@0
|
385 beatDistribution.resetMaximumPosterior();
|
andrew@0
|
386
|
andrew@0
|
387
|
andrew@0
|
388 int tmpBeatIndex;
|
andrew@0
|
389 //&& interval > 0.8 idea?
|
andrew@0
|
390 if (timeInterval > 0 && timeInterval < 12000 ){//need between 0 and 12 seconds only to update
|
andrew@0
|
391
|
andrew@0
|
392 for (tmpBeatIndex = 0;tmpBeatIndex < ARRAY_SIZE;tmpBeatIndex++){
|
andrew@0
|
393
|
andrew@0
|
394 tmpArray[tmpBeatIndex] = 0;
|
andrew@0
|
395 float minusMsecToMakeUp = beatIndexToMsec(tmpBeatIndex) / interval;
|
andrew@0
|
396 float plusMsecToMakeUp = beatIndexToMsec(ARRAY_SIZE - tmpBeatIndex) / interval;
|
andrew@0
|
397 float convertMsecToTempoIndex = ARRAY_SIZE / (tempoMaximum - tempoMinimum) ;
|
andrew@0
|
398
|
andrew@0
|
399
|
andrew@0
|
400 int minTempoIndex = -1 * (int)(minusMsecToMakeUp * convertMsecToTempoIndex);
|
andrew@0
|
401 int maxTempoIndex = (int)(plusMsecToMakeUp * convertMsecToTempoIndex);
|
andrew@0
|
402
|
andrew@0
|
403
|
andrew@0
|
404 if (tmpBeatIndex == beatDistribution.maximumIndex){
|
andrew@0
|
405 // minTmpDebug = tempoDistribution.maximumIndex + minTempoIndex;
|
andrew@0
|
406 // maxTmpDebug = tempoDistribution.maximumIndex + maxTempoIndex;
|
andrew@0
|
407 debugArray[0] = beatDistribution.maximumIndex;//
|
andrew@0
|
408 debugArray[1] = timeInterval;
|
andrew@0
|
409 debugArray[2] = interval;//beatDistribution.maximumIndex;
|
andrew@0
|
410 debugArray[3] = tempoDistribution.maximumIndex;
|
andrew@0
|
411 }
|
andrew@0
|
412
|
andrew@0
|
413 for (tmpTempoIndex = minTempoIndex;tmpTempoIndex <= maxTempoIndex;tmpTempoIndex++){
|
andrew@0
|
414
|
andrew@0
|
415 if ((tempoDistribution.maximumIndex + tmpTempoIndex) >= 0
|
andrew@0
|
416 && (tempoDistribution.maximumIndex + tmpTempoIndex) < ARRAY_SIZE
|
andrew@0
|
417 && (tmpBeatIndex - (int)(interval*tmpTempoIndex)) >= 0
|
andrew@0
|
418 && (tmpBeatIndex - (int)(interval*tmpTempoIndex))< ARRAY_SIZE){
|
andrew@0
|
419 tmpArray[tmpBeatIndex] += beatDistribution.posterior[tmpBeatIndex - (int)(interval*tmpTempoIndex)] * tempoDistribution.posterior[(int)tempoDistribution.maximumIndex + tmpTempoIndex];
|
andrew@0
|
420 }
|
andrew@0
|
421 }//end for tmpTmepo
|
andrew@0
|
422
|
andrew@0
|
423
|
andrew@0
|
424
|
andrew@0
|
425 }
|
andrew@0
|
426
|
andrew@0
|
427 float tmpFloat;
|
andrew@0
|
428 for (tmpBeatIndex = 0;tmpBeatIndex < ARRAY_SIZE;tmpBeatIndex++){
|
andrew@0
|
429 //debug - dont actually update::
|
andrew@0
|
430
|
andrew@0
|
431 tmpFloat = beatDistribution.posterior[tmpBeatIndex];
|
andrew@0
|
432 beatDistribution.posterior[tmpBeatIndex] = tmpArray[tmpBeatIndex];
|
andrew@0
|
433 tmpArray[tmpBeatIndex] = tmpFloat;
|
andrew@0
|
434 }
|
andrew@0
|
435 beatDistribution.renormaliseArray(&beatDistribution.posterior[0], ARRAY_SIZE);
|
andrew@0
|
436
|
andrew@0
|
437 } //end if
|
andrew@0
|
438
|
andrew@0
|
439
|
andrew@0
|
440 }
|
andrew@0
|
441
|
andrew@0
|
442
|
andrew@0
|
443 void BayesDrumTracker::updateTempoProcess(const double& cpuTime, const string& onsetDescription){
|
andrew@0
|
444
|
andrew@0
|
445 if (filterBeatTime(cpuTime) == true){
|
andrew@0
|
446 //checks for no repeat
|
andrew@0
|
447
|
andrew@0
|
448 if (onsetDescription == "kick")
|
andrew@0
|
449 beatTimes.addBeatTime(cpuTime, 1);
|
andrew@0
|
450 else
|
andrew@0
|
451 beatTimes.addBeatTime(cpuTime, 2);
|
andrew@0
|
452
|
andrew@0
|
453
|
andrew@0
|
454 //recalculate the distribution
|
andrew@0
|
455 int altIndex = 0;
|
andrew@0
|
456
|
andrew@0
|
457 tempoDataString = "Tatum :";
|
andrew@0
|
458 tempoDataString += ofToString(beatTimes.tatum, 2);
|
andrew@0
|
459 tempoDataString += " BPM ";
|
andrew@0
|
460 tempoDataString += ofToString((double)30000/beatTimes.tatum, 2);
|
andrew@0
|
461
|
andrew@0
|
462 timeString = "Last BEAT ";
|
andrew@0
|
463 timeString += ofToString(beatTimes.lastBeatTime);
|
andrew@0
|
464 timeString += " CLICK ";
|
andrew@0
|
465 timeString += ofToString(beatTimes.lastClickTime);
|
andrew@0
|
466 timeString += " DIFDF ";
|
andrew@0
|
467 timeString += ofToString(beatTimes.timeDifference);
|
andrew@0
|
468 timeString += " segment ";
|
andrew@0
|
469 timeString += ofToString(beatTimes.beatSegment);
|
andrew@0
|
470
|
andrew@0
|
471
|
andrew@0
|
472 for (altIndex = 0;altIndex< 16;altIndex++){
|
andrew@0
|
473 tempoInterval = beatTimes.intervalDifferences[beatTimes.index][altIndex];
|
andrew@0
|
474 integerMultipleOfTatum = beatTimes.relativeIntervals[altIndex][1];
|
andrew@0
|
475
|
andrew@0
|
476
|
andrew@0
|
477 ///NEW VERSION
|
andrew@0
|
478 tempoUpdateStrings[altIndex] = "";
|
andrew@0
|
479 double timeInterval = beatTimes.beatTimes[beatTimes.index] - beatTimes.beatTimes[altIndex];
|
andrew@0
|
480 //raw time difference
|
andrew@0
|
481 beatTimes.intervalDifferences[beatTimes.index][altIndex] = 0;
|
andrew@0
|
482 beatTimes.intervalUsed[beatTimes.index][altIndex] = false;
|
andrew@0
|
483
|
andrew@0
|
484 if (onsetType == "kick")
|
andrew@0
|
485 beatTimes.OnsetIsKick[beatTimes.index] = true;
|
andrew@0
|
486 else
|
andrew@0
|
487 beatTimes.OnsetIsKick[beatTimes.index] = false;
|
andrew@0
|
488
|
andrew@0
|
489
|
andrew@0
|
490
|
andrew@0
|
491 if (!accompanimentStarted){
|
andrew@0
|
492 //if we need to find tempo and start use this method
|
andrew@0
|
493 //we have 'started' once std dev is sufficiently low
|
andrew@0
|
494
|
andrew@0
|
495 updateTempoIfWithinRange(timeInterval);//taken as being the tatum interval
|
andrew@0
|
496
|
andrew@0
|
497
|
andrew@0
|
498
|
andrew@0
|
499 for (int i = 1;i <= 4;i++){
|
andrew@0
|
500 //we test the main beats and the two bar (16 tatum intervals)
|
andrew@0
|
501
|
andrew@0
|
502 double testInterval = timeInterval / 2*i;//pow(2, i);//pow(2.0, i);
|
andrew@0
|
503
|
andrew@0
|
504 if (updateTempoIfWithinRange(testInterval)){
|
andrew@0
|
505 //printf("test time %f, beats %i\n", testInterval, i);
|
andrew@0
|
506
|
andrew@0
|
507 beatTimes.intervalUsed[beatTimes.index][altIndex] = true;
|
andrew@0
|
508 beatTimes.intervalDifferences[beatTimes.index][altIndex] = testInterval;
|
andrew@0
|
509 //xx what if two within range here?
|
andrew@0
|
510
|
andrew@0
|
511 tempoUpdateStrings[altIndex] = "Tempo Updates (";
|
andrew@0
|
512 tempoUpdateStrings[altIndex] += ofToString(beatTimes.index, 0);
|
andrew@0
|
513 tempoUpdateStrings[altIndex] += ") : [";
|
andrew@0
|
514 tempoUpdateStrings[altIndex] += ofToString(altIndex);
|
andrew@0
|
515 tempoUpdateStrings[altIndex] += "]] : ";
|
andrew@0
|
516 tempoUpdateStrings[altIndex] += ofToString(timeInterval);
|
andrew@0
|
517 tempoUpdateStrings[altIndex] += ", ioi:";
|
andrew@0
|
518 tempoUpdateStrings[altIndex] += ofToString(i);
|
andrew@0
|
519 //tempoUpdateStrings[altIndex] += "";
|
andrew@0
|
520
|
andrew@0
|
521 }
|
andrew@0
|
522
|
andrew@0
|
523 }
|
andrew@0
|
524
|
andrew@0
|
525 double testInterval = timeInterval / 16;//pow(2, i);//pow(2.0, i);
|
andrew@0
|
526 if (updateTempoIfWithinRange(testInterval)){
|
andrew@0
|
527 beatTimes.intervalUsed[beatTimes.index][altIndex] = true;
|
andrew@0
|
528 beatTimes.intervalDifferences[beatTimes.index][altIndex] = testInterval;
|
andrew@0
|
529 }
|
andrew@0
|
530
|
andrew@0
|
531 }else{
|
andrew@0
|
532 //OLD VERSON
|
andrew@0
|
533 //THIS USES THE CURRENT TEMPO ESTIMATE TO DECIDE WHAT THE BEST INTERVAL IS
|
andrew@0
|
534 //&& integerMultipleOfTatum % 2 == 0 removed below XXX put back
|
andrew@0
|
535 if (altIndex != beatTimes.index && integerMultipleOfTatum < 17
|
andrew@0
|
536 && integerMultipleOfTatum > 0 && beatTimes.startIndex > 8//beattimes.index > 8 - the start
|
andrew@0
|
537 && integerMultipleOfTatum%2 == 0){//mod 2 - i.e. proper beat intervals only
|
andrew@0
|
538
|
andrew@0
|
539 double testInterval = timeInterval / integerMultipleOfTatum;
|
andrew@0
|
540
|
andrew@0
|
541 if (updateTempoIfWithinRange(testInterval)){
|
andrew@0
|
542
|
andrew@0
|
543 beatTimes.intervalUsed[beatTimes.index][altIndex] = true;
|
andrew@0
|
544 beatTimes.intervalDifferences[beatTimes.index][altIndex] = testInterval;
|
andrew@0
|
545
|
andrew@0
|
546 if (paused == false){
|
andrew@0
|
547 tempoUpdateStrings[altIndex] = "Tempo Updates : (";
|
andrew@0
|
548 tempoUpdateStrings[altIndex] += ofToString(beatTimes.index, 0);
|
andrew@0
|
549 tempoUpdateStrings[altIndex] += ") : [";
|
andrew@0
|
550 tempoUpdateStrings[altIndex] += ofToString(altIndex, 0);
|
andrew@0
|
551 tempoUpdateStrings[altIndex] += "] :: ";
|
andrew@0
|
552 tempoUpdateStrings[altIndex] += ofToString(integerMultipleOfTatum);
|
andrew@0
|
553 tempoUpdateStrings[altIndex] += " intervals :: ";
|
andrew@0
|
554 tempoUpdateStrings[altIndex] += ofToString(tempoInterval);
|
andrew@0
|
555 tempoUpdateStrings[altIndex] += " ms.";
|
andrew@0
|
556 // tempoUpdateStrings[altIndex] += ", ioi:";
|
andrew@0
|
557
|
andrew@0
|
558 // tempoUpdateStrings[altIndex] += ofToString(integerMultipleOfTatum);
|
andrew@0
|
559
|
andrew@0
|
560
|
andrew@0
|
561
|
andrew@0
|
562
|
andrew@0
|
563 }//end if not paused
|
andrew@0
|
564
|
andrew@0
|
565
|
andrew@0
|
566 }//end if good interval to update
|
andrew@0
|
567
|
andrew@0
|
568 }//end if not same index etc
|
andrew@0
|
569
|
andrew@0
|
570
|
andrew@0
|
571 }
|
andrew@0
|
572
|
andrew@0
|
573
|
andrew@0
|
574
|
andrew@0
|
575 }//end for all intervals
|
andrew@0
|
576
|
andrew@0
|
577 sendMaxTempo();
|
andrew@0
|
578 }//end if new beat time
|
andrew@0
|
579 double tempoEstimate = tempoDistribution.getIntegratedEstimateIndex();
|
andrew@0
|
580 tempoDistribution.calculateStandardDeviation();
|
andrew@0
|
581 tempoStdDev = tempoDistribution.standardDeviation;
|
andrew@0
|
582
|
andrew@0
|
583 }
|
andrew@0
|
584
|
andrew@0
|
585
|
andrew@0
|
586 bool BayesDrumTracker::updateTempoIfWithinRange(double timeInterval){
|
andrew@0
|
587
|
andrew@0
|
588 bool updated = false;
|
andrew@0
|
589
|
andrew@0
|
590 if (timeInterval > tempoMinimum && timeInterval < tempoMaximum ){
|
andrew@0
|
591 calculateTempoUpdate(timeInterval);
|
andrew@0
|
592 updated = true;
|
andrew@0
|
593 }
|
andrew@0
|
594
|
andrew@0
|
595 return updated;
|
andrew@0
|
596 }
|
andrew@0
|
597
|
andrew@0
|
598
|
andrew@0
|
599 void BayesDrumTracker::calculateTempoUpdate(double tempoInterval){
|
andrew@0
|
600
|
andrew@0
|
601
|
andrew@0
|
602 tempoDistribution.resetPrior();
|
andrew@0
|
603 //need to relook at likelihood for the tempo distribution - not the same as....
|
andrew@0
|
604 tempoDistribution.setGaussianLikelihood(ARRAY_SIZE * (tempoInterval-tempoMinimum)/(tempoMaximum - tempoMinimum), tempoDistribution.likelihoodStdDev);
|
andrew@0
|
605 tempoDistribution.calculatePosterior();
|
andrew@0
|
606 tempoDistribution.renormalisePosterior();
|
andrew@0
|
607
|
andrew@0
|
608 //did take pic of screen here - see initialiser4
|
andrew@0
|
609 }
|
andrew@0
|
610
|
andrew@0
|
611
|
andrew@0
|
612 float BayesDrumTracker::tempoIndexToMsec(const int& index){
|
andrew@0
|
613 float msec;
|
andrew@0
|
614 msec = index * (tempoMaximum - tempoMinimum) / ARRAY_SIZE;
|
andrew@0
|
615 msec += tempoMinimum;
|
andrew@0
|
616 return msec;
|
andrew@0
|
617 }
|
andrew@0
|
618
|
andrew@0
|
619 float BayesDrumTracker::beatIndexToMsec(const int& index){
|
andrew@0
|
620 float msec;
|
andrew@0
|
621 msec = index * maxTempo / ARRAY_SIZE;
|
andrew@0
|
622 msec += tempoMinimum;
|
andrew@0
|
623 return msec;
|
andrew@0
|
624 }
|
andrew@0
|
625
|