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_drvOpen(LPCSTR str)
48 /***********************************************************************
51 static LRESULT ADPCM_drvClose(DWORD_PTR dwDevID)
56 typedef struct tagAcmAdpcmData
58 void (*convert)(PACMDRVSTREAMINSTANCE adsi,
59 const unsigned char*, LPDWORD, unsigned char*, LPDWORD);
60 /* IMA encoding only */
66 /* table to list all supported formats... those are the basic ones. this
67 * also helps given a unique index to each of the supported formats
76 static const Format PCM_Formats[] =
78 {1, 8, 8000}, {2, 8, 8000}, {1, 16, 8000}, {2, 16, 8000},
79 {1, 8, 11025}, {2, 8, 11025}, {1, 16, 11025}, {2, 16, 11025},
80 {1, 8, 22050}, {2, 8, 22050}, {1, 16, 22050}, {2, 16, 22050},
81 {1, 8, 44100}, {2, 8, 44100}, {1, 16, 44100}, {2, 16, 44100},
84 static const Format ADPCM_Formats[] =
86 {1, 4, 8000}, {2, 4, 8000}, {1, 4, 11025}, {2, 4, 11025},
87 {1, 4, 22050}, {2, 4, 22050}, {1, 4, 44100}, {2, 4, 44100},
90 #define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
91 #define NUM_ADPCM_FORMATS (sizeof(ADPCM_Formats) / sizeof(ADPCM_Formats[0]))
93 /***********************************************************************
94 * ADPCM_GetFormatIndex
96 static DWORD ADPCM_GetFormatIndex(const WAVEFORMATEX *wfx)
101 switch (wfx->wFormatTag)
103 case WAVE_FORMAT_PCM:
104 hi = NUM_PCM_FORMATS;
107 case WAVE_FORMAT_IMA_ADPCM:
108 hi = NUM_ADPCM_FORMATS;
109 fmts = ADPCM_Formats;
115 for (i = 0; i < hi; i++)
117 if (wfx->nChannels == fmts[i].nChannels &&
118 wfx->nSamplesPerSec == fmts[i].rate &&
119 wfx->wBitsPerSample == fmts[i].nBits)
123 switch (wfx->wFormatTag)
125 case WAVE_FORMAT_PCM:
126 if(3 > wfx->nChannels &&
127 wfx->nChannels > 0 &&
128 wfx->nAvgBytesPerSec == 2 * wfx->nSamplesPerSec * wfx->nChannels &&
129 wfx->nBlockAlign == 2 * wfx->nChannels &&
130 wfx->wBitsPerSample == 16)
133 case WAVE_FORMAT_IMA_ADPCM:
134 if(3 > wfx->nChannels &&
135 wfx->nChannels > 0 &&
136 wfx->wBitsPerSample == 4 &&
145 static void init_wfx_ima_adpcm(IMAADPCMWAVEFORMAT* awfx/*, DWORD nba*/)
147 register WAVEFORMATEX* pwfx = &awfx->wfx;
149 /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample
150 * have been initialized... */
152 if (pwfx->wFormatTag != WAVE_FORMAT_IMA_ADPCM) {FIXME("wrong FT\n"); return;}
153 if (ADPCM_GetFormatIndex(pwfx) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;}
155 switch (pwfx->nSamplesPerSec)
157 case 8000: pwfx->nBlockAlign = 256 * pwfx->nChannels; break;
158 case 11025: pwfx->nBlockAlign = 256 * pwfx->nChannels; break;
159 case 22050: pwfx->nBlockAlign = 512 * pwfx->nChannels; break;
160 case 44100: pwfx->nBlockAlign = 1024 * pwfx->nChannels; break;
161 default: /*pwfx->nBlockAlign = nba;*/ break;
163 pwfx->cbSize = sizeof(WORD);
165 awfx->wSamplesPerBlock = (pwfx->nBlockAlign - (4 * pwfx->nChannels) * 2) / pwfx->nChannels + 1;
166 pwfx->nAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) / awfx->wSamplesPerBlock;
169 /***********************************************************************
172 * Read a 16 bit sample (correctly handles endianess)
174 static inline short R16(const unsigned char* src)
176 return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
179 /***********************************************************************
182 * Write a 16 bit sample (correctly handles endianess)
184 static inline void W16(unsigned char* dst, short s)
190 /* IMA (or DVI) APDCM codec routines */
192 static const unsigned IMA_StepTable[89] =
194 7, 8, 9, 10, 11, 12, 13, 14,
195 16, 17, 19, 21, 23, 25, 28, 31,
196 34, 37, 41, 45, 50, 55, 60, 66,
197 73, 80, 88, 97, 107, 118, 130, 143,
198 157, 173, 190, 209, 230, 253, 279, 307,
199 337, 371, 408, 449, 494, 544, 598, 658,
200 724, 796, 876, 963, 1060, 1166, 1282, 1411,
201 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
202 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
203 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
204 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
208 static const int IMA_IndexTable[16] =
210 -1, -1, -1, -1, 2, 4, 6, 8,
211 -1, -1, -1, -1, 2, 4, 6, 8
214 static inline void clamp_step_index(int* stepIndex)
216 if (*stepIndex < 0 ) *stepIndex = 0;
217 if (*stepIndex > 88) *stepIndex = 88;
220 static inline void clamp_sample(int* sample)
222 if (*sample < -32768) *sample = -32768;
223 if (*sample > 32767) *sample = 32767;
226 static inline void process_nibble(unsigned char code, int* stepIndex, int* sample)
233 step = IMA_StepTable[*stepIndex];
235 if (code & 1) diff += step >> 2;
236 if (code & 2) diff += step >> 1;
237 if (code & 4) diff += step;
238 if (code & 8) *sample -= diff;
239 else *sample += diff;
240 clamp_sample(sample);
241 *stepIndex += IMA_IndexTable[code];
242 clamp_step_index(stepIndex);
245 static inline unsigned char generate_nibble(int in, int* stepIndex, int* sample)
247 int effdiff, diff = in - *sample;
261 step = IMA_StepTable[*stepIndex];
262 effdiff = (step >> 3);
282 if (code & 8) *sample -= effdiff;
283 else *sample += effdiff;
284 clamp_sample(sample);
285 *stepIndex += IMA_IndexTable[code];
286 clamp_step_index(stepIndex);
290 static void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi,
291 const unsigned char* src, LPDWORD nsrc,
292 unsigned char* dst, LPDWORD ndst)
295 int sampleL, sampleR;
296 int stepIndexL, stepIndexR;
297 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
299 /* compute the number of entire blocks we can decode...
300 * it's the min of the number of entire blocks in source buffer and the number
301 * of entire blocks in destination buffer
303 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
304 *ndst / (nsamp_blk * 2 * 2));
306 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
307 *ndst = nblock * (nsamp_blk * 2 * 2);
309 nsamp_blk--; /* remove the sample in block header */
310 for (; nblock > 0; nblock--)
312 const unsigned char* in_src = src;
314 /* handle headers first */
316 stepIndexL = (unsigned)*(src + 2);
317 clamp_step_index(&stepIndexL);
319 W16(dst, sampleL); dst += 2;
322 stepIndexR = (unsigned)*(src + 2);
323 clamp_step_index(&stepIndexR);
325 W16(dst, sampleR); dst += 2;
327 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
329 for (i = 0; i < 4; i++)
331 process_nibble(*src, &stepIndexL, &sampleL);
332 W16(dst + (2 * i + 0) * 4 + 0, sampleL);
333 process_nibble(*src++ >> 4, &stepIndexL, &sampleL);
334 W16(dst + (2 * i + 1) * 4 + 0, sampleL);
336 for (i = 0; i < 4; i++)
338 process_nibble(*src , &stepIndexR, &sampleR);
339 W16(dst + (2 * i + 0) * 4 + 2, sampleR);
340 process_nibble(*src++ >>4, &stepIndexR, &sampleR);
341 W16(dst + (2 * i + 1) * 4 + 2, sampleR);
345 /* we have now to realign the source pointer on block */
346 src = in_src + adsi->pwfxSrc->nBlockAlign;
350 static void cvtMMima16K(PACMDRVSTREAMINSTANCE adsi,
351 const unsigned char* src, LPDWORD nsrc,
352 unsigned char* dst, LPDWORD ndst)
356 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
358 /* compute the number of entire blocks we can decode...
359 * it's the min of the number of entire blocks in source buffer and the number
360 * of entire blocks in destination buffer
362 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
363 *ndst / (nsamp_blk * 2));
365 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
366 *ndst = nblock * nsamp_blk * 2;
368 nsamp_blk--; /* remove the sample in block header */
369 for (; nblock > 0; nblock--)
371 const unsigned char* in_src = src;
373 /* handle header first */
375 stepIndex = (unsigned)*(src + 2);
376 clamp_step_index(&stepIndex);
378 W16(dst, sample); dst += 2;
380 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
382 process_nibble(*src, &stepIndex, &sample);
383 W16(dst, sample); dst += 2;
384 process_nibble(*src++ >> 4, &stepIndex, &sample);
385 W16(dst, sample); dst += 2;
387 /* we have now to realign the source pointer on block */
388 src = in_src + adsi->pwfxSrc->nBlockAlign;
392 static void cvtSS16imaK(PACMDRVSTREAMINSTANCE adsi,
393 const unsigned char* src, LPDWORD nsrc,
394 unsigned char* dst, LPDWORD ndst)
396 int stepIndexL, stepIndexR;
397 int sampleL, sampleR;
399 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
401 /* compute the number of entire blocks we can decode...
402 * it's the min of the number of entire blocks in source buffer and the number
403 * of entire blocks in destination buffer
405 DWORD nblock = min(*nsrc / (nsamp_blk * 2 * 2),
406 *ndst / adsi->pwfxDst->nBlockAlign);
408 *nsrc = nblock * (nsamp_blk * 2 * 2);
409 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
411 stepIndexL = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
412 stepIndexR = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR;
414 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
416 for (; nblock > 0; nblock--)
418 unsigned char* in_dst = dst;
420 /* generate header */
421 sampleL = R16(src); src += 2;
422 W16(dst, sampleL); dst += 2;
423 *dst = (unsigned char)(unsigned)stepIndexL;
426 sampleR = R16(src); src += 2;
427 W16(dst, sampleR); dst += 2;
428 *dst = (unsigned char)(unsigned)stepIndexR;
431 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
433 for (i = 0; i < 4; i++)
435 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 0),
436 &stepIndexL, &sampleL);
437 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 0),
438 &stepIndexL, &sampleL);
439 *dst++ = (code1 << 4) | code2;
441 for (i = 0; i < 4; i++)
443 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 1),
444 &stepIndexR, &sampleR);
445 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 1),
446 &stepIndexR, &sampleR);
447 *dst++ = (code1 << 4) | code2;
451 dst = in_dst + adsi->pwfxDst->nBlockAlign;
453 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndexL;
454 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR = stepIndexR;
457 static void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi,
458 const unsigned char* src, LPDWORD nsrc,
459 unsigned char* dst, LPDWORD ndst)
464 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
466 /* compute the number of entire blocks we can decode...
467 * it's the min of the number of entire blocks in source buffer and the number
468 * of entire blocks in destination buffer
470 DWORD nblock = min(*nsrc / (nsamp_blk * 2),
471 *ndst / adsi->pwfxDst->nBlockAlign);
473 *nsrc = nblock * (nsamp_blk * 2);
474 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
476 stepIndex = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
477 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
479 for (; nblock > 0; nblock--)
481 unsigned char* in_dst = dst;
483 /* generate header */
484 /* FIXME: what about the last effective sample from previous block ??? */
485 /* perhaps something like:
486 * sample += R16(src);
487 * clamp_sample(sample);
489 * + saving the sample in adsi->dwDriver when all blocks are done
490 + + reset should set the field in adsi->dwDriver to 0 too
492 sample = R16(src); src += 2;
493 W16(dst, sample); dst += 2;
494 *dst = (unsigned char)(unsigned)stepIndex;
497 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
499 code1 = generate_nibble(R16(src), &stepIndex, &sample);
501 code2 = generate_nibble(R16(src), &stepIndex, &sample);
503 *dst++ = (code1 << 4) | code2;
505 dst = in_dst + adsi->pwfxDst->nBlockAlign;
507 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndex;
510 /***********************************************************************
511 * ADPCM_DriverDetails
514 static LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
516 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
517 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
520 add->vdwACM = 0x3320000;
521 add->vdwDriver = 0x04000000;
522 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
523 add->cFormatTags = 2; /* PCM, IMA ADPCM */
524 add->cFilterTags = 0;
526 MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM", -1,
527 add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
528 MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM CODEC", -1,
529 add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
530 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
531 add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
532 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
533 add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
534 add->szFeatures[0] = 0;
536 return MMSYSERR_NOERROR;
539 /***********************************************************************
540 * ADPCM_FormatTagDetails
543 static LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
545 static const WCHAR szPcm[]={'P','C','M',0};
546 static const WCHAR szImaAdPcm[]={'I','M','A',' ','A','D','P','C','M',0};
550 case ACM_FORMATTAGDETAILSF_INDEX:
551 if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
553 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
554 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
556 aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
560 case ACM_FORMATTAGDETAILSF_FORMATTAG:
561 switch (aftd->dwFormatTag)
563 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break;
564 case WAVE_FORMAT_IMA_ADPCM: aftd->dwFormatTagIndex = 1; break;
565 default: return ACMERR_NOTPOSSIBLE;
569 WARN("Unsupported query %08x\n", dwQuery);
570 return MMSYSERR_NOTSUPPORTED;
573 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
574 switch (aftd->dwFormatTagIndex)
577 aftd->dwFormatTag = WAVE_FORMAT_PCM;
578 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
579 aftd->cStandardFormats = NUM_PCM_FORMATS;
580 lstrcpyW(aftd->szFormatTag, szPcm);
583 aftd->dwFormatTag = WAVE_FORMAT_IMA_ADPCM;
584 aftd->cbFormatSize = sizeof(IMAADPCMWAVEFORMAT);
585 aftd->cStandardFormats = NUM_ADPCM_FORMATS;
586 lstrcpyW(aftd->szFormatTag, szImaAdPcm);
589 return MMSYSERR_NOERROR;
592 /***********************************************************************
593 * ADPCM_FormatDetails
596 static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
600 case ACM_FORMATDETAILSF_FORMAT:
601 if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
603 case ACM_FORMATDETAILSF_INDEX:
604 afd->pwfx->wFormatTag = afd->dwFormatTag;
605 switch (afd->dwFormatTag)
607 case WAVE_FORMAT_PCM:
608 if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
609 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
610 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
611 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
612 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
613 * afd->pwfx->cbSize = 0;
615 afd->pwfx->nBlockAlign =
616 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
617 afd->pwfx->nAvgBytesPerSec =
618 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
620 case WAVE_FORMAT_IMA_ADPCM:
621 if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE;
622 afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
623 afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
624 afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
625 afd->pwfx->nBlockAlign = 1024;
626 /* we got 4 bits per sample */
627 afd->pwfx->nAvgBytesPerSec =
628 (afd->pwfx->nSamplesPerSec * 4) / 8;
629 if (afd->cbwfx >= sizeof(WAVEFORMATEX))
630 afd->pwfx->cbSize = sizeof(WORD);
631 if (afd->cbwfx >= sizeof(IMAADPCMWAVEFORMAT))
632 ((IMAADPCMWAVEFORMAT*)afd->pwfx)->wSamplesPerBlock = (1024 - 4 * afd->pwfx->nChannels) * (2 / afd->pwfx->nChannels) + 1;
635 WARN("Unsupported tag %08x\n", afd->dwFormatTag);
636 return MMSYSERR_INVALPARAM;
640 WARN("Unsupported query %08x\n", dwQuery);
641 return MMSYSERR_NOTSUPPORTED;
643 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
644 afd->szFormat[0] = 0; /* let MSACM format this for us... */
646 return MMSYSERR_NOERROR;
649 /***********************************************************************
650 * ADPCM_FormatSuggest
653 static LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
656 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
657 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
658 adfs->pwfxSrc->wFormatTag == adfs->pwfxDst->wFormatTag ||
659 ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
661 /* If no suggestion for destination, then copy source value */
662 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
663 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
664 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
665 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
667 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
669 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
670 adfs->pwfxDst->wBitsPerSample = 4;
672 adfs->pwfxDst->wBitsPerSample = 16;
674 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
676 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
677 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
679 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
682 /* recompute other values */
683 switch (adfs->pwfxDst->wFormatTag)
685 case WAVE_FORMAT_PCM:
686 if (adfs->cbwfxSrc < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
687 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
688 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
689 /* check if result is ok */
690 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
692 case WAVE_FORMAT_IMA_ADPCM:
693 if (adfs->cbwfxDst < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
694 init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT*)adfs->pwfxDst);
695 /* FIXME: not handling header overhead */
696 TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock);
697 /* check if result is ok */
698 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
701 return ACMERR_NOTPOSSIBLE;
704 return MMSYSERR_NOERROR;
707 /***********************************************************************
711 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
713 aad->stepIndexL = aad->stepIndexR = 0;
716 /***********************************************************************
720 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
725 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
727 if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
728 ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
729 return ACMERR_NOTPOSSIBLE;
731 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
732 if (aad == 0) return MMSYSERR_NOMEM;
734 adsi->dwDriver = (DWORD_PTR)aad;
736 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
737 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
741 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
742 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
744 /* resampling or mono <=> stereo not available
745 * ADPCM algo only define 16 bit per sample output
747 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
748 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
749 adsi->pwfxDst->wBitsPerSample != 16)
752 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
753 TRACE("spb=%u\n", nspb);
755 /* we check that in a block, after the header, samples are present on
756 * 4-sample packet pattern
757 * we also check that the block alignment is bigger than the expected size
759 if (((nspb - 1) & 3) != 0) goto theEnd;
760 if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
763 /* adpcm decoding... */
764 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
765 aad->convert = cvtSSima16K;
766 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
767 aad->convert = cvtMMima16K;
769 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
770 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
772 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
773 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
774 adsi->pwfxSrc->wBitsPerSample != 16)
777 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
778 TRACE("spb=%u\n", nspb);
780 /* we check that in a block, after the header, samples are present on
781 * 4-sample packet pattern
782 * we also check that the block alignment is bigger than the expected size
784 if (((nspb - 1) & 3) != 0) goto theEnd;
785 if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
788 /* adpcm coding... */
789 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
790 aad->convert = cvtSS16imaK;
791 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
792 aad->convert = cvtMM16imaK;
795 ADPCM_Reset(adsi, aad);
797 return MMSYSERR_NOERROR;
800 HeapFree(GetProcessHeap(), 0, aad);
802 return MMSYSERR_NOTSUPPORTED;
805 /***********************************************************************
809 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
811 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
812 return MMSYSERR_NOERROR;
815 /***********************************************************************
819 static LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
823 switch (adss->fdwSize)
825 case ACM_STREAMSIZEF_DESTINATION:
826 /* cbDstLength => cbSrcLength */
827 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
828 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
830 nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign;
832 return ACMERR_NOTPOSSIBLE;
833 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
835 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
836 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
838 nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock);
840 return ACMERR_NOTPOSSIBLE;
841 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
845 return MMSYSERR_NOTSUPPORTED;
848 case ACM_STREAMSIZEF_SOURCE:
849 /* cbSrcLength => cbDstLength */
850 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
851 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
853 nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock);
855 return ACMERR_NOTPOSSIBLE;
856 if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock))
857 /* Round block count up. */
859 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign;
861 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
862 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
864 nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign;
866 return ACMERR_NOTPOSSIBLE;
867 if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
868 /* Round block count up. */
870 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
874 return MMSYSERR_NOTSUPPORTED;
878 WARN("Unsupported query %08x\n", adss->fdwSize);
879 return MMSYSERR_NOTSUPPORTED;
881 return MMSYSERR_NOERROR;
884 /***********************************************************************
885 * ADPCM_StreamConvert
888 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
890 AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver;
891 DWORD nsrc = adsh->cbSrcLength;
892 DWORD ndst = adsh->cbDstLength;
894 if (adsh->fdwConvert &
895 ~(ACM_STREAMCONVERTF_BLOCKALIGN|
896 ACM_STREAMCONVERTF_END|
897 ACM_STREAMCONVERTF_START))
899 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
901 /* ACM_STREAMCONVERTF_BLOCKALIGN
902 * currently all conversions are block aligned, so do nothing for this flag
903 * ACM_STREAMCONVERTF_END
904 * no pending data, so do nothing for this flag
906 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
908 ADPCM_Reset(adsi, aad);
911 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
912 adsh->cbSrcLengthUsed = nsrc;
913 adsh->cbDstLengthUsed = ndst;
915 return MMSYSERR_NOERROR;
918 /**************************************************************************
919 * ADPCM_DriverProc [exported]
921 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
922 LPARAM dwParam1, LPARAM dwParam2)
924 TRACE("(%08lx %p %04x %08lx %08lx);\n",
925 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
929 case DRV_LOAD: return 1;
930 case DRV_FREE: return 1;
931 case DRV_OPEN: return ADPCM_drvOpen((LPSTR)dwParam1);
932 case DRV_CLOSE: return ADPCM_drvClose(dwDevID);
933 case DRV_ENABLE: return 1;
934 case DRV_DISABLE: return 1;
935 case DRV_QUERYCONFIGURE: return 1;
936 case DRV_CONFIGURE: MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK); return 1;
937 case DRV_INSTALL: return DRVCNF_RESTART;
938 case DRV_REMOVE: return DRVCNF_RESTART;
940 case ACMDM_DRIVER_NOTIFY:
941 /* no caching from other ACM drivers is done so far */
942 return MMSYSERR_NOERROR;
944 case ACMDM_DRIVER_DETAILS:
945 return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
947 case ACMDM_FORMATTAG_DETAILS:
948 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
950 case ACMDM_FORMAT_DETAILS:
951 return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
953 case ACMDM_FORMAT_SUGGEST:
954 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
956 case ACMDM_STREAM_OPEN:
957 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
959 case ACMDM_STREAM_CLOSE:
960 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
962 case ACMDM_STREAM_SIZE:
963 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
965 case ACMDM_STREAM_CONVERT:
966 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
968 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
969 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
970 /* this converter is not a hardware driver */
971 case ACMDM_FILTERTAG_DETAILS:
972 case ACMDM_FILTER_DETAILS:
973 /* this converter is not a filter */
974 case ACMDM_STREAM_RESET:
975 /* only needed for asynchronous driver... we aren't, so just say it */
976 return MMSYSERR_NOTSUPPORTED;
977 case ACMDM_STREAM_PREPARE:
978 case ACMDM_STREAM_UNPREPARE:
979 /* nothing special to do here... so don't do anything */
980 return MMSYSERR_NOERROR;
983 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);