source: src/onsetdetection.c @ cad8783

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

add Kullback Liebler onset detection function and its modified version

  • Property mode set to 100644
File size: 9.3 KB
Line 
1/*
2   Copyright (C) 2003 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 "fft.h"
23#include "mathutils.h"
24#include "hist.h"
25#include "onsetdetection.h"
26
27
28struct _aubio_onsetdetection_t {
29        aubio_onsetdetection_type type;
30        /** Pointer to aubio_onsetdetection_<type> function */
31        void (*funcpointer)(aubio_onsetdetection_t *o,
32                        cvec_t * fftgrain, fvec_t * onset);
33        smpl_t threshold;
34        fvec_t *oldmag;
35        fft_data_t *meas;
36        fvec_t *dev1 ;
37        fvec_t *theta1;
38        fvec_t *theta2;
39        aubio_hist_t * histog;
40};
41
42
43static aubio_onsetdetection_t * aubio_onsetdetection_alloc(aubio_onsetdetection_type type, uint_t size, uint_t channels);
44
45/* Energy based onset detection function */
46void aubio_onsetdetection_energy  (aubio_onsetdetection_t *o,
47                cvec_t * fftgrain, fvec_t * onset) {
48        uint_t i,j;
49        for (i=0;i<fftgrain->channels;i++) {
50                onset->data[i][0] = 0.;
51                for (j=0;j<fftgrain->length;j++) {
52                        onset->data[i][0] += SQR(fftgrain->norm[i][j]);
53                }
54        }
55}
56
57/* High Frequency Content onset detection function */
58void aubio_onsetdetection_hfc(aubio_onsetdetection_t *o,        cvec_t * fftgrain, fvec_t * onset){
59        uint_t i,j;
60        for (i=0;i<fftgrain->channels;i++) {
61                onset->data[i][0] = 0.;
62                for (j=0;j<fftgrain->length;j++) {
63                        onset->data[i][0] += (j+1)*fftgrain->norm[i][j];
64                }
65        }
66}
67
68
69/* Complex Domain Method onset detection function */
70void aubio_onsetdetection_complex (aubio_onsetdetection_t *o, cvec_t * fftgrain, fvec_t * onset) {
71        uint_t i, j;
72        uint_t nbins = fftgrain->length;
73        for (i=0;i<fftgrain->channels; i++)     {
74                onset->data[i][0] = 0.;
75                for (j=0;j<nbins; j++)  {
76                        o->dev1->data[i][j]      = unwrap2pi(
77                                        fftgrain->phas[i][j]
78                                        -2.0*o->theta1->data[i][j]+
79                                        o->theta2->data[i][j]);
80                        o->meas[j] = fftgrain->norm[i][j]*CEXPC(I*o->dev1->data[i][j]);
81                        /* sum on all bins */
82                        onset->data[i][0]                += //(fftgrain->norm[i][j]);
83                                        SQRT(SQR( REAL(o->oldmag->data[i][j]-o->meas[j]) )
84                                                +  SQR( IMAG(o->oldmag->data[i][j]-o->meas[j]) )
85                                                );
86                        /* swap old phase data (need to remember 2 frames behind)*/
87                        o->theta2->data[i][j] = o->theta1->data[i][j];
88                        o->theta1->data[i][j] = fftgrain->phas[i][j];
89                        /* swap old magnitude data (1 frame is enough) */
90                        o->oldmag->data[i][j] = fftgrain->norm[i][j];
91                }
92        }
93}
94
95
96/* Phase Based Method onset detection function */
97void aubio_onsetdetection_phase(aubio_onsetdetection_t *o, 
98                cvec_t * fftgrain, fvec_t * onset){
99        uint_t i, j;
100        uint_t nbins = fftgrain->length;
101        for (i=0;i<fftgrain->channels; i++)     {
102                onset->data[i][0] = 0.0f;
103                o->dev1->data[i][0]=0.;
104                for ( j=0;j<nbins; j++ )        {
105                        o->dev1->data[i][j] = 
106                                unwrap2pi(
107                                                fftgrain->phas[i][j]
108                                                -2.0*o->theta1->data[i][j]
109                                                +o->theta2->data[i][j]);
110                        if ( o->threshold < fftgrain->norm[i][j] )
111                                o->dev1->data[i][j] = ABS(o->dev1->data[i][j]);
112                        else 
113                                o->dev1->data[i][j] = 0.0f;
114                        /* keep a track of the past frames */
115                        o->theta2->data[i][j] = o->theta1->data[i][j];
116                        o->theta1->data[i][j] = fftgrain->phas[i][j];
117                }
118                /* apply o->histogram */
119                aubio_hist_dyn_notnull(o->histog,o->dev1);
120                /* weight it */
121                aubio_hist_weigth(o->histog);
122                /* its mean is the result */
123                onset->data[i][0] = aubio_hist_mean(o->histog); 
124                //onset->data[i][0] = vec_mean(o->dev1);
125        }
126}
127
128/* Spectral difference method onset detection function */
129void aubio_onsetdetection_specdiff(aubio_onsetdetection_t *o,
130                cvec_t * fftgrain, fvec_t * onset){
131        uint_t i, j;
132        uint_t nbins = fftgrain->length;
133        for (i=0;i<fftgrain->channels; i++)     {
134                onset->data[i][0] = 0.0f;
135                for (j=0;j<nbins; j++)  {
136                        o->dev1->data[i][j] = SQRT(
137                                        ABS(SQR( fftgrain->norm[i][j])
138                                                - SQR(o->oldmag->data[i][j])));
139                        if (o->threshold < fftgrain->norm[i][j] )
140                                o->dev1->data[i][j] = ABS(o->dev1->data[i][j]);
141                        else 
142                                o->dev1->data[i][j] = 0.0f;
143                        o->oldmag->data[i][j] = fftgrain->norm[i][j];
144                }
145
146                /* apply o->histogram (act somewhat as a low pass on the
147                 * overall function)*/
148                aubio_hist_dyn_notnull(o->histog,o->dev1);
149                /* weight it */
150                aubio_hist_weigth(o->histog);
151                /* its mean is the result */
152                onset->data[i][0] = aubio_hist_mean(o->histog); 
153
154        }
155}
156
157/* Kullback Liebler onset detection function
158 * note we use ln(1+Xn/(Xn-1+0.0001)) to avoid
159 * negative (1.+) and infinite values (+1.e-10) */
160void aubio_onsetdetection_kl(aubio_onsetdetection_t *o, cvec_t * fftgrain, fvec_t * onset){
161        uint_t i,j;
162        for (i=0;i<fftgrain->channels;i++) {
163                onset->data[i][0] = 0.;
164                for (j=0;j<fftgrain->length;j++) {
165                        onset->data[i][0] += fftgrain->norm[i][j]
166                                *LOG(1.+fftgrain->norm[i][j]/(o->oldmag->data[i][j]+1.e-10));
167                        o->oldmag->data[i][j] = fftgrain->norm[i][j];
168                }
169                if (isnan(onset->data[i][0])) onset->data[i][0] = 0.;
170        }
171}
172
173/* Modified Kullback Liebler onset detection function
174 * note we use ln(1+Xn/(Xn-1+0.0001)) to avoid
175 * negative (1.+) and infinite values (+1.e-10) */
176void aubio_onsetdetection_mkl(aubio_onsetdetection_t *o, cvec_t * fftgrain, fvec_t * onset){
177        uint_t i,j;
178        for (i=0;i<fftgrain->channels;i++) {
179                onset->data[i][0] = 0.;
180                for (j=0;j<fftgrain->length;j++) {
181                        onset->data[i][0] += LOG(1.+fftgrain->norm[i][j]/(o->oldmag->data[i][j]+1.e-10));
182                        o->oldmag->data[i][j] = fftgrain->norm[i][j];
183                }
184                if (isnan(onset->data[i][0])) onset->data[i][0] = 0.;
185        }
186}
187
188/* Generic function pointing to the choosen one */
189void 
190aubio_onsetdetection(aubio_onsetdetection_t *o, cvec_t * fftgrain, 
191                fvec_t * onset) {
192        o->funcpointer(o,fftgrain,onset);
193}
194
195/* Allocate memory for an onset detection */
196aubio_onsetdetection_t * 
197new_aubio_onsetdetection (aubio_onsetdetection_type type, 
198                uint_t size, uint_t channels){
199        return aubio_onsetdetection_alloc(type,size,channels);
200}
201
202/* depending on the choosen type, allocate memory as needed */
203aubio_onsetdetection_t * 
204aubio_onsetdetection_alloc (aubio_onsetdetection_type type, 
205                uint_t size, uint_t channels){
206        aubio_onsetdetection_t * o = AUBIO_NEW(aubio_onsetdetection_t);
207        uint_t rsize = size/2+1;
208        switch(type) {
209                /* for both energy and hfc, only fftgrain->norm is required */
210                case energy: 
211                        break;
212                case hfc:
213                        break;
214                /* the other approaches will need some more memory spaces */
215                case complexdomain:
216                        o->oldmag = new_fvec(rsize,channels);
217                        /** bug: must be complex array */
218                        o->meas = AUBIO_ARRAY(fft_data_t,size);
219                        o->dev1  = new_fvec(rsize,channels);
220                        o->theta1 = new_fvec(rsize,channels);
221                        o->theta2 = new_fvec(rsize,channels);
222                        break;
223                case phase:
224                        o->dev1  = new_fvec(rsize,channels);
225                        o->theta1 = new_fvec(rsize,channels);
226                        o->theta2 = new_fvec(rsize,channels);
227                        o->histog = new_aubio_hist(0.0f, PI, 10, channels);
228                        o->threshold = 0.1;
229                        break;
230                case specdiff:
231                        o->oldmag = new_fvec(rsize,channels);
232                        o->dev1   = new_fvec(rsize,channels);
233                        o->histog = new_aubio_hist(0.0f, PI, 10, channels);
234                        o->threshold = 0.1;
235                        break;
236                case kl:
237                        o->oldmag = new_fvec(rsize,channels);
238                        break;
239                case mkl:
240                        o->oldmag = new_fvec(rsize,channels);
241                        break;
242                default:
243                        break;
244        }
245       
246        /* this switch could be in its own function to change between
247         * detections on the fly. this would need getting rid of the switch
248         * above and always allocate all the structure */
249
250        switch(type) {
251                case energy:
252                        o->funcpointer = aubio_onsetdetection_energy;
253                        break;
254                case hfc:
255                        o->funcpointer = aubio_onsetdetection_hfc;
256                        break;
257                case complexdomain:
258                        o->funcpointer = aubio_onsetdetection_complex;
259                        break;
260                case phase:
261                        o->funcpointer = aubio_onsetdetection_phase;
262                        break;
263                case specdiff:
264                        o->funcpointer = aubio_onsetdetection_specdiff;
265                        break;
266                case kl:
267                        o->funcpointer = aubio_onsetdetection_kl;
268                        break;
269                case mkl:
270                        o->funcpointer = aubio_onsetdetection_mkl;
271                        break;
272                default:
273                        break;
274        }
275        o->type = type;
276        return o;
277}
278
279void aubio_onsetdetection_free (aubio_onsetdetection_t *o){
280
281        switch(o->type) {
282                /* for both energy and hfc, only fftgrain->norm is required */
283                case energy: 
284                        break;
285                case hfc:
286                        break;
287                /* the other approaches will need some more memory spaces */
288                case complexdomain:
289                        AUBIO_FREE(o->meas);
290                        del_fvec(o->oldmag);
291                        del_fvec(o->dev1);
292                        del_fvec(o->theta1);
293                        del_fvec(o->theta2);
294                        break;
295                case phase:
296                        del_fvec(o->dev1);
297                        del_fvec(o->theta1);
298                        del_fvec(o->theta2);
299                        del_aubio_hist(o->histog);
300                        break;
301                case specdiff:
302                        del_fvec(o->oldmag);
303                        del_fvec(o->dev1);
304                        del_aubio_hist(o->histog);
305                        break;
306                default:
307                        break;
308        }
309        AUBIO_FREE(o);
310       
311}
Note: See TracBrowser for help on using the repository browser.