📄 mmadpcm.pas
字号:
{ sample and multiply that with dwDecoded... }
adpcmDecode4BitExit:
Result := (dwDecoded * ((bBitsPerSample div 8) * bChannels));
end;
{==============================================================================}
function adpcmEncode4Bit_FirstDelta(iCoef1, iCoef2, iP5, iP4, iP3, iP2, iP1: Smallint): Smallint;
var
lTotal: Longint;
lTemp : Longint;
begin
{ use average of 3 predictions }
lTemp := ((Longint(iP5) * iCoef2) + (Longint(iP4) * iCoef1)) shr MSADPCM_CSCALE;
if (lTemp > iP3) then
lTotal := lTemp - iP3
else
lTotal := iP3 - lTemp;
lTemp := ((Longint(iP4) * iCoef2) + (Longint(iP3) * iCoef1)) shr MSADPCM_CSCALE;
if (lTemp > iP2) then
lTotal := lTotal + (lTemp - iP2)
else
lTotal := lTotal + (iP2 - lTemp);
lTemp := ((Longint(iP3) * iCoef2) + (Longint(iP2) * iCoef1)) shr MSADPCM_CSCALE;
if (lTemp > iP1) then
lTotal := lTotal + (lTemp - iP1)
else
lTotal := lTotal + (iP1 - lTemp);
{ optimal iDelta is 1/4 of prediction error }
Result := lTotal div 12;
if (Result < MSADPCM_DELTA4_MIN) then
Result := MSADPCM_DELTA4_MIN;
end;
const
ENCODE_DELTA_LOOKAHEAD = 5;
{==============================================================================}
function adpcmEncode4Bit(lpwfPCM: PWaveFormatEx; lpwfADPCM: PADPCMWaveFormat;
pSrc: PChar; pDst: PChar; dwSrcLen: DWORD): DWORD;
var
lpSamplesBuf, lpSamples: Pchar;
abBestPredictor: array[0..MSADPCM_MAX_CHANNELS-1] of Byte;
adwTotalError: array[0..MSADPCM_NUM_COEF-1,0..MSADPCM_MAX_CHANNELS-1] of DWORD;
aiSamples: array[0..ENCODE_DELTA_LOOKAHEAD-1,0..MSADPCM_MAX_CHANNELS-1] of Smallint;
aiFirstDelta: array[0..MSADPCM_NUM_COEF-1,0..MSADPCM_MAX_CHANNELS-1] of Smallint;
aiDelta: array[0..MSADPCM_MAX_CHANNELS-1] of Smallint;
aiSamp1: array[0..MSADPCM_MAX_CHANNELS-1] of Smallint;
aiSamp2: array[0..MSADPCM_MAX_CHANNELS-1] of Smallint;
iCoef1,iCoef2,iSamp1,iSamp2,iDelta,iSample,iOutput: Smallint;
lSamp: Longint;
dw,dwTotalConverted,dwInputPos: DWORD;
lError,lPrediction: Longint;
wSamplesPerBlock,
cbSample,
wBlockHeaderBytes,
wBlockSize,
wNextWrite,
wFirstNibble,
n: Word;
m,
i,
bChannels,
bBitsPerSample: Byte;
begin
{ first copy some information into more accessible (cheaper and shorter) }
{ variables--and precompute some stuff... }
wSamplesPerBlock := lpwfADPCM^.wSamplesPerBlock;
bChannels := lpwfPCM^.nChannels;
bBitsPerSample := lpwfPCM^.wBitsPerSample;
wBlockHeaderBytes := bChannels * 7;
dwInputPos := 0;
dwTotalConverted := 0;
{ calculate the number of bytes per sample in the PCM data }
{ }
{ note: the following code works because we _know_ that we only deal }
{ with 8 or 16 bits per sample PCM and 1 or 2 channels.. }
cbSample := (bBitsPerSample div 8) * bChannels;
{ we allocate and use a small buffer (<64k) to hold an entire block of }
{ samples to be encoded. the reason for this is mainly because we }
{ make 8 passes over the data per block and using huge pointers all }
{ of the time is expensive. so we put it in a <64k chunk and eliminate }
{ the huge pointer stuff }
lpSamplesBuf := GlobalAllocPtr(GMEM_MOVEABLE or GMEM_SHARE, wSamplesPerBlock * cbSample);
if (lpSamplesBuf = nil) then
begin
Result := 0;
exit;
end;
{ step through each block of PCM data and encode it to 4 bit ADPCM }
while dwInputPos < dwSrcLen do
begin
{ determine how much data we should encode for this block--this }
{ will be wSamplesPerBlock until we hit the last chunk of PCM }
{ data that will not fill a complete block. so on the last block }
{ we only encode that amount of data remaining... }
dw := (dwSrcLen - dwInputPos) div cbSample;
wBlockSize := Min(wSamplesPerBlock, dw);
if (wBlockSize <= 0) then
break;
{ copy the samples that we will be encoding into our small data }
{ samples buffer (this is faster than doing huge pointer arith }
{ all of the time) }
GlobalMoveMem(PChar(@pSrc[dwInputPos])^,lpSamplesBuf^, wBlockSize * cbSample);
{ find the optimal predictor for each channel: to do this, we }
{ must step through and encode using each coefficient set (one }
{ at a time) and determine which one has the least error from }
{ the original data. the one with the least error is then used }
{ for the final encode (the 8th pass done below). }
{ }
{ NOTE: keeping the encoded data of the one that has the least }
{ error at all times is an obvious optimization that should be }
{ done. in this way, we only need to do 7 passes instead of 8. }
for i := 0 to MSADPCM_NUM_COEF-1 do
begin
{ reset pointer to beginning of our temporary small data }
{ samples buffer }
lpSamples := lpSamplesBuf;
{ copy the coefficient pair for the current coefficient set }
{ we are using into more convenient/cheaper variables }
iCoef1 := lpwfADPCM^.aCoef[i].iCoef1;
iCoef2 := lpwfADPCM^.aCoef[i].iCoef2;
{ we need to choose the first iDelta--to do this, we need }
{ to look at the first few samples. for convenience, we copy }
{ the first ENCODE_DELTA_LOOKAHEAD samples (converted to }
{ 16 bit samples) into a temporary buffer }
for n := 0 to ENCODE_DELTA_LOOKAHEAD-1 do
begin
for m := 0 to bChannels-1 do
begin
if (bBitsPerSample <> 8) then
begin
iSample := PSmallint(lpSamples)^;
inc(lpSamples,2);
end
else
begin
iSample := Smallint(PByte(lpSamples)^ - 128) shl 8;
inc(lpSamples);
end;
aiSamples[n][m] := iSample;
end;
end;
{ now choose the first iDelta and setup the first two samples }
{ based on the 16 samples we copied from the source data above }
{ for each channel }
for m := 0 to bChannels-1 do
begin
{ reset total error calculation for new block }
adwTotalError[i][m] := 0;
{ first 2 samples will come from real data--compute }
{ starting from there }
aiSamp1[m] := aiSamples[1][m];
aiSamp2[m] := aiSamples[0][m];
{ calculate initial iDelta }
iDelta := adpcmEncode4Bit_FirstDelta(iCoef1, iCoef2,
aiSamples[0][m],
aiSamples[1][m],
aiSamples[2][m],
aiSamples[3][m],
aiSamples[4][m]);
aiDelta[m] := iDelta;
aiFirstDelta[i][m] := iDelta;
end;
{ step over first two complete samples--we took care of them above }
lpSamples := @lpSamplesBuf[cbSample*2];
{ now encode the rest of the PCM data in this block--note }
{ we start 2 samples ahead because the first two samples are }
{ simply copied into the ADPCM block header... }
for n := 2 to wBlockSize-1 do
begin
{ each channel gets encoded independently... obviously. }
for m := 0 to bChannels-1 do
begin
{ yes, copy into cheaper variables because we access them a lot }
iSamp1 := aiSamp1[m];
iSamp2 := aiSamp2[m];
iDelta := aiDelta[m];
{ calculate the prediction based on the previous two samples }
lPrediction := sar((Longint(iSamp1) * iCoef1 +
Longint(iSamp2) * iCoef2),MSADPCM_CSCALE);
{ grab the sample (for the current channel) to encode }
{ from the source and convert it to a 16 bit data if }
{ necessary }
if (bBitsPerSample <> 8) then
begin
iSample := PSmallint(lpSamples)^;
inc(lpSamples,2);
end
else
begin
iSample := Smallint(PByte(lpSamples)^ - 128) shl 8;
inc(lpSamples);
end;
{ encode it }
lError := iSample - lPrediction;
iOutput := (lError div iDelta);
if (iOutput > MSADPCM_OUTPUT4_MAX) then
iOutput := MSADPCM_OUTPUT4_MAX
else if (iOutput < MSADPCM_OUTPUT4_MIN) then
iOutput := MSADPCM_OUTPUT4_MIN;
lSamp := lPrediction + (Longint(iDelta) * iOutput);
if (lSamp > 32767) then
lSamp := 32767
else if (lSamp < -32768) then
lSamp := -32768;
{ compute the next iDelta }
iDelta := sar((gaiP4[iOutput and 15] * Longint(iDelta)),MSADPCM_PSCALE);
if (iDelta < MSADPCM_DELTA4_MIN) then
iDelta := MSADPCM_DELTA4_MIN;
{ save updated values for this channel back into the }
{ original arrays... }
aiDelta[m] := iDelta;
aiSamp2[m] := iSamp1;
aiSamp1[m] := lSamp;
{ keep a running status on the error for the current }
{ coefficient pair for this channel }
lError := lSamp - iSample;
inc(adwTotalError[i][m],sar(lError * lError,7));
end;
end;
end;
{ WHEW! we have now made 7 passes over the data and calculated }
{ the error for each--so it's time to find the one that produced }
{ the lowest error and use that predictor (this is for each }
{ channel of course) }
for m := 0 to bChannels-1 do
begin
abBestPredictor[m] := 0;
dw := adwTotalError[0][m];
for i := 1 to MSADPCM_NUM_COEF-1 do
begin
if (adwTotalError[i][m] < dw) then
begin
abBestPredictor[m] := i;
dw := adwTotalError[i][m];
end;
end;
end;
{ reset pointer to beginning of our temporary samples buffer-- }
{ we're going to make our final pass on the data with the optimal }
{ predictor that we found above }
lpSamples := lpSamplesBuf;
{ grab first iDelta from our precomputed first deltas that we }
{ calculated above }
for m := 0 to bChannels-1 do
begin
i := abBestPredictor[m];
aiDelta[m] := aiFirstDelta[i][m];
end;
{ get the first two samples from the source data (so we can write }
{ them into the ADPCM block header and use them in our prediction }
{ calculation when encoding the rest of the data). }
if (bBitsPerSample <> 8) then
begin
for m := 0 to bChannels-1 do
begin
aiSamp2[m] := PSmallint(lpSamples)^;
inc(lpSamples,2);
end;
for m := 0 to bChannels-1 do
begin
aiSamp1[m] := PSmallint(lpSamples)^;
inc(lpSamples,2);
end;
end
else
begin
for m := 0 to bChannels-1 do
begin
aiSamp2[m] := (Smallint(PByte(lpSamples)^) - 128) shl 8;
inc(lpSamples);
end;
for m := 0 to bChannels-1 do
begin
aiSamp1[m] := (Smallint(PByte(lpSamples)^) - 128) shl 8;
end;
end;
{ write the block header for the encoded data }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -