comparison dsp/tempotracking/TempoTrackV2.cpp @ 53:796170a9c8e4

* Update with fixes from Matthew's newer code
author cannam
date Mon, 09 Feb 2009 16:05:32 +0000
parents 4d1f32efcafd
children 5bec06ecc88a
comparison
equal deleted inserted replaced
52:4d1f32efcafd 53:796170a9c8e4
10 10
11 #include "TempoTrackV2.h" 11 #include "TempoTrackV2.h"
12 12
13 #include <cmath> 13 #include <cmath>
14 #include <cstdlib> 14 #include <cstdlib>
15 #include <iostream>
15 16
16 17
17 //#define FRAMESIZE 512 18 //#define FRAMESIZE 512
18 //#define BIGFRAMESIZE 1024 19 //#define BIGFRAMESIZE 1024
19 #define TWOPI 6.283185307179586232 20 #define TWOPI 6.283185307179586232
23 TempoTrackV2::~TempoTrackV2() { } 24 TempoTrackV2::~TempoTrackV2() { }
24 25
25 void 26 void
26 TempoTrackV2::adapt_thresh(d_vec_t &df) 27 TempoTrackV2::adapt_thresh(d_vec_t &df)
27 { 28 {
28 29 d_vec_t smoothed(df.size());
29 d_vec_t smoothed(df.size());
30 30
31 int p_post = 7; 31 int p_post = 7;
32 int p_pre = 8; 32 int p_pre = 8;
33 33
34 int t = std::min(static_cast<int>(df.size()),p_post); // what is smaller, p_post of df size. This is to avoid accessing outside of arrays 34 int t = std::min(static_cast<int>(df.size()),p_post); // what is smaller, p_post of df size. This is to avoid accessing outside of arrays
35 35
36 // find threshold for first 't' samples, where a full average cannot be computed yet 36 // find threshold for first 't' samples, where a full average cannot be computed yet
37 for (int i = 0;i <= t;i++) 37 for (int i = 0;i <= t;i++)
38 { 38 {
39 int k = std::min((i+p_pre),static_cast<int>(df.size())); 39 int k = std::min((i+p_pre),static_cast<int>(df.size()));
40 smoothed[i] = mean_array(df,1,k); 40 smoothed[i] = mean_array(df,1,k);
41 } 41 }
42 // find threshold for bulk of samples across a moving average from [i-p_pre,i+p_post] 42 // find threshold for bulk of samples across a moving average from [i-p_pre,i+p_post]
43 for (uint i = t+1;i < df.size()-p_post;i++) 43 for (uint i = t+1;i < df.size()-p_post;i++)
44 { 44 {
45 smoothed[i] = mean_array(df,i-p_pre,i+p_post); 45 smoothed[i] = mean_array(df,i-p_pre,i+p_post);
46 } 46 }
47 // for last few samples calculate threshold, again, not enough samples to do as above 47 // for last few samples calculate threshold, again, not enough samples to do as above
48 for (uint i = df.size()-p_post;i < df.size();i++) 48 for (uint i = df.size()-p_post;i < df.size();i++)
49 { 49 {
50 int k = std::max((static_cast<int> (i) -p_post),1); 50 int k = std::max((static_cast<int> (i) -p_post),1);
51 smoothed[i] = mean_array(df,k,df.size()); 51 smoothed[i] = mean_array(df,k,df.size());
52 } 52 }
53 53
54 // subtract the threshold from the detection function and check that it is not less than 0 54 // subtract the threshold from the detection function and check that it is not less than 0
55 for (uint i = 0;i < df.size();i++) 55 for (uint i = 0;i < df.size();i++)
56 { 56 {
57 df[i] -= smoothed[i]; 57 df[i] -= smoothed[i];
58 if (df[i] < 0) 58 if (df[i] < 0)
59 { 59 {
60 df[i] = 0; 60 df[i] = 0;
61 } 61 }
62 } 62 }
63 } 63 }
64 64
65 double 65 double
66 TempoTrackV2::mean_array(const d_vec_t &dfin,int start,int end) 66 TempoTrackV2::mean_array(const d_vec_t &dfin,int start,int end)
67 { 67 {
68 68 double sum = 0.;
69 double sum = 0.;
70 69
71 // find sum 70 // find sum
72 for (int i = start;i < end+1;i++) 71 for (int i = start;i < end;i++)
73 { 72 {
74 sum += dfin[i]; 73 sum += dfin[i];
75 } 74 }
76 75
77 return static_cast<double> (sum / (end - start + 1) ); // average and return 76 return static_cast<double> (sum / (end - start + 1) ); // average and return
78 } 77 }
79 78
80 void 79 void
81 TempoTrackV2::filter_df(d_vec_t &df) 80 TempoTrackV2::filter_df(d_vec_t &df)
82 { 81 {
83 82 d_vec_t a(3);
84 83 d_vec_t b(3);
85 d_vec_t a(3); 84 d_vec_t lp_df(df.size());
86 d_vec_t b(3); 85
87 d_vec_t lp_df(df.size()); 86 //equivalent in matlab to [b,a] = butter(2,0.4);
88 87 a[0] = 1.0000;
89 //equivalent in matlab to [b,a] = butter(2,0.4); 88 a[1] = -0.3695;
90 a[0] = 1.0000; 89 a[2] = 0.1958;
91 a[1] = -0.3695; 90 b[0] = 0.2066;
92 a[2] = 0.1958; 91 b[1] = 0.4131;
93 b[0] = 0.2066; 92 b[2] = 0.2066;
94 b[1] = 0.4131; 93
95 b[2] = 0.2066; 94 double inp1 = 0.;
95 double inp2 = 0.;
96 double out1 = 0.;
97 double out2 = 0.;
98
99
100 // forwards filtering
101 for (uint i = 0;i < df.size();i++)
102 {
103 lp_df[i] = b[0]*df[i] + b[1]*inp1 + b[2]*inp2 - a[1]*out1 - a[2]*out2;
104 inp2 = inp1;
105 inp1 = df[i];
106 out2 = out1;
107 out1 = lp_df[i];
108 }
109
110 // copy forwards filtering to df...
111 // but, time-reversed, ready for backwards filtering
112 for (uint i = 0;i < df.size();i++)
113 {
114 df[i] = lp_df[df.size()-i-1];
115 }
116
117 for (uint i = 0;i < df.size();i++)
118 {
119 lp_df[i] = 0.;
120 }
121
122 inp1 = 0.; inp2 = 0.;
123 out1 = 0.; out2 = 0.;
124
125 // backwards filetering on time-reversed df
126 for (uint i = 0;i < df.size();i++)
127 {
128 lp_df[i] = b[0]*df[i] + b[1]*inp1 + b[2]*inp2 - a[1]*out1 - a[2]*out2;
129 inp2 = inp1;
130 inp1 = df[i];
131 out2 = out1;
132 out1 = lp_df[i];
133 }
134
135 // write the re-reversed (i.e. forward) version back to df
136 for (uint i = 0;i < df.size();i++)
137 {
138 df[i] = lp_df[df.size()-i-1];
139 }
140 }
141
142
143 void
144 TempoTrackV2::calculateBeatPeriod(const d_vec_t &df, d_vec_t &beat_period,
145 d_vec_t &tempi)
146 {
147 // to follow matlab.. split into 512 sample frames with a 128 hop size
148 // calculate the acf,
149 // then the rcf.. and then stick the rcfs as columns of a matrix
150 // then call viterbi decoding with weight vector and transition matrix
151 // and get best path
152
153 uint wv_len = 128;
154 double rayparam = 43.;
155
156 // make rayleigh weighting curve
157 d_vec_t wv(wv_len);
158 for (uint i=0; i<wv.size(); i++)
159 {
160 wv[i] = (static_cast<double> (i) / pow(rayparam,2.)) * exp((-1.*pow(-static_cast<double> (i),2.)) / (2.*pow(rayparam,2.)));
161 }
162
163 // beat tracking frame size (roughly 6 seconds) and hop (1.5 seconds)
164 uint winlen = 512;
165 uint step = 128;
166
167 // matrix to store output of comb filter bank, increment column of matrix at each frame
168 d_mat_t rcfmat;
169 int col_counter = -1;
170
171 // main loop for beat period calculation
172 for (uint i=0; i<(df.size()-winlen); i+=step)
173 {
174 // get dfframe
175 d_vec_t dfframe(winlen);
176 for (uint k=0; k<winlen; k++)
177 {
178 dfframe[k] = df[i+k];
179 }
180 // get rcf vector for current frame
181 d_vec_t rcf(wv_len);
182 get_rcf(dfframe,wv,rcf);
183
184 rcfmat.push_back( d_vec_t() ); // adds a new column
185 col_counter++;
186 for (uint j=0; j<rcf.size(); j++)
187 {
188 rcfmat[col_counter].push_back( rcf[j] );
189 }
190 }
191
192 // now call viterbi decoding function
193 viterbi_decode(rcfmat,wv,beat_period,tempi);
194 }
195
196
197 void
198 TempoTrackV2::get_rcf(const d_vec_t &dfframe_in, const d_vec_t &wv, d_vec_t &rcf)
199 {
200 // calculate autocorrelation function
201 // then rcf
202 // just hard code for now... don't really need separate functions to do this
203
204 // make acf
205
206 d_vec_t dfframe(dfframe_in);
207
208 adapt_thresh(dfframe);
209
210 d_vec_t acf(dfframe.size());
211
212
213 for (uint lag=0; lag<dfframe.size(); lag++)
214 {
215 double sum = 0.;
216 double tmp = 0.;
217
218 for (uint n=0; n<(dfframe.size()-lag); n++)
219 {
220 tmp = dfframe[n] * dfframe[n+lag];
221 sum += tmp;
222 }
223 acf[lag] = static_cast<double> (sum/ (dfframe.size()-lag));
224 }
225
226 // now apply comb filtering
227 int numelem = 4;
96 228
97 double inp1 = 0.; 229 for (uint i = 2;i < rcf.size();i++) // max beat period
98 double inp2 = 0.; 230 {
99 double out1 = 0.; 231 for (int a = 1;a <= numelem;a++) // number of comb elements
100 double out2 = 0.; 232 {
101 233 for (int b = 1-a;b <= a-1;b++) // general state using normalisation of comb elements
102 234 {
103 // forwards filtering 235 rcf[i-1] += ( acf[(a*i+b)-1]*wv[i-1] ) / (2.*a-1.); // calculate value for comb filter row
104 for (uint i = 0;i < df.size();i++) 236 }
105 { 237 }
106 lp_df[i] = b[0]*df[i] + b[1]*inp1 + b[2]*inp2 - a[1]*out1 - a[2]*out2; 238 }
107 inp2 = inp1;
108 inp1 = df[i];
109 out2 = out1;
110 out1 = lp_df[i];
111 }
112
113
114 // copy forwards filtering to df...
115 // but, time-reversed, ready for backwards filtering
116 for (uint i = 0;i < df.size();i++)
117 {
118 df[i] = lp_df[df.size()-i];
119 }
120
121 for (uint i = 0;i < df.size();i++)
122 {
123 lp_df[i] = 0.;
124 }
125
126 inp1 = 0.; inp2 = 0.;
127 out1 = 0.; out2 = 0.;
128
129 // backwards filetering on time-reversed df
130 for (uint i = 0;i < df.size();i++)
131 {
132 lp_df[i] = b[0]*df[i] + b[1]*inp1 + b[2]*inp2 - a[1]*out1 - a[2]*out2;
133 inp2 = inp1;
134 inp1 = df[i];
135 out2 = out1;
136 out1 = lp_df[i];
137 }
138
139 // write the re-reversed (i.e. forward) version back to df
140 for (uint i = 0;i < df.size();i++)
141 {
142 df[i] = lp_df[df.size()-i];
143 }
144
145
146 }
147
148
149 void
150 TempoTrackV2::calculateBeatPeriod(const d_vec_t &df, d_vec_t &beat_period)
151 {
152
153 // to follow matlab.. split into 512 sample frames with a 128 hop size
154 // calculate the acf,
155 // then the rcf.. and then stick the rcfs as columns of a matrix
156 // then call viterbi decoding with weight vector and transition matrix
157 // and get best path
158
159 uint wv_len = 128;
160 double rayparam = 43.;
161
162 // make rayleigh weighting curve
163 d_vec_t wv(wv_len);
164 for (uint i=0; i<wv.size(); i++)
165 {
166 wv[i] = (static_cast<double> (i) / pow(rayparam,2.)) * exp((-1.*pow(-static_cast<double> (i),2.)) / (2.*pow(rayparam,2.)));
167 }
168
169
170 uint winlen = 512;
171 uint step = 128;
172
173 d_mat_t rcfmat;
174 int col_counter = -1;
175 // main loop for beat period calculation
176 for (uint i=0; i<(df.size()-winlen); i+=step)
177 {
178 // get dfframe
179 d_vec_t dfframe(winlen);
180 for (uint k=0; k<winlen; k++)
181 {
182 dfframe[k] = df[i+k];
183 }
184 // get rcf vector for current frame
185 d_vec_t rcf(wv_len);
186 get_rcf(dfframe,wv,rcf);
187 239
188 rcfmat.push_back( d_vec_t() ); // adds a new column 240 // apply adaptive threshold to rcf
189 col_counter++; 241 adapt_thresh(rcf);
190 for (uint j=0; j<rcf.size(); j++)
191 {
192 rcfmat[col_counter].push_back( rcf[j] );
193 }
194
195 }
196 242
197 // now call viterbi decoding function 243 double rcfsum =0.;
198 viterbi_decode(rcfmat,wv,beat_period); 244 for (uint i=0; i<rcf.size(); i++)
199 245 {
200 246 rcf[i] += EPS ;
201 247 rcfsum += rcf[i];
202 } 248 }
203 249
204 250 // normalise rcf to sum to unity
205 void 251 for (uint i=0; i<rcf.size(); i++)
206 TempoTrackV2::get_rcf(const d_vec_t &dfframe_in, const d_vec_t &wv, d_vec_t &rcf) 252 {
207 { 253 rcf[i] /= (rcfsum + EPS);
208 // calculate autocorrelation function 254 }
209 // then rcf 255 }
210 // just hard code for now... don't really need separate functions to do this 256
211 257 void
212 // make acf 258 TempoTrackV2::viterbi_decode(const d_mat_t &rcfmat, const d_vec_t &wv, d_vec_t &beat_period, d_vec_t &tempi)
213 259 {
214 d_vec_t dfframe(dfframe_in); 260 // following Kevin Murphy's Viterbi decoding to get best path of
215 261 // beat periods through rfcmat
216 adapt_thresh(dfframe); 262
217 263 // make transition matrix
218 d_vec_t acf(dfframe.size()); 264 d_mat_t tmat;
219 265 for (uint i=0;i<wv.size();i++)
220 266 {
221 for (uint lag=0; lag<dfframe.size(); lag++) 267 tmat.push_back ( d_vec_t() ); // adds a new column
222 { 268 for (uint j=0; j<wv.size(); j++)
223 269 {
224 double sum = 0.; 270 tmat[i].push_back(0.); // fill with zeros initially
225 double tmp = 0.; 271 }
226 272 }
227 for (uint n=0; n<(dfframe.size()-lag); n++) 273
228 { 274 // variance of Gaussians in transition matrix
229 tmp = dfframe[n] * dfframe[n+lag]; 275 // formed of Gaussians on diagonal - implies slow tempo change
230 sum += tmp; 276 double sigma = 8.;
231 } 277 // don't want really short beat periods, or really long ones
232 acf[lag] = static_cast<double> (sum/ (dfframe.size()-lag)); 278 for (uint i=20;i <wv.size()-20; i++)
233 } 279 {
234 280 for (uint j=20; j<wv.size()-20; j++)
235 281 {
236 // for (uint i=0; i<dfframe.size(); i++) 282 double mu = static_cast<double>(i);
237 // { 283 tmat[i][j] = exp( (-1.*pow((j-mu),2.)) / (2.*pow(sigma,2.)) );
238 // cout << dfframe[i] << " " << acf[i] << endl; 284 }
239 // } 285 }
240 286
241 // cout << "~~~~~~~~~~~~~~" << endl; 287 // parameters for Viterbi decoding... this part is taken from
242 288 // Murphy's matlab
243 289
244 290 d_mat_t delta;
245 291 i_mat_t psi;
246 292 for (uint i=0;i <rcfmat.size(); i++)
247 // now apply comb filtering 293 {
248 int numelem = 4; 294 delta.push_back( d_vec_t());
249 295 psi.push_back( i_vec_t());
250 // for (uint i = 1;i < 118;i++) // max beat period 296 for (uint j=0; j<rcfmat[i].size(); j++)
251 for (uint i = 2;i < rcf.size();i++) // max beat period 297 {
252 { 298 delta[i].push_back(0.); // fill with zeros initially
253 for (int a = 1;a <= numelem;a++) // number of comb elements 299 psi[i].push_back(0); // fill with zeros initially
254 { 300 }
255 for (int b = 1-a;b <= a-1;b++) // general state using normalisation of comb elements 301 }
256 { 302
257 rcf[i-1] += ( acf[(a*i+b)-1]*wv[i-1] ) / (2.*a-1.); // calculate value for comb filter row 303
258 } 304 uint T = delta.size();
259 } 305 uint Q = delta[0].size();
260 } 306
261 307 // initialize first column of delta
262 // apply adaptive threshold to rcf
263 adapt_thresh(rcf);
264
265 double rcfsum =0.;
266 for (uint i=0; i<rcf.size(); i++)
267 {
268 // rcf[i] *= acf[i];
269 rcf[i] += EPS ;
270 rcfsum += rcf[i];
271 }
272
273 // normalise rcf to sum to unity
274 for (uint i=0; i<rcf.size(); i++)
275 {
276 rcf[i] /= (rcfsum + EPS);
277 }
278
279
280
281 }
282
283 void
284 TempoTrackV2::viterbi_decode(const d_mat_t &rcfmat, const d_vec_t &wv, d_vec_t &beat_period)
285 {
286
287 // make transition matrix
288 d_mat_t tmat;
289 for (uint i=0;i<wv.size();i++)
290 {
291 tmat.push_back ( d_vec_t() ); // adds a new column
292 for (uint j=0; j<wv.size(); j++)
293 {
294 tmat[i].push_back(0.); // fill with zeros initially
295 }
296 }
297
298 double sigma = 8.;
299 for (uint i=20;i <wv.size()-20; i++)
300 {
301 for (uint j=20; j<wv.size()-20; j++)
302 {
303 double mu = static_cast<double>(i);
304 tmat[i][j] = exp( (-1.*pow((j-mu),2.)) / (2.*pow(sigma,2.)) );
305 }
306 }
307
308 d_mat_t delta;
309 i_mat_t psi;
310 for (uint i=0;i <rcfmat.size(); i++)
311 {
312 delta.push_back( d_vec_t());
313 psi.push_back( i_vec_t());
314 for (uint j=0; j<rcfmat[i].size(); j++)
315 {
316 delta[i].push_back(0.); // fill with zeros initially
317 psi[i].push_back(0); // fill with zeros initially
318 }
319 }
320
321
322 uint T = delta.size();
323 uint Q = delta[0].size();
324
325 // initialize first column of delta
326 for (uint j=0; j<Q; j++)
327 {
328 delta[0][j] = wv[j] * rcfmat[0][j];
329 psi[0][j] = 0;
330 }
331
332 double deltasum = 0.;
333 for (uint i=0; i<Q; i++)
334 {
335 deltasum += delta[0][i];
336 }
337 for (uint i=0; i<Q; i++)
338 {
339 delta[0][i] /= (deltasum + EPS);
340 }
341
342
343
344 for (uint t=1; t<T; t++)
345 {
346 d_vec_t tmp_vec(Q);
347
348 for (uint j=0; j<Q; j++) 308 for (uint j=0; j<Q; j++)
349 { 309 {
350 310 delta[0][j] = wv[j] * rcfmat[0][j];
351 for (uint i=0; i<Q; i++) 311 psi[0][j] = 0;
352 { 312 }
353 tmp_vec[i] = delta[t-1][i] * tmat[j][i]; 313
354 }
355
356 delta[t][j] = get_max_val(tmp_vec);
357
358 psi[t][j] = get_max_ind(tmp_vec);
359
360 delta[t][j] *= rcfmat[t][j];
361
362
363 }
364
365 double deltasum = 0.; 314 double deltasum = 0.;
366 for (uint i=0; i<Q; i++) 315 for (uint i=0; i<Q; i++)
367 { 316 {
368 deltasum += delta[t][i]; 317 deltasum += delta[0][i];
369 } 318 }
370 for (uint i=0; i<Q; i++) 319 for (uint i=0; i<Q; i++)
371 { 320 {
372 delta[t][i] /= (deltasum + EPS); 321 delta[0][i] /= (deltasum + EPS);
373 } 322 }
374 323
375 324
376 325 for (uint t=1; t<T; t++)
377 326 {
378 } 327 d_vec_t tmp_vec(Q);
379 328
380 329 for (uint j=0; j<Q; j++)
381 // ofstream tmatfile; 330 {
382 // tmatfile.open("/home/matthewd/Desktop/tmat.txt"); 331 for (uint i=0; i<Q; i++)
383 332 {
384 // for (uint i=0;i <delta.size(); i++) 333 tmp_vec[i] = delta[t-1][i] * tmat[j][i];
385 // { 334 }
386 // for (uint j=0; j<delta[i].size(); j++) 335
387 // { 336 delta[t][j] = get_max_val(tmp_vec);
388 // tmatfile << rcfmat[i][j] << endl; 337
389 // } 338 psi[t][j] = get_max_ind(tmp_vec);
390 // }
391
392 // tmatfile.close();
393
394 i_vec_t bestpath(T);
395 d_vec_t tmp_vec(Q);
396 for (uint i=0; i<Q; i++)
397 {
398 tmp_vec[i] = delta[T-1][i];
399 }
400
401
402 bestpath[T-1] = get_max_ind(tmp_vec);
403 339
404 for (uint t=T-2; t>0 ;t--) 340 delta[t][j] *= rcfmat[t][j];
405 { 341 }
406 bestpath[t] = psi[t+1][bestpath[t+1]]; 342
407 } 343 // normalise current delta column
408 // very weird hack! 344 double deltasum = 0.;
409 bestpath[0] = psi[1][bestpath[1]]; 345 for (uint i=0; i<Q; i++)
410 346 {
411 // for (uint i=0; i<bestpath.size(); i++) 347 deltasum += delta[t][i];
412 // { 348 }
413 // cout << bestpath[i] << endl; 349 for (uint i=0; i<Q; i++)
414 // } 350 {
415 351 delta[t][i] /= (deltasum + EPS);
416 352 }
417 uint lastind = 0; 353 }
418 for (uint i=0; i<T; i++) 354
419 { 355 i_vec_t bestpath(T);
420 uint step = 128; 356 d_vec_t tmp_vec(Q);
421 // cout << bestpath[i] << " " << i << endl; 357 for (uint i=0; i<Q; i++)
422 for (uint j=0; j<step; j++) 358 {
423 { 359 tmp_vec[i] = delta[T-1][i];
424 lastind = i*step+j; 360 }
425 beat_period[lastind] = bestpath[i]; 361
426 362 // find starting point - best beat period for "last" frame
427 } 363 bestpath[T-1] = get_max_ind(tmp_vec);
428 }
429
430 //fill in the last values...
431 for (uint i=lastind; i<beat_period.size(); i++)
432 {
433 beat_period[i] = beat_period[lastind];
434 }
435 364
436 365 // backtrace through index of maximum values in psi
437 366 for (uint t=T-2; t>0 ;t--)
367 {
368 bestpath[t] = psi[t+1][bestpath[t+1]];
369 }
370
371 // weird but necessary hack -- couldn't get above loop to terminate at t >= 0
372 bestpath[0] = psi[1][bestpath[1]];
373
374 uint lastind = 0;
375 for (uint i=0; i<T; i++)
376 {
377 uint step = 128;
378 for (uint j=0; j<step; j++)
379 {
380 lastind = i*step+j;
381 beat_period[lastind] = bestpath[i];
382 }
383 }
384
385 //fill in the last values...
386 for (uint i=lastind; i<beat_period.size(); i++)
387 {
388 beat_period[i] = beat_period[lastind];
389 }
390
391 for (uint i = 0; i < beat_period.size(); i++)
392 {
393 tempi.push_back((60.*44100./512.)/beat_period[i]);
394 }
438 } 395 }
439 396
440 double 397 double
441 TempoTrackV2::get_max_val(const d_vec_t &df) 398 TempoTrackV2::get_max_val(const d_vec_t &df)
442 { 399 {
443 double maxval = 0.; 400 double maxval = 0.;
444 for (uint i=0; i<df.size(); i++) 401 for (uint i=0; i<df.size(); i++)
445 { 402 {
446 403 if (maxval < df[i])
447 if (maxval < df[i]) 404 {
448 { 405 maxval = df[i];
449 maxval = df[i]; 406 }
450 } 407 }
451 408
452 } 409 return maxval;
453
454
455 return maxval;
456
457 } 410 }
458 411
459 int 412 int
460 TempoTrackV2::get_max_ind(const d_vec_t &df) 413 TempoTrackV2::get_max_ind(const d_vec_t &df)
461 { 414 {
462 415 double maxval = 0.;
463 double maxval = 0.; 416 int ind = 0;
464 int ind = 0; 417 for (uint i=0; i<df.size(); i++)
465 for (uint i=0; i<df.size(); i++) 418 {
466 { 419 if (maxval < df[i])
467 if (maxval < df[i]) 420 {
468 { 421 maxval = df[i];
469 maxval = df[i]; 422 ind = i;
470 ind = i; 423 }
471 } 424 }
472 425
473 } 426 return ind;
474
475 return ind;
476
477 } 427 }
478 428
479 void 429 void
480 TempoTrackV2::normalise_vec(d_vec_t &df) 430 TempoTrackV2::normalise_vec(d_vec_t &df)
481 { 431 {
482 double sum = 0.; 432 double sum = 0.;
483 for (uint i=0; i<df.size(); i++) 433 for (uint i=0; i<df.size(); i++)
484 { 434 {
485 sum += df[i]; 435 sum += df[i];
486 } 436 }
487 437
488 for (uint i=0; i<df.size(); i++) 438 for (uint i=0; i<df.size(); i++)
489 { 439 {
490 df[i]/= (sum + EPS); 440 df[i]/= (sum + EPS);
491 } 441 }
492
493
494 } 442 }
495 443
496 void 444 void
497 TempoTrackV2::calculateBeats(const d_vec_t &df, const d_vec_t &beat_period, 445 TempoTrackV2::calculateBeats(const d_vec_t &df, const d_vec_t &beat_period,
498 d_vec_t &beats) 446 d_vec_t &beats)
499 { 447 {
500 448 d_vec_t cumscore(df.size()); // store cumulative score
501 d_vec_t cumscore(df.size()); 449 i_vec_t backlink(df.size()); // backlink (stores best beat locations at each time instant)
502 i_vec_t backlink(df.size()); 450 d_vec_t localscore(df.size()); // localscore, for now this is the same as the detection function
503 d_vec_t localscore(df.size()); 451
504 452 for (uint i=0; i<df.size(); i++)
505 // WHEN I FIGURE OUT HOW, I'LL WANT TO DO SOME FILTERING ON THIS... 453 {
506 for (uint i=0; i<df.size(); i++) 454 localscore[i] = df[i];
507 { 455 backlink[i] = -1;
508 localscore[i] = df[i]; 456 }
509 backlink[i] = -1; 457
510 } 458 double tightness = 4.;
511 459 double alpha = 0.9;
512 double tightness = 4.; 460
513 double alpha = 0.9; 461 // main loop
514 462 for (uint i=0; i<localscore.size(); i++)
515 // main loop 463 {
516 for (uint i=3*beat_period[0]; i<localscore.size(); i++) 464 int prange_min = -2*beat_period[i];
517 { 465 int prange_max = round(-0.5*beat_period[i]);
518 int prange_min = -2*beat_period[i]; 466
519 int prange_max = round(-0.5*beat_period[i]); 467 // transition range
520 468 d_vec_t txwt (prange_max - prange_min + 1);
521 d_vec_t txwt (prange_max - prange_min + 1); 469 d_vec_t scorecands (txwt.size());
522 d_vec_t scorecands (txwt.size()); 470
523 471 for (uint j=0;j<txwt.size();j++)
524 for (uint j=0;j<txwt.size();j++) 472 {
525 { 473 double mu = static_cast<double> (beat_period[i]);
526 double mu = static_cast<double> (beat_period[i]); 474 txwt[j] = exp( -0.5*pow(tightness * log((round(2*mu)-j)/mu),2));
527 txwt[j] = exp( -0.5*pow(tightness * log((round(2*mu)-j)/mu),2)); 475
528 476 // IF IN THE ALLOWED RANGE, THEN LOOK AT CUMSCORE[I+PRANGE_MIN+J
529 scorecands[j] = txwt[j] * cumscore[i+prange_min+j]; 477 // ELSE LEAVE AT DEFAULT VALUE FROM INITIALISATION: D_VEC_T SCORECANDS (TXWT.SIZE());
530 } 478
531 479 int cscore_ind = i+prange_min+j;
532 double vv = get_max_val(scorecands); 480 if (cscore_ind >= 0)
533 int xx = get_max_ind(scorecands); 481 {
534 482 scorecands[j] = txwt[j] * cumscore[cscore_ind];
535 cumscore[i] = alpha*vv + (1.-alpha)*localscore[i]; 483 }
536 484 }
537 backlink[i] = i+prange_min+xx; 485
538 486 // find max value and index of maximum value
539 } 487 double vv = get_max_val(scorecands);
540 488 int xx = get_max_ind(scorecands);
541 489
542 d_vec_t tmp_vec; 490 cumscore[i] = alpha*vv + (1.-alpha)*localscore[i];
543 for (uint i=cumscore.size() - beat_period[beat_period.size()-1] ; i<cumscore.size(); i++) 491 backlink[i] = i+prange_min+xx;
544 { 492 }
545 tmp_vec.push_back(cumscore[i]); 493
546 } 494 // STARTING POINT, I.E. LAST BEAT.. PICK A STRONG POINT IN cumscore VECTOR
547 495 d_vec_t tmp_vec;
548 int startpoint = get_max_ind(tmp_vec) + cumscore.size() - beat_period[beat_period.size()-1] ; 496 for (uint i=cumscore.size() - beat_period[beat_period.size()-1] ; i<cumscore.size(); i++)
549 497 {
550 i_vec_t ibeats; 498 tmp_vec.push_back(cumscore[i]);
551 ibeats.push_back(startpoint); 499 }
552 while (backlink[ibeats.back()] > 3*beat_period[0]) 500
553 { 501 int startpoint = get_max_ind(tmp_vec) + cumscore.size() - beat_period[beat_period.size()-1] ;
554 ibeats.push_back(backlink[ibeats.back()]); 502
555 } 503 // USE BACKLINK TO GET EACH NEW BEAT (TOWARDS THE BEGINNING OF THE FILE)
504 // BACKTRACKING FROM THE END TO THE BEGINNING.. MAKING SURE NOT TO GO BEFORE SAMPLE 0
505 i_vec_t ibeats;
506 ibeats.push_back(startpoint);
507 while (backlink[ibeats.back()] > 0)
508 {
509 ibeats.push_back(backlink[ibeats.back()]);
510 }
556 511
557 512 // REVERSE SEQUENCE OF IBEATS AND STORE AS BEATS
558 for (uint i=0; i<ibeats.size(); i++) 513 for (uint i=0; i<ibeats.size(); i++)
559 { 514 {
560 515 beats.push_back( static_cast<double>(ibeats[ibeats.size()-i-1]) );
561 beats.push_back( static_cast<double>(ibeats[i]) ); 516 }
562 517 }
563 // cout << ibeats[i] << " " << beats[i] <<endl; 518
564 } 519
565 }
566
567