annotate dsp/tempotracking/TempoTrackV2.cpp @ 209:ccd2019190bf msvc

Some MSVC fixes, including (temporarily, probably) renaming the FFT source file to avoid getting it mixed up with the Vamp SDK one in our object dir
author Chris Cannam
date Thu, 01 Feb 2018 16:34:08 +0000
parents c32a2446f7fe
children 7e52c034cf62
rev   line source
cannam@52 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@52 2
cannam@52 3 /*
cannam@52 4 QM DSP Library
cannam@52 5
cannam@52 6 Centre for Digital Music, Queen Mary, University of London.
cannam@52 7 This file copyright 2008-2009 Matthew Davies and QMUL.
Chris@84 8
Chris@84 9 This program is free software; you can redistribute it and/or
Chris@84 10 modify it under the terms of the GNU General Public License as
Chris@84 11 published by the Free Software Foundation; either version 2 of the
Chris@84 12 License, or (at your option) any later version. See the file
Chris@84 13 COPYING included with this distribution for more information.
cannam@52 14 */
cannam@52 15
cannam@52 16 #include "TempoTrackV2.h"
cannam@52 17
cannam@52 18 #include <cmath>
cannam@52 19 #include <cstdlib>
cannam@53 20 #include <iostream>
cannam@52 21
cannam@54 22 #include "maths/MathUtilities.h"
cannam@52 23
cannam@52 24 #define EPS 0.0000008 // just some arbitrary small number
cannam@52 25
cannam@54 26 TempoTrackV2::TempoTrackV2(float rate, size_t increment) :
cannam@54 27 m_rate(rate), m_increment(increment) { }
cannam@52 28 TempoTrackV2::~TempoTrackV2() { }
cannam@52 29
cannam@52 30 void
cannam@52 31 TempoTrackV2::filter_df(d_vec_t &df)
cannam@52 32 {
cannam@53 33 d_vec_t a(3);
cannam@53 34 d_vec_t b(3);
cannam@53 35 d_vec_t lp_df(df.size());
cannam@52 36
cannam@53 37 //equivalent in matlab to [b,a] = butter(2,0.4);
cannam@53 38 a[0] = 1.0000;
cannam@53 39 a[1] = -0.3695;
cannam@53 40 a[2] = 0.1958;
cannam@53 41 b[0] = 0.2066;
cannam@53 42 b[1] = 0.4131;
cannam@53 43 b[2] = 0.2066;
luis@100 44
cannam@53 45 double inp1 = 0.;
cannam@53 46 double inp2 = 0.;
cannam@53 47 double out1 = 0.;
cannam@53 48 double out2 = 0.;
cannam@52 49
cannam@52 50
cannam@53 51 // forwards filtering
cannam@70 52 for (unsigned int i = 0;i < df.size();i++)
cannam@53 53 {
cannam@53 54 lp_df[i] = b[0]*df[i] + b[1]*inp1 + b[2]*inp2 - a[1]*out1 - a[2]*out2;
cannam@53 55 inp2 = inp1;
cannam@53 56 inp1 = df[i];
cannam@53 57 out2 = out1;
cannam@53 58 out1 = lp_df[i];
cannam@53 59 }
cannam@52 60
cannam@53 61 // copy forwards filtering to df...
cannam@53 62 // but, time-reversed, ready for backwards filtering
cannam@70 63 for (unsigned int i = 0;i < df.size();i++)
cannam@53 64 {
cannam@53 65 df[i] = lp_df[df.size()-i-1];
cannam@53 66 }
cannam@52 67
cannam@70 68 for (unsigned int i = 0;i < df.size();i++)
cannam@53 69 {
luis@100 70 lp_df[i] = 0.;
cannam@53 71 }
cannam@52 72
cannam@53 73 inp1 = 0.; inp2 = 0.;
cannam@53 74 out1 = 0.; out2 = 0.;
cannam@52 75
cannam@52 76 // backwards filetering on time-reversed df
cannam@70 77 for (unsigned int i = 0;i < df.size();i++)
cannam@53 78 {
cannam@53 79 lp_df[i] = b[0]*df[i] + b[1]*inp1 + b[2]*inp2 - a[1]*out1 - a[2]*out2;
cannam@53 80 inp2 = inp1;
cannam@53 81 inp1 = df[i];
cannam@53 82 out2 = out1;
cannam@53 83 out1 = lp_df[i];
cannam@53 84 }
cannam@52 85
cannam@52 86 // write the re-reversed (i.e. forward) version back to df
cannam@70 87 for (unsigned int i = 0;i < df.size();i++)
cannam@53 88 {
cannam@53 89 df[i] = lp_df[df.size()-i-1];
cannam@53 90 }
cannam@52 91 }
cannam@52 92
cannam@52 93
luis@100 94 // MEPD 28/11/12
luis@100 95 // This function now allows for a user to specify an inputtempo (in BPM)
luis@100 96 // and a flag "constraintempo" which replaces the general rayleigh weighting for periodicities
luis@100 97 // with a gaussian which is centered around the input tempo
luis@100 98 // Note, if inputtempo = 120 and constraintempo = false, then functionality is
luis@100 99 // as it was before
cannam@52 100 void
cannam@79 101 TempoTrackV2::calculateBeatPeriod(const vector<double> &df,
cannam@79 102 vector<double> &beat_period,
luis@100 103 vector<double> &tempi,
luis@100 104 double inputtempo, bool constraintempo)
cannam@52 105 {
cannam@53 106 // to follow matlab.. split into 512 sample frames with a 128 hop size
cannam@53 107 // calculate the acf,
cannam@53 108 // then the rcf.. and then stick the rcfs as columns of a matrix
cannam@53 109 // then call viterbi decoding with weight vector and transition matrix
cannam@53 110 // and get best path
cannam@52 111
cannam@70 112 unsigned int wv_len = 128;
luis@100 113
luis@100 114 // MEPD 28/11/12
luis@100 115 // the default value of inputtempo in the beat tracking plugin is 120
luis@100 116 // so if the user specifies a different inputtempo, the rayparam will be updated
luis@100 117 // accordingly.
luis@100 118 // note: 60*44100/512 is a magic number
luis@100 119 // this might (will?) break if a user specifies a different frame rate for the onset detection function
luis@100 120 double rayparam = (60*44100/512)/inputtempo;
luis@100 121
luis@100 122 // these debug statements can be removed.
Chris@105 123 // std::cerr << "inputtempo" << inputtempo << std::endl;
Chris@105 124 // std::cerr << "rayparam" << rayparam << std::endl;
Chris@105 125 // std::cerr << "constraintempo" << constraintempo << std::endl;
cannam@52 126
cannam@53 127 // make rayleigh weighting curve
cannam@53 128 d_vec_t wv(wv_len);
luis@100 129
luis@100 130 // check whether or not to use rayleigh weighting (if constraintempo is false)
luis@100 131 // or use gaussian weighting it (constraintempo is true)
luis@100 132 if (constraintempo)
cannam@52 133 {
luis@100 134 for (unsigned int i=0; i<wv.size(); i++)
luis@100 135 {
luis@100 136 // MEPD 28/11/12
luis@100 137 // do a gaussian weighting instead of rayleigh
luis@100 138 wv[i] = exp( (-1.*pow((static_cast<double> (i)-rayparam),2.)) / (2.*pow(rayparam/4.,2.)) );
luis@100 139 }
luis@100 140 }
luis@100 141 else
luis@100 142 {
luis@100 143 for (unsigned int i=0; i<wv.size(); i++)
luis@100 144 {
luis@100 145 // MEPD 28/11/12
luis@100 146 // standard rayleigh weighting over periodicities
luis@100 147 wv[i] = (static_cast<double> (i) / pow(rayparam,2.)) * exp((-1.*pow(-static_cast<double> (i),2.)) / (2.*pow(rayparam,2.)));
luis@100 148 }
cannam@52 149 }
cannam@52 150
cannam@53 151 // beat tracking frame size (roughly 6 seconds) and hop (1.5 seconds)
cannam@70 152 unsigned int winlen = 512;
cannam@70 153 unsigned int step = 128;
cannam@53 154
cannam@53 155 // matrix to store output of comb filter bank, increment column of matrix at each frame
cannam@53 156 d_mat_t rcfmat;
cannam@53 157 int col_counter = -1;
cannam@53 158
cannam@53 159 // main loop for beat period calculation
cannam@70 160 for (unsigned int i=0; i+winlen<df.size(); i+=step)
cannam@53 161 {
cannam@53 162 // get dfframe
cannam@53 163 d_vec_t dfframe(winlen);
cannam@70 164 for (unsigned int k=0; k<winlen; k++)
cannam@53 165 {
cannam@53 166 dfframe[k] = df[i+k];
cannam@53 167 }
cannam@53 168 // get rcf vector for current frame
luis@100 169 d_vec_t rcf(wv_len);
cannam@53 170 get_rcf(dfframe,wv,rcf);
luis@100 171
cannam@53 172 rcfmat.push_back( d_vec_t() ); // adds a new column
cannam@53 173 col_counter++;
cannam@70 174 for (unsigned int j=0; j<rcf.size(); j++)
cannam@53 175 {
cannam@53 176 rcfmat[col_counter].push_back( rcf[j] );
cannam@53 177 }
cannam@53 178 }
luis@100 179
cannam@53 180 // now call viterbi decoding function
cannam@53 181 viterbi_decode(rcfmat,wv,beat_period,tempi);
cannam@52 182 }
cannam@52 183
cannam@52 184
cannam@52 185 void
cannam@52 186 TempoTrackV2::get_rcf(const d_vec_t &dfframe_in, const d_vec_t &wv, d_vec_t &rcf)
cannam@52 187 {
cannam@53 188 // calculate autocorrelation function
cannam@53 189 // then rcf
cannam@53 190 // just hard code for now... don't really need separate functions to do this
cannam@52 191
cannam@53 192 // make acf
cannam@52 193
cannam@53 194 d_vec_t dfframe(dfframe_in);
cannam@52 195
cannam@54 196 MathUtilities::adaptiveThreshold(dfframe);
cannam@52 197
cannam@53 198 d_vec_t acf(dfframe.size());
cannam@52 199
luis@100 200
cannam@70 201 for (unsigned int lag=0; lag<dfframe.size(); lag++)
cannam@53 202 {
cannam@53 203 double sum = 0.;
cannam@53 204 double tmp = 0.;
cannam@52 205
cannam@70 206 for (unsigned int n=0; n<(dfframe.size()-lag); n++)
cannam@53 207 {
luis@100 208 tmp = dfframe[n] * dfframe[n+lag];
cannam@53 209 sum += tmp;
cannam@53 210 }
cannam@53 211 acf[lag] = static_cast<double> (sum/ (dfframe.size()-lag));
cannam@53 212 }
cannam@52 213
cannam@53 214 // now apply comb filtering
cannam@53 215 int numelem = 4;
luis@100 216
cannam@70 217 for (unsigned int i = 2;i < rcf.size();i++) // max beat period
cannam@53 218 {
cannam@53 219 for (int a = 1;a <= numelem;a++) // number of comb elements
cannam@53 220 {
cannam@53 221 for (int b = 1-a;b <= a-1;b++) // general state using normalisation of comb elements
cannam@53 222 {
cannam@53 223 rcf[i-1] += ( acf[(a*i+b)-1]*wv[i-1] ) / (2.*a-1.); // calculate value for comb filter row
cannam@53 224 }
cannam@53 225 }
cannam@53 226 }
luis@100 227
cannam@53 228 // apply adaptive threshold to rcf
cannam@54 229 MathUtilities::adaptiveThreshold(rcf);
luis@100 230
cannam@53 231 double rcfsum =0.;
cannam@70 232 for (unsigned int i=0; i<rcf.size(); i++)
cannam@53 233 {
cannam@53 234 rcf[i] += EPS ;
cannam@53 235 rcfsum += rcf[i];
cannam@53 236 }
cannam@52 237
cannam@53 238 // normalise rcf to sum to unity
cannam@70 239 for (unsigned int i=0; i<rcf.size(); i++)
cannam@52 240 {
cannam@53 241 rcf[i] /= (rcfsum + EPS);
cannam@52 242 }
cannam@52 243 }
cannam@52 244
cannam@52 245 void
cannam@53 246 TempoTrackV2::viterbi_decode(const d_mat_t &rcfmat, const d_vec_t &wv, d_vec_t &beat_period, d_vec_t &tempi)
cannam@52 247 {
cannam@53 248 // following Kevin Murphy's Viterbi decoding to get best path of
cannam@53 249 // beat periods through rfcmat
cannam@52 250
cannam@53 251 // make transition matrix
cannam@53 252 d_mat_t tmat;
cannam@70 253 for (unsigned int i=0;i<wv.size();i++)
cannam@53 254 {
cannam@53 255 tmat.push_back ( d_vec_t() ); // adds a new column
cannam@70 256 for (unsigned int j=0; j<wv.size(); j++)
luis@100 257 {
cannam@53 258 tmat[i].push_back(0.); // fill with zeros initially
cannam@53 259 }
cannam@53 260 }
luis@100 261
cannam@53 262 // variance of Gaussians in transition matrix
cannam@53 263 // formed of Gaussians on diagonal - implies slow tempo change
cannam@53 264 double sigma = 8.;
cannam@53 265 // don't want really short beat periods, or really long ones
cannam@70 266 for (unsigned int i=20;i <wv.size()-20; i++)
cannam@53 267 {
cannam@70 268 for (unsigned int j=20; j<wv.size()-20; j++)
luis@100 269 {
cannam@53 270 double mu = static_cast<double>(i);
cannam@53 271 tmat[i][j] = exp( (-1.*pow((j-mu),2.)) / (2.*pow(sigma,2.)) );
cannam@53 272 }
cannam@53 273 }
cannam@52 274
cannam@53 275 // parameters for Viterbi decoding... this part is taken from
cannam@53 276 // Murphy's matlab
cannam@52 277
cannam@53 278 d_mat_t delta;
cannam@53 279 i_mat_t psi;
cannam@70 280 for (unsigned int i=0;i <rcfmat.size(); i++)
cannam@53 281 {
cannam@53 282 delta.push_back( d_vec_t());
cannam@53 283 psi.push_back( i_vec_t());
cannam@70 284 for (unsigned int j=0; j<rcfmat[i].size(); j++)
luis@100 285 {
cannam@53 286 delta[i].push_back(0.); // fill with zeros initially
cannam@53 287 psi[i].push_back(0); // fill with zeros initially
cannam@53 288 }
cannam@53 289 }
cannam@52 290
cannam@52 291
cannam@70 292 unsigned int T = delta.size();
cannam@56 293
cannam@56 294 if (T < 2) return; // can't do anything at all meaningful
cannam@56 295
cannam@70 296 unsigned int Q = delta[0].size();
cannam@52 297
cannam@53 298 // initialize first column of delta
cannam@70 299 for (unsigned int j=0; j<Q; j++)
cannam@52 300 {
cannam@53 301 delta[0][j] = wv[j] * rcfmat[0][j];
cannam@53 302 psi[0][j] = 0;
cannam@52 303 }
luis@100 304
cannam@52 305 double deltasum = 0.;
cannam@70 306 for (unsigned int i=0; i<Q; i++)
cannam@52 307 {
cannam@53 308 deltasum += delta[0][i];
luis@100 309 }
cannam@70 310 for (unsigned int i=0; i<Q; i++)
cannam@52 311 {
cannam@53 312 delta[0][i] /= (deltasum + EPS);
luis@100 313 }
cannam@52 314
cannam@52 315
cannam@70 316 for (unsigned int t=1; t<T; t++)
cannam@53 317 {
cannam@53 318 d_vec_t tmp_vec(Q);
cannam@52 319
cannam@70 320 for (unsigned int j=0; j<Q; j++)
cannam@53 321 {
cannam@70 322 for (unsigned int i=0; i<Q; i++)
cannam@53 323 {
cannam@53 324 tmp_vec[i] = delta[t-1][i] * tmat[j][i];
luis@100 325 }
luis@100 326
luis@100 327 delta[t][j] = get_max_val(tmp_vec);
cannam@52 328
cannam@53 329 psi[t][j] = get_max_ind(tmp_vec);
luis@100 330
cannam@53 331 delta[t][j] *= rcfmat[t][j];
cannam@53 332 }
cannam@52 333
cannam@53 334 // normalise current delta column
cannam@53 335 double deltasum = 0.;
cannam@70 336 for (unsigned int i=0; i<Q; i++)
cannam@53 337 {
cannam@53 338 deltasum += delta[t][i];
luis@100 339 }
cannam@70 340 for (unsigned int i=0; i<Q; i++)
cannam@53 341 {
cannam@53 342 delta[t][i] /= (deltasum + EPS);
luis@100 343 }
cannam@53 344 }
cannam@52 345
cannam@53 346 i_vec_t bestpath(T);
cannam@53 347 d_vec_t tmp_vec(Q);
cannam@70 348 for (unsigned int i=0; i<Q; i++)
luis@100 349 {
cannam@53 350 tmp_vec[i] = delta[T-1][i];
cannam@53 351 }
cannam@52 352
cannam@53 353 // find starting point - best beat period for "last" frame
cannam@53 354 bestpath[T-1] = get_max_ind(tmp_vec);
luis@100 355
cannam@53 356 // backtrace through index of maximum values in psi
cannam@70 357 for (unsigned int t=T-2; t>0 ;t--)
cannam@53 358 {
cannam@53 359 bestpath[t] = psi[t+1][bestpath[t+1]];
cannam@53 360 }
cannam@52 361
cannam@53 362 // weird but necessary hack -- couldn't get above loop to terminate at t >= 0
cannam@53 363 bestpath[0] = psi[1][bestpath[1]];
cannam@52 364
cannam@70 365 unsigned int lastind = 0;
cannam@70 366 for (unsigned int i=0; i<T; i++)
luis@100 367 {
cannam@70 368 unsigned int step = 128;
cannam@70 369 for (unsigned int j=0; j<step; j++)
cannam@53 370 {
cannam@53 371 lastind = i*step+j;
cannam@53 372 beat_period[lastind] = bestpath[i];
cannam@53 373 }
cannam@57 374 // std::cerr << "bestpath[" << i << "] = " << bestpath[i] << " (used for beat_periods " << i*step << " to " << i*step+step-1 << ")" << std::endl;
cannam@53 375 }
cannam@52 376
cannam@53 377 //fill in the last values...
cannam@70 378 for (unsigned int i=lastind; i<beat_period.size(); i++)
cannam@53 379 {
cannam@53 380 beat_period[i] = beat_period[lastind];
cannam@53 381 }
cannam@52 382
cannam@70 383 for (unsigned int i = 0; i < beat_period.size(); i++)
cannam@52 384 {
cannam@54 385 tempi.push_back((60. * m_rate / m_increment)/beat_period[i]);
cannam@52 386 }
cannam@52 387 }
cannam@52 388
cannam@52 389 double
cannam@52 390 TempoTrackV2::get_max_val(const d_vec_t &df)
cannam@52 391 {
cannam@53 392 double maxval = 0.;
cannam@70 393 for (unsigned int i=0; i<df.size(); i++)
cannam@52 394 {
cannam@53 395 if (maxval < df[i])
cannam@53 396 {
cannam@53 397 maxval = df[i];
cannam@53 398 }
cannam@52 399 }
luis@100 400
cannam@53 401 return maxval;
cannam@52 402 }
cannam@52 403
cannam@52 404 int
cannam@52 405 TempoTrackV2::get_max_ind(const d_vec_t &df)
cannam@52 406 {
cannam@53 407 double maxval = 0.;
cannam@53 408 int ind = 0;
cannam@70 409 for (unsigned int i=0; i<df.size(); i++)
cannam@52 410 {
cannam@53 411 if (maxval < df[i])
cannam@53 412 {
cannam@53 413 maxval = df[i];
cannam@53 414 ind = i;
cannam@53 415 }
cannam@52 416 }
luis@100 417
cannam@53 418 return ind;
cannam@52 419 }
cannam@52 420
cannam@52 421 void
cannam@52 422 TempoTrackV2::normalise_vec(d_vec_t &df)
cannam@52 423 {
cannam@53 424 double sum = 0.;
cannam@70 425 for (unsigned int i=0; i<df.size(); i++)
cannam@53 426 {
cannam@53 427 sum += df[i];
cannam@53 428 }
luis@100 429
cannam@70 430 for (unsigned int i=0; i<df.size(); i++)
cannam@53 431 {
cannam@53 432 df[i]/= (sum + EPS);
cannam@53 433 }
cannam@52 434 }
cannam@52 435
luis@100 436 // MEPD 28/11/12
luis@100 437 // this function has been updated to allow the "alpha" and "tightness" parameters
luis@100 438 // of the dynamic program to be set by the user
luis@100 439 // the default value of alpha = 0.9 and tightness = 4
cannam@52 440 void
cannam@79 441 TempoTrackV2::calculateBeats(const vector<double> &df,
cannam@79 442 const vector<double> &beat_period,
luis@100 443 vector<double> &beats, double alpha, double tightness)
cannam@52 444 {
cannam@56 445 if (df.empty() || beat_period.empty()) return;
cannam@56 446
cannam@53 447 d_vec_t cumscore(df.size()); // store cumulative score
cannam@53 448 i_vec_t backlink(df.size()); // backlink (stores best beat locations at each time instant)
cannam@53 449 d_vec_t localscore(df.size()); // localscore, for now this is the same as the detection function
cannam@52 450
cannam@70 451 for (unsigned int i=0; i<df.size(); i++)
cannam@52 452 {
cannam@53 453 localscore[i] = df[i];
cannam@53 454 backlink[i] = -1;
cannam@52 455 }
cannam@52 456
luis@100 457 //double tightness = 4.;
luis@100 458 //double alpha = 0.9;
luis@100 459 // MEPD 28/11/12
luis@100 460 // debug statements that can be removed.
Chris@105 461 // std::cerr << "alpha" << alpha << std::endl;
Chris@105 462 // std::cerr << "tightness" << tightness << std::endl;
cannam@52 463
cannam@53 464 // main loop
cannam@70 465 for (unsigned int i=0; i<localscore.size(); i++)
cannam@53 466 {
cannam@53 467 int prange_min = -2*beat_period[i];
cannam@53 468 int prange_max = round(-0.5*beat_period[i]);
cannam@52 469
cannam@53 470 // transition range
cannam@53 471 d_vec_t txwt (prange_max - prange_min + 1);
cannam@53 472 d_vec_t scorecands (txwt.size());
cannam@52 473
cannam@70 474 for (unsigned int j=0;j<txwt.size();j++)
cannam@53 475 {
cannam@53 476 double mu = static_cast<double> (beat_period[i]);
cannam@53 477 txwt[j] = exp( -0.5*pow(tightness * log((round(2*mu)-j)/mu),2));
cannam@52 478
cannam@53 479 // IF IN THE ALLOWED RANGE, THEN LOOK AT CUMSCORE[I+PRANGE_MIN+J
cannam@53 480 // ELSE LEAVE AT DEFAULT VALUE FROM INITIALISATION: D_VEC_T SCORECANDS (TXWT.SIZE());
cannam@52 481
cannam@53 482 int cscore_ind = i+prange_min+j;
luis@100 483 if (cscore_ind >= 0)
cannam@53 484 {
cannam@53 485 scorecands[j] = txwt[j] * cumscore[cscore_ind];
cannam@53 486 }
cannam@53 487 }
cannam@52 488
cannam@53 489 // find max value and index of maximum value
cannam@53 490 double vv = get_max_val(scorecands);
cannam@53 491 int xx = get_max_ind(scorecands);
cannam@52 492
cannam@53 493 cumscore[i] = alpha*vv + (1.-alpha)*localscore[i];
cannam@53 494 backlink[i] = i+prange_min+xx;
cannam@55 495
cannam@57 496 // std::cerr << "backlink[" << i << "] <= " << backlink[i] << std::endl;
cannam@53 497 }
cannam@53 498
cannam@53 499 // STARTING POINT, I.E. LAST BEAT.. PICK A STRONG POINT IN cumscore VECTOR
cannam@53 500 d_vec_t tmp_vec;
cannam@70 501 for (unsigned int i=cumscore.size() - beat_period[beat_period.size()-1] ; i<cumscore.size(); i++)
cannam@53 502 {
cannam@53 503 tmp_vec.push_back(cumscore[i]);
luis@100 504 }
cannam@53 505
cannam@53 506 int startpoint = get_max_ind(tmp_vec) + cumscore.size() - beat_period[beat_period.size()-1] ;
cannam@53 507
cannam@56 508 // can happen if no results obtained earlier (e.g. input too short)
Chris@102 509 if (startpoint >= (int)backlink.size()) startpoint = backlink.size()-1;
cannam@56 510
cannam@53 511 // USE BACKLINK TO GET EACH NEW BEAT (TOWARDS THE BEGINNING OF THE FILE)
cannam@53 512 // BACKTRACKING FROM THE END TO THE BEGINNING.. MAKING SURE NOT TO GO BEFORE SAMPLE 0
cannam@53 513 i_vec_t ibeats;
cannam@53 514 ibeats.push_back(startpoint);
cannam@57 515 // std::cerr << "startpoint = " << startpoint << std::endl;
cannam@53 516 while (backlink[ibeats.back()] > 0)
cannam@53 517 {
cannam@57 518 // std::cerr << "backlink[" << ibeats.back() << "] = " << backlink[ibeats.back()] << std::endl;
cannam@56 519 int b = ibeats.back();
cannam@56 520 if (backlink[b] == b) break; // shouldn't happen... haha
cannam@56 521 ibeats.push_back(backlink[b]);
cannam@53 522 }
luis@100 523
cannam@53 524 // REVERSE SEQUENCE OF IBEATS AND STORE AS BEATS
cannam@70 525 for (unsigned int i=0; i<ibeats.size(); i++)
luis@100 526 {
cannam@53 527 beats.push_back( static_cast<double>(ibeats[ibeats.size()-i-1]) );
cannam@53 528 }
cannam@52 529 }
cannam@52 530
cannam@52 531