1557 lines
48 KiB
C
1557 lines
48 KiB
C
//==========================================================================;
|
|
//
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
|
|
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
|
|
// PURPOSE.
|
|
//
|
|
// Copyright (c) 1992 - 1994 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// imaadpcm.c
|
|
//
|
|
// Description:
|
|
// This file contains encode and decode routines for the IMA's ADPCM
|
|
// format. This format is the same format used in Intel's DVI standard.
|
|
// Intel has made this algorithm public domain and the IMA has endorsed
|
|
// this format as a standard for audio compression.
|
|
//
|
|
// Implementation notes:
|
|
//
|
|
// A previous distribution of this codec used a data format which did
|
|
// not comply with the IMA standard. For stereo files, the interleaving
|
|
// of left and right samples was incorrect: the IMA standard requires
|
|
// that a DWORD of left-channel data be followed by a DWORD of right-
|
|
// channel data, but the previous implementation of this codec
|
|
// interleaved the data at the byte level, with the 4 LSBs being the
|
|
// left channel data and the 4 MSBs being the right channel data.
|
|
// For mono files, each pair of samples was reversed: the first sample
|
|
// was stored in the 4 MSBs rather than the 4 LSBs. This problem is
|
|
// fixed during the current release. Note: files compressed by the
|
|
// old codec will sound terrible when played back with the new codec,
|
|
// and vice versa. Please recompress these files with the new codec,
|
|
// since they do not conform to the standard and will not be reproduced
|
|
// correctly by hardware codecs, etc.
|
|
//
|
|
// A previous distribution of this codec had an implementation problem
|
|
// which degraded the sound quality of the encoding. This was due to
|
|
// the fact that the step index was not properly maintained between
|
|
// conversions. This problem has been fixed in the current release.
|
|
//
|
|
// The codec has been speeded up considerably by breaking
|
|
// the encode and decode routines into four separate routines each:
|
|
// mono 8-bit, mono 16-bit, stereo 8-bit, and stereo 16-bit. This
|
|
// approach is recommended for real-time conversion routines.
|
|
//
|
|
//==========================================================================;
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <mmsystem.h>
|
|
#include <mmreg.h>
|
|
#include <msacm.h>
|
|
#include <msacmdrv.h>
|
|
#include "codec.h"
|
|
#include "imaadpcm.h"
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
//
|
|
// This array is used by imaadpcmNextStepIndex to determine the next step
|
|
// index to use. The step index is an index to the step[] array, below.
|
|
//
|
|
const short next_step[16] =
|
|
{
|
|
-1, -1, -1, -1, 2, 4, 6, 8,
|
|
-1, -1, -1, -1, 2, 4, 6, 8
|
|
};
|
|
|
|
//
|
|
// This array contains the array of step sizes used to encode the ADPCM
|
|
// samples. The step index in each ADPCM block is an index to this array.
|
|
//
|
|
const short step[89] =
|
|
{
|
|
7, 8, 9, 10, 11, 12, 13,
|
|
14, 16, 17, 19, 21, 23, 25,
|
|
28, 31, 34, 37, 41, 45, 50,
|
|
55, 60, 66, 73, 80, 88, 97,
|
|
107, 118, 130, 143, 157, 173, 190,
|
|
209, 230, 253, 279, 307, 337, 371,
|
|
408, 449, 494, 544, 598, 658, 724,
|
|
796, 876, 963, 1060, 1166, 1282, 1411,
|
|
1552, 1707, 1878, 2066, 2272, 2499, 2749,
|
|
3024, 3327, 3660, 4026, 4428, 4871, 5358,
|
|
5894, 6484, 7132, 7845, 8630, 9493, 10442,
|
|
11487, 12635, 13899, 15289, 16818, 18500, 20350,
|
|
22385, 24623, 27086, 29794, 32767
|
|
};
|
|
|
|
|
|
|
|
|
|
#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);
|
|
}
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
//
|
|
// This code assumes that the integer nPredictedSample is 32-bits wide!!!
|
|
//
|
|
// The following define replaces the pair of calls to the inline functions
|
|
// imaadpcmSampleEncode() and imaadpcmSampleDecode which are called in the
|
|
// encode routines. There is some redundancy between them which is exploited
|
|
// in this define. Because there are two returns (nEncodedSample and
|
|
// nPredictedSample), it is more efficient to use a #define rather than an
|
|
// inline function which would require a pointer to one of the returns.
|
|
//
|
|
// Basically, nPredictedSample is calculated based on the lDifference value
|
|
// already there, rather than regenerating it through imaadpcmSampleDecode().
|
|
//
|
|
#define imaadpcmFastEncode(nEncodedSample,nPredictedSample,nInputSample,nStepSize) \
|
|
{ \
|
|
LONG lDifference; \
|
|
\
|
|
lDifference = nInputSample - nPredictedSample; \
|
|
nEncodedSample = 0; \
|
|
if( lDifference<0 ) { \
|
|
nEncodedSample = 8; \
|
|
lDifference = -lDifference; \
|
|
} \
|
|
\
|
|
if( lDifference >= nStepSize ) { \
|
|
nEncodedSample |= 4; \
|
|
lDifference -= nStepSize; \
|
|
} \
|
|
\
|
|
nStepSize >>= 1; \
|
|
if( lDifference >= nStepSize ) { \
|
|
nEncodedSample |= 2; \
|
|
lDifference -= nStepSize; \
|
|
} \
|
|
\
|
|
nStepSize >>= 1; \
|
|
if( lDifference >= nStepSize ) { \
|
|
nEncodedSample |= 1; \
|
|
lDifference -= nStepSize; \
|
|
} \
|
|
\
|
|
if( nEncodedSample & 8 ) \
|
|
nPredictedSample = nInputSample + lDifference - (nStepSize>>1); \
|
|
else \
|
|
nPredictedSample = nInputSample - lDifference + (nStepSize>>1); \
|
|
\
|
|
if( nPredictedSample > 32767 ) \
|
|
nPredictedSample = 32767; \
|
|
else if( nPredictedSample < -32768 ) \
|
|
nPredictedSample = -32768; \
|
|
}
|
|
|
|
#else
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// int imaadpcmSampleEncode
|
|
//
|
|
// Description:
|
|
// This routine encodes a single ADPCM sample. 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:
|
|
// int nInputSample: The sample to be encoded.
|
|
// int nPredictedSample: The predicted value of nInputSample.
|
|
// int nStepSize: The quantization step size for the difference between
|
|
// nInputSample and nPredictedSample.
|
|
//
|
|
// Return (int): The 4-bit ADPCM encoded sample, which corresponds to the
|
|
// quantized difference value.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
INLINE int imaadpcmSampleEncode
|
|
(
|
|
int nInputSample,
|
|
int nPredictedSample,
|
|
int nStepSize
|
|
)
|
|
{
|
|
LONG lDifference; // difference may require 17 bits!
|
|
int nEncodedSample;
|
|
|
|
|
|
//
|
|
// set sign bit (bit 3 of the encoded sample) based on sign of the
|
|
// difference (nInputSample-nPredictedSample). Note that we want the
|
|
// absolute value of the difference for the subsequent quantization.
|
|
//
|
|
lDifference = nInputSample - nPredictedSample;
|
|
nEncodedSample = 0;
|
|
if( lDifference<0 ) {
|
|
nEncodedSample = 8;
|
|
lDifference = -lDifference;
|
|
}
|
|
|
|
//
|
|
// quantize lDifference sample
|
|
//
|
|
if( lDifference >= nStepSize ) { // Bit 2.
|
|
nEncodedSample |= 4;
|
|
lDifference -= nStepSize;
|
|
}
|
|
|
|
nStepSize >>= 1;
|
|
if( lDifference >= nStepSize ) { // Bit 1.
|
|
nEncodedSample |= 2;
|
|
lDifference -= nStepSize;
|
|
}
|
|
|
|
nStepSize >>= 1;
|
|
if( lDifference >= nStepSize ) { // Bit 0.
|
|
nEncodedSample |= 1;
|
|
}
|
|
|
|
return (nEncodedSample);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// int imaadpcmSampleDecode
|
|
//
|
|
// Description:
|
|
// This routine decodes a single ADPCM sample. 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:
|
|
// int nEncodedSample: The sample to be decoded.
|
|
// int nPredictedSample: The predicted value of the sample (in PCM).
|
|
// int nStepSize: The quantization step size used to encode the sample.
|
|
//
|
|
// Return (int): The decoded PCM sample.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
INLINE int imaadpcmSampleDecode
|
|
(
|
|
int nEncodedSample,
|
|
int nPredictedSample,
|
|
int nStepSize
|
|
)
|
|
{
|
|
LONG lDifference;
|
|
LONG lNewSample;
|
|
|
|
//
|
|
// calculate difference:
|
|
//
|
|
// lDifference = (nEncodedSample + 1/2) * nStepSize / 4
|
|
//
|
|
lDifference = nStepSize>>3;
|
|
|
|
if (nEncodedSample & 4)
|
|
lDifference += nStepSize;
|
|
|
|
if (nEncodedSample & 2)
|
|
lDifference += nStepSize>>1;
|
|
|
|
if (nEncodedSample & 1)
|
|
lDifference += nStepSize>>2;
|
|
|
|
//
|
|
// If the 'sign bit' of the encoded nibble is set, then the
|
|
// difference is negative...
|
|
//
|
|
if (nEncodedSample & 8)
|
|
lDifference = -lDifference;
|
|
|
|
//
|
|
// adjust predicted sample based on calculated difference
|
|
//
|
|
lNewSample = nPredictedSample + lDifference;
|
|
|
|
//
|
|
// check for overflow and clamp if necessary to a 16 signed sample.
|
|
// Note that this is optimized for the most common case, when we
|
|
// don't have to clamp.
|
|
//
|
|
if( (long)(short)lNewSample == lNewSample )
|
|
{
|
|
return (int)lNewSample;
|
|
}
|
|
|
|
//
|
|
// Clamp.
|
|
//
|
|
if( lNewSample < -32768 )
|
|
return (int)-32768;
|
|
else
|
|
return (int)32767;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// int imaadpcmNextStepIndex
|
|
//
|
|
// Description:
|
|
// This routine calculates the step index value to use for the next
|
|
// encode, based on the current value of the step index and the current
|
|
// encoded sample. 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:
|
|
// int nEncodedSample: The current encoded ADPCM sample.
|
|
// int nStepIndex: The step index value used to encode nEncodedSample.
|
|
//
|
|
// Return (int): The step index to use for the next sample.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
INLINE int imaadpcmNextStepIndex
|
|
(
|
|
int nEncodedSample,
|
|
int nStepIndex
|
|
)
|
|
{
|
|
//
|
|
// compute new stepsize step
|
|
//
|
|
nStepIndex += next_step[nEncodedSample];
|
|
|
|
if (nStepIndex < 0)
|
|
nStepIndex = 0;
|
|
else if (nStepIndex > 88)
|
|
nStepIndex = 88;
|
|
|
|
return (nStepIndex);
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// BOOL imaadpcmValidStepIndex
|
|
//
|
|
// Description:
|
|
// This routine checks the step index value to make sure that it is
|
|
// within the legal range.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// int nStepIndex: The step index value.
|
|
//
|
|
// Return (BOOL): TRUE if the step index is valid; FALSE otherwise.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
INLINE BOOL imaadpcmValidStepIndex
|
|
(
|
|
int nStepIndex
|
|
)
|
|
{
|
|
|
|
if( nStepIndex >= 0 && nStepIndex <= 88 )
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================;
|
|
//
|
|
// DECODE ROUTINES
|
|
//
|
|
//==========================================================================;
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// DWORD imaadpcmDecode4Bit_M08
|
|
// DWORD imaadpcmDecode4Bit_M16
|
|
// DWORD imaadpcmDecode4Bit_S08
|
|
// DWORD imaadpcmDecode4Bit_S16
|
|
//
|
|
// Description:
|
|
// These functions decode a buffer of data from ADPCM to PCM in the
|
|
// specified format. The appropriate function is called once for each
|
|
// ACMDM_STREAM_CONVERT message received. Note that since these
|
|
// functions must share the same prototype as the encoding functions
|
|
// (see acmdStreamOpen() and acmdStreamConvert() in codec.c for more
|
|
// details), not all the parameters are used by these routines.
|
|
//
|
|
// Arguments:
|
|
// HPBYTE pbSrc: Pointer to the source buffer (ADPCM data).
|
|
// DWORD cbSrcLength: The length of the source buffer (in bytes).
|
|
// HPBYTE pbDst: Pointer to the destination buffer (PCM data). Note
|
|
// that it is assumed that the destination buffer is
|
|
// large enough to hold all the encoded data; see
|
|
// acmdStreamSize() in codec.c for more details.
|
|
// UINT nBlockAlignment: The block alignment of the ADPCM data (in
|
|
// bytes).
|
|
// UINT cSamplesPerBlock: The number of samples in each ADPCM block;
|
|
// not used for decoding.
|
|
// int *pnStepIndexL: Pointer to the step index value (left channel)
|
|
// in the STREAMINSTANCE structure; not used for
|
|
// decoding.
|
|
// int *pnStepIndexR: Pointer to the step index value (right channel)
|
|
// in the STREAMINSTANCE structure; not used for
|
|
// decoding.
|
|
//
|
|
// Return (DWORD): The number of bytes used in the destination buffer.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD FNGLOBAL imaadpcmDecode4Bit_M08
|
|
(
|
|
HPBYTE pbSrc,
|
|
DWORD cbSrcLength,
|
|
HPBYTE pbDst,
|
|
UINT nBlockAlignment,
|
|
UINT cSamplesPerBlock,
|
|
int * pnStepIndexL,
|
|
int * pnStepIndexR
|
|
)
|
|
{
|
|
HPBYTE pbDstStart;
|
|
UINT cbHeader;
|
|
UINT cbBlockLength;
|
|
BYTE bSample;
|
|
int nStepSize;
|
|
|
|
int nEncSample;
|
|
int nPredSample;
|
|
int nStepIndex;
|
|
|
|
|
|
pbDstStart = pbDst;
|
|
cbHeader = IMAADPCM_HEADER_LENGTH * 1; // 1 = number of channels.
|
|
|
|
|
|
DPF(3,"Starting imaadpcmDecode4Bit_M08().");
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
while (cbSrcLength >= cbHeader)
|
|
{
|
|
DWORD dwHeader;
|
|
|
|
cbBlockLength = (UINT)min(cbSrcLength, nBlockAlignment);
|
|
cbSrcLength -= cbBlockLength;
|
|
cbBlockLength -= cbHeader;
|
|
|
|
//
|
|
// block header
|
|
//
|
|
dwHeader = *(DWORD HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(DWORD);
|
|
nPredSample = (int)(short)LOWORD(dwHeader);
|
|
nStepIndex = (int)(BYTE)HIWORD(dwHeader);
|
|
|
|
if( !imaadpcmValidStepIndex(nStepIndex) ) {
|
|
//
|
|
// The step index is out of range - this is considered a fatal
|
|
// error as the input stream is corrupted. We fail by returning
|
|
// zero bytes converted.
|
|
//
|
|
DPF(1,"imaadpcmDecode4Bit_M08: invalid step index.");
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// write out first sample
|
|
//
|
|
*pbDst++ = (BYTE)((nPredSample >> 8) + 128);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
while (cbBlockLength--)
|
|
{
|
|
bSample = *pbSrc++;
|
|
|
|
//
|
|
// sample 1
|
|
//
|
|
nEncSample = (bSample & (BYTE)0x0F);
|
|
nStepSize = step[nStepIndex];
|
|
nPredSample = imaadpcmSampleDecode(nEncSample, nPredSample, nStepSize);
|
|
nStepIndex = imaadpcmNextStepIndex(nEncSample, nStepIndex);
|
|
|
|
//
|
|
// write out sample
|
|
//
|
|
*pbDst++ = (BYTE)((nPredSample >> 8) + 128);
|
|
|
|
//
|
|
// sample 2
|
|
//
|
|
nEncSample = (bSample >> 4);
|
|
nStepSize = step[nStepIndex];
|
|
nPredSample = imaadpcmSampleDecode(nEncSample, nPredSample, nStepSize);
|
|
nStepIndex = imaadpcmNextStepIndex(nEncSample, nStepIndex);
|
|
|
|
//
|
|
// write out sample
|
|
//
|
|
*pbDst++ = (BYTE)((nPredSample >> 8) + 128);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
|
|
} // imaadpcmDecode4Bit_M08()
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD FNGLOBAL imaadpcmDecode4Bit_M16
|
|
(
|
|
HPBYTE pbSrc,
|
|
DWORD cbSrcLength,
|
|
HPBYTE pbDst,
|
|
UINT nBlockAlignment,
|
|
UINT cSamplesPerBlock,
|
|
int * pnStepIndexL,
|
|
int * pnStepIndexR
|
|
)
|
|
{
|
|
HPBYTE pbDstStart;
|
|
UINT cbHeader;
|
|
UINT cbBlockLength;
|
|
BYTE bSample;
|
|
int nStepSize;
|
|
|
|
int nEncSample;
|
|
int nPredSample;
|
|
int nStepIndex;
|
|
|
|
|
|
pbDstStart = pbDst;
|
|
cbHeader = IMAADPCM_HEADER_LENGTH * 1; // 1 = number of channels.
|
|
|
|
|
|
DPF(3,"Starting imaadpcmDecode4Bit_M16().");
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
while (cbSrcLength >= cbHeader)
|
|
{
|
|
DWORD dwHeader;
|
|
|
|
cbBlockLength = (UINT)min(cbSrcLength, nBlockAlignment);
|
|
cbSrcLength -= cbBlockLength;
|
|
cbBlockLength -= cbHeader;
|
|
|
|
//
|
|
// block header
|
|
//
|
|
dwHeader = *(DWORD HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(DWORD);
|
|
nPredSample = (int)(short)LOWORD(dwHeader);
|
|
nStepIndex = (int)(BYTE)HIWORD(dwHeader);
|
|
|
|
if( !imaadpcmValidStepIndex(nStepIndex) ) {
|
|
//
|
|
// The step index is out of range - this is considered a fatal
|
|
// error as the input stream is corrupted. We fail by returning
|
|
// zero bytes converted.
|
|
//
|
|
DPF(1,"imaadpcmDecode4Bit_M16: invalid step index.");
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// write out first sample
|
|
//
|
|
*(short HUGE_T *)pbDst = (short)nPredSample;
|
|
pbDst += sizeof(short);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
while (cbBlockLength--)
|
|
{
|
|
bSample = *pbSrc++;
|
|
|
|
//
|
|
// sample 1
|
|
//
|
|
nEncSample = (bSample & (BYTE)0x0F);
|
|
nStepSize = step[nStepIndex];
|
|
nPredSample = imaadpcmSampleDecode(nEncSample, nPredSample, nStepSize);
|
|
nStepIndex = imaadpcmNextStepIndex(nEncSample, nStepIndex);
|
|
|
|
//
|
|
// write out sample
|
|
//
|
|
*(short HUGE_T *)pbDst = (short)nPredSample;
|
|
pbDst += sizeof(short);
|
|
|
|
//
|
|
// sample 2
|
|
//
|
|
nEncSample = (bSample >> 4);
|
|
nStepSize = step[nStepIndex];
|
|
nPredSample = imaadpcmSampleDecode(nEncSample, nPredSample, nStepSize);
|
|
nStepIndex = imaadpcmNextStepIndex(nEncSample, nStepIndex);
|
|
|
|
//
|
|
// write out sample
|
|
//
|
|
*(short HUGE_T *)pbDst = (short)nPredSample;
|
|
pbDst += sizeof(short);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
|
|
} // imaadpcmDecode4Bit_M16()
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD FNGLOBAL imaadpcmDecode4Bit_S08
|
|
(
|
|
HPBYTE pbSrc,
|
|
DWORD cbSrcLength,
|
|
HPBYTE pbDst,
|
|
UINT nBlockAlignment,
|
|
UINT cSamplesPerBlock,
|
|
int * pnStepIndexL,
|
|
int * pnStepIndexR
|
|
)
|
|
{
|
|
HPBYTE pbDstStart;
|
|
UINT cbHeader;
|
|
UINT cbBlockLength;
|
|
int nStepSize;
|
|
DWORD dwHeader;
|
|
DWORD dwLeft;
|
|
DWORD dwRight;
|
|
int i;
|
|
|
|
int nEncSampleL;
|
|
int nPredSampleL;
|
|
int nStepIndexL;
|
|
|
|
int nEncSampleR;
|
|
int nPredSampleR;
|
|
int nStepIndexR;
|
|
|
|
|
|
pbDstStart = pbDst;
|
|
cbHeader = IMAADPCM_HEADER_LENGTH * 2; // 2 = number of channels.
|
|
|
|
|
|
DPF(3,"Starting imaadpcmDecode4Bit_S08().");
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
while( 0 != cbSrcLength )
|
|
{
|
|
//
|
|
// The data should always be block aligned.
|
|
//
|
|
ASSERT( cbSrcLength >= nBlockAlignment );
|
|
|
|
cbBlockLength = nBlockAlignment;
|
|
cbSrcLength -= cbBlockLength;
|
|
cbBlockLength -= cbHeader;
|
|
|
|
|
|
//
|
|
// LEFT channel header
|
|
//
|
|
dwHeader = *(DWORD HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(DWORD);
|
|
nPredSampleL = (int)(short)LOWORD(dwHeader);
|
|
nStepIndexL = (int)(BYTE)HIWORD(dwHeader);
|
|
|
|
if( !imaadpcmValidStepIndex(nStepIndexL) ) {
|
|
//
|
|
// The step index is out of range - this is considered a fatal
|
|
// error as the input stream is corrupted. We fail by returning
|
|
// zero bytes converted.
|
|
//
|
|
DPF(1,"imaadpcmDecode4Bit_S08: invalid step index (L).");
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// RIGHT channel header
|
|
//
|
|
dwHeader = *(DWORD HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(DWORD);
|
|
nPredSampleR = (int)(short)LOWORD(dwHeader);
|
|
nStepIndexR = (int)(BYTE)HIWORD(dwHeader);
|
|
|
|
if( !imaadpcmValidStepIndex(nStepIndexR) ) {
|
|
//
|
|
// The step index is out of range - this is considered a fatal
|
|
// error as the input stream is corrupted. We fail by returning
|
|
// zero bytes converted.
|
|
//
|
|
DPF(1,"imaadpcmDecode4Bit_S08: invalid step index (R).");
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// write out first sample
|
|
//
|
|
*pbDst++ = (BYTE)((nPredSampleL >> 8) + 128);
|
|
*pbDst++ = (BYTE)((nPredSampleR >> 8) + 128);
|
|
|
|
|
|
//
|
|
// The first DWORD contains 4 left samples, the second DWORD
|
|
// contains 4 right samples. We process the source in 8-byte
|
|
// chunks to make it easy to interleave the output correctly.
|
|
//
|
|
ASSERT( 0 == cbBlockLength%8 );
|
|
while( 0 != cbBlockLength )
|
|
{
|
|
cbBlockLength -= 8;
|
|
|
|
dwLeft = *(DWORD HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(DWORD);
|
|
dwRight = *(DWORD HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(DWORD);
|
|
|
|
for( i=8; i>0; i-- )
|
|
{
|
|
//
|
|
// LEFT channel
|
|
//
|
|
nEncSampleL = (dwLeft & 0x0F);
|
|
nStepSize = step[nStepIndexL];
|
|
nPredSampleL = imaadpcmSampleDecode(nEncSampleL, nPredSampleL, nStepSize);
|
|
nStepIndexL = imaadpcmNextStepIndex(nEncSampleL, nStepIndexL);
|
|
|
|
//
|
|
// RIGHT channel
|
|
//
|
|
nEncSampleR = (dwRight & 0x0F);
|
|
nStepSize = step[nStepIndexR];
|
|
nPredSampleR = imaadpcmSampleDecode(nEncSampleR, nPredSampleR, nStepSize);
|
|
nStepIndexR = imaadpcmNextStepIndex(nEncSampleR, nStepIndexR);
|
|
|
|
//
|
|
// write out sample
|
|
//
|
|
*pbDst++ = (BYTE)((nPredSampleL >> 8) + 128);
|
|
*pbDst++ = (BYTE)((nPredSampleR >> 8) + 128);
|
|
|
|
//
|
|
// Shift the next input sample into the low-order 4 bits.
|
|
//
|
|
dwLeft >>= 4;
|
|
dwRight >>= 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
|
|
} // imaadpcmDecode4Bit_S08()
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD FNGLOBAL imaadpcmDecode4Bit_S16
|
|
(
|
|
HPBYTE pbSrc,
|
|
DWORD cbSrcLength,
|
|
HPBYTE pbDst,
|
|
UINT nBlockAlignment,
|
|
UINT cSamplesPerBlock,
|
|
int * pnStepIndexL,
|
|
int * pnStepIndexR
|
|
)
|
|
{
|
|
HPBYTE pbDstStart;
|
|
UINT cbHeader;
|
|
UINT cbBlockLength;
|
|
int nStepSize;
|
|
DWORD dwHeader;
|
|
DWORD dwLeft;
|
|
DWORD dwRight;
|
|
int i;
|
|
|
|
int nEncSampleL;
|
|
int nPredSampleL;
|
|
int nStepIndexL;
|
|
|
|
int nEncSampleR;
|
|
int nPredSampleR;
|
|
int nStepIndexR;
|
|
|
|
|
|
pbDstStart = pbDst;
|
|
cbHeader = IMAADPCM_HEADER_LENGTH * 2; // 2 = number of channels.
|
|
|
|
|
|
DPF(3,"Starting imaadpcmDecode4Bit_S16().");
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
while( 0 != cbSrcLength )
|
|
{
|
|
//
|
|
// The data should always be block aligned.
|
|
//
|
|
ASSERT( cbSrcLength >= nBlockAlignment );
|
|
|
|
cbBlockLength = nBlockAlignment;
|
|
cbSrcLength -= cbBlockLength;
|
|
cbBlockLength -= cbHeader;
|
|
|
|
|
|
//
|
|
// LEFT channel header
|
|
//
|
|
dwHeader = *(DWORD HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(DWORD);
|
|
nPredSampleL = (int)(short)LOWORD(dwHeader);
|
|
nStepIndexL = (int)(BYTE)HIWORD(dwHeader);
|
|
|
|
if( !imaadpcmValidStepIndex(nStepIndexL) ) {
|
|
//
|
|
// The step index is out of range - this is considered a fatal
|
|
// error as the input stream is corrupted. We fail by returning
|
|
// zero bytes converted.
|
|
//
|
|
DPF(1,"imaadpcmDecode4Bit_S16: invalid step index %u (L).", nStepIndexL);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// RIGHT channel header
|
|
//
|
|
dwHeader = *(DWORD HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(DWORD);
|
|
nPredSampleR = (int)(short)LOWORD(dwHeader);
|
|
nStepIndexR = (int)(BYTE)HIWORD(dwHeader);
|
|
|
|
if( !imaadpcmValidStepIndex(nStepIndexR) ) {
|
|
//
|
|
// The step index is out of range - this is considered a fatal
|
|
// error as the input stream is corrupted. We fail by returning
|
|
// zero bytes converted.
|
|
//
|
|
DPF(1,"imaadpcmDecode4Bit_S16: invalid step index %u (R).",nStepIndexR);
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// write out first sample
|
|
//
|
|
*(DWORD HUGE_T *)pbDst = MAKELONG(nPredSampleL, nPredSampleR);
|
|
pbDst += sizeof(DWORD);
|
|
|
|
|
|
//
|
|
// The first DWORD contains 4 left samples, the second DWORD
|
|
// contains 4 right samples. We process the source in 8-byte
|
|
// chunks to make it easy to interleave the output correctly.
|
|
//
|
|
ASSERT( 0 == cbBlockLength%8 );
|
|
while( 0 != cbBlockLength )
|
|
{
|
|
cbBlockLength -= 8;
|
|
|
|
dwLeft = *(DWORD HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(DWORD);
|
|
dwRight = *(DWORD HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(DWORD);
|
|
|
|
for( i=8; i>0; i-- )
|
|
{
|
|
//
|
|
// LEFT channel
|
|
//
|
|
nEncSampleL = (dwLeft & 0x0F);
|
|
nStepSize = step[nStepIndexL];
|
|
nPredSampleL = imaadpcmSampleDecode(nEncSampleL, nPredSampleL, nStepSize);
|
|
nStepIndexL = imaadpcmNextStepIndex(nEncSampleL, nStepIndexL);
|
|
|
|
//
|
|
// RIGHT channel
|
|
//
|
|
nEncSampleR = (dwRight & 0x0F);
|
|
nStepSize = step[nStepIndexR];
|
|
nPredSampleR = imaadpcmSampleDecode(nEncSampleR, nPredSampleR, nStepSize);
|
|
nStepIndexR = imaadpcmNextStepIndex(nEncSampleR, nStepIndexR);
|
|
|
|
//
|
|
// write out sample
|
|
//
|
|
*(DWORD HUGE_T *)pbDst = MAKELONG(nPredSampleL, nPredSampleR);
|
|
pbDst += sizeof(DWORD);
|
|
|
|
//
|
|
// Shift the next input sample into the low-order 4 bits.
|
|
//
|
|
dwLeft >>= 4;
|
|
dwRight >>= 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
|
|
} // imaadpcmDecode4Bit_S16()
|
|
|
|
|
|
|
|
//==========================================================================;
|
|
//
|
|
// ENCODE ROUTINES
|
|
//
|
|
//==========================================================================;
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// DWORD imaadpcmEncode4Bit_M08
|
|
// DWORD imaadpcmEncode4Bit_M16
|
|
// DWORD imaadpcmEncode4Bit_S08
|
|
// DWORD imaadpcmEncode4Bit_S16
|
|
//
|
|
// Description:
|
|
// These functions encode a buffer of data from PCM to ADPCM in the
|
|
// specified format. The appropriate function is called once for each
|
|
// ACMDM_STREAM_CONVERT message received. Note that since these
|
|
// functions must share the same prototype as the decoding functions
|
|
// (see acmdStreamOpen() and acmdStreamConvert() in codec.c for more
|
|
// details), not all the parameters are used by these routines.
|
|
//
|
|
// Arguments:
|
|
// HPBYTE pbSrc: Pointer to the source buffer (PCM data).
|
|
// DWORD cbSrcLength: The length of the source buffer (in bytes).
|
|
// HPBYTE pbDst: Pointer to the destination buffer (ADPCM data). Note
|
|
// that it is assumed that the destination buffer is
|
|
// large enough to hold all the encoded data; see
|
|
// acmdStreamSize() in codec.c for more details.
|
|
// UINT nBlockAlignment: The block alignment of the ADPCM data (in
|
|
// bytes); not used for encoding.
|
|
// UINT cSamplesPerBlock: The number of samples in each ADPCM block.
|
|
// int *pnStepIndexL: Pointer to the step index value (left channel)
|
|
// in the STREAMINSTANCE structure; this is used to
|
|
// maintain the step index across converts.
|
|
// int *pnStepIndexR: Pointer to the step index value (right channel)
|
|
// in the STREAMINSTANCE structure; this is used to
|
|
// maintain the step index across converts. It is only
|
|
// used for stereo converts.
|
|
//
|
|
// Return (DWORD): The number of bytes used in the destination buffer.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD FNGLOBAL imaadpcmEncode4Bit_M08
|
|
(
|
|
HPBYTE pbSrc,
|
|
DWORD cbSrcLength,
|
|
HPBYTE pbDst,
|
|
UINT nBlockAlignment,
|
|
UINT cSamplesPerBlock,
|
|
int * pnStepIndexL,
|
|
int * pnStepIndexR
|
|
)
|
|
{
|
|
HPBYTE pbDstStart;
|
|
DWORD cSrcSamples;
|
|
UINT cBlockSamples;
|
|
int nSample;
|
|
int nStepSize;
|
|
|
|
int nEncSample1;
|
|
int nEncSample2;
|
|
int nPredSample;
|
|
int nStepIndex;
|
|
|
|
|
|
pbDstStart = pbDst;
|
|
cSrcSamples = pcmM08BytesToSamples(cbSrcLength);
|
|
|
|
//
|
|
// Restore the Step Index to that of the final convert of the previous
|
|
// buffer. Remember to restore this value to psi->nStepIndexL.
|
|
//
|
|
nStepIndex = (*pnStepIndexL);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
while (0 != cSrcSamples)
|
|
{
|
|
cBlockSamples = (UINT)min(cSrcSamples, cSamplesPerBlock);
|
|
cSrcSamples -= cBlockSamples;
|
|
|
|
//
|
|
// block header
|
|
//
|
|
nPredSample = ((short)*pbSrc++ - 128) << 8;
|
|
cBlockSamples--;
|
|
|
|
*(LONG HUGE_T *)pbDst = MAKELONG(nPredSample, nStepIndex);
|
|
pbDst += sizeof(LONG);
|
|
|
|
|
|
//
|
|
// We have written the header for this block--now write the data
|
|
// chunk (which consists of a bunch of encoded nibbles). Note
|
|
// that if we don't have enough data to fill a complete byte, then
|
|
// we add a 0 nibble on the end.
|
|
//
|
|
while( cBlockSamples>0 )
|
|
{
|
|
//
|
|
// sample 1
|
|
//
|
|
nSample = ((short)*pbSrc++ - 128) << 8;
|
|
cBlockSamples--;
|
|
|
|
nStepSize = step[nStepIndex];
|
|
imaadpcmFastEncode(nEncSample1,nPredSample,nSample,nStepSize);
|
|
nStepIndex = imaadpcmNextStepIndex(nEncSample1, nStepIndex);
|
|
|
|
//
|
|
// sample 2
|
|
//
|
|
nEncSample2 = 0;
|
|
if( cBlockSamples>0 ) {
|
|
|
|
nSample = ((short)*pbSrc++ - 128) << 8;
|
|
cBlockSamples--;
|
|
|
|
nStepSize = step[nStepIndex];
|
|
imaadpcmFastEncode(nEncSample2,nPredSample,nSample,nStepSize);
|
|
nStepIndex = imaadpcmNextStepIndex(nEncSample2, nStepIndex);
|
|
}
|
|
|
|
//
|
|
// Write out encoded byte.
|
|
//
|
|
*pbDst++ = (BYTE)(nEncSample1 | (nEncSample2 << 4));
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Restore the value of the Step Index, to be used on the next buffer.
|
|
//
|
|
(*pnStepIndexL) = nStepIndex;
|
|
|
|
|
|
//
|
|
// 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);
|
|
|
|
} // imaadpcmEncode4Bit_M08()
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD FNGLOBAL imaadpcmEncode4Bit_M16
|
|
(
|
|
HPBYTE pbSrc,
|
|
DWORD cbSrcLength,
|
|
HPBYTE pbDst,
|
|
UINT nBlockAlignment,
|
|
UINT cSamplesPerBlock,
|
|
int * pnStepIndexL,
|
|
int * pnStepIndexR
|
|
)
|
|
{
|
|
HPBYTE pbDstStart;
|
|
DWORD cSrcSamples;
|
|
UINT cBlockSamples;
|
|
int nSample;
|
|
int nStepSize;
|
|
|
|
int nEncSample1;
|
|
int nEncSample2;
|
|
int nPredSample;
|
|
int nStepIndex;
|
|
|
|
|
|
pbDstStart = pbDst;
|
|
cSrcSamples = pcmM16BytesToSamples(cbSrcLength);
|
|
|
|
//
|
|
// Restore the Step Index to that of the final convert of the previous
|
|
// buffer. Remember to restore this value to psi->nStepIndexL.
|
|
//
|
|
nStepIndex = (*pnStepIndexL);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
while (0 != cSrcSamples)
|
|
{
|
|
cBlockSamples = (UINT)min(cSrcSamples, cSamplesPerBlock);
|
|
cSrcSamples -= cBlockSamples;
|
|
|
|
//
|
|
// block header
|
|
//
|
|
nPredSample = *(short HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(short);
|
|
cBlockSamples--;
|
|
|
|
*(LONG HUGE_T *)pbDst = MAKELONG(nPredSample, nStepIndex);
|
|
pbDst += sizeof(LONG);
|
|
|
|
|
|
//
|
|
// We have written the header for this block--now write the data
|
|
// chunk (which consists of a bunch of encoded nibbles). Note
|
|
// that if we don't have enough data to fill a complete byte, then
|
|
// we add a 0 nibble on the end.
|
|
//
|
|
while( cBlockSamples>0 )
|
|
{
|
|
//
|
|
// sample 1
|
|
//
|
|
nSample = *(short HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(short);
|
|
cBlockSamples--;
|
|
|
|
nStepSize = step[nStepIndex];
|
|
imaadpcmFastEncode(nEncSample1,nPredSample,nSample,nStepSize);
|
|
nStepIndex = imaadpcmNextStepIndex(nEncSample1, nStepIndex);
|
|
|
|
//
|
|
// sample 2
|
|
//
|
|
nEncSample2 = 0;
|
|
if( cBlockSamples>0 ) {
|
|
|
|
nSample = *(short HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(short);
|
|
cBlockSamples--;
|
|
|
|
nStepSize = step[nStepIndex];
|
|
imaadpcmFastEncode(nEncSample2,nPredSample,nSample,nStepSize);
|
|
nStepIndex = imaadpcmNextStepIndex(nEncSample2, nStepIndex);
|
|
}
|
|
|
|
//
|
|
// Write out encoded byte.
|
|
//
|
|
*pbDst++ = (BYTE)(nEncSample1 | (nEncSample2 << 4));
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Restore the value of the Step Index, to be used on the next buffer.
|
|
//
|
|
(*pnStepIndexL) = nStepIndex;
|
|
|
|
|
|
//
|
|
// 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);
|
|
|
|
} // imaadpcmEncode4Bit_M16()
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD FNGLOBAL imaadpcmEncode4Bit_S08
|
|
(
|
|
HPBYTE pbSrc,
|
|
DWORD cbSrcLength,
|
|
HPBYTE pbDst,
|
|
UINT nBlockAlignment,
|
|
UINT cSamplesPerBlock,
|
|
int * pnStepIndexL,
|
|
int * pnStepIndexR
|
|
)
|
|
{
|
|
HPBYTE pbDstStart;
|
|
DWORD cSrcSamples;
|
|
UINT cBlockSamples;
|
|
int nSample;
|
|
int nStepSize;
|
|
DWORD dwLeft;
|
|
DWORD dwRight;
|
|
int i;
|
|
|
|
int nEncSampleL;
|
|
int nPredSampleL;
|
|
int nStepIndexL;
|
|
|
|
int nEncSampleR;
|
|
int nPredSampleR;
|
|
int nStepIndexR;
|
|
|
|
|
|
pbDstStart = pbDst;
|
|
cSrcSamples = pcmS08BytesToSamples(cbSrcLength);
|
|
|
|
//
|
|
// Restore the Step Index to that of the final convert of the previous
|
|
// buffer. Remember to restore this value to psi->nStepIndexL,R.
|
|
//
|
|
nStepIndexL = (*pnStepIndexL);
|
|
nStepIndexR = (*pnStepIndexR);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
while( 0 != cSrcSamples )
|
|
{
|
|
//
|
|
// The samples should always be block aligned.
|
|
//
|
|
ASSERT( cSrcSamples >= cSamplesPerBlock );
|
|
|
|
cBlockSamples = cSamplesPerBlock;
|
|
cSrcSamples -= cBlockSamples;
|
|
|
|
//
|
|
// LEFT channel block header
|
|
//
|
|
nPredSampleL = ((short)*pbSrc++ - 128) << 8;
|
|
|
|
*(LONG HUGE_T *)pbDst = MAKELONG(nPredSampleL, nStepIndexL);
|
|
pbDst += sizeof(LONG);
|
|
|
|
//
|
|
// RIGHT channel block header
|
|
//
|
|
nPredSampleR = ((short)*pbSrc++ - 128) << 8;
|
|
|
|
*(LONG HUGE_T *)pbDst = MAKELONG(nPredSampleR, nStepIndexR);
|
|
pbDst += sizeof(LONG);
|
|
|
|
|
|
cBlockSamples--; // One sample is in the header.
|
|
|
|
|
|
//
|
|
// We have written the header for this block--now write the data
|
|
// chunk. This consists of 8 left samples (one DWORD of output)
|
|
// followed by 8 right samples (also one DWORD). Since the input
|
|
// samples are interleaved, we create the left and right DWORDs
|
|
// sample by sample, and then write them both out.
|
|
//
|
|
ASSERT( 0 == cBlockSamples%8 );
|
|
while( 0 != cBlockSamples )
|
|
{
|
|
cBlockSamples -= 8;
|
|
dwLeft = 0;
|
|
dwRight = 0;
|
|
|
|
for( i=0; i<8; i++ )
|
|
{
|
|
//
|
|
// LEFT channel
|
|
//
|
|
nSample = ((short)*pbSrc++ - 128) << 8;
|
|
nStepSize = step[nStepIndexL];
|
|
imaadpcmFastEncode(nEncSampleL,nPredSampleL,nSample,nStepSize);
|
|
nStepIndexL = imaadpcmNextStepIndex(nEncSampleL, nStepIndexL);
|
|
dwLeft |= ((DWORD)nEncSampleL) << 4*i;
|
|
|
|
//
|
|
// RIGHT channel
|
|
//
|
|
nSample = ((short)*pbSrc++ - 128) << 8;
|
|
nStepSize = step[nStepIndexR];
|
|
imaadpcmFastEncode(nEncSampleR,nPredSampleR,nSample,nStepSize);
|
|
nStepIndexR = imaadpcmNextStepIndex(nEncSampleR, nStepIndexR);
|
|
dwRight |= ((DWORD)nEncSampleR) << 4*i;
|
|
}
|
|
|
|
|
|
//
|
|
// Write out encoded DWORDs.
|
|
//
|
|
*(DWORD HUGE_T *)pbDst = dwLeft;
|
|
pbDst += sizeof(DWORD);
|
|
*(DWORD HUGE_T *)pbDst = dwRight;
|
|
pbDst += sizeof(DWORD);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Restore the value of the Step Index, to be used on the next buffer.
|
|
//
|
|
(*pnStepIndexL) = nStepIndexL;
|
|
(*pnStepIndexR) = nStepIndexR;
|
|
|
|
|
|
//
|
|
// 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);
|
|
|
|
} // imaadpcmEncode4Bit_S08()
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD FNGLOBAL imaadpcmEncode4Bit_S16
|
|
(
|
|
HPBYTE pbSrc,
|
|
DWORD cbSrcLength,
|
|
HPBYTE pbDst,
|
|
UINT nBlockAlignment,
|
|
UINT cSamplesPerBlock,
|
|
int * pnStepIndexL,
|
|
int * pnStepIndexR
|
|
)
|
|
{
|
|
HPBYTE pbDstStart;
|
|
DWORD cSrcSamples;
|
|
UINT cBlockSamples;
|
|
int nSample;
|
|
int nStepSize;
|
|
DWORD dwLeft;
|
|
DWORD dwRight;
|
|
int i;
|
|
|
|
int nEncSampleL;
|
|
int nPredSampleL;
|
|
int nStepIndexL;
|
|
|
|
int nEncSampleR;
|
|
int nPredSampleR;
|
|
int nStepIndexR;
|
|
|
|
|
|
pbDstStart = pbDst;
|
|
cSrcSamples = pcmS16BytesToSamples(cbSrcLength);
|
|
|
|
//
|
|
// Restore the Step Index to that of the final convert of the previous
|
|
// buffer. Remember to restore this value to psi->nStepIndexL,R.
|
|
//
|
|
nStepIndexL = (*pnStepIndexL);
|
|
nStepIndexR = (*pnStepIndexR);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
while( 0 != cSrcSamples )
|
|
{
|
|
//
|
|
// The samples should always be block aligned.
|
|
//
|
|
ASSERT( cSrcSamples >= cSamplesPerBlock );
|
|
|
|
cBlockSamples = cSamplesPerBlock;
|
|
cSrcSamples -= cBlockSamples;
|
|
|
|
|
|
//
|
|
// LEFT channel block header
|
|
//
|
|
nPredSampleL = *(short HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(short);
|
|
|
|
*(LONG HUGE_T *)pbDst = MAKELONG(nPredSampleL, nStepIndexL);
|
|
pbDst += sizeof(LONG);
|
|
|
|
//
|
|
// RIGHT channel block header
|
|
//
|
|
nPredSampleR = *(short HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(short);
|
|
|
|
*(LONG HUGE_T *)pbDst = MAKELONG(nPredSampleR, nStepIndexR);
|
|
pbDst += sizeof(LONG);
|
|
|
|
|
|
cBlockSamples--; // One sample is in the header.
|
|
|
|
|
|
//
|
|
// We have written the header for this block--now write the data
|
|
// chunk. This consists of 8 left samples (one DWORD of output)
|
|
// followed by 8 right samples (also one DWORD). Since the input
|
|
// samples are interleaved, we create the left and right DWORDs
|
|
// sample by sample, and then write them both out.
|
|
//
|
|
ASSERT( 0 == cBlockSamples%8 );
|
|
while( 0 != cBlockSamples )
|
|
{
|
|
cBlockSamples -= 8;
|
|
dwLeft = 0;
|
|
dwRight = 0;
|
|
|
|
for( i=0; i<8; i++ )
|
|
{
|
|
//
|
|
// LEFT channel
|
|
//
|
|
nSample = *(short HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(short);
|
|
|
|
nStepSize = step[nStepIndexL];
|
|
imaadpcmFastEncode(nEncSampleL,nPredSampleL,nSample,nStepSize);
|
|
nStepIndexL = imaadpcmNextStepIndex(nEncSampleL, nStepIndexL);
|
|
dwLeft |= ((DWORD)nEncSampleL) << 4*i;
|
|
|
|
//
|
|
// RIGHT channel
|
|
//
|
|
nSample = *(short HUGE_T *)pbSrc;
|
|
pbSrc += sizeof(short);
|
|
|
|
nStepSize = step[nStepIndexR];
|
|
imaadpcmFastEncode(nEncSampleR,nPredSampleR,nSample,nStepSize);
|
|
nStepIndexR = imaadpcmNextStepIndex(nEncSampleR, nStepIndexR);
|
|
dwRight |= ((DWORD)nEncSampleR) << 4*i;
|
|
}
|
|
|
|
|
|
//
|
|
// Write out encoded DWORDs.
|
|
//
|
|
*(DWORD HUGE_T *)pbDst = dwLeft;
|
|
pbDst += sizeof(DWORD);
|
|
*(DWORD HUGE_T *)pbDst = dwRight;
|
|
pbDst += sizeof(DWORD);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Restore the value of the Step Index, to be used on the next buffer.
|
|
//
|
|
(*pnStepIndexL) = nStepIndexL;
|
|
(*pnStepIndexR) = nStepIndexR;
|
|
|
|
|
|
//
|
|
// 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);
|
|
|
|
} // imaadpcmEncode4Bit_S16()
|
|
|