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