From b78805a67bc32ed91a6da4e02647755dbbdf6338 Mon Sep 17 00:00:00 2001 From: Paul Brossier Date: Sun, 22 May 2005 16:36:47 +0000 Subject: [PATCH] import 0.1.9beta5 with beat tracking import 0.1.9beta5 with beat tracking --- VERSION | 4 +- examples/Makefile.am | 3 + examples/aubiotrack.c | 146 +++++++++++++++++++++ src/Makefile.am | 3 + src/aubio.h | 1 + src/beattracking.c | 351 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/beattracking.h | 59 +++++++++ src/peakpick.c | 3 +- 8 files changed, 567 insertions(+), 3 deletions(-) create mode 100644 examples/aubiotrack.c create mode 100644 src/beattracking.c create mode 100644 src/beattracking.h diff --git a/VERSION b/VERSION index 547cf88d..81ea2b97 100644 --- a/VERSION +++ b/VERSION @@ -1,5 +1,5 @@ AUBIO_MAJOR_VERSION=0 AUBIO_MINOR_VERSION=1 -AUBIO_PATCH_VERSION=8 -AUBIO_VERSION_STATUS= +AUBIO_PATCH_VERSION=9 +AUBIO_VERSION_STATUS=beta5 diff --git a/examples/Makefile.am b/examples/Makefile.am index 2c49eddf..330c62c7 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -8,6 +8,7 @@ AM_LDFLAGS = -L../src -L../ext @LADCCA_LIBS@ -laubioext -laubio # add your programs to this list bin_PROGRAMS = \ aubioonset \ + aubiotrack \ aubionotes EXTRA_DIST = utils.h @@ -15,6 +16,8 @@ EXTRA_DIST = utils.h # optionally add sources file for these programs aubioonset_SOURCES = aubioonset.c utils.c aubionotes_SOURCES = aubionotes.c utils.c +aubiotrack_SOURCES = aubiotrack.c utils.c aubioonset_LDADD = @JACK_LIBS@ aubionotes_LDADD = @JACK_LIBS@ +aubiotrack_LDADD = @JACK_LIBS@ diff --git a/examples/aubiotrack.c b/examples/aubiotrack.c new file mode 100644 index 00000000..4261e30e --- /dev/null +++ b/examples/aubiotrack.c @@ -0,0 +1,146 @@ +/* + Copyright (C) 2003 Paul Brossier + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "utils.h" +#include "beattracking.h" + +unsigned int pos = 0; /* frames%dspblocksize */ +unsigned int pos2 = 0; /* frames%dspblocksize */ +uint_t usepitch = 0; +fvec_t * dfframe = NULL; +fvec_t * out = NULL; +aubio_beattracking_t * bt = NULL; +uint_t winlen = 512; +uint_t step = 128; +uint_t laglen = 128; +uint_t rayparam = 43; +uint_t istactus = 0; + +int aubio_process(float **input, float **output, int nframes); +int aubio_process(float **input, float **output, int nframes) { + unsigned int i; /*channels*/ + unsigned int j; /*frames*/ + smpl_t * btoutput = out->data[0]; + for (j=0;jdata[0][0] *= onset2->data[0][0]; + } + /* execute every overlap_size*step */ + if (pos2 == step -1 ) { + + /* check dfframe */ + /* + outmsg("\n"); + for (i = 0; i < winlen; i++ ) + outmsg("%f,", dfframe->data[0][i]); + outmsg("\n"); + */ + + aubio_beattracking_do(bt,dfframe,out); + + /* rotate dfframe */ + for (i = 0 ; i < winlen - step; i++ ) + dfframe->data[0][i] = dfframe->data[0][i+step]; + for (i = winlen - step ; i < winlen; i++ ) + dfframe->data[0][i] = 0.; + + pos2 = -1; + } + pos2++; + isonset = aubio_peakpick_pimrt_wt(onset,parms,&(dfframe->data[0][winlen - step + pos2])); + /* end of second level loop */ + istactus = 0; + i=0; + for (i = 1; i <= btoutput[0]; i++ ) { + if (pos2 == btoutput[i] && btoutput[i] != 0.) { + //printf("pos2: %d\n", pos2); + /* test for silence */ + if (aubio_silence_detection(ibuf, threshold2)==1) { + isonset = 0; + istactus = 0; + } else { + istactus = 1; + } + } + } + + if (istactus ==1) { + for (pos = 0; pos < overlap_size; pos++) + obuf->data[0][pos] = woodblock->data[0][pos]; + } else { + for (pos = 0; pos < overlap_size; pos++) + obuf->data[0][pos] = 0.; + } + /* end of block loop */ + pos = -1; /* so it will be zero next j loop */ + } + pos++; + } + return 1; +} + +void process_print (void); +void process_print (void) { + if (output_filename == NULL) { + if (istactus) + outmsg("%d\t%f",pos2,(frames)*overlap_size/(float)samplerate); + if (isonset) + outmsg(" \t \t%f\n",(frames)*overlap_size/(float)samplerate); + } +} + +int main(int argc, char **argv) { + + /* override default settings */ + examples_common_init(argc,argv); + + dfframe = new_fvec(winlen,channels); + out = new_fvec(step,channels); + /* test input : impulses starting from 15, at intervals of 50 samples */ + //for(i=0;i<16;i++){ + // dfframe->data[0][50*i+14] = 1.; + //} + + bt = new_aubio_beattracking(winlen,step, laglen, + rayparam, channels); + + examples_common_process(aubio_process,process_print); + + examples_common_del(); + + debug("End of program.\n"); + + fflush(stderr); + + return 0; +} + diff --git a/src/Makefile.am b/src/Makefile.am index f0516e30..718dbec5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,6 +19,7 @@ pkginclude_HEADERS = aubio.h \ pitchyin.h \ pitchschmitt.h \ pitchfcomb.h \ + beattracking.h \ filter.h lib_LTLIBRARIES = libaubio.la @@ -56,6 +57,8 @@ libaubio_la_SOURCES = aubio.h \ pitchschmitt.h \ pitchfcomb.c \ pitchfcomb.h \ + beattracking.c \ + beattracking.h \ filter.c \ filter.h diff --git a/src/aubio.h b/src/aubio.h index 44ce440d..bc345f93 100644 --- a/src/aubio.h +++ b/src/aubio.h @@ -74,6 +74,7 @@ extern "C" { #include "pitchyin.h" #include "pitchschmitt.h" #include "pitchfcomb.h" +#include "beattracking.h" #ifdef __cplusplus } /* extern "C" */ diff --git a/src/beattracking.c b/src/beattracking.c new file mode 100644 index 00000000..bfe77a05 --- /dev/null +++ b/src/beattracking.c @@ -0,0 +1,351 @@ +/* + Copyright (C) 2005 Matthew Davies and Paul Brossier + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "aubio_priv.h" +#include "sample.h" +#include "mathutils.h" +#include "beattracking.h" + +/* maximum length for rp */ +static uint_t MAXRP = 512; +static smpl_t constthresh = 3.901; //empirically derived! +static smpl_t stepthresh = 2.*3.901; + +uint_t fvec_gettimesig(smpl_t * acf, uint_t acflen, uint_t gp); +void aubio_beattracking_checkstate(aubio_beattracking_t * bt); + +/* could move to struct */ +uint_t gp=0, bp = 0, rp1 = 0, rp2 = 0; +smpl_t g_mu =0.; +smpl_t g_var = 3.901; +uint_t flagconst = 0; +uint_t flagstep = 0; +// needs to be a signed ? +sint_t counter = 0; +uint_t maxindex = 0; +uint_t timesig = 0; +uint_t rp = 1; +uint_t lastbeat = 0; +//number of harmonics in shift invariant comb filterbank +uint_t numelem = 4; + +struct _aubio_beattracking_t { + fvec_t * rwv; /* rayleigh weight vector - rayleigh distribution function */ + fvec_t * gwv; /* rayleigh weight vector - rayleigh distribution function */ + fvec_t * dfwv; /* detection function weighting - exponential curve */ + fvec_t * dfrev; /* reversed onset detection function */ + fvec_t * acf; /* vector for autocorrelation function (of current detection function frame) */ + fvec_t * acfout; /* store result of passing acf through s.i.c.f.b. */ + fvec_t * phwv; /* beat expectation alignment weighting */ + fvec_t * phout; + //uint_t timesig; /* time signature of input, set to zero until context dependent model activated */ + uint_t step; +}; + +aubio_beattracking_t * new_aubio_beattracking(uint_t winlen, + uint_t step, + uint_t laglen, + uint_t rayparam, + uint_t channels) { + + aubio_beattracking_t * p = AUBIO_NEW(aubio_beattracking_t); + + uint_t i = 0; + smpl_t dfwvnorm = EXP((LOG(2.0)/rayparam)*(winlen+2)); + + p->step = step; + p->rwv = new_fvec(laglen,channels); + p->gwv = new_fvec(laglen,channels); + p->dfwv = new_fvec(winlen,channels); + p->dfrev = new_fvec(winlen,channels); + p->acf = new_fvec(winlen,channels); + p->acfout = new_fvec(laglen,channels); + p->phwv = new_fvec(2*laglen,channels); + p->phout = new_fvec(MAXRP,channels); + //p->timesig = 0; + + /* exponential weighting, dfwv = 0.5 when i = 43 */ + for (i=0;idfwv->data[0][i] = (EXP((LOG(2.0)/rayparam)*(i+1))) + / dfwvnorm; + } + + for (i=0;i<(laglen);i++){ + p->rwv->data[0][i] = ((smpl_t)(i+1.) / SQR((smpl_t)rayparam)) * + EXP((-SQR((smpl_t)(i+1.)) / (2.*SQR((smpl_t)rayparam)))); + } + + return p; + +} + +void del_aubio_beattracking(aubio_beattracking_t * p) { + del_fvec(p->rwv); + del_fvec(p->gwv); + del_fvec(p->dfwv); + del_fvec(p->dfrev); + del_fvec(p->acf); + del_fvec(p->acfout); + del_fvec(p->phwv); + del_fvec(p->phout); + AUBIO_FREE(p); +} + + +void aubio_beattracking_do(aubio_beattracking_t * bt, fvec_t * dfframe, fvec_t * output) { + + uint_t i,k; + /* current beat period value found using gaussian weighting (from context dependent model) */ + uint_t step = bt->step; + uint_t laglen = bt->rwv->length; + uint_t winlen = bt->dfwv->length; + smpl_t * phout = bt->phout->data[0]; + smpl_t * phwv = bt->phwv->data[0]; + smpl_t * dfrev = bt->dfrev->data[0]; + smpl_t * dfwv = bt->dfwv->data[0]; + smpl_t * rwv = bt->rwv->data[0]; + smpl_t * acfout = bt->acfout->data[0]; + smpl_t * acf = bt->acf->data[0]; + //smpl_t * out = output->data[0]; + + //parameters for making s.i.c.f.b. + uint_t a,b; + //beat alignment + uint_t phase; + uint_t kmax; + uint_t beat; + + for (i = 0; i < winlen; i++){ + dfrev[winlen-1-i] = 0.; + dfrev[winlen-1-i] = dfframe->data[0][i]*dfwv[i]; + } + + /* find autocorrelation function */ + aubio_autocorr(dfframe,bt->acf); + /* + for (i = 0; i < winlen; i++){ + AUBIO_DBG("%f,",acf[i]); + } + AUBIO_DBG("\n"); + */ + + /* get acfout - assume Rayleigh weightvector only */ + /* if timesig is unknown, use metrically unbiased version of filterbank */ + //if(!timesig) + // AUBIO_DBG("using unbiased filterbank, timesig: %d\n", timesig); + //else + // AUBIO_DBG("using biased filterbank, timesig: %d\n", timesig); + if(!timesig) + numelem = 4; + else + numelem = timesig; + + /* first and last output values are left intentionally as zero */ + for (i=0; i < bt->acfout->length; i++) + acfout[i] = 0.; + for(i=1;iacfout); + rp = maxindex ? maxindex : 1; + rp = (maxindex==127) ? 43 : maxindex; //rayparam + + /* activate biased filterbank */ + aubio_beattracking_checkstate(bt); + /* end of biased filterbank */ + + /* initialize output */ + for(i=0;iphout); + if (maxindex == winlen-1) maxindex = 0; + phase = 1 + maxindex; + + /* debug */ + //AUBIO_DBG("beat period = %d, rp1 = %d, rp2 = %d\n", bp, rp1, rp2); + //AUBIO_DBG("rp = %d, gp = %d, phase = %d\n", rp, gp, phase); + + /* reset output */ + for (i = 0; i < laglen; i++) + output->data[0][i] = 0.; + + i = 1; + beat = bp - phase; + /* start counting the beats */ + if(beat) + { + output->data[0][i] = (smpl_t)beat; + i++; + } + + while( beat+bp < step ) + { + beat += bp; + output->data[0][i] = (smpl_t)beat; + i++; + } + + lastbeat = beat; + + output->data[0][0] = i; + +} + +uint_t fvec_gettimesig(smpl_t * acf, uint_t acflen, uint_t gp){ + sint_t k = 0; + smpl_t three_energy = 0., four_energy = 0.; + if( acflen > 6 * gp + 2 ){ + for(k=-2;k<2;k++){ + three_energy += acf[3*gp+k]; + four_energy += acf[4*gp+k]; + } + } + else{ /*Expanded to be more accurate in time sig estimation*/ + for(k=-2;k<2;k++){ + three_energy += acf[3*gp+k]+acf[6*gp+k]; + four_energy += acf[4*gp+k]+acf[2*gp+k]; + } + } + return (three_energy > four_energy) ? 3 : 4; +} + +void aubio_beattracking_checkstate(aubio_beattracking_t * bt) { + uint_t i,j,a,b; + uint_t laglen = bt->rwv->length; + uint_t acflen = bt->acf->length; + uint_t step = bt->step; + smpl_t * acf = bt->acf->data[0]; + smpl_t * acfout = bt->acfout->data[0]; + smpl_t * gwv = bt->gwv->data[0]; + smpl_t * phwv = bt->phwv->data[0]; + + if (gp) { + // doshiftfbank again only if context dependent model is in operation + //acfout = doshiftfbank(acf,gwv,timesig,laglen,acfout); + //don't need acfout now, so can reuse vector + // gwv is, in first loop, definitely all zeros, but will have + // proper values when context dependent model is activated + for (i=0; i < bt->acfout->length; i++) + acfout[i] = 0.; + for(i=1;iacfout); + } else { + //still only using general model + gp = 0; + } + + //now look for step change - i.e. a difference between gp and rp that + // is greater than stepthresh - always true in first case, since gp = 0 + if(counter == 0){ + if(ABS(gp - rp) > stepthresh) { + flagstep = 1; // have observed step change. + counter = 3; // setup 3 frame counter + } else { + flagstep = 0; + } + } + + //i.e. 3rd frame after flagstep initially set + if (counter==1 && flagstep==1) { + //check for consistency between previous beatperiod values + if(ABS(2.*rp - rp1 -rp2) < constthresh) { + //if true, can activate context dependent model + flagconst = 1; + counter = 0; // reset counter and flagstep + } else { + //if not consistent, then don't flag consistency! + flagconst = 0; + counter = 2; // let it look next time + } + } else if (counter > 0) { + //if counter doesn't = 1, + counter = counter-1; + } + + rp2 = rp1; rp1 = rp; + + if (flagconst) { + /* first run of new hypothesis */ + gp = rp; + g_mu = gp; + timesig = fvec_gettimesig(acf,acflen, gp); + for(j=0;j lastbeat) { + for(j=0;j<2*laglen;j++) { + phwv[j] = EXP(-.5*SQR((smpl_t)(1.+j-step+lastbeat))/(bp/8.)); + } + } else { + AUBIO_DBG("NOT using phase weighting as step is %d and lastbeat %d \n", + step,lastbeat); + for(j=0;j<2*laglen;j++) {phwv[j] = 1.;} + } + } else { + /* initial state */ + bp = rp; + /* flat phase weighting */ + for(j=0;j<2*laglen;j++) {phwv[j] = 1.;} + } + + + /* do some further checks on the final bp value */ + /* if tempo is > 206 bpm, half it */ + while (bp < 25) { + bp = bp*2; + AUBIO_DBG("warning, halving the tempo to %f\n", 5168./bp); + } + + AUBIO_DBG("tempo:\t%3.5f bpm | time signature: %d \n", 5168./bp, timesig); + +} diff --git a/src/beattracking.h b/src/beattracking.h new file mode 100644 index 00000000..f7175ad3 --- /dev/null +++ b/src/beattracking.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2003 Matthew Davies and Paul Brossier + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef BEATTRACKING_H +#define BEATTRACKING_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * beat tracking object + */ +typedef struct _aubio_beattracking_t aubio_beattracking_t; +/** + * create beat tracking object + * \param frame size [512] + * \param step increment - both in detection function samples -i.e. 11.6ms or 1 onset frame [128] + * \param length over which beat period is found [128] + * \param parameter for rayleigh weight vector - sets preferred tempo to 120bpm [43] + * \param channel number (not functionnal) [1] */ +aubio_beattracking_t * new_aubio_beattracking(uint_t winlen, + uint_t step, + uint_t laglen, + uint_t rayparam, + uint_t channels); +/** + * track the beat + * \param beat tracking object + * \param current input detection function frame. already smoothed by adaptive median threshold. + * \param stored tactus candidate positions + */ +void aubio_beattracking_do(aubio_beattracking_t * bt, fvec_t * dfframes, fvec_t * out); +/** + * delete beat tracker object + */ +void del_aubio_beattracking(aubio_beattracking_t * p); + +#ifdef __cplusplus +} +#endif + +#endif /* BEATTRACKING_H */ diff --git a/src/peakpick.c b/src/peakpick.c index 96ad4706..91d4b387 100644 --- a/src/peakpick.c +++ b/src/peakpick.c @@ -157,7 +157,8 @@ uint_t aubio_peakpick_pimrt_wt(fvec_t * onset, pickparams_t * p, smpl_t* peakva uint_t isonset = (p->pickerfn)(onset_peek,1); - if ( isonset && peakval != NULL ) + //if ( isonset && peakval != NULL ) + if ( peakval != NULL ) *peakval = onset_peek->data[i][1]; return isonset; -- 2.11.0