jamie@1
|
1 /* libxtract feature extraction library
|
jamie@1
|
2 *
|
jamie@1
|
3 * Copyright (C) 2006 Jamie Bullock
|
jamie@1
|
4 *
|
jamie@1
|
5 * This program is free software; you can redistribute it and/or modify
|
jamie@1
|
6 * it under the terms of the GNU General Public License as published by
|
jamie@1
|
7 * the Free Software Foundation; either version 2 of the License, or
|
jamie@1
|
8 * (at your option) any later version.
|
jamie@1
|
9 *
|
jamie@1
|
10 * This program is distributed in the hope that it will be useful,
|
jamie@1
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
jamie@1
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
jamie@1
|
13 * GNU General Public License for more details.
|
jamie@1
|
14 *
|
jamie@1
|
15 * You should have received a copy of the GNU General Public License
|
jamie@1
|
16 * along with this program; if not, write to the Free Software
|
jamie@1
|
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
jamie@1
|
18 * USA.
|
jamie@1
|
19 */
|
jamie@1
|
20
|
jamie@107
|
21 /* init.c: defines initialisation and free functions. Also contains library constructor routine. */
|
jamie@1
|
22
|
jamie@98
|
23 #ifdef HAVE_CONFIG_H
|
jamie@98
|
24 # include <config.h>
|
jamie@98
|
25 #endif
|
jamie@98
|
26
|
jamie@1
|
27 #include <math.h>
|
jamie@26
|
28 #include <stdlib.h>
|
jamie@1
|
29
|
jamie@98
|
30 #include "xtract/libxtract.h"
|
jamie@107
|
31 #include "xtract_window_private.h"
|
jamie@102
|
32 #define DEFINE_GLOBALS
|
jamie@98
|
33 #include "xtract_globals_private.h"
|
jamie@98
|
34
|
jamie@98
|
35 #ifdef XTRACT_FFT
|
jamie@98
|
36 #include <fftw3.h>
|
jamie@98
|
37
|
jamie@98
|
38 #ifndef XTRACT_FFT_OPTIMISATION_LEVEL
|
jamie@98
|
39 /* This should never happen */
|
jamie@98
|
40 #define XTRACT_FFT_OPTIMISATION_LEVEL 1
|
jamie@98
|
41 #endif
|
jamie@98
|
42
|
jamie@43
|
43 int xtract_init_mfcc(int N, float nyquist, int style, float freq_min, float freq_max, int freq_bands, float **fft_tables){
|
jamie@1
|
44
|
jamie@39
|
45 int n, i, k, *fft_peak, M, next_peak;
|
jamie@1
|
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@1
|
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@1
|
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@1
|
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
|
danstowell@100
|
74 for (n = 1; n < freq_bands + 2; n++){
|
danstowell@100
|
75 //roll out peak locations - mel, linear and linear on fft window scale
|
jamie@1
|
76 mel_peak[n] = mel_peak[n - 1] + freq_bw_mel;
|
jamie@1
|
77 lin_peak[n] = 700 * (exp(mel_peak[n] / 1127) -1);
|
jamie@1
|
78 fft_peak[n] = lin_peak[n] / nyquist * M;
|
jamie@1
|
79 }
|
jamie@1
|
80
|
jamie@1
|
81 for (n = 0; n < freq_bands; n++){
|
danstowell@100
|
82 //roll out normalised gain of each peak
|
jamie@56
|
83 if (style == XTRACT_EQUAL_GAIN){
|
jamie@1
|
84 height = 1;
|
jamie@1
|
85 norm_fact = norm;
|
jamie@1
|
86 }
|
jamie@1
|
87 else{
|
jamie@1
|
88 height = 2 / (lin_peak[n + 2] - lin_peak[n]);
|
jamie@1
|
89 norm_fact = norm / (2 / (lin_peak[2] - lin_peak[0]));
|
jamie@1
|
90 }
|
jamie@1
|
91 height_norm[n] = height * norm_fact;
|
jamie@1
|
92 }
|
jamie@1
|
93
|
jamie@1
|
94 i = 0;
|
jamie@107
|
95
|
jamie@1
|
96 for(n = 0; n < freq_bands; n++){
|
jamie@107
|
97
|
jamie@107
|
98 // calculate the rise increment
|
danstowell@95
|
99 if(n==0)
|
danstowell@95
|
100 inc = height_norm[n] / fft_peak[n];
|
danstowell@95
|
101 else
|
jamie@1
|
102 inc = height_norm[n] / (fft_peak[n] - fft_peak[n - 1]);
|
jamie@1
|
103 val = 0;
|
jamie@107
|
104
|
jamie@107
|
105 // zero the start of the array
|
jamie@107
|
106 for(k = 0; k < i; k++)
|
jamie@107
|
107 fft_tables[n][k] = 0.f;
|
jamie@107
|
108
|
jamie@107
|
109 // fill in the rise
|
jamie@1
|
110 for(; i <= fft_peak[n]; i++){
|
jamie@1
|
111 fft_tables[n][i] = val;
|
jamie@1
|
112 val += inc;
|
jamie@1
|
113 }
|
jamie@107
|
114
|
danstowell@95
|
115 // calculate the fall increment
|
jamie@1
|
116 inc = height_norm[n] / (fft_peak[n + 1] - fft_peak[n]);
|
jamie@107
|
117
|
jamie@1
|
118 val = 0;
|
jamie@107
|
119 next_peak = fft_peak[n + 1];
|
jamie@107
|
120
|
jamie@107
|
121 // reverse fill the 'fall'
|
jamie@39
|
122 for(i = next_peak; i > fft_peak[n]; i--){
|
jamie@1
|
123 fft_tables[n][i] = val;
|
jamie@1
|
124 val += inc;
|
jamie@1
|
125 }
|
jamie@39
|
126
|
jamie@107
|
127 // zero the rest of the array
|
jamie@107
|
128 for(k = next_peak + 1; k < N; k++)
|
jamie@107
|
129 fft_tables[n][k] = 0.f;
|
jamie@1
|
130 }
|
jamie@1
|
131
|
jamie@98
|
132
|
jamie@98
|
133 /* Initialise the fft_plan for the DCT */
|
jamie@98
|
134 xtract_init_fft(freq_bands, XTRACT_MFCC);
|
jamie@98
|
135
|
jamie@1
|
136 free(mel_peak);
|
jamie@1
|
137 free(lin_peak);
|
jamie@1
|
138 free(height_norm);
|
jamie@1
|
139 free(fft_peak);
|
jamie@1
|
140
|
jamie@56
|
141 return XTRACT_SUCCESS;
|
jamie@1
|
142
|
jamie@1
|
143 }
|
jamie@1
|
144
|
jamie@98
|
145 int xtract_init_fft(int N, int feature_name){
|
jamie@98
|
146
|
jamie@98
|
147 float *input, *output;
|
jamie@98
|
148 int optimisation;
|
jamie@107
|
149
|
jamie@98
|
150 input = output = NULL;
|
jamie@107
|
151
|
jamie@98
|
152 fprintf(stderr, "Optimisation level: %d\n", XTRACT_FFT_OPTIMISATION_LEVEL);
|
jamie@98
|
153
|
jamie@98
|
154 if(XTRACT_FFT_OPTIMISATION_LEVEL == 0)
|
jamie@98
|
155 optimisation = FFTW_ESTIMATE;
|
jamie@98
|
156 else if(XTRACT_FFT_OPTIMISATION_LEVEL == 1)
|
jamie@98
|
157 optimisation = FFTW_MEASURE;
|
jamie@98
|
158 else if(XTRACT_FFT_OPTIMISATION_LEVEL == 2)
|
jamie@98
|
159 optimisation = FFTW_PATIENT;
|
jamie@98
|
160 else
|
jamie@98
|
161 optimisation = FFTW_MEASURE; /* The default */
|
jamie@98
|
162
|
jamie@98
|
163 if(feature_name == XTRACT_AUTOCORRELATION_FFT)
|
jamie@98
|
164 N <<= 1;
|
jamie@98
|
165
|
jamie@98
|
166 input = malloc(N * sizeof(float));
|
jamie@98
|
167 output = malloc(N * sizeof(float));
|
jamie@98
|
168
|
jamie@98
|
169 switch(feature_name){
|
jamie@98
|
170 case XTRACT_SPECTRUM:
|
jamie@102
|
171 if(fft_plans.spectrum_plan != NULL)
|
jamie@102
|
172 fftwf_destroy_plan(fft_plans.spectrum_plan);
|
jamie@102
|
173 fft_plans.spectrum_plan =
|
jamie@98
|
174 fftwf_plan_r2r_1d(N, input, output, FFTW_R2HC, optimisation);
|
jamie@98
|
175 break;
|
jamie@98
|
176 case XTRACT_AUTOCORRELATION_FFT:
|
jamie@102
|
177 if(fft_plans.autocorrelation_fft_plan_1 != NULL)
|
jamie@102
|
178 fftwf_destroy_plan(fft_plans.autocorrelation_fft_plan_1);
|
jamie@102
|
179 if(fft_plans.autocorrelation_fft_plan_2 != NULL)
|
jamie@102
|
180 fftwf_destroy_plan(fft_plans.autocorrelation_fft_plan_2);
|
jamie@102
|
181 fft_plans.autocorrelation_fft_plan_1 =
|
jamie@98
|
182 fftwf_plan_r2r_1d(N, input, output, FFTW_R2HC, optimisation);
|
jamie@102
|
183 fft_plans.autocorrelation_fft_plan_2 =
|
jamie@98
|
184 fftwf_plan_r2r_1d(N, input, output, FFTW_HC2R, optimisation);
|
jamie@98
|
185 break;
|
jamie@98
|
186 case XTRACT_DCT:
|
jamie@102
|
187 if(fft_plans.dct_plan != NULL)
|
jamie@102
|
188 fftwf_destroy_plan(fft_plans.dct_plan);
|
jamie@102
|
189 fft_plans.dct_plan =
|
jamie@98
|
190 fftwf_plan_r2r_1d(N, input, output, FFTW_REDFT00, optimisation);
|
jamie@98
|
191 case XTRACT_MFCC:
|
jamie@102
|
192 if(fft_plans.dct_plan != NULL)
|
jamie@102
|
193 fftwf_destroy_plan(fft_plans.dct_plan);
|
jamie@102
|
194 fft_plans.dct_plan =
|
jamie@98
|
195 fftwf_plan_r2r_1d(N, output, output, FFTW_REDFT00, optimisation);
|
jamie@98
|
196 break;
|
jamie@98
|
197 }
|
jamie@98
|
198
|
jamie@98
|
199 free(input);
|
jamie@98
|
200 free(output);
|
jamie@98
|
201
|
jamie@98
|
202 return XTRACT_SUCCESS;
|
jamie@98
|
203
|
jamie@98
|
204 }
|
jamie@98
|
205
|
jamie@98
|
206 #endif
|
jamie@98
|
207
|
jamie@59
|
208 int xtract_init_bark(int N, float sr, int *band_limits){
|
jamie@1
|
209
|
jamie@38
|
210 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
|
211
|
jamie@59
|
212 int bands = XTRACT_BARK_BANDS;
|
jamie@107
|
213
|
jamie@1
|
214 while(bands--)
|
jamie@59
|
215 band_limits[bands] = edges[bands] / sr * N;
|
jamie@107
|
216 /*FIX shohuld use rounding, but couldn't get it to work */
|
jamie@38
|
217
|
jamie@56
|
218 return XTRACT_SUCCESS;
|
jamie@1
|
219 }
|
jamie@98
|
220
|
jamie@107
|
221 float *xtract_init_window(const int N, const int type){
|
jamie@107
|
222
|
jamie@107
|
223 float *window;
|
jamie@107
|
224
|
jamie@107
|
225 window = malloc(N * sizeof(float));
|
jamie@107
|
226
|
jamie@107
|
227 switch (type) {
|
jamie@107
|
228 case XTRACT_GAUSS:
|
jamie@107
|
229 gauss(window, N, 0.4);
|
jamie@107
|
230 break;
|
jamie@107
|
231 case XTRACT_HAMMING:
|
jamie@107
|
232 hamming(window, N);
|
jamie@107
|
233 break;
|
jamie@107
|
234 case XTRACT_HANN:
|
jamie@107
|
235 hann(window, N);
|
jamie@107
|
236 break;
|
jamie@107
|
237 case XTRACT_BARTLETT:
|
jamie@107
|
238 bartlett(window, N);
|
jamie@107
|
239 break;
|
jamie@107
|
240 case XTRACT_TRIANGULAR:
|
jamie@107
|
241 triangular(window, N);
|
jamie@107
|
242 break;
|
jamie@107
|
243 case XTRACT_BARTLETT_HANN:
|
jamie@107
|
244 bartlett_hann(window, N);
|
jamie@107
|
245 break;
|
jamie@107
|
246 case XTRACT_BLACKMAN:
|
jamie@107
|
247 blackman(window, N);
|
jamie@107
|
248 break;
|
jamie@107
|
249 case XTRACT_KAISER:
|
jamie@107
|
250 kaiser(window, N, 3 * PI);
|
jamie@107
|
251 break;
|
jamie@107
|
252 case XTRACT_BLACKMAN_HARRIS:
|
jamie@107
|
253 blackman_harris(window, N);
|
jamie@107
|
254 break;
|
jamie@107
|
255 default:
|
jamie@107
|
256 hann(window, N);
|
jamie@107
|
257 break;
|
jamie@107
|
258 }
|
jamie@107
|
259
|
jamie@107
|
260 return window;
|
jamie@107
|
261
|
jamie@107
|
262 }
|
jamie@107
|
263
|
jamie@107
|
264 void xtract_free_window(float *window){
|
jamie@107
|
265
|
jamie@107
|
266 free(window);
|
jamie@107
|
267
|
jamie@107
|
268 }
|
jamie@107
|
269
|
jamie@102
|
270 #ifdef __GNUC__
|
jamie@102
|
271 __attribute__((constructor)) void init()
|
jamie@102
|
272 #else
|
jamie@102
|
273 void _init()ยท
|
jamie@102
|
274 #endif
|
jamie@102
|
275 {
|
jamie@102
|
276 fft_plans.spectrum_plan = NULL;
|
jamie@102
|
277 fft_plans.autocorrelation_fft_plan_1 = NULL;
|
jamie@102
|
278 fft_plans.autocorrelation_fft_plan_2 = NULL;
|
jamie@102
|
279 fft_plans.dct_plan = NULL;
|
jamie@102
|
280 }
|