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

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

// method: readRawData
//
// 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 raw audio file and put each channel data
// into a VectorFloat
//
long AudioFile::readRawData(Vector<VectorFloat>& data_a, long ctag_a,
			    long start_samp_a, long num_samp_a) {
  
  // for binary read
  //
  if (file_format_d != RAW) {
    Error::handle(name(), L"readRawData", ERR_TYPE, __FILE__, __LINE__);
    return -1;
  }

  String output;
  String values;
  data_a.setLength(num_channels_d);
  long lines = 0;
   
  if (file_type_d == TEXT) {
    rewind();
    while (!eof()) {
      lines++;
      values.assign(lines);
      values.concat(L": ");
      File::get(output);
      values.concat(output);
      //      Console::put(values);
    }

    rewind();

    long len = (lines - 1) / num_channels_d;

    if ((start_samp_a + num_samp_a) > len * num_channels_d ) {
    
      // set the number of samples to be all samples remaining
      //      
      num_samp_a = len * num_channels_d - start_samp_a;
      
      if (debug_level_d >= Integral::DETAILED) {
	String output;
	output.assign(num_samp_a);
	output.insert(L"readRawData: clipping num_samp_a to ", 0);
	Console::put(output);
      }
    }    
    
    for (long i = 0; i < num_channels_d; i++) {
      data_a(i).setLength(num_samp_a / num_channels_d);
    }

    // search starting point
    //
    lines = 0;
    while (lines < start_samp_a) {
      lines++;
      File::get(output);
    }

    for (long i = 0; i < num_samp_a / num_channels_d; i++) {
      for (long j = 0; j < num_channels_d; j++) {
	File::get(output);
	data_a(j)(i).assign(output);
      }
    }
    
    // return the number of samples read
    //
    return num_samp_a;    
  }
     
  long bytes_per_samp = (sample_num_bytes_d * num_channels_d);
  
  // get the file size
  //
  seek(0, POS_PLUS_END);
  long file_size = tell();
  rewind();

  if ((num_samp_a == ALL_SAMPLES)
      || ((start_samp_a + num_samp_a) > (file_size / bytes_per_samp))) {
    
    // set the number of samples to be all samples remaining
    //      
    num_samp_a = (file_size / bytes_per_samp) - start_samp_a;

    if (debug_level_d >= Integral::DETAILED) {
      String output;
      output.assign(num_samp_a);
      output.insert(L"readRawData: clipping num_samp_a to ", 0);
      Console::put(output);
    }
  }

  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"readRawData", 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;
  }
  
  // position the file to the start time
  //
  seek(start_samp_a * bytes_per_samp, POS);

  // temporary holder for all the data
  //
  long num_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)) {
    byte8* buffer = (byte8*)io_buf_d;
    
    if (File::read(buffer, sizeof(byte8), num_read) != num_read) {
      Error::handle(name(), L"readRawData", Error::READ, __FILE__, __LINE__);
      return -1;
    }
    if (!interleaved_d.assign(num_read, buffer)) {
      Error::handle(name(), L"readRawData", VectorFloat::ERR,
		    __FILE__, __LINE__);
      return -1;
    }
  }
  
  // 16 bit samples, read short integers
  //   
  else if (sample_num_bytes_d == (Long)sizeof(int16)) {
    int16* buffer = (int16*)io_buf_d;
  
    if (File::read(buffer, sizeof(int16), num_read) != num_read) {
      return Error::handle(name(), L"readRawData", Error::READ,
			   __FILE__, __LINE__);
    }
    if (!interleaved_d.assign(num_read, buffer)) {
      Error::handle(name(), L"readRawData", VectorFloat::ERR,
		    __FILE__, __LINE__);
      return -1;
    }
  }

  // 32 bit samples, read long integers
  //   
  else if (sample_num_bytes_d == (Long)sizeof(int32)) {
    int32* buffer = (int32*)io_buf_d;
    
    if (File::read(buffer, sizeof(int32), num_read) != num_read) {
      return Error::handle(name(), L"readRawData", Error::READ,
			   __FILE__, __LINE__);
    }
    
    if (!interleaved_d.assign(num_read, buffer)) {
      Error::handle(name(), L"readRawData", VectorFloat::ERR,
		    __FILE__, __LINE__);
      return -1;
    }

  }
  
  // separate the whole data to different channels, assume interwoven
  // structure
  //
  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++) {
      
      // pull the sample out of the single buffer
      //
      data_a(i)(j) = (float)interleaved_d(j * num_channels_d + i);
      
      // scale the sample
      //
      data_a(i)(j) /= max_sample_val_d;
    }
  }
  
  // return the number of samples read
  //
  return num_samp_a;
}

// method: writeRawData
//
// 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 a raw audio file
//
long AudioFile::writeRawData(Vector<VectorFloat>& data_a,
			       long ctag_a) {
  
  // write to raw file
  //
  if (file_format_d != RAW) {
    return Error::handle(name(), L"writeRawData", ERR, __FILE__, __LINE__);
  }

  String output;

  if (file_type_d == TEXT) {
    long channels = data_a.length();
    long len = data_a(0).length();
    for (long i = 0; i < len; i++) {
      for (long j = 0; j < channels; j++) {
	output.clear();
	output.concat(data_a(j)(i));
	output.concat(L"\n");
	File::put(output);
      }
    }
    
    // exit gracefully
    //
    return true;    
  }
  
  // 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)) {
    
    byte8 buffer[num_write];
    
    for (long i = 0; i < num_write; i++) {
      buffer[i] = (byte8)whole_data(i);
    }
    
    // call the base class write
    //
    File::write(buffer, sizeof(byte8), num_write);
  }
  else if (sample_num_bytes_d == (Long)sizeof(int16)) {
    
    int16 buffer[num_write];
    
    for (long i = 0; i < num_write; i++) {
      buffer[i] = (int16)whole_data(i);
    }
    
    // call the base class write
    //
    File::write(buffer, 2, num_write);
  }
  else if (sample_num_bytes_d == (Long)sizeof(int32)) {
    
    int32 buffer[num_write];
    
    for (long i = 0; i < num_write; i++) {
      buffer[i] = (int32)whole_data(i);
    }
    
    // call the base class write
    //
    File::write(buffer, sizeof(int32), num_write);
  }
  else {
    return Error::handle(name(), L"writeRawData", ERR, __FILE__,
			 __LINE__);
  }
  
  // exit gracefully
  //
  return true;
}

// method: readRawHeader
//
// arguments: none
//  
// return: a boolean value indicating status
//
// this method is the dummy read for the RAW header
//
boolean AudioFile::readRawHeader() {

  // write to Raw file
  //
  if (file_format_d != RAW) {
    return Error::handle(name(), L"readRawHeader", ERR, __FILE__, __LINE__);
  }

  // exit gracefully
  //
  return true;
}

// method: writeRawHeader
//
// arguments: none
//  
// return: a boolean value indicating status
//
// this method is the dummy method for RAW header write
//
boolean AudioFile::writeRawHeader() const {

  // write to Raw file
  //
  if (file_format_d != RAW) {
    return Error::handle(name(), L"writeRawHeader", ERR, __FILE__, __LINE__);
  }

  // exit gracefully
  //
  return true;
}
