Mercurial > hg > btrack
changeset 55:5e520f59127f
Changed the interface of the algorithm so that onset detection function samples are calculated internally. This makes the call to the algorithm for most cases much simpler. Also added a static function for calculating beat times in seconds based upon sampling frequency, hop size and the current frame number.
author | Adam Stark <adamstark@users.noreply.github.com> |
---|---|
date | Wed, 22 Jan 2014 18:47:16 +0000 |
parents | 9699024bb3d0 |
children | b6d440942ff6 |
files | modules-and-plug-ins/python-module/btrack_python_module.cpp src/BTrack.cpp src/BTrack.h |
diffstat | 3 files changed, 135 insertions(+), 108 deletions(-) [+] |
line wrap: on
line diff
--- a/modules-and-plug-ins/python-module/btrack_python_module.cpp Wed Jan 22 02:49:29 2014 +0000 +++ b/modules-and-plug-ins/python-module/btrack_python_module.cpp Wed Jan 22 18:47:16 2014 +0000 @@ -4,6 +4,7 @@ #include "../../src/BTrack.h" #include <numpy/arrayobject.h> +//======================================================================= static PyObject * btrack_onsetdf(PyObject *dummy, PyObject *args) { PyObject *arg1=NULL; @@ -29,23 +30,19 @@ // get array size long 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 hopSize = 512; + int frameSize = 1024; int df_type = 6; int numframes; - double buffer[hsize]; // buffer to hold one hopsize worth of audio samples + double buffer[hopSize]; // 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)); + numframes = (int) floor(((double) signal_length) / ((double) hopSize)); - OnsetDetectionFunction onset(hsize,fsize,df_type,1); + OnsetDetectionFunction onset(hopSize,frameSize,df_type,1); double df[numframes]; @@ -57,9 +54,9 @@ for (int i=0;i < numframes;i++) { // add new samples to frame - for (int n = 0;n < hsize;n++) + for (int n = 0;n < hopSize;n++) { - buffer[n] = data[(i*hsize)+n]; + buffer[n] = data[(i*hopSize)+n]; } df[i] = onset.getDFsample(buffer); @@ -91,19 +88,9 @@ //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; @@ -129,35 +116,25 @@ // get array size long 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 hopSize = 512; + int frameSize = 1024; + int numframes; - double buffer[hsize]; // buffer to hold one hopsize worth of audio samples + double buffer[hopSize]; // 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)); + numframes = (int) floor(((double) signal_length) / ((double) hopSize)); - OnsetDetectionFunction onset(hsize,fsize,df_type,1); - BTrack b; + + BTrack b(hopSize,frameSize); - b.initialise((int) hsize); // initialise beat tracker - - // set parameters - //b.setparams(0.9,5); - double df[numframes]; double beats[5000]; int beatnum = 0; - - double df_val; /////////////////////////////////////////// //////// Begin Processing Loop //////////// @@ -165,21 +142,20 @@ for (int i=0;i < numframes;i++) { // add new samples to frame - for (int n = 0;n < hsize;n++) + for (int n = 0;n < hopSize;n++) { - buffer[n] = data[(i*hsize)+n]; + buffer[n] = data[(i*hopSize)+n]; } - df[i] = onset.getDFsample(buffer); + // process the current audio frame + b.processAudioFrame(buffer); - df_val = df[i] + 0.0001; - - b.process(df_val); // process df sample in beat tracker - + // if a beat is currently scheduled if (b.playbeat == 1) { - beats[beatnum] = (((double) hsize) / 44100) * ((double) i); - beatnum = beatnum + 1; + //beats[beatnum] = (((double) hopSize) / 44100) * ((double) i); + beats[beatnum] = BTrack::getBeatTimeInSeconds(i,hopSize,44100); + beatnum = beatnum + 1; } } @@ -217,18 +193,9 @@ //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; @@ -254,20 +221,12 @@ // get array size long numframes = PyArray_Size((PyObject*)arr1); - //int k = (int) theSize; - - // get data type - //char type = PyArray_DESCR(arr1)->type; - + ////////// BEGIN PROCESS /////////////////// - int hsize = 512; + int hopSize = 512; + int frameSize = 2*hopSize; - BTrack b; - - b.initialise((int) hsize); // initialise beat tracker - - // set parameters - //b.setparams(0.9,5); + BTrack b(hopSize,frameSize); double beats[5000]; int beatnum = 0; @@ -280,11 +239,12 @@ { df_val = data[i] + 0.0001; - b.process(df_val); // process df sample in beat tracker + b.processOnsetDetectionFunctionSample(df_val); // process df sample in beat tracker if (b.playbeat == 1) { - beats[beatnum] = (((double) hsize) / 44100) * ((double) i); + //beats[beatnum] = (((double) hopSize) / 44100) * ((double) i); + beats[beatnum] = BTrack::getBeatTimeInSeconds(i,hopSize,44100); beatnum = beatnum + 1; } @@ -323,20 +283,10 @@ //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"}, @@ -344,12 +294,14 @@ {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 */
--- a/src/BTrack.cpp Wed Jan 22 02:49:29 2014 +0000 +++ b/src/BTrack.cpp Wed Jan 22 18:47:16 2014 +0000 @@ -24,11 +24,54 @@ #include "BTrack.h" #include "samplerate.h" +//======================================================================= +BTrack::BTrack() : odf(512,1024,6,1) +{ + initialise(512, 1024); +} //======================================================================= -BTrack :: BTrack() +BTrack::BTrack(int hopSize) : odf(hopSize,2*hopSize,6,1) { - double rayparam = 43; + initialise(hopSize, 2*hopSize); +} + +//======================================================================= +BTrack::BTrack(int hopSize,int frameSize) : odf(hopSize,frameSize,6,1) +{ + initialise(hopSize, frameSize); +} + +//======================================================================= +BTrack::~BTrack() +{ + +} + +//======================================================================= +double BTrack::getBeatTimeInSeconds(long frameNumber,int hopSize,int fs) +{ + double hop = (double) hopSize; + double samplingFrequency = (double) fs; + double frameNum = (double) frameNumber; + + return ((hop / samplingFrequency) * frameNum); +} + +//======================================================================= +double BTrack::getBeatTimeInSeconds(int frameNumber,int hopSize,int fs) +{ + long frameNum = (long) frameNumber; + + return getBeatTimeInSeconds(frameNum, hopSize, fs); +} + + + +//======================================================================= +void BTrack::initialise(int hopSize, int frameSize) +{ + double rayparam = 43; double pi = 3.14159265; @@ -72,27 +115,22 @@ 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; + + // initialise algorithm given the hopsize + setHopSize(hopSize); } //======================================================================= -BTrack :: ~BTrack() +void BTrack :: setHopSize(int hopSize) { + framesize = hopSize; + dfbuffer_size = (512*512)/hopSize; // calculate df buffer size -} - - - -//======================================================================= -void BTrack :: initialise(int fsize) -{ - framesize = fsize; - dfbuffer_size = (512*512)/fsize; // calculate df buffer size - - bperiod = round(60/((((double) fsize)/44100)*tempo)); + bperiod = round(60/((((double) hopSize)/44100)*tempo)); dfbuffer = new double[dfbuffer_size]; // create df_buffer cumscore = new double[dfbuffer_size]; // create cumscore @@ -113,7 +151,21 @@ } //======================================================================= -void BTrack :: process(double df_sample) +void BTrack::processAudioFrame(double *frame) +{ + // calculate the onset detection function sample for the frame + double sample = odf.getDFsample(frame); + + // add a tiny constant to the sample to stop it from ever going + // to zero. this is to avoid problems further down the line + sample = sample + 0.0001; + + // process the new onset detection function sample in the beat tracking algorithm + processOnsetDetectionFunctionSample(sample); +} + +//======================================================================= +void BTrack::processOnsetDetectionFunctionSample(double newSample) { m0--; beat--; @@ -126,10 +178,10 @@ } // add new sample at the end - dfbuffer[dfbuffer_size-1] = df_sample; + dfbuffer[dfbuffer_size-1] = newSample; // update cumulative score - updatecumscore(df_sample); + updatecumscore(newSample); // if we are halfway between beats if (m0 == 0)
--- a/src/BTrack.h Wed Jan 22 02:49:29 2014 +0000 +++ b/src/BTrack.h Wed Jan 22 18:47:16 2014 +0000 @@ -22,21 +22,39 @@ #ifndef __BTRACK_H #define __BTRACK_H +#include "OnsetDetectionFunction.h" + class BTrack { public: - /** constructor */ + /** constructor assuming hop size of 512 and frame size of 1024 */ BTrack(); + /** constructor assuming frame size will be double hopSize + * @param hopSize the step size in audio samples by which we will receive audio frames + */ + BTrack(int hopSize); + + /** constructor taking both hopSize and frameSize + * @param hopSize the step size in audio samples by which we will receive audio frames + * @param frameSize the audio frame size in audio samples + */ + BTrack(int hopSize,int frameSize); + /** destructor */ ~BTrack(); - /** Initialise with frame size and set all frame sizes accordingly */ - void initialise(int fsize); + void initialise(int hopSize,int frameSize); - /** Add new sample to buffer and apply beat tracking */ - void process(double df_sample); + /** Initialise with hop size and set all frame sizes accordingly */ + void setHopSize(int hopSize); + + /** Process a single audio frame */ + void processAudioFrame(double *frame); + + /** Add new onset detection function sample to buffer and apply beat tracking */ + void processOnsetDetectionFunctionSample(double sample); /** Set the tempo of the beat tracker */ void settempo(double tempo); @@ -46,7 +64,11 @@ /** do not fix the tempo anymore */ void unfixtempo(); - + + static double getBeatTimeInSeconds(long frameNumber,int hopSize,int fs); + + static double getBeatTimeInSeconds(int frameNumber,int hopSize,int fs); + int playbeat; double cscoreval; double est_tempo; @@ -100,6 +122,7 @@ double t_tmat[41][41]; /**< transition matrix */ + OnsetDetectionFunction odf; // parameters double tightness;