[88199ce] | 1 | /* |
---|
[f918cb9] | 2 | Copyright (C) 2007 Amaury Hazan <ahazan@iua.upf.edu> |
---|
| 3 | and Paul Brossier <piem@piem.org> |
---|
[88199ce] | 4 | |
---|
| 5 | This program is free software; you can redistribute it and/or modify |
---|
| 6 | it under the terms of the GNU General Public License as published by |
---|
| 7 | the Free Software Foundation; either version 2 of the License, or |
---|
| 8 | (at your option) any later version. |
---|
| 9 | |
---|
| 10 | This program is distributed in the hope that it will be useful, |
---|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 13 | GNU General Public License for more details. |
---|
| 14 | |
---|
| 15 | You should have received a copy of the GNU General Public License |
---|
| 16 | along with this program; if not, write to the Free Software |
---|
| 17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
| 18 | |
---|
| 19 | */ |
---|
| 20 | |
---|
[f918cb9] | 21 | |
---|
[7c6c806d] | 22 | #include "aubio_priv.h" |
---|
[b276dee] | 23 | #include "sample.h" |
---|
[71d3bf0] | 24 | #include "filterbank.h" |
---|
[88199ce] | 25 | |
---|
[7a46bf6] | 26 | #include "stdio.h" |
---|
[7c6c806d] | 27 | |
---|
[b276dee] | 28 | #define USE_EQUAL_GAIN 1 |
---|
| 29 | #define VERY_SMALL_NUMBER 2e-42 |
---|
[7c6c806d] | 30 | |
---|
[8708556] | 31 | /** \brief A structure to store a set of n_filters filters of lenghts win_s */ |
---|
| 32 | struct aubio_filterbank_t_ { |
---|
| 33 | uint_t win_s; |
---|
| 34 | uint_t n_filters; |
---|
[b276dee] | 35 | fvec_t **filters; |
---|
[7c6c806d] | 36 | }; |
---|
| 37 | |
---|
[8708556] | 38 | aubio_filterbank_t * new_aubio_filterbank(uint_t n_filters, uint_t win_s){ |
---|
| 39 | /** allocating space for filterbank object */ |
---|
| 40 | aubio_filterbank_t * fb = AUBIO_NEW(aubio_filterbank_t); |
---|
[f918cb9] | 41 | uint_t filter_cnt; |
---|
[8708556] | 42 | fb->win_s=win_s; |
---|
| 43 | fb->n_filters=n_filters; |
---|
[88199ce] | 44 | |
---|
[8708556] | 45 | /** allocating filter tables */ |
---|
[b276dee] | 46 | fb->filters=AUBIO_ARRAY(fvec_t*,n_filters); |
---|
[8708556] | 47 | for (filter_cnt=0; filter_cnt<n_filters; filter_cnt++) |
---|
| 48 | /* considering one-channel filters */ |
---|
[b276dee] | 49 | fb->filters[filter_cnt]=new_fvec(win_s, 1); |
---|
[88199ce] | 50 | |
---|
[b276dee] | 51 | return fb; |
---|
| 52 | } |
---|
| 53 | |
---|
[f72ceeb] | 54 | aubio_filterbank_t * new_aubio_filterbank_mfcc(uint_t n_filters, uint_t win_s, uint_t samplerate, smpl_t freq_min, smpl_t freq_max){ |
---|
[7a46bf6] | 55 | |
---|
[b276dee] | 56 | smpl_t nyquist = samplerate/2.; |
---|
| 57 | uint_t style = 1; |
---|
| 58 | aubio_filterbank_t * fb = new_aubio_filterbank(n_filters, win_s); |
---|
[88199ce] | 59 | |
---|
[b276dee] | 60 | uint_t n, i, k, *fft_peak, M, next_peak; |
---|
| 61 | smpl_t norm, mel_freq_max, mel_freq_min, norm_fact, height, inc, val, |
---|
| 62 | freq_bw_mel, *mel_peak, *height_norm, *lin_peak; |
---|
[88199ce] | 63 | |
---|
[b276dee] | 64 | mel_peak = height_norm = lin_peak = NULL; |
---|
| 65 | fft_peak = NULL; |
---|
| 66 | norm = 1; |
---|
[88199ce] | 67 | |
---|
[b276dee] | 68 | mel_freq_max = 1127 * log(1 + freq_max / 700); |
---|
| 69 | mel_freq_min = 1127 * log(1 + freq_min / 700); |
---|
| 70 | freq_bw_mel = (mel_freq_max - mel_freq_min) / fb->n_filters; |
---|
[88199ce] | 71 | |
---|
[b276dee] | 72 | mel_peak = (smpl_t *)malloc((fb->n_filters + 2) * sizeof(smpl_t)); |
---|
| 73 | /* +2 for zeros at start and end */ |
---|
| 74 | lin_peak = (smpl_t *)malloc((fb->n_filters + 2) * sizeof(smpl_t)); |
---|
| 75 | fft_peak = (uint_t *)malloc((fb->n_filters + 2) * sizeof(uint_t)); |
---|
| 76 | height_norm = (smpl_t *)malloc(fb->n_filters * sizeof(smpl_t)); |
---|
[88199ce] | 77 | |
---|
[b276dee] | 78 | if(mel_peak == NULL || height_norm == NULL || |
---|
| 79 | lin_peak == NULL || fft_peak == NULL) |
---|
| 80 | return NULL; |
---|
[88199ce] | 81 | |
---|
[b276dee] | 82 | M = fb->win_s >> 1; |
---|
| 83 | |
---|
| 84 | mel_peak[0] = mel_freq_min; |
---|
| 85 | lin_peak[0] = 700 * (exp(mel_peak[0] / 1127) - 1); |
---|
| 86 | fft_peak[0] = lin_peak[0] / nyquist * M; |
---|
| 87 | |
---|
| 88 | for (n = 1; n <= fb->n_filters; n++){ |
---|
[88199ce] | 89 | /*roll out peak locations - mel, linear and linear on fft window scale */ |
---|
[b276dee] | 90 | mel_peak[n] = mel_peak[n - 1] + freq_bw_mel; |
---|
| 91 | lin_peak[n] = 700 * (exp(mel_peak[n] / 1127) -1); |
---|
| 92 | fft_peak[n] = lin_peak[n] / nyquist * M; |
---|
| 93 | } |
---|
| 94 | |
---|
| 95 | for (n = 0; n < fb->n_filters; n++){ |
---|
| 96 | /*roll out normalised gain of each peak*/ |
---|
| 97 | if (style == USE_EQUAL_GAIN){ |
---|
| 98 | height = 1; |
---|
| 99 | norm_fact = norm; |
---|
[88199ce] | 100 | } |
---|
[b276dee] | 101 | else{ |
---|
| 102 | height = 2 / (lin_peak[n + 2] - lin_peak[n]); |
---|
| 103 | norm_fact = norm / (2 / (lin_peak[2] - lin_peak[0])); |
---|
| 104 | } |
---|
| 105 | height_norm[n] = height * norm_fact; |
---|
| 106 | } |
---|
| 107 | |
---|
| 108 | i = 0; |
---|
[88199ce] | 109 | |
---|
[b276dee] | 110 | for(n = 0; n < fb->n_filters; n++){ |
---|
| 111 | |
---|
| 112 | /*calculate the rise increment*/ |
---|
| 113 | if(n > 0) |
---|
| 114 | inc = height_norm[n] / (fft_peak[n] - fft_peak[n - 1]); |
---|
| 115 | else |
---|
| 116 | inc = height_norm[n] / fft_peak[n]; |
---|
| 117 | val = 0; |
---|
| 118 | |
---|
| 119 | /*zero the start of the array*/ |
---|
| 120 | for(k = 0; k < i; k++) |
---|
| 121 | fb->filters[n]->data[0][k]=0.f; |
---|
| 122 | |
---|
| 123 | /*fill in the rise */ |
---|
| 124 | for(; i <= fft_peak[n]; i++){ |
---|
| 125 | fb->filters[n]->data[0][k]=val; |
---|
| 126 | val += inc; |
---|
[88199ce] | 127 | } |
---|
| 128 | |
---|
[b276dee] | 129 | /*calculate the fall increment */ |
---|
| 130 | inc = height_norm[n] / (fft_peak[n + 1] - fft_peak[n]); |
---|
| 131 | |
---|
| 132 | val = 0; |
---|
| 133 | next_peak = fft_peak[n + 1]; |
---|
| 134 | |
---|
| 135 | /*reverse fill the 'fall' */ |
---|
| 136 | for(i = next_peak; i > fft_peak[n]; i--){ |
---|
| 137 | fb->filters[n]->data[0][k]=val; |
---|
| 138 | val += inc; |
---|
| 139 | } |
---|
| 140 | |
---|
| 141 | /*zero the rest of the array*/ |
---|
| 142 | for(k = next_peak + 1; k < fb->win_s; k++) |
---|
| 143 | fb->filters[n]->data[0][k]=0.f; |
---|
[7a46bf6] | 144 | |
---|
[88199ce] | 145 | |
---|
[b276dee] | 146 | } |
---|
| 147 | |
---|
| 148 | free(mel_peak); |
---|
| 149 | free(lin_peak); |
---|
| 150 | free(height_norm); |
---|
| 151 | free(fft_peak); |
---|
| 152 | |
---|
[7a46bf6] | 153 | |
---|
[b276dee] | 154 | return fb; |
---|
[88199ce] | 155 | |
---|
[8708556] | 156 | } |
---|
| 157 | |
---|
[83d5abf] | 158 | /* |
---|
| 159 | FB initialization based on Slaney's auditory toolbox |
---|
| 160 | TODO: |
---|
| 161 | *solve memory leak problems while |
---|
| 162 | *solve quantization issues when constructing signal: |
---|
| 163 | *bug for win_s=512 |
---|
| 164 | *corrections for win_s=1024 -> why even filters with smaller amplitude |
---|
| 165 | |
---|
| 166 | */ |
---|
[ef1c3b7] | 167 | |
---|
[f72ceeb] | 168 | aubio_filterbank_t * new_aubio_filterbank_mfcc2(uint_t n_filters, uint_t win_s, uint_t samplerate, smpl_t freq_min, smpl_t freq_max){ |
---|
| 169 | |
---|
| 170 | aubio_filterbank_t * fb = new_aubio_filterbank(n_filters, win_s); |
---|
| 171 | |
---|
[ef1c3b7] | 172 | |
---|
| 173 | //slaney params |
---|
| 174 | smpl_t lowestFrequency = 133.3333; |
---|
| 175 | smpl_t linearSpacing = 66.66666666; |
---|
| 176 | smpl_t logSpacing = 1.0711703; |
---|
| 177 | |
---|
| 178 | uint_t linearFilters = 13; |
---|
| 179 | uint_t logFilters = 27; |
---|
| 180 | uint_t allFilters = linearFilters + logFilters; |
---|
[7a46bf6] | 181 | |
---|
[ef1c3b7] | 182 | //buffers for computing filter frequencies |
---|
[95a64c7] | 183 | fvec_t * freqs=new_fvec(allFilters+2 , 1); |
---|
[787f1f3] | 184 | |
---|
[ef1c3b7] | 185 | fvec_t * lower_freqs=new_fvec( allFilters, 1); |
---|
| 186 | fvec_t * upper_freqs=new_fvec( allFilters, 1); |
---|
| 187 | fvec_t * center_freqs=new_fvec( allFilters, 1); |
---|
[95a64c7] | 188 | |
---|
[787f1f3] | 189 | |
---|
[ef1c3b7] | 190 | fvec_t * triangle_heights=new_fvec( allFilters, 1); |
---|
| 191 | //lookup table of each bin frequency in hz |
---|
[f72ceeb] | 192 | fvec_t * fft_freqs=new_fvec(win_s, 1); |
---|
[ef1c3b7] | 193 | |
---|
| 194 | uint_t filter_cnt, bin_cnt; |
---|
| 195 | |
---|
[95a64c7] | 196 | //first step: filling all the linear filter frequencies |
---|
[ef1c3b7] | 197 | for(filter_cnt=0; filter_cnt<linearFilters; filter_cnt++){ |
---|
[f72ceeb] | 198 | freqs->data[0][filter_cnt]=lowestFrequency+ filter_cnt*linearSpacing; |
---|
[ef1c3b7] | 199 | } |
---|
[f72ceeb] | 200 | smpl_t lastlinearCF=freqs->data[0][filter_cnt-1]; |
---|
[ef1c3b7] | 201 | |
---|
[95a64c7] | 202 | //second step: filling all the log filter frequencies |
---|
[ef1c3b7] | 203 | for(filter_cnt=0; filter_cnt<logFilters+2; filter_cnt++){ |
---|
[f72ceeb] | 204 | freqs->data[0][filter_cnt+linearFilters]=lastlinearCF*(pow(logSpacing,filter_cnt+1)); |
---|
[ef1c3b7] | 205 | } |
---|
[f72ceeb] | 206 | |
---|
[95a64c7] | 207 | //Option 1. copying interesting values to lower_freqs, center_freqs and upper freqs arrays |
---|
| 208 | //TODO: would be nicer to have a reference to freqs->data, anyway we do not care in this init step |
---|
| 209 | |
---|
| 210 | for(filter_cnt=0; filter_cnt<allFilters; filter_cnt++){ |
---|
| 211 | lower_freqs->data[0][filter_cnt]=freqs->data[0][filter_cnt]; |
---|
| 212 | center_freqs->data[0][filter_cnt]=freqs->data[0][filter_cnt+1]; |
---|
| 213 | upper_freqs->data[0][filter_cnt]=freqs->data[0][filter_cnt+2]; |
---|
| 214 | } |
---|
| 215 | |
---|
| 216 | |
---|
[ef1c3b7] | 217 | //computing triangle heights so that each triangle has unit area |
---|
| 218 | for(filter_cnt=0; filter_cnt<allFilters; filter_cnt++){ |
---|
[f72ceeb] | 219 | triangle_heights->data[0][filter_cnt]=2./(upper_freqs->data[0][filter_cnt]-lower_freqs->data[0][filter_cnt]); |
---|
[ef1c3b7] | 220 | } |
---|
[95a64c7] | 221 | |
---|
| 222 | |
---|
[787f1f3] | 223 | //AUBIO_DBG |
---|
| 224 | AUBIO_DBG("filter tables frequencies\n"); |
---|
[f72ceeb] | 225 | for(filter_cnt=0; filter_cnt<allFilters; filter_cnt++) |
---|
[787f1f3] | 226 | AUBIO_DBG("filter n. %d %f %f %f %f\n",filter_cnt, lower_freqs->data[0][filter_cnt], center_freqs->data[0][filter_cnt], upper_freqs->data[0][filter_cnt], triangle_heights->data[0][filter_cnt]); |
---|
[bc4ba75] | 227 | |
---|
[f72ceeb] | 228 | //filling the fft_freqs lookup table, which assigns the frequency in hz to each bin |
---|
[ef1c3b7] | 229 | for(bin_cnt=0; bin_cnt<win_s; bin_cnt++){ |
---|
| 230 | //TODO: check the formula! |
---|
[f72ceeb] | 231 | fft_freqs->data[0][bin_cnt]= (smpl_t)samplerate* (smpl_t)bin_cnt/ (smpl_t)win_s; |
---|
[ef1c3b7] | 232 | } |
---|
[bc4ba75] | 233 | |
---|
[f72ceeb] | 234 | //building each filter table |
---|
[ef1c3b7] | 235 | for(filter_cnt=0; filter_cnt<allFilters; filter_cnt++){ |
---|
| 236 | |
---|
[f72ceeb] | 237 | //TODO:check special case : lower freq =0 |
---|
| 238 | //calculating rise increment in mag/Hz |
---|
| 239 | smpl_t riseInc= triangle_heights->data[0][filter_cnt]/(center_freqs->data[0][filter_cnt]-lower_freqs->data[0][filter_cnt]); |
---|
| 240 | |
---|
| 241 | |
---|
[bc4ba75] | 242 | AUBIO_DBG("\nfilter %d",filter_cnt); |
---|
| 243 | //zeroing begining of filter |
---|
[787f1f3] | 244 | AUBIO_DBG("\nzero begin\n"); |
---|
[f72ceeb] | 245 | for(bin_cnt=0; bin_cnt<win_s-1; bin_cnt++){ |
---|
| 246 | //zeroing beigining of array |
---|
[ef1c3b7] | 247 | fb->filters[filter_cnt]->data[0][bin_cnt]=0.f; |
---|
[787f1f3] | 248 | AUBIO_DBG("."); |
---|
| 249 | //AUBIO_DBG("%f %f %f\n", fft_freqs->data[0][bin_cnt], fft_freqs->data[0][bin_cnt+1], lower_freqs->data[0][filter_cnt]); |
---|
[f72ceeb] | 250 | if(fft_freqs->data[0][bin_cnt]<= lower_freqs->data[0][filter_cnt] && fft_freqs->data[0][bin_cnt+1]> lower_freqs->data[0][filter_cnt]){ |
---|
| 251 | break; |
---|
| 252 | } |
---|
[88199ce] | 253 | } |
---|
[f72ceeb] | 254 | bin_cnt++; |
---|
| 255 | |
---|
[787f1f3] | 256 | AUBIO_DBG("\npos slope\n"); |
---|
[f72ceeb] | 257 | //positive slope |
---|
| 258 | for(; bin_cnt<win_s-1; bin_cnt++){ |
---|
[787f1f3] | 259 | AUBIO_DBG("."); |
---|
[f72ceeb] | 260 | fb->filters[filter_cnt]->data[0][bin_cnt]=(fft_freqs->data[0][bin_cnt]-lower_freqs->data[0][filter_cnt])*riseInc; |
---|
| 261 | //if(fft_freqs->data[0][bin_cnt]<= center_freqs->data[0][filter_cnt] && fft_freqs->data[0][bin_cnt+1]> center_freqs->data[0][filter_cnt]) |
---|
| 262 | if(fft_freqs->data[0][bin_cnt+1]> center_freqs->data[0][filter_cnt]) |
---|
| 263 | break; |
---|
[b276dee] | 264 | } |
---|
[f72ceeb] | 265 | //bin_cnt++; |
---|
| 266 | |
---|
[83d5abf] | 267 | |
---|
[f72ceeb] | 268 | //negative slope |
---|
[787f1f3] | 269 | AUBIO_DBG("\nneg slope\n"); |
---|
[f72ceeb] | 270 | for(; bin_cnt<win_s-1; bin_cnt++){ |
---|
[787f1f3] | 271 | //AUBIO_DBG("."); |
---|
[f72ceeb] | 272 | |
---|
| 273 | //checking whether last value is less than 0... |
---|
| 274 | smpl_t val=triangle_heights->data[0][filter_cnt]-(fft_freqs->data[0][bin_cnt]-center_freqs->data[0][filter_cnt])*riseInc; |
---|
| 275 | if(val>=0) |
---|
| 276 | fb->filters[filter_cnt]->data[0][bin_cnt]=val; |
---|
| 277 | else fb->filters[filter_cnt]->data[0][bin_cnt]=0.f; |
---|
| 278 | |
---|
| 279 | //if(fft_freqs->data[0][bin_cnt]<= upper_freqs->data[0][bin_cnt] && fft_freqs->data[0][bin_cnt+1]> upper_freqs->data[0][filter_cnt]) |
---|
| 280 | //TODO: CHECK whether bugfix correct |
---|
| 281 | if(fft_freqs->data[0][bin_cnt+1]> upper_freqs->data[0][filter_cnt]) |
---|
| 282 | break; |
---|
[b276dee] | 283 | } |
---|
[f72ceeb] | 284 | //bin_cnt++; |
---|
| 285 | |
---|
[787f1f3] | 286 | AUBIO_DBG("\nzero end\n"); |
---|
[f72ceeb] | 287 | //zeroing tail |
---|
| 288 | for(; bin_cnt<win_s; bin_cnt++) |
---|
[787f1f3] | 289 | //AUBIO_DBG("."); |
---|
[f72ceeb] | 290 | fb->filters[filter_cnt]->data[0][bin_cnt]=0.f; |
---|
[88199ce] | 291 | |
---|
[b276dee] | 292 | } |
---|
[f72ceeb] | 293 | |
---|
| 294 | |
---|
[95a64c7] | 295 | |
---|
[f72ceeb] | 296 | del_fvec(freqs); |
---|
[95a64c7] | 297 | del_fvec(lower_freqs); |
---|
| 298 | del_fvec(upper_freqs); |
---|
| 299 | del_fvec(center_freqs); |
---|
[b276dee] | 300 | |
---|
[f72ceeb] | 301 | del_fvec(triangle_heights); |
---|
| 302 | del_fvec(fft_freqs); |
---|
[b276dee] | 303 | |
---|
| 304 | return fb; |
---|
[88199ce] | 305 | |
---|
[8708556] | 306 | } |
---|
| 307 | |
---|
[ef1c3b7] | 308 | void aubio_dump_filterbank(aubio_filterbank_t * fb){ |
---|
| 309 | |
---|
| 310 | FILE * mlog; |
---|
| 311 | mlog=fopen("filterbank.txt","w"); |
---|
| 312 | |
---|
| 313 | int k,n; |
---|
| 314 | //dumping filter values |
---|
| 315 | //smpl_t area_tmp=0.f; |
---|
| 316 | for(n = 0; n < fb->n_filters; n++){ |
---|
| 317 | for(k = 0; k < fb->win_s; k++){ |
---|
| 318 | fprintf(mlog,"%f ",fb->filters[n]->data[0][k]); |
---|
| 319 | } |
---|
| 320 | fprintf(mlog,"\n"); |
---|
| 321 | } |
---|
| 322 | |
---|
| 323 | if(mlog) fclose(mlog); |
---|
| 324 | } |
---|
[b276dee] | 325 | |
---|
[8708556] | 326 | void del_aubio_filterbank(aubio_filterbank_t * fb){ |
---|
[b276dee] | 327 | uint_t filter_cnt; |
---|
[8708556] | 328 | /** deleting filter tables first */ |
---|
| 329 | for (filter_cnt=0; filter_cnt<fb->n_filters; filter_cnt++) |
---|
| 330 | del_fvec(fb->filters[filter_cnt]); |
---|
| 331 | AUBIO_FREE(fb->filters); |
---|
| 332 | AUBIO_FREE(fb); |
---|
| 333 | } |
---|
[88199ce] | 334 | |
---|
[b276dee] | 335 | void aubio_filterbank_do(aubio_filterbank_t * f, cvec_t * in, fvec_t *out) { |
---|
| 336 | uint_t n, filter_cnt; |
---|
[f14a78d] | 337 | for(filter_cnt = 0; (filter_cnt < f->n_filters) |
---|
| 338 | && (filter_cnt < out->length); filter_cnt++){ |
---|
[b276dee] | 339 | out->data[0][filter_cnt] = 0.f; |
---|
[f14a78d] | 340 | for(n = 0; n < in->length; n++){ |
---|
[b276dee] | 341 | out->data[0][filter_cnt] += in->norm[0][n] |
---|
| 342 | * f->filters[filter_cnt]->data[0][n]; |
---|
| 343 | } |
---|
| 344 | out->data[0][filter_cnt] = |
---|
| 345 | LOG(out->data[0][filter_cnt] < VERY_SMALL_NUMBER ? |
---|
| 346 | VERY_SMALL_NUMBER : out->data[0][filter_cnt]); |
---|
| 347 | } |
---|
| 348 | |
---|
| 349 | return; |
---|
[fe28ff3] | 350 | } |
---|