Mercurial > hg > qm-dsp
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 |