shithub: aubio

ref: fdf39bad6a0efebca0fe1dba5f44861e89df20bd
dir: /src/filterbank.c/

View raw version
/*
   Copyright (C) 2007 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 "filterbank.h"


// Struct Declaration

/** \brief A structure to store a set of n_filters Mel filters */
typedef struct aubio_mel_filter_ {
    int n_filters;
    smpl_t **filters;
};

// Initialization

int aubio_mfcc_init(int N, smpl_t nyquist, int style, smpl_t freq_min, smpl_t freq_max, int freq_bands, smpl_t **fft_tables){

    int n, i, k, *fft_peak, M, next_peak; 
    smpl_t norm, mel_freq_max, mel_freq_min, norm_fact, height, inc, val, 
        freq_bw_mel, *mel_peak, *height_norm, *lin_peak;

    mel_peak = height_norm = lin_peak = NULL;
    fft_peak = NULL;
    norm = 1; 

    mel_freq_max = 1127 * log(1 + freq_max / 700);
    mel_freq_min = 1127 * log(1 + freq_min / 700);
    freq_bw_mel = (mel_freq_max - mel_freq_min) / freq_bands;

    mel_peak = (smpl_t *)malloc((freq_bands + 2) * sizeof(smpl_t)); 
    /* +2 for zeros at start and end */
    lin_peak = (smpl_t *)malloc((freq_bands + 2) * sizeof(smpl_t));
    fft_peak = (int *)malloc((freq_bands + 2) * sizeof(int));
    height_norm = (smpl_t *)malloc(freq_bands * sizeof(smpl_t));

    if(mel_peak == NULL || height_norm == NULL || 
                    lin_peak == NULL || fft_peak == NULL)
                    return XTRACT_MALLOC_FAILED;
    
    M = N >> 1;

    mel_peak[0] = mel_freq_min;
    lin_peak[0] = 700 * (exp(mel_peak[0] / 1127) - 1);
    fft_peak[0] = lin_peak[0] / nyquist * M;


    for (n = 1; n <= freq_bands; n++){  
    /*roll out peak locations - mel, linear and linear on fft window scale */
        mel_peak[n] = mel_peak[n - 1] + freq_bw_mel;
        lin_peak[n] = 700 * (exp(mel_peak[n] / 1127) -1);
        fft_peak[n] = lin_peak[n] / nyquist * M;
    }

    for (n = 0; n < freq_bands; n++){
        /*roll out normalised gain of each peak*/
        if (style == XTRACT_EQUAL_GAIN){
            height = 1; 
            norm_fact = norm;
        }
        else{
            height = 2 / (lin_peak[n + 2] - lin_peak[n]);
            norm_fact = norm / (2 / (lin_peak[2] - lin_peak[0]));
        }
        height_norm[n] = height * norm_fact;
    }

    i = 0;
   
    for(n = 0; n < freq_bands; n++){
  
  /*calculate the rise increment*/
        if(n > 0)
            inc = height_norm[n] / (fft_peak[n] - fft_peak[n - 1]);
        else
            inc = height_norm[n] / fft_peak[n];
        val = 0;  
  
  /*zero the start of the array*/
  for(k = 0; k < i; k++)
     fft_tables[n][k] = 0.f;
  
  /*fill in the rise */
        for(; i <= fft_peak[n]; i++){ 
            fft_tables[n][i] = val;
            val += inc;
        }
  
        /*calculate the fall increment */
        inc = height_norm[n] / (fft_peak[n + 1] - fft_peak[n]);
  
        val = 0;
  next_peak = fft_peak[n + 1];
  
  /*reverse fill the 'fall' */
        for(i = next_peak; i > fft_peak[n]; i--){ 
            fft_tables[n][i] = val;
            val += inc;
        }

  /*zero the rest of the array*/
  for(k = next_peak + 1; k < N; k++)
      fft_tables[n][k] = 0.f;
    }

    free(mel_peak);
    free(lin_peak);
    free(height_norm);
    free(fft_peak);

    return XTRACT_SUCCESS;

}