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@1
|
414 int n = N;
|
jamie@1
|
415
|
jamie@83
|
416 float num = 0.f, den = 0.f, temp = 0.f;
|
jamie@83
|
417
|
jamie@83
|
418 if(argv == NULL)
|
jamie@83
|
419 return XTRACT_BAD_ARGV;
|
jamie@1
|
420
|
jamie@1
|
421 while(n--){
|
jamie@48
|
422 temp = n - *(float *)argv;
|
jamie@56
|
423 num += XTRACT_SQ(temp) * data[n];
|
jamie@25
|
424 den += data[n];
|
jamie@1
|
425 }
|
jamie@1
|
426
|
jamie@117
|
427 /* FIX: spectral spread is mathematically equivalent to spectral variance --
|
jamie@117
|
428 * here we are computing the spectral standard deviation */
|
jamie@113
|
429 *result = sqrtf(num / den);
|
jamie@25
|
430
|
jamie@56
|
431 return XTRACT_SUCCESS;
|
jamie@1
|
432 }
|
jamie@1
|
433
|
jamie@43
|
434 int xtract_zcr(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
435
|
jamie@1
|
436 int n = N;
|
jamie@25
|
437
|
jamie@1
|
438 for(n = 1; n < N; n++)
|
jamie@25
|
439 if(data[n] * data[n-1] < 0) (*result)++;
|
jamie@25
|
440
|
jamie@113
|
441 *result /= (float)N;
|
jamie@25
|
442
|
jamie@56
|
443 return XTRACT_SUCCESS;
|
jamie@1
|
444 }
|
jamie@1
|
445
|
jamie@43
|
446 int xtract_rolloff(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
447
|
jamie@1
|
448 int n = N;
|
jamie@55
|
449 float pivot, temp, percentile;
|
jamie@42
|
450
|
jamie@42
|
451 pivot = temp = 0.f;
|
jamie@55
|
452 percentile = ((float *)argv)[1];
|
jamie@25
|
453
|
jamie@1
|
454 while(n--) pivot += data[n];
|
jamie@25
|
455
|
jamie@55
|
456 pivot *= percentile / 100.f;
|
jamie@25
|
457
|
jamie@42
|
458 for(n = 0; temp < pivot; n++)
|
jamie@42
|
459 temp += data[n];
|
jamie@1
|
460
|
jamie@55
|
461 *result = n * ((float *)argv)[0];
|
jamie@55
|
462 /* *result = (n / (float)N) * (((float *)argv)[1] * .5); */
|
jamie@25
|
463
|
jamie@56
|
464 return XTRACT_SUCCESS;
|
jamie@1
|
465 }
|
jamie@1
|
466
|
jamie@43
|
467 int xtract_loudness(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
468
|
jamie@47
|
469 int n = N, rv;
|
jamie@25
|
470
|
jamie@113
|
471 *result = 0.f;
|
jamie@113
|
472
|
jamie@93
|
473 if(n > XTRACT_BARK_BANDS){
|
jamie@93
|
474 n = XTRACT_BARK_BANDS;
|
jamie@56
|
475 rv = XTRACT_BAD_VECTOR_SIZE;
|
jamie@93
|
476 }
|
jamie@47
|
477 else
|
jamie@56
|
478 rv = XTRACT_SUCCESS;
|
jamie@1
|
479
|
jamie@1
|
480 while(n--)
|
jamie@59
|
481 *result += powf(data[n], 0.23);
|
jamie@38
|
482
|
jamie@47
|
483 return rv;
|
jamie@1
|
484 }
|
jamie@1
|
485
|
jamie@43
|
486 int xtract_flatness(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
487
|
jamie@113
|
488 int n, count, denormal_found;
|
jamie@1
|
489
|
jamie@44
|
490 double num, den, temp;
|
jamie@25
|
491
|
jamie@113
|
492 num = 1.f;
|
jamie@113
|
493 den = temp = 0.f;
|
jamie@43
|
494
|
jamie@113
|
495 denormal_found = 0;
|
jamie@113
|
496 count = 0;
|
jamie@113
|
497
|
jamie@113
|
498 for(n = 0; n < N; n++){
|
jamie@113
|
499 if((temp = data[n]) != 0.f) {
|
jamie@113
|
500 if (xtract_is_denormal(num)){
|
jamie@113
|
501 denormal_found = 1;
|
jamie@113
|
502 break;
|
jamie@113
|
503 }
|
jamie@113
|
504 num *= temp;
|
jamie@113
|
505 den += temp;
|
jamie@113
|
506 count++;
|
jamie@113
|
507 }
|
jamie@1
|
508 }
|
jamie@44
|
509
|
jamie@113
|
510 if(!count){
|
jamie@113
|
511 *result = 0.f;
|
jamie@113
|
512 return XTRACT_NO_RESULT;
|
jamie@113
|
513 }
|
jamie@25
|
514
|
jamie@113
|
515 num = powf(num, 1.f / (float)N);
|
jamie@113
|
516 den /= (float)N;
|
jamie@44
|
517
|
jamie@44
|
518
|
jamie@113
|
519 *result = (float) (num / den);
|
jamie@113
|
520
|
jamie@113
|
521 if(denormal_found)
|
jamie@113
|
522 return XTRACT_DENORMAL_FOUND;
|
jamie@113
|
523 else
|
jamie@113
|
524 return XTRACT_SUCCESS;
|
jamie@113
|
525
|
jamie@113
|
526 }
|
jamie@113
|
527
|
jamie@113
|
528 int xtract_flatness_db(const float *data, const int N, const void *argv, float *result){
|
jamie@113
|
529
|
jamie@115
|
530 float flatness;
|
jamie@113
|
531
|
jamie@115
|
532 flatness = *(float *)argv;
|
jamie@113
|
533
|
jamie@115
|
534 if (flatness <= 0)
|
jamie@115
|
535 flatness = XTRACT_LOG_LIMIT;
|
jamie@113
|
536
|
jamie@115
|
537 *result = 10 * log10f(flatness);
|
jamie@25
|
538
|
jamie@56
|
539 return XTRACT_SUCCESS;
|
jamie@44
|
540
|
jamie@1
|
541 }
|
jamie@1
|
542
|
jamie@43
|
543 int xtract_tonality(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
544
|
jamie@113
|
545 float sfmdb;
|
jamie@25
|
546
|
jamie@113
|
547 sfmdb = *(float *)argv;
|
jamie@1
|
548
|
jamie@113
|
549 *result = XTRACT_MIN(sfmdb / -60.f, 1);
|
jamie@25
|
550
|
jamie@56
|
551 return XTRACT_SUCCESS;
|
jamie@1
|
552 }
|
jamie@1
|
553
|
jamie@43
|
554 int xtract_crest(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
555
|
jamie@45
|
556 float max, mean;
|
jamie@45
|
557
|
jamie@45
|
558 max = mean = 0.f;
|
jamie@45
|
559
|
jamie@45
|
560 max = *(float *)argv;
|
jamie@45
|
561 mean = *((float *)argv+1);
|
jamie@45
|
562
|
jamie@45
|
563 *result = max / mean;
|
jamie@45
|
564
|
jamie@56
|
565 return XTRACT_SUCCESS;
|
jamie@25
|
566
|
jamie@1
|
567 }
|
jamie@1
|
568
|
jamie@43
|
569 int xtract_noisiness(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
570
|
jamie@45
|
571 float h, i, p; /*harmonics, inharmonics, partials */
|
jamie@45
|
572
|
jamie@45
|
573 i = p = h = 0.f;
|
jamie@45
|
574
|
jamie@45
|
575 h = *(float *)argv;
|
jamie@45
|
576 p = *((float *)argv+1);
|
jamie@45
|
577
|
jamie@45
|
578 i = p - h;
|
jamie@45
|
579
|
jamie@45
|
580 *result = i / p;
|
jamie@45
|
581
|
jamie@56
|
582 return XTRACT_SUCCESS;
|
jamie@25
|
583
|
jamie@1
|
584 }
|
jamie@2
|
585
|
jamie@43
|
586 int xtract_rms_amplitude(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
587
|
jamie@1
|
588 int n = N;
|
jamie@1
|
589
|
jamie@113
|
590 *result = 0.f;
|
jamie@113
|
591
|
jamie@56
|
592 while(n--) *result += XTRACT_SQ(data[n]);
|
jamie@1
|
593
|
jamie@113
|
594 *result = sqrtf(*result / (float)N);
|
jamie@25
|
595
|
jamie@56
|
596 return XTRACT_SUCCESS;
|
jamie@1
|
597 }
|
jamie@1
|
598
|
jamie@52
|
599 int xtract_spectral_inharmonicity(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
600
|
jamie@41
|
601 int n = N >> 1;
|
jamie@43
|
602 float num = 0.f, den = 0.f, fund;
|
jamie@43
|
603 const float *freqs, *amps;
|
jamie@1
|
604
|
jamie@41
|
605 fund = *(float *)argv;
|
jamie@52
|
606 amps = data;
|
jamie@52
|
607 freqs = data + n;
|
jamie@25
|
608
|
jamie@1
|
609 while(n--){
|
jamie@59
|
610 if(amps[n]){
|
jamie@113
|
611 num += fabsf(freqs[n] - n * fund) * XTRACT_SQ(amps[n]);
|
jamie@59
|
612 den += XTRACT_SQ(amps[n]);
|
jamie@59
|
613 }
|
jamie@1
|
614 }
|
jamie@1
|
615
|
jamie@41
|
616 *result = (2 * num) / (fund * den);
|
jamie@25
|
617
|
jamie@56
|
618 return XTRACT_SUCCESS;
|
jamie@1
|
619 }
|
jamie@1
|
620
|
jamie@1
|
621
|
jamie@43
|
622 int xtract_power(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
623
|
jamie@56
|
624 return XTRACT_FEATURE_NOT_IMPLEMENTED;
|
jamie@25
|
625
|
jamie@1
|
626 }
|
jamie@1
|
627
|
jamie@43
|
628 int xtract_odd_even_ratio(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
629
|
jamie@43
|
630 int M = (N >> 1), n;
|
jamie@1
|
631
|
jamie@113
|
632 float odd = 0.f, even = 0.f, temp;
|
jamie@44
|
633
|
jamie@43
|
634 for(n = 0; n < M; n++){
|
jamie@43
|
635 if((temp = data[n])){
|
jamie@59
|
636 if(XTRACT_IS_ODD(n)){
|
jamie@113
|
637 odd += temp;
|
jamie@43
|
638 }
|
jamie@43
|
639 else{
|
jamie@113
|
640 even += temp;
|
jamie@43
|
641 }
|
jamie@43
|
642 }
|
jamie@1
|
643 }
|
jamie@1
|
644
|
jamie@113
|
645 if(odd == 0.f || even == 0.f){
|
jamie@113
|
646 *result = 0.f;
|
jamie@113
|
647 return XTRACT_NO_RESULT;
|
jamie@113
|
648 }
|
jamie@113
|
649 else {
|
jamie@113
|
650 *result = odd / even;
|
jamie@113
|
651 return XTRACT_SUCCESS;
|
jamie@113
|
652 }
|
jamie@1
|
653 }
|
jamie@1
|
654
|
jamie@43
|
655 int xtract_sharpness(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
656
|
jamie@48
|
657 int n = N, rv;
|
jamie@113
|
658 float sl, g; /* sl = specific loudness */
|
jamie@113
|
659 double temp;
|
jamie@48
|
660
|
jamie@113
|
661 sl = g = 0.f;
|
jamie@113
|
662 temp = 0.f;
|
jamie@48
|
663
|
jamie@56
|
664 if(n > XTRACT_BARK_BANDS)
|
jamie@56
|
665 rv = XTRACT_BAD_VECTOR_SIZE;
|
jamie@48
|
666 else
|
jamie@56
|
667 rv = XTRACT_SUCCESS;
|
jamie@48
|
668
|
jamie@48
|
669
|
jamie@48
|
670 while(n--){
|
jamie@59
|
671 sl = powf(data[n], 0.23);
|
jamie@59
|
672 g = (n < 15 ? 1.f : 0.066 * expf(0.171 * n));
|
jamie@49
|
673 temp += n * g * sl;
|
jamie@48
|
674 }
|
jamie@48
|
675
|
jamie@113
|
676 temp = 0.11 * temp / (float)N;
|
jamie@113
|
677 *result = (float)temp;
|
jamie@48
|
678
|
jamie@48
|
679 return rv;
|
jamie@25
|
680
|
jamie@1
|
681 }
|
jamie@1
|
682
|
jamie@52
|
683 int xtract_spectral_slope(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
684
|
jamie@48
|
685 const float *freqs, *amps;
|
jamie@48
|
686 float f, a,
|
jamie@56
|
687 F, A, FA, FXTRACT_SQ; /* sums of freqs, amps, freq * amps, freq squared */
|
jamie@48
|
688 int n, M;
|
jamie@48
|
689
|
jamie@56
|
690 F = A = FA = FXTRACT_SQ = 0.f;
|
jamie@48
|
691 n = M = N >> 1;
|
jamie@48
|
692
|
jamie@52
|
693 amps = data;
|
jamie@52
|
694 freqs = data + n;
|
jamie@48
|
695
|
jamie@48
|
696 while(n--){
|
jamie@48
|
697 f = freqs[n];
|
jamie@48
|
698 a = amps[n];
|
jamie@48
|
699 F += f;
|
jamie@48
|
700 A += a;
|
jamie@48
|
701 FA += f * a;
|
jamie@56
|
702 FXTRACT_SQ += f * f;
|
jamie@48
|
703 }
|
jamie@48
|
704
|
jamie@56
|
705 *result = (1.f / A) * (M * FA - F * A) / (M * FXTRACT_SQ - F * F);
|
jamie@48
|
706
|
jamie@56
|
707 return XTRACT_SUCCESS;
|
jamie@25
|
708
|
jamie@1
|
709 }
|
jamie@1
|
710
|
jamie@45
|
711 int xtract_lowest_value(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
712
|
jamie@45
|
713 int n = N;
|
jamie@45
|
714 float temp;
|
jamie@45
|
715
|
jamie@46
|
716 *result = data[--n];
|
jamie@45
|
717
|
jamie@45
|
718 while(n--){
|
jamie@45
|
719 if((temp = data[n]) > *(float *)argv)
|
jamie@56
|
720 *result = XTRACT_MIN(*result, data[n]);
|
jamie@45
|
721 }
|
jamie@45
|
722
|
jamie@56
|
723 return XTRACT_SUCCESS;
|
jamie@45
|
724 }
|
jamie@45
|
725
|
jamie@45
|
726 int xtract_highest_value(const float *data, const int N, const void *argv, float *result){
|
jamie@45
|
727
|
jamie@1
|
728 int n = N;
|
jamie@1
|
729
|
jamie@46
|
730 *result = data[--n];
|
jamie@44
|
731
|
jamie@45
|
732 while(n--)
|
jamie@56
|
733 *result = XTRACT_MAX(*result, data[n]);
|
jamie@44
|
734
|
jamie@56
|
735 return XTRACT_SUCCESS;
|
jamie@1
|
736 }
|
jamie@1
|
737
|
jamie@45
|
738
|
jamie@45
|
739 int xtract_sum(const float *data, const int N, const void *argv, float *result){
|
jamie@45
|
740
|
jamie@45
|
741 int n = N;
|
jamie@45
|
742
|
jamie@113
|
743 *result = 0.f;
|
jamie@113
|
744
|
jamie@45
|
745 while(n--)
|
jamie@45
|
746 *result += *data++;
|
jamie@45
|
747
|
jamie@56
|
748 return XTRACT_SUCCESS;
|
jamie@45
|
749
|
jamie@45
|
750 }
|
jamie@45
|
751
|
jamie@59
|
752 int xtract_nonzero_count(const float *data, const int N, const void *argv, float *result){
|
jamie@59
|
753
|
jamie@59
|
754 int n = N;
|
jamie@113
|
755
|
jamie@122
|
756 *result = 0.f;
|
jamie@59
|
757
|
jamie@59
|
758 while(n--)
|
jamie@59
|
759 *result += (*data++ ? 1 : 0);
|
jamie@59
|
760
|
jamie@59
|
761 return XTRACT_SUCCESS;
|
jamie@59
|
762
|
jamie@59
|
763 }
|
jamie@59
|
764
|
jamie@43
|
765 int xtract_hps(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
766
|
jamie@1
|
767 int n = N, M, m, l, peak_index, position1_lwr;
|
jamie@1
|
768 float *coeffs2, *coeffs3, *product, L,
|
jamie@25
|
769 largest1_lwr, peak, ratio1, sr;
|
jamie@1
|
770
|
jamie@25
|
771 sr = *(float*)argv;
|
jamie@78
|
772 if(sr == 0)
|
jamie@78
|
773 sr = 44100.f;
|
jamie@25
|
774
|
jamie@1
|
775 coeffs2 = (float *)malloc(N * sizeof(float));
|
jamie@1
|
776 coeffs3 = (float *)malloc(N * sizeof(float));
|
jamie@1
|
777 product = (float *)malloc(N * sizeof(float));
|
jamie@25
|
778
|
jamie@1
|
779 while(n--) coeffs2[n] = coeffs3[n] = 1;
|
jamie@1
|
780
|
jamie@1
|
781 M = N >> 1;
|
jamie@113
|
782 L = N / 3.f;
|
jamie@1
|
783
|
jamie@1
|
784 while(M--){
|
jamie@25
|
785 m = M << 1;
|
jamie@25
|
786 coeffs2[M] = (data[m] + data[m+1]) * 0.5f;
|
jamie@1
|
787
|
jamie@25
|
788 if(M < L){
|
jamie@25
|
789 l = M * 3;
|
jamie@113
|
790 coeffs3[M] = (data[l] + data[l+1] + data[l+2]) / 3.f;
|
jamie@25
|
791 }
|
jamie@1
|
792 }
|
jamie@25
|
793
|
jamie@1
|
794 peak_index = peak = 0;
|
jamie@25
|
795
|
jamie@1
|
796 for(n = 1; n < N; n++){
|
jamie@25
|
797 product[n] = data[n] * coeffs2[n] * coeffs3[n];
|
jamie@25
|
798 if(product[n] > peak){
|
jamie@25
|
799 peak_index = n;
|
jamie@25
|
800 peak = product[n];
|
jamie@25
|
801 }
|
jamie@1
|
802 }
|
jamie@1
|
803
|
jamie@1
|
804 largest1_lwr = position1_lwr = 0;
|
jamie@1
|
805
|
jamie@1
|
806 for(n = 0; n < N; n++){
|
jamie@25
|
807 if(data[n] > largest1_lwr && n != peak_index){
|
jamie@25
|
808 largest1_lwr = data[n];
|
jamie@25
|
809 position1_lwr = n;
|
jamie@25
|
810 }
|
jamie@1
|
811 }
|
jamie@1
|
812
|
jamie@1
|
813 ratio1 = data[position1_lwr] / data[peak_index];
|
jamie@1
|
814
|
jamie@1
|
815 if(position1_lwr > peak_index * 0.4 && position1_lwr <
|
jamie@25
|
816 peak_index * 0.6 && ratio1 > 0.1)
|
jamie@25
|
817 peak_index = position1_lwr;
|
jamie@1
|
818
|
jamie@22
|
819 *result = sr / (float)peak_index;
|
jamie@25
|
820
|
jamie@1
|
821 free(coeffs2);
|
jamie@1
|
822 free(coeffs3);
|
jamie@1
|
823 free(product);
|
jamie@25
|
824
|
jamie@56
|
825 return XTRACT_SUCCESS;
|
jamie@1
|
826 }
|
jamie@5
|
827
|
jamie@5
|
828
|
jamie@43
|
829 int xtract_f0(const float *data, const int N, const void *argv, float *result){
|
jamie@5
|
830
|
jamie@78
|
831 int M, tau, n;
|
jamie@78
|
832 float sr;
|
jamie@43
|
833 size_t bytes;
|
jamie@43
|
834 float f0, err_tau_1, err_tau_x, array_max,
|
jamie@43
|
835 threshold_peak, threshold_centre,
|
jamie@43
|
836 *input;
|
jamie@22
|
837
|
jamie@25
|
838 sr = *(float *)argv;
|
jamie@78
|
839 if(sr == 0)
|
jamie@78
|
840 sr = 44100.f;
|
jamie@43
|
841
|
jamie@43
|
842 input = (float *)malloc(bytes = N * sizeof(float));
|
jamie@43
|
843 input = memcpy(input, data, bytes);
|
jamie@25
|
844 /* threshold_peak = *((float *)argv+1);
|
jamie@25
|
845 threshold_centre = *((float *)argv+2);
|
jamie@25
|
846 printf("peak: %.2f\tcentre: %.2f\n", threshold_peak, threshold_centre);*/
|
jamie@25
|
847 /* add temporary dynamic control over thresholds to test clipping effects */
|
jamie@22
|
848
|
jamie@25
|
849 /* FIX: tweak and make into macros */
|
jamie@25
|
850 threshold_peak = .8;
|
jamie@25
|
851 threshold_centre = .3;
|
jamie@25
|
852 M = N >> 1;
|
jamie@25
|
853 err_tau_1 = 0;
|
jamie@25
|
854 array_max = 0;
|
jamie@25
|
855
|
jamie@25
|
856 /* Find the array max */
|
jamie@25
|
857 for(n = 0; n < N; n++){
|
jamie@43
|
858 if (input[n] > array_max)
|
jamie@43
|
859 array_max = input[n];
|
jamie@12
|
860 }
|
jamie@25
|
861
|
jamie@25
|
862 threshold_peak *= array_max;
|
jamie@25
|
863
|
jamie@25
|
864 /* peak clip */
|
jamie@25
|
865 for(n = 0; n < N; n++){
|
jamie@43
|
866 if(input[n] > threshold_peak)
|
jamie@43
|
867 input[n] = threshold_peak;
|
jamie@43
|
868 else if(input[n] < -threshold_peak)
|
jamie@43
|
869 input[n] = -threshold_peak;
|
jamie@25
|
870 }
|
jamie@25
|
871
|
jamie@25
|
872 threshold_centre *= array_max;
|
jamie@25
|
873
|
jamie@25
|
874 /* Centre clip */
|
jamie@25
|
875 for(n = 0; n < N; n++){
|
jamie@43
|
876 if (input[n] < threshold_centre)
|
jamie@43
|
877 input[n] = 0;
|
jamie@25
|
878 else
|
jamie@43
|
879 input[n] -= threshold_centre;
|
jamie@25
|
880 }
|
jamie@25
|
881
|
jamie@25
|
882 /* Estimate fundamental freq */
|
jamie@25
|
883 for (n = 1; n < M; n++)
|
jamie@113
|
884 err_tau_1 = err_tau_1 + fabsf(input[n] - input[n+1]);
|
jamie@25
|
885 /* 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
|
886 for (tau = 2; tau < M; tau++){
|
jamie@25
|
887 err_tau_x = 0;
|
jamie@25
|
888 for (n = 1; n < M; n++){
|
jamie@113
|
889 err_tau_x = err_tau_x + fabsf(input[n] - input[n+tau]);
|
jamie@25
|
890 }
|
jamie@25
|
891 if (err_tau_x < err_tau_1) {
|
jamie@25
|
892 f0 = sr / (tau + (err_tau_x / err_tau_1));
|
jamie@25
|
893 *result = f0;
|
jamie@43
|
894 free(input);
|
jamie@56
|
895 return XTRACT_SUCCESS;
|
jamie@25
|
896 }
|
jamie@25
|
897 }
|
jamie@43
|
898 *result = -0;
|
jamie@43
|
899 free(input);
|
jamie@56
|
900 return XTRACT_NO_RESULT;
|
jamie@5
|
901 }
|
jamie@43
|
902
|
jamie@43
|
903 int xtract_failsafe_f0(const float *data, const int N, const void *argv, float *result){
|
jamie@44
|
904
|
jamie@59
|
905 float *spectrum = NULL, argf[2], *peaks = NULL, return_code, sr;
|
jamie@44
|
906
|
jamie@43
|
907 return_code = xtract_f0(data, N, argv, result);
|
jamie@44
|
908
|
jamie@56
|
909 if(return_code == XTRACT_NO_RESULT){
|
jamie@44
|
910
|
jamie@59
|
911 sr = *(float *)argv;
|
jamie@78
|
912 if(sr == 0)
|
jamie@78
|
913 sr = 44100.f;
|
jamie@59
|
914 spectrum = (float *)malloc(N * sizeof(float));
|
jamie@43
|
915 peaks = (float *)malloc(N * sizeof(float));
|
jamie@59
|
916 argf[0] = sr;
|
jamie@59
|
917 argf[1] = XTRACT_MAGNITUDE_SPECTRUM;
|
jamie@59
|
918 xtract_spectrum(data, N, argf, spectrum);
|
jamie@59
|
919 argf[1] = 10.f;
|
jamie@59
|
920 xtract_peak_spectrum(spectrum, N >> 1, argf, peaks);
|
jamie@43
|
921 argf[0] = 0.f;
|
jamie@59
|
922 xtract_lowest_value(peaks+(N >> 1), N >> 1, argf, result);
|
jamie@44
|
923
|
jamie@59
|
924 free(spectrum);
|
jamie@43
|
925 free(peaks);
|
jamie@43
|
926 }
|
jamie@43
|
927
|
jamie@56
|
928 return XTRACT_SUCCESS;
|
jamie@43
|
929
|
jamie@43
|
930 }
|
jamie@44
|
931
|