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