// file: $isip/class/mmedia/AudioFile/AudioFile.h
// version: $Id: AudioFile.h 9280 2003-08-02 15:00:05Z parihar $
//

// make sure definitions are only made once
//
#ifndef ISIP_AUDIO_FILE
#define ISIP_AUDIO_FILE

// system include files
//

//-----------------------------------------------------------------------------
//
// include files for external packages:
//
//  this class makes use of two external packages to provide support
//  for different file types:
//
//   audiofile is supported using a sgi package
//   sphere is supported using a nist package (version 2.6a)
//
//  note that the order is important here. the external packages
//  must be included first.
//
#ifdef HAVE_AUDIOFILE
#include <audiofile.h>
#endif

#ifdef HAVE_SPHERE
#include <sp/sphere.h>

// undef conflicting variables and macros:
//  the nist sphere package uses some names that conflict
//  with definition in various places in the ifcs. therefore
//  we have to undef these. our interfaces to the sphere code
//  currently do not require these.
//
#undef NEWLINE
#undef NULL_CHAR
#undef SLASH
#undef WAV
#undef FUNCTION

#endif
//
//-----------------------------------------------------------------------------

// isip include files
//
#ifndef ISIP_FILE
#include <File.h>
#endif

#ifndef ISIP_FILENAME
#include <Filename.h>
#endif

#ifndef ISIP_LONG
#include <Long.h>
#endif

#ifndef ISIP_DOUBLE
#include <Double.h>
#endif

#ifndef ISIP_NAME_MAP
#include <NameMap.h>
#endif

#ifndef ISIP_CIRCULAR_BUFFER
#include <CircularBuffer.h>
#endif

#ifndef ISIP_VECTOR
#include <Vector.h>
#endif

#ifndef ISIP_VECTOR_FLOAT
#include <VectorFloat.h>
#endif

#ifndef ISIP_VECTOR_LONG
#include <VectorLong.h>
#endif

// AudioFile: a class that provides a uniform interface to a variety
// of audio formats. in addition to support for sof and raw files,
// this class provides support for microsoft wav files using
// sgi's audiofile library. a new type can be added by supplying
// implementations for a handful of private functions.
//
class AudioFile : public File {
  
  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:
  
  // define the class name
  //
  static const String CLASS_NAME;
  
  //---------------------------------------
  //
  // other important constants
  //
  //---------------------------------------
  
  // define the supported file types
  //
  enum FILE_TYPE { TEXT = 0, BINARY, DEF_FILE_TYPE = TEXT };

  // define the supported file formats
  //  formats supported natively within ifc's : SOF, RAW
  //  formats supported by nist's sphere lib  : SPHERE
  //  formats supported by sgi's audiofile lib: AIFF, AIFFC, AU, BICSF, WAV
  //  see http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi/0650/bks/
  //  SGI_Developer/DMediaDev_PG/sgi_html/ch07.html for additional
  //  documentation on audiofile formats
  //
  enum FILE_FORMAT { SOF = 0, RAW, SPHERE, AIFF, AIFFC, AU, BICSF, WAV,
		     DEF_FILE_FORMAT = SOF };

  // define the supported compression types
  //  types supported by SOF format   : LINEAR
  //  types supported by RAW format   : LINEAR
  //  types supported by SPHERE format: PCM, ULAW,
  //                                    PCM_SHORTEN1, PCM_SHORTEN2,
  //                                    ULAW_SHORTEN1, ULAW_SHORTEN2,
  //                                    PCM_WAVPACK1, ULAW_WAVPACK1,
  //                                    PCM_SHORTPACK0 (Read-only)
  //                                    
  enum COMP_TYPE { LINEAR = 0, ALAW, PCM, ULAW,  PCM_SHORTEN1, PCM_SHORTEN2,
		   ULAW_SHORTEN1, ULAW_SHORTEN2, PCM_WAVPACK1, ULAW_WAVPACK1,
		   PCM_SHORTPACK0, DEF_COMP_TYPE = LINEAR };

  // define the supported sample precision
  //
  enum SAMPLE_PRECISION { NONE = 0, USE_SIZE, EIGHT_BITS, TWELVE_BITS,
			  SIXTEEN_BITS, TWENTY_BITS, TWENTY_FOUR_BITS,
			  THIRTY_TWO_BITS, DEF_SAMPLE_PRECISION = NONE };
  
  // define the names for each of the enumerated values
  //
  static NameMap FILE_TYPE_MAP;
  static NameMap FILE_FORMAT_MAP;
  static NameMap COMP_TYPE_MAP;
  static NameMap SAMPLE_PRECISION_MAP;  

  // define additional name maps for the type of data (e.g., features)
  // and the byte mode (e.g., little endian)
  //
  static NameMap DATA_TYPE_MAP;  
  static NameMap BMODE_MAP;
  
  // define the channel related constants
  //
  static const long CHANNEL_TAG_RIGHT = 1;
  static const long CHANNEL_TAG_LEFT = 0;
  static const long CHANNEL_TAG_ALL = -2;
  static const long DEF_CHANNEL_TAG = CHANNEL_TAG_ALL;

  // define a special values to indicate processing of all samples
  //
  static const long ALL_SAMPLES = -2;

  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------

  static const String PARAM_BYTE_ORDER;
  static const String PARAM_FILE_TYPE;
  static const String PARAM_FILE_FORMAT;
  static const String PARAM_DATA_TYPE;
  static const String PARAM_COMP_TYPE;
  static const String PARAM_RANGE;
  static const String PARAM_DATA;
  static const String PARAM_TAG;
  static const String PARAM_SAMPLE_FREQUENCY;
  static const String PARAM_SAMPLE_NUM_BYTES;
  static const String PARAM_SAMPLE_PRECISION;
  static const String PARAM_NUM_CHANNELS;
  static const String PARAM_BLOCK_SIZE;
  static const String PARAM_BUF_SIZE;
  static const String PARAM_ID;
  static const String PARAM_MA_COEFF;
  static const String PARAM_AR_COEFF;

  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------

  // default values
  //
  static const double DEF_AMPLITUDE_RANGE = 1.0;
  static const double DEF_SAMPLE_FREQ = 8000.0;
  static const long DEF_SAMPLE_NUM_BYTES = 2;
  static const long DEF_NUM_CHANNELS = 1;
  
  // a buffer contains DEF_BUF_SIZE * DEF_BLOCK_SIZE elements
  //
  static const long DEF_BLOCK_SIZE = 8192;
  static const long DEF_BUF_SIZE = 4;

  // coefficients of the built-in filter
  //
  static const VectorFloat DEF_MA_COEFF;
  static const VectorFloat DEF_AR_COEFF;

  // default arguments to methods
  //
  static const double DEF_START_TIME = 0.0;
  static const double DEF_CENTER_TIME = 0.25;
  static const double DEF_DURATION = 0.5;

  static const long DEF_START_SAMP = 0;
  static const long DEF_NUM_SAMP = 4000;
  static const long DEF_TAG = 0;

  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  

  static const long ERR = 50000;
  static const long ERR_TYPE = 50001;
  static const long ERR_ARCOEF = 50002;
  static const long ERR_PTYPE = 50003;
  static const long ERR_PMODE = 50004;
  static const long ERR_PRECFG = 50005;

  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // buffer of audio data 
  //
  Vector< CircularBuffer<Float> > buffers_d;
  Vector<Long> buf_end_samp_d;
  
  // parameters of the audio file
  //
  FILE_TYPE file_type_d;                  // file type
  FILE_FORMAT file_format_d;              // file format
  COMP_TYPE compression_type_d;           // compression type
  Double amplitude_range_d;               // range threshold for compression
  
  Double sample_freq_d;                   // sample frequency
  Long sample_num_bytes_d;                // number of bytes per sample
  SAMPLE_PRECISION sample_precision_d;    // sample precision in bits
  Long num_channels_d;                    // number of channels

  // maximum sample value: computed from sample_precision_d
  //  and sample_num_bytes_d
  //
  double max_sample_val_d;
  
  // we read this many bytes from the file at a time
  //
  Long block_size_d;
  Long buf_size_d;

  // the file's id (for databases)
  //
  String id_d;
  
  // parameters of the IIR filter
  //
  VectorFloat ma_coeff_d;
  VectorFloat ar_coeff_d;
  Vector< CircularBuffer<Float> > ma_mem_d;
  Vector< CircularBuffer<Float> > ar_mem_d;
    
  // internal buffers for reading and writing from the file
  //
  byte* io_buf_d;
  VectorFloat interleaved_d;

  // old configuration: if we open a file that has its own
  // configuration we should store the user's configuration wishes in
  // case we later encounter a file without parameters. for example,
  // the user sets the byte order to native, reads in an Sof file that
  // is rev4, then later encounters a raw file.
  //
  AudioFile* backup_config_d;
  
  // since the AudioFile class can either hold configuration
  // information for auxiliary file types (RAW, SPHERE, WAV, etc) or
  // the actual signal data, this flag lets the class keep track of if
  // data is actually present in the file or not.
  //
  boolean no_data_d;

  // have we reached the end of file?
  //
  boolean end_of_file_d;
  
  // buf to store the whole data when read AudioFile object in one time
  // instead of reading frame by frame or piece by piece
  //
  Vector< VectorFloat> sampled_data_d;
  
  // in case this is an Sof file
  //
  Sof* sof_d;
  Long tag_d;

  // if we are writing to an Sof file we need to keep track of where
  // we write the AudioFile object's size and the vector's length
  //
  long sof_length_pos_d;
  long samples_written_d;

  // debugging parameters:
  //  this debug_level_d is not inherited because the AudioFile needs
  //  to have its own debug level
  //
  static Integral::DEBUG debug_level_d;

  // a static memory manager for AudioFile objects
  //
  static MemoryManager mgr_d;

  // a static memory manager for the byte* scratch space
  //
  static MemoryManager scratch_mgr_d;
  
  // this section contains data for specific file formats
  //

  // file format: Nist's Sphere format
  // description: file object for a file opened
  // notes: this is a type defined in the Nist Sphere's library
  //
#ifdef HAVE_SPHERE
 SP_FILE* sp_file_d;
#endif
  
  // file type: anything supported by the sgi audio file library
  // description: file object for a file opened in audio file
  // notes: this is a type defined in the audio file library
  //
#ifdef HAVE_AUDIOFILE
  AFfilehandle af_file_d;
  AFfilesetup af_setup_d;
#endif
  
  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:
  
  // method: name
  //
  inline static const String& name() {
    return CLASS_NAME;
  }

  // other static methods
  //
  static boolean diagnose(Integral::DEBUG debug_level);
  
  // method: setDebug
  //
  inline static boolean setDebug(Integral::DEBUG debug_level) {
    debug_level_d = debug_level;
    return true;
  }

  // other debug methods
  //
  boolean debug(const unichar* message) const;
    
  // destructor/constructor(s)
  //
  ~AudioFile();
  AudioFile(FILE_TYPE ftype = DEF_FILE_TYPE,
	    FILE_FORMAT fformat = DEF_FILE_FORMAT);

  // copy constructor
  //
  AudioFile(const AudioFile& copy_audio_file);
  
  // assign methods
  //
  boolean assign(const AudioFile& copy_audio_file);

  // method: operator=
  //
  inline AudioFile& operator=(const AudioFile& arg) {
    if (!assign(arg)) {
      Error::handle(name(), L"operator=",
		    Error::ARG, __FILE__, __LINE__);
    }      
    return *this;
  }  

  // i/o methods:
  //  these are the standard IFC I/O methods. note that the read
  //  method reads the entire file, while the write method
  //  writes to disk only the amount of the file that has been
  //  read into memory.
  //
  long sofSize() const;

  boolean read(Sof& sof, long tag, const String& name = CLASS_NAME);

  boolean write(Sof& sof, long tag, const String& name = CLASS_NAME) const;
  
  boolean readData(Sof& sof, const String& pname = String::getEmptyString(),
		   long size =  SofParser::FULL_OBJECT,
		   boolean param = true,
                   boolean nested = false);  

  boolean writeData(Sof& sof,
		    const String& pname = String::getEmptyString()) const;

  // equality methods
  //
  boolean eq(const AudioFile& compare_audio_file) const;
  
  // method: operator new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }

  // method: operator new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: operator delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }

  // method: operator delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }

  // method: setGrowSize
  //
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }

  boolean clear(Integral::CMODE cmode = Integral::DEF_CMODE);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods
  //
  //---------------------------------------------------------------------------

  // constructor(s)
  //
  AudioFile(FILE_TYPE file_type, FILE_FORMAT file_format,
	    double sample_frequency, long sample_num_bytes,
	    long num_channels);
  
  // open and close methods:
  //   these also handle clearing the internal data
  //
  boolean open(const Filename& filename, MODE mode = READ_ONLY);
  boolean open(const unichar* filename, MODE mode = READ_ONLY);
  boolean isOpen() const;
  boolean close();

  //---------------------------------------
  //
  // this section contains get functions
  // that retrieve sampled data
  //
  //---------------------------------------

  // method: getData
  //
  long getData(Vector<VectorFloat>& data,
	       double start_time = DEF_START_TIME,
	       double duration = DEF_DURATION) {
    return getData(data, timeToSample(start_time), timeToSample(duration));
  }

  // method: getData
  //
  long getData(VectorFloat& data, long channel_tag,
	       double start_time = DEF_START_TIME,
	       double duration = DEF_DURATION) {
    return getData(data, channel_tag,
		   timeToSample(start_time), timeToSample(duration));
  }

  // other getData methods
  //
  long getData(Vector<VectorFloat>& data,
	       long start_samp, long num_samp);
  long getData(VectorFloat& data, long channel_tag,
	       long start_samp, long num_samp);
  
  // method: getWindow
  //
  long getWindow(Vector<VectorFloat>& data,
		 double center_time,
		 double duration = DEF_DURATION) {
    double start_time = center_time - duration / 2.0;
    return getData(data, timeToSample(start_time),
		   timeToSample(duration));
  }

  // method: getWindow
  //
  long getWindow(VectorFloat& data, long channel_tag,
		 double center_time, double duration = DEF_DURATION) {

    double start_time = center_time - duration / 2.0;
    return getData(data, channel_tag, timeToSample(start_time),
		   timeToSample(duration));
  }

  // method: getRange
  //
  long getRange(Vector<VectorFloat>& data,
		double start_time, double end_time) {
    double duration = end_time - start_time;
    return getData(data, timeToSample(start_time),
		   timeToSample(duration) + 1);
  }

  // method: getRange
  //
  long getRange(VectorFloat& data, long channel_tag,
		double start_time, double end_time) {
    double duration = end_time - start_time;
    return getData(data, channel_tag, timeToSample(start_time),
		   timeToSample(duration) + 1);
  }

  // specialized methods:
  //  read/write data to/from an audio file. writeAudioData
  //  is currently the only way to write data to a file.
  //
  long readAudioData(Vector<VectorFloat>& data,
		     long channel_tag = DEF_CHANNEL_TAG,
		     long start_samp = DEF_START_SAMP,
		     long num_samp = DEF_NUM_SAMP);
  
  long writeAudioData(Vector<VectorFloat>& data,
		      long channel_tag = DEF_CHANNEL_TAG);

  //---------------------------------------
  //
  // this section contains get methods
  // that retrieve auxillary information
  //
  //---------------------------------------

  // method: getAmplitudeRange
  //
  double getAmplitudeRange() const {
    return amplitude_range_d;
  }

  // method: getCompType
  //
  COMP_TYPE getCompType() const {
    return compression_type_d;
  }

  // method: getFileFormat
  //
  FILE_FORMAT getFileFormat() const {
    return file_format_d;
  }

  // method: getFileType
  //
  FILE_TYPE getFileType() const {
    return file_type_d;
  }

  // method: getID
  //
  const String& getID() const {
    return id_d;
  }

  // method: getNumChannels
  //
  long getNumChannels() const {
    return num_channels_d;
  }

  // method to get the number of samples
  //
  long getNumSamples() const;
  
  // method: getSampleFrequency
  //
  double getSampleFrequency() const {
    return sample_freq_d;
  }

  // method: getSampleNumBytes
  //
  long getSampleNumBytes() const {
    return sample_num_bytes_d;
  }

  // method: getSamplePrecision
  //
  SAMPLE_PRECISION getSamplePrecision() const {
    return sample_precision_d;
  }
  
  //---------------------------------------
  //
  // this section contains set functions
  //
  //---------------------------------------

  // method: setAmplitudeRange
  //
  boolean setAmplitudeRange(double amplitude_range) {
    amplitude_range_d = amplitude_range;
    return true;
  }

  // methods to set the block size and buffer
  //
  boolean setBlockSize(long nbytes);
  boolean setBufferSize(long nblocks);

  // method: setCompType
  //
  boolean setCompType(COMP_TYPE comp_type) {
    compression_type_d = comp_type;
    return true;
  }

  // method: setFileFormat
  //
  boolean setFileFormat(FILE_FORMAT file_format) {
    file_format_d = file_format;
    return true;
  }
  
  // method: setFileType
  //
  boolean setFileType(FILE_TYPE file_type) {
    file_type_d = file_type;
    return true;
  }
  
  // method: setID
  //
  boolean setID(const String& id) {
    return id_d.assign(id);
  }
  
  // methods to set the number of bytes per sample, sample precision
  // and num of channels
  //
  boolean setNumChannels(long num_channels);
  boolean setSampleNumBytes(long sample_num_bytes);
  boolean setSamplePrecision(SAMPLE_PRECISION sample_precision);

  // method: setSampleFrequency
  //
  boolean setSampleFrequency(double sample_freq) {
    if (sample_freq < 0) {
      return Error::handle(name(), L"setSampleFrequency",
			   Error::ARG, __FILE__, __LINE__);
    }
    sample_freq_d = sample_freq;
    return true;
  }

  //---------------------------------------
  //
  // this section contains functions
  // that manipulate the internal filter
  //
  //---------------------------------------

  // method: getMaCoeff
  //
  const VectorFloat& getMaCoeff() const {
    return ma_coeff_d;
  }

  // method: getArCoeff
  //
  const VectorFloat& getArCoeff() const {
    return ar_coeff_d;
  }

  // filter parameter set methods
  //
  boolean setMaCoeff(const VectorFloat& ma_coeff);
  boolean setArCoeff(const VectorFloat& ar_coeff);
  
  //---------------------------------------
  //
  // this section contains methods
  // that perform units conversions
  //
  //---------------------------------------

  // method: timeToSample
  //
  long timeToSample(double time) const {
    return (long)Integral::round(time * sample_freq_d);
  }

  // method: sampleToTime
  //
  double sampleToTime(long index) const {
    return (double)index / sample_freq_d;
  }

  //---------------------------------------
  //
  // this section contains methods used to
  // deal specifically with Sof files
  //
  //---------------------------------------

  // these methods read/write the entire audio data from the audiofile
  // in Sof format
  //
  long readSofData(Sof& sof_a);
  long writeSofData(Sof& sof_a) const;

  // start methods:
  //  these methods are analogous to read, write, readData and
  //  writeData methods except these these don't read the audio
  //  data. these methods are needed by readSofHeader and
  //  writeSofHeader methods. these methods are specific to Sof format
  //
  boolean readSofStart(Sof& sof, long tag, const String& name = CLASS_NAME);
  boolean writeSofStart(Sof& sof, long tag,
			const String& name = CLASS_NAME) const;
  boolean readSofStartData(Sof& sof,
			   const String& pname = String::getEmptyString(),
			   long size =  SofParser::FULL_OBJECT,
			   boolean param = true,
			   boolean nested = false);
  boolean writeSofStartData(Sof& sof, const String& pname
			    = String::getEmptyString()) const;
  
  // config methods:
  //  these methods read/write the class data members (configuration
  //  parameters) from/to an audiofile in Sof format
  //
  boolean writeSofConfig(Sof& sof_a) const;
  boolean readSofConfig(Sof& sof_a, SofParser& parser);

  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:
  
  //---------------------------------------
  //
  // this section contains private functions
  // that operate on all types of files
  //
  //---------------------------------------

  // method: getStartSamp
  //
  long getStartSamp(long ctag = DEF_CHANNEL_TAG) const {

    long buf_duration = buffers_d(ctag).getNumElements();
    long buf_end = buf_end_samp_d(ctag);
    
    // calculate and return the start time
    //
    return (buf_end - buf_duration);
  }

  // method: getEndSamp
  //
  long getEndSamp(long ctag = DEF_CHANNEL_TAG) const {
    return buf_end_samp_d(ctag);
  }
  
  // methods to read the next block of data
  //
  boolean appendData();
  
  // methods to convert the Vector<VectorFloat> to bytes for writing
  //
  boolean revertData(VectorLong& whole_data, Vector<VectorFloat>& data,
		     long channel_tag) const;
  
  // methods to round the sample number up or down by block boundaries
  //
  long blockFloor(long samp_num) const;
  long blockCeil(long samp_num) const;

  // methods to clear out buffer and pointers
  //
  boolean resetBuffer(long channel_tag = CHANNEL_TAG_ALL);
  boolean resetFilter(long channel_tag = CHANNEL_TAG_ALL);

  //---------------------------------------
  //
  // this section contains file format specific methods.
  // every file type supported must implement these six methods:
  //  open, read/write header, read/write data
  //
  // format: sof
  //
  //---------------------------------------

  boolean openSofStream(const Filename& filename, MODE mode = READ_ONLY);
  boolean openSof(const Filename& filename, MODE mode = READ_ONLY);

  boolean readSofHeader();
  boolean writeSofHeader();
  
  long readSofData(Vector<VectorFloat>& data,
		   long channel_tag = DEF_CHANNEL_TAG,
		   long start_samp = DEF_START_SAMP,
		   long num_samp = DEF_NUM_SAMP);
  long writeSofData(Vector<VectorFloat>& data,
		    long channel_tag = DEF_CHANNEL_TAG);
  
  //---------------------------------------
  //
  // format: raw
  //
  //---------------------------------------

  boolean openRawStream(const Filename& filename, MODE mode = READ_ONLY);
  boolean openRaw(const Filename& filename, MODE mode = READ_ONLY);

  boolean readRawHeader();
  boolean writeRawHeader() const;
  
  long readRawData(Vector<VectorFloat>& data,
		   long channel_tag = DEF_CHANNEL_TAG,
		   long start_samp = DEF_START_SAMP,
		   long num_samp = DEF_NUM_SAMP);
  long writeRawData(Vector<VectorFloat>& data,
		    long channel_tag = DEF_CHANNEL_TAG);

  //---------------------------------------
  //
  // format: sphere
  //
  //---------------------------------------

  boolean openSphereStream(const Filename& filename, MODE mode = READ_ONLY);
  boolean openSphere(const Filename& filename, MODE mode = READ_ONLY);

  boolean readSphereHeader();
  boolean writeSphereHeader() const;

  long readSphereData(Vector<VectorFloat>& data,
		      long channel_tag = DEF_CHANNEL_TAG,
		      long start_samp = DEF_START_SAMP,
		      long num_samp = DEF_NUM_SAMP);
  long writeSphereData(Vector<VectorFloat>& data,
		       long channel_tag = DEF_CHANNEL_TAG);

  //---------------------------------------
  //
  // format: sgi audiofile support
  //
  //---------------------------------------
  
  boolean openAFStream(const Filename& filename, MODE mode = READ_ONLY);
  boolean openAF(const Filename& filename, MODE mode = READ_ONLY);
  
  boolean readAFHeader();
  boolean writeAFHeader() const;
  
  long readAFData(Vector<VectorFloat>& data,
		  long channel_tag = DEF_CHANNEL_TAG,
		  long start_samp = DEF_START_SAMP,
		  long num_samp = DEF_NUM_SAMP);  
  long writeAFData(Vector<VectorFloat>& data,
		   long channel_tag  = DEF_CHANNEL_TAG);
};

// end of include file
//
#endif
