//==========================================================================; // // msadpcm.c // // Copyright (c) 1992-1994 Microsoft Corporation // // Description: // // // History: // //==========================================================================; #include #include #include #include #include #include #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