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@1: #include jamie@26: #include jamie@140: #include jamie@140: jamie@150: #include "fft.h" jamie@1: jamie@259: #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@150: #ifdef USE_OOURA jamie@150: void xtract_init_ooura_data(xtract_ooura_data *ooura_data, unsigned int N) jamie@150: { andrea@211: ooura_data->ooura_ip = (int *)calloc(2 + sqrt((double)N), sizeof(int)); jamie@176: ooura_data->ooura_w = (double *)calloc(N * 5 / 4, sizeof(double)); jamie@150: ooura_data->initialised = true; jamie@150: } jamie@150: jamie@150: void xtract_free_ooura_data(xtract_ooura_data *ooura_data) jamie@150: { jamie@150: free(ooura_data->ooura_ip); jamie@150: free(ooura_data->ooura_w); jamie@150: ooura_data->ooura_ip = NULL; jamie@150: ooura_data->ooura_w = NULL; jamie@150: ooura_data->initialised = false; jamie@150: } jamie@150: jamie@150: int xtract_init_ooura_(int N, int feature_name) jamie@150: { jamie@150: jamie@150: int M = N >> 1; jamie@150: jamie@150: if(feature_name == XTRACT_AUTOCORRELATION_FFT) jamie@150: { jamie@150: M = N; /* allow for zero padding */ jamie@150: } jamie@150: jamie@150: switch(feature_name) jamie@150: { jamie@150: case XTRACT_SPECTRUM: jamie@150: if(ooura_data_spectrum.initialised) jamie@150: { jamie@150: xtract_free_ooura_data(&ooura_data_spectrum); jamie@150: } jamie@150: xtract_init_ooura_data(&ooura_data_spectrum, M); jamie@150: break; jamie@150: case XTRACT_AUTOCORRELATION_FFT: jamie@150: if(ooura_data_autocorrelation_fft.initialised) jamie@150: { jamie@150: xtract_free_ooura_data(&ooura_data_autocorrelation_fft); jamie@150: } jamie@150: xtract_init_ooura_data(&ooura_data_autocorrelation_fft, M); jamie@150: break; jamie@150: case XTRACT_DCT: jamie@150: if(ooura_data_dct.initialised) jamie@150: { jamie@150: xtract_free_ooura_data(&ooura_data_dct); jamie@150: } jamie@150: xtract_init_ooura_data(&ooura_data_dct, M); jamie@150: case XTRACT_MFCC: jamie@150: if(ooura_data_mfcc.initialised) jamie@150: { jamie@150: xtract_free_ooura_data(&ooura_data_mfcc); jamie@150: } jamie@150: xtract_init_ooura_data(&ooura_data_mfcc, M); jamie@150: break; jamie@150: } jamie@150: jamie@150: return XTRACT_SUCCESS; jamie@150: } jamie@150: jamie@150: void xtract_free_ooura_(void) jamie@150: { jamie@150: if(ooura_data_spectrum.initialised) jamie@150: { jamie@150: xtract_free_ooura_data(&ooura_data_spectrum); jamie@150: } jamie@150: if(ooura_data_autocorrelation_fft.initialised) jamie@150: { jamie@150: xtract_free_ooura_data(&ooura_data_autocorrelation_fft); jamie@150: } jamie@150: if(ooura_data_dct.initialised) jamie@150: { jamie@150: xtract_free_ooura_data(&ooura_data_dct); jamie@150: } jamie@150: if(ooura_data_mfcc.initialised) jamie@150: { jamie@150: xtract_free_ooura_data(&ooura_data_mfcc); jamie@150: } jamie@150: } jamie@150: jamie@150: #else jamie@150: jamie@150: void xtract_init_vdsp_data(xtract_vdsp_data *vdsp_data, unsigned int N) jamie@150: { jamie@150: vdsp_data->setup = vDSP_create_fftsetupD(log2f(N), FFT_RADIX2); jamie@164: vdsp_data->fft.realp = (double *) malloc((N >> 1) * sizeof(double) + 1); jamie@164: vdsp_data->fft.imagp = (double *) malloc((N >> 1) * sizeof(double) + 1); jamie@150: vdsp_data->log2N = log2f(N); jamie@150: vdsp_data->initialised = true; jamie@150: } jamie@150: jamie@150: void xtract_free_vdsp_data(xtract_vdsp_data *vdsp_data) jamie@150: { jamie@150: free(vdsp_data->fft.realp); jamie@150: free(vdsp_data->fft.imagp); jamie@150: vDSP_destroy_fftsetupD(vdsp_data->setup); jamie@150: vdsp_data->fft.realp = NULL; jamie@150: vdsp_data->fft.imagp = NULL; jamie@150: vdsp_data->initialised = false; jamie@150: } jamie@150: jamie@150: int xtract_init_vdsp_(int N, int feature_name) jamie@150: { jamie@150: switch(feature_name) jamie@150: { jamie@150: case XTRACT_SPECTRUM: jamie@150: if(vdsp_data_spectrum.initialised) jamie@150: { jamie@150: xtract_free_vdsp_data(&vdsp_data_spectrum); jamie@150: } jamie@164: xtract_init_vdsp_data(&vdsp_data_spectrum, N); jamie@150: break; jamie@150: case XTRACT_AUTOCORRELATION_FFT: jamie@150: if(vdsp_data_autocorrelation_fft.initialised) jamie@150: { jamie@150: xtract_free_vdsp_data(&vdsp_data_autocorrelation_fft); jamie@150: } jamie@164: xtract_init_vdsp_data(&vdsp_data_autocorrelation_fft, N * 2); // allow for zero padding jamie@150: break; jamie@150: case XTRACT_DCT: jamie@150: if(vdsp_data_dct.initialised) jamie@150: { jamie@150: xtract_free_vdsp_data(&vdsp_data_dct); jamie@150: } jamie@164: xtract_init_vdsp_data(&vdsp_data_dct, N); jamie@150: case XTRACT_MFCC: jamie@150: if(vdsp_data_mfcc.initialised) jamie@150: { jamie@150: xtract_free_vdsp_data(&vdsp_data_mfcc); jamie@150: } jamie@164: xtract_init_vdsp_data(&vdsp_data_mfcc, N); jamie@150: break; jamie@150: } jamie@150: jamie@150: return XTRACT_SUCCESS; jamie@150: } jamie@150: jamie@150: void xtract_free_vdsp_(void) jamie@150: { jamie@150: if(vdsp_data_spectrum.initialised) jamie@150: { jamie@150: xtract_free_vdsp_data(&vdsp_data_spectrum); jamie@150: } jamie@150: if(vdsp_data_autocorrelation_fft.initialised) jamie@150: { jamie@150: xtract_free_vdsp_data(&vdsp_data_autocorrelation_fft); jamie@150: } jamie@150: if(vdsp_data_dct.initialised) jamie@150: { jamie@150: xtract_free_vdsp_data(&vdsp_data_dct); jamie@150: } jamie@150: if(vdsp_data_mfcc.initialised) jamie@150: { jamie@150: xtract_free_vdsp_data(&vdsp_data_mfcc); jamie@150: } jamie@150: } jamie@150: jamie@150: jamie@150: #endif jamie@150: jamie@150: int xtract_init_fft(int N, int feature_name) jamie@150: { jamie@150: if(!xtract_is_poweroftwo(N)) jamie@150: { jamie@150: fprintf(stderr, jamie@150: "libxtract: error: only power-of-two FFT sizes are supported by Ooura FFT.\n"); jamie@150: exit(EXIT_FAILURE); jamie@150: } jamie@150: #ifdef USE_OOURA jamie@150: return xtract_init_ooura_(N, feature_name); jamie@150: #else jamie@150: return xtract_init_vdsp_(N, feature_name); jamie@150: #endif jamie@150: } jamie@150: jamie@150: void xtract_free_fft(void) jamie@150: { jamie@150: #ifdef USE_OOURA jamie@150: xtract_free_ooura_(); jamie@150: #else jamie@150: xtract_free_vdsp_(); jamie@150: #endif jamie@150: } jamie@150: jamie@150: jamie@150: int xtract_init_bark(int N, double sr, int *band_limits) jamie@150: { jamie@150: jamie@150: double 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@150: jamie@150: int bands = XTRACT_BARK_BANDS; jamie@150: jamie@150: while(bands--) jamie@150: band_limits[bands] = edges[bands] / sr * N; jamie@150: /*FIX shohuld use rounding, but couldn't get it to work */ jamie@150: jamie@150: return XTRACT_SUCCESS; jamie@150: } jamie@150: jamie@146: int xtract_init_mfcc(int N, double nyquist, int style, double freq_min, double freq_max, int freq_bands, double **fft_tables) jamie@140: { jamie@98: jamie@140: int n, i, k, *fft_peak, M, next_peak; jamie@146: double 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@204: if (freq_bands <= 1) jamie@204: { jamie@204: return XTRACT_ARGUMENT_ERROR; jamie@204: } jamie@204: 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@146: mel_peak = (double *)malloc((freq_bands + 2) * sizeof(double)); jamie@1: /* +2 for zeros at start and end */ jamie@202: jamie@202: if (mel_peak == NULL) jamie@202: { jamie@202: perror("error"); jamie@202: return XTRACT_MALLOC_FAILED; jamie@202: } jamie@202: jamie@146: lin_peak = (double *)malloc((freq_bands + 2) * sizeof(double)); jamie@202: jamie@202: if (lin_peak == NULL) jamie@202: { jamie@202: perror("error"); jamie@204: free(mel_peak); jamie@202: return XTRACT_MALLOC_FAILED; jamie@202: } jamie@202: jamie@1: fft_peak = (int *)malloc((freq_bands + 2) * sizeof(int)); jamie@202: jamie@202: if (fft_peak == NULL) jamie@202: { jamie@202: perror("error"); jamie@204: free(mel_peak); jamie@204: free(lin_peak); jamie@202: return XTRACT_MALLOC_FAILED; jamie@202: } jamie@202: jamie@146: height_norm = (double *)malloc(freq_bands * sizeof(double)); jamie@202: jamie@202: if (height_norm == NULL) jamie@202: { jamie@202: perror("error"); jamie@204: free(mel_peak); jamie@204: free(lin_peak); jamie@204: free(fft_peak); jamie@107: return XTRACT_MALLOC_FAILED; jamie@202: } 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@204: 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@146: fft_tables[n][k] = 0.0; 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@146: fft_tables[n][k] = 0.0; 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@161: int xtract_init_wavelet_f0_state(void) jamie@161: { jamie@161: dywapitch_inittracking(&wavelet_f0_state); jamie@162: return XTRACT_SUCCESS; jamie@161: } jamie@161: jamie@146: double *xtract_init_window(const int N, const int type) jamie@140: { jamie@146: double *window; jamie@107: andrea@211: window = (double*)malloc(N * sizeof(double)); 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@146: void xtract_free_window(double *window) jamie@140: { jamie@107: free(window); jamie@107: } jamie@107: jamie@102: #ifdef __GNUC__ jamie@102: __attribute__((constructor)) void init() jamie@102: #else andrea@211: void _init() jamie@102: #endif jamie@102: { jamie@150: #ifdef USE_OOURA 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@173: printf("LibXtract compiled with ooura FFT\n"); jamie@150: #else jamie@150: vdsp_data_dct.initialised = false; jamie@150: vdsp_data_spectrum.initialised = false; jamie@150: vdsp_data_autocorrelation_fft.initialised = false; jamie@150: vdsp_data_mfcc.initialised = false; jamie@173: printf("LibXtract compiled with Accelerate FFT\n"); jamie@150: #endif jamie@102: }