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@54
|
31 double rayparam = 43;
|
adamstark@54
|
32 double 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@54
|
53 wv[n] = ((double) n / pow(rayparam,2)) * exp((-1*pow((double)-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@54
|
62 double t_mu = 41/2;
|
adamstark@54
|
63 double m_sig;
|
adamstark@54
|
64 double 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@54
|
95 bperiod = round(60/((((double) fsize)/44100)*tempo));
|
adamstark@46
|
96
|
adamstark@54
|
97 dfbuffer = new double[dfbuffer_size]; // create df_buffer
|
adamstark@54
|
98 cumscore = new double[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@54
|
116 void BTrack :: process(double 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@54
|
152 void BTrack :: settempo(double 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@54
|
184 int new_bperiod = (int) round(60/((((double) 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@54
|
215 m0 = (int) round(((double) new_bperiod)/2);
|
adamstark@46
|
216 }
|
adamstark@46
|
217
|
adamstark@51
|
218 //=======================================================================
|
adamstark@54
|
219 void BTrack :: fixtempo(double 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@54
|
259 float input[dfbuffer_size];
|
adamstark@54
|
260
|
adamstark@54
|
261 for (int i = 0;i < dfbuffer_size;i++)
|
adamstark@54
|
262 {
|
adamstark@54
|
263 input[i] = (float) dfbuffer[i];
|
adamstark@54
|
264 }
|
adamstark@46
|
265
|
adamstark@46
|
266 double src_ratio = 512.0/((double) dfbuffer_size);
|
adamstark@46
|
267 int BUFFER_LEN = dfbuffer_size;
|
adamstark@46
|
268 int output_len;
|
adamstark@46
|
269 SRC_DATA src_data ;
|
adamstark@46
|
270
|
adamstark@46
|
271 //output_len = (int) floor (((double) BUFFER_LEN) * src_ratio) ;
|
adamstark@46
|
272 output_len = 512;
|
adamstark@46
|
273
|
adamstark@54
|
274 src_data.data_in = input;
|
adamstark@46
|
275 src_data.input_frames = BUFFER_LEN;
|
adamstark@46
|
276
|
adamstark@46
|
277 src_data.src_ratio = src_ratio;
|
adamstark@46
|
278
|
adamstark@46
|
279 src_data.data_out = output;
|
adamstark@46
|
280 src_data.output_frames = output_len;
|
adamstark@46
|
281
|
adamstark@46
|
282 src_simple (&src_data, SRC_SINC_BEST_QUALITY, 1);
|
adamstark@46
|
283
|
adamstark@46
|
284 for (int i = 0;i < output_len;i++)
|
adamstark@46
|
285 {
|
adamstark@54
|
286 df512[i] = (double) src_data.data_out[i];
|
adamstark@46
|
287 }
|
adamstark@46
|
288 }
|
adamstark@46
|
289
|
adamstark@51
|
290 //=======================================================================
|
adamstark@46
|
291 void BTrack :: calcTempo()
|
adamstark@46
|
292 {
|
adamstark@46
|
293 // adaptive threshold on input
|
adamstark@46
|
294 adapt_thresh(df512,512);
|
adamstark@46
|
295
|
adamstark@46
|
296 // calculate auto-correlation function of detection function
|
adamstark@46
|
297 acf_bal(df512);
|
adamstark@46
|
298
|
adamstark@46
|
299 // calculate output of comb filterbank
|
adamstark@46
|
300 getrcfoutput();
|
adamstark@46
|
301
|
adamstark@46
|
302
|
adamstark@46
|
303 // adaptive threshold on rcf
|
adamstark@46
|
304 adapt_thresh(rcf,128);
|
adamstark@46
|
305
|
adamstark@46
|
306
|
adamstark@46
|
307 int t_index;
|
adamstark@46
|
308 int t_index2;
|
adamstark@46
|
309 // calculate tempo observation vector from bperiod observation vector
|
adamstark@46
|
310 for (int i = 0;i < 41;i++)
|
adamstark@46
|
311 {
|
adamstark@54
|
312 t_index = (int) round(p_fact / ((double) ((2*i)+80)));
|
adamstark@54
|
313 t_index2 = (int) round(p_fact / ((double) ((4*i)+160)));
|
adamstark@46
|
314
|
adamstark@46
|
315
|
adamstark@46
|
316 t_obs[i] = rcf[t_index-1] + rcf[t_index2-1];
|
adamstark@46
|
317 }
|
adamstark@46
|
318
|
adamstark@46
|
319
|
adamstark@54
|
320 double maxval;
|
adamstark@54
|
321 double maxind;
|
adamstark@54
|
322 double curval;
|
adamstark@46
|
323
|
adamstark@46
|
324 // if tempo is fixed then always use a fixed set of tempi as the previous observation probability function
|
adamstark@46
|
325 if (tempofix == 1)
|
adamstark@46
|
326 {
|
adamstark@46
|
327 for (int k = 0;k < 41;k++)
|
adamstark@46
|
328 {
|
adamstark@46
|
329 prev_delta[k] = prev_delta_fix[k];
|
adamstark@46
|
330 }
|
adamstark@46
|
331 }
|
adamstark@46
|
332
|
adamstark@46
|
333 for (int j=0;j < 41;j++)
|
adamstark@46
|
334 {
|
adamstark@46
|
335 maxval = -1;
|
adamstark@46
|
336 for (int i = 0;i < 41;i++)
|
adamstark@46
|
337 {
|
adamstark@46
|
338 curval = prev_delta[i]*t_tmat[i][j];
|
adamstark@46
|
339
|
adamstark@46
|
340 if (curval > maxval)
|
adamstark@46
|
341 {
|
adamstark@46
|
342 maxval = curval;
|
adamstark@46
|
343 }
|
adamstark@46
|
344 }
|
adamstark@46
|
345
|
adamstark@46
|
346 delta[j] = maxval*t_obs[j];
|
adamstark@46
|
347 }
|
adamstark@46
|
348
|
adamstark@46
|
349
|
adamstark@46
|
350 normalise(delta,41);
|
adamstark@46
|
351
|
adamstark@46
|
352 maxind = -1;
|
adamstark@46
|
353 maxval = -1;
|
adamstark@46
|
354
|
adamstark@46
|
355 for (int j=0;j < 41;j++)
|
adamstark@46
|
356 {
|
adamstark@46
|
357 if (delta[j] > maxval)
|
adamstark@46
|
358 {
|
adamstark@46
|
359 maxval = delta[j];
|
adamstark@46
|
360 maxind = j;
|
adamstark@46
|
361 }
|
adamstark@46
|
362
|
adamstark@46
|
363 prev_delta[j] = delta[j];
|
adamstark@46
|
364 }
|
adamstark@46
|
365
|
adamstark@54
|
366 bperiod = round((60.0*44100.0)/(((2*maxind)+80)*((double) framesize)));
|
adamstark@46
|
367
|
adamstark@46
|
368 if (bperiod > 0)
|
adamstark@46
|
369 {
|
adamstark@54
|
370 est_tempo = 60.0/((((double) framesize) / 44100.0)*bperiod);
|
adamstark@46
|
371 }
|
adamstark@46
|
372
|
adamstark@46
|
373 //cout << bperiod << endl;
|
adamstark@46
|
374 }
|
adamstark@46
|
375
|
adamstark@51
|
376 //=======================================================================
|
adamstark@54
|
377 void BTrack :: adapt_thresh(double *x,int N)
|
adamstark@46
|
378 {
|
adamstark@46
|
379 //int N = 512; // length of df
|
adamstark@46
|
380 int i = 0;
|
adamstark@46
|
381 int k,t = 0;
|
adamstark@54
|
382 double x_thresh[N];
|
adamstark@46
|
383
|
adamstark@46
|
384 int p_post = 7;
|
adamstark@46
|
385 int p_pre = 8;
|
adamstark@46
|
386
|
adamstark@52
|
387 t = std::min(N,p_post); // what is smaller, p_post of df size. This is to avoid accessing outside of arrays
|
adamstark@46
|
388
|
adamstark@46
|
389 // find threshold for first 't' samples, where a full average cannot be computed yet
|
adamstark@46
|
390 for (i = 0;i <= t;i++)
|
adamstark@46
|
391 {
|
adamstark@52
|
392 k = std::min((i+p_pre),N);
|
adamstark@46
|
393 x_thresh[i] = mean_array(x,1,k);
|
adamstark@46
|
394 }
|
adamstark@46
|
395 // find threshold for bulk of samples across a moving average from [i-p_pre,i+p_post]
|
adamstark@46
|
396 for (i = t+1;i < N-p_post;i++)
|
adamstark@46
|
397 {
|
adamstark@46
|
398 x_thresh[i] = mean_array(x,i-p_pre,i+p_post);
|
adamstark@46
|
399 }
|
adamstark@46
|
400 // for last few samples calculate threshold, again, not enough samples to do as above
|
adamstark@46
|
401 for (i = N-p_post;i < N;i++)
|
adamstark@46
|
402 {
|
adamstark@52
|
403 k = std::max((i-p_post),1);
|
adamstark@46
|
404 x_thresh[i] = mean_array(x,k,N);
|
adamstark@46
|
405 }
|
adamstark@46
|
406
|
adamstark@46
|
407 // subtract the threshold from the detection function and check that it is not less than 0
|
adamstark@46
|
408 for (i = 0;i < N;i++)
|
adamstark@46
|
409 {
|
adamstark@46
|
410 x[i] = x[i] - x_thresh[i];
|
adamstark@46
|
411 if (x[i] < 0)
|
adamstark@46
|
412 {
|
adamstark@46
|
413 x[i] = 0;
|
adamstark@46
|
414 }
|
adamstark@46
|
415 }
|
adamstark@46
|
416 }
|
adamstark@46
|
417
|
adamstark@51
|
418 //=======================================================================
|
adamstark@46
|
419 void BTrack :: getrcfoutput()
|
adamstark@46
|
420 {
|
adamstark@46
|
421 int numelem;
|
adamstark@46
|
422
|
adamstark@46
|
423 for (int i = 0;i < 128;i++)
|
adamstark@46
|
424 {
|
adamstark@46
|
425 rcf[i] = 0;
|
adamstark@46
|
426 }
|
adamstark@46
|
427
|
adamstark@46
|
428 numelem = 4;
|
adamstark@46
|
429
|
adamstark@46
|
430 for (int i = 2;i <= 127;i++) // max beat period
|
adamstark@46
|
431 {
|
adamstark@46
|
432 for (int a = 1;a <= numelem;a++) // number of comb elements
|
adamstark@46
|
433 {
|
adamstark@46
|
434 for (int b = 1-a;b <= a-1;b++) // general state using normalisation of comb elements
|
adamstark@46
|
435 {
|
adamstark@46
|
436 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
|
437 }
|
adamstark@46
|
438 }
|
adamstark@46
|
439 }
|
adamstark@46
|
440 }
|
adamstark@46
|
441
|
adamstark@51
|
442 //=======================================================================
|
adamstark@54
|
443 void BTrack :: acf_bal(double *df_thresh)
|
adamstark@46
|
444 {
|
adamstark@46
|
445 int l, n = 0;
|
adamstark@54
|
446 double sum, tmp;
|
adamstark@46
|
447
|
adamstark@46
|
448 // for l lags from 0-511
|
adamstark@46
|
449 for (l = 0;l < 512;l++)
|
adamstark@46
|
450 {
|
adamstark@46
|
451 sum = 0;
|
adamstark@46
|
452
|
adamstark@46
|
453 // for n samples from 0 - (512-lag)
|
adamstark@46
|
454 for (n = 0;n < (512-l);n++)
|
adamstark@46
|
455 {
|
adamstark@46
|
456 tmp = df_thresh[n] * df_thresh[n+l]; // multiply current sample n by sample (n+l)
|
adamstark@46
|
457 sum = sum + tmp; // add to sum
|
adamstark@46
|
458 }
|
adamstark@46
|
459
|
adamstark@46
|
460 acf[l] = sum / (512-l); // weight by number of mults and add to acf buffer
|
adamstark@46
|
461 }
|
adamstark@46
|
462 }
|
adamstark@46
|
463
|
adamstark@51
|
464 //=======================================================================
|
adamstark@54
|
465 double BTrack :: mean_array(double *array,int start,int end)
|
adamstark@46
|
466 {
|
adamstark@46
|
467 int i;
|
adamstark@47
|
468 double sum = 0;
|
adamstark@47
|
469
|
adamstark@47
|
470 int length = end - start;
|
adamstark@46
|
471
|
adamstark@46
|
472 // find sum
|
adamstark@47
|
473 for (i = start;i < end;i++)
|
adamstark@46
|
474 {
|
adamstark@46
|
475 sum = sum + array[i];
|
adamstark@46
|
476 }
|
adamstark@46
|
477
|
adamstark@47
|
478 if (length > 0)
|
adamstark@47
|
479 {
|
adamstark@47
|
480 return sum / length; // average and return
|
adamstark@47
|
481 }
|
adamstark@47
|
482 else
|
adamstark@47
|
483 {
|
adamstark@47
|
484 return 0;
|
adamstark@47
|
485 }
|
adamstark@46
|
486 }
|
adamstark@46
|
487
|
adamstark@51
|
488 //=======================================================================
|
adamstark@54
|
489 void BTrack :: normalise(double *array,int N)
|
adamstark@46
|
490 {
|
adamstark@46
|
491 double sum = 0;
|
adamstark@46
|
492
|
adamstark@46
|
493 for (int i = 0;i < N;i++)
|
adamstark@46
|
494 {
|
adamstark@46
|
495 if (array[i] > 0)
|
adamstark@46
|
496 {
|
adamstark@46
|
497 sum = sum + array[i];
|
adamstark@46
|
498 }
|
adamstark@46
|
499 }
|
adamstark@46
|
500
|
adamstark@46
|
501 if (sum > 0)
|
adamstark@46
|
502 {
|
adamstark@46
|
503 for (int i = 0;i < N;i++)
|
adamstark@46
|
504 {
|
adamstark@46
|
505 array[i] = array[i] / sum;
|
adamstark@46
|
506 }
|
adamstark@46
|
507 }
|
adamstark@46
|
508 }
|
adamstark@46
|
509
|
adamstark@51
|
510 //=======================================================================
|
adamstark@54
|
511 void BTrack :: updatecumscore(double df_sample)
|
adamstark@46
|
512 {
|
adamstark@46
|
513 int start, end, winsize;
|
adamstark@54
|
514 double max;
|
adamstark@46
|
515
|
adamstark@46
|
516 start = dfbuffer_size - round(2*bperiod);
|
adamstark@46
|
517 end = dfbuffer_size - round(bperiod/2);
|
adamstark@46
|
518 winsize = end-start+1;
|
adamstark@46
|
519
|
adamstark@54
|
520 double w1[winsize];
|
adamstark@54
|
521 double v = -2*bperiod;
|
adamstark@54
|
522 double wcumscore;
|
adamstark@46
|
523
|
adamstark@46
|
524
|
adamstark@46
|
525 // create window
|
adamstark@46
|
526 for (int i = 0;i < winsize;i++)
|
adamstark@46
|
527 {
|
adamstark@46
|
528 w1[i] = exp((-1*pow(tightness*log(-v/bperiod),2))/2);
|
adamstark@46
|
529 v = v+1;
|
adamstark@46
|
530 }
|
adamstark@46
|
531
|
adamstark@46
|
532 // calculate new cumulative score value
|
adamstark@46
|
533 max = 0;
|
adamstark@46
|
534 int n = 0;
|
adamstark@46
|
535 for (int i=start;i <= end;i++)
|
adamstark@46
|
536 {
|
adamstark@46
|
537 wcumscore = cumscore[i]*w1[n];
|
adamstark@46
|
538
|
adamstark@46
|
539 if (wcumscore > max)
|
adamstark@46
|
540 {
|
adamstark@46
|
541 max = wcumscore;
|
adamstark@46
|
542 }
|
adamstark@46
|
543 n++;
|
adamstark@46
|
544 }
|
adamstark@46
|
545
|
adamstark@46
|
546
|
adamstark@46
|
547 // shift cumulative score back one
|
adamstark@46
|
548 for (int i = 0;i < (dfbuffer_size-1);i++)
|
adamstark@46
|
549 {
|
adamstark@46
|
550 cumscore[i] = cumscore[i+1];
|
adamstark@46
|
551 }
|
adamstark@46
|
552
|
adamstark@46
|
553 // add new value to cumulative score
|
adamstark@46
|
554 cumscore[dfbuffer_size-1] = ((1-alpha)*df_sample) + (alpha*max);
|
adamstark@46
|
555
|
adamstark@46
|
556 cscoreval = cumscore[dfbuffer_size-1];
|
adamstark@46
|
557
|
adamstark@46
|
558 //cout << cumscore[dfbuffer_size-1] << endl;
|
adamstark@46
|
559
|
adamstark@46
|
560 }
|
adamstark@46
|
561
|
adamstark@51
|
562 //=======================================================================
|
adamstark@46
|
563 void BTrack :: predictbeat()
|
adamstark@46
|
564 {
|
adamstark@46
|
565 int winsize = (int) bperiod;
|
adamstark@54
|
566 double fcumscore[dfbuffer_size + winsize];
|
adamstark@54
|
567 double w2[winsize];
|
adamstark@46
|
568 // copy cumscore to first part of fcumscore
|
adamstark@46
|
569 for (int i = 0;i < dfbuffer_size;i++)
|
adamstark@46
|
570 {
|
adamstark@46
|
571 fcumscore[i] = cumscore[i];
|
adamstark@46
|
572 }
|
adamstark@46
|
573
|
adamstark@46
|
574 // create future window
|
adamstark@54
|
575 double v = 1;
|
adamstark@46
|
576 for (int i = 0;i < winsize;i++)
|
adamstark@46
|
577 {
|
adamstark@46
|
578 w2[i] = exp((-1*pow((v - (bperiod/2)),2)) / (2*pow((bperiod/2) ,2)));
|
adamstark@46
|
579 v++;
|
adamstark@46
|
580 }
|
adamstark@46
|
581
|
adamstark@46
|
582 // create past window
|
adamstark@46
|
583 v = -2*bperiod;
|
adamstark@46
|
584 int start = dfbuffer_size - round(2*bperiod);
|
adamstark@46
|
585 int end = dfbuffer_size - round(bperiod/2);
|
adamstark@46
|
586 int pastwinsize = end-start+1;
|
adamstark@54
|
587 double w1[pastwinsize];
|
adamstark@46
|
588
|
adamstark@46
|
589 for (int i = 0;i < pastwinsize;i++)
|
adamstark@46
|
590 {
|
adamstark@46
|
591 w1[i] = exp((-1*pow(tightness*log(-v/bperiod),2))/2);
|
adamstark@46
|
592 v = v+1;
|
adamstark@46
|
593 }
|
adamstark@46
|
594
|
adamstark@46
|
595
|
adamstark@46
|
596
|
adamstark@46
|
597 // calculate future cumulative score
|
adamstark@54
|
598 double max;
|
adamstark@46
|
599 int n;
|
adamstark@54
|
600 double wcumscore;
|
adamstark@46
|
601 for (int i = dfbuffer_size;i < (dfbuffer_size+winsize);i++)
|
adamstark@46
|
602 {
|
adamstark@46
|
603 start = i - round(2*bperiod);
|
adamstark@46
|
604 end = i - round(bperiod/2);
|
adamstark@46
|
605
|
adamstark@46
|
606 max = 0;
|
adamstark@46
|
607 n = 0;
|
adamstark@46
|
608 for (int k=start;k <= end;k++)
|
adamstark@46
|
609 {
|
adamstark@46
|
610 wcumscore = fcumscore[k]*w1[n];
|
adamstark@46
|
611
|
adamstark@46
|
612 if (wcumscore > max)
|
adamstark@46
|
613 {
|
adamstark@46
|
614 max = wcumscore;
|
adamstark@46
|
615 }
|
adamstark@46
|
616 n++;
|
adamstark@46
|
617 }
|
adamstark@46
|
618
|
adamstark@46
|
619 fcumscore[i] = max;
|
adamstark@46
|
620 }
|
adamstark@46
|
621
|
adamstark@46
|
622
|
adamstark@46
|
623 // predict beat
|
adamstark@46
|
624 max = 0;
|
adamstark@46
|
625 n = 0;
|
adamstark@46
|
626
|
adamstark@46
|
627 for (int i = dfbuffer_size;i < (dfbuffer_size+winsize);i++)
|
adamstark@46
|
628 {
|
adamstark@46
|
629 wcumscore = fcumscore[i]*w2[n];
|
adamstark@46
|
630
|
adamstark@46
|
631 if (wcumscore > max)
|
adamstark@46
|
632 {
|
adamstark@46
|
633 max = wcumscore;
|
adamstark@46
|
634 beat = n;
|
adamstark@46
|
635 }
|
adamstark@46
|
636
|
adamstark@46
|
637 n++;
|
adamstark@46
|
638 }
|
adamstark@46
|
639
|
adamstark@46
|
640 // set next prediction time
|
adamstark@46
|
641 m0 = beat+round(bperiod/2);
|
adamstark@46
|
642
|
adamstark@46
|
643
|
adamstark@46
|
644 } |