Mercurial > hg > qm-dsp
comparison dsp/tempotracking/TempoTrack.cpp @ 264:766f770b358f
* Updated tempo tracking code from Matthew Davies
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Fri, 01 Feb 2008 16:45:14 +0000 |
parents | a98dd8ec96f8 |
children | 4f1870dbab2c |
comparison
equal
deleted
inserted
replaced
263:715b0a6bcdc0 | 264:766f770b358f |
---|---|
14 #include "maths/MathUtilities.h" | 14 #include "maths/MathUtilities.h" |
15 | 15 |
16 #include <iostream> | 16 #include <iostream> |
17 | 17 |
18 | 18 |
19 #define RAY43VAL | |
20 | |
19 ////////////////////////////////////////////////////////////////////// | 21 ////////////////////////////////////////////////////////////////////// |
20 // Construction/Destruction | 22 // Construction/Destruction |
21 ////////////////////////////////////////////////////////////////////// | 23 ////////////////////////////////////////////////////////////////////// |
22 | 24 |
23 TempoTrack::TempoTrack( TTParams Params ) | 25 TempoTrack::TempoTrack( TTParams Params ) |
24 { | 26 { |
25 m_tempoScratch = NULL; | 27 m_tempoScratch = NULL; |
26 m_rawDFFrame = NULL; | 28 m_rawDFFrame = NULL; |
27 m_smoothDFFrame = NULL; | 29 m_smoothDFFrame = NULL; |
28 m_frameACF = NULL; | 30 m_frameACF = NULL; |
31 m_smoothRCF = NULL; | |
29 | 32 |
30 m_dataLength = 0; | 33 m_dataLength = 0; |
31 m_winLength = 0; | 34 m_winLength = 0; |
32 m_lagLength = 0; | 35 m_lagLength = 0; |
33 | 36 |
54 | 57 |
55 m_rawDFFrame = new double[ m_winLength ]; | 58 m_rawDFFrame = new double[ m_winLength ]; |
56 m_smoothDFFrame = new double[ m_winLength ]; | 59 m_smoothDFFrame = new double[ m_winLength ]; |
57 m_frameACF = new double[ m_winLength ]; | 60 m_frameACF = new double[ m_winLength ]; |
58 m_tempoScratch = new double[ m_lagLength ]; | 61 m_tempoScratch = new double[ m_lagLength ]; |
62 m_smoothRCF = new double[ m_lagLength ]; | |
63 | |
59 | 64 |
60 unsigned int winPre = Params.WinT.pre; | 65 unsigned int winPre = Params.WinT.pre; |
61 unsigned int winPost = Params.WinT.post; | 66 unsigned int winPost = Params.WinT.post; |
62 | 67 |
63 m_DFFramer.configure( m_winLength, m_lagLength ); | 68 m_DFFramer.configure( m_winLength, m_lagLength ); |
71 m_DFPParams.winPost = Params.WinT.post; | 76 m_DFPParams.winPost = Params.WinT.post; |
72 m_DFPParams.isMedianPositive = true; | 77 m_DFPParams.isMedianPositive = true; |
73 | 78 |
74 m_DFConditioning = new DFProcess( m_DFPParams ); | 79 m_DFConditioning = new DFProcess( m_DFPParams ); |
75 | 80 |
81 | |
82 // these are parameters for smoothing m_tempoScratch | |
83 m_RCFPParams.length = m_lagLength; | |
84 m_RCFPParams.AlphaNormParam = Params.alpha; | |
85 m_RCFPParams.LPOrd = Params.LPOrd; | |
86 m_RCFPParams.LPACoeffs = Params.LPACoeffs; | |
87 m_RCFPParams.LPBCoeffs = Params.LPBCoeffs; | |
88 m_RCFPParams.winPre = Params.WinT.pre; | |
89 m_RCFPParams.winPost = Params.WinT.post; | |
90 m_RCFPParams.isMedianPositive = true; | |
91 | |
92 m_RCFConditioning = new DFProcess( m_RCFPParams ); | |
93 | |
76 } | 94 } |
77 | 95 |
78 void TempoTrack::deInitialise() | 96 void TempoTrack::deInitialise() |
79 { | 97 { |
80 delete [] m_rawDFFrame; | 98 delete [] m_rawDFFrame; |
81 | 99 |
82 delete [] m_smoothDFFrame; | 100 delete [] m_smoothDFFrame; |
101 | |
102 delete [] m_smoothRCF; | |
83 | 103 |
84 delete [] m_frameACF; | 104 delete [] m_frameACF; |
85 | 105 |
86 delete [] m_tempoScratch; | 106 delete [] m_tempoScratch; |
87 | 107 |
88 delete m_DFConditioning; | 108 delete m_DFConditioning; |
109 | |
110 delete m_RCFConditioning; | |
111 | |
89 } | 112 } |
90 | 113 |
91 void TempoTrack::createCombFilter(double* Filter, unsigned int winLength, unsigned int TSig, double beatLag) | 114 void TempoTrack::createCombFilter(double* Filter, unsigned int winLength, unsigned int TSig, double beatLag) |
92 { | 115 { |
93 unsigned int i; | 116 unsigned int i; |
99 Filter[ i ] = ( ( i + 1 ) / pow( m_rayparam, 2.0) ) * exp( ( -pow(( i + 1 ),2.0 ) / ( 2.0 * pow( m_rayparam, 2.0)))); | 122 Filter[ i ] = ( ( i + 1 ) / pow( m_rayparam, 2.0) ) * exp( ( -pow(( i + 1 ),2.0 ) / ( 2.0 * pow( m_rayparam, 2.0)))); |
100 } | 123 } |
101 } | 124 } |
102 else | 125 else |
103 { | 126 { |
104 m_sigma = beatLag/8; | 127 m_sigma = beatLag/4; |
105 for( i = 0; i < winLength; i++ ) | 128 for( i = 0; i < winLength; i++ ) |
106 { | 129 { |
107 double dlag = (double)(i+1) - beatLag; | 130 double dlag = (double)(i+1) - beatLag; |
108 Filter[ i ] = exp(-0.5 * pow(( dlag / m_sigma), 2.0) ) / (sqrt( 2 * PI) * m_sigma); | 131 Filter[ i ] = exp(-0.5 * pow(( dlag / m_sigma), 2.0) ) / (sqrt( 2 * PI) * m_sigma); |
109 } | 132 } |
121 | 144 |
122 unsigned int maxIndexTemp; | 145 unsigned int maxIndexTemp; |
123 double maxValTemp; | 146 double maxValTemp; |
124 unsigned int count; | 147 unsigned int count; |
125 | 148 |
126 unsigned int numelem; | 149 unsigned int numelem,i,j; |
127 int i, a, b; | 150 int a, b; |
128 | 151 |
129 for( i = 0; i < m_lagLength; i++ ) | 152 for( i = 0; i < m_lagLength; i++ ) |
130 m_tempoScratch[ i ] = 0.0; | 153 m_tempoScratch[ i ] = 0.0; |
131 | 154 |
132 if( tsig == 0 ) | 155 if( tsig == 0 ) |
157 } | 180 } |
158 } | 181 } |
159 } | 182 } |
160 | 183 |
161 | 184 |
162 //NOW FIND MAX INDEX OF ACFOUT | 185 ////////////////////////////////////////////////// |
163 for( i = 0; i < m_lagLength; i++) | 186 // MODIFIED BEAT PERIOD EXTRACTION ////////////// |
164 { | 187 ///////////////////////////////////////////////// |
165 if( m_tempoScratch[ i ] > maxValRCF) | 188 |
166 { | 189 // find smoothed version of RCF ( as applied to Detection Function) |
167 maxValRCF = m_tempoScratch[ i ]; | 190 m_RCFConditioning->process( m_tempoScratch, m_smoothRCF); |
168 maxIndexRCF = i; | 191 |
169 } | 192 if (tsig != 0) // i.e. in context dependent state |
170 } | 193 { |
194 // NOW FIND MAX INDEX OF ACFOUT | |
195 for( i = 0; i < m_lagLength; i++) | |
196 { | |
197 if( m_tempoScratch[ i ] > maxValRCF) | |
198 { | |
199 maxValRCF = m_tempoScratch[ i ]; | |
200 maxIndexRCF = i; | |
201 } | |
202 } | |
203 } | |
204 else // using rayleigh weighting | |
205 { | |
206 vector <vector<double> > rcfMat; | |
207 | |
208 double sumRcf = 0.; | |
209 | |
210 double maxVal = 0.; | |
211 // now find the two values which minimise rcfMat | |
212 double minVal = 0.; | |
213 int p_i = 1; // periodicity for row i; | |
214 int p_j = 1; //periodicity for column j; | |
215 | |
216 | |
217 for ( i=0; i<m_lagLength; i++) | |
218 { | |
219 m_tempoScratch[i] =m_smoothRCF[i]; | |
220 } | |
221 | |
222 // normalise m_tempoScratch so that it sums to zero. | |
223 for ( i=0; i<m_lagLength; i++) | |
224 { | |
225 sumRcf += m_tempoScratch[i]; | |
226 } | |
227 | |
228 for( i=0; i<m_lagLength; i++) | |
229 { | |
230 m_tempoScratch[i] /= sumRcf; | |
231 } | |
232 | |
233 // create a matrix to store m_tempoScratchValues modified by log2 ratio | |
234 for ( i=0; i<m_lagLength; i++) | |
235 { | |
236 rcfMat.push_back ( vector<double>() ); // adds a new row... | |
237 } | |
238 | |
239 for (i=0; i<m_lagLength; i++) | |
240 { | |
241 for (j=0; j<m_lagLength; j++) | |
242 { | |
243 rcfMat[i].push_back (0.); | |
244 } | |
245 } | |
246 | |
247 // the 'i' and 'j' indices deliberately start from '1' and not '0' | |
248 for ( i=1; i<m_lagLength; i++) | |
249 { | |
250 for (j=1; j<m_lagLength; j++) | |
251 { | |
252 double log2PeriodRatio = log( static_cast<double>(i)/static_cast<double>(j) ) / log(2.0); | |
253 rcfMat[i][j] = ( abs(1.0-abs(log2PeriodRatio)) ); | |
254 rcfMat[i][j] += ( 0.01*( 1./(m_tempoScratch[i]+m_tempoScratch[j]) ) ); | |
255 } | |
256 } | |
257 | |
258 // set diagonal equal to maximum value in rcfMat | |
259 // we don't want to pick one strong middle peak - we need a combination of two peaks. | |
260 | |
261 for ( i=1; i<m_lagLength; i++) | |
262 { | |
263 for (j=1; j<m_lagLength; j++) | |
264 { | |
265 if (rcfMat[i][j] > maxVal) | |
266 { | |
267 maxVal = rcfMat[i][j]; | |
268 } | |
269 } | |
270 } | |
271 | |
272 for ( i=1; i<m_lagLength; i++) | |
273 { | |
274 rcfMat[i][i] = maxVal; | |
275 } | |
276 | |
277 // now find the row and column number which minimise rcfMat | |
278 minVal = maxVal; | |
279 | |
280 for ( i=1; i<m_lagLength; i++) | |
281 { | |
282 for ( j=1; j<m_lagLength; j++) | |
283 { | |
284 if (rcfMat[i][j] < minVal) | |
285 { | |
286 minVal = rcfMat[i][j]; | |
287 p_i = i; | |
288 p_j = j; | |
289 } | |
290 } | |
291 } | |
292 | |
293 | |
294 // initially choose p_j (arbitrary) - saves on an else statement | |
295 int beatPeriod = p_j; | |
296 if (m_tempoScratch[p_i] > m_tempoScratch[p_j]) | |
297 { | |
298 beatPeriod = p_i; | |
299 } | |
300 | |
301 // now write the output | |
302 maxIndexRCF = static_cast<int>(beatPeriod); | |
303 | |
304 } | |
305 | |
171 | 306 |
172 double locked = 5168.f / maxIndexRCF; | 307 double locked = 5168.f / maxIndexRCF; |
173 if (locked >= 30 && locked <= 180) { | 308 if (locked >= 30 && locked <= 180) { |
174 m_lockedTempo = locked; | 309 m_lockedTempo = locked; |
175 } | 310 } |
406 } | 541 } |
407 | 542 |
408 if( lastBeat != 0 ) | 543 if( lastBeat != 0 ) |
409 { | 544 { |
410 int mu = p; | 545 int mu = p; |
411 double sigma = (double)p/4; | 546 double sigma = (double)p/8; |
412 double PhaseMin = 0.0; | 547 double PhaseMin = 0.0; |
413 double PhaseMax = 0.0; | 548 double PhaseMax = 0.0; |
414 unsigned int scratchLength = p*2; | 549 unsigned int scratchLength = p*2; |
415 double temp = 0.0; | 550 double temp = 0.0; |
416 | 551 |
455 double* align = new double[ p ]; | 590 double* align = new double[ p ]; |
456 | 591 |
457 for( int i = 0; i < winLength; i++ ) | 592 for( int i = 0; i < winLength; i++ ) |
458 { | 593 { |
459 y[ i ] = (double)( -i + winLength )/(double)winLength; | 594 y[ i ] = (double)( -i + winLength )/(double)winLength; |
595 y[ i ] = pow(y [i ],2.0); // raise to power 2. | |
460 } | 596 } |
461 | 597 |
462 for( int o = 0; o < p; o++ ) | 598 for( int o = 0; o < p; o++ ) |
463 { | 599 { |
464 temp = 0.0; | 600 temp = 0.0; |
594 | 730 |
595 periodG[ TTLoopIndex ] = tempoMM( m_frameACF, GW, tsig ); | 731 periodG[ TTLoopIndex ] = tempoMM( m_frameACF, GW, tsig ); |
596 | 732 |
597 period = periodG[ TTLoopIndex ]; | 733 period = periodG[ TTLoopIndex ]; |
598 | 734 |
599 createPhaseExtractor( PW, m_winLength, period, FSP, 0 ); | 735 // am temporarily changing the last input parameter to lastBeat instead of '0' |
736 createPhaseExtractor( PW, m_winLength, period, FSP, lastBeat ); | |
600 | 737 |
601 constFlag = 0; | 738 constFlag = 0; |
602 | 739 |
603 } | 740 } |
604 else | 741 else |