//| Copyright: (C) 2009-2020 Kevin Larke //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file. //( { file_desc: "Read and write AIFF and WAV audio files." kw:[file audio] } // // This class supports reading uncompressed AIFF and WAV files and writing uncompressed AIFF files. // The reading and writing routines are known to work with 8,16,24, and 32 bit integer sample formats. // //) #ifndef cmAudioFile_h #define cmAudioFile_h #ifdef __cplusplus extern "C" { #endif //( #ifndef cmAudioFile_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 cmAudioFile_MAX_FRAME_READ_CNT (8192) #endif // Audio file result codes. enum { kOkAfRC = 0, kOpenFailAfRC, kReadFailAfRC, kWriteFailAfRC, kSeekFailAfRC, kCloseFailAfRC, kNotAiffAfRC, kInvalidBitWidthAfRC, kInvalidFileModeAfRC, kInvalidHandleAfRC, kInvalidChCountAfRC, kRptFileFailAfRC, kUnknownErrAfRC }; // 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]; } cmAudioFileMarker_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 } cmAudioFileBext_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 cmAudioFileMarker_t* markerArray; // array of markers cmAudioFileBext_t bextRecd; // only used with Broadcast WAV files } cmAudioFileInfo_t; typedef cmHandle_t cmAudioFileH_t; // opaque audio file handle extern cmAudioFileH_t cmNullAudioFileH; // NULL audio file handle // Create an audio file handle and optionally use the handle to open an audio file. // // fn The audio file name to open or NULL to create the audio file handle without opening the file. // infoPtr A pointer to an audioFileInfo record to be filled when the file is open or NULL to ignore. // rcPtr A pointer to a result code to be set in the event of a runtime error or NULL to ignore. // rpt A pointer to a cmRpt_t object which error messages from this class will be directed to. // Returns cmAudioFileH_t A new audio file handle. // cmAudioFileH_t cmAudioFileNewOpen( const cmChar_t* fn, cmAudioFileInfo_t* infoPtr, cmRC_t* rcPtr, cmRpt_t* rpt ); // Open an audio file for writing cmAudioFileH_t cmAudioFileNewCreate( const cmChar_t* fn, double srate, unsigned bits, unsigned chCnt, cmRC_t* rcPtr, cmRpt_t* rpt ); // Open an audio file for reading using a handle returned from an earlier call to audioFileNewXXX(). // // h A file handle returned from and earlier call to cmAudioFileNewOpen() or cmAudioFileNewCreate(). // fn The audio file name to open or NULL to create the audio file handle without opening the file. // infoPtr A pointer to an audioFileInfo record to be filled when the file is open or NULL to ignore. // Returns an cmRC_t value indicating the success (kOkAfRC) or failure of the call. // // If the audio file handle 'h' refers to an open file then it is automatically closed prior to being // reopened with the new file. cmRC_t cmAudioFileOpen( cmAudioFileH_t h, const cmChar_t* fn, cmAudioFileInfo_t* infoPtr ); // Open an audio file for writing. The type of the audio file, AIF or WAV // is determined by the file name extension. cmRC_t cmAudioFileCreate( cmAudioFileH_t h, // Handle returned from an earlier call to cmAudioFileNewCreate() or cmAudioFileNewOpen(). const cmChar_t* fn, // File name of the new file. double srate, // Sample rate of the new file. unsigned bits, // Sample word width for the new file in bits (must be 8,16,24 or 32). unsigned chCnt // Audio channel count for the new file. ); // Close a the file associated with handle 'h' but do not release the handle. // If the file was opened for writing (cmAudioFileCreate()) then this function will // write the file header prior to closing the file. cmRC_t cmAudioFileClose( cmAudioFileH_t* h ); // Close the file associated with handle 'h' (via an internal call to // cmAudioFileClose()) and release the handle and any resources // associated with it. This is the complement to cmAudioFileOpen/Create(). cmRC_t cmAudioFileDelete( cmAudioFileH_t* h ); // Return true if the handle is not closed or deleted. bool cmAudioFileIsValid( cmAudioFileH_t h ); // Return true if the handle is open. bool cmAudioFileIsOpen( cmAudioFileH_t h ); // Return true if the current file position is at the end of the file. bool cmAudioFileIsEOF( cmAudioFileH_t h ); // Return the current file position as a frame index. unsigned cmAudioFileTell( cmAudioFileH_t h ); // Set the current file position as an offset from the first frame. cmRC_t cmAudioFileSeek( cmAudioFileH_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 cmAudioFileSeek()). 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 cmAudioFileTell()). // 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) cmRC_t cmAudioFileReadInt( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr ); cmRC_t cmAudioFileReadFloat( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr ); cmRC_t cmAudioFileReadDouble( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr ); cmRC_t cmAudioFileGetInt( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt ); cmRC_t cmAudioFileGetFloat( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt ); cmRC_t cmAudioFileGetDouble( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt ); // Sum the returned samples into the output buffer. cmRC_t cmAudioFileReadSumInt( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr ); cmRC_t cmAudioFileReadSumFloat( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr ); cmRC_t cmAudioFileReadSumDouble( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr ); cmRC_t cmAudioFileGetSumInt( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt ); cmRC_t cmAudioFileGetSumFloat( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt ); cmRC_t cmAudioFileGetSumDouble( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt ); // Sample Writing Functions cmRC_t cmAudioFileWriteInt( cmAudioFileH_t h, unsigned frmCnt, unsigned chCnt, int** bufPtrPtr ); cmRC_t cmAudioFileWriteFloat( cmAudioFileH_t h, unsigned frmCnt, unsigned chCnt, float** bufPtrPtr ); cmRC_t cmAudioFileWriteDouble( cmAudioFileH_t h, unsigned frmCnt, unsigned chCnt, double** bufPtrPtr ); cmRC_t cmAudioFileWriteFileInt( const char* fn, double srate, unsigned bit, unsigned frmCnt, unsigned chCnt, int** bufPtrPtr, cmRpt_t* rpt ); cmRC_t cmAudioFileWriteFileFloat( const char* fn, double srate, unsigned bit, unsigned frmCnt, unsigned chCnt, float** bufPtrPtr, cmRpt_t* rpt ); cmRC_t cmAudioFileWriteFileDouble( const char* fn, double srate, unsigned bit, unsigned frmCnt, unsigned chCnt, double** bufPtrPtr, cmRpt_t* rpt ); // Alias the cmSample_t and cmReal_t sample reading and writing functions to the appropriate // type based on #CM_FLOAT_SMP and #CM_FLOAT_REAL. #if CM_FLOAT_SMP == 1 #define cmAudioFileReadSample cmAudioFileReadFloat #define cmAudioFileReadSumSample cmAudioFileReadSumFloat #define cmAudioFileGetSample cmAudioFileGetFloat #define cmAudioFileGetSumSample cmAudioFileGetSumFloat #define cmAudioFileWriteSample cmAudioFileWriteFloat #define cmAudioFileWriteFileSample cmAudioFileWriteFileFloat #else #define cmAudioFileReadSample cmAudioFileReadDouble #define cmAudioFileReadSumSample cmAudioFileReadSumDouble #define cmAudioFileGetSample cmAudioFileGetDouble #define cmAudioFileGetSumSample cmAudioFileGetSumDouble #define cmAudioFileWriteSample cmAudioFileWriteDouble #define cmAudioFileWriteFileSample cmAudioFileWriteFileDouble #endif #if CM_FLOAT_REAL == 1 #define cmAudioFileReadReal cmAudioFileReadFloat #define cmAudioFileReadSumReal cmAudioFileReadSumFloat #define cmAudioFileGetReal cmAudioFileGetFloat #define cmAudioFileGetSumReal cmAudioFileGetSumFloat #define cmAudioFileWriteReal cmAudioFileWriteFloat #define cmAudioFileWriteFileReal cmAudioFileWriteFileFloat #else #define cmAudioFileReadReal cmAudioFileReadDouble #define cmAudioFileReadSumReal cmAudioFileReadSumDouble #define cmAudioFileGetReal cmAudioFileGetDouble #define cmAudioFileGetSumReal cmAudioFileGetSumDouble #define cmAudioFileWriteReal cmAudioFileWriteDouble #define cmAudioFileWriteFileReal cmAudioFileWriteFileDouble #endif // 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 cmRC_t cmAudioFileMinMaxMean( cmAudioFileH_t h, unsigned chIdx, cmSample_t* minPtr, cmSample_t* maxPtr, cmSample_t* meanPtr ); cmRC_t cmAudioFileMinMaxMeanFn( const cmChar_t* fn, unsigned chIdx, cmSample_t* minPtr, cmSample_t* maxPtr, cmSample_t* meanPtr, cmRpt_t* rpt ); // Return the file name associated with a audio file handle. const cmChar_t* cmAudioFileName( cmAudioFileH_t h ); // Given an error code return the associated message. const char* cmAudioFileErrorMsg( unsigned rc ); // Return the cmAudioFileInfo_t record associated with a file. cmRC_t cmAudioFileGetInfo( const cmChar_t* fn, cmAudioFileInfo_t* infoPtr, cmRpt_t* rpt ); // Print the cmAudioFileInfo_t to a file. void cmAudioFilePrintInfo( const cmAudioFileInfo_t* infoPtr, cmRpt_t* ); cmRC_t cmAudioFileReportInfo( cmCtx_t* ctx, const cmChar_t* audioFn, const cmChar_t* rptFn ); // Print the file header information and frmCnt sample values beginning at frame index frmIdx. cmRC_t cmAudioFileReport( cmAudioFileH_t h, cmRpt_t* rpt, unsigned frmIdx, unsigned frmCnt ); // Print the file header information and frmCnt sample values beginning at frame index frmIdx. cmRC_t cmAudioFileReportFn( const cmChar_t* fn, unsigned frmIdx, unsigned frmCnt, cmRpt_t* rpt ); // 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. cmRC_t cmAudioFileSetSrate( const cmChar_t* audioFn, unsigned srate ); // Generate a sine tone and write it to a file. cmRC_t cmAudioFileSine( cmCtx_t* ctx, const cmChar_t* fn, double srate, unsigned bits, double hz, double gain, double secs ); // Testing and example routine for functions in cmAudioFile.h. // Also see cmProcTest.c cmAudioFileReadWriteTest() void cmAudioFileTest( cmCtx_t* ctx, int argc, const char* argv[] ); //) #ifdef __cplusplus } #endif #endif