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