src/mathutils.c: do not return NULL when wrong window type is passed (thanks to Olivi...
[aubio.git] / src / mathutils.c
1 /*
2   Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
3
4   This file is part of aubio.
5
6   aubio is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   aubio is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with aubio.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 /* see in mathutils.h for doc */
22
23 #include "aubio_priv.h"
24 #include "fvec.h"
25 #include "mathutils.h"
26 #include "musicutils.h"
27 #include "config.h"
28
29
30 /** Window types */
31 typedef enum
32 {
33   aubio_win_rectangle,
34   aubio_win_hamming,
35   aubio_win_hanning,
36   aubio_win_hanningz,
37   aubio_win_blackman,
38   aubio_win_blackman_harris,
39   aubio_win_gaussian,
40   aubio_win_welch,
41   aubio_win_parzen,
42   aubio_win_default = aubio_win_hanningz,
43 } aubio_window_type;
44
45 fvec_t *
46 new_aubio_window (char_t * window_type, uint_t size)
47 {
48   fvec_t * win = new_fvec (size);
49   smpl_t * w = win->data;
50   uint_t i;
51   aubio_window_type wintype;
52   if (strcmp (window_type, "rectangle") == 0)
53       wintype = aubio_win_rectangle;
54   else if (strcmp (window_type, "hamming") == 0)
55       wintype = aubio_win_hamming;
56   else if (strcmp (window_type, "hanning") == 0)
57       wintype = aubio_win_hanning;
58   else if (strcmp (window_type, "hanningz") == 0)
59       wintype = aubio_win_hanningz;
60   else if (strcmp (window_type, "blackman") == 0)
61       wintype = aubio_win_blackman;
62   else if (strcmp (window_type, "blackman_harris") == 0)
63       wintype = aubio_win_blackman_harris;
64   else if (strcmp (window_type, "gaussian") == 0)
65       wintype = aubio_win_gaussian;
66   else if (strcmp (window_type, "welch") == 0)
67       wintype = aubio_win_welch;
68   else if (strcmp (window_type, "parzen") == 0)
69       wintype = aubio_win_parzen;
70   else if (strcmp (window_type, "default") == 0)
71       wintype = aubio_win_default;
72   else {
73       AUBIO_ERR ("unknown window type %s, using default.\n", window_type);
74       wintype = aubio_win_default;
75   }
76   switch(wintype) {
77     case aubio_win_rectangle:
78       for (i=0;i<size;i++)
79         w[i] = 0.5;
80       break;
81     case aubio_win_hamming:
82       for (i=0;i<size;i++)
83         w[i] = 0.54 - 0.46 * COS(TWO_PI * i / (size));
84       break;
85     case aubio_win_hanning:
86       for (i=0;i<size;i++)
87         w[i] = 0.5 - (0.5 * COS(TWO_PI * i / (size)));
88       break;
89     case aubio_win_hanningz:
90       for (i=0;i<size;i++)
91         w[i] = 0.5 * (1.0 - COS(TWO_PI * i / (size)));
92       break;
93     case aubio_win_blackman:
94       for (i=0;i<size;i++)
95         w[i] = 0.42
96           - 0.50 * COS(    TWO_PI*i/(size-1.0))
97           + 0.08 * COS(2.0*TWO_PI*i/(size-1.0));
98       break;
99     case aubio_win_blackman_harris:
100       for (i=0;i<size;i++)
101         w[i] = 0.35875
102           - 0.48829 * COS(    TWO_PI*i/(size-1.0))
103           + 0.14128 * COS(2.0*TWO_PI*i/(size-1.0))
104           - 0.01168 * COS(3.0*TWO_PI*i/(size-1.0));
105       break;
106     case aubio_win_gaussian:
107       for (i=0;i<size;i++)
108         w[i] = EXP(- 1.0 / SQR(size) * SQR(2.0*i-size));
109       break;
110     case aubio_win_welch:
111       for (i=0;i<size;i++)
112         w[i] = 1.0 - SQR((2*i-size)/(size+1.0));
113       break;
114     case aubio_win_parzen:
115       for (i=0;i<size;i++)
116         w[i] = 1.0 - ABS((2*i-size)/(size+1.0));
117       break;
118     default:
119       break;
120   }
121   return win;
122 }
123
124 smpl_t
125 aubio_unwrap2pi (smpl_t phase)
126 {
127   /* mod(phase+pi,-2pi)+pi */
128   return phase + TWO_PI * (1. + FLOOR (-(phase + PI) / TWO_PI));
129 }
130
131 smpl_t
132 fvec_mean (fvec_t * s)
133 {
134   uint_t j;
135   smpl_t tmp = 0.0;
136   for (j = 0; j < s->length; j++) {
137     tmp += s->data[j];
138   }
139   return tmp / (smpl_t) (s->length);
140 }
141
142 smpl_t
143 fvec_sum (fvec_t * s)
144 {
145   uint_t j;
146   smpl_t tmp = 0.0;
147   for (j = 0; j < s->length; j++) {
148     tmp += s->data[j];
149   }
150   return tmp;
151 }
152
153 smpl_t
154 fvec_max (fvec_t * s)
155 {
156   uint_t j;
157   smpl_t tmp = 0.0;
158   for (j = 0; j < s->length; j++) {
159     tmp = (tmp > s->data[j]) ? tmp : s->data[j];
160   }
161   return tmp;
162 }
163
164 smpl_t
165 fvec_min (fvec_t * s)
166 {
167   uint_t j;
168   smpl_t tmp = s->data[0];
169   for (j = 0; j < s->length; j++) {
170     tmp = (tmp < s->data[j]) ? tmp : s->data[j];
171   }
172   return tmp;
173 }
174
175 uint_t
176 fvec_min_elem (fvec_t * s)
177 {
178   uint_t j, pos = 0.;
179   smpl_t tmp = s->data[0];
180   for (j = 0; j < s->length; j++) {
181     pos = (tmp < s->data[j]) ? pos : j;
182     tmp = (tmp < s->data[j]) ? tmp : s->data[j];
183   }
184   return pos;
185 }
186
187 uint_t
188 fvec_max_elem (fvec_t * s)
189 {
190   uint_t j, pos = 0;
191   smpl_t tmp = 0.0;
192   for (j = 0; j < s->length; j++) {
193     pos = (tmp > s->data[j]) ? pos : j;
194     tmp = (tmp > s->data[j]) ? tmp : s->data[j];
195   }
196   return pos;
197 }
198
199 void
200 fvec_shift (fvec_t * s)
201 {
202   uint_t j;
203   for (j = 0; j < s->length / 2; j++) {
204     ELEM_SWAP (s->data[j], s->data[j + s->length / 2]);
205   }
206 }
207
208 smpl_t
209 fvec_local_energy (fvec_t * f)
210 {
211   smpl_t energy = 0.;
212   uint_t j;
213   for (j = 0; j < f->length; j++) {
214     energy += SQR (f->data[j]);
215   }
216   return energy / f->length;
217 }
218
219 smpl_t
220 fvec_local_hfc (fvec_t * v)
221 {
222   smpl_t hfc = 0.;
223   uint_t j;
224   for (j = 0; j < v->length; j++) {
225     hfc += (j + 1) * v->data[j];
226   }
227   return hfc;
228 }
229
230 void
231 fvec_min_removal (fvec_t * v)
232 {
233   smpl_t v_min = fvec_min (v);
234   fvec_add (v,  - v_min );
235 }
236
237 smpl_t
238 fvec_alpha_norm (fvec_t * o, smpl_t alpha)
239 {
240   uint_t j;
241   smpl_t tmp = 0.;
242   for (j = 0; j < o->length; j++) {
243     tmp += POW (ABS (o->data[j]), alpha);
244   }
245   return POW (tmp / o->length, 1. / alpha);
246 }
247
248 void
249 fvec_alpha_normalise (fvec_t * o, smpl_t alpha)
250 {
251   uint_t j;
252   smpl_t norm = fvec_alpha_norm (o, alpha);
253   for (j = 0; j < o->length; j++) {
254     o->data[j] /= norm;
255   }
256 }
257
258 void
259 fvec_add (fvec_t * o, smpl_t val)
260 {
261   uint_t j;
262   for (j = 0; j < o->length; j++) {
263     o->data[j] += val;
264   }
265 }
266
267 void fvec_adapt_thres(fvec_t * vec, fvec_t * tmp,
268     uint_t post, uint_t pre) {
269   uint_t length = vec->length, j;
270   for (j=0;j<length;j++) {
271     vec->data[j] -= fvec_moving_thres(vec, tmp, post, pre, j);
272   }
273 }
274
275 smpl_t
276 fvec_moving_thres (fvec_t * vec, fvec_t * tmpvec,
277     uint_t post, uint_t pre, uint_t pos)
278 {
279   uint_t k;
280   smpl_t *medar = (smpl_t *) tmpvec->data;
281   uint_t win_length = post + pre + 1;
282   uint_t length = vec->length;
283   /* post part of the buffer does not exist */
284   if (pos < post + 1) {
285     for (k = 0; k < post + 1 - pos; k++)
286       medar[k] = 0.;            /* 0-padding at the beginning */
287     for (k = post + 1 - pos; k < win_length; k++)
288       medar[k] = vec->data[k + pos - post];
289     /* the buffer is fully defined */
290   } else if (pos + pre < length) {
291     for (k = 0; k < win_length; k++)
292       medar[k] = vec->data[k + pos - post];
293     /* pre part of the buffer does not exist */
294   } else {
295     for (k = 0; k < length - pos + post; k++)
296       medar[k] = vec->data[k + pos - post];
297     for (k = length - pos + post; k < win_length; k++)
298       medar[k] = 0.;            /* 0-padding at the end */
299   }
300   return fvec_median (tmpvec);
301 }
302
303 smpl_t fvec_median (fvec_t * input) {
304   uint_t n = input->length;
305   smpl_t * arr = (smpl_t *) input->data;
306   uint_t low, high ;
307   uint_t median;
308   uint_t middle, ll, hh;
309
310   low = 0 ; high = n-1 ; median = (low + high) / 2;
311   for (;;) {
312     if (high <= low) /* One element only */
313       return arr[median] ;
314
315     if (high == low + 1) {  /* Two elements only */
316       if (arr[low] > arr[high])
317         ELEM_SWAP(arr[low], arr[high]) ;
318       return arr[median] ;
319     }
320
321     /* Find median of low, middle and high items; swap into position low */
322     middle = (low + high) / 2;
323     if (arr[middle] > arr[high])    ELEM_SWAP(arr[middle], arr[high]);
324     if (arr[low]    > arr[high])    ELEM_SWAP(arr[low],    arr[high]);
325     if (arr[middle] > arr[low])     ELEM_SWAP(arr[middle], arr[low]) ;
326
327     /* Swap low item (now in position middle) into position (low+1) */
328     ELEM_SWAP(arr[middle], arr[low+1]) ;
329
330     /* Nibble from each end towards middle, swapping items when stuck */
331     ll = low + 1;
332     hh = high;
333     for (;;) {
334       do ll++; while (arr[low] > arr[ll]) ;
335       do hh--; while (arr[hh]  > arr[low]) ;
336
337       if (hh < ll)
338         break;
339
340       ELEM_SWAP(arr[ll], arr[hh]) ;
341     }
342
343     /* Swap middle item (in position low) back into correct position */
344     ELEM_SWAP(arr[low], arr[hh]) ;
345
346     /* Re-set active partition */
347     if (hh <= median)
348       low = ll;
349     if (hh >= median)
350       high = hh - 1;
351   }
352 }
353
354 smpl_t fvec_quadint (fvec_t * x, uint_t pos) {
355   smpl_t s0, s1, s2;
356   uint_t x0 = (pos < 1) ? pos : pos - 1;
357   uint_t x2 = (pos + 1 < x->length) ? pos + 1 : pos;
358   if (x0 == pos) return (x->data[pos] <= x->data[x2]) ? pos : x2;
359   if (x2 == pos) return (x->data[pos] <= x->data[x0]) ? pos : x0;
360   s0 = x->data[x0];
361   s1 = x->data[pos];
362   s2 = x->data[x2];
363   return pos + 0.5 * (s2 - s0 ) / (s2 - 2.* s1 + s0);
364 }
365
366 uint_t fvec_peakpick(fvec_t * onset, uint_t pos) {
367   uint_t tmp=0;
368   tmp = (onset->data[pos] > onset->data[pos-1]
369       &&  onset->data[pos] > onset->data[pos+1]
370       &&  onset->data[pos] > 0.);
371   return tmp;
372 }
373
374 smpl_t
375 aubio_quadfrac (smpl_t s0, smpl_t s1, smpl_t s2, smpl_t pf)
376 {
377   smpl_t tmp =
378       s0 + (pf / 2.) * (pf * (s0 - 2. * s1 + s2) - 3. * s0 + 4. * s1 - s2);
379   return tmp;
380 }
381
382 smpl_t
383 aubio_freqtomidi (smpl_t freq)
384 {
385   /* log(freq/A-2)/log(2) */
386   smpl_t midi = freq / 6.875;
387   midi = LOG (midi) / 0.69314718055995;
388   midi *= 12;
389   midi -= 3;
390   return midi;
391 }
392
393 smpl_t
394 aubio_miditofreq (smpl_t midi)
395 {
396   smpl_t freq = (midi + 3.) / 12.;
397   freq = EXP (freq * 0.69314718055995);
398   freq *= 6.875;
399   return freq;
400 }
401
402 smpl_t
403 aubio_bintofreq (smpl_t bin, smpl_t samplerate, smpl_t fftsize)
404 {
405   smpl_t freq = samplerate / fftsize;
406   return freq * bin;
407 }
408
409 smpl_t
410 aubio_bintomidi (smpl_t bin, smpl_t samplerate, smpl_t fftsize)
411 {
412   smpl_t midi = aubio_bintofreq (bin, samplerate, fftsize);
413   return aubio_freqtomidi (midi);
414 }
415
416 smpl_t
417 aubio_freqtobin (smpl_t freq, smpl_t samplerate, smpl_t fftsize)
418 {
419   smpl_t bin = fftsize / samplerate;
420   return freq * bin;
421 }
422
423 smpl_t
424 aubio_miditobin (smpl_t midi, smpl_t samplerate, smpl_t fftsize)
425 {
426   smpl_t freq = aubio_miditofreq (midi);
427   return aubio_freqtobin (freq, samplerate, fftsize);
428 }
429
430 uint_t
431 aubio_is_power_of_two (uint_t a)
432 {
433   if ((a & (a - 1)) == 0) {
434     return 1;
435   } else {
436     return 0;
437   }
438 }
439
440 uint_t
441 aubio_next_power_of_two (uint_t a)
442 {
443   uint_t i = 1;
444   while (i < a) i <<= 1;
445   return i;
446 }
447
448 smpl_t
449 aubio_db_spl (fvec_t * o)
450 {
451   return 10. * LOG10 (fvec_local_energy (o));
452 }
453
454 uint_t
455 aubio_silence_detection (fvec_t * o, smpl_t threshold)
456 {
457   return (aubio_db_spl (o) < threshold);
458 }
459
460 smpl_t
461 aubio_level_detection (fvec_t * o, smpl_t threshold)
462 {
463   smpl_t db_spl = aubio_db_spl (o);
464   if (db_spl < threshold) {
465     return 1.;
466   } else {
467     return db_spl;
468   }
469 }
470
471 smpl_t
472 aubio_zero_crossing_rate (fvec_t * input)
473 {
474   uint_t j;
475   uint_t zcr = 0;
476   for (j = 1; j < input->length; j++) {
477     // previous was strictly negative
478     if (input->data[j - 1] < 0.) {
479       // current is positive or null
480       if (input->data[j] >= 0.) {
481         zcr += 1;
482       }
483       // previous was positive or null
484     } else {
485       // current is strictly negative
486       if (input->data[j] < 0.) {
487         zcr += 1;
488       }
489     }
490   }
491   return zcr / (smpl_t) input->length;
492 }
493
494 void
495 aubio_autocorr (fvec_t * input, fvec_t * output)
496 {
497   uint_t i, j, length = input->length;
498   smpl_t *data, *acf;
499   smpl_t tmp = 0;
500   data = input->data;
501   acf = output->data;
502   for (i = 0; i < length; i++) {
503     tmp = 0.;
504     for (j = i; j < length; j++) {
505       tmp += data[j - i] * data[j];
506     }
507     acf[i] = tmp / (smpl_t) (length - i);
508   }
509 }
510
511 void
512 aubio_cleanup (void)
513 {
514 #if HAVE_FFTW3
515   fftw_cleanup ();
516 #else
517 #if HAVE_FFTW3F
518   fftwf_cleanup ();
519 #endif
520 #endif
521 }