annotate dsp/tempotracking/TempoTrack.cpp @ 209:ccd2019190bf msvc

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