mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-28 04:31:06 +00:00
c1a4db611b
Original commit message from CVS: Add monkeyaudio plugin
393 lines
21 KiB
C++
393 lines
21 KiB
C++
/*****************************************************************************************
|
|
Monkey's Audio MACLib.h (include for using MACLib.lib in your projects)
|
|
Copyright (C) 2000-2002 by Matthew T. Ashland All Rights Reserved.
|
|
|
|
Overview:
|
|
|
|
There are two main interfaces... create one (using CreateIAPExxx) and go to town:
|
|
|
|
IAPECompress - for creating APE files
|
|
IAPEDecompress - for decompressing and analyzing APE files
|
|
|
|
Note(s):
|
|
|
|
-unless otherwise specified, functions return ERROR_SUCCESS (0) on success and an
|
|
error code on failure.
|
|
|
|
-the terminology "Sample" refers to a single sample value, and "Block" refers
|
|
to a collection of "Channel" samples. For simplicity, MAC typically uses blocks
|
|
everywhere so that channel mis-alignment cannot happen. (i.e. on a CD, a sample is
|
|
2 bytes and a block is 4 bytes ([2 bytes / sample] * [2 channels] = 4 bytes))
|
|
|
|
Questions / Suggestions:
|
|
|
|
Please direct questions or comments to the Monkey's Audio developers board:
|
|
http://www.monkeysaudio.com/cgi-bin/YaBB/YaBB.cgi -> Developers
|
|
or, if necessary, email @ monkeysaudio.com
|
|
*****************************************************************************************/
|
|
|
|
#ifndef APE_MACLIB_H
|
|
#define APE_MACLIB_H
|
|
|
|
/*****************************************************************************************
|
|
Defines
|
|
*****************************************************************************************/
|
|
#define COMPRESSION_LEVEL_FAST 1000
|
|
#define COMPRESSION_LEVEL_NORMAL 2000
|
|
#define COMPRESSION_LEVEL_HIGH 3000
|
|
#define COMPRESSION_LEVEL_EXTRA_HIGH 4000
|
|
#define COMPRESSION_LEVEL_INSANE_HIGH 5000
|
|
#define COMPRESSION_LEVEL_BRAINDEAD_HIGH 6000
|
|
|
|
#define MAC_FORMAT_FLAG_8_BIT 1 // is 8-bit
|
|
#define MAC_FORMAT_FLAG_CRC 2 // uses the new CRC32 error detection
|
|
#define MAC_FORMAT_FLAG_HAS_PEAK_LEVEL 4 // unsigned __int32 Peak_Level after the header
|
|
#define MAC_FORMAT_FLAG_24_BIT 8 // is 24-bit
|
|
#define MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS 16 // has the number of seek elements after the peak level
|
|
#define MAC_FORMAT_FLAG_CREATE_WAV_HEADER 32 // create the wave header on decompression (not stored)
|
|
|
|
#define CREATE_WAV_HEADER_ON_DECOMPRESSION -1
|
|
#define MAX_AUDIO_BYTES_UNKNOWN -1
|
|
|
|
typedef void (__stdcall * APE_PROGRESS_CALLBACK) (int);
|
|
|
|
/*****************************************************************************************
|
|
WAV header structure
|
|
*****************************************************************************************/
|
|
struct WAVE_HEADER
|
|
{
|
|
// RIFF header
|
|
char cRIFFHeader[4];
|
|
unsigned int nRIFFBytes;
|
|
|
|
// data type
|
|
char cDataTypeID[4];
|
|
|
|
// wave format
|
|
char cFormatHeader[4];
|
|
unsigned int nFormatBytes;
|
|
|
|
unsigned short nFormatTag;
|
|
unsigned short nChannels;
|
|
unsigned int nSamplesPerSec;
|
|
unsigned int nAvgBytesPerSec;
|
|
unsigned short nBlockAlign;
|
|
unsigned short nBitsPerSample;
|
|
|
|
// data chunk header
|
|
char cDataHeader[4];
|
|
unsigned int nDataBytes;
|
|
};
|
|
|
|
/*****************************************************************************************
|
|
APE header structure (what's at the front of an APE file)
|
|
*****************************************************************************************/
|
|
#define APE_HEADER_BYTES 32
|
|
struct APE_HEADER
|
|
{
|
|
char cID[4]; // should equal 'MAC '
|
|
unsigned __int16 nVersion; // version number * 1000 (3.81 = 3810)
|
|
unsigned __int16 nCompressionLevel; // the compression level
|
|
unsigned __int16 nFormatFlags; // any format flags (for future use)
|
|
unsigned __int16 nChannels; // the number of channels (1 or 2)
|
|
unsigned __int32 nSampleRate; // the sample rate (typically 44100)
|
|
unsigned __int32 nHeaderBytes; // the bytes after the MAC header that compose the WAV header
|
|
unsigned __int32 nTerminatingBytes; // the bytes after that raw data (for extended info)
|
|
unsigned __int32 nTotalFrames; // the number of frames in the file
|
|
unsigned __int32 nFinalFrameBlocks; // the number of samples in the final frame
|
|
};
|
|
|
|
/*************************************************************************************************
|
|
Classes (fully defined elsewhere)
|
|
*************************************************************************************************/
|
|
class CIO;
|
|
class CInputSource;
|
|
|
|
/*************************************************************************************************
|
|
IAPEDecompress fields - used when querying for information
|
|
|
|
Note(s):
|
|
-the distinction between APE_INFO_XXXX and APE_DECOMPRESS_XXXX is that the first is querying the APE
|
|
information engine, and the other is querying the decompressor, and since the decompressor can be
|
|
a range of an APE file (for APL), differences will arise. Typically, use the APE_DECOMPRESS_XXXX
|
|
fields when querying for info about the length, etc. so APL will work properly.
|
|
(i.e. (APE_INFO_TOTAL_BLOCKS != APE_DECOMPRESS_TOTAL_BLOCKS) for APL files)
|
|
*************************************************************************************************/
|
|
enum APE_DECOMPRESS_FIELDS
|
|
{
|
|
APE_INFO_FILE_VERSION = 1000, // version of the APE file * 1000 (3.93 = 3930) [ignored, ignored]
|
|
APE_INFO_COMPRESSION_LEVEL = 1001, // compression level of the APE file [ignored, ignored]
|
|
APE_INFO_FORMAT_FLAGS = 1002, // format flags of the APE file [ignored, ignored]
|
|
APE_INFO_SAMPLE_RATE = 1003, // sample rate (Hz) [ignored, ignored]
|
|
APE_INFO_BITS_PER_SAMPLE = 1004, // bits per sample [ignored, ignored]
|
|
APE_INFO_BYTES_PER_SAMPLE = 1005, // number of bytes per sample [ignored, ignored]
|
|
APE_INFO_CHANNELS = 1006, // channels [ignored, ignored]
|
|
APE_INFO_BLOCK_ALIGN = 1007, // block alignment [ignored, ignored]
|
|
APE_INFO_BLOCKS_PER_FRAME = 1008, // number of blocks in a frame (frames are used internally) [ignored, ignored]
|
|
APE_INFO_FINAL_FRAME_BLOCKS = 1009, // blocks in the final frame (frames are used internally) [ignored, ignored]
|
|
APE_INFO_TOTAL_FRAMES = 1010, // total number frames (frames are used internally) [ignored, ignored]
|
|
APE_INFO_WAV_HEADER_BYTES = 1011, // header bytes of the decompressed WAV [ignored, ignored]
|
|
APE_INFO_WAV_TERMINATING_BYTES = 1012, // terminating bytes of the decompressed WAV [ignored, ignored]
|
|
APE_INFO_WAV_DATA_BYTES = 1013, // data bytes of the decompressed WAV [ignored, ignored]
|
|
APE_INFO_WAV_TOTAL_BYTES = 1014, // total bytes of the decompressed WAV [ignored, ignored]
|
|
APE_INFO_APE_TOTAL_BYTES = 1015, // total bytes of the APE file [ignored, ignored]
|
|
APE_INFO_TOTAL_BLOCKS = 1016, // total blocks of audio data [ignored, ignored]
|
|
APE_INFO_LENGTH_MS = 1017, // length in ms (1 sec = 1000 ms) [ignored, ignored]
|
|
APE_INFO_AVERAGE_BITRATE = 1018, // average bitrate of the APE [ignored, ignored]
|
|
APE_INFO_FRAME_BITRATE = 1019, // bitrate of specified APE frame [frame index, ignored]
|
|
APE_INFO_DECOMPRESSED_BITRATE = 1020, // bitrate of the decompressed WAV [ignored, ignored]
|
|
APE_INFO_PEAK_LEVEL = 1021, // peak audio level (-1 is unknown) [ignored, ignored]
|
|
APE_INFO_SEEK_BIT = 1022, // bit offset [frame index, ignored]
|
|
APE_INFO_SEEK_BYTE = 1023, // byte offset [frame index, ignored]
|
|
APE_INFO_WAV_HEADER_DATA = 1024, // error code [buffer *, max bytes]
|
|
APE_INFO_WAV_TERMINATING_DATA = 1025, // error code [buffer *, max bytes]
|
|
APE_INFO_WAVEFORMATEX = 1026, // error code [waveformatex *, ignored]
|
|
APE_INFO_IO_SOURCE = 1027, // I/O source (CIO *) [ignored, ignored]
|
|
APE_INFO_FRAME_BYTES = 1028, // bytes (compressed) of the frame [frame index, ignored]
|
|
APE_INFO_FRAME_BLOCKS = 1029, // blocks in a given frame [frame index, ignored]
|
|
APE_INFO_TAG = 1030, // point to tag (CAPETag *) [ignored, ignored]
|
|
|
|
APE_DECOMPRESS_CURRENT_BLOCK = 2000, // current block location [ignored, ignored]
|
|
APE_DECOMPRESS_CURRENT_MS = 2001, // current millisecond location [ignored, ignored]
|
|
APE_DECOMPRESS_TOTAL_BLOCKS = 2002, // total blocks in the decompressors range [ignored, ignored]
|
|
APE_DECOMPRESS_LENGTH_MS = 2003, // total blocks in the decompressors range [ignored, ignored]
|
|
APE_DECOMPRESS_CURRENT_BITRATE = 2004, // current bitrate [ignored, ignored]
|
|
APE_DECOMPRESS_AVERAGE_BITRATE = 2005 // average bitrate (works with ranges) [ignored, ignored]
|
|
};
|
|
|
|
/*************************************************************************************************
|
|
IAPEDecompress - interface for working with existing APE files (decoding, seeking, analyzing, etc.)
|
|
*************************************************************************************************/
|
|
class IAPEDecompress
|
|
{
|
|
public:
|
|
|
|
// destructor (needed so implementation's destructor will be called)
|
|
virtual ~IAPEDecompress() {}
|
|
|
|
/*********************************************************************************************
|
|
* Decompress / Seek
|
|
*********************************************************************************************/
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// GetData(...) - gets raw decompressed audio
|
|
//
|
|
// Parameters:
|
|
// char * pBuffer
|
|
// a pointer to a buffer to put the data into
|
|
// int nBlocks
|
|
// the number of audio blocks desired (see note at intro about blocks vs. samples)
|
|
// int * pBlocksRetrieved
|
|
// the number of blocks actually retrieved (could be less at end of file or on critical failure)
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
virtual int GetData(char * pBuffer, int nBlocks, int * pBlocksRetrieved) = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Seek(...) - seeks
|
|
//
|
|
// Parameters:
|
|
// int nBlockOffset
|
|
// the block to seek to (see note at intro about blocks vs. samples)
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
virtual int Seek(int nBlockOffset) = 0;
|
|
|
|
/*********************************************************************************************
|
|
* Get Information
|
|
*********************************************************************************************/
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// GetInfo(...) - get information about the APE file or the state of the decompressor
|
|
//
|
|
// Parameters:
|
|
// APE_DECOMPRESS_FIELDS Field
|
|
// the field we're querying (see APE_DECOMPRESS_FIELDS above for more info)
|
|
// int nParam1
|
|
// generic parameter... usage is listed in APE_DECOMPRESS_FIELDS
|
|
// int nParam2
|
|
// generic parameter... usage is listed in APE_DECOMPRESS_FIELDS
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
virtual int GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1 = 0, int nParam2 = 0) = 0;
|
|
};
|
|
|
|
/*************************************************************************************************
|
|
IAPECompress - interface for creating APE files
|
|
|
|
Usage:
|
|
|
|
To create an APE file, you Start(...), then add data (in a variety of ways), then Finish(...)
|
|
*************************************************************************************************/
|
|
class IAPECompress
|
|
{
|
|
public:
|
|
|
|
// destructor (needed so implementation's destructor will be called)
|
|
virtual ~IAPECompress() {}
|
|
|
|
/*********************************************************************************************
|
|
* Start
|
|
*********************************************************************************************/
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Start(...) / StartEx(...) - starts encoding
|
|
//
|
|
// Parameters:
|
|
// CIO * pioOutput / const char * pFilename
|
|
// the output... either a filename or an I/O source
|
|
// WAVEFORMATEX * pwfeInput
|
|
// format of the audio to encode (use FillWaveFormatEx() if necessary)
|
|
// int nMaxAudioBytes
|
|
// the absolute maximum audio bytes that will be encoded... encoding fails with a
|
|
// ERROR_APE_COMPRESS_TOO_MUCH_DATA if you attempt to encode more than specified here
|
|
// (if unknown, use MAX_AUDIO_BYTES_UNKNOWN to allocate as much storage in the seek table as
|
|
// possible... limit is then 2 GB of data (~4 hours of CD music)... this wastes around
|
|
// 30kb, so only do it if completely necessary)
|
|
// int nCompressionLevel
|
|
// the compression level for the APE file (fast - extra high)
|
|
// (note: extra-high is much slower for little gain)
|
|
// const unsigned char * pHeaderData
|
|
// a pointer to a buffer containing the WAV header (data before the data block in the WAV)
|
|
// (note: use NULL for on-the-fly encoding... see next parameter)
|
|
// int nHeaderBytes
|
|
// number of bytes in the header data buffer (use CREATE_WAV_HEADER_ON_DECOMPRESSION and
|
|
// NULL for the pHeaderData and MAC will automatically create the appropriate WAV header
|
|
// on decompression)
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
virtual int Start(const char * pOutputFilename, const WAVEFORMATEX * pwfeInput,
|
|
int nMaxAudioBytes = MAX_AUDIO_BYTES_UNKNOWN, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL,
|
|
const unsigned char * pHeaderData = NULL, int nHeaderBytes = CREATE_WAV_HEADER_ON_DECOMPRESSION) = 0;
|
|
|
|
virtual int StartEx(CIO * pioOutput, const WAVEFORMATEX * pwfeInput,
|
|
int nMaxAudioBytes = MAX_AUDIO_BYTES_UNKNOWN, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL,
|
|
const unsigned char * pHeaderData = NULL, int nHeaderBytes = CREATE_WAV_HEADER_ON_DECOMPRESSION) = 0;
|
|
|
|
/*********************************************************************************************
|
|
* Add / Compress Data
|
|
* - there are 3 ways to add data:
|
|
* 1) simple call AddData(...)
|
|
* 2) lock MAC's buffer, copy into it, and unlock (LockBuffer(...) / UnlockBuffer(...))
|
|
* 3) from an I/O source (AddDataFromInputSource(...))
|
|
*********************************************************************************************/
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// AddData(...) - adds data to the encoder
|
|
//
|
|
// Parameters:
|
|
// unsigned char * pData
|
|
// a pointer to a buffer containing the raw audio data
|
|
// int nBytes
|
|
// the number of bytes in the buffer
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
virtual int AddData(unsigned char * pData, int nBytes) = 0;
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// GetBufferBytesAvailable(...) - returns the number of bytes available in the buffer
|
|
// (helpful when locking)
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
virtual int GetBufferBytesAvailable() = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// LockBuffer(...) - locks MAC's buffer so we can copy into it
|
|
//
|
|
// Parameters:
|
|
// int * pBytesAvailable
|
|
// returns the number of bytes available in the buffer (DO NOT COPY MORE THAN THIS IN)
|
|
//
|
|
// Return:
|
|
// pointer to the buffer (add at that location)
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
virtual unsigned char * LockBuffer(int * pBytesAvailable) = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// UnlockBuffer(...) - releases the buffer
|
|
//
|
|
// Parameters:
|
|
// int nBytesAdded
|
|
// the number of bytes copied into the buffer
|
|
// BOOL bProcess
|
|
// whether MAC should process as much as possible of the buffer
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
virtual int UnlockBuffer(int nBytesAdded, BOOL bProcess = TRUE) = 0;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// AddDataFromInputSource(...) - use a CInputSource (input source) to add data
|
|
//
|
|
// Parameters:
|
|
// CInputSource * pInputSource
|
|
// a pointer to the input source
|
|
// int nMaxBytes
|
|
// the maximum number of bytes to let MAC add (-1 if MAC can add any amount)
|
|
// int * pBytesAdded
|
|
// returns the number of bytes added from the I/O source
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
virtual int AddDataFromInputSource(CInputSource * pInputSource, int nMaxBytes = -1, int * pBytesAdded = NULL) = 0;
|
|
|
|
/*********************************************************************************************
|
|
* Finish / Kill
|
|
*********************************************************************************************/
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Finish(...) - ends encoding and finalizes the file
|
|
//
|
|
// Parameters:
|
|
// unsigned char * pTerminatingData
|
|
// a pointer to a buffer containing the information to place at the end of the APE file
|
|
// (comprised of the WAV terminating data (data after the data block in the WAV) followed
|
|
// by any tag information)
|
|
// int nTerminatingBytes
|
|
// number of bytes in the terminating data buffer
|
|
// int nWAVTerminatingBytes
|
|
// the number of bytes of the terminating data buffer that should be appended to a decoded
|
|
// WAV file (it's basically nTerminatingBytes - the bytes that make up the tag)
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
virtual int Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes) = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Kill(...) - stops encoding and deletes the output file
|
|
// --- NOT CURRENTLY IMPLEMENTED ---
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
virtual int Kill() = 0;
|
|
};
|
|
|
|
/*************************************************************************************************
|
|
Functions to create the interfaces
|
|
|
|
Usage:
|
|
Interface creation returns a NULL pointer on failure (and fills error code if it was passed in)
|
|
|
|
Usage example:
|
|
int nErrorCode;
|
|
IAPEDecompress * pAPEDecompress = CreateIAPEDecompress("c:\\1.ape", &nErrorCode);
|
|
if (pAPEDecompress == NULL)
|
|
{
|
|
// failure... nErrorCode will have specific code
|
|
}
|
|
|
|
*************************************************************************************************/
|
|
extern "C"
|
|
{
|
|
IAPEDecompress * __stdcall CreateIAPEDecompress(const char * pFilename, int * pErrorCode = NULL);
|
|
IAPEDecompress * __stdcall CreateIAPEDecompressEx(CIO * pIO, int * pErrorCode = NULL);
|
|
IAPECompress * __stdcall CreateIAPECompress(int * pErrorCode = NULL);
|
|
}
|
|
|
|
/*************************************************************************************************
|
|
Simple functions - see the SDK sample projects for usage examples
|
|
*************************************************************************************************/
|
|
extern "C"
|
|
{
|
|
// process whole files
|
|
DLLEXPORT int __stdcall CompressFile(const char * pInputFile, const char * pOutputFile, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL, int * pPercentageDone = NULL, APE_PROGRESS_CALLBACK ProgressCallback = 0, int * pKillFlag = NULL);
|
|
DLLEXPORT int __stdcall DecompressFile(const char * pInputFilename, const char * pOutputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
|
DLLEXPORT int __stdcall ConvertFile(const char * pInputFilename, const char * pOutputFilename, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
|
DLLEXPORT int __stdcall VerifyFile(const char * pInputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
|
|
|
// helper functions
|
|
DLLEXPORT int __stdcall FillWaveFormatEx(WAVEFORMATEX * pWaveFormatEx, int nSampleRate = 44100, int nBitsPerSample = 16, int nChannels = 2);
|
|
DLLEXPORT int __stdcall FillWaveHeader(WAVE_HEADER * pWAVHeader, int nAudioBytes, WAVEFORMATEX * pWaveFormatEx, int nTerminatingBytes = 0);
|
|
}
|
|
|
|
#endif /* APE_MACLIB_H */
|