jamie@141
|
1 /*
|
jamie@141
|
2 * Copyright (C) 2012 Jamie Bullock
|
jamie@140
|
3 *
|
jamie@141
|
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
|
jamie@141
|
5 * of this software and associated documentation files (the "Software"), to
|
jamie@141
|
6 * deal in the Software without restriction, including without limitation the
|
jamie@141
|
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
jamie@141
|
8 * sell copies of the Software, and to permit persons to whom the Software is
|
jamie@141
|
9 * furnished to do so, subject to the following conditions:
|
jamie@1
|
10 *
|
jamie@141
|
11 * The above copyright notice and this permission notice shall be included in
|
jamie@141
|
12 * all copies or substantial portions of the Software.
|
jamie@1
|
13 *
|
jamie@141
|
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
jamie@141
|
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
jamie@141
|
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
jamie@141
|
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
jamie@141
|
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
jamie@141
|
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
jamie@141
|
20 * IN THE SOFTWARE.
|
jamie@1
|
21 *
|
jamie@1
|
22 */
|
jamie@1
|
23
|
jamie@1
|
24 /* xtract_vector.c: defines functions that extract a feature as a single value from an input vector */
|
jamie@1
|
25
|
jamie@1
|
26 #include <math.h>
|
jamie@43
|
27 #include <string.h>
|
jamie@43
|
28 #include <stdlib.h>
|
jamie@171
|
29 #include <assert.h>
|
jamie@30
|
30
|
jamie@148
|
31 #include "fft.h"
|
jamie@140
|
32
|
jamie@259
|
33 #include "xtract/libxtract.h"
|
jamie@98
|
34 #include "xtract_macros_private.h"
|
jamie@146
|
35 #include "xtract_globals_private.h"
|
jamie@98
|
36
|
jamie@154
|
37 #ifndef M_PI
|
jamie@154
|
38 #define M_PI 3.14159265358979323846264338327
|
jamie@154
|
39 #endif
|
jamie@154
|
40
|
jamie@146
|
41 int xtract_spectrum(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
42 {
|
jamie@1
|
43
|
jamie@140
|
44 int vector = 0;
|
jamie@140
|
45 int withDC = 0;
|
jamie@140
|
46 int normalise = 0;
|
jamie@146
|
47 double q = 0.0;
|
jamie@146
|
48 double temp = 0.0;
|
jamie@146
|
49 double max = 0.0;
|
jamie@146
|
50 double NxN = XTRACT_SQ(N);
|
jamie@146
|
51 double *marker = NULL;
|
jamie@150
|
52 double real = 0.0;
|
jamie@150
|
53 double imag = 0.0;
|
jamie@140
|
54 unsigned int n = 0;
|
jamie@140
|
55 unsigned int m = 0;
|
jamie@140
|
56 unsigned int M = N >> 1;
|
jamie@171
|
57 #ifdef USE_OOURA
|
jamie@171
|
58 double *fft = NULL;
|
jamie@171
|
59 #else
|
jamie@150
|
60 DSPDoubleSplitComplex *fft = NULL;
|
jamie@150
|
61 #endif
|
jamie@98
|
62
|
jamie@146
|
63 q = *(double *)argv;
|
jamie@146
|
64 vector = (int)*((double *)argv+1);
|
jamie@146
|
65 withDC = (int)*((double *)argv+2);
|
jamie@146
|
66 normalise = (int)*((double *)argv+3);
|
jamie@105
|
67
|
jamie@56
|
68 XTRACT_CHECK_q;
|
jamie@150
|
69 #ifdef USE_OOURA
|
jamie@140
|
70 if(!ooura_data_spectrum.initialised)
|
jamie@150
|
71 #else
|
jamie@150
|
72 if(!vdsp_data_spectrum.initialised)
|
jamie@150
|
73 #endif
|
jamie@140
|
74 {
|
jamie@140
|
75 fprintf(stderr,
|
jamie@140
|
76 "libxtract: error: xtract_spectrum() failed, "
|
jamie@140
|
77 "fft data unitialised.\n");
|
jamie@98
|
78 return XTRACT_NO_RESULT;
|
jamie@98
|
79 }
|
jamie@98
|
80
|
jamie@150
|
81 #ifdef USE_OOURA
|
jamie@140
|
82 /* ooura is in-place
|
jamie@147
|
83 * the output format is
|
jamie@140
|
84 * a[0] - DC, a[1] - nyquist, a[2...N-1] - remaining bins
|
jamie@140
|
85 */
|
andrea@211
|
86 fft = (double*)malloc(N * sizeof(double));
|
jamie@171
|
87 assert(fft != NULL);
|
jamie@171
|
88 memcpy(fft, data, N * sizeof(double));
|
jamie@171
|
89
|
jamie@171
|
90 rdft(N, 1, fft, ooura_data_spectrum.ooura_ip,
|
jamie@140
|
91 ooura_data_spectrum.ooura_w);
|
jamie@150
|
92 #else
|
jamie@150
|
93 fft = &vdsp_data_spectrum.fft;
|
jamie@150
|
94 vDSP_ctozD((DSPDoubleComplex *)data, 2, fft, 1, N >> 1);
|
jamie@150
|
95 vDSP_fft_zripD(vdsp_data_spectrum.setup, fft, 1,
|
jamie@150
|
96 vdsp_data_spectrum.log2N, FFT_FORWARD);
|
jamie@150
|
97 #endif
|
jamie@54
|
98
|
jamie@140
|
99 switch(vector)
|
jamie@140
|
100 {
|
jamie@67
|
101
|
jamie@120
|
102 case XTRACT_LOG_MAGNITUDE_SPECTRUM:
|
jamie@140
|
103 for(n = 0, m = 0; m < M; ++n, ++m)
|
jamie@140
|
104 {
|
jamie@150
|
105 marker = &result[m];
|
jamie@150
|
106
|
jamie@150
|
107 if(n==0 && !withDC) /* discard DC and keep Nyquist */
|
jamie@140
|
108 {
|
jamie@150
|
109 ++n;
|
jamie@150
|
110 #ifdef USE_OOURA
|
jamie@150
|
111 marker = &result[M-1];
|
jamie@150
|
112 #endif
|
jamie@140
|
113 }
|
jamie@150
|
114 #ifdef USE_OOURA
|
jamie@150
|
115 if(n==1 && withDC) /* discard Nyquist */
|
jamie@150
|
116 {
|
jamie@150
|
117 ++n;
|
jamie@150
|
118 }
|
jamie@178
|
119 if(n == M)
|
jamie@178
|
120 {
|
jamie@178
|
121 XTRACT_SET_FREQUENCY;
|
jamie@178
|
122 break;
|
jamie@178
|
123 }
|
jamie@150
|
124
|
jamie@171
|
125 real = fft[n*2];
|
jamie@171
|
126 imag = fft[n*2+1];
|
jamie@150
|
127 #else
|
jamie@150
|
128 real = fft->realp[n];
|
jamie@150
|
129 imag = fft->realp[n];
|
jamie@150
|
130 #endif
|
jamie@150
|
131
|
jamie@150
|
132 temp = XTRACT_SQ(real) + XTRACT_SQ(imag);
|
jamie@140
|
133 if (temp > XTRACT_LOG_LIMIT)
|
jamie@140
|
134 {
|
jamie@146
|
135 temp = log(sqrt(temp) / (double)N);
|
jamie@140
|
136 }
|
jamie@140
|
137 else
|
jamie@140
|
138 {
|
jamie@140
|
139 temp = XTRACT_LOG_LIMIT_DB;
|
jamie@140
|
140 }
|
jamie@140
|
141 result[m] =
|
jamie@140
|
142 /* Scaling */
|
jamie@140
|
143 (temp + XTRACT_DB_SCALE_OFFSET) /
|
jamie@140
|
144 XTRACT_DB_SCALE_OFFSET;
|
jamie@111
|
145
|
jamie@140
|
146 XTRACT_SET_FREQUENCY;
|
jamie@140
|
147 XTRACT_GET_MAX;
|
jamie@140
|
148 }
|
jamie@140
|
149 break;
|
jamie@67
|
150
|
jamie@140
|
151 case XTRACT_POWER_SPECTRUM:
|
jamie@140
|
152 for(n = 0, m = 0; m < M; ++n, ++m)
|
jamie@140
|
153 {
|
jamie@150
|
154
|
jamie@150
|
155 marker = &result[m];
|
jamie@150
|
156
|
jamie@150
|
157 if(n==0 && !withDC) /* discard DC and keep Nyquist */
|
jamie@150
|
158 {
|
jamie@150
|
159 ++n;
|
jamie@150
|
160 #ifdef USE_OOURA
|
jamie@150
|
161 marker = &result[M-1];
|
jamie@150
|
162 #endif
|
jamie@150
|
163 }
|
jamie@150
|
164 #ifdef USE_OOURA
|
jamie@150
|
165 if(n==1 && withDC) /* discard Nyquist */
|
jamie@140
|
166 {
|
jamie@140
|
167 ++n;
|
jamie@120
|
168 }
|
jamie@178
|
169 if(n == M)
|
jamie@178
|
170 {
|
jamie@178
|
171 XTRACT_SET_FREQUENCY;
|
jamie@178
|
172 break;
|
jamie@178
|
173 }
|
jamie@150
|
174
|
jamie@171
|
175 real = fft[n*2];
|
jamie@171
|
176 imag = fft[n*2+1];
|
jamie@150
|
177 #else
|
jamie@150
|
178 real = fft->realp[n];
|
jamie@150
|
179 imag = fft->realp[n];
|
jamie@150
|
180 #endif
|
jamie@150
|
181
|
jamie@150
|
182 result[m] = (XTRACT_SQ(real) + XTRACT_SQ(imag)) / NxN;
|
jamie@140
|
183 XTRACT_SET_FREQUENCY;
|
jamie@140
|
184 XTRACT_GET_MAX;
|
jamie@140
|
185 }
|
jamie@140
|
186 break;
|
jamie@120
|
187
|
jamie@140
|
188 case XTRACT_LOG_POWER_SPECTRUM:
|
jamie@140
|
189 for(n = 0, m = 0; m < M; ++n, ++m)
|
jamie@140
|
190 {
|
jamie@150
|
191 marker = &result[m];
|
jamie@150
|
192
|
jamie@150
|
193 if(n==0 && !withDC) /* discard DC and keep Nyquist */
|
jamie@150
|
194 {
|
jamie@150
|
195 ++n;
|
jamie@150
|
196 #ifdef USE_OOURA
|
jamie@150
|
197 marker = &result[M-1];
|
jamie@150
|
198 #endif
|
jamie@150
|
199 }
|
jamie@150
|
200 #ifdef USE_OOURA
|
jamie@150
|
201 if(n==1 && withDC) /* discard Nyquist */
|
jamie@140
|
202 {
|
jamie@140
|
203 ++n;
|
jamie@120
|
204 }
|
jamie@178
|
205 if(n == M)
|
jamie@178
|
206 {
|
jamie@178
|
207 XTRACT_SET_FREQUENCY;
|
jamie@178
|
208 break;
|
jamie@178
|
209 }
|
jamie@150
|
210
|
jamie@171
|
211 real = fft[n*2];
|
jamie@171
|
212 imag = fft[n*2+1];
|
jamie@150
|
213 #else
|
jamie@150
|
214 real = fft->realp[n];
|
jamie@150
|
215 imag = fft->realp[n];
|
jamie@150
|
216 #endif
|
jamie@150
|
217
|
jamie@150
|
218 if ((temp = XTRACT_SQ(real) + XTRACT_SQ(imag)) >
|
jamie@140
|
219 XTRACT_LOG_LIMIT)
|
jamie@146
|
220 temp = log(temp / NxN);
|
jamie@140
|
221 else
|
jamie@140
|
222 temp = XTRACT_LOG_LIMIT_DB;
|
jamie@67
|
223
|
jamie@140
|
224 result[m] = (temp + XTRACT_DB_SCALE_OFFSET) /
|
jamie@140
|
225 XTRACT_DB_SCALE_OFFSET;
|
jamie@140
|
226 XTRACT_SET_FREQUENCY;
|
jamie@140
|
227 XTRACT_GET_MAX;
|
jamie@140
|
228 }
|
jamie@140
|
229 break;
|
jamie@111
|
230
|
jamie@140
|
231 default:
|
jamie@140
|
232 /* MAGNITUDE_SPECTRUM */
|
jamie@140
|
233 for(n = 0, m = 0; m < M; ++n, ++m)
|
jamie@140
|
234 {
|
jamie@140
|
235 marker = &result[m];
|
jamie@140
|
236
|
jamie@140
|
237 if(n==0 && !withDC) /* discard DC and keep Nyquist */
|
jamie@140
|
238 {
|
jamie@140
|
239 ++n;
|
jamie@150
|
240 #ifdef USE_OOURA
|
jamie@140
|
241 marker = &result[M-1];
|
jamie@150
|
242 #endif
|
jamie@120
|
243 }
|
jamie@150
|
244 #ifdef USE_OOURA
|
jamie@140
|
245 if(n==1 && withDC) /* discard Nyquist */
|
jamie@140
|
246 {
|
jamie@140
|
247 ++n;
|
jamie@140
|
248 }
|
jamie@178
|
249 if(n == M)
|
jamie@178
|
250 {
|
jamie@178
|
251 XTRACT_SET_FREQUENCY;
|
jamie@178
|
252 break;
|
jamie@178
|
253 }
|
jamie@178
|
254
|
jamie@171
|
255 real = fft[n*2];
|
jamie@171
|
256 imag = fft[n*2+1];
|
jamie@150
|
257 #else
|
jamie@150
|
258 real = fft->realp[n];
|
jamie@150
|
259 imag = fft->realp[n];
|
jamie@150
|
260 #endif
|
jamie@150
|
261 *marker = sqrt(XTRACT_SQ(real) + XTRACT_SQ(imag)) / (double)N;
|
jamie@111
|
262
|
jamie@140
|
263 XTRACT_SET_FREQUENCY;
|
jamie@140
|
264 XTRACT_GET_MAX;
|
jamie@140
|
265 }
|
jamie@140
|
266 break;
|
jamie@70
|
267 }
|
jamie@105
|
268
|
jamie@140
|
269 if(normalise)
|
jamie@140
|
270 {
|
jamie@105
|
271 for(n = 0; n < M; n++)
|
jamie@105
|
272 result[n] /= max;
|
jamie@105
|
273 }
|
jamie@105
|
274
|
jamie@171
|
275 #ifdef USE_OOURA
|
jamie@171
|
276 free(fft);
|
jamie@171
|
277 #endif
|
jamie@171
|
278
|
jamie@56
|
279 return XTRACT_SUCCESS;
|
jamie@1
|
280 }
|
jamie@1
|
281
|
jamie@146
|
282 int xtract_autocorrelation_fft(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
283 {
|
jamie@120
|
284
|
jamie@140
|
285 double *rfft = NULL;
|
jamie@140
|
286 int n = 0;
|
jamie@140
|
287 int M = 0;
|
jamie@150
|
288 #ifndef USE_OOURA
|
jamie@150
|
289 DSPDoubleSplitComplex *fft = NULL;
|
jamie@154
|
290 double M_double = 0.0;
|
jamie@150
|
291 #endif
|
jamie@1
|
292
|
jamie@75
|
293 M = N << 1;
|
jamie@43
|
294
|
jamie@75
|
295 /* Zero pad the input vector */
|
jamie@140
|
296 rfft = (double *)calloc(M, sizeof(double));
|
jamie@146
|
297 memcpy(rfft, data, N * sizeof(double));
|
jamie@75
|
298
|
jamie@150
|
299 #ifdef USE_OOURA
|
jamie@140
|
300 rdft(M, 1, rfft, ooura_data_autocorrelation_fft.ooura_ip,
|
jamie@140
|
301 ooura_data_autocorrelation_fft.ooura_w);
|
jamie@1
|
302
|
jamie@150
|
303 for(n = 2; n < M; ++n)
|
jamie@140
|
304 {
|
jamie@140
|
305 rfft[n*2] = XTRACT_SQ(rfft[n*2]) + XTRACT_SQ(rfft[n*2+1]);
|
jamie@146
|
306 rfft[n*2+1] = 0.0;
|
jamie@75
|
307 }
|
jamie@120
|
308
|
jamie@140
|
309 rfft[0] = XTRACT_SQ(rfft[0]);
|
jamie@140
|
310 rfft[1] = XTRACT_SQ(rfft[1]);
|
jamie@75
|
311
|
jamie@140
|
312 rdft(M, -1, rfft, ooura_data_autocorrelation_fft.ooura_ip,
|
jamie@140
|
313 ooura_data_autocorrelation_fft.ooura_w);
|
jamie@120
|
314
|
jamie@150
|
315 #else
|
jamie@150
|
316 /* vDSP has its own autocorrelation function, but it doesn't fit the
|
jamie@150
|
317 * LibXtract model, e.g. we can't guarantee it's going to use
|
jamie@150
|
318 * an FFT for all values of N */
|
jamie@150
|
319 fft = &vdsp_data_autocorrelation_fft.fft;
|
jamie@150
|
320 vDSP_ctozD((DSPDoubleComplex *)data, 2, fft, 1, N);
|
jamie@150
|
321 vDSP_fft_zripD(vdsp_data_autocorrelation_fft.setup, fft, 1,
|
jamie@150
|
322 vdsp_data_autocorrelation_fft.log2N, FFT_FORWARD);
|
jamie@150
|
323
|
jamie@150
|
324 for(n = 0; n < N; ++n)
|
jamie@150
|
325 {
|
jamie@150
|
326 fft->realp[n] = XTRACT_SQ(fft->realp[n]) + XTRACT_SQ(fft->imagp[n]);
|
jamie@150
|
327 fft->imagp[n] = 0.0;
|
jamie@150
|
328 }
|
jamie@150
|
329
|
jamie@150
|
330 vDSP_fft_zripD(vdsp_data_autocorrelation_fft.setup, fft, 1,
|
jamie@150
|
331 vdsp_data_autocorrelation_fft.log2N, FFT_INVERSE);
|
jamie@150
|
332 #endif
|
jamie@150
|
333
|
jamie@75
|
334 /* Normalisation factor */
|
jamie@75
|
335 M = M * N;
|
jamie@75
|
336
|
jamie@150
|
337 #ifdef USE_OOURA
|
jamie@75
|
338 for(n = 0; n < N; n++)
|
jamie@146
|
339 result[n] = rfft[n] / (double)M;
|
jamie@140
|
340 free(rfft);
|
jamie@150
|
341 #else
|
jamie@150
|
342 M_double = (double)M;
|
jamie@150
|
343 vDSP_ztocD(fft, 1, (DOUBLE_COMPLEX *)result, 2, N);
|
jamie@150
|
344 vDSP_vsdivD(result, 1, &M_double, result, 1, N);
|
jamie@150
|
345 #endif
|
jamie@38
|
346
|
jamie@56
|
347 return XTRACT_SUCCESS;
|
jamie@1
|
348 }
|
jamie@1
|
349
|
jamie@146
|
350 int xtract_mfcc(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
351 {
|
jamie@30
|
352
|
jamie@30
|
353 xtract_mel_filter *f;
|
jamie@30
|
354 int n, filter;
|
jamie@30
|
355
|
jamie@30
|
356 f = (xtract_mel_filter *)argv;
|
jamie@120
|
357
|
jamie@140
|
358 for(filter = 0; filter < f->n_filters; filter++)
|
jamie@140
|
359 {
|
jamie@146
|
360 result[filter] = 0.0;
|
jamie@140
|
361 for(n = 0; n < N; n++)
|
jamie@140
|
362 {
|
jamie@71
|
363 result[filter] += data[n] * f->filters[filter][n];
|
jamie@30
|
364 }
|
jamie@146
|
365 result[filter] = log(result[filter] < XTRACT_LOG_LIMIT ? XTRACT_LOG_LIMIT : result[filter]);
|
jamie@30
|
366 }
|
jamie@30
|
367
|
jamie@30
|
368 xtract_dct(result, f->n_filters, NULL, result);
|
jamie@120
|
369
|
jamie@56
|
370 return XTRACT_SUCCESS;
|
jamie@30
|
371 }
|
jamie@30
|
372
|
jamie@146
|
373 int xtract_dct(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
374 {
|
jamie@120
|
375
|
jamie@148
|
376 int n;
|
jamie@148
|
377 int m;
|
andrea@211
|
378 double *temp = (double*)calloc(N, sizeof(double));
|
jamie@120
|
379
|
jamie@148
|
380 for (n = 0; n < N; ++n)
|
jamie@148
|
381 {
|
jamie@148
|
382 for(m = 1; m <= N; ++m) {
|
jamie@148
|
383 temp[n] += data[m - 1] * cos(M_PI * (n / (double)N) * (m - 0.5));
|
jamie@140
|
384 }
|
jamie@148
|
385 }
|
jamie@120
|
386
|
jamie@148
|
387 memcpy(result, temp, N * sizeof(double));
|
jamie@148
|
388 free(temp);
|
jamie@148
|
389
|
jamie@148
|
390 return XTRACT_SUCCESS;
|
jamie@30
|
391 }
|
jamie@30
|
392
|
jamie@146
|
393 int xtract_autocorrelation(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
394 {
|
jamie@30
|
395
|
jamie@30
|
396 /* Naive time domain implementation */
|
jamie@120
|
397
|
jamie@30
|
398 int n = N, i;
|
jamie@120
|
399
|
jamie@146
|
400 double corr;
|
jamie@30
|
401
|
jamie@140
|
402 while(n--)
|
jamie@140
|
403 {
|
jamie@120
|
404 corr = 0;
|
jamie@140
|
405 for(i = 0; i < N - n; i++)
|
jamie@140
|
406 {
|
jamie@30
|
407 corr += data[i] * data[i + n];
|
jamie@30
|
408 }
|
jamie@30
|
409 result[n] = corr / N;
|
jamie@30
|
410 }
|
jamie@38
|
411
|
jamie@56
|
412 return XTRACT_SUCCESS;
|
jamie@30
|
413 }
|
jamie@30
|
414
|
jamie@146
|
415 int xtract_amdf(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
416 {
|
jamie@1
|
417
|
jamie@1
|
418 int n = N, i;
|
jamie@120
|
419
|
jamie@146
|
420 double md, temp;
|
jamie@1
|
421
|
jamie@140
|
422 while(n--)
|
jamie@140
|
423 {
|
jamie@146
|
424 md = 0.0;
|
jamie@140
|
425 for(i = 0; i < N - n; i++)
|
jamie@140
|
426 {
|
jamie@6
|
427 temp = data[i] - data[i + n];
|
jamie@120
|
428 temp = (temp < 0 ? -temp : temp);
|
jamie@120
|
429 md += temp;
|
jamie@1
|
430 }
|
jamie@146
|
431 result[n] = md / (double)N;
|
jamie@1
|
432 }
|
jamie@38
|
433
|
jamie@56
|
434 return XTRACT_SUCCESS;
|
jamie@1
|
435 }
|
jamie@1
|
436
|
jamie@146
|
437 int xtract_asdf(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
438 {
|
jamie@120
|
439
|
jamie@1
|
440 int n = N, i;
|
jamie@120
|
441
|
jamie@146
|
442 double sd;
|
jamie@1
|
443
|
jamie@140
|
444 while(n--)
|
jamie@140
|
445 {
|
jamie@146
|
446 sd = 0.0;
|
jamie@140
|
447 for(i = 0; i < N - n; i++)
|
jamie@140
|
448 {
|
jamie@6
|
449 /*sd = 1;*/
|
jamie@56
|
450 sd += XTRACT_SQ(data[i] - data[i + n]);
|
jamie@1
|
451 }
|
jamie@146
|
452 result[n] = sd / (double)N;
|
jamie@1
|
453 }
|
jamie@38
|
454
|
jamie@56
|
455 return XTRACT_SUCCESS;
|
jamie@1
|
456 }
|
jamie@1
|
457
|
jamie@146
|
458 int xtract_bark_coefficients(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
459 {
|
jamie@1
|
460
|
jamie@1
|
461 int *limits, band, n;
|
jamie@1
|
462
|
jamie@1
|
463 limits = (int *)argv;
|
jamie@120
|
464
|
jamie@140
|
465 for(band = 0; band < XTRACT_BARK_BANDS - 1; band++)
|
jamie@140
|
466 {
|
jamie@146
|
467 result[band] = 0.0;
|
jamie@1
|
468 for(n = limits[band]; n < limits[band + 1]; n++)
|
jamie@1
|
469 result[band] += data[n];
|
jamie@1
|
470 }
|
jamie@38
|
471
|
jamie@56
|
472 return XTRACT_SUCCESS;
|
jamie@1
|
473 }
|
jamie@1
|
474
|
jamie@146
|
475 int xtract_peak_spectrum(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
476 {
|
jamie@1
|
477
|
jamie@146
|
478 double threshold, max, y, y2, y3, p, q, *input = NULL;
|
jamie@43
|
479 size_t bytes;
|
jamie@59
|
480 int n = N, rv = XTRACT_SUCCESS;
|
jamie@49
|
481
|
jamie@146
|
482 threshold = max = y = y2 = y3 = p = q = 0.0;
|
jamie@120
|
483
|
jamie@140
|
484 if(argv != NULL)
|
jamie@140
|
485 {
|
jamie@146
|
486 q = ((double *)argv)[0];
|
jamie@146
|
487 threshold = ((double *)argv)[1];
|
jamie@1
|
488 }
|
jamie@49
|
489 else
|
jamie@56
|
490 rv = XTRACT_BAD_ARGV;
|
jamie@49
|
491
|
jamie@140
|
492 if(threshold < 0 || threshold > 100)
|
jamie@140
|
493 {
|
jamie@55
|
494 threshold = 0;
|
jamie@56
|
495 rv = XTRACT_BAD_ARGV;
|
jamie@1
|
496 }
|
jamie@1
|
497
|
jamie@56
|
498 XTRACT_CHECK_q;
|
jamie@49
|
499
|
jamie@146
|
500 input = (double *)calloc(N, sizeof(double));
|
jamie@98
|
501
|
jamie@146
|
502 bytes = N * sizeof(double);
|
jamie@43
|
503
|
jamie@43
|
504 if(input != NULL)
|
andrea@211
|
505 input = (double*)memcpy(input, data, bytes);
|
jamie@43
|
506 else
|
jamie@120
|
507 return XTRACT_MALLOC_FAILED;
|
jamie@43
|
508
|
jamie@45
|
509 while(n--)
|
jamie@56
|
510 max = XTRACT_MAX(max, input[n]);
|
jamie@120
|
511
|
jamie@55
|
512 threshold *= .01 * max;
|
jamie@1
|
513
|
jamie@1
|
514 result[0] = 0;
|
jamie@59
|
515 result[N] = 0;
|
jamie@1
|
516
|
jamie@140
|
517 for(n = 1; n < N; n++)
|
jamie@140
|
518 {
|
jamie@140
|
519 if(input[n] >= threshold)
|
jamie@140
|
520 {
|
jamie@140
|
521 if(input[n] > input[n - 1] && n + 1 < N && input[n] > input[n + 1])
|
jamie@140
|
522 {
|
jamie@180
|
523 result[N + n] = q * (n + 1 + (p = .5 * ((y = input[n-1]) -
|
jamie@140
|
524 (y3 = input[n+1])) / (input[n - 1] - 2 *
|
jamie@140
|
525 (y2 = input[n]) + input[n + 1])));
|
jamie@52
|
526 result[n] = y2 - .25 * (y - y3) * p;
|
jamie@1
|
527 }
|
jamie@140
|
528 else
|
jamie@140
|
529 {
|
jamie@1
|
530 result[n] = 0;
|
jamie@59
|
531 result[N + n] = 0;
|
jamie@1
|
532 }
|
jamie@1
|
533 }
|
jamie@140
|
534 else
|
jamie@140
|
535 {
|
jamie@1
|
536 result[n] = 0;
|
jamie@59
|
537 result[N + n] = 0;
|
jamie@1
|
538 }
|
jamie@140
|
539 }
|
jamie@120
|
540
|
jamie@179
|
541 free(input);
|
jamie@56
|
542 return (rv ? rv : XTRACT_SUCCESS);
|
jamie@1
|
543 }
|
jamie@120
|
544
|
jamie@146
|
545 int xtract_harmonic_spectrum(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
546 {
|
jamie@120
|
547
|
jamie@140
|
548 int n = (N >> 1), M = n;
|
jamie@38
|
549
|
jamie@146
|
550 const double *freqs, *amps;
|
jamie@146
|
551 double f0, threshold, ratio, nearest, distance;
|
jamie@38
|
552
|
jamie@52
|
553 amps = data;
|
jamie@52
|
554 freqs = data + n;
|
jamie@146
|
555 f0 = *((double *)argv);
|
jamie@146
|
556 threshold = *((double *)argv+1);
|
jamie@38
|
557
|
jamie@146
|
558 ratio = nearest = distance = 0.0;
|
jamie@38
|
559
|
jamie@140
|
560 while(n--)
|
jamie@140
|
561 {
|
jamie@140
|
562 if(freqs[n])
|
jamie@140
|
563 {
|
jamie@120
|
564 ratio = freqs[n] / f0;
|
andrea@211
|
565 nearest = floor( 0.5f + ratio); // replace -> nearest = round(ratio);
|
andrea@211
|
566 distance = fabs(nearest - ratio);
|
jamie@120
|
567 if(distance > threshold)
|
jamie@146
|
568 result[n] = result[M + n] = 0.0;
|
jamie@140
|
569 else
|
jamie@140
|
570 {
|
jamie@120
|
571 result[n] = amps[n];
|
jamie@120
|
572 result[M + n] = freqs[n];
|
jamie@120
|
573 }
|
jamie@120
|
574 }
|
jamie@120
|
575 else
|
jamie@146
|
576 result[n] = result[M + n] = 0.0;
|
jamie@38
|
577 }
|
jamie@56
|
578 return XTRACT_SUCCESS;
|
jamie@38
|
579 }
|
jamie@120
|
580
|
jamie@146
|
581 int xtract_lpc(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
582 {
|
jamie@104
|
583
|
jamie@154
|
584 int i, j, M, L;
|
jamie@146
|
585 double r = 0.0,
|
jamie@146
|
586 error = 0.0;
|
jamie@104
|
587
|
jamie@146
|
588 double *ref = NULL,
|
jamie@140
|
589 *lpc = NULL ;
|
jamie@104
|
590
|
jamie@104
|
591 error = data[0];
|
jamie@104
|
592 L = N - 1; /* The number of LPC coefficients */
|
jamie@104
|
593 M = L * 2; /* The length of *result */
|
jamie@104
|
594 ref = result;
|
jamie@104
|
595 lpc = result+L;
|
jamie@113
|
596
|
jamie@140
|
597 if(error == 0.0)
|
jamie@140
|
598 {
|
jamie@146
|
599 memset(result, 0, M * sizeof(double));
|
jamie@104
|
600 return XTRACT_NO_RESULT;
|
jamie@104
|
601 }
|
jamie@113
|
602
|
jamie@146
|
603 memset(result, 0, M * sizeof(double));
|
jamie@104
|
604
|
jamie@140
|
605 for (i = 0; i < L; i++)
|
jamie@140
|
606 {
|
jamie@104
|
607
|
jamie@104
|
608 /* Sum up this iteration's reflection coefficient. */
|
jamie@104
|
609 r = -data[i + 1];
|
jamie@140
|
610 for (j = 0; j < i; j++)
|
jamie@104
|
611 r -= lpc[j] * data[i - j];
|
jamie@104
|
612 ref[i] = r /= error;
|
jamie@104
|
613
|
jamie@104
|
614 /* Update LPC coefficients and total error. */
|
jamie@104
|
615 lpc[i] = r;
|
jamie@140
|
616 for (j = 0; j < i / 2; j++)
|
jamie@140
|
617 {
|
jamie@146
|
618 double tmp = lpc[j];
|
jamie@104
|
619 lpc[j] = r * lpc[i - 1 - j];
|
jamie@104
|
620 lpc[i - 1 - j] += r * tmp;
|
jamie@104
|
621 }
|
jamie@104
|
622 if (i % 2) lpc[j] += lpc[j] * r;
|
jamie@104
|
623
|
jamie@104
|
624 error *= 1 - r * r;
|
jamie@104
|
625 }
|
jamie@104
|
626
|
jamie@104
|
627 return XTRACT_SUCCESS;
|
jamie@104
|
628 }
|
jamie@104
|
629
|
jamie@146
|
630 int xtract_lpcc(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
631 {
|
jamie@104
|
632
|
jamie@104
|
633 /* Given N lpc coefficients extract an LPC cepstrum of size argv[0] */
|
jamie@104
|
634 /* Based on an an algorithm by rabiner and Juang */
|
jamie@104
|
635
|
jamie@104
|
636 int n, k;
|
jamie@146
|
637 double sum;
|
jamie@104
|
638 int order = N - 1; /* Eventually change this to Q = 3/2 p as suggested in Rabiner */
|
jamie@140
|
639 int cep_length;
|
jamie@120
|
640
|
jamie@104
|
641 if(argv == NULL)
|
jamie@115
|
642 cep_length = N - 1; /* FIX: if we're going to have default values, they should come from the descriptor */
|
jamie@104
|
643 else
|
jamie@115
|
644 cep_length = *(int *)argv;
|
jamie@146
|
645 //cep_length = (int)((double *)argv)[0];
|
jamie@104
|
646
|
jamie@146
|
647 memset(result, 0, cep_length * sizeof(double));
|
jamie@104
|
648
|
jamie@140
|
649 for (n = 1; n <= order && n <= cep_length; n++)
|
jamie@140
|
650 {
|
jamie@146
|
651 sum = 0.0;
|
jamie@104
|
652 for (k = 1; k < n; k++)
|
jamie@104
|
653 sum += k * result[k-1] * data[n - k];
|
jamie@104
|
654 result[n-1] = data[n] + sum / n;
|
jamie@104
|
655 }
|
jamie@104
|
656
|
jamie@104
|
657 /* be wary of these interpolated values */
|
jamie@140
|
658 for(n = order + 1; n <= cep_length; n++)
|
jamie@140
|
659 {
|
jamie@146
|
660 sum = 0.0;
|
jamie@104
|
661 for (k = n - (order - 1); k < n; k++)
|
jamie@104
|
662 sum += k * result[k-1] * data[n - k];
|
jamie@104
|
663 result[n-1] = sum / n;
|
jamie@104
|
664 }
|
jamie@104
|
665
|
jamie@104
|
666 return XTRACT_SUCCESS;
|
jamie@104
|
667
|
jamie@104
|
668 }
|
jamie@146
|
669 //int xtract_lpcc_s(const double *data, const int N, const void *argv, double *result){
|
jamie@104
|
670 // return XTRACT_SUCCESS;
|
jamie@104
|
671 //}
|
jamie@104
|
672
|
jamie@146
|
673 int xtract_subbands(const double *data, const int N, const void *argv, double *result)
|
jamie@140
|
674 {
|
jamie@104
|
675
|
jamie@114
|
676 int n, bw, xtract_func, nbands, scale, start, lower, *argi, rv;
|
jamie@114
|
677
|
jamie@114
|
678 argi = (int *)argv;
|
jamie@114
|
679
|
jamie@114
|
680 xtract_func = argi[0];
|
jamie@114
|
681 nbands = argi[1];
|
jamie@114
|
682 scale = argi[2];
|
jamie@114
|
683 start = argi[3];
|
jamie@114
|
684
|
jamie@114
|
685 if(scale == XTRACT_LINEAR_SUBBANDS)
|
jamie@114
|
686 bw = floorf((N - start) / nbands);
|
jamie@114
|
687 else
|
jamie@114
|
688 bw = start;
|
jamie@114
|
689
|
jamie@114
|
690 lower = start;
|
jamie@115
|
691 rv = XTRACT_SUCCESS;
|
jamie@114
|
692
|
jamie@140
|
693 for(n = 0; n < nbands; n++)
|
jamie@140
|
694 {
|
jamie@114
|
695
|
jamie@114
|
696 /* Bounds sanity check */
|
jamie@140
|
697 if(lower >= N || lower + bw >= N)
|
jamie@140
|
698 {
|
jamie@120
|
699 // printf("n: %d\n", n);
|
jamie@146
|
700 result[n] = 0.0;
|
jamie@114
|
701 continue;
|
jamie@115
|
702 }
|
jamie@114
|
703
|
jamie@114
|
704 rv = xtract[xtract_func](data+lower, bw, NULL, &result[n]);
|
jamie@114
|
705
|
jamie@114
|
706 if(rv != XTRACT_SUCCESS)
|
jamie@114
|
707 return rv;
|
jamie@114
|
708
|
jamie@140
|
709 switch(scale)
|
jamie@140
|
710 {
|
jamie@140
|
711 case XTRACT_OCTAVE_SUBBANDS:
|
jamie@140
|
712 lower += bw;
|
jamie@140
|
713 bw = lower;
|
jamie@140
|
714 break;
|
jamie@140
|
715 case XTRACT_LINEAR_SUBBANDS:
|
jamie@140
|
716 lower += bw;
|
jamie@140
|
717 break;
|
jamie@114
|
718 }
|
jamie@114
|
719
|
jamie@114
|
720 }
|
jamie@114
|
721
|
jamie@114
|
722 return rv;
|
jamie@114
|
723
|
jamie@114
|
724 }
|
jamie@114
|
725
|
jamie@114
|
726
|
jamie@114
|
727
|