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

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

// method: apply
//
// arguments:
//  Vector<AlgorithmData>& output: (output) output data
//  const Vector< CircularBuffer<AlgorithmData> >& input: (input) input data
//
// return: a boolean value indicating status
//
// this method calls the appropriate computation methods
//
boolean LogAreaRatio::apply(Vector<AlgorithmData>& output_a,
			    const Vector< CircularBuffer<AlgorithmData> >&
			    input_a) {

  // check the compute mode
  //
  if (cmode_d != FRAME_INTERNAL) {
    return Error::handle(name(), L"apply", ERR_UNSUPM, __FILE__, __LINE__);
  }

  // determine the number of input channels and force the output to be
  // that number
  //
  long len = input_a.length();
  output_a.setLength(len);
  boolean res = true;

  // start the debugging output
  //
  displayStart(this);
  
  // loop over the channels and call the compute method
  //
  for (long c = 0; c < len; c++) {

    // display the channel number
    //
    displayChannel(c);
    
    // call AlgorithmData::makeVectorFloat to force the output vector for
    // this channel to be a VectorFloat, call AlgorithmData::getVectorFloat
    // on the input for this channel to check that the input is
    // already a VectorFloat and return that vector.
    //
    res &= compute(output_a(c).makeVectorFloat(),
		   input_a(c)(0).getVectorFloat(),
		   input_a(c)(0).getCoefType(), c);

    // set the coefficient type for the output
    //            
    output_a(c).setCoefType(AlgorithmData::LOG_AREA_RATIO);
  }

  // finish the debugging output
  //
  displayFinish(this);
  
  // exit gracefully
  //
  return res;
}

// method: compute
//
// arguments:
//  VectorFloat& output: (output) output data
//  const VectorFloat& input: (input) input data
//  AlgorithmData::COEF_TYPE input_coef_type: (input) type of input
//  long index: (input) channel number
//
// return: a boolean value indicating status
//
// this method computes the log-area-ratio of single-channel
// reflection or prediction coefficients input using the specified
// algorithm and implementation
//
boolean LogAreaRatio::compute(VectorFloat& output_a,
			      const VectorFloat& input_a,
			      AlgorithmData::COEF_TYPE input_coef_type_a,
			      long index_a) {

  // declare local variables
  //
  boolean status = false;
  
  // branch on algorithm and implementation types
  //
  if (algorithm_d == LATTICE) {
    if (implementation_d == KELLY_LOCHBAUM) {
      status = computeLatticeKellyLochbaum(output_a, input_a,
					   input_coef_type_a);
    }
  }

  // possibly display the data
  //
  display(output_a, input_a, name());

  // exit gracefully
  //
  return status;
}

// method: computeLatticeKellyLochbaum
//
// arguments:
//  VectorFloat& output: (output) output data
//  const VectorFloat& input: (input) input data
//  AlgorithmData::COEF_TYPE input_coef_type: (input) type of input
//
// return: a boolean value indicating status
//
// this method computes the log-area-ratio of the input signal.
// log-area-ratio can be computed from reflection and prediction
// coefficients. this method is called by the public compute method.
//
boolean LogAreaRatio::computeLatticeKellyLochbaum(VectorFloat& output_a,
						  const VectorFloat& input_a,
						  AlgorithmData::COEF_TYPE
						  input_coef_type_a) {

  // check algorithm and implementation
  //
  if ((algorithm_d != LATTICE) ||
      (implementation_d != KELLY_LOCHBAUM)) {
    return Error::handle(name(), L"computeLatticeKellyLochbaum",
			 ERR, __FILE__, __LINE__);
  }

  // declare local variables
  //
  long order = input_a.length();
    
  // branch on input coefficient type
  //  Coefficient = REFLECTION
  //
  if (input_coef_type_a == AlgorithmData::REFLECTION) {

    // declare local variables
    //
    double g;
    output_a.setLength(order);

    // compute log area ratio using:
    //                        1 - refl_coef(i)
    //  log_area_ratio(i) = -------------------
    //                        1 + refl_coef(i)
    //
    for (long i = 0; i < order; i++) {
      if (input_a(i) <= (float)-1.0 || input_a(i) >= (float)1.0) {
	return Error::handle(name(), L"computeLatticeKellyLochbaum", Error::ARG, __FILE__, __LINE__);
      }
      g = log((double)((1 - input_a(i)) / (1 + input_a(i))));
      output_a(i) = (float)g;
    }
  }

  //  Coefficient = PREDICTION
  //
  else if (input_coef_type_a == AlgorithmData::PREDICTION) {

    // compute the reflection coefficient from prediction coefficient
    //
    Reflection refl;
    refl.set(Reflection::PREDICTION, Reflection::STEP_UP,
	     order, Reflection::DEF_DYN_RANGE);
    VectorFloat refl_const;
    refl.compute(refl_const, input_a, AlgorithmData::PREDICTION);

    // call compute method for reflection coefficient
    //
    computeLatticeKellyLochbaum(output_a, refl_const,
				AlgorithmData::REFLECTION);
  }

  // else: error unsupported coefficient type
  //
  else {
    return Error::handle(name(), L"computeLatticeKellyLochbaum",
			 ERR_UNCTYP, __FILE__, __LINE__);
  }
  
  // exit gracefully
  //
  return true;
}
