annotate dsp/tempotracking/TempoTrack.cpp @ 96:88f3cfcff55f

A threshold (delta) is added in the peak picking parameters structure (PPickParams). It is used as an offset when computing the smoothed detection function. A constructor for the structure PPickParams is also added to set the parameters to 0 when a structure instance is created. Hence programmes using the peak picking parameter structure and which do not set the delta parameter (e.g. QM Vamp note onset detector) won't be affected by the modifications. Functions modified: - dsp/onsets/PeakPicking.cpp - dsp/onsets/PeakPicking.h - dsp/signalconditioning/DFProcess.cpp - dsp/signalconditioning/DFProcess.h
author mathieub <mathieu.barthet@eecs.qmul.ac.uk>
date Mon, 20 Jun 2011 19:01:48 +0100
parents e5907ae6de17
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 }