annotate 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
rev   line source
adamstark@46 1 //=======================================================================
adamstark@46 2 /** @file BTrack.cpp
adamstark@47 3 * @brief BTrack - a real-time beat tracker
adamstark@46 4 * @author Adam Stark
adamstark@46 5 * @copyright Copyright (C) 2008-2014 Queen Mary University of London
adamstark@46 6 *
adamstark@46 7 * This program is free software: you can redistribute it and/or modify
adamstark@46 8 * it under the terms of the GNU General Public License as published by
adamstark@46 9 * the Free Software Foundation, either version 3 of the License, or
adamstark@46 10 * (at your option) any later version.
adamstark@46 11 *
adamstark@46 12 * This program is distributed in the hope that it will be useful,
adamstark@46 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
adamstark@46 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
adamstark@46 15 * GNU General Public License for more details.
adamstark@46 16 *
adamstark@46 17 * You should have received a copy of the GNU General Public License
adamstark@46 18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
adamstark@46 19 */
adamstark@46 20 //=======================================================================
adamstark@46 21
adamstark@46 22 #include <cmath>
adamstark@52 23 #include <algorithm>
adamstark@46 24 #include "BTrack.h"
adamstark@46 25 #include "samplerate.h"
adamstark@46 26
adamstark@55 27 //=======================================================================
adamstark@57 28 BTrack::BTrack() : odf(512,1024,ComplexSpectralDifferenceHWR,HanningWindow)
adamstark@55 29 {
adamstark@55 30 initialise(512, 1024);
adamstark@55 31 }
adamstark@46 32
adamstark@51 33 //=======================================================================
adamstark@57 34 BTrack::BTrack(int hopSize_) : odf(hopSize_,2*hopSize_,ComplexSpectralDifferenceHWR,HanningWindow)
adamstark@46 35 {
adamstark@57 36 initialise(hopSize_, 2*hopSize_);
adamstark@55 37 }
adamstark@55 38
adamstark@55 39 //=======================================================================
adamstark@57 40 BTrack::BTrack(int hopSize_,int frameSize_) : odf(hopSize_,frameSize_,ComplexSpectralDifferenceHWR,HanningWindow)
adamstark@55 41 {
adamstark@57 42 initialise(hopSize_, frameSize_);
adamstark@55 43 }
adamstark@55 44
adamstark@55 45 //=======================================================================
adamstark@55 46 double BTrack::getBeatTimeInSeconds(long frameNumber,int hopSize,int fs)
adamstark@55 47 {
adamstark@55 48 double hop = (double) hopSize;
adamstark@55 49 double samplingFrequency = (double) fs;
adamstark@55 50 double frameNum = (double) frameNumber;
adamstark@55 51
adamstark@55 52 return ((hop / samplingFrequency) * frameNum);
adamstark@55 53 }
adamstark@55 54
adamstark@55 55 //=======================================================================
adamstark@55 56 double BTrack::getBeatTimeInSeconds(int frameNumber,int hopSize,int fs)
adamstark@55 57 {
adamstark@55 58 long frameNum = (long) frameNumber;
adamstark@55 59
adamstark@55 60 return getBeatTimeInSeconds(frameNum, hopSize, fs);
adamstark@55 61 }
adamstark@55 62
adamstark@55 63
adamstark@55 64
adamstark@55 65 //=======================================================================
adamstark@57 66 void BTrack::initialise(int hopSize_, int frameSize_)
adamstark@55 67 {
adamstark@55 68 double rayparam = 43;
adamstark@54 69 double pi = 3.14159265;
adamstark@46 70
adamstark@46 71
adamstark@46 72 // initialise parameters
adamstark@46 73 tightness = 5;
adamstark@46 74 alpha = 0.9;
adamstark@46 75 tempo = 120;
adamstark@46 76 est_tempo = 120;
adamstark@46 77 p_fact = 60.*44100./512.;
adamstark@46 78
adamstark@46 79 m0 = 10;
adamstark@46 80 beat = -1;
adamstark@46 81
adamstark@57 82 beatDueInFrame = false;
adamstark@46 83
adamstark@46 84
adamstark@46 85
adamstark@46 86
adamstark@46 87 // create rayleigh weighting vector
adamstark@46 88 for (int n = 0;n < 128;n++)
adamstark@46 89 {
adamstark@54 90 wv[n] = ((double) n / pow(rayparam,2)) * exp((-1*pow((double)-n,2)) / (2*pow(rayparam,2)));
adamstark@46 91 }
adamstark@46 92
adamstark@46 93 // initialise prev_delta
adamstark@46 94 for (int i = 0;i < 41;i++)
adamstark@46 95 {
adamstark@46 96 prev_delta[i] = 1;
adamstark@46 97 }
adamstark@46 98
adamstark@54 99 double t_mu = 41/2;
adamstark@54 100 double m_sig;
adamstark@54 101 double x;
adamstark@46 102 // create tempo transition matrix
adamstark@46 103 m_sig = 41/8;
adamstark@46 104 for (int i = 0;i < 41;i++)
adamstark@46 105 {
adamstark@46 106 for (int j = 0;j < 41;j++)
adamstark@46 107 {
adamstark@46 108 x = j+1;
adamstark@46 109 t_mu = i+1;
adamstark@46 110 t_tmat[i][j] = (1 / (m_sig * sqrt(2*pi))) * exp( (-1*pow((x-t_mu),2)) / (2*pow(m_sig,2)) );
adamstark@46 111 }
adamstark@55 112 }
adamstark@46 113
adamstark@46 114 // tempo is not fixed
adamstark@46 115 tempofix = 0;
adamstark@55 116
adamstark@55 117 // initialise algorithm given the hopsize
adamstark@57 118 setHopSize(hopSize_);
adamstark@46 119 }
adamstark@46 120
adamstark@51 121 //=======================================================================
adamstark@57 122 void BTrack::setHopSize(int hopSize_)
adamstark@46 123 {
adamstark@57 124 hopSize = hopSize_;
adamstark@55 125 dfbuffer_size = (512*512)/hopSize; // calculate df buffer size
adamstark@46 126
adamstark@57 127 beatPeriod = round(60/((((double) hopSize)/44100)*tempo));
adamstark@46 128
adamstark@54 129 dfbuffer = new double[dfbuffer_size]; // create df_buffer
adamstark@54 130 cumscore = new double[dfbuffer_size]; // create cumscore
adamstark@46 131
adamstark@46 132
adamstark@46 133 // initialise df_buffer to zeros
adamstark@46 134 for (int i = 0;i < dfbuffer_size;i++)
adamstark@46 135 {
adamstark@46 136 dfbuffer[i] = 0;
adamstark@46 137 cumscore[i] = 0;
adamstark@46 138
adamstark@46 139
adamstark@57 140 if ((i % ((int) round(beatPeriod))) == 0)
adamstark@46 141 {
adamstark@46 142 dfbuffer[i] = 1;
adamstark@46 143 }
adamstark@46 144 }
adamstark@46 145 }
adamstark@46 146
adamstark@51 147 //=======================================================================
adamstark@57 148 bool BTrack::beatDueInCurrentFrame()
adamstark@57 149 {
adamstark@57 150 return beatDueInFrame;
adamstark@57 151 }
adamstark@57 152
adamstark@57 153 //=======================================================================
adamstark@57 154 int BTrack::getHopSize()
adamstark@57 155 {
adamstark@57 156 return hopSize;
adamstark@57 157 }
adamstark@57 158
adamstark@57 159 //=======================================================================
adamstark@55 160 void BTrack::processAudioFrame(double *frame)
adamstark@55 161 {
adamstark@55 162 // calculate the onset detection function sample for the frame
adamstark@55 163 double sample = odf.getDFsample(frame);
adamstark@55 164
adamstark@56 165
adamstark@55 166
adamstark@55 167 // process the new onset detection function sample in the beat tracking algorithm
adamstark@55 168 processOnsetDetectionFunctionSample(sample);
adamstark@55 169 }
adamstark@55 170
adamstark@55 171 //=======================================================================
adamstark@55 172 void BTrack::processOnsetDetectionFunctionSample(double newSample)
adamstark@56 173 {
adamstark@56 174 // we need to ensure that the onset
adamstark@56 175 // detection function sample is positive
adamstark@56 176 newSample = fabs(newSample);
adamstark@56 177
adamstark@56 178 // add a tiny constant to the sample to stop it from ever going
adamstark@56 179 // to zero. this is to avoid problems further down the line
adamstark@56 180 newSample = newSample + 0.0001;
adamstark@56 181
adamstark@46 182 m0--;
adamstark@46 183 beat--;
adamstark@57 184 beatDueInFrame = false;
adamstark@46 185
adamstark@46 186 // move all samples back one step
adamstark@46 187 for (int i=0;i < (dfbuffer_size-1);i++)
adamstark@46 188 {
adamstark@46 189 dfbuffer[i] = dfbuffer[i+1];
adamstark@46 190 }
adamstark@46 191
adamstark@46 192 // add new sample at the end
adamstark@55 193 dfbuffer[dfbuffer_size-1] = newSample;
adamstark@46 194
adamstark@46 195 // update cumulative score
adamstark@57 196 updateCumulativeScore(newSample);
adamstark@46 197
adamstark@46 198 // if we are halfway between beats
adamstark@46 199 if (m0 == 0)
adamstark@46 200 {
adamstark@57 201 predictBeat();
adamstark@46 202 }
adamstark@46 203
adamstark@46 204 // if we are at a beat
adamstark@46 205 if (beat == 0)
adamstark@46 206 {
adamstark@57 207 beatDueInFrame = true; // indicate a beat should be output
adamstark@46 208
adamstark@46 209 // recalculate the tempo
adamstark@57 210 resampleOnsetDetectionFunction();
adamstark@57 211 calculateTempo();
adamstark@46 212 }
adamstark@46 213 }
adamstark@46 214
adamstark@51 215 //=======================================================================
adamstark@57 216 void BTrack::setTempo(double tempo)
adamstark@46 217 {
adamstark@46 218
adamstark@46 219 /////////// TEMPO INDICATION RESET //////////////////
adamstark@46 220
adamstark@46 221 // firstly make sure tempo is between 80 and 160 bpm..
adamstark@46 222 while (tempo > 160)
adamstark@46 223 {
adamstark@46 224 tempo = tempo/2;
adamstark@46 225 }
adamstark@46 226
adamstark@46 227 while (tempo < 80)
adamstark@46 228 {
adamstark@46 229 tempo = tempo * 2;
adamstark@46 230 }
adamstark@46 231
adamstark@46 232 // convert tempo from bpm value to integer index of tempo probability
adamstark@46 233 int tempo_index = (int) round((tempo - 80)/2);
adamstark@46 234
adamstark@46 235 // now set previous tempo observations to zero
adamstark@46 236 for (int i=0;i < 41;i++)
adamstark@46 237 {
adamstark@46 238 prev_delta[i] = 0;
adamstark@46 239 }
adamstark@46 240
adamstark@46 241 // set desired tempo index to 1
adamstark@46 242 prev_delta[tempo_index] = 1;
adamstark@46 243
adamstark@46 244
adamstark@46 245 /////////// CUMULATIVE SCORE ARTIFICAL TEMPO UPDATE //////////////////
adamstark@46 246
adamstark@46 247 // calculate new beat period
adamstark@57 248 int new_bperiod = (int) round(60/((((double) hopSize)/44100)*tempo));
adamstark@46 249
adamstark@46 250 int bcounter = 1;
adamstark@46 251 // initialise df_buffer to zeros
adamstark@46 252 for (int i = (dfbuffer_size-1);i >= 0;i--)
adamstark@46 253 {
adamstark@46 254 if (bcounter == 1)
adamstark@46 255 {
adamstark@46 256 cumscore[i] = 150;
adamstark@46 257 dfbuffer[i] = 150;
adamstark@46 258 }
adamstark@46 259 else
adamstark@46 260 {
adamstark@46 261 cumscore[i] = 10;
adamstark@46 262 dfbuffer[i] = 10;
adamstark@46 263 }
adamstark@46 264
adamstark@46 265 bcounter++;
adamstark@46 266
adamstark@46 267 if (bcounter > new_bperiod)
adamstark@46 268 {
adamstark@46 269 bcounter = 1;
adamstark@46 270 }
adamstark@46 271 }
adamstark@46 272
adamstark@46 273 /////////// INDICATE THAT THIS IS A BEAT //////////////////
adamstark@46 274
adamstark@46 275 // beat is now
adamstark@46 276 beat = 0;
adamstark@46 277
adamstark@46 278 // offbeat is half of new beat period away
adamstark@54 279 m0 = (int) round(((double) new_bperiod)/2);
adamstark@46 280 }
adamstark@46 281
adamstark@51 282 //=======================================================================
adamstark@57 283 void BTrack::fixTempo(double tempo)
adamstark@46 284 {
adamstark@46 285 // firstly make sure tempo is between 80 and 160 bpm..
adamstark@46 286 while (tempo > 160)
adamstark@46 287 {
adamstark@46 288 tempo = tempo/2;
adamstark@46 289 }
adamstark@46 290
adamstark@46 291 while (tempo < 80)
adamstark@46 292 {
adamstark@46 293 tempo = tempo * 2;
adamstark@46 294 }
adamstark@46 295
adamstark@46 296 // convert tempo from bpm value to integer index of tempo probability
adamstark@46 297 int tempo_index = (int) round((tempo - 80)/2);
adamstark@46 298
adamstark@46 299 // now set previous fixed previous tempo observation values to zero
adamstark@46 300 for (int i=0;i < 41;i++)
adamstark@46 301 {
adamstark@46 302 prev_delta_fix[i] = 0;
adamstark@46 303 }
adamstark@46 304
adamstark@46 305 // set desired tempo index to 1
adamstark@46 306 prev_delta_fix[tempo_index] = 1;
adamstark@46 307
adamstark@46 308 // set the tempo fix flag
adamstark@46 309 tempofix = 1;
adamstark@46 310 }
adamstark@46 311
adamstark@51 312 //=======================================================================
adamstark@57 313 void BTrack::doNotFixTempo()
adamstark@46 314 {
adamstark@46 315 // set the tempo fix flag
adamstark@46 316 tempofix = 0;
adamstark@46 317 }
adamstark@46 318
adamstark@51 319 //=======================================================================
adamstark@57 320 void BTrack::resampleOnsetDetectionFunction()
adamstark@46 321 {
adamstark@46 322 float output[512];
adamstark@54 323 float input[dfbuffer_size];
adamstark@54 324
adamstark@54 325 for (int i = 0;i < dfbuffer_size;i++)
adamstark@54 326 {
adamstark@54 327 input[i] = (float) dfbuffer[i];
adamstark@54 328 }
adamstark@46 329
adamstark@46 330 double src_ratio = 512.0/((double) dfbuffer_size);
adamstark@46 331 int BUFFER_LEN = dfbuffer_size;
adamstark@46 332 int output_len;
adamstark@46 333 SRC_DATA src_data ;
adamstark@46 334
adamstark@46 335 //output_len = (int) floor (((double) BUFFER_LEN) * src_ratio) ;
adamstark@46 336 output_len = 512;
adamstark@46 337
adamstark@54 338 src_data.data_in = input;
adamstark@46 339 src_data.input_frames = BUFFER_LEN;
adamstark@46 340
adamstark@46 341 src_data.src_ratio = src_ratio;
adamstark@46 342
adamstark@46 343 src_data.data_out = output;
adamstark@46 344 src_data.output_frames = output_len;
adamstark@46 345
adamstark@46 346 src_simple (&src_data, SRC_SINC_BEST_QUALITY, 1);
adamstark@46 347
adamstark@46 348 for (int i = 0;i < output_len;i++)
adamstark@46 349 {
adamstark@54 350 df512[i] = (double) src_data.data_out[i];
adamstark@46 351 }
adamstark@46 352 }
adamstark@46 353
adamstark@51 354 //=======================================================================
adamstark@57 355 void BTrack::calculateTempo()
adamstark@46 356 {
adamstark@46 357 // adaptive threshold on input
adamstark@57 358 adaptiveThreshold(df512,512);
adamstark@46 359
adamstark@46 360 // calculate auto-correlation function of detection function
adamstark@57 361 calculateBalancedACF(df512);
adamstark@46 362
adamstark@46 363 // calculate output of comb filterbank
adamstark@57 364 calculateOutputOfCombFilterBank();
adamstark@46 365
adamstark@46 366
adamstark@46 367 // adaptive threshold on rcf
adamstark@57 368 adaptiveThreshold(rcf,128);
adamstark@46 369
adamstark@46 370
adamstark@46 371 int t_index;
adamstark@46 372 int t_index2;
adamstark@46 373 // calculate tempo observation vector from bperiod observation vector
adamstark@46 374 for (int i = 0;i < 41;i++)
adamstark@46 375 {
adamstark@54 376 t_index = (int) round(p_fact / ((double) ((2*i)+80)));
adamstark@54 377 t_index2 = (int) round(p_fact / ((double) ((4*i)+160)));
adamstark@46 378
adamstark@46 379
adamstark@46 380 t_obs[i] = rcf[t_index-1] + rcf[t_index2-1];
adamstark@46 381 }
adamstark@46 382
adamstark@46 383
adamstark@54 384 double maxval;
adamstark@54 385 double maxind;
adamstark@54 386 double curval;
adamstark@46 387
adamstark@46 388 // if tempo is fixed then always use a fixed set of tempi as the previous observation probability function
adamstark@46 389 if (tempofix == 1)
adamstark@46 390 {
adamstark@46 391 for (int k = 0;k < 41;k++)
adamstark@46 392 {
adamstark@46 393 prev_delta[k] = prev_delta_fix[k];
adamstark@46 394 }
adamstark@46 395 }
adamstark@46 396
adamstark@46 397 for (int j=0;j < 41;j++)
adamstark@46 398 {
adamstark@46 399 maxval = -1;
adamstark@46 400 for (int i = 0;i < 41;i++)
adamstark@46 401 {
adamstark@46 402 curval = prev_delta[i]*t_tmat[i][j];
adamstark@46 403
adamstark@46 404 if (curval > maxval)
adamstark@46 405 {
adamstark@46 406 maxval = curval;
adamstark@46 407 }
adamstark@46 408 }
adamstark@46 409
adamstark@46 410 delta[j] = maxval*t_obs[j];
adamstark@46 411 }
adamstark@46 412
adamstark@46 413
adamstark@57 414 normaliseArray(delta,41);
adamstark@46 415
adamstark@46 416 maxind = -1;
adamstark@46 417 maxval = -1;
adamstark@46 418
adamstark@46 419 for (int j=0;j < 41;j++)
adamstark@46 420 {
adamstark@46 421 if (delta[j] > maxval)
adamstark@46 422 {
adamstark@46 423 maxval = delta[j];
adamstark@46 424 maxind = j;
adamstark@46 425 }
adamstark@46 426
adamstark@46 427 prev_delta[j] = delta[j];
adamstark@46 428 }
adamstark@46 429
adamstark@57 430 beatPeriod = round((60.0*44100.0)/(((2*maxind)+80)*((double) hopSize)));
adamstark@46 431
adamstark@57 432 if (beatPeriod > 0)
adamstark@46 433 {
adamstark@57 434 est_tempo = 60.0/((((double) hopSize) / 44100.0)*beatPeriod);
adamstark@46 435 }
adamstark@46 436 }
adamstark@46 437
adamstark@51 438 //=======================================================================
adamstark@57 439 void BTrack::adaptiveThreshold(double *x,int N)
adamstark@46 440 {
adamstark@46 441 //int N = 512; // length of df
adamstark@46 442 int i = 0;
adamstark@46 443 int k,t = 0;
adamstark@54 444 double x_thresh[N];
adamstark@46 445
adamstark@46 446 int p_post = 7;
adamstark@46 447 int p_pre = 8;
adamstark@46 448
adamstark@52 449 t = std::min(N,p_post); // what is smaller, p_post of df size. This is to avoid accessing outside of arrays
adamstark@46 450
adamstark@46 451 // find threshold for first 't' samples, where a full average cannot be computed yet
adamstark@46 452 for (i = 0;i <= t;i++)
adamstark@46 453 {
adamstark@52 454 k = std::min((i+p_pre),N);
adamstark@57 455 x_thresh[i] = calculateMeanOfArray(x,1,k);
adamstark@46 456 }
adamstark@46 457 // find threshold for bulk of samples across a moving average from [i-p_pre,i+p_post]
adamstark@46 458 for (i = t+1;i < N-p_post;i++)
adamstark@46 459 {
adamstark@57 460 x_thresh[i] = calculateMeanOfArray(x,i-p_pre,i+p_post);
adamstark@46 461 }
adamstark@46 462 // for last few samples calculate threshold, again, not enough samples to do as above
adamstark@46 463 for (i = N-p_post;i < N;i++)
adamstark@46 464 {
adamstark@52 465 k = std::max((i-p_post),1);
adamstark@57 466 x_thresh[i] = calculateMeanOfArray(x,k,N);
adamstark@46 467 }
adamstark@46 468
adamstark@46 469 // subtract the threshold from the detection function and check that it is not less than 0
adamstark@46 470 for (i = 0;i < N;i++)
adamstark@46 471 {
adamstark@46 472 x[i] = x[i] - x_thresh[i];
adamstark@46 473 if (x[i] < 0)
adamstark@46 474 {
adamstark@46 475 x[i] = 0;
adamstark@46 476 }
adamstark@46 477 }
adamstark@46 478 }
adamstark@46 479
adamstark@51 480 //=======================================================================
adamstark@57 481 void BTrack::calculateOutputOfCombFilterBank()
adamstark@46 482 {
adamstark@46 483 int numelem;
adamstark@46 484
adamstark@46 485 for (int i = 0;i < 128;i++)
adamstark@46 486 {
adamstark@46 487 rcf[i] = 0;
adamstark@46 488 }
adamstark@46 489
adamstark@46 490 numelem = 4;
adamstark@46 491
adamstark@46 492 for (int i = 2;i <= 127;i++) // max beat period
adamstark@46 493 {
adamstark@46 494 for (int a = 1;a <= numelem;a++) // number of comb elements
adamstark@46 495 {
adamstark@46 496 for (int b = 1-a;b <= a-1;b++) // general state using normalisation of comb elements
adamstark@46 497 {
adamstark@46 498 rcf[i-1] = rcf[i-1] + (acf[(a*i+b)-1]*wv[i-1])/(2*a-1); // calculate value for comb filter row
adamstark@46 499 }
adamstark@46 500 }
adamstark@46 501 }
adamstark@46 502 }
adamstark@46 503
adamstark@51 504 //=======================================================================
adamstark@57 505 void BTrack::calculateBalancedACF(double *df_thresh)
adamstark@46 506 {
adamstark@46 507 int l, n = 0;
adamstark@54 508 double sum, tmp;
adamstark@46 509
adamstark@46 510 // for l lags from 0-511
adamstark@46 511 for (l = 0;l < 512;l++)
adamstark@46 512 {
adamstark@46 513 sum = 0;
adamstark@46 514
adamstark@46 515 // for n samples from 0 - (512-lag)
adamstark@46 516 for (n = 0;n < (512-l);n++)
adamstark@46 517 {
adamstark@46 518 tmp = df_thresh[n] * df_thresh[n+l]; // multiply current sample n by sample (n+l)
adamstark@46 519 sum = sum + tmp; // add to sum
adamstark@46 520 }
adamstark@46 521
adamstark@46 522 acf[l] = sum / (512-l); // weight by number of mults and add to acf buffer
adamstark@46 523 }
adamstark@46 524 }
adamstark@46 525
adamstark@51 526 //=======================================================================
adamstark@57 527 double BTrack::calculateMeanOfArray(double *array,int start,int end)
adamstark@46 528 {
adamstark@46 529 int i;
adamstark@47 530 double sum = 0;
adamstark@47 531
adamstark@47 532 int length = end - start;
adamstark@46 533
adamstark@46 534 // find sum
adamstark@47 535 for (i = start;i < end;i++)
adamstark@46 536 {
adamstark@46 537 sum = sum + array[i];
adamstark@46 538 }
adamstark@46 539
adamstark@47 540 if (length > 0)
adamstark@47 541 {
adamstark@47 542 return sum / length; // average and return
adamstark@47 543 }
adamstark@47 544 else
adamstark@47 545 {
adamstark@47 546 return 0;
adamstark@47 547 }
adamstark@46 548 }
adamstark@46 549
adamstark@51 550 //=======================================================================
adamstark@57 551 void BTrack::normaliseArray(double *array,int N)
adamstark@46 552 {
adamstark@46 553 double sum = 0;
adamstark@46 554
adamstark@46 555 for (int i = 0;i < N;i++)
adamstark@46 556 {
adamstark@46 557 if (array[i] > 0)
adamstark@46 558 {
adamstark@46 559 sum = sum + array[i];
adamstark@46 560 }
adamstark@46 561 }
adamstark@46 562
adamstark@46 563 if (sum > 0)
adamstark@46 564 {
adamstark@46 565 for (int i = 0;i < N;i++)
adamstark@46 566 {
adamstark@46 567 array[i] = array[i] / sum;
adamstark@46 568 }
adamstark@46 569 }
adamstark@46 570 }
adamstark@46 571
adamstark@51 572 //=======================================================================
adamstark@57 573 void BTrack::updateCumulativeScore(double df_sample)
adamstark@46 574 {
adamstark@46 575 int start, end, winsize;
adamstark@54 576 double max;
adamstark@46 577
adamstark@57 578 start = dfbuffer_size - round(2*beatPeriod);
adamstark@57 579 end = dfbuffer_size - round(beatPeriod/2);
adamstark@46 580 winsize = end-start+1;
adamstark@46 581
adamstark@54 582 double w1[winsize];
adamstark@57 583 double v = -2*beatPeriod;
adamstark@54 584 double wcumscore;
adamstark@46 585
adamstark@46 586
adamstark@46 587 // create window
adamstark@46 588 for (int i = 0;i < winsize;i++)
adamstark@46 589 {
adamstark@57 590 w1[i] = exp((-1*pow(tightness*log(-v/beatPeriod),2))/2);
adamstark@46 591 v = v+1;
adamstark@46 592 }
adamstark@46 593
adamstark@46 594 // calculate new cumulative score value
adamstark@46 595 max = 0;
adamstark@46 596 int n = 0;
adamstark@46 597 for (int i=start;i <= end;i++)
adamstark@46 598 {
adamstark@46 599 wcumscore = cumscore[i]*w1[n];
adamstark@46 600
adamstark@46 601 if (wcumscore > max)
adamstark@46 602 {
adamstark@46 603 max = wcumscore;
adamstark@46 604 }
adamstark@46 605 n++;
adamstark@46 606 }
adamstark@46 607
adamstark@46 608
adamstark@46 609 // shift cumulative score back one
adamstark@46 610 for (int i = 0;i < (dfbuffer_size-1);i++)
adamstark@46 611 {
adamstark@46 612 cumscore[i] = cumscore[i+1];
adamstark@46 613 }
adamstark@46 614
adamstark@46 615 // add new value to cumulative score
adamstark@46 616 cumscore[dfbuffer_size-1] = ((1-alpha)*df_sample) + (alpha*max);
adamstark@46 617
adamstark@46 618 cscoreval = cumscore[dfbuffer_size-1];
adamstark@46 619
adamstark@46 620 //cout << cumscore[dfbuffer_size-1] << endl;
adamstark@46 621
adamstark@46 622 }
adamstark@46 623
adamstark@51 624 //=======================================================================
adamstark@57 625 void BTrack::predictBeat()
adamstark@46 626 {
adamstark@57 627 int winsize = (int) beatPeriod;
adamstark@54 628 double fcumscore[dfbuffer_size + winsize];
adamstark@54 629 double w2[winsize];
adamstark@46 630 // copy cumscore to first part of fcumscore
adamstark@46 631 for (int i = 0;i < dfbuffer_size;i++)
adamstark@46 632 {
adamstark@46 633 fcumscore[i] = cumscore[i];
adamstark@46 634 }
adamstark@46 635
adamstark@46 636 // create future window
adamstark@54 637 double v = 1;
adamstark@46 638 for (int i = 0;i < winsize;i++)
adamstark@46 639 {
adamstark@57 640 w2[i] = exp((-1*pow((v - (beatPeriod/2)),2)) / (2*pow((beatPeriod/2) ,2)));
adamstark@46 641 v++;
adamstark@46 642 }
adamstark@46 643
adamstark@46 644 // create past window
adamstark@57 645 v = -2*beatPeriod;
adamstark@57 646 int start = dfbuffer_size - round(2*beatPeriod);
adamstark@57 647 int end = dfbuffer_size - round(beatPeriod/2);
adamstark@46 648 int pastwinsize = end-start+1;
adamstark@54 649 double w1[pastwinsize];
adamstark@46 650
adamstark@46 651 for (int i = 0;i < pastwinsize;i++)
adamstark@46 652 {
adamstark@57 653 w1[i] = exp((-1*pow(tightness*log(-v/beatPeriod),2))/2);
adamstark@46 654 v = v+1;
adamstark@46 655 }
adamstark@46 656
adamstark@46 657
adamstark@46 658
adamstark@46 659 // calculate future cumulative score
adamstark@54 660 double max;
adamstark@46 661 int n;
adamstark@54 662 double wcumscore;
adamstark@46 663 for (int i = dfbuffer_size;i < (dfbuffer_size+winsize);i++)
adamstark@46 664 {
adamstark@57 665 start = i - round(2*beatPeriod);
adamstark@57 666 end = i - round(beatPeriod/2);
adamstark@46 667
adamstark@46 668 max = 0;
adamstark@46 669 n = 0;
adamstark@46 670 for (int k=start;k <= end;k++)
adamstark@46 671 {
adamstark@46 672 wcumscore = fcumscore[k]*w1[n];
adamstark@46 673
adamstark@46 674 if (wcumscore > max)
adamstark@46 675 {
adamstark@46 676 max = wcumscore;
adamstark@46 677 }
adamstark@46 678 n++;
adamstark@46 679 }
adamstark@46 680
adamstark@46 681 fcumscore[i] = max;
adamstark@46 682 }
adamstark@46 683
adamstark@46 684
adamstark@46 685 // predict beat
adamstark@46 686 max = 0;
adamstark@46 687 n = 0;
adamstark@46 688
adamstark@46 689 for (int i = dfbuffer_size;i < (dfbuffer_size+winsize);i++)
adamstark@46 690 {
adamstark@46 691 wcumscore = fcumscore[i]*w2[n];
adamstark@46 692
adamstark@46 693 if (wcumscore > max)
adamstark@46 694 {
adamstark@46 695 max = wcumscore;
adamstark@46 696 beat = n;
adamstark@46 697 }
adamstark@46 698
adamstark@46 699 n++;
adamstark@46 700 }
adamstark@46 701
adamstark@46 702 // set next prediction time
adamstark@57 703 m0 = beat+round(beatPeriod/2);
adamstark@46 704
adamstark@46 705
adamstark@46 706 }