void bob::ap::Ceps::operator()(const blitz::Array<double,1>& input, blitz::Array<double,2>& ceps_matrix) { // Get expected dimensionality of output array blitz::TinyVector<int,2> feature_shape = bob::ap::Ceps::getShape(input); // Check dimensionality of output array bob::core::array::assertSameShape(ceps_matrix, feature_shape); int n_frames=feature_shape(0); int shift_frame=0; double last_frame_elem=0; // Create the holder for the previous frame and make sure it's the same as the current frame // Used by SSFC features computation blitz::Array<double,1> _prev_frame_d; _prev_frame_d.resize(m_cache_frame_d.shape()); // Create the temporary holder for SSFC features computation blitz::Array<double,1> _temp_frame_d; _temp_frame_d.resize(m_cache_frame_d.shape()); if (m_ssfc_features) { //we are going to always process the next frame within the loop shift_frame = 1; // Init the first frame to the input extractNormalizeFrame(input, 0, _prev_frame_d); // Apply pre-emphasis pre_emphasis(_prev_frame_d, last_frame_elem); // Apply the Hamming window hammingWindow(_prev_frame_d); // Take the power spectrum of the first part of the FFT powerSpectrumFFT(_prev_frame_d); } blitz::Range r1(0,m_n_ceps-1); for (int i=0; i<n_frames; ++i) { // Init the current frame from the input, we process (i+1)th frame for SSFC features extractNormalizeFrame(input, i+shift_frame, m_cache_frame_d); // Update output with energy if required if (m_with_energy) ceps_matrix(i,(int)m_n_ceps) = logEnergy(m_cache_frame_d); // Apply pre-emphasis pre_emphasis(m_cache_frame_d, last_frame_elem); // Apply the Hamming window hammingWindow(m_cache_frame_d); // Take the power spectrum of the first part of the FFT // Note that after this call, we only operate on the first half of m_cache_frame_d array. The second half is ignored. // powerSpectrumFFT changes first half+1 elements of m_cache_frame_d array powerSpectrumFFT(m_cache_frame_d); if (m_ssfc_features) { // retrieve the previous frame into our temp _temp_frame_d = _prev_frame_d; // remember the current frame for the next round, before we change current frame _prev_frame_d = m_cache_frame_d; // Computation of SSFC features: // We take the previous frame and find the difference between values of current and previous frames m_cache_frame_d -= _temp_frame_d; // We compute norm2 for the difference as per SSFC features m_cache_frame_d = blitz::pow2(m_cache_frame_d); // Then, we can apply the filter and DCT later on } // Filter with triangular or rectangular filter bank (either in linear or Mel domain) filterBank(m_cache_frame_d); // Apply DCT kernel and update the output blitz::Array<double,1> ceps_matrix_row(ceps_matrix(i,r1)); if (m_scfc_features) // do not apply DCT on SCFC features ceps_matrix_row = m_cache_filters(r1); else applyDct(ceps_matrix_row); } //compute the center of the cut-off frequencies const int n_coefs = (m_with_energy ? m_n_ceps + 1 : m_n_ceps); blitz::Range rall = blitz::Range::all(); blitz::Range ro0(0,n_coefs-1); blitz::Range ro1(n_coefs,2*n_coefs-1); blitz::Range ro2(2*n_coefs,3*n_coefs-1); if (m_with_delta) { blitz::Array<double,2> ceps_matrix_0(ceps_matrix(rall,ro0)); blitz::Array<double,2> ceps_matrix_1(ceps_matrix(rall,ro1)); addDerivative(ceps_matrix_0, ceps_matrix_1); if (m_with_delta_delta) { blitz::Array<double,2> ceps_matrix_2(ceps_matrix(rall,ro2)); addDerivative(ceps_matrix_1, ceps_matrix_2); } } }
double * extractFeatures(short *samples) { int N = firstPowerOfTwo(S); double *P; complex *x; complex *X; double *fftBins; double *filterBankEnergies; double *DCT; x = (complex *)malloc(sizeof(complex_t) * N); if (x == NULL) { Log("Error: memory allocation failed\n"); return NULL; } for (int i = 0; i < S; i++) { x[i].re = (double)samples[i] * hammingWindow(i, N); x[i].im = 0; } for (int i = S; i < N; i++) { x[i].re = 0; x[i].im = 0; } X = fft(x, N); P = (double *)malloc(sizeof(double) * (N / 2 + 1)); if (P == NULL) { Log("Error: memory allocation failed\n"); return NULL; } for (int i = 0; i <= N / 2; i++) { P[i] = (1.0 / (double)N) * pow(magnitude(X[i]), 2); } double melLowerBound = 1125.0 * log(1.0 + ((double)MEL_LOWER_BOUND_HZ / 700.0)); double melUpperBound = 1125.0 * log(1.0 + ((double)MEL_UPPER_BOUND_HZ / 700.0)); fftBins = (double *)malloc(sizeof(double) * (FILTERBANKS + 2)); if (fftBins == NULL) { Log("Error: memory allocation failed\n"); return NULL; } double diff = (melUpperBound - melLowerBound) / ((double)FILTERBANKS + 1); double filter; for (int i = 0; i < FILTERBANKS + 2; i++) { filter = 700.0 * (exp((melLowerBound + (double)i * diff) / 1125.0) - 1.0); fftBins[i] = floor(filter * (N + 1) / SAMPLING_FREQ); } filterBankEnergies = (double *)malloc(sizeof(double) * FILTERBANKS); if (filterBankEnergies == NULL) { Log("Error: memory allocation failed\n"); return NULL; } for (int m = 1; m <= FILTERBANKS; m++) { double result = 0; for (int k = 0; k <= N / 2; k++) { if (k >= fftBins[m - 1] && k <= fftBins[m]) { result += P[k] * ((k - fftBins[m - 1]) / (fftBins[m] - fftBins[m - 1])); } else if (k >= fftBins[m] && k <= fftBins[m + 1]) { result += P[k] * ((fftBins[m + 1] - k) / (fftBins[m + 1] - fftBins[m])); } } filterBankEnergies[m - 1] = log(result); } DCT = (double *)malloc(sizeof(double) * FILTERBANKS); if (DCT == NULL) { Log("Error: memory allocation failed\n"); return NULL; } DCT[0] = 0.0; double N1 = (1 / sqrt((double)FILTERBANKS)); for (int m = 0; m < FILTERBANKS; m++) { DCT[0] += N1 * filterBankEnergies[m]; } N1 = sqrt(2.0 / (double)FILTERBANKS); for (int k = 1; k < FILTERBANKS; k++) { DCT[k] = 0.0; for (int m = 0; m < FILTERBANKS; m++) { DCT[k] += N1 * filterBankEnergies[m] * cos((M_PI * (double)k * (2.0 * (double)m + 1)) / (2.0 * (double)FILTERBANKS)); } } /*for (int k = 0; k < FILTERBANKS; k++) { Log("%lf\n", DCT[k]); }*/ free(P); free(x); free(X); free(fftBins); free(filterBankEnergies); return DCT; }