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@1
|
21
|
jamie@1
|
22 /* xtract_vector.c: defines functions that extract a feature as a single value from an input vector */
|
jamie@1
|
23
|
jamie@1
|
24 #include "xtract/libxtract.h"
|
jamie@1
|
25 #include <math.h>
|
jamie@43
|
26 #include <string.h>
|
jamie@43
|
27 #include <stdlib.h>
|
jamie@30
|
28
|
jamie@30
|
29 #ifdef XTRACT_FFT
|
jamie@30
|
30
|
jamie@1
|
31 #include <fftw3.h>
|
jamie@1
|
32
|
jamie@54
|
33 int xtract_spectrum(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
34
|
jamie@55
|
35 float *input, *rfft, nyquist, temp;
|
jamie@43
|
36 size_t bytes;
|
jamie@54
|
37 int n , NxN, M, vector;
|
jamie@1
|
38 fftwf_plan plan;
|
jamie@1
|
39
|
jamie@54
|
40 M = N >> 1;
|
jamie@54
|
41 NxN = SQ(N);
|
jamie@54
|
42
|
jamie@54
|
43 rfft = (float *)fftwf_malloc(N * sizeof(float));
|
jamie@43
|
44 input = (float *)malloc(bytes = N * sizeof(float));
|
jamie@43
|
45 input = memcpy(input, data, bytes);
|
jamie@1
|
46
|
jamie@55
|
47 nyquist = *(float *)argv;
|
jamie@54
|
48 vector = (int)*((float *)argv+1);
|
jamie@46
|
49
|
jamie@55
|
50 CHECK_nyquist;
|
jamie@46
|
51
|
jamie@54
|
52 plan = fftwf_plan_r2r_1d(N, input, rfft, FFTW_R2HC, FFTW_ESTIMATE);
|
jamie@1
|
53
|
jamie@1
|
54 fftwf_execute(plan);
|
jamie@54
|
55
|
jamie@54
|
56 switch(vector){
|
jamie@54
|
57 case MAGNITUDE_SPECTRUM:
|
jamie@54
|
58 for(n = 0; n < M; n++){
|
jamie@54
|
59 result[n] = sqrt(SQ(rfft[n]) + SQ(rfft[N - n])) / N;
|
jamie@55
|
60 result[M + n] = n * nyquist;
|
jamie@54
|
61 }
|
jamie@54
|
62 break;
|
jamie@54
|
63 case LOG_MAGNITUDE_SPECTRUM:
|
jamie@54
|
64 for(n = 0; n < M; n++){
|
jamie@54
|
65 if ((temp = SQ(rfft[n]) + SQ(rfft[N - n])) > LOG_LIMIT)
|
jamie@54
|
66 temp = log(sqrt(temp) / N);
|
jamie@54
|
67 else
|
jamie@54
|
68 temp = LOG_LIMIT_DB;
|
jamie@54
|
69 /*Normalise*/
|
jamie@54
|
70 result[n] = (temp + DB_SCALE_OFFSET) / DB_SCALE_OFFSET;
|
jamie@55
|
71 result[M + n] = n * nyquist;
|
jamie@54
|
72 }
|
jamie@54
|
73 break;
|
jamie@54
|
74 case POWER_SPECTRUM:
|
jamie@54
|
75 for(n = 0; n < M; n++){
|
jamie@54
|
76 result[n] = (SQ(rfft[n]) + SQ(rfft[N - n])) / NxN;
|
jamie@55
|
77 result[M + n] = n * nyquist;
|
jamie@54
|
78 }
|
jamie@54
|
79 break;
|
jamie@54
|
80 case LOG_POWER_SPECTRUM:
|
jamie@54
|
81 for(n = 0; n < M; n++){
|
jamie@54
|
82 if ((temp = SQ(rfft[n]) + SQ(rfft[N - n])) > LOG_LIMIT)
|
jamie@54
|
83 temp = log(temp / NxN);
|
jamie@54
|
84 else
|
jamie@54
|
85 temp = LOG_LIMIT_DB;
|
jamie@54
|
86 result[n] = (temp + DB_SCALE_OFFSET) / DB_SCALE_OFFSET;
|
jamie@55
|
87 result[M + n] = n * nyquist;
|
jamie@54
|
88 }
|
jamie@54
|
89 break;
|
jamie@54
|
90 default:
|
jamie@54
|
91 /* MAGNITUDE_SPECTRUM */
|
jamie@54
|
92 for(n = 0; n < M; n++){
|
jamie@54
|
93 result[n] = sqrt(SQ(rfft[n]) + SQ(rfft[N - n])) / N;
|
jamie@55
|
94 result[M + n] = n * nyquist;
|
jamie@54
|
95 }
|
jamie@54
|
96 break;
|
jamie@1
|
97 }
|
jamie@1
|
98
|
jamie@54
|
99 /* result[0] = fabs(temp[0]) / N */
|
jamie@55
|
100 result[M] = nyquist * .5;
|
jamie@1
|
101
|
jamie@1
|
102 fftwf_destroy_plan(plan);
|
jamie@54
|
103 fftwf_free(rfft);
|
jamie@43
|
104 free(input);
|
jamie@1
|
105
|
jamie@38
|
106 return SUCCESS;
|
jamie@1
|
107 }
|
jamie@1
|
108
|
jamie@43
|
109 int xtract_autocorrelation_fft(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
110
|
jamie@43
|
111 float *temp, *input;
|
jamie@43
|
112 size_t bytes;
|
jamie@1
|
113 int n;
|
jamie@1
|
114 fftwf_plan plan;
|
jamie@1
|
115
|
jamie@1
|
116 temp = (float *)fftwf_malloc(N * sizeof(float));
|
jamie@43
|
117 input = (float *)malloc(bytes = N * sizeof(float));
|
jamie@43
|
118 input = memcpy(input, data, bytes);
|
jamie@43
|
119
|
jamie@43
|
120 plan = fftwf_plan_r2r_1d(N, input, temp, FFTW_HC2R, FFTW_ESTIMATE);
|
jamie@1
|
121
|
jamie@1
|
122 fftwf_execute(plan);
|
jamie@1
|
123
|
jamie@1
|
124 for(n = 0; n < N - 1; n++)
|
jamie@1
|
125 result[n] = temp[n+1];
|
jamie@1
|
126
|
jamie@1
|
127 fftwf_destroy_plan(plan);
|
jamie@1
|
128 fftwf_free(temp);
|
jamie@43
|
129 free(input);
|
jamie@38
|
130
|
jamie@38
|
131 return SUCCESS;
|
jamie@1
|
132 }
|
jamie@1
|
133
|
jamie@43
|
134 int xtract_mfcc(const float *data, const int N, const void *argv, float *result){
|
jamie@30
|
135
|
jamie@30
|
136 xtract_mel_filter *f;
|
jamie@43
|
137 float *input;
|
jamie@43
|
138 size_t bytes;
|
jamie@30
|
139 int n, filter;
|
jamie@30
|
140
|
jamie@30
|
141 f = (xtract_mel_filter *)argv;
|
jamie@39
|
142
|
jamie@43
|
143 input = (float *)malloc(bytes = N * sizeof(float));
|
jamie@43
|
144 input = memcpy(input, data, bytes);
|
jamie@43
|
145
|
jamie@30
|
146 for(filter = 0; filter < f->n_filters; filter++){
|
jamie@30
|
147 for(n = 0; n < N; n++){
|
jamie@43
|
148 result[filter] += input[n] * f->filters[filter][n];
|
jamie@30
|
149 }
|
jamie@30
|
150 if(result[filter] < LOG_LIMIT) result[filter] = LOG_LIMIT;
|
jamie@30
|
151 result[filter] = log(result[filter]);
|
jamie@30
|
152 }
|
jamie@30
|
153
|
jamie@30
|
154 for(n = filter + 1; n < N; n++) result[n] = 0;
|
jamie@30
|
155
|
jamie@30
|
156 xtract_dct(result, f->n_filters, NULL, result);
|
jamie@30
|
157
|
jamie@43
|
158 free(input);
|
jamie@43
|
159
|
jamie@38
|
160 return SUCCESS;
|
jamie@30
|
161 }
|
jamie@30
|
162
|
jamie@43
|
163 int xtract_dct(const float *data, const int N, const void *argv, float *result){
|
jamie@30
|
164
|
jamie@30
|
165 fftwf_plan plan;
|
jamie@43
|
166 float *input;
|
jamie@43
|
167 size_t bytes;
|
jamie@30
|
168
|
jamie@43
|
169 input = (float *)malloc(bytes = N * sizeof(float));
|
jamie@43
|
170 input = memcpy(input, data, bytes);
|
jamie@43
|
171
|
jamie@30
|
172 plan =
|
jamie@43
|
173 fftwf_plan_r2r_1d(N, input, result, FFTW_REDFT00, FFTW_ESTIMATE);
|
jamie@30
|
174
|
jamie@30
|
175 fftwf_execute(plan);
|
jamie@30
|
176 fftwf_destroy_plan(plan);
|
jamie@43
|
177 free(input);
|
jamie@38
|
178
|
jamie@38
|
179 return SUCCESS;
|
jamie@30
|
180 }
|
jamie@30
|
181
|
jamie@30
|
182 #else
|
jamie@30
|
183
|
jamie@43
|
184 int xtract_magnitude_spectrum(const float *data, const int N, const void *argv, float *result){
|
jamie@30
|
185
|
jamie@34
|
186 NEEDS_FFTW;
|
jamie@30
|
187
|
jamie@30
|
188 }
|
jamie@30
|
189
|
jamie@43
|
190 int xtract_autocorrelation_fft(const float *data, const int N, const void *argv, float *result){
|
jamie@30
|
191
|
jamie@34
|
192 NEEDS_FFTW;
|
jamie@30
|
193
|
jamie@30
|
194 }
|
jamie@30
|
195
|
jamie@43
|
196 int xtract_mfcc(const float *data, const int N, const void *argv, float *result){
|
jamie@30
|
197
|
jamie@34
|
198 NEEDS_FFTW;
|
jamie@30
|
199
|
jamie@30
|
200 }
|
jamie@30
|
201
|
jamie@43
|
202 int xtract_dct(const float *data, const int N, const void *argv, float *result){
|
jamie@30
|
203
|
jamie@34
|
204 NEEDS_FFTW;
|
jamie@30
|
205
|
jamie@30
|
206 }
|
jamie@30
|
207
|
jamie@30
|
208 #endif
|
jamie@30
|
209
|
jamie@43
|
210 int xtract_autocorrelation(const float *data, const int N, const void *argv, float *result){
|
jamie@30
|
211
|
jamie@30
|
212 /* Naive time domain implementation */
|
jamie@30
|
213
|
jamie@30
|
214 int n = N, i;
|
jamie@30
|
215
|
jamie@30
|
216 float corr;
|
jamie@30
|
217
|
jamie@30
|
218 while(n--){
|
jamie@30
|
219 corr = 0;
|
jamie@30
|
220 for(i = 0; i < N - n; i++){
|
jamie@30
|
221 corr += data[i] * data[i + n];
|
jamie@30
|
222 }
|
jamie@30
|
223 result[n] = corr / N;
|
jamie@30
|
224 }
|
jamie@38
|
225
|
jamie@38
|
226 return SUCCESS;
|
jamie@30
|
227 }
|
jamie@30
|
228
|
jamie@43
|
229 int xtract_amdf(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
230
|
jamie@1
|
231 int n = N, i;
|
jamie@1
|
232
|
jamie@6
|
233 float md, temp;
|
jamie@1
|
234
|
jamie@1
|
235 while(n--){
|
jamie@1
|
236 md = 0;
|
jamie@1
|
237 for(i = 0; i < N - n; i++){
|
jamie@6
|
238 temp = data[i] - data[i + n];
|
jamie@6
|
239 temp = (temp < 0 ? -temp : temp);
|
jamie@6
|
240 md += temp;
|
jamie@1
|
241 }
|
jamie@1
|
242 result[n] = md / N;
|
jamie@1
|
243 }
|
jamie@38
|
244
|
jamie@38
|
245 return SUCCESS;
|
jamie@1
|
246 }
|
jamie@1
|
247
|
jamie@43
|
248 int xtract_asdf(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
249
|
jamie@1
|
250 int n = N, i;
|
jamie@1
|
251
|
jamie@1
|
252 float sd;
|
jamie@1
|
253
|
jamie@1
|
254 while(n--){
|
jamie@1
|
255 sd = 0;
|
jamie@1
|
256 for(i = 0; i < N - n; i++){
|
jamie@6
|
257 /*sd = 1;*/
|
jamie@1
|
258 sd += SQ(data[i] - data[i + n]);
|
jamie@1
|
259 }
|
jamie@1
|
260 result[n] = sd / N;
|
jamie@1
|
261 }
|
jamie@38
|
262
|
jamie@38
|
263 return SUCCESS;
|
jamie@1
|
264 }
|
jamie@1
|
265
|
jamie@43
|
266 int xtract_bark_coefficients(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
267
|
jamie@1
|
268 int *limits, band, n;
|
jamie@1
|
269
|
jamie@1
|
270 limits = (int *)argv;
|
jamie@1
|
271
|
jamie@1
|
272 for(band = 0; band < BARK_BANDS; band++){
|
jamie@1
|
273 for(n = limits[band]; n < limits[band + 1]; n++)
|
jamie@1
|
274 result[band] += data[n];
|
jamie@1
|
275 }
|
jamie@38
|
276
|
jamie@38
|
277 return SUCCESS;
|
jamie@1
|
278 }
|
jamie@1
|
279
|
jamie@52
|
280 int xtract_peak_spectrum(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
281
|
jamie@55
|
282 float threshold, max, y, y2, y3, p, nyquist, *input = NULL;
|
jamie@43
|
283 size_t bytes;
|
jamie@49
|
284 int n = N, M, rv = SUCCESS;
|
jamie@49
|
285
|
jamie@55
|
286 threshold = max = y = y2 = y3 = p = nyquist = 0.f;
|
jamie@1
|
287
|
jamie@1
|
288 if(argv != NULL){
|
jamie@55
|
289 nyquist = ((float *)argv)[0];
|
jamie@55
|
290 threshold = ((float *)argv)[1];
|
jamie@1
|
291 }
|
jamie@49
|
292 else
|
jamie@49
|
293 rv = BAD_ARGV;
|
jamie@49
|
294
|
jamie@55
|
295 if(threshold < 0 || threshold > 100){
|
jamie@55
|
296 threshold = 0;
|
jamie@49
|
297 rv = BAD_ARGV;
|
jamie@1
|
298 }
|
jamie@1
|
299
|
jamie@55
|
300 CHECK_nyquist;
|
jamie@49
|
301
|
jamie@43
|
302 input = (float *)malloc(bytes = N * sizeof(float));
|
jamie@43
|
303
|
jamie@43
|
304 if(input != NULL)
|
jamie@43
|
305 input = memcpy(input, data, bytes);
|
jamie@43
|
306 else
|
jamie@43
|
307 return MALLOC_FAILED;
|
jamie@43
|
308
|
jamie@1
|
309 M = N >> 1;
|
jamie@1
|
310
|
jamie@45
|
311 while(n--)
|
jamie@43
|
312 max = MAX(max, input[n]);
|
jamie@1
|
313
|
jamie@55
|
314 threshold *= .01 * max;
|
jamie@1
|
315
|
jamie@1
|
316 result[0] = 0;
|
jamie@1
|
317 result[M] = 0;
|
jamie@1
|
318
|
jamie@1
|
319 for(n = 1; n < M; n++){
|
jamie@55
|
320 if(input[n] >= threshold){
|
jamie@43
|
321 if(input[n] > input[n - 1] && input[n] > input[n + 1]){
|
jamie@55
|
322 result[M + n] = nyquist * (n + (p = .5 * (y = input[n-1] -
|
jamie@52
|
323 (y3 = input[n+1])) / (input[n - 1] - 2 *
|
jamie@52
|
324 (y2 = input[n]) + input[n + 1])));
|
jamie@52
|
325 result[n] = y2 - .25 * (y - y3) * p;
|
jamie@1
|
326 }
|
jamie@1
|
327 else{
|
jamie@1
|
328 result[n] = 0;
|
jamie@1
|
329 result[M + n] = 0;
|
jamie@1
|
330 }
|
jamie@1
|
331 }
|
jamie@1
|
332 else{
|
jamie@1
|
333 result[n] = 0;
|
jamie@1
|
334 result[M + n] = 0;
|
jamie@1
|
335 }
|
jamie@1
|
336 }
|
jamie@1
|
337
|
jamie@43
|
338 free(input);
|
jamie@49
|
339 return (rv ? rv : SUCCESS);
|
jamie@1
|
340 }
|
jamie@41
|
341
|
jamie@52
|
342 int xtract_harmonic_spectrum(const float *data, const int N, const void *argv, float *result){
|
jamie@38
|
343
|
jamie@38
|
344 int n = (N >> 1), M = n;
|
jamie@38
|
345
|
jamie@43
|
346 const float *freqs, *amps;
|
jamie@55
|
347 float f0, threshold, ratio, nearest, distance;
|
jamie@38
|
348
|
jamie@52
|
349 amps = data;
|
jamie@52
|
350 freqs = data + n;
|
jamie@38
|
351 f0 = *((float *)argv);
|
jamie@55
|
352 threshold = *((float *)argv+1);
|
jamie@38
|
353
|
jamie@38
|
354 ratio = nearest = distance = 0.f;
|
jamie@38
|
355
|
jamie@38
|
356 while(n--){
|
jamie@38
|
357 if(freqs[n]){
|
jamie@38
|
358 ratio = freqs[n] / f0;
|
jamie@38
|
359 nearest = round(ratio);
|
jamie@38
|
360 distance = fabs(nearest - ratio);
|
jamie@55
|
361 if(distance > threshold)
|
jamie@38
|
362 result[n] = result[M + n] = 0.f;
|
jamie@42
|
363 else {
|
jamie@52
|
364 result[n] = amps[n];
|
jamie@52
|
365 result[M + n] = freqs[n];
|
jamie@42
|
366 }
|
jamie@38
|
367 }
|
jamie@38
|
368 else
|
jamie@38
|
369 result[n] = result[M + n] = 0.f;
|
jamie@38
|
370 }
|
jamie@38
|
371 return SUCCESS;
|
jamie@38
|
372 }
|
jamie@38
|
373
|