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