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_vector.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@1
|
25 #include <math.h>
|
jamie@1
|
26 #include <fftw3.h>
|
jamie@1
|
27
|
jamie@1
|
28 int xtract_magnitude_spectrum(float *data, int N, void *argv, float *result){
|
jamie@1
|
29
|
jamie@1
|
30 float *temp;
|
jamie@1
|
31 int n , M = N >> 1;
|
jamie@1
|
32 fftwf_plan plan;
|
jamie@1
|
33
|
jamie@1
|
34 temp = (float *)fftwf_malloc(N * sizeof(float));
|
jamie@1
|
35
|
jamie@1
|
36 plan = fftwf_plan_r2r_1d(N, data, temp, FFTW_R2HC, FFTW_ESTIMATE);
|
jamie@1
|
37
|
jamie@1
|
38 fftwf_execute(plan);
|
jamie@1
|
39
|
jamie@1
|
40 for(n = 1; n < M; n++){
|
jamie@1
|
41 result[n] = sqrt(SQ(temp[n]) + SQ(temp[N - n])) / N;
|
jamie@1
|
42 result[N-n] = 0.0f;
|
jamie@1
|
43 }
|
jamie@1
|
44
|
jamie@1
|
45 result[0] = fabs(temp[0]) / N;
|
jamie@1
|
46 result[M] = fabs(temp[M]) / N;
|
jamie@1
|
47
|
jamie@1
|
48 fftwf_destroy_plan(plan);
|
jamie@1
|
49 fftwf_free(temp);
|
jamie@1
|
50
|
jamie@1
|
51 }
|
jamie@1
|
52
|
jamie@1
|
53 int xtract_autocorrelation(float *data, int N, void *argv, float *result){
|
jamie@1
|
54
|
jamie@1
|
55 /* Naive time domain implementation */
|
jamie@1
|
56
|
jamie@1
|
57 int n = N, i;
|
jamie@1
|
58
|
jamie@1
|
59 float corr;
|
jamie@1
|
60
|
jamie@1
|
61 while(n--){
|
jamie@1
|
62 corr = 0;
|
jamie@1
|
63 for(i = 0; i < N - n; i++){
|
jamie@1
|
64 corr += data[i] * data[i + n];
|
jamie@1
|
65 }
|
jamie@1
|
66 result[n] = corr / N;
|
jamie@1
|
67 }
|
jamie@1
|
68 }
|
jamie@1
|
69
|
jamie@1
|
70 int xtract_autocorrelation_fft(float *data, int N, void *argv, float *result){
|
jamie@1
|
71
|
jamie@1
|
72 float *temp;
|
jamie@1
|
73 int n;
|
jamie@1
|
74 fftwf_plan plan;
|
jamie@1
|
75
|
jamie@1
|
76 temp = (float *)fftwf_malloc(N * sizeof(float));
|
jamie@1
|
77 plan = fftwf_plan_r2r_1d(N, data, temp, FFTW_HC2R, FFTW_ESTIMATE);
|
jamie@1
|
78
|
jamie@1
|
79 fftwf_execute(plan);
|
jamie@1
|
80
|
jamie@1
|
81 for(n = 0; n < N - 1; n++)
|
jamie@1
|
82 result[n] = temp[n+1];
|
jamie@1
|
83
|
jamie@1
|
84 fftwf_destroy_plan(plan);
|
jamie@1
|
85 fftwf_free(temp);
|
jamie@1
|
86 }
|
jamie@1
|
87
|
jamie@1
|
88 int xtract_amdf(float *data, int N, void *argv, float *result){
|
jamie@1
|
89
|
jamie@1
|
90 int n = N, i;
|
jamie@1
|
91
|
jamie@1
|
92 float md;
|
jamie@1
|
93
|
jamie@1
|
94 while(n--){
|
jamie@1
|
95 md = 0;
|
jamie@1
|
96 for(i = 0; i < N - n; i++){
|
jamie@1
|
97 md += abs(data[i] - data[i + n]);
|
jamie@1
|
98 }
|
jamie@1
|
99 result[n] = md / N;
|
jamie@1
|
100 }
|
jamie@1
|
101 }
|
jamie@1
|
102
|
jamie@1
|
103 int xtract_asdf(float *data, int N, void *argv, float *result){
|
jamie@1
|
104
|
jamie@1
|
105 int n = N, i;
|
jamie@1
|
106
|
jamie@1
|
107 float sd;
|
jamie@1
|
108
|
jamie@1
|
109 while(n--){
|
jamie@1
|
110 sd = 0;
|
jamie@1
|
111 for(i = 0; i < N - n; i++){
|
jamie@1
|
112 sd = 1;
|
jamie@1
|
113 sd += SQ(data[i] - data[i + n]);
|
jamie@1
|
114 }
|
jamie@1
|
115 result[n] = sd / N;
|
jamie@1
|
116 }
|
jamie@1
|
117 }
|
jamie@1
|
118
|
jamie@1
|
119 int xtract_mfcc(float *data, int N, void *argv, float *result){
|
jamie@1
|
120
|
jamie@1
|
121 xtract_mel_filter *f;
|
jamie@1
|
122 int n, filter;
|
jamie@1
|
123 fftwf_plan plan;
|
jamie@1
|
124
|
jamie@1
|
125 f = (xtract_mel_filter *)argv;
|
jamie@1
|
126
|
jamie@1
|
127 for(filter = 0; filter < f->n_filters; filter++){
|
jamie@1
|
128 for(n = 0; n < N; n++){
|
jamie@1
|
129 result[filter] += data[n] * f->filters[filter][n];
|
jamie@1
|
130 }
|
jamie@1
|
131 if(result[filter] < LOG_LIMIT) result[filter] = LOG_LIMIT;
|
jamie@1
|
132 result[filter] = log(result[filter]);
|
jamie@1
|
133 }
|
jamie@1
|
134
|
jamie@1
|
135 for(n = filter + 1; n < N; n++) result[n] = 0;
|
jamie@1
|
136
|
jamie@1
|
137 xtract_dct(result, f->n_filters, NULL, result);
|
jamie@1
|
138
|
jamie@1
|
139 }
|
jamie@1
|
140
|
jamie@1
|
141 int xtract_dct(float *data, int N, void *argv, float *result){
|
jamie@1
|
142
|
jamie@1
|
143 fftwf_plan plan;
|
jamie@1
|
144
|
jamie@1
|
145 plan =
|
jamie@1
|
146 fftwf_plan_r2r_1d(N, data, result, FFTW_REDFT00, FFTW_ESTIMATE);
|
jamie@1
|
147
|
jamie@1
|
148 fftwf_execute(plan);
|
jamie@1
|
149 fftwf_destroy_plan(plan);
|
jamie@1
|
150 }
|
jamie@1
|
151
|
jamie@1
|
152 int xtract_bark_coefficients(float *data, int N, void *argv, float *result){
|
jamie@1
|
153
|
jamie@1
|
154 int *limits, band, n;
|
jamie@1
|
155
|
jamie@1
|
156 limits = (int *)argv;
|
jamie@1
|
157
|
jamie@1
|
158 for(band = 0; band < BARK_BANDS; band++){
|
jamie@1
|
159 for(n = limits[band]; n < limits[band + 1]; n++)
|
jamie@1
|
160 result[band] += data[n];
|
jamie@1
|
161 }
|
jamie@1
|
162 }
|
jamie@1
|
163
|
jamie@1
|
164 int xtract_peaks(float *data, int N, void *argv, float *result){
|
jamie@1
|
165
|
jamie@1
|
166 float thresh, max, y, y2, y3, p, width, sr;
|
jamie@1
|
167 int n = N, M, return_code;
|
jamie@1
|
168
|
jamie@1
|
169 if(argv != NULL){
|
jamie@1
|
170 thresh = ((float *)argv)[0];
|
jamie@1
|
171 sr = ((float *)argv)[1];
|
jamie@1
|
172 return_code = BAD_ARGV;
|
jamie@1
|
173 }
|
jamie@1
|
174 else{
|
jamie@1
|
175 thresh = 0;
|
jamie@1
|
176 sr = 44100;
|
jamie@1
|
177 }
|
jamie@1
|
178
|
jamie@1
|
179 M = N >> 1;
|
jamie@1
|
180 width = sr / N;
|
jamie@1
|
181
|
jamie@1
|
182 y = y2 = y3 = p = max = 0;
|
jamie@1
|
183
|
jamie@1
|
184 if(thresh < 0 || thresh > 100){
|
jamie@1
|
185 thresh = 0;
|
jamie@1
|
186 return_code = BAD_ARGV;
|
jamie@1
|
187 }
|
jamie@1
|
188
|
jamie@1
|
189 if(!sr){
|
jamie@1
|
190 sr = 44100;
|
jamie@1
|
191 return_code = BAD_ARGV;
|
jamie@1
|
192 }
|
jamie@1
|
193
|
jamie@1
|
194 while(n--){
|
jamie@1
|
195 max = MAX(max, data[n]);
|
jamie@1
|
196 /* ensure we never take log10(0) */
|
jamie@1
|
197 /*data[n] = (data[n] < LOG_LIMIT ? LOG_LIMIT : data[n]);*/
|
jamie@1
|
198 if ((data[n] * 100000) <= 1)
|
jamie@1
|
199 /* We get a more stable peak this way */
|
jamie@1
|
200 data[n] = 1;
|
jamie@1
|
201
|
jamie@1
|
202 }
|
jamie@1
|
203
|
jamie@1
|
204 thresh *= .01 * max;
|
jamie@1
|
205
|
jamie@1
|
206 result[0] = 0;
|
jamie@1
|
207 result[M] = 0;
|
jamie@1
|
208
|
jamie@1
|
209 for(n = 1; n < M; n++){
|
jamie@1
|
210 if(data[n] >= thresh){
|
jamie@1
|
211 if(data[n] > data[n - 1] && data[n] > data[n + 1]){
|
jamie@1
|
212 result[n] = width * (n + (p = .5 * (y = 20 * log10(data[n-1]) - (y3 = 20 * log10(data[n+1]))) / (20 * log10(data[n - 1]) - 2 * (y2 = 20 * log10(data[n])) + 20 * log10(data[n + 1]))));
|
jamie@1
|
213 result[M + n] = y2 - .25 * (y - y3) * p;
|
jamie@1
|
214 }
|
jamie@1
|
215 else{
|
jamie@1
|
216 result[n] = 0;
|
jamie@1
|
217 result[M + n] = 0;
|
jamie@1
|
218 }
|
jamie@1
|
219 }
|
jamie@1
|
220 else{
|
jamie@1
|
221 result[n] = 0;
|
jamie@1
|
222 result[M + n] = 0;
|
jamie@1
|
223 }
|
jamie@1
|
224 }
|
jamie@1
|
225
|
jamie@1
|
226 return (return_code ? return_code : SUCCESS);
|
jamie@1
|
227 }
|
jamie@1
|
228
|