2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 //BeatTrack UGen implemented by Nick Collins (http://www.informatics.sussex.ac.uk/users/nc81/)
22 //post FFT UGen version 1 Nov 2007
24 //conversion of Matthew Davies autocorrelation beat tracking model, adapted for real-time use
25 //currently using QMUL complex domain onset detection function model
27 //#include "SC_PlugIn.h"
28 //#include <vecLib/vecLib.h>
37 //#define N 1024 //FFT size
40 //#define NOVER4 256 //FFT size
42 //#define OVERLAPINDEX 512
45 //#define FS 44100 //assumes fixed sampling rate
46 //#define FRAMESR 86.1328
47 //converted for different sampling rates
48 #define FRAMEPERIOD 0.01161
50 //#define TIMEELAPSED 1.48608
52 //this data assumes LAGS is 128
53 static float g_m
[128]= {0.00054069,0.00108050,0.00161855,0.00215399,0.00268594,0.00321356,0.00373600,0.00425243,0.00476204,0.00526404,0.00575765,0.00624213,0.00671675,0.00718080,0.00763362,0.00807455,0.00850299,0.00891836,0.00932010,0.00970771,0.01008071,0.01043866,0.01078115,0.01110782,0.01141834,0.01171242,0.01198982,0.01225033,0.01249378,0.01272003,0.01292899,0.01312061,0.01329488,0.01345182,0.01359148,0.01371396,0.01381939,0.01390794,0.01397980,0.01403520,0.01407439,0.01409768,0.01410536,0.01409780,0.01407534,0.01403838,0.01398734,0.01392264,0.01384474,0.01375410,0.01365120,0.01353654,0.01341062,0.01327397,0.01312710,0.01297054,0.01280484,0.01263053,0.01244816,0.01225827,0.01206139,0.01185807,0.01164884,0.01143424,0.01121478,0.01099099,0.01076337,0.01053241,0.01029861,0.01006244,0.00982437,0.00958484,0.00934429,0.00910314,0.00886181,0.00862067,0.00838011,0.00814049,0.00790214,0.00766540,0.00743057,0.00719793,0.00696778,0.00674036,0.00651591,0.00629466,0.00607682,0.00586256,0.00565208,0.00544551,0.00524301,0.00504470,0.00485070,0.00466109,0.00447597,0.00429540,0.00411944,0.00394813,0.00378151,0.00361959,0.00346238,0.00330989,0.00316210,0.00301899,0.00288053,0.00274669,0.00261741,0.00249266,0.00237236,0.00225646,0.00214488,0.00203755,0.00193440,0.00183532,0.00174025,0.00164909,0.00156174,0.00147811,0.00139810,0.00132161,0.00124854,0.00117880,0.00111228,0.00104887,0.00098848,0.00093100,0.00087634,0.00082438,};
54 static float g_mg
[257]= {0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000004,0.00000055,0.00000627,0.00005539,0.00037863,0.00200318,0.00820201,0.02599027,0.06373712,0.12096648,0.17767593,0.20196826,0.17767593,0.12096648,0.06373712,0.02599027,0.00820201,0.00200318,0.00037863,0.00005539,0.00000627,0.00000055,0.00000004,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,};
57 static void BeatTrack_dofft(BeatTrack
*unit
, uint32
);
58 static void complexdf(BeatTrack
*unit
);
59 static void finaldecision(BeatTrack
*unit
);
62 static void autocorr(BeatTrack
*unit
,int j
);
63 static void beatperiod(BeatTrack
*unit
,int j
, int whichm
);
64 static float findtor(BeatTrack
*unit
);
66 //as many amortisation steps as tor
67 static void findphase(BeatTrack
*unit
,int j
,int gaussflag
,int predicted
);
69 static int detectperiodchange(BeatTrack
*unit
);
70 static void findmeter(BeatTrack
*unit
);
71 static void setupphaseexpectation(BeatTrack
*unit
); //create Gaussian focussed matrix for phase
74 void BeatTrack_Ctor(BeatTrack
* unit
)
77 //check sampling rate and establish multipliers on estimates and FFT window size
78 //down sampling by factor of two automatic
80 unit
->m_srate
= unit
->mWorld
->mFullRate
.mSampleRate
;
82 //if sample rate is 88200 or 96000, assume taking double size FFT to start with
83 if(unit
->m_srate
> (44100.0*1.5)) unit
->m_srate
= unit
->m_srate
*0.5;
85 unit
->m_srateconversion
= unit
->m_srate
/44100.0;
87 //assumes base of 1024 FFT
88 unit
->m_frameperiod
= (FRAMEPERIOD
/unit
->m_srateconversion
); //in seconds //(int) ((FRAMEPERIOD/unit->m_srateconversion) +0.5);
90 printf("srate %f conversion factor %f frame period %f \n", unit
->m_srate
, unit
->m_srateconversion
, unit
->m_frameperiod
);
92 unit
->m_prevmag
= (float*)RTAlloc(unit
->mWorld
, NOVER2
* sizeof(float));
93 unit
->m_prevphase
= (float*)RTAlloc(unit
->mWorld
, NOVER2
* sizeof(float));
94 unit
->m_predict
= (float*)RTAlloc(unit
->mWorld
, NOVER2
* sizeof(float));
96 ////////time positions//////////
97 unit
->m_frame
=1; //don't decide immediately, wait for maximum period!
100 unit
->m_dfcounter
=DFSTORE
-1;
101 //random uncorrelated noise df store for initialisation
102 //RGen& rgen = *unit->mParent->mRGen;
104 //don't want this noise, want consistent starting point!
105 for(int j
=0;j
<DFSTORE
;++j
) {
106 unit
->m_df
[j
]=0.0; //(2*rgen.frand() - 1.0);
109 unit
->m_dfmemorycounter
=14;
111 Clear(15, unit
->m_dfmemory
);
113 /////////tempo assess///////////
116 ////////phase assess///////////
118 unit
->m_currphase
=0.0;
123 unit
->m_phaseperblock
= ((float)unit
->mWorld
->mFullRate
.mBufLength
*2)/((float)unit
->mWorld
->mSampleRate
);
125 unit
->m_outputphase
= unit
->m_phase
;
126 unit
->m_outputtempo
= unit
->m_currtempo
;
127 unit
->m_outputphaseperblock
= unit
->m_phaseperblock
;
133 //amortisation and states
134 unit
->m_amortisationstate
=0; //off
139 unit
->mCalcFunc
= (UnitCalcFunc
)&BeatTrack_next
;
144 void BeatTrack_Dtor(BeatTrack
*unit
)
146 RTFree(unit
->mWorld
, unit
->m_prevmag
);
147 RTFree(unit
->mWorld
, unit
->m_prevphase
);
148 RTFree(unit
->mWorld
, unit
->m_predict
);
152 void BeatTrack_next(BeatTrack
*unit
, int wrongNumSamples
)
156 //printf("%d \n",wrongNumSamples);
157 //int numSamples = unit->mWorld->mFullRate.mBufLength;
159 //conditions in reverse order to avoid immediate spillover
160 //printf("state %d \n",unit->m_amortisationstate);
162 //keeps incrementing but will be reset with each calculation run
163 unit
->m_amortisationsteps
=unit
->m_amortisationsteps
+1;
165 //if state nonzero do something
166 switch(unit
->m_amortisationstate
) {
168 break; //do nothing case
169 case 1: //calculate acf
170 autocorr(unit
,unit
->m_amortcount
);
172 unit
->m_amortcount
=unit
->m_amortcount
+1;
174 if(unit
->m_amortcount
==unit
->m_amortlength
) {
175 unit
->m_amortisationstate
=2;
176 unit
->m_amortlength
=128;
177 unit
->m_amortcount
=0;
179 unit
->m_bestcolumn
=0;
180 unit
->m_besttorsum
= -1000.0;
186 beatperiod(unit
,unit
->m_amortcount
,0);
188 unit
->m_amortcount
=unit
->m_amortcount
+1;
190 if(unit
->m_amortcount
==unit
->m_amortlength
) {
192 unit
->m_periodp
=findtor(unit
);
194 if(unit
->m_stateflag
==1) {
195 unit
->m_amortisationstate
=3;
196 unit
->m_amortlength
=128;
197 unit
->m_amortcount
=0;
199 unit
->m_bestcolumn
=0;
200 unit
->m_besttorsum
= -1000.0;
203 unit
->m_periodg
= -1000; //will always trigger initially
204 unit
->m_amortisationstate
=4;
210 beatperiod(unit
,unit
->m_amortcount
,1);
211 unit
->m_amortcount
=unit
->m_amortcount
+1;
213 if(unit
->m_amortcount
==unit
->m_amortlength
) {
215 unit
->m_periodg
=findtor(unit
);
217 unit
->m_amortisationstate
=4;
221 case 4: //stepdetect/constdetect
223 if(detectperiodchange(unit
)) {
225 unit
->m_amortisationstate
=5;
226 unit
->m_amortlength
=128;
227 unit
->m_amortcount
=0;
229 unit
->m_bestcolumn
=0;
230 unit
->m_besttorsum
= -1000.0;
235 //set up Gaussian weighting centred on periodp
236 int startindex
= 128- ((int)(unit
->m_periodp
+0.5));
238 float * mg
=unit
->m_mg
;
240 for (int ii
=0; ii
<128;++ii
){
241 mg
[ii
]= g_mg
[startindex
+ii
];
246 if(unit
->m_stateflag
==1)
247 unit
->m_tor
= unit
->m_periodg
;
249 unit
->m_tor
= unit
->m_periodp
;
251 unit
->m_torround
= int(unit
->m_tor
+0.5);
253 unit
->m_amortisationstate
=7;
254 unit
->m_amortlength
=unit
->m_torround
;
255 unit
->m_amortcount
=0;
260 case 5: //redo periodg calculation
261 beatperiod(unit
,unit
->m_amortcount
,1);
262 unit
->m_amortcount
=unit
->m_amortcount
+1;
264 if(unit
->m_amortcount
==unit
->m_amortlength
) {
266 unit
->m_periodg
=findtor(unit
);
268 unit
->m_tor
= unit
->m_periodg
;
269 unit
->m_torround
= int(unit
->m_tor
+0.5f
);
271 unit
->m_amortisationstate
=6;
272 unit
->m_amortlength
=unit
->m_torround
;
273 unit
->m_amortcount
=0;
275 setupphaseexpectation(unit
);
277 //don't need to reset change flag since it isn't stored
281 case 6: //flat phase calc after move to context, avoids bias
282 findphase(unit
,unit
->m_amortcount
,0,0);
283 unit
->m_amortcount
=unit
->m_amortcount
+1;
285 if(unit
->m_amortcount
==unit
->m_amortlength
) {
287 unit
->m_amortisationstate
=8; //final state
292 case 7: //phase calc with possible gaussian narrowing of the allowed phases
294 findphase(unit
,unit
->m_amortcount
,unit
->m_stateflag
,(int)(unit
->m_currphase
*unit
->m_torround
+0.5f
));
295 unit
->m_amortcount
=unit
->m_amortcount
+1;
297 if(unit
->m_amortcount
==unit
->m_amortlength
) {
299 unit
->m_amortisationstate
=8; //final state
306 unit
->m_amortisationstate
=0;
314 //MUST CHECK IF INCIDENT FFT IS >1, if so update buffer with appropriate coefficients
316 float fbufnum
= ZIN0(0);
318 //next FFT bufffer ready, update
319 //assuming at this point that buffer precalculated for any resampling
322 unit
->m_frame
= unit
->m_frame
+1;
323 BeatTrack_dofft(unit
, (uint32
)fbufnum
);
328 //test if impulse to output
329 unit
->m_phase
+=unit
->m_phaseperblock
;
331 //if not locked, update output phase from model phase, else keep a separate output phase
334 //printf("lock %f \n",lock);
337 unit
->m_outputphase
= unit
->m_phase
;
338 unit
->m_outputtempo
= unit
->m_currtempo
;
339 unit
->m_outputphaseperblock
= unit
->m_phaseperblock
;
341 unit
->m_outputphase
+=unit
->m_outputphaseperblock
;
343 if (unit
->m_phase
>= 1.f
) unit
->m_phase
-= 1.f
;
345 //0 is beat, 1 is quaver, 2 is semiquaver, 3 is actual current tempo in bps
346 //so no audio accuracy with beats, just asap, may as well be control rate
350 ZOUT0(3)=unit
->m_outputtempo
; //*0.016666667;
353 if (unit
->m_outputphase
>= 1.f
) {
357 unit
->m_outputphase
-= 1.f
;
366 if (unit
->m_outputphase
>=0.5f
&& unit
->halftrig
==0) {
372 if (unit
->m_outputphase
>=0.25f
&& unit
->q1trig
==0) {
377 if (unit
->m_outputphase
>=0.75f
&& unit
->q2trig
==0) {
388 //calculation function once FFT data ready
389 void BeatTrack_dofft(BeatTrack
*unit
, uint32 ibufnum
)
391 World
*world
= unit
->mWorld
;
393 if (ibufnum
>= world
->mNumSndBufs
) {
394 int localBufNum
= ibufnum
- world
->mNumSndBufs
;
395 Graph
*parent
= unit
->mParent
;
396 if(localBufNum
<= parent
->localBufNum
) {
397 buf
= parent
->mLocalSndBufs
+ localBufNum
;
399 buf
= world
->mSndBufs
;
402 buf
= world
->mSndBufs
+ ibufnum
;
405 //int numbins = buf->samples - 2 >> 1;
407 unit
->m_FFTBuf
= buf
->data
; //just assign it!
409 //transfer data to fftbuf in the format expected by this plugin
411 //ideally, should do this part separate to plug-in as well, so can compare different detection functions;
412 //also, can run multiple in parallel with own autocorrelations; committee? Committee.ar(period1, phase1, period2, phase2, period3, phase3)...
413 //chooses predominant estimate?
414 //feature detection function
417 if (unit
->m_frame
%SKIP
==0) {
419 //printf("amortisation time \n");
421 //amortisation- 8 control periods in a frame
422 //have 2000 calcs to do, split over 100 control periods = 6400 samples, ie one tempo per control period
424 unit
->m_bestcolumn
=0;
425 unit
->m_besttorsum
= -1000.0;
427 unit
->m_bestphasescore
= -1000.0;
428 unit
->m_bestphase
= 0;
430 //state 0 is do nothing
431 unit
->m_amortisationstate
=1;
432 unit
->m_amortcount
=0;
433 unit
->m_amortlength
=128;
434 unit
->m_amortisationsteps
=0;
436 //fix time reference for calculations, so it doesn't update during the amortisation- this is the beginning of the df frame
437 unit
->m_storedfcounter
= unit
->m_dfcounter
+DFSTORE
-DFFRAMELENGTH
;
439 //ref for phase calculations
440 unit
->m_storedfcounterend
= unit
->m_dfcounter
;
442 //unit->m_fftstoreposhold= unit->m_fftstorepos;
444 unit
->m_currphase
=unit
->m_phase
;
451 void autocorr(BeatTrack
*unit
,int j
)
453 int baseframe
=unit
->m_storedfcounter
+DFSTORE
;
454 float * df
= unit
->m_df
;
455 float * acf
= unit
->m_acf
;
457 //work out four lags each time
458 for (int k
=0;k
<4;++k
) {
462 int correction
= abs(lag
-DFFRAMELENGTH
);
466 for (int i
=lag
;i
<DFFRAMELENGTH
; ++i
) {
468 float val1
= df
[(i
+baseframe
)%DFSTORE
];
469 float val2
= df
[(i
+baseframe
-lag
)%DFSTORE
];
474 acf
[lag
]=sum
*correction
;
482 //timesig 4 has one more sum term
483 //indices as MATLAB but need to correct maxinds to be in range of tested, not in global range
484 float findtor(BeatTrack
*unit
)
489 //put into MATLAB indexing, from 1 to 512
490 int ind
= unit
->m_bestcolumn
+1;
492 float * acf
= unit
->m_acf
-1;
497 for(int i
=2*ind
-1;i
<=(2*ind
+1);++i
){
509 //[val2,ind2] = max(acf(2*ind-1:2*ind+1));
510 ind2
= ind2
+ 2*(ind
+1)-2;
515 for(int i
=3*ind
-2;i
<=(3*ind
+2);++i
){
527 //[val3,ind3] = max(acf(3*ind-2:3*ind+2));
528 ind3
= ind3
+ 3*ind
-4;
532 if (unit
->m_timesig
==4) {
537 for(int i
=4*ind
-3;i
<=4*ind
+3;++i
){
549 //[val4,ind4] = max(acf(4*ind-3:4*ind+3));
550 ind4
= ind4
+ 4*ind
-9;
552 period
= (ind
+ ind2
*0.5+ind3
/3.f
+ind4
*0.25)*0.25;
556 period
= (ind
+ ind2
*0.5+ind3
/3.f
)*0.3333333;
559 //printf("period %f ind %d ind2 %d ind3 %d ind4 %d \n",period, ind,ind2,ind3,ind4);
561 //unit->m_tor=period;
562 //unit->m_torround= int(period+0.5);
571 //128 calculation calls for multiplying M and acf, calculates M as it goes apart from precalculated Gaussian or Raleigh distribution
572 void beatperiod(BeatTrack
*unit
,int j
, int whichm
)
574 int baseframe
= unit
->m_storedfcounter
+DFSTORE
;
575 float * acf
= unit
->m_acf
;
577 //int startindex= 512*j;
578 //int endindex=startindex+512;
582 //unit->m_timesig harmonics
583 for (int i
=1;i
<=(unit
->m_timesig
); ++i
) {
586 float wt
= 1.0/(float)num
;
588 for (int k
=0;k
<num
; ++k
) {
599 //assumes Mg appropriately rotated already
603 m
=g_m
; //Gaussian weighted context model
605 m
=unit
->m_mg
; //general model even weighting
609 if (sum
>unit
->m_besttorsum
) {
610 unit
->m_besttorsum
=sum
;
611 unit
->m_bestcolumn
=j
;
616 //j out of unit->m_torround
617 //differs to Davies original in that weight the most recent events more- want minimum reaction time
618 void findphase(BeatTrack
*unit
,int j
,int gaussflag
, int predicted
)
620 float * df
= unit
->m_df
;
622 int period
= unit
->m_torround
;
623 int baseframe
=unit
->m_storedfcounterend
+DFSTORE
;
629 numfit
= (int)(DFFRAMELENGTH
/period
)-1;
631 //testing backwards from the baseframe, weighting goes down as 1/k
634 for (int k
=0;k
<numfit
;++k
) {
637 int location
= (baseframe
-(period
*k
)-j
)%DFSTORE
;
639 sum
+= df
[location
]/((float)(k
+1));
643 //Gaussian focus weighting if desired
646 //difference of predicted from j, min distance within period
647 int diff
= sc_min(abs(predicted
-j
),abs(period
-predicted
+j
));
649 sum
*= unit
->m_phaseweights
[diff
];
653 if (sum
>unit
->m_bestphasescore
) {
655 unit
->m_bestphasescore
= sum
;
656 unit
->m_bestphase
= j
;
663 void setupphaseexpectation(BeatTrack
*unit
) //create Gaussian focussed matrix for phase
665 float * wts
= unit
->m_phaseweights
;
667 float sigma
= unit
->m_torround
* 0.25f
;
670 float mult
= 1.0/(2.5066283*sigma
);
671 float mult2
= 1.0/(2.0*sigma
*sigma
);
674 for (int i
=0; i
<128;++i
) {
675 wts
[i
]= mult
*(exp(-(i
*i
)*mult2
));
681 //why force a countdown each time? Why not keep a continuous buffer of previous periodp, periodg?
682 int detectperiodchange(BeatTrack
*unit
)
684 //stepthresh = 3.9017;
686 if(unit
->m_flagstep
==0) {
688 if(fabs(unit
->m_periodg
-unit
->m_periodp
) > 3.9017f
) {
693 unit
->m_flagstep
= unit
->m_flagstep
-1;
696 if(unit
->m_flagstep
) {
698 unit
->m_prevperiodp
[unit
->m_flagstep
-1]=unit
->m_periodp
;
701 if(unit
->m_flagstep
==1) {
705 if(fabs(2*unit
->m_prevperiodp
[0] - unit
->m_prevperiodp
[1] - unit
->m_prevperiodp
[2]) < 7.8034f
) //(2*3.9017)
715 void findmeter(BeatTrack
*unit
)
720 //float * acf= unit->m_acf;
722 // float * acf= unit->m_acf-1;
725 // int period = ((int)(unit->m_periodp+0.5));
727 // float three_energy=0.0;
728 // float four_energy=0.0;
730 // for(i=(3*period-2);i<(3*period+3);++i)
731 // three_energy += acf[i];
733 // for(i=(4*period-2);i<(4*period+3);++i)
734 // four_energy += acf[i];
736 // if((6*period+2)<512) {
738 // for(i=(6*period-2);i<(6*period+3);++i)
739 // three_energy += acf[i];
741 // for(i=(2*period-2);i<(2*period+3);++i)
742 // four_energy += acf[i];
745 // if (three_energy > four_energy)
746 // unit->m_timesig = 3;
749 //worked better in evaluation without any 3/4 at all!
752 //printf("time sig %d \n",unit->m_timesig);
757 //period is unit->m_tor, phase is unit->m_bestphase
758 // float m_tor; int m_torround;
759 void finaldecision(BeatTrack
*unit
)
763 unit
->m_currtempo
= 1.0/(unit
->m_tor
*unit
->m_frameperiod
);
765 unit
->m_phaseperblock
= ((float)unit
->mWorld
->mFullRate
.mBufLength
*(unit
->m_currtempo
))/((float)unit
->mWorld
->mSampleRate
);
767 //printf("SAMPLErate %f %f %f", unit->mWorld->mSampleRate,unit->m_phaseperblock,unit->m_currtempo);
769 //unit->m_amortisationstate control periods worth = 512/64 = 8
770 //float frameselapsed= 0.125*unit->m_amortisationstate;
771 //float timeelapsed= frameselapsed*unit->m_frameperiod;
773 float timeelapsed
= ((float)(unit
->m_amortisationsteps
)*(unit
->mWorld
->mFullRate
.mBufLength
)/((float)unit
->mWorld
->mSampleRate
));
775 timeelapsed
+= 7*unit
->m_frameperiod
; //compensation for detection function being delayed by 7 frames
777 float phaseelapsed
= timeelapsed
*(unit
->m_currtempo
);
779 float phasebeforeamort
= ((float)unit
->m_bestphase
/unit
->m_torround
);
781 //add phase to compensate for ELAPSEDTIME
782 unit
->m_currphase
= unit
->m_phase
= fmod(phasebeforeamort
+phaseelapsed
,(float)1.0);
787 //Now the format is standardised for the SC FFT UGen as
788 //dc, nyquist and then real/imag pairs for each bin going up successively in frequency
790 void complexdf(BeatTrack
*unit
)
792 float * fftbuf
= unit
->m_FFTBuf
;
794 float * prevmag
= unit
->m_prevmag
;
795 float * prevphase
= unit
->m_prevphase
;
796 float * predict
= unit
->m_predict
;
800 //printf("complex df time \n");
803 for (int k
=1; k
<NOVER2
; ++k
){
806 int index
= 2*k
; //k; //2*k;
808 float real
=fftbuf
[index
];
809 //N=1024 conventionally here
810 float imag
=fftbuf
[index
+1]; //fftbuf[N-index];
812 float mag
= sqrt(real
*real
+ imag
*imag
); // was 0.5*sqrt(real*real+ imag*imag); reduce by factor of 2 because of altivec side effect
813 float qmag
= prevmag
[k
];
817 float phase
= atan2(imag
,real
);
818 float oldphase
= predict
[k
];
820 predict
[k
]= 2*phase
- prevphase
[k
];
823 float phasediff
= phase
-oldphase
;
825 //if(k==2) printf("%f %f\n",phase, phasediff);
827 //tables for cos/sin/sqrt speeds up? sqrt(1-c*c) slower than sin
829 float realpart
= (qmag
-(mag
*cos(phasediff
)));
830 float imagpart
= (mag
*sin(phasediff
)); //no need for negative
832 float detect
= sqrt(realpart
*realpart
+ imagpart
*imagpart
);
834 //detect is always positive
836 sum
+=detect
; //(fmod(phase+(16*pi),twopi)); //detect;
842 //smoothing and peak picking operation, delay of 8 frames, must be taken account of in final phase correction
844 unit
->m_dfmemorycounter
=(unit
->m_dfmemorycounter
+1)%15;
845 unit
->m_dfmemory
[unit
->m_dfmemorycounter
]=sum
; //divide by num of bands to get a dB answer
849 float * dfmemory
=unit
->m_dfmemory
;
851 int refpos
=unit
->m_dfmemorycounter
+15;
852 int centrepos
=(refpos
-7)%15;
853 float centreval
=dfmemory
[centrepos
];
855 for (int k
=0;k
<15; ++k
) {
857 int pos
=(refpos
-k
)%15;
859 float nextval
= centreval
-dfmemory
[pos
];
867 if(rating
<0.0) rating
=0.0;
869 //increment first so this frame is unit->m_loudnesscounterdfcounter
870 unit
->m_dfcounter
=(unit
->m_dfcounter
+1)%DFSTORE
;
872 unit
->m_df
[unit
->m_dfcounter
]=rating
*0.1f
; //sum //divide by num of bands to get a dB answer