summaryrefslogtreecommitdiff
path: root/utils/xbox/MakeGameData/imaadpcm.h
blob: a9fdd087a1a98a7d32f089fed2725a153777e8d2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//========= Copyright Valve Corporation, All rights reserved. ============//
/***************************************************************************
 *
 *  Copyright (C) 2001 Microsoft Corporation.  All Rights Reserved.
 *
 *  File:       imaadpcm.h
 *  Content:    IMA ADPCM CODEC.
 *  History:
 *   Date       By      Reason
 *   ====       ==      ======
 *  04/29/01    dereks  Created.
 *
 ****************************************************************************/

#ifndef __IMAADPCM_H__
#define __IMAADPCM_H__

#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <ctype.h>
#include <mmreg.h>
#include <msacm.h>

#define XBOX_ADPCM_SAMPLES_PER_BLOCK    64

#define WAVE_FORMAT_XBOX_ADPCM          0x0069
                                        
#define IMAADPCM_BITS_PER_SAMPLE        4
#define IMAADPCM_HEADER_LENGTH          4
                                        
#define IMAADPCM_MAX_CHANNELS           2
#define IMAADPCM_PCM_BITS_PER_SAMPLE    16

#define NUMELMS(a) (sizeof(a) / sizeof(a[0]))

typedef const WAVEFORMATEX *LPCWAVEFORMATEX;
typedef const IMAADPCMWAVEFORMAT *LPCIMAADPCMWAVEFORMAT;

#ifdef __cplusplus

//
// IMA ADPCM encoder function prototype
//

typedef BOOL (*LPFNIMAADPCMCONVERT)(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR);

//
// Codec mode
//

enum CODEC_MODE
{
    CODEC_MODE_DECODE,
    CODEC_MODE_ENCODE_NORMAL,
    CODEC_MODE_ENCODE_OPTIMIZE_WHOLE_FILE,
    CODEC_MODE_ENCODE_OPTIMIZE_EACH_BLOCK,
};

//
// IMA ADPCM CODEC
//

class CImaAdpcmCodec
{
private:
    static const short      m_asNextStep[16];           // Step increment array
    static const short      m_asStep[89];               // Step value array
    IMAADPCMWAVEFORMAT      m_wfxEncode;                // Encoded format description
    CODEC_MODE              m_cmCodecMode;              // Codec mode
    int                     m_nStepIndexL;              // Left-channel stepping index
    int                     m_nStepIndexR;              // Right-channel stepping index
    LPFNIMAADPCMCONVERT     m_pfnConvert;               // Conversion function

public:
    CImaAdpcmCodec(void);
    ~CImaAdpcmCodec(void);

public:
    // Initialization
    BOOL Initialize(LPCIMAADPCMWAVEFORMAT pwfxEncode, CODEC_MODE cmCodecMode);

    // Size conversions
    WORD GetEncodeAlignment(void);
    WORD GetDecodeAlignment(void);
    WORD GetSourceAlignment(void);
    WORD GetDestinationAlignment(void);

    // Data conversions
    BOOL Convert(LPCVOID pvSrc, LPVOID pvDst, UINT cBlocks);
    void Reset(void);

    // Format descriptions
    static void CreatePcmFormat(WORD nChannels, DWORD nSamplesPerSec, LPWAVEFORMATEX pwfxFormat);
    static void CreateImaAdpcmFormat(WORD nChannels, DWORD nSamplesPerSec, WORD nSamplesPerBlock, LPIMAADPCMWAVEFORMAT pwfxFormat);

    static BOOL IsValidPcmFormat(LPCWAVEFORMATEX pwfxFormat);
    static BOOL IsValidImaAdpcmFormat(LPCIMAADPCMWAVEFORMAT pwfxFormat);

private:
    // En/decoded data alignment
    static WORD CalculateEncodeAlignment(WORD nSamplesPerBlock, WORD nChannels);
    
    // Data conversion functions
    static BOOL EncodeM16(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR);
    static BOOL EncodeS16(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR);
    static BOOL DecodeM16(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR);
    static BOOL DecodeS16(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR);

    static int EncodeSample(int nInputSample, int *nPredictedSample, int nStepSize);
    static int DecodeSample(int nInputSample, int nPredictedSample, int nStepSize);

    static int NextStepIndex(int nEncodedSample, int nStepIndex);
    static BOOL ValidStepIndex(int nStepIndex);

    /*static ULONGLONG CalcDifference(LPDWORD pvBuffer1, LPDWORD pvBuffer2, DWORD dwLength);*/
    ULONGLONG CalcDifference(LPBYTE pvBuffer1, LPBYTE pvBuffer2, UINT cBlocks, UINT cTotalBlocks, DWORD dwBlockSize);
};

__inline WORD CImaAdpcmCodec::GetSourceAlignment(void)
{
    return ( m_cmCodecMode == CODEC_MODE_DECODE ) ? GetEncodeAlignment() : GetDecodeAlignment();
}

__inline WORD CImaAdpcmCodec::GetDestinationAlignment(void)
{
    return ( m_cmCodecMode == CODEC_MODE_DECODE ) ? GetDecodeAlignment() : GetEncodeAlignment();
}

__inline int CImaAdpcmCodec::NextStepIndex(int nEncodedSample, int nStepIndex)
{
    nStepIndex += m_asNextStep[nEncodedSample];

    if(nStepIndex < 0)
    {
        nStepIndex = 0;
    }
    else if(nStepIndex >= NUMELMS(m_asStep))
    {
        nStepIndex = NUMELMS(m_asStep) - 1;
    }

    return nStepIndex;
}

__inline BOOL CImaAdpcmCodec::ValidStepIndex(int nStepIndex)
{
    return (nStepIndex >= 0) && (nStepIndex < NUMELMS(m_asStep));
}

#endif // __cplusplus

#endif // __IMAADPCM_H__