// file: $isip/class/mmedia/AudioFile/adf_06.cc
// version: $Id: adf_06.cc 9286 2003-08-05 19:46:21Z parihar $
//

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

// method: setSampleNumBytes
//
// arguments:
//  long sample_num_bytes: (input) the number of bytes per sample 
//
// return: a boolean value indicating status
//
// this method sets the number of bytes per sample
//
boolean AudioFile::setSampleNumBytes(long sample_num_bytes_a) {
  
  // check the arguments
  //
  if ((sample_num_bytes_d != (Long)sizeof(byte8))
      && (sample_num_bytes_d != (Long)sizeof(int16))
      && (sample_num_bytes_d != (Long)sizeof(int32))) {
    return Error::handle(name(), L"setSampleNumBytes", Error::ARG,
			 __FILE__, __LINE__);
  }

  // set the data
  //
  sample_num_bytes_d = sample_num_bytes_a;

  // if the sample precision is set to code zero, calculate max value
  // based on this setting.
  // 
  if (sample_precision_d == USE_SIZE) {

    // range scaling is broken, error
    //
    return Error::handle(name(), L"setSampleNumBytes", Error::NOT_IMPLEM,
			 __FILE__, __LINE__);
    
    long num_bits = (long)sample_num_bytes_d * 8;

    llong value = 1;
    value <<= (num_bits - 2);
    max_sample_val_d = (double)value;
  }
    
  // exit gracefully
  //
  return true;
}

// method: setNumChannels
//
// arguments:
//  long num_channels: (input) the number of channels to set
//
// return: a boolean value indicating status
//
// this method sets the number of channels
//
boolean AudioFile::setNumChannels(long num_channels_a) {
  
  if (num_channels_a < 0) {
    return Error::handle(name(), L"setNumChannels", Error::ARG,
			 __FILE__, __LINE__);
  }

  // do not need to set channels for sof file, reading from file directly
  //
  if ((file_format_d == SOF) && (isOpen())) {
    return true;
  }
  
  // can set the number of channels for an open file of anything
  // except SOF format
  //
  if ((file_format_d == SOF) && (isOpen())) {
    debug(L"before error");
    return Error::handle(name(), L"setNumChannels", ERR_PRECFG,
			 __FILE__, __LINE__, Error::WARNING);
  }

  num_channels_d = num_channels_a;

  // set the buffer
  //
  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);

  // the memory requirements change
  //
  setBlockSize(block_size_d);
  setBufferSize(buf_size_d);

  // setup the filters circular buffers
  //
  for (long i = 0; i < num_channels_d; i++) {
    ma_mem_d(i).setCapacity(ma_coeff_d.length() + 1);
    ar_mem_d(i).setCapacity(ar_coeff_d.length() + 1);
  }
  
  // exit gracefully
  //
  return true;
}

// method: setSamplePrecision
//
// arguments:
//  SAMPLE_PRECISION sample_precision: (input) the sample precision to set
//
// return: a boolean value indicating status
//
// this method sets the sample precision
//
boolean AudioFile::setSamplePrecision(SAMPLE_PRECISION sample_precision_a) {
  
  sample_precision_d = sample_precision_a;

  // if the sample precision is set to code zero, calculate max value
  // based on this setting.
  // 
  if (sample_precision_d == USE_SIZE) {

    // range scaling is broken, error
    //
    return Error::handle(name(), L"setSamplePrecision", Error::NOT_IMPLEM,
			 __FILE__, __LINE__);
    
    long num_bits = (long)sample_num_bytes_d * 8;

    llong value = 1;
    value <<= (num_bits - 2);
    max_sample_val_d = (double)value;
  }

  // NONE means no scaling
  //
  else if (sample_precision_d == NONE) {

    // no scaling
    //
    max_sample_val_d = 1.0;	
  }

  // calculate max for scaling
  //
  else if (sample_precision_d == EIGHT_BITS) {

    // range scaling is broken, error
    //
    return Error::handle(name(), L"setSamplePrecision", Error::NOT_IMPLEM,
			 __FILE__, __LINE__);
    
    long num_bits = 8;

    llong value = 1;
    value <<= (num_bits - 2);
    max_sample_val_d = (double)value;
  }    

  else if (sample_precision_d == TWELVE_BITS) {

    // range scaling is broken, error
    //
    return Error::handle(name(), L"setSamplePrecision", Error::NOT_IMPLEM,
			 __FILE__, __LINE__);
    
    long num_bits = 12;

    llong value = 1;
    value <<= (num_bits - 2);
    max_sample_val_d = (double)value;
  }    

  else if (sample_precision_d == SIXTEEN_BITS) {

    // range scaling is broken, error
    //
    return Error::handle(name(), L"setSamplePrecision", Error::NOT_IMPLEM,
			 __FILE__, __LINE__);
    
    long num_bits = 16;

    llong value = 1;
    value <<= (num_bits - 2);
    max_sample_val_d = (double)value;
  }    

  else if (sample_precision_d == TWENTY_BITS) {

    // range scaling is broken, error
    //
    return Error::handle(name(), L"setSamplePrecision", Error::NOT_IMPLEM,
			 __FILE__, __LINE__);
    
    long num_bits = 20;

    llong value = 1;
    value <<= (num_bits - 2);
    max_sample_val_d = (double)value;
  }    

  else if (sample_precision_d == TWENTY_FOUR_BITS) {

    // range scaling is broken, error
    //
    return Error::handle(name(), L"setSamplePrecision", Error::NOT_IMPLEM,
			 __FILE__, __LINE__);
    
    long num_bits = 24;

    llong value = 1;
    value <<= (num_bits - 2);
    max_sample_val_d = (double)value;
  }    

  else if (sample_precision_d == THIRTY_TWO_BITS) {

    // range scaling is broken, error
    //
    return Error::handle(name(), L"setSamplePrecision", Error::NOT_IMPLEM,
			 __FILE__, __LINE__);
    
    long num_bits = 32;

    llong value = 1;
    value <<= (num_bits - 2);
    max_sample_val_d = (double)value;
  }    

  // bad value
  //
  else {
    return Error::handle(name(), L"setSamplePrecision", Error::ARG,
			 __FILE__, __LINE__);
  }

  // exit gracefully
  //
  return true;
}

// method: setMaCoeff
//
// arguments:
//  const VectorFloat& ma_coeff: (input) ma coefficient for filter
//
// return: a boolean value indicating status
//
// this method sets the ma coefficients
//
boolean AudioFile::setMaCoeff(const VectorFloat& ma_coeff_a) {
  
  // check arguments
  //
  if (ma_coeff_a.length() < 1) {
    return Error::handle(name(), L"setMaCoeff", Error::ARG,
			 __FILE__, __LINE__);
  }

  // assign the data
  //
  ma_coeff_d.assign(ma_coeff_a);

  // set the capacity for each channel
  //
  for (long i = 0; i < num_channels_d; i++) {
    ma_mem_d(i).setCapacity(ma_coeff_d.length() + 1);
    if (!resetFilter(i)) {
      return Error::handle(name(), L"setMaCoeff", ERR,
			   __FILE__, __LINE__);
    }
  }

  // exit gracefully
  //
  return true;
}

// method: setArCoeff
//
// arguments:
//  const VectorFloat& ar_coeff: (input) ar coefficient for filter
//
// return: a boolean value indicating status
//
// this method sets the ar coefficients
//
boolean AudioFile::setArCoeff(const VectorFloat& ar_coeff_a) {

  // check arguments
  //
  if (ar_coeff_a.length() < 1) {
    return Error::handle(name(), L"setArCoeff", Error::ARG,
			 __FILE__, __LINE__);
  }
  
  // check for bad ar coefficients
  //
  if (ar_coeff_a(0) != (Float)1.0) {
    return Error::handle(name(), L"setArCoeff", ERR_ARCOEF,
			 __FILE__, __LINE__);
  }

  // assign the data
  //
  ar_coeff_d.assign(ar_coeff_a);

  // set the capacity for each channel
  //
  for (long i = 0; i < num_channels_d; i++) {
    ar_mem_d(i).setCapacity(ar_coeff_d.length() + 1);
    if (!resetFilter(i)) {
      return Error::handle(name(), L"setArCoeff", ERR,
			   __FILE__, __LINE__);
    }
  }

  // exit gracefully
  //
  return true;
}

// method: setBufferSize
//
// arguments:
//  long nblocks: (input) number of blocks per buffer
//
// return: a boolean value indicating status
//
// this method sets capacity of the buffer
//
boolean AudioFile::setBufferSize(long nblocks_a) {

  // save the value to class data
  //
  buf_size_d = nblocks_a;
  long block_num_samp = block_size_d / (sample_num_bytes_d * num_channels_d);
  
  for (long i = 0; i < num_channels_d; i++) {
    buffers_d(i).setCapacity(nblocks_a * block_num_samp);
  }
  
  // exit gracefully
  //
  return true;
}

// method: setBlockSize
//
// arguments:
//  long nbytes: (input) number of bytes per block
//
// return: a boolean value indicating status
//
// this method sets the block size
//
boolean AudioFile::setBlockSize(long nbytes_a) {

  // save the value to class data
  //
  block_size_d = nbytes_a;
  if (sample_num_bytes_d == (Long)0) {
    return Error::handle(name(), L"setBlockSize", Error::ARG, __FILE__,
			 __LINE__);
  }

  if (num_channels_d == (Long)0) {
    return Error::handle(name(), L"setBlockSize", Error::ARG, __FILE__,
			 __LINE__);
  }

  long block_num_samp = block_size_d / (sample_num_bytes_d * num_channels_d);

  // the io buffer is what is pulled from the file
  //
  if (io_buf_d != (byte*)NULL) {
    scratch_mgr_d.releaseBlock(io_buf_d);
  }
  io_buf_d = (byte*)scratch_mgr_d.
    getBlock(sizeof(byte) * block_size_d * num_channels_d);

  // the interleaved buffer holds samples before breaking into channels
  //
  interleaved_d.setLength(block_num_samp * num_channels_d);
  interleaved_d.setCapacity(block_num_samp * num_channels_d);
  
  // exit gracefully
  //
  return true;
}
