annotate dsp/tempotracking/TempoTrack.cpp @ 73:dcb555b90924

* Key detector: when returning key strengths, use the peak value of the three underlying chromagram correlations (from 36-bin chromagram) corresponding to each key, instead of the mean. Rationale: This is the same method as used when returning the key value, and it's nice to have the same results in both returned value and plot. The peak performed better than the sum with a simple test set of triads, so it seems reasonable to change the plot to match the key output rather than the other way around. * FFT: kiss_fftr returns only the non-conjugate bins, synthesise the rest rather than leaving them (perhaps dangerously) undefined. Fixes an uninitialised data error in chromagram that could cause garbage results from key detector. * Constant Q: remove precalculated values again, I reckon they're not proving such a good tradeoff.
author cannam
date Fri, 05 Jun 2009 15:12:39 +0000
parents 09aba2ccd94a
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 }