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