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@107
|
24 /* scalar.c: defines functions that extract a feature as a single value from an input vector */
|
jamie@1
|
25
|
jamie@113
|
26 #include <config.h>
|
jamie@113
|
27
|
jamie@5
|
28 #include <stdlib.h>
|
jamie@43
|
29 #include <string.h>
|
jamie@78
|
30 #include <stdio.h>
|
jamie@113
|
31 #include <math.h>
|
jamie@113
|
32
|
jamie@113
|
33 #include "xtract/libxtract.h"
|
jamie@113
|
34 #include "xtract/xtract_helper.h"
|
jamie@113
|
35 #include "xtract_macros_private.h"
|
jamie@1
|
36
|
jamie@85
|
37 #ifndef powf
|
jamie@140
|
38 #define powf pow
|
jamie@85
|
39 #endif
|
jamie@85
|
40
|
jamie@85
|
41 #ifndef expf
|
jamie@140
|
42 #define expf exp
|
jamie@85
|
43 #endif
|
jamie@85
|
44
|
jamie@113
|
45 #ifndef sqrtf
|
jamie@140
|
46 #define sqrtf sqrt
|
jamie@113
|
47 #endif
|
jamie@113
|
48
|
jamie@113
|
49 #ifndef fabsf
|
jamie@140
|
50 #define fabsf fabs
|
jamie@113
|
51 #endif
|
jamie@113
|
52
|
jamie@113
|
53
|
jamie@140
|
54 void test(void)
|
jamie@140
|
55 {
|
jamie@113
|
56 printf("Hello world\n");
|
jamie@113
|
57 #ifdef WORDS_BIGENDIAN
|
jamie@113
|
58 printf("Big endian!\n");
|
jamie@113
|
59 #endif
|
jamie@88
|
60 }
|
jamie@88
|
61
|
jamie@140
|
62 int xtract_mean(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
63 {
|
jamie@25
|
64
|
jamie@1
|
65 int n = N;
|
jamie@1
|
66
|
jamie@122
|
67 *result = 0.f;
|
jamie@113
|
68
|
jamie@1
|
69 while(n--)
|
jamie@140
|
70 *result += data[n];
|
jamie@140
|
71
|
jamie@140
|
72 *result /= N;
|
jamie@140
|
73
|
jamie@140
|
74 return XTRACT_SUCCESS;
|
jamie@140
|
75 }
|
jamie@140
|
76
|
jamie@140
|
77 int xtract_variance(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
78 {
|
jamie@140
|
79
|
jamie@140
|
80 int n = N;
|
jamie@140
|
81
|
jamie@140
|
82 *result = 0.f;
|
jamie@140
|
83
|
jamie@140
|
84 while(n--)
|
jamie@140
|
85 *result += powf(data[n] - *(float *)argv, 2);
|
jamie@25
|
86
|
jamie@43
|
87 *result = *result / (N - 1);
|
jamie@44
|
88
|
jamie@56
|
89 return XTRACT_SUCCESS;
|
jamie@1
|
90 }
|
jamie@1
|
91
|
jamie@140
|
92 int xtract_standard_deviation(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
93 {
|
jamie@25
|
94
|
jamie@113
|
95 *result = sqrtf(*(float *)argv);
|
jamie@25
|
96
|
jamie@56
|
97 return XTRACT_SUCCESS;
|
jamie@1
|
98 }
|
jamie@1
|
99
|
jamie@140
|
100 int xtract_average_deviation(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
101 {
|
jamie@25
|
102
|
jamie@1
|
103 int n = N;
|
jamie@44
|
104
|
jamie@122
|
105 *result = 0.f;
|
jamie@113
|
106
|
jamie@1
|
107 while(n--)
|
jamie@140
|
108 *result += fabsf(data[n] - *(float *)argv);
|
jamie@25
|
109
|
jamie@1
|
110 *result /= N;
|
jamie@1
|
111
|
jamie@56
|
112 return XTRACT_SUCCESS;
|
jamie@1
|
113 }
|
jamie@1
|
114
|
jamie@140
|
115 int xtract_skewness(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
116 {
|
jamie@25
|
117
|
jamie@1
|
118 int n = N;
|
jamie@1
|
119
|
jamie@59
|
120 float temp = 0.f;
|
jamie@25
|
121
|
jamie@122
|
122 *result = 0.f;
|
jamie@113
|
123
|
jamie@140
|
124 while(n--)
|
jamie@140
|
125 {
|
jamie@140
|
126 temp = (data[n] - ((float *)argv)[0]) / ((float *)argv)[1];
|
jamie@140
|
127 *result += powf(temp, 3);
|
jamie@42
|
128 }
|
jamie@1
|
129
|
jamie@42
|
130 *result /= N;
|
jamie@44
|
131
|
jamie@59
|
132
|
jamie@56
|
133 return XTRACT_SUCCESS;
|
jamie@1
|
134 }
|
jamie@1
|
135
|
jamie@140
|
136 int xtract_kurtosis(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
137 {
|
jamie@25
|
138
|
jamie@1
|
139 int n = N;
|
jamie@1
|
140
|
jamie@113
|
141 float temp = 0.f;
|
jamie@113
|
142
|
jamie@122
|
143 *result = 0.f;
|
jamie@25
|
144
|
jamie@140
|
145 while(n--)
|
jamie@140
|
146 {
|
jamie@140
|
147 temp = (data[n] - ((float *)argv)[0]) / ((float *)argv)[1];
|
jamie@140
|
148 *result += powf(temp, 4);
|
jamie@42
|
149 }
|
jamie@25
|
150
|
jamie@42
|
151 *result /= N;
|
jamie@42
|
152 *result -= 3.0f;
|
jamie@44
|
153
|
jamie@56
|
154 return XTRACT_SUCCESS;
|
jamie@1
|
155 }
|
jamie@1
|
156
|
jamie@140
|
157 int xtract_spectral_centroid(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
158 {
|
jamie@25
|
159
|
jamie@37
|
160 int n = (N >> 1);
|
jamie@11
|
161
|
jamie@43
|
162 const float *freqs, *amps;
|
jamie@43
|
163 float FA = 0.f, A = 0.f;
|
jamie@11
|
164
|
jamie@52
|
165 amps = data;
|
jamie@52
|
166 freqs = data + n;
|
jamie@25
|
167
|
jamie@140
|
168 while(n--)
|
jamie@140
|
169 {
|
jamie@140
|
170 FA += freqs[n] * amps[n];
|
jamie@140
|
171 A += amps[n];
|
jamie@25
|
172 }
|
jamie@25
|
173
|
jamie@113
|
174 if(A == 0.f)
|
jamie@113
|
175 *result = 0.f;
|
jamie@113
|
176 else
|
jamie@113
|
177 *result = FA / A;
|
jamie@11
|
178
|
jamie@56
|
179 return XTRACT_SUCCESS;
|
jamie@11
|
180 }
|
jamie@11
|
181
|
jamie@140
|
182 int xtract_spectral_mean(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
183 {
|
jamie@52
|
184
|
jamie@52
|
185 return xtract_spectral_centroid(data, N, argv, result);
|
jamie@52
|
186
|
jamie@52
|
187 }
|
jamie@52
|
188
|
jamie@140
|
189 int xtract_spectral_variance(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
190 {
|
jamie@52
|
191
|
jamie@53
|
192 int m;
|
jamie@53
|
193 float A = 0.f;
|
jamie@53
|
194 const float *freqs, *amps;
|
jamie@52
|
195
|
jamie@53
|
196 m = N >> 1;
|
jamie@52
|
197
|
jamie@53
|
198 amps = data;
|
jamie@53
|
199 freqs = data + m;
|
jamie@52
|
200
|
jamie@122
|
201 *result = 0.f;
|
jamie@113
|
202
|
jamie@140
|
203 while(m--)
|
jamie@140
|
204 {
|
jamie@123
|
205 A += amps[m];
|
jamie@123
|
206 *result += powf(freqs[m] - ((float *)argv)[0], 2) * amps[m];
|
jamie@53
|
207 }
|
jamie@53
|
208
|
jamie@123
|
209 *result = *result / A;
|
jamie@52
|
210
|
jamie@56
|
211 return XTRACT_SUCCESS;
|
jamie@52
|
212 }
|
jamie@52
|
213
|
jamie@140
|
214 int xtract_spectral_standard_deviation(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
215 {
|
jamie@52
|
216
|
jamie@140
|
217 *result = sqrtf(*(float *)argv);
|
jamie@52
|
218
|
jamie@56
|
219 return XTRACT_SUCCESS;
|
jamie@52
|
220 }
|
jamie@52
|
221
|
jamie@123
|
222 /*int xtract_spectral_average_deviation(const float *data, const int N, const void *argv, float *result){
|
jamie@52
|
223
|
jamie@53
|
224 int m;
|
jamie@53
|
225 float A = 0.f;
|
jamie@53
|
226 const float *freqs, *amps;
|
jamie@52
|
227
|
jamie@53
|
228 m = N >> 1;
|
jamie@52
|
229
|
jamie@53
|
230 amps = data;
|
jamie@53
|
231 freqs = data + m;
|
jamie@52
|
232
|
jamie@122
|
233 *result = 0.f;
|
jamie@113
|
234
|
jamie@53
|
235 while(m--){
|
jamie@123
|
236 A += amps[m];
|
jamie@123
|
237 *result += fabsf((amps[m] * freqs[m]) - *(float *)argv);
|
jamie@53
|
238 }
|
jamie@53
|
239
|
jamie@53
|
240 *result /= A;
|
jamie@52
|
241
|
jamie@56
|
242 return XTRACT_SUCCESS;
|
jamie@123
|
243 }*/
|
jamie@52
|
244
|
jamie@140
|
245 int xtract_spectral_skewness(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
246 {
|
jamie@52
|
247
|
jamie@53
|
248 int m;
|
jamie@53
|
249 const float *freqs, *amps;
|
jamie@52
|
250
|
jamie@53
|
251 m = N >> 1;
|
jamie@53
|
252
|
jamie@53
|
253 amps = data;
|
jamie@53
|
254 freqs = data + m;
|
jamie@52
|
255
|
jamie@122
|
256 *result = 0.f;
|
jamie@113
|
257
|
jamie@123
|
258 while(m--)
|
jamie@123
|
259 *result += powf(freqs[m] - ((float *)argv)[0], 3) * amps[m];
|
jamie@52
|
260
|
jamie@123
|
261 *result /= powf(((float *)argv)[1], 3);
|
jamie@52
|
262
|
jamie@56
|
263 return XTRACT_SUCCESS;
|
jamie@52
|
264 }
|
jamie@52
|
265
|
jamie@140
|
266 int xtract_spectral_kurtosis(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
267 {
|
jamie@52
|
268
|
jamie@53
|
269 int m;
|
jamie@53
|
270 const float *freqs, *amps;
|
jamie@52
|
271
|
jamie@53
|
272 m = N >> 1;
|
jamie@53
|
273
|
jamie@53
|
274 amps = data;
|
jamie@53
|
275 freqs = data + m;
|
jamie@52
|
276
|
jamie@122
|
277 *result = 0.f;
|
jamie@113
|
278
|
jamie@123
|
279 while(m--)
|
jamie@123
|
280 *result += powf(freqs[m] - ((float *)argv)[0], 4) * amps[m];
|
jamie@52
|
281
|
jamie@123
|
282 *result /= powf(((float *)argv)[1], 4);
|
jamie@52
|
283 *result -= 3.0f;
|
jamie@52
|
284
|
jamie@56
|
285 return XTRACT_SUCCESS;
|
jamie@52
|
286 }
|
jamie@52
|
287
|
jamie@140
|
288 int xtract_irregularity_k(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
289 {
|
jamie@25
|
290
|
jamie@1
|
291 int n,
|
jamie@140
|
292 M = N - 1;
|
jamie@140
|
293
|
jamie@113
|
294 *result = 0.f;
|
jamie@140
|
295
|
jamie@1
|
296 for(n = 1; n < M; n++)
|
jamie@140
|
297 *result += fabsf(data[n] - (data[n-1] + data[n] + data[n+1]) / 3.f);
|
jamie@1
|
298
|
jamie@56
|
299 return XTRACT_SUCCESS;
|
jamie@1
|
300 }
|
jamie@1
|
301
|
jamie@140
|
302 int xtract_irregularity_j(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
303 {
|
jamie@25
|
304
|
jamie@1
|
305 int n = N;
|
jamie@1
|
306
|
jamie@59
|
307 double num = 0.f, den = 0.f;
|
jamie@1
|
308
|
jamie@140
|
309 while(n--)
|
jamie@140
|
310 {
|
jamie@140
|
311 num += powf(data[n] - data[n+1], 2);
|
jamie@140
|
312 den += powf(data[n], 2);
|
jamie@1
|
313 }
|
jamie@25
|
314
|
jamie@59
|
315 *result = (float)(num / den);
|
jamie@1
|
316
|
jamie@56
|
317 return XTRACT_SUCCESS;
|
jamie@1
|
318 }
|
jamie@1
|
319
|
jamie@140
|
320 int xtract_tristimulus_1(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
321 {
|
jamie@1
|
322
|
jamie@1
|
323 int n = N;
|
jamie@1
|
324
|
jamie@42
|
325 float den, p1, temp;
|
jamie@1
|
326
|
jamie@42
|
327 den = p1 = temp = 0.f;
|
jamie@1
|
328
|
jamie@140
|
329 for(n = 0; n < N; n++)
|
jamie@140
|
330 {
|
jamie@140
|
331 if((temp = data[n]))
|
jamie@140
|
332 {
|
jamie@140
|
333 den += temp;
|
jamie@140
|
334 if(!p1)
|
jamie@140
|
335 p1 = temp;
|
jamie@140
|
336 }
|
jamie@42
|
337 }
|
jamie@42
|
338
|
jamie@140
|
339 if(den == 0.f || p1 == 0.f)
|
jamie@140
|
340 {
|
jamie@113
|
341 *result = 0.f;
|
jamie@113
|
342 return XTRACT_NO_RESULT;
|
jamie@113
|
343 }
|
jamie@140
|
344 else
|
jamie@140
|
345 {
|
jamie@113
|
346 *result = p1 / den;
|
jamie@113
|
347 return XTRACT_SUCCESS;
|
jamie@113
|
348 }
|
jamie@1
|
349 }
|
jamie@1
|
350
|
jamie@140
|
351 int xtract_tristimulus_2(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
352 {
|
jamie@25
|
353
|
jamie@1
|
354 int n = N;
|
jamie@1
|
355
|
jamie@113
|
356 float den, p2, p3, p4, ps, temp;
|
jamie@1
|
357
|
jamie@113
|
358 den = p2 = p3 = p4 = ps = temp = 0.f;
|
jamie@1
|
359
|
jamie@140
|
360 for(n = 0; n < N; n++)
|
jamie@140
|
361 {
|
jamie@140
|
362 if((temp = data[n]))
|
jamie@140
|
363 {
|
jamie@140
|
364 den += temp;
|
jamie@140
|
365 if(!p2)
|
jamie@140
|
366 p2 = temp;
|
jamie@140
|
367 else if(!p3)
|
jamie@140
|
368 p3 = temp;
|
jamie@140
|
369 else if(!p4)
|
jamie@140
|
370 p4 = temp;
|
jamie@140
|
371 }
|
jamie@42
|
372 }
|
jamie@42
|
373
|
jamie@113
|
374 ps = p2 + p3 + p4;
|
jamie@25
|
375
|
jamie@140
|
376 if(den == 0.f || ps == 0.f)
|
jamie@140
|
377 {
|
jamie@113
|
378 *result = 0.f;
|
jamie@113
|
379 return XTRACT_NO_RESULT;
|
jamie@113
|
380 }
|
jamie@140
|
381 else
|
jamie@140
|
382 {
|
jamie@113
|
383 *result = ps / den;
|
jamie@113
|
384 return XTRACT_SUCCESS;
|
jamie@113
|
385 }
|
jamie@113
|
386
|
jamie@1
|
387 }
|
jamie@1
|
388
|
jamie@140
|
389 int xtract_tristimulus_3(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
390 {
|
jamie@25
|
391
|
jamie@42
|
392 int n = N, count = 0;
|
jamie@1
|
393
|
jamie@42
|
394 float den, num, temp;
|
jamie@1
|
395
|
jamie@42
|
396 den = num = temp = 0.f;
|
jamie@1
|
397
|
jamie@140
|
398 for(n = 0; n < N; n++)
|
jamie@140
|
399 {
|
jamie@140
|
400 if((temp = data[n]))
|
jamie@140
|
401 {
|
jamie@140
|
402 den += temp;
|
jamie@140
|
403 if(count >= 5)
|
jamie@140
|
404 num += temp;
|
jamie@140
|
405 count++;
|
jamie@140
|
406 }
|
jamie@42
|
407 }
|
jamie@25
|
408
|
jamie@140
|
409 if(den == 0.f || num == 0.f)
|
jamie@140
|
410 {
|
jamie@113
|
411 *result = 0.f;
|
jamie@113
|
412 return XTRACT_NO_RESULT;
|
jamie@113
|
413 }
|
jamie@140
|
414 else
|
jamie@140
|
415 {
|
jamie@113
|
416 *result = num / den;
|
jamie@113
|
417 return XTRACT_SUCCESS;
|
jamie@113
|
418 }
|
jamie@1
|
419 }
|
jamie@1
|
420
|
jamie@140
|
421 int xtract_smoothness(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
422 {
|
jamie@25
|
423
|
jamie@59
|
424 int n, M;
|
jamie@1
|
425
|
jamie@43
|
426 float *input;
|
jamie@43
|
427
|
jamie@43
|
428 input = (float *)malloc(N * sizeof(float));
|
jamie@59
|
429 memcpy(input, data, N * sizeof(float));
|
jamie@43
|
430
|
jamie@140
|
431 if (input[0] <= 0)
|
jamie@113
|
432 input[0] = XTRACT_LOG_LIMIT;
|
jamie@140
|
433 if (input[1] <= 0)
|
jamie@113
|
434 input[1] = XTRACT_LOG_LIMIT;
|
jamie@25
|
435
|
jamie@59
|
436 M = N - 1;
|
jamie@59
|
437
|
jamie@140
|
438 for(n = 1; n < M; n++)
|
jamie@140
|
439 {
|
jamie@140
|
440 if(input[n+1] <= 0)
|
jamie@113
|
441 input[n+1] = XTRACT_LOG_LIMIT;
|
jamie@140
|
442 *result += fabsf(20.f * logf(input[n]) - (20.f * logf(input[n-1]) +
|
jamie@140
|
443 20.f * logf(input[n]) + 20.f * logf(input[n+1])) / 3.f);
|
jamie@25
|
444 }
|
jamie@43
|
445
|
jamie@43
|
446 free(input);
|
jamie@44
|
447
|
jamie@56
|
448 return XTRACT_SUCCESS;
|
jamie@1
|
449 }
|
jamie@1
|
450
|
jamie@140
|
451 int xtract_spread(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
452 {
|
jamie@1
|
453
|
jamie@140
|
454 return xtract_spectral_variance(data, N, argv, result);
|
jamie@1
|
455 }
|
jamie@1
|
456
|
jamie@140
|
457 int xtract_zcr(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
458 {
|
jamie@1
|
459
|
jamie@1
|
460 int n = N;
|
jamie@25
|
461
|
jamie@1
|
462 for(n = 1; n < N; n++)
|
jamie@140
|
463 if(data[n] * data[n-1] < 0) (*result)++;
|
jamie@25
|
464
|
jamie@113
|
465 *result /= (float)N;
|
jamie@25
|
466
|
jamie@56
|
467 return XTRACT_SUCCESS;
|
jamie@1
|
468 }
|
jamie@1
|
469
|
jamie@140
|
470 int xtract_rolloff(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
471 {
|
jamie@1
|
472
|
jamie@1
|
473 int n = N;
|
jamie@55
|
474 float pivot, temp, percentile;
|
jamie@42
|
475
|
jamie@42
|
476 pivot = temp = 0.f;
|
jamie@55
|
477 percentile = ((float *)argv)[1];
|
jamie@25
|
478
|
jamie@140
|
479 while(n--) pivot += data[n];
|
jamie@25
|
480
|
jamie@55
|
481 pivot *= percentile / 100.f;
|
jamie@25
|
482
|
jamie@42
|
483 for(n = 0; temp < pivot; n++)
|
jamie@140
|
484 temp += data[n];
|
jamie@1
|
485
|
jamie@55
|
486 *result = n * ((float *)argv)[0];
|
jamie@55
|
487 /* *result = (n / (float)N) * (((float *)argv)[1] * .5); */
|
jamie@25
|
488
|
jamie@56
|
489 return XTRACT_SUCCESS;
|
jamie@1
|
490 }
|
jamie@1
|
491
|
jamie@140
|
492 int xtract_loudness(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
493 {
|
jamie@25
|
494
|
jamie@47
|
495 int n = N, rv;
|
jamie@25
|
496
|
jamie@113
|
497 *result = 0.f;
|
jamie@113
|
498
|
jamie@140
|
499 if(n > XTRACT_BARK_BANDS)
|
jamie@140
|
500 {
|
jamie@140
|
501 n = XTRACT_BARK_BANDS;
|
jamie@140
|
502 rv = XTRACT_BAD_VECTOR_SIZE;
|
jamie@93
|
503 }
|
jamie@47
|
504 else
|
jamie@140
|
505 rv = XTRACT_SUCCESS;
|
jamie@1
|
506
|
jamie@1
|
507 while(n--)
|
jamie@140
|
508 *result += powf(data[n], 0.23);
|
jamie@38
|
509
|
jamie@47
|
510 return rv;
|
jamie@1
|
511 }
|
jamie@1
|
512
|
jamie@140
|
513 int xtract_flatness(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
514 {
|
jamie@1
|
515
|
jamie@113
|
516 int n, count, denormal_found;
|
jamie@1
|
517
|
jamie@140
|
518 double num, den, temp;
|
jamie@25
|
519
|
jamie@113
|
520 num = 1.f;
|
jamie@113
|
521 den = temp = 0.f;
|
jamie@43
|
522
|
jamie@113
|
523 denormal_found = 0;
|
jamie@113
|
524 count = 0;
|
jamie@113
|
525
|
jamie@140
|
526 for(n = 0; n < N; n++)
|
jamie@140
|
527 {
|
jamie@140
|
528 if((temp = data[n]) != 0.f)
|
jamie@140
|
529 {
|
jamie@140
|
530 if (xtract_is_denormal(num))
|
jamie@140
|
531 {
|
jamie@113
|
532 denormal_found = 1;
|
jamie@113
|
533 break;
|
jamie@113
|
534 }
|
jamie@113
|
535 num *= temp;
|
jamie@113
|
536 den += temp;
|
jamie@113
|
537 count++;
|
jamie@113
|
538 }
|
jamie@1
|
539 }
|
jamie@44
|
540
|
jamie@140
|
541 if(!count)
|
jamie@140
|
542 {
|
jamie@113
|
543 *result = 0.f;
|
jamie@113
|
544 return XTRACT_NO_RESULT;
|
jamie@113
|
545 }
|
jamie@25
|
546
|
jamie@113
|
547 num = powf(num, 1.f / (float)N);
|
jamie@113
|
548 den /= (float)N;
|
jamie@44
|
549
|
jamie@44
|
550
|
jamie@113
|
551 *result = (float) (num / den);
|
jamie@113
|
552
|
jamie@113
|
553 if(denormal_found)
|
jamie@113
|
554 return XTRACT_DENORMAL_FOUND;
|
jamie@113
|
555 else
|
jamie@113
|
556 return XTRACT_SUCCESS;
|
jamie@140
|
557
|
jamie@113
|
558 }
|
jamie@113
|
559
|
jamie@140
|
560 int xtract_flatness_db(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
561 {
|
jamie@113
|
562
|
jamie@115
|
563 float flatness;
|
jamie@113
|
564
|
jamie@115
|
565 flatness = *(float *)argv;
|
jamie@113
|
566
|
jamie@140
|
567 if (flatness <= 0)
|
jamie@115
|
568 flatness = XTRACT_LOG_LIMIT;
|
jamie@113
|
569
|
jamie@115
|
570 *result = 10 * log10f(flatness);
|
jamie@25
|
571
|
jamie@56
|
572 return XTRACT_SUCCESS;
|
jamie@44
|
573
|
jamie@1
|
574 }
|
jamie@1
|
575
|
jamie@140
|
576 int xtract_tonality(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
577 {
|
jamie@25
|
578
|
jamie@113
|
579 float sfmdb;
|
jamie@25
|
580
|
jamie@113
|
581 sfmdb = *(float *)argv;
|
jamie@1
|
582
|
jamie@113
|
583 *result = XTRACT_MIN(sfmdb / -60.f, 1);
|
jamie@25
|
584
|
jamie@56
|
585 return XTRACT_SUCCESS;
|
jamie@1
|
586 }
|
jamie@1
|
587
|
jamie@140
|
588 int xtract_crest(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
589 {
|
jamie@25
|
590
|
jamie@140
|
591 float max, mean;
|
jamie@45
|
592
|
jamie@45
|
593 max = mean = 0.f;
|
jamie@45
|
594
|
jamie@45
|
595 max = *(float *)argv;
|
jamie@45
|
596 mean = *((float *)argv+1);
|
jamie@45
|
597
|
jamie@45
|
598 *result = max / mean;
|
jamie@45
|
599
|
jamie@56
|
600 return XTRACT_SUCCESS;
|
jamie@25
|
601
|
jamie@1
|
602 }
|
jamie@1
|
603
|
jamie@140
|
604 int xtract_noisiness(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
605 {
|
jamie@25
|
606
|
jamie@45
|
607 float h, i, p; /*harmonics, inharmonics, partials */
|
jamie@45
|
608
|
jamie@45
|
609 i = p = h = 0.f;
|
jamie@45
|
610
|
jamie@45
|
611 h = *(float *)argv;
|
jamie@45
|
612 p = *((float *)argv+1);
|
jamie@45
|
613
|
jamie@45
|
614 i = p - h;
|
jamie@45
|
615
|
jamie@45
|
616 *result = i / p;
|
jamie@45
|
617
|
jamie@56
|
618 return XTRACT_SUCCESS;
|
jamie@25
|
619
|
jamie@1
|
620 }
|
jamie@2
|
621
|
jamie@140
|
622 int xtract_rms_amplitude(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
623 {
|
jamie@1
|
624
|
jamie@1
|
625 int n = N;
|
jamie@1
|
626
|
jamie@113
|
627 *result = 0.f;
|
jamie@113
|
628
|
jamie@56
|
629 while(n--) *result += XTRACT_SQ(data[n]);
|
jamie@1
|
630
|
jamie@113
|
631 *result = sqrtf(*result / (float)N);
|
jamie@25
|
632
|
jamie@56
|
633 return XTRACT_SUCCESS;
|
jamie@1
|
634 }
|
jamie@1
|
635
|
jamie@140
|
636 int xtract_spectral_inharmonicity(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
637 {
|
jamie@1
|
638
|
jamie@41
|
639 int n = N >> 1;
|
jamie@140
|
640 float num = 0.f, den = 0.f, fund;
|
jamie@43
|
641 const float *freqs, *amps;
|
jamie@1
|
642
|
jamie@41
|
643 fund = *(float *)argv;
|
jamie@52
|
644 amps = data;
|
jamie@52
|
645 freqs = data + n;
|
jamie@25
|
646
|
jamie@140
|
647 while(n--)
|
jamie@140
|
648 {
|
jamie@140
|
649 if(amps[n])
|
jamie@140
|
650 {
|
jamie@140
|
651 num += fabsf(freqs[n] - n * fund) * XTRACT_SQ(amps[n]);
|
jamie@140
|
652 den += XTRACT_SQ(amps[n]);
|
jamie@140
|
653 }
|
jamie@1
|
654 }
|
jamie@1
|
655
|
jamie@140
|
656 *result = (2 * num) / (fund * den);
|
jamie@25
|
657
|
jamie@56
|
658 return XTRACT_SUCCESS;
|
jamie@1
|
659 }
|
jamie@1
|
660
|
jamie@1
|
661
|
jamie@140
|
662 int xtract_power(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
663 {
|
jamie@1
|
664
|
jamie@56
|
665 return XTRACT_FEATURE_NOT_IMPLEMENTED;
|
jamie@25
|
666
|
jamie@1
|
667 }
|
jamie@1
|
668
|
jamie@140
|
669 int xtract_odd_even_ratio(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
670 {
|
jamie@1
|
671
|
jamie@43
|
672 int M = (N >> 1), n;
|
jamie@1
|
673
|
jamie@113
|
674 float odd = 0.f, even = 0.f, temp;
|
jamie@44
|
675
|
jamie@140
|
676 for(n = 0; n < M; n++)
|
jamie@140
|
677 {
|
jamie@140
|
678 if((temp = data[n]))
|
jamie@140
|
679 {
|
jamie@140
|
680 if(XTRACT_IS_ODD(n))
|
jamie@140
|
681 {
|
jamie@140
|
682 odd += temp;
|
jamie@140
|
683 }
|
jamie@140
|
684 else
|
jamie@140
|
685 {
|
jamie@140
|
686 even += temp;
|
jamie@140
|
687 }
|
jamie@140
|
688 }
|
jamie@1
|
689 }
|
jamie@1
|
690
|
jamie@140
|
691 if(odd == 0.f || even == 0.f)
|
jamie@140
|
692 {
|
jamie@113
|
693 *result = 0.f;
|
jamie@113
|
694 return XTRACT_NO_RESULT;
|
jamie@113
|
695 }
|
jamie@140
|
696 else
|
jamie@140
|
697 {
|
jamie@113
|
698 *result = odd / even;
|
jamie@113
|
699 return XTRACT_SUCCESS;
|
jamie@113
|
700 }
|
jamie@1
|
701 }
|
jamie@1
|
702
|
jamie@140
|
703 int xtract_sharpness(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
704 {
|
jamie@1
|
705
|
jamie@48
|
706 int n = N, rv;
|
jamie@113
|
707 float sl, g; /* sl = specific loudness */
|
jamie@140
|
708 double temp;
|
jamie@48
|
709
|
jamie@113
|
710 sl = g = 0.f;
|
jamie@113
|
711 temp = 0.f;
|
jamie@48
|
712
|
jamie@140
|
713 if(n > XTRACT_BARK_BANDS)
|
jamie@140
|
714 rv = XTRACT_BAD_VECTOR_SIZE;
|
jamie@48
|
715 else
|
jamie@140
|
716 rv = XTRACT_SUCCESS;
|
jamie@48
|
717
|
jamie@48
|
718
|
jamie@140
|
719 while(n--)
|
jamie@140
|
720 {
|
jamie@140
|
721 sl = powf(data[n], 0.23);
|
jamie@140
|
722 g = (n < 15 ? 1.f : 0.066 * expf(0.171 * n));
|
jamie@140
|
723 temp += n * g * sl;
|
jamie@48
|
724 }
|
jamie@48
|
725
|
jamie@113
|
726 temp = 0.11 * temp / (float)N;
|
jamie@113
|
727 *result = (float)temp;
|
jamie@48
|
728
|
jamie@48
|
729 return rv;
|
jamie@25
|
730
|
jamie@1
|
731 }
|
jamie@1
|
732
|
jamie@140
|
733 int xtract_spectral_slope(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
734 {
|
jamie@1
|
735
|
jamie@140
|
736 const float *freqs, *amps;
|
jamie@48
|
737 float f, a,
|
jamie@140
|
738 F, A, FA, FXTRACT_SQ; /* sums of freqs, amps, freq * amps, freq squared */
|
jamie@140
|
739 int n, M;
|
jamie@140
|
740
|
jamie@56
|
741 F = A = FA = FXTRACT_SQ = 0.f;
|
jamie@48
|
742 n = M = N >> 1;
|
jamie@48
|
743
|
jamie@52
|
744 amps = data;
|
jamie@52
|
745 freqs = data + n;
|
jamie@48
|
746
|
jamie@140
|
747 while(n--)
|
jamie@140
|
748 {
|
jamie@140
|
749 f = freqs[n];
|
jamie@140
|
750 a = amps[n];
|
jamie@140
|
751 F += f;
|
jamie@140
|
752 A += a;
|
jamie@140
|
753 FA += f * a;
|
jamie@140
|
754 FXTRACT_SQ += f * f;
|
jamie@48
|
755 }
|
jamie@48
|
756
|
jamie@140
|
757 *result = (1.f / A) * (M * FA - F * A) / (M * FXTRACT_SQ - F * F);
|
jamie@48
|
758
|
jamie@56
|
759 return XTRACT_SUCCESS;
|
jamie@25
|
760
|
jamie@1
|
761 }
|
jamie@1
|
762
|
jamie@140
|
763 int xtract_lowest_value(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
764 {
|
jamie@25
|
765
|
jamie@45
|
766 int n = N;
|
jamie@45
|
767 float temp;
|
jamie@45
|
768
|
jamie@46
|
769 *result = data[--n];
|
jamie@45
|
770
|
jamie@140
|
771 while(n--)
|
jamie@140
|
772 {
|
jamie@140
|
773 if((temp = data[n]) > *(float *)argv)
|
jamie@140
|
774 *result = XTRACT_MIN(*result, data[n]);
|
jamie@45
|
775 }
|
jamie@45
|
776
|
jamie@56
|
777 return XTRACT_SUCCESS;
|
jamie@45
|
778 }
|
jamie@45
|
779
|
jamie@140
|
780 int xtract_highest_value(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
781 {
|
jamie@45
|
782
|
jamie@1
|
783 int n = N;
|
jamie@1
|
784
|
jamie@46
|
785 *result = data[--n];
|
jamie@44
|
786
|
jamie@140
|
787 while(n--)
|
jamie@140
|
788 *result = XTRACT_MAX(*result, data[n]);
|
jamie@44
|
789
|
jamie@56
|
790 return XTRACT_SUCCESS;
|
jamie@1
|
791 }
|
jamie@1
|
792
|
jamie@45
|
793
|
jamie@140
|
794 int xtract_sum(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
795 {
|
jamie@45
|
796
|
jamie@45
|
797 int n = N;
|
jamie@45
|
798
|
jamie@113
|
799 *result = 0.f;
|
jamie@113
|
800
|
jamie@45
|
801 while(n--)
|
jamie@140
|
802 *result += *data++;
|
jamie@45
|
803
|
jamie@56
|
804 return XTRACT_SUCCESS;
|
jamie@45
|
805
|
jamie@45
|
806 }
|
jamie@45
|
807
|
jamie@140
|
808 int xtract_nonzero_count(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
809 {
|
jamie@59
|
810
|
jamie@59
|
811 int n = N;
|
jamie@140
|
812
|
jamie@122
|
813 *result = 0.f;
|
jamie@59
|
814
|
jamie@59
|
815 while(n--)
|
jamie@140
|
816 *result += (*data++ ? 1 : 0);
|
jamie@59
|
817
|
jamie@59
|
818 return XTRACT_SUCCESS;
|
jamie@59
|
819
|
jamie@59
|
820 }
|
jamie@59
|
821
|
jamie@140
|
822 int xtract_hps(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
823 {
|
jamie@1
|
824
|
jamie@1
|
825 int n = N, M, m, l, peak_index, position1_lwr;
|
jamie@140
|
826 float *coeffs2, *coeffs3, *product, L,
|
jamie@140
|
827 largest1_lwr, peak, ratio1, sr;
|
jamie@1
|
828
|
jamie@25
|
829 sr = *(float*)argv;
|
jamie@78
|
830 if(sr == 0)
|
jamie@140
|
831 sr = 44100.f;
|
jamie@25
|
832
|
jamie@1
|
833 coeffs2 = (float *)malloc(N * sizeof(float));
|
jamie@1
|
834 coeffs3 = (float *)malloc(N * sizeof(float));
|
jamie@1
|
835 product = (float *)malloc(N * sizeof(float));
|
jamie@25
|
836
|
jamie@1
|
837 while(n--) coeffs2[n] = coeffs3[n] = 1;
|
jamie@1
|
838
|
jamie@1
|
839 M = N >> 1;
|
jamie@113
|
840 L = N / 3.f;
|
jamie@1
|
841
|
jamie@140
|
842 while(M--)
|
jamie@140
|
843 {
|
jamie@140
|
844 m = M << 1;
|
jamie@140
|
845 coeffs2[M] = (data[m] + data[m+1]) * 0.5f;
|
jamie@1
|
846
|
jamie@140
|
847 if(M < L)
|
jamie@140
|
848 {
|
jamie@140
|
849 l = M * 3;
|
jamie@140
|
850 coeffs3[M] = (data[l] + data[l+1] + data[l+2]) / 3.f;
|
jamie@140
|
851 }
|
jamie@1
|
852 }
|
jamie@25
|
853
|
jamie@1
|
854 peak_index = peak = 0;
|
jamie@25
|
855
|
jamie@140
|
856 for(n = 1; n < N; n++)
|
jamie@140
|
857 {
|
jamie@140
|
858 product[n] = data[n] * coeffs2[n] * coeffs3[n];
|
jamie@140
|
859 if(product[n] > peak)
|
jamie@140
|
860 {
|
jamie@140
|
861 peak_index = n;
|
jamie@140
|
862 peak = product[n];
|
jamie@140
|
863 }
|
jamie@1
|
864 }
|
jamie@1
|
865
|
jamie@1
|
866 largest1_lwr = position1_lwr = 0;
|
jamie@1
|
867
|
jamie@140
|
868 for(n = 0; n < N; n++)
|
jamie@140
|
869 {
|
jamie@140
|
870 if(data[n] > largest1_lwr && n != peak_index)
|
jamie@140
|
871 {
|
jamie@140
|
872 largest1_lwr = data[n];
|
jamie@140
|
873 position1_lwr = n;
|
jamie@140
|
874 }
|
jamie@1
|
875 }
|
jamie@1
|
876
|
jamie@1
|
877 ratio1 = data[position1_lwr] / data[peak_index];
|
jamie@1
|
878
|
jamie@140
|
879 if(position1_lwr > peak_index * 0.4 && position1_lwr <
|
jamie@140
|
880 peak_index * 0.6 && ratio1 > 0.1)
|
jamie@140
|
881 peak_index = position1_lwr;
|
jamie@1
|
882
|
jamie@140
|
883 *result = sr / (float)peak_index;
|
jamie@25
|
884
|
jamie@1
|
885 free(coeffs2);
|
jamie@1
|
886 free(coeffs3);
|
jamie@1
|
887 free(product);
|
jamie@25
|
888
|
jamie@56
|
889 return XTRACT_SUCCESS;
|
jamie@1
|
890 }
|
jamie@5
|
891
|
jamie@5
|
892
|
jamie@140
|
893 int xtract_f0(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
894 {
|
jamie@5
|
895
|
jamie@78
|
896 int M, tau, n;
|
jamie@78
|
897 float sr;
|
jamie@43
|
898 size_t bytes;
|
jamie@140
|
899 float f0, err_tau_1, err_tau_x, array_max,
|
jamie@140
|
900 threshold_peak, threshold_centre,
|
jamie@140
|
901 *input;
|
jamie@22
|
902
|
jamie@25
|
903 sr = *(float *)argv;
|
jamie@78
|
904 if(sr == 0)
|
jamie@140
|
905 sr = 44100.f;
|
jamie@43
|
906
|
jamie@43
|
907 input = (float *)malloc(bytes = N * sizeof(float));
|
jamie@43
|
908 input = memcpy(input, data, bytes);
|
jamie@25
|
909 /* threshold_peak = *((float *)argv+1);
|
jamie@140
|
910 threshold_centre = *((float *)argv+2);
|
jamie@140
|
911 printf("peak: %.2f\tcentre: %.2f\n", threshold_peak, threshold_centre);*/
|
jamie@25
|
912 /* add temporary dynamic control over thresholds to test clipping effects */
|
jamie@22
|
913
|
jamie@25
|
914 /* FIX: tweak and make into macros */
|
jamie@25
|
915 threshold_peak = .8;
|
jamie@25
|
916 threshold_centre = .3;
|
jamie@25
|
917 M = N >> 1;
|
jamie@25
|
918 err_tau_1 = 0;
|
jamie@25
|
919 array_max = 0;
|
jamie@25
|
920
|
jamie@25
|
921 /* Find the array max */
|
jamie@140
|
922 for(n = 0; n < N; n++)
|
jamie@140
|
923 {
|
jamie@140
|
924 if (input[n] > array_max)
|
jamie@140
|
925 array_max = input[n];
|
jamie@12
|
926 }
|
jamie@25
|
927
|
jamie@25
|
928 threshold_peak *= array_max;
|
jamie@25
|
929
|
jamie@25
|
930 /* peak clip */
|
jamie@140
|
931 for(n = 0; n < N; n++)
|
jamie@140
|
932 {
|
jamie@140
|
933 if(input[n] > threshold_peak)
|
jamie@140
|
934 input[n] = threshold_peak;
|
jamie@140
|
935 else if(input[n] < -threshold_peak)
|
jamie@140
|
936 input[n] = -threshold_peak;
|
jamie@25
|
937 }
|
jamie@25
|
938
|
jamie@25
|
939 threshold_centre *= array_max;
|
jamie@25
|
940
|
jamie@25
|
941 /* Centre clip */
|
jamie@140
|
942 for(n = 0; n < N; n++)
|
jamie@140
|
943 {
|
jamie@140
|
944 if (input[n] < threshold_centre)
|
jamie@140
|
945 input[n] = 0;
|
jamie@140
|
946 else
|
jamie@140
|
947 input[n] -= threshold_centre;
|
jamie@25
|
948 }
|
jamie@25
|
949
|
jamie@25
|
950 /* Estimate fundamental freq */
|
jamie@25
|
951 for (n = 1; n < M; n++)
|
jamie@140
|
952 err_tau_1 = err_tau_1 + fabsf(input[n] - input[n+1]);
|
jamie@140
|
953 /* FIX: this doesn't pose too much load if it returns 'early', but if it can't find f0, load can be significant for larger block sizes M^2 iterations! */
|
jamie@140
|
954 for (tau = 2; tau < M; tau++)
|
jamie@140
|
955 {
|
jamie@140
|
956 err_tau_x = 0;
|
jamie@140
|
957 for (n = 1; n < M; n++)
|
jamie@140
|
958 {
|
jamie@140
|
959 err_tau_x = err_tau_x + fabsf(input[n] - input[n+tau]);
|
jamie@140
|
960 }
|
jamie@140
|
961 if (err_tau_x < err_tau_1)
|
jamie@140
|
962 {
|
jamie@140
|
963 f0 = sr / (tau + (err_tau_x / err_tau_1));
|
jamie@140
|
964 *result = f0;
|
jamie@140
|
965 free(input);
|
jamie@140
|
966 return XTRACT_SUCCESS;
|
jamie@140
|
967 }
|
jamie@25
|
968 }
|
jamie@43
|
969 *result = -0;
|
jamie@43
|
970 free(input);
|
jamie@56
|
971 return XTRACT_NO_RESULT;
|
jamie@5
|
972 }
|
jamie@43
|
973
|
jamie@140
|
974 int xtract_failsafe_f0(const float *data, const int N, const void *argv, float *result)
|
jamie@140
|
975 {
|
jamie@44
|
976
|
jamie@59
|
977 float *spectrum = NULL, argf[2], *peaks = NULL, return_code, sr;
|
jamie@44
|
978
|
jamie@43
|
979 return_code = xtract_f0(data, N, argv, result);
|
jamie@44
|
980
|
jamie@140
|
981 if(return_code == XTRACT_NO_RESULT)
|
jamie@140
|
982 {
|
jamie@44
|
983
|
jamie@140
|
984 sr = *(float *)argv;
|
jamie@140
|
985 if(sr == 0)
|
jamie@140
|
986 sr = 44100.f;
|
jamie@140
|
987 spectrum = (float *)malloc(N * sizeof(float));
|
jamie@140
|
988 peaks = (float *)malloc(N * sizeof(float));
|
jamie@140
|
989 argf[0] = sr;
|
jamie@140
|
990 argf[1] = XTRACT_MAGNITUDE_SPECTRUM;
|
jamie@140
|
991 xtract_spectrum(data, N, argf, spectrum);
|
jamie@140
|
992 argf[1] = 10.f;
|
jamie@140
|
993 xtract_peak_spectrum(spectrum, N >> 1, argf, peaks);
|
jamie@140
|
994 argf[0] = 0.f;
|
jamie@140
|
995 xtract_lowest_value(peaks+(N >> 1), N >> 1, argf, result);
|
jamie@44
|
996
|
jamie@140
|
997 free(spectrum);
|
jamie@140
|
998 free(peaks);
|
jamie@43
|
999 }
|
jamie@43
|
1000
|
jamie@56
|
1001 return XTRACT_SUCCESS;
|
jamie@43
|
1002
|
jamie@43
|
1003 }
|
jamie@44
|
1004
|