source: src/onset/onsetdetection.c @ 47eabeb

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

src/onset/onsetdetection.c: simplify complex domain computation

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