Mercurial > hg > btrack
comparison src/BTrack.cpp @ 91:a88d887bd281
Code style update to BTrack class
author | Adam Stark <adamstark.uk@gmail.com> |
---|---|
date | Wed, 11 May 2016 00:06:52 +0100 |
parents | b6fc77f471bb |
children | 4aa362058011 |
comparison
equal
deleted
inserted
replaced
90:b6fc77f471bb | 91:a88d887bd281 |
---|---|
24 #include "BTrack.h" | 24 #include "BTrack.h" |
25 #include "samplerate.h" | 25 #include "samplerate.h" |
26 #include <iostream> | 26 #include <iostream> |
27 | 27 |
28 //======================================================================= | 28 //======================================================================= |
29 BTrack::BTrack() : odf(512,1024,ComplexSpectralDifferenceHWR,HanningWindow) | 29 BTrack::BTrack() |
30 : odf (512, 1024, ComplexSpectralDifferenceHWR, HanningWindow) | |
30 { | 31 { |
31 initialise(512, 1024); | 32 initialise(512, 1024); |
32 } | 33 } |
33 | 34 |
34 //======================================================================= | 35 //======================================================================= |
35 BTrack::BTrack(int hopSize_) : odf(hopSize_,2*hopSize_,ComplexSpectralDifferenceHWR,HanningWindow) | 36 BTrack::BTrack (int hopSize_) |
37 : odf(hopSize_, 2*hopSize_, ComplexSpectralDifferenceHWR, HanningWindow) | |
36 { | 38 { |
37 initialise(hopSize_, 2*hopSize_); | 39 initialise(hopSize_, 2*hopSize_); |
38 } | 40 } |
39 | 41 |
40 //======================================================================= | 42 //======================================================================= |
41 BTrack::BTrack(int hopSize_,int frameSize_) : odf(hopSize_,frameSize_,ComplexSpectralDifferenceHWR,HanningWindow) | 43 BTrack::BTrack (int hopSize_, int frameSize_) |
42 { | 44 : odf (hopSize_, frameSize_, ComplexSpectralDifferenceHWR, HanningWindow) |
43 initialise(hopSize_, frameSize_); | 45 { |
46 initialise (hopSize_, frameSize_); | |
44 } | 47 } |
45 | 48 |
46 //======================================================================= | 49 //======================================================================= |
47 BTrack::~BTrack() | 50 BTrack::~BTrack() |
48 { | 51 { |
49 // destroy fft plan | 52 // destroy fft plan |
50 fftw_destroy_plan(acfForwardFFT); | 53 fftw_destroy_plan (acfForwardFFT); |
51 fftw_destroy_plan(acfBackwardFFT); | 54 fftw_destroy_plan (acfBackwardFFT); |
52 fftw_free(complexIn); | 55 fftw_free (complexIn); |
53 fftw_free(complexOut); | 56 fftw_free (complexOut); |
54 } | 57 } |
55 | 58 |
56 //======================================================================= | 59 //======================================================================= |
57 double BTrack::getBeatTimeInSeconds(long frameNumber,int hopSize,int fs) | 60 double BTrack::getBeatTimeInSeconds (long frameNumber, int hopSize, int fs) |
58 { | 61 { |
59 double hop = (double) hopSize; | 62 double hop = (double) hopSize; |
60 double samplingFrequency = (double) fs; | 63 double samplingFrequency = (double) fs; |
61 double frameNum = (double) frameNumber; | 64 double frameNum = (double) frameNumber; |
62 | 65 |
63 return ((hop / samplingFrequency) * frameNum); | 66 return ((hop / samplingFrequency) * frameNum); |
64 } | 67 } |
65 | 68 |
66 //======================================================================= | 69 //======================================================================= |
67 double BTrack::getBeatTimeInSeconds(int frameNumber,int hopSize,int fs) | 70 double BTrack::getBeatTimeInSeconds (int frameNumber, int hopSize, int fs) |
68 { | 71 { |
69 long frameNum = (long) frameNumber; | 72 long frameNum = (long) frameNumber; |
70 | 73 |
71 return getBeatTimeInSeconds(frameNum, hopSize, fs); | 74 return getBeatTimeInSeconds (frameNum, hopSize, fs); |
72 } | 75 } |
73 | 76 |
74 | 77 |
75 | 78 |
76 //======================================================================= | 79 //======================================================================= |
77 void BTrack::initialise(int hopSize_, int frameSize_) | 80 void BTrack::initialise (int hopSize_, int frameSize_) |
78 { | 81 { |
79 double rayparam = 43; | 82 double rayparam = 43; |
80 double pi = 3.14159265; | 83 double pi = 3.14159265; |
81 | 84 |
82 | 85 |
92 | 95 |
93 beatDueInFrame = false; | 96 beatDueInFrame = false; |
94 | 97 |
95 | 98 |
96 // create rayleigh weighting vector | 99 // create rayleigh weighting vector |
97 for (int n = 0;n < 128;n++) | 100 for (int n = 0; n < 128; n++) |
98 { | 101 { |
99 weightingVector[n] = ((double) n / pow(rayparam,2)) * exp((-1*pow((double)-n,2)) / (2*pow(rayparam,2))); | 102 weightingVector[n] = ((double) n / pow(rayparam,2)) * exp((-1*pow((double)-n,2)) / (2*pow(rayparam,2))); |
100 } | 103 } |
101 | 104 |
102 // initialise prev_delta | 105 // initialise prev_delta |
103 for (int i = 0;i < 41;i++) | 106 for (int i = 0; i < 41; i++) |
104 { | 107 { |
105 prevDelta[i] = 1; | 108 prevDelta[i] = 1; |
106 } | 109 } |
107 | 110 |
108 double t_mu = 41/2; | 111 double t_mu = 41/2; |
132 | 135 |
133 | 136 |
134 // Set up FFT for calculating the auto-correlation function | 137 // Set up FFT for calculating the auto-correlation function |
135 FFTLengthForACFCalculation = 1024; | 138 FFTLengthForACFCalculation = 1024; |
136 | 139 |
137 complexIn = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * FFTLengthForACFCalculation); // complex array to hold fft data | 140 complexIn = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * FFTLengthForACFCalculation); // complex array to hold fft data |
138 complexOut = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * FFTLengthForACFCalculation); // complex array to hold fft data | 141 complexOut = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * FFTLengthForACFCalculation); // complex array to hold fft data |
139 | 142 |
140 acfForwardFFT = fftw_plan_dft_1d(FFTLengthForACFCalculation, complexIn, complexOut, FFTW_FORWARD, FFTW_ESTIMATE); // FFT plan initialisation | 143 acfForwardFFT = fftw_plan_dft_1d (FFTLengthForACFCalculation, complexIn, complexOut, FFTW_FORWARD, FFTW_ESTIMATE); // FFT plan initialisation |
141 acfBackwardFFT = fftw_plan_dft_1d(FFTLengthForACFCalculation, complexOut, complexIn, FFTW_BACKWARD, FFTW_ESTIMATE); // FFT plan initialisation | 144 acfBackwardFFT = fftw_plan_dft_1d (FFTLengthForACFCalculation, complexOut, complexIn, FFTW_BACKWARD, FFTW_ESTIMATE); // FFT plan initialisation |
142 } | 145 } |
143 | 146 |
144 //======================================================================= | 147 //======================================================================= |
145 void BTrack::setHopSize(int hopSize_) | 148 void BTrack::setHopSize (int hopSize_) |
146 { | 149 { |
147 hopSize = hopSize_; | 150 hopSize = hopSize_; |
148 onsetDFBufferSize = (512*512)/hopSize; // calculate df buffer size | 151 onsetDFBufferSize = (512*512)/hopSize; // calculate df buffer size |
149 | 152 |
150 beatPeriod = round(60/((((double) hopSize)/44100)*tempo)); | 153 beatPeriod = round(60/((((double) hopSize)/44100)*tempo)); |
151 | 154 |
152 // set size of onset detection function buffer | 155 // set size of onset detection function buffer |
153 onsetDF.resize(onsetDFBufferSize); | 156 onsetDF.resize (onsetDFBufferSize); |
154 | 157 |
155 // set size of cumulative score buffer | 158 // set size of cumulative score buffer |
156 cumulativeScore.resize(onsetDFBufferSize); | 159 cumulativeScore.resize (onsetDFBufferSize); |
157 | 160 |
158 // initialise df_buffer to zeros | 161 // initialise df_buffer to zeros |
159 for (int i = 0;i < onsetDFBufferSize;i++) | 162 for (int i = 0; i < onsetDFBufferSize; i++) |
160 { | 163 { |
161 onsetDF[i] = 0; | 164 onsetDF[i] = 0; |
162 cumulativeScore[i] = 0; | 165 cumulativeScore[i] = 0; |
163 | 166 |
164 | |
165 if ((i % ((int) round(beatPeriod))) == 0) | 167 if ((i % ((int) round(beatPeriod))) == 0) |
166 { | 168 { |
167 onsetDF[i] = 1; | 169 onsetDF[i] = 1; |
168 } | 170 } |
169 } | 171 } |
170 } | 172 } |
171 | 173 |
172 //======================================================================= | 174 //======================================================================= |
173 void BTrack::updateHopAndFrameSize(int hopSize_,int frameSize_) | 175 void BTrack::updateHopAndFrameSize (int hopSize_, int frameSize_) |
174 { | 176 { |
175 // update the onset detection function object | 177 // update the onset detection function object |
176 odf.initialise(hopSize_, frameSize_); | 178 odf.initialise (hopSize_, frameSize_); |
177 | 179 |
178 // update the hop size being used by the beat tracker | 180 // update the hop size being used by the beat tracker |
179 setHopSize(hopSize_); | 181 setHopSize (hopSize_); |
180 } | 182 } |
181 | 183 |
182 //======================================================================= | 184 //======================================================================= |
183 bool BTrack::beatDueInCurrentFrame() | 185 bool BTrack::beatDueInCurrentFrame() |
184 { | 186 { |
202 { | 204 { |
203 return latestCumulativeScoreValue; | 205 return latestCumulativeScoreValue; |
204 } | 206 } |
205 | 207 |
206 //======================================================================= | 208 //======================================================================= |
207 void BTrack::processAudioFrame(double *frame) | 209 void BTrack::processAudioFrame (double* frame) |
208 { | 210 { |
209 // calculate the onset detection function sample for the frame | 211 // calculate the onset detection function sample for the frame |
210 double sample = odf.calculateOnsetDetectionFunctionSample(frame); | 212 double sample = odf.calculateOnsetDetectionFunctionSample (frame); |
211 | |
212 | |
213 | 213 |
214 // process the new onset detection function sample in the beat tracking algorithm | 214 // process the new onset detection function sample in the beat tracking algorithm |
215 processOnsetDetectionFunctionSample(sample); | 215 processOnsetDetectionFunctionSample (sample); |
216 } | 216 } |
217 | 217 |
218 //======================================================================= | 218 //======================================================================= |
219 void BTrack::processOnsetDetectionFunctionSample(double newSample) | 219 void BTrack::processOnsetDetectionFunctionSample (double newSample) |
220 { | 220 { |
221 // we need to ensure that the onset | 221 // we need to ensure that the onset |
222 // detection function sample is positive | 222 // detection function sample is positive |
223 newSample = fabs(newSample); | 223 newSample = fabs (newSample); |
224 | 224 |
225 // add a tiny constant to the sample to stop it from ever going | 225 // add a tiny constant to the sample to stop it from ever going |
226 // to zero. this is to avoid problems further down the line | 226 // to zero. this is to avoid problems further down the line |
227 newSample = newSample + 0.0001; | 227 newSample = newSample + 0.0001; |
228 | 228 |
229 m0--; | 229 m0--; |
230 beatCounter--; | 230 beatCounter--; |
231 beatDueInFrame = false; | 231 beatDueInFrame = false; |
232 | 232 |
233 // add new sample at the end | 233 // add new sample at the end |
234 onsetDF.addSampleToEnd(newSample); | 234 onsetDF.addSampleToEnd (newSample); |
235 | 235 |
236 // update cumulative score | 236 // update cumulative score |
237 updateCumulativeScore(newSample); | 237 updateCumulativeScore (newSample); |
238 | 238 |
239 // if we are halfway between beats | 239 // if we are halfway between beats |
240 if (m0 == 0) | 240 if (m0 == 0) |
241 { | 241 { |
242 predictBeat(); | 242 predictBeat(); |
252 calculateTempo(); | 252 calculateTempo(); |
253 } | 253 } |
254 } | 254 } |
255 | 255 |
256 //======================================================================= | 256 //======================================================================= |
257 void BTrack::setTempo(double tempo) | 257 void BTrack::setTempo (double tempo) |
258 { | 258 { |
259 | 259 |
260 /////////// TEMPO INDICATION RESET ////////////////// | 260 /////////// TEMPO INDICATION RESET ////////////////// |
261 | 261 |
262 // firstly make sure tempo is between 80 and 160 bpm.. | 262 // firstly make sure tempo is between 80 and 160 bpm.. |
319 // offbeat is half of new beat period away | 319 // offbeat is half of new beat period away |
320 m0 = (int) round(((double) new_bperiod)/2); | 320 m0 = (int) round(((double) new_bperiod)/2); |
321 } | 321 } |
322 | 322 |
323 //======================================================================= | 323 //======================================================================= |
324 void BTrack::fixTempo(double tempo) | 324 void BTrack::fixTempo (double tempo) |
325 { | 325 { |
326 // firstly make sure tempo is between 80 and 160 bpm.. | 326 // firstly make sure tempo is between 80 and 160 bpm.. |
327 while (tempo > 160) | 327 while (tempo > 160) |
328 { | 328 { |
329 tempo = tempo/2; | 329 tempo = tempo/2; |
360 //======================================================================= | 360 //======================================================================= |
361 void BTrack::resampleOnsetDetectionFunction() | 361 void BTrack::resampleOnsetDetectionFunction() |
362 { | 362 { |
363 float output[512]; | 363 float output[512]; |
364 | 364 |
365 | |
366 float input[onsetDFBufferSize]; | 365 float input[onsetDFBufferSize]; |
367 | 366 |
368 for (int i = 0;i < onsetDFBufferSize;i++) | 367 for (int i = 0;i < onsetDFBufferSize;i++) |
369 { | 368 { |
370 input[i] = (float) onsetDF[i]; | 369 input[i] = (float) onsetDF[i]; |
396 | 395 |
397 //======================================================================= | 396 //======================================================================= |
398 void BTrack::calculateTempo() | 397 void BTrack::calculateTempo() |
399 { | 398 { |
400 // adaptive threshold on input | 399 // adaptive threshold on input |
401 adaptiveThreshold(resampledOnsetDF,512); | 400 adaptiveThreshold (resampledOnsetDF,512); |
402 | 401 |
403 // calculate auto-correlation function of detection function | 402 // calculate auto-correlation function of detection function |
404 calculateBalancedACF(resampledOnsetDF); | 403 calculateBalancedACF (resampledOnsetDF); |
405 | 404 |
406 // calculate output of comb filterbank | 405 // calculate output of comb filterbank |
407 calculateOutputOfCombFilterBank(); | 406 calculateOutputOfCombFilterBank(); |
408 | 407 |
409 | |
410 // adaptive threshold on rcf | 408 // adaptive threshold on rcf |
411 adaptiveThreshold(combFilterBankOutput,128); | 409 adaptiveThreshold (combFilterBankOutput,128); |
412 | 410 |
413 | 411 |
414 int t_index; | 412 int t_index; |
415 int t_index2; | 413 int t_index2; |
416 // calculate tempo observation vector from beat period observation vector | 414 // calculate tempo observation vector from beat period observation vector |
417 for (int i = 0;i < 41;i++) | 415 for (int i = 0;i < 41;i++) |
418 { | 416 { |
419 t_index = (int) round(tempoToLagFactor / ((double) ((2*i)+80))); | 417 t_index = (int) round (tempoToLagFactor / ((double) ((2*i)+80))); |
420 t_index2 = (int) round(tempoToLagFactor / ((double) ((4*i)+160))); | 418 t_index2 = (int) round (tempoToLagFactor / ((double) ((4*i)+160))); |
421 | 419 |
422 | 420 |
423 tempoObservationVector[i] = combFilterBankOutput[t_index-1] + combFilterBankOutput[t_index2-1]; | 421 tempoObservationVector[i] = combFilterBankOutput[t_index-1] + combFilterBankOutput[t_index2-1]; |
424 } | 422 } |
425 | 423 |
440 for (int j=0;j < 41;j++) | 438 for (int j=0;j < 41;j++) |
441 { | 439 { |
442 maxval = -1; | 440 maxval = -1; |
443 for (int i = 0;i < 41;i++) | 441 for (int i = 0;i < 41;i++) |
444 { | 442 { |
445 curval = prevDelta[i]*tempoTransitionMatrix[i][j]; | 443 curval = prevDelta[i] * tempoTransitionMatrix[i][j]; |
446 | 444 |
447 if (curval > maxval) | 445 if (curval > maxval) |
448 { | 446 { |
449 maxval = curval; | 447 maxval = curval; |
450 } | 448 } |
451 } | 449 } |
452 | 450 |
453 delta[j] = maxval*tempoObservationVector[j]; | 451 delta[j] = maxval * tempoObservationVector[j]; |
454 } | 452 } |
455 | 453 |
456 | 454 |
457 normaliseArray(delta,41); | 455 normaliseArray(delta,41); |
458 | 456 |
468 } | 466 } |
469 | 467 |
470 prevDelta[j] = delta[j]; | 468 prevDelta[j] = delta[j]; |
471 } | 469 } |
472 | 470 |
473 beatPeriod = round((60.0*44100.0)/(((2*maxind)+80)*((double) hopSize))); | 471 beatPeriod = round ((60.0*44100.0)/(((2*maxind)+80)*((double) hopSize))); |
474 | 472 |
475 if (beatPeriod > 0) | 473 if (beatPeriod > 0) |
476 { | 474 { |
477 estimatedTempo = 60.0/((((double) hopSize) / 44100.0)*beatPeriod); | 475 estimatedTempo = 60.0/((((double) hopSize) / 44100.0) * beatPeriod); |
478 } | 476 } |
479 } | 477 } |
480 | 478 |
481 //======================================================================= | 479 //======================================================================= |
482 void BTrack::adaptiveThreshold(double *x,int N) | 480 void BTrack::adaptiveThreshold (double*x, int N) |
483 { | 481 { |
484 int i = 0; | 482 int i = 0; |
485 int k,t = 0; | 483 int k,t = 0; |
486 double x_thresh[N]; | 484 double x_thresh[N]; |
487 | 485 |
491 t = std::min(N,p_post); // what is smaller, p_post of df size. This is to avoid accessing outside of arrays | 489 t = std::min(N,p_post); // what is smaller, p_post of df size. This is to avoid accessing outside of arrays |
492 | 490 |
493 // find threshold for first 't' samples, where a full average cannot be computed yet | 491 // find threshold for first 't' samples, where a full average cannot be computed yet |
494 for (i = 0;i <= t;i++) | 492 for (i = 0;i <= t;i++) |
495 { | 493 { |
496 k = std::min((i+p_pre),N); | 494 k = std::min ((i+p_pre),N); |
497 x_thresh[i] = calculateMeanOfArray(x,1,k); | 495 x_thresh[i] = calculateMeanOfArray (x,1,k); |
498 } | 496 } |
499 // find threshold for bulk of samples across a moving average from [i-p_pre,i+p_post] | 497 // find threshold for bulk of samples across a moving average from [i-p_pre,i+p_post] |
500 for (i = t+1;i < N-p_post;i++) | 498 for (i = t+1;i < N-p_post;i++) |
501 { | 499 { |
502 x_thresh[i] = calculateMeanOfArray(x,i-p_pre,i+p_post); | 500 x_thresh[i] = calculateMeanOfArray (x,i-p_pre,i+p_post); |
503 } | 501 } |
504 // for last few samples calculate threshold, again, not enough samples to do as above | 502 // for last few samples calculate threshold, again, not enough samples to do as above |
505 for (i = N-p_post;i < N;i++) | 503 for (i = N-p_post;i < N;i++) |
506 { | 504 { |
507 k = std::max((i-p_post),1); | 505 k = std::max ((i-p_post),1); |
508 x_thresh[i] = calculateMeanOfArray(x,k,N); | 506 x_thresh[i] = calculateMeanOfArray (x,k,N); |
509 } | 507 } |
510 | 508 |
511 // subtract the threshold from the detection function and check that it is not less than 0 | 509 // subtract the threshold from the detection function and check that it is not less than 0 |
512 for (i = 0;i < N;i++) | 510 for (i = 0; i < N; i++) |
513 { | 511 { |
514 x[i] = x[i] - x_thresh[i]; | 512 x[i] = x[i] - x_thresh[i]; |
515 if (x[i] < 0) | 513 if (x[i] < 0) |
516 { | 514 { |
517 x[i] = 0; | 515 x[i] = 0; |
529 combFilterBankOutput[i] = 0; | 527 combFilterBankOutput[i] = 0; |
530 } | 528 } |
531 | 529 |
532 numelem = 4; | 530 numelem = 4; |
533 | 531 |
534 for (int i = 2;i <= 127;i++) // max beat period | 532 for (int i = 2; i <= 127; i++) // max beat period |
535 { | 533 { |
536 for (int a = 1;a <= numelem;a++) // number of comb elements | 534 for (int a = 1; a <= numelem; a++) // number of comb elements |
537 { | 535 { |
538 for (int b = 1-a;b <= a-1;b++) // general state using normalisation of comb elements | 536 for (int b = 1-a; b <= a-1; b++) // general state using normalisation of comb elements |
539 { | 537 { |
540 combFilterBankOutput[i-1] = combFilterBankOutput[i-1] + (acf[(a*i+b)-1]*weightingVector[i-1])/(2*a-1); // calculate value for comb filter row | 538 combFilterBankOutput[i-1] = combFilterBankOutput[i-1] + (acf[(a*i+b)-1]*weightingVector[i-1])/(2*a-1); // calculate value for comb filter row |
541 } | 539 } |
542 } | 540 } |
543 } | 541 } |
544 } | 542 } |
545 | 543 |
546 //======================================================================= | 544 //======================================================================= |
547 void BTrack::calculateBalancedACF(double *onsetDetectionFunction) | 545 void BTrack::calculateBalancedACF (double* onsetDetectionFunction) |
548 { | 546 { |
549 int onsetDetectionFunctionLength = 512; | 547 int onsetDetectionFunctionLength = 512; |
550 | 548 |
551 // copy into complex array and zero pad | 549 // copy into complex array and zero pad |
552 for (int i = 0;i < FFTLengthForACFCalculation;i++) | 550 for (int i = 0;i < FFTLengthForACFCalculation;i++) |
562 complexIn[i][1] = 0.0; | 560 complexIn[i][1] = 0.0; |
563 } | 561 } |
564 } | 562 } |
565 | 563 |
566 // perform the fft | 564 // perform the fft |
567 fftw_execute(acfForwardFFT); | 565 fftw_execute (acfForwardFFT); |
568 | 566 |
569 // multiply by complex conjugate | 567 // multiply by complex conjugate |
570 for (int i = 0;i < FFTLengthForACFCalculation;i++) | 568 for (int i = 0;i < FFTLengthForACFCalculation;i++) |
571 { | 569 { |
572 complexOut[i][0] = complexOut[i][0]*complexOut[i][0] + complexOut[i][1]*complexOut[i][1]; | 570 complexOut[i][0] = complexOut[i][0]*complexOut[i][0] + complexOut[i][1]*complexOut[i][1]; |
573 complexOut[i][1] = 0.0; | 571 complexOut[i][1] = 0.0; |
574 } | 572 } |
575 | 573 |
576 // perform the ifft | 574 // perform the ifft |
577 fftw_execute(acfBackwardFFT); | 575 fftw_execute (acfBackwardFFT); |
578 | 576 |
579 | 577 |
580 double lag = 512; | 578 double lag = 512; |
581 | 579 |
582 for (int i = 0;i < 512;i++) | 580 for (int i = 0; i < 512; i++) |
583 { | 581 { |
584 // calculate absolute value of result | 582 // calculate absolute value of result |
585 double absValue = sqrt(complexIn[i][0]*complexIn[i][0] + complexIn[i][1]*complexIn[i][1]); | 583 double absValue = sqrt (complexIn[i][0]*complexIn[i][0] + complexIn[i][1]*complexIn[i][1]); |
586 | 584 |
587 // divide by inverse lad to deal with scale bias towards small lags | 585 // divide by inverse lad to deal with scale bias towards small lags |
588 acf[i] = absValue / lag; | 586 acf[i] = absValue / lag; |
589 | 587 |
590 // this division by 1024 is technically unnecessary but it ensures the algorithm produces | 588 // this division by 1024 is technically unnecessary but it ensures the algorithm produces |
595 lag = lag - 1.; | 593 lag = lag - 1.; |
596 } | 594 } |
597 } | 595 } |
598 | 596 |
599 //======================================================================= | 597 //======================================================================= |
600 double BTrack::calculateMeanOfArray(double *array,int startIndex,int endIndex) | 598 double BTrack::calculateMeanOfArray (double* array, int startIndex, int endIndex) |
601 { | 599 { |
602 int i; | 600 int i; |
603 double sum = 0; | 601 double sum = 0; |
604 | 602 |
605 int length = endIndex - startIndex; | 603 int length = endIndex - startIndex; |
606 | 604 |
607 // find sum | 605 // find sum |
608 for (i = startIndex;i < endIndex;i++) | 606 for (i = startIndex; i < endIndex; i++) |
609 { | 607 { |
610 sum = sum + array[i]; | 608 sum = sum + array[i]; |
611 } | 609 } |
612 | 610 |
613 if (length > 0) | 611 if (length > 0) |
619 return 0; | 617 return 0; |
620 } | 618 } |
621 } | 619 } |
622 | 620 |
623 //======================================================================= | 621 //======================================================================= |
624 void BTrack::normaliseArray(double *array,int N) | 622 void BTrack::normaliseArray(double* array, int N) |
625 { | 623 { |
626 double sum = 0; | 624 double sum = 0; |
627 | 625 |
628 for (int i = 0;i < N;i++) | 626 for (int i = 0; i < N; i++) |
629 { | 627 { |
630 if (array[i] > 0) | 628 if (array[i] > 0) |
631 { | 629 { |
632 sum = sum + array[i]; | 630 sum = sum + array[i]; |
633 } | 631 } |
634 } | 632 } |
635 | 633 |
636 if (sum > 0) | 634 if (sum > 0) |
637 { | 635 { |
638 for (int i = 0;i < N;i++) | 636 for (int i = 0; i < N; i++) |
639 { | 637 { |
640 array[i] = array[i] / sum; | 638 array[i] = array[i] / sum; |
641 } | 639 } |
642 } | 640 } |
643 } | 641 } |
644 | 642 |
645 //======================================================================= | 643 //======================================================================= |
646 void BTrack::updateCumulativeScore(double odfSample) | 644 void BTrack::updateCumulativeScore (double odfSample) |
647 { | 645 { |
648 int start, end, winsize; | 646 int start, end, winsize; |
649 double max; | 647 double max; |
650 | 648 |
651 start = onsetDFBufferSize - round(2*beatPeriod); | 649 start = onsetDFBufferSize - round (2 * beatPeriod); |
652 end = onsetDFBufferSize - round(beatPeriod/2); | 650 end = onsetDFBufferSize - round (beatPeriod / 2); |
653 winsize = end-start+1; | 651 winsize = end-start+1; |
654 | 652 |
655 double w1[winsize]; | 653 double w1[winsize]; |
656 double v = -2*beatPeriod; | 654 double v = -2*beatPeriod; |
657 double wcumscore; | 655 double wcumscore; |
658 | 656 |
659 | 657 |
660 // create window | 658 // create window |
661 for (int i = 0;i < winsize;i++) | 659 for (int i = 0; i < winsize; i++) |
662 { | 660 { |
663 w1[i] = exp((-1*pow(tightness*log(-v/beatPeriod),2))/2); | 661 w1[i] = exp((-1*pow (tightness * log (-v / beatPeriod), 2)) / 2); |
664 v = v+1; | 662 v = v+1; |
665 } | 663 } |
666 | 664 |
667 // calculate new cumulative score value | 665 // calculate new cumulative score value |
668 max = 0; | 666 max = 0; |
669 int n = 0; | 667 int n = 0; |
670 for (int i=start;i <= end;i++) | 668 for (int i=start; i <= end; i++) |
671 { | 669 { |
672 wcumscore = cumulativeScore[i]*w1[n]; | 670 wcumscore = cumulativeScore[i]*w1[n]; |
673 | 671 |
674 if (wcumscore > max) | 672 if (wcumscore > max) |
675 { | 673 { |
679 } | 677 } |
680 | 678 |
681 | 679 |
682 latestCumulativeScoreValue = ((1-alpha)*odfSample) + (alpha*max); | 680 latestCumulativeScoreValue = ((1-alpha)*odfSample) + (alpha*max); |
683 | 681 |
684 cumulativeScore.addSampleToEnd(latestCumulativeScoreValue); | 682 cumulativeScore.addSampleToEnd (latestCumulativeScoreValue); |
685 } | 683 } |
686 | 684 |
687 //======================================================================= | 685 //======================================================================= |
688 void BTrack::predictBeat() | 686 void BTrack::predictBeat() |
689 { | 687 { |
696 futureCumulativeScore[i] = cumulativeScore[i]; | 694 futureCumulativeScore[i] = cumulativeScore[i]; |
697 } | 695 } |
698 | 696 |
699 // create future window | 697 // create future window |
700 double v = 1; | 698 double v = 1; |
701 for (int i = 0;i < windowSize;i++) | 699 for (int i = 0; i < windowSize; i++) |
702 { | 700 { |
703 w2[i] = exp((-1*pow((v - (beatPeriod/2)),2)) / (2*pow((beatPeriod/2) ,2))); | 701 w2[i] = exp((-1*pow((v - (beatPeriod/2)),2)) / (2*pow((beatPeriod/2) ,2))); |
704 v++; | 702 v++; |
705 } | 703 } |
706 | 704 |
721 | 719 |
722 // calculate future cumulative score | 720 // calculate future cumulative score |
723 double max; | 721 double max; |
724 int n; | 722 int n; |
725 double wcumscore; | 723 double wcumscore; |
726 for (int i = onsetDFBufferSize;i < (onsetDFBufferSize+windowSize);i++) | 724 for (int i = onsetDFBufferSize; i < (onsetDFBufferSize + windowSize); i++) |
727 { | 725 { |
728 start = i - round(2*beatPeriod); | 726 start = i - round (2*beatPeriod); |
729 end = i - round(beatPeriod/2); | 727 end = i - round (beatPeriod/2); |
730 | 728 |
731 max = 0; | 729 max = 0; |
732 n = 0; | 730 n = 0; |
733 for (int k=start;k <= end;k++) | 731 for (int k=start;k <= end;k++) |
734 { | 732 { |
747 | 745 |
748 // predict beat | 746 // predict beat |
749 max = 0; | 747 max = 0; |
750 n = 0; | 748 n = 0; |
751 | 749 |
752 for (int i = onsetDFBufferSize;i < (onsetDFBufferSize+windowSize);i++) | 750 for (int i = onsetDFBufferSize; i < (onsetDFBufferSize + windowSize); i++) |
753 { | 751 { |
754 wcumscore = futureCumulativeScore[i]*w2[n]; | 752 wcumscore = futureCumulativeScore[i]*w2[n]; |
755 | 753 |
756 if (wcumscore > max) | 754 if (wcumscore > max) |
757 { | 755 { |
761 | 759 |
762 n++; | 760 n++; |
763 } | 761 } |
764 | 762 |
765 // set next prediction time | 763 // set next prediction time |
766 m0 = beatCounter+round(beatPeriod/2); | 764 m0 = beatCounter + round (beatPeriod / 2); |
767 | 765 } |
768 | |
769 } |