📄 imaalgorith.c
字号:
//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992-1999 G&G Lab Corporation
//
//--------------------------------------------------------------------------;
//
// IMAAlgorith.c
//
// Description:
// This file contains encode and decode routines for the IMA's ADPCM
// format. This format is the same format used in Intel's DVI standard.
// Intel has made this algorithm public domain and the IMA has endorsed
// this format as a standard for audio compression.
//
// Implementation notes:
//
// A previous distribution of this ACM used a data format which did
// not comply with the IMA standard. For stereo files, the interleaving
// of left and right samples was incorrect: the IMA standard requires
// that a DWORD of left-channel data be followed by a DWORD of right-
// channel data, but the previous implementation of this ACM
// interleaved the data at the byte level, with the 4 LSBs being the
// left channel data and the 4 MSBs being the right channel data.
// For mono files, each pair of samples was reversed: the first sample
// was stored in the 4 MSBs rather than the 4 LSBs. This problem is
// fixed during the current release. Note: files compressed by the
// old ACM will sound distorted when played back with the new ACM,
// and vice versa. Please recompress these files with the new ACM,
// since they do not conform to the standard and will not be reproduced
// correctly by hardware ACMs, etc.
//
// A previous distribution of this ACM had an implementation problem
// which degraded the sound quality of the encoding. This was due to
// the fact that the step index was not properly maintained between
// conversions. This problem has been fixed in the current release.
//
// The ACM has been speeded up considerably by breaking
// the encode and decode routines into four separate routines each:
// mono 8-bit, mono 16-bit, stereo 8-bit, and stereo 16-bit. This
// approach is recommended for real-time conversion routines.
//
//==========================================================================;
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <msacm.h>
#include <msacmdrv.h>
#include "ACM.h"
#include "IMAAlgorith.h"
#include "debug.h"
//
// This array is used by IMAAlgorithNextStepIndex to determine the next step
// index to use. The step index is an index to the step[] array, below.
//
const short next_step[16] =
{
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8
};
//
// This array contains the array of step sizes used to encode the ADPCM
// samples. The step index in each ADPCM block is an index to this array.
//
const short step[89] =
{
7, 8, 9, 10, 11, 12, 13,
14, 16, 17, 19, 21, 23, 25,
28, 31, 34, 37, 41, 45, 50,
55, 60, 66, 73, 80, 88, 97,
107, 118, 130, 143, 157, 173, 190,
209, 230, 253, 279, 307, 337, 371,
408, 449, 494, 544, 598, 658, 724,
796, 876, 963, 1060, 1166, 1282, 1411,
1552, 1707, 1878, 2066, 2272, 2499, 2749,
3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442,
11487, 12635, 13899, 15289, 16818, 18500, 20350,
22385, 24623, 27086, 29794, 32767
};
#ifndef INLINE
#define INLINE __inline
#endif
//--------------------------------------------------------------------------;
//
// DWORD pcmM08BytesToSamples
// DWORD pcmM16BytesToSamples
// DWORD pcmS08BytesToSamples
// DWORD pcmS16BytesToSamples
//
// Description:
// These functions return the number of samples in a buffer of PCM
// of the specified format. For efficiency, it is declared INLINE.
// Note that, depending on the optimization flags, it may not
// actually be implemented as INLINE. Optimizing for speed (-Oxwt)
// will generally obey the INLINE specification.
//
// Arguments:
// DWORD cb: The length of the buffer, in bytes.
//
// Return (DWORD): The length of the buffer in samples.
//
//--------------------------------------------------------------------------;
INLINE DWORD pcmM08BytesToSamples(
DWORD cb
)
{
return cb;
}
INLINE DWORD pcmM16BytesToSamples(
DWORD cb
)
{
return cb / ((DWORD)2);
}
INLINE DWORD pcmS08BytesToSamples(
DWORD cb
)
{
return cb / ((DWORD)2);
}
INLINE DWORD pcmS16BytesToSamples(
DWORD cb
)
{
return cb / ((DWORD)4);
}
#ifdef WIN32
//
// This code assumes that the integer nPredictedSample is 32-bits wide!!!
//
// The following define replaces the pair of calls to the inline functions
// IMAAlgorithSampleEncode() and IMAAlgorithSampleDecode which are called in the
// encode routines. There is some redundancy between them which is exploited
// in this define. Because there are two returns (nEncodedSample and
// nPredictedSample), it is more efficient to use a #define rather than an
// inline function which would require a pointer to one of the returns.
//
// Basically, nPredictedSample is calculated based on the lDifference value
// already there, rather than regenerating it through IMAAlgorithSampleDecode().
//
#define IMAAlgorithFastEncode(nEncodedSample,nPredictedSample,nInputSample,nStepSize) \
{ \
LONG lDifference; \
\
lDifference = nInputSample - nPredictedSample; \
nEncodedSample = 0; \
if( lDifference<0 ) { \
nEncodedSample = 8; \
lDifference = -lDifference; \
} \
\
if( lDifference >= nStepSize ) { \
nEncodedSample |= 4; \
lDifference -= nStepSize; \
} \
\
nStepSize >>= 1; \
if( lDifference >= nStepSize ) { \
nEncodedSample |= 2; \
lDifference -= nStepSize; \
} \
\
nStepSize >>= 1; \
if( lDifference >= nStepSize ) { \
nEncodedSample |= 1; \
lDifference -= nStepSize; \
} \
\
if( nEncodedSample & 8 ) \
nPredictedSample = nInputSample + lDifference - (nStepSize>>1); \
else \
nPredictedSample = nInputSample - lDifference + (nStepSize>>1); \
\
if( nPredictedSample > 32767 ) \
nPredictedSample = 32767; \
else if( nPredictedSample < -32768 ) \
nPredictedSample = -32768; \
}
#else
//--------------------------------------------------------------------------;
//
// int IMAAlgorithSampleEncode
//
// Description:
// This routine encodes a single ADPCM sample. For efficiency, it is
// declared INLINE. Note that, depending on the optimization flags,
// it may not actually be implemented as INLINE. Optimizing for speed
// (-Oxwt) will generally obey the INLINE specification.
//
// Arguments:
// int nInputSample: The sample to be encoded.
// int nPredictedSample: The predicted value of nInputSample.
// int nStepSize: The quantization step size for the difference between
// nInputSample and nPredictedSample.
//
// Return (int): The 4-bit ADPCM encoded sample, which corresponds to the
// quantized difference value.
//
//--------------------------------------------------------------------------;
INLINE int IMAAlgorithSampleEncode
(
int nInputSample,
int nPredictedSample,
int nStepSize
)
{
LONG lDifference; // difference may require 17 bits!
int nEncodedSample;
//
// set sign bit (bit 3 of the encoded sample) based on sign of the
// difference (nInputSample-nPredictedSample). Note that we want the
// absolute value of the difference for the subsequent quantization.
//
lDifference = nInputSample - nPredictedSample;
nEncodedSample = 0;
if( lDifference<0 ) {
nEncodedSample = 8;
lDifference = -lDifference;
}
//
// quantize lDifference sample
//
if( lDifference >= nStepSize ) { // Bit 2.
nEncodedSample |= 4;
lDifference -= nStepSize;
}
nStepSize >>= 1;
if( lDifference >= nStepSize ) { // Bit 1.
nEncodedSample |= 2;
lDifference -= nStepSize;
}
nStepSize >>= 1;
if( lDifference >= nStepSize ) { // Bit 0.
nEncodedSample |= 1;
}
return (nEncodedSample);
}
#endif
//--------------------------------------------------------------------------;
//
// int IMAAlgorithSampleDecode
//
// Description:
// This routine decodes a single ADPCM sample. For efficiency, it is
// declared INLINE. Note that, depending on the optimization flags,
// it may not actually be implemented as INLINE. Optimizing for speed
// (-Oxwt) will generally obey the INLINE specification.
//
// Arguments:
// int nEncodedSample: The sample to be decoded.
// int nPredictedSample: The predicted value of the sample (in PCM).
// int nStepSize: The quantization step size used to encode the sample.
//
// Return (int): The decoded PCM sample.
//
//--------------------------------------------------------------------------;
INLINE int IMAAlgorithSampleDecode
(
int nEncodedSample,
int nPredictedSample,
int nStepSize
)
{
LONG lDifference;
LONG lNewSample;
//
// calculate difference:
//
// lDifference = (nEncodedSample + 1/2) * nStepSize / 4
//
lDifference = nStepSize>>3;
if (nEncodedSample & 4)
lDifference += nStepSize;
if (nEncodedSample & 2)
lDifference += nStepSize>>1;
if (nEncodedSample & 1)
lDifference += nStepSize>>2;
//
// If the 'sign bit' of the encoded nibble is set, then the
// difference is negative...
//
if (nEncodedSample & 8)
lDifference = -lDifference;
//
// adjust predicted sample based on calculated difference
//
lNewSample = nPredictedSample + lDifference;
//
// check for overflow and clamp if necessary to a 16 signed sample.
// Note that this is optimized for the most common case, when we
// don't have to clamp.
//
if( (long)(short)lNewSample == lNewSample )
{
return (int)lNewSample;
}
//
// Clamp.
//
if( lNewSample < -32768 )
return (int)-32768;
else
return (int)32767;
}
//--------------------------------------------------------------------------;
//
// int IMAAlgorithNextStepIndex
//
// Description:
// This routine calculates the step index value to use for the next
// encode, based on the current value of the step index and the current
// encoded sample. For efficiency, it is declared INLINE. Note that,
// depending on the optimization flags, it may not actually be
// implemented as INLINE. Optimizing for speed (-Oxwt) will generally
// obey the INLINE specification.
//
// Arguments:
// int nEncodedSample: The current encoded ADPCM sample.
// int nStepIndex: The step index value used to encode nEncodedSample.
//
// Return (int): The step index to use for the next sample.
//
//--------------------------------------------------------------------------;
INLINE int IMAAlgorithNextStepIndex
(
int nEncodedSample,
int nStepIndex
)
{
//
// compute new stepsize step
//
nStepIndex += next_step[nEncodedSample];
if (nStepIndex < 0)
nStepIndex = 0;
else if (nStepIndex > 88)
nStepIndex = 88;
return (nStepIndex);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -