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 float * acf
= unit
->m_acf
;
576 //int startindex= 512*j;
577 //int endindex=startindex+512;
581 //unit->m_timesig harmonics
582 for (int i
=1;i
<=(unit
->m_timesig
); ++i
) {
585 float wt
= 1.0/(float)num
;
587 for (int k
=0;k
<num
; ++k
) {
598 //assumes Mg appropriately rotated already
602 m
=g_m
; //Gaussian weighted context model
604 m
=unit
->m_mg
; //general model even weighting
608 if (sum
>unit
->m_besttorsum
) {
609 unit
->m_besttorsum
=sum
;
610 unit
->m_bestcolumn
=j
;
615 //j out of unit->m_torround
616 //differs to Davies original in that weight the most recent events more- want minimum reaction time
617 void findphase(BeatTrack
*unit
,int j
,int gaussflag
, int predicted
)
619 float * df
= unit
->m_df
;
621 int period
= unit
->m_torround
;
622 int baseframe
=unit
->m_storedfcounterend
+DFSTORE
;
628 numfit
= (int)(DFFRAMELENGTH
/period
)-1;
630 //testing backwards from the baseframe, weighting goes down as 1/k
633 for (int k
=0;k
<numfit
;++k
) {
636 int location
= (baseframe
-(period
*k
)-j
)%DFSTORE
;
638 sum
+= df
[location
]/((float)(k
+1));
642 //Gaussian focus weighting if desired
645 //difference of predicted from j, min distance within period
646 int diff
= sc_min(abs(predicted
-j
),abs(period
-predicted
+j
));
648 sum
*= unit
->m_phaseweights
[diff
];
652 if (sum
>unit
->m_bestphasescore
) {
654 unit
->m_bestphasescore
= sum
;
655 unit
->m_bestphase
= j
;
662 void setupphaseexpectation(BeatTrack
*unit
) //create Gaussian focussed matrix for phase
664 float * wts
= unit
->m_phaseweights
;
666 float sigma
= unit
->m_torround
* 0.25f
;
669 float mult
= 1.0/(2.5066283*sigma
);
670 float mult2
= 1.0/(2.0*sigma
*sigma
);
673 for (int i
=0; i
<128;++i
) {
674 wts
[i
]= mult
*(exp(-(i
*i
)*mult2
));
680 //why force a countdown each time? Why not keep a continuous buffer of previous periodp, periodg?
681 int detectperiodchange(BeatTrack
*unit
)
683 //stepthresh = 3.9017;
685 if(unit
->m_flagstep
==0) {
687 if(fabs(unit
->m_periodg
-unit
->m_periodp
) > 3.9017f
) {
692 unit
->m_flagstep
= unit
->m_flagstep
-1;
695 if(unit
->m_flagstep
) {
697 unit
->m_prevperiodp
[unit
->m_flagstep
-1]=unit
->m_periodp
;
700 if(unit
->m_flagstep
==1) {
704 if(fabs(2*unit
->m_prevperiodp
[0] - unit
->m_prevperiodp
[1] - unit
->m_prevperiodp
[2]) < 7.8034f
) //(2*3.9017)
714 void findmeter(BeatTrack
*unit
)
719 //float * acf= unit->m_acf;
721 // float * acf= unit->m_acf-1;
724 // int period = ((int)(unit->m_periodp+0.5));
726 // float three_energy=0.0;
727 // float four_energy=0.0;
729 // for(i=(3*period-2);i<(3*period+3);++i)
730 // three_energy += acf[i];
732 // for(i=(4*period-2);i<(4*period+3);++i)
733 // four_energy += acf[i];
735 // if((6*period+2)<512) {
737 // for(i=(6*period-2);i<(6*period+3);++i)
738 // three_energy += acf[i];
740 // for(i=(2*period-2);i<(2*period+3);++i)
741 // four_energy += acf[i];
744 // if (three_energy > four_energy)
745 // unit->m_timesig = 3;
748 //worked better in evaluation without any 3/4 at all!
751 //printf("time sig %d \n",unit->m_timesig);
756 //period is unit->m_tor, phase is unit->m_bestphase
757 // float m_tor; int m_torround;
758 void finaldecision(BeatTrack
*unit
)
762 unit
->m_currtempo
= 1.0/(unit
->m_tor
*unit
->m_frameperiod
);
764 unit
->m_phaseperblock
= ((float)unit
->mWorld
->mFullRate
.mBufLength
*(unit
->m_currtempo
))/((float)unit
->mWorld
->mSampleRate
);
766 //printf("SAMPLErate %f %f %f", unit->mWorld->mSampleRate,unit->m_phaseperblock,unit->m_currtempo);
768 //unit->m_amortisationstate control periods worth = 512/64 = 8
769 //float frameselapsed= 0.125*unit->m_amortisationstate;
770 //float timeelapsed= frameselapsed*unit->m_frameperiod;
772 float timeelapsed
= ((float)(unit
->m_amortisationsteps
)*(unit
->mWorld
->mFullRate
.mBufLength
)/((float)unit
->mWorld
->mSampleRate
));
774 timeelapsed
+= 7*unit
->m_frameperiod
; //compensation for detection function being delayed by 7 frames
776 float phaseelapsed
= timeelapsed
*(unit
->m_currtempo
);
778 float phasebeforeamort
= ((float)unit
->m_bestphase
/unit
->m_torround
);
780 //add phase to compensate for ELAPSEDTIME
781 unit
->m_currphase
= unit
->m_phase
= fmod(phasebeforeamort
+phaseelapsed
,(float)1.0);
786 //Now the format is standardised for the SC FFT UGen as
787 //dc, nyquist and then real/imag pairs for each bin going up successively in frequency
789 void complexdf(BeatTrack
*unit
)
791 float * fftbuf
= unit
->m_FFTBuf
;
793 float * prevmag
= unit
->m_prevmag
;
794 float * prevphase
= unit
->m_prevphase
;
795 float * predict
= unit
->m_predict
;
799 //printf("complex df time \n");
802 for (int k
=1; k
<NOVER2
; ++k
){
805 int index
= 2*k
; //k; //2*k;
807 float real
=fftbuf
[index
];
808 //N=1024 conventionally here
809 float imag
=fftbuf
[index
+1]; //fftbuf[N-index];
811 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
812 float qmag
= prevmag
[k
];
816 float phase
= atan2(imag
,real
);
817 float oldphase
= predict
[k
];
819 predict
[k
]= 2*phase
- prevphase
[k
];
822 float phasediff
= phase
-oldphase
;
824 //if(k==2) printf("%f %f\n",phase, phasediff);
826 //tables for cos/sin/sqrt speeds up? sqrt(1-c*c) slower than sin
828 float realpart
= (qmag
-(mag
*cos(phasediff
)));
829 float imagpart
= (mag
*sin(phasediff
)); //no need for negative
831 float detect
= sqrt(realpart
*realpart
+ imagpart
*imagpart
);
833 //detect is always positive
835 sum
+=detect
; //(fmod(phase+(16*pi),twopi)); //detect;
841 //smoothing and peak picking operation, delay of 8 frames, must be taken account of in final phase correction
843 unit
->m_dfmemorycounter
=(unit
->m_dfmemorycounter
+1)%15;
844 unit
->m_dfmemory
[unit
->m_dfmemorycounter
]=sum
; //divide by num of bands to get a dB answer
848 float * dfmemory
=unit
->m_dfmemory
;
850 int refpos
=unit
->m_dfmemorycounter
+15;
851 int centrepos
=(refpos
-7)%15;
852 float centreval
=dfmemory
[centrepos
];
854 for (int k
=0;k
<15; ++k
) {
856 int pos
=(refpos
-k
)%15;
858 float nextval
= centreval
-dfmemory
[pos
];
866 if(rating
<0.0) rating
=0.0;
868 //increment first so this frame is unit->m_loudnesscounterdfcounter
869 unit
->m_dfcounter
=(unit
->m_dfcounter
+1)%DFSTORE
;
871 unit
->m_df
[unit
->m_dfcounter
]=rating
*0.1f
; //sum //divide by num of bands to get a dB answer