jamie@141
|
1 /*
|
jamie@141
|
2 * Copyright (C) 2012 Jamie Bullock
|
jamie@140
|
3 *
|
jamie@141
|
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
|
jamie@141
|
5 * of this software and associated documentation files (the "Software"), to
|
jamie@141
|
6 * deal in the Software without restriction, including without limitation the
|
jamie@141
|
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
jamie@141
|
8 * sell copies of the Software, and to permit persons to whom the Software is
|
jamie@141
|
9 * furnished to do so, subject to the following conditions:
|
jamie@1
|
10 *
|
jamie@141
|
11 * The above copyright notice and this permission notice shall be included in
|
jamie@141
|
12 * all copies or substantial portions of the Software.
|
jamie@1
|
13 *
|
jamie@141
|
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
jamie@141
|
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
jamie@141
|
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
jamie@141
|
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
jamie@141
|
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
jamie@141
|
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
jamie@141
|
20 * IN THE SOFTWARE.
|
jamie@1
|
21 *
|
jamie@1
|
22 */
|
jamie@1
|
23
|
jamie@107
|
24 /* init.c: defines initialisation and free functions. Also contains library constructor routine. */
|
jamie@1
|
25
|
jamie@98
|
26 #ifdef HAVE_CONFIG_H
|
jamie@98
|
27 # include <config.h>
|
jamie@98
|
28 #endif
|
jamie@98
|
29
|
jamie@1
|
30 #include <math.h>
|
jamie@26
|
31 #include <stdlib.h>
|
jamie@140
|
32 #include <stdio.h>
|
jamie@140
|
33
|
jamie@140
|
34 #include "fftsg.h"
|
jamie@1
|
35
|
jamie@98
|
36 #include "xtract/libxtract.h"
|
jamie@107
|
37 #include "xtract_window_private.h"
|
jamie@102
|
38 #define DEFINE_GLOBALS
|
jamie@98
|
39 #include "xtract_globals_private.h"
|
jamie@98
|
40
|
jamie@98
|
41
|
jamie@140
|
42 int xtract_init_mfcc(int N, float nyquist, int style, float freq_min, float freq_max, int freq_bands, float **fft_tables)
|
jamie@140
|
43 {
|
jamie@98
|
44
|
jamie@140
|
45 int n, i, k, *fft_peak, M, next_peak;
|
jamie@140
|
46 float norm, mel_freq_max, mel_freq_min, norm_fact, height, inc, val,
|
jamie@107
|
47 freq_bw_mel, *mel_peak, *height_norm, *lin_peak;
|
jamie@1
|
48
|
jamie@1
|
49 mel_peak = height_norm = lin_peak = NULL;
|
jamie@1
|
50 fft_peak = NULL;
|
jamie@140
|
51 norm = 1;
|
jamie@1
|
52
|
jamie@1
|
53 mel_freq_max = 1127 * log(1 + freq_max / 700);
|
jamie@1
|
54 mel_freq_min = 1127 * log(1 + freq_min / 700);
|
jamie@1
|
55 freq_bw_mel = (mel_freq_max - mel_freq_min) / freq_bands;
|
jamie@1
|
56
|
jamie@140
|
57 mel_peak = (float *)malloc((freq_bands + 2) * sizeof(float));
|
jamie@1
|
58 /* +2 for zeros at start and end */
|
jamie@1
|
59 lin_peak = (float *)malloc((freq_bands + 2) * sizeof(float));
|
jamie@1
|
60 fft_peak = (int *)malloc((freq_bands + 2) * sizeof(int));
|
jamie@1
|
61 height_norm = (float *)malloc(freq_bands * sizeof(float));
|
jamie@1
|
62
|
jamie@140
|
63 if(mel_peak == NULL || height_norm == NULL ||
|
jamie@107
|
64 lin_peak == NULL || fft_peak == NULL)
|
jamie@107
|
65 return XTRACT_MALLOC_FAILED;
|
jamie@107
|
66
|
jamie@1
|
67 M = N >> 1;
|
jamie@1
|
68
|
jamie@1
|
69 mel_peak[0] = mel_freq_min;
|
danstowell@95
|
70 lin_peak[0] = freq_min; // === 700 * (exp(mel_peak[0] / 1127) - 1);
|
jamie@1
|
71 fft_peak[0] = lin_peak[0] / nyquist * M;
|
jamie@1
|
72
|
jamie@1
|
73
|
jamie@140
|
74 for (n = 1; n < freq_bands + 2; n++)
|
jamie@140
|
75 {
|
jamie@140
|
76 //roll out peak locations - mel, linear and linear on fft window scale
|
jamie@1
|
77 mel_peak[n] = mel_peak[n - 1] + freq_bw_mel;
|
jamie@1
|
78 lin_peak[n] = 700 * (exp(mel_peak[n] / 1127) -1);
|
jamie@1
|
79 fft_peak[n] = lin_peak[n] / nyquist * M;
|
jamie@1
|
80 }
|
jamie@1
|
81
|
jamie@140
|
82 for (n = 0; n < freq_bands; n++)
|
jamie@140
|
83 {
|
danstowell@100
|
84 //roll out normalised gain of each peak
|
jamie@140
|
85 if (style == XTRACT_EQUAL_GAIN)
|
jamie@140
|
86 {
|
jamie@140
|
87 height = 1;
|
jamie@1
|
88 norm_fact = norm;
|
jamie@1
|
89 }
|
jamie@140
|
90 else
|
jamie@140
|
91 {
|
jamie@1
|
92 height = 2 / (lin_peak[n + 2] - lin_peak[n]);
|
jamie@1
|
93 norm_fact = norm / (2 / (lin_peak[2] - lin_peak[0]));
|
jamie@1
|
94 }
|
jamie@1
|
95 height_norm[n] = height * norm_fact;
|
jamie@1
|
96 }
|
jamie@1
|
97
|
jamie@1
|
98 i = 0;
|
jamie@107
|
99
|
jamie@140
|
100 for(n = 0; n < freq_bands; n++)
|
jamie@140
|
101 {
|
jamie@107
|
102
|
jamie@107
|
103 // calculate the rise increment
|
danstowell@95
|
104 if(n==0)
|
danstowell@95
|
105 inc = height_norm[n] / fft_peak[n];
|
danstowell@95
|
106 else
|
jamie@1
|
107 inc = height_norm[n] / (fft_peak[n] - fft_peak[n - 1]);
|
jamie@140
|
108 val = 0;
|
jamie@107
|
109
|
jamie@107
|
110 // zero the start of the array
|
jamie@107
|
111 for(k = 0; k < i; k++)
|
jamie@107
|
112 fft_tables[n][k] = 0.f;
|
jamie@107
|
113
|
jamie@107
|
114 // fill in the rise
|
jamie@140
|
115 for(; i <= fft_peak[n]; i++)
|
jamie@140
|
116 {
|
jamie@1
|
117 fft_tables[n][i] = val;
|
jamie@1
|
118 val += inc;
|
jamie@1
|
119 }
|
jamie@107
|
120
|
danstowell@95
|
121 // calculate the fall increment
|
jamie@1
|
122 inc = height_norm[n] / (fft_peak[n + 1] - fft_peak[n]);
|
jamie@107
|
123
|
jamie@1
|
124 val = 0;
|
jamie@107
|
125 next_peak = fft_peak[n + 1];
|
jamie@107
|
126
|
jamie@140
|
127 // reverse fill the 'fall'
|
jamie@140
|
128 for(i = next_peak; i > fft_peak[n]; i--)
|
jamie@140
|
129 {
|
jamie@1
|
130 fft_tables[n][i] = val;
|
jamie@1
|
131 val += inc;
|
jamie@1
|
132 }
|
jamie@39
|
133
|
jamie@107
|
134 // zero the rest of the array
|
jamie@107
|
135 for(k = next_peak + 1; k < N; k++)
|
jamie@107
|
136 fft_tables[n][k] = 0.f;
|
jamie@1
|
137 }
|
jamie@1
|
138
|
jamie@98
|
139
|
jamie@98
|
140 /* Initialise the fft_plan for the DCT */
|
jamie@140
|
141 /*
|
jamie@140
|
142 * Ooura doesn't support non power-of-two DCT
|
jamie@98
|
143 xtract_init_fft(freq_bands, XTRACT_MFCC);
|
jamie@140
|
144 */
|
jamie@98
|
145
|
jamie@1
|
146 free(mel_peak);
|
jamie@1
|
147 free(lin_peak);
|
jamie@1
|
148 free(height_norm);
|
jamie@1
|
149 free(fft_peak);
|
jamie@1
|
150
|
jamie@56
|
151 return XTRACT_SUCCESS;
|
jamie@1
|
152
|
jamie@1
|
153 }
|
jamie@1
|
154
|
jamie@140
|
155 void xtract_init_ooura(xtract_ooura_data *ooura_data, unsigned int N)
|
jamie@140
|
156 {
|
jamie@140
|
157 ooura_data->ooura_ip = (int *)calloc((2 + sqrt(N)), sizeof(int));
|
jamie@140
|
158 ooura_data->ooura_w = (double *)calloc((N - 1), sizeof(double));
|
jamie@140
|
159 ooura_data->initialised = true;
|
jamie@140
|
160 }
|
jamie@98
|
161
|
jamie@140
|
162 void xtract_free_ooura(xtract_ooura_data *ooura_data)
|
jamie@140
|
163 {
|
jamie@140
|
164 free(ooura_data->ooura_ip);
|
jamie@140
|
165 free(ooura_data->ooura_w);
|
jamie@140
|
166 ooura_data->ooura_ip = NULL;
|
jamie@140
|
167 ooura_data->ooura_w = NULL;
|
jamie@140
|
168 ooura_data->initialised = false;
|
jamie@140
|
169 }
|
jamie@107
|
170
|
jamie@140
|
171 int xtract_init_fft(int N, int feature_name)
|
jamie@140
|
172 {
|
jamie@107
|
173
|
jamie@140
|
174 int M = N >> 1;
|
jamie@98
|
175
|
jamie@140
|
176 if(!xtract_is_poweroftwo(N))
|
jamie@140
|
177 {
|
jamie@140
|
178 fprintf(stderr,
|
jamie@140
|
179 "libxtract: error: only power-of-two FFT sizes are supported.\n");
|
jamie@140
|
180 exit(EXIT_FAILURE);
|
jamie@140
|
181 }
|
jamie@98
|
182
|
jamie@98
|
183 if(feature_name == XTRACT_AUTOCORRELATION_FFT)
|
jamie@140
|
184 {
|
jamie@140
|
185 M = N; /* allow for zero padding */
|
jamie@98
|
186 }
|
jamie@98
|
187
|
jamie@140
|
188 switch(feature_name)
|
jamie@140
|
189 {
|
jamie@140
|
190 case XTRACT_SPECTRUM:
|
jamie@140
|
191 if(ooura_data_spectrum.initialised)
|
jamie@140
|
192 {
|
jamie@140
|
193 xtract_free_ooura(&ooura_data_spectrum);
|
jamie@140
|
194 }
|
jamie@140
|
195 xtract_init_ooura(&ooura_data_spectrum, M);
|
jamie@140
|
196 break;
|
jamie@140
|
197 case XTRACT_AUTOCORRELATION_FFT:
|
jamie@140
|
198 if(ooura_data_autocorrelation_fft.initialised)
|
jamie@140
|
199 {
|
jamie@140
|
200 xtract_free_ooura(&ooura_data_autocorrelation_fft);
|
jamie@140
|
201 }
|
jamie@140
|
202 xtract_init_ooura(&ooura_data_autocorrelation_fft, M);
|
jamie@140
|
203 break;
|
jamie@140
|
204 case XTRACT_DCT:
|
jamie@140
|
205 if(ooura_data_dct.initialised)
|
jamie@140
|
206 {
|
jamie@140
|
207 xtract_free_ooura(&ooura_data_dct);
|
jamie@140
|
208 }
|
jamie@140
|
209 xtract_init_ooura(&ooura_data_dct, M);
|
jamie@140
|
210 case XTRACT_MFCC:
|
jamie@140
|
211 if(ooura_data_mfcc.initialised)
|
jamie@140
|
212 {
|
jamie@140
|
213 xtract_free_ooura(&ooura_data_mfcc);
|
jamie@140
|
214 }
|
jamie@140
|
215 xtract_init_ooura(&ooura_data_mfcc, M);
|
jamie@140
|
216 break;
|
jamie@140
|
217 }
|
jamie@98
|
218
|
jamie@98
|
219 return XTRACT_SUCCESS;
|
jamie@98
|
220 }
|
jamie@98
|
221
|
jamie@140
|
222 void xtract_free_fft(void)
|
jamie@140
|
223 {
|
jamie@140
|
224 if(ooura_data_spectrum.initialised)
|
jamie@140
|
225 {
|
jamie@140
|
226 xtract_free_ooura(&ooura_data_spectrum);
|
jamie@140
|
227 }
|
jamie@140
|
228 if(ooura_data_autocorrelation_fft.initialised)
|
jamie@140
|
229 {
|
jamie@140
|
230 xtract_free_ooura(&ooura_data_autocorrelation_fft);
|
jamie@140
|
231 }
|
jamie@140
|
232 if(ooura_data_dct.initialised)
|
jamie@140
|
233 {
|
jamie@140
|
234 xtract_free_ooura(&ooura_data_dct);
|
jamie@140
|
235 }
|
jamie@140
|
236 if(ooura_data_mfcc.initialised)
|
jamie@140
|
237 {
|
jamie@140
|
238 xtract_free_ooura(&ooura_data_mfcc);
|
jamie@140
|
239 }
|
jamie@110
|
240 }
|
jamie@110
|
241
|
jamie@140
|
242 int xtract_init_bark(int N, float sr, int *band_limits)
|
jamie@140
|
243 {
|
jamie@1
|
244
|
jamie@38
|
245 float edges[] = {0, 100, 200, 300, 400, 510, 630, 770, 920, 1080, 1270, 1480, 1720, 2000, 2320, 2700, 3150, 3700, 4400, 5300, 6400, 7700, 9500, 12000, 15500, 20500, 27000}; /* Takes us up to sr = 54kHz (CCRMA: JOS)*/
|
jamie@1
|
246
|
jamie@59
|
247 int bands = XTRACT_BARK_BANDS;
|
jamie@107
|
248
|
jamie@1
|
249 while(bands--)
|
jamie@59
|
250 band_limits[bands] = edges[bands] / sr * N;
|
jamie@107
|
251 /*FIX shohuld use rounding, but couldn't get it to work */
|
jamie@38
|
252
|
jamie@56
|
253 return XTRACT_SUCCESS;
|
jamie@1
|
254 }
|
jamie@98
|
255
|
jamie@140
|
256 float *xtract_init_window(const int N, const int type)
|
jamie@140
|
257 {
|
jamie@107
|
258 float *window;
|
jamie@107
|
259
|
jamie@107
|
260 window = malloc(N * sizeof(float));
|
jamie@107
|
261
|
jamie@140
|
262 switch (type)
|
jamie@140
|
263 {
|
jamie@140
|
264 case XTRACT_GAUSS:
|
jamie@140
|
265 gauss(window, N, 0.4);
|
jamie@140
|
266 break;
|
jamie@140
|
267 case XTRACT_HAMMING:
|
jamie@140
|
268 hamming(window, N);
|
jamie@140
|
269 break;
|
jamie@140
|
270 case XTRACT_HANN:
|
jamie@140
|
271 hann(window, N);
|
jamie@140
|
272 break;
|
jamie@140
|
273 case XTRACT_BARTLETT:
|
jamie@140
|
274 bartlett(window, N);
|
jamie@140
|
275 break;
|
jamie@140
|
276 case XTRACT_TRIANGULAR:
|
jamie@140
|
277 triangular(window, N);
|
jamie@140
|
278 break;
|
jamie@140
|
279 case XTRACT_BARTLETT_HANN:
|
jamie@140
|
280 bartlett_hann(window, N);
|
jamie@140
|
281 break;
|
jamie@140
|
282 case XTRACT_BLACKMAN:
|
jamie@140
|
283 blackman(window, N);
|
jamie@140
|
284 break;
|
jamie@140
|
285 case XTRACT_KAISER:
|
jamie@140
|
286 kaiser(window, N, 3 * PI);
|
jamie@140
|
287 break;
|
jamie@140
|
288 case XTRACT_BLACKMAN_HARRIS:
|
jamie@140
|
289 blackman_harris(window, N);
|
jamie@140
|
290 break;
|
jamie@140
|
291 default:
|
jamie@140
|
292 hann(window, N);
|
jamie@140
|
293 break;
|
jamie@107
|
294 }
|
jamie@107
|
295
|
jamie@107
|
296 return window;
|
jamie@107
|
297 }
|
jamie@107
|
298
|
jamie@140
|
299 void xtract_free_window(float *window)
|
jamie@140
|
300 {
|
jamie@107
|
301 free(window);
|
jamie@107
|
302 }
|
jamie@107
|
303
|
jamie@102
|
304 #ifdef __GNUC__
|
jamie@102
|
305 __attribute__((constructor)) void init()
|
jamie@102
|
306 #else
|
jamie@140
|
307 void _init()ยท
|
jamie@102
|
308 #endif
|
jamie@102
|
309 {
|
jamie@140
|
310 ooura_data_dct.initialised = false;
|
jamie@140
|
311 ooura_data_spectrum.initialised = false;
|
jamie@140
|
312 ooura_data_autocorrelation_fft.initialised = false;
|
jamie@140
|
313 ooura_data_mfcc.initialised = false;
|
jamie@102
|
314 }
|