📄 imaadp32.c
字号:
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
*
*/
static LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
{
add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
add->wMid = 0xFF;
add->wPid = 0x00;
add->vdwACM = 0x01000000;
add->vdwDriver = 0x01000000;
add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
add->cFormatTags = 2; /* PCM, IMA ADPCM */
add->cFilterTags = 0;
add->hicon = NULL;
MultiByteToWideChar( CP_ACP, 0, "WINE-ADPCM", -1,
add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
MultiByteToWideChar( CP_ACP, 0, "Wine IMA ADPCM converter", -1,
add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
add->szFeatures[0] = 0;
return MMSYSERR_NOERROR;
}
/***********************************************************************
* ADPCM_FormatTagDetails
*
*/
static LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
{
static WCHAR szPcm[]={'P','C','M',0};
static WCHAR szImaAdPcm[]={'I','M','A',' ','A','d','P','C','M',0};
switch (dwQuery)
{
case ACM_FORMATTAGDETAILSF_INDEX:
if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
break;
case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
{
aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
break;
}
/* fall thru */
case ACM_FORMATTAGDETAILSF_FORMATTAG:
switch (aftd->dwFormatTag)
{
case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break;
case WAVE_FORMAT_IMA_ADPCM: aftd->dwFormatTagIndex = 1; break;
default: return ACMERR_NOTPOSSIBLE;
}
break;
default:
WARN("Unsupported query %08lx\n", dwQuery);
return MMSYSERR_NOTSUPPORTED;
}
aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
switch (aftd->dwFormatTagIndex)
{
case 0:
aftd->dwFormatTag = WAVE_FORMAT_PCM;
aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
aftd->cStandardFormats = NUM_PCM_FORMATS;
lstrcpyW(aftd->szFormatTag, szPcm);
break;
case 1:
aftd->dwFormatTag = WAVE_FORMAT_IMA_ADPCM;
aftd->cbFormatSize = sizeof(IMAADPCMWAVEFORMAT);
aftd->cStandardFormats = NUM_ADPCM_FORMATS;
lstrcpyW(aftd->szFormatTag, szImaAdPcm);
break;
}
return MMSYSERR_NOERROR;
}
/***********************************************************************
* ADPCM_FormatDetails
*
*/
static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
{
switch (dwQuery)
{
case ACM_FORMATDETAILSF_FORMAT:
if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
break;
case ACM_FORMATDETAILSF_INDEX:
afd->pwfx->wFormatTag = afd->dwFormatTag;
switch (afd->dwFormatTag)
{
case WAVE_FORMAT_PCM:
if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
/* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
* afd->pwfx->cbSize = 0;
*/
afd->pwfx->nBlockAlign =
(afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
afd->pwfx->nAvgBytesPerSec =
afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
break;
case WAVE_FORMAT_IMA_ADPCM:
if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE;
afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
afd->pwfx->nBlockAlign = 1024;
/* we got 4 bits per sample */
afd->pwfx->nAvgBytesPerSec =
(afd->pwfx->nSamplesPerSec * 4) / 8;
if (afd->cbwfx >= sizeof(WAVEFORMATEX))
afd->pwfx->cbSize = sizeof(WORD);
if (afd->cbwfx >= sizeof(IMAADPCMWAVEFORMAT))
((IMAADPCMWAVEFORMAT*)afd->pwfx)->wSamplesPerBlock = (1024 - 4 * afd->pwfx->nChannels) * (2 / afd->pwfx->nChannels) + 1;
break;
default:
WARN("Unsupported tag %08lx\n", afd->dwFormatTag);
return MMSYSERR_INVALPARAM;
}
break;
default:
WARN("Unsupported query %08lx\n", dwQuery);
return MMSYSERR_NOTSUPPORTED;
}
afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
afd->szFormat[0] = 0; /* let MSACM format this for us... */
return MMSYSERR_NOERROR;
}
/***********************************************************************
* ADPCM_FormatSuggest
*
*/
static LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
{
/* some tests ... */
if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
/* FIXME: should do those tests against the real size (according to format tag */
/* If no suggestion for destination, then copy source value */
if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
{
if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -