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

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

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

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

// method: dct4Real
//
// 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 4
// (DCT_IV) 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) * sum{x[n] * cos((2k+1)*(2n+1)*pi/4N)}, k = 0,1,..,N-1
//                    n=[0:N-1]
//
// Inverse Algorithm:
//  x[n] = sqrt(2/N) * sum{C[k] * cos((2k+1)*(2n+1)*pi/4N)}, n = 0,1,..,N-1
//                  k=[0:N-1]
//
boolean FourierTransform::dct4Real(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();
  long M = (olen_d == DEF_LENGTH) ? N : (long)olen_d;
  float norm_factor = sqrt(2.0 / N);
  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_IV
    //
    for (long k = 0; k < M; k++) {
      
      // initialize values to zero
      //
      sum = 0.0;
      
      // loop over the length of input vector
      //
      for (long n = 0; n < N; n++) {
	sum += (float)input_a(n) *
	  cos((2 * k + 1) * (2 * n + 1) * (Integral::PI) / (4 * N));
      }

      // normalize the output coefficients
      //
      output_a(k) = sum * norm_factor;
    }
  }

  else {

    // inverse algorithm of DCT_IV
    //
    for (long n = 0; n < M; n++) {
      
      // initialize output value
      //
      sum = 0.0;
      
      // loop over the length of input vector
      //
      for (long k = 0; k < N; k++) {
	sum += (float)input_a(k) *
	  cos((2 * k + 1) * (2 * n + 1) * (Integral::PI) / (4 * N));
      }
      output_a(n) = sum * norm_factor;
    }
  }    

  // exit gracefully
  //
  return true;
}

// method: dct4Complex
//
// 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::dct4Complex(VectorFloat& output_a,
				     const VectorFloat& input_a) {

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