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