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