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

📄 imaadp32.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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 + -