// file: $isip/class/sp/AudioFrontEnd/afnd_00.cc
// version: $Id: afnd_00.cc 9236 2003-06-23 18:12:22Z gao $
//

// isip include files
//
#include "AudioFrontEnd.h"
#include <typeinfo>
 
//------------------------------------------------------------------------
//
// required public methods
//
//-----------------------------------------------------------------------

// method: default constructor
//
// arguments: none
//
// return: none
//
// this is the default constructor for the AudioFrontEnd class
//
AudioFrontEnd::AudioFrontEnd() {

  // initialize class data
  //
  input_data_type_d = DEF_INPUT_DATA_TYPE;
  input_flag_d = DEF_INPUT_FLAG;

  frame_duration_d = DEF_FRAME_DURATION;
  signal_duration_d = DEF_SIGNAL_DURATION;
  sample_frequency_d = DEF_SAMPLE_FREQ;
  number_of_features_d = DEF_NUMBER_OF_FEATURES;

  start_time_d = DEF_START_TIME;
  end_time_d = DEF_END_TIME;
  context_window_d = DEF_CONTEXT_WINDOW;
  partial_process_d = DEF_PARTIAL_PROCESS;
  channel_index_d = DEF_CHANNEL_INDEX;
  offset_frame_d = DEF_OFFSET_FRAME;
  
  num_channels_d = DEF_NUM_CHANNELS;

  input_filename_d.clear();
  output_directory_d.assign(String::NULL_STRING);
  output_basename_d.assign(String::NULL_STRING);
  output_extension_d.assign(String::NULL_STRING);  
  output_filename_d.clear();
  output_preserve_d.assign(Filename::DEF_DIR_PRES);
  output_suffix_d.assign(String::NULL_STRING);
  output_type_flag_d = DEF_OUTPUT_TYPE_FLAG;  

  recipe_d.setAllocationMode(DstrBase::USER);
  coef_name_d.assign(DEF_COEF_NAME);
  data_mode_d = AlgorithmBase::DEF_DMODE;

  // initialize other parameters
  //
  end_of_data_d = false;
  resetBuffer();
}

// method: copy constructor
//
// arguments:
//  const AudioFrontEnd& arg: (input) the AudioFrontEnd to copy
//
// return: none
//
// this is the copy constructor for the AudioFrontEnd class
//
AudioFrontEnd::AudioFrontEnd(const AudioFrontEnd& arg_a) {
  
  // initialize class data
  //
  recipe_d.setAllocationMode(DstrBase::USER);
  resetBuffer();

  // call the assign method to copy the AudioFrontEnd
  //
  assign(arg_a);
}

// method: assign
//
// arguments:
//  const AudioFrontEnd& arg: (input) object to be assigned
//
// return: a boolean value indicating status
//
// this method assigns the input object to the current object
//
boolean AudioFrontEnd::assign(const AudioFrontEnd& arg_a) {
  
  // copy all parameters
  //
  input_data_type_d = arg_a.input_data_type_d; 
  input_flag_d = arg_a.input_flag_d;
  audio_input_d.assign(arg_a.audio_input_d);
  feature_input_d.assign(arg_a.feature_input_d);
  
  frame_duration_d.assign(arg_a.frame_duration_d);
  signal_duration_d = arg_a.signal_duration_d;
  number_of_features_d.assign(arg_a.number_of_features_d);

  start_time_d = arg_a.start_time_d;
  end_time_d = arg_a.end_time_d;
  context_window_d = arg_a.context_window_d;
  partial_process_d.assign(arg_a.partial_process_d);
  offset_frame_d = arg_a.offset_frame_d;
  
  channel_index_d = arg_a.channel_index_d;
  
  sample_frequency_d = arg_a.sample_frequency_d;
  num_channels_d = arg_a.num_channels_d;

  // copy the recipe
  //
  recipe_d.clear(Integral::FREE);
  recipe_d.setAllocationMode(DstrBase::SYSTEM);
  recipe_d.assign(arg_a.recipe_d);
  recipe_d.setAllocationMode(DstrBase::USER);

  component_list_d.assign(arg_a.component_list_d);
  
  // remap the algorithms with internal pointers, not shared ones
  //
  coef_components_d.clear();
  if (arg_a.coef_name_d.length() > 0) {
    setCoefName(arg_a.coef_name_d);
  }
  
  // copy the data processing mode
  //
  data_mode_d = arg_a.data_mode_d;
  
  // reset the buffers
  //
  return resetBuffer();
}

// method: eq
//
// arguments:
//  const AudioFrontEnd& arg: (input) the AudioFrontEnd to compare
//
// return: a boolean value indicating status
//
// this method checks whether the current AudioFrontEnd object is identical
// to the input object
//
boolean AudioFrontEnd::eq(const AudioFrontEnd& arg_a) const {

  // compare the configuration of these two AudioFrontEnd
  //
  if ((input_data_type_d != arg_a.input_data_type_d) ||
      (input_flag_d != arg_a.input_flag_d) ||
      (!frame_duration_d.eq(arg_a.frame_duration_d)) ||
      (signal_duration_d != arg_a.signal_duration_d) ||
      (!number_of_features_d.eq(arg_a.number_of_features_d)) ||
      (!sample_frequency_d.eq(arg_a.sample_frequency_d)) ||
      (!start_time_d.eq(arg_a.start_time_d)) ||
      (!end_time_d.eq(arg_a.end_time_d)) ||
      (!partial_process_d.eq(arg_a.partial_process_d)) ||
      (offset_frame_d != arg_a.offset_frame_d) ||
      (channel_index_d != arg_a.channel_index_d) ||
      (num_channels_d != arg_a.num_channels_d) ||
      (!coef_name_d.eq(arg_a.coef_name_d))) {
    return false;
  }

  // they are equal, exit gracefully
  //
  return true;
}

// method: clear
//
// arguments:
//  Integral::CMODE ctype: (input) clear mode
//
// return: a boolean value indicating status
//
// this method clears the contents of AudioFrontEnd and close the file
// if necessary
//
boolean AudioFrontEnd::clear(Integral::CMODE ctype_a) {

  // close the AudioFile
  //
  if (audio_input_d.isOpen()) {
    audio_input_d.close();
  }

  // close the FeatureFile
  //
  if (feature_input_d.isOpen()) {
    feature_input_d.close();
  }
  
  // clean up the components
  //
  recipe_d.clear(Integral::FREE);
  coef_components_d.clear(ctype_a);
  coef_name_d.assign(DEF_COEF_NAME);

  // clear the parameters
  //
  input_data_type_d = DEF_INPUT_DATA_TYPE;
  input_flag_d = DEF_INPUT_FLAG;

  frame_duration_d = DEF_FRAME_DURATION;
  signal_duration_d = DEF_SIGNAL_DURATION;
  number_of_features_d = DEF_NUMBER_OF_FEATURES;  
  start_time_d = DEF_START_TIME;
  end_time_d = DEF_END_TIME;
  context_window_d = DEF_CONTEXT_WINDOW;
  partial_process_d = DEF_PARTIAL_PROCESS;
  offset_frame_d = DEF_OFFSET_FRAME;
  channel_index_d=DEF_CHANNEL_INDEX;
 
  num_channels_d = DEF_NUM_CHANNELS;
  sample_frequency_d = DEF_SAMPLE_FREQ;

  end_of_data_d = false;
  
  // clear the features and the buffer
  //
  return buf_d.clear(ctype_a);
}

//---------------------------------------------------------------------------
//
// class-specific public methods:
//  public methods required by the FrontEndBase interface contract
//
//---------------------------------------------------------------------------

// method: assign
//
// arguments:
//  const FrontEndBase& arg: (input) the object to be assigned
//
// return: a boolean value indicating status
//
// this method assigns the input object to the current object
//
boolean AudioFrontEnd::assign(const FrontEndBase& arg_a) {
  
  // case: input is an AudioFrontEnd object
  //
  if (typeid(arg_a) == typeid(AudioFrontEnd)) {
    return assign((AudioFrontEnd&)arg_a);
  }

  // case: other
  //  if the input object is not an AudioFrontEnd object, error
  //
  else {
    return Error::handle(name(), L"assign", Error::ARG, __FILE__, __LINE__);
  }
}

// method: eq
//
// arguments:
//  const FrontEndBase& arg: (input) the object to compare
//
// return: a boolean value indicating status
//
// this method checks whether the current AudioFrontEnd object is identical
// to the input object
//
boolean AudioFrontEnd::eq(const FrontEndBase& arg_a) const {

  // case: input is an AudioFrontEnd object
  //
  if (typeid(arg_a) == typeid(AudioFrontEnd)) {
    return eq((AudioFrontEnd&)arg_a);
  }

  // case: other
  //  if the input algorithm object is not an AudioFrontEnd object, error
  //
  else {
    return Error::handle(name(), L"eq", Error::ARG, __FILE__, __LINE__);
  }
  
  // they are equal, exit gracefully
  //
  return true;
}

// method: init
//
// arguments:
//  float start_time: (input) start time to process
//  float end_time: (input) stop time to process
//  int channel_tag: (input) channel tag to process
//  
// return: a boolean value indicating status
//
// this method processes the given frame of data
//
boolean AudioFrontEnd::init(float start_time_a, float end_time_a,
			    int channel_tag_a) {
  
  start_time_d = start_time_a;
  end_time_d = end_time_a;
  channel_index_d = channel_tag_a;
  partial_process_d = true;

  double num_frames = (double) start_time_d;
  num_frames /= frame_duration_d;

  // read from features file
  //
  if (input_data_type_d == FrontEndBase::FEATURES) {  
    offset_frame_d = (long)Integral::floor(num_frames);
  }
      
  // exit gracefully
  //
  return true;
}


//-----------------------------------------------------------------------------
//
// we define non-integral constants in the default constructor
//      
//-----------------------------------------------------------------------------

// constants: class name
//
const String AudioFrontEnd::CLASS_NAME(L"AudioFrontEnd");

// constants: i/o related constants
//
const String AudioFrontEnd::PARAM_INPUT_DATA_TYPE(L"input_data_type");
const String AudioFrontEnd::PARAM_INPUT_FLAG(L"input_flag");
const String AudioFrontEnd::PARAM_AUDIO_INPUT(L"audio_input");
const String AudioFrontEnd::PARAM_FEATURE_INPUT(L"feature_input");

const String AudioFrontEnd::PARAM_FRAME_DURATION(L"frame_duration");
const String AudioFrontEnd::PARAM_NUMBER_OF_FEATURES(L"number_of_features");
const String AudioFrontEnd::PARAM_SIGNAL_DURATION(L"signal_duration");
const String AudioFrontEnd::PARAM_START_TIME(L"start_time");
const String AudioFrontEnd::PARAM_END_TIME(L"end_time");
const String AudioFrontEnd::PARAM_CONTEXT_WINDOW(L"context_window");
const String AudioFrontEnd::PARAM_CHANNEL_INDEX(L"channel_index"); 

const String AudioFrontEnd::PARAM_COMPONENT_LIST(L"components");
const String AudioFrontEnd::PARAM_COEF_NAME(L"target");
const String AudioFrontEnd::PARAM_DATA_MODE(L"data_mode");

// constants: default arguments to methods
//
const String AudioFrontEnd::DEF_COEF_NAME(L"__output_FEATURES");
const String AudioFrontEnd::DEF_COMPONENT_LIST(L"<this_file>");

// constants: some internal constants
//
const String AudioFrontEnd::SAMPLED_DATA_NAME(L"__input_SAMPLED_DATA");
const Long AudioFrontEnd::SAMPLED_DATA_TAG(Sof::NO_TAG);

// static instantiations: memory manager
//
MemoryManager AudioFrontEnd::mgr_d(sizeof(AudioFrontEnd));
