Mercurial > hg > btrack
comparison src/BTrack.cpp @ 57:296af6af6c3d
Replaced switch statements in OnsetDetectionFunction with enums. Renamed lots of functions so that they have better names, in camel case. Added some unit tests for initialisation of BTrack.
author | Adam Stark <adamstark@users.noreply.github.com> |
---|---|
date | Thu, 23 Jan 2014 15:31:11 +0000 |
parents | b6d440942ff6 |
children | f84ccd07e17f |
comparison
equal
deleted
inserted
replaced
56:b6d440942ff6 | 57:296af6af6c3d |
---|---|
23 #include <algorithm> | 23 #include <algorithm> |
24 #include "BTrack.h" | 24 #include "BTrack.h" |
25 #include "samplerate.h" | 25 #include "samplerate.h" |
26 | 26 |
27 //======================================================================= | 27 //======================================================================= |
28 BTrack::BTrack() : odf(512,1024,6,1) | 28 BTrack::BTrack() : odf(512,1024,ComplexSpectralDifferenceHWR,HanningWindow) |
29 { | 29 { |
30 initialise(512, 1024); | 30 initialise(512, 1024); |
31 } | 31 } |
32 | 32 |
33 //======================================================================= | 33 //======================================================================= |
34 BTrack::BTrack(int hopSize) : odf(hopSize,2*hopSize,6,1) | 34 BTrack::BTrack(int hopSize_) : odf(hopSize_,2*hopSize_,ComplexSpectralDifferenceHWR,HanningWindow) |
35 { | 35 { |
36 initialise(hopSize, 2*hopSize); | 36 initialise(hopSize_, 2*hopSize_); |
37 } | 37 } |
38 | 38 |
39 //======================================================================= | 39 //======================================================================= |
40 BTrack::BTrack(int hopSize,int frameSize) : odf(hopSize,frameSize,6,1) | 40 BTrack::BTrack(int hopSize_,int frameSize_) : odf(hopSize_,frameSize_,ComplexSpectralDifferenceHWR,HanningWindow) |
41 { | 41 { |
42 initialise(hopSize, frameSize); | 42 initialise(hopSize_, frameSize_); |
43 } | 43 } |
44 | 44 |
45 //======================================================================= | 45 //======================================================================= |
46 double BTrack::getBeatTimeInSeconds(long frameNumber,int hopSize,int fs) | 46 double BTrack::getBeatTimeInSeconds(long frameNumber,int hopSize,int fs) |
47 { | 47 { |
61 } | 61 } |
62 | 62 |
63 | 63 |
64 | 64 |
65 //======================================================================= | 65 //======================================================================= |
66 void BTrack::initialise(int hopSize, int frameSize) | 66 void BTrack::initialise(int hopSize_, int frameSize_) |
67 { | 67 { |
68 double rayparam = 43; | 68 double rayparam = 43; |
69 double pi = 3.14159265; | 69 double pi = 3.14159265; |
70 | 70 |
71 | 71 |
77 p_fact = 60.*44100./512.; | 77 p_fact = 60.*44100./512.; |
78 | 78 |
79 m0 = 10; | 79 m0 = 10; |
80 beat = -1; | 80 beat = -1; |
81 | 81 |
82 playbeat = 0; | 82 beatDueInFrame = false; |
83 | 83 |
84 | 84 |
85 | 85 |
86 | 86 |
87 // create rayleigh weighting vector | 87 // create rayleigh weighting vector |
113 | 113 |
114 // tempo is not fixed | 114 // tempo is not fixed |
115 tempofix = 0; | 115 tempofix = 0; |
116 | 116 |
117 // initialise algorithm given the hopsize | 117 // initialise algorithm given the hopsize |
118 setHopSize(hopSize); | 118 setHopSize(hopSize_); |
119 } | 119 } |
120 | 120 |
121 //======================================================================= | 121 //======================================================================= |
122 void BTrack :: setHopSize(int hopSize) | 122 void BTrack::setHopSize(int hopSize_) |
123 { | 123 { |
124 framesize = hopSize; | 124 hopSize = hopSize_; |
125 dfbuffer_size = (512*512)/hopSize; // calculate df buffer size | 125 dfbuffer_size = (512*512)/hopSize; // calculate df buffer size |
126 | 126 |
127 bperiod = round(60/((((double) hopSize)/44100)*tempo)); | 127 beatPeriod = round(60/((((double) hopSize)/44100)*tempo)); |
128 | 128 |
129 dfbuffer = new double[dfbuffer_size]; // create df_buffer | 129 dfbuffer = new double[dfbuffer_size]; // create df_buffer |
130 cumscore = new double[dfbuffer_size]; // create cumscore | 130 cumscore = new double[dfbuffer_size]; // create cumscore |
131 | 131 |
132 | 132 |
135 { | 135 { |
136 dfbuffer[i] = 0; | 136 dfbuffer[i] = 0; |
137 cumscore[i] = 0; | 137 cumscore[i] = 0; |
138 | 138 |
139 | 139 |
140 if ((i % ((int) round(bperiod))) == 0) | 140 if ((i % ((int) round(beatPeriod))) == 0) |
141 { | 141 { |
142 dfbuffer[i] = 1; | 142 dfbuffer[i] = 1; |
143 } | 143 } |
144 } | 144 } |
145 } | |
146 | |
147 //======================================================================= | |
148 bool BTrack::beatDueInCurrentFrame() | |
149 { | |
150 return beatDueInFrame; | |
151 } | |
152 | |
153 //======================================================================= | |
154 int BTrack::getHopSize() | |
155 { | |
156 return hopSize; | |
145 } | 157 } |
146 | 158 |
147 //======================================================================= | 159 //======================================================================= |
148 void BTrack::processAudioFrame(double *frame) | 160 void BTrack::processAudioFrame(double *frame) |
149 { | 161 { |
167 // to zero. this is to avoid problems further down the line | 179 // to zero. this is to avoid problems further down the line |
168 newSample = newSample + 0.0001; | 180 newSample = newSample + 0.0001; |
169 | 181 |
170 m0--; | 182 m0--; |
171 beat--; | 183 beat--; |
172 playbeat = 0; | 184 beatDueInFrame = false; |
173 | 185 |
174 // move all samples back one step | 186 // move all samples back one step |
175 for (int i=0;i < (dfbuffer_size-1);i++) | 187 for (int i=0;i < (dfbuffer_size-1);i++) |
176 { | 188 { |
177 dfbuffer[i] = dfbuffer[i+1]; | 189 dfbuffer[i] = dfbuffer[i+1]; |
179 | 191 |
180 // add new sample at the end | 192 // add new sample at the end |
181 dfbuffer[dfbuffer_size-1] = newSample; | 193 dfbuffer[dfbuffer_size-1] = newSample; |
182 | 194 |
183 // update cumulative score | 195 // update cumulative score |
184 updatecumscore(newSample); | 196 updateCumulativeScore(newSample); |
185 | 197 |
186 // if we are halfway between beats | 198 // if we are halfway between beats |
187 if (m0 == 0) | 199 if (m0 == 0) |
188 { | 200 { |
189 predictbeat(); | 201 predictBeat(); |
190 } | 202 } |
191 | 203 |
192 // if we are at a beat | 204 // if we are at a beat |
193 if (beat == 0) | 205 if (beat == 0) |
194 { | 206 { |
195 playbeat = 1; // indicate a beat should be output | 207 beatDueInFrame = true; // indicate a beat should be output |
196 | 208 |
197 // recalculate the tempo | 209 // recalculate the tempo |
198 dfconvert(); | 210 resampleOnsetDetectionFunction(); |
199 calcTempo(); | 211 calculateTempo(); |
200 } | 212 } |
201 } | 213 } |
202 | 214 |
203 //======================================================================= | 215 //======================================================================= |
204 void BTrack :: settempo(double tempo) | 216 void BTrack::setTempo(double tempo) |
205 { | 217 { |
206 | 218 |
207 /////////// TEMPO INDICATION RESET ////////////////// | 219 /////////// TEMPO INDICATION RESET ////////////////// |
208 | 220 |
209 // firstly make sure tempo is between 80 and 160 bpm.. | 221 // firstly make sure tempo is between 80 and 160 bpm.. |
231 | 243 |
232 | 244 |
233 /////////// CUMULATIVE SCORE ARTIFICAL TEMPO UPDATE ////////////////// | 245 /////////// CUMULATIVE SCORE ARTIFICAL TEMPO UPDATE ////////////////// |
234 | 246 |
235 // calculate new beat period | 247 // calculate new beat period |
236 int new_bperiod = (int) round(60/((((double) framesize)/44100)*tempo)); | 248 int new_bperiod = (int) round(60/((((double) hopSize)/44100)*tempo)); |
237 | 249 |
238 int bcounter = 1; | 250 int bcounter = 1; |
239 // initialise df_buffer to zeros | 251 // initialise df_buffer to zeros |
240 for (int i = (dfbuffer_size-1);i >= 0;i--) | 252 for (int i = (dfbuffer_size-1);i >= 0;i--) |
241 { | 253 { |
266 // offbeat is half of new beat period away | 278 // offbeat is half of new beat period away |
267 m0 = (int) round(((double) new_bperiod)/2); | 279 m0 = (int) round(((double) new_bperiod)/2); |
268 } | 280 } |
269 | 281 |
270 //======================================================================= | 282 //======================================================================= |
271 void BTrack :: fixtempo(double tempo) | 283 void BTrack::fixTempo(double tempo) |
272 { | 284 { |
273 // firstly make sure tempo is between 80 and 160 bpm.. | 285 // firstly make sure tempo is between 80 and 160 bpm.. |
274 while (tempo > 160) | 286 while (tempo > 160) |
275 { | 287 { |
276 tempo = tempo/2; | 288 tempo = tempo/2; |
296 // set the tempo fix flag | 308 // set the tempo fix flag |
297 tempofix = 1; | 309 tempofix = 1; |
298 } | 310 } |
299 | 311 |
300 //======================================================================= | 312 //======================================================================= |
301 void BTrack :: unfixtempo() | 313 void BTrack::doNotFixTempo() |
302 { | 314 { |
303 // set the tempo fix flag | 315 // set the tempo fix flag |
304 tempofix = 0; | 316 tempofix = 0; |
305 } | 317 } |
306 | 318 |
307 //======================================================================= | 319 //======================================================================= |
308 void BTrack :: dfconvert() | 320 void BTrack::resampleOnsetDetectionFunction() |
309 { | 321 { |
310 float output[512]; | 322 float output[512]; |
311 float input[dfbuffer_size]; | 323 float input[dfbuffer_size]; |
312 | 324 |
313 for (int i = 0;i < dfbuffer_size;i++) | 325 for (int i = 0;i < dfbuffer_size;i++) |
338 df512[i] = (double) src_data.data_out[i]; | 350 df512[i] = (double) src_data.data_out[i]; |
339 } | 351 } |
340 } | 352 } |
341 | 353 |
342 //======================================================================= | 354 //======================================================================= |
343 void BTrack :: calcTempo() | 355 void BTrack::calculateTempo() |
344 { | 356 { |
345 // adaptive threshold on input | 357 // adaptive threshold on input |
346 adapt_thresh(df512,512); | 358 adaptiveThreshold(df512,512); |
347 | 359 |
348 // calculate auto-correlation function of detection function | 360 // calculate auto-correlation function of detection function |
349 acf_bal(df512); | 361 calculateBalancedACF(df512); |
350 | 362 |
351 // calculate output of comb filterbank | 363 // calculate output of comb filterbank |
352 getrcfoutput(); | 364 calculateOutputOfCombFilterBank(); |
353 | 365 |
354 | 366 |
355 // adaptive threshold on rcf | 367 // adaptive threshold on rcf |
356 adapt_thresh(rcf,128); | 368 adaptiveThreshold(rcf,128); |
357 | 369 |
358 | 370 |
359 int t_index; | 371 int t_index; |
360 int t_index2; | 372 int t_index2; |
361 // calculate tempo observation vector from bperiod observation vector | 373 // calculate tempo observation vector from bperiod observation vector |
397 | 409 |
398 delta[j] = maxval*t_obs[j]; | 410 delta[j] = maxval*t_obs[j]; |
399 } | 411 } |
400 | 412 |
401 | 413 |
402 normalise(delta,41); | 414 normaliseArray(delta,41); |
403 | 415 |
404 maxind = -1; | 416 maxind = -1; |
405 maxval = -1; | 417 maxval = -1; |
406 | 418 |
407 for (int j=0;j < 41;j++) | 419 for (int j=0;j < 41;j++) |
413 } | 425 } |
414 | 426 |
415 prev_delta[j] = delta[j]; | 427 prev_delta[j] = delta[j]; |
416 } | 428 } |
417 | 429 |
418 bperiod = round((60.0*44100.0)/(((2*maxind)+80)*((double) framesize))); | 430 beatPeriod = round((60.0*44100.0)/(((2*maxind)+80)*((double) hopSize))); |
419 | 431 |
420 if (bperiod > 0) | 432 if (beatPeriod > 0) |
421 { | 433 { |
422 est_tempo = 60.0/((((double) framesize) / 44100.0)*bperiod); | 434 est_tempo = 60.0/((((double) hopSize) / 44100.0)*beatPeriod); |
423 } | 435 } |
424 | 436 } |
425 //cout << bperiod << endl; | 437 |
426 } | 438 //======================================================================= |
427 | 439 void BTrack::adaptiveThreshold(double *x,int N) |
428 //======================================================================= | |
429 void BTrack :: adapt_thresh(double *x,int N) | |
430 { | 440 { |
431 //int N = 512; // length of df | 441 //int N = 512; // length of df |
432 int i = 0; | 442 int i = 0; |
433 int k,t = 0; | 443 int k,t = 0; |
434 double x_thresh[N]; | 444 double x_thresh[N]; |
440 | 450 |
441 // find threshold for first 't' samples, where a full average cannot be computed yet | 451 // find threshold for first 't' samples, where a full average cannot be computed yet |
442 for (i = 0;i <= t;i++) | 452 for (i = 0;i <= t;i++) |
443 { | 453 { |
444 k = std::min((i+p_pre),N); | 454 k = std::min((i+p_pre),N); |
445 x_thresh[i] = mean_array(x,1,k); | 455 x_thresh[i] = calculateMeanOfArray(x,1,k); |
446 } | 456 } |
447 // find threshold for bulk of samples across a moving average from [i-p_pre,i+p_post] | 457 // find threshold for bulk of samples across a moving average from [i-p_pre,i+p_post] |
448 for (i = t+1;i < N-p_post;i++) | 458 for (i = t+1;i < N-p_post;i++) |
449 { | 459 { |
450 x_thresh[i] = mean_array(x,i-p_pre,i+p_post); | 460 x_thresh[i] = calculateMeanOfArray(x,i-p_pre,i+p_post); |
451 } | 461 } |
452 // for last few samples calculate threshold, again, not enough samples to do as above | 462 // for last few samples calculate threshold, again, not enough samples to do as above |
453 for (i = N-p_post;i < N;i++) | 463 for (i = N-p_post;i < N;i++) |
454 { | 464 { |
455 k = std::max((i-p_post),1); | 465 k = std::max((i-p_post),1); |
456 x_thresh[i] = mean_array(x,k,N); | 466 x_thresh[i] = calculateMeanOfArray(x,k,N); |
457 } | 467 } |
458 | 468 |
459 // subtract the threshold from the detection function and check that it is not less than 0 | 469 // subtract the threshold from the detection function and check that it is not less than 0 |
460 for (i = 0;i < N;i++) | 470 for (i = 0;i < N;i++) |
461 { | 471 { |
466 } | 476 } |
467 } | 477 } |
468 } | 478 } |
469 | 479 |
470 //======================================================================= | 480 //======================================================================= |
471 void BTrack :: getrcfoutput() | 481 void BTrack::calculateOutputOfCombFilterBank() |
472 { | 482 { |
473 int numelem; | 483 int numelem; |
474 | 484 |
475 for (int i = 0;i < 128;i++) | 485 for (int i = 0;i < 128;i++) |
476 { | 486 { |
490 } | 500 } |
491 } | 501 } |
492 } | 502 } |
493 | 503 |
494 //======================================================================= | 504 //======================================================================= |
495 void BTrack :: acf_bal(double *df_thresh) | 505 void BTrack::calculateBalancedACF(double *df_thresh) |
496 { | 506 { |
497 int l, n = 0; | 507 int l, n = 0; |
498 double sum, tmp; | 508 double sum, tmp; |
499 | 509 |
500 // for l lags from 0-511 | 510 // for l lags from 0-511 |
512 acf[l] = sum / (512-l); // weight by number of mults and add to acf buffer | 522 acf[l] = sum / (512-l); // weight by number of mults and add to acf buffer |
513 } | 523 } |
514 } | 524 } |
515 | 525 |
516 //======================================================================= | 526 //======================================================================= |
517 double BTrack :: mean_array(double *array,int start,int end) | 527 double BTrack::calculateMeanOfArray(double *array,int start,int end) |
518 { | 528 { |
519 int i; | 529 int i; |
520 double sum = 0; | 530 double sum = 0; |
521 | 531 |
522 int length = end - start; | 532 int length = end - start; |
536 return 0; | 546 return 0; |
537 } | 547 } |
538 } | 548 } |
539 | 549 |
540 //======================================================================= | 550 //======================================================================= |
541 void BTrack :: normalise(double *array,int N) | 551 void BTrack::normaliseArray(double *array,int N) |
542 { | 552 { |
543 double sum = 0; | 553 double sum = 0; |
544 | 554 |
545 for (int i = 0;i < N;i++) | 555 for (int i = 0;i < N;i++) |
546 { | 556 { |
558 } | 568 } |
559 } | 569 } |
560 } | 570 } |
561 | 571 |
562 //======================================================================= | 572 //======================================================================= |
563 void BTrack :: updatecumscore(double df_sample) | 573 void BTrack::updateCumulativeScore(double df_sample) |
564 { | 574 { |
565 int start, end, winsize; | 575 int start, end, winsize; |
566 double max; | 576 double max; |
567 | 577 |
568 start = dfbuffer_size - round(2*bperiod); | 578 start = dfbuffer_size - round(2*beatPeriod); |
569 end = dfbuffer_size - round(bperiod/2); | 579 end = dfbuffer_size - round(beatPeriod/2); |
570 winsize = end-start+1; | 580 winsize = end-start+1; |
571 | 581 |
572 double w1[winsize]; | 582 double w1[winsize]; |
573 double v = -2*bperiod; | 583 double v = -2*beatPeriod; |
574 double wcumscore; | 584 double wcumscore; |
575 | 585 |
576 | 586 |
577 // create window | 587 // create window |
578 for (int i = 0;i < winsize;i++) | 588 for (int i = 0;i < winsize;i++) |
579 { | 589 { |
580 w1[i] = exp((-1*pow(tightness*log(-v/bperiod),2))/2); | 590 w1[i] = exp((-1*pow(tightness*log(-v/beatPeriod),2))/2); |
581 v = v+1; | 591 v = v+1; |
582 } | 592 } |
583 | 593 |
584 // calculate new cumulative score value | 594 // calculate new cumulative score value |
585 max = 0; | 595 max = 0; |
610 //cout << cumscore[dfbuffer_size-1] << endl; | 620 //cout << cumscore[dfbuffer_size-1] << endl; |
611 | 621 |
612 } | 622 } |
613 | 623 |
614 //======================================================================= | 624 //======================================================================= |
615 void BTrack :: predictbeat() | 625 void BTrack::predictBeat() |
616 { | 626 { |
617 int winsize = (int) bperiod; | 627 int winsize = (int) beatPeriod; |
618 double fcumscore[dfbuffer_size + winsize]; | 628 double fcumscore[dfbuffer_size + winsize]; |
619 double w2[winsize]; | 629 double w2[winsize]; |
620 // copy cumscore to first part of fcumscore | 630 // copy cumscore to first part of fcumscore |
621 for (int i = 0;i < dfbuffer_size;i++) | 631 for (int i = 0;i < dfbuffer_size;i++) |
622 { | 632 { |
625 | 635 |
626 // create future window | 636 // create future window |
627 double v = 1; | 637 double v = 1; |
628 for (int i = 0;i < winsize;i++) | 638 for (int i = 0;i < winsize;i++) |
629 { | 639 { |
630 w2[i] = exp((-1*pow((v - (bperiod/2)),2)) / (2*pow((bperiod/2) ,2))); | 640 w2[i] = exp((-1*pow((v - (beatPeriod/2)),2)) / (2*pow((beatPeriod/2) ,2))); |
631 v++; | 641 v++; |
632 } | 642 } |
633 | 643 |
634 // create past window | 644 // create past window |
635 v = -2*bperiod; | 645 v = -2*beatPeriod; |
636 int start = dfbuffer_size - round(2*bperiod); | 646 int start = dfbuffer_size - round(2*beatPeriod); |
637 int end = dfbuffer_size - round(bperiod/2); | 647 int end = dfbuffer_size - round(beatPeriod/2); |
638 int pastwinsize = end-start+1; | 648 int pastwinsize = end-start+1; |
639 double w1[pastwinsize]; | 649 double w1[pastwinsize]; |
640 | 650 |
641 for (int i = 0;i < pastwinsize;i++) | 651 for (int i = 0;i < pastwinsize;i++) |
642 { | 652 { |
643 w1[i] = exp((-1*pow(tightness*log(-v/bperiod),2))/2); | 653 w1[i] = exp((-1*pow(tightness*log(-v/beatPeriod),2))/2); |
644 v = v+1; | 654 v = v+1; |
645 } | 655 } |
646 | 656 |
647 | 657 |
648 | 658 |
650 double max; | 660 double max; |
651 int n; | 661 int n; |
652 double wcumscore; | 662 double wcumscore; |
653 for (int i = dfbuffer_size;i < (dfbuffer_size+winsize);i++) | 663 for (int i = dfbuffer_size;i < (dfbuffer_size+winsize);i++) |
654 { | 664 { |
655 start = i - round(2*bperiod); | 665 start = i - round(2*beatPeriod); |
656 end = i - round(bperiod/2); | 666 end = i - round(beatPeriod/2); |
657 | 667 |
658 max = 0; | 668 max = 0; |
659 n = 0; | 669 n = 0; |
660 for (int k=start;k <= end;k++) | 670 for (int k=start;k <= end;k++) |
661 { | 671 { |
688 | 698 |
689 n++; | 699 n++; |
690 } | 700 } |
691 | 701 |
692 // set next prediction time | 702 // set next prediction time |
693 m0 = beat+round(bperiod/2); | 703 m0 = beat+round(beatPeriod/2); |
694 | 704 |
695 | 705 |
696 } | 706 } |