📄 audioacm.pas
字号:
{-----------------------------------------------------------------------------
Unit Name: AudioACM
Author: Dancemammal
Purpose: Wave Utils and conversion functions
History: First release
-----------------------------------------------------------------------------}
unit AudioACM;
interface
uses
Windows, Messages, Classes, SysUtils, mmSystem;
const
// addons for extra codecs
WAVE_FORMAT_MSG723 = 66;
WAVE_FORMAT_MPEGLAYER3 = 85;
MPEGLAYER3_WFX_EXTRA_BYTES = 12;
MPEGLAYER3_ID_UNKNOWN = 0;
MPEGLAYER3_ID_MPEG = 1;
MPEGLAYER3_ID_CONSTANTFRAMESIZE = 2;
MPEGLAYER3_FLAG_PADDING_ISO = $00000000;
MPEGLAYER3_FLAG_PADDING_ON = $00000001;
MPEGLAYER3_FLAG_PADDING_OFF = $00000002;
type
// Milliseconds to string format specifiers
TMS2StrFormat = (
msHMSh, // Hour:Minute:Second.Hunderdth
msHMS, // Hour:Minute:Second
msMSh, // Minute:Second.Hunderdth
msMS, // Minute:Second
msSh, // Second.Hunderdth
msS, // Second
msAh, // Best format with hunderdth of second
msA); // Best format without hunderdth of second
// Standard PCM Audio Format
TPCMChannel = (cMono, cStereo);
TPCMSamplesPerSec = (ss8000Hz, ss11025Hz, ss22050Hz, ss44100Hz, ss48000Hz);
TPCMBitsPerSample = (bs8Bit, bs16Bit);
TPCMFormat = (nonePCM, Mono8Bit8000Hz, Stereo8bit8000Hz, Mono16bit8000Hz,
Stereo16bit8000Hz, Mono8bit11025Hz, Stereo8bit11025Hz, Mono16bit11025Hz,
Stereo16bit11025Hz, Mono8bit22050Hz, Stereo8bit22050Hz, Mono16bit22050Hz,
Stereo16bit22050Hz, Mono8bit44100Hz, Stereo8bit44100Hz, Mono16bit44100Hz,
Stereo16bit44100Hz, Mono8bit48000Hz, Stereo8bit48000Hz, Mono16bit48000Hz,
Stereo16bit48000Hz);
// TMP3Bitrates = (96kBits,112kBits,128kBits,160kBits,192kBits,224kBits,256kBits,320kBits)
// Wave Device Supported PCM Formats
TWaveDeviceFormats = set of TPCMFormat;
// Wave Out Device Supported Features
TWaveOutDeviceSupport = (dsVolume, dsStereoVolume, dsPitch, dsPlaybackRate, dsPosition, dsAsynchronize, dsDirectSound);
TWaveOutDeviceSupports = set of TWaveOutDeviceSupport;
// Wave Out Options
TWaveOutOption = (woSetVolume, woSetPitch, woSetPlaybackRate);
TWaveOutOptions = set of TWaveOutOption;
// Wave Audio Exceptions
EWaveAudioError = class(Exception);
EWaveAudioSysError = class(EWaveAudioError);
EWaveAudioInvalidOperation = class(EWaveAudioError);
function GetWaveAudioInfo(mmIO: HMMIO; out pWaveFormat: PWaveFormatEx;
out DataSize, DataOffset: DWORD): Boolean;
function CreateWaveAudio(mmIO: HMMIO; const pWaveFormat: PWaveFormatEx;
out ckRIFF, ckData: TMMCKInfo): Boolean;
procedure CloseWaveAudio(mmIO: HMMIO; var ckRIFF, ckData: TMMCKInfo);
function GetStreamWaveAudioInfo(Stream: TStream; out pWaveFormat: PWaveFormatEx;
out DataSize, DataOffset: DWORD): Boolean;
function CreateStreamWaveAudio(Stream: TStream; const pWaveFormat: PWaveFormatEx;
out ckRIFF, ckData: TMMCKInfo): HMMIO;
function OpenStreamWaveAudio(Stream: TStream): HMMIO;
function CalcWaveBufferSize(const pWaveFormat: PWaveFormatEx; Duration: DWORD): DWORD;
function GetWaveAudioFormat(const pWaveFormat: PWaveFormatEx): String;
function GetWaveAudioLength(const pWaveFormat: PWaveFormatEx; DataSize: DWORD): DWORD;
function GetWaveAudioBitRate(const pWaveFormat: PWaveFormatEx): DWORD;
function GetWaveAudioPeakLevel(const Data: Pointer; DataSize: DWORD;
BitsPerSample: WORD): Integer;
procedure InvertWaveAudio(const Data: Pointer; DataSize: DWORD;
BitsPerSample: WORD);
procedure SilenceWaveAudio(const Data: Pointer; DataSize: DWORD;
BitsPerSample: WORD);
procedure ChangeWaveAudioVolume(const Data: Pointer; DataSize: DWORD;
BitsPerSample: WORD; Percent: Integer);
function ConvertWaveFormat(const srcFormat: PWaveFormatEx; srcData: Pointer; srcDataSize: DWORD;
const dstFormat: PWaveFormatEx; out dstData: Pointer; out dstDataSize: DWORD): Boolean;
procedure SetPCMAudioFormat(const pWaveFormat: PWaveFormatEx; Channels: TPCMChannel;
SamplesPerSec: TPCMSamplesPerSec; BitsPerSample: TPCMBitsPerSample);
procedure SetPCMAudioFormatS(const pWaveFormat: PWaveFormatEx; PCMFormat: TPCMFormat);
function GetPCMAudioFormat(const pWaveFormat: PWaveFormatEx): TPCMFormat;
procedure SetMP3AudioFormatS(const pWaveFormat: PWaveFormatEx; PCMFormat: TPCMFormat);
function GetMP3AudioFormat(const pWaveFormat: PWaveFormatEx): TPCMFormat;
function MS2Str(Milliseconds: DWORD; Fmt: TMS2StrFormat): String;
function WaitForSyncObject(SyncObject: THandle; Timeout: DWORD): DWORD;
function mmioStreamProc(lpmmIOInfo: PMMIOInfo; uMsg, lParam1, lParam2: DWORD): LRESULT; stdcall;
implementation
const
// acmStreamConvert flags
ACM_STREAMCONVERTF_BLOCKALIGN = $00000004;
ACM_STREAMCONVERTF_START = $00000010;
ACM_STREAMCONVERTF_END = $00000020;
// acmStreamOpen flags
ACM_STREAMOPENF_QUERY = $00000001;
ACM_STREAMOPENF_ASYNC = $00000002;
ACM_STREAMOPENF_NONREALTIME = $00000004;
// acmStreamSize flags
ACM_STREAMSIZEF_SOURCE = $00000000;
ACM_STREAMSIZEF_DESTINATION = $00000001;
type
// ACM Driver Handle
HACMDRIVER = DWORD;
// ACM Stream Handle
HACMSTREAM = DWORD;
// ACM Stream Header
PACMSTREAMHEADER = ^TACMSTREAMHEADER;
TACMSTREAMHEADER = packed record
cbStruct: DWORD;
fdwStatus: DWORD;
dwUser: DWORD;
pbSrc: PBYTE;
cbSrcLength: DWORD;
cbSrcLengthUsed: DWORD;
dwSrcUser: DWORD;
pbDst: PBYTE;
cbDstLength: DWORD;
cbDstLengthUsed: DWORD;
dwDstUser: DWORD;
dwReservedDriver: array[0..9] of DWORD;
end;
// ACM Wave Filter
PWAVEFILTER = ^TWAVEFILTER;
TWAVEFILTER = packed record
cbStruct: DWORD;
dwFilterTag: DWORD;
fdwFilter: DWORD;
dwReserved: array[0..4] of DWORD;
end;
function acmStreamOpen(var phas: HACMSTREAM; had: HACMDRIVER;
pwfxSrc: PWAVEFORMATEX; pwfxDst: PWAVEFORMATEX; pwfltr: PWAVEFILTER;
dwCallback: DWORD; dwInstance: DWORD; fdwOpen: DWORD): MMRESULT; stdcall;
external 'msacm32.dll';
function acmStreamClose(has: HACMSTREAM; fdwClose: DWORD): MMRESULT; stdcall;
external 'msacm32.dll';
function acmStreamPrepareHeader(has: HACMSTREAM; var pash: TACMSTREAMHEADER;
fdwPrepare: DWORD): MMRESULT; stdcall;
external 'msacm32.dll';
function acmStreamUnprepareHeader(has: HACMSTREAM; var pash: TACMSTREAMHEADER;
fdwUnprepare: DWORD): MMRESULT; stdcall;
external 'msacm32.dll';
function acmStreamConvert(has: HACMSTREAM; var pash: TACMSTREAMHEADER;
fdwConvert: DWORD): MMRESULT; stdcall;
external 'msacm32.dll';
function acmStreamSize(has: HACMSTREAM; cbInput: DWORD;
var pdwOutputBytes: DWORD; fdwSize: DWORD): MMRESULT; stdcall;
external 'msacm32.dll';
{ Global Procedures }
// To open a stream using mmIO API functions, use the following code sample:
//
// FillChar(mmioInfo, SizeOf(mmioInfo), 0);
// mmioInfo.pIOProc := @mmioStreamProc;
// mmioInfo.adwInfo[0] := DWORD(your_stream_instance);
// mmIO := mmioOpen(nil, @mmioInfo, dwOpenFlags);
//
// The flags specified by the dwOpenFlags parameter of mmioOpen function can
// be only one of MMIO_READ, MMIO_WRITE, and MMIO_READWRITE flags. If you use
// another flags, simply they will be ignored by this user defined function.
function mmIOStreamProc(lpmmIOInfo: PMMIOInfo; uMsg, lParam1, lParam2: DWORD): LRESULT; stdcall;
var
Stream: TStream;
begin
if Assigned(lpmmIOInfo) and (lpmmIOInfo^.adwInfo[0] <> 0) then
begin
Stream := TStream(lpmmIOInfo^.adwInfo[0]);
case uMsg of
MMIOM_OPEN:
begin
if TObject(lpmmIOInfo^.adwInfo[0]) is TStream then
begin
Stream.Seek(0, SEEK_SET);
lpmmIOInfo^.lDiskOffset := 0;
Result := MMSYSERR_NOERROR;
end
else
Result := -1;
end;
MMIOM_CLOSE:
Result := MMSYSERR_NOERROR;
MMIOM_SEEK:
try
if lParam2 = SEEK_CUR then
Stream.Seek(lpmmIOInfo^.lDiskOffset, SEEK_SET);
Result := Stream.Seek(lParam1, lParam2);
lpmmIOInfo^.lDiskOffset := Result;
except
Result := -1;
end;
MMIOM_READ:
try
Stream.Seek(lpmmIOInfo^.lDiskOffset, SEEK_SET);
Result := Stream.Read(Pointer(lParam1)^, lParam2);
lpmmIOInfo^.lDiskOffset := Stream.Seek(0, SEEK_CUR);
except
Result := -1;
end;
MMIOM_WRITE,
MMIOM_WRITEFLUSH:
try
Stream.Seek(lpmmIOInfo^.lDiskOffset, SEEK_SET);
Result := Stream.Write(Pointer(lParam1)^, lParam2);
lpmmIOInfo^.lDiskOffset := Stream.Seek(0, SEEK_CUR);
except
Result := -1;
end
else
Result := MMSYSERR_NOERROR;
end;
end
else
Result := -1;
end;
// Retrieves format, size, and offset of the wave audio for an open mmIO
// handle. On success when the the function returns true, it is the caller
// responsibility to free the memory allocated for the Wave Format structure.
function GetWaveAudioInfo(mmIO: HMMIO; out pWaveFormat: PWaveFormatEx;
out DataSize, DataOffset: DWORD): Boolean;
function GetWaveFormat(const ckRIFF: TMMCKInfo): Boolean;
var
ckFormat: TMMCKInfo;
begin
Result := False;
ckFormat.ckid := mmioStringToFOURCC('fmt', 0);
if (mmioDescend(mmIO, @ckFormat, @ckRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) and
(ckFormat.cksize >= SizeOf(TWaveFormat)) then
begin
if ckFormat.cksize < SizeOf(TWaveFormatEx) then
begin
GetMem(pWaveFormat, SizeOf(TWaveFormatEx));
FillChar(pWaveFormat^, SizeOf(TWaveFormatEx), 0);
end
else
GetMem(pWaveFormat, ckFormat.cksize);
Result := (mmioRead(mmIO, PChar(pWaveFormat), ckFormat.cksize) = Integer(ckFormat.cksize));
end;
end;
function GetWaveData(const ckRIFF: TMMCKInfo): Boolean;
var
ckData: TMMCKInfo;
begin
Result := False;
ckData.ckid := mmioStringToFOURCC('data', 0);
if (mmioDescend(mmIO, @ckData, @ckRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) then
begin
DataSize := ckData.cksize;
DataOffset := ckData.dwDataOffset;
Result := True;
end;
end;
var
ckRIFF: TMMCKInfo;
OrgPos: Integer;
begin
Result := False;
OrgPos := mmioSeek(mmIO, 0, SEEK_CUR);
try
mmioSeek(mmIO, 0, SEEK_SET);
ckRIFF.fccType := mmioStringToFOURCC('WAVE', 0);
if (mmioDescend(mmIO, @ckRIFF, nil, MMIO_FINDRIFF) = MMSYSERR_NOERROR) then
begin
pWaveFormat := nil;
if GetWaveFormat(ckRIFF) and GetWaveData(ckRIFF) then
Result := True
else if Assigned(pWaveFormat) then
ReallocMem(pWaveFormat, 0);
end
finally
mmioSeek(mmIO, OrgPos, SEEK_SET);
end;
end;
// Initializes a new wave RIFF format in an open mmIO handle. The previous
// content of mmIO will be lost.
function CreateWaveAudio(mmIO: HMMIO; const pWaveFormat: PWaveFormatEx;
out ckRIFF, ckData: TMMCKInfo): Boolean;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -