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 }