home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Microsoft Multimedia Jumpstart 1.1a
/
CD_ROM.BIN
/
develpmt
/
source
/
waveconv
/
msadpcm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-12
|
40KB
|
1,199 lines
/** msadpcm.c
*
(C) Copyright Microsoft Corp. 1991, 1992. All rights reserved.
You have a royalty-free right to use, modify, reproduce and
distribute the Sample Files (and/or any modified version) in
any way you find useful, provided that you agree that
Microsoft has no warranty obligations or liability for any
Sample Application Files which are modified.
If you did not get this from Microsoft Sources, then it may not be the
most current version. This sample code in particular will be updated
and include more documentation.
Sources are:
The MM Sys File Transfer BBS: The phone number is 206 936-4082.
CompuServe: WINSDK forum, MDK section.
Anonymous FTP from ftp.uu.net vendors\microsoft\multimedia
*/
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include "mmreg.h"
#include "msadpcm.h"
//
// constants used by the Microsoft 4 Bit ADPCM algorithm
//
// CAUTION: the code contained in this file assumes that the number of
// channels will be no greater than 2! this is for minor optimization
// purposes and would be very easy to change if >2 channels is required.
// it also assumes that the PCM data will either be 8 or 16 bit.
//
// the code to look out for looks 'similar' to this:
//
// PCM.BytesPerSample = (PCM.BitsPerSample >> 3) << (Channels >> 1);
//
#define MSADPCM_NUM_COEF (7)
#define MSADPCM_MAX_CHANNELS (2)
#define MSADPCM_CSCALE (8)
#define MSADPCM_PSCALE (8)
#define MSADPCM_CSCALE_NUM (1 << MSADPCM_CSCALE)
#define MSADPCM_PSCALE_NUM (1 << MSADPCM_PSCALE)
#define MSADPCM_DELTA4_MIN (16)
#define MSADPCM_OUTPUT4_MAX (7)
#define MSADPCM_OUTPUT4_MIN (-8)
//
// Fixed point Delta adaption table:
//
// Next Delta = Delta * gaiP4[ this output ] / MSADPCM_PSCALE
//
static short gaiP4[] = { 230, 230, 230, 230, 307, 409, 512, 614,
768, 614, 512, 409, 307, 230, 230, 230 };
/** DWORD FAR PASCAL adpcmDecode4Bit(LPADPCMWAVEFORMAT lpwfADPCM, HPSTR hpSrc, LPPCMWAVEFORMAT lpwfPCM, HPSTR hpDst, DWORD dwSrcLen)
*
* DESCRIPTION:
*
*
* ARGUMENTS:
* (LPADPCMWAVEFORMAT lpwfADPCM, HPSTR hpSrc, LPPCMWAVEFORMAT lpwfPCM, HPSTR hpDst, DWORD dwSrcLen)
*
* RETURN (DWORD FAR PASCAL):
*
*
* NOTES:
*
** */
DWORD FAR PASCAL adpcmDecode4Bit(LPADPCMWAVEFORMAT lpwfADPCM, HPSTR hpSrc, LPPCMWAVEFORMAT lpwfPCM, HPSTR hpDst, DWORD dwSrcLen)
{
short iInput;
short iNextInput;
short iFirstNibble;
short iDelta;
long lSamp;
long lPrediction;
BYTE bPredictors;
BYTE bChannels;
BYTE bBitsPerSample;
BYTE m;
WORD n;
WORD wSamplesPerBlock;
WORD wBlockHeaderBytes;
DWORD dwTotalPos;
DWORD dwDecoded;
short aiSamp1[MSADPCM_MAX_CHANNELS];
short aiSamp2[MSADPCM_MAX_CHANNELS];
short aiCoef1[MSADPCM_MAX_CHANNELS];
short aiCoef2[MSADPCM_MAX_CHANNELS];
short aiDelta[MSADPCM_MAX_CHANNELS];
LPADPCMCOEFSET lpCoefSet;
//
// put some commonly used info in more accessible variables and init
// the wBlockHeaderBytes, dwDecoded and dwTotalPos vars...
//
lpCoefSet = &lpwfADPCM->aCoef[0];
bPredictors = (BYTE)lpwfADPCM->wNumCoef;
bChannels = (BYTE)lpwfADPCM->wfx.nChannels;
bBitsPerSample = (BYTE)lpwfPCM->wBitsPerSample;
wSamplesPerBlock = lpwfADPCM->wSamplesPerBlock;
wBlockHeaderBytes = bChannels * 7;
dwDecoded = 0L;
dwTotalPos = 0L;
//
// step through each byte of ADPCM data and decode it to the requested
// PCM format (8 or 16 bit).
//
while (dwTotalPos < dwSrcLen)
{
//
// the first thing we need to do with each block of ADPCM data is
// to read the header which consists of 7 bytes of data per channel.
// so our first check is to make sure that we have _at least_
// enough input data for a complete ADPCM block header--if there
// is not enough data for the header, then exit.
//
// the header looks like this:
// 1 byte predictor per channel
// 2 byte delta per channel
// 2 byte first sample per channel
// 2 byte second sample per channel
//
// this gives us (7 * bChannels) bytes of header information. note
// that as long as there is _at least_ (7 * bChannels) of header
// info, we will grab the two samples from the header (and if no
// data exists following the header we will exit in the decode
// loop below).
//
dwTotalPos += wBlockHeaderBytes;
if (dwTotalPos > dwSrcLen)
goto adpcmDecode4BitExit;
//
// grab and validate the predictor for each channel
//
for (m = 0; m < bChannels; m++)
{
BYTE bPredictor;
bPredictor = (BYTE)(*hpSrc++);
if (bPredictor >= bPredictors)
{
//
// the predictor is out of range--this is considered a
// fatal error with the ADPCM data, so we fail by returning
// zero bytes decoded
//
dwDecoded = 0;
goto adpcmDecode4BitExit;
}
//
// get the coefficients for the predictor index
//
aiCoef1[m] = lpCoefSet[bPredictor].iCoef1;
aiCoef2[m] = lpCoefSet[bPredictor].iCoef2;
}
//
// get the starting delta for each channel
//
for (m = 0; m < bChannels; m++)
{
aiDelta[m] = *(short huge *)hpSrc;
hpSrc++;
hpSrc++;
}
//
// get the sample just previous to the first encoded sample per
// channel
//
for (m = 0; m < bChannels; m++)
{
aiSamp1[m] = *(short huge *)hpSrc;
hpSrc++;
hpSrc++;
}
//
// get the sample previous to aiSamp1[x] per channel
//
for (m = 0; m < bChannels; m++)
{
aiSamp2[m] = *(short huge *)hpSrc;
hpSrc++;
hpSrc++;
}
//
// write out first 2 samples for each channel.
//
// NOTE: the samples are written to the destination PCM buffer
// in the _reverse_ order that they are in the header block:
// remember that aiSamp2[x] is the _previous_ sample to aiSamp1[x].
//
if (bBitsPerSample == (BYTE)8)
{
for (m = 0; m < bChannels; m++)
{
*hpDst++ = (char)((aiSamp2[m] >> 8) + 128);
}
for (m = 0; m < bChannels; m++)
{
*hpDst++ = (char)((aiSamp1[m] >> 8) + 128);
}
}
else
{
for (m = 0; m < bChannels; m++)
{
*(short huge *)hpDst = aiSamp2[m];
hpDst++;
hpDst++;
}
for (m = 0; m < bChannels; m++)
{
*(short huge *)hpDst = aiSamp1[m];
hpDst++;
hpDst++;
}
}
//
// we have decoded the first two samples for this block, so add
// two to our decoded count
//
dwDecoded += 2;
//
// we now need to decode the 'data' section of the ADPCM block.
// this consists of packed 4 bit nibbles.
//
// NOTE: we start our count for the number of data bytes to decode
// at 2 because we have already decoded the first 2 samples in
// this block.
//
iFirstNibble = 1;
for (n = 2; n < wSamplesPerBlock; n++)
{
for (m = 0; m < bChannels; m++)
{
if (iFirstNibble)
{
//
// we need to grab the next byte to decode--make sure
// that there is a byte for us to grab before continue
//
dwTotalPos++;
if (dwTotalPos > dwSrcLen)
goto adpcmDecode4BitExit;
//
// grab the next two nibbles and create sign extended
// integers out of them:
//
// iInput is the first nibble to decode
// iNextInput will be the next nibble decoded
//
iNextInput = (short)*hpSrc++;
iInput = iNextInput >> 4;
iNextInput = (iNextInput << 12) >> 12;
iFirstNibble = 0;
}
else
{
//
// put the next sign extended nibble into iInput and
// decode it--also set iFirstNibble back to 1 so we
// will read another byte from the source stream on
// the next iteration...
//
iInput = iNextInput;
iFirstNibble = 1;
}
//
// compute the next Adaptive Scale Factor (ASF) and put
// this value in aiDelta for the current channel.
//
iDelta = aiDelta[m];
aiDelta[m] = (short)((gaiP4[iInput & 15] * (long)iDelta) >> MSADPCM_PSCALE);
if (aiDelta[m] < MSADPCM_DELTA4_MIN)
aiDelta[m] = MSADPCM_DELTA4_MIN;
//
// decode iInput (the sign extended 4 bit nibble)--there are
// two steps to this:
//
// 1. predict the next sample using the previous two
// samples and the predictor coefficients:
//
// Prediction = (aiSamp1[channel] * aiCoef1[channel] +
// aiSamp2[channel] * aiCoef2[channel]) / 256;
//
// 2. reconstruct the original PCM sample using the encoded
// sample (iInput), the Adaptive Scale Factor (aiDelta)
// and the prediction value computed in step 1 above.
//
// Sample = (iInput * aiDelta[channel]) + Prediction;
//
lPrediction = (((long)aiSamp1[m] * aiCoef1[m]) +
((long)aiSamp2[m] * aiCoef2[m])) >> MSADPCM_CSCALE;
lSamp = ((long)iInput * iDelta) + lPrediction;
//
// now we need to clamp lSamp to [-32768..32767]--this value
// will then be a valid 16 bit sample.
//
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// lSamp contains the decoded iInput sample--now write it
// out to the destination buffer
//
if (bBitsPerSample == (BYTE)8)
{
*hpDst++ = (char)(((short)lSamp >> 8) + 128);
}
else
{
*(short huge *)hpDst = (short)lSamp;
hpDst++;
hpDst++;
}
//
// ripple our previous samples down making the new aiSamp1
// equal to the sample we just decoded
//
aiSamp2[m] = aiSamp1[m];
aiSamp1[m] = (short)lSamp;
}
//
// we have decoded one more complete sample
//
dwDecoded++;
}
}
//
// we're done decoding the input data. dwDecoded contains the number
// of complete _SAMPLES_ that were decoded. we need to return the
// number of _BYTES_ decoded. so calculate the number of bytes per
// sample and multiply that with dwDecoded...
//
adpcmDecode4BitExit:
return (dwDecoded * ((bBitsPerSample >> (BYTE)3) << (bChannels >> 1)));
} /* adpcmDecode4Bit() */
/** short NEAR PASCAL adpcmEncode4Bit_FirstDelta(short iCoef1, short iCoef2, short iP5, short iP4, short iP3, short iP2, short iP1)
*
* DESCRIPTION:
*
*
* ARGUMENTS:
* (short iCoef1, short iCoef2, short iP5, short iP4, short iP3, short iP2, short iP1)
*
* RETURN (short NEAR PASCAL):
*
*
* NOTES:
*
** */
short NEAR PASCAL adpcmEncode4Bit_FirstDelta(short iCoef1, short iCoef2, short iP5, short iP4, short iP3, short iP2, short iP1)
{
long lTotal;
short iRtn;
long lTemp;
//
// use average of 3 predictions
//
lTemp = (((long)iP5 * iCoef2) + ((long)iP4 * iCoef1)) >> MSADPCM_CSCALE;
lTotal = (lTemp > iP3) ? (lTemp - iP3) : (iP3 - lTemp);
lTemp = (((long)iP4 * iCoef2) + ((long)iP3 * iCoef1)) >> MSADPCM_CSCALE;
lTotal += (lTemp > iP2) ? (lTemp - iP2) : (iP2 - lTemp);
lTemp = (((long)iP3 * iCoef2) + ((long)iP2 * iCoef1)) >> MSADPCM_CSCALE;
lTotal += (lTemp > iP1) ? (lTemp - iP1) : (iP1 - lTemp);
//
// optimal iDelta is 1/4 of prediction error
//
iRtn = (short)(lTotal / 12);
if (iRtn < MSADPCM_DELTA4_MIN)
iRtn = MSADPCM_DELTA4_MIN;
return (iRtn);
} /* adpcmEncode4Bit_FirstDelta() */
/** DWORD FAR PASCAL adpcmEncode4Bit(LPPCMWAVEFORMAT lpwfPCM, HPSTR hpSrc, LPADPCMWAVEFORMAT lpwfADPCM, HPSTR hpDst, DWORD dwSrcLen)
*
* DESCRIPTION:
*
*
* ARGUMENTS:
* (LPPCMWAVEFORMAT lpwfPCM, HPSTR hpSrc, LPADPCMWAVEFORMAT lpwfADPCM, HPSTR hpDst, DWORD dwSrcLen)
*
* RETURN (DWORD FAR PASCAL):
*
*
* NOTES:
*
** */
#define ENCODE_DELTA_LOOKAHEAD 5
DWORD FAR PASCAL adpcmEncode4Bit(LPPCMWAVEFORMAT lpwfPCM, HPSTR hpSrc, LPADPCMWAVEFORMAT lpwfADPCM, HPSTR hpDst, DWORD dwSrcLen)
{
LPSTR lpSamplesBuf;
LPSTR lpSamples;
BYTE abBestPredictor[MSADPCM_MAX_CHANNELS];
DWORD adwTotalError[MSADPCM_NUM_COEF][MSADPCM_MAX_CHANNELS];
short aiSamples[ENCODE_DELTA_LOOKAHEAD][MSADPCM_MAX_CHANNELS];
short aiFirstDelta[MSADPCM_NUM_COEF][MSADPCM_MAX_CHANNELS];
short aiDelta[MSADPCM_MAX_CHANNELS];
short aiSamp1[MSADPCM_MAX_CHANNELS];
short aiSamp2[MSADPCM_MAX_CHANNELS];
short iCoef1;
short iCoef2;
short iSamp1;
short iSamp2;
short iDelta;
short iSample;
short iOutput;
long lSamp;
DWORD dw;
DWORD dwTotalConverted;
DWORD dwInputPos;
long lError;
long lPrediction;
WORD wSamplesPerBlock;
WORD cbSample;
WORD wBlockHeaderBytes;
WORD wBlockSize;
WORD wNextWrite;
WORD wFirstNibble;
WORD n;
BYTE m;
BYTE i;
BYTE bChannels;
BYTE bBitsPerSample;
//
// first copy some information into more accessible (cheaper and shorter)
// variables--and precompute some stuff...
//
wSamplesPerBlock = lpwfADPCM->wSamplesPerBlock;
bChannels = (BYTE)lpwfPCM->wf.nChannels;
bBitsPerSample = (BYTE)lpwfPCM->wBitsPerSample;
wBlockHeaderBytes = bChannels * 7;
dwInputPos = 0L;
dwTotalConverted = 0L;
//
// calculate the number of bytes per sample in the PCM data
//
// note: the following code works because we _know_ that we only deal
// with 8 or 16 bits per sample PCM and 1 or 2 channels..
//
cbSample = (bBitsPerSample >> 3) << (bChannels >> 1);
//
// we allocate and use a small buffer (<64k) to hold an entire block of
// samples to be encoded. the reason for this is mainly because we
// make 8 passes over the data per block and using huge pointers all
// of the time is expensive. so we put it in a <64k chunk and eliminate
// the huge pointer stuff
//
lpSamplesBuf = GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE, wSamplesPerBlock * cbSample);
if (!lpSamplesBuf)
return (0L);
//
// step through each block of PCM data and encode it to 4 bit ADPCM
//
for ( ; dwInputPos < dwSrcLen; dwInputPos += (wBlockSize * cbSample))
{
//
// determine how much data we should encode for this block--this
// will be wSamplesPerBlock until we hit the last chunk of PCM
// data that will not fill a complete block. so on the last block
// we only encode that amount of data remaining...
//
dw = (dwSrcLen - dwInputPos) / cbSample;
wBlockSize = (WORD)min((DWORD)wSamplesPerBlock, dw);
if (!wBlockSize)
break;
//
// copy the samples that we will be encoding into our small data
// samples buffer (this is faster than doing huge pointer arith
// all of the time)
//
hmemcpy(lpSamplesBuf, &hpSrc[dwInputPos], wBlockSize * cbSample);
//
// find the optimal predictor for each channel: to do this, we
// must step through and encode using each coefficient set (one
// at a time) and determine which one has the least error from
// the original data. the one with the least error is then used
// for the final encode (the 8th pass done below).
//
// NOTE: keeping the encoded data of the one that has the least
// error at all times is an obvious optimization that should be
// done. in this way, we only need to do 7 passes instead of 8.
//
for (i = 0; i < MSADPCM_NUM_COEF; i++)
{
//
// reset pointer to beginning of our temporary small data
// samples buffer
//
lpSamples = lpSamplesBuf;
//
// copy the coefficient pair for the current coefficient set
// we are using into more convenient/cheaper variables
//
iCoef1 = lpwfADPCM->aCoef[i].iCoef1;
iCoef2 = lpwfADPCM->aCoef[i].iCoef2;
//
// we need to choose the first iDelta--to do this, we need
// to look at the first few samples. for convenience, we copy
// the first ENCODE_DELTA_LOOKAHEAD samples (converted to
// 16 bit samples) into a temporary buffer
//
for (n = 0; n < ENCODE_DELTA_LOOKAHEAD; n++)
{
for (m = 0; m < bChannels; m++)
{
if (bBitsPerSample != 8)
{
iSample = *(short far *)lpSamples;
lpSamples++;
lpSamples++;
}
else
iSample = ((short)*lpSamples++ - 128) << 8;
aiSamples[n][m] = iSample;
}
}
//
// now choose the first iDelta and setup the first two samples
// based on the 16 samples we copied from the source data above
// for each channel
//
for (m = 0; m < bChannels; m++)
{
//
// reset total error calculation for new block
//
adwTotalError[i][m] = 0L;
//
// first 2 samples will come from real data--compute
// starting from there
//
aiSamp1[m] = aiSamples[1][m];
aiSamp2[m] = aiSamples[0][m];
//
// calculate initial iDelta
//
iDelta = adpcmEncode4Bit_FirstDelta(iCoef1, iCoef2,
aiSamples[0][m], aiSamples[1][m], aiSamples[2][m],
aiSamples[3][m], aiSamples[4][m]);
aiDelta[m] = aiFirstDelta[i][m] = iDelta;
}
//
// step over first two complete samples--we took care of them
// above
//
lpSamples = &lpSamplesBuf[cbSample * 2];
//
// now encode the rest of the PCM data in this block--note
// we start 2 samples ahead because the first two samples are
// simply copied into the ADPCM block header...
//
for (n = 2; n < wBlockSize; n++)
{
//
// each channel gets encoded independently... obviously.
//
for (m = 0; m < bChannels; m++)
{
//
// yes, copy into cheaper variables because we access
// them a lot
//
iSamp1 = aiSamp1[m];
iSamp2 = aiSamp2[m];
iDelta = aiDelta[m];
//
// calculate the prediction based on the previous two
// samples
//
lPrediction = ((long)iSamp1 * iCoef1 +
(long)iSamp2 * iCoef2) >> MSADPCM_CSCALE;
//
// grab the sample (for the current channel) to encode
// from the source and convert it to a 16 bit data if
// necessary
//
if (bBitsPerSample != 8)
{
iSample = *(short far *)lpSamples;
lpSamples++;
lpSamples++;
}
else
iSample = ((short)*lpSamples++ - 128) << 8;
//
// encode it
//
lError = (long)iSample - lPrediction;
iOutput = (short)(lError / iDelta);
if (iOutput > MSADPCM_OUTPUT4_MAX)
iOutput = MSADPCM_OUTPUT4_MAX;
else if (iOutput < MSADPCM_OUTPUT4_MIN)
iOutput = MSADPCM_OUTPUT4_MIN;
lSamp = lPrediction + ((long)iDelta * iOutput);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDelta = (short)((gaiP4[iOutput & 15] * (long)iDelta) >> MSADPCM_PSCALE);
if (iDelta < MSADPCM_DELTA4_MIN)
iDelta = MSADPCM_DELTA4_MIN;
//
// save updated values for this channel back into the
// original arrays...
//
aiDelta[m] = iDelta;
aiSamp2[m] = iSamp1;
aiSamp1[m] = (short)lSamp;
//
// keep a running status on the error for the current
// coefficient pair for this channel
//
lError = lSamp - iSample;
adwTotalError[i][m] += (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 (this is for each
// channel of course)
//
for (m = 0; m < bChannels; m++)
{
abBestPredictor[m] = 0;
dw = adwTotalError[0][m];
for (i = 1; i < MSADPCM_NUM_COEF; i++)
{
if (adwTotalError[i][m] < dw)
{
abBestPredictor[m] = i;
dw = adwTotalError[i][m];
}
}
}
//
// reset pointer to beginning of our temporary samples buffer--
// we're going to make our final pass on the data with the optimal
// predictor that we found above
//
lpSamples = lpSamplesBuf;
//
// grab first iDelta from our precomputed first deltas that we
// calculated above
//
for (m = 0; m < bChannels; m++)
{
i = abBestPredictor[m];
aiDelta[m] = aiFirstDelta[i][m];
}
//
// get the first two samples from the source data (so we can write
// them into the ADPCM block header and use them in our prediction
// calculation when encoding the rest of the data).
//
if (bBitsPerSample != 8)
{
for (m = 0; m < bChannels; m++)
{
aiSamp2[m] = *(short far *)lpSamples;
lpSamples++;
lpSamples++;
}
for (m = 0; m < bChannels; m++)
{
aiSamp1[m] = *(short far *)lpSamples;
lpSamples++;
lpSamples++;
}
}
else
{
for (m = 0; m < bChannels; m++)
{
aiSamp2[m] = ((short)*lpSamples++ - 128) << 8;
}
for (m = 0; m < bChannels; m++)
{
aiSamp1[m] = ((short)*lpSamples++ - 128) << 8;
}
}
//
// 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 sample per channel
// 2 byte second sample per channel
//
// this gives us (7 * bChannels) bytes of header information
//
// so first write the 1 byte predictor for each channel into the
// destination buffer
//
for (m = 0; m < bChannels; m++)
{
*hpDst++ = abBestPredictor[m];
}
//
// now write the 2 byte delta per channel...
//
for (m = 0; m < bChannels; m++)
{
*(short huge *)hpDst = aiDelta[m];
hpDst++;
hpDst++;
}
//
// finally, write the first two samples (2 bytes each per channel)
//
for (m = 0; m < bChannels; m++)
{
*(short huge *)hpDst = aiSamp1[m];
hpDst++;
hpDst++;
}
for (m = 0; m < bChannels; m++)
{
*(short huge *)hpDst = aiSamp2[m];
hpDst++;
hpDst++;
}
//
// the number of bytes that we have written to the destination
// buffer is (7 * bChannels)--so add this to our total number of
// bytes written to the destination.. for our return value.
//
dwTotalConverted += wBlockHeaderBytes;
//
// we have written the header for this block--now write the data
// chunk (which consists of a bunch of encoded nibbles). note that
// we start our count at 2 because we already wrote the first
// two samples into the destination buffer as part of the header
//
wFirstNibble = 1;
for (n = 2; n < wBlockSize; n++)
{
//
// each channel gets encoded independently... obviously.
//
for (m = 0; m < bChannels; m++)
{
//
// use our chosen best predictor and grab the coefficient
// pair to use for this channel...
//
i = abBestPredictor[m];
iCoef1 = lpwfADPCM->aCoef[i].iCoef1;
iCoef2 = lpwfADPCM->aCoef[i].iCoef2;
//
// copy into cheaper variables because we access them a lot
//
iSamp1 = aiSamp1[m];
iSamp2 = aiSamp2[m];
iDelta = aiDelta[m];
//
// calculate the prediction based on the previous two samples
//
lPrediction = ((long)iSamp1 * iCoef1 +
(long)iSamp2 * iCoef2) >> MSADPCM_CSCALE;
//
// grab the sample to encode--convert it to 16 bit data if
// necessary...
//
if (bBitsPerSample != 8)
{
iSample = *(short far *)lpSamples;
lpSamples++;
lpSamples++;
}
else
iSample = ((short)*lpSamples++ - 128) << 8;
//
// encode the sample
//
lError = (long)iSample - lPrediction;
iOutput = (short)(lError / iDelta);
if (iOutput > MSADPCM_OUTPUT4_MAX)
iOutput = MSADPCM_OUTPUT4_MAX;
else if (iOutput < MSADPCM_OUTPUT4_MIN)
iOutput = MSADPCM_OUTPUT4_MIN;
lSamp = lPrediction + ((long)iDelta * iOutput);
if (lSamp > 32767)
lSamp = 32767;
else if (lSamp < -32768)
lSamp = -32768;
//
// compute the next iDelta
//
iDelta = (short)((gaiP4[iOutput&15] * (long)iDelta) >> MSADPCM_PSCALE);
if (iDelta < MSADPCM_DELTA4_MIN)
iDelta = MSADPCM_DELTA4_MIN;
//
// save updated values for this channel back into the
// original arrays...
//
aiDelta[m] = iDelta;
aiSamp2[m] = iSamp1;
aiSamp1[m] = (short)lSamp;
//
// we have another nibble of encoded data--either combine
// this with the previous nibble and write out a full
// byte, or save this nibble for the next nibble to be
// combined into a full byte and written to the destination
// buffer... uhg!
//
if (wFirstNibble)
{
wNextWrite = (iOutput & 15) << 4;
wFirstNibble = 0;
}
else
{
*hpDst++ = (BYTE)(wNextWrite | (iOutput & 15));
dwTotalConverted += 1;
wFirstNibble++;
}
}
}
}
//
// free the memory used for our small data buffer and return the number
// of bytes that we wrote into the destination buffer...
//
GlobalFreePtr(lpSamplesBuf);
return (dwTotalConverted);
} /* adpcmEncode4Bit() */
//---------------------------------------------------------------------------
//
// the code below provides 'support' routines for building/verifying ADPCM
// headers, etc.
//
// the coefficient pairs that should be in the wave format header for
// the Microsoft 4 Bit ADPCM algorithm. the code to copy the coefficients
// into the wave format header is shown:
//
// short gaiCoef1[] = { 256, 512, 0, 192, 240, 460, 392 };
// short gaiCoef2[] = { 0, -256, 0, 64, 0, -208, -232 };
//
// for (w = 0; w < MSADPCM_NUM_COEF; w++)
// {
// lpwfADPCM->aCoef[w].iCoef1 = gaiCoef1[w];
// lpwfADPCM->aCoef[w].iCoef2 = gaiCoef2[w];
// }
//
//---------------------------------------------------------------------------
static short gaiCoef1[] = { 256, 512, 0, 192, 240, 460, 392 };
static short gaiCoef2[] = { 0, -256, 0, 64, 0, -208, -232 };
/** BOOL FAR PASCAL adpcmIsValidFormat(LPWAVEFORMATEX lpwfx)
*
* DESCRIPTION:
*
*
* ARGUMENTS:
* (LPWAVEFORMATEX lpwfx)
*
* RETURN (BOOL FAR PASCAL):
*
*
* NOTES:
*
** */
BOOL FAR PASCAL adpcmIsValidFormat(LPWAVEFORMATEX lpwfx)
{
LPADPCMWAVEFORMAT lpwfADPCM;
WORD w;
if (!lpwfx)
return (FALSE);
if (lpwfx->wFormatTag != WAVE_FORMAT_ADPCM)
return (FALSE);
if (lpwfx->wBitsPerSample != 4)
return (FALSE);
if ((lpwfx->nChannels < 1) || (lpwfx->nChannels > MSADPCM_MAX_CHANNELS))
return (FALSE);
//
// check coef's to see if it is Microsoft's standard 4 Bit ADPCM
//
lpwfADPCM = (LPADPCMWAVEFORMAT)lpwfx;
if (lpwfADPCM->wNumCoef != MSADPCM_NUM_COEF)
return (FALSE);
for (w = 0; w < MSADPCM_NUM_COEF; w++)
{
if (lpwfADPCM->aCoef[w].iCoef1 != gaiCoef1[w])
return (FALSE);
if (lpwfADPCM->aCoef[w].iCoef2 != gaiCoef2[w])
return (FALSE);
}
return (TRUE);
} /* adpcmIsValidFormat() */
/** BOOL FAR PASCAL pcmIsValidFormat(LPWAVEFORMATEX lpwfx)
*
* DESCRIPTION:
*
*
* ARGUMENTS:
* (LPWAVEFORMATEX lpwfx)
*
* RETURN (BOOL FAR PASCAL):
*
*
* NOTES:
*
** */
BOOL FAR PASCAL pcmIsValidFormat(LPWAVEFORMATEX lpwfx)
{
if (!lpwfx)
return (FALSE);
if (lpwfx->wFormatTag != WAVE_FORMAT_PCM)
return (FALSE);
if ((lpwfx->wBitsPerSample != 8) && (lpwfx->wBitsPerSample != 16))
return (FALSE);
if ((lpwfx->nChannels < 1) || (lpwfx->nChannels > MSADPCM_MAX_CHANNELS))
return (FALSE);
return (TRUE);
} /* pcmIsValidFormat() */
/** BOOL FAR PASCAL adpcmBuildFormatHeader(LPWAVEFORMATEX lpwfxSrc, LPWAVEFORMATEX lpwfxDst)
*
* DESCRIPTION:
*
*
* ARGUMENTS:
* (LPWAVEFORMATEX lpwfxSrc, LPWAVEFORMATEX lpwfxDst)
*
* RETURN (BOOL FAR PASCAL):
*
*
* NOTES:
*
** */
BOOL FAR PASCAL adpcmBuildFormatHeader(LPWAVEFORMATEX lpwfxSrc, LPWAVEFORMATEX lpwfxDst)
{
LPADPCMWAVEFORMAT lpwfADPCM;
WORD wBlockAlign;
WORD wChannels;
WORD wBitsPerSample;
WORD wHeaderBytes;
DWORD dw;
WORD w;
//
// if the source format is PCM, then build an ADPCM destination format
// header... assuming the PCM format header is valid.
//
if (lpwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
{
if (!pcmIsValidFormat(lpwfxSrc))
return (FALSE);
lpwfADPCM = (LPADPCMWAVEFORMAT)lpwfxDst;
//
// fill in destination header with appropriate ADPCM stuff based
// on source PCM header...
//
lpwfxDst->wFormatTag = WAVE_FORMAT_ADPCM;
lpwfxDst->nSamplesPerSec = lpwfxSrc->nSamplesPerSec;
lpwfxDst->nChannels = wChannels = lpwfxSrc->nChannels;
lpwfxDst->wBitsPerSample = wBitsPerSample = 4;
//
// choose a block alignment that makes sense for the sample rate
// that the original PCM data is. basically, this needs to be
// some reasonable number to allow efficient streaming, etc.
//
// don't let block alignment get too small...
//
wBlockAlign = 256 * wChannels;
if (lpwfxSrc->nSamplesPerSec > 11025)
wBlockAlign *= (WORD)(lpwfxSrc->nSamplesPerSec / 11000);
lpwfxDst->nBlockAlign = wBlockAlign;
//
// compute that 'samples per block' that will be in the encoded
// ADPCM data blocks. this is determined by subtracting out the
// 'other info' contained in each block--a block is composed of
// a header followed by 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 sample per channel
// 2 byte second sample per channel
//
// this gives us (7 * wChannels) bytes of header information that
// contains our first two full samples (so we add two below).
//
wHeaderBytes = (7 * wChannels);
w = (wBlockAlign - wHeaderBytes) * 8;
lpwfADPCM->wSamplesPerBlock = (w / (wBitsPerSample * wChannels)) + 2;
//
// now compute the avg bytes per second (man this code bites!)
//
dw = (((DWORD)wBitsPerSample * wChannels *
(DWORD)lpwfxDst->nSamplesPerSec) / 8);
lpwfxDst->nAvgBytesPerSec = (WORD)(dw + wHeaderBytes +
((dw / wBlockAlign) * wHeaderBytes));
//
// fill in the cbSize field of the extended wave format header.
// this number is the number of _EXTRA BYTES_ *after* the end
// of the WAVEFORMATEX structure that are need for the compression
// format.
//
// for Microsoft's 4 Bit ADPCM format, this number is 32:
//
lpwfxDst->cbSize = sizeof(ADPCMWAVEFORMAT) - sizeof(WAVEFORMATEX) +
(MSADPCM_NUM_COEF * sizeof(ADPCMCOEFSET));
//
// copy the Microsoft 4 Bit ADPCM coef's into the header
//
lpwfADPCM->wNumCoef = MSADPCM_NUM_COEF;
for (w = 0; w < MSADPCM_NUM_COEF; w++)
{
lpwfADPCM->aCoef[w].iCoef1 = gaiCoef1[w];
lpwfADPCM->aCoef[w].iCoef2 = gaiCoef2[w];
}
return (TRUE);
}
//
// if the source format is ADPCM, then build an appropriate PCM header
//
else if (lpwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM)
{
if (!adpcmIsValidFormat(lpwfxSrc))
return (FALSE);
//
// fill in the info for our destination format...
//
lpwfxDst->wFormatTag = WAVE_FORMAT_PCM;
lpwfxDst->nSamplesPerSec = lpwfxSrc->nSamplesPerSec;
lpwfxDst->nChannels = wChannels = lpwfxSrc->nChannels;
//
// NOTE: bits per sample can be 8 or 16.. most people don't have
// 16 bit boards (yet!), so default to 8 bit decoding..
//
#if 0
lpwfxDst->wBitsPerSample = wBitsPerSample = 16;
#else
lpwfxDst->wBitsPerSample = wBitsPerSample = 8;
#endif
//
// set nAvgBytesPerSec and nBlockAlign
//
lpwfxDst->nBlockAlign = (wBitsPerSample >> 3) << (wChannels >> 1);
lpwfxDst->nAvgBytesPerSec = lpwfxDst->nSamplesPerSec * wBitsPerSample;
return (TRUE);
}
return (FALSE);
} /* adpcmBuildFormatHeader() */
/** EOF: msadpcm.c **/