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

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

// method: isOpen
//
// arguments: none
//
// return: boolean answer
//
// this method checks if the audiofile is open
//
boolean AudioFile::isOpen() const {

  // branch on file type
  //
  if (file_format_d == RAW) {
    return File::isOpen();
  }
  else if (file_format_d == SOF) {
    if (sof_d != (Sof*)NULL) {
      return sof_d->isOpen();
    }
  }

#ifdef HAVE_SPHERE
  else if (file_format_d == SPHERE) {
    return sp_file_d != (SP_FILE*)NULL;
  }
#endif

#ifdef HAVE_AUDIOFILE
  else {
    return af_file_d != (AFfilehandle)NULL;
  }
#endif
  
  // must not be open
  //
  return false;
}

// method: open
//
// arguments:
//  const unichar* filename: (input) file to open
//  MODE mode: (input) open mode
//
// return: a boolean value indicating status
//
// open the file
//
boolean AudioFile::open(const unichar* filename_a, MODE mode_a) {

  Filename temp(filename_a);

  // call the master function
  //
  return open(temp, mode_a);
}

// method: open
//
// arguments:
//  const Filename& filename: (input) file to open
//  MODE mode: (input) open mode
//
// return: a boolean value indicating status
//
// open the file
//
boolean AudioFile::open(const Filename& filename_a, MODE mode_a) {

  // save the configuration
  //
  if (backup_config_d != (AudioFile*)NULL) {
    return Error::handle(name(), L"open", Error::MEM, __FILE__, __LINE__);
  }
  backup_config_d = new AudioFile;
  backup_config_d->assign(*this);
  
  // if the filename is a '-' (streaming input from stdin)
  //
  if (filename_a.eq(STREAM_FILE)) {

    // format: SOF
    //
    if (file_format_d == SOF) {      
      if (!openSofStream(filename_a, mode_a)) {
      	return Error::handle(name(), L"open", Error::IO, __FILE__,
			     __LINE__, Error::WARNING);
      }      
    }
    
    // format: RAW
    //
    else if (file_format_d == RAW) {      
      if (!openRawStream(filename_a, mode_a)) {
      	return Error::handle(name(), L"open", Error::IO, __FILE__,
			     __LINE__, Error::WARNING);
      }      
    }
    
    // format: SPHERE
    //
    else if (file_format_d == SPHERE) {      
      if (!openSphereStream(filename_a, mode_a)) {
      	return Error::handle(name(), L"open", Error::IO, __FILE__,
			     __LINE__, Error::WARNING);
      }      
    }
    
    // format: supported by sgi audiofile library
    //
    else {
      if (!openAFStream(filename_a, mode_a)) {
      	return Error::handle(name(), L"open", Error::IO, __FILE__,
			     __LINE__, Error::WARNING);
      }
    }
  }

  // non-piped file, branch on type
  //
  else {
    
    // format: SOF
    //
    if (file_format_d == SOF) {
      if (!openSof(filename_a, mode_a)) {
	return Error::handle(name(), L"open", Error::IO, __FILE__,
			     __LINE__, Error::WARNING);
      }      
    }
    
    // format: RAW
    //
    else if (file_format_d == RAW) {
      if (!openRaw(filename_a, mode_a)) {
	return Error::handle(name(), L"open", Error::IO, __FILE__,
			     __LINE__, Error::WARNING);
      }
    }

    // format: SPHERE
    //
    else if (file_format_d == SPHERE) {
      if (!openSphere(filename_a, mode_a)) {
	return Error::handle(name(), L"open", Error::IO, __FILE__,
			     __LINE__, Error::WARNING);
      }
    }
    
    // format: supported though sgi's audiofile library
    //
    else {
      if (!openAF(filename_a, mode_a)) {
	return Error::handle(name(), L"open", Error::IO, __FILE__,
			     __LINE__, Error::WARNING);
      }
    }    
  }
  
  // reset the buffers and filters
  //
  resetBuffer();
  resetFilter();
  
  // exit gracefully
  //
  return true;
}

// method: openRawStream
//
// arguments:
//  const Filename& filename: (input) file to open
//  MODE mode: (input) open mode
//
// return: a boolean value indicating status
//
// open the audiofile as streaming input from stdin
//
boolean AudioFile::openRawStream(const Filename& filename_a, MODE mode_a) {
  
  
  // if the filename is a '-', open the pipe
  //
  if (filename_a.eq(STREAM_FILE)) {
    
    if (file_format_d == RAW) {
      
      // a read only pipe pulls data from stdin
      //
      if (mode_a == READ_ONLY) {
	File::open(STREAM_FILE, mode_a);
	
	// read the dummy raw header
	//
	if (!readRawHeader()) {
	  return Error::handle(name(), L"openRawStream", Error::READ, __FILE__,
			       __LINE__, Error::WARNING);
	}
      }
      
      // a write only pipe pushes to stdout
      //
      else if (mode_a == WRITE_ONLY) {
	File::open(STREAM_FILE, mode_a);

	// write the dummy raw header
	//
	if (!writeRawHeader()) {
	  return Error::handle(name(), L"openRawStream", Error::WRITE,
			       __FILE__, __LINE__, Error::WARNING);
	}
      }

      // no other pipes are supported
      //
      else {
	return Error::handle(name(), L"openRawStream", ERR_PMODE,
			     __FILE__, __LINE__);
      }
    }

    // wrong file type
    //
    else {
      return Error::handle(name(), L"openRawStream", ERR_PTYPE,
			   __FILE__, __LINE__);
    }
  }

  // wrong file type
  //
  else {
    return Error::handle(name(), L"openRawStream", ERR_PTYPE,
			 __FILE__, __LINE__);
  }
  
  // set the id to the stream file symbol
  //
  id_d.assign(STREAM_FILE);
  
  // exit gracefully
  //
  return true;
}

// method: openRaw
//
// arguments:
//  const Filename& filename: (input) file to open
//  MODE mode: (input) open mode
//
// return: a boolean value indicating status
//
// open the file
//
boolean AudioFile::openRaw(const Filename& filename_a, MODE mode_a) {

  // only RAW format
  //
  if (file_format_d == RAW) {
    
    // non-piped file
    //
    if (filename_a.ne(STREAM_FILE)) {
      
      if (!exists(filename_a)) {
	
	// the file doesn't need to exist if we are in write only mode
	//
	if (mode_a == WRITE_ONLY) {
	  
	  if (num_channels_d == (Long)0) {
	    return Error::handle(name(), L"openRaw", ERR, __FILE__, __LINE__);
	  }
	  
	  File::TYPE type = File::BINARY;
	  if (file_type_d == TEXT) {
	    type = File::TEXT;
	  }
	  
	  // call the master function in the File class
	  //
	  if (!File::open(filename_a, mode_a, type)) {
	    return Error::handle(name(), L"openRaw", Error::IO, __FILE__,
				 __LINE__, Error::WARNING);
	  }
	  
	  // write the dummy raw header
	  //
	  if (!writeRawHeader()) {
	    return Error::handle(name(), L"openRaw", Error::WRITE,
				 __FILE__, __LINE__, Error::WARNING);
	  }	  
	}
	
	// file does not exist but should, error
	//
	else {
	  return Error::handle(name(), L"openRaw", Error::FILE_NOTFND,
			       __FILE__, __LINE__, Error::WARNING);
	}
      }
      
      // else read existing file
      //
      else {
	
	// call the master function in the File class
	//
	if (!File::open(filename_a, mode_a)) {
	  return Error::handle(name(), L"openRaw", Error::IO,
			       __FILE__, __LINE__, Error::WARNING);
	}
	
	// read or write dummy raw header
	//
	if (mode_a == READ_ONLY) {
	  if (!readRawHeader()) {
	    return Error::handle(name(), L"openRaw", Error::READ,
				 __FILE__, __LINE__, Error::WARNING);
	  }
	}
	else if (mode_a == WRITE_ONLY) {
	  if (!writeRawHeader()) {
	    return Error::handle(name(), L"openRaw", Error::WRITE,
				 __FILE__, __LINE__, Error::WARNING);
	  }
	}
	
	if (num_channels_d == (Long)0) {
	  return Error::handle(name(), L"openRaw", ERR, __FILE__, __LINE__);
	}
      }
    }
    
    // bad streaming type
    //
    else {
      return Error::handle(name(), L"openRaw", ERR_PTYPE, __FILE__, __LINE__);
    }        
  }
  
  // bad enumeration value
  //
  else {
    return Error::handle(name(), L"openRaw", Error::ENUM, __FILE__, __LINE__);
  }
  
  // get the file basename as the id
  //
  filename_a.getBase(id_d);
  
  // exit gracefully
  //
  return true;
}

// method: openSofStream
//
// arguments:
//  const Filename& filename: (input) file to open
//  MODE mode: (input) open mode
//
// return: a boolean value indicating status
//
// open the audiofile as streaming input from stdin
//
boolean AudioFile::openSofStream(const Filename& filename_a, MODE mode_a) {

  // error
  //
  Error::handle(name(), L"readSofStream", Error::NOT_IMPLEM, __FILE__,
  		__LINE__);
  return -1;
}

// method: openSof
//
// arguments:
//  const Filename& filename: (input) file to open
//  MODE mode: (input) open mode
//
// return: a boolean value indicating status
//
// open the audiofile (SOF format)
//
boolean AudioFile::openSof(const Filename& filename_a, MODE mode_a) {
  
  // only SOF format
  //
  if (file_format_d == SOF) {
    
    // non-piped file
    //
    if (filename_a.ne(STREAM_FILE)) {
      
      if (!exists(filename_a)) {
	
	// the file doesn't need to exist if we are in write only mode
	//
	if (mode_a == WRITE_ONLY) {
	  
	  if (num_channels_d == (Long)0) {
	    return Error::handle(name(), L"openSof", ERR, __FILE__, __LINE__);
	  }
	  
	  if (sof_d != (Sof*)NULL) {
	    return Error::handle(name(), L"openSof", Error::MEM, __FILE__,
				 __LINE__);
	  }

	  sof_d = new Sof;
	  sof_d->fp_d.setBMode(byte_mode_d);
	  
	  File::TYPE type = File::BINARY;
	  if (file_type_d == TEXT) {
	    type = File::TEXT;
	  }
	  
	  if (!sof_d->open(filename_a, mode_a, type)) {
	    return Error::handle(name(), L"openSof", Error::IO,
				 __FILE__, __LINE__, Error::WARNING);
	  }

	  // write the sof header
	  //
	  if (!writeSofHeader()) {
	    return Error::handle(name(), L"openSof", Error::WRITE,
				 __FILE__, __LINE__, Error::WARNING);
	  }	    
	}
	
	// file does not exist but should, error
	//
	else {
	  return Error::handle(name(), L"openSof", Error::FILE_NOTFND,
			       __FILE__, __LINE__, Error::WARNING);
	}
      }
      
      // else read existing file
      //
      else {
	
	// make sure it is valid
	//
	if ((mode_a != WRITE_ONLY) && (!Sof::isSof(filename_a))) {
	  Error::handle(name(), L"openSof", Sof::ERR_NOTSOF,
			__FILE__, __LINE__, Error::WARNING);
	}
	
	if (sof_d != (Sof*)NULL) {
	  return Error::handle(name(), L"openSof", Error::MEM, __FILE__,
			       __LINE__);
	}
	
	sof_d = new Sof;
      
	// if we READ an existing file these commands will be ignored by Sof
	//
	sof_d->fp_d.setBMode(byte_mode_d);
	
	File::TYPE type = File::BINARY;
	if (file_type_d == TEXT) {
	  type = File::TEXT;
	}

	if (!sof_d->open(filename_a, mode_a, type)) {
	  filename_a.debug(L"file_name");
	  return Error::handle(name(), L"openSof", Error::IO, __FILE__,
			       __LINE__, Error::WARNING);
	}
	
	// set the byte order from the sof file
	//
	byte_mode_d = sof_d->fp_d.getBMode();
	
	// start the partial read or write though the header
	//
	if (mode_a == READ_ONLY) {
	  if (!readSofHeader()) {
	    return Error::handle(name(), L"openSof", Error::READ,
				 __FILE__, __LINE__, Error::WARNING);
	  }
	}
	else if (mode_a == WRITE_ONLY) {
	  if (!writeSofHeader()) {
	    return Error::handle(name(), L"openSof", Error::WRITE,
				 __FILE__, __LINE__, Error::WARNING);
	  }
	}
      }
    }
    
    // bad streaming type
    //
    else {
      return Error::handle(name(), L"openSof", ERR_PTYPE, __FILE__, __LINE__);
    }        
  }
  
  // bad enumeration value
  //
  else {
    return Error::handle(name(), L"openSof", Error::ENUM, __FILE__, __LINE__);
  }
  
  // exit gracefully
  //
  return true;
}

// method: openSphereStream
//
// arguments:
//  const Filename& filename: (input) file to open
//  MODE mode: (input) open mode
//
// return: a boolean value indicating status
//
// open the SPHERE format as streaming input from stdin
//
boolean AudioFile::openSphereStream(const Filename& filename_a, MODE mode_a) {
  

#ifdef HAVE_SPHERE
  // if the filename is a '-', open the pipe
  //
  if (filename_a.eq(STREAM_FILE)) {
    
    // format supported by Nist's Sphere library
    //
    if (file_format_d == SPHERE) {
      
      if (mode_a == READ_ONLY) {
	
	// open the sphere file handler with checksum checking enabled
	//
	if ((sp_file_d = sp_open((char*)(byte*)filename_a, "rv"))
	    == (SP_FILE*)NULL) {
	  return Error::handle(name(), L"openSphereStream", Error::IO,
			       __FILE__, __LINE__, Error::WARNING);
	}
	
	// read the Sphere header
	//
	if (!readSphereHeader()) {
	  return Error::handle(name(), L"openSphereStream", Error::READ,
			       __FILE__, __LINE__, Error::WARNING);
	}
      }
      
      // no other modes are supported
      //
      else {
	return Error::handle(name(), L"openSphereStream", ERR_PMODE,
			     __FILE__, __LINE__);
      }
    }
    
    // wrong file format
    //
    else {
      return Error::handle(name(), L"openSphereStream", ERR_PTYPE,
			   __FILE__, __LINE__);
    }
  }
  
  // wrong file type
  //
  else {
    return Error::handle(name(), L"openSphereStream", ERR_PTYPE,
			 __FILE__, __LINE__);
  }
  
  // set the id to the stream file symbol
  //
  id_d.assign(STREAM_FILE);

#else
  // not supported
  
  Error::handle(name(), L"openSphereStream", Error::NOT_IMPLEM,
  		__FILE__, __LINE__);  
#endif
  
  // exit gracefully
  //
  return true;
}

// method: openSphere
//
// arguments:
//  const Filename& filename: (input) file to open
//  MODE mode: (input) open mode
//
// return: a boolean value indicating status
//
// open the SPHERE format audiofile
//
boolean AudioFile::openSphere(const Filename& filename_a, MODE mode_a) {
  
#ifdef HAVE_SPHERE
  
  // Nist's Sphere format
  //
  if (file_format_d == SPHERE) {
    
    // non-piped file
    //
    if (filename_a.ne(STREAM_FILE)) {
      
      if (!exists(filename_a)) {
	
	// the file doesn't need to exist if we are in write only mode
	//
	if (mode_a == WRITE_ONLY) {
	  
	  if (num_channels_d == (Long)0) {
	    return Error::handle(name(), L"openSphere", ERR, __FILE__,
				 __LINE__);
	  }
	  
	  // open the sphere file handler with checksum checking enabled
	  //
	  if ((sp_file_d = sp_open((char*)(byte*)filename_a, "wv"))
	      == (SP_FILE*)NULL) {
	    return Error::handle(name(), L"openSphere", Error::IO,
				 __FILE__, __LINE__, Error::WARNING);
	  }
	  	  
	  // write the Sphere header
	  //
	  if (!writeSphereHeader()) {
	    return Error::handle(name(), L"openSphere", Error::WRITE,
				 __FILE__, __LINE__, Error::WARNING);
	  }
	}
	
	// file does not exist but should, error
	//
	else {
	  return Error::handle(name(), L"openSphere", Error::FILE_NOTFND,
			       __FILE__, __LINE__, Error::WARNING);
	}
      }
      
      // else read existing file
      //
      else {
	
	if (mode_a == READ_ONLY) {
	  
	  // open the sphere file as read-only with checksum checking enabled
	  // 
	  if ((sp_file_d = sp_open((char*)(byte*)filename_a, "rv"))
	      == (SP_FILE*)NULL) {
	    return Error::handle(name(), L"openSphere", Error::IO,
				 __FILE__, __LINE__, Error::WARNING);
	  }
	  
	  // read the Sphere header
	  //
	  if (!readSphereHeader()) {
	    return Error::handle(name(), L"openSphere", Error::READ,
				 __FILE__, __LINE__, Error::WARNING);
	  }	  
	}
	
	else if (mode_a == WRITE_ONLY) {
	  
	  // open the audiofile with checksum checking enabled
	  //
	  if ((sp_file_d = sp_open((char*)(byte*)filename_a, "wv"))
	      == (SP_FILE*)NULL) {
	    return Error::handle(name(), L"openSphere", Error::IO,
				 __FILE__, __LINE__, Error::WARNING);
	  }
	  
	  // write the Sphere header
	  //
	  if (!writeSphereHeader()) {
	    return Error::handle(name(), L"openSphere", Error::WRITE,
				 __FILE__, __LINE__, Error::WARNING);
	  }	    
	}
	
	// bad enumeration type
	//
	else { 
	  return Error::handle(name(), L"openSphere", Error::ENUM,
			       __FILE__, __LINE__);
	}
      }
    }
    
    // bad streaming type
    //
    else {
      return Error::handle(name(), L"openSphere", ERR_PTYPE, __FILE__,
			   __LINE__);
    }
  }
  
  // bad enumeration value
  //
  else {
    return Error::handle(name(), L"openSphere", Error::ENUM, __FILE__,
			 __LINE__);
  }
  
  // get the file basename as the id
  //
  filename_a.getBase(id_d);
  
#else
  // not supported
  //
  Error::handle(name(), L"openSphere", Error::NOT_IMPLEM, __FILE__, __LINE__);
#endif
  
  // exit gracefully
  //
  return true;	
}

// method: openAFStream
//
// arguments:
//  const Filename& filename: (input) file to open
//  MODE mode: (input) open mode
//
// return: a boolean value indicating status
//
// open the sgi's audiofile as streaming input from stdin. only raw
// mode is called in the code below
//
boolean AudioFile::openAFStream(const Filename& filename_a, MODE mode_a) {
  
#ifdef HAVE_AUDIOFILE
  // if the filename is a '-', open the pipe
  //
  if (filename_a.eq(STREAM_FILE)) {

    // open a new setup for SGI audiofile
    //
    af_setup_d = afNewFileSetup();
    
    // format supported by SGI's audiofile library
    //
    if ((file_format_d == AIFF) || (file_format_d == AIFFC) ||
	(file_format_d == AU) || (file_format_d == BICSF) ||
	(file_format_d == WAV)) {
      
      if (mode_a == READ_ONLY) {
	
	// open the sgi audiofile handler
	//
	if ((af_file_d = afOpenFD(0, "r", NULL)) == (AFfilehandle)NULL) {
	  return Error::handle(name(), L"openAFStream", Error::IO,
			       __FILE__, __LINE__, Error::WARNING);
	}
	
	// read the Wav header
	//
	if (!readAFHeader()) {
	  return Error::handle(name(), L"openAFStream", Error::READ, __FILE__,
			       __LINE__, Error::WARNING);
	}
      }
      
      // no other modes are supported
      //
      else {
	return Error::handle(name(), L"openAFStream", ERR_PMODE,
			     __FILE__, __LINE__);
      }
    }
    
    // wrong file format
    //
    else {
      return Error::handle(name(), L"openAFStream", ERR_PTYPE,
			   __FILE__, __LINE__);
    }
  }
  
  // wrong file type
  //
  else {
    return Error::handle(name(), L"openAFStream", ERR_PTYPE,
			 __FILE__, __LINE__);
  }
  
  // set the id to the stream file symbol
  //
  id_d.assign(STREAM_FILE);

#else
  // not supported
  //
  Error::handle(name(), L"openAFStream", Error::NOT_IMPLEM,
		__FILE__, __LINE__);  
#endif
  
  // exit gracefully
  //
  return true;
}

// method: openAF
//
// arguments:
//  const Filename& filename: (input) file to open
//  MODE mode: (input) open mode
//
// return: a boolean value indicating status
//
// open the audiofile (sgi file handler)
//
boolean AudioFile::openAF(const Filename& filename_a, MODE mode_a) {
  
#ifdef HAVE_AUDIOFILE

  // any format supported by sgi audiofile library
  //
  if ((file_format_d == AIFF) || (file_format_d == AIFFC) ||
      (file_format_d == AU) || (file_format_d == BICSF) ||
      (file_format_d == WAV)) {
    
    // non-piped file
    //
    if (filename_a.ne(STREAM_FILE)) {
      
      // open a new setup for SGI audiofile
      //
      af_setup_d = afNewFileSetup();
      
      if (!exists(filename_a)) {
	
	// the file doesn't need to exist if we are in write only mode
	//
	if (mode_a == WRITE_ONLY) {
	  
	  if (num_channels_d == (Long)0) {
	    return Error::handle(name(), L"openAF", ERR, __FILE__, __LINE__);
	  }
	  
	  // set the header information in the setup before opening
	  // the file. note that this is important for writing in the
	  // correct format
	  //
	  if (!writeAFHeader()) {
	    return Error::handle(name(), L"openAF", Error::WRITE,
				 __FILE__, __LINE__, Error::WARNING);
	  }    
	  
	  // open a new sgi's audiofile setup
	  // 
	  if ((af_file_d = afOpenFile((char*)(byte*)filename_a,
				      "w", af_setup_d))
	      == (AFfilehandle)NULL) {
	    return Error::handle(name(), L"openAF", Error::IO,
				 __FILE__, __LINE__, Error::WARNING);
	  }
	}
	
	// file does not exist but should, error
	//
	else {
	  return Error::handle(name(), L"openAF", Error::FILE_NOTFND,
			       __FILE__, __LINE__, Error::WARNING);
	}
      }
      
      // else read existing file
      //
      else {

	if (mode_a == READ_ONLY) {
	  
	  // open the sgi's audiofile as read-only
	  // 
	  if ((af_file_d = afOpenFile((char*)(byte*)filename_a,
				      "r", NULL))
	      == (AFfilehandle)NULL) {
	    return Error::handle(name(), L"openAF", Error::IO,
				 __FILE__, __LINE__, Error::WARNING);
	  }
	  // read the AF header
	  //
	  if (!readAFHeader()) {
	    return Error::handle(name(), L"openAF", Error::READ,
				 __FILE__, __LINE__, Error::WARNING);
	  }	  
	}
	
	else if (mode_a == WRITE_ONLY) {
	  
	  // now, open the audiofile
	  //
	  if ((af_file_d = afOpenFile((char*)(byte*)filename_a,
				      "w", af_setup_d))
	      == (AFfilehandle)NULL) {
	    return Error::handle(name(), L"openAF", Error::IO,
				 __FILE__, __LINE__, Error::WARNING);
	  }
	  
	  // write the AF header
	  //
	  if (!writeAFHeader()) {
	    return Error::handle(name(), L"openAF", Error::WRITE,
				 __FILE__, __LINE__, Error::WARNING);
	  }	    
	}
	
	// bad enumeration type
	//
	else { 
	  return Error::handle(name(), L"openAF", Error::ENUM,
			       __FILE__, __LINE__);
	}
      }
    }
    
    // bad streaming type
    //
    else {
      return Error::handle(name(), L"openAF", ERR_PTYPE, __FILE__, __LINE__);
    }     
  }
  
  // bad enumeration value
  //
  else {
    return Error::handle(name(), L"openAF", Error::ENUM, __FILE__, __LINE__);
  }
  
  // get the file basename as the id
  //
  filename_a.getBase(id_d);
  
#else
  // not supported
  //
  Error::handle(name(), L"openAF", Error::NOT_IMPLEM,
  		__FILE__, __LINE__);
#endif
  
  // exit gracefully
  //
  return true;	
}
  
// method: close
//
// arguments:
//
// return: a boolean value indicating status
//
// close the file
//
boolean AudioFile::close() {

  // close the Sof file and delete object
  //
  if (sof_d != (Sof*)NULL) {

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

      if (sof_d->getPartialRead()) {

	// call the partial read terminate method
	//
	buffer.readTerminate(*sof_d);
      }

      else if (sof_d->getPartialWrite()) {

	// call the partial write terminate method
	//
	buffer.writeTerminate(*sof_d, PARAM_DATA);
      }
    }
    else if (sample_num_bytes_d == (Long)sizeof(int16)) {
      
      VectorShort buffer;

      if (sof_d->getPartialRead()) {

	// call the partial read terminate method
	//
	buffer.readTerminate(*sof_d);
      }

      else if (sof_d->getPartialWrite()) {

	// call the partial write terminate method
	//
	buffer.writeTerminate(*sof_d, PARAM_DATA);
      }
    }
    
    else if (sample_num_bytes_d == (Long)sizeof(int32)) {
      
      VectorLong buffer;

      if (sof_d->getPartialRead()) {

	// call the partial read terminate method
	//
	buffer.readTerminate(*sof_d);
      }

      else if (sof_d->getPartialWrite()) {

	// call the partial write terminate method
	//
	buffer.writeTerminate(*sof_d, PARAM_DATA);
      }
    }
    else {
      return Error::handle(name(), L"unaligned word", ERR, __FILE__,
			   __LINE__);
    }

    sof_d->close();
    delete sof_d;
    sof_d = (Sof*)NULL;
  }

  // call the master function in the File class
  //
  else if (fp_d != NULL) {
    if (!File::close()) {
      return Error::handle(name(), L"close", Error::IO, __FILE__, __LINE__,
			   Error::WARNING);
    }
  }

#ifdef HAVE_SPHERE
  // format: SPHERE
  //
  else if (sp_file_d != (SP_FILE*)NULL) {
    if (sp_close(sp_file_d) > (long)0) {
      return Error::handle(name(), L"close", Error::IO, __FILE__, __LINE__,
			   Error::WARNING);
    }
    sp_file_d = (SP_FILE*)NULL;
  }
#endif
  
#ifdef HAVE_AUDIOFILE
  // if audiofile format is supported by sgi audiofile library
  //
  else if (af_file_d != (AFfilehandle)NULL) {
    if ((long)afCloseFile(af_file_d) != (long)0) {
      return Error::handle(name(), L"close", Error::IO, __FILE__, __LINE__,
    			   Error::WARNING);
    }
    af_file_d = (AFfilehandle)NULL;
    
    // free the file setup
    //
    afFreeFileSetup(af_setup_d);
  }
#endif
  
  // reset the buffers
  //
  resetBuffer();
  
  // if the configuration was saved, restore it and delete object
  //
  if (backup_config_d != (AudioFile*)NULL) {
    assign(*backup_config_d);
    delete backup_config_d;
    backup_config_d = (AudioFile*)NULL;
  }
  
  // initialize the id
  //
  id_d.clear();
  
  // exit gracefully
  //
  return true;
}
