// file: extract_feature/extf_algo_2.cc
//

// isip include files
//
#include "extract_feature.h"
#include "extract_feature_constants.h"

#include <string.h>
#include <math.h>

// method: compute_fft_mfcc_cc
//
// arguments:
//  float_8* vector: (output) feature
//  float_8* window_buffer_a: (input) window of data
//
// This method uses the FFT to compute Mel-Cepstral coefficients
//

// compute the mel-frequencies
//
logical_1 Extract_feature::compute_mel_cc(int num_a, float_8* mel_a) {

  int k;
  for (k=0; k<num_a+1; k++) {
    mel_a[k] = 2595 * log10(1 + k*(sample_freq_d/((2*num_a)*700.0)));
  }
  // return without error
  //
  return ISIP_TRUE;
}

// compute the center frequence in mel-frequence domain
//
logical_1 Extract_feature::compute_cenf_cc(int num_a, float_8* cenf_a,
					   float_8* mel_a) {

  cenf_a[0] = 0.0;

  if (mel_width_d == (float_8)0) {
    float_8 s = mel_a[num_a];   
    for (int i = 1; i <= num_fbanks_d + 1; i++) {
      cenf_a[i] = (float_8) i / (float_8)(num_fbanks_d+1) * s;
    }
  }

  else {
    for (int i = 1; i <= num_fbanks_d + 1; i++) {
      cenf_a[i] = mel_width_d + cenf_a[i - 1];
    }
  }
    
  // return without error
  //
  return ISIP_TRUE;
}

logical_1 Extract_feature::compute_fft_mfcc_cc(float_8* vector_a,
					       int_4 num_coeffs_a, 
					       float_8* window_buffer_a) {

  int_4 size = power_of_2(window_num_samples_d);
  float_8 *spectrum = new float_8[size];
  float_8 *mfbank = new float_8[num_fbanks_d];
  float_8 *cepstrum = new float_8[num_coeffs_a + 1];

  memset(spectrum, 0, size * sizeof(float_8));
  memset(mfbank, 0, num_fbanks_d * sizeof(float_8));
  memset(cepstrum, 0, (num_coeffs_a+1) * sizeof(float_8));
  
  // compute the magnitude spectrum via the FFT
  //
  func_fft_cc(spectrum, window_buffer_a, size);

  // vocal tract length normalization (VTLN)
  //
  if (vtln_d)
    func_vtln_cc(spectrum, size / 2);

  // run the spectrum through a mel spaced triangular filter bank
  //
  func_mfbank_cc(mfbank, spectrum, size);

  // take the log of each filter bank coefficient
  //
  for (int n = 0; n < num_fbanks_d; n++) {
    if (mfbank[n] > 1) {
      mfbank[n] = log(mfbank[n]);
    } else {
      //mfbank[n] = log((float)ISIP_MINIMUM_FLOAT_4);
      mfbank[n] = 0;
    }
  }

  // take the DCT of the log filterbank amplitudes to compute the
  // cepstrum
  //
  cepstrum[0] = 0.0;
  int_4 n = 1;  
  if (c0_d) {
    n = 0;
  }
  
  for (; n < num_coeffs_a + 1; n++) {
    cepstrum[n] = (float_8)0;
    for (int_4 k = 0; k < num_fbanks_d; k++) {
      cepstrum[n] += mfbank[k] * cos((M_PI * (float_8)n *
				      ((float_8)k + 0.5))/
				     (float_8)(num_fbanks_d));
    }
    cepstrum[n] *= sqrt(2.0 / (float_8)(num_fbanks_d));
  }

  // implement liftering to smooth the cepstral coefficients
  //
  if (use_liftering_d == ISIP_TRUE) {
    func_lifter_cc(cepstrum, num_coeffs_a + 1);
  }
  
  // copy over the specified number of mfcc's onto the vector
  //
  if (c0_d) {

    // move the c0 to end, so that the order is c1 c2 .. cn c0
    //
    float_8 temp = cepstrum[0];

    for (int_4 n = 0; n < num_coeffs_a; n++) {
      cepstrum[n] = cepstrum[n+1];      
    }
    cepstrum[num_coeffs_a] = temp;
      
    memcpy(vector_a, &cepstrum[0], (num_coeffs_a + 1) * sizeof(float_8));    
  }
  
  else
    memcpy(vector_a, &cepstrum[1], num_coeffs_a * sizeof(float_8));

  // clean up memory
  //
  delete [] spectrum;
  delete [] mfbank;
  delete [] cepstrum;

  // return without error
  //
  return ISIP_TRUE;
}
