comparison src/BTrack.cpp @ 97:6a4dd7478954

Replaced C-style arrays with std vectors and modernised some code
author Adam Stark <adamstark.uk@gmail.com>
date Fri, 11 Aug 2017 18:18:33 +0100
parents 4aa362058011
children 3b24b01fbe15
comparison
equal deleted inserted replaced
95:4ba1239fa120 97:6a4dd7478954
19 */ 19 */
20 //======================================================================= 20 //=======================================================================
21 21
22 #include <cmath> 22 #include <cmath>
23 #include <algorithm> 23 #include <algorithm>
24 #include <numeric>
24 #include "BTrack.h" 25 #include "BTrack.h"
25 #include "samplerate.h" 26 #include "samplerate.h"
26 #include <iostream> 27 #include <iostream>
27 28
28 //======================================================================= 29 //=======================================================================
32 initialise (512, 1024); 33 initialise (512, 1024);
33 } 34 }
34 35
35 //======================================================================= 36 //=======================================================================
36 BTrack::BTrack (int hopSize_) 37 BTrack::BTrack (int hopSize_)
37 : odf(hopSize_, 2*hopSize_, ComplexSpectralDifferenceHWR, HanningWindow) 38 : odf (hopSize_, 2 * hopSize_, ComplexSpectralDifferenceHWR, HanningWindow)
38 { 39 {
39 initialise (hopSize_, 2*hopSize_); 40 initialise (hopSize_, 2 * hopSize_);
40 } 41 }
41 42
42 //======================================================================= 43 //=======================================================================
43 BTrack::BTrack (int hopSize_, int frameSize_) 44 BTrack::BTrack (int hopSize_, int frameSize_)
44 : odf (hopSize_, frameSize_, ComplexSpectralDifferenceHWR, HanningWindow) 45 : odf (hopSize_, frameSize_, ComplexSpectralDifferenceHWR, HanningWindow)
86 87
87 88
88 //======================================================================= 89 //=======================================================================
89 void BTrack::initialise (int hopSize_, int frameSize_) 90 void BTrack::initialise (int hopSize_, int frameSize_)
90 { 91 {
92 // set vector sizes
93 resampledOnsetDF.resize (512);
94 acf.resize (512);
95 weightingVector.resize (128);
96 combFilterBankOutput.resize (128);
97 tempoObservationVector.resize (41);
98 delta.resize (41);
99 prevDelta.resize (41);
100 prevDeltaFixed.resize (41);
101
91 double rayparam = 43; 102 double rayparam = 43;
92 double pi = 3.14159265; 103 double pi = 3.14159265;
93 104
94 105
95 // initialise parameters 106 // initialise parameters
109 for (int n = 0; n < 128; n++) 120 for (int n = 0; n < 128; n++)
110 { 121 {
111 weightingVector[n] = ((double) n / pow(rayparam,2)) * exp((-1*pow((double)-n,2)) / (2*pow(rayparam,2))); 122 weightingVector[n] = ((double) n / pow(rayparam,2)) * exp((-1*pow((double)-n,2)) / (2*pow(rayparam,2)));
112 } 123 }
113 124
114 // initialise prev_delta 125 // initialise prev_delta
115 for (int i = 0; i < 41; i++) 126 std::fill (prevDelta.begin(), prevDelta.end(), 1);
116 { 127
117 prevDelta[i] = 1;
118 }
119
120 double t_mu = 41/2; 128 double t_mu = 41/2;
121 double m_sig; 129 double m_sig;
122 double x; 130 double x;
123 // create tempo transition matrix 131 // create tempo transition matrix
124 m_sig = 41/8; 132 m_sig = 41/8;
164 172
165 //======================================================================= 173 //=======================================================================
166 void BTrack::setHopSize (int hopSize_) 174 void BTrack::setHopSize (int hopSize_)
167 { 175 {
168 hopSize = hopSize_; 176 hopSize = hopSize_;
169 onsetDFBufferSize = (512*512)/hopSize; // calculate df buffer size 177 onsetDFBufferSize = (512 * 512) / hopSize; // calculate df buffer size
170 178
171 beatPeriod = round(60/((((double) hopSize)/44100)*tempo)); 179 beatPeriod = round(60/((((double) hopSize)/44100)*tempo));
172 180
173 // set size of onset detection function buffer 181 // set size of onset detection function buffer
174 onsetDF.resize (onsetDFBufferSize); 182 onsetDF.resize (onsetDFBufferSize);
252 onsetDF.addSampleToEnd (newSample); 260 onsetDF.addSampleToEnd (newSample);
253 261
254 // update cumulative score 262 // update cumulative score
255 updateCumulativeScore (newSample); 263 updateCumulativeScore (newSample);
256 264
257 // if we are halfway between beats 265 // if we are halfway between beats, predict a beat
258 if (m0 == 0) 266 if (m0 == 0)
259 { 267 predictBeat();
260 predictBeat();
261 }
262 268
263 // if we are at a beat 269 // if we are at a beat
264 if (beatCounter == 0) 270 if (beatCounter == 0)
265 { 271 {
266 beatDueInFrame = true; // indicate a beat should be output 272 beatDueInFrame = true; // indicate a beat should be output
271 } 277 }
272 } 278 }
273 279
274 //======================================================================= 280 //=======================================================================
275 void BTrack::setTempo (double tempo) 281 void BTrack::setTempo (double tempo)
276 { 282 {
277
278 /////////// TEMPO INDICATION RESET ////////////////// 283 /////////// TEMPO INDICATION RESET //////////////////
279 284
280 // firstly make sure tempo is between 80 and 160 bpm.. 285 // firstly make sure tempo is between 80 and 160 bpm..
281 while (tempo > 160) 286 while (tempo > 160)
282 { 287 tempo = tempo / 2;
283 tempo = tempo/2;
284 }
285 288
286 while (tempo < 80) 289 while (tempo < 80)
287 { 290 tempo = tempo * 2;
288 tempo = tempo * 2;
289 }
290 291
291 // convert tempo from bpm value to integer index of tempo probability 292 // convert tempo from bpm value to integer index of tempo probability
292 int tempo_index = (int) round((tempo - 80)/2); 293 int tempo_index = (int) round((tempo - 80)/2);
293 294
294 // now set previous tempo observations to zero 295 // now set previous tempo observations to zero and set desired tempo index to 1
295 for (int i=0;i < 41;i++) 296 std::fill (prevDelta.begin(), prevDelta.end(), 0);
296 {
297 prevDelta[i] = 0;
298 }
299
300 // set desired tempo index to 1
301 prevDelta[tempo_index] = 1; 297 prevDelta[tempo_index] = 1;
302 298
303
304 /////////// CUMULATIVE SCORE ARTIFICAL TEMPO UPDATE ////////////////// 299 /////////// CUMULATIVE SCORE ARTIFICAL TEMPO UPDATE //////////////////
305 300
306 // calculate new beat period 301 // calculate new beat period
307 int new_bperiod = (int) round(60/((((double) hopSize)/44100)*tempo)); 302 int newBeatPeriod = (int) round (60 / ((((double) hopSize) / 44100) * tempo));
308 303
309 int bcounter = 1; 304 int k = 1;
310 // initialise df_buffer to zeros 305
311 for (int i = (onsetDFBufferSize-1);i >= 0;i--) 306 // initialise onset detection function with delta functions spaced
312 { 307 // at the new beat period
313 if (bcounter == 1) 308 for (int i = onsetDFBufferSize - 1; i >= 0; i--)
309 {
310 if (k == 1)
314 { 311 {
315 cumulativeScore[i] = 150; 312 cumulativeScore[i] = 150;
316 onsetDF[i] = 150; 313 onsetDF[i] = 150;
317 } 314 }
318 else 315 else
319 { 316 {
320 cumulativeScore[i] = 10; 317 cumulativeScore[i] = 10;
321 onsetDF[i] = 10; 318 onsetDF[i] = 10;
322 } 319 }
323 320
324 bcounter++; 321 k++;
325 322
326 if (bcounter > new_bperiod) 323 if (k > newBeatPeriod)
327 { 324 {
328 bcounter = 1; 325 k = 1;
329 } 326 }
330 } 327 }
331 328
332 /////////// INDICATE THAT THIS IS A BEAT ////////////////// 329 /////////// INDICATE THAT THIS IS A BEAT //////////////////
333 330
334 // beat is now 331 // beat is now
335 beatCounter = 0; 332 beatCounter = 0;
336 333
337 // offbeat is half of new beat period away 334 // offbeat is half of new beat period away
338 m0 = (int) round(((double) new_bperiod)/2); 335 m0 = (int) round (((double) newBeatPeriod) / 2);
339 } 336 }
340 337
341 //======================================================================= 338 //=======================================================================
342 void BTrack::fixTempo (double tempo) 339 void BTrack::fixTempo (double tempo)
343 { 340 {
377 374
378 //======================================================================= 375 //=======================================================================
379 void BTrack::resampleOnsetDetectionFunction() 376 void BTrack::resampleOnsetDetectionFunction()
380 { 377 {
381 float output[512]; 378 float output[512];
382
383 float input[onsetDFBufferSize]; 379 float input[onsetDFBufferSize];
384 380
385 for (int i = 0;i < onsetDFBufferSize;i++) 381 for (int i = 0;i < onsetDFBufferSize;i++)
386 {
387 input[i] = (float) onsetDF[i]; 382 input[i] = (float) onsetDF[i];
388 }
389 383
390 double src_ratio = 512.0/((double) onsetDFBufferSize); 384 double ratio = 512.0 / ((double) onsetDFBufferSize);
391 int BUFFER_LEN = onsetDFBufferSize; 385 int bufferLength = onsetDFBufferSize;
392 int output_len; 386 int outputLength = 512;
393 SRC_DATA src_data ; 387
394 388 SRC_DATA src_data;
395 //output_len = (int) floor (((double) BUFFER_LEN) * src_ratio) ;
396 output_len = 512;
397
398 src_data.data_in = input; 389 src_data.data_in = input;
399 src_data.input_frames = BUFFER_LEN; 390 src_data.input_frames = bufferLength;
400 391 src_data.src_ratio = ratio;
401 src_data.src_ratio = src_ratio;
402
403 src_data.data_out = output; 392 src_data.data_out = output;
404 src_data.output_frames = output_len; 393 src_data.output_frames = outputLength;
405 394
406 src_simple (&src_data, SRC_SINC_BEST_QUALITY, 1); 395 src_simple (&src_data, SRC_SINC_BEST_QUALITY, 1);
407 396
408 for (int i = 0;i < output_len;i++) 397 for (int i = 0; i < outputLength; i++)
409 {
410 resampledOnsetDF[i] = (double) src_data.data_out[i]; 398 resampledOnsetDF[i] = (double) src_data.data_out[i];
411 }
412 } 399 }
413 400
414 //======================================================================= 401 //=======================================================================
415 void BTrack::calculateTempo() 402 void BTrack::calculateTempo()
416 { 403 {
417 // adaptive threshold on input 404 // adaptive threshold on input
418 adaptiveThreshold (resampledOnsetDF,512); 405 adaptiveThreshold (resampledOnsetDF, 512);
419 406
420 // calculate auto-correlation function of detection function 407 // calculate auto-correlation function of detection function
421 calculateBalancedACF (resampledOnsetDF); 408 calculateBalancedACF (&resampledOnsetDF[0]);
422 409
423 // calculate output of comb filterbank 410 // calculate output of comb filterbank
424 calculateOutputOfCombFilterBank(); 411 calculateOutputOfCombFilterBank();
425 412
426 // adaptive threshold on rcf 413 // adaptive threshold on rcf
427 adaptiveThreshold (combFilterBankOutput,128); 414 adaptiveThreshold (combFilterBankOutput, 128);
428 415
429 416
430 int t_index; 417 int t_index;
431 int t_index2; 418 int t_index2;
432 // calculate tempo observation vector from beat period observation vector 419 // calculate tempo observation vector from beat period observation vector
468 455
469 delta[j] = maxval * tempoObservationVector[j]; 456 delta[j] = maxval * tempoObservationVector[j];
470 } 457 }
471 458
472 459
473 normaliseArray(delta,41); 460 normaliseArray (delta);
474 461
475 maxind = -1; 462 maxind = -1;
476 maxval = -1; 463 maxval = -1;
477 464
478 for (int j=0;j < 41;j++) 465 for (int j=0;j < 41;j++)
493 estimatedTempo = 60.0/((((double) hopSize) / 44100.0) * beatPeriod); 480 estimatedTempo = 60.0/((((double) hopSize) / 44100.0) * beatPeriod);
494 } 481 }
495 } 482 }
496 483
497 //======================================================================= 484 //=======================================================================
498 void BTrack::adaptiveThreshold (double* x, int N) 485 void BTrack::adaptiveThreshold (std::vector<double>& x, int N)
499 { 486 {
500 int i = 0; 487 int i = 0;
501 int k,t = 0; 488 int k,t = 0;
502 double x_thresh[N]; 489 double x_thresh[N];
503 490
505 int p_pre = 8; 492 int p_pre = 8;
506 493
507 t = std::min(N,p_post); // what is smaller, p_post of df size. This is to avoid accessing outside of arrays 494 t = std::min(N,p_post); // what is smaller, p_post of df size. This is to avoid accessing outside of arrays
508 495
509 // find threshold for first 't' samples, where a full average cannot be computed yet 496 // find threshold for first 't' samples, where a full average cannot be computed yet
510 for (i = 0;i <= t;i++) 497 for (i = 0; i <= t; i++)
511 { 498 {
512 k = std::min ((i+p_pre),N); 499 k = std::min ((i + p_pre), N);
513 x_thresh[i] = calculateMeanOfArray (x,1,k); 500 x_thresh[i] = calculateMeanOfArray (x, 1, k);
514 } 501 }
515 // find threshold for bulk of samples across a moving average from [i-p_pre,i+p_post] 502 // find threshold for bulk of samples across a moving average from [i-p_pre,i+p_post]
516 for (i = t+1;i < N-p_post;i++) 503 for (i = t + 1; i < N - p_post; i++)
517 { 504 {
518 x_thresh[i] = calculateMeanOfArray (x,i-p_pre,i+p_post); 505 x_thresh[i] = calculateMeanOfArray (x, i - p_pre, i + p_post);
519 } 506 }
520 // for last few samples calculate threshold, again, not enough samples to do as above 507 // for last few samples calculate threshold, again, not enough samples to do as above
521 for (i = N-p_post;i < N;i++) 508 for (i = N - p_post; i < N; i++)
522 { 509 {
523 k = std::max ((i-p_post),1); 510 k = std::max ((i - p_post), 1);
524 x_thresh[i] = calculateMeanOfArray (x,k,N); 511 x_thresh[i] = calculateMeanOfArray (x, k, N);
525 } 512 }
526 513
527 // subtract the threshold from the detection function and check that it is not less than 0 514 // subtract the threshold from the detection function and check that it is not less than 0
528 for (i = 0; i < N; i++) 515 for (i = 0; i < N; i++)
529 { 516 {
650 lag = lag - 1.; 637 lag = lag - 1.;
651 } 638 }
652 } 639 }
653 640
654 //======================================================================= 641 //=======================================================================
655 double BTrack::calculateMeanOfArray (double* array, int startIndex, int endIndex) 642 double BTrack::calculateMeanOfArray (std::vector<double>& array, int startIndex, int endIndex)
656 { 643 {
657 int i;
658 double sum = 0;
659
660 int length = endIndex - startIndex; 644 int length = endIndex - startIndex;
661 645 double sum = std::accumulate (array.begin() + startIndex, array.begin() + endIndex, 0.0);
662 // find sum 646
663 for (i = startIndex; i < endIndex; i++)
664 {
665 sum = sum + array[i];
666 }
667
668 if (length > 0) 647 if (length > 0)
648 return sum / static_cast<double> (length); // average and return
649 else
650 return 0;
651 }
652
653 //=======================================================================
654 void BTrack::normaliseArray (std::vector<double>& array)
655 {
656 double sum = std::accumulate (array.begin(), array.end(), 0.0);
657
658 if (sum > 0)
669 { 659 {
670 return sum / length; // average and return 660 for (int i = 0; i < array.size(); i++)
661 array[i] = array[i] / sum;
671 } 662 }
672 else
673 {
674 return 0;
675 }
676 }
677
678 //=======================================================================
679 void BTrack::normaliseArray (double* array, int N)
680 {
681 double sum = 0;
682
683 for (int i = 0; i < N; i++)
684 {
685 if (array[i] > 0)
686 {
687 sum = sum + array[i];
688 }
689 }
690
691 if (sum > 0)
692 {
693 for (int i = 0; i < N; i++)
694 {
695 array[i] = array[i] / sum;
696 }
697 }
698 } 663 }
699 664
700 //======================================================================= 665 //=======================================================================
701 void BTrack::updateCumulativeScore (double odfSample) 666 void BTrack::updateCumulativeScore (double odfSample)
702 { 667 {
703 int start, end, winsize; 668 int start, end, winsize;
704 double max; 669 double max;
705 670
706 start = onsetDFBufferSize - round (2 * beatPeriod); 671 start = onsetDFBufferSize - round (2. * beatPeriod);
707 end = onsetDFBufferSize - round (beatPeriod / 2); 672 end = onsetDFBufferSize - round (beatPeriod / 2.);
708 winsize = end-start+1; 673 winsize = end - start + 1;
709 674
710 double w1[winsize]; 675 double w1[winsize];
711 double v = -2*beatPeriod; 676 double v = -2. * beatPeriod;
712 double wcumscore; 677 double wcumscore;
713 678
714 // create window 679 // create window
715 for (int i = 0; i < winsize; i++) 680 for (int i = 0; i < winsize; i++)
716 { 681 {
717 w1[i] = exp((-1 * pow (tightness * log (-v / beatPeriod), 2)) / 2); 682 w1[i] = exp((-1 * pow (tightness * log (-v / beatPeriod), 2)) / 2);
718 v = v+1; 683 v = v + 1;
719 } 684 }
720 685
721 // calculate new cumulative score value 686 // calculate new cumulative score value
722 max = 0; 687 max = 0;
723 int n = 0; 688 int n = 0;