annotate dsp/tempotracking/TempoTrack.cpp @ 68:09aba2ccd94a

* Fix race condition
author cannam
date Mon, 18 May 2009 15:44:03 +0000
parents 38bf09927942
children e5907ae6de17
rev   line source
cannam@39 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@39 2
cannam@39 3 /*
cannam@39 4 QM DSP Library
cannam@39 5
cannam@39 6 Centre for Digital Music, Queen Mary, University of London.
cannam@68 7 This file copyright 2005-2006 Christian Landone and Matthew Davies.
cannam@39 8 All rights reserved.
cannam@39 9 */
cannam@39 10
cannam@39 11 #include "TempoTrack.h"
cannam@39 12
cannam@39 13 #include "maths/MathAliases.h"
cannam@39 14 #include "maths/MathUtilities.h"
cannam@39 15
cannam@39 16 #include <iostream>
cannam@39 17
cannam@46 18 #include <cassert>
cannam@46 19
cannam@47 20 //#define DEBUG_TEMPO_TRACK 1
cannam@47 21
cannam@39 22
cannam@39 23 #define RAY43VAL
cannam@39 24
cannam@39 25 //////////////////////////////////////////////////////////////////////
cannam@39 26 // Construction/Destruction
cannam@39 27 //////////////////////////////////////////////////////////////////////
cannam@39 28
cannam@39 29 TempoTrack::TempoTrack( TTParams Params )
cannam@39 30 {
cannam@39 31 m_tempoScratch = NULL;
cannam@39 32 m_rawDFFrame = NULL;
cannam@39 33 m_smoothDFFrame = NULL;
cannam@39 34 m_frameACF = NULL;
cannam@39 35 m_smoothRCF = NULL;
cannam@39 36
cannam@39 37 m_dataLength = 0;
cannam@39 38 m_winLength = 0;
cannam@39 39 m_lagLength = 0;
cannam@39 40
cannam@39 41 m_rayparam = 0;
cannam@39 42 m_sigma = 0;
cannam@39 43 m_DFWVNnorm = 0;
cannam@39 44
cannam@39 45 initialise( Params );
cannam@39 46 }
cannam@39 47
cannam@39 48 TempoTrack::~TempoTrack()
cannam@39 49 {
cannam@39 50 deInitialise();
cannam@39 51 }
cannam@39 52
cannam@39 53 void TempoTrack::initialise( TTParams Params )
cannam@39 54 {
cannam@39 55 m_winLength = Params.winLength;
cannam@39 56 m_lagLength = Params.lagLength;
cannam@39 57
cannam@39 58 m_rayparam = 43.0;
cannam@39 59 m_sigma = sqrt(3.9017);
cannam@39 60 m_DFWVNnorm = exp( ( log( 2.0 ) / m_rayparam ) * ( m_winLength + 2 ) );
cannam@39 61
cannam@39 62 m_rawDFFrame = new double[ m_winLength ];
cannam@39 63 m_smoothDFFrame = new double[ m_winLength ];
cannam@39 64 m_frameACF = new double[ m_winLength ];
cannam@39 65 m_tempoScratch = new double[ m_lagLength ];
cannam@39 66 m_smoothRCF = new double[ m_lagLength ];
cannam@39 67
cannam@39 68
cannam@39 69 unsigned int winPre = Params.WinT.pre;
cannam@39 70 unsigned int winPost = Params.WinT.post;
cannam@39 71
cannam@39 72 m_DFFramer.configure( m_winLength, m_lagLength );
cannam@39 73
cannam@39 74 m_DFPParams.length = m_winLength;
cannam@39 75 m_DFPParams.AlphaNormParam = Params.alpha;
cannam@39 76 m_DFPParams.LPOrd = Params.LPOrd;
cannam@39 77 m_DFPParams.LPACoeffs = Params.LPACoeffs;
cannam@39 78 m_DFPParams.LPBCoeffs = Params.LPBCoeffs;
cannam@39 79 m_DFPParams.winPre = Params.WinT.pre;
cannam@39 80 m_DFPParams.winPost = Params.WinT.post;
cannam@39 81 m_DFPParams.isMedianPositive = true;
cannam@39 82
cannam@39 83 m_DFConditioning = new DFProcess( m_DFPParams );
cannam@39 84
cannam@39 85
cannam@39 86 // these are parameters for smoothing m_tempoScratch
cannam@39 87 m_RCFPParams.length = m_lagLength;
cannam@39 88 m_RCFPParams.AlphaNormParam = Params.alpha;
cannam@39 89 m_RCFPParams.LPOrd = Params.LPOrd;
cannam@39 90 m_RCFPParams.LPACoeffs = Params.LPACoeffs;
cannam@39 91 m_RCFPParams.LPBCoeffs = Params.LPBCoeffs;
cannam@39 92 m_RCFPParams.winPre = Params.WinT.pre;
cannam@39 93 m_RCFPParams.winPost = Params.WinT.post;
cannam@39 94 m_RCFPParams.isMedianPositive = true;
cannam@39 95
cannam@39 96 m_RCFConditioning = new DFProcess( m_RCFPParams );
cannam@39 97
cannam@39 98 }
cannam@39 99
cannam@39 100 void TempoTrack::deInitialise()
cannam@39 101 {
cannam@39 102 delete [] m_rawDFFrame;
cannam@39 103
cannam@39 104 delete [] m_smoothDFFrame;
cannam@39 105
cannam@39 106 delete [] m_smoothRCF;
cannam@39 107
cannam@39 108 delete [] m_frameACF;
cannam@39 109
cannam@39 110 delete [] m_tempoScratch;
cannam@39 111
cannam@39 112 delete m_DFConditioning;
cannam@39 113
cannam@39 114 delete m_RCFConditioning;
cannam@39 115
cannam@39 116 }
cannam@39 117
cannam@39 118 void TempoTrack::createCombFilter(double* Filter, unsigned int winLength, unsigned int TSig, double beatLag)
cannam@39 119 {
cannam@39 120 unsigned int i;
cannam@39 121
cannam@39 122 if( beatLag == 0 )
cannam@39 123 {
cannam@39 124 for( i = 0; i < winLength; i++ )
cannam@39 125 {
cannam@39 126 Filter[ i ] = ( ( i + 1 ) / pow( m_rayparam, 2.0) ) * exp( ( -pow(( i + 1 ),2.0 ) / ( 2.0 * pow( m_rayparam, 2.0))));
cannam@39 127 }
cannam@39 128 }
cannam@39 129 else
cannam@39 130 {
cannam@39 131 m_sigma = beatLag/4;
cannam@39 132 for( i = 0; i < winLength; i++ )
cannam@39 133 {
cannam@39 134 double dlag = (double)(i+1) - beatLag;
cannam@39 135 Filter[ i ] = exp(-0.5 * pow(( dlag / m_sigma), 2.0) ) / (sqrt( 2 * PI) * m_sigma);
cannam@39 136 }
cannam@39 137 }
cannam@39 138 }
cannam@39 139
cannam@39 140 double TempoTrack::tempoMM(double* ACF, double* weight, int tsig)
cannam@39 141 {
cannam@39 142
cannam@39 143 double period = 0;
cannam@39 144 double maxValRCF = 0.0;
cannam@39 145 unsigned int maxIndexRCF = 0;
cannam@39 146
cannam@39 147 double* pdPeaks;
cannam@39 148
cannam@39 149 unsigned int maxIndexTemp;
cannam@39 150 double maxValTemp;
cannam@39 151 unsigned int count;
cannam@39 152
cannam@39 153 unsigned int numelem,i,j;
cannam@39 154 int a, b;
cannam@39 155
cannam@39 156 for( i = 0; i < m_lagLength; i++ )
cannam@39 157 m_tempoScratch[ i ] = 0.0;
cannam@39 158
cannam@39 159 if( tsig == 0 )
cannam@39 160 {
cannam@39 161 //if time sig is unknown, use metrically unbiased version of Filterbank
cannam@39 162 numelem = 4;
cannam@39 163 }
cannam@39 164 else
cannam@39 165 {
cannam@39 166 numelem = tsig;
cannam@39 167 }
cannam@39 168
cannam@47 169 #ifdef DEBUG_TEMPO_TRACK
cannam@46 170 std::cerr << "tempoMM: m_winLength = " << m_winLength << ", m_lagLength = " << m_lagLength << ", numelem = " << numelem << std::endl;
cannam@47 171 #endif
cannam@46 172
cannam@39 173 for(i=1;i<m_lagLength-1;i++)
cannam@39 174 {
cannam@39 175 //first and last output values are left intentionally as zero
cannam@39 176 for (a=1;a<=numelem;a++)
cannam@39 177 {
cannam@39 178 for(b=(1-a);b<a;b++)
cannam@39 179 {
cannam@39 180 if( tsig == 0 )
cannam@39 181 {
cannam@39 182 m_tempoScratch[i] += ACF[a*(i+1)+b-1] * (1.0 / (2.0 * (double)a-1)) * weight[i];
cannam@39 183 }
cannam@39 184 else
cannam@39 185 {
cannam@39 186 m_tempoScratch[i] += ACF[a*(i+1)+b-1] * 1 * weight[i];
cannam@39 187 }
cannam@39 188 }
cannam@39 189 }
cannam@39 190 }
cannam@39 191
cannam@39 192
cannam@39 193 //////////////////////////////////////////////////
cannam@39 194 // MODIFIED BEAT PERIOD EXTRACTION //////////////
cannam@39 195 /////////////////////////////////////////////////
cannam@39 196
cannam@39 197 // find smoothed version of RCF ( as applied to Detection Function)
cannam@39 198 m_RCFConditioning->process( m_tempoScratch, m_smoothRCF);
cannam@39 199
cannam@39 200 if (tsig != 0) // i.e. in context dependent state
cannam@39 201 {
cannam@39 202 // NOW FIND MAX INDEX OF ACFOUT
cannam@46 203 for( i = 0; i < m_lagLength; i++)
cannam@46 204 {
cannam@46 205 if( m_tempoScratch[ i ] > maxValRCF)
cannam@46 206 {
cannam@46 207 maxValRCF = m_tempoScratch[ i ];
cannam@46 208 maxIndexRCF = i;
cannam@46 209 }
cannam@46 210 }
cannam@39 211 }
cannam@39 212 else // using rayleigh weighting
cannam@39 213 {
cannam@39 214 vector <vector<double> > rcfMat;
cannam@39 215
cannam@39 216 double sumRcf = 0.;
cannam@39 217
cannam@39 218 double maxVal = 0.;
cannam@39 219 // now find the two values which minimise rcfMat
cannam@39 220 double minVal = 0.;
cannam@39 221 int p_i = 1; // periodicity for row i;
cannam@39 222 int p_j = 1; //periodicity for column j;
cannam@39 223
cannam@39 224
cannam@39 225 for ( i=0; i<m_lagLength; i++)
cannam@39 226 {
cannam@39 227 m_tempoScratch[i] =m_smoothRCF[i];
cannam@39 228 }
cannam@39 229
cannam@39 230 // normalise m_tempoScratch so that it sums to zero.
cannam@39 231 for ( i=0; i<m_lagLength; i++)
cannam@39 232 {
cannam@39 233 sumRcf += m_tempoScratch[i];
cannam@39 234 }
cannam@39 235
cannam@39 236 for( i=0; i<m_lagLength; i++)
cannam@39 237 {
cannam@39 238 m_tempoScratch[i] /= sumRcf;
cannam@39 239 }
cannam@39 240
cannam@39 241 // create a matrix to store m_tempoScratchValues modified by log2 ratio
cannam@39 242 for ( i=0; i<m_lagLength; i++)
cannam@39 243 {
cannam@39 244 rcfMat.push_back ( vector<double>() ); // adds a new row...
cannam@39 245 }
cannam@39 246
cannam@39 247 for (i=0; i<m_lagLength; i++)
cannam@39 248 {
cannam@39 249 for (j=0; j<m_lagLength; j++)
cannam@39 250 {
cannam@39 251 rcfMat[i].push_back (0.);
cannam@39 252 }
cannam@39 253 }
cannam@39 254
cannam@39 255 // the 'i' and 'j' indices deliberately start from '1' and not '0'
cannam@39 256 for ( i=1; i<m_lagLength; i++)
cannam@39 257 {
cannam@39 258 for (j=1; j<m_lagLength; j++)
cannam@39 259 {
cannam@39 260 double log2PeriodRatio = log( static_cast<double>(i)/static_cast<double>(j) ) / log(2.0);
cannam@39 261 rcfMat[i][j] = ( abs(1.0-abs(log2PeriodRatio)) );
cannam@39 262 rcfMat[i][j] += ( 0.01*( 1./(m_tempoScratch[i]+m_tempoScratch[j]) ) );
cannam@39 263 }
cannam@39 264 }
cannam@39 265
cannam@39 266 // set diagonal equal to maximum value in rcfMat
cannam@39 267 // we don't want to pick one strong middle peak - we need a combination of two peaks.
cannam@39 268
cannam@39 269 for ( i=1; i<m_lagLength; i++)
cannam@39 270 {
cannam@39 271 for (j=1; j<m_lagLength; j++)
cannam@39 272 {
cannam@39 273 if (rcfMat[i][j] > maxVal)
cannam@39 274 {
cannam@39 275 maxVal = rcfMat[i][j];
cannam@39 276 }
cannam@39 277 }
cannam@39 278 }
cannam@39 279
cannam@39 280 for ( i=1; i<m_lagLength; i++)
cannam@39 281 {
cannam@39 282 rcfMat[i][i] = maxVal;
cannam@39 283 }
cannam@39 284
cannam@39 285 // now find the row and column number which minimise rcfMat
cannam@39 286 minVal = maxVal;
cannam@39 287
cannam@39 288 for ( i=1; i<m_lagLength; i++)
cannam@39 289 {
cannam@39 290 for ( j=1; j<m_lagLength; j++)
cannam@39 291 {
cannam@39 292 if (rcfMat[i][j] < minVal)
cannam@39 293 {
cannam@39 294 minVal = rcfMat[i][j];
cannam@39 295 p_i = i;
cannam@39 296 p_j = j;
cannam@39 297 }
cannam@39 298 }
cannam@39 299 }
cannam@39 300
cannam@39 301
cannam@39 302 // initially choose p_j (arbitrary) - saves on an else statement
cannam@39 303 int beatPeriod = p_j;
cannam@39 304 if (m_tempoScratch[p_i] > m_tempoScratch[p_j])
cannam@39 305 {
cannam@39 306 beatPeriod = p_i;
cannam@39 307 }
cannam@39 308
cannam@39 309 // now write the output
cannam@39 310 maxIndexRCF = static_cast<int>(beatPeriod);
cannam@39 311 }
cannam@39 312
cannam@39 313
cannam@39 314 double locked = 5168.f / maxIndexRCF;
cannam@39 315 if (locked >= 30 && locked <= 180) {
cannam@39 316 m_lockedTempo = locked;
cannam@39 317 }
cannam@39 318
cannam@47 319 #ifdef DEBUG_TEMPO_TRACK
cannam@47 320 std::cerr << "tempoMM: locked tempo = " << m_lockedTempo << std::endl;
cannam@47 321 #endif
cannam@47 322
cannam@39 323 if( tsig == 0 )
cannam@39 324 tsig = 4;
cannam@39 325
cannam@46 326
cannam@47 327 #ifdef DEBUG_TEMPO_TRACK
cannam@46 328 std::cerr << "tempoMM: maxIndexRCF = " << maxIndexRCF << std::endl;
cannam@47 329 #endif
cannam@39 330
cannam@39 331 if( tsig == 4 )
cannam@39 332 {
cannam@47 333 #ifdef DEBUG_TEMPO_TRACK
cannam@47 334 std::cerr << "tsig == 4" << std::endl;
cannam@47 335 #endif
cannam@47 336
cannam@39 337 pdPeaks = new double[ 4 ];
cannam@39 338 for( i = 0; i < 4; i++ ){ pdPeaks[ i ] = 0.0;}
cannam@39 339
cannam@39 340 pdPeaks[ 0 ] = ( double )maxIndexRCF + 1;
cannam@39 341
cannam@39 342 maxIndexTemp = 0;
cannam@39 343 maxValTemp = 0.0;
cannam@39 344 count = 0;
cannam@39 345
cannam@39 346 for( i = (2 * maxIndexRCF + 1) - 1; i < (2 * maxIndexRCF + 1) + 2; i++ )
cannam@39 347 {
cannam@39 348 if( ACF[ i ] > maxValTemp )
cannam@39 349 {
cannam@39 350 maxValTemp = ACF[ i ];
cannam@39 351 maxIndexTemp = count;
cannam@39 352 }
cannam@39 353 count++;
cannam@39 354 }
cannam@39 355 pdPeaks[ 1 ] = (double)( maxIndexTemp + 1 + ( (2 * maxIndexRCF + 1 ) - 2 ) + 1 )/2;
cannam@39 356
cannam@39 357 maxIndexTemp = 0;
cannam@39 358 maxValTemp = 0.0;
cannam@39 359 count = 0;
cannam@39 360
cannam@39 361 for( i = (3 * maxIndexRCF + 2 ) - 2; i < (3 * maxIndexRCF + 2 ) + 3; i++ )
cannam@39 362 {
cannam@39 363 if( ACF[ i ] > maxValTemp )
cannam@39 364 {
cannam@39 365 maxValTemp = ACF[ i ];
cannam@39 366 maxIndexTemp = count;
cannam@39 367 }
cannam@39 368 count++;
cannam@39 369 }
cannam@39 370 pdPeaks[ 2 ] = (double)( maxIndexTemp + 1 + ( (3 * maxIndexRCF + 2) - 4 ) + 1 )/3;
cannam@39 371
cannam@39 372 maxIndexTemp = 0;
cannam@39 373 maxValTemp = 0.0;
cannam@39 374 count = 0;
cannam@39 375
cannam@39 376 for( i = ( 4 * maxIndexRCF + 3) - 3; i < ( 4 * maxIndexRCF + 3) + 4; i++ )
cannam@39 377 {
cannam@39 378 if( ACF[ i ] > maxValTemp )
cannam@39 379 {
cannam@39 380 maxValTemp = ACF[ i ];
cannam@39 381 maxIndexTemp = count;
cannam@39 382 }
cannam@39 383 count++;
cannam@39 384 }
cannam@39 385 pdPeaks[ 3 ] = (double)( maxIndexTemp + 1 + ( (4 * maxIndexRCF + 3) - 9 ) + 1 )/4 ;
cannam@39 386
cannam@39 387
cannam@39 388 period = MathUtilities::mean( pdPeaks, 4 );
cannam@39 389 }
cannam@39 390 else
cannam@47 391 {
cannam@47 392 #ifdef DEBUG_TEMPO_TRACK
cannam@47 393 std::cerr << "tsig != 4" << std::endl;
cannam@47 394 #endif
cannam@47 395
cannam@39 396 pdPeaks = new double[ 3 ];
cannam@39 397 for( i = 0; i < 3; i++ ){ pdPeaks[ i ] = 0.0;}
cannam@39 398
cannam@39 399 pdPeaks[ 0 ] = ( double )maxIndexRCF + 1;
cannam@39 400
cannam@39 401 maxIndexTemp = 0;
cannam@39 402 maxValTemp = 0.0;
cannam@39 403 count = 0;
cannam@39 404
cannam@39 405 for( i = (2 * maxIndexRCF + 1) - 1; i < (2 * maxIndexRCF + 1) + 2; i++ )
cannam@39 406 {
cannam@39 407 if( ACF[ i ] > maxValTemp )
cannam@39 408 {
cannam@39 409 maxValTemp = ACF[ i ];
cannam@39 410 maxIndexTemp = count;
cannam@39 411 }
cannam@39 412 count++;
cannam@39 413 }
cannam@39 414 pdPeaks[ 1 ] = (double)( maxIndexTemp + 1 + ( (2 * maxIndexRCF + 1 ) - 2 ) + 1 )/2;
cannam@39 415
cannam@39 416 maxIndexTemp = 0;
cannam@39 417 maxValTemp = 0.0;
cannam@39 418 count = 0;
cannam@39 419
cannam@39 420 for( i = (3 * maxIndexRCF + 2 ) - 2; i < (3 * maxIndexRCF + 2 ) + 3; i++ )
cannam@39 421 {
cannam@39 422 if( ACF[ i ] > maxValTemp )
cannam@39 423 {
cannam@39 424 maxValTemp = ACF[ i ];
cannam@39 425 maxIndexTemp = count;
cannam@39 426 }
cannam@39 427 count++;
cannam@39 428 }
cannam@39 429 pdPeaks[ 2 ] = (double)( maxIndexTemp + 1 + ( (3 * maxIndexRCF + 2) - 4 ) + 1 )/3;
cannam@39 430
cannam@39 431
cannam@39 432 period = MathUtilities::mean( pdPeaks, 3 );
cannam@39 433 }
cannam@39 434
cannam@39 435 delete [] pdPeaks;
cannam@39 436
cannam@39 437 return period;
cannam@39 438 }
cannam@39 439
cannam@39 440 void TempoTrack::stepDetect( double* periodP, double* periodG, int currentIdx, int* flag )
cannam@39 441 {
cannam@39 442 double stepthresh = 1 * 3.9017;
cannam@39 443
cannam@39 444 if( *flag )
cannam@39 445 {
cannam@39 446 if(abs(periodG[ currentIdx ] - periodP[ currentIdx ]) > stepthresh)
cannam@39 447 {
cannam@39 448 // do nuffin'
cannam@39 449 }
cannam@39 450 }
cannam@39 451 else
cannam@39 452 {
cannam@39 453 if(fabs(periodG[ currentIdx ]-periodP[ currentIdx ]) > stepthresh)
cannam@39 454 {
cannam@39 455 *flag = 3;
cannam@39 456 }
cannam@39 457 }
cannam@39 458 }
cannam@39 459
cannam@39 460 void TempoTrack::constDetect( double* periodP, int currentIdx, int* flag )
cannam@39 461 {
cannam@39 462 double constthresh = 2 * 3.9017;
cannam@39 463
cannam@39 464 if( fabs( 2 * periodP[ currentIdx ] - periodP[ currentIdx - 1] - periodP[ currentIdx - 2] ) < constthresh)
cannam@39 465 {
cannam@39 466 *flag = 1;
cannam@39 467 }
cannam@39 468 else
cannam@39 469 {
cannam@39 470 *flag = 0;
cannam@39 471 }
cannam@39 472 }
cannam@39 473
cannam@39 474 int TempoTrack::findMeter(double *ACF, unsigned int len, double period)
cannam@39 475 {
cannam@39 476 int i;
cannam@39 477 int p = (int)MathUtilities::round( period );
cannam@39 478 int tsig;
cannam@39 479
cannam@39 480 double Energy_3 = 0.0;
cannam@39 481 double Energy_4 = 0.0;
cannam@39 482
cannam@39 483 double temp3A = 0.0;
cannam@39 484 double temp3B = 0.0;
cannam@39 485 double temp4A = 0.0;
cannam@39 486 double temp4B = 0.0;
cannam@39 487
cannam@39 488 double* dbf = new double[ len ]; int t = 0;
cannam@39 489 for( unsigned int u = 0; u < len; u++ ){ dbf[ u ] = 0.0; }
cannam@39 490
cannam@39 491 if( (double)len < 6 * p + 2 )
cannam@39 492 {
cannam@39 493 for( i = ( 3 * p - 2 ); i < ( 3 * p + 2 ) + 1; i++ )
cannam@39 494 {
cannam@39 495 temp3A += ACF[ i ];
cannam@39 496 dbf[ t++ ] = ACF[ i ];
cannam@39 497 }
cannam@39 498
cannam@39 499 for( i = ( 4 * p - 2 ); i < ( 4 * p + 2 ) + 1; i++ )
cannam@39 500 {
cannam@39 501 temp4A += ACF[ i ];
cannam@39 502 }
cannam@39 503
cannam@39 504 Energy_3 = temp3A;
cannam@39 505 Energy_4 = temp4A;
cannam@39 506 }
cannam@39 507 else
cannam@39 508 {
cannam@39 509 for( i = ( 3 * p - 2 ); i < ( 3 * p + 2 ) + 1; i++ )
cannam@39 510 {
cannam@39 511 temp3A += ACF[ i ];
cannam@39 512 }
cannam@39 513
cannam@39 514 for( i = ( 4 * p - 2 ); i < ( 4 * p + 2 ) + 1; i++ )
cannam@39 515 {
cannam@39 516 temp4A += ACF[ i ];
cannam@39 517 }
cannam@39 518
cannam@39 519 for( i = ( 6 * p - 2 ); i < ( 6 * p + 2 ) + 1; i++ )
cannam@39 520 {
cannam@39 521 temp3B += ACF[ i ];
cannam@39 522 }
cannam@39 523
cannam@39 524 for( i = ( 2 * p - 2 ); i < ( 2 * p + 2 ) + 1; i++ )
cannam@39 525 {
cannam@39 526 temp4B += ACF[ i ];
cannam@39 527 }
cannam@39 528
cannam@39 529 Energy_3 = temp3A + temp3B;
cannam@39 530 Energy_4 = temp4A + temp4B;
cannam@39 531 }
cannam@39 532
cannam@39 533 if (Energy_3 > Energy_4)
cannam@39 534 {
cannam@39 535 tsig = 3;
cannam@39 536 }
cannam@39 537 else
cannam@39 538 {
cannam@39 539 tsig = 4;
cannam@39 540 }
cannam@39 541
cannam@39 542
cannam@39 543 return tsig;
cannam@39 544 }
cannam@39 545
cannam@39 546 void TempoTrack::createPhaseExtractor(double *Filter, unsigned int winLength, double period, unsigned int fsp, unsigned int lastBeat)
cannam@39 547 {
cannam@39 548 int p = (int)MathUtilities::round( period );
cannam@39 549 int predictedOffset = 0;
cannam@39 550
cannam@47 551 #ifdef DEBUG_TEMPO_TRACK
cannam@46 552 std::cerr << "TempoTrack::createPhaseExtractor: period = " << period << ", p = " << p << std::endl;
cannam@47 553 #endif
cannam@46 554
cannam@47 555 if (p > 10000) {
cannam@47 556 std::cerr << "TempoTrack::createPhaseExtractor: WARNING! Highly implausible period value " << p << "!" << std::endl;
cannam@47 557 period = 5168 / 120;
cannam@47 558 }
cannam@46 559
cannam@47 560 double* phaseScratch = new double[ p*2 + 2 ];
cannam@47 561 for (int i = 0; i < p*2 + 2; ++i) phaseScratch[i] = 0.0;
cannam@39 562
cannam@39 563
cannam@39 564 if( lastBeat != 0 )
cannam@39 565 {
cannam@39 566 lastBeat = (int)MathUtilities::round((double)lastBeat );///(double)winLength);
cannam@39 567
cannam@47 568 predictedOffset = lastBeat + p - fsp;
cannam@39 569
cannam@47 570 if (predictedOffset < 0)
cannam@47 571 {
cannam@47 572 lastBeat = 0;
cannam@47 573 }
cannam@39 574 }
cannam@39 575
cannam@39 576 if( lastBeat != 0 )
cannam@39 577 {
cannam@39 578 int mu = p;
cannam@39 579 double sigma = (double)p/8;
cannam@39 580 double PhaseMin = 0.0;
cannam@39 581 double PhaseMax = 0.0;
cannam@39 582 unsigned int scratchLength = p*2;
cannam@39 583 double temp = 0.0;
cannam@39 584
cannam@39 585 for( int i = 0; i < scratchLength; i++ )
cannam@39 586 {
cannam@39 587 phaseScratch[ i ] = exp( -0.5 * pow( ( i - mu ) / sigma, 2 ) ) / ( sqrt( 2*PI ) *sigma );
cannam@39 588 }
cannam@39 589
cannam@39 590 MathUtilities::getFrameMinMax( phaseScratch, scratchLength, &PhaseMin, &PhaseMax );
cannam@39 591
cannam@39 592 for(int i = 0; i < scratchLength; i ++)
cannam@39 593 {
cannam@39 594 temp = phaseScratch[ i ];
cannam@39 595 phaseScratch[ i ] = (temp - PhaseMin)/PhaseMax;
cannam@39 596 }
cannam@39 597
cannam@47 598 #ifdef DEBUG_TEMPO_TRACK
cannam@46 599 std::cerr << "predictedOffset = " << predictedOffset << std::endl;
cannam@47 600 #endif
cannam@46 601
cannam@39 602 unsigned int index = 0;
cannam@47 603 for (int i = p - ( predictedOffset - 1); i < p + ( p - predictedOffset) + 1; i++)
cannam@39 604 {
cannam@47 605 #ifdef DEBUG_TEMPO_TRACK
cannam@47 606 std::cerr << "assigning to filter index " << index << " (size = " << p*2 << ")" << " value " << phaseScratch[i] << " from scratch index " << i << std::endl;
cannam@47 607 #endif
cannam@39 608 Filter[ index++ ] = phaseScratch[ i ];
cannam@39 609 }
cannam@39 610 }
cannam@39 611 else
cannam@39 612 {
cannam@39 613 for( int i = 0; i < p; i ++)
cannam@39 614 {
cannam@39 615 Filter[ i ] = 1;
cannam@39 616 }
cannam@39 617 }
cannam@39 618
cannam@39 619 delete [] phaseScratch;
cannam@39 620 }
cannam@39 621
cannam@39 622 int TempoTrack::phaseMM(double *DF, double *weighting, unsigned int winLength, double period)
cannam@39 623 {
cannam@39 624 int alignment = 0;
cannam@39 625 int p = (int)MathUtilities::round( period );
cannam@39 626
cannam@39 627 double temp = 0.0;
cannam@39 628
cannam@39 629 double* y = new double[ winLength ];
cannam@39 630 double* align = new double[ p ];
cannam@39 631
cannam@39 632 for( int i = 0; i < winLength; i++ )
cannam@39 633 {
cannam@39 634 y[ i ] = (double)( -i + winLength )/(double)winLength;
cannam@39 635 y[ i ] = pow(y [i ],2.0); // raise to power 2.
cannam@39 636 }
cannam@39 637
cannam@39 638 for( int o = 0; o < p; o++ )
cannam@39 639 {
cannam@39 640 temp = 0.0;
cannam@39 641 for(int i = 1 + (o - 1); i< winLength; i += (p + 1))
cannam@39 642 {
cannam@39 643 temp = temp + DF[ i ] * y[ i ];
cannam@39 644 }
cannam@39 645 align[ o ] = temp * weighting[ o ];
cannam@39 646 }
cannam@39 647
cannam@39 648
cannam@39 649 double valTemp = 0.0;
cannam@39 650 for(int i = 0; i < p; i++)
cannam@39 651 {
cannam@39 652 if( align[ i ] > valTemp )
cannam@39 653 {
cannam@39 654 valTemp = align[ i ];
cannam@39 655 alignment = i;
cannam@39 656 }
cannam@39 657 }
cannam@39 658
cannam@39 659 delete [] y;
cannam@39 660 delete [] align;
cannam@39 661
cannam@39 662 return alignment;
cannam@39 663 }
cannam@39 664
cannam@39 665 int TempoTrack::beatPredict(unsigned int FSP0, double alignment, double period, unsigned int step )
cannam@39 666 {
cannam@39 667 int beat = 0;
cannam@39 668
cannam@39 669 int p = (int)MathUtilities::round( period );
cannam@39 670 int align = (int)MathUtilities::round( alignment );
cannam@39 671 int FSP = (int)MathUtilities::round( FSP0 );
cannam@39 672
cannam@39 673 int FEP = FSP + ( step );
cannam@39 674
cannam@39 675 beat = FSP + align;
cannam@39 676
cannam@39 677 m_beats.push_back( beat );
cannam@39 678
cannam@39 679 while( beat + p < FEP )
cannam@39 680 {
cannam@39 681 beat += p;
cannam@39 682
cannam@39 683 m_beats.push_back( beat );
cannam@39 684 }
cannam@39 685
cannam@39 686 return beat;
cannam@39 687 }
cannam@39 688
cannam@39 689
cannam@39 690
cannam@39 691 vector<int> TempoTrack::process( vector <double> DF,
cannam@39 692 vector <double> *tempoReturn )
cannam@39 693 {
cannam@39 694 m_dataLength = DF.size();
cannam@39 695
cannam@39 696 m_lockedTempo = 0.0;
cannam@39 697
cannam@39 698 double period = 0.0;
cannam@39 699 int stepFlag = 0;
cannam@39 700 int constFlag = 0;
cannam@39 701 int FSP = 0;
cannam@39 702 int tsig = 0;
cannam@39 703 int lastBeat = 0;
cannam@39 704
cannam@39 705 vector <double> causalDF;
cannam@39 706
cannam@39 707 causalDF = DF;
cannam@39 708
cannam@39 709 //Prepare Causal Extension DFData
cannam@39 710 unsigned int DFCLength = m_dataLength + m_winLength;
cannam@39 711
cannam@39 712 for( unsigned int j = 0; j < m_winLength; j++ )
cannam@39 713 {
cannam@39 714 causalDF.push_back( 0 );
cannam@39 715 }
cannam@39 716
cannam@39 717
cannam@39 718 double* RW = new double[ m_lagLength ];
cannam@39 719 for( unsigned int clear = 0; clear < m_lagLength; clear++){ RW[ clear ] = 0.0;}
cannam@39 720
cannam@39 721 double* GW = new double[ m_lagLength ];
cannam@39 722 for(unsigned int clear = 0; clear < m_lagLength; clear++){ GW[ clear ] = 0.0;}
cannam@39 723
cannam@39 724 double* PW = new double[ m_lagLength ];
cannam@39 725 for(unsigned clear = 0; clear < m_lagLength; clear++){ PW[ clear ] = 0.0;}
cannam@39 726
cannam@39 727 m_DFFramer.setSource( &causalDF[0], m_dataLength );
cannam@39 728
cannam@39 729 unsigned int TTFrames = m_DFFramer.getMaxNoFrames();
cannam@47 730
cannam@47 731 #ifdef DEBUG_TEMPO_TRACK
cannam@47 732 std::cerr << "TTFrames = " << TTFrames << std::endl;
cannam@47 733 #endif
cannam@39 734
cannam@39 735 double* periodP = new double[ TTFrames ];
cannam@39 736 for(unsigned clear = 0; clear < TTFrames; clear++){ periodP[ clear ] = 0.0;}
cannam@39 737
cannam@39 738 double* periodG = new double[ TTFrames ];
cannam@39 739 for(unsigned clear = 0; clear < TTFrames; clear++){ periodG[ clear ] = 0.0;}
cannam@39 740
cannam@39 741 double* alignment = new double[ TTFrames ];
cannam@39 742 for(unsigned clear = 0; clear < TTFrames; clear++){ alignment[ clear ] = 0.0;}
cannam@39 743
cannam@39 744 m_beats.clear();
cannam@39 745
cannam@39 746 createCombFilter( RW, m_lagLength, 0, 0 );
cannam@39 747
cannam@39 748 int TTLoopIndex = 0;
cannam@39 749
cannam@39 750 for( unsigned int i = 0; i < TTFrames; i++ )
cannam@39 751 {
cannam@39 752 m_DFFramer.getFrame( m_rawDFFrame );
cannam@39 753
cannam@39 754 m_DFConditioning->process( m_rawDFFrame, m_smoothDFFrame );
cannam@39 755
cannam@39 756 m_correlator.doAutoUnBiased( m_smoothDFFrame, m_frameACF, m_winLength );
cannam@39 757
cannam@39 758 periodP[ TTLoopIndex ] = tempoMM( m_frameACF, RW, 0 );
cannam@39 759
cannam@39 760 if( GW[ 0 ] != 0 )
cannam@39 761 {
cannam@39 762 periodG[ TTLoopIndex ] = tempoMM( m_frameACF, GW, tsig );
cannam@39 763 }
cannam@39 764 else
cannam@39 765 {
cannam@39 766 periodG[ TTLoopIndex ] = 0.0;
cannam@39 767 }
cannam@39 768
cannam@39 769 stepDetect( periodP, periodG, TTLoopIndex, &stepFlag );
cannam@39 770
cannam@39 771 if( stepFlag == 1)
cannam@39 772 {
cannam@39 773 constDetect( periodP, TTLoopIndex, &constFlag );
cannam@39 774 stepFlag = 0;
cannam@39 775 }
cannam@39 776 else
cannam@39 777 {
cannam@39 778 stepFlag -= 1;
cannam@39 779 }
cannam@39 780
cannam@39 781 if( stepFlag < 0 )
cannam@39 782 {
cannam@39 783 stepFlag = 0;
cannam@39 784 }
cannam@39 785
cannam@39 786 if( constFlag != 0)
cannam@39 787 {
cannam@39 788 tsig = findMeter( m_frameACF, m_winLength, periodP[ TTLoopIndex ] );
cannam@39 789
cannam@39 790 createCombFilter( GW, m_lagLength, tsig, periodP[ TTLoopIndex ] );
cannam@39 791
cannam@39 792 periodG[ TTLoopIndex ] = tempoMM( m_frameACF, GW, tsig );
cannam@39 793
cannam@39 794 period = periodG[ TTLoopIndex ];
cannam@39 795
cannam@47 796 #ifdef DEBUG_TEMPO_TRACK
cannam@47 797 std::cerr << "TempoTrack::process: constFlag == " << constFlag << ", TTLoopIndex = " << TTLoopIndex << ", period from periodG = " << period << std::endl;
cannam@47 798 #endif
cannam@46 799
cannam@39 800 createPhaseExtractor( PW, m_winLength, period, FSP, 0 );
cannam@39 801
cannam@39 802 constFlag = 0;
cannam@39 803
cannam@39 804 }
cannam@39 805 else
cannam@39 806 {
cannam@39 807 if( GW[ 0 ] != 0 )
cannam@39 808 {
cannam@39 809 period = periodG[ TTLoopIndex ];
cannam@46 810
cannam@47 811 #ifdef DEBUG_TEMPO_TRACK
cannam@47 812 std::cerr << "TempoTrack::process: GW[0] == " << GW[0] << ", TTLoopIndex = " << TTLoopIndex << ", period from periodG = " << period << std::endl;
cannam@47 813 #endif
cannam@46 814
cannam@46 815 if (period > 10000) {
cannam@47 816 std::cerr << "TempoTrack::process: WARNING! Highly implausible period value " << period << "!" << std::endl;
cannam@46 817 std::cerr << "periodG contains (of " << TTFrames << " frames): " << std::endl;
cannam@46 818 for (int i = 0; i < TTLoopIndex + 3 && i < TTFrames; ++i) {
cannam@46 819 std::cerr << i << " -> " << periodG[i] << std::endl;
cannam@46 820 }
cannam@46 821 std::cerr << "periodP contains (of " << TTFrames << " frames): " << std::endl;
cannam@46 822 for (int i = 0; i < TTLoopIndex + 3 && i < TTFrames; ++i) {
cannam@46 823 std::cerr << i << " -> " << periodP[i] << std::endl;
cannam@46 824 }
cannam@47 825 period = 5168 / 120;
cannam@46 826 }
cannam@46 827
cannam@39 828 createPhaseExtractor( PW, m_winLength, period, FSP, lastBeat );
cannam@39 829
cannam@39 830 }
cannam@39 831 else
cannam@39 832 {
cannam@39 833 period = periodP[ TTLoopIndex ];
cannam@46 834
cannam@47 835 #ifdef DEBUG_TEMPO_TRACK
cannam@47 836 std::cerr << "TempoTrack::process: GW[0] == " << GW[0] << ", TTLoopIndex = " << TTLoopIndex << ", period from periodP = " << period << std::endl;
cannam@47 837 #endif
cannam@46 838
cannam@39 839 createPhaseExtractor( PW, m_winLength, period, FSP, 0 );
cannam@39 840 }
cannam@39 841 }
cannam@39 842
cannam@39 843 alignment[ TTLoopIndex ] = phaseMM( m_rawDFFrame, PW, m_winLength, period );
cannam@39 844
cannam@39 845 lastBeat = beatPredict(FSP, alignment[ TTLoopIndex ], period, m_lagLength );
cannam@39 846
cannam@39 847 FSP += (m_lagLength);
cannam@39 848
cannam@39 849 if (tempoReturn) tempoReturn->push_back(m_lockedTempo);
cannam@39 850
cannam@39 851 TTLoopIndex++;
cannam@39 852 }
cannam@39 853
cannam@39 854
cannam@39 855 delete [] periodP;
cannam@39 856 delete [] periodG;
cannam@39 857 delete [] alignment;
cannam@39 858
cannam@39 859 delete [] RW;
cannam@39 860 delete [] GW;
cannam@39 861 delete [] PW;
cannam@39 862
cannam@39 863 return m_beats;
cannam@39 864 }