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@53
|
189 A += amps[m];
|
jamie@59
|
190 *result += powf((freqs[m] - *(float *)argv) * amps[m], 2);
|
jamie@53
|
191 }
|
jamie@53
|
192
|
jamie@59
|
193 *result = *result / (A /*- 1*/);
|
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@52
|
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@53
|
219 A += amps[m];
|
jamie@113
|
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@52
|
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 float temp, A = 0.f;
|
jamie@53
|
232 const float *freqs, *amps;
|
jamie@52
|
233
|
jamie@53
|
234 m = N >> 1;
|
jamie@53
|
235
|
jamie@53
|
236 amps = data;
|
jamie@53
|
237 freqs = data + m;
|
jamie@52
|
238
|
jamie@122
|
239 *result = 0.f;
|
jamie@113
|
240
|
jamie@52
|
241 while(m--){
|
jamie@53
|
242 A += amps[m];
|
jamie@53
|
243 temp = ((amps[m] * freqs[m]) -
|
jamie@52
|
244 ((float *)argv)[0]) / ((float *)argv)[1];
|
jamie@113
|
245 *result += powf(temp, 3);
|
jamie@52
|
246 }
|
jamie@52
|
247
|
jamie@53
|
248 *result /= A;
|
jamie@52
|
249
|
jamie@56
|
250 return XTRACT_SUCCESS;
|
jamie@52
|
251 }
|
jamie@52
|
252
|
jamie@52
|
253 int xtract_spectral_kurtosis(const float *data, const int N, const void *argv, float *result){
|
jamie@52
|
254
|
jamie@53
|
255 int m;
|
jamie@53
|
256 float temp, A = 0.f;
|
jamie@53
|
257 const float *freqs, *amps;
|
jamie@52
|
258
|
jamie@53
|
259 m = N >> 1;
|
jamie@53
|
260
|
jamie@53
|
261 amps = data;
|
jamie@53
|
262 freqs = data + m;
|
jamie@52
|
263
|
jamie@122
|
264 *result = 0.f;
|
jamie@113
|
265
|
jamie@52
|
266 while(m--){
|
jamie@53
|
267 A += amps[m];
|
jamie@53
|
268 temp = ((amps[m] * freqs[m]) -
|
jamie@52
|
269 ((float *)argv)[0]) / ((float *)argv)[1];
|
jamie@113
|
270 *result += powf(temp, 4);
|
jamie@52
|
271 }
|
jamie@52
|
272
|
jamie@53
|
273 *result /= A;
|
jamie@52
|
274 *result -= 3.0f;
|
jamie@52
|
275
|
jamie@56
|
276 return XTRACT_SUCCESS;
|
jamie@52
|
277 }
|
jamie@52
|
278
|
jamie@43
|
279 int xtract_irregularity_k(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
280
|
jamie@1
|
281 int n,
|
jamie@37
|
282 M = N - 1;
|
danstowell@84
|
283
|
jamie@113
|
284 *result = 0.f;
|
danstowell@84
|
285
|
jamie@1
|
286 for(n = 1; n < M; n++)
|
jamie@113
|
287 *result += fabsf(data[n] - (data[n-1] + data[n] + data[n+1]) / 3.f);
|
jamie@1
|
288
|
jamie@56
|
289 return XTRACT_SUCCESS;
|
jamie@1
|
290 }
|
jamie@1
|
291
|
jamie@43
|
292 int xtract_irregularity_j(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
293
|
jamie@1
|
294 int n = N;
|
jamie@1
|
295
|
jamie@59
|
296 double num = 0.f, den = 0.f;
|
jamie@1
|
297
|
jamie@1
|
298 while(n--){
|
jamie@113
|
299 num += powf(data[n] - data[n+1], 2);
|
jamie@113
|
300 den += powf(data[n], 2);
|
jamie@1
|
301 }
|
jamie@25
|
302
|
jamie@59
|
303 *result = (float)(num / den);
|
jamie@1
|
304
|
jamie@56
|
305 return XTRACT_SUCCESS;
|
jamie@1
|
306 }
|
jamie@1
|
307
|
jamie@43
|
308 int xtract_tristimulus_1(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
309
|
jamie@1
|
310 int n = N;
|
jamie@1
|
311
|
jamie@42
|
312 float den, p1, temp;
|
jamie@1
|
313
|
jamie@42
|
314 den = p1 = temp = 0.f;
|
jamie@1
|
315
|
jamie@42
|
316 for(n = 0; n < N; n++){
|
jamie@42
|
317 if((temp = data[n])){
|
jamie@42
|
318 den += temp;
|
jamie@42
|
319 if(!p1)
|
jamie@42
|
320 p1 = temp;
|
jamie@42
|
321 }
|
jamie@42
|
322 }
|
jamie@42
|
323
|
jamie@113
|
324 if(den == 0.f || p1 == 0.f){
|
jamie@113
|
325 *result = 0.f;
|
jamie@113
|
326 return XTRACT_NO_RESULT;
|
jamie@113
|
327 }
|
jamie@113
|
328 else{
|
jamie@113
|
329 *result = p1 / den;
|
jamie@113
|
330 return XTRACT_SUCCESS;
|
jamie@113
|
331 }
|
jamie@1
|
332 }
|
jamie@1
|
333
|
jamie@43
|
334 int xtract_tristimulus_2(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
335
|
jamie@1
|
336 int n = N;
|
jamie@1
|
337
|
jamie@113
|
338 float den, p2, p3, p4, ps, temp;
|
jamie@1
|
339
|
jamie@113
|
340 den = p2 = p3 = p4 = ps = temp = 0.f;
|
jamie@1
|
341
|
jamie@42
|
342 for(n = 0; n < N; n++){
|
jamie@42
|
343 if((temp = data[n])){
|
jamie@42
|
344 den += temp;
|
jamie@42
|
345 if(!p2)
|
jamie@42
|
346 p2 = temp;
|
jamie@42
|
347 else if(!p3)
|
jamie@42
|
348 p3 = temp;
|
jamie@42
|
349 else if(!p4)
|
jamie@42
|
350 p4 = temp;
|
jamie@42
|
351 }
|
jamie@42
|
352 }
|
jamie@42
|
353
|
jamie@113
|
354 ps = p2 + p3 + p4;
|
jamie@25
|
355
|
jamie@113
|
356 if(den == 0.f || ps == 0.f){
|
jamie@113
|
357 *result = 0.f;
|
jamie@113
|
358 return XTRACT_NO_RESULT;
|
jamie@113
|
359 }
|
jamie@113
|
360 else{
|
jamie@113
|
361 *result = ps / den;
|
jamie@113
|
362 return XTRACT_SUCCESS;
|
jamie@113
|
363 }
|
jamie@113
|
364
|
jamie@1
|
365 }
|
jamie@1
|
366
|
jamie@43
|
367 int xtract_tristimulus_3(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
368
|
jamie@42
|
369 int n = N, count = 0;
|
jamie@1
|
370
|
jamie@42
|
371 float den, num, temp;
|
jamie@1
|
372
|
jamie@42
|
373 den = num = temp = 0.f;
|
jamie@1
|
374
|
jamie@42
|
375 for(n = 0; n < N; n++){
|
jamie@42
|
376 if((temp = data[n])){
|
jamie@42
|
377 den += temp;
|
jamie@42
|
378 if(count >= 5)
|
jamie@42
|
379 num += temp;
|
jamie@42
|
380 count++;
|
jamie@42
|
381 }
|
jamie@42
|
382 }
|
jamie@25
|
383
|
jamie@113
|
384 if(den == 0.f || num == 0.f){
|
jamie@113
|
385 *result = 0.f;
|
jamie@113
|
386 return XTRACT_NO_RESULT;
|
jamie@113
|
387 }
|
jamie@113
|
388 else{
|
jamie@113
|
389 *result = num / den;
|
jamie@113
|
390 return XTRACT_SUCCESS;
|
jamie@113
|
391 }
|
jamie@1
|
392 }
|
jamie@1
|
393
|
jamie@43
|
394 int xtract_smoothness(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
395
|
jamie@59
|
396 int n, M;
|
jamie@1
|
397
|
jamie@43
|
398 float *input;
|
jamie@43
|
399
|
jamie@43
|
400 input = (float *)malloc(N * sizeof(float));
|
jamie@59
|
401 memcpy(input, data, N * sizeof(float));
|
jamie@43
|
402
|
jamie@113
|
403 if (input[0] <= 0)
|
jamie@113
|
404 input[0] = XTRACT_LOG_LIMIT;
|
jamie@113
|
405 if (input[1] <= 0)
|
jamie@113
|
406 input[1] = XTRACT_LOG_LIMIT;
|
jamie@25
|
407
|
jamie@59
|
408 M = N - 1;
|
jamie@59
|
409
|
jamie@59
|
410 for(n = 1; n < M; n++){
|
jamie@113
|
411 if(input[n+1] <= 0)
|
jamie@113
|
412 input[n+1] = XTRACT_LOG_LIMIT;
|
jamie@113
|
413 *result += fabsf(20.f * logf(input[n]) - (20.f * logf(input[n-1]) +
|
jamie@113
|
414 20.f * logf(input[n]) + 20.f * logf(input[n+1])) / 3.f);
|
jamie@25
|
415 }
|
jamie@43
|
416
|
jamie@43
|
417 free(input);
|
jamie@44
|
418
|
jamie@56
|
419 return XTRACT_SUCCESS;
|
jamie@1
|
420 }
|
jamie@1
|
421
|
jamie@43
|
422 int xtract_spread(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
423
|
jamie@1
|
424 int n = N;
|
jamie@1
|
425
|
jamie@83
|
426 float num = 0.f, den = 0.f, temp = 0.f;
|
jamie@83
|
427
|
jamie@83
|
428 if(argv == NULL)
|
jamie@83
|
429 return XTRACT_BAD_ARGV;
|
jamie@1
|
430
|
jamie@1
|
431 while(n--){
|
jamie@48
|
432 temp = n - *(float *)argv;
|
jamie@56
|
433 num += XTRACT_SQ(temp) * data[n];
|
jamie@25
|
434 den += data[n];
|
jamie@1
|
435 }
|
jamie@1
|
436
|
jamie@117
|
437 /* FIX: spectral spread is mathematically equivalent to spectral variance --
|
jamie@117
|
438 * here we are computing the spectral standard deviation */
|
jamie@113
|
439 *result = sqrtf(num / den);
|
jamie@25
|
440
|
jamie@56
|
441 return XTRACT_SUCCESS;
|
jamie@1
|
442 }
|
jamie@1
|
443
|
jamie@43
|
444 int xtract_zcr(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
445
|
jamie@1
|
446 int n = N;
|
jamie@25
|
447
|
jamie@1
|
448 for(n = 1; n < N; n++)
|
jamie@25
|
449 if(data[n] * data[n-1] < 0) (*result)++;
|
jamie@25
|
450
|
jamie@113
|
451 *result /= (float)N;
|
jamie@25
|
452
|
jamie@56
|
453 return XTRACT_SUCCESS;
|
jamie@1
|
454 }
|
jamie@1
|
455
|
jamie@43
|
456 int xtract_rolloff(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
457
|
jamie@1
|
458 int n = N;
|
jamie@55
|
459 float pivot, temp, percentile;
|
jamie@42
|
460
|
jamie@42
|
461 pivot = temp = 0.f;
|
jamie@55
|
462 percentile = ((float *)argv)[1];
|
jamie@25
|
463
|
jamie@1
|
464 while(n--) pivot += data[n];
|
jamie@25
|
465
|
jamie@55
|
466 pivot *= percentile / 100.f;
|
jamie@25
|
467
|
jamie@42
|
468 for(n = 0; temp < pivot; n++)
|
jamie@42
|
469 temp += data[n];
|
jamie@1
|
470
|
jamie@55
|
471 *result = n * ((float *)argv)[0];
|
jamie@55
|
472 /* *result = (n / (float)N) * (((float *)argv)[1] * .5); */
|
jamie@25
|
473
|
jamie@56
|
474 return XTRACT_SUCCESS;
|
jamie@1
|
475 }
|
jamie@1
|
476
|
jamie@43
|
477 int xtract_loudness(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
478
|
jamie@47
|
479 int n = N, rv;
|
jamie@25
|
480
|
jamie@113
|
481 *result = 0.f;
|
jamie@113
|
482
|
jamie@93
|
483 if(n > XTRACT_BARK_BANDS){
|
jamie@93
|
484 n = XTRACT_BARK_BANDS;
|
jamie@56
|
485 rv = XTRACT_BAD_VECTOR_SIZE;
|
jamie@93
|
486 }
|
jamie@47
|
487 else
|
jamie@56
|
488 rv = XTRACT_SUCCESS;
|
jamie@1
|
489
|
jamie@1
|
490 while(n--)
|
jamie@59
|
491 *result += powf(data[n], 0.23);
|
jamie@38
|
492
|
jamie@47
|
493 return rv;
|
jamie@1
|
494 }
|
jamie@1
|
495
|
jamie@43
|
496 int xtract_flatness(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
497
|
jamie@113
|
498 int n, count, denormal_found;
|
jamie@1
|
499
|
jamie@44
|
500 double num, den, temp;
|
jamie@25
|
501
|
jamie@113
|
502 num = 1.f;
|
jamie@113
|
503 den = temp = 0.f;
|
jamie@43
|
504
|
jamie@113
|
505 denormal_found = 0;
|
jamie@113
|
506 count = 0;
|
jamie@113
|
507
|
jamie@113
|
508 for(n = 0; n < N; n++){
|
jamie@113
|
509 if((temp = data[n]) != 0.f) {
|
jamie@113
|
510 if (xtract_is_denormal(num)){
|
jamie@113
|
511 denormal_found = 1;
|
jamie@113
|
512 break;
|
jamie@113
|
513 }
|
jamie@113
|
514 num *= temp;
|
jamie@113
|
515 den += temp;
|
jamie@113
|
516 count++;
|
jamie@113
|
517 }
|
jamie@1
|
518 }
|
jamie@44
|
519
|
jamie@113
|
520 if(!count){
|
jamie@113
|
521 *result = 0.f;
|
jamie@113
|
522 return XTRACT_NO_RESULT;
|
jamie@113
|
523 }
|
jamie@25
|
524
|
jamie@113
|
525 num = powf(num, 1.f / (float)N);
|
jamie@113
|
526 den /= (float)N;
|
jamie@44
|
527
|
jamie@44
|
528
|
jamie@113
|
529 *result = (float) (num / den);
|
jamie@113
|
530
|
jamie@113
|
531 if(denormal_found)
|
jamie@113
|
532 return XTRACT_DENORMAL_FOUND;
|
jamie@113
|
533 else
|
jamie@113
|
534 return XTRACT_SUCCESS;
|
jamie@113
|
535
|
jamie@113
|
536 }
|
jamie@113
|
537
|
jamie@113
|
538 int xtract_flatness_db(const float *data, const int N, const void *argv, float *result){
|
jamie@113
|
539
|
jamie@115
|
540 float flatness;
|
jamie@113
|
541
|
jamie@115
|
542 flatness = *(float *)argv;
|
jamie@113
|
543
|
jamie@115
|
544 if (flatness <= 0)
|
jamie@115
|
545 flatness = XTRACT_LOG_LIMIT;
|
jamie@113
|
546
|
jamie@115
|
547 *result = 10 * log10f(flatness);
|
jamie@25
|
548
|
jamie@56
|
549 return XTRACT_SUCCESS;
|
jamie@44
|
550
|
jamie@1
|
551 }
|
jamie@1
|
552
|
jamie@43
|
553 int xtract_tonality(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
554
|
jamie@113
|
555 float sfmdb;
|
jamie@25
|
556
|
jamie@113
|
557 sfmdb = *(float *)argv;
|
jamie@1
|
558
|
jamie@113
|
559 *result = XTRACT_MIN(sfmdb / -60.f, 1);
|
jamie@25
|
560
|
jamie@56
|
561 return XTRACT_SUCCESS;
|
jamie@1
|
562 }
|
jamie@1
|
563
|
jamie@43
|
564 int xtract_crest(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
565
|
jamie@45
|
566 float max, mean;
|
jamie@45
|
567
|
jamie@45
|
568 max = mean = 0.f;
|
jamie@45
|
569
|
jamie@45
|
570 max = *(float *)argv;
|
jamie@45
|
571 mean = *((float *)argv+1);
|
jamie@45
|
572
|
jamie@45
|
573 *result = max / mean;
|
jamie@45
|
574
|
jamie@56
|
575 return XTRACT_SUCCESS;
|
jamie@25
|
576
|
jamie@1
|
577 }
|
jamie@1
|
578
|
jamie@43
|
579 int xtract_noisiness(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
580
|
jamie@45
|
581 float h, i, p; /*harmonics, inharmonics, partials */
|
jamie@45
|
582
|
jamie@45
|
583 i = p = h = 0.f;
|
jamie@45
|
584
|
jamie@45
|
585 h = *(float *)argv;
|
jamie@45
|
586 p = *((float *)argv+1);
|
jamie@45
|
587
|
jamie@45
|
588 i = p - h;
|
jamie@45
|
589
|
jamie@45
|
590 *result = i / p;
|
jamie@45
|
591
|
jamie@56
|
592 return XTRACT_SUCCESS;
|
jamie@25
|
593
|
jamie@1
|
594 }
|
jamie@2
|
595
|
jamie@43
|
596 int xtract_rms_amplitude(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
597
|
jamie@1
|
598 int n = N;
|
jamie@1
|
599
|
jamie@113
|
600 *result = 0.f;
|
jamie@113
|
601
|
jamie@56
|
602 while(n--) *result += XTRACT_SQ(data[n]);
|
jamie@1
|
603
|
jamie@113
|
604 *result = sqrtf(*result / (float)N);
|
jamie@25
|
605
|
jamie@56
|
606 return XTRACT_SUCCESS;
|
jamie@1
|
607 }
|
jamie@1
|
608
|
jamie@52
|
609 int xtract_spectral_inharmonicity(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
610
|
jamie@41
|
611 int n = N >> 1;
|
jamie@43
|
612 float num = 0.f, den = 0.f, fund;
|
jamie@43
|
613 const float *freqs, *amps;
|
jamie@1
|
614
|
jamie@41
|
615 fund = *(float *)argv;
|
jamie@52
|
616 amps = data;
|
jamie@52
|
617 freqs = data + n;
|
jamie@25
|
618
|
jamie@1
|
619 while(n--){
|
jamie@59
|
620 if(amps[n]){
|
jamie@113
|
621 num += fabsf(freqs[n] - n * fund) * XTRACT_SQ(amps[n]);
|
jamie@59
|
622 den += XTRACT_SQ(amps[n]);
|
jamie@59
|
623 }
|
jamie@1
|
624 }
|
jamie@1
|
625
|
jamie@41
|
626 *result = (2 * num) / (fund * den);
|
jamie@25
|
627
|
jamie@56
|
628 return XTRACT_SUCCESS;
|
jamie@1
|
629 }
|
jamie@1
|
630
|
jamie@1
|
631
|
jamie@43
|
632 int xtract_power(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
633
|
jamie@56
|
634 return XTRACT_FEATURE_NOT_IMPLEMENTED;
|
jamie@25
|
635
|
jamie@1
|
636 }
|
jamie@1
|
637
|
jamie@43
|
638 int xtract_odd_even_ratio(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
639
|
jamie@43
|
640 int M = (N >> 1), n;
|
jamie@1
|
641
|
jamie@113
|
642 float odd = 0.f, even = 0.f, temp;
|
jamie@44
|
643
|
jamie@43
|
644 for(n = 0; n < M; n++){
|
jamie@43
|
645 if((temp = data[n])){
|
jamie@59
|
646 if(XTRACT_IS_ODD(n)){
|
jamie@113
|
647 odd += temp;
|
jamie@43
|
648 }
|
jamie@43
|
649 else{
|
jamie@113
|
650 even += temp;
|
jamie@43
|
651 }
|
jamie@43
|
652 }
|
jamie@1
|
653 }
|
jamie@1
|
654
|
jamie@113
|
655 if(odd == 0.f || even == 0.f){
|
jamie@113
|
656 *result = 0.f;
|
jamie@113
|
657 return XTRACT_NO_RESULT;
|
jamie@113
|
658 }
|
jamie@113
|
659 else {
|
jamie@113
|
660 *result = odd / even;
|
jamie@113
|
661 return XTRACT_SUCCESS;
|
jamie@113
|
662 }
|
jamie@1
|
663 }
|
jamie@1
|
664
|
jamie@43
|
665 int xtract_sharpness(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
666
|
jamie@48
|
667 int n = N, rv;
|
jamie@113
|
668 float sl, g; /* sl = specific loudness */
|
jamie@113
|
669 double temp;
|
jamie@48
|
670
|
jamie@113
|
671 sl = g = 0.f;
|
jamie@113
|
672 temp = 0.f;
|
jamie@48
|
673
|
jamie@56
|
674 if(n > XTRACT_BARK_BANDS)
|
jamie@56
|
675 rv = XTRACT_BAD_VECTOR_SIZE;
|
jamie@48
|
676 else
|
jamie@56
|
677 rv = XTRACT_SUCCESS;
|
jamie@48
|
678
|
jamie@48
|
679
|
jamie@48
|
680 while(n--){
|
jamie@59
|
681 sl = powf(data[n], 0.23);
|
jamie@59
|
682 g = (n < 15 ? 1.f : 0.066 * expf(0.171 * n));
|
jamie@49
|
683 temp += n * g * sl;
|
jamie@48
|
684 }
|
jamie@48
|
685
|
jamie@113
|
686 temp = 0.11 * temp / (float)N;
|
jamie@113
|
687 *result = (float)temp;
|
jamie@48
|
688
|
jamie@48
|
689 return rv;
|
jamie@25
|
690
|
jamie@1
|
691 }
|
jamie@1
|
692
|
jamie@52
|
693 int xtract_spectral_slope(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
694
|
jamie@48
|
695 const float *freqs, *amps;
|
jamie@48
|
696 float f, a,
|
jamie@56
|
697 F, A, FA, FXTRACT_SQ; /* sums of freqs, amps, freq * amps, freq squared */
|
jamie@48
|
698 int n, M;
|
jamie@48
|
699
|
jamie@56
|
700 F = A = FA = FXTRACT_SQ = 0.f;
|
jamie@48
|
701 n = M = N >> 1;
|
jamie@48
|
702
|
jamie@52
|
703 amps = data;
|
jamie@52
|
704 freqs = data + n;
|
jamie@48
|
705
|
jamie@48
|
706 while(n--){
|
jamie@48
|
707 f = freqs[n];
|
jamie@48
|
708 a = amps[n];
|
jamie@48
|
709 F += f;
|
jamie@48
|
710 A += a;
|
jamie@48
|
711 FA += f * a;
|
jamie@56
|
712 FXTRACT_SQ += f * f;
|
jamie@48
|
713 }
|
jamie@48
|
714
|
jamie@56
|
715 *result = (1.f / A) * (M * FA - F * A) / (M * FXTRACT_SQ - F * F);
|
jamie@48
|
716
|
jamie@56
|
717 return XTRACT_SUCCESS;
|
jamie@25
|
718
|
jamie@1
|
719 }
|
jamie@1
|
720
|
jamie@45
|
721 int xtract_lowest_value(const float *data, const int N, const void *argv, float *result){
|
jamie@25
|
722
|
jamie@45
|
723 int n = N;
|
jamie@45
|
724 float temp;
|
jamie@45
|
725
|
jamie@46
|
726 *result = data[--n];
|
jamie@45
|
727
|
jamie@45
|
728 while(n--){
|
jamie@45
|
729 if((temp = data[n]) > *(float *)argv)
|
jamie@56
|
730 *result = XTRACT_MIN(*result, data[n]);
|
jamie@45
|
731 }
|
jamie@45
|
732
|
jamie@56
|
733 return XTRACT_SUCCESS;
|
jamie@45
|
734 }
|
jamie@45
|
735
|
jamie@45
|
736 int xtract_highest_value(const float *data, const int N, const void *argv, float *result){
|
jamie@45
|
737
|
jamie@1
|
738 int n = N;
|
jamie@1
|
739
|
jamie@46
|
740 *result = data[--n];
|
jamie@44
|
741
|
jamie@45
|
742 while(n--)
|
jamie@56
|
743 *result = XTRACT_MAX(*result, data[n]);
|
jamie@44
|
744
|
jamie@56
|
745 return XTRACT_SUCCESS;
|
jamie@1
|
746 }
|
jamie@1
|
747
|
jamie@45
|
748
|
jamie@45
|
749 int xtract_sum(const float *data, const int N, const void *argv, float *result){
|
jamie@45
|
750
|
jamie@45
|
751 int n = N;
|
jamie@45
|
752
|
jamie@113
|
753 *result = 0.f;
|
jamie@113
|
754
|
jamie@45
|
755 while(n--)
|
jamie@45
|
756 *result += *data++;
|
jamie@45
|
757
|
jamie@56
|
758 return XTRACT_SUCCESS;
|
jamie@45
|
759
|
jamie@45
|
760 }
|
jamie@45
|
761
|
jamie@59
|
762 int xtract_nonzero_count(const float *data, const int N, const void *argv, float *result){
|
jamie@59
|
763
|
jamie@59
|
764 int n = N;
|
jamie@113
|
765
|
jamie@122
|
766 *result = 0.f;
|
jamie@59
|
767
|
jamie@59
|
768 while(n--)
|
jamie@59
|
769 *result += (*data++ ? 1 : 0);
|
jamie@59
|
770
|
jamie@59
|
771 return XTRACT_SUCCESS;
|
jamie@59
|
772
|
jamie@59
|
773 }
|
jamie@59
|
774
|
jamie@43
|
775 int xtract_hps(const float *data, const int N, const void *argv, float *result){
|
jamie@1
|
776
|
jamie@1
|
777 int n = N, M, m, l, peak_index, position1_lwr;
|
jamie@1
|
778 float *coeffs2, *coeffs3, *product, L,
|
jamie@25
|
779 largest1_lwr, peak, ratio1, sr;
|
jamie@1
|
780
|
jamie@25
|
781 sr = *(float*)argv;
|
jamie@78
|
782 if(sr == 0)
|
jamie@78
|
783 sr = 44100.f;
|
jamie@25
|
784
|
jamie@1
|
785 coeffs2 = (float *)malloc(N * sizeof(float));
|
jamie@1
|
786 coeffs3 = (float *)malloc(N * sizeof(float));
|
jamie@1
|
787 product = (float *)malloc(N * sizeof(float));
|
jamie@25
|
788
|
jamie@1
|
789 while(n--) coeffs2[n] = coeffs3[n] = 1;
|
jamie@1
|
790
|
jamie@1
|
791 M = N >> 1;
|
jamie@113
|
792 L = N / 3.f;
|
jamie@1
|
793
|
jamie@1
|
794 while(M--){
|
jamie@25
|
795 m = M << 1;
|
jamie@25
|
796 coeffs2[M] = (data[m] + data[m+1]) * 0.5f;
|
jamie@1
|
797
|
jamie@25
|
798 if(M < L){
|
jamie@25
|
799 l = M * 3;
|
jamie@113
|
800 coeffs3[M] = (data[l] + data[l+1] + data[l+2]) / 3.f;
|
jamie@25
|
801 }
|
jamie@1
|
802 }
|
jamie@25
|
803
|
jamie@1
|
804 peak_index = peak = 0;
|
jamie@25
|
805
|
jamie@1
|
806 for(n = 1; n < N; n++){
|
jamie@25
|
807 product[n] = data[n] * coeffs2[n] * coeffs3[n];
|
jamie@25
|
808 if(product[n] > peak){
|
jamie@25
|
809 peak_index = n;
|
jamie@25
|
810 peak = product[n];
|
jamie@25
|
811 }
|
jamie@1
|
812 }
|
jamie@1
|
813
|
jamie@1
|
814 largest1_lwr = position1_lwr = 0;
|
jamie@1
|
815
|
jamie@1
|
816 for(n = 0; n < N; n++){
|
jamie@25
|
817 if(data[n] > largest1_lwr && n != peak_index){
|
jamie@25
|
818 largest1_lwr = data[n];
|
jamie@25
|
819 position1_lwr = n;
|
jamie@25
|
820 }
|
jamie@1
|
821 }
|
jamie@1
|
822
|
jamie@1
|
823 ratio1 = data[position1_lwr] / data[peak_index];
|
jamie@1
|
824
|
jamie@1
|
825 if(position1_lwr > peak_index * 0.4 && position1_lwr <
|
jamie@25
|
826 peak_index * 0.6 && ratio1 > 0.1)
|
jamie@25
|
827 peak_index = position1_lwr;
|
jamie@1
|
828
|
jamie@22
|
829 *result = sr / (float)peak_index;
|
jamie@25
|
830
|
jamie@1
|
831 free(coeffs2);
|
jamie@1
|
832 free(coeffs3);
|
jamie@1
|
833 free(product);
|
jamie@25
|
834
|
jamie@56
|
835 return XTRACT_SUCCESS;
|
jamie@1
|
836 }
|
jamie@5
|
837
|
jamie@5
|
838
|
jamie@43
|
839 int xtract_f0(const float *data, const int N, const void *argv, float *result){
|
jamie@5
|
840
|
jamie@78
|
841 int M, tau, n;
|
jamie@78
|
842 float sr;
|
jamie@43
|
843 size_t bytes;
|
jamie@43
|
844 float f0, err_tau_1, err_tau_x, array_max,
|
jamie@43
|
845 threshold_peak, threshold_centre,
|
jamie@43
|
846 *input;
|
jamie@22
|
847
|
jamie@25
|
848 sr = *(float *)argv;
|
jamie@78
|
849 if(sr == 0)
|
jamie@78
|
850 sr = 44100.f;
|
jamie@43
|
851
|
jamie@43
|
852 input = (float *)malloc(bytes = N * sizeof(float));
|
jamie@43
|
853 input = memcpy(input, data, bytes);
|
jamie@25
|
854 /* threshold_peak = *((float *)argv+1);
|
jamie@25
|
855 threshold_centre = *((float *)argv+2);
|
jamie@25
|
856 printf("peak: %.2f\tcentre: %.2f\n", threshold_peak, threshold_centre);*/
|
jamie@25
|
857 /* add temporary dynamic control over thresholds to test clipping effects */
|
jamie@22
|
858
|
jamie@25
|
859 /* FIX: tweak and make into macros */
|
jamie@25
|
860 threshold_peak = .8;
|
jamie@25
|
861 threshold_centre = .3;
|
jamie@25
|
862 M = N >> 1;
|
jamie@25
|
863 err_tau_1 = 0;
|
jamie@25
|
864 array_max = 0;
|
jamie@25
|
865
|
jamie@25
|
866 /* Find the array max */
|
jamie@25
|
867 for(n = 0; n < N; n++){
|
jamie@43
|
868 if (input[n] > array_max)
|
jamie@43
|
869 array_max = input[n];
|
jamie@12
|
870 }
|
jamie@25
|
871
|
jamie@25
|
872 threshold_peak *= array_max;
|
jamie@25
|
873
|
jamie@25
|
874 /* peak clip */
|
jamie@25
|
875 for(n = 0; n < N; n++){
|
jamie@43
|
876 if(input[n] > threshold_peak)
|
jamie@43
|
877 input[n] = threshold_peak;
|
jamie@43
|
878 else if(input[n] < -threshold_peak)
|
jamie@43
|
879 input[n] = -threshold_peak;
|
jamie@25
|
880 }
|
jamie@25
|
881
|
jamie@25
|
882 threshold_centre *= array_max;
|
jamie@25
|
883
|
jamie@25
|
884 /* Centre clip */
|
jamie@25
|
885 for(n = 0; n < N; n++){
|
jamie@43
|
886 if (input[n] < threshold_centre)
|
jamie@43
|
887 input[n] = 0;
|
jamie@25
|
888 else
|
jamie@43
|
889 input[n] -= threshold_centre;
|
jamie@25
|
890 }
|
jamie@25
|
891
|
jamie@25
|
892 /* Estimate fundamental freq */
|
jamie@25
|
893 for (n = 1; n < M; n++)
|
jamie@113
|
894 err_tau_1 = err_tau_1 + fabsf(input[n] - input[n+1]);
|
jamie@25
|
895 /* 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
|
896 for (tau = 2; tau < M; tau++){
|
jamie@25
|
897 err_tau_x = 0;
|
jamie@25
|
898 for (n = 1; n < M; n++){
|
jamie@113
|
899 err_tau_x = err_tau_x + fabsf(input[n] - input[n+tau]);
|
jamie@25
|
900 }
|
jamie@25
|
901 if (err_tau_x < err_tau_1) {
|
jamie@25
|
902 f0 = sr / (tau + (err_tau_x / err_tau_1));
|
jamie@25
|
903 *result = f0;
|
jamie@43
|
904 free(input);
|
jamie@56
|
905 return XTRACT_SUCCESS;
|
jamie@25
|
906 }
|
jamie@25
|
907 }
|
jamie@43
|
908 *result = -0;
|
jamie@43
|
909 free(input);
|
jamie@56
|
910 return XTRACT_NO_RESULT;
|
jamie@5
|
911 }
|
jamie@43
|
912
|
jamie@43
|
913 int xtract_failsafe_f0(const float *data, const int N, const void *argv, float *result){
|
jamie@44
|
914
|
jamie@59
|
915 float *spectrum = NULL, argf[2], *peaks = NULL, return_code, sr;
|
jamie@44
|
916
|
jamie@43
|
917 return_code = xtract_f0(data, N, argv, result);
|
jamie@44
|
918
|
jamie@56
|
919 if(return_code == XTRACT_NO_RESULT){
|
jamie@44
|
920
|
jamie@59
|
921 sr = *(float *)argv;
|
jamie@78
|
922 if(sr == 0)
|
jamie@78
|
923 sr = 44100.f;
|
jamie@59
|
924 spectrum = (float *)malloc(N * sizeof(float));
|
jamie@43
|
925 peaks = (float *)malloc(N * sizeof(float));
|
jamie@59
|
926 argf[0] = sr;
|
jamie@59
|
927 argf[1] = XTRACT_MAGNITUDE_SPECTRUM;
|
jamie@59
|
928 xtract_spectrum(data, N, argf, spectrum);
|
jamie@59
|
929 argf[1] = 10.f;
|
jamie@59
|
930 xtract_peak_spectrum(spectrum, N >> 1, argf, peaks);
|
jamie@43
|
931 argf[0] = 0.f;
|
jamie@59
|
932 xtract_lowest_value(peaks+(N >> 1), N >> 1, argf, result);
|
jamie@44
|
933
|
jamie@59
|
934 free(spectrum);
|
jamie@43
|
935 free(peaks);
|
jamie@43
|
936 }
|
jamie@43
|
937
|
jamie@56
|
938 return XTRACT_SUCCESS;
|
jamie@43
|
939
|
jamie@43
|
940 }
|
jamie@44
|
941
|