3543 lines
107 KiB
C
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
|