annotate dsp/tempotracking/TempoTrack.cpp @ 298:255e431ae3d4

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