source: src/beattracking.c @ b78805a

feature/autosinkfeature/cnnfeature/cnn_orgfeature/constantqfeature/crepefeature/crepe_orgfeature/pitchshiftfeature/pydocstringsfeature/timestretchfix/ffmpeg5pitchshiftsamplertimestretchyinfft+
Last change on this file since b78805a was b78805a, checked in by Paul Brossier <piem@altern.org>, 19 years ago

import 0.1.9beta5 with beat tracking
import 0.1.9beta5 with beat tracking

  • Property mode set to 100644
File size: 12.2 KB
Line 
1/*
2         Copyright (C) 2005 Matthew Davies and Paul Brossier
3
4         This program is free software; you can redistribute it and/or modify
5         it under the terms of the GNU General Public License as published by
6         the Free Software Foundation; either version 2 of the License, or
7         (at your option) any later version.
8
9         This program is distributed in the hope that it will be useful,
10         but WITHOUT ANY WARRANTY; without even the implied warranty of
11         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12         GNU General Public License for more details.
13
14         You should have received a copy of the GNU General Public License
15         along with this program; if not, write to the Free Software
16         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17         
18*/
19
20#include "aubio_priv.h"
21#include "sample.h"
22#include "mathutils.h"
23#include "beattracking.h"
24
25/* maximum length for rp */
26static uint_t MAXRP = 512;
27static smpl_t constthresh = 3.901; //empirically derived!
28static smpl_t stepthresh = 2.*3.901;
29
30uint_t fvec_gettimesig(smpl_t * acf, uint_t acflen, uint_t gp);
31void aubio_beattracking_checkstate(aubio_beattracking_t * bt);
32
33/* could move to struct */
34uint_t gp=0, bp = 0, rp1 = 0, rp2 = 0;
35smpl_t g_mu =0.;
36smpl_t g_var = 3.901;
37uint_t flagconst = 0;
38uint_t flagstep  = 0;
39// needs to be a signed ?
40sint_t counter = 0;
41uint_t maxindex  = 0;
42uint_t timesig   = 0;
43uint_t rp        = 1;
44uint_t lastbeat  = 0;
45//number of harmonics in shift invariant comb filterbank
46uint_t numelem   = 4;
47
48struct _aubio_beattracking_t {
49        fvec_t * rwv;    /* rayleigh weight vector - rayleigh distribution function */                   
50        fvec_t * gwv;    /* rayleigh weight vector - rayleigh distribution function */                   
51        fvec_t * dfwv;   /* detection function weighting - exponential curve */
52        fvec_t * dfrev;  /* reversed onset detection function */
53        fvec_t * acf;    /* vector for autocorrelation function (of current detection function frame) */
54        fvec_t * acfout; /* store result of passing acf through s.i.c.f.b. */
55        fvec_t * phwv;   /* beat expectation alignment weighting */
56        fvec_t * phout;
57        //uint_t timesig;  /* time signature of input, set to zero until context dependent model activated */
58        uint_t step;
59};
60
61aubio_beattracking_t * new_aubio_beattracking(uint_t winlen,
62                uint_t step,
63                uint_t laglen,
64                uint_t rayparam,
65                uint_t channels) {
66
67        aubio_beattracking_t * p = AUBIO_NEW(aubio_beattracking_t);
68
69        uint_t i        = 0;
70        smpl_t dfwvnorm = EXP((LOG(2.0)/rayparam)*(winlen+2));
71
72        p->step    = step;
73        p->rwv     = new_fvec(laglen,channels);
74        p->gwv     = new_fvec(laglen,channels);
75        p->dfwv    = new_fvec(winlen,channels);
76        p->dfrev   = new_fvec(winlen,channels);
77        p->acf     = new_fvec(winlen,channels);
78        p->acfout  = new_fvec(laglen,channels);
79        p->phwv    = new_fvec(2*laglen,channels);
80        p->phout   = new_fvec(MAXRP,channels);
81        //p->timesig = 0;
82
83        /* exponential weighting, dfwv = 0.5 when i =  43 */
84        for (i=0;i<winlen;i++) {
85                p->dfwv->data[0][i] = (EXP((LOG(2.0)/rayparam)*(i+1)))
86                        / dfwvnorm;
87        } 
88
89        for (i=0;i<(laglen);i++){
90                p->rwv->data[0][i] = ((smpl_t)(i+1.) / SQR((smpl_t)rayparam)) * 
91                        EXP((-SQR((smpl_t)(i+1.)) / (2.*SQR((smpl_t)rayparam))));
92        }
93
94        return p;
95
96}
97
98void del_aubio_beattracking(aubio_beattracking_t * p) {
99        del_fvec(p->rwv);
100        del_fvec(p->gwv);
101        del_fvec(p->dfwv);
102        del_fvec(p->dfrev);
103        del_fvec(p->acf);
104        del_fvec(p->acfout);
105        del_fvec(p->phwv);
106        del_fvec(p->phout);
107        AUBIO_FREE(p);
108}
109
110
111void aubio_beattracking_do(aubio_beattracking_t * bt, fvec_t * dfframe, fvec_t * output) {
112
113        uint_t i,k;
114        /* current beat period value found using gaussian weighting (from context dependent model) */
115        uint_t step     = bt->step;
116        uint_t laglen   = bt->rwv->length;
117        uint_t winlen   = bt->dfwv->length;
118        smpl_t * phout  = bt->phout->data[0];
119        smpl_t * phwv   = bt->phwv->data[0];
120        smpl_t * dfrev  = bt->dfrev->data[0];
121        smpl_t * dfwv   = bt->dfwv->data[0];
122        smpl_t * rwv    = bt->rwv->data[0];
123        smpl_t * acfout = bt->acfout->data[0];
124        smpl_t * acf    = bt->acf->data[0];
125        //smpl_t * out    = output->data[0];
126
127        //parameters for making s.i.c.f.b.
128        uint_t a,b; 
129        //beat alignment
130        uint_t phase; 
131        uint_t kmax;
132        uint_t beat; 
133
134        for (i = 0; i < winlen; i++){
135                dfrev[winlen-1-i] = 0.;
136                dfrev[winlen-1-i] = dfframe->data[0][i]*dfwv[i];
137        }
138
139        /* find autocorrelation function */
140        aubio_autocorr(dfframe,bt->acf); 
141        /*
142        for (i = 0; i < winlen; i++){
143                AUBIO_DBG("%f,",acf[i]);
144        }
145        AUBIO_DBG("\n");
146        */
147
148        /* get acfout - assume Rayleigh weightvector only */
149        /* if timesig is unknown, use metrically unbiased version of filterbank */
150        //if(!timesig) 
151        //        AUBIO_DBG("using unbiased filterbank, timesig: %d\n", timesig);
152        //else         
153        //        AUBIO_DBG("using biased filterbank, timesig: %d\n", timesig);
154        if(!timesig) 
155                numelem = 4;
156        else
157                numelem = timesig;
158
159        /* first and last output values are left intentionally as zero */
160        for (i=0; i < bt->acfout->length; i++)
161                acfout[i] = 0.;
162        for(i=1;i<laglen-1;i++){ 
163                for (a=1;a<=numelem;a++){
164                        for(b=(1-a);b<a;b++){
165                                acfout[i] += acf[a*(i+1)+b-1] 
166                                        * 1./(2.*a-1.)*rwv[i];
167                        }
168                }
169        }
170
171        /* find non-zero Rayleigh period */
172        maxindex = vec_max_elem(bt->acfout);
173        rp = maxindex ? maxindex : 1;
174        rp = (maxindex==127) ? 43 : maxindex; //rayparam
175
176        /* activate biased filterbank */
177        aubio_beattracking_checkstate(bt);
178        /* end of biased filterbank */
179
180        /* initialize output */
181        for(i=0;i<MAXRP;i++)     {phout[i] = 0.;} 
182
183        /* deliberate integer operation */
184        /* could be set to 3 max eventually */
185        kmax = winlen/bp;
186
187        for(i=0;i<bp;i++){
188                phout[i] = 0.;
189                for(k=0;k<kmax;k++){
190                        phout[i] += dfrev[i+bp*k] * phwv[i];
191                }
192        }
193
194
195        /* find Rayleigh period */
196        maxindex = vec_max_elem(bt->phout);
197        if (maxindex == winlen-1) maxindex = 0;
198        phase =  1 + maxindex;
199
200        /* debug */
201        //AUBIO_DBG("beat period = %d, rp1 = %d, rp2 = %d\n", bp, rp1, rp2);
202        //AUBIO_DBG("rp = %d, gp = %d, phase = %d\n", rp, gp, phase);
203
204        /* reset output */
205        for (i = 0; i < laglen; i++)
206                output->data[0][i] = 0.;
207
208        i = 1;
209        beat =  bp - phase;
210        /* start counting the beats */
211        if(beat)
212        {
213                output->data[0][i] = (smpl_t)beat;
214                i++;
215        }
216
217        while( beat+bp < step )
218        {
219                beat += bp;
220                output->data[0][i] = (smpl_t)beat;
221                i++;
222        }
223
224        lastbeat = beat;
225
226        output->data[0][0] = i;
227
228}
229
230uint_t fvec_gettimesig(smpl_t * acf, uint_t acflen, uint_t gp){
231        sint_t k = 0;
232        smpl_t three_energy = 0., four_energy = 0.;
233        if( acflen > 6 * gp + 2 ){
234                for(k=-2;k<2;k++){
235                        three_energy += acf[3*gp+k];
236                        four_energy += acf[4*gp+k];
237                }
238        }
239        else{ /*Expanded to be more accurate in time sig estimation*/
240                for(k=-2;k<2;k++){
241                        three_energy += acf[3*gp+k]+acf[6*gp+k];
242                        four_energy += acf[4*gp+k]+acf[2*gp+k];
243                }
244        }
245        return (three_energy > four_energy) ? 3 : 4;
246}
247
248void aubio_beattracking_checkstate(aubio_beattracking_t * bt) {
249        uint_t i,j,a,b;
250        uint_t laglen   = bt->rwv->length;
251        uint_t acflen   = bt->acf->length;
252        uint_t step     = bt->step;
253        smpl_t * acf    = bt->acf->data[0];
254        smpl_t * acfout = bt->acfout->data[0];
255        smpl_t * gwv    = bt->gwv->data[0];
256        smpl_t * phwv   = bt->phwv->data[0];
257
258        if (gp) {
259                // doshiftfbank again only if context dependent model is in operation
260                //acfout = doshiftfbank(acf,gwv,timesig,laglen,acfout);
261                //don't need acfout now, so can reuse vector
262                // gwv is, in first loop, definitely all zeros, but will have
263                // proper values when context dependent model is activated
264                for (i=0; i < bt->acfout->length; i++)
265                       acfout[i] = 0.;
266                for(i=1;i<laglen-1;i++){ 
267                        for (a=1;a<=timesig;a++){
268                                for(b=(1-a);b<a;b++){
269                                        acfout[i] += acf[a*(i+1)+b-1] 
270                                                * 1. * gwv[i];
271                                }
272                        }
273                }
274                gp = vec_max_elem(bt->acfout);
275        } else {
276                //still only using general model
277                gp = 0; 
278        }
279
280        //now look for step change - i.e. a difference between gp and rp that
281        // is greater than stepthresh - always true in first case, since gp = 0
282        if(counter == 0){
283                if(ABS(gp - rp) > stepthresh) {
284                        flagstep = 1; // have observed  step change.
285                        counter  = 3; // setup 3 frame counter
286                } else {
287                        flagstep = 0;
288                }
289        }
290
291        //i.e. 3rd frame after flagstep initially set
292        if (counter==1 && flagstep==1) {
293                //check for consistency between previous beatperiod values
294                if(ABS(2.*rp - rp1 -rp2) < constthresh) {
295                        //if true, can activate context dependent model
296                        flagconst = 1;
297                        counter   = 0; // reset counter and flagstep
298                } else {
299                        //if not consistent, then don't flag consistency!
300                        flagconst = 0;
301                        counter   = 2; // let it look next time
302                }
303        } else if (counter > 0) {
304                //if counter doesn't = 1,
305                counter = counter-1;
306        }
307
308        rp2 = rp1; rp1 = rp; 
309
310        if (flagconst) {
311                /* first run of new hypothesis */
312                gp = rp;
313                g_mu = gp;
314                timesig = fvec_gettimesig(acf,acflen, gp);
315                for(j=0;j<laglen;j++)
316                        gwv[j] = EXP(-.5*SQR((smpl_t)(j+1.-g_mu))/SQR(g_var));
317                flagconst = 0;
318                bp = gp;
319                /* flat phase weighting */
320                for(j=0;j<2*laglen;j++)  {phwv[j] = 1.;} 
321        } else if (timesig) {
322                /* context dependant model */
323                bp = gp;
324                /* gaussian phase weighting */
325                if (step > lastbeat) {
326                        for(j=0;j<2*laglen;j++)  {
327                                phwv[j] = EXP(-.5*SQR((smpl_t)(1.+j-step+lastbeat))/(bp/8.));
328                        }
329                } else { 
330                        AUBIO_DBG("NOT using phase weighting as step is %d and lastbeat %d \n",
331                                        step,lastbeat);
332                        for(j=0;j<2*laglen;j++)  {phwv[j] = 1.;} 
333                }
334        } else {
335                /* initial state */ 
336                bp = rp;
337                /* flat phase weighting */
338                for(j=0;j<2*laglen;j++)  {phwv[j] = 1.;} 
339        }
340
341
342        /* do some further checks on the final bp value */
343        /* if tempo is > 206 bpm, half it */
344        while (bp < 25) {
345                bp = bp*2;
346                AUBIO_DBG("warning, halving the tempo to %f\n", 5168./bp);
347        }
348       
349        AUBIO_DBG("tempo:\t%3.5f bpm | time signature: %d \n", 5168./bp, timesig);
350
351}
Note: See TracBrowser for help on using the repository browser.