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