// file: $isip_ifc/class/sp/AudioFrontEnd/AudioFrontEnd.h
// version: $Id: AudioFrontEnd.h 10640 2007-01-27 02:36:04Z tm334 $
//

// this file defines the AudioFrontEnd class
//

// make sure definitions are only made once
//
#ifndef ISIP_AUDIO_FRONT_END
#define ISIP_AUDIO_FRONT_END

// isip include files
//
#ifndef ISIP_FRONTEND_BASE
#include <FrontEndBase.h>
#endif

#ifndef ISIP_FTR_BUFFER
#include <FtrBuffer.h>
#endif

#ifndef ISIP_ALGORITHM_BASE
#include <AlgorithmBase.h>
#endif

#ifndef ISIP_AUDIO_FILE
#include <AudioFile.h>
#endif

#ifndef ISIP_FEATURE_FILE
#include <FeatureFile.h>
#endif

#ifndef ISIP_FILENAME
#include <Filename.h>
#endif

#ifndef ISIP_RECIPE
#include <Recipe.h>
#endif

#ifndef ISIP_VECTOR
#include <Vector.h>
#endif

#ifndef ISIP_SINGLE_LINKED_LIST
#include <SingleLinkedList.h>
#endif

#ifndef ISIP_COMPONENT
#include <Component.h>
#endif

#ifndef ISIP_STRING
#include <String.h>
#endif

#ifndef ISIP_FLOAT
#include <Float.h>
#endif

#ifndef ISIP_LONG
#include <Long.h>
#endif

#ifndef ISIP_BOOLEAN
#include <Boolean.h>
#endif

// forward class definitions
//
class VectorFloat;

// AudioFrontEnd: a class for multichannel audio signals. this class implements
// a general front end for audio signal data processing. signals can be
// in many different formats, precisions, encodings, etc.
//
class AudioFrontEnd : public FrontEndBase {

  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:

  // define the class name
  //
  static const String CLASS_NAME;
  
  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------

  static const String PARAM_INPUT_DATA_TYPE;
  static const String PARAM_INPUT_FLAG;  
  static const String PARAM_AUDIO_INPUT;
  static const String PARAM_FEATURE_INPUT;

  static const String PARAM_FRAME_DURATION;
  static const String PARAM_SIGNAL_DURATION;
  static const String PARAM_NUMBER_OF_FEATURES;
  static const String PARAM_START_TIME;
  static const String PARAM_END_TIME;
  static const String PARAM_CONTEXT_WINDOW;
  static const String PARAM_CHANNEL_INDEX;
  
  static const String PARAM_COMPONENT_LIST;
  static const String PARAM_COEF_NAME;
  static const String PARAM_DATA_MODE;

  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------
  
  // default values for i/o related parameters
  //
  static const FrontEndBase::DATA_TYPE DEF_INPUT_DATA_TYPE = FrontEndBase::DEF_DATA_TYPE;
  static const boolean DEF_INPUT_FLAG = true;
  static const boolean DEF_OUTPUT_TYPE_FLAG = false;
  static const boolean DEF_PARTIAL_PROCESS = false;
  
  static const float DEF_FRAME_DURATION = 0.01;
  static const float DEF_SIGNAL_DURATION = 0.1;
  static const long DEF_NUMBER_OF_FEATURES = 39;  
  static const long DEF_OFFSET_FRAME = 0;
  static const float ALL_TIME = -1;
  static const float DEF_START_TIME = 0;

  // ‘ALL_TIME’ cannot appear in a constant-expression
  //
  //  static const float DEF_END_TIME = ALL_TIME;
  //  static const float DEF_CONTEXT_WINDOW = ALL_TIME;
  static const float DEF_END_TIME = -1;
  static const float DEF_CONTEXT_WINDOW = -1;

  // other signal processing related parameters
  //
  static const float DEF_SAMPLE_FREQ = 8000.0;
  static const long DEF_NUM_CHANNELS = AudioFile::DEF_NUM_CHANNELS;
  static const long DEF_CHANNEL_INDEX = AudioFile::CHANNEL_TAG_ALL; // (= -2);

  // default arguments to methods
  //
  static const String DEF_COEF_NAME;
  static const String DEF_COMPONENT_LIST;

  // define some internal names used to facilitate recipe processing
  //
  static const String SAMPLED_DATA_NAME;
  static const Long SAMPLED_DATA_TAG;

  // miscellaneous parameters
  //
  static const long DEF_COEF_BUF_CAPACITY = 512;

  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  
  
  static const long ERR = 80000;
  static const long ERR_NOVEC = 80001;
  static const long ERR_EMPTY = 80002;
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // hold all features in a circular buffer
  //
  FtrBuffer buf_d;

  // input data type
  //
  DATA_TYPE input_data_type_d;

  // define the data processing mode
  //
  AlgorithmBase::DMODE data_mode_d;  
  
  // define a audio file
  //
  AudioFile audio_input_d;
  
  // define a feature file
  //
  FeatureFile feature_input_d;
  
  // define variables to handle the recipe
  //
  Filename component_list_d;
  Recipe recipe_d;

  // define an ordered list of the components we will apply.  the first
  // element is the list of components that can be applied with zero
  // latency, the second with one frame of latency, etc.
  //
  Vector< SingleLinkedList<Component> > coef_components_d;

  // the name of the required output
  //
  String coef_name_d;

  // parameters for excising
  //
  Float start_time_d;
  Float end_time_d;
  Long channel_index_d;
  long offset_frame_d;

  // how far out of the excised window should we look for signal
  // analysis?
  //
  Float context_window_d;
  
  // other signal processing related parameters
  //
  Float frame_duration_d;
  Float sample_frequency_d;  
  Float signal_duration_d;
  Long number_of_features_d;
  long num_channels_d;

  // input file specification, specially used when Constant class in
  // recipe
  //
  Vector<Filename> input_filename_d;

  // output file specification
  //
  Vector<Filename> output_filename_d;
  String output_directory_d;
  String output_basename_d;  
  String output_extension_d;
  Long output_preserve_d;
  String output_suffix_d;
  File::TYPE output_type_d;
  boolean output_type_flag_d;
  
  // are we out of data ?
  //
  boolean end_of_data_d;

  // do we need an input file?
  //
  Boolean input_flag_d;

  // do we process partial data
  //
  Boolean partial_process_d;
  
  // id for output, generally it is the basename of input file
  //
  String id_d;
  
  // the memory manager
  //
  static MemoryManager mgr_d;
  
  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:

  // method: name
  //
  static const String& name() {
    return CLASS_NAME;
  }
  
  static boolean diagnose(Integral::DEBUG level);

  // method: setDebug
  //
  boolean setDebug(Integral::DEBUG level) {
    debug_level_d = level;
    recipe_d.setDebug(level);
    buf_d.setDebug(level);
    return true;
  }
  
  // other debug methods
  //
  boolean debug(const unichar* message) const;

  // method: destructor
  //
  ~AudioFrontEnd() {
    clear();
  }

  // other constructors:
  //
  AudioFrontEnd();
  AudioFrontEnd(const AudioFrontEnd& arg);

  // assign methods
  //
  boolean assign(const AudioFrontEnd& arg);

  // i/o methods
  //
  long sofSize() const;
  boolean read(Sof& sof_a, long tag, const String& name = CLASS_NAME);
  boolean write(Sof& sof_a, long tag, const String& name = CLASS_NAME) const;

  boolean readData(Sof& sof_a, const String& pname = String::getEmptyString(),
		   long size = SofParser::FULL_OBJECT,
		   boolean param = true,
		   boolean nested = false);
  boolean writeData(Sof& sof_a,
		    const String& param = String::getEmptyString()) const;
  boolean setParser(SofParser* parser);

  // equality methods
  //
  boolean eq(const AudioFrontEnd& arg) const;

  // method: new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }

  // method: new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }

  // method: delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }

  // method: setGrowSize
  //
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }

  // clear methods
  //
  boolean clear(Integral::CMODE cmode = Integral::DEF_CMODE);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  set methods
  //
  //---------------------------------------------------------------------------

  // method: setInputDataType
  //
  boolean setInputDataType(FrontEndBase::DATA_TYPE data_type) {
    input_data_type_d = data_type;
    return true;
  }
  
  // method: setInputFlag
  //
  boolean setInputFlag(Boolean arg) {
    input_flag_d = arg;
    return true;  
  }
  
  // method: setAudioInput
  //  
  boolean setAudioInput(AudioFile& arg)  {
    return audio_input_d.assign(arg);
  }
  
  // method: setOutputDirectory
  //
  boolean setOutputDirectory(const String& new_dir) {
    return output_directory_d.assign(new_dir);
  }

  // method: setOutputBasename
  //
  boolean setOutputBasename(String& basename) {
    output_basename_d = basename;
    return true;
  }

  // method: setOutputExtension
  //
  boolean setOutputExtension(String& extension) {
    output_extension_d = extension;
    return true;
  }
  
  // method: setOutputFilename
  //
  boolean setOutputFilename(String& filename) {
    output_filename_d.concat(filename);
    return true;
  }

  // method: setOutputPreserve
  //
  boolean setOutputPreserve(long new_preserve_level) {
    return output_preserve_d.assign(new_preserve_level);
  }
  
  // method: setOutputSuffix
  //
  boolean setOutputSuffix(String& suffix) {
    output_suffix_d = suffix;
    return true;
  }

  // method: setOutputType
  //
  boolean setOutputType(File::TYPE type) {
    output_type_d = type;
    output_type_flag_d = true;
    return true;
  }

  // method: setFrameDuration
  //
  boolean setFrameDuration(float arg) {
    frame_duration_d = arg;
    return true;
  }

  // method: setSignalDuration
  //
  boolean setSignalDuration(float arg) {
    signal_duration_d = arg;
    return true;
  }

  // method: setSampleFrequency
  //
  boolean setSampleFrequency(float arg) {
    sample_frequency_d = arg;
    return true;
  }
  
  // method: setNumChannels
  //
  boolean setNumChannels(long arg) {
    num_channels_d = arg;
    return resetBuffer();
  }

  // set the name of the required features
  //
  boolean setCoefName(const String& name);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  get methods
  //
  //---------------------------------------------------------------------------

  // method: getAudioInput
  //
  AudioFile& getAudioInput() {
    return audio_input_d;
  }

  // method: getAudioInput
  //  
  const AudioFile& getAudioInput() const {
    return audio_input_d;
  }

  // method: getInputFilename
  //
  const boolean getInputFilename(Vector<Filename>& filename) const {
    filename = input_filename_d;
    return true;
  }
  
  // method: getInputFlag
  //
  boolean getInputFlag() const {
    return input_flag_d;
  }

  // method: getOutputDirectory
  //
  const String& getOutputDirectory() const {
    return output_directory_d;
  }

  // method: getOutputBasename
  //
  const boolean getOutputBasename(String& basename) const {
    basename = output_basename_d;
    return true;
  }

  // method: getOutputExtension
  //
  const boolean getOutputExtension(String& extension) const {
    extension = output_extension_d;
    return true;
  }
  
  // method: getOutputFilename
  //
  const boolean getOutputFilename(Vector<Filename>& filename) const {
    filename = output_filename_d;
    return true;
  }

  // method: getOutputPreserve
  //
  long getOutputPreserve() const {
    return (long)output_preserve_d;
  }
  
  // method: getOutputSuffix
  //
  const boolean getOutputSuffix(String& suffix) const {
    suffix = output_suffix_d;
    return true;
  }

  // method: getOutputType
  //
  const File::TYPE& getOutputType() const {
    return output_type_d;
  }  
  
  // method: getFrameDuration
  //
  float getFrameDuration() const {
    return frame_duration_d;
  }

  // method: getNumChannels
  //
  long getNumChannels() const {
    return num_channels_d;
  }

  // method: getSampleFrequency
  //
  float getSampleFrequency() const {
    return sample_frequency_d;
  }

  // method: getSignalDuration
  //
  float getSignalDuration() const {
    return signal_duration_d;
  }

  // get the total number of frames of the input file
  //
  long getNumFrames();

  // get the total number of features after processing a certain component
  //
  long getNumFeatures();
  
  // method: getCoefName
  //
  const String& getCoefName() const {
    return coef_name_d;
  }
  
  // method: getID
  //
  const String& getID() const {
    if (audio_input_d.isOpen()) {
      return audio_input_d.getID();
    }
    else if (feature_input_d.isOpen()) {
      return feature_input_d.getID();
    }
    return id_d;
  }
  
  // determine if a given coefficient is an input
  //
  boolean isNameInput(const String& name) const;

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  FrontEndBase interface contract methods
  //
  //---------------------------------------------------------------------------

  // assignment and equality
  //
  boolean eq(const FrontEndBase& arg) const;
  boolean assign(const FrontEndBase& arg);
  
  // method: className
  //
  const String& className() const {
    return CLASS_NAME;
  }

  // get the coeff vector for a given frame
  //
  boolean getVector(VectorFloat& coeffs, long channel, long frame_index);

  //MY
  // get the coeff vector for a given frame
  //
  boolean getVector(AlgorithmData& coeffs, long channel, long frame_index);
  
  // method: getVector
  //
  boolean getVector(Vector<VectorFloat>& coeffs, long frame_index);

  //MY
  // method: getVector
  //
  boolean getVector(Vector<AlgorithmData>& coeffs, long frame_index);

  // open or close the input file
  //
  boolean open(const Filename& input);
  boolean close();
  
  // process an entire file at a time
  //
  boolean run(const Filename& input);

  // parameters initialization for audio frontend
  //
  boolean init(float start_time, float stop_time, int channel);

  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:
  
  // process the next frame and add it to the buffer
  //
  boolean processNextFrame();
  
  // what processing can be done for the current frame in isolation?
  //
  boolean processFrame(long frame_index);

  // what processing can be done for the last frames
  //
  boolean finishFrames();

  // reset the buffer of data
  //
  boolean resetBuffer();

  // method: getFirstFrame
  //  get the boundaries of the current buffer
  //
  long getFirstFrame() const {
    return buf_d.getFrameIndex() - buf_d.getBuffer()(0).getNumElements();
  }

  // method: getLastFrame
  //
  long getLastFrame() const {
    return buf_d.getFrameIndex();
  }

  // the three stages in Component computation
  //
  boolean readInput(long& new_offset, long frame_index);
  boolean processComponents(long offset, long pad_offset,
			    boolean append_data = false);
  boolean preconfigureComponents(SingleLinkedList<Component>&);
  boolean configureComponents();

  // other configuration methods
  //
  boolean getInputNames(Vector<String>& names);
  boolean makeBuffers(SingleLinkedList<Component>& Component);
  
  // used by the run method
  //
  boolean outputFeatures();

  // process target methods
  //
  boolean processTarget();
  boolean processTarget(Vector<String>& names);
};

// end of include file
//
#endif
