Files
lazarus-ccr/components/acs/Src/fileformats/windows/macdll.pas

1201 lines
44 KiB
ObjectPascal

{
delphi interface to macdll.dll 3.97
by thomas la cour 30-04-2003
http://www.top-house.dk/~nr161/delphi/
still missing:
StartEx for TAPECompress
Slightly modified by Andrei Borovsky for better ACS complience.
}
{
$Log: macdll.pas,v $
Revision 1.1 2005/12/19 18:36:49 z0m3ie
*** empty log message ***
Revision 1.1 2005/09/12 22:04:53 z0m3ie
modified structure again, fileformats are now in an sperat folder.
all File In/Out classes are capsulated from TFileIn and TFileOut
Revision 1.1 2005/08/25 20:18:00 z0m3ie
Version 2.4 restructure
TCDPlayer removed (fits not in component structure)
TMP3ToWavConverter removed (fits not in component structure)
Revision 1.2 2005/08/22 20:17:02 z0m3ie
changed Headers to log
changed mail adress
}
unit macdll;
interface
uses classes, sysutils, windows, mmsystem;
const
MACPath = 'MACDll.dll';
var
MACLoaded : Boolean = False;
type
{$IFDEF FPC}
TWaveFormatEx = MMSystem.WaveFormatEx;
{$ELSE}
TWaveFormatEx = MMSystem.TWaveFormatEx;
{$ENDIF}
////////////////////////////////////////////////////////////////////////////////
// MAC Error Codes
////////////////////////////////////////////////////////////////////////////////
const
// file and i/o errors (1000's)
MAC_ERROR_IO_READ = 1000;
MAC_ERROR_IO_WRITE = 1001;
MAC_ERROR_INVALID_INPUT_FILE = 1002;
MAC_ERROR_INVALID_OUTPUT_FILE = 1003;
MAC_ERROR_INPUT_FILE_TOO_LARGE = 1004;
MAC_ERROR_INPUT_FILE_UNSUPPORTED_BIT_DEPTH = 1005;
MAC_ERROR_INPUT_FILE_UNSUPPORTED_SAMPLE_RATE = 1006;
MAC_ERROR_INPUT_FILE_UNSUPPORTED_CHANNEL_COUNT = 1007;
MAC_ERROR_INPUT_FILE_TOO_SMALL = 1008;
MAC_ERROR_INVALID_CHECKSUM = 1009;
MAC_ERROR_DECOMPRESSING_FRAME = 1010;
MAC_ERROR_INITIALIZING_UNMAC = 1011;
MAC_ERROR_INVALID_FUNCTION_PARAMETER = 1012;
MAC_ERROR_UNSUPPORTED_FILE_TYPE = 1013;
MAC_ERROR_UPSUPPORTED_FILE_VERSION = 1014;
// memory errors (2000's)
MAC_ERROR_INSUFFICIENT_MEMORY = 2000;
// dll errors (3000's)
MAC_ERROR_LOADINGAPE_DLL = 3000;
MAC_ERROR_LOADINGAPE_INFO_DLL = 3001;
MAC_ERROR_LOADING_UNMAC_DLL = 3002;
// general and misc errors
MAC_ERROR_USER_STOPPED_PROCESSING = 4000;
MAC_ERROR_SKIPPED = 4001;
// programmer errors
MAC_ERROR_BAD_PARAMETER = 5000;
// IAPECompress errors
MAC_ERROR_APE_COMPRESS_TOO_MUCH_DATA = 6000;
// unknown error
MAC_ERROR_UNDEFINED = -1;
////////////////////////////////////////////////////////////////////////////////
// MAC compression codes
////////////////////////////////////////////////////////////////////////////////
const
COMPRESSION_LEVEL_FAST = 1000;
COMPRESSION_LEVEL_NORMAL = 2000;
COMPRESSION_LEVEL_HIGH = 3000;
COMPRESSION_LEVEL_EXTRA_HIGH = 4000;
MAC_FORMAT_FLAG_8_BIT = 1; // is 8-bit
mac_format_flag_crc = 2; // uses the new crc32 error detection
mac_format_flag_has_peak_level = 4; // unsigned __int32 peak_level after the header
mac_format_flag_24_bit = 8; // is 24-bit
mac_format_flag_has_seek_elements = 16; // has the number of seek elements after the peak level
mac_format_flag_create_wav_header = 32; // create the wave header on decompression (not stored)
CREATE_WAV_HEADER_ON_DECOMPRESSION = -1;
MAX_AUDIO_BYTES_UNKNOWN = -1;
type
macProgressCallback_t = procedure(PercentageDone: LongInt); stdcall;
var
macProgressCallback : macProgressCallback_t;
////////////////////////////////////////////////////////////////////////////////
// WAV header structure
////////////////////////////////////////////////////////////////////////////////
type
TWaveHeader = packed record
// RIFF header
cRIFFHeader: array[0..3] of char; //unsigned int nRIFFBytes;
nRIFFBytes: Longword;
// data type
cDataTypeID: array[0..3] of char; //char cDataTypeID[4];
// wave format
cFormatHeader: array[0..3] of char; //char cFormatHeader[4];
nFormatBytes: Longword; //unsigned int nFormatBytes;
nFormatTag: Word; //unsigned short nFormatTag;
nChannels: Word; //unsigned short nChannels;
nSamplesPerSec: Longword; //unsigned int nSamplesPerSec;
nAvgBytesPerSec: Longword; //unsigned int nAvgBytesPerSec;
nBlockAlign: Word; //unsigned short nBlockAlign;
nBitsPerSample: Word; //unsigned short nBitsPerSample;
// data chunk header
cDataHeader: array[0..3] of char; //char cDataHeader[4];
nDataBytes: Longword; //unsigned int nDataBytes;
end;
PWaveHeader = ^TWaveHeader;
{*****************************************************************************************
APE header structure (what's at the front of an APE file)
*****************************************************************************************}
type
TAPEHeader = packed record
cID: array[0..3] of char; // should equal 'MAC '
nVersion: SmallInt; // version number * 1000 (3.81 = 3810)
nCompressionLevel: SmallInt; // the compression level
nFormatFlags: SmallInt; // any format flags (for future use)
nChannels: SmallInt; // the number of channels (1 or 2)
nSampleRate: LongInt; // the sample rate (typically 44100)
nHeaderBytes: LongInt; // the bytes after the MAC header that compose the WAV header
nTerminatingBytes: LongInt; // the bytes after that raw data (for extended info)
nTotalFrames: LongInt; // the number of frames in the file
nFinalFrameBlocks: LongInt; // the number of samples in the final frame
end;
PAPEHeader = ^TAPEHeader;
{*******************************************************************************
TAPEDecompress 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)
*******************************************************************************}
type
APE_DECOMPRESS_FIELDS = Integer;
const
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]
////////////////////////////////////////////////////////////////////////////////
// misc types
////////////////////////////////////////////////////////////////////////////////
type
ID3_TAG = record
TagHeader: array[1..3] of Char; // should equal 'TAG'
Title: array[1..30] of Char; // title
Artist: array[1..30] of Char; // artist
Album: array[1..30] of Char; // album
Year: array[1..4] of Char; // year
Comment: array[1..30] of Char; // comment
Track: Byte; // track
Genre: Byte; // genre
end;
pID3_TAG = ^ID3_TAG;
type
APE_DECOMPRESS_HANDLE = LongWord;//Pointer;
APE_COMPRESS_HANDLE = LongWord;//Pointer;
////////////////////////////////////////////////////////////////////////////////
// Simple functions - see the SDK sample projects for usage examples
////////////////////////////////////////////////////////////////////////////////
type
macRemoveTag_t = function(pFilename: PChar): LongInt; stdcall;
macCompressFile_t = function (
InputFile: PChar;
OutputFile: PChar;
CompressionLevel: LongInt;
PercentageDone: PInteger;
ProgressCalllback: macProgressCallback_t;
KillFlag: PInteger
): LongInt; stdcall;
macConvertFile_t = function(
InputFile: PChar;
OutputFile: PChar;
CompressionLevel: LongInt;
var PercentageDone: Integer;
ProgressCalllback: macProgressCallback_t;
var KillFlag: Integer
): LongInt; stdcall;
macDecompressFile_t = function(
InputFile: PChar;
OutputFile: PChar;
var PercentageDone: Integer; //Pointer;
ProgressCalllback: macProgressCallback_t;
var KillFlag: Integer
): LongInt; stdcall;
macFillWaveFormatEx_t = function(
var WaveFormatEx: TWaveFormatEx;
SampleRate: Integer = 44100;
BitsPerSample: Integer = 16;
Channels: Integer = 2
): LongInt; stdcall;
macFillWaveHeader_t = function(
var WaveHeader: TWaveHeader;
AudioBytes: Integer;
var WaveFormatEx: TWaveFormatEx;
TerminatingBytes: Integer = 0
): LongInt; stdcall;
macGetID3Tag_t = function(
pFilename: PChar;
pID3Tag: pID3_TAG
): LongInt; stdcall;
macGetInterfaceCompatibility_t = function(
nVersion: Integer;
bDisplayWarningsOnFailure: Boolean;
hwndParent: HWND
): LongInt; stdcall;
macGetVersionNumber_t = function(): LongInt; stdcall;
macShowFileInfoDialog_t = function(
Filename: PChar;
HWndWindow: HWND
): LongInt; stdcall;
macTagFileSimple_t = function(
pFilename: PChar;
pArtist: PChar;
pAlbum: PChar;
pTitle: PChar;
pComment: PChar;
pGenre: PChar;
pYear: PChar;
pTrack: PChar;
bClearFirst: boolean;
bUseOldID3: boolean
): LongInt; stdcall;
macVerifyFile_t = function(
InputFile: PChar;
var PercentageDone: Integer;
ProgressCalllback: macProgressCallback_t;
var KillFlag: Integer
): LongInt; stdcall;
//
// Utility functions
//
function macErrorExplanation(MacErrorCode: LongInt): string;
function macMSToTime(MilliSeconds: LongInt): Double;
var
macRemoveTag : macRemoveTag_t;
macCompressFile : macCompressFile_t;
macConvertFile : macConvertFile_t;
macDecompressFile : macDecompressFile_t;
macFillWaveFormatEx : macFillWaveFormatEx_t;
macFillWaveHeader : macFillWaveHeader_t;
macGetID3Tag : macGetID3Tag_t;
macGetInterfaceCompatibility : macGetInterfaceCompatibility_t;
macGetVersionNumber : macGetVersionNumber_t;
macShowFileInfoDialog : macShowFileInfoDialog_t;
macTagFileSimple : macTagFileSimple_t;
macVerifyFile : macVerifyFile_t;
//
// EAPEException
//
type
EAPEException = class(Exception)
public
constructor Create(MacErrorCode: LongInt); overload;
end;
{*************************************************************************************************
TAPECompress - class for creating APE files
Usage:
To create an APE file, you Start(...), then add data (in a variety of ways), then Finish(...)
*************************************************************************************************}
TAPECompress = class
private
FHandle: APE_COMPRESS_HANDLE;
//FFilename: string;
public
ErrorCode: Integer;
constructor Create;
destructor Destroy; override;
{*********************************************************************************************
* 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;}
function Start(
pOutputFilename: PChar;
pwfeInput: PWaveFormatEx;
nMaxAudioBytes: Integer = MAX_AUDIO_BYTES_UNKNOWN;
nCompressionLevel: Integer = COMPRESSION_LEVEL_NORMAL;
pHeaderData: Pointer = nil;
nHeaderBytes: Integer = CREATE_WAV_HEADER_ON_DECOMPRESSION
): LongInt;
{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;
function AddData(
pData: Pointer;
nBytes: Integer
): LongInt;
//////////////////////////////////////////////////////////////////////////////////////////////
// GetBufferBytesAvailable(...) - returns the number of bytes available in the buffer
// (helpful when locking)
//////////////////////////////////////////////////////////////////////////////////////////////
//virtual int GetBufferBytesAvailable() = 0;
function GetBufferBytesAvailable(
): LongInt; stdcall;
//////////////////////////////////////////////////////////////////////////////////////////////
// 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;
function LockBuffer(
var pBytesAvailable: Integer
): Pointer;
//////////////////////////////////////////////////////////////////////////////////////////////
// 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;
function UnlockBuffer(
nBytesAdded: Integer;
bProcess: Boolean = True
): LongInt;
//////////////////////////////////////////////////////////////////////////////////////////////
// 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;
function Finish(
pTerminatingData: Pointer;
nTerminatingBytes: Integer;
nWAVTerminatingBytes: Integer
): LongInt;
//////////////////////////////////////////////////////////////////////////////////////////////
// Kill(...) - stops encoding and deletes the output file
// --- NOT CURRENTLY IMPLEMENTED ---
//////////////////////////////////////////////////////////////////////////////////////////////
//virtual int Kill() = 0;
function Kill(
): LongInt;
published
property Handle: APE_DECOMPRESS_HANDLE read FHandle;
end;
{*************************************************************************************************
TAPEDecompress - class for working with existing APE files (decoding, seeking, analyzing, etc.)
*************************************************************************************************}
TAPEDecompress = class
private
FHandle: APE_DECOMPRESS_HANDLE;
FFilename: string;
public
ErrorCode: Integer;
constructor Create(Filename: string);
destructor Destroy; override;
//////////////////////////////////////////////////////////////////////////////////////////////
// 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;
function GetData(pBuffer: Pointer; nBlocks: Integer; var pBlocksRetrieved: Integer): LongInt;
//////////////////////////////////////////////////////////////////////////////////////////////
// Seek(...) - seeks
//
// Parameters:
// int nBlockOffset
// the block to seek to (see note at intro about blocks vs. samples)
//////////////////////////////////////////////////////////////////////////////////////////////
//virtual int Seek(int nBlockOffset) = 0;
function Seek(nBlockOffset: Integer): LongInt;
//////////////////////////////////////////////////////////////////////////////////////////////
// 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;
function GetInfo(Field: APE_DECOMPRESS_FIELDS; nParam1: Integer = 0; nParam2: Integer = 0): LongInt;
function AverageBitrate: LongWord;
function CurrentBitrate: LongWord;
function CurrentBlock: LongWord;
function CurrentMS: LongWord;
function LengthMS: LongWord;
function TotalBlocks: LongWord;
function InfoApeTotalBytes: LongInt;
function InfoAverageBitrage: LongInt;
function InfoBitsPerSample: LongInt;
function InfoBlockAlign: LongInt;
function InfoBlocksPerFrame: LongInt;
function InfoBytesPerSample: LongInt;
function InfoChannels: LongInt;
function InfoCompressionLevel: LongInt;
function InfoDecompressedBitrate: LongInt;
function InfoFileVersion: LongInt;
function InfoFinalFrameBlocks: LongInt;
function InfoFormatFlags: LongInt;
function InfoFrameBitrate(FrameIndex: Integer): LongInt;
function InfoFrameBlocks(FrameIndex: Integer): LongInt;
function InfoFrameBytes(FrameIndex: Integer): LongInt;
function InfoIOSource: LongInt;
function InfoLengthMS: LongInt;
function InfoPeakLevel: LongInt;
function InfoSampleRate: LongInt;
function InfoSeekBit(FrameIndex: Integer): LongInt;
function InfoSeekByte(FrameIndex: Integer): LongInt;
function InfoTag: Pointer;
function InfoTerminatingData(Buffer: Pointer;
MaxBytes: Integer): LongInt;
function InfoTotalBlocks: LongInt;
function InfoTotalFrames: LongInt;
function InfoWavDataBytes: LongInt;
function InfoWaveFormatEx(var WaveFormatEx: TWaveFormatEx): LongInt;
function InfoWavHeaderBytes: LongInt;
function InfoWavHeaderData(Buffer: Pointer;
MaxBytes: Integer): LongInt;
function InfoWavTerminatingBytes: LongInt;
function InfoWavTotalBytes: LongInt;
published
property Handle: APE_DECOMPRESS_HANDLE read FHandle;
property Filename: string read FFilename;
end;
implementation
function macErrorExplanation(MACErrorCode: LongInt): string;
begin
case MACErrorCode of
0: Result := 'OK';
MAC_ERROR_IO_READ: Result := 'I/O read error';
MAC_ERROR_IO_WRITE: Result := 'I/O write error';
MAC_ERROR_INVALID_INPUT_FILE: Result := 'invalid input file';
MAC_ERROR_INVALID_OUTPUT_FILE: Result := 'invalid output file';
MAC_ERROR_INPUT_FILE_TOO_LARGE: Result := 'input file file too large';
MAC_ERROR_INPUT_FILE_UNSUPPORTED_BIT_DEPTH: Result := 'input file unsupported bit depth';
MAC_ERROR_INPUT_FILE_UNSUPPORTED_SAMPLE_RATE: Result := 'input file unsupported sample rate';
MAC_ERROR_INPUT_FILE_UNSUPPORTED_CHANNEL_COUNT: Result := 'input file unsupported channel count';
MAC_ERROR_INPUT_FILE_TOO_SMALL: Result := 'input file too small';
MAC_ERROR_INVALID_CHECKSUM: Result := 'invalid checksum';
MAC_ERROR_DECOMPRESSING_FRAME: Result := 'decompressing frame';
MAC_ERROR_INITIALIZING_UNMAC: Result := 'initializing unmac';
MAC_ERROR_INVALID_FUNCTION_PARAMETER: Result := 'invalid function parameter';
MAC_ERROR_UNSUPPORTED_FILE_TYPE: Result := 'unsupported file type';
MAC_ERROR_INSUFFICIENT_MEMORY: Result := 'insufficient memory';
MAC_ERROR_LOADINGAPE_DLL: Result := 'loading MAC.dll';
MAC_ERROR_LOADINGAPE_INFO_DLL: Result := 'loading MACinfo.dll';
MAC_ERROR_LOADING_UNMAC_DLL: Result := 'loading UnMAC.dll';
MAC_ERROR_USER_STOPPED_PROCESSING: Result := 'user stopped processing';
MAC_ERROR_SKIPPED: Result := 'skipped...';
MAC_ERROR_BAD_PARAMETER: Result := 'bad parameter';
MAC_ERROR_APE_COMPRESS_TOO_MUCH_DATA: Result := 'APE compress too much data';
else
Result := 'undefined (' + inttostr(MACErrorCode) + ')'; //MAC_ERROR_UNDEFINED
end;
end;
function macMSToTime(MilliSeconds: LongInt): Double;
const
MS_PER_DAY = 24 * 60 * 60 * 1000;
begin
Result := MilliSeconds / MS_PER_DAY;
end;
{ EAPEException }
constructor EAPEException.Create(MacErrorCode: Integer);
begin
inherited Create('MACDll error: '+macErrorExplanation(MacErrorCode));
end;
////////////////////////////////////////////////////////////////////////////////
// TAPECompress wrapper(s)
////////////////////////////////////////////////////////////////////////////////
{int __stdcall c_APECompress_AddData(
APE_COMPRESS_HANDLE hAPECompress, unsigned char * pData, int nBytes);}
type
c_APECompress_AddData_t = function(
hAPECompress: APE_COMPRESS_HANDLE;
pData: Pointer;
nBytes: Integer
): LongInt; stdcall;
// c_APECompress_Create; Index 14; Information not available
{APE_COMPRESS_HANDLE __stdcall c_APECompress_Create(
int * pErrorCode = NULL);}
c_APECompress_Create_t = function(
var pErrorCode: Integer
): APE_COMPRESS_HANDLE; stdcall;
// c_APECompress_Destroy; Index 15; Information not available
{void __stdcall c_APECompress_Destroy(
APE_COMPRESS_HANDLE hAPECompress);}
c_APECompress_Destroy_t = procedure(
hAPECompress: APE_COMPRESS_HANDLE
); stdcall;
// c_APECompress_Finish; Index 16; Information not available
{int __stdcall c_APECompress_Finish(
APE_COMPRESS_HANDLE hAPECompress,
unsigned char * pTerminatingData,
int nTerminatingBytes,
int nWAVTerminatingBytes);}
c_APECompress_Finish_t = function(
hAPECompress: APE_COMPRESS_HANDLE;
pTerminatingData: Pointer;
nTerminatingBytes: Integer;
nWAVTerminatingBytes: Integer
): LongInt; stdcall;
// c_APECompress_GetBufferBytesAvailable; Index 17; Information not available
{int __stdcall c_APECompress_GetBufferBytesAvailable(
APE_COMPRESS_HANDLE hAPECompress);}
c_APECompress_GetBufferBytesAvailable_t = function(
hAPECompress: APE_COMPRESS_HANDLE
): LongInt; stdcall;
// c_APECompress_Kill; Index 18; Information not available
{int __stdcall c_APECompress_Kill(APE_COMPRESS_HANDLE hAPECompress);}
c_APECompress_Kill_t = function(
hAPECompress: APE_COMPRESS_HANDLE
): LongInt; stdcall;
// c_APECompress_LockBuffer; Index 19; Information not available
{unsigned char * __stdcall c_APECompress_LockBuffer(
APE_COMPRESS_HANDLE hAPECompress, int * pBytesAvailable);}
c_APECompress_LockBuffer_t = function(
hAPECompress: APE_COMPRESS_HANDLE;
var BytesAvailable: Integer
): Pointer; stdcall;
// c_APECompress_Start; Index 20; Information not available
{int __stdcall c_APECompress_Start(
APE_COMPRESS_HANDLE hAPECompress,
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);}
c_APECompress_Start_t = function(
hAPECompress: APE_COMPRESS_HANDLE;
pOutputFilename: PChar;
pwfeInput: PWaveFormatEx;
nMaxAudioBytes: Integer = MAX_AUDIO_BYTES_UNKNOWN;
nCompressionLevel: Integer = COMPRESSION_LEVEL_NORMAL;
pHeaderData: Pointer = nil;
nHeaderBytes: Integer = CREATE_WAV_HEADER_ON_DECOMPRESSION
): LongInt; stdcall;
// c_APECompress_UnlockBuffer; Index 21; Information not available
{int __stdcall c_APECompress_UnlockBuffer(
APE_COMPRESS_HANDLE hAPECompress,
int nBytesAdded,
BOOL bProcess = TRUE);}
c_APECompress_UnlockBuffer_t = function(
hAPECompress: APE_COMPRESS_HANDLE;
nBytesAdded: Integer;
bProcess: Boolean = True
): LongInt; stdcall;
var
c_APECompress_AddData : c_APECompress_AddData_t;
c_APECompress_Create : c_APECompress_Create_t;
c_APECompress_Destroy : c_APECompress_Destroy_t;
c_APECompress_Finish : c_APECompress_Finish_t;
c_APECompress_GetBufferBytesAvailable : c_APECompress_GetBufferBytesAvailable_t;
c_APECompress_Kill : c_APECompress_Kill_t;
c_APECompress_LockBuffer : c_APECompress_LockBuffer_t;
c_APECompress_Start : c_APECompress_Start_t;
c_APECompress_UnlockBuffer : c_APECompress_UnlockBuffer_t;
////////////////////////////////////////////////////////////////////////////////
// TAPECompress
////////////////////////////////////////////////////////////////////////////////
function TAPECompress.AddData(pData: Pointer; nBytes: Integer): LongInt;
begin
Result := c_APECompress_AddData(FHandle, pData, nBytes);
end;
function TAPECompress.Kill: LongInt;
begin
Result := c_APECompress_Kill(FHandle);
end;
function TAPECompress.Start(pOutputFilename: PChar;
pwfeInput: PWaveFormatEx; nMaxAudioBytes, nCompressionLevel: Integer;
pHeaderData: Pointer; nHeaderBytes: Integer): LongInt;
begin
Result := c_APECompress_Start(FHandle, pOutputFilename,
pwfeInput, nMaxAudioBytes, nCompressionLevel,
pHeaderData, nHeaderBytes);
end;
constructor TAPECompress.Create;
begin
FHandle := c_APECompress_Create(ErrorCode);
if ErrorCode<>0 then
raise EAPEException.Create(ErrorCode);
end;
destructor TAPECompress.Destroy;
begin
if FHandle<>0 then
c_APECompress_Destroy(FHandle);
inherited;
end;
function TAPECompress.Finish(pTerminatingData: Pointer; nTerminatingBytes,
nWAVTerminatingBytes: Integer): LongInt;
begin
Result := c_APECompress_Finish(FHandle, pTerminatingData,
nTerminatingBytes, nWAVTerminatingBytes);
end;
function TAPECompress.GetBufferBytesAvailable: LongInt;
begin
Result := c_APECompress_GetBufferBytesAvailable(FHandle);
end;
function TAPECompress.LockBuffer(var pBytesAvailable: Integer): Pointer;
begin
Result := c_APECompress_LockBuffer(FHandle, pBytesAvailable);
end;
function TAPECompress.UnlockBuffer(nBytesAdded: Integer;
bProcess: Boolean): LongInt;
begin
Result := c_APECompress_UnlockBuffer(FHandle, nBytesAdded);
end;
////////////////////////////////////////////////////////////////////////////////
// TAPEDecompress wrapper(s)
////////////////////////////////////////////////////////////////////////////////
// c_APEDecompress_Create; Index 22; Information not available
type
c_APEDecompress_Create_t = function(
pFilename: PChar;
var pErrorCode: Integer
): APE_DECOMPRESS_HANDLE; stdcall;
// c_APEDecompress_Destroy; Index 23; Information not available
c_APEDecompress_Destroy_t = procedure(
hAPEDecompress: APE_DECOMPRESS_HANDLE
); stdcall;
// c_APEDecompress_GetData; Index 24; Information not available
{ __declspec( dllexport ) int __stdcall c_APEDecompress_GetData(
APE_DECOMPRESS_HANDLE hAPEDecompress, char * pBuffer, int nBlocks, int * pBlocksRetrieved);}
c_APEDecompress_GetData_t = function(
hAPEDecompress: APE_DECOMPRESS_HANDLE;
pBuffer: Pointer;
nBlocks: Integer;
var pBlocksRetrieved: Integer
): LongInt; stdcall;
// c_APEDecompress_GetInfo; Index 25; Information not available
c_APEDecompress_GetInfo_t = function(
hAPEDecompress: APE_DECOMPRESS_HANDLE;
Field: APE_DECOMPRESS_FIELDS;
nParam1: Integer = 0;
nParam2: Integer = 0
): LongInt; stdcall;
// c_APEDecompress_Seek; Index 26; Information not available
{__declspec(dllexport)int __stdcall c_APEDecompress_Seek(
APE_DECOMPRESS_HANDLE hAPEDecompress, int nBlockOffset);}
c_APEDecompress_Seek_t = function(
hAPEDecompress: APE_DECOMPRESS_HANDLE;
nBlockOffset: Integer
): LongInt; stdcall;
var
c_APEDecompress_Create : c_APEDecompress_Create_t;
c_APEDecompress_Destroy : c_APEDecompress_Destroy_t;
c_APEDecompress_GetData : c_APEDecompress_GetData_t;
c_APEDecompress_GetInfo : c_APEDecompress_GetInfo_t;
c_APEDecompress_Seek : c_APEDecompress_Seek_t;
////////////////////////////////////////////////////////////////////////////////
// TAPEDecompress
////////////////////////////////////////////////////////////////////////////////
constructor TAPEDecompress.Create(Filename: string);
begin
FFilename := Filename;
FHandle := c_APEDecompress_Create(PChar(FFilename), ErrorCode);
if ErrorCode<>0 then
raise EAPEException.Create(ErrorCode);
end;
destructor TAPEDecompress.Destroy;
begin
if FHandle<>0 then
c_APEDecompress_Destroy(FHandle);
inherited;
end;
function TAPEDecompress.GetData(pBuffer: Pointer; nBlocks: LongInt;
var pBlocksRetrieved: Integer): LongInt;
begin
Result := c_APEDecompress_GetData(FHandle, pBuffer, nBlocks, pBlocksRetrieved);
end;
function TAPEDecompress.GetInfo(Field: APE_DECOMPRESS_FIELDS; nParam1,
nParam2: Integer): LongInt;
begin
Result := c_APEDecompress_GetInfo(FHandle, Field, nParam1, nParam2);
end;
function TAPEDecompress.Seek(nBlockOffset: Integer): LongInt;
begin
Result := c_APEDecompress_Seek(FHandle, nBlockOffset);
end;
// querying the information engine
function TAPEDecompress.InfoFileVersion: LongInt;
// version of the APE file * 1000 (3.93 = 3930) [ignored, ignored]
begin // APE_INFO_FILE_VERSION = 1000;
Result := GetInfo(APE_INFO_FILE_VERSION);
end;
function TAPEDecompress.InfoCompressionLevel: LongInt;
// compression level of the APE file [ignored, ignored]
begin // APE_INFO_COMPRESSION_LEVEL = 1001;
Result := GetInfo(APE_INFO_COMPRESSION_LEVEL);
end;
function TAPEDecompress.InfoFormatFlags: LongInt;
// format flags of the APE file [ignored, ignored]
begin // APE_INFO_FORMAT_FLAGS = 1002;
Result := GetInfo(APE_INFO_FORMAT_FLAGS);
end;
function TAPEDecompress.InfoSampleRate: LongInt;
// sample rate (Hz) [ignored, ignored]
begin // APE_INFO_SAMPLE_RATE = 1003;
Result := GetInfo(APE_INFO_SAMPLE_RATE);
end;
function TAPEDecompress.InfoBitsPerSample: LongInt;
// bits per sample [ignored, ignored]
begin // APE_INFO_BITS_PER_SAMPLE = 1004;
Result := GetInfo(APE_INFO_BITS_PER_SAMPLE);
end;
function TAPEDecompress.InfoBytesPerSample: LongInt;
// number of bytes per sample [ignored, ignored]
begin // APE_INFO_BYTES_PER_SAMPLE = 1005;
Result := GetInfo(APE_INFO_BYTES_PER_SAMPLE);
end;
function TAPEDecompress.InfoChannels: LongInt;
// channels [ignored, ignored]
begin // APE_INFO_CHANNELS = 1006;
Result := GetInfo(APE_INFO_CHANNELS);
end;
function TAPEDecompress.InfoBlockAlign: LongInt;
// block alignment [ignored, ignored]
begin // APE_INFO_BLOCK_ALIGN = 1007;
Result := GetInfo(APE_INFO_BLOCK_ALIGN);
end;
function TAPEDecompress.InfoBlocksPerFrame: LongInt;
// number of blocks in a frame (frames are used internally) [ignored, ignored]
begin // APE_INFO_BLOCKS_PER_FRAME = 1008;
Result := GetInfo(APE_INFO_BLOCKS_PER_FRAME);
end;
function TAPEDecompress.InfoFinalFrameBlocks: LongInt;
// blocks in the final frame (frames are used internally) [ignored, ignored]
begin // APE_INFO_FINAL_FRAME_BLOCKS = 1009;
Result := GetInfo(APE_INFO_FINAL_FRAME_BLOCKS);
end;
function TAPEDecompress.InfoTotalFrames: LongInt;
begin // APE_INFO_TOTAL_FRAMES = 1010;
// total number frames (frames are used internally) [ignored, ignored]
Result := GetInfo(APE_INFO_TOTAL_FRAMES);
end;
function TAPEDecompress.InfoWavHeaderBytes: LongInt;
// header bytes of the decompressed WAV [ignored, ignored]
begin // APE_INFO_WAV_HEADER_BYTES = 1011;
Result := GetInfo(APE_INFO_WAV_HEADER_BYTES);
end;
function TAPEDecompress.InfoWavTerminatingBytes: LongInt;
// terminating bytes of the decompressed WAV [ignored, ignored]
begin // APE_INFO_WAV_TERMINATING_BYTES = 1012;
Result := GetInfo(APE_INFO_WAV_TERMINATING_BYTES);
end;
function TAPEDecompress.InfoWavDataBytes: LongInt;
// data bytes of the decompressed WAV [ignored, ignored]
begin // APE_INFO_WAV_DATA_BYTES = 1013;
Result := GetInfo(APE_INFO_WAV_DATA_BYTES);
end;
function TAPEDecompress.InfoWavTotalBytes: LongInt;
// total bytes of the decompressed WAV [ignored, ignored]
begin // APE_INFO_WAV_TOTAL_BYTES = 1014;
Result := GetInfo(APE_INFO_WAV_TOTAL_BYTES);
end;
function TAPEDecompress.InfoApeTotalBytes: LongInt;
// total bytes of the APE file [ignored, ignored]
begin // APE_INFO_APE_TOTAL_BYTES = 1015;
Result := GetInfo(APE_INFO_APE_TOTAL_BYTES);
end;
function TAPEDecompress.InfoTotalBlocks: LongInt;
// total blocks of audio data [ignored, ignored]
begin // APE_INFO_TOTAL_BLOCKS = 1016;
Result := GetInfo(APE_INFO_TOTAL_BLOCKS);
end;
function TAPEDecompress.InfoLengthMS: LongInt;
// length in ms (1 sec = 1000 ms) [ignored, ignored]
begin // APE_INFO_LENGTH_MS = 1017;
Result := GetInfo(APE_INFO_LENGTH_MS);
end;
function TAPEDecompress.InfoAverageBitrage: LongInt;
// average bitrate of the APE [ignored, ignored]
begin // APE_INFO_AVERAGE_BITRATE = 1018;
Result := GetInfo(APE_INFO_AVERAGE_BITRATE);
end;
function TAPEDecompress.InfoFrameBitrate(FrameIndex: Integer): LongInt;
// bitrate of specified APE frame [frame index, ignored]
begin // APE_INFO_FRAME_BITRATE = 1019;
Result := GetInfo(APE_INFO_FRAME_BITRATE, FrameIndex);
end;
function TAPEDecompress.InfoDecompressedBitrate: LongInt;
// bitrate of the decompressed WAV [ignored, ignored]
begin // APE_INFO_DECOMPRESSED_BITRATE = 1020;
Result := GetInfo(APE_INFO_DECOMPRESSED_BITRATE);
end;
function TAPEDecompress.InfoPeakLevel: LongInt;
// peak audio level (-1 is unknown) [ignored, ignored]
begin // APE_INFO_PEAK_LEVEL = 1021;
Result := GetInfo(APE_INFO_PEAK_LEVEL);
end;
function TAPEDecompress.InfoSeekBit(FrameIndex: Integer): LongInt;
// bit offset [frame index, ignored]
begin // APE_INFO_SEEK_BIT = 1022;
Result := GetInfo(APE_INFO_SEEK_BIT, FrameIndex);
end;
function TAPEDecompress.InfoSeekByte(FrameIndex: Integer): LongInt;
// byte offset [frame index, ignored]
begin // APE_INFO_SEEK_BYTE = 1023;
Result := GetInfo(APE_INFO_SEEK_BYTE, FrameIndex);
end;
function TAPEDecompress.InfoWavHeaderData(Buffer: Pointer; MaxBytes: Integer): LongInt;
// error code [buffer *, max bytes]
begin // APE_INFO_WAV_HEADER_DATA = 1024;
Result := GetInfo(APE_INFO_WAV_HEADER_DATA, Integer(Buffer), MaxBytes);
end;
function TAPEDecompress.InfoTerminatingData(Buffer: Pointer; MaxBytes: Integer): LongInt;
// error code [buffer *, max bytes]
begin // APE_INFO_WAV_TERMINATING_DATA = 1025;
Result := GetInfo(APE_INFO_WAV_TERMINATING_DATA, Integer(Buffer), MaxBytes);
end;
function TAPEDecompress.InfoWaveFormatEx(var WaveFormatEx: TWaveFormatEx): LongInt;
// error code [waveformatex *, ignored]
begin // APE_INFO_WAVEFORMATEX = 1026;
Result := GetInfo(APE_INFO_WAVEFORMATEX, Integer(@WaveFormatEx));
end;
function TAPEDecompress.InfoIOSource: LongInt;
// I/O source (CIO *) [ignored, ignored]
begin // APE_INFO_IO_SOURCE = 1027;
Result := GetInfo(APE_INFO_IO_SOURCE);
end;
function TAPEDecompress.InfoFrameBytes(FrameIndex: Integer): LongInt;
// bytes (compressed) of the frame [frame index, ignored]
begin // APE_INFO_FRAME_BYTES = 1028;
Result := GetInfo(APE_INFO_SEEK_BYTE, FrameIndex);
end;
function TAPEDecompress.InfoFrameBlocks(FrameIndex: Integer): LongInt;
// blocks in a given frame [frame index, ignored]
begin // APE_INFO_FRAME_BLOCKS = 1029;
Result := GetInfo(APE_INFO_FRAME_BLOCKS, FrameIndex);
end;
function TAPEDecompress.InfoTag: Pointer;
// point to tag (CAPETag *) [ignored, ignored]
begin // APE_INFO_TAG = 1030;
Result := Pointer(GetInfo(APE_INFO_TAG));
end;
// querying the decompressor
function TAPEDecompress.CurrentBlock: LongWord;
// current block location [ignored, ignored]
begin
Result := GetInfo(APE_DECOMPRESS_CURRENT_BLOCK);
end;
function TAPEDecompress.CurrentMS: LongWord;
// current millisecond location [ignored, ignored]
begin
Result := GetInfo(APE_DECOMPRESS_CURRENT_MS);
end;
function TAPEDecompress.TotalBlocks: LongWord;
// total blocks in the decompressors range [ignored, ignored]
begin
Result := GetInfo(APE_DECOMPRESS_TOTAL_BLOCKS);
end;
function TAPEDecompress.LengthMS: LongWord;
// total blocks in the decompressors range [ignored, ignored]
begin
Result := GetInfo(APE_DECOMPRESS_LENGTH_MS);
end;
function TAPEDecompress.CurrentBitrate: LongWord;
// current bitrate [ignored, ignored]
begin
Result := GetInfo(APE_DECOMPRESS_CURRENT_BITRATE);
end;
function TAPEDecompress.AverageBitrate: LongWord;
// average bitrate (works with ranges) [ignored, ignored]
begin
Result := GetInfo(APE_DECOMPRESS_AVERAGE_BITRATE);
end;
var
Libhandle : HMODULE;
initialization
Libhandle := LoadLibraryEx(MACPath, 0, 0);
if Libhandle <> 0 then
begin
MACLoaded := True;
macProgressCallback := GetProcAddress(Libhandle, 'ProgressCallback');
macRemoveTag := GetProcAddress(Libhandle, 'RemoveTag');
macCompressFile := GetProcAddress(Libhandle, 'CompressFile');
macConvertFile := GetProcAddress(Libhandle, 'ConvertFile');
macDecompressFile := GetProcAddress(Libhandle, 'DecompressFile');
macFillWaveFormatEx := GetProcAddress(Libhandle, 'FillWaveFormatEx');
macFillWaveHeader := GetProcAddress(Libhandle, 'FillWaveHeader');
macGetID3Tag := GetProcAddress(Libhandle, 'GetID3Tag');
macGetInterfaceCompatibility := GetProcAddress(Libhandle, 'GetInterfaceCompatibility');
macGetVersionNumber := GetProcAddress(Libhandle, 'GetVersionNumber');
macShowFileInfoDialog := GetProcAddress(Libhandle, 'ShowFileInfoDialog');
macTagFileSimple := GetProcAddress(Libhandle, 'TagFileSimple');
macVerifyFile := GetProcAddress(Libhandle, 'VerifyFile');
c_APECompress_AddData := GetProcAddress(Libhandle, 'c_APECompress_AddData');
c_APECompress_Create := GetProcAddress(Libhandle, 'c_APECompress_Create');
c_APECompress_Destroy := GetProcAddress(Libhandle, 'c_APECompress_Destroy');
c_APECompress_Finish := GetProcAddress(Libhandle, 'c_APECompress_Finish');
c_APECompress_GetBufferBytesAvailable := GetProcAddress(Libhandle, 'c_APECompress_GetBufferBytesAvailable');
c_APECompress_Kill := GetProcAddress(Libhandle, 'c_APECompress_Kill');
c_APECompress_LockBuffer := GetProcAddress(Libhandle, 'c_APECompress_LockBuffer');
c_APECompress_Start := GetProcAddress(Libhandle, 'c_APECompress_Start');
c_APECompress_UnlockBuffer := GetProcAddress(Libhandle, 'c_APECompress_UnlockBuffer');
c_APEDecompress_Create := GetProcAddress(Libhandle, 'c_APEDecompress_Create');
c_APEDecompress_Destroy := GetProcAddress(Libhandle, 'c_APEDecompress_Destroy');
c_APEDecompress_GetData := GetProcAddress(Libhandle, 'c_APEDecompress_GetData');
c_APEDecompress_GetInfo := GetProcAddress(Libhandle, 'c_APEDecompress_GetInfo');
c_APEDecompress_Seek := GetProcAddress(Libhandle, 'c_APEDecompress_Seek');
end;
finalization
if Libhandle <> 0 then FreeLibrary(Libhandle);
end.