//| Copyright: (C) 2020-2024 Kevin Larke //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file. #ifndef cwAudioFile_h #define cwAudioFile_h #ifndef cwAudioFile_MAX_FRAME_READ_CNT // Maximum number of samples which will be read in one call to fread(). // This value is only significant in that an internal buffer is created on the stack // whose size must be limited to prevent stack overflows. #define cwAudioFile_MAX_FRAME_READ_CNT (8192) #endif namespace cw { namespace audiofile { typedef handle handle_t; // Informational flags used by audioFileInfo enum { kAiffAfFl = 0x01, // this is an AIFF file kWavAfFl = 0x02, // this is a WAV file kSwapAfFl = 0x04, // file header bytes must be swapped kAifcAfFl = 0x08, // this is an AIFC file kSwapSamplesAfFl = 0x10, // file sample bytes must be swapped }; // Constants enum { kAudioFileLabelCharCnt = 256, kAfBextDescN = 256, kAfBextOriginN = 32, kAfBextOriginRefN = 32, kAfBextOriginDateN = 10, kAfBextOriginTimeN = 8 }; // Aiff marker record typedef struct { unsigned id; unsigned frameIdx; char label[kAudioFileLabelCharCnt]; } marker_t; // Broadcast WAV header record As used by ProTools audio files. See http://en.wikipedia.org/wiki/Broadcast_Wave_Format // When generated from Protools the timeRefLow/timeRefHigh values appear to actually refer // to the position on the Protools time-line rather than the wall clock time. typedef struct { char desc[ kAfBextDescN + 1 ]; char origin[ kAfBextOriginN + 1 ]; char originRef[ kAfBextOriginRefN + 1 ]; char originDate[kAfBextOriginDateN + 1 ]; char originTime[kAfBextOriginTimeN + 1 ]; unsigned timeRefLow; // sample count since midnight low word unsigned timeRefHigh; // sample count since midnight high word } bext_t; // Audio file information record used by audioFileNew and audioFileOpen typedef struct { unsigned bits; // bits per sample unsigned chCnt; // count of audio file channels double srate; // audio file sample rate in samples per second unsigned frameCnt; // total number of sample frames in the audio file unsigned flags; // informational flags unsigned markerCnt; // count of markers in markerArray marker_t* markerArray; // array of markers bext_t bextRecd; // only used with Broadcast WAV files } info_t; // The file path for fn is internally expanded if it begins with a '~' or '..'. rc_t open( handle_t& h, const char* fn, info_t* info ); // Set bits to 0 to write the file in IEEE float format. // The file path for fn is internally expanded if it begins with a '~' or '..'. rc_t create( handle_t& h, const char* fn, double srate, unsigned bits, unsigned chN ); rc_t close( handle_t& h ); // Return true if the handle is open. bool isOpen( handle_t h ); // Return true if the current file position is at the end of the file. bool isEOF( handle_t h ); // Return the current file position as a frame index. unsigned tell( handle_t h ); // Set the current file position as an offset from the first frame. rc_t seek( handle_t h, unsigned frmIdx ); // Sample Reading Functions. // // Fill a user suppled buffer with up to frmCnt samples. // If less than frmCnt samples are available at the specified audio file location then the unused // buffer space is set to zero. Check *actualFrmCntPtr for the count of samples actually available // in the return buffer. Functions which do not include a begFrmIdx argument begin reading from // the current file location (see seek()). The buf argument is always a pointer to an // array of pointers of length chCnt. Each channel buffer specified in buf[] must contain at least // frmCnt samples. // // // h An audio file handle returned from an earlier call to audioFileNew() // fn The name of the audio file to read. // begFrmIdx The frame index of the first sample to read. Functions that do not use this parameter begin reading at the current file location (See tell()). // frmCnt The number of samples allocated in buf. // chIdx The index of the first channel to read. // chCnt The count of channels to read. // buf An array containing chCnt pointers to arrays of frmCnt samples. // actualFrmCntPtr The number of frames actually written to the return buffer (ignored if NULL) rc_t readInt( handle_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr ); rc_t readFloat( handle_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr ); rc_t readDouble( handle_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr ); rc_t getInt( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr, info_t* afInfoPtr); rc_t getFloat( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr, info_t* afInfoPtr); rc_t getDouble( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr, info_t* afInfoPtr); // Sum the returned samples into the output buffer. rc_t readSumInt( handle_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr ); rc_t readSumFloat( handle_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr ); rc_t readSumDouble( handle_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr ); rc_t getSumInt( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr, info_t* afInfoPtr); rc_t getSumFloat( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr, info_t* afInfoPtr); rc_t getSumDouble( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr, info_t* afInfoPtr); // Allocate a buffer and read the file into it rc_t allocFloatBuf( const char* fn, float**& chBufRef, unsigned& chCntRef, unsigned& frmCntRef, info_t& afInfoPtrRef, unsigned begFrmIdx=0, unsigned frmCnt=0, unsigned chIdx=0, unsigned chCnt=0 ); rc_t freeFloatBuf( float** floatBufRef, unsigned chCnt ); // Sample Writing Functions rc_t writeInt( handle_t h, unsigned frmCnt, unsigned chCnt, const int* const* bufPtrPtr ); rc_t writeFloat( handle_t h, unsigned frmCnt, unsigned chCnt, const float* const* bufPtrPtr ); rc_t writeDouble( handle_t h, unsigned frmCnt, unsigned chCnt, const double* const* bufPtrPtr ); // Write a buffer of interleaved floating point samples. Note that no sample format conversion is // implemented on this function. The samples are directly written to the current file location. // This means that the file must have been 'created()' with 'bits' set to 0 to indicate that the // file is using a single precision float sample format. This limitation could easily be removed // by adding sample conversion to integer types. rc_t writeFloatInterleaved( handle_t h, unsigned frmCnt, unsigned chCnt, const float* bufPtr ); // File Writing Functions // Set 'bit' to 0 to write the file in IEEE float format. rc_t writeFileInt( const char* fn, double srate, unsigned bit, unsigned frmCnt, unsigned chCnt, const int* const * bufPtrPtr); rc_t writeFileFloat( const char* fn, double srate, unsigned bit, unsigned frmCnt, unsigned chCnt, const float* const* bufPtrPtr); rc_t writeFileDouble( const char* fn, double srate, unsigned bit, unsigned frmCnt, unsigned chCnt, const double* const* bufPtrPtr); // Scan an entire audio file and return the minimum, maximum and mean sample value. // On error *minPtr, *maxPtr, and *meanPtr are set to -acSample_MAX, cmSample_MAX, and 0 respectively rc_t minMaxMean( handle_t h, unsigned chIdx, float* minPtr, float* maxPtr, float* meanPtr ); rc_t minMaxMeanFn( const char* fn, unsigned chIdx, float* minPtr, float* maxPtr, float* meanPtr ); // Return the file name associated with a audio file handle. const char* name( handle_t h ); unsigned channelCount( handle_t h ); double sampleRate( handle_t h ); // Return the info_t record associated with a file. rc_t getInfo( const char* fn, info_t* infoPtr ); // Print the info_t to a file. void printInfo( const info_t* infoPtr, log::handle_t logH ); rc_t reportInfo( const char* audioFn ); // Print the file header information and frmCnt sample values beginning at frame index frmIdx. rc_t report( handle_t h, log::handle_t logH, unsigned frmIdx=0, unsigned frmCnt=kInvalidCnt ); rc_t reportFn( const char* fn, log::handle_t logH, unsigned frmIdx=0, unsigned frmCnt=kInvalidCnt ); // Change the sample rate value in the header. Note that this function does not resample the audio // signal it simply changes the value of the sample rate in the header. rc_t setSrate( const char* audioFn, unsigned srate ); // Testing and example routine for functions in .h. // Also see cmProcTest.c readWriteTest() rc_t test( const object_t* cfg ); } } #endif