4 * Copyright (C) 2001,2002 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wine/debug.h"
36 /* see http://www.pcisys.net/~melanson/codecs/adpcm.txt for the details */
38 WINE_DEFAULT_DEBUG_CHANNEL(adpcm);
40 /***********************************************************************
43 static LRESULT ADPCM_drvClose(DWORD_PTR dwDevID)
48 typedef struct tagAcmAdpcmData
50 void (*convert)(PACMDRVSTREAMINSTANCE adsi,
51 const unsigned char*, LPDWORD, unsigned char*, LPDWORD);
52 /* IMA encoding only */
58 /* table to list all supported formats... those are the basic ones. this
59 * also helps given a unique index to each of the supported formats
68 static const Format PCM_Formats[] =
70 {1, 8, 8000}, {2, 8, 8000}, {1, 16, 8000}, {2, 16, 8000},
71 {1, 8, 11025}, {2, 8, 11025}, {1, 16, 11025}, {2, 16, 11025},
72 {1, 8, 22050}, {2, 8, 22050}, {1, 16, 22050}, {2, 16, 22050},
73 {1, 8, 44100}, {2, 8, 44100}, {1, 16, 44100}, {2, 16, 44100},
76 static const Format ADPCM_Formats[] =
78 {1, 4, 8000}, {2, 4, 8000}, {1, 4, 11025}, {2, 4, 11025},
79 {1, 4, 22050}, {2, 4, 22050}, {1, 4, 44100}, {2, 4, 44100},
82 #define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
83 #define NUM_ADPCM_FORMATS (sizeof(ADPCM_Formats) / sizeof(ADPCM_Formats[0]))
85 /***********************************************************************
86 * ADPCM_GetFormatIndex
88 static DWORD ADPCM_GetFormatIndex(const WAVEFORMATEX *wfx)
93 switch (wfx->wFormatTag)
99 case WAVE_FORMAT_IMA_ADPCM:
100 hi = NUM_ADPCM_FORMATS;
101 fmts = ADPCM_Formats;
107 for (i = 0; i < hi; i++)
109 if (wfx->nChannels == fmts[i].nChannels &&
110 wfx->nSamplesPerSec == fmts[i].rate &&
111 wfx->wBitsPerSample == fmts[i].nBits)
115 switch (wfx->wFormatTag)
117 case WAVE_FORMAT_PCM:
118 if(3 > wfx->nChannels &&
119 wfx->nChannels > 0 &&
120 wfx->nAvgBytesPerSec == 2 * wfx->nSamplesPerSec * wfx->nChannels &&
121 wfx->nBlockAlign == 2 * wfx->nChannels &&
122 wfx->wBitsPerSample == 16)
125 case WAVE_FORMAT_IMA_ADPCM:
126 if(3 > wfx->nChannels &&
127 wfx->nChannels > 0 &&
128 wfx->wBitsPerSample == 4 &&
137 static void init_wfx_ima_adpcm(IMAADPCMWAVEFORMAT* awfx/*, DWORD nba*/)
139 register WAVEFORMATEX* pwfx = &awfx->wfx;
141 /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample
142 * have been initialized... */
144 if (pwfx->wFormatTag != WAVE_FORMAT_IMA_ADPCM) {FIXME("wrong FT\n"); return;}
145 if (ADPCM_GetFormatIndex(pwfx) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;}
147 switch (pwfx->nSamplesPerSec)
149 case 8000: pwfx->nBlockAlign = 256 * pwfx->nChannels; break;
150 case 11025: pwfx->nBlockAlign = 256 * pwfx->nChannels; break;
151 case 22050: pwfx->nBlockAlign = 512 * pwfx->nChannels; break;
152 case 44100: pwfx->nBlockAlign = 1024 * pwfx->nChannels; break;
153 default: /*pwfx->nBlockAlign = nba;*/ break;
155 pwfx->cbSize = sizeof(WORD);
157 awfx->wSamplesPerBlock = (pwfx->nBlockAlign - (4 * pwfx->nChannels) * 2) / pwfx->nChannels + 1;
158 pwfx->nAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) / awfx->wSamplesPerBlock;
161 /***********************************************************************
164 * Read a 16 bit sample (correctly handles endianess)
166 static inline short R16(const unsigned char* src)
168 return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
171 /***********************************************************************
174 * Write a 16 bit sample (correctly handles endianess)
176 static inline void W16(unsigned char* dst, short s)
182 /* IMA (or DVI) APDCM codec routines */
184 static const unsigned IMA_StepTable[89] =
186 7, 8, 9, 10, 11, 12, 13, 14,
187 16, 17, 19, 21, 23, 25, 28, 31,
188 34, 37, 41, 45, 50, 55, 60, 66,
189 73, 80, 88, 97, 107, 118, 130, 143,
190 157, 173, 190, 209, 230, 253, 279, 307,
191 337, 371, 408, 449, 494, 544, 598, 658,
192 724, 796, 876, 963, 1060, 1166, 1282, 1411,
193 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
194 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
195 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
196 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
200 static const int IMA_IndexTable[16] =
202 -1, -1, -1, -1, 2, 4, 6, 8,
203 -1, -1, -1, -1, 2, 4, 6, 8
206 static inline void clamp_step_index(int* stepIndex)
208 if (*stepIndex < 0 ) *stepIndex = 0;
209 if (*stepIndex > 88) *stepIndex = 88;
212 static inline void clamp_sample(int* sample)
214 if (*sample < -32768) *sample = -32768;
215 if (*sample > 32767) *sample = 32767;
218 static inline void process_nibble(unsigned char code, int* stepIndex, int* sample)
225 step = IMA_StepTable[*stepIndex];
227 if (code & 1) diff += step >> 2;
228 if (code & 2) diff += step >> 1;
229 if (code & 4) diff += step;
230 if (code & 8) *sample -= diff;
231 else *sample += diff;
232 clamp_sample(sample);
233 *stepIndex += IMA_IndexTable[code];
234 clamp_step_index(stepIndex);
237 static inline unsigned char generate_nibble(int in, int* stepIndex, int* sample)
239 int effdiff, diff = in - *sample;
253 step = IMA_StepTable[*stepIndex];
254 effdiff = (step >> 3);
274 if (code & 8) *sample -= effdiff;
275 else *sample += effdiff;
276 clamp_sample(sample);
277 *stepIndex += IMA_IndexTable[code];
278 clamp_step_index(stepIndex);
282 static void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi,
283 const unsigned char* src, LPDWORD nsrc,
284 unsigned char* dst, LPDWORD ndst)
287 int sampleL, sampleR;
288 int stepIndexL, stepIndexR;
289 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
291 /* compute the number of entire blocks we can decode...
292 * it's the min of the number of entire blocks in source buffer and the number
293 * of entire blocks in destination buffer
295 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
296 *ndst / (nsamp_blk * 2 * 2));
298 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
299 *ndst = nblock * (nsamp_blk * 2 * 2);
301 nsamp_blk--; /* remove the sample in block header */
302 for (; nblock > 0; nblock--)
304 const unsigned char* in_src = src;
306 /* handle headers first */
308 stepIndexL = (unsigned)*(src + 2);
309 clamp_step_index(&stepIndexL);
311 W16(dst, sampleL); dst += 2;
314 stepIndexR = (unsigned)*(src + 2);
315 clamp_step_index(&stepIndexR);
317 W16(dst, sampleR); dst += 2;
319 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
321 for (i = 0; i < 4; i++)
323 process_nibble(*src, &stepIndexL, &sampleL);
324 W16(dst + (2 * i + 0) * 4 + 0, sampleL);
325 process_nibble(*src++ >> 4, &stepIndexL, &sampleL);
326 W16(dst + (2 * i + 1) * 4 + 0, sampleL);
328 for (i = 0; i < 4; i++)
330 process_nibble(*src , &stepIndexR, &sampleR);
331 W16(dst + (2 * i + 0) * 4 + 2, sampleR);
332 process_nibble(*src++ >>4, &stepIndexR, &sampleR);
333 W16(dst + (2 * i + 1) * 4 + 2, sampleR);
337 /* we have now to realign the source pointer on block */
338 src = in_src + adsi->pwfxSrc->nBlockAlign;
342 static void cvtMMima16K(PACMDRVSTREAMINSTANCE adsi,
343 const unsigned char* src, LPDWORD nsrc,
344 unsigned char* dst, LPDWORD ndst)
348 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
350 /* compute the number of entire blocks we can decode...
351 * it's the min of the number of entire blocks in source buffer and the number
352 * of entire blocks in destination buffer
354 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
355 *ndst / (nsamp_blk * 2));
357 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
358 *ndst = nblock * nsamp_blk * 2;
360 nsamp_blk--; /* remove the sample in block header */
361 for (; nblock > 0; nblock--)
363 const unsigned char* in_src = src;
365 /* handle header first */
367 stepIndex = (unsigned)*(src + 2);
368 clamp_step_index(&stepIndex);
370 W16(dst, sample); dst += 2;
372 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
374 process_nibble(*src, &stepIndex, &sample);
375 W16(dst, sample); dst += 2;
376 process_nibble(*src++ >> 4, &stepIndex, &sample);
377 W16(dst, sample); dst += 2;
379 /* we have now to realign the source pointer on block */
380 src = in_src + adsi->pwfxSrc->nBlockAlign;
384 static void cvtSS16imaK(PACMDRVSTREAMINSTANCE adsi,
385 const unsigned char* src, LPDWORD nsrc,
386 unsigned char* dst, LPDWORD ndst)
388 int stepIndexL, stepIndexR;
389 int sampleL, sampleR;
391 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
393 /* compute the number of entire blocks we can decode...
394 * it's the min of the number of entire blocks in source buffer and the number
395 * of entire blocks in destination buffer
397 DWORD nblock = min(*nsrc / (nsamp_blk * 2 * 2),
398 *ndst / adsi->pwfxDst->nBlockAlign);
400 *nsrc = nblock * (nsamp_blk * 2 * 2);
401 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
403 stepIndexL = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
404 stepIndexR = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR;
406 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
408 for (; nblock > 0; nblock--)
410 unsigned char* in_dst = dst;
412 /* generate header */
413 sampleL = R16(src); src += 2;
414 W16(dst, sampleL); dst += 2;
415 *dst = (unsigned char)(unsigned)stepIndexL;
418 sampleR = R16(src); src += 2;
419 W16(dst, sampleR); dst += 2;
420 *dst = (unsigned char)(unsigned)stepIndexR;
423 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
425 for (i = 0; i < 4; i++)
427 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 0),
428 &stepIndexL, &sampleL);
429 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 0),
430 &stepIndexL, &sampleL);
431 *dst++ = (code1 << 4) | code2;
433 for (i = 0; i < 4; i++)
435 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 1),
436 &stepIndexR, &sampleR);
437 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 1),
438 &stepIndexR, &sampleR);
439 *dst++ = (code1 << 4) | code2;
443 dst = in_dst + adsi->pwfxDst->nBlockAlign;
445 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndexL;
446 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR = stepIndexR;
449 static void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi,
450 const unsigned char* src, LPDWORD nsrc,
451 unsigned char* dst, LPDWORD ndst)
456 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
458 /* compute the number of entire blocks we can decode...
459 * it's the min of the number of entire blocks in source buffer and the number
460 * of entire blocks in destination buffer
462 DWORD nblock = min(*nsrc / (nsamp_blk * 2),
463 *ndst / adsi->pwfxDst->nBlockAlign);
465 *nsrc = nblock * (nsamp_blk * 2);
466 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
468 stepIndex = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
469 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
471 for (; nblock > 0; nblock--)
473 unsigned char* in_dst = dst;
475 /* generate header */
476 /* FIXME: what about the last effective sample from previous block ??? */
477 /* perhaps something like:
478 * sample += R16(src);
479 * clamp_sample(sample);
481 * + saving the sample in adsi->dwDriver when all blocks are done
482 + + reset should set the field in adsi->dwDriver to 0 too
484 sample = R16(src); src += 2;
485 W16(dst, sample); dst += 2;
486 *dst = (unsigned char)(unsigned)stepIndex;
489 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
491 code1 = generate_nibble(R16(src), &stepIndex, &sample);
493 code2 = generate_nibble(R16(src), &stepIndex, &sample);
495 *dst++ = (code1 << 4) | code2;
497 dst = in_dst + adsi->pwfxDst->nBlockAlign;
499 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndex;
502 /***********************************************************************
503 * ADPCM_DriverDetails
506 static LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
508 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
509 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
512 add->vdwACM = 0x3320000;
513 add->vdwDriver = 0x04000000;
514 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
515 add->cFormatTags = 2; /* PCM, IMA ADPCM */
516 add->cFilterTags = 0;
518 MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM", -1,
519 add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
520 MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM CODEC", -1,
521 add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
522 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
523 add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
524 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
525 add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
526 add->szFeatures[0] = 0;
528 return MMSYSERR_NOERROR;
531 /***********************************************************************
532 * ADPCM_FormatTagDetails
535 static LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
537 static const WCHAR szPcm[]={'P','C','M',0};
538 static const WCHAR szImaAdPcm[]={'I','M','A',' ','A','D','P','C','M',0};
542 case ACM_FORMATTAGDETAILSF_INDEX:
543 if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
545 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
546 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
548 aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
552 case ACM_FORMATTAGDETAILSF_FORMATTAG:
553 switch (aftd->dwFormatTag)
555 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break;
556 case WAVE_FORMAT_IMA_ADPCM: aftd->dwFormatTagIndex = 1; break;
557 default: return ACMERR_NOTPOSSIBLE;
561 WARN("Unsupported query %08x\n", dwQuery);
562 return MMSYSERR_NOTSUPPORTED;
565 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
566 switch (aftd->dwFormatTagIndex)
569 aftd->dwFormatTag = WAVE_FORMAT_PCM;
570 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
571 aftd->cStandardFormats = NUM_PCM_FORMATS;
572 lstrcpyW(aftd->szFormatTag, szPcm);
575 aftd->dwFormatTag = WAVE_FORMAT_IMA_ADPCM;
576 aftd->cbFormatSize = sizeof(IMAADPCMWAVEFORMAT);
577 aftd->cStandardFormats = NUM_ADPCM_FORMATS;
578 lstrcpyW(aftd->szFormatTag, szImaAdPcm);
581 return MMSYSERR_NOERROR;
584 /***********************************************************************
585 * ADPCM_FormatDetails
588 static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
592 case ACM_FORMATDETAILSF_FORMAT:
593 if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
595 case ACM_FORMATDETAILSF_INDEX:
596 afd->pwfx->wFormatTag = afd->dwFormatTag;
597 switch (afd->dwFormatTag)
599 case WAVE_FORMAT_PCM:
600 if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
601 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
602 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
603 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
604 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
605 * afd->pwfx->cbSize = 0;
607 afd->pwfx->nBlockAlign =
608 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
609 afd->pwfx->nAvgBytesPerSec =
610 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
612 case WAVE_FORMAT_IMA_ADPCM:
613 if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE;
614 afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
615 afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
616 afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
617 afd->pwfx->nBlockAlign = 1024;
618 /* we got 4 bits per sample */
619 afd->pwfx->nAvgBytesPerSec =
620 (afd->pwfx->nSamplesPerSec * 4) / 8;
621 if (afd->cbwfx >= sizeof(WAVEFORMATEX))
622 afd->pwfx->cbSize = sizeof(WORD);
623 if (afd->cbwfx >= sizeof(IMAADPCMWAVEFORMAT))
624 ((IMAADPCMWAVEFORMAT*)afd->pwfx)->wSamplesPerBlock = (1024 - 4 * afd->pwfx->nChannels) * (2 / afd->pwfx->nChannels) + 1;
627 WARN("Unsupported tag %08x\n", afd->dwFormatTag);
628 return MMSYSERR_INVALPARAM;
632 WARN("Unsupported query %08x\n", dwQuery);
633 return MMSYSERR_NOTSUPPORTED;
635 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
636 afd->szFormat[0] = 0; /* let MSACM format this for us... */
638 return MMSYSERR_NOERROR;
641 /***********************************************************************
642 * ADPCM_FormatSuggest
645 static LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
648 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
649 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
650 adfs->pwfxSrc->wFormatTag == adfs->pwfxDst->wFormatTag ||
651 ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
653 /* If no suggestion for destination, then copy source value */
654 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
655 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
656 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
657 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
659 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
661 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
662 adfs->pwfxDst->wBitsPerSample = 4;
664 adfs->pwfxDst->wBitsPerSample = 16;
666 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
668 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
669 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
671 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
674 /* recompute other values */
675 switch (adfs->pwfxDst->wFormatTag)
677 case WAVE_FORMAT_PCM:
678 if (adfs->cbwfxSrc < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
679 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
680 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
681 /* check if result is ok */
682 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
684 case WAVE_FORMAT_IMA_ADPCM:
685 if (adfs->cbwfxDst < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
686 init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT*)adfs->pwfxDst);
687 /* FIXME: not handling header overhead */
688 TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock);
689 /* check if result is ok */
690 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
693 return ACMERR_NOTPOSSIBLE;
696 return MMSYSERR_NOERROR;
699 /***********************************************************************
703 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
705 aad->stepIndexL = aad->stepIndexR = 0;
708 /***********************************************************************
712 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
717 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
719 if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
720 ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
721 return ACMERR_NOTPOSSIBLE;
723 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
724 if (aad == 0) return MMSYSERR_NOMEM;
726 adsi->dwDriver = (DWORD_PTR)aad;
728 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
729 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
733 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
734 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
736 /* resampling or mono <=> stereo not available
737 * ADPCM algo only define 16 bit per sample output
739 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
740 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
741 adsi->pwfxDst->wBitsPerSample != 16)
744 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
745 TRACE("spb=%u\n", nspb);
747 /* we check that in a block, after the header, samples are present on
748 * 4-sample packet pattern
749 * we also check that the block alignment is bigger than the expected size
751 if (((nspb - 1) & 3) != 0) goto theEnd;
752 if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
755 /* adpcm decoding... */
756 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
757 aad->convert = cvtSSima16K;
758 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
759 aad->convert = cvtMMima16K;
761 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
762 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
764 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
765 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
766 adsi->pwfxSrc->wBitsPerSample != 16)
769 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
770 TRACE("spb=%u\n", nspb);
772 /* we check that in a block, after the header, samples are present on
773 * 4-sample packet pattern
774 * we also check that the block alignment is bigger than the expected size
776 if (((nspb - 1) & 3) != 0) goto theEnd;
777 if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
780 /* adpcm coding... */
781 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
782 aad->convert = cvtSS16imaK;
783 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
784 aad->convert = cvtMM16imaK;
787 ADPCM_Reset(adsi, aad);
789 return MMSYSERR_NOERROR;
792 HeapFree(GetProcessHeap(), 0, aad);
794 return MMSYSERR_NOTSUPPORTED;
797 /***********************************************************************
801 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
803 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
804 return MMSYSERR_NOERROR;
807 /***********************************************************************
811 static LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
815 switch (adss->fdwSize)
817 case ACM_STREAMSIZEF_DESTINATION:
818 /* cbDstLength => cbSrcLength */
819 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
820 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
822 nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign;
824 return ACMERR_NOTPOSSIBLE;
825 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
827 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
828 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
830 nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock);
832 return ACMERR_NOTPOSSIBLE;
833 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
837 return MMSYSERR_NOTSUPPORTED;
840 case ACM_STREAMSIZEF_SOURCE:
841 /* cbSrcLength => cbDstLength */
842 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
843 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
845 nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock);
847 return ACMERR_NOTPOSSIBLE;
848 if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock))
849 /* Round block count up. */
851 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign;
853 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
854 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
856 nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign;
858 return ACMERR_NOTPOSSIBLE;
859 if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
860 /* Round block count up. */
862 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
866 return MMSYSERR_NOTSUPPORTED;
870 WARN("Unsupported query %08x\n", adss->fdwSize);
871 return MMSYSERR_NOTSUPPORTED;
873 return MMSYSERR_NOERROR;
876 /***********************************************************************
877 * ADPCM_StreamConvert
880 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
882 AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver;
883 DWORD nsrc = adsh->cbSrcLength;
884 DWORD ndst = adsh->cbDstLength;
886 if (adsh->fdwConvert &
887 ~(ACM_STREAMCONVERTF_BLOCKALIGN|
888 ACM_STREAMCONVERTF_END|
889 ACM_STREAMCONVERTF_START))
891 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
893 /* ACM_STREAMCONVERTF_BLOCKALIGN
894 * currently all conversions are block aligned, so do nothing for this flag
895 * ACM_STREAMCONVERTF_END
896 * no pending data, so do nothing for this flag
898 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
900 ADPCM_Reset(adsi, aad);
903 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
904 adsh->cbSrcLengthUsed = nsrc;
905 adsh->cbDstLengthUsed = ndst;
907 return MMSYSERR_NOERROR;
910 /**************************************************************************
911 * ADPCM_DriverProc [exported]
913 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
914 LPARAM dwParam1, LPARAM dwParam2)
916 TRACE("(%08lx %p %04x %08lx %08lx);\n",
917 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
921 case DRV_LOAD: return 1;
922 case DRV_FREE: return 1;
923 case DRV_OPEN: return 1;
924 case DRV_CLOSE: return ADPCM_drvClose(dwDevID);
925 case DRV_ENABLE: return 1;
926 case DRV_DISABLE: return 1;
927 case DRV_QUERYCONFIGURE: return 1;
928 case DRV_CONFIGURE: MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK); return 1;
929 case DRV_INSTALL: return DRVCNF_RESTART;
930 case DRV_REMOVE: return DRVCNF_RESTART;
932 case ACMDM_DRIVER_NOTIFY:
933 /* no caching from other ACM drivers is done so far */
934 return MMSYSERR_NOERROR;
936 case ACMDM_DRIVER_DETAILS:
937 return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
939 case ACMDM_FORMATTAG_DETAILS:
940 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
942 case ACMDM_FORMAT_DETAILS:
943 return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
945 case ACMDM_FORMAT_SUGGEST:
946 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
948 case ACMDM_STREAM_OPEN:
949 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
951 case ACMDM_STREAM_CLOSE:
952 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
954 case ACMDM_STREAM_SIZE:
955 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
957 case ACMDM_STREAM_CONVERT:
958 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
960 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
961 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
962 /* this converter is not a hardware driver */
963 case ACMDM_FILTERTAG_DETAILS:
964 case ACMDM_FILTER_DETAILS:
965 /* this converter is not a filter */
966 case ACMDM_STREAM_RESET:
967 /* only needed for asynchronous driver... we aren't, so just say it */
968 return MMSYSERR_NOTSUPPORTED;
969 case ACMDM_STREAM_PREPARE:
970 case ACMDM_STREAM_UNPREPARE:
971 /* nothing special to do here... so don't do anything */
972 return MMSYSERR_NOERROR;
975 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);