import 0.1.9beta5 with beat tracking
authorPaul Brossier <piem@altern.org>
Sun, 22 May 2005 16:36:47 +0000 (16:36 +0000)
committerPaul Brossier <piem@altern.org>
Sun, 22 May 2005 16:36:47 +0000 (16:36 +0000)
import 0.1.9beta5 with beat tracking

VERSION
examples/Makefile.am
examples/aubiotrack.c [new file with mode: 0644]
src/Makefile.am
src/aubio.h
src/beattracking.c [new file with mode: 0644]
src/beattracking.h [new file with mode: 0644]
src/peakpick.c

diff --git a/VERSION b/VERSION
index 547cf88dbd0351b9371a1485378758d28e56328a..81ea2b97f94a33fdc0a0c86a8f4f28ab3577a50c 100644 (file)
--- 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
 
index 2c49eddf87b3f23f9a52d13bf8b4775b03080eb7..330c62c7d99e15e638aa9885e18a0ac4d9366d3a 100644 (file)
@@ -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 (file)
index 0000000..4261e30
--- /dev/null
@@ -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;j<nframes;j++) {
+    if(usejack) {
+      for (i=0;i<channels;i++) {
+        /* write input to datanew */
+        fvec_write_sample(ibuf, input[i][j], i, pos);
+        /* put synthnew in output */
+        output[i][j] = fvec_read_sample(obuf, i, pos);
+      }
+    }
+    /*time for fft*/
+    if (pos == overlap_size-1) {         
+      /* block loop */
+      aubio_pvoc_do (pv,ibuf, fftgrain);
+      aubio_onsetdetection(o,fftgrain, onset);
+      if (usedoubled) {
+        aubio_onsetdetection(o2,fftgrain, onset2);
+        onset->data[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;
+}
+
index f0516e30ce568f6c48b4ec7286c0d41f38f0b88e..718dbec515e9c72a2f61b74670d6c4273582d57d 100644 (file)
@@ -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
 
index 44ce440def8eb52d2bf3b26389fe89023df9e58b..bc345f93d5afd81f551d45e9b982d0082f43ef0d 100644 (file)
@@ -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 (file)
index 0000000..bfe77a0
--- /dev/null
@@ -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;i<winlen;i++) {
+                p->dfwv->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;i<laglen-1;i++){ 
+                for (a=1;a<=numelem;a++){
+                        for(b=(1-a);b<a;b++){
+                                acfout[i] += acf[a*(i+1)+b-1] 
+                                        * 1./(2.*a-1.)*rwv[i];
+                        }
+                }
+        }
+
+        /* find non-zero Rayleigh period */
+        maxindex = vec_max_elem(bt->acfout);
+        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;i<MAXRP;i++)     {phout[i] = 0.;} 
+
+        /* deliberate integer operation */
+        /* could be set to 3 max eventually */
+        kmax = winlen/bp;
+
+        for(i=0;i<bp;i++){
+                phout[i] = 0.;
+                for(k=0;k<kmax;k++){
+                        phout[i] += dfrev[i+bp*k] * phwv[i];
+                }
+        }
+
+
+        /* find Rayleigh period */
+        maxindex = vec_max_elem(bt->phout);
+        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;i<laglen-1;i++){ 
+                        for (a=1;a<=timesig;a++){
+                                for(b=(1-a);b<a;b++){
+                                        acfout[i] += acf[a*(i+1)+b-1] 
+                                                * 1. * gwv[i];
+                                }
+                        }
+                }
+                gp = vec_max_elem(bt->acfout);
+        } 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<laglen;j++)
+                        gwv[j] = EXP(-.5*SQR((smpl_t)(j+1.-g_mu))/SQR(g_var));
+                flagconst = 0;
+                bp = gp;
+                /* flat phase weighting */
+                for(j=0;j<2*laglen;j++)  {phwv[j] = 1.;} 
+        } else if (timesig) {
+                /* context dependant model */
+                bp = gp;
+                /* gaussian phase weighting */
+                if (step > 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 (file)
index 0000000..f7175ad
--- /dev/null
@@ -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 */
index 96ad4706ff7808f9f30440fad4daa481c25f896e..91d4b387fed97a7dce0ed6447866c62c17744b91 100644 (file)
@@ -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;