windows-nt/Source/XPSP1/NT/multimedia/media/msacm/msadpcm/msadpcm.c
2020-09-26 16:20:57 +08:00

3543 lines
107 KiB
C

//==========================================================================;
//
// msadpcm.c
//
// Copyright (c) 1992-1994 Microsoft Corporation
//
// Description:
//
//
// History:
//
//==========================================================================;
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <msacm.h>
#include <msacmdrv.h>
#include "codec.h"
#include "msadpcm.h"
#include "debug.h"
//
// these are in dec386.asm for Win 16
//
// _gaiCoef1 dw 256, 512, 0, 192, 240, 460, 392
// _gaiCoef2 dw 0, -256, 0, 64, 0, -208, -232
//
// _gaiP4 dw 230, 230, 230, 230, 307, 409, 512, 614
// dw 768, 614, 512, 409, 307, 230, 230, 230
//
#ifdef WIN32
const int gaiCoef1[]= {256, 512, 0, 192, 240, 460, 392};
const int gaiCoef2[]= { 0, -256, 0, 64, 0, -208, -232};
const int gaiP4[] = {230, 230, 230, 230, 307, 409, 512, 614,
768, 614, 512, 409, 307, 230, 230, 230};
#endif
#ifndef INLINE
#define INLINE __inline
#endif
//--------------------------------------------------------------------------;
//
// DWORD pcmM08BytesToSamples
// DWORD pcmM16BytesToSamples
// DWORD pcmS08BytesToSamples
// DWORD pcmS16BytesToSamples
//
// Description:
// These functions return the number of samples in a buffer of PCM
// of the specified format. For efficiency, it is declared INLINE.
// Note that, depending on the optimization flags, it may not
// actually be implemented as INLINE. Optimizing for speed (-Oxwt)
// will generally obey the INLINE specification.
//
// Arguments:
// DWORD cb: The length of the buffer, in bytes.
//
// Return (DWORD): The length of the buffer in samples.
//
//--------------------------------------------------------------------------;
INLINE DWORD pcmM08BytesToSamples( DWORD cb )
{
return cb;
}
INLINE DWORD pcmM16BytesToSamples( DWORD cb )
{
return cb / ((DWORD)2);
}
INLINE DWORD pcmS08BytesToSamples( DWORD cb )
{
return cb / ((DWORD)2);
}
INLINE DWORD pcmS16BytesToSamples( DWORD cb )
{
return cb / ((DWORD)4);
}
//--------------------------------------------------------------------------;
//
// int pcmRead08
// int pcmRead16
// int pcmRead16Unaligned
//
// Description:
// These functions read an 8 or 16 bit PCM value from the specified
// buffer. Note that the buffers are either HUGE or UNALIGNED in all
// cases. However, if a single 16-bit value crosses a segment boundary
// in Win16, then pcmRead16 will wrap around; use pcmRead16Unaligned
// instead.
//
// Arguments:
// HPBYTE pb: Pointer to the input buffer.
//
// Return (int): The PCM value converted to 16-bit format.
//
//--------------------------------------------------------------------------;
INLINE int pcmRead08( HPBYTE pb )
{
return ( (int)*pb - 128 ) << 8;
}
INLINE int pcmRead16( HPBYTE pb )
{
return (int)*(short HUGE_T *)pb;
}
#ifdef WIN32
#define pcmRead16Unaligned pcmRead16
#else
INLINE int pcmRead16Unaligned( HPBYTE pb )
{
return (int)(short)( ((WORD)*pb) | (((WORD)*(pb+1))<<8) );
}
#endif
//--------------------------------------------------------------------------;
//
// void pcmWrite08
// void pcmWrite16
// void pcmWrite16Unaligned
//
// Description:
// These functions write a PCM sample (a 16-bit integer) into the
// specified buffer in the appropriate format. Note that the buffers
// are either HUGE or UNALIGNED. However, if a single 16-bit value is
// written across a segment boundary, then pcmWrite16 will not handle
// it correctly; us pcmWrite16Unaligned instead.
//
// Arguments:
// HPBYTE pb: Pointer to the output buffer.
// int iSamp: The sample.
//
// Return (int): The PCM value converted to 16-bit format.
//
//--------------------------------------------------------------------------;
INLINE void pcmWrite08( HPBYTE pb, int iSamp )
{
*pb = (BYTE)((iSamp >> 8) + 128);
}
INLINE void pcmWrite16( HPBYTE pb, int iSamp )
{
*(short HUGE_T *)pb = (short)iSamp;
}
#ifdef WIN32
#define pcmWrite16Unaligned pcmWrite16
#else
INLINE void pcmWrite16Unaligned( HPBYTE pb, int iSamp )
{
*pb = (BYTE)( iSamp&0x00FF );
*(pb+1) = (BYTE)( iSamp>>8 );
}
#endif
//--------------------------------------------------------------------------;
//
// int adpcmCalcDelta
//
// Description:
// This function computes the next Adaptive Scale Factor (ASF) value
// based on the the current ASF and the current encoded sample.
//
// Arguments:
// int iEnc: The current encoded sample (as a signed integer).
// int iDelta: The current ASF.
//
// Return (int): The next ASF.
//
//--------------------------------------------------------------------------;
INLINE int adpcmCalcDelta
(
int iEnc,
int iDelta
)
{
int iNewDelta;
iNewDelta = (int)((gaiP4[iEnc&OUTPUT4MASK] * (long)iDelta) >> PSCALE);
if( iNewDelta < DELTA4MIN )
iNewDelta = DELTA4MIN;
return iNewDelta;
}
//--------------------------------------------------------------------------;
//
// long adpcmCalcPrediction
//
// Description:
// This function calculates the predicted sample value based on the
// previous two samples and the current coefficients.
//
// Arguments:
// int iSamp1: The previous decoded sample.
// int iCoef1: The coefficient for iSamp1.
// int iSamp2: The decoded sample before iSamp1.
// int iCoef2: The coefficient for iSamp2.
//
// Return (long): The predicted sample.
//
//--------------------------------------------------------------------------;
INLINE long adpcmCalcPrediction
(
int iSamp1,
int iCoef1,
int iSamp2,
int iCoef2
)
{
return ((long)iSamp1 * iCoef1 + (long)iSamp2 * iCoef2) >> CSCALE;
}
//--------------------------------------------------------------------------;
//
// int adpcmDecodeSample
//
// Description:
// This function decodes a single 4-bit encoded ADPCM sample. There
// are three steps:
//
// 1. Sign-extend the 4-bit iInput.
//
// 2. predict the next sample using the previous two
// samples and the predictor coefficients:
//
// Prediction = (iSamp1 * aiCoef1 + iSamp2 * iCoef2) / 256;
//
// 3. 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 * iDelta) + Prediction;
//
// Arguments:
// int iSamp1: The previous decoded sample.
// int iCoef1: The coefficient for iSamp1.
// int iSamp2: The decoded sample before iSamp1.
// int iCoef2: The coefficient for iSamp2.
// int iInput: The current encoded sample (lower 4 bits).
// int iDelta: The current ASF.
//
// Return (int): The decoded sample.
//
//--------------------------------------------------------------------------;
INLINE int adpcmDecodeSample
(
int iSamp1,
int iCoef1,
int iSamp2,
int iCoef2,
int iInput,
int iDelta
)
{
long lSamp;
iInput = (int)( ((signed char)(iInput<<4)) >> 4 );
lSamp = ((long)iInput * iDelta) +
adpcmCalcPrediction(iSamp1,iCoef1,iSamp2,iCoef2);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
return (int)lSamp;
}
//--------------------------------------------------------------------------;
//
// int adpcmEncode4Bit_FirstDelta
//
// Description:
//
//
// Arguments:
//
//
// Return (short FNLOCAL):
//
//
// History:
// 1/27/93 cjp [curtisp]
//
//--------------------------------------------------------------------------;
INLINE int FNLOCAL adpcmEncode4Bit_FirstDelta
(
int iCoef1,
int iCoef2,
int iP5,
int iP4,
int iP3,
int iP2,
int iP1
)
{
long lTotal;
int iRtn;
long lTemp;
//
// use average of 3 predictions
//
lTemp = (((long)iP5 * iCoef2) + ((long)iP4 * iCoef1)) >> CSCALE;
lTotal = (lTemp > iP3) ? (lTemp - iP3) : (iP3 - lTemp);
lTemp = (((long)iP4 * iCoef2) + ((long)iP3 * iCoef1)) >> CSCALE;
lTotal += (lTemp > iP2) ? (lTemp - iP2) : (iP2 - lTemp);
lTemp = (((long)iP3 * iCoef2) + ((long)iP2 * iCoef1)) >> CSCALE;
lTotal += (lTemp > iP1) ? (lTemp - iP1) : (iP1 - lTemp);
//
// optimal iDelta is 1/4 of prediction error
//
iRtn = (int)(lTotal / 12);
if (iRtn < DELTA4MIN)
iRtn = DELTA4MIN;
return (iRtn);
} // adpcmEncode4Bit_FirstDelta()
//==========================================================================;
//
// NON-REALTIME ENCODE ROUTINES
//
//==========================================================================;
//--------------------------------------------------------------------------;
//
// DWORD adpcmEncode4Bit_M08_FullPass
// DWORD adpcmEncode4Bit_M16_FullPass
// DWORD adpcmEncode4Bit_S08_FullPass
// DWORD adpcmEncode4Bit_S16_FullPass
//
// Description:
// These functions encode a buffer of data from PCM to MS ADPCM in the
// specified format. These functions use a fullpass algorithm which
// tries each set of coefficients in order to determine which set
// produces the smallest coding error. The appropriate function is
// called once for each ACMDM_STREAM_CONVERT message received.
//
//
// Arguments:
//
//
// Return (DWORD): The number of bytes used in the destination buffer.
//
//--------------------------------------------------------------------------;
#define ENCODE_DELTA_LOOKAHEAD 5
DWORD FNGLOBAL adpcmEncode4Bit_M08_FullPass
(
HPBYTE pbSrc,
DWORD cbSrcLength,
HPBYTE pbDst,
UINT nBlockAlignment,
UINT cSamplesPerBlock,
UINT nNumCoef,
LPADPCMCOEFSET lpCoefSet
)
{
HPBYTE pbDstStart;
HPBYTE pbSrcThisBlock;
DWORD cSrcSamples;
UINT cBlockSamples;
int aiSamples[ENCODE_DELTA_LOOKAHEAD];
int aiFirstDelta[MSADPCM_MAX_COEFFICIENTS];
DWORD adwTotalError[MSADPCM_MAX_COEFFICIENTS];
int iCoef1;
int iCoef2;
int iSamp1;
int iSamp2;
int iDelta;
int iOutput1;
int iOutput2;
int iBestPredictor;
int iSample;
long lSamp;
long lError;
long lPrediction;
DWORD dw;
UINT i,n;
pbDstStart = pbDst;
cSrcSamples = pcmM08BytesToSamples(cbSrcLength);
//
// step through each block of PCM data and encode it to 4 bit ADPCM
//
while( 0 != cSrcSamples )
{
//
// determine how much data we should encode for this block--this
// will be cSamplesPerBlock 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...
//
cBlockSamples = (UINT)min(cSrcSamples, cSamplesPerBlock);
cSrcSamples -= cBlockSamples;
//
// We need the first ENCODE_DELTA_LOOKAHEAD samples in order to
// calculate the first iDelta value. Therefore we put these samples
// into a more accessible array: aiSamples[]. Note: if we don't
// have ENCODE_DELTA_LOOKAHEAD samples, we pretend that the samples
// that we don't have are actually zeros. This is important not
// only for the iDelta calculation, but also for the case where
// there is only 1 sample to encode ... in this case, there is not
// really enough data to complete the ADPCM block header, but since
// the two delay samples for the block header will be taken from
// the aiSamples[] array, iSamp1 [the second sample] will be taken
// as zero and there will no problem.
//
pbSrcThisBlock = pbSrc;
for (n = 0; n < ENCODE_DELTA_LOOKAHEAD; n++)
{
if( n < cBlockSamples )
aiSamples[n] = pcmRead08(pbSrcThisBlock++);
else
aiSamples[n] = 0;
}
//
// 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; i < MSADPCM_MAX_COEFFICIENTS; i++)
{
//
// Reset source pointer to the beginning of the block.
//
pbSrcThisBlock = pbSrc;
//
// Reset variables for this pass.
//
adwTotalError[i] = 0L;
iCoef1 = lpCoefSet[i].iCoef1;
iCoef2 = lpCoefSet[i].iCoef2;
//
// We need to choose the first iDelta--to do this, we need
// to look at the first few samples.
//
iDelta = adpcmEncode4Bit_FirstDelta(iCoef1, iCoef2,
aiSamples[0], aiSamples[1], aiSamples[2],
aiSamples[3], aiSamples[4]);
aiFirstDelta[i] = iDelta;
//
// Set up first two samples - these have already been converted
// to 16-bit values in aiSamples[], but make sure to increment
// pbSrcThisBlock so that it keeps in sync.
//
iSamp1 = aiSamples[1];
iSamp2 = aiSamples[0];
pbSrcThisBlock += 2*sizeof(BYTE);
//
// 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; n < cBlockSamples; n++)
{
//
// calculate the prediction based on the previous two
// samples
//
lPrediction = adpcmCalcPrediction( iSamp1, iCoef1,
iSamp2, iCoef2 );
//
// Grab the next sample to encode.
//
iSample = pcmRead08(pbSrcThisBlock++);
//
// encode it
//
lError = (long)iSample - lPrediction;
iOutput1 = (int)(lError / iDelta);
if (iOutput1 > OUTPUT4MAX)
iOutput1 = OUTPUT4MAX;
else if (iOutput1 < OUTPUT4MIN)
iOutput1 = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDelta * iOutput1);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDelta = adpcmCalcDelta(iOutput1,iDelta);
//
// Save updated delay samples.
//
iSamp2 = iSamp1;
iSamp1 = (int)lSamp;
//
// keep a running status on the error for the current
// coefficient pair for this channel
//
lError = lSamp - iSample;
adwTotalError[i] += (lError * lError) >> 7;
}
}
//
// 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.
//
iBestPredictor = 0;
dw = adwTotalError[0];
for (i = 1; i < MSADPCM_MAX_COEFFICIENTS; i++)
{
if (adwTotalError[i] < dw)
{
iBestPredictor = i;
dw = adwTotalError[i];
}
}
iCoef1 = lpCoefSet[iBestPredictor].iCoef1;
iCoef2 = lpCoefSet[iBestPredictor].iCoef2;
//
// grab first iDelta from our precomputed first deltas that we
// calculated above
//
iDelta = aiFirstDelta[iBestPredictor];
//
// Set up first two samples - these have already been converted
// to 16-bit values in aiSamples[], but make sure to increment
// pbSrc so that it keeps in sync.
//
iSamp1 = aiSamples[1];
iSamp2 = aiSamples[0];
pbSrc += 2*sizeof(BYTE);
ASSERT( cBlockSamples != 1 );
cBlockSamples -= 2;
//
// write the block header for the encoded data
//
// the block header is composed of the following data:
// 1 byte predictor per channel
// 2 byte delta per channel
// 2 byte first delayed sample per channel
// 2 byte second delayed sample per channel
//
*pbDst++ = (BYTE)iBestPredictor;
pcmWrite16Unaligned(pbDst,iDelta);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp1);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp2);
pbDst += sizeof(short);
//
// We have written the header for this block--now write the data
// chunk (which consists of a bunch of encoded nibbles).
//
while( cBlockSamples>0 )
{
//
// Sample 1.
//
iSample = pcmRead08(pbSrc++);
cBlockSamples--;
//
// calculate the prediction based on the previous two samples
//
lPrediction = adpcmCalcPrediction(iSamp1,iCoef1,iSamp2,iCoef2);
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutput1 = (int)(lError / iDelta);
if (iOutput1 > OUTPUT4MAX)
iOutput1 = OUTPUT4MAX;
else if (iOutput1 < OUTPUT4MIN)
iOutput1 = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDelta * iOutput1);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDelta = adpcmCalcDelta(iOutput1,iDelta);
//
// Save updated delay samples.
//
iSamp2 = iSamp1;
iSamp1 = (int)lSamp;
//
// Sample 2.
//
if( cBlockSamples>0 ) {
iSample = pcmRead08(pbSrc++);
cBlockSamples--;
//
// calculate the prediction based on the previous two samples
//
lPrediction = adpcmCalcPrediction(iSamp1,iCoef1,iSamp2,iCoef2);
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutput2 = (int)(lError / iDelta);
if (iOutput2 > OUTPUT4MAX)
iOutput2 = OUTPUT4MAX;
else if (iOutput2 < OUTPUT4MIN)
iOutput2 = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDelta * iOutput2);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDelta = adpcmCalcDelta(iOutput2,iDelta);
//
// Save updated delay samples.
//
iSamp2 = iSamp1;
iSamp1 = (int)lSamp;
} else {
iOutput2 = 0;
}
//
// Write out the encoded byte.
//
*pbDst++ = (BYTE)( ((iOutput1&OUTPUT4MASK)<<4) |
(iOutput2&OUTPUT4MASK) );
}
}
//
// We return the number of bytes used in the destination. This is
// simply the difference in bytes from where we started.
//
return (DWORD)(pbDst - pbDstStart);
} // adpcmEncode4Bit_M08_FullPass()
//--------------------------------------------------------------------------;
//--------------------------------------------------------------------------;
DWORD FNGLOBAL adpcmEncode4Bit_M16_FullPass
(
HPBYTE pbSrc,
DWORD cbSrcLength,
HPBYTE pbDst,
UINT nBlockAlignment,
UINT cSamplesPerBlock,
UINT nNumCoef,
LPADPCMCOEFSET lpCoefSet
)
{
HPBYTE pbDstStart;
HPBYTE pbSrcThisBlock;
DWORD cSrcSamples;
UINT cBlockSamples;
int aiSamples[ENCODE_DELTA_LOOKAHEAD];
int aiFirstDelta[MSADPCM_MAX_COEFFICIENTS];
DWORD adwTotalError[MSADPCM_MAX_COEFFICIENTS];
int iCoef1;
int iCoef2;
int iSamp1;
int iSamp2;
int iDelta;
int iOutput1;
int iOutput2;
int iBestPredictor;
int iSample;
long lSamp;
long lError;
long lPrediction;
DWORD dw;
UINT i,n;
pbDstStart = pbDst;
cSrcSamples = pcmM16BytesToSamples(cbSrcLength);
//
// step through each block of PCM data and encode it to 4 bit ADPCM
//
while( 0 != cSrcSamples )
{
//
// determine how much data we should encode for this block--this
// will be cSamplesPerBlock 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...
//
cBlockSamples = (UINT)min(cSrcSamples, cSamplesPerBlock);
cSrcSamples -= cBlockSamples;
//
// We need the first ENCODE_DELTA_LOOKAHEAD samples in order to
// calculate the first iDelta value. Therefore we put these samples
// into a more accessible array: aiSamples[]. Note: if we don't
// have ENCODE_DELTA_LOOKAHEAD samples, we pretend that the samples
// that we don't have are actually zeros. This is important not
// only for the iDelta calculation, but also for the case where
// there is only 1 sample to encode ... in this case, there is not
// really enough data to complete the ADPCM block header, but since
// the two delay samples for the block header will be taken from
// the aiSamples[] array, iSamp1 [the second sample] will be taken
// as zero and there will no problem.
//
pbSrcThisBlock = pbSrc;
for (n = 0; n < ENCODE_DELTA_LOOKAHEAD; n++)
{
if( n < cBlockSamples )
{
aiSamples[n] = pcmRead16(pbSrcThisBlock);
pbSrcThisBlock += sizeof(short);
}
else
aiSamples[n] = 0;
}
//
// 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; i < MSADPCM_MAX_COEFFICIENTS; i++)
{
//
// Reset source pointer to the beginning of the block.
//
pbSrcThisBlock = pbSrc;
//
// Reset variables for this pass.
//
adwTotalError[i] = 0L;
iCoef1 = lpCoefSet[i].iCoef1;
iCoef2 = lpCoefSet[i].iCoef2;
//
// We need to choose the first iDelta--to do this, we need
// to look at the first few samples.
//
iDelta = adpcmEncode4Bit_FirstDelta(iCoef1, iCoef2,
aiSamples[0], aiSamples[1], aiSamples[2],
aiSamples[3], aiSamples[4]);
aiFirstDelta[i] = iDelta;
//
// Set up first two samples - these have already been converted
// to 16-bit values in aiSamples[], but make sure to increment
// pbSrcThisBlock so that it keeps in sync.
//
iSamp1 = aiSamples[1];
iSamp2 = aiSamples[0];
pbSrcThisBlock += 2*sizeof(short);
//
// 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; n < cBlockSamples; n++)
{
//
// calculate the prediction based on the previous two
// samples
//
lPrediction = adpcmCalcPrediction( iSamp1, iCoef1,
iSamp2, iCoef2 );
//
// Grab the next sample to encode.
//
iSample = pcmRead16(pbSrcThisBlock);
pbSrcThisBlock += sizeof(short);
//
// encode it
//
lError = (long)iSample - lPrediction;
iOutput1 = (int)(lError / iDelta);
if (iOutput1 > OUTPUT4MAX)
iOutput1 = OUTPUT4MAX;
else if (iOutput1 < OUTPUT4MIN)
iOutput1 = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDelta * iOutput1);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDelta = adpcmCalcDelta(iOutput1,iDelta);
//
// Save updated delay samples.
//
iSamp2 = iSamp1;
iSamp1 = (int)lSamp;
//
// keep a running status on the error for the current
// coefficient pair for this channel
//
lError = lSamp - iSample;
adwTotalError[i] += (lError * lError) >> 7;
}
}
//
// 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.
//
iBestPredictor = 0;
dw = adwTotalError[0];
for (i = 1; i < MSADPCM_MAX_COEFFICIENTS; i++)
{
if (adwTotalError[i] < dw)
{
iBestPredictor = i;
dw = adwTotalError[i];
}
}
iCoef1 = lpCoefSet[iBestPredictor].iCoef1;
iCoef2 = lpCoefSet[iBestPredictor].iCoef2;
//
// grab first iDelta from our precomputed first deltas that we
// calculated above
//
iDelta = aiFirstDelta[iBestPredictor];
//
// Set up first two samples - these have already been converted
// to 16-bit values in aiSamples[], but make sure to increment
// pbSrc so that it keeps in sync.
//
iSamp1 = aiSamples[1];
iSamp2 = aiSamples[0];
pbSrc += 2*sizeof(short);
ASSERT( cBlockSamples != 1 );
cBlockSamples -= 2;
//
// write the block header for the encoded data
//
// the block header is composed of the following data:
// 1 byte predictor per channel
// 2 byte delta per channel
// 2 byte first delayed sample per channel
// 2 byte second delayed sample per channel
//
*pbDst++ = (BYTE)iBestPredictor;
pcmWrite16Unaligned(pbDst,iDelta);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp1);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp2);
pbDst += sizeof(short);
//
// We have written the header for this block--now write the data
// chunk (which consists of a bunch of encoded nibbles).
//
while( cBlockSamples>0 )
{
//
// Sample 1.
//
iSample = pcmRead16(pbSrc);
pbSrc += sizeof(short);
cBlockSamples--;
//
// calculate the prediction based on the previous two samples
//
lPrediction = adpcmCalcPrediction(iSamp1,iCoef1,iSamp2,iCoef2);
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutput1 = (int)(lError / iDelta);
if (iOutput1 > OUTPUT4MAX)
iOutput1 = OUTPUT4MAX;
else if (iOutput1 < OUTPUT4MIN)
iOutput1 = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDelta * iOutput1);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDelta = adpcmCalcDelta(iOutput1,iDelta);
//
// Save updated delay samples.
//
iSamp2 = iSamp1;
iSamp1 = (int)lSamp;
//
// Sample 2.
//
if( cBlockSamples>0 ) {
iSample = pcmRead16(pbSrc);
pbSrc += sizeof(short);
cBlockSamples--;
//
// calculate the prediction based on the previous two samples
//
lPrediction = adpcmCalcPrediction(iSamp1,iCoef1,iSamp2,iCoef2);
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutput2 = (int)(lError / iDelta);
if (iOutput2 > OUTPUT4MAX)
iOutput2 = OUTPUT4MAX;
else if (iOutput2 < OUTPUT4MIN)
iOutput2 = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDelta * iOutput2);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDelta = adpcmCalcDelta(iOutput2,iDelta);
//
// Save updated delay samples.
//
iSamp2 = iSamp1;
iSamp1 = (int)lSamp;
} else {
iOutput2 = 0;
}
//
// Write out the encoded byte.
//
*pbDst++ = (BYTE)( ((iOutput1&OUTPUT4MASK)<<4) |
(iOutput2&OUTPUT4MASK) );
}
}
//
// We return the number of bytes used in the destination. This is
// simply the difference in bytes from where we started.
//
return (DWORD)(pbDst - pbDstStart);
} // adpcmEncode4Bit_M16_FullPass()
//--------------------------------------------------------------------------;
//--------------------------------------------------------------------------;
DWORD FNGLOBAL adpcmEncode4Bit_S08_FullPass
(
HPBYTE pbSrc,
DWORD cbSrcLength,
HPBYTE pbDst,
UINT nBlockAlignment,
UINT cSamplesPerBlock,
UINT nNumCoef,
LPADPCMCOEFSET lpCoefSet
)
{
HPBYTE pbDstStart;
HPBYTE pbSrcThisBlock;
DWORD cSrcSamples;
UINT cBlockSamples;
int aiSamplesL[ENCODE_DELTA_LOOKAHEAD];
int aiSamplesR[ENCODE_DELTA_LOOKAHEAD];
int aiFirstDeltaL[MSADPCM_MAX_COEFFICIENTS];
int aiFirstDeltaR[MSADPCM_MAX_COEFFICIENTS];
DWORD adwTotalErrorL[MSADPCM_MAX_COEFFICIENTS];
DWORD adwTotalErrorR[MSADPCM_MAX_COEFFICIENTS];
int iCoef1;
int iCoef2;
int iCoef1L;
int iCoef2L;
int iSamp1L;
int iSamp2L;
int iDeltaL;
int iOutputL;
int iBestPredictorL;
int iCoef1R;
int iCoef2R;
int iSamp1R;
int iSamp2R;
int iDeltaR;
int iOutputR;
int iBestPredictorR;
int iSample;
long lSamp;
long lError;
long lPrediction;
DWORD dwL, dwR;
UINT i,n;
pbDstStart = pbDst;
cSrcSamples = pcmS08BytesToSamples(cbSrcLength);
//
// step through each block of PCM data and encode it to 4 bit ADPCM
//
while( 0 != cSrcSamples )
{
//
// determine how much data we should encode for this block--this
// will be cSamplesPerBlock 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...
//
cBlockSamples = (UINT)min(cSrcSamples, cSamplesPerBlock);
cSrcSamples -= cBlockSamples;
//
// We need the first ENCODE_DELTA_LOOKAHEAD samples in order to
// calculate the first iDelta value. Therefore we put these samples
// into a more accessible array: aiSamples[]. Note: if we don't
// have ENCODE_DELTA_LOOKAHEAD samples, we pretend that the samples
// that we don't have are actually zeros. This is important not
// only for the iDelta calculation, but also for the case where
// there is only 1 sample to encode ... in this case, there is not
// really enough data to complete the ADPCM block header, but since
// the two delay samples for the block header will be taken from
// the aiSamples[] array, iSamp1 [the second sample] will be taken
// as zero and there will no problem.
//
pbSrcThisBlock = pbSrc;
for (n = 0; n < ENCODE_DELTA_LOOKAHEAD; n++)
{
if( n < cBlockSamples )
{
aiSamplesL[n] = pcmRead08(pbSrcThisBlock++);
aiSamplesR[n] = pcmRead08(pbSrcThisBlock++);
}
else
{
aiSamplesL[n] = 0;
aiSamplesR[n] = 0;
}
}
//
// 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; i < MSADPCM_MAX_COEFFICIENTS; i++)
{
//
// Reset source pointer to the beginning of the block.
//
pbSrcThisBlock = pbSrc;
//
// Reset variables for this pass (coefs are the same for L, R).
//
adwTotalErrorL[i] = 0L;
adwTotalErrorR[i] = 0L;
iCoef1 = lpCoefSet[i].iCoef1;
iCoef2 = lpCoefSet[i].iCoef2;
//
// We need to choose the first iDelta--to do this, we need
// to look at the first few samples.
//
iDeltaL = adpcmEncode4Bit_FirstDelta(iCoef1, iCoef2,
aiSamplesL[0], aiSamplesL[1], aiSamplesL[2],
aiSamplesL[3], aiSamplesL[4]);
iDeltaR = adpcmEncode4Bit_FirstDelta(iCoef1, iCoef2,
aiSamplesR[0], aiSamplesR[1], aiSamplesR[2],
aiSamplesR[3], aiSamplesR[4]);
aiFirstDeltaL[i] = iDeltaL;
aiFirstDeltaR[i] = iDeltaR;
//
// Set up first two samples - these have already been converted
// to 16-bit values in aiSamples[], but make sure to increment
// pbSrcThisBlock so that it keeps in sync.
//
iSamp1L = aiSamplesL[1];
iSamp1R = aiSamplesR[1];
iSamp2L = aiSamplesL[0];
iSamp2R = aiSamplesR[0];
pbSrcThisBlock += 2*sizeof(BYTE) * 2; // Last 2 = # of channels.
//
// 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; n < cBlockSamples; n++)
{
//
// LEFT channel.
//
//
// calculate the prediction based on the previous two
// samples
//
lPrediction = adpcmCalcPrediction( iSamp1L, iCoef1,
iSamp2L, iCoef2 );
//
// Grab the next sample to encode.
//
iSample = pcmRead08(pbSrcThisBlock++);
//
// encode it
//
lError = (long)iSample - lPrediction;
iOutputL = (int)(lError / iDeltaL);
if (iOutputL > OUTPUT4MAX)
iOutputL = OUTPUT4MAX;
else if (iOutputL < OUTPUT4MIN)
iOutputL = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDeltaL * iOutputL);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDeltaL = adpcmCalcDelta(iOutputL,iDeltaL);
//
// Save updated delay samples.
//
iSamp2L = iSamp1L;
iSamp1L = (int)lSamp;
//
// keep a running status on the error for the current
// coefficient pair for this channel
//
lError = lSamp - iSample;
adwTotalErrorL[i] += (lError * lError) >> 7;
//
// RIGHT channel.
//
//
// calculate the prediction based on the previous two
// samples
//
lPrediction = adpcmCalcPrediction( iSamp1R, iCoef1,
iSamp2R, iCoef2 );
//
// Grab the next sample to encode.
//
iSample = pcmRead08(pbSrcThisBlock++);
//
// encode it
//
lError = (long)iSample - lPrediction;
iOutputR = (int)(lError / iDeltaR);
if (iOutputR > OUTPUT4MAX)
iOutputR = OUTPUT4MAX;
else if (iOutputR < OUTPUT4MIN)
iOutputR = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDeltaR * iOutputR);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDeltaR = adpcmCalcDelta(iOutputR,iDeltaR);
//
// Save updated delay samples.
//
iSamp2R = iSamp1R;
iSamp1R = (int)lSamp;
//
// keep a running status on the error for the current
// coefficient pair for this channel
//
lError = lSamp - iSample;
adwTotalErrorR[i] += (lError * lError) >> 7;
}
}
//
// 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.
//
iBestPredictorL = 0;
iBestPredictorR = 0;
dwL = adwTotalErrorL[0];
dwR = adwTotalErrorR[0];
for (i = 1; i < MSADPCM_MAX_COEFFICIENTS; i++)
{
if (adwTotalErrorL[i] < dwL)
{
iBestPredictorL = i;
dwL = adwTotalErrorL[i];
}
if (adwTotalErrorR[i] < dwR)
{
iBestPredictorR = i;
dwR = adwTotalErrorR[i];
}
}
iCoef1L = lpCoefSet[iBestPredictorL].iCoef1;
iCoef1R = lpCoefSet[iBestPredictorR].iCoef1;
iCoef2L = lpCoefSet[iBestPredictorL].iCoef2;
iCoef2R = lpCoefSet[iBestPredictorR].iCoef2;
//
// grab first iDelta from our precomputed first deltas that we
// calculated above
//
iDeltaL = aiFirstDeltaL[iBestPredictorL];
iDeltaR = aiFirstDeltaR[iBestPredictorR];
//
// Set up first two samples - these have already been converted
// to 16-bit values in aiSamples[], but make sure to increment
// pbSrc so that it keeps in sync.
//
iSamp1L = aiSamplesL[1];
iSamp1R = aiSamplesR[1];
iSamp2L = aiSamplesL[0];
iSamp2R = aiSamplesR[0];
pbSrc += 2*sizeof(BYTE) * 2; // Last 2 = # of channels.
ASSERT( cBlockSamples != 1 );
cBlockSamples -= 2;
//
// write the block header for the encoded data
//
// the block header is composed of the following data:
// 1 byte predictor per channel
// 2 byte delta per channel
// 2 byte first delayed sample per channel
// 2 byte second delayed sample per channel
//
*pbDst++ = (BYTE)iBestPredictorL;
*pbDst++ = (BYTE)iBestPredictorR;
pcmWrite16Unaligned(pbDst,iDeltaL);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iDeltaR);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp1L);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp1R);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp2L);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp2R);
pbDst += sizeof(short);
//
// We have written the header for this block--now write the data
// chunk (which consists of a bunch of encoded nibbles).
//
while( cBlockSamples-- )
{
//
// LEFT channel.
//
iSample = pcmRead08(pbSrc++);
//
// calculate the prediction based on the previous two samples
//
lPrediction = adpcmCalcPrediction(iSamp1L,iCoef1L,iSamp2L,iCoef2L);
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutputL = (int)(lError / iDeltaL);
if (iOutputL > OUTPUT4MAX)
iOutputL = OUTPUT4MAX;
else if (iOutputL < OUTPUT4MIN)
iOutputL = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDeltaL * iOutputL);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDeltaL = adpcmCalcDelta(iOutputL,iDeltaL);
//
// Save updated delay samples.
//
iSamp2L = iSamp1L;
iSamp1L = (int)lSamp;
//
// RIGHT channel.
//
iSample = pcmRead08(pbSrc++);
//
// calculate the prediction based on the previous two samples
//
lPrediction = adpcmCalcPrediction(iSamp1R,iCoef1R,iSamp2R,iCoef2R);
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutputR = (int)(lError / iDeltaR);
if (iOutputR > OUTPUT4MAX)
iOutputR = OUTPUT4MAX;
else if (iOutputR < OUTPUT4MIN)
iOutputR = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDeltaR * iOutputR);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDeltaR = adpcmCalcDelta(iOutputR,iDeltaR);
//
// Save updated delay samples.
//
iSamp2R = iSamp1R;
iSamp1R = (int)lSamp;
//
// Write out the encoded byte.
//
*pbDst++ = (BYTE)( ((iOutputL&OUTPUT4MASK)<<4) |
(iOutputR&OUTPUT4MASK) );
}
}
//
// We return the number of bytes used in the destination. This is
// simply the difference in bytes from where we started.
//
return (DWORD)(pbDst - pbDstStart);
} // adpcmEncode4Bit_S08_FullPass()
//--------------------------------------------------------------------------;
//--------------------------------------------------------------------------;
DWORD FNGLOBAL adpcmEncode4Bit_S16_FullPass
(
HPBYTE pbSrc,
DWORD cbSrcLength,
HPBYTE pbDst,
UINT nBlockAlignment,
UINT cSamplesPerBlock,
UINT nNumCoef,
LPADPCMCOEFSET lpCoefSet
)
{
HPBYTE pbDstStart;
HPBYTE pbSrcThisBlock;
DWORD cSrcSamples;
UINT cBlockSamples;
int aiSamplesL[ENCODE_DELTA_LOOKAHEAD];
int aiSamplesR[ENCODE_DELTA_LOOKAHEAD];
int aiFirstDeltaL[MSADPCM_MAX_COEFFICIENTS];
int aiFirstDeltaR[MSADPCM_MAX_COEFFICIENTS];
DWORD adwTotalErrorL[MSADPCM_MAX_COEFFICIENTS];
DWORD adwTotalErrorR[MSADPCM_MAX_COEFFICIENTS];
int iCoef1;
int iCoef2;
int iCoef1L;
int iCoef2L;
int iSamp1L;
int iSamp2L;
int iDeltaL;
int iOutputL;
int iBestPredictorL;
int iCoef1R;
int iCoef2R;
int iSamp1R;
int iSamp2R;
int iDeltaR;
int iOutputR;
int iBestPredictorR;
int iSample;
long lSamp;
long lError;
long lPrediction;
DWORD dwL, dwR;
UINT i,n;
pbDstStart = pbDst;
cSrcSamples = pcmS16BytesToSamples(cbSrcLength);
//
// step through each block of PCM data and encode it to 4 bit ADPCM
//
while( 0 != cSrcSamples )
{
//
// determine how much data we should encode for this block--this
// will be cSamplesPerBlock 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...
//
cBlockSamples = (UINT)min(cSrcSamples, cSamplesPerBlock);
cSrcSamples -= cBlockSamples;
//
// We need the first ENCODE_DELTA_LOOKAHEAD samples in order to
// calculate the first iDelta value. Therefore we put these samples
// into a more accessible array: aiSamples[]. Note: if we don't
// have ENCODE_DELTA_LOOKAHEAD samples, we pretend that the samples
// that we don't have are actually zeros. This is important not
// only for the iDelta calculation, but also for the case where
// there is only 1 sample to encode ... in this case, there is not
// really enough data to complete the ADPCM block header, but since
// the two delay samples for the block header will be taken from
// the aiSamples[] array, iSamp1 [the second sample] will be taken
// as zero and there will no problem.
//
pbSrcThisBlock = pbSrc;
for (n = 0; n < ENCODE_DELTA_LOOKAHEAD; n++)
{
if( n < cBlockSamples )
{
aiSamplesL[n] = pcmRead16(pbSrcThisBlock);
pbSrcThisBlock += sizeof(short);
aiSamplesR[n] = pcmRead16(pbSrcThisBlock);
pbSrcThisBlock += sizeof(short);
}
else
{
aiSamplesL[n] = 0;
aiSamplesR[n] = 0;
}
}
//
// 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; i < MSADPCM_MAX_COEFFICIENTS; i++)
{
//
// Reset source pointer to the beginning of the block.
//
pbSrcThisBlock = pbSrc;
//
// Reset variables for this pass (coefs are the same for L, R).
//
adwTotalErrorL[i] = 0L;
adwTotalErrorR[i] = 0L;
iCoef1 = lpCoefSet[i].iCoef1;
iCoef2 = lpCoefSet[i].iCoef2;
//
// We need to choose the first iDelta--to do this, we need
// to look at the first few samples.
//
iDeltaL = adpcmEncode4Bit_FirstDelta(iCoef1, iCoef2,
aiSamplesL[0], aiSamplesL[1], aiSamplesL[2],
aiSamplesL[3], aiSamplesL[4]);
iDeltaR = adpcmEncode4Bit_FirstDelta(iCoef1, iCoef2,
aiSamplesR[0], aiSamplesR[1], aiSamplesR[2],
aiSamplesR[3], aiSamplesR[4]);
aiFirstDeltaL[i] = iDeltaL;
aiFirstDeltaR[i] = iDeltaR;
//
// Set up first two samples - these have already been converted
// to 16-bit values in aiSamples[], but make sure to increment
// pbSrcThisBlock so that it keeps in sync.
//
iSamp1L = aiSamplesL[1];
iSamp1R = aiSamplesR[1];
iSamp2L = aiSamplesL[0];
iSamp2R = aiSamplesR[0];
pbSrcThisBlock += 2*sizeof(short) * 2; // Last 2 = # of channels.
//
// 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; n < cBlockSamples; n++)
{
//
// LEFT channel.
//
//
// calculate the prediction based on the previous two
// samples
//
lPrediction = adpcmCalcPrediction( iSamp1L, iCoef1,
iSamp2L, iCoef2 );
//
// Grab the next sample to encode.
//
iSample = pcmRead16(pbSrcThisBlock);
pbSrcThisBlock += sizeof(short);
//
// encode it
//
lError = (long)iSample - lPrediction;
iOutputL = (int)(lError / iDeltaL);
if (iOutputL > OUTPUT4MAX)
iOutputL = OUTPUT4MAX;
else if (iOutputL < OUTPUT4MIN)
iOutputL = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDeltaL * iOutputL);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDeltaL = adpcmCalcDelta(iOutputL,iDeltaL);
//
// Save updated delay samples.
//
iSamp2L = iSamp1L;
iSamp1L = (int)lSamp;
//
// keep a running status on the error for the current
// coefficient pair for this channel
//
lError = lSamp - iSample;
adwTotalErrorL[i] += (lError * lError) >> 7;
//
// RIGHT channel.
//
//
// calculate the prediction based on the previous two
// samples
//
lPrediction = adpcmCalcPrediction( iSamp1R, iCoef1,
iSamp2R, iCoef2 );
//
// Grab the next sample to encode.
//
iSample = pcmRead16(pbSrcThisBlock);
pbSrcThisBlock += sizeof(short);
//
// encode it
//
lError = (long)iSample - lPrediction;
iOutputR = (int)(lError / iDeltaR);
if (iOutputR > OUTPUT4MAX)
iOutputR = OUTPUT4MAX;
else if (iOutputR < OUTPUT4MIN)
iOutputR = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDeltaR * iOutputR);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDeltaR = adpcmCalcDelta(iOutputR,iDeltaR);
//
// Save updated delay samples.
//
iSamp2R = iSamp1R;
iSamp1R = (int)lSamp;
//
// keep a running status on the error for the current
// coefficient pair for this channel
//
lError = lSamp - iSample;
adwTotalErrorR[i] += (lError * lError) >> 7;
}
}
//
// 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.
//
iBestPredictorL = 0;
iBestPredictorR = 0;
dwL = adwTotalErrorL[0];
dwR = adwTotalErrorR[0];
for (i = 1; i < MSADPCM_MAX_COEFFICIENTS; i++)
{
if (adwTotalErrorL[i] < dwL)
{
iBestPredictorL = i;
dwL = adwTotalErrorL[i];
}
if (adwTotalErrorR[i] < dwR)
{
iBestPredictorR = i;
dwR = adwTotalErrorR[i];
}
}
iCoef1L = lpCoefSet[iBestPredictorL].iCoef1;
iCoef1R = lpCoefSet[iBestPredictorR].iCoef1;
iCoef2L = lpCoefSet[iBestPredictorL].iCoef2;
iCoef2R = lpCoefSet[iBestPredictorR].iCoef2;
//
// grab first iDelta from our precomputed first deltas that we
// calculated above
//
iDeltaL = aiFirstDeltaL[iBestPredictorL];
iDeltaR = aiFirstDeltaR[iBestPredictorR];
//
// Set up first two samples - these have already been converted
// to 16-bit values in aiSamples[], but make sure to increment
// pbSrc so that it keeps in sync.
//
iSamp1L = aiSamplesL[1];
iSamp1R = aiSamplesR[1];
iSamp2L = aiSamplesL[0];
iSamp2R = aiSamplesR[0];
pbSrc += 2*sizeof(short) * 2; // Last 2 = # of channels.
ASSERT( cBlockSamples != 1 );
cBlockSamples -= 2;
//
// write the block header for the encoded data
//
// the block header is composed of the following data:
// 1 byte predictor per channel
// 2 byte delta per channel
// 2 byte first delayed sample per channel
// 2 byte second delayed sample per channel
//
*pbDst++ = (BYTE)iBestPredictorL;
*pbDst++ = (BYTE)iBestPredictorR;
pcmWrite16Unaligned(pbDst,iDeltaL);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iDeltaR);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp1L);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp1R);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp2L);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp2R);
pbDst += sizeof(short);
//
// We have written the header for this block--now write the data
// chunk (which consists of a bunch of encoded nibbles).
//
while( cBlockSamples-- )
{
//
// LEFT channel.
//
iSample = pcmRead16(pbSrc);
pbSrc += sizeof(short);
//
// calculate the prediction based on the previous two samples
//
lPrediction = adpcmCalcPrediction(iSamp1L,iCoef1L,iSamp2L,iCoef2L);
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutputL = (int)(lError / iDeltaL);
if (iOutputL > OUTPUT4MAX)
iOutputL = OUTPUT4MAX;
else if (iOutputL < OUTPUT4MIN)
iOutputL = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDeltaL * iOutputL);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDeltaL = adpcmCalcDelta(iOutputL,iDeltaL);
//
// Save updated delay samples.
//
iSamp2L = iSamp1L;
iSamp1L = (int)lSamp;
//
// RIGHT channel.
//
iSample = pcmRead16(pbSrc);
pbSrc += sizeof(short);
//
// calculate the prediction based on the previous two samples
//
lPrediction = adpcmCalcPrediction(iSamp1R,iCoef1R,iSamp2R,iCoef2R);
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutputR = (int)(lError / iDeltaR);
if (iOutputR > OUTPUT4MAX)
iOutputR = OUTPUT4MAX;
else if (iOutputR < OUTPUT4MIN)
iOutputR = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDeltaR * iOutputR);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDeltaR = adpcmCalcDelta(iOutputR,iDeltaR);
//
// Save updated delay samples.
//
iSamp2R = iSamp1R;
iSamp1R = (int)lSamp;
//
// Write out the encoded byte.
//
*pbDst++ = (BYTE)( ((iOutputL&OUTPUT4MASK)<<4) |
(iOutputR&OUTPUT4MASK) );
}
}
//
// We return the number of bytes used in the destination. This is
// simply the difference in bytes from where we started.
//
return (DWORD)(pbDst - pbDstStart);
} // adpcmEncode4Bit_S16_FullPass()
//==========================================================================;
//
// The code below this point is only compiled into WIN32 builds. Win16
// builds will call 386 assembler routines instead; see the routine
// acmdStreamOpen() in codec.c for more details.
//
//==========================================================================;
#ifdef WIN32
//==========================================================================;
//
// REALTIME ENCODE ROUTINES
//
//==========================================================================;
//--------------------------------------------------------------------------;
//
// DWORD FNGLOBAL adpcmEncode4Bit_M08_OnePass
// DWORD FNGLOBAL adpcmEncode4Bit_M16_OnePass
// DWORD FNGLOBAL adpcmEncode4Bit_S08_OnePass
// DWORD FNGLOBAL adpcmEncode4Bit_S16_OnePass
//
// Description:
//
//
// Arguments:
//
//
// Return (DWORD FNGLOBAL):
//
//
// History:
// 1/27/93 cjp [curtisp]
// 3/03/94 rmh [bobhed]
//
//--------------------------------------------------------------------------;
DWORD FNGLOBAL adpcmEncode4Bit_M08_OnePass
(
HPBYTE pbSrc,
DWORD cbSrcLength,
HPBYTE pbDst,
UINT nBlockAlignment,
UINT cSamplesPerBlock,
UINT nNumCoef,
LPADPCMCOEFSET lpCoefSet
)
{
HPBYTE pbDstStart;
DWORD cSrcSamples;
UINT cBlockSamples;
int iSamp1;
int iSamp2;
int iDelta;
int iOutput1;
int iOutput2;
int iSample;
long lSamp;
long lError;
long lPrediction;
pbDstStart = pbDst;
cSrcSamples = pcmM08BytesToSamples(cbSrcLength);
//
// step through each block of PCM data and encode it to 4 bit ADPCM
//
while( 0 != cSrcSamples )
{
//
// determine how much data we should encode for this block--this
// will be cSamplesPerBlock 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...
//
cBlockSamples = (UINT)min(cSrcSamples, cSamplesPerBlock);
cSrcSamples -= cBlockSamples;
//
// write the block header for the encoded data
//
// the block header is composed of the following data:
// 1 byte predictor per channel
// 2 byte delta per channel
// 2 byte first delayed sample per channel
// 2 byte second delayed sample per channel
//
*pbDst++ = (BYTE)1;
iDelta = DELTA4START;
pcmWrite16Unaligned(pbDst,DELTA4START); // Same as iDelta.
pbDst += sizeof(short);
//
// Note that iSamp2 comes before iSamp1. If we only have one
// sample, then set iSamp1 to zero.
//
iSamp2 = pcmRead08(pbSrc++);
if( --cBlockSamples > 0 ) {
iSamp1 = pcmRead08(pbSrc++);
cBlockSamples--;
} else {
iSamp1 = 0;
}
pcmWrite16Unaligned(pbDst,iSamp1);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp2);
pbDst += sizeof(short);
//
// We have written the header for this block--now write the data
// chunk (which consists of a bunch of encoded nibbles).
//
while( cBlockSamples>0 )
{
//
// Sample 1.
//
iSample = pcmRead08(pbSrc++);
cBlockSamples--;
//
// calculate the prediction based on the previous two samples
//
lPrediction = ((long)iSamp1<<1) - iSamp2;
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutput1 = (int)(lError / iDelta);
if (iOutput1 > OUTPUT4MAX)
iOutput1 = OUTPUT4MAX;
else if (iOutput1 < OUTPUT4MIN)
iOutput1 = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDelta * iOutput1);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDelta = adpcmCalcDelta(iOutput1,iDelta);
//
// Save updated delay samples.
//
iSamp2 = iSamp1;
iSamp1 = (int)lSamp;
//
// Sample 2.
//
if( cBlockSamples>0 ) {
iSample = pcmRead08(pbSrc++);
cBlockSamples--;
//
// calculate the prediction based on the previous two samples
//
lPrediction = ((long)iSamp1<<1) - iSamp2;
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutput2 = (int)(lError / iDelta);
if (iOutput2 > OUTPUT4MAX)
iOutput2 = OUTPUT4MAX;
else if (iOutput2 < OUTPUT4MIN)
iOutput2 = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDelta * iOutput2);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDelta = adpcmCalcDelta(iOutput2,iDelta);
//
// Save updated delay samples.
//
iSamp2 = iSamp1;
iSamp1 = (int)lSamp;
} else {
iOutput2 = 0;
}
//
// Write out the encoded byte.
//
*pbDst++ = (BYTE)( ((iOutput1&OUTPUT4MASK)<<4) |
(iOutput2&OUTPUT4MASK) );
}
}
//
// We return the number of bytes used in the destination. This is
// simply the difference in bytes from where we started.
//
return (DWORD)(pbDst - pbDstStart);
} // adpcmEncode4Bit_M08_OnePass()
//--------------------------------------------------------------------------;
//--------------------------------------------------------------------------;
DWORD FNGLOBAL adpcmEncode4Bit_M16_OnePass
(
HPBYTE pbSrc,
DWORD cbSrcLength,
HPBYTE pbDst,
UINT nBlockAlignment,
UINT cSamplesPerBlock,
UINT nNumCoef,
LPADPCMCOEFSET lpCoefSet
)
{
HPBYTE pbDstStart;
DWORD cSrcSamples;
UINT cBlockSamples;
int iSamp1;
int iSamp2;
int iDelta;
int iOutput1;
int iOutput2;
int iSample;
long lSamp;
long lError;
long lPrediction;
pbDstStart = pbDst;
cSrcSamples = pcmM16BytesToSamples(cbSrcLength);
//
// step through each block of PCM data and encode it to 4 bit ADPCM
//
while( 0 != cSrcSamples )
{
//
// determine how much data we should encode for this block--this
// will be cSamplesPerBlock 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...
//
cBlockSamples = (UINT)min(cSrcSamples, cSamplesPerBlock);
cSrcSamples -= cBlockSamples;
//
// write the block header for the encoded data
//
// the block header is composed of the following data:
// 1 byte predictor per channel
// 2 byte delta per channel
// 2 byte first delayed sample per channel
// 2 byte second delayed sample per channel
//
*pbDst++ = (BYTE)1;
iDelta = DELTA4START;
pcmWrite16Unaligned(pbDst,DELTA4START); // Same as iDelta;
pbDst += sizeof(short);
//
// Note that iSamp2 comes before iSamp1. If we only have one
// sample, then set iSamp1 to zero.
//
iSamp2 = pcmRead16(pbSrc);
pbSrc += sizeof(short);
if( --cBlockSamples > 0 ) {
iSamp1 = pcmRead16(pbSrc);
pbSrc += sizeof(short);
cBlockSamples--;
} else {
iSamp1 = 0;
}
pcmWrite16Unaligned(pbDst,iSamp1);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp2);
pbDst += sizeof(short);
//
// We have written the header for this block--now write the data
// chunk (which consists of a bunch of encoded nibbles).
//
while( cBlockSamples>0 )
{
//
// Sample 1.
//
iSample = pcmRead16(pbSrc);
pbSrc += sizeof(short);
cBlockSamples--;
//
// calculate the prediction based on the previous two samples
//
lPrediction = ((long)iSamp1<<1) - iSamp2;
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutput1 = (int)(lError / iDelta);
if (iOutput1 > OUTPUT4MAX)
iOutput1 = OUTPUT4MAX;
else if (iOutput1 < OUTPUT4MIN)
iOutput1 = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDelta * iOutput1);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDelta = adpcmCalcDelta(iOutput1,iDelta);
//
// Save updated delay samples.
//
iSamp2 = iSamp1;
iSamp1 = (int)lSamp;
//
// Sample 2.
//
if( cBlockSamples>0 ) {
iSample = pcmRead16(pbSrc);
pbSrc += sizeof(short);
cBlockSamples--;
//
// calculate the prediction based on the previous two samples
//
lPrediction = ((long)iSamp1<<1) - iSamp2;
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutput2 = (int)(lError / iDelta);
if (iOutput2 > OUTPUT4MAX)
iOutput2 = OUTPUT4MAX;
else if (iOutput2 < OUTPUT4MIN)
iOutput2 = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDelta * iOutput2);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDelta = adpcmCalcDelta(iOutput2,iDelta);
//
// Save updated delay samples.
//
iSamp2 = iSamp1;
iSamp1 = (int)lSamp;
} else {
iOutput2 = 0;
}
//
// Write out the encoded byte.
//
*pbDst++ = (BYTE)( ((iOutput1&OUTPUT4MASK)<<4) |
(iOutput2&OUTPUT4MASK) );
}
}
//
// We return the number of bytes used in the destination. This is
// simply the difference in bytes from where we started.
//
return (DWORD)(pbDst - pbDstStart);
} // adpcmEncode4Bit_M16_OnePass()
//--------------------------------------------------------------------------;
//--------------------------------------------------------------------------;
DWORD FNGLOBAL adpcmEncode4Bit_S08_OnePass
(
HPBYTE pbSrc,
DWORD cbSrcLength,
HPBYTE pbDst,
UINT nBlockAlignment,
UINT cSamplesPerBlock,
UINT nNumCoef,
LPADPCMCOEFSET lpCoefSet
)
{
HPBYTE pbDstStart;
DWORD cSrcSamples;
UINT cBlockSamples;
int iSamp1L;
int iSamp2L;
int iDeltaL;
int iOutputL;
int iSamp1R;
int iSamp2R;
int iDeltaR;
int iOutputR;
int iSample;
long lSamp;
long lError;
long lPrediction;
pbDstStart = pbDst;
cSrcSamples = pcmS08BytesToSamples(cbSrcLength);
//
// step through each block of PCM data and encode it to 4 bit ADPCM
//
while( 0 != cSrcSamples )
{
//
// determine how much data we should encode for this block--this
// will be cSamplesPerBlock 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...
//
cBlockSamples = (UINT)min(cSrcSamples, cSamplesPerBlock);
cSrcSamples -= cBlockSamples;
//
// write the block header for the encoded data
//
// the block header is composed of the following data:
// 1 byte predictor per channel
// 2 byte delta per channel
// 2 byte first delayed sample per channel
// 2 byte second delayed sample per channel
//
*pbDst++ = (BYTE)1;
*pbDst++ = (BYTE)1;
iDeltaL = DELTA4START;
iDeltaR = DELTA4START;
pcmWrite16Unaligned(pbDst,DELTA4START); // Same as iDeltaL.
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,DELTA4START); // Same as iDeltaR.
pbDst += sizeof(short);
//
// Note that iSamp2 comes before iSamp1. If we only have one
// sample, then set iSamp1 to zero.
//
iSamp2L = pcmRead08(pbSrc++);
iSamp2R = pcmRead08(pbSrc++);
if( --cBlockSamples > 0 ) {
iSamp1L = pcmRead08(pbSrc++);
iSamp1R = pcmRead08(pbSrc++);
cBlockSamples--;
} else {
iSamp1L = 0;
iSamp1R = 0;
}
pcmWrite16Unaligned(pbDst,iSamp1L);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp1R);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp2L);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp2R);
pbDst += sizeof(short);
//
// We have written the header for this block--now write the data
// chunk (which consists of a bunch of encoded nibbles).
//
while( cBlockSamples-- )
{
//
// LEFT channel.
//
iSample = pcmRead08(pbSrc++);
//
// calculate the prediction based on the previous two samples
//
lPrediction = ((long)iSamp1L<<1) - iSamp2L;
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutputL = (int)(lError / iDeltaL);
if (iOutputL > OUTPUT4MAX)
iOutputL = OUTPUT4MAX;
else if (iOutputL < OUTPUT4MIN)
iOutputL = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDeltaL * iOutputL);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDeltaL = adpcmCalcDelta(iOutputL,iDeltaL);
//
// Save updated delay samples.
//
iSamp2L = iSamp1L;
iSamp1L = (int)lSamp;
//
// RIGHT channel.
//
iSample = pcmRead08(pbSrc++);
//
// calculate the prediction based on the previous two samples
//
lPrediction = ((long)iSamp1R<<1) - iSamp2R;
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutputR = (int)(lError / iDeltaR);
if (iOutputR > OUTPUT4MAX)
iOutputR = OUTPUT4MAX;
else if (iOutputR < OUTPUT4MIN)
iOutputR = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDeltaR * iOutputR);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDeltaR = adpcmCalcDelta(iOutputR,iDeltaR);
//
// Save updated delay samples.
//
iSamp2R = iSamp1R;
iSamp1R = (int)lSamp;
//
// Write out the encoded byte.
//
*pbDst++ = (BYTE)( ((iOutputL&OUTPUT4MASK)<<4) |
(iOutputR&OUTPUT4MASK) );
}
}
//
// We return the number of bytes used in the destination. This is
// simply the difference in bytes from where we started.
//
return (DWORD)(pbDst - pbDstStart);
} // adpcmEncode4Bit_S08_OnePass()
//--------------------------------------------------------------------------;
//--------------------------------------------------------------------------;
DWORD FNGLOBAL adpcmEncode4Bit_S16_OnePass
(
HPBYTE pbSrc,
DWORD cbSrcLength,
HPBYTE pbDst,
UINT nBlockAlignment,
UINT cSamplesPerBlock,
UINT nNumCoef,
LPADPCMCOEFSET lpCoefSet
)
{
HPBYTE pbDstStart;
DWORD cSrcSamples;
UINT cBlockSamples;
int iSamp1L;
int iSamp2L;
int iDeltaL;
int iOutputL;
int iSamp1R;
int iSamp2R;
int iDeltaR;
int iOutputR;
int iSample;
long lSamp;
long lError;
long lPrediction;
pbDstStart = pbDst;
cSrcSamples = pcmS16BytesToSamples(cbSrcLength);
//
// step through each block of PCM data and encode it to 4 bit ADPCM
//
while( 0 != cSrcSamples )
{
//
// determine how much data we should encode for this block--this
// will be cSamplesPerBlock 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...
//
cBlockSamples = (UINT)min(cSrcSamples, cSamplesPerBlock);
cSrcSamples -= cBlockSamples;
//
// write the block header for the encoded data
//
// the block header is composed of the following data:
// 1 byte predictor per channel
// 2 byte delta per channel
// 2 byte first delayed sample per channel
// 2 byte second delayed sample per channel
//
*pbDst++ = (BYTE)1;
*pbDst++ = (BYTE)1;
iDeltaL = DELTA4START;
iDeltaR = DELTA4START;
pcmWrite16Unaligned(pbDst,DELTA4START); // Same as iDeltaL.
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,DELTA4START); // Same as iDeltaR.
pbDst += sizeof(short);
//
// Note that iSamp2 comes before iSamp1. If we only have one
// sample, then set iSamp1 to zero.
//
iSamp2L = pcmRead16(pbSrc);
pbSrc += sizeof(short);
iSamp2R = pcmRead16(pbSrc);
pbSrc += sizeof(short);
if( --cBlockSamples > 0 ) {
iSamp1L = pcmRead16(pbSrc);
pbSrc += sizeof(short);
iSamp1R = pcmRead16(pbSrc);
pbSrc += sizeof(short);
cBlockSamples--;
} else {
iSamp1L = 0;
iSamp1R = 0;
}
pcmWrite16Unaligned(pbDst,iSamp1L);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp1R);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp2L);
pbDst += sizeof(short);
pcmWrite16Unaligned(pbDst,iSamp2R);
pbDst += sizeof(short);
//
// We have written the header for this block--now write the data
// chunk (which consists of a bunch of encoded nibbles).
//
while( cBlockSamples-- )
{
//
// LEFT channel.
//
iSample = pcmRead16(pbSrc);
pbSrc += sizeof(short);
//
// calculate the prediction based on the previous two samples
//
lPrediction = ((long)iSamp1L<<1) - iSamp2L;
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutputL = (int)(lError / iDeltaL);
if (iOutputL > OUTPUT4MAX)
iOutputL = OUTPUT4MAX;
else if (iOutputL < OUTPUT4MIN)
iOutputL = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDeltaL * iOutputL);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDeltaL = adpcmCalcDelta(iOutputL,iDeltaL);
//
// Save updated delay samples.
//
iSamp2L = iSamp1L;
iSamp1L = (int)lSamp;
//
// RIGHT channel.
//
iSample = pcmRead16(pbSrc);
pbSrc += sizeof(short);
//
// calculate the prediction based on the previous two samples
//
lPrediction = ((long)iSamp1R<<1) - iSamp2R;
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutputR = (int)(lError / iDeltaR);
if (iOutputR > OUTPUT4MAX)
iOutputR = OUTPUT4MAX;
else if (iOutputR < OUTPUT4MIN)
iOutputR = OUTPUT4MIN;
lSamp = lPrediction + ((long)iDeltaR * iOutputR);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDeltaR = adpcmCalcDelta(iOutputR,iDeltaR);
//
// Save updated delay samples.
//
iSamp2R = iSamp1R;
iSamp1R = (int)lSamp;
//
// Write out the encoded byte.
//
*pbDst++ = (BYTE)( ((iOutputL&OUTPUT4MASK)<<4) |
(iOutputR&OUTPUT4MASK) );
}
}
//
// We return the number of bytes used in the destination. This is
// simply the difference in bytes from where we started.
//
return (DWORD)(pbDst - pbDstStart);
} // adpcmEncode4Bit_S16_OnePass()
//==========================================================================;
//
// DECODE ROUTINES
//
//==========================================================================;
//--------------------------------------------------------------------------;
//
// DWORD adpcmDecode4Bit_M08
// DWORD adpcmDecode4Bit_M16
// DWORD adpcmDecode4Bit_S08
// DWORD adpcmDecode4Bit_S16
//
// Description:
// These functions decode a buffer of data from MS ADPCM to PCM in the
// specified format. The appropriate function is called once for each
// ACMDM_STREAM_CONVERT message received.
//
//
// Arguments:
//
//
// Return (DWORD): The number of bytes used in the destination buffer.
//
//--------------------------------------------------------------------------;
DWORD FNGLOBAL adpcmDecode4Bit_M08
(
HPBYTE pbSrc,
DWORD cbSrcLength,
HPBYTE pbDst,
UINT nBlockAlignment,
UINT cSamplesPerBlock,
UINT nNumCoef,
LPADPCMCOEFSET lpCoefSet
)
{
HPBYTE pbDstStart;
UINT cbHeader;
UINT cbBlockLength;
UINT nPredictor;
BYTE bSample;
int iInput;
int iSamp;
int iSamp1;
int iSamp2;
int iCoef1;
int iCoef2;
int iDelta;
pbDstStart = pbDst;
cbHeader = MSADPCM_HEADER_LENGTH * 1; // 1 = number of channels.
//
//
//
while( cbSrcLength >= cbHeader )
{
//
// We have at least enough data to read a full block header.
//
// the header looks like this:
// 1 byte predictor per channel (determines coefficients).
// 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. We figure
// out how much data we have in the rest of the block, ie. whether
// we have a full block or not. That way we don't have to test
// each sample to see if we have run out of data.
//
cbBlockLength = (UINT)min(cbSrcLength,nBlockAlignment);
cbSrcLength -= cbBlockLength;
cbBlockLength -= cbHeader;
//
// Process the block header.
//
nPredictor = (UINT)(BYTE)(*pbSrc++);
if( nPredictor >= nNumCoef )
{
//
// the predictor is out of range--this is considered a
// fatal error with the ADPCM data, so we fail by returning
// zero bytes decoded
//
return 0;
}
iCoef1 = lpCoefSet[nPredictor].iCoef1;
iCoef2 = lpCoefSet[nPredictor].iCoef2;
iDelta = pcmRead16Unaligned(pbSrc);
pbSrc += sizeof(short);
iSamp1 = pcmRead16Unaligned(pbSrc);
pbSrc += sizeof(short);
iSamp2 = pcmRead16Unaligned(pbSrc);
pbSrc += sizeof(short);
//
// write out first 2 samples.
//
// NOTE: the samples are written to the destination PCM buffer
// in the _reverse_ order that they are in the header block:
// remember that iSamp2 is the _previous_ sample to iSamp1.
//
pcmWrite08(pbDst,iSamp2);
pcmWrite08(pbDst,iSamp1);
//
// we now need to decode the 'data' section of the ADPCM block.
// this consists of packed 4 bit nibbles. The high-order nibble
// contains the first sample; the low-order nibble contains the
// second sample.
//
while( cbBlockLength-- )
{
bSample = *pbSrc++;
//
// Sample 1.
//
iInput = (int)(((signed char)bSample) >> 4); //Sign-extend.
iSamp = adpcmDecodeSample( iSamp1,iCoef1,
iSamp2,iCoef2,
iInput,iDelta );
iDelta = adpcmCalcDelta( iInput,iDelta );
pcmWrite08(pbDst++,iSamp);
//
// ripple our previous samples down making the new iSamp1
// equal to the sample we just decoded
//
iSamp2 = iSamp1;
iSamp1 = iSamp;
//
// Sample 2.
//
iInput = (int)(((signed char)(bSample<<4)) >> 4); //Sign-extend.
iSamp = adpcmDecodeSample( iSamp1,iCoef1,
iSamp2,iCoef2,
iInput,iDelta );
iDelta = adpcmCalcDelta( iInput,iDelta );
pcmWrite08(pbDst++,iSamp);
//
// ripple our previous samples down making the new iSamp1
// equal to the sample we just decoded
//
iSamp2 = iSamp1;
iSamp1 = iSamp;
}
}
//
// We return the number of bytes used in the destination. This is
// simply the difference in bytes from where we started.
//
return (DWORD)(pbDst - pbDstStart);
} // adpcmDecode4Bit_M08()
//--------------------------------------------------------------------------;
//--------------------------------------------------------------------------;
DWORD FNGLOBAL adpcmDecode4Bit_M16
(
HPBYTE pbSrc,
DWORD cbSrcLength,
HPBYTE pbDst,
UINT nBlockAlignment,
UINT cSamplesPerBlock,
UINT nNumCoef,
LPADPCMCOEFSET lpCoefSet
)
{
HPBYTE pbDstStart;
UINT cbHeader;
UINT cbBlockLength;
UINT nPredictor;
BYTE bSample;
int iInput;
int iSamp;
int iSamp1;
int iSamp2;
int iCoef1;
int iCoef2;
int iDelta;
pbDstStart = pbDst;
cbHeader = MSADPCM_HEADER_LENGTH * 1; // 1 = number of channels.
//
//
//
while( cbSrcLength >= cbHeader )
{
//
// We have at least enough data to read a full block header.
//
// the header looks like this:
// 1 byte predictor per channel (determines coefficients).
// 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. We figure
// out how much data we have in the rest of the block, ie. whether
// we have a full block or not. That way we don't have to test
// each sample to see if we have run out of data.
//
cbBlockLength = (UINT)min(cbSrcLength,nBlockAlignment);
cbSrcLength -= cbBlockLength;
cbBlockLength -= cbHeader;
//
// Process the block header.
//
nPredictor = (UINT)(BYTE)(*pbSrc++);
if( nPredictor >= nNumCoef )
{
//
// the predictor is out of range--this is considered a
// fatal error with the ADPCM data, so we fail by returning
// zero bytes decoded
//
return 0;
}
iCoef1 = lpCoefSet[nPredictor].iCoef1;
iCoef2 = lpCoefSet[nPredictor].iCoef2;
iDelta = pcmRead16Unaligned(pbSrc);
pbSrc += sizeof(short);
iSamp1 = pcmRead16Unaligned(pbSrc);
pbSrc += sizeof(short);
iSamp2 = pcmRead16Unaligned(pbSrc);
pbSrc += sizeof(short);
//
// write out first 2 samples.
//
// NOTE: the samples are written to the destination PCM buffer
// in the _reverse_ order that they are in the header block:
// remember that iSamp2 is the _previous_ sample to iSamp1.
//
pcmWrite16(pbDst,iSamp2);
pbDst += sizeof(short);
pcmWrite16(pbDst,iSamp1);
pbDst += sizeof(short);
//
// we now need to decode the 'data' section of the ADPCM block.
// this consists of packed 4 bit nibbles. The high-order nibble
// contains the first sample; the low-order nibble contains the
// second sample.
//
while( cbBlockLength-- )
{
bSample = *pbSrc++;
//
// Sample 1.
//
iInput = (int)(((signed char)bSample) >> 4); //Sign-extend.
iSamp = adpcmDecodeSample( iSamp1,iCoef1,
iSamp2,iCoef2,
iInput,iDelta );
iDelta = adpcmCalcDelta( iInput,iDelta );
pcmWrite16(pbDst,iSamp);
pbDst += sizeof(short);
//
// ripple our previous samples down making the new iSamp1
// equal to the sample we just decoded
//
iSamp2 = iSamp1;
iSamp1 = iSamp;
//
// Sample 2.
//
iInput = (int)(((signed char)(bSample<<4)) >> 4); //Sign-extend.
iSamp = adpcmDecodeSample( iSamp1,iCoef1,
iSamp2,iCoef2,
iInput,iDelta );
iDelta = adpcmCalcDelta( iInput,iDelta );
pcmWrite16(pbDst,iSamp);
pbDst += sizeof(short);
//
// ripple our previous samples down making the new iSamp1
// equal to the sample we just decoded
//
iSamp2 = iSamp1;
iSamp1 = iSamp;
}
}
//
// We return the number of bytes used in the destination. This is
// simply the difference in bytes from where we started.
//
return (DWORD)(pbDst - pbDstStart);
} // adpcmDecode4Bit_M16()
//--------------------------------------------------------------------------;
//--------------------------------------------------------------------------;
DWORD FNGLOBAL adpcmDecode4Bit_S08
(
HPBYTE pbSrc,
DWORD cbSrcLength,
HPBYTE pbDst,
UINT nBlockAlignment,
UINT cSamplesPerBlock,
UINT nNumCoef,
LPADPCMCOEFSET lpCoefSet
)
{
HPBYTE pbDstStart;
UINT cbHeader;
UINT cbBlockLength;
UINT nPredictor;
BYTE bSample;
int iInput;
int iSamp;
int iSamp1L;
int iSamp2L;
int iCoef1L;
int iCoef2L;
int iDeltaL;
int iSamp1R;
int iSamp2R;
int iCoef1R;
int iCoef2R;
int iDeltaR;
pbDstStart = pbDst;
cbHeader = MSADPCM_HEADER_LENGTH * 2; // 2 = number of channels.
//
//
//
while( cbSrcLength >= cbHeader )
{
//
// We have at least enough data to read a full block header.
//
// the header looks like this:
// 1 byte predictor per channel (determines coefficients).
// 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. We figure
// out how much data we have in the rest of the block, ie. whether
// we have a full block or not. That way we don't have to test
// each sample to see if we have run out of data.
//
cbBlockLength = (UINT)min(cbSrcLength,nBlockAlignment);
cbSrcLength -= cbBlockLength;
cbBlockLength -= cbHeader;
//
// Process the block header.
//
nPredictor = (UINT)(BYTE)(*pbSrc++); // Left.
if( nPredictor >= nNumCoef )
{
//
// the predictor is out of range--this is considered a
// fatal error with the ADPCM data, so we fail by returning
// zero bytes decoded
//
return 0;
}
iCoef1L = lpCoefSet[nPredictor].iCoef1;
iCoef2L = lpCoefSet[nPredictor].iCoef2;
nPredictor = (UINT)(BYTE)(*pbSrc++); // Right.
if( nPredictor >= nNumCoef )
{
//
// the predictor is out of range--this is considered a
// fatal error with the ADPCM data, so we fail by returning
// zero bytes decoded
//
return 0;
}
iCoef1R = lpCoefSet[nPredictor].iCoef1;
iCoef2R = lpCoefSet[nPredictor].iCoef2;
iDeltaL = pcmRead16Unaligned(pbSrc); // Left.
pbSrc += sizeof(short);
iDeltaR = pcmRead16Unaligned(pbSrc); // Right.
pbSrc += sizeof(short);
iSamp1L = pcmRead16Unaligned(pbSrc); // Left.
pbSrc += sizeof(short);
iSamp1R = pcmRead16Unaligned(pbSrc); // Right.
pbSrc += sizeof(short);
iSamp2L = pcmRead16Unaligned(pbSrc); // Left.
pbSrc += sizeof(short);
iSamp2R = pcmRead16Unaligned(pbSrc); // Right.
pbSrc += sizeof(short);
//
// write out first 2 samples (per channel).
//
// NOTE: the samples are written to the destination PCM buffer
// in the _reverse_ order that they are in the header block:
// remember that iSamp2 is the _previous_ sample to iSamp1.
//
pcmWrite08(pbDst++,iSamp2L);
pcmWrite08(pbDst++,iSamp2R);
pcmWrite08(pbDst++,iSamp1L);
pcmWrite08(pbDst++,iSamp1R);
//
// we now need to decode the 'data' section of the ADPCM block.
// this consists of packed 4 bit nibbles. The high-order nibble
// contains the left sample; the low-order nibble contains the
// right sample.
//
while( cbBlockLength-- )
{
bSample = *pbSrc++;
//
// Left sample.
//
iInput = (int)(((signed char)bSample) >> 4); //Sign-extend.
iSamp = adpcmDecodeSample( iSamp1L,iCoef1L,
iSamp2L,iCoef2L,
iInput,iDeltaL );
iDeltaL = adpcmCalcDelta( iInput,iDeltaL );
pcmWrite08(pbDst++,iSamp);
//
// ripple our previous samples down making the new iSamp1
// equal to the sample we just decoded
//
iSamp2L = iSamp1L;
iSamp1L = iSamp;
//
// Right sample.
//
iInput = (int)(((signed char)(bSample<<4)) >> 4); //Sign-extend.
iSamp = adpcmDecodeSample( iSamp1R,iCoef1R,
iSamp2R,iCoef2R,
iInput,iDeltaR );
iDeltaR = adpcmCalcDelta( iInput,iDeltaR );
pcmWrite08(pbDst++,iSamp);
//
// ripple our previous samples down making the new iSamp1
// equal to the sample we just decoded
//
iSamp2R = iSamp1R;
iSamp1R = iSamp;
}
}
//
// We return the number of bytes used in the destination. This is
// simply the difference in bytes from where we started.
//
return (DWORD)(pbDst - pbDstStart);
} // adpcmDecode4Bit_S08()
//--------------------------------------------------------------------------;
//--------------------------------------------------------------------------;
DWORD FNGLOBAL adpcmDecode4Bit_S16
(
HPBYTE pbSrc,
DWORD cbSrcLength,
HPBYTE pbDst,
UINT nBlockAlignment,
UINT cSamplesPerBlock,
UINT nNumCoef,
LPADPCMCOEFSET lpCoefSet
)
{
HPBYTE pbDstStart;
UINT cbHeader;
UINT cbBlockLength;
UINT nPredictor;
BYTE bSample;
int iInput;
int iSamp;
int iSamp1L;
int iSamp2L;
int iCoef1L;
int iCoef2L;
int iDeltaL;
int iSamp1R;
int iSamp2R;
int iCoef1R;
int iCoef2R;
int iDeltaR;
pbDstStart = pbDst;
cbHeader = MSADPCM_HEADER_LENGTH * 2; // 2 = number of channels.
//
//
//
while( cbSrcLength >= cbHeader )
{
//
// We have at least enough data to read a full block header.
//
// the header looks like this:
// 1 byte predictor per channel (determines coefficients).
// 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. We figure
// out how much data we have in the rest of the block, ie. whether
// we have a full block or not. That way we don't have to test
// each sample to see if we have run out of data.
//
cbBlockLength = (UINT)min(cbSrcLength,nBlockAlignment);
cbSrcLength -= cbBlockLength;
cbBlockLength -= cbHeader;
//
// Process the block header.
//
nPredictor = (UINT)(BYTE)(*pbSrc++); // Left.
if( nPredictor >= nNumCoef )
{
//
// the predictor is out of range--this is considered a
// fatal error with the ADPCM data, so we fail by returning
// zero bytes decoded
//
return 0;
}
iCoef1L = lpCoefSet[nPredictor].iCoef1;
iCoef2L = lpCoefSet[nPredictor].iCoef2;
nPredictor = (UINT)(BYTE)(*pbSrc++); // Right.
if( nPredictor >= nNumCoef )
{
//
// the predictor is out of range--this is considered a
// fatal error with the ADPCM data, so we fail by returning
// zero bytes decoded
//
return 0;
}
iCoef1R = lpCoefSet[nPredictor].iCoef1;
iCoef2R = lpCoefSet[nPredictor].iCoef2;
iDeltaL = pcmRead16Unaligned(pbSrc); // Left.
pbSrc += sizeof(short);
iDeltaR = pcmRead16Unaligned(pbSrc); // Right.
pbSrc += sizeof(short);
iSamp1L = pcmRead16Unaligned(pbSrc); // Left.
pbSrc += sizeof(short);
iSamp1R = pcmRead16Unaligned(pbSrc); // Right.
pbSrc += sizeof(short);
iSamp2L = pcmRead16Unaligned(pbSrc); // Left.
pbSrc += sizeof(short);
iSamp2R = pcmRead16Unaligned(pbSrc); // Right.
pbSrc += sizeof(short);
//
// write out first 2 samples (per channel).
//
// NOTE: the samples are written to the destination PCM buffer
// in the _reverse_ order that they are in the header block:
// remember that iSamp2 is the _previous_ sample to iSamp1.
//
pcmWrite16(pbDst,iSamp2L);
pbDst += sizeof(short);
pcmWrite16(pbDst,iSamp2R);
pbDst += sizeof(short);
pcmWrite16(pbDst,iSamp1L);
pbDst += sizeof(short);
pcmWrite16(pbDst,iSamp1R);
pbDst += sizeof(short);
//
// we now need to decode the 'data' section of the ADPCM block.
// this consists of packed 4 bit nibbles. The high-order nibble
// contains the left sample; the low-order nibble contains the
// right sample.
//
while( cbBlockLength-- )
{
bSample = *pbSrc++;
//
// Left sample.
//
iInput = (int)(((signed char)bSample) >> 4); //Sign-extend.
iSamp = adpcmDecodeSample( iSamp1L,iCoef1L,
iSamp2L,iCoef2L,
iInput,iDeltaL );
iDeltaL = adpcmCalcDelta( iInput,iDeltaL );
pcmWrite16(pbDst,iSamp);
pbDst += sizeof(short);
//
// ripple our previous samples down making the new iSamp1
// equal to the sample we just decoded
//
iSamp2L = iSamp1L;
iSamp1L = iSamp;
//
// Right sample.
//
iInput = (int)(((signed char)(bSample<<4)) >> 4); //Sign-extend.
iSamp = adpcmDecodeSample( iSamp1R,iCoef1R,
iSamp2R,iCoef2R,
iInput,iDeltaR );
iDeltaR = adpcmCalcDelta( iInput,iDeltaR );
pcmWrite16(pbDst,iSamp);
pbDst += sizeof(short);
//
// ripple our previous samples down making the new iSamp1
// equal to the sample we just decoded
//
iSamp2R = iSamp1R;
iSamp1R = iSamp;
}
}
//
// We return the number of bytes used in the destination. This is
// simply the difference in bytes from where we started.
//
return (DWORD)(pbDst - pbDstStart);
} // adpcmDecode4Bit_S16()
#endif