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