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