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