// file: $isip/class/mmedia/AudioFile/adf_00.cc
// version: $Id: adf_00.cc 9328 2003-10-27 21:43:25Z parihar $
//

// isip include files
//
#include "AudioFile.h"
 
// method: destructor
//
// arguments: none
//
// return: none
//
// this is the default destructor for the AudioFile class
//
AudioFile::~AudioFile() {

  if (sof_d != (Sof*)NULL) {
    delete sof_d;
  }

  if (backup_config_d != (AudioFile*)NULL) {
    delete backup_config_d;
  }

  if (io_buf_d != (byte*)NULL) {
    scratch_mgr_d.releaseBlock(io_buf_d);
  }
  
  // reset the data members (and close files)
  //
  clear(Integral::RETAIN);
  
  // exit gracefully
  //
}

// method: default constructor
//
// arguments:
//  FILE_TYPE ftype: (input) type of file
//  FILE_FORMAT fformat: (input) file format
//
// return: none
//
// this is the default constructor for the AudioFile class
//
AudioFile::AudioFile(FILE_TYPE ftype_a,
		     FILE_FORMAT fformat_a) {

  // initialize class data
  //
  file_type_d = ftype_a;
  file_format_d = fformat_a;
  compression_type_d = DEF_COMP_TYPE;
  amplitude_range_d = DEF_AMPLITUDE_RANGE;
  
  sample_freq_d = DEF_SAMPLE_FREQ;
  sample_num_bytes_d = DEF_SAMPLE_NUM_BYTES;
  num_channels_d = DEF_NUM_CHANNELS;
  sample_precision_d = DEF_SAMPLE_PRECISION;

  // set the max_sample_val
  //
  setSamplePrecision(sample_precision_d);
  
  no_data_d = true;
  sof_d = (Sof*)NULL;

#ifdef HAVE_AUDIOFILE
  af_file_d = (AFfilehandle)NULL;
#endif
  
#ifdef HAVE_SPHERE
  sp_file_d = (SP_FILE*)NULL;
#endif
  
  tag_d = DEF_TAG;
  sof_length_pos_d = -1;
  samples_written_d = 0;
  
  buffers_d.setLength((long)num_channels_d);

  buf_end_samp_d.setLength((long)num_channels_d);
  Long num((long)-1);
  buf_end_samp_d.assign(num);
  end_of_file_d = false;
  
  ma_mem_d.setLength((long)num_channels_d);
  ar_mem_d.setLength((long)num_channels_d);

  io_buf_d = (byte*)NULL;

  backup_config_d = (AudioFile*)NULL;
  
  // initialize filters to do nothing, just pass samples straight
  // through
  //
  setMaCoeff(DEF_MA_COEFF);
  setArCoeff(DEF_AR_COEFF);
  
  // set the capacity of each channel's buffer
  //
  setBlockSize(DEF_BLOCK_SIZE);
  setBufferSize(DEF_BUF_SIZE);
  
  // exit gracefully
  //
}

// method: copy constructor
//
// arguments:
//  const AudioFile& arg: (input) the AudioFile to copy
//
// return: none
//
// this is the copy constructor for the AudioFile class
//
AudioFile::AudioFile(const AudioFile& arg_a) {
  
  // initialize class data
  //
  file_type_d = DEF_FILE_TYPE;
  file_format_d = DEF_FILE_FORMAT;
  compression_type_d = DEF_COMP_TYPE;
  amplitude_range_d = DEF_AMPLITUDE_RANGE;
  
  sample_freq_d = DEF_SAMPLE_FREQ;
  sample_num_bytes_d = DEF_SAMPLE_NUM_BYTES;
  num_channels_d = DEF_NUM_CHANNELS;
  sample_precision_d = DEF_SAMPLE_PRECISION;

  // set the max_sample_val
  //
  setSamplePrecision(sample_precision_d);

  block_size_d = DEF_BLOCK_SIZE;
  buf_size_d = DEF_BUF_SIZE;
  
  no_data_d = true;
  sof_d = (Sof*)NULL;

#ifdef HAVE_AUDIOFILE
  af_file_d = (AFfilehandle)NULL;
#endif
  
#ifdef HAVE_SPHERE
  sp_file_d = (SP_FILE*)NULL;
#endif
  
  sof_length_pos_d = -1;
  samples_written_d = 0;
  end_of_file_d = false;
  
  backup_config_d = (AudioFile*)NULL;
  
  io_buf_d = (byte*)NULL;

  buffers_d.setLength((long)num_channels_d);
  buf_end_samp_d.setLength((long)num_channels_d);

  Long num((long)-1);
  buf_end_samp_d.assign(num);

  // call the assign method to copy the AudioFile
  //
  assign(arg_a);
  
  // exit gracefully
  //
}

// method: constructor
//
// arguments:
//  FILE_TYPE file_type: (input) the file type
//  FILE_FORMAT file_format: (input) file format
//  double sample_frequency: (input) the sample frequency
//  long sample_num_bytes: (input) the number of bytes per sample 
//  long num_channels: (input) the number of channels
//
// return: none
//
// this is the default constructor for the AudioFile class
//
AudioFile::AudioFile(FILE_TYPE file_type_a,
		     FILE_FORMAT file_format_a,
		     double sample_frequency_a,
		     long sample_num_bytes_a,
		     long num_channels_a) {

  // initialize class data
  //
  file_type_d = file_type_a;
  file_format_d = file_format_a;
  compression_type_d = DEF_COMP_TYPE;
  amplitude_range_d = DEF_AMPLITUDE_RANGE;
  
  sample_freq_d = sample_frequency_a;
  sample_num_bytes_d = sample_num_bytes_a;
  num_channels_d = num_channels_a;
  sample_precision_d = DEF_SAMPLE_PRECISION;

  // set the max_sample_val
  //
  setSamplePrecision(sample_precision_d);
  
  no_data_d = true;
  sof_d = (Sof*)NULL;
  
#ifdef HAVE_AUDIOFILE
  af_file_d = (AFfilehandle)NULL;
#endif
  
#ifdef HAVE_SPHERE
  sp_file_d = (SP_FILE*)NULL;
#endif
  
  sof_length_pos_d = -1;
  samples_written_d = 0;
  end_of_file_d = false;
  
  backup_config_d = (AudioFile*)NULL;
  
  buffers_d.setLength((long)num_channels_d);

  buf_end_samp_d.setLength((long)num_channels_d);
  Long num((long)-1);
  buf_end_samp_d.assign(num);
  
  ma_mem_d.setLength((long)num_channels_d);
  ar_mem_d.setLength((long)num_channels_d);

  io_buf_d = (byte*)NULL;
  
  // initialize filters to do nothing, just pass samples straight
  // through
  //
  setMaCoeff(DEF_MA_COEFF);
  setArCoeff(DEF_AR_COEFF);
  
  // set the capacity of each channel's buffer
  //
  setBlockSize(DEF_BLOCK_SIZE);
  setBufferSize(DEF_BUF_SIZE);
  
  // exit gracefully
  //
}

// method: assign
//
// arguments:
//  const AudioFile& copy_file: (input) the AudioFile to assign
//
// return: a boolean value indicating status
//
// this is the copy assign method
//
boolean AudioFile::assign(const AudioFile& copy_file_a) {
  
  // copy the file parameters
  //
  file_type_d = copy_file_a.file_type_d;
  file_format_d = copy_file_a.file_format_d;
  
  compression_type_d = copy_file_a.compression_type_d;
  amplitude_range_d = copy_file_a.amplitude_range_d;
  
  sample_freq_d = copy_file_a.sample_freq_d;
  sample_num_bytes_d = copy_file_a.sample_num_bytes_d;
  sample_precision_d = copy_file_a.sample_precision_d;
  num_channels_d = copy_file_a.num_channels_d;

  byte_mode_d = copy_file_a.byte_mode_d;
  
  max_sample_val_d = copy_file_a.max_sample_val_d;
  
  block_size_d = copy_file_a.block_size_d;
  buf_size_d = copy_file_a.buf_size_d;

  ma_coeff_d.assign(copy_file_a.ma_coeff_d);
  ar_coeff_d.assign(copy_file_a.ar_coeff_d);

  tag_d.assign(copy_file_a.tag_d);

  id_d.assign(copy_file_a.id_d);
  
  // this resets all buffers and allocates them to be the proper
  // capacities
  //
  setNumChannels(num_channels_d);
  
  // exit gracefully
  //
  return true;
}

// method: eq
//
// arguments:
//  const AudioFile& arg: (input) the AudioFile to compare
//
// return: a boolean value indicating status
//
// this method compares two AudioFile objects for equivalence
//
boolean AudioFile::eq(const AudioFile& arg_a) const {

  // compare the file parameters
  //
  if (file_type_d != arg_a.file_type_d) {
    return false;
  }
  if (file_format_d != arg_a.file_format_d) {
    return false;
  }
  
  if (compression_type_d != arg_a.compression_type_d) {
    return false;
  }
  
  if (!amplitude_range_d.almostEqual(arg_a.amplitude_range_d)) {
    return false;
  }
  
  if (!sample_freq_d.almostEqual(arg_a.sample_freq_d)) {
    return false;
  }
  
  if (sample_num_bytes_d != arg_a.sample_num_bytes_d) {
    return false;
  }
  
  if (sample_precision_d != arg_a.sample_precision_d) {
    return false;
  } 

  if (num_channels_d != arg_a.num_channels_d) {
    return false;
  }
  
  if (block_size_d != arg_a.block_size_d) {
    return false;
  }

  if (buf_size_d != arg_a.buf_size_d) {
    return false;
  }

  if (!ma_coeff_d.almostEqual(arg_a.ma_coeff_d)) {
    return false;
  } 

  if (!ar_coeff_d.almostEqual(arg_a.ar_coeff_d)) {
    return false;
  } 

  if (!id_d.eq(arg_a.id_d)) {
    return false;
  }
  
  if (tag_d != arg_a.tag_d) {
    return false;
  } 
  
  // they are equal, exit gracefully
  //
  return true;
}

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

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

// constants: i/o related
//
const String AudioFile::PARAM_BYTE_ORDER(L"byte_order");
const String AudioFile::PARAM_FILE_TYPE(L"file_type");
const String AudioFile::PARAM_FILE_FORMAT(L"file_format");
const String AudioFile::PARAM_DATA_TYPE(L"data_type");
const String AudioFile::PARAM_COMP_TYPE(L"compression_type");
const String AudioFile::PARAM_RANGE(L"amplitude_range");
const String AudioFile::PARAM_DATA(L"data");
const String AudioFile::PARAM_TAG(L"tag");
const String AudioFile::PARAM_SAMPLE_FREQUENCY(L"sample_frequency");
const String AudioFile::PARAM_SAMPLE_NUM_BYTES(L"sample_num_bytes");
const String AudioFile::PARAM_SAMPLE_PRECISION(L"sample_precision");
const String AudioFile::PARAM_NUM_CHANNELS(L"num_channels");
const String AudioFile::PARAM_BLOCK_SIZE(L"block_size");
const String AudioFile::PARAM_BUF_SIZE(L"buf_size");
const String AudioFile::PARAM_ID(L"id");
const String AudioFile::PARAM_MA_COEFF(L"ma_coeff");
const String AudioFile::PARAM_AR_COEFF(L"ar_coeff");

// static instantiations: namemaps for enumerations
//
NameMap AudioFile::FILE_TYPE_MAP(L"TEXT, BINARY");
NameMap AudioFile::FILE_FORMAT_MAP(L"SOF, RAW, SPHERE, AIFF, AIFFC, AU, BICSF, WAV, DEF_FILE_FORMAT = SOF");
NameMap AudioFile::DATA_TYPE_MAP(L"SAMPLED_DATA, FEATURES");
NameMap AudioFile::COMP_TYPE_MAP(L"LINEAR, ALAW, PCM, ULAW,  PCM_SHORTEN1, PCM_SHORTEN2, ULAW_SHORTEN1, ULAW_SHORTEN2, PCM_WAVPACK1, ULAW_WAVPACK1, PCM_SHORTPACK0");
NameMap AudioFile::SAMPLE_PRECISION_MAP(L"NONE, USE_SIZE, EIGHT_BITS, TWELVE_BITS, SIXTEEN_BITS, TWENTY_BITS, TWENTY_FOUR_BITS, THIRTY_TWO_BITS");
NameMap AudioFile::BMODE_MAP(L"NATIVE, SWAP, BIG_ENDIAN, LITTLE_ENDIAN");

// constants: default values for class data
//
const VectorFloat AudioFile::DEF_MA_COEFF(L"1.0");
const VectorFloat AudioFile::DEF_AR_COEFF(L"1.0");

// static instantiations: memory managers and debug level
//
Integral::DEBUG AudioFile::debug_level_d = Integral::NONE;
MemoryManager AudioFile::mgr_d(sizeof(AudioFile), AudioFile::name());
MemoryManager AudioFile::scratch_mgr_d(sizeof(byte));
