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