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