📄 audioacm.pas
字号:
var
ckFormat: TMMCKInfo;
FormatSize: Integer;
begin
Result := False;
FormatSize := SizeOf(TWaveFormatEx) + pWaveFormat^.cbSize;
mmIOSeek(mmIO, 0, SEEK_SET);
FillChar(ckRIFF, SizeOf(TMMCKInfo), 0);
ckRIFF.fccType := mmioStringToFOURCC('WAVE', 0);
if mmioCreateChunk(mmIO, @ckRIFF, MMIO_CREATERIFF) = MMSYSERR_NOERROR then
begin
FillChar(ckFormat, SizeOf(TMMCKInfo), 0);
ckFormat.ckid := mmioStringToFOURCC('fmt', 0);
if (mmioCreateChunk(mmIO, @ckFormat, 0) = MMSYSERR_NOERROR) and
(mmioWrite(mmIO, PChar(pWaveFormat), FormatSize) = FormatSize) and
(mmioAscend(mmIO, @ckFormat, 0) = MMSYSERR_NOERROR) then
begin
FillChar(ckData, SizeOf(TMMCKInfo), 0);
ckData.ckid := mmioStringToFOURCC('data', 0);
Result := (mmioCreateChunk(mmIO, @ckData, 0) = MMSYSERR_NOERROR);
end;
end;
end;
// Updates the chunks and closes an mmIO handle.
procedure CloseWaveAudio(mmIO: HMMIO; var ckRIFF, ckData: TMMCKInfo);
begin
mmioAscend(mmIO, @ckData, 0);
mmioAscend(mmIO, @ckRIFF, 0);
mmioClose(mmIO, 0);
end;
// Retrieves format, size, and offset of the wave audio for a stream. On
// success when the the function returns true, it is the caller responsibility
// to free the memory allocated for the Wave Format structure.
function GetStreamWaveAudioInfo(Stream: TStream; out pWaveFormat: PWaveFormatEx;
out DataSize, DataOffset: DWORD): Boolean;
var
mmIO: HMMIO;
begin
Result := False;
if Stream.Size <> 0 then
begin
mmIO := OpenStreamWaveAudio(Stream);
if mmIO <> 0 then
try
Result := GetWaveAudioInfo(mmIO, pWaveFormat, DataSize, DataOffset);
finally
mmioClose(mmIO, MMIO_FHOPEN);
end;
end;
end;
// Initializes wave RIFF format in a stream and returns the mmIO handle.
// After calling this function, the previous content of the stream will be lost.
function CreateStreamWaveAudio(Stream: TStream; const pWaveFormat: PWaveFormatEx;
out ckRIFF, ckData: TMMCKInfo): HMMIO;
begin
Result := OpenStreamWaveAudio(Stream);
if Result <> 0 then
begin
Stream.Size := 0;
if not CreateWaveAudio(Result, pWaveFormat, ckRIFF, ckData) then
begin
mmioClose(Result, MMIO_FHOPEN);
Result := 0;
end;
end;
end;
// Opens wave RIFF format in a stream for read and write operations and returns
// the mmIO handle.
function OpenStreamWaveAudio(Stream: TStream): HMMIO;
var
mmIOInfo: TMMIOINFO;
begin
FillChar(mmIOInfo, SizeOf(mmIOInfo), 0);
mmIOInfo.pIOProc := @mmIOStreamProc;
mmIOInfo.adwInfo[0] := DWORD(Stream);
Result := mmioOpen(nil, @mmIOInfo, MMIO_READ or MMIO_WRITE);
end;
// Claculates the wave buffer size for the specified duration.
function CalcWaveBufferSize(const pWaveFormat: PWaveFormatEx; Duration: DWORD): DWORD;
var
Alignment: DWORD;
begin
Result := MulDiv(Duration, pWaveFormat^.nAvgBytesPerSec, 1000);
if pWaveFormat^.nBlockAlign <> 0 then
begin
Alignment := Result mod pWaveFormat^.nBlockAlign;
if Alignment <> 0 then Inc(Result, pWaveFormat^.nBlockAlign - Alignment);
end;
end;
// Returns the string representation of a wave audio format.
function GetWaveAudioFormat(const pWaveFormat: PWaveFormatEx): String;
const
Channels: array[1..2] of String = ('Mono', 'Stereo');
begin
with pWaveFormat^ do
begin
if nChannels in [1..2] then
Result := Format('%.3f kHz, %d Bit, %s', [nSamplesPerSec / 1000,
wBitsPerSample, Channels[nChannels]])
else
Result := Format('%.3f kHz, %d Bit, %d Ch', [nSamplesPerSec / 1000,
wBitsPerSample, nChannels]);
if wFormatTag = WAVE_FORMAT_PCM then
Result := 'PCM ' + Result;
end;
end;
// Returns the wave's length in milliseconds.
function GetWaveAudioLength(const pWaveFormat: PWaveFormatEx; DataSize: DWORD): DWORD;
begin
with pWaveFormat^ do
if nAvgBytesPerSec <> 0 then
Result := MulDiv(1000, DataSize, nAvgBytesPerSec)
else
Result := 0;
end;
// Returns the wave's bit rate in kbps (kilo bits per second).
function GetWaveAudioBitRate(const pWaveFormat: PWaveFormatEx): DWORD;
begin
with pWaveFormat^ do
Result := MulDiv(nSamplesPerSec, nChannels * wBitsPerSample, 1000);
end;
// Returns the wave data peak level in percent (PCM format only).
function GetWaveAudioPeakLevel(const Data: Pointer; DataSize: DWORD;
BitsPerSample: WORD): Integer;
function GetAudioPeakLevel8Bit: Integer;
var
pSample: PByte;
Max: Byte;
begin
Max := 0;
pSample := Data;
while DataSize > 0 do
begin
if pSample^ > Max then
Max := pSample^;
Inc(pSample);
Dec(DataSize);
end;
if ByteBool(Max and $80) then
Max := Max and $7F
else
Max := 0;
Result := (100 * Max) div $7F;
end;
function GetAudioPeakLevel16Bit: Integer;
var
pSample: PSmallInt;
Max: SmallInt;
begin
Max := 0;
pSample := Data;
while DataSize > 0 do
begin
if pSample^ > Max then
Max := pSample^;
Inc(pSample);
Dec(DataSize, 2);
end;
Result := (100 * Max) div $7FFF;
end;
begin
case BitsPerSample of
8: Result := GetAudioPeakLevel8Bit;
16: Result := GetAudioPeakLevel16Bit;
else
Result := -1;
end;
end;
// Inverts the wave data (PCM format only).
procedure InvertWaveAudio(const Data: Pointer; DataSize: DWORD;
BitsPerSample: WORD);
procedure Invert8Bit;
var
pStart, pEnd: PByte;
begin
pStart := Data;
pEnd := PByte(DWORD(pStart) + DataSize - SizeOf(Byte));
while DWORD(pStart) < DWORD(pEnd) do
begin
pStart^ := pStart^ xor pEnd^;
pEnd^ := pStart^ xor pEnd^;
pStart^ := pStart^ xor pEnd^;
Inc(pStart);
Dec(pEnd);
end;
end;
procedure Invert16Bit;
var
pStart, pEnd: PSmallInt;
begin
pStart := Data;
pEnd := PSmallInt(DWORD(pStart) + DataSize - SizeOf(SmallInt));
while DWORD(pStart) < DWORD(pEnd) do
begin
pStart^ := pStart^ xor pEnd^;
pEnd^ := pStart^ xor pEnd^;
pStart^ := pStart^ xor pEnd^;
Inc(pStart);
Dec(pEnd);
end;
end;
begin
case BitsPerSample of
8: Invert8Bit;
16: Invert16Bit;
end;
end;
// Fills the wave data with silence
procedure SilenceWaveAudio(const Data: Pointer; DataSize: DWORD;
BitsPerSample: WORD);
begin
case BitsPerSample of
8: FillChar(Data^, DataSize, $7F);
16: FillChar(Data^, DataSize, 0);
end;
end;
// Increases/Decreases the wave data volume by the specified percentage (PCM format only).
procedure ChangeWaveAudioVolume(const Data: Pointer; DataSize: DWORD;
BitsPerSample: WORD; Percent: Integer);
procedure ChangeVolume8Bit;
var
pSample: PByte;
Value: Integer;
begin
pSample := Data;
while DataSize > 0 do
begin
Value := pSample^ + (pSample^ * Percent) div 100;
if Value > High(Byte) then
Value := High(Byte)
else if Value < 0 then
Value := 0;
pSample^ := Value;
Inc(pSample);
Dec(DataSize, SizeOf(Byte));
end;
end;
procedure ChangeVolume16Bit;
var
pSample: PSmallInt;
Value: Integer;
begin
pSample := Data;
while DataSize > 0 do
begin
Value := pSample^ + (pSample^ * Percent) div 100;
if Value > High(SmallInt) then
Value := High(SmallInt)
else if Value < -High(SmallInt) then
Value := -High(SmallInt);
pSample^ := Value;
Inc(pSample);
Dec(DataSize, SizeOf(SmallInt));
end;
end;
begin
case BitsPerSample of
8: ChangeVolume8Bit;
16: ChangeVolume16Bit;
end;
end;
// Converts the wave data to the specified format. The caller is responsible to
// release the memory allocated for the converted wave data buffer.
function ConvertWaveFormat(const srcFormat: PWaveFormatEx; srcData: Pointer; srcDataSize: DWORD;
const dstFormat: PWaveFormatEx; out dstData: Pointer; out dstDataSize: DWORD): Boolean;
var
hStream: HACMSTREAM;
Header: TACMSTREAMHEADER;
begin
Result := False;
if acmStreamOpen(hStream, 0, srcFormat, dstFormat, nil, 0, 0, ACM_STREAMOPENF_NONREALTIME) = 0 then
begin
try
if acmStreamSize(hStream, srcDataSize, dstDataSize, ACM_STREAMSIZEF_SOURCE) = 0 then
begin
dstData := nil;
FillChar(Header, SizeOf(Header), 0);
ReallocMem(dstData, dstDataSize);
try
Header.cbStruct := SizeOf(Header);
Header.pbSrc := srcData;
Header.cbSrcLength := srcDataSize;
Header.pbDst := dstData;
Header.cbDstLength := dstDataSize;
if acmStreamPrepareHeader(hStream, Header, 0) = 0 then
try
Result := (acmStreamConvert(hStream, Header, ACM_STREAMCONVERTF_START or ACM_STREAMCONVERTF_END) = 0);
finally
acmStreamUnprepareHeader(hStream, Header, 0);
end;
finally
ReallocMem(dstData, Header.cbDstLengthUsed);
dstDataSize := Header.cbDstLengthUsed;
end;
end;
finally
acmStreamClose(hStream, 0);
end;
end;
end;
// Initializes a standard MP3 wave format header. The size of memory referenced
// by the pWaveFormat parameter must not be less than the size of TWaveFormatEx
// record.
procedure SetMP3AudioFormat(const pWaveFormat: PWaveFormatEx;
Channels: TPCMChannel; SamplesPerSec: TPCMSamplesPerSec;
BitsPerSample: TPCMBitsPerSample);
begin
{
.nChannels = wfxIN.nChannels
.nSamplesPerSec = wfxIN.nSamplesPerSec
.wFormatTag = WAVE_FORMAT_MPEGLAYER3}
with pWaveFormat^ do
begin
wFormatTag := WAVE_FORMAT_MPEGLAYER3;
case Channels of
cMono: nChannels := 1;
cStereo: nChannels := 2;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -