// file: $isip/class/algo/FourierTransform/ft_15.cc
// version: $Id: ft_15.cc 8165 2002-05-31 21:57:33Z picone $
//

// isip include files
//
#include "FourierTransform.h"

// method: dct1Init
//
// arguments:
//  long order: (input) new order
//
// return: a boolean value indicating status
//
// this method creates lookup tables for the discrete cosine transform
//
boolean FourierTransform::dct1Init(long order_a) {

  return Error::handle(name(), L"dct1Init", ERR, __FILE__, __LINE__);
}

// method: dct1Real
//
// arguments:
//  VectorFloat& output: (output) output data vector
//  const VectorFloat& input: (input) input data vector
//
// return: a boolean value indicating status
//
// this method implements a discrete cosine transformation with type 1
// (DCT_I) given input vector
//
// this code very closely follows the algorithm described in:
//   X. Huang, A. Acero, and H. Hon, Spoken Language Processing,
//   Prentice Hall PTR, Upper Saddle River, New Jersey, pp. 228, 2001.
//   
//   K, Rao, and P. Yip, Discrete Cosine Transform: Algorithms,
//   Advantages and Applications, Academic Press, San Diego,
//   California, pp. 15, 1990.
//
// Forward Algorithm:
//  C[k] = sqrt(2/N) * c[k] * sum{c[n] * x[n] * cos(k*n*pi/N)}, k = 0,1,..,N
//                           n=[0:N]
//
// Inverse Algorithm:
//  x[n] = sqrt(2/N) * c[n] * sum{c[k] * C[k] * cos(k*n*pi/N)}, n = 0,1,..,N
//                           k=[0:N]
//
//    where, c[p] = 1 / sqrt(2) when p = 0 or N
//           c[p] = 1           when p != 0 or N
//
boolean FourierTransform::dct1Real(VectorFloat& output_a,
				   const VectorFloat& input_a) {

  // declare local variable
  //  N: required input length
  //  M: default or user specified output length
  //
  long N = input_a.length(), order = N - 1;
  long M = (olen_d == DEF_LENGTH) ? N : (long)olen_d;
  long n, k;
  float norm_factor = sqrt(2.0 / order), norm_N = sqrt(0.5);
  float sum;
  
  // set the length of the output vector
  //
  output_a.setLength(M);

  // compute discrete cosine transform
  //
  if (direction_d == FORWARD) {

    // forward algorithm of DCT_I
    //
    for (k = 0; k < M; k++) {
      
      // initialize values to zero
      //
      sum = input_a(0) * norm_N;
      
      // loop over the length of input vector
      //
      for (n = 1; n < order; n++) {
	sum += (float)input_a(n) * cos(k * n * (Integral::PI) / order);
      }

      // sum the Nth input
      //
      sum += (float)input_a(n) * norm_N * cos(k * n * (Integral::PI) / order);
      
      // normalize the output coefficients
      //
      if (k % order) {
	output_a(k) = sum * norm_factor;
      }
      else {
	output_a(k) = sum * norm_factor * norm_N;
      }
    }
  }

  else {

    // inverse algorithm of DCT_I
    //
    for (n = 0; n < M; n++) {
      
      // initialize output value
      //
      sum = input_a(0) * norm_N;
      
      // loop over the length of input vector
      //
      for (k = 1; k < order; k++) {
	sum += (float)input_a(k) *  cos(k * n * (Integral::PI) / order);
      }

      // sum the Nth input
      //
      sum += (float)input_a(k) * norm_N * cos(k * n * (Integral::PI) / order);
      
      // normalize the output coefficients
      //
      if (n % order) {
	output_a(n) = sum * norm_factor;
      }
      else {
	output_a(n) = sum * norm_factor * norm_N;
      }
    }
  }    

  // exit gracefully
  //
  return true;
}

// method: dct1Complex
//
// arguments:
//  VectorFloat& output: (output) output data vector
//  const VectorFloat& input: (input) input data vector
//
// return: a boolean value indicating status
//
// this method computes the discrete cosine transform of given input vector
//
boolean FourierTransform::dct1Complex(VectorFloat& output_a,
				     const VectorFloat& input_a) {

  return Error::handle(name(), L"dct1Complex", Error::NOT_IMPLEM,
		       __FILE__, __LINE__);  
  
}
