jamie@141: /* jamie@141: * Copyright (C) 2012 Jamie Bullock jamie@140: * jamie@141: * Permission is hereby granted, free of charge, to any person obtaining a copy jamie@141: * of this software and associated documentation files (the "Software"), to jamie@141: * deal in the Software without restriction, including without limitation the jamie@141: * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or jamie@141: * sell copies of the Software, and to permit persons to whom the Software is jamie@141: * furnished to do so, subject to the following conditions: jamie@1: * jamie@141: * The above copyright notice and this permission notice shall be included in jamie@141: * all copies or substantial portions of the Software. jamie@1: * jamie@141: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR jamie@141: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, jamie@141: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE jamie@141: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER jamie@141: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING jamie@141: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS jamie@141: * IN THE SOFTWARE. jamie@1: * jamie@1: */ jamie@1: jamie@107: /* init.c: defines initialisation and free functions. Also contains library constructor routine. */ jamie@1: jamie@98: #ifdef HAVE_CONFIG_H jamie@98: # include jamie@98: #endif jamie@98: jamie@1: #include jamie@26: #include jamie@140: #include jamie@140: jamie@140: #include "fftsg.h" jamie@1: jamie@98: #include "xtract/libxtract.h" jamie@107: #include "xtract_window_private.h" jamie@102: #define DEFINE_GLOBALS jamie@98: #include "xtract_globals_private.h" jamie@98: jamie@98: jamie@140: int xtract_init_mfcc(int N, float nyquist, int style, float freq_min, float freq_max, int freq_bands, float **fft_tables) jamie@140: { jamie@98: jamie@140: int n, i, k, *fft_peak, M, next_peak; jamie@140: float norm, mel_freq_max, mel_freq_min, norm_fact, height, inc, val, jamie@107: freq_bw_mel, *mel_peak, *height_norm, *lin_peak; jamie@1: jamie@1: mel_peak = height_norm = lin_peak = NULL; jamie@1: fft_peak = NULL; jamie@140: norm = 1; jamie@1: jamie@1: mel_freq_max = 1127 * log(1 + freq_max / 700); jamie@1: mel_freq_min = 1127 * log(1 + freq_min / 700); jamie@1: freq_bw_mel = (mel_freq_max - mel_freq_min) / freq_bands; jamie@1: jamie@140: mel_peak = (float *)malloc((freq_bands + 2) * sizeof(float)); jamie@1: /* +2 for zeros at start and end */ jamie@1: lin_peak = (float *)malloc((freq_bands + 2) * sizeof(float)); jamie@1: fft_peak = (int *)malloc((freq_bands + 2) * sizeof(int)); jamie@1: height_norm = (float *)malloc(freq_bands * sizeof(float)); jamie@1: jamie@140: if(mel_peak == NULL || height_norm == NULL || jamie@107: lin_peak == NULL || fft_peak == NULL) jamie@107: return XTRACT_MALLOC_FAILED; jamie@107: jamie@1: M = N >> 1; jamie@1: jamie@1: mel_peak[0] = mel_freq_min; danstowell@95: lin_peak[0] = freq_min; // === 700 * (exp(mel_peak[0] / 1127) - 1); jamie@1: fft_peak[0] = lin_peak[0] / nyquist * M; jamie@1: jamie@1: jamie@140: for (n = 1; n < freq_bands + 2; n++) jamie@140: { jamie@140: //roll out peak locations - mel, linear and linear on fft window scale jamie@1: mel_peak[n] = mel_peak[n - 1] + freq_bw_mel; jamie@1: lin_peak[n] = 700 * (exp(mel_peak[n] / 1127) -1); jamie@1: fft_peak[n] = lin_peak[n] / nyquist * M; jamie@1: } jamie@1: jamie@140: for (n = 0; n < freq_bands; n++) jamie@140: { danstowell@100: //roll out normalised gain of each peak jamie@140: if (style == XTRACT_EQUAL_GAIN) jamie@140: { jamie@140: height = 1; jamie@1: norm_fact = norm; jamie@1: } jamie@140: else jamie@140: { jamie@1: height = 2 / (lin_peak[n + 2] - lin_peak[n]); jamie@1: norm_fact = norm / (2 / (lin_peak[2] - lin_peak[0])); jamie@1: } jamie@1: height_norm[n] = height * norm_fact; jamie@1: } jamie@1: jamie@1: i = 0; jamie@107: jamie@140: for(n = 0; n < freq_bands; n++) jamie@140: { jamie@107: jamie@107: // calculate the rise increment danstowell@95: if(n==0) danstowell@95: inc = height_norm[n] / fft_peak[n]; danstowell@95: else jamie@1: inc = height_norm[n] / (fft_peak[n] - fft_peak[n - 1]); jamie@140: val = 0; jamie@107: jamie@107: // zero the start of the array jamie@107: for(k = 0; k < i; k++) jamie@107: fft_tables[n][k] = 0.f; jamie@107: jamie@107: // fill in the rise jamie@140: for(; i <= fft_peak[n]; i++) jamie@140: { jamie@1: fft_tables[n][i] = val; jamie@1: val += inc; jamie@1: } jamie@107: danstowell@95: // calculate the fall increment jamie@1: inc = height_norm[n] / (fft_peak[n + 1] - fft_peak[n]); jamie@107: jamie@1: val = 0; jamie@107: next_peak = fft_peak[n + 1]; jamie@107: jamie@140: // reverse fill the 'fall' jamie@140: for(i = next_peak; i > fft_peak[n]; i--) jamie@140: { jamie@1: fft_tables[n][i] = val; jamie@1: val += inc; jamie@1: } jamie@39: jamie@107: // zero the rest of the array jamie@107: for(k = next_peak + 1; k < N; k++) jamie@107: fft_tables[n][k] = 0.f; jamie@1: } jamie@1: jamie@98: jamie@98: /* Initialise the fft_plan for the DCT */ jamie@140: /* jamie@140: * Ooura doesn't support non power-of-two DCT jamie@98: xtract_init_fft(freq_bands, XTRACT_MFCC); jamie@140: */ jamie@98: jamie@1: free(mel_peak); jamie@1: free(lin_peak); jamie@1: free(height_norm); jamie@1: free(fft_peak); jamie@1: jamie@56: return XTRACT_SUCCESS; jamie@1: jamie@1: } jamie@1: jamie@140: void xtract_init_ooura(xtract_ooura_data *ooura_data, unsigned int N) jamie@140: { jamie@140: ooura_data->ooura_ip = (int *)calloc((2 + sqrt(N)), sizeof(int)); jamie@140: ooura_data->ooura_w = (double *)calloc((N - 1), sizeof(double)); jamie@140: ooura_data->initialised = true; jamie@140: } jamie@98: jamie@140: void xtract_free_ooura(xtract_ooura_data *ooura_data) jamie@140: { jamie@140: free(ooura_data->ooura_ip); jamie@140: free(ooura_data->ooura_w); jamie@140: ooura_data->ooura_ip = NULL; jamie@140: ooura_data->ooura_w = NULL; jamie@140: ooura_data->initialised = false; jamie@140: } jamie@107: jamie@140: int xtract_init_fft(int N, int feature_name) jamie@140: { jamie@107: jamie@140: int M = N >> 1; jamie@98: jamie@140: if(!xtract_is_poweroftwo(N)) jamie@140: { jamie@140: fprintf(stderr, jamie@140: "libxtract: error: only power-of-two FFT sizes are supported.\n"); jamie@140: exit(EXIT_FAILURE); jamie@140: } jamie@98: jamie@98: if(feature_name == XTRACT_AUTOCORRELATION_FFT) jamie@140: { jamie@140: M = N; /* allow for zero padding */ jamie@98: } jamie@98: jamie@140: switch(feature_name) jamie@140: { jamie@140: case XTRACT_SPECTRUM: jamie@140: if(ooura_data_spectrum.initialised) jamie@140: { jamie@140: xtract_free_ooura(&ooura_data_spectrum); jamie@140: } jamie@140: xtract_init_ooura(&ooura_data_spectrum, M); jamie@140: break; jamie@140: case XTRACT_AUTOCORRELATION_FFT: jamie@140: if(ooura_data_autocorrelation_fft.initialised) jamie@140: { jamie@140: xtract_free_ooura(&ooura_data_autocorrelation_fft); jamie@140: } jamie@140: xtract_init_ooura(&ooura_data_autocorrelation_fft, M); jamie@140: break; jamie@140: case XTRACT_DCT: jamie@140: if(ooura_data_dct.initialised) jamie@140: { jamie@140: xtract_free_ooura(&ooura_data_dct); jamie@140: } jamie@140: xtract_init_ooura(&ooura_data_dct, M); jamie@140: case XTRACT_MFCC: jamie@140: if(ooura_data_mfcc.initialised) jamie@140: { jamie@140: xtract_free_ooura(&ooura_data_mfcc); jamie@140: } jamie@140: xtract_init_ooura(&ooura_data_mfcc, M); jamie@140: break; jamie@140: } jamie@98: jamie@98: return XTRACT_SUCCESS; jamie@98: } jamie@98: jamie@140: void xtract_free_fft(void) jamie@140: { jamie@140: if(ooura_data_spectrum.initialised) jamie@140: { jamie@140: xtract_free_ooura(&ooura_data_spectrum); jamie@140: } jamie@140: if(ooura_data_autocorrelation_fft.initialised) jamie@140: { jamie@140: xtract_free_ooura(&ooura_data_autocorrelation_fft); jamie@140: } jamie@140: if(ooura_data_dct.initialised) jamie@140: { jamie@140: xtract_free_ooura(&ooura_data_dct); jamie@140: } jamie@140: if(ooura_data_mfcc.initialised) jamie@140: { jamie@140: xtract_free_ooura(&ooura_data_mfcc); jamie@140: } jamie@110: } jamie@110: jamie@140: int xtract_init_bark(int N, float sr, int *band_limits) jamie@140: { jamie@1: jamie@38: float edges[] = {0, 100, 200, 300, 400, 510, 630, 770, 920, 1080, 1270, 1480, 1720, 2000, 2320, 2700, 3150, 3700, 4400, 5300, 6400, 7700, 9500, 12000, 15500, 20500, 27000}; /* Takes us up to sr = 54kHz (CCRMA: JOS)*/ jamie@1: jamie@59: int bands = XTRACT_BARK_BANDS; jamie@107: jamie@1: while(bands--) jamie@59: band_limits[bands] = edges[bands] / sr * N; jamie@107: /*FIX shohuld use rounding, but couldn't get it to work */ jamie@38: jamie@56: return XTRACT_SUCCESS; jamie@1: } jamie@98: jamie@140: float *xtract_init_window(const int N, const int type) jamie@140: { jamie@107: float *window; jamie@107: jamie@107: window = malloc(N * sizeof(float)); jamie@107: jamie@140: switch (type) jamie@140: { jamie@140: case XTRACT_GAUSS: jamie@140: gauss(window, N, 0.4); jamie@140: break; jamie@140: case XTRACT_HAMMING: jamie@140: hamming(window, N); jamie@140: break; jamie@140: case XTRACT_HANN: jamie@140: hann(window, N); jamie@140: break; jamie@140: case XTRACT_BARTLETT: jamie@140: bartlett(window, N); jamie@140: break; jamie@140: case XTRACT_TRIANGULAR: jamie@140: triangular(window, N); jamie@140: break; jamie@140: case XTRACT_BARTLETT_HANN: jamie@140: bartlett_hann(window, N); jamie@140: break; jamie@140: case XTRACT_BLACKMAN: jamie@140: blackman(window, N); jamie@140: break; jamie@140: case XTRACT_KAISER: jamie@140: kaiser(window, N, 3 * PI); jamie@140: break; jamie@140: case XTRACT_BLACKMAN_HARRIS: jamie@140: blackman_harris(window, N); jamie@140: break; jamie@140: default: jamie@140: hann(window, N); jamie@140: break; jamie@107: } jamie@107: jamie@107: return window; jamie@107: } jamie@107: jamie@140: void xtract_free_window(float *window) jamie@140: { jamie@107: free(window); jamie@107: } jamie@107: jamie@102: #ifdef __GNUC__ jamie@102: __attribute__((constructor)) void init() jamie@102: #else jamie@140: void _init()ยท jamie@102: #endif jamie@102: { jamie@140: ooura_data_dct.initialised = false; jamie@140: ooura_data_spectrum.initialised = false; jamie@140: ooura_data_autocorrelation_fft.initialised = false; jamie@140: ooura_data_mfcc.initialised = false; jamie@102: }