📄 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; 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)); *nsrc = nblock * adsi->pwfxSrc->nBlockAlign; *ndst = nblock * nsamp_blk * 2; nsamp_blk--; /* remove the sample in block header */ for (; nblock > 0; nblock--) { const unsigned char* in_src = src; /* handle header first */ sample = R16(src); stepIndex = (unsigned)*(src + 2); clamp_step_index(&stepIndex); src += 4; W16(dst, sample); dst += 2; for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2) { process_nibble(*src, &stepIndex, &sample); W16(dst, sample); dst += 2; process_nibble(*src++ >> 4, &stepIndex, &sample); W16(dst, sample); dst += 2; } /* we have now to realign the source pointer on block */ src = in_src + adsi->pwfxSrc->nBlockAlign; }}static void cvtSS16imaK(PACMDRVSTREAMINSTANCE adsi, const unsigned char* src, LPDWORD nsrc, unsigned char* dst, LPDWORD ndst){ int stepIndexL, stepIndexR; int sampleL, sampleR; BYTE code1, code2; int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock; int i, 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 / (nsamp_blk * 2 * 2), *ndst / adsi->pwfxDst->nBlockAlign); *nsrc = nblock * (nsamp_blk * 2 * 2); *ndst = nblock * adsi->pwfxDst->nBlockAlign; stepIndexL = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL; stepIndexR = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR; nsamp_blk--; /* so that we won't count the sample in header while filling the block */ for (; nblock > 0; nblock--) { char* in_dst = dst; /* generate header */ sampleL = R16(src); src += 2; W16(dst, sampleL); dst += 2; *dst = (unsigned char)(unsigned)stepIndexL; dst += 2; sampleR = R16(src); src += 2; W16(dst, sampleR); dst += 2; *dst = (unsigned char)(unsigned)stepIndexR; dst += 2; for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8) { for (i = 0; i < 4; i++) { code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 0), &stepIndexL, &sampleL); code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 0), &stepIndexL, &sampleL); *dst++ = (code1 << 4) | code2; } for (i = 0; i < 4; i++) { code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 1), &stepIndexR, &sampleR); code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 1), &stepIndexR, &sampleR); *dst++ = (code1 << 4) | code2; } src += 32; } dst = in_dst + adsi->pwfxDst->nBlockAlign; } ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndexL; ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR = stepIndexR;}static void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi, const unsigned char* src, LPDWORD nsrc, unsigned char* dst, LPDWORD ndst){ int stepIndex; int sample; BYTE code1, code2; int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->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 / (nsamp_blk * 2), *ndst / adsi->pwfxDst->nBlockAlign); *nsrc = nblock * (nsamp_blk * 2); *ndst = nblock * adsi->pwfxDst->nBlockAlign; stepIndex = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL; nsamp_blk--; /* so that we won't count the sample in header while filling the block */ for (; nblock > 0; nblock--) { char* in_dst = dst; /* generate header */ /* FIXME: what about the last effective sample from previous block ??? */ /* perhaps something like: * sample += R16(src); * clamp_sample(sample); * and with : * + saving the sample in adsi->dwDriver when all blocks are done + + reset should set the field in adsi->dwDriver to 0 too */ sample = R16(src); src += 2; W16(dst, sample); dst += 2; *dst = (unsigned char)(unsigned)stepIndex; dst += 2; for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2) { code1 = generate_nibble(R16(src), &stepIndex, &sample); src += 2; code2 = generate_nibble(R16(src), &stepIndex, &sample); src += 2; *dst++ = (code1 << 4) | code2; } dst = in_dst + adsi->pwfxDst->nBlockAlign; } ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndex;}/*********************************************************************** * ADPCM_DriverDetails * */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -