source: src/onsetdetection.c @ fabb7cd

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

onsetdection.{c,h}: add spectral flux (L2 norm, only energy increases)

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