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