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