// file: $isip/class/mmedia/AudioFile/adf_11.cc
// version: $Id: adf_11.cc 9266 2003-07-15 19:33:59Z parihar $
//

// isip include files
//
#include "AudioFile.h"
#include <VectorByte.h>
#include <VectorShort.h>
#include <VectorLong.h>

// method: readSofData
//
// arguments:
//  Vector<VectorFloat>& data: (output) the audio data
//  long ctag: (input) the channel to read
//  long start_samp: (input) the start time of the audio data
//  long num_samp: (input) the end time of the audio data
//  
// return: number of samples read
//
// this method gets data from the sof audio file and put each channel data
// into a VectorFloat
//
long AudioFile::readSofData(Vector<VectorFloat>& data_a, long ctag_a,
			    long start_samp_a, long num_samp_a) {
  
  // check mode
  //
  if (file_format_d != SOF) {
    Error::handle(name(), L"readSofData", ERR_TYPE, __FILE__, __LINE__);
    return -1;
  }

  // check objects
  //
  if (sof_d == (Sof*)NULL) {
    return Error::handle(name(), L"readSofData", Error::MEM,
			 __FILE__, __LINE__);
  }

  // set the length for channels
  //
  data_a.setLength(num_channels_d);

  if (num_samp_a < 0) {
    for (long i = 0; i < num_channels_d; i++) {
      data_a(i).setLength(0);
    }
    Error::handle(name(), L"readSofData", Error::ARG, __FILE__, __LINE__);
    return -1;
  }

  if (num_samp_a == 0) {
    for (long i = 0; i < num_channels_d; i++) {
      data_a(i).setLength(0);
    }
    return 0;
  }

  // data is interleaved, calculate real number
  //
  long num_to_read = num_samp_a * num_channels_d;
  
  // branch on number of bytes per sample
  //

  // 8 bit samples, read single bytes
  //   
  if (sample_num_bytes_d == (Long)sizeof(byte8)) {

    VectorByte vec(num_to_read);
    
    long num_read = 
      vec.readPartialData(*sof_d, start_samp_a,
			  num_to_read, PARAM_DATA, 0, false, false);

    num_samp_a = num_read / num_channels_d;
    
    for (long i = 0; i < num_channels_d; i++) {
      data_a(i).setLength(num_samp_a);
      for (long j = 0; j < num_samp_a; j++) {
	data_a(i)(j) = (float)vec(j * num_channels_d + i) / max_sample_val_d;
      }
    }
  }
  
  // 16 bit samples, read short integers
  //   
  else if (sample_num_bytes_d == (Long)sizeof(int16)) {

    VectorShort vec(num_to_read);

    long num_read = 
      vec.readPartialData(*sof_d, start_samp_a,
			  num_to_read, PARAM_DATA, 0, false, false);

    num_samp_a = num_read / num_channels_d;
    
    for (long i = 0; i < num_channels_d; i++) {
      data_a(i).setLength(num_samp_a);
      for (long j = 0; j < num_samp_a; j++) {
	data_a(i)(j) = (float)vec(j * num_channels_d + i) / max_sample_val_d;
      }
    }
  }

  // 32 bit samples, read long integers
  //   
  else if (sample_num_bytes_d == (Long)sizeof(int32)) {

    VectorLong vec(num_to_read);

    long num_read = 
      vec.readPartialData(*sof_d, start_samp_a,
			  num_to_read, PARAM_DATA, 0, false, false);

    num_samp_a = num_read / num_channels_d;
    
    for (long i = 0; i < num_channels_d; i++) {
      data_a(i).setLength(num_samp_a);
      for (long j = 0; j < num_samp_a; j++) {
	data_a(i)(j) = (float)vec(j * num_channels_d + i) / max_sample_val_d;
      }
    }
  }
  
  // return the number of samples read
  //
  return num_samp_a;
}

// method: writeSofData
//
// arguments:
//  Vector<VectorFloat>& data: (input) the audio data to write
//  long ctag: (input) channel tag
//  
// return: the number of elements written
//
// this method writes the audio data to raw audio file
//
long AudioFile::writeSofData(Vector<VectorFloat>& data_a,
			     long ctag_a) {
  
  // Sof file
  //
  if (file_format_d != SOF) {
    return Error::handle(name(), L"writeSofData", ERR, __FILE__, __LINE__);
  }

  // combine the multi-channel data to a single Vector
  //
  VectorLong whole_data;
  
  revertData(whole_data, data_a, ctag_a);

  long num_write = whole_data.length();

  if (sample_num_bytes_d == (Long)sizeof(byte8)) {
    
    VectorByte buffer(num_write);

    for (long i = 0; i < num_write; i++) {
      buffer(i).assign(whole_data(i));
    }
      
    // call the partial write method
    //
    samples_written_d += buffer.writePartialData(*sof_d, 0, buffer.length());
  }
  else if (sample_num_bytes_d == (Long)sizeof(int16)) {
      
    VectorShort buffer(num_write);

    for (long i = 0; i < num_write; i++) {
      buffer(i).assign(whole_data(i));
    }
      
    // call the partial write method
    //
    samples_written_d += buffer.writePartialData(*sof_d, 0, buffer.length());
  }
  else if (sample_num_bytes_d == (Long)sizeof(int32)) {
      
    VectorLong buffer(num_write);

    for (long i = 0; i < num_write; i++) {
      buffer(i).assign(whole_data(i));
    }
      
    // call the partial write method
    //
    samples_written_d += buffer.writePartialData(*sof_d, 0, buffer.length());
  }
  else {
    return Error::handle(name(), L"writeSofData", ERR, __FILE__,
			 __LINE__);
  }
  
  // exit gracefully
  //
  return true;
}

// method: readSofHeader
//
// arguments: none
//  
// return: a boolean value indicating status
//
// this method writes the audio data to raw audio file
//
boolean AudioFile::readSofHeader() {
  
  // make sure the object is allocated
  //
  if (sof_d == (Sof*)NULL) {
    return Error::handle(name(), L"readSofHeader", Error::MEM,
			 __FILE__, __LINE__);
  }

  // you can't configure a file if it is already in sof mode
  //
  file_format_d = RAW;
  
  if (!readSofStart(*sof_d, tag_d)) {
    return Error::handle(name(), L"readSofHeader", Error::READ,
			 __FILE__, __LINE__, Error::WARNING);
  }

  if (file_format_d != SOF) {
    return Error::handle(name(), L"readSofHeader", Error::READ,
			 __FILE__, __LINE__, Error::WARNING);
  }
  
  if (no_data_d) {
    return Error::handle(name(), L"readSofHeader", Error::READ,
			 __FILE__, __LINE__);
  }
  
  // save the object size from the temporary placeholder
  //
  long object_size = sof_length_pos_d;

  // now set the sof_length_pos_d flag to the start of the object
  //
  sof_length_pos_d = sof_d->tell();
  
  // start the read
  //
  if (sample_num_bytes_d == (Long)sizeof(byte8)) {
    
    VectorByte vec;
    if (!vec.readStart(*sof_d, PARAM_DATA, object_size, false, false)) {
      return Error::handle(name(), L"readSofHeader", Error::READ,
			   __FILE__, __LINE__, Error::WARNING);
    }
  }
  else if (sample_num_bytes_d == (Long)sizeof(int16)) {
      
    VectorShort vec;
    if (!vec.readStart(*sof_d, PARAM_DATA, object_size, false, false)) {
      return Error::handle(name(), L"readSofHeader", Error::READ,
			   __FILE__, __LINE__, Error::WARNING);
    }
  }
  else if (sample_num_bytes_d == (Long)sizeof(int32)) {
    
    VectorLong vec;
    if (!vec.readStart(*sof_d, PARAM_DATA, object_size, false, false)) {
      return Error::handle(name(), L"readSofHeader", Error::READ,
			   __FILE__, __LINE__, Error::WARNING);
    }
  }
  else {
    return Error::handle(name(), L"unaligned word", ERR, __FILE__,
			 __LINE__);
  }

  // exit gracefully
  //
  return true;
}

// method: writeSofHeader
//
// arguments: none
//  
// return: a boolean value indicating status
//
// this method writes the audio data to raw audio file
//
boolean AudioFile::writeSofHeader() {
  
  // make sure the object is allocated
  //
  if (sof_d == (Sof*)NULL) {
    return Error::handle(name(), L"writeSofHeader", Error::MEM,
			 __FILE__, __LINE__);
  }
  
  // write the object configuration to the Sof file.
  //
  if (!writeSofStart(*sof_d, tag_d)) {
    return Error::handle(name(), L"writeSofHeader", Error::WRITE,
			 __FILE__, __LINE__);
  }

  // initialize sof pointers
  //
  samples_written_d = 0;
  boolean status;
  
  // now write a zero-length vector to the file
  //
  if (sample_num_bytes_d == (Long)sizeof(byte8)) {
    
    VectorByte vec;
    status = vec.writeStart(*sof_d, PARAM_DATA);
  }
  else if (sample_num_bytes_d == (Long)sizeof(int16)) {
    
    VectorShort vec;
    status = vec.writeStart(*sof_d, PARAM_DATA);
  }
  else if (sample_num_bytes_d == (Long)sizeof(int32)) {
    
    VectorLong vec;
    status = vec.writeStart(*sof_d, PARAM_DATA);
  }
  else {
    return Error::handle(name(), L"unaligned word", ERR, __FILE__,
			 __LINE__);
  }

  // set the sof pointers
  //
  sof_length_pos_d = sof_d->getStartPos();

  // exit gracefully
  //
  return status;
}
