// 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 #endif #ifdef HAVE_SPHERE #include // 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 #endif #ifndef ISIP_FILENAME #include #endif #ifndef ISIP_LONG #include #endif #ifndef ISIP_DOUBLE #include #endif #ifndef ISIP_NAME_MAP #include #endif #ifndef ISIP_CIRCULAR_BUFFER #include #endif #ifndef ISIP_VECTOR #include #endif #ifndef ISIP_VECTOR_FLOAT #include #endif #ifndef ISIP_VECTOR_LONG #include #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 int32 CHANNEL_TAG_RIGHT = 1; static const int32 CHANNEL_TAG_LEFT = 0; static const int32 CHANNEL_TAG_ALL = -2; static const int32 DEF_CHANNEL_TAG = CHANNEL_TAG_ALL; // define a special values to indicate processing of all samples // static const int32 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 float64 DEF_AMPLITUDE_RANGE = 1.0; static const float64 DEF_SAMPLE_FREQ = 8000.0; static const int32 DEF_SAMPLE_NUM_BYTES = 2; static const int32 DEF_NUM_CHANNELS = 1; // a buffer contains DEF_BUF_SIZE * DEF_BLOCK_SIZE elements // static const int32 DEF_BLOCK_SIZE = 8192; static const int32 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 float64 DEF_START_TIME = 0.0; static const float64 DEF_CENTER_TIME = 0.25; static const float64 DEF_DURATION = 0.5; static const int32 DEF_START_SAMP = 0; static const int32 DEF_NUM_SAMP = 4000; static const int32 DEF_TAG = 0; //---------------------------------------- // // error codes // //---------------------------------------- static const int32 ERR = 50000; static const int32 ERR_TYPE = 50001; static const int32 ERR_ARCOEF = 50002; static const int32 ERR_PTYPE = 50003; static const int32 ERR_PMODE = 50004; static const int32 ERR_PRECFG = 50005; //--------------------------------------------------------------------------- // // protected data // //--------------------------------------------------------------------------- protected: // buffer of audio data // Vector< CircularBuffer > buffers_d; Vector 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 // float64 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 > ma_mem_d; Vector< CircularBuffer > ar_mem_d; // internal buffers for reading and writing from the file // byte8* 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. // bool8 no_data_d; // have we reached the end of file? // bool8 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 // int32 sof_length_pos_d; int32 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 bool8 diagnose(Integral::DEBUG debug_level); // method: setDebug // inline static bool8 setDebug(Integral::DEBUG debug_level) { debug_level_d = debug_level; return true; } // other debug methods // bool8 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 // bool8 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. // int32 sofSize() const; bool8 read(Sof& sof, int32 tag, const String& name = CLASS_NAME); bool8 write(Sof& sof, int32 tag, const String& name = CLASS_NAME) const; bool8 readData(Sof& sof, const String& pname = String::getEmptyString(), int32 size = SofParser::FULL_OBJECT, bool8 param = true, bool8 nested = false); bool8 writeData(Sof& sof, const String& pname = String::getEmptyString()) const; // equality methods // bool8 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 bool8 setGrowSize(int32 grow_size) { return mgr_d.setGrow(grow_size); } bool8 clear(Integral::CMODE cmode = Integral::DEF_CMODE); //--------------------------------------------------------------------------- // // class-specific public methods // //--------------------------------------------------------------------------- // constructor(s) // AudioFile(FILE_TYPE file_type, FILE_FORMAT file_format, float64 sample_frequency, int32 sample_num_bytes, int32 num_channels); // open and close methods: // these also handle clearing the internal data // bool8 open(const Filename& filename, MODE mode = READ_ONLY); bool8 open(const unichar* filename, MODE mode = READ_ONLY); bool8 isOpen() const; bool8 close(); //--------------------------------------- // // this section contains get functions // that retrieve sampled data // //--------------------------------------- // method: getData // int32 getData(Vector& data, float64 start_time = DEF_START_TIME, float64 duration = DEF_DURATION) { return getData(data, timeToSample(start_time), timeToSample(duration)); } // method: getData // int32 getData(VectorFloat& data, int32 channel_tag, float64 start_time = DEF_START_TIME, float64 duration = DEF_DURATION) { return getData(data, channel_tag, timeToSample(start_time), timeToSample(duration)); } // other getData methods //* int32 getData(Vector& data, int32 start_samp, int32 num_samp); int32 getData(VectorFloat& data, int32 channel_tag, int32 start_samp, int32 num_samp); // method: getWindow // int32 getWindow(Vector& data, float64 center_time, float64 duration = DEF_DURATION) { float64 start_time = center_time - duration / 2.0; return getData(data, timeToSample(start_time), timeToSample(duration)); } // method: getWindow // int32 getWindow(VectorFloat& data, int32 channel_tag, float64 center_time, float64 duration = DEF_DURATION) { float64 start_time = center_time - duration / 2.0; return getData(data, channel_tag, timeToSample(start_time), timeToSample(duration)); } // method: getRange // int32 getRange(Vector& data, float64 start_time, float64 end_time) { float64 duration = end_time - start_time; return getData(data, timeToSample(start_time), timeToSample(duration) + 1); } // method: getRange // int32 getRange(VectorFloat& data, int32 channel_tag, float64 start_time, float64 end_time) { float64 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. // int32 readAudioData(Vector& data, int32 channel_tag = DEF_CHANNEL_TAG, int32 start_samp = DEF_START_SAMP, int32 num_samp = DEF_NUM_SAMP); int32 writeAudioData(Vector& data, int32 channel_tag = DEF_CHANNEL_TAG); //--------------------------------------- // // this section contains get methods // that retrieve auxillary information // //--------------------------------------- // method: getAmplitudeRange // float64 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 // int32 getNumChannels() const { return num_channels_d; } // method to get the number of samples // int32 getNumSamples() const; // method: getSampleFrequency // float64 getSampleFrequency() const { return sample_freq_d; } // method: getSampleNumBytes // int32 getSampleNumBytes() const { return sample_num_bytes_d; } // method: getSamplePrecision // SAMPLE_PRECISION getSamplePrecision() const { return sample_precision_d; } //--------------------------------------- // // this section contains set functions // //--------------------------------------- // method: setAmplitudeRange // bool8 setAmplitudeRange(float64 amplitude_range) { amplitude_range_d = amplitude_range; return true; } // methods to set the block size and buffer // bool8 setBlockSize(int32 nbytes); bool8 setBufferSize(int32 nblocks); // method: setCompType // bool8 setCompType(COMP_TYPE comp_type) { compression_type_d = comp_type; return true; } // method: setFileFormat // bool8 setFileFormat(FILE_FORMAT file_format) { file_format_d = file_format; return true; } // method: setFileType // bool8 setFileType(FILE_TYPE file_type) { file_type_d = file_type; return true; } // method: setID // bool8 setID(const String& id) { return id_d.assign(id); } // methods to set the number of bytes per sample, sample precision // and num of channels // bool8 setNumChannels(int32 num_channels); bool8 setSampleNumBytes(int32 sample_num_bytes); bool8 setSamplePrecision(SAMPLE_PRECISION sample_precision); // method: setSampleFrequency // bool8 setSampleFrequency(float64 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 // bool8 setMaCoeff(const VectorFloat& ma_coeff); bool8 setArCoeff(const VectorFloat& ar_coeff); //--------------------------------------- // // this section contains methods // that perform units conversions // //--------------------------------------- // method: timeToSample // int32 timeToSample(float64 time) const { return (int32)Integral::round(time * sample_freq_d); } // method: sampleToTime // float64 sampleToTime(int32 index) const { return (float64)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 // int32 readSofData(Sof& sof_a); int32 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 // bool8 readSofStart(Sof& sof, int32 tag, const String& name = CLASS_NAME); bool8 writeSofStart(Sof& sof, int32 tag, const String& name = CLASS_NAME) const; bool8 readSofStartData(Sof& sof, const String& pname = String::getEmptyString(), int32 size = SofParser::FULL_OBJECT, bool8 param = true, bool8 nested = false); bool8 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 // bool8 writeSofConfig(Sof& sof_a) const; bool8 readSofConfig(Sof& sof_a, SofParser& parser); //--------------------------------------------------------------------------- // // private methods // //--------------------------------------------------------------------------- private: //--------------------------------------- // // this section contains private functions // that operate on all types of files // //--------------------------------------- // method: getStartSamp // int32 getStartSamp(int32 ctag = DEF_CHANNEL_TAG) const { int32 buf_duration = buffers_d(ctag).getNumElements(); int32 buf_end = buf_end_samp_d(ctag); // calculate and return the start time // return (buf_end - buf_duration); } // method: getEndSamp // int32 getEndSamp(int32 ctag = DEF_CHANNEL_TAG) const { return buf_end_samp_d(ctag); } // methods to read the next block of data // bool8 appendData(); // methods to convert the Vector to bytes for writing // bool8 revertData(VectorLong& whole_data, Vector& data, int32 channel_tag) const; // methods to round the sample number up or down by block boundaries // int32 blockFloor(int32 samp_num) const; int32 blockCeil(int32 samp_num) const; // methods to clear out buffer and pointers // bool8 resetBuffer(int32 channel_tag = CHANNEL_TAG_ALL); bool8 resetFilter(int32 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 // //--------------------------------------- bool8 openSofStream(const Filename& filename, MODE mode = READ_ONLY); bool8 openSof(const Filename& filename, MODE mode = READ_ONLY); bool8 readSofHeader(); bool8 writeSofHeader(); int32 readSofData(Vector& data, int32 channel_tag = DEF_CHANNEL_TAG, int32 start_samp = DEF_START_SAMP, int32 num_samp = DEF_NUM_SAMP); int32 writeSofData(Vector& data, int32 channel_tag = DEF_CHANNEL_TAG); //--------------------------------------- // // format: raw // //--------------------------------------- bool8 openRawStream(const Filename& filename, MODE mode = READ_ONLY); bool8 openRaw(const Filename& filename, MODE mode = READ_ONLY); bool8 readRawHeader(); bool8 writeRawHeader() const; int32 readRawData(Vector& data, int32 channel_tag = DEF_CHANNEL_TAG, int32 start_samp = DEF_START_SAMP, int32 num_samp = DEF_NUM_SAMP); int32 writeRawData(Vector& data, int32 channel_tag = DEF_CHANNEL_TAG); //--------------------------------------- // // format: sphere // //--------------------------------------- bool8 openSphereStream(const Filename& filename, MODE mode = READ_ONLY); bool8 openSphere(const Filename& filename, MODE mode = READ_ONLY); bool8 readSphereHeader(); bool8 writeSphereHeader() const; int32 readSphereData(Vector& data, int32 channel_tag = DEF_CHANNEL_TAG, int32 start_samp = DEF_START_SAMP, int32 num_samp = DEF_NUM_SAMP); int32 writeSphereData(Vector& data, int32 channel_tag = DEF_CHANNEL_TAG); //--------------------------------------- // // format: sgi audiofile support // //--------------------------------------- bool8 openAFStream(const Filename& filename, MODE mode = READ_ONLY); bool8 openAF(const Filename& filename, MODE mode = READ_ONLY); bool8 readAFHeader(); bool8 writeAFHeader() const; int32 readAFData(Vector& data, int32 channel_tag = DEF_CHANNEL_TAG, int32 start_samp = DEF_START_SAMP, int32 num_samp = DEF_NUM_SAMP); int32 writeAFData(Vector& data, int32 channel_tag = DEF_CHANNEL_TAG); }; // end of include file // #endif