📄 mmadpcm.pas
字号:
{========================================================================}
{= (c) 1995-98 SwiftSoft Ronald Dittrich =}
{========================================================================}
{= All Rights Reserved =}
{========================================================================}
{= D 01099 Dresden = Fax.: +49 (0)351-8037944 =}
{= Loewenstr.7a = info@swiftsoft.de =}
{========================================================================}
{= Actual versions on http://www.swiftsoft.de/mmtools.html =}
{========================================================================}
{= This code is for reference purposes only and may not be copied or =}
{= distributed in any format electronic or otherwise except one copy =}
{= for backup purposes. =}
{= =}
{= No Delphi Component Kit or Component individually or in a collection=}
{= subclassed or otherwise from the code in this unit, or associated =}
{= .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed =}
{= without express permission from SwiftSoft. =}
{= =}
{= For more licence informations please refer to the associated =}
{= HelpFile. =}
{========================================================================}
{= $Date: 08.09.98 - 11:53:22 $ =}
{========================================================================}
unit MMADPCM;
{$I COMPILER.INC}
interface
uses
{$IFDEF WIN32}
Windows,
{$ELSE}
WinProcs,
WinTypes,
{$ENDIF}
SysUtils,
MMSystem,
MMObj,
MMUtils,
MMMulDiv,
MMRegs,
MMPCMSup;
function adpcmDecode4Bit(lpwfADPCM: PADPCMWaveFormat; lpwfPCM: PWaveFormatEx; pSrc, pDst: PChar; dwSrcLen: DWORD): DWORD;
function adpcmEncode4Bit(lpwfPCM: PWaveFormatEx; lpwfADPCM: PADPCMWaveFormat; pSrc, pDst: PChar; dwSrcLen: DWORD): DWORD;
function adpcmIsValidFormat(lpwfx: PWaveFormatEx): Boolean;
function adpcmBuildFormatHeader(lpwfxSrc, lpwfxDst: PWaveFormatEx; PCMBitLength,DestChannels,DestRate: integer): Boolean;
implementation
(*============================================================================*)
(* *)
(* constants used by the Microsoft 4 Bit ADPCM algorithm *)
(* *)
(* CAUTION: the code contained in this file assumes that the number of *)
(* channels will be no greater than 2! this is for minor optimization *)
(* purposes and would be very easy to change if >2 channels is required. *)
(* it also assumes that the PCM data will either be 8 or 16 bit. *)
(* *)
(* the code to look out for looks 'similar' to this: *)
(* *)
(* PCM.BytesPerSample = (PCM.BitsPerSample >> 3) << (Channels >> 1); *)
(* *)
(*============================================================================*)
const
MSADPCM_NUM_COEF = 7;
MSADPCM_MAX_CHANNELS = 2;
MSADPCM_CSCALE = 8;
MSADPCM_PSCALE = 8;
MSADPCM_CSCALE_NUM = 1 shl MSADPCM_CSCALE;
MSADPCM_PSCALE_NUM = 1 shl MSADPCM_PSCALE;
MSADPCM_DELTA4_MIN = 16;
MSADPCM_OUTPUT4_MAX = 7;
MSADPCM_OUTPUT4_MIN = -8;
(* Fixed point Delta adaption table: *)
(* *)
(* Next Delta = Delta * gaiP4[ this output ] / MSADPCM_PSCALE *)
const
gaiP4: array[0..15]of Smallint = (230, 230, 230, 230, 307, 409, 512, 614,
768, 614, 512, 409, 307, 230, 230, 230);
{==============================================================================}
function adpcmDecode4Bit(lpwfADPCM: PADPCMWaveFormat; lpwfPCM: PWaveFormatEx; pSrc, pDst: PChar; dwSrcLen: DWORD): DWORD;
Label adpcmDecode4BitExit;
type
PCoefSet = ^TCoefSet;
TCoefSet = array[0..0] of TADPCMCOEFSET;
var
iInput, iNextInput, iFirstNibble, iDelta: Smallint;
lSamp, lPrediction: Longint;
bPredictor, bPredictors, bChannels, bBitsPerSample, m: Byte;
n, wSamplesPerBlock, wBlockHeaderBytes: Word;
dwTotalPos, dwDecoded: DWORD;
aiSamp1: array[0..MSADPCM_MAX_CHANNELS-1] of Smallint;
aiSamp2: array[0..MSADPCM_MAX_CHANNELS-1] of Smallint;
aiCoef1: array[0..MSADPCM_MAX_CHANNELS-1] of Smallint;
aiCoef2: array[0..MSADPCM_MAX_CHANNELS-1] of Smallint;
aiDelta: array[0..MSADPCM_MAX_CHANNELS-1] of Smallint;
lpCoefSet: PCoefSet;
begin
{ put some commonly used info in more accessible variables and init }
{ the wBlockHeaderBytes, dwDecoded and dwTotalPos vars... }
lpCoefSet := @lpwfADPCM^.aCoef[0];
bPredictors := lpwfADPCM^.wNumCoef;
bChannels := lpwfADPCM^.wfx.nChannels;
bBitsPerSample := lpwfPCM^.wBitsPerSample;
wSamplesPerBlock := lpwfADPCM^.wSamplesPerBlock;
wBlockHeaderBytes := bChannels * 7;
dwDecoded := 0;
dwTotalPos := 0;
{ step through each byte of ADPCM data and decode it to the requested }
{ PCM format (8 or 16 bit). }
while (dwTotalPos < dwSrcLen) do
begin
{ the first thing we need to do with each block of ADPCM data is }
{ to read the header which consists of 7 bytes of data per channel. }
{ so our first check is to make sure that we have _at least_ }
{ enough input data for a complete ADPCM block header--if there }
{ is not enough data for the header, then exit. }
{ }
{ the header looks like this: }
{ 1 byte predictor per channel }
{ 2 byte delta per channel }
{ 2 byte first sample per channel }
{ 2 byte second sample per channel }
{ }
{ this gives us (7 * bChannels) bytes of header information. note }
{ that as long as there is _at least_ (7 * bChannels) of header }
{ info, we will grab the two samples from the header (and if no }
{ data exists following the header we will exit in the decode }
{ loop below). }
inc(dwTotalPos,wBlockHeaderBytes);
if (dwTotalPos > dwSrcLen) then
goto adpcmDecode4BitExit;
{ grab and validate the predictor for each channel }
for m := 0 to bChannels-1 do
begin
bPredictor := PByte(pSrc)^;
inc(pSrc);
if (bPredictor >= bPredictors) then
begin
{ the predictor is out of range--this is considered a }
{ fatal error with the ADPCM data, so we fail by returning }
{ zero bytes decoded }
dwDecoded := 0;
goto adpcmDecode4BitExit;
end;
{ get the coefficients for the predictor index }
aiCoef1[m] := lpCoefSet^[bPredictor].iCoef1;
aiCoef2[m] := lpCoefSet^[bPredictor].iCoef2;
end;
{ get the starting delta for each channel }
for m := 0 to bChannels-1 do
begin
aiDelta[m] := PSmallint(pSrc)^;
inc(pSrc,2);
end;
{ get the sample just previous to the first encoded sample per channel }
for m := 0 to bChannels-1 do
begin
aiSamp1[m] := PSmallint(pSrc)^;
inc(pSrc,2);
end;
{ get the sample previous to aiSamp1[x] per channel }
for m := 0 to bChannels-1 do
begin
aiSamp2[m] := PSmallint(pSrc)^;
inc(pSrc,2);
end;
{ write out first 2 samples for each channel. }
{ NOTE: the samples are written to the destination PCM buffer }
{ in the _reverse_ order that they are in the header block: }
{ remember that aiSamp2[x] is the _previous_ sample to aiSamp1[x]. }
if (bBitsPerSample = 8) then
begin
for m := 0 to bChannels-1 do
begin
PByte(pDst)^ := (aiSamp2[m] div 256) + 128;
inc(pDst);
end;
for m := 0 to bChannels-1 do
begin
PByte(pDst)^ := (aiSamp1[m] div 256) + 128;
inc(pDst);
end;
end
else
begin
for m := 0 to bChannels-1 do
begin
PSmallint(pDst)^ := aiSamp2[m];
inc(pDst,2);
end;
for m := 0 to bChannels-1 do
begin
PSmallint(pDst)^ := aiSamp1[m];
inc(pDst,2);
end;
end;
{ we have decoded the first two samples for this block, so add }
{ two to our decoded count }
inc(dwDecoded,2);
{ we now need to decode the 'data' section of the ADPCM block. }
{ this consists of packed 4 bit nibbles. }
{ }
{ NOTE: we start our count for the number of data bytes to decode }
{ at 2 because we have already decoded the first 2 samples in }
{ this block. }
iFirstNibble := 1;
for n := 2 to wSamplesPerBlock-1 do
begin
for m := 0 to bChannels-1 do
begin
if (iFirstNibble > 0) then
begin
{ we need to grab the next byte to decode--make sure }
{ that there is a byte for us to grab before continue }
inc(dwTotalPos);
if (dwTotalPos > dwSrcLen) then
goto adpcmDecode4BitExit;
{ grab the next two nibbles and create sign extended }
{ integers out of them: }
{ }
{ iInput is the first nibble to decode }
{ iNextInput will be the next nibble decoded }
iNextInput := PShortInt(pSrc)^;
inc(pSrc);
iInput := Sar(iNextInput,4);
{ iNextInput := (iNextInput shl 12) shr 12); }
asm
mov ax, iNextInput
sal ax, 12
sar ax, 12
mov iNextInput, ax
end;
iFirstNibble := 0;
end
else
begin
{ put the next sign extended nibble into iInput and }
{ decode it--also set iFirstNibble back to 1 so we }
{ will read another byte from the source stream on }
{ the next iteration... }
iInput := iNextInput;
iFirstNibble := 1;
end;
{ compute the next Adaptive Scale Factor (ASF) and put }
{ this value in aiDelta for the current channel. }
iDelta := aiDelta[m];
aiDelta[m] := Sar((gaiP4[iInput and 15] * Longint(iDelta)),MSADPCM_PSCALE);
if (aiDelta[m] < MSADPCM_DELTA4_MIN) then
aiDelta[m] := MSADPCM_DELTA4_MIN;
{ decode iInput (the sign extended 4 bit nibble)--there are }
{ two steps to this: }
{ }
{ 1. predict the next sample using the previous two }
{ samples and the predictor coefficients: }
{ }
{ Prediction = (aiSamp1[channel] * aiCoef1[channel] + }
{ aiSamp2[channel] * aiCoef2[channel]) / 256; }
{ }
{ 2. reconstruct the original PCM sample using the encoded }
{ sample (iInput), the Adaptive Scale Factor (aiDelta) }
{ and the prediction value computed in step 1 above. }
{ }
{ Sample = (iInput * aiDelta[channel]) + Prediction; }
lPrediction := Sar((Longint(aiSamp1[m]) * aiCoef1[m]) +
(Longint(aiSamp2[m]) * aiCoef2[m]),MSADPCM_CSCALE);
lSamp := (Longint(iInput) * iDelta) + lPrediction;
{ now we need to clamp lSamp to [-32768..32767]--this value }
{ will then be a valid 16 bit sample. }
if (lSamp > 32767) then
lSamp := 32767
else if (lSamp < -32768) then
lSamp := -32768;
{ lSamp contains the decoded iInput sample--now write it }
{ out to the destination buffer }
if (bBitsPerSample = 8) then
begin
PByte(pDst)^ := (lSamp div 256) + 128;
inc(pDst);
end
else
begin
PSmallint(pDst)^ := lSamp;
inc(pDst,2);
end;
{ ripple our previous samples down making the new aiSamp1 }
{ equal to the sample we just decoded }
aiSamp2[m] := aiSamp1[m];
aiSamp1[m] := lSamp;
end;
{ we have decoded one more complete sample }
inc(dwDecoded);
end;
end;
{ we're done decoding the input data. dwDecoded contains the number }
{ of complete _SAMPLES_ that were decoded. we need to return the }
{ number of _BYTES_ decoded. so calculate the number of bytes per }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -