adamstark@46
|
1 //=======================================================================
|
adamstark@46
|
2 /** @file BTrack.cpp
|
adamstark@47
|
3 * @brief BTrack - a real-time beat tracker
|
adamstark@46
|
4 * @author Adam Stark
|
adamstark@46
|
5 * @copyright Copyright (C) 2008-2014 Queen Mary University of London
|
adamstark@46
|
6 *
|
adamstark@46
|
7 * This program is free software: you can redistribute it and/or modify
|
adamstark@46
|
8 * it under the terms of the GNU General Public License as published by
|
adamstark@46
|
9 * the Free Software Foundation, either version 3 of the License, or
|
adamstark@46
|
10 * (at your option) any later version.
|
adamstark@46
|
11 *
|
adamstark@46
|
12 * This program is distributed in the hope that it will be useful,
|
adamstark@46
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
adamstark@46
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
adamstark@46
|
15 * GNU General Public License for more details.
|
adamstark@46
|
16 *
|
adamstark@46
|
17 * You should have received a copy of the GNU General Public License
|
adamstark@46
|
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
adamstark@46
|
19 */
|
adamstark@46
|
20 //=======================================================================
|
adamstark@46
|
21
|
adamstark@46
|
22 #include <cmath>
|
adamstark@52
|
23 #include <algorithm>
|
adamstark@46
|
24 #include "BTrack.h"
|
adamstark@46
|
25 #include "samplerate.h"
|
adamstark@46
|
26
|
adamstark@46
|
27
|
adamstark@51
|
28 //=======================================================================
|
adamstark@46
|
29 BTrack :: BTrack()
|
adamstark@46
|
30 {
|
adamstark@46
|
31 float rayparam = 43;
|
adamstark@46
|
32 float pi = 3.14159265;
|
adamstark@46
|
33
|
adamstark@46
|
34
|
adamstark@46
|
35 // initialise parameters
|
adamstark@46
|
36 tightness = 5;
|
adamstark@46
|
37 alpha = 0.9;
|
adamstark@46
|
38 tempo = 120;
|
adamstark@46
|
39 est_tempo = 120;
|
adamstark@46
|
40 p_fact = 60.*44100./512.;
|
adamstark@46
|
41
|
adamstark@46
|
42 m0 = 10;
|
adamstark@46
|
43 beat = -1;
|
adamstark@46
|
44
|
adamstark@46
|
45 playbeat = 0;
|
adamstark@46
|
46
|
adamstark@46
|
47
|
adamstark@46
|
48
|
adamstark@46
|
49
|
adamstark@46
|
50 // create rayleigh weighting vector
|
adamstark@46
|
51 for (int n = 0;n < 128;n++)
|
adamstark@46
|
52 {
|
adamstark@46
|
53 wv[n] = ((float) n / pow(rayparam,2)) * exp((-1*pow((float)-n,2)) / (2*pow(rayparam,2)));
|
adamstark@46
|
54 }
|
adamstark@46
|
55
|
adamstark@46
|
56 // initialise prev_delta
|
adamstark@46
|
57 for (int i = 0;i < 41;i++)
|
adamstark@46
|
58 {
|
adamstark@46
|
59 prev_delta[i] = 1;
|
adamstark@46
|
60 }
|
adamstark@46
|
61
|
adamstark@46
|
62 float t_mu = 41/2;
|
adamstark@46
|
63 float m_sig;
|
adamstark@46
|
64 float x;
|
adamstark@46
|
65 // create tempo transition matrix
|
adamstark@46
|
66 m_sig = 41/8;
|
adamstark@46
|
67 for (int i = 0;i < 41;i++)
|
adamstark@46
|
68 {
|
adamstark@46
|
69 for (int j = 0;j < 41;j++)
|
adamstark@46
|
70 {
|
adamstark@46
|
71 x = j+1;
|
adamstark@46
|
72 t_mu = i+1;
|
adamstark@46
|
73 t_tmat[i][j] = (1 / (m_sig * sqrt(2*pi))) * exp( (-1*pow((x-t_mu),2)) / (2*pow(m_sig,2)) );
|
adamstark@46
|
74 }
|
adamstark@46
|
75 }
|
adamstark@46
|
76
|
adamstark@46
|
77 // tempo is not fixed
|
adamstark@46
|
78 tempofix = 0;
|
adamstark@46
|
79 }
|
adamstark@46
|
80
|
adamstark@51
|
81 //=======================================================================
|
adamstark@46
|
82 BTrack :: ~BTrack()
|
adamstark@46
|
83 {
|
adamstark@46
|
84
|
adamstark@46
|
85 }
|
adamstark@46
|
86
|
adamstark@51
|
87
|
adamstark@51
|
88
|
adamstark@51
|
89 //=======================================================================
|
adamstark@46
|
90 void BTrack :: initialise(int fsize)
|
adamstark@46
|
91 {
|
adamstark@46
|
92 framesize = fsize;
|
adamstark@46
|
93 dfbuffer_size = (512*512)/fsize; // calculate df buffer size
|
adamstark@46
|
94
|
adamstark@46
|
95 bperiod = round(60/((((float) fsize)/44100)*tempo));
|
adamstark@46
|
96
|
adamstark@46
|
97 dfbuffer = new float[dfbuffer_size]; // create df_buffer
|
adamstark@46
|
98 cumscore = new float[dfbuffer_size]; // create cumscore
|
adamstark@46
|
99
|
adamstark@46
|
100
|
adamstark@46
|
101 // initialise df_buffer to zeros
|
adamstark@46
|
102 for (int i = 0;i < dfbuffer_size;i++)
|
adamstark@46
|
103 {
|
adamstark@46
|
104 dfbuffer[i] = 0;
|
adamstark@46
|
105 cumscore[i] = 0;
|
adamstark@46
|
106
|
adamstark@46
|
107
|
adamstark@46
|
108 if ((i % ((int) round(bperiod))) == 0)
|
adamstark@46
|
109 {
|
adamstark@46
|
110 dfbuffer[i] = 1;
|
adamstark@46
|
111 }
|
adamstark@46
|
112 }
|
adamstark@46
|
113 }
|
adamstark@46
|
114
|
adamstark@51
|
115 //=======================================================================
|
adamstark@46
|
116 void BTrack :: process(float df_sample)
|
adamstark@46
|
117 {
|
adamstark@46
|
118 m0--;
|
adamstark@46
|
119 beat--;
|
adamstark@46
|
120 playbeat = 0;
|
adamstark@46
|
121
|
adamstark@46
|
122 // move all samples back one step
|
adamstark@46
|
123 for (int i=0;i < (dfbuffer_size-1);i++)
|
adamstark@46
|
124 {
|
adamstark@46
|
125 dfbuffer[i] = dfbuffer[i+1];
|
adamstark@46
|
126 }
|
adamstark@46
|
127
|
adamstark@46
|
128 // add new sample at the end
|
adamstark@46
|
129 dfbuffer[dfbuffer_size-1] = df_sample;
|
adamstark@46
|
130
|
adamstark@46
|
131 // update cumulative score
|
adamstark@46
|
132 updatecumscore(df_sample);
|
adamstark@46
|
133
|
adamstark@46
|
134 // if we are halfway between beats
|
adamstark@46
|
135 if (m0 == 0)
|
adamstark@46
|
136 {
|
adamstark@46
|
137 predictbeat();
|
adamstark@46
|
138 }
|
adamstark@46
|
139
|
adamstark@46
|
140 // if we are at a beat
|
adamstark@46
|
141 if (beat == 0)
|
adamstark@46
|
142 {
|
adamstark@46
|
143 playbeat = 1; // indicate a beat should be output
|
adamstark@46
|
144
|
adamstark@46
|
145 // recalculate the tempo
|
adamstark@46
|
146 dfconvert();
|
adamstark@46
|
147 calcTempo();
|
adamstark@46
|
148 }
|
adamstark@46
|
149 }
|
adamstark@46
|
150
|
adamstark@51
|
151 //=======================================================================
|
adamstark@46
|
152 void BTrack :: settempo(float tempo)
|
adamstark@46
|
153 {
|
adamstark@46
|
154
|
adamstark@46
|
155 /////////// TEMPO INDICATION RESET //////////////////
|
adamstark@46
|
156
|
adamstark@46
|
157 // firstly make sure tempo is between 80 and 160 bpm..
|
adamstark@46
|
158 while (tempo > 160)
|
adamstark@46
|
159 {
|
adamstark@46
|
160 tempo = tempo/2;
|
adamstark@46
|
161 }
|
adamstark@46
|
162
|
adamstark@46
|
163 while (tempo < 80)
|
adamstark@46
|
164 {
|
adamstark@46
|
165 tempo = tempo * 2;
|
adamstark@46
|
166 }
|
adamstark@46
|
167
|
adamstark@46
|
168 // convert tempo from bpm value to integer index of tempo probability
|
adamstark@46
|
169 int tempo_index = (int) round((tempo - 80)/2);
|
adamstark@46
|
170
|
adamstark@46
|
171 // now set previous tempo observations to zero
|
adamstark@46
|
172 for (int i=0;i < 41;i++)
|
adamstark@46
|
173 {
|
adamstark@46
|
174 prev_delta[i] = 0;
|
adamstark@46
|
175 }
|
adamstark@46
|
176
|
adamstark@46
|
177 // set desired tempo index to 1
|
adamstark@46
|
178 prev_delta[tempo_index] = 1;
|
adamstark@46
|
179
|
adamstark@46
|
180
|
adamstark@46
|
181 /////////// CUMULATIVE SCORE ARTIFICAL TEMPO UPDATE //////////////////
|
adamstark@46
|
182
|
adamstark@46
|
183 // calculate new beat period
|
adamstark@46
|
184 int new_bperiod = (int) round(60/((((float) framesize)/44100)*tempo));
|
adamstark@46
|
185
|
adamstark@46
|
186 int bcounter = 1;
|
adamstark@46
|
187 // initialise df_buffer to zeros
|
adamstark@46
|
188 for (int i = (dfbuffer_size-1);i >= 0;i--)
|
adamstark@46
|
189 {
|
adamstark@46
|
190 if (bcounter == 1)
|
adamstark@46
|
191 {
|
adamstark@46
|
192 cumscore[i] = 150;
|
adamstark@46
|
193 dfbuffer[i] = 150;
|
adamstark@46
|
194 }
|
adamstark@46
|
195 else
|
adamstark@46
|
196 {
|
adamstark@46
|
197 cumscore[i] = 10;
|
adamstark@46
|
198 dfbuffer[i] = 10;
|
adamstark@46
|
199 }
|
adamstark@46
|
200
|
adamstark@46
|
201 bcounter++;
|
adamstark@46
|
202
|
adamstark@46
|
203 if (bcounter > new_bperiod)
|
adamstark@46
|
204 {
|
adamstark@46
|
205 bcounter = 1;
|
adamstark@46
|
206 }
|
adamstark@46
|
207 }
|
adamstark@46
|
208
|
adamstark@46
|
209 /////////// INDICATE THAT THIS IS A BEAT //////////////////
|
adamstark@46
|
210
|
adamstark@46
|
211 // beat is now
|
adamstark@46
|
212 beat = 0;
|
adamstark@46
|
213
|
adamstark@46
|
214 // offbeat is half of new beat period away
|
adamstark@46
|
215 m0 = (int) round(((float) new_bperiod)/2);
|
adamstark@46
|
216 }
|
adamstark@46
|
217
|
adamstark@51
|
218 //=======================================================================
|
adamstark@46
|
219 void BTrack :: fixtempo(float tempo)
|
adamstark@46
|
220 {
|
adamstark@46
|
221 // firstly make sure tempo is between 80 and 160 bpm..
|
adamstark@46
|
222 while (tempo > 160)
|
adamstark@46
|
223 {
|
adamstark@46
|
224 tempo = tempo/2;
|
adamstark@46
|
225 }
|
adamstark@46
|
226
|
adamstark@46
|
227 while (tempo < 80)
|
adamstark@46
|
228 {
|
adamstark@46
|
229 tempo = tempo * 2;
|
adamstark@46
|
230 }
|
adamstark@46
|
231
|
adamstark@46
|
232 // convert tempo from bpm value to integer index of tempo probability
|
adamstark@46
|
233 int tempo_index = (int) round((tempo - 80)/2);
|
adamstark@46
|
234
|
adamstark@46
|
235 // now set previous fixed previous tempo observation values to zero
|
adamstark@46
|
236 for (int i=0;i < 41;i++)
|
adamstark@46
|
237 {
|
adamstark@46
|
238 prev_delta_fix[i] = 0;
|
adamstark@46
|
239 }
|
adamstark@46
|
240
|
adamstark@46
|
241 // set desired tempo index to 1
|
adamstark@46
|
242 prev_delta_fix[tempo_index] = 1;
|
adamstark@46
|
243
|
adamstark@46
|
244 // set the tempo fix flag
|
adamstark@46
|
245 tempofix = 1;
|
adamstark@46
|
246 }
|
adamstark@46
|
247
|
adamstark@51
|
248 //=======================================================================
|
adamstark@46
|
249 void BTrack :: unfixtempo()
|
adamstark@46
|
250 {
|
adamstark@46
|
251 // set the tempo fix flag
|
adamstark@46
|
252 tempofix = 0;
|
adamstark@46
|
253 }
|
adamstark@46
|
254
|
adamstark@51
|
255 //=======================================================================
|
adamstark@46
|
256 void BTrack :: dfconvert()
|
adamstark@46
|
257 {
|
adamstark@46
|
258 float output[512];
|
adamstark@46
|
259
|
adamstark@46
|
260 double src_ratio = 512.0/((double) dfbuffer_size);
|
adamstark@46
|
261 int BUFFER_LEN = dfbuffer_size;
|
adamstark@46
|
262 int output_len;
|
adamstark@46
|
263 SRC_DATA src_data ;
|
adamstark@46
|
264
|
adamstark@46
|
265 //output_len = (int) floor (((double) BUFFER_LEN) * src_ratio) ;
|
adamstark@46
|
266 output_len = 512;
|
adamstark@46
|
267
|
adamstark@46
|
268 src_data.data_in = dfbuffer;
|
adamstark@46
|
269 src_data.input_frames = BUFFER_LEN;
|
adamstark@46
|
270
|
adamstark@46
|
271 src_data.src_ratio = src_ratio;
|
adamstark@46
|
272
|
adamstark@46
|
273 src_data.data_out = output;
|
adamstark@46
|
274 src_data.output_frames = output_len;
|
adamstark@46
|
275
|
adamstark@46
|
276 src_simple (&src_data, SRC_SINC_BEST_QUALITY, 1);
|
adamstark@46
|
277
|
adamstark@46
|
278 for (int i = 0;i < output_len;i++)
|
adamstark@46
|
279 {
|
adamstark@46
|
280 df512[i] = src_data.data_out[i];
|
adamstark@46
|
281 }
|
adamstark@46
|
282 }
|
adamstark@46
|
283
|
adamstark@51
|
284 //=======================================================================
|
adamstark@46
|
285 void BTrack :: calcTempo()
|
adamstark@46
|
286 {
|
adamstark@46
|
287 // adaptive threshold on input
|
adamstark@46
|
288 adapt_thresh(df512,512);
|
adamstark@46
|
289
|
adamstark@46
|
290 // calculate auto-correlation function of detection function
|
adamstark@46
|
291 acf_bal(df512);
|
adamstark@46
|
292
|
adamstark@46
|
293 // calculate output of comb filterbank
|
adamstark@46
|
294 getrcfoutput();
|
adamstark@46
|
295
|
adamstark@46
|
296
|
adamstark@46
|
297 // adaptive threshold on rcf
|
adamstark@46
|
298 adapt_thresh(rcf,128);
|
adamstark@46
|
299
|
adamstark@46
|
300
|
adamstark@46
|
301 int t_index;
|
adamstark@46
|
302 int t_index2;
|
adamstark@46
|
303 // calculate tempo observation vector from bperiod observation vector
|
adamstark@46
|
304 for (int i = 0;i < 41;i++)
|
adamstark@46
|
305 {
|
adamstark@46
|
306 t_index = (int) round(p_fact / ((float) ((2*i)+80)));
|
adamstark@46
|
307 t_index2 = (int) round(p_fact / ((float) ((4*i)+160)));
|
adamstark@46
|
308
|
adamstark@46
|
309
|
adamstark@46
|
310 t_obs[i] = rcf[t_index-1] + rcf[t_index2-1];
|
adamstark@46
|
311 }
|
adamstark@46
|
312
|
adamstark@46
|
313
|
adamstark@46
|
314 float maxval;
|
adamstark@46
|
315 float maxind;
|
adamstark@46
|
316 float curval;
|
adamstark@46
|
317
|
adamstark@46
|
318 // if tempo is fixed then always use a fixed set of tempi as the previous observation probability function
|
adamstark@46
|
319 if (tempofix == 1)
|
adamstark@46
|
320 {
|
adamstark@46
|
321 for (int k = 0;k < 41;k++)
|
adamstark@46
|
322 {
|
adamstark@46
|
323 prev_delta[k] = prev_delta_fix[k];
|
adamstark@46
|
324 }
|
adamstark@46
|
325 }
|
adamstark@46
|
326
|
adamstark@46
|
327 for (int j=0;j < 41;j++)
|
adamstark@46
|
328 {
|
adamstark@46
|
329 maxval = -1;
|
adamstark@46
|
330 for (int i = 0;i < 41;i++)
|
adamstark@46
|
331 {
|
adamstark@46
|
332 curval = prev_delta[i]*t_tmat[i][j];
|
adamstark@46
|
333
|
adamstark@46
|
334 if (curval > maxval)
|
adamstark@46
|
335 {
|
adamstark@46
|
336 maxval = curval;
|
adamstark@46
|
337 }
|
adamstark@46
|
338 }
|
adamstark@46
|
339
|
adamstark@46
|
340 delta[j] = maxval*t_obs[j];
|
adamstark@46
|
341 }
|
adamstark@46
|
342
|
adamstark@46
|
343
|
adamstark@46
|
344 normalise(delta,41);
|
adamstark@46
|
345
|
adamstark@46
|
346 maxind = -1;
|
adamstark@46
|
347 maxval = -1;
|
adamstark@46
|
348
|
adamstark@46
|
349 for (int j=0;j < 41;j++)
|
adamstark@46
|
350 {
|
adamstark@46
|
351 if (delta[j] > maxval)
|
adamstark@46
|
352 {
|
adamstark@46
|
353 maxval = delta[j];
|
adamstark@46
|
354 maxind = j;
|
adamstark@46
|
355 }
|
adamstark@46
|
356
|
adamstark@46
|
357 prev_delta[j] = delta[j];
|
adamstark@46
|
358 }
|
adamstark@46
|
359
|
adamstark@46
|
360 bperiod = round((60.0*44100.0)/(((2*maxind)+80)*((float) framesize)));
|
adamstark@46
|
361
|
adamstark@46
|
362 if (bperiod > 0)
|
adamstark@46
|
363 {
|
adamstark@46
|
364 est_tempo = 60.0/((((float) framesize) / 44100.0)*bperiod);
|
adamstark@46
|
365 }
|
adamstark@46
|
366
|
adamstark@46
|
367 //cout << bperiod << endl;
|
adamstark@46
|
368 }
|
adamstark@46
|
369
|
adamstark@51
|
370 //=======================================================================
|
adamstark@46
|
371 void BTrack :: adapt_thresh(float x[],int N)
|
adamstark@46
|
372 {
|
adamstark@46
|
373 //int N = 512; // length of df
|
adamstark@46
|
374 int i = 0;
|
adamstark@46
|
375 int k,t = 0;
|
adamstark@46
|
376 float x_thresh[N];
|
adamstark@46
|
377
|
adamstark@46
|
378 int p_post = 7;
|
adamstark@46
|
379 int p_pre = 8;
|
adamstark@46
|
380
|
adamstark@52
|
381 t = std::min(N,p_post); // what is smaller, p_post of df size. This is to avoid accessing outside of arrays
|
adamstark@46
|
382
|
adamstark@46
|
383 // find threshold for first 't' samples, where a full average cannot be computed yet
|
adamstark@46
|
384 for (i = 0;i <= t;i++)
|
adamstark@46
|
385 {
|
adamstark@52
|
386 k = std::min((i+p_pre),N);
|
adamstark@46
|
387 x_thresh[i] = mean_array(x,1,k);
|
adamstark@46
|
388 }
|
adamstark@46
|
389 // find threshold for bulk of samples across a moving average from [i-p_pre,i+p_post]
|
adamstark@46
|
390 for (i = t+1;i < N-p_post;i++)
|
adamstark@46
|
391 {
|
adamstark@46
|
392 x_thresh[i] = mean_array(x,i-p_pre,i+p_post);
|
adamstark@46
|
393 }
|
adamstark@46
|
394 // for last few samples calculate threshold, again, not enough samples to do as above
|
adamstark@46
|
395 for (i = N-p_post;i < N;i++)
|
adamstark@46
|
396 {
|
adamstark@52
|
397 k = std::max((i-p_post),1);
|
adamstark@46
|
398 x_thresh[i] = mean_array(x,k,N);
|
adamstark@46
|
399 }
|
adamstark@46
|
400
|
adamstark@46
|
401 // subtract the threshold from the detection function and check that it is not less than 0
|
adamstark@46
|
402 for (i = 0;i < N;i++)
|
adamstark@46
|
403 {
|
adamstark@46
|
404 x[i] = x[i] - x_thresh[i];
|
adamstark@46
|
405 if (x[i] < 0)
|
adamstark@46
|
406 {
|
adamstark@46
|
407 x[i] = 0;
|
adamstark@46
|
408 }
|
adamstark@46
|
409 }
|
adamstark@46
|
410 }
|
adamstark@46
|
411
|
adamstark@51
|
412 //=======================================================================
|
adamstark@46
|
413 void BTrack :: getrcfoutput()
|
adamstark@46
|
414 {
|
adamstark@46
|
415 int numelem;
|
adamstark@46
|
416
|
adamstark@46
|
417 for (int i = 0;i < 128;i++)
|
adamstark@46
|
418 {
|
adamstark@46
|
419 rcf[i] = 0;
|
adamstark@46
|
420 }
|
adamstark@46
|
421
|
adamstark@46
|
422 numelem = 4;
|
adamstark@46
|
423
|
adamstark@46
|
424 for (int i = 2;i <= 127;i++) // max beat period
|
adamstark@46
|
425 {
|
adamstark@46
|
426 for (int a = 1;a <= numelem;a++) // number of comb elements
|
adamstark@46
|
427 {
|
adamstark@46
|
428 for (int b = 1-a;b <= a-1;b++) // general state using normalisation of comb elements
|
adamstark@46
|
429 {
|
adamstark@46
|
430 rcf[i-1] = rcf[i-1] + (acf[(a*i+b)-1]*wv[i-1])/(2*a-1); // calculate value for comb filter row
|
adamstark@46
|
431 }
|
adamstark@46
|
432 }
|
adamstark@46
|
433 }
|
adamstark@46
|
434 }
|
adamstark@46
|
435
|
adamstark@51
|
436 //=======================================================================
|
adamstark@46
|
437 void BTrack :: acf_bal(float df_thresh[])
|
adamstark@46
|
438 {
|
adamstark@46
|
439 int l, n = 0;
|
adamstark@46
|
440 float sum, tmp;
|
adamstark@46
|
441
|
adamstark@46
|
442 // for l lags from 0-511
|
adamstark@46
|
443 for (l = 0;l < 512;l++)
|
adamstark@46
|
444 {
|
adamstark@46
|
445 sum = 0;
|
adamstark@46
|
446
|
adamstark@46
|
447 // for n samples from 0 - (512-lag)
|
adamstark@46
|
448 for (n = 0;n < (512-l);n++)
|
adamstark@46
|
449 {
|
adamstark@46
|
450 tmp = df_thresh[n] * df_thresh[n+l]; // multiply current sample n by sample (n+l)
|
adamstark@46
|
451 sum = sum + tmp; // add to sum
|
adamstark@46
|
452 }
|
adamstark@46
|
453
|
adamstark@46
|
454 acf[l] = sum / (512-l); // weight by number of mults and add to acf buffer
|
adamstark@46
|
455 }
|
adamstark@46
|
456 }
|
adamstark@46
|
457
|
adamstark@51
|
458 //=======================================================================
|
adamstark@46
|
459 float BTrack :: mean_array(float array[],int start,int end)
|
adamstark@46
|
460 {
|
adamstark@46
|
461 int i;
|
adamstark@47
|
462 double sum = 0;
|
adamstark@47
|
463
|
adamstark@47
|
464 int length = end - start;
|
adamstark@46
|
465
|
adamstark@46
|
466 // find sum
|
adamstark@47
|
467 for (i = start;i < end;i++)
|
adamstark@46
|
468 {
|
adamstark@46
|
469 sum = sum + array[i];
|
adamstark@46
|
470 }
|
adamstark@46
|
471
|
adamstark@47
|
472 if (length > 0)
|
adamstark@47
|
473 {
|
adamstark@47
|
474 return sum / length; // average and return
|
adamstark@47
|
475 }
|
adamstark@47
|
476 else
|
adamstark@47
|
477 {
|
adamstark@47
|
478 return 0;
|
adamstark@47
|
479 }
|
adamstark@46
|
480 }
|
adamstark@46
|
481
|
adamstark@51
|
482 //=======================================================================
|
adamstark@46
|
483 void BTrack :: normalise(float array[],int N)
|
adamstark@46
|
484 {
|
adamstark@46
|
485 double sum = 0;
|
adamstark@46
|
486
|
adamstark@46
|
487 for (int i = 0;i < N;i++)
|
adamstark@46
|
488 {
|
adamstark@46
|
489 if (array[i] > 0)
|
adamstark@46
|
490 {
|
adamstark@46
|
491 sum = sum + array[i];
|
adamstark@46
|
492 }
|
adamstark@46
|
493 }
|
adamstark@46
|
494
|
adamstark@46
|
495 if (sum > 0)
|
adamstark@46
|
496 {
|
adamstark@46
|
497 for (int i = 0;i < N;i++)
|
adamstark@46
|
498 {
|
adamstark@46
|
499 array[i] = array[i] / sum;
|
adamstark@46
|
500 }
|
adamstark@46
|
501 }
|
adamstark@46
|
502 }
|
adamstark@46
|
503
|
adamstark@51
|
504 //=======================================================================
|
adamstark@46
|
505 void BTrack :: updatecumscore(float df_sample)
|
adamstark@46
|
506 {
|
adamstark@46
|
507 int start, end, winsize;
|
adamstark@46
|
508 float max;
|
adamstark@46
|
509
|
adamstark@46
|
510 start = dfbuffer_size - round(2*bperiod);
|
adamstark@46
|
511 end = dfbuffer_size - round(bperiod/2);
|
adamstark@46
|
512 winsize = end-start+1;
|
adamstark@46
|
513
|
adamstark@46
|
514 float w1[winsize];
|
adamstark@46
|
515 float v = -2*bperiod;
|
adamstark@46
|
516 float wcumscore;
|
adamstark@46
|
517
|
adamstark@46
|
518
|
adamstark@46
|
519 // create window
|
adamstark@46
|
520 for (int i = 0;i < winsize;i++)
|
adamstark@46
|
521 {
|
adamstark@46
|
522 w1[i] = exp((-1*pow(tightness*log(-v/bperiod),2))/2);
|
adamstark@46
|
523 v = v+1;
|
adamstark@46
|
524 }
|
adamstark@46
|
525
|
adamstark@46
|
526 // calculate new cumulative score value
|
adamstark@46
|
527 max = 0;
|
adamstark@46
|
528 int n = 0;
|
adamstark@46
|
529 for (int i=start;i <= end;i++)
|
adamstark@46
|
530 {
|
adamstark@46
|
531 wcumscore = cumscore[i]*w1[n];
|
adamstark@46
|
532
|
adamstark@46
|
533 if (wcumscore > max)
|
adamstark@46
|
534 {
|
adamstark@46
|
535 max = wcumscore;
|
adamstark@46
|
536 }
|
adamstark@46
|
537 n++;
|
adamstark@46
|
538 }
|
adamstark@46
|
539
|
adamstark@46
|
540
|
adamstark@46
|
541 // shift cumulative score back one
|
adamstark@46
|
542 for (int i = 0;i < (dfbuffer_size-1);i++)
|
adamstark@46
|
543 {
|
adamstark@46
|
544 cumscore[i] = cumscore[i+1];
|
adamstark@46
|
545 }
|
adamstark@46
|
546
|
adamstark@46
|
547 // add new value to cumulative score
|
adamstark@46
|
548 cumscore[dfbuffer_size-1] = ((1-alpha)*df_sample) + (alpha*max);
|
adamstark@46
|
549
|
adamstark@46
|
550 cscoreval = cumscore[dfbuffer_size-1];
|
adamstark@46
|
551
|
adamstark@46
|
552 //cout << cumscore[dfbuffer_size-1] << endl;
|
adamstark@46
|
553
|
adamstark@46
|
554 }
|
adamstark@46
|
555
|
adamstark@51
|
556 //=======================================================================
|
adamstark@46
|
557 void BTrack :: predictbeat()
|
adamstark@46
|
558 {
|
adamstark@46
|
559 int winsize = (int) bperiod;
|
adamstark@46
|
560 float fcumscore[dfbuffer_size + winsize];
|
adamstark@46
|
561 float w2[winsize];
|
adamstark@46
|
562 // copy cumscore to first part of fcumscore
|
adamstark@46
|
563 for (int i = 0;i < dfbuffer_size;i++)
|
adamstark@46
|
564 {
|
adamstark@46
|
565 fcumscore[i] = cumscore[i];
|
adamstark@46
|
566 }
|
adamstark@46
|
567
|
adamstark@46
|
568 // create future window
|
adamstark@46
|
569 float v = 1;
|
adamstark@46
|
570 for (int i = 0;i < winsize;i++)
|
adamstark@46
|
571 {
|
adamstark@46
|
572 w2[i] = exp((-1*pow((v - (bperiod/2)),2)) / (2*pow((bperiod/2) ,2)));
|
adamstark@46
|
573 v++;
|
adamstark@46
|
574 }
|
adamstark@46
|
575
|
adamstark@46
|
576 // create past window
|
adamstark@46
|
577 v = -2*bperiod;
|
adamstark@46
|
578 int start = dfbuffer_size - round(2*bperiod);
|
adamstark@46
|
579 int end = dfbuffer_size - round(bperiod/2);
|
adamstark@46
|
580 int pastwinsize = end-start+1;
|
adamstark@46
|
581 float w1[pastwinsize];
|
adamstark@46
|
582
|
adamstark@46
|
583 for (int i = 0;i < pastwinsize;i++)
|
adamstark@46
|
584 {
|
adamstark@46
|
585 w1[i] = exp((-1*pow(tightness*log(-v/bperiod),2))/2);
|
adamstark@46
|
586 v = v+1;
|
adamstark@46
|
587 }
|
adamstark@46
|
588
|
adamstark@46
|
589
|
adamstark@46
|
590
|
adamstark@46
|
591 // calculate future cumulative score
|
adamstark@46
|
592 float max;
|
adamstark@46
|
593 int n;
|
adamstark@46
|
594 float wcumscore;
|
adamstark@46
|
595 for (int i = dfbuffer_size;i < (dfbuffer_size+winsize);i++)
|
adamstark@46
|
596 {
|
adamstark@46
|
597 start = i - round(2*bperiod);
|
adamstark@46
|
598 end = i - round(bperiod/2);
|
adamstark@46
|
599
|
adamstark@46
|
600 max = 0;
|
adamstark@46
|
601 n = 0;
|
adamstark@46
|
602 for (int k=start;k <= end;k++)
|
adamstark@46
|
603 {
|
adamstark@46
|
604 wcumscore = fcumscore[k]*w1[n];
|
adamstark@46
|
605
|
adamstark@46
|
606 if (wcumscore > max)
|
adamstark@46
|
607 {
|
adamstark@46
|
608 max = wcumscore;
|
adamstark@46
|
609 }
|
adamstark@46
|
610 n++;
|
adamstark@46
|
611 }
|
adamstark@46
|
612
|
adamstark@46
|
613 fcumscore[i] = max;
|
adamstark@46
|
614 }
|
adamstark@46
|
615
|
adamstark@46
|
616
|
adamstark@46
|
617 // predict beat
|
adamstark@46
|
618 max = 0;
|
adamstark@46
|
619 n = 0;
|
adamstark@46
|
620
|
adamstark@46
|
621 for (int i = dfbuffer_size;i < (dfbuffer_size+winsize);i++)
|
adamstark@46
|
622 {
|
adamstark@46
|
623 wcumscore = fcumscore[i]*w2[n];
|
adamstark@46
|
624
|
adamstark@46
|
625 if (wcumscore > max)
|
adamstark@46
|
626 {
|
adamstark@46
|
627 max = wcumscore;
|
adamstark@46
|
628 beat = n;
|
adamstark@46
|
629 }
|
adamstark@46
|
630
|
adamstark@46
|
631 n++;
|
adamstark@46
|
632 }
|
adamstark@46
|
633
|
adamstark@46
|
634
|
adamstark@46
|
635 // set beat
|
adamstark@51
|
636 //beat = beat;
|
adamstark@46
|
637
|
adamstark@46
|
638 // set next prediction time
|
adamstark@46
|
639 m0 = beat+round(bperiod/2);
|
adamstark@46
|
640
|
adamstark@46
|
641
|
adamstark@46
|
642 } |