annotate dsp/tempotracking/TempoTrack.cpp @ 46:4f1870dbab2c

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