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 } | 
