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