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