⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 imaalgorith.c

📁 书中的主要程序文件。在打开例题的.dsw文件后,请读者在 tools菜单下的 Options 的 Directories 标签中选择 Executable files
💻 C
📖 第 1 页 / 共 4 页
字号:
//==========================================================================;
//
//  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 + -