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