From: Paul Brossier Date: Sat, 24 Nov 2007 17:46:30 +0000 (+0100) Subject: merge with aubio-mfcc branch, adding filterbank and mfcc first draft. thank you Amaury X-Git-Tag: bzr2git~442 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=7873363105371224e0b8d1f5545f55672203f464;p=aubio.git Merge ... aubio-mfcc branch, adding filterbank and mfcc first draft. thank you Amaury --- 7873363105371224e0b8d1f5545f55672203f464 diff --cc src/filterbank.c index 00000000,30c2942c..d60890a0 mode 000000,100644..100644 --- a/src/filterbank.c +++ b/src/filterbank.c @@@ -1,0 -1,221 +1,220 @@@ + /* + Copyright (C) 2007 Amaury Hazan + and Paul Brossier + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + + + #include "aubio_priv.h" + #include "sample.h" + #include "filterbank.h" + #include "mathutils.h" + + #include "stdio.h" + -#define USE_EQUAL_GAIN 1 + #define VERY_SMALL_NUMBER 2e-42 + + /** \brief A structure to store a set of n_filters filters of lenghts win_s */ + struct aubio_filterbank_t_ { + uint_t win_s; + uint_t n_filters; + fvec_t **filters; + }; + + aubio_filterbank_t * new_aubio_filterbank(uint_t n_filters, uint_t win_s){ + /** allocating space for filterbank object */ + aubio_filterbank_t * fb = AUBIO_NEW(aubio_filterbank_t); + uint_t filter_cnt; + fb->win_s=win_s; + fb->n_filters=n_filters; + + /** allocating filter tables */ + fb->filters=AUBIO_ARRAY(fvec_t*,n_filters); + for (filter_cnt=0; filter_cntfilters[filter_cnt]=new_fvec(win_s, 1); + + return fb; + } + + /* + FB initialization based on Slaney's auditory toolbox + TODO: + *solve memory leak problems while + *solve quantization issues when constructing signal: + *bug for win_s=512 + *corrections for win_s=1024 -> why even filters with smaller amplitude + + */ + + 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){ + + aubio_filterbank_t * fb = new_aubio_filterbank(n_filters, win_s); + + + //slaney params + smpl_t lowestFrequency = 133.3333; + smpl_t linearSpacing = 66.66666666; + smpl_t logSpacing = 1.0711703; + + uint_t linearFilters = 13; + uint_t logFilters = 27; + uint_t allFilters = linearFilters + logFilters; + + //buffers for computing filter frequencies + fvec_t * freqs=new_fvec(allFilters+2 , 1); + + fvec_t * lower_freqs=new_fvec( allFilters, 1); + fvec_t * upper_freqs=new_fvec( allFilters, 1); + fvec_t * center_freqs=new_fvec( allFilters, 1); + + fvec_t * triangle_heights=new_fvec( allFilters, 1); + //lookup table of each bin frequency in hz + fvec_t * fft_freqs=new_fvec(win_s, 1); + + uint_t filter_cnt, bin_cnt; + + //first step: filling all the linear filter frequencies + for(filter_cnt=0; filter_cntdata[0][filter_cnt]=lowestFrequency+ filter_cnt*linearSpacing; + } + smpl_t lastlinearCF=freqs->data[0][filter_cnt-1]; + + //second step: filling all the log filter frequencies + for(filter_cnt=0; filter_cntdata[0][filter_cnt+linearFilters] = + lastlinearCF*(pow(logSpacing,filter_cnt+1)); + } + + //Option 1. copying interesting values to lower_freqs, center_freqs and upper freqs arrays + //TODO: would be nicer to have a reference to freqs->data, anyway we do not care in this init step + + for(filter_cnt=0; filter_cntdata[0][filter_cnt]=freqs->data[0][filter_cnt]; + center_freqs->data[0][filter_cnt]=freqs->data[0][filter_cnt+1]; + upper_freqs->data[0][filter_cnt]=freqs->data[0][filter_cnt+2]; + } + + //computing triangle heights so that each triangle has unit area + for(filter_cnt=0; filter_cntdata[0][filter_cnt] = 2./(upper_freqs->data[0][filter_cnt] + - lower_freqs->data[0][filter_cnt]); + } + + //AUBIO_DBG("filter tables frequencies\n"); + //for(filter_cnt=0; filter_cntdata[0][filter_cnt], + // center_freqs->data[0][filter_cnt], upper_freqs->data[0][filter_cnt], + // triangle_heights->data[0][filter_cnt]); + + //filling the fft_freqs lookup table, which assigns the frequency in hz to each bin + for(bin_cnt=0; bin_cntdata[0][bin_cnt]= aubio_bintofreq(bin_cnt, samplerate, win_s); + } + + //building each filter table + for(filter_cnt=0; filter_cntdata[0][filter_cnt]/(center_freqs->data[0][filter_cnt]-lower_freqs->data[0][filter_cnt]); + + //zeroing begining of filter + for(bin_cnt=0; bin_cntfilters[filter_cnt]->data[0][bin_cnt]=0.f; + 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]) { + break; + } + } + bin_cnt++; + + //positive slope + for(; bin_cntfilters[filter_cnt]->data[0][bin_cnt]=(fft_freqs->data[0][bin_cnt]-lower_freqs->data[0][filter_cnt])*riseInc; + //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]) + if(fft_freqs->data[0][bin_cnt+1]> center_freqs->data[0][filter_cnt]) + break; + } + //bin_cnt++; + + //negative slope + for(; bin_cntdata[0][filter_cnt]-(fft_freqs->data[0][bin_cnt]-center_freqs->data[0][filter_cnt])*riseInc; + if(val>=0) + fb->filters[filter_cnt]->data[0][bin_cnt]=val; + else fb->filters[filter_cnt]->data[0][bin_cnt]=0.f; + + //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]) + //TODO: CHECK whether bugfix correct + if(fft_freqs->data[0][bin_cnt+1]> upper_freqs->data[0][filter_cnt]) + break; + } + //bin_cnt++; + + //zeroing tail + for(; bin_cntfilters[filter_cnt]->data[0][bin_cnt]=0.f; + + } + + + del_fvec(freqs); + del_fvec(lower_freqs); + del_fvec(upper_freqs); + del_fvec(center_freqs); + + del_fvec(triangle_heights); + del_fvec(fft_freqs); + + return fb; + + } + + void del_aubio_filterbank(aubio_filterbank_t * fb){ + uint_t filter_cnt; + /** deleting filter tables first */ + for (filter_cnt=0; filter_cntn_filters; filter_cnt++) + del_fvec(fb->filters[filter_cnt]); + AUBIO_FREE(fb->filters); + AUBIO_FREE(fb); + } + + void aubio_filterbank_do(aubio_filterbank_t * f, cvec_t * in, fvec_t *out) { + uint_t n, filter_cnt; + for(filter_cnt = 0; (filter_cnt < f->n_filters) + && (filter_cnt < out->length); filter_cnt++){ + out->data[0][filter_cnt] = 0.f; + for(n = 0; n < in->length; n++){ + out->data[0][filter_cnt] += in->norm[0][n] + * f->filters[filter_cnt]->data[0][n]; + } + out->data[0][filter_cnt] = + LOG(out->data[0][filter_cnt] < VERY_SMALL_NUMBER ? + VERY_SMALL_NUMBER : out->data[0][filter_cnt]); + } + + return; + } + + fvec_t * aubio_filterbank_getchannel(aubio_filterbank_t * f, uint_t channel) { + if ( (channel >= 0) && (channel < f->n_filters) ) { return f->filters[channel]; } + else { return NULL; } + } diff --cc src/mfcc.c index 00000000,a77aae4a..2420d803 mode 000000,100644..100644 --- a/src/mfcc.c +++ b/src/mfcc.c @@@ -1,0 -1,124 +1,124 @@@ + /* + Copyright (C) 2006 Amaury Hazan + Ported to aubio from LibXtract + http://libxtract.sourceforge.net/ + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + + #include "aubio_priv.h" + #include "sample.h" + #include "fft.h" + #include "filterbank.h" + #include "mfcc.h" + #include "math.h" + + /** Internal structure for mfcc object **/ + + struct aubio_mfcc_t_{ + uint_t win_s; /** grain length */ + uint_t samplerate; /** sample rate (needed?) */ + uint_t channels; /** number of channels */ + uint_t n_filters; /** number of *filters */ + uint_t n_coefs; /** number of coefficients (<= n_filters/2 +1) */ + smpl_t lowfreq; /** lowest frequency for filters */ + smpl_t highfreq; /** highest frequency for filters */ + aubio_filterbank_t * fb; /** filter bank */ + fvec_t * in_dct; /** input buffer for dct * [fb->n_filters] */ - aubio_mfft_t * fft_dct; /** fft object for dct */ ++ aubio_fft_t * fft_dct; /** fft object for dct */ + cvec_t * fftgrain_dct; /** output buffer for dct */ + }; + + + aubio_mfcc_t * new_aubio_mfcc (uint_t win_s, uint_t samplerate, uint_t n_filters, uint_t n_coefs, smpl_t lowfreq, smpl_t highfreq, uint_t channels){ + /** allocating space for mfcc object */ + aubio_mfcc_t * mfcc = AUBIO_NEW(aubio_mfcc_t); + + //we need (n_coefs-1)*2 filters to obtain n_coefs coefficients after dct + //uint_t n_filters = (n_coefs-1)*2; + + mfcc->win_s=win_s; + mfcc->samplerate=samplerate; + mfcc->channels=channels; + mfcc->n_filters=n_filters; + mfcc->n_coefs=n_coefs; + mfcc->lowfreq=lowfreq; + mfcc->highfreq=highfreq; + + + /** filterbank allocation */ + mfcc->fb = new_aubio_filterbank_mfcc(n_filters, mfcc->win_s, samplerate, lowfreq, highfreq); + + /** allocating space for fft object (used for dct) */ - mfcc->fft_dct=new_aubio_mfft(n_filters, 1); ++ mfcc->fft_dct=new_aubio_fft(n_filters, 1); + + /** allocating buffers */ + mfcc->in_dct=new_fvec(mfcc->win_s, 1); + + mfcc->fftgrain_dct=new_cvec(n_filters, 1); + + return mfcc; + }; + + void del_aubio_mfcc(aubio_mfcc_t *mf){ + /** deleting filterbank */ + del_aubio_filterbank(mf->fb); - /** deleting mfft object */ - del_aubio_mfft(mf->fft_dct); ++ /** deleting fft object */ ++ del_aubio_fft(mf->fft_dct); + /** deleting buffers */ + del_fvec(mf->in_dct); + del_cvec(mf->fftgrain_dct); + + /** deleting mfcc object */ + AUBIO_FREE(mf); + } + + + /** intermediate dct involved in aubio_mfcc_do + + \param mf mfcc object as returned by new_aubio_mfcc + \param in input spectrum (n_filters long) + \param out output mel coefficients buffer (n_filters/2 +1 long) + + */ + void aubio_dct_do(aubio_mfcc_t * mf, fvec_t *in, fvec_t *out); + + void aubio_mfcc_do(aubio_mfcc_t * mf, cvec_t *in, fvec_t *out){ + // compute filterbank + aubio_filterbank_do(mf->fb, in, mf->in_dct); + //TODO: check that zero padding + // the following line seems useless since the in_dct buffer has the correct size + //for(n = filter + 1; n < N; n++) result[n] = 0; + + aubio_dct_do(mf, mf->in_dct, out); + + return; + } + + void aubio_dct_do(aubio_mfcc_t * mf, fvec_t *in, fvec_t *out){ + uint_t i; + //compute mag spectrum - aubio_mfft_do (mf->fft_dct, in, mf->fftgrain_dct); ++ aubio_fft_do (mf->fft_dct, in, mf->fftgrain_dct); + //extract real part of fft grain + for(i=0; in_coefs ;i++){ + //for(i=0; ilength;i++){ + out->data[0][i]= mf->fftgrain_dct->norm[0][i] + *COS(mf->fftgrain_dct->phas[0][i]); + } + return; + } + diff --cc swig/aubio.i index 90af8663,8984c981..0ad423a9 --- a/swig/aubio.i +++ b/swig/aubio.i @@@ -154,6 -148,19 +154,18 @@@ void aubio_autocorr(fvec_t * in, fvec_ smpl_t aubio_zero_crossing_rate(fvec_t * input); smpl_t aubio_spectral_centroid(cvec_t * spectrum, smpl_t samplerate); + /* filterbank */ + aubio_filterbank_t * new_aubio_filterbank(uint_t win_s, uint_t channels); + 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); + void del_aubio_filterbank(aubio_filterbank_t * fb); + void aubio_filterbank_do(aubio_filterbank_t * fb, cvec_t * in, fvec_t *out); + fvec_t * aubio_filterbank_getchannel(aubio_filterbank_t * fb, uint_t channel); + + /* mfcc */ + aubio_mfcc_t * new_aubio_mfcc (uint_t win_s, uint_t samplerate, uint_t n_filters, uint_t n_coefs, smpl_t lowfreq, smpl_t highfreq, uint_t channels); + void del_aubio_mfcc(aubio_mfcc_t *mf); + void aubio_mfcc_do(aubio_mfcc_t *mf, cvec_t *in, fvec_t *out); + - /* scale */ extern aubio_scale_t * new_aubio_scale(smpl_t flow, smpl_t fhig, smpl_t ilow, smpl_t ihig ); extern void aubio_scale_set (aubio_scale_t *s, smpl_t ilow, smpl_t ihig, smpl_t olow, smpl_t ohig); diff --cc tests/python/demo/plot_mfcc_filterbank.py index 00000000,fb527f02..fb527f02 mode 000000,100755..100755 --- a/tests/python/demo/plot_mfcc_filterbank.py +++ b/tests/python/demo/plot_mfcc_filterbank.py diff --cc tests/python/filterbank.py index 00000000,3b04d290..3b04d290 mode 000000,100644..100644 --- a/tests/python/filterbank.py +++ b/tests/python/filterbank.py diff --cc tests/python/filterbank_mfcc.txt index 00000000,1a5443f3..1a5443f3 mode 000000,100644..100644 --- a/tests/python/filterbank_mfcc.txt +++ b/tests/python/filterbank_mfcc.txt