/*
	SuperCollider real time audio synthesis system
 Copyright (c) 2002 James McCartney. All rights reserved.
	http://www.audiosynth.com

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

//BeatTrack UGen implemented by Nick Collins (http://www.informatics.sussex.ac.uk/users/nc81/)
//post FFT UGen version 1 Nov 2007

//conversion of Matthew Davies autocorrelation beat tracking model, adapted for real-time use
//currently using QMUL complex domain onset detection function model

//#include "SC_PlugIn.h"
//#include <vecLib/vecLib.h>
//#include <string.h>
//#include <math.h>
//#include <stdlib.h>
//#include <stdio.h>

#include "ML.h"

//FFT data
//#define N 1024  //FFT size
//FFT size over 2
#define NOVER2 512
//#define NOVER4 256  //FFT size
//#define OVERLAP 512
//#define OVERLAPINDEX 512
//#define HOPSIZE 512

//#define FS 44100 //assumes fixed sampling rate
//#define FRAMESR 86.1328
//converted for different sampling rates
#define FRAMEPERIOD 0.01161
#define SKIP 128
//#define TIMEELAPSED 1.48608

//this data assumes LAGS is 128
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,};
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,};

//other functions
static void BeatTrack_dofft(BeatTrack *unit, uint32);
static void complexdf(BeatTrack *unit);
static void finaldecision(BeatTrack *unit);

//amortisation
static void autocorr(BeatTrack *unit,int j);
static void beatperiod(BeatTrack *unit,int j, int whichm);
static float findtor(BeatTrack *unit);

//as many amortisation steps as tor
static void findphase(BeatTrack *unit,int j,int gaussflag,int predicted);

static int detectperiodchange(BeatTrack *unit);
static void findmeter(BeatTrack *unit);
static void setupphaseexpectation(BeatTrack *unit); //create Gaussian focussed matrix for phase


void BeatTrack_Ctor(BeatTrack* unit)
{
	///////
	//check sampling rate and establish multipliers on estimates and FFT window size
	//down sampling by factor of two automatic

	unit->m_srate = unit->mWorld->mFullRate.mSampleRate;

	//if sample rate is 88200 or 96000, assume taking double size FFT to start with
	if(unit->m_srate > (44100.0*1.5)) unit->m_srate = unit->m_srate*0.5;

	unit->m_srateconversion = unit->m_srate/44100.0;

	//assumes base of 1024 FFT
	unit->m_frameperiod= (FRAMEPERIOD/unit->m_srateconversion); //in seconds //(int) ((FRAMEPERIOD/unit->m_srateconversion) +0.5);

	printf("srate %f conversion factor %f frame period %f \n", unit->m_srate, unit->m_srateconversion, unit->m_frameperiod);

	unit->m_prevmag= (float*)RTAlloc(unit->mWorld, NOVER2 * sizeof(float));
	unit->m_prevphase= (float*)RTAlloc(unit->mWorld, NOVER2 * sizeof(float));
	unit->m_predict= (float*)RTAlloc(unit->mWorld, NOVER2 * sizeof(float));

	////////time positions//////////
	unit->m_frame=1; //don't decide immediately, wait for maximum period!

	/////////df////////
	unit->m_dfcounter=DFSTORE-1;
	//random uncorrelated noise df store for initialisation
	//RGen& rgen = *unit->mParent->mRGen;

	//don't want this noise, want consistent starting point!
	for(int j=0;j<DFSTORE;++j) {
		unit->m_df[j]=0.0; //(2*rgen.frand() - 1.0);
	}

	unit->m_dfmemorycounter=14;

	Clear(15, unit->m_dfmemory);

	/////////tempo assess///////////
	unit->m_currtempo=2;

	////////phase assess///////////

	unit->m_currphase=0.0;

	unit->m_phase=0.0;

	//default of 2bps
	unit->m_phaseperblock= ((float)unit->mWorld->mFullRate.mBufLength*2)/((float)unit->mWorld->mSampleRate);

	unit->m_outputphase= unit->m_phase;
	unit->m_outputtempo= unit->m_currtempo;
	unit->m_outputphaseperblock= unit->m_phaseperblock;

	unit->halftrig=0;
	unit->q1trig=0;
	unit->q2trig=0;

	//amortisation and states
	unit->m_amortisationstate=0; //off
	unit->m_stateflag=0;
	unit->m_timesig=4;
	unit->m_flagstep=0;

	unit->mCalcFunc = (UnitCalcFunc)&BeatTrack_next;

	// initialize outputs
	ZOUT0(0) = 0.0;
	ZOUT0(1) = 0.0;
	ZOUT0(2) = 0.0;
	ZOUT0(3) = unit->m_outputtempo;
}



void BeatTrack_Dtor(BeatTrack *unit)
{
	RTFree(unit->mWorld, unit->m_prevmag);
	RTFree(unit->mWorld, unit->m_prevphase);
	RTFree(unit->mWorld, unit->m_predict);
}


void BeatTrack_next(BeatTrack *unit, int wrongNumSamples)
{
	//float *in = IN(0);

	//printf("%d \n",wrongNumSamples);
	//int numSamples = unit->mWorld->mFullRate.mBufLength;

	//conditions in reverse order to avoid immediate spillover
	//printf("state %d \n",unit->m_amortisationstate);

	//keeps incrementing but will be reset with each calculation run
	unit->m_amortisationsteps=unit->m_amortisationsteps+1;

	//if state nonzero do something
	switch(unit->m_amortisationstate) {
		case 0:
			break; //do nothing case
		case 1: //calculate acf
			autocorr(unit,unit->m_amortcount);

			unit->m_amortcount=unit->m_amortcount+1;

			if(unit->m_amortcount==unit->m_amortlength) {
				unit->m_amortisationstate=2;
				unit->m_amortlength=128;
				unit->m_amortcount=0;

				unit->m_bestcolumn=0;
				unit->m_besttorsum= -1000.0;

			}

				break;
		case 2: //periodp
			beatperiod(unit,unit->m_amortcount,0);

			unit->m_amortcount=unit->m_amortcount+1;

			if(unit->m_amortcount==unit->m_amortlength) {

				unit->m_periodp=findtor(unit);

				if(unit->m_stateflag==1) {
					unit->m_amortisationstate=3;
					unit->m_amortlength=128;
					unit->m_amortcount=0;

					unit->m_bestcolumn=0;
					unit->m_besttorsum= -1000.0;

				} else {
					unit->m_periodg= -1000; //will always trigger initially
					unit->m_amortisationstate=4;
				}
			}

				break;
		case 3: //periodg
			beatperiod(unit,unit->m_amortcount,1);
			unit->m_amortcount=unit->m_amortcount+1;

			if(unit->m_amortcount==unit->m_amortlength) {

				unit->m_periodg=findtor(unit);

				unit->m_amortisationstate=4;
			}

				break;
		case 4: //stepdetect/constdetect

			if(detectperiodchange(unit)) {

				unit->m_amortisationstate=5;
				unit->m_amortlength=128;
				unit->m_amortcount=0;

				unit->m_bestcolumn=0;
				unit->m_besttorsum= -1000.0;

				unit->m_stateflag=1;
				findmeter(unit);

				//set up Gaussian weighting centred on periodp
				int startindex= 128- ((int)(unit->m_periodp+0.5));

				float * mg=unit->m_mg;

				for (int ii=0; ii<128;++ii){
					mg[ii]= g_mg[startindex+ii];
				}

			} else {

				if(unit->m_stateflag==1)
					unit->m_tor= unit->m_periodg;
				else
					unit->m_tor= unit->m_periodp;

				unit->m_torround= int(unit->m_tor+0.5);

				unit->m_amortisationstate=7;
				unit->m_amortlength=unit->m_torround;
				unit->m_amortcount=0;
			}

			break;

		case 5: //redo periodg calculation
			beatperiod(unit,unit->m_amortcount,1);
			unit->m_amortcount=unit->m_amortcount+1;

			if(unit->m_amortcount==unit->m_amortlength) {

				unit->m_periodg=findtor(unit);

				unit->m_tor= unit->m_periodg;
				unit->m_torround= int(unit->m_tor+0.5f);

				unit->m_amortisationstate=6;
				unit->m_amortlength=unit->m_torround;
				unit->m_amortcount=0;

				setupphaseexpectation(unit);

				//don't need to reset change flag since it isn't stored
			}

				break;
		case 6: //flat phase calc after move to context, avoids bias
			findphase(unit,unit->m_amortcount,0,0);
			unit->m_amortcount=unit->m_amortcount+1;

			if(unit->m_amortcount==unit->m_amortlength) {

				unit->m_amortisationstate=8; //final state
			}

				break;

		case 7: //phase calc with possible gaussian narrowing of the allowed phases

			findphase(unit,unit->m_amortcount,unit->m_stateflag,(int)(unit->m_currphase*unit->m_torround+0.5f));
			unit->m_amortcount=unit->m_amortcount+1;

			if(unit->m_amortcount==unit->m_amortlength) {

				unit->m_amortisationstate=8; //final state
			}

				break;
		case 8:

			finaldecision(unit);
			unit->m_amortisationstate=0;
			break;

		default:
			break;
	}


	//MUST CHECK IF INCIDENT FFT IS >1, if so update buffer with appropriate coefficients

	float fbufnum = ZIN0(0);

	//next FFT bufffer ready, update
	//assuming at this point that buffer precalculated for any resampling
	if (!(fbufnum<0)) {

		unit->m_frame= unit->m_frame+1;
		BeatTrack_dofft(unit, (uint32)fbufnum);

	}


	//test if impulse to output
	unit->m_phase+=unit->m_phaseperblock;

	//if not locked, update output phase from model phase, else keep a separate output phase

	float lock= ZIN0(1);
	//printf("lock %f \n",lock);

	if (lock<0.5f) {
		unit->m_outputphase= unit->m_phase;
		unit->m_outputtempo= unit->m_currtempo;
		unit->m_outputphaseperblock= unit->m_phaseperblock;
	} else
		unit->m_outputphase+=unit->m_outputphaseperblock;

	if (unit->m_phase >= 1.f) unit->m_phase-= 1.f;

	//0 is beat, 1 is quaver, 2 is semiquaver, 3 is actual current tempo in bps
	//so no audio accuracy with beats, just asap, may as well be control rate
	ZOUT0(0)=0.0;
	ZOUT0(1)=0.0;
	ZOUT0(2)=0.0;
	ZOUT0(3)=unit->m_outputtempo; //*0.016666667;

	//output beat
	if (unit->m_outputphase >= 1.f) {

		//printf("beat \n");

		unit->m_outputphase -= 1.f;
		ZOUT0(0)=1.0;
		ZOUT0(1)=1.0;
		ZOUT0(2)=1.0;
		unit->halftrig=0;
		unit->q1trig=0;
		unit->q2trig=0;
	}

	if (unit->m_outputphase>=0.5f && unit->halftrig==0) {
		ZOUT0(1)=1.0;
		ZOUT0(2)=1.0;
		unit->halftrig=1;
	}

	if (unit->m_outputphase>=0.25f && unit->q1trig==0) {
		ZOUT0(2)=1.0;
		unit->q1trig=1;
	}

	if (unit->m_outputphase>=0.75f && unit->q2trig==0) {
		ZOUT0(2)=1.0;
		unit->q2trig=1;
	}

}



//

//calculation function once FFT data ready
void BeatTrack_dofft(BeatTrack *unit, uint32 ibufnum)
{
	World *world = unit->mWorld;
	SndBuf *buf;
	if (ibufnum >= world->mNumSndBufs) {
		int localBufNum = ibufnum - world->mNumSndBufs;
		Graph *parent = unit->mParent;
		if(localBufNum <= parent->localBufNum) {
			buf = parent->mLocalSndBufs + localBufNum;
		} else {
			buf = world->mSndBufs;
		}
	} else {
		buf = world->mSndBufs + ibufnum;
	}
	LOCK_SNDBUF(buf);
	//int numbins = buf->samples - 2 >> 1;

	unit->m_FFTBuf = buf->data; //just assign it!

	//transfer data to fftbuf in the format expected by this plugin

	//ideally, should do this part separate to plug-in as well, so can compare different detection functions;
	//also, can run multiple in parallel with own autocorrelations; committee? Committee.ar(period1, phase1, period2, phase2, period3, phase3)...
	//chooses predominant estimate?
	//feature detection function
	complexdf(unit);

	if (unit->m_frame%SKIP==0) {

		//printf("amortisation time \n");

		//amortisation- 8 control periods in a frame
		//have 2000 calcs to do, split over 100 control periods = 6400 samples, ie one tempo per control period

		unit->m_bestcolumn=0;
		unit->m_besttorsum= -1000.0;

		unit->m_bestphasescore = -1000.0;
		unit->m_bestphase = 0;

		//state 0 is do nothing
		unit->m_amortisationstate=1;
		unit->m_amortcount=0;
		unit->m_amortlength=128;
		unit->m_amortisationsteps=0;

		//fix time reference for calculations, so it doesn't update during the amortisation- this is the beginning of the df frame
		unit->m_storedfcounter= unit->m_dfcounter+DFSTORE-DFFRAMELENGTH;

		//ref for phase calculations
		unit->m_storedfcounterend= unit->m_dfcounter;

		//unit->m_fftstoreposhold= unit->m_fftstorepos;

		unit->m_currphase=unit->m_phase;

	}

}


void autocorr(BeatTrack *unit,int j)
{
	int baseframe=unit->m_storedfcounter+DFSTORE;
	float * df= unit->m_df;
	float * acf= unit->m_acf;

	//work out four lags each time
	for (int k=0;k<4;++k) {

		int lag=4*j+k;

		int correction= abs(lag-DFFRAMELENGTH);

		float sum=0.0;

		for (int i=lag;i<DFFRAMELENGTH; ++i) {

			float val1= df[(i+baseframe)%DFSTORE];
			float val2= df[(i+baseframe-lag)%DFSTORE];

			sum+= val1*val2;
		}

		acf[lag]=sum*correction;

	}

}



//timesig 4 has one more sum term
//indices as MATLAB but need to correct maxinds to be in range of tested, not in global range
float findtor(BeatTrack *unit)
{
	float maxval, val;
	int ind2,ind3,ind4;

	//put into MATLAB indexing, from 1 to 512
	int ind= unit->m_bestcolumn+1;

	float * acf= unit->m_acf-1;

	ind2=0;
	maxval=-1000;

	for(int i=2*ind-1;i<=(2*ind+1);++i){

		val=acf[i];

		if(val>maxval) {

			maxval=val;
			ind2=i-(2*ind-1)+1;
		}

	}

	//[val2,ind2] = max(acf(2*ind-1:2*ind+1));
	ind2 = ind2 + 2*(ind+1)-2;

	ind3=0;
	maxval=-1000;

	for(int i=3*ind-2;i<=(3*ind+2);++i){

		val=acf[i];

		if(val>maxval) {

			maxval=val;
			ind3=i-(3*ind-2)+1;
		}

	}

	//[val3,ind3] = max(acf(3*ind-2:3*ind+2));
	ind3 = ind3 + 3*ind-4;

	float period;

	if (unit->m_timesig==4) {

		ind4=0;
		maxval=-1000;

		for(int i=4*ind-3;i<=4*ind+3;++i){

			val=acf[i];

			if(val>maxval) {

				maxval=val;
				ind4=i-(4*ind-3)+1;
			}

		}

		//[val4,ind4] = max(acf(4*ind-3:4*ind+3));
		ind4 = ind4 + 4*ind-9;

		period= (ind+ ind2*0.5+ind3/3.f +ind4*0.25)*0.25;

	} else

		period= (ind+ ind2*0.5+ind3/3.f)*0.3333333;


	//printf("period %f ind %d ind2 %d ind3 %d ind4 %d \n",period, ind,ind2,ind3,ind4);

	//unit->m_tor=period;
	//unit->m_torround= int(period+0.5);
	//

	return period;
}




//128 calculation calls for multiplying M and acf, calculates M as it goes apart from precalculated Gaussian or Raleigh distribution
void beatperiod(BeatTrack *unit,int j, int whichm)
{
	float * acf = unit->m_acf;

	//int startindex= 512*j;
	//int endindex=startindex+512;

	float sum=0.0;

	//unit->m_timesig harmonics
	for (int i=1;i<=(unit->m_timesig); ++i) {

		int num = 2*i-1;
		float wt= 1.0/(float)num;

		for (int k=0;k<num; ++k) {

			int pos= k+(i*j);

			//m[startindex+pos]
			if(pos<512)
				sum+= acf[pos]*wt;
		}

	}

	//assumes Mg appropriately rotated already
	float * m;

	if(whichm)
		m=g_m; //Gaussian weighted context model
	else
		m=unit->m_mg; //general model even weighting

	sum=sum*m[j];

	if (sum>unit->m_besttorsum) {
		unit->m_besttorsum=sum;
		unit->m_bestcolumn=j;
	}
}


//j out of unit->m_torround
//differs to Davies original in that weight the most recent events more- want minimum reaction time
void findphase(BeatTrack *unit,int j,int gaussflag, int predicted)
{
	float * df= unit->m_df;

	int period= unit->m_torround;
	int baseframe=unit->m_storedfcounterend+DFSTORE;

	int numfit= -1;

	if(period != 0)
	//round down
	numfit= (int)(DFFRAMELENGTH/period)-1;

	//testing backwards from the baseframe, weighting goes down as 1/k
	float sum=0.0;

	for (int k=0;k<numfit;++k) {

		//j is phase to test
		int location= (baseframe-(period*k)-j)%DFSTORE;

		sum+= df[location]/((float)(k+1));

	}

	//Gaussian focus weighting if desired
	if (gaussflag) {

		//difference of predicted from j, min distance within period
		int diff= sc_min(abs(predicted-j),abs(period-predicted+j));

		sum *= unit->m_phaseweights[diff];

	}

	if (sum>unit->m_bestphasescore) {

		unit->m_bestphasescore = sum;
		unit->m_bestphase = j;

	}

}

//, int predicted
void setupphaseexpectation(BeatTrack *unit)  //create Gaussian focussed matrix for phase
{
	float * wts= unit->m_phaseweights;

	float sigma= unit->m_torround * 0.25f;
	//float mu=period;

	float mult= 1.0/(2.5066283*sigma);
	float mult2= 1.0/(2.0*sigma*sigma);

	//unit->m_torround
	for (int i=0; i<128;++i) {
		wts[i]= mult*(exp(-(i*i)*mult2));
	}

}


//why force a countdown each time? Why not keep a continuous buffer of previous periodp, periodg?
int detectperiodchange(BeatTrack *unit)
{
	//stepthresh = 3.9017;

	if(unit->m_flagstep==0) {

		if(fabs(unit->m_periodg-unit->m_periodp) > 3.9017f) {
			unit->m_flagstep= 3;
		}

	} else {
		unit->m_flagstep= unit->m_flagstep-1;
	}

	if(unit->m_flagstep) {

		unit->m_prevperiodp[unit->m_flagstep-1]=unit->m_periodp;
	}

	if(unit->m_flagstep==1) {

		unit->m_flagstep= 0;

		if(fabs(2*unit->m_prevperiodp[0] - unit->m_prevperiodp[1] - unit->m_prevperiodp[2]) < 7.8034f) //(2*3.9017)
			return 1;

	}

	return 0;

}

//add test
void findmeter(BeatTrack *unit)
{

	//int i;

	//float * acf= unit->m_acf;

//	float * acf= unit->m_acf-1;
//
//
//	int period = ((int)(unit->m_periodp+0.5));
//
//	float three_energy=0.0;
//	float four_energy=0.0;
//
//	for(i=(3*period-2);i<(3*period+3);++i)
//		three_energy += acf[i];
//
//	for(i=(4*period-2);i<(4*period+3);++i)
//		four_energy += acf[i];
//
//	if((6*period+2)<512) {
//
//		for(i=(6*period-2);i<(6*period+3);++i)
//			three_energy += acf[i];
//
//		for(i=(2*period-2);i<(2*period+3);++i)
//			four_energy += acf[i];
//	}
//
//	if (three_energy > four_energy)
//		unit->m_timesig = 3;
//	else

//worked better in evaluation without any 3/4 at all!
		unit->m_timesig = 4;

	//printf("time sig %d \n",unit->m_timesig);

}


//period is unit->m_tor, phase is unit->m_bestphase
//	float m_tor; int m_torround;
void finaldecision(BeatTrack *unit)
{
	//int i,j;

	unit->m_currtempo= 1.0/(unit->m_tor*unit->m_frameperiod);

	unit->m_phaseperblock= ((float)unit->mWorld->mFullRate.mBufLength*(unit->m_currtempo))/((float)unit->mWorld->mSampleRate);

	//printf("SAMPLErate %f %f %f", unit->mWorld->mSampleRate,unit->m_phaseperblock,unit->m_currtempo);

	//unit->m_amortisationstate control periods worth = 512/64 = 8
	//float frameselapsed= 0.125*unit->m_amortisationstate;
	//float timeelapsed= frameselapsed*unit->m_frameperiod;

	float timeelapsed= ((float)(unit->m_amortisationsteps)*(unit->mWorld->mFullRate.mBufLength)/((float)unit->mWorld->mSampleRate));

	timeelapsed += 7*unit->m_frameperiod; //compensation for detection function being delayed by 7 frames

	float phaseelapsed= timeelapsed*(unit->m_currtempo);

	float phasebeforeamort= ((float)unit->m_bestphase/unit->m_torround);

	//add phase to compensate for ELAPSEDTIME
	unit->m_currphase= unit->m_phase = fmod(phasebeforeamort+phaseelapsed,(float)1.0);

}


//Now the format is standardised for the SC FFT UGen as
//dc, nyquist and then real/imag pairs for each bin going up successively in frequency

void complexdf(BeatTrack *unit)
{
	float * fftbuf= unit->m_FFTBuf;

	float * prevmag= unit->m_prevmag;
	float * prevphase= unit->m_prevphase;
	float * predict= unit->m_predict;

	float sum=0.0;

	//printf("complex df time \n");

	//sum bins 2 to 256
	for (int k=1; k<NOVER2; ++k){

			//Change to fftw
			int index= 2*k; //k; //2*k;

			float real=fftbuf[index];
			//N=1024 conventionally here
			float imag=fftbuf[index+1]; //fftbuf[N-index];

			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
			float qmag= prevmag[k];

			prevmag[k]=mag;

			float phase= atan2(imag,real);
			float oldphase = predict[k];

			predict[k]= 2*phase- prevphase[k];
			prevphase[k]= phase;

			float phasediff= phase-oldphase;

			//if(k==2) printf("%f %f\n",phase, phasediff);

			//tables for cos/sin/sqrt speeds up? sqrt(1-c*c) slower than sin

			float realpart= (qmag-(mag*cos(phasediff)));
			float imagpart= (mag*sin(phasediff)); //no need for negative

			float detect= sqrt(realpart*realpart + imagpart*imagpart);

			//detect is always positive
			//if(k==1)
			sum+=detect; //(fmod(phase+(16*pi),twopi)); //detect;

			//if(k==1) sum+=mag;
	}


	//smoothing and peak picking operation, delay of 8 frames, must be taken account of in final phase correction

	unit->m_dfmemorycounter=(unit->m_dfmemorycounter+1)%15;
	unit->m_dfmemory[unit->m_dfmemorycounter]=sum; //divide by num of bands to get a dB answer

	float rating=0.0;

	float * dfmemory=unit->m_dfmemory;

	int refpos=unit->m_dfmemorycounter+15;
	int centrepos=(refpos-7)%15;
	float centreval=dfmemory[centrepos];

	for (int k=0;k<15; ++k) {

		int pos=(refpos-k)%15;

		float nextval= centreval-dfmemory[pos];

		if (nextval<0.0)
			nextval=nextval*10;

		rating+=nextval;
	}

	if(rating<0.0) rating=0.0;

	//increment first so this frame is unit->m_loudnesscounterdfcounter
	unit->m_dfcounter=(unit->m_dfcounter+1)%DFSTORE;

	unit->m_df[unit->m_dfcounter]=rating*0.1f; //sum //divide by num of bands to get a dB answer

}
