// file: extract_feature/extf_func_6.cc
//

// isip include files
//
#include "extract_feature.h"
#include <string.h>
#include <math.h>
#include "extract_feature_constants.h"

// method: func_vtln_cc
//
// arguments:
//  float_8* vector: (input/output) spectrum/normalized spectrum
//  int_4 num_samples: (input) number of samples to operate upon in frequency
//
// This method is to perform some arogrithm upon the output of fourier
// transform to warp the spectrum to normalized spectrum.
//
logical_1 Extract_feature::func_vtln_cc(float_8* vector_a,
					int_4 num_samples_a) {

  // define local variables
  //
  float_8* vec_out;
  
  if (vtln_algo_d == EXTF_BILINEAR) {

    // bilinear algorithm
    //
    
    // if VTLN factor equals 1.0, there is no warping
    //
    if (vtln_factor_d == 1.0) {
      return ISIP_TRUE;
    }
    
    // compute the width of each spectral bin in radians
    //
    float_8 omiga_bin = 2 * M_PI / EXTF_FT_ORDER;

    // compress or expand the frequency axis using the bilinear transform
    //
    vec_out = new float_8[num_samples_a];
    vec_out[0] = vector_a[0];
    for (int_4 k = 1; k < num_samples_a; k++) {

      // omiga  = normalized frequency (2 * pi * (f/fs)) = (2 * pi * (k/N))
      // omiga_alpha = the warped frequency 
      //
      float_8 omiga = 2 * M_PI * k / EXTF_FT_ORDER;

      // compute the warped frequency:
      //
      float_8 omiga_alpha = omiga +
	2 * atan(((1 - vtln_factor_d) * sin(omiga)) /
		 (1 - (1 - vtln_factor_d) * cos(omiga)));
      
      // omiga_alpha_index: the index of bin that omiga_alpha falls in 
      //                    so this index could be no integer value
      // omiga_l: the index of the bin that omiga_alpha falls in
      // omiga_h: the index to the right of the bin that omiga_alpha  falls in
      //
      float_8 omiga_alpha_index = omiga_alpha / omiga_bin;
      int_4 omiga_l = (int_4) floor(omiga_alpha_index);
      int_4 omiga_h = omiga_l + 1;

      // interpolate the frequency bins with simple linear interpolation.
      // last paragraph of section 2.2 in the reference.
      // rho: the distance between omiga_alpha and omiga_h
      //
      float_8 rho = omiga_h - omiga_alpha_index;
      vec_out[k] = rho * vector_a[omiga_l] + (1 - rho) * vector_a[omiga_h];
    }
    
    // copy over the specified number of mfcc's onto the vector
    //
    memcpy(vector_a, vec_out, num_samples_a * sizeof(float_8));

    // free memory
    //
    delete [] vec_out;    
  }

  // exit gracefully
  //
  return ISIP_TRUE;
}

