source: src/onset/onsetdetection.c @ 1942323

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

src/onset/onsetdetection.c: fix off by one error in complexdomain without complex.h

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