📄 imaadp32.c
字号:
/*
* IMA ADPCM handling
*
* Copyright (C) 2001,2002 Eric Pouech
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <assert.h>
#include <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "mmsystem.h"
#include "mmreg.h"
#include "msacm.h"
#include "msacmdrv.h"
#include "wine/debug.h"
/* see http://www.pcisys.net/~melanson/codecs/adpcm.txt for the details */
WINE_DEFAULT_DEBUG_CHANNEL(adpcm);
/***********************************************************************
* ADPCM_drvOpen
*/
static DWORD ADPCM_drvOpen(LPCSTR str)
{
return 1;
}
/***********************************************************************
* ADPCM_drvClose
*/
static DWORD ADPCM_drvClose(DWORD dwDevID)
{
return 1;
}
typedef struct tagAcmAdpcmData
{
void (*convert)(PACMDRVSTREAMINSTANCE adsi,
const unsigned char*, LPDWORD, unsigned char*, LPDWORD);
/* IMA encoding only */
BYTE stepIndexL;
BYTE stepIndexR;
/* short sample; */
} AcmAdpcmData;
/* table to list all supported formats... those are the basic ones. this
* also helps given a unique index to each of the supported formats
*/
typedef struct
{
int nChannels;
int nBits;
int rate;
} Format;
static Format PCM_Formats[] =
{
{1, 8, 8000}, {2, 8, 8000}, {1, 16, 8000}, {2, 16, 8000},
{1, 8, 11025}, {2, 8, 11025}, {1, 16, 11025}, {2, 16, 11025},
{1, 8, 22050}, {2, 8, 22050}, {1, 16, 22050}, {2, 16, 22050},
{1, 8, 44100}, {2, 8, 44100}, {1, 16, 44100}, {2, 16, 44100},
};
static Format ADPCM_Formats[] =
{
{1, 4, 8000}, {2, 4, 8000}, {1, 4, 11025}, {2, 4, 11025},
{1, 4, 22050}, {2, 4, 22050}, {1, 4, 44100}, {2, 4, 44100},
};
#define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
#define NUM_ADPCM_FORMATS (sizeof(ADPCM_Formats) / sizeof(ADPCM_Formats[0]))
/***********************************************************************
* ADPCM_GetFormatIndex
*/
static DWORD ADPCM_GetFormatIndex(LPWAVEFORMATEX wfx)
{
int i, hi;
Format* fmts;
switch (wfx->wFormatTag)
{
case WAVE_FORMAT_PCM:
hi = NUM_PCM_FORMATS;
fmts = PCM_Formats;
break;
case WAVE_FORMAT_IMA_ADPCM:
hi = NUM_ADPCM_FORMATS;
fmts = ADPCM_Formats;
break;
default:
return 0xFFFFFFFF;
}
for (i = 0; i < hi; i++)
{
if (wfx->nChannels == fmts[i].nChannels &&
wfx->nSamplesPerSec == fmts[i].rate &&
wfx->wBitsPerSample == fmts[i].nBits)
return i;
}
return 0xFFFFFFFF;
}
/***********************************************************************
* R16
*
* Read a 16 bit sample (correctly handles endianess)
*/
static inline short R16(const unsigned char* src)
{
return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
}
/***********************************************************************
* W16
*
* Write a 16 bit sample (correctly handles endianess)
*/
static inline void W16(unsigned char* dst, short s)
{
dst[0] = LOBYTE(s);
dst[1] = HIBYTE(s);
}
/* IMA (or DVI) APDCM codec routines */
static const unsigned IMA_StepTable[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
};
static const int IMA_IndexTable[16] =
{
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8
};
static inline void clamp_step_index(int* stepIndex)
{
if (*stepIndex < 0 ) *stepIndex = 0;
if (*stepIndex > 88) *stepIndex = 88;
}
static inline void clamp_sample(int* sample)
{
if (*sample < -32768) *sample = -32768;
if (*sample > 32767) *sample = 32767;
}
static inline void process_nibble(unsigned char code, int* stepIndex, int* sample)
{
unsigned step;
int diff;
code &= 0x0F;
step = IMA_StepTable[*stepIndex];
diff = step >> 3;
if (code & 1) diff += step >> 2;
if (code & 2) diff += step >> 1;
if (code & 4) diff += step;
if (code & 8) *sample -= diff;
else *sample += diff;
clamp_sample(sample);
*stepIndex += IMA_IndexTable[code];
clamp_step_index(stepIndex);
}
static inline unsigned char generate_nibble(int in, int* stepIndex, int* sample)
{
int effdiff, diff = in - *sample;
unsigned step;
unsigned char code;
if (diff < 0)
{
diff = -diff;
code = 8;
}
else
{
code = 0;
}
step = IMA_StepTable[*stepIndex];
effdiff = (step >> 3);
if (diff >= step)
{
code |= 4;
diff -= step;
effdiff += step;
}
step >>= 1;
if (diff >= step)
{
code |= 2;
diff -= step;
effdiff += step;
}
step >>= 1;
if (diff >= step)
{
code |= 1;
effdiff += step;
}
if (code & 8) *sample -= effdiff;
else *sample += effdiff;
clamp_sample(sample);
*stepIndex += IMA_IndexTable[code];
clamp_step_index(stepIndex);
return code;
}
static void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi,
const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
{
int i;
int sampleL, sampleR;
int stepIndexL, stepIndexR;
int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
int nsamp;
/* compute the number of entire blocks we can decode...
* it's the min of the number of entire blocks in source buffer and the number
* of entire blocks in destination buffer
*/
DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
*ndst / (nsamp_blk * 2 * 2));
*nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
*ndst = nblock * (nsamp_blk * 2 * 2);
nsamp_blk--; /* remove the sample in block header */
for (; nblock > 0; nblock--)
{
const unsigned char* in_src = src;
/* handle headers first */
sampleL = R16(src);
stepIndexL = (unsigned)*(src + 2);
clamp_step_index(&stepIndexL);
src += 4;
W16(dst, sampleL); dst += 2;
sampleR = R16(src);
stepIndexR = (unsigned)*(src + 2);
clamp_step_index(&stepIndexR);
src += 4;
W16(dst, sampleR); dst += 2;
for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
{
for (i = 0; i < 4; i++)
{
process_nibble(*src, &stepIndexL, &sampleL);
W16(dst + (2 * i + 0) * 4 + 0, sampleL);
process_nibble(*src++ >> 4, &stepIndexL, &sampleL);
W16(dst + (2 * i + 1) * 4 + 0, sampleL);
}
for (i = 0; i < 4; i++)
{
process_nibble(*src , &stepIndexR, &sampleR);
W16(dst + (2 * i + 0) * 4 + 2, sampleR);
process_nibble(*src++ >>4, &stepIndexR, &sampleR);
W16(dst + (2 * i + 1) * 4 + 2, sampleR);
}
dst += 32;
}
/* we have now to realign the source pointer on block */
src = in_src + adsi->pwfxSrc->nBlockAlign;
}
}
static void cvtMMima16K(PACMDRVSTREAMINSTANCE adsi,
const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
{
int sample;
int stepIndex;
int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -