annotate dsp/tempotracking/TempoTrack.cpp @ 84:e5907ae6de17

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