wscript: With --enable-$x, the existence of $x should be mandatory
[aubio.git] / src / spectral / filterbank_mel.c
1 /*
2   Copyright (C) 2007-2009 Paul Brossier <piem@aubio.org>
3                       and Amaury Hazan <ahazan@iua.upf.edu>
4
5   This file is part of aubio.
6
7   aubio is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   aubio is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with aubio.  If not, see <http://www.gnu.org/licenses/>.
19
20 */
21
22 #include "aubio_priv.h"
23 #include "fmat.h"
24 #include "fvec.h"
25 #include "cvec.h"
26 #include "spectral/filterbank.h"
27 #include "mathutils.h"
28
29 uint_t
30 aubio_filterbank_set_triangle_bands (aubio_filterbank_t * fb,
31     fvec_t * freqs, smpl_t samplerate)
32 {
33
34   fmat_t *filters = aubio_filterbank_get_coeffs (fb);
35   uint_t n_filters = filters->height, win_s = filters->length;
36
37   uint_t fn;                    /* filter counter */
38   uint_t bin;                   /* bin counter */
39
40   /* freqs define the bands of triangular overlapping windows.
41      throw a warning if filterbank object fb is too short. */
42   if (freqs->length - 2 > n_filters) {
43     AUBIO_WRN ("not enough filters, %d allocated but %d requested\n",
44         n_filters, freqs->length - 2);
45   }
46
47   if (freqs->length - 2 < n_filters) {
48     AUBIO_WRN ("too many filters, %d allocated but %d requested\n",
49         n_filters, freqs->length - 2);
50   }
51
52   if (freqs->data[freqs->length - 1] > samplerate / 2) {
53     AUBIO_WRN ("Nyquist frequency is %fHz, but highest frequency band ends at \
54 %fHz\n", samplerate / 2, freqs->data[freqs->length - 1]);
55   }
56
57   /* convenience reference to lower/center/upper frequency for each triangle */
58   fvec_t *lower_freqs = new_fvec (n_filters);
59   fvec_t *upper_freqs = new_fvec (n_filters);
60   fvec_t *center_freqs = new_fvec (n_filters);
61
62   /* height of each triangle */
63   fvec_t *triangle_heights = new_fvec (n_filters);
64
65   /* lookup table of each bin frequency in hz */
66   fvec_t *fft_freqs = new_fvec (win_s);
67
68   /* fill up the lower/center/upper */
69   for (fn = 0; fn < n_filters; fn++) {
70     lower_freqs->data[fn] = freqs->data[fn];
71     center_freqs->data[fn] = freqs->data[fn + 1];
72     upper_freqs->data[fn] = freqs->data[fn + 2];
73   }
74
75   /* compute triangle heights so that each triangle has unit area */
76   for (fn = 0; fn < n_filters; fn++) {
77     triangle_heights->data[fn] =
78         2. / (upper_freqs->data[fn] - lower_freqs->data[fn]);
79   }
80
81   /* fill fft_freqs lookup table, which assigns the frequency in hz to each bin */
82   for (bin = 0; bin < win_s; bin++) {
83     fft_freqs->data[bin] =
84         aubio_bintofreq (bin, samplerate, (win_s - 1) * 2);
85   }
86
87   /* zeroing of all filters */
88   fmat_zeros (filters);
89
90   if (fft_freqs->data[1] >= lower_freqs->data[0]) {
91     /* - 1 to make sure we don't miss the smallest power of two */
92     uint_t min_win_s =
93         (uint_t) FLOOR (samplerate / lower_freqs->data[0]) - 1;
94     AUBIO_WRN ("Lowest frequency bin (%.2fHz) is higher than lowest frequency \
95 band (%.2f-%.2fHz). Consider increasing the window size from %d to %d.\n",
96         fft_freqs->data[1], lower_freqs->data[0],
97         upper_freqs->data[0], (win_s - 1) * 2,
98         aubio_next_power_of_two (min_win_s));
99   }
100
101   /* building each filter table */
102   for (fn = 0; fn < n_filters; fn++) {
103
104     /* skip first elements */
105     for (bin = 0; bin < win_s - 1; bin++) {
106       if (fft_freqs->data[bin] <= lower_freqs->data[fn] &&
107           fft_freqs->data[bin + 1] > lower_freqs->data[fn]) {
108         bin++;
109         break;
110       }
111     }
112
113     /* compute positive slope step size */
114     smpl_t riseInc =
115         triangle_heights->data[fn] /
116         (center_freqs->data[fn] - lower_freqs->data[fn]);
117
118     /* compute coefficients in positive slope */
119     for (; bin < win_s - 1; bin++) {
120       filters->data[fn][bin] =
121           (fft_freqs->data[bin] - lower_freqs->data[fn]) * riseInc;
122
123       if (fft_freqs->data[bin + 1] >= center_freqs->data[fn]) {
124         bin++;
125         break;
126       }
127     }
128
129     /* compute negative slope step size */
130     smpl_t downInc =
131         triangle_heights->data[fn] /
132         (upper_freqs->data[fn] - center_freqs->data[fn]);
133
134     /* compute coefficents in negative slope */
135     for (; bin < win_s - 1; bin++) {
136       filters->data[fn][bin] +=
137           (upper_freqs->data[fn] - fft_freqs->data[bin]) * downInc;
138
139       if (filters->data[fn][bin] < 0.) {
140         filters->data[fn][bin] = 0.;
141       }
142
143       if (fft_freqs->data[bin + 1] >= upper_freqs->data[fn])
144         break;
145     }
146     /* nothing else to do */
147
148   }
149
150   /* destroy temporarly allocated vectors */
151   del_fvec (lower_freqs);
152   del_fvec (upper_freqs);
153   del_fvec (center_freqs);
154
155   del_fvec (triangle_heights);
156   del_fvec (fft_freqs);
157
158   return 0;
159 }
160
161 uint_t
162 aubio_filterbank_set_mel_coeffs_slaney (aubio_filterbank_t * fb,
163     smpl_t samplerate)
164 {
165   uint_t retval;
166
167   /* Malcolm Slaney parameters */
168   smpl_t lowestFrequency = 133.3333;
169   smpl_t linearSpacing = 66.66666666;
170   smpl_t logSpacing = 1.0711703;
171
172   uint_t linearFilters = 13;
173   uint_t logFilters = 27;
174   uint_t n_filters = linearFilters + logFilters;
175
176   uint_t fn;                    /* filter counter */
177
178   /* buffers to compute filter frequencies */
179   fvec_t *freqs = new_fvec (n_filters + 2);
180
181   /* first step: fill all the linear filter frequencies */
182   for (fn = 0; fn < linearFilters; fn++) {
183     freqs->data[fn] = lowestFrequency + fn * linearSpacing;
184   }
185   smpl_t lastlinearCF = freqs->data[fn - 1];
186
187   /* second step: fill all the log filter frequencies */
188   for (fn = 0; fn < logFilters + 2; fn++) {
189     freqs->data[fn + linearFilters] =
190         lastlinearCF * (POW (logSpacing, fn + 1));
191   }
192
193   /* now compute the actual coefficients */
194   retval = aubio_filterbank_set_triangle_bands (fb, freqs, samplerate);
195
196   /* destroy vector used to store frequency limits */
197   del_fvec (freqs);
198
199   return retval;
200 }