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

📄 imaadp32.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 + -