changeset 46:af7739411685

Added all source code
author Adam Stark <adamstark@users.noreply.github.com>
date Tue, 21 Jan 2014 00:10:11 +0000
parents 493a22e749f8
children 9f45f9dbc6b5
files .hgignore python-module/btrack_python_module.cpp python-module/setup.py src/BTrack.cpp src/BTrack.h src/OnsetDetectionFunction.cpp src/OnsetDetectionFunction.h
diffstat 7 files changed, 2040 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Tue Jan 21 00:10:11 2014 +0000
@@ -0,0 +1,1 @@
+python-module/build
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python-module/btrack_python_module.cpp	Tue Jan 21 00:10:11 2014 +0000
@@ -0,0 +1,362 @@
+#include <iostream>
+#include <Python.h>
+#include "../src/OnsetDetectionFunction.h"
+#include "../src/BTrack.h"
+#include <numpy/arrayobject.h>
+
+static PyObject * btrack_onsetdf(PyObject *dummy, PyObject *args) 
+{
+    PyObject *arg1=NULL;
+    PyObject *arr1=NULL;
+    
+    if (!PyArg_ParseTuple(args, "O", &arg1)) 
+    {
+        return NULL;
+    }
+    
+    arr1 = PyArray_FROM_OTF(arg1, NPY_DOUBLE, NPY_IN_ARRAY); 
+    if (arr1 == NULL) 
+    {
+        return NULL;
+    }
+
+
+    
+    ////////// GET INPUT DATA ///////////////////
+    
+    // get data as array
+    double* data = (double*) PyArray_DATA(arr1);
+    
+    // get array size
+    int signal_length = PyArray_Size((PyObject*)arr1);
+    //int k = (int) theSize;
+    
+    // get data type 
+    char type = PyArray_DESCR(arr1)->type;
+    
+    ////////// BEGIN PROCESS ///////////////////
+    int hsize = 512;
+    int fsize = 1024;
+    int df_type = 6;
+    int numframes;
+    double buffer[hsize];	// buffer to hold one hopsize worth of audio samples
+
+    
+    // get number of audio frames, given the hop size and signal length
+	numframes = (int) floor(((double) signal_length) / ((double) hsize));
+    
+    OnsetDetectionFunction onset(hsize,fsize,df_type,1);
+
+    double df[numframes];
+    
+
+    
+    ///////////////////////////////////////////
+	//////// Begin Processing Loop ////////////
+	
+	for (int i=0;i < numframes;i++)
+	{		
+		// add new samples to frame
+		for (int n = 0;n < hsize;n++)
+		{
+			buffer[n] = data[(i*hsize)+n];
+		}
+		
+		df[i] = onset.getDFsample(buffer);
+		
+	}
+	
+	///////// End Processing Loop /////////////
+	///////////////////////////////////////////
+    
+    
+    ////////// END PROCESS ///////////////////
+    
+    
+    
+    ////////// CREATE ARRAY AND RETURN IT ///////////////////
+    int nd=1;
+    npy_intp m= numframes;
+    //double fArray[5] = {0,1,2,3,4};
+    
+    PyObject* c=PyArray_SimpleNew(nd, &m, NPY_DOUBLE);
+    
+    void *arr_data = PyArray_DATA((PyArrayObject*)c);
+        
+    memcpy(arr_data, df, PyArray_ITEMSIZE((PyArrayObject*) c) * m); 
+    
+     
+    Py_DECREF(arr1);  
+    Py_INCREF(Py_None); 
+    //return Py_None;
+    
+    return (PyObject *)c;
+    
+    //return Py_BuildValue("c", type);
+    //return Py_BuildValue("d", sum);
+    //return Py_BuildValue("i", k);
+/*    
+fail:
+    Py_XDECREF(arr1); 
+    Py_XDECREF(arr2); 
+    PyArray_XDECREF_ERR(oarr); 
+    return NULL;*/
+}
+
+
+static PyObject * btrack_btrack(PyObject *dummy, PyObject *args) 
+{
+    PyObject *arg1=NULL;
+    PyObject *arr1=NULL;
+    
+    if (!PyArg_ParseTuple(args, "O", &arg1)) 
+    {
+        return NULL;
+    }
+    
+    arr1 = PyArray_FROM_OTF(arg1, NPY_DOUBLE, NPY_IN_ARRAY); 
+    if (arr1 == NULL) 
+    {
+        return NULL;
+    }
+    
+    
+    
+    ////////// GET INPUT DATA ///////////////////
+    
+    // get data as array
+    double* data = (double*) PyArray_DATA(arr1);
+    
+    // get array size
+    int signal_length = PyArray_Size((PyObject*)arr1);
+    //int k = (int) theSize;
+    
+    // get data type 
+    char type = PyArray_DESCR(arr1)->type;
+    
+    ////////// BEGIN PROCESS ///////////////////
+    int hsize = 512;
+    int fsize = 1024;
+    int df_type = 6;
+    int numframes;
+    double buffer[hsize];	// buffer to hold one hopsize worth of audio samples
+    
+    
+    // get number of audio frames, given the hop size and signal length
+	numframes = (int) floor(((double) signal_length) / ((double) hsize));
+    
+    OnsetDetectionFunction onset(hsize,fsize,df_type,1);
+    BTrack b;
+    
+    b.initialise((int) hsize);	// initialise beat tracker
+	
+	// set parameters
+    //b.setparams(0.9,5);
+    
+    double df[numframes];
+    double beats[5000];
+    int beatnum = 0;
+    float df_val;
+    
+    ///////////////////////////////////////////
+	//////// Begin Processing Loop ////////////
+	
+	for (int i=0;i < numframes;i++)
+	{		
+		// add new samples to frame
+		for (int n = 0;n < hsize;n++)
+		{
+			buffer[n] = data[(i*hsize)+n];
+		}
+		
+		df[i] = onset.getDFsample(buffer);
+        
+        df_val = (float) (df[i] + 0.0001);
+                
+		b.process(df_val);				// process df sample in beat tracker
+		
+		if (b.playbeat == 1)
+		{
+			beats[beatnum] = (((double) hsize) / 44100) * ((double) i);
+			beatnum = beatnum + 1;	
+		}
+		
+	}
+	
+	///////// End Processing Loop /////////////
+	///////////////////////////////////////////
+    
+    
+    ////////// END PROCESS ///////////////////
+    
+    double beats_out[beatnum];          // create output array
+    
+    // copy beats into output array
+    for (int i = 0;i < beatnum;i++)     
+    {
+        beats_out[i] = beats[i];
+    }
+    
+    
+    
+    ////////// CREATE ARRAY AND RETURN IT ///////////////////
+    int nd=1;
+    npy_intp m= beatnum;
+    //double fArray[5] = {0,1,2,3,4};
+    
+    PyObject* c=PyArray_SimpleNew(nd, &m, NPY_DOUBLE);
+    
+    void *arr_data = PyArray_DATA((PyArrayObject*)c);
+    
+    memcpy(arr_data, beats_out, PyArray_ITEMSIZE((PyArrayObject*) c) * m); 
+    
+    
+    Py_DECREF(arr1);  
+    Py_INCREF(Py_None); 
+    //return Py_None;
+    
+    return (PyObject *)c;
+    
+    //return Py_BuildValue("c", type);
+    //return Py_BuildValue("d", sum);
+    //return Py_BuildValue("i", k);
+    /*    
+     fail:
+     Py_XDECREF(arr1); 
+     Py_XDECREF(arr2); 
+     PyArray_XDECREF_ERR(oarr); 
+     return NULL;*/
+}
+
+static PyObject * btrack_btrack_df(PyObject *dummy, PyObject *args) 
+{
+    PyObject *arg1=NULL;
+    PyObject *arr1=NULL;
+    
+    if (!PyArg_ParseTuple(args, "O", &arg1)) 
+    {
+        return NULL;
+    }
+    
+    arr1 = PyArray_FROM_OTF(arg1, NPY_DOUBLE, NPY_IN_ARRAY); 
+    if (arr1 == NULL) 
+    {
+        return NULL;
+    }
+    
+    
+    
+    ////////// GET INPUT DATA ///////////////////
+    
+    // get data as array
+    double* data = (double*) PyArray_DATA(arr1);
+    
+    // get array size
+    int numframes = PyArray_Size((PyObject*)arr1);
+    //int k = (int) theSize;
+    
+    // get data type 
+    char type = PyArray_DESCR(arr1)->type;
+    
+    ////////// BEGIN PROCESS ///////////////////
+    int hsize = 512;
+
+    BTrack b;
+    
+    b.initialise((int) hsize);	// initialise beat tracker
+	
+	// set parameters
+    //b.setparams(0.9,5);
+    
+    double beats[5000];
+    int beatnum = 0;
+    float df_val;
+    
+    ///////////////////////////////////////////
+	//////// Begin Processing Loop ////////////
+	
+	for (int i=0;i < numframes;i++)
+	{		
+        df_val = (float) (data[i] + 0.0001);
+        
+		b.process(df_val);				// process df sample in beat tracker
+		
+		if (b.playbeat == 1)
+		{
+			beats[beatnum] = (((double) hsize) / 44100) * ((double) i);
+			beatnum = beatnum + 1;	
+		}
+		
+	}
+	
+	///////// End Processing Loop /////////////
+	///////////////////////////////////////////
+    
+    
+    ////////// END PROCESS ///////////////////
+    
+    double beats_out[beatnum];          // create output array
+    
+    
+    // copy beats into output array
+    for (int i = 0;i < beatnum;i++)     
+    {
+        beats_out[i] = beats[i];
+    }
+    
+    
+    ////////// CREATE ARRAY AND RETURN IT ///////////////////
+    int nd=1;
+    npy_intp m= beatnum;
+    //double fArray[5] = {0,1,2,3,4};
+    
+    PyObject* c=PyArray_SimpleNew(nd, &m, NPY_DOUBLE);
+    
+    void *arr_data = PyArray_DATA((PyArrayObject*)c);
+    
+    memcpy(arr_data, beats_out, PyArray_ITEMSIZE((PyArrayObject*) c) * m); 
+    
+    
+    Py_DECREF(arr1);  
+    Py_INCREF(Py_None); 
+    //return Py_None;
+    
+    return (PyObject *)c;
+    
+    //return Py_BuildValue("c", type);
+    //return Py_BuildValue("d", sum);
+    //return Py_BuildValue("i", k);
+    /*    
+     fail:
+     Py_XDECREF(arr1); 
+     Py_XDECREF(arr2); 
+     PyArray_XDECREF_ERR(oarr); 
+     return NULL;*/
+}
+
+
+
+static PyMethodDef btrack_methods[] = {
+    { "onsetdf",btrack_onsetdf,METH_VARARGS,"onset detection function"},
+    { "btrack",btrack_btrack,METH_VARARGS,"beat tracker"},
+    { "btrack_df",btrack_btrack_df,METH_VARARGS,"beat tracker with detection function input"},
+    {NULL, NULL, 0, NULL} /* Sentinel */
+};
+
+PyMODINIT_FUNC initbtrack(void)
+{
+    (void)Py_InitModule("btrack", btrack_methods);
+    import_array();
+}
+
+int main(int argc, char *argv[])
+{
+    /* Pass argv[0] to the Python interpreter */
+    Py_SetProgramName(argv[0]);
+    
+    /* Initialize the Python interpreter.  Required. */
+    Py_Initialize();
+    
+    /* Add a static module */
+    initbtrack();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python-module/setup.py	Tue Jan 21 00:10:11 2014 +0000
@@ -0,0 +1,16 @@
+# setup.py
+# build command : python setup.py build build_ext --inplace
+from numpy.distutils.core import setup, Extension
+import os, numpy
+
+name = 'btrack'
+sources = ['btrack_python_module.cpp','../src/OnsetDetectionFunction.cpp','../src/BTrack.cpp']
+
+include_dirs = [
+                numpy.get_include(),'/usr/local/include'
+                ]
+
+setup( name = 'BTtrack',
+      include_dirs = include_dirs,
+      ext_modules = [Extension(name, sources,libraries = ['fftw3','samplerate'])]
+      )
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/BTrack.cpp	Tue Jan 21 00:10:11 2014 +0000
@@ -0,0 +1,665 @@
+//=======================================================================
+/** @file BTrack.cpp
+ *  @brief Implementation file for the BTrack beat tracker
+ *  @author Adam Stark
+ *  @copyright Copyright (C) 2008-2014  Queen Mary University of London
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+//=======================================================================
+
+#include <iostream>
+#include <cmath>
+#include "BTrack.h"
+#include "samplerate.h"
+using namespace std;
+
+
+
+
+//-------------------------------------------------------------------------------
+// Constructor
+BTrack :: BTrack()
+{	
+	float rayparam = 43;
+	float pi = 3.14159265;
+	
+	
+	// initialise parameters
+	tightness = 5;
+	alpha = 0.9;
+	tempo = 120;
+	est_tempo = 120;
+	p_fact = 60.*44100./512.;
+	
+	m0 = 10;
+	beat = -1;
+	
+	playbeat = 0;
+	
+	
+	
+	
+	// create rayleigh weighting vector
+	for (int n = 0;n < 128;n++)
+	{
+		wv[n] = ((float) n / pow(rayparam,2)) * exp((-1*pow((float)-n,2)) / (2*pow(rayparam,2)));
+	}
+	
+	// initialise prev_delta
+	for (int i = 0;i < 41;i++)
+	{
+		prev_delta[i] = 1;
+	}
+	
+	float t_mu = 41/2;
+	float m_sig;
+	float x;
+	// create tempo transition matrix
+	m_sig = 41/8;
+	for (int i = 0;i < 41;i++)
+	{
+		for (int j = 0;j < 41;j++)
+		{
+			x = j+1;
+			t_mu = i+1;
+			t_tmat[i][j] = (1 / (m_sig * sqrt(2*pi))) * exp( (-1*pow((x-t_mu),2)) / (2*pow(m_sig,2)) );
+		}
+	}	
+	
+	// tempo is not fixed
+	tempofix = 0;
+}
+
+//-------------------------------------------------------------------------------
+// Destructor
+BTrack :: ~BTrack()
+{	
+	
+}
+
+//-------------------------------------------------------------------------------
+// Initialise with frame size and set all frame sizes accordingly
+void BTrack :: initialise(int fsize)
+{	
+	framesize = fsize;
+	dfbuffer_size = (512*512)/fsize;		// calculate df buffer size
+	
+	bperiod = round(60/((((float) fsize)/44100)*tempo));
+	
+	dfbuffer = new float[dfbuffer_size];	// create df_buffer
+	cumscore = new float[dfbuffer_size];	// create cumscore
+	
+	
+	// initialise df_buffer to zeros
+	for (int i = 0;i < dfbuffer_size;i++)
+	{
+		dfbuffer[i] = 0;
+		cumscore[i] = 0;
+		
+		
+		if ((i %  ((int) round(bperiod))) == 0)
+		{
+			dfbuffer[i] = 1;
+		}
+	}
+}
+
+//-------------------------------------------------------------------------------
+// Add new sample to buffer and apply beat tracking
+void BTrack :: process(float df_sample)
+{	 
+	m0--;
+	beat--;
+	playbeat = 0;
+	
+	// move all samples back one step
+	for (int i=0;i < (dfbuffer_size-1);i++)
+	{
+		dfbuffer[i] = dfbuffer[i+1];
+	}
+	
+	// add new sample at the end
+	dfbuffer[dfbuffer_size-1] = df_sample;	
+	
+	// update cumulative score
+	updatecumscore(df_sample);
+	
+	// if we are halfway between beats
+	if (m0 == 0)
+	{
+		predictbeat();
+	}
+	
+	// if we are at a beat
+	if (beat == 0)
+	{
+		playbeat = 1;	// indicate a beat should be output
+		
+		// recalculate the tempo
+		dfconvert();	
+		calcTempo();
+	}
+}
+
+//-------------------------------------------------------------------------------
+// Set the tempo of the beat tracker
+void BTrack :: settempo(float tempo)
+{	 
+	
+	/////////// TEMPO INDICATION RESET //////////////////
+	
+	// firstly make sure tempo is between 80 and 160 bpm..
+	while (tempo > 160)
+	{
+		tempo = tempo/2;
+	}
+	
+	while (tempo < 80)
+	{
+		tempo = tempo * 2;
+	}
+		
+	// convert tempo from bpm value to integer index of tempo probability 
+	int tempo_index = (int) round((tempo - 80)/2);
+	
+	// now set previous tempo observations to zero
+	for (int i=0;i < 41;i++)
+	{
+		prev_delta[i] = 0;
+	}
+	
+	// set desired tempo index to 1
+	prev_delta[tempo_index] = 1;
+	
+	
+	/////////// CUMULATIVE SCORE ARTIFICAL TEMPO UPDATE //////////////////
+	
+	// calculate new beat period
+	int new_bperiod = (int) round(60/((((float) framesize)/44100)*tempo));
+	
+	int bcounter = 1;
+	// initialise df_buffer to zeros
+	for (int i = (dfbuffer_size-1);i >= 0;i--)
+	{
+		if (bcounter == 1)
+		{
+			cumscore[i] = 150;
+			dfbuffer[i] = 150;
+		}
+		else
+		{
+			cumscore[i] = 10;
+			dfbuffer[i] = 10;
+		}
+		
+		bcounter++;
+		
+		if (bcounter > new_bperiod)
+		{
+			bcounter = 1;
+		}
+	}
+	
+	/////////// INDICATE THAT THIS IS A BEAT //////////////////
+	
+	// beat is now
+	beat = 0;
+	
+	// offbeat is half of new beat period away
+	m0 = (int) round(((float) new_bperiod)/2);
+}
+
+
+//-------------------------------------------------------------------------------
+// fix tempo to roughly around some value
+void BTrack :: fixtempo(float tempo)
+{	
+	// firstly make sure tempo is between 80 and 160 bpm..
+	while (tempo > 160)
+	{
+		tempo = tempo/2;
+	}
+	
+	while (tempo < 80)
+	{
+		tempo = tempo * 2;
+	}
+	
+	// convert tempo from bpm value to integer index of tempo probability 
+	int tempo_index = (int) round((tempo - 80)/2);
+	
+	// now set previous fixed previous tempo observation values to zero
+	for (int i=0;i < 41;i++)
+	{
+		prev_delta_fix[i] = 0;
+	}
+	
+	// set desired tempo index to 1
+	prev_delta_fix[tempo_index] = 1;
+		
+	// set the tempo fix flag
+	tempofix = 1;	
+}
+
+//-------------------------------------------------------------------------------
+// do not fix the tempo anymore
+void BTrack :: unfixtempo()
+{	
+	// set the tempo fix flag
+	tempofix = 0;	
+}
+
+//-------------------------------------------------------------------------------
+// Convert detection function from N samples to 512
+void BTrack :: dfconvert()
+{
+	float output[512];
+		
+	double src_ratio = 512.0/((double) dfbuffer_size);
+	int BUFFER_LEN = dfbuffer_size;
+	int output_len;
+	SRC_DATA	src_data ;
+	
+	//output_len = (int) floor (((double) BUFFER_LEN) * src_ratio) ;
+	output_len = 512;
+	
+	src_data.data_in = dfbuffer;
+	src_data.input_frames = BUFFER_LEN;
+	
+	src_data.src_ratio = src_ratio;
+	
+	src_data.data_out = output;
+	src_data.output_frames = output_len;
+	
+	src_simple (&src_data, SRC_SINC_BEST_QUALITY, 1);
+			
+	for (int i = 0;i < output_len;i++)
+	{
+		df512[i] = src_data.data_out[i];
+	}
+}
+
+//-------------------------------------------------------------------------------
+// To calculate the current tempo expressed as the beat period in detection function samples
+void BTrack :: calcTempo()
+{
+	// adaptive threshold on input
+	adapt_thresh(df512,512);
+		
+	// calculate auto-correlation function of detection function
+	acf_bal(df512);
+	
+	// calculate output of comb filterbank
+	getrcfoutput();
+	
+	
+	// adaptive threshold on rcf
+	adapt_thresh(rcf,128);
+
+	
+	int t_index;
+	int t_index2;
+	// calculate tempo observation vector from bperiod observation vector
+	for (int i = 0;i < 41;i++)
+	{
+		t_index = (int) round(p_fact / ((float) ((2*i)+80)));
+		t_index2 = (int) round(p_fact / ((float) ((4*i)+160)));
+
+		
+		t_obs[i] = rcf[t_index-1] + rcf[t_index2-1];
+	}
+	
+	
+	float maxval;
+	float maxind;
+	float curval;
+	
+	// if tempo is fixed then always use a fixed set of tempi as the previous observation probability function
+	if (tempofix == 1)
+	{
+		for (int k = 0;k < 41;k++)
+		{
+			prev_delta[k] = prev_delta_fix[k];
+		}
+	}
+		
+	for (int j=0;j < 41;j++)
+	{
+		maxval = -1;
+		for (int i = 0;i < 41;i++)
+		{
+			curval = prev_delta[i]*t_tmat[i][j];
+			
+			if (curval > maxval)
+			{
+				maxval = curval;
+			}
+		}
+		
+		delta[j] = maxval*t_obs[j];
+	}
+	
+
+	normalise(delta,41);
+	
+	maxind = -1;
+	maxval = -1;
+	
+	for (int j=0;j < 41;j++)
+	{
+		if (delta[j] > maxval)
+		{
+			maxval = delta[j];
+			maxind = j;
+		}
+		
+		prev_delta[j] = delta[j];
+	}
+	
+	bperiod = round((60.0*44100.0)/(((2*maxind)+80)*((float) framesize)));
+	
+	if (bperiod > 0)
+	{
+		est_tempo = 60.0/((((float) framesize) / 44100.0)*bperiod);
+	}
+	
+	//cout << bperiod << endl;
+}
+
+//-------------------------------------------------------------------------------
+// calculates an adaptive threshold which is used to remove low level energy from detection function and emphasise peaks
+void BTrack :: adapt_thresh(float x[],int N)
+{
+	//int N = 512; // length of df
+	int i = 0;
+	int k,t = 0;
+	float x_thresh[N];
+	
+	int p_post = 7;
+	int p_pre = 8;
+	
+	t = min(N,p_post);	// what is smaller, p_post of df size. This is to avoid accessing outside of arrays
+	
+	// find threshold for first 't' samples, where a full average cannot be computed yet 
+	for (i = 0;i <= t;i++)
+	{	
+		k = min((i+p_pre),N);
+		x_thresh[i] = mean_array(x,1,k);
+	}
+	// find threshold for bulk of samples across a moving average from [i-p_pre,i+p_post]
+	for (i = t+1;i < N-p_post;i++)
+	{
+		x_thresh[i] = mean_array(x,i-p_pre,i+p_post);
+	}
+	// for last few samples calculate threshold, again, not enough samples to do as above
+	for (i = N-p_post;i < N;i++)
+	{
+		k = max((i-p_post),1);
+		x_thresh[i] = mean_array(x,k,N);
+	}
+	
+	// subtract the threshold from the detection function and check that it is not less than 0
+	for (i = 0;i < N;i++)
+	{
+		x[i] = x[i] - x_thresh[i];
+		if (x[i] < 0)
+		{
+			x[i] = 0;
+		}
+	}
+}
+
+//-------------------------------------------------------------------------------
+// returns the output of the comb filter
+void BTrack :: getrcfoutput()
+{
+	int numelem;
+	
+	for (int i = 0;i < 128;i++)
+	{
+		rcf[i] = 0;
+	}
+	
+	numelem = 4;
+	
+	for (int i = 2;i <= 127;i++) // max beat period
+	{
+		for (int a = 1;a <= numelem;a++) // number of comb elements
+		{
+			for (int b = 1-a;b <= a-1;b++) // general state using normalisation of comb elements
+			{
+				rcf[i-1] = rcf[i-1] + (acf[(a*i+b)-1]*wv[i-1])/(2*a-1);	// calculate value for comb filter row
+			}
+		}
+	}
+}
+
+//-------------------------------------------------------------------------------
+// calculates the balanced autocorrelation of the smoothed detection function
+void BTrack :: acf_bal(float df_thresh[])
+{
+	int l, n = 0;
+	float sum, tmp;
+	
+	// for l lags from 0-511
+	for (l = 0;l < 512;l++)
+	{
+		sum = 0;	
+		
+		// for n samples from 0 - (512-lag)
+		for (n = 0;n < (512-l);n++)
+		{
+			tmp = df_thresh[n] * df_thresh[n+l];	// multiply current sample n by sample (n+l)
+			sum = sum + tmp;	// add to sum
+		}
+		
+		acf[l] = sum / (512-l);		// weight by number of mults and add to acf buffer
+	}
+}
+
+
+//-------------------------------------------------------------------------------
+// calculates the mean of values in an array from index locations [start,end]
+float BTrack :: mean_array(float array[],int start,int end)
+{
+	int i;
+	float sum = 0;
+	int length = end - start + 1;
+	
+	// find sum
+	for (i = start;i < end+1;i++)
+	{
+		sum = sum + array[i];
+	}
+	
+	return sum / length;	// average and return
+}
+
+//-------------------------------------------------------------------------------
+// normalise the array
+void BTrack :: normalise(float array[],int N)
+{
+	double sum = 0;
+	
+	for (int i = 0;i < N;i++)
+	{
+		if (array[i] > 0)
+		{
+			sum = sum + array[i];
+		}
+	}
+	
+	if (sum > 0)
+	{
+		for (int i = 0;i < N;i++)
+		{
+			array[i] = array[i] / sum;
+		}
+	}
+}
+
+//-------------------------------------------------------------------------------
+// plot contents of detection function buffer
+void BTrack :: plotdfbuffer()
+{	 
+	for (int i=0;i < dfbuffer_size;i++)
+	{
+		cout << dfbuffer[i] << endl;
+	}
+	
+	cout << "--------------------------------" << endl;
+}
+
+//-------------------------------------------------------------------------------
+// update the cumulative score
+void BTrack :: updatecumscore(float df_sample)
+{	 
+	int start, end, winsize;
+	float max;
+	
+	start = dfbuffer_size - round(2*bperiod);
+	end = dfbuffer_size - round(bperiod/2);
+	winsize = end-start+1;
+	
+	float w1[winsize];
+	float v = -2*bperiod;
+	float wcumscore;
+	
+	
+	// create window
+	for (int i = 0;i < winsize;i++)
+	{
+		w1[i] = exp((-1*pow(tightness*log(-v/bperiod),2))/2);
+		v = v+1;
+	}	
+	
+	// calculate new cumulative score value
+	max = 0;
+	int n = 0;
+	for (int i=start;i <= end;i++)
+	{
+			wcumscore = cumscore[i]*w1[n];
+		
+			if (wcumscore > max)
+			{
+				max = wcumscore;
+			}
+		n++;
+	}
+	
+	
+	// shift cumulative score back one
+	for (int i = 0;i < (dfbuffer_size-1);i++)
+	{
+		cumscore[i] = cumscore[i+1];
+	}
+	
+	// add new value to cumulative score
+	cumscore[dfbuffer_size-1] = ((1-alpha)*df_sample) + (alpha*max);
+	
+	cscoreval = cumscore[dfbuffer_size-1];
+	
+	//cout << cumscore[dfbuffer_size-1] << endl;
+		
+}
+
+//-------------------------------------------------------------------------------
+// plot contents of detection function buffer
+void BTrack :: predictbeat()
+{	 
+	int winsize = (int) bperiod;
+	float fcumscore[dfbuffer_size + winsize];
+	float w2[winsize];
+	// copy cumscore to first part of fcumscore
+	for (int i = 0;i < dfbuffer_size;i++)
+	{
+		fcumscore[i] = cumscore[i];
+	}
+	
+	// create future window
+	float v = 1;
+	for (int i = 0;i < winsize;i++)
+	{
+		w2[i] = exp((-1*pow((v - (bperiod/2)),2))   /  (2*pow((bperiod/2) ,2)));
+		v++;
+	}
+	
+	// create past window
+	v = -2*bperiod;
+	int start = dfbuffer_size - round(2*bperiod);
+	int end = dfbuffer_size - round(bperiod/2);
+	int pastwinsize = end-start+1;
+	float w1[pastwinsize];
+
+	for (int i = 0;i < pastwinsize;i++)
+	{
+		w1[i] = exp((-1*pow(tightness*log(-v/bperiod),2))/2);
+		v = v+1;
+	}
+
+	
+
+	// calculate future cumulative score
+	float max;
+	int n;
+	float wcumscore;
+	for (int i = dfbuffer_size;i < (dfbuffer_size+winsize);i++)
+	{
+		start = i - round(2*bperiod);
+		end = i - round(bperiod/2);
+		
+		max = 0;
+		n = 0;
+		for (int k=start;k <= end;k++)
+		{
+			wcumscore = fcumscore[k]*w1[n];
+			
+			if (wcumscore > max)
+			{
+				max = wcumscore;
+			}
+			n++;
+		}
+		
+		fcumscore[i] = max;
+	}
+	
+	
+	// predict beat
+	max = 0;
+	n = 0;
+	
+	for (int i = dfbuffer_size;i < (dfbuffer_size+winsize);i++)
+	{
+		wcumscore = fcumscore[i]*w2[n];
+		
+		if (wcumscore > max)
+		{
+			max = wcumscore;
+			beat = n;
+		}	
+		
+		n++;
+	}
+		
+	
+	// set beat
+	beat = beat;
+	
+	// set next prediction time
+	m0 = beat+round(bperiod/2);
+	
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/BTrack.h	Tue Jan 21 00:10:11 2014 +0000
@@ -0,0 +1,99 @@
+//=======================================================================
+/** @file BTrack.h
+ *  @brief Header file for the BTrack beat tracker
+ *  @author Adam Stark
+ *  @copyright Copyright (C) 2008-2014  Queen Mary University of London
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+//=======================================================================
+
+#ifndef __BTRACK_H
+#define __BTRACK_H
+
+//#include "fftw3.h"
+
+class BTrack {
+	
+public:
+	BTrack();				// constructor
+	~BTrack();				// destructor	
+	
+	void initialise(int fsize);
+	void process(float df_sample);
+	void plotdfbuffer();
+	void updatecumscore(float df_sample);
+	void predictbeat();
+	void dfconvert();
+	void calcTempo();
+	void adapt_thresh(float x[],int N);
+	float mean_array(float array[],int start,int end);
+	void normalise(float array[],int N);
+	void acf_bal(float df_thresh[]);
+	void getrcfoutput();
+	void settempo(float tempo);
+	void fixtempo(float tempo);
+	void unfixtempo();
+	
+	int playbeat;
+	float cscoreval;
+	float est_tempo;
+			
+private:
+	
+	// buffers
+	float *dfbuffer;			// to hold detection function
+	float df512[512];			// to hold resampled detection function 
+	float *cumscore;			// to hold cumulative score
+	
+	float acf[512];				// to hold autocorrelation function
+	
+	float wv[128];				// to hold weighting vector
+	
+	float rcf[128];				// to hold comb filter output
+	float t_obs[41];			// to hold tempo version of comb filter output
+	
+	float delta[41];			// to hold final tempo candidate array
+	float prev_delta[41];		// previous delta
+	float prev_delta_fix[41];	// fixed tempo version of previous delta
+	
+	float t_tmat[41][41];		// transition matrix
+	
+	
+	// parameters
+	float tightness;
+	float alpha;
+	float bperiod;
+	float tempo;
+	
+	
+	float p_fact;
+	
+	
+	//
+	int m0;				// indicates when the next point to predict the next beat is
+	int beat;
+	
+	int dfbuffer_size;
+		
+	
+	int framesize;
+	
+	
+	int tempofix;
+	
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/OnsetDetectionFunction.cpp	Tue Jan 21 00:10:11 2014 +0000
@@ -0,0 +1,805 @@
+//=======================================================================
+/** @file OnsetDetectionFunction.cpp
+ *  @brief A class for calculating onset detection functions
+ *  @author Adam Stark
+ *  @copyright Copyright (C) 2008-2014  Queen Mary University of London
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+//=======================================================================
+
+#include <math.h>
+#include <iostream>
+#include "OnsetDetectionFunction.h"
+using namespace std;
+
+//-------------------------------------------------------------------------------
+// Constructor
+OnsetDetectionFunction :: OnsetDetectionFunction()
+{	
+	// indicate that we have not initialised yet
+	initialised = 0;		
+	
+	// set pi
+	pi = 3.14159265358979;	
+	
+	// initialise with hopsize = 512, framesize = 1024, complex spectral difference DF and hanning window
+	initialise(512,1024,6,1);	
+}
+
+
+//-------------------------------------------------------------------------------
+// Constructor (with arguments)
+OnsetDetectionFunction :: OnsetDetectionFunction(int arg_hsize,int arg_fsize,int arg_df_type,int arg_win_type)
+{	
+	// indicate that we have not initialised yet
+	initialised = 0;		
+	
+	// set pi
+	pi = 3.14159265358979;	
+	
+	// initialise with arguments to constructor
+	initialise(arg_hsize,arg_fsize,arg_df_type,arg_win_type);
+}
+
+
+//--------------------------------------------------------------------------------------
+// Destructor
+OnsetDetectionFunction :: ~OnsetDetectionFunction()
+{
+	// destroy fft plan
+    fftw_destroy_plan(p);
+	fftw_free(in); 
+	fftw_free(out);
+	
+	// deallocate memory
+	delete [] frame;
+	frame = NULL;	
+	delete [] window;
+	window = NULL;									
+	delete [] wframe;
+	wframe = NULL;											
+	delete [] mag;
+	mag = NULL;
+	delete [] mag_old;
+	mag_old = NULL;
+	delete [] phase;
+	phase = NULL;
+	delete [] phase_old;
+	phase_old = NULL;	
+	delete [] phase_old_2;
+	phase_old_2 = NULL;
+}
+
+//-------------------------------------------------------------------------------
+// Initialisation
+void OnsetDetectionFunction :: initialise(int arg_hsize,int arg_fsize,int arg_df_type,int arg_win_type)
+{
+	if (initialised == 1) // if we have already initialised some buffers and an FFT plan
+	{
+		//////////////////////////////////
+		// TIDY UP FIRST - If initialise is called after the class has been initialised
+		// then we want to free up memory and cancel existing FFT plans
+	
+		// destroy fft plan
+		fftw_destroy_plan(p);
+		fftw_free(in); 
+		fftw_free(out);
+	
+	
+		// deallocate memory
+		delete [] frame;
+		frame = NULL;	
+		delete [] window;
+		window = NULL;									
+		delete [] wframe;
+		wframe = NULL;											
+		delete [] mag;
+		mag = NULL;
+		delete [] mag_old;
+		mag_old = NULL;
+		delete [] phase;
+		phase = NULL;
+		delete [] phase_old;
+		phase_old = NULL;	
+		delete [] phase_old_2;
+		phase_old_2 = NULL;
+	
+		////// END TIDY UP ///////////////
+		//////////////////////////////////
+	}
+	
+	hopsize = arg_hsize; // set hopsize
+	framesize = arg_fsize; // set framesize
+	
+	df_type = arg_df_type; // set detection function type
+		
+	// initialise buffers
+	frame = new double[framesize];											
+	window = new double[framesize];	
+	wframe = new double[framesize];		
+	
+	mag = new double[framesize];											
+	mag_old = new double[framesize];
+	
+	phase = new double[framesize];
+	phase_old = new double[framesize];
+	phase_old_2 = new double[framesize];
+	
+	
+	// set the window to the specified type
+	switch (arg_win_type){
+		case 0:
+			set_win_rectangular();		// Rectangular window
+			break;	
+		case 1:	
+			set_win_hanning();			// Hanning Window
+			break;
+		case 2:
+			set_win_hamming();			// Hamming Window
+			break;
+		case 3:
+			set_win_blackman();			// Blackman Window
+			break;
+		case 4:
+			set_win_tukey();			// Tukey Window
+			break;
+		default:
+			set_win_hanning();			// DEFAULT: Hanning Window
+	}
+	
+	
+	
+	
+	// initialise previous magnitude spectrum to zero
+	for (int i = 0;i < framesize;i++)
+	{
+		mag_old[i] = 0.0;
+		phase_old[i] = 0.0;
+		phase_old_2[i] = 0.0;
+		frame[i] = 0.0;
+	}
+	
+	energy_sum_old = 0.0;	// initialise previous energy sum value to zero
+	
+	/*  Init fft */
+	in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * framesize);		// complex array to hold fft data
+	out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * framesize);	// complex array to hold fft data
+	p = fftw_plan_dft_1d(framesize, in, out, FFTW_FORWARD, FFTW_ESTIMATE);	// FFT plan initialisation
+	
+	initialised = 1;
+}
+
+//--------------------------------------------------------------------------------------
+// set the detection function type to that specified by the argument
+void OnsetDetectionFunction :: set_df_type(int arg_df_type)
+{
+	df_type = arg_df_type; // set detection function type
+}
+
+
+//--------------------------------------------------------------------------------------
+// calculates a single detection function sample from a single audio frame.
+double OnsetDetectionFunction :: getDFsample(double inputbuffer[])
+{	
+	double df_sample;
+		
+	// shift audio samples back in frame by hop size
+	for (int i = 0; i < (framesize-hopsize);i++)
+	{
+		frame[i] = frame[i+hopsize];
+	}
+	
+	// add new samples to frame from input buffer
+	int j = 0;
+	for (int i = (framesize-hopsize);i < framesize;i++)
+	{
+		frame[i] = inputbuffer[j];
+		j++;
+	}
+		
+	switch (df_type){
+		case 0:
+			df_sample = energy_envelope();	// calculate energy envelope detection function sample
+			break;	
+		case 1:
+			df_sample = energy_difference();	// calculate half-wave rectified energy difference detection function sample
+			break;
+		case 2:
+			df_sample = spectral_difference();	// calculate spectral difference detection function sample
+			break;
+		case 3:
+			df_sample = spectral_difference_hwr(); // calculate spectral difference detection function sample (half wave rectified)
+			break;
+		case 4:
+			df_sample = phase_deviation();		// calculate phase deviation detection function sample (half wave rectified)
+			break;
+		case 5:
+			df_sample = complex_spectral_difference(); // calcualte complex spectral difference detection function sample
+			break;
+		case 6:
+			df_sample = complex_spectral_difference_hwr();  // calcualte complex spectral difference detection function sample (half-wave rectified)
+			break;
+		case 7:
+			df_sample = high_frequency_content(); // calculate high frequency content detection function sample
+			break;
+		case 8:
+			df_sample = high_frequency_spectral_difference(); // calculate high frequency spectral difference detection function sample
+			break;
+		case 9:
+			df_sample = high_frequency_spectral_difference_hwr(); // calculate high frequency spectral difference detection function (half-wave rectified)
+			break;
+		default:
+			df_sample = 1.0;
+	}
+		
+	return df_sample;
+}
+
+
+//--------------------------------------------------------------------------------------
+// performs the fft, storing the complex result in 'out'
+void OnsetDetectionFunction :: perform_FFT()
+{
+	int fsize2 = (framesize/2);
+	
+	// window frame and copy to complex array, swapping the first and second half of the signal
+	for (int i = 0;i < fsize2;i++)
+	{
+		in[i][0] = frame[i+fsize2] * window[i+fsize2];
+		in[i][1] = 0.0;
+		in[i+fsize2][0] = frame[i] * window[i];
+		in[i+fsize2][1] = 0.0;
+	}
+	
+	// perform the fft
+	fftw_execute(p);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////// Methods for Detection Functions /////////////////////////////////
+
+//--------------------------------------------------------------------------------------
+// calculates an energy envelope detection function sample
+double OnsetDetectionFunction :: energy_envelope()
+{
+	double sum;
+	
+	sum = 0;	// initialise sum
+	
+	// sum the squares of the samples
+	for (int i = 0;i < framesize;i++)
+	{
+		sum = sum + (frame[i]*frame[i]);
+	}
+	
+	return sum;		// return sum
+}
+
+//--------------------------------------------------------------------------------------
+// calculates a half-wave rectified energy difference detection function sample
+double OnsetDetectionFunction :: energy_difference()
+{
+	double sum;
+	double sample;
+	
+	sum = 0;	// initialise sum
+	
+	// sum the squares of the samples
+	for (int i = 0;i < framesize;i++)
+	{
+		sum = sum + (frame[i]*frame[i]);
+	}
+	
+	sample = sum - energy_sum_old;	// sample is first order difference in energy
+	
+	energy_sum_old = sum;	// store energy value for next calculation
+	
+	if (sample > 0)
+	{
+		return sample;		// return difference
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+//--------------------------------------------------------------------------------------
+// calculates a spectral difference detection function sample
+double OnsetDetectionFunction :: spectral_difference()
+{
+	double diff;
+	double sum;
+	
+	// perform the FFT
+	perform_FFT();
+	
+	// compute first (N/2)+1 mag values
+	for (int i = 0;i < (framesize/2)+1;i++)
+	{
+		mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2));
+	}
+	// mag spec symmetric above (N/2)+1 so copy previous values
+	for (int i = (framesize/2)+1;i < framesize;i++)
+	{
+		mag[i] = mag[framesize-i];		
+	}
+	
+	sum = 0;	// initialise sum to zero
+
+	for (int i = 0;i < framesize;i++)
+	{
+		// calculate difference
+		diff = mag[i] - mag_old[i];
+		
+		// ensure all difference values are positive
+		if (diff < 0)
+		{
+			diff = diff*-1;
+		}
+		
+		// add difference to sum
+		sum = sum+diff;
+		
+		// store magnitude spectrum bin for next detection function sample calculation
+		mag_old[i] = mag[i];
+	}
+	
+	return sum;		
+}
+
+//--------------------------------------------------------------------------------------
+// calculates a spectral difference detection function sample
+double OnsetDetectionFunction :: spectral_difference_hwr()
+{
+	double diff;
+	double sum;
+	
+	// perform the FFT
+	perform_FFT();
+	
+	// compute first (N/2)+1 mag values
+	for (int i = 0;i < (framesize/2)+1;i++)
+	{
+		mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2));
+	}
+	// mag spec symmetric above (N/2)+1 so copy previous values
+	for (int i = (framesize/2)+1;i < framesize;i++)
+	{
+		mag[i] = mag[framesize-i];		
+	}
+	
+	sum = 0;	// initialise sum to zero
+	
+	for (int i = 0;i < framesize;i++)
+	{
+		// calculate difference
+		diff = mag[i] - mag_old[i];
+		
+		// only add up positive differences
+		if (diff > 0)
+		{
+			// add difference to sum
+			sum = sum+diff;
+		}
+		
+		
+		
+		// store magnitude spectrum bin for next detection function sample calculation
+		mag_old[i] = mag[i];
+	}
+	
+	return sum;		
+}
+
+
+//--------------------------------------------------------------------------------------
+// calculates a phase deviation detection function sample
+double OnsetDetectionFunction :: phase_deviation()
+{
+	double dev,pdev;
+	double sum;
+	
+	// perform the FFT
+	perform_FFT();
+	
+	sum = 0; // initialise sum to zero
+	
+	// compute phase values from fft output and sum deviations
+	for (int i = 0;i < framesize;i++)
+	{
+		// calculate phase value
+		phase[i] = atan2(out[i][1],out[i][0]);
+		
+		// calculate magnitude value
+		mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2));
+		
+		
+		// if bin is not just a low energy bin then examine phase deviation
+		if (mag[i] > 0.1)
+		{
+			dev = phase[i] - (2*phase_old[i]) + phase_old_2[i];	// phase deviation
+			pdev = princarg(dev);	// wrap into [-pi,pi] range
+		
+			// make all values positive
+			if (pdev < 0)	
+			{
+				pdev = pdev*-1;
+			}
+						
+			// add to sum
+			sum = sum + pdev;
+		}
+				
+		// store values for next calculation
+		phase_old_2[i] = phase_old[i];
+		phase_old[i] = phase[i];
+	}
+	
+	return sum;		
+}
+
+//--------------------------------------------------------------------------------------
+// calculates a complex spectral difference detection function sample
+double OnsetDetectionFunction :: complex_spectral_difference()
+{
+	double dev,pdev;
+	double sum;
+	double mag_diff,phase_diff;
+	double value;
+	
+	// perform the FFT
+	perform_FFT();
+	
+	sum = 0; // initialise sum to zero
+	
+	// compute phase values from fft output and sum deviations
+	for (int i = 0;i < framesize;i++)
+	{
+		// calculate phase value
+		phase[i] = atan2(out[i][1],out[i][0]);
+		
+		// calculate magnitude value
+		mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2));
+		
+		
+		// phase deviation
+		dev = phase[i] - (2*phase_old[i]) + phase_old_2[i];	
+		
+		// wrap into [-pi,pi] range
+		pdev = princarg(dev);	
+		
+		
+		// calculate magnitude difference (real part of Euclidean distance between complex frames)
+		mag_diff = mag[i] - mag_old[i];
+		
+		// calculate phase difference (imaginary part of Euclidean distance between complex frames)
+		phase_diff = -mag[i]*sin(pdev);
+		
+
+		
+		// square real and imaginary parts, sum and take square root
+		value = sqrt(pow(mag_diff,2) + pow(phase_diff,2));
+	
+			
+		// add to sum
+		sum = sum + value;
+		
+		
+		// store values for next calculation
+		phase_old_2[i] = phase_old[i];
+		phase_old[i] = phase[i];
+		mag_old[i] = mag[i];
+	}
+	
+	return sum;		
+}
+
+//--------------------------------------------------------------------------------------
+// calculates a complex spectral difference detection function sample (half-wave rectified)
+double OnsetDetectionFunction :: complex_spectral_difference_hwr()
+{
+	double dev,pdev;
+	double sum;
+	double mag_diff,phase_diff;
+	double value;
+	
+	// perform the FFT
+	perform_FFT();
+	
+	sum = 0; // initialise sum to zero
+	
+	// compute phase values from fft output and sum deviations
+	for (int i = 0;i < framesize;i++)
+	{
+		// calculate phase value
+		phase[i] = atan2(out[i][1],out[i][0]);
+		
+		// calculate magnitude value
+		mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2));
+		
+		
+		// phase deviation
+		dev = phase[i] - (2*phase_old[i]) + phase_old_2[i];	
+		
+		// wrap into [-pi,pi] range
+		pdev = princarg(dev);	
+		
+		
+		// calculate magnitude difference (real part of Euclidean distance between complex frames)
+		mag_diff = mag[i] - mag_old[i];
+		
+		// if we have a positive change in magnitude, then include in sum, otherwise ignore (half-wave rectification)
+		if (mag_diff > 0)
+		{
+			// calculate phase difference (imaginary part of Euclidean distance between complex frames)
+			phase_diff = -mag[i]*sin(pdev);
+
+			// square real and imaginary parts, sum and take square root
+			value = sqrt(pow(mag_diff,2) + pow(phase_diff,2));
+		
+			// add to sum
+			sum = sum + value;
+		}
+		
+		// store values for next calculation
+		phase_old_2[i] = phase_old[i];
+		phase_old[i] = phase[i];
+		mag_old[i] = mag[i];
+	}
+	
+	return sum;		
+}
+
+
+//--------------------------------------------------------------------------------------
+// calculates a high frequency content detection function sample
+double OnsetDetectionFunction :: high_frequency_content()
+{
+	double sum;
+	double mag_diff;
+	
+	// perform the FFT
+	perform_FFT();
+	
+	sum = 0; // initialise sum to zero
+	
+	// compute phase values from fft output and sum deviations
+	for (int i = 0;i < framesize;i++)
+	{		
+		// calculate magnitude value
+		mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2));
+		
+		
+		sum = sum + (mag[i]*((double) (i+1)));
+		
+		// store values for next calculation
+		mag_old[i] = mag[i];
+	}
+	
+	return sum;		
+}
+
+//--------------------------------------------------------------------------------------
+// calculates a high frequency spectral difference detection function sample
+double OnsetDetectionFunction :: high_frequency_spectral_difference()
+{
+	double sum;
+	double mag_diff;
+	
+	// perform the FFT
+	perform_FFT();
+	
+	sum = 0; // initialise sum to zero
+	
+	// compute phase values from fft output and sum deviations
+	for (int i = 0;i < framesize;i++)
+	{		
+		// calculate magnitude value
+		mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2));
+		
+		// calculate difference
+		mag_diff = mag[i] - mag_old[i];
+		
+		if (mag_diff < 0)
+		{
+			mag_diff = -mag_diff;
+		}
+		
+		sum = sum + (mag_diff*((double) (i+1)));
+		
+		// store values for next calculation
+		mag_old[i] = mag[i];
+	}
+	
+	return sum;		
+}
+
+//--------------------------------------------------------------------------------------
+// calculates a high frequency spectral difference detection function sample (half-wave rectified)
+double OnsetDetectionFunction :: high_frequency_spectral_difference_hwr()
+{
+	double sum;
+	double mag_diff;
+	
+	// perform the FFT
+	perform_FFT();
+	
+	sum = 0; // initialise sum to zero
+	
+	// compute phase values from fft output and sum deviations
+	for (int i = 0;i < framesize;i++)
+	{		
+		// calculate magnitude value
+		mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2));
+		
+		// calculate difference
+		mag_diff = mag[i] - mag_old[i];
+		
+		if (mag_diff > 0)
+		{
+			sum = sum + (mag_diff*((double) (i+1)));
+		}
+
+		// store values for next calculation
+		mag_old[i] = mag[i];
+	}
+	
+	return sum;		
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////// Methods to Calculate Windows ////////////////////////////////////
+
+//--------------------------------------------------------------------------------------
+// HANNING: set the window in the buffer 'window' to a Hanning window
+void OnsetDetectionFunction :: set_win_hanning()
+{
+	double N;		// variable to store framesize minus 1
+	
+	N = (double) (framesize-1);	// framesize minus 1
+	
+	// Hanning window calculation
+	for (int n = 0;n < framesize;n++)
+	{
+		window[n] = 0.5*(1-cos(2*pi*(n/N)));
+	}
+}
+
+//--------------------------------------------------------------------------------------
+// HAMMING: set the window in the buffer 'window' to a Hanning window
+void OnsetDetectionFunction :: set_win_hamming()
+{
+	double N;		// variable to store framesize minus 1
+	double n_val;	// double version of index 'n'
+	
+	N = (double) (framesize-1);	// framesize minus 1
+	n_val = 0;
+	
+	// Hamming window calculation
+	for (int n = 0;n < framesize;n++)
+	{
+		window[n] = 0.54 - (0.46*cos(2*pi*(n_val/N)));
+		n_val = n_val+1;
+	}
+}
+
+//--------------------------------------------------------------------------------------
+// BLACKMAN: set the window in the buffer 'window' to a Blackman window
+void OnsetDetectionFunction :: set_win_blackman()
+{
+	double N;		// variable to store framesize minus 1
+	double n_val;	// double version of index 'n'
+	
+	N = (double) (framesize-1);	// framesize minus 1
+	n_val = 0;
+	
+	// Blackman window calculation
+	for (int n = 0;n < framesize;n++)
+	{
+		window[n] = 0.42 - (0.5*cos(2*pi*(n_val/N))) + (0.08*cos(4*pi*(n_val/N)));
+		n_val = n_val+1;
+	}
+}
+
+//--------------------------------------------------------------------------------------
+// TUKEY: set the window in the buffer 'window' to a Tukey window
+void OnsetDetectionFunction :: set_win_tukey()
+{
+	double N;		// variable to store framesize minus 1
+	double n_val;	// double version of index 'n'
+	double alpha;	// alpha [default value = 0.5];
+	
+	int lim1,lim2;
+	
+	alpha = 0.5;
+	
+	N = (double) (framesize-1);	// framesize minus 1
+		
+	// Tukey window calculation
+	
+	n_val = (double) (-1*((framesize/2)))+1;
+
+	for (int n = 0;n < framesize;n++)	// left taper
+	{
+		if ((n_val >= 0) && (n_val <= (alpha*(N/2))))
+		{
+			window[n] = 1.0;
+		}
+		else if ((n_val <= 0) && (n_val >= (-1*alpha*(N/2))))
+		{
+			window[n] = 1.0;
+		}
+		else
+		{
+			window[n] = 0.5*(1+cos(pi*(((2*n_val)/(alpha*N))-1)));
+		}
+
+		n_val = n_val+1;			 
+	}
+
+}
+
+//--------------------------------------------------------------------------------------
+// RECTANGULAR: set the window in the buffer 'window' to a Rectangular window
+void OnsetDetectionFunction :: set_win_rectangular()
+{
+	// Rectangular window calculation
+	for (int n = 0;n < framesize;n++)
+	{
+		window[n] = 1.0;
+	}
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// Other Handy Methods //////////////////////////////////////////
+
+//--------------------------------------------------------------------------------------
+// set phase values to the range [-pi,pi]
+double OnsetDetectionFunction :: princarg(double phaseval)
+{	
+	// if phase value is less than or equal to -pi then add 2*pi
+	while (phaseval <= (-pi)) 
+	{
+		phaseval = phaseval + (2*pi);
+	}
+	
+	// if phase value is larger than pi, then subtract 2*pi
+	while (phaseval > pi)
+	{
+		phaseval = phaseval - (2*pi);
+	}
+			
+	return phaseval;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/OnsetDetectionFunction.h	Tue Jan 21 00:10:11 2014 +0000
@@ -0,0 +1,92 @@
+//=======================================================================
+/** @file OnsetDetectionFunction.h
+ *  @brief A class for calculating onset detection functions
+ *  @author Adam Stark
+ *  @copyright Copyright (C) 2008-2014  Queen Mary University of London
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+//=======================================================================
+
+#ifndef __RTONSETDF_H
+#define __RTONSETDF_H
+
+#include "fftw3.h"
+
+class OnsetDetectionFunction
+{
+public:
+	OnsetDetectionFunction();																// Constructor
+	OnsetDetectionFunction(int arg_hsize,int arg_fsize,int arg_df_type,int arg_win_type);	// Constructor (with arguments)
+	~OnsetDetectionFunction();																// Destructor
+	void initialise(int arg_hsize,int arg_fsize,int arg_df_type,int arg_win_type);			// Initialisation Function
+	
+	double getDFsample(double inputbuffer[]);												// process input buffer and calculate detection function sample
+	void set_df_type(int arg_df_type);														// set the detection function type
+	
+private:
+	
+	void perform_FFT();																		// perform the FFT on the data in 'frame'
+
+	double energy_envelope();																// calculate energy envelope detection function sample
+	double energy_difference();																// calculate energy difference detection function sample
+	double spectral_difference();															// calculate spectral difference detection function sample
+	double spectral_difference_hwr();														// calculate spectral difference (half wave rectified) detection function sample
+	double phase_deviation();																// calculate phase deviation detection function sample
+	double complex_spectral_difference();													// calculate complex spectral difference detection function sample
+	double complex_spectral_difference_hwr();												// calculate complex spectral difference detection function sample (half-wave rectified)
+	double high_frequency_content();														// calculate high frequency content detection function sample
+	double high_frequency_spectral_difference();											// calculate high frequency spectral difference detection function sample
+	double high_frequency_spectral_difference_hwr();										// calculate high frequency spectral difference detection function sample (half-wave rectified)
+
+	void set_win_rectangular();																// calculate a Rectangular window	
+	void set_win_hanning();																	// calculate a Hanning window
+	void set_win_hamming();																	// calculate a Hamming window
+	void set_win_blackman();																// calculate a Blackman window
+	void set_win_tukey();																	// calculate a Tukey window
+
+	
+	double princarg(double phaseval);														// set phase values between [-pi, pi]
+	
+	
+	double pi;																				// pi, the constant
+	
+	int framesize;																			// audio framesize
+	int hopsize;																			// audio hopsize	
+	int df_type;																			// type of detection function
+	
+	fftw_plan p;																			// create fft plan
+	fftw_complex *in;																		// to hold complex fft values for input
+	fftw_complex *out;																		// to hold complex fft values for output
+	
+	int initialised;																		// flag indicating whether buffers and FFT plans have been initialised
+	
+
+	double *frame;																			// audio frame
+	double *window;																			// window
+	double *wframe;																			// windowed frame
+	
+	double energy_sum_old;																	// to hold the previous energy sum value
+	
+	double *mag;																			// magnitude spectrum
+	double *mag_old;																		// previous magnitude spectrum
+	
+	double *phase;																			// FFT phase values
+	double *phase_old;																		// previous phase values
+	double *phase_old_2;																	// second order previous phase values
+
+};
+
+
+#endif
\ No newline at end of file