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;
660 /* FIXME: should do those tests against the real size (according to format tag */
662 /* If no suggestion for destination, then copy source value */
663 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
664 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
665 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
666 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
668 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
670 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
671 adfs->pwfxDst->wBitsPerSample = 4;
673 adfs->pwfxDst->wBitsPerSample = 16;
675 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
677 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
678 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
680 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
683 /* recompute other values */
684 switch (adfs->pwfxDst->wFormatTag)
686 case WAVE_FORMAT_PCM:
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 init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT*)adfs->pwfxDst);
694 /* FIXME: not handling header overhead */
695 TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock);
696 /* check if result is ok */
697 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
700 return ACMERR_NOTPOSSIBLE;
703 return MMSYSERR_NOERROR;
706 /***********************************************************************
710 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
712 aad->stepIndexL = aad->stepIndexR = 0;
715 /***********************************************************************
719 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
724 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
726 if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
727 ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
728 return ACMERR_NOTPOSSIBLE;
730 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
731 if (aad == 0) return MMSYSERR_NOMEM;
733 adsi->dwDriver = (DWORD_PTR)aad;
735 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
736 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
740 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
741 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
743 /* resampling or mono <=> stereo not available
744 * ADPCM algo only define 16 bit per sample output
746 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
747 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
748 adsi->pwfxDst->wBitsPerSample != 16)
751 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
752 TRACE("spb=%u\n", nspb);
754 /* we check that in a block, after the header, samples are present on
755 * 4-sample packet pattern
756 * we also check that the block alignment is bigger than the expected size
758 if (((nspb - 1) & 3) != 0) goto theEnd;
759 if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
762 /* adpcm decoding... */
763 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
764 aad->convert = cvtSSima16K;
765 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
766 aad->convert = cvtMMima16K;
768 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
769 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
771 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
772 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
773 adsi->pwfxSrc->wBitsPerSample != 16)
776 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
777 TRACE("spb=%u\n", nspb);
779 /* we check that in a block, after the header, samples are present on
780 * 4-sample packet pattern
781 * we also check that the block alignment is bigger than the expected size
783 if (((nspb - 1) & 3) != 0) goto theEnd;
784 if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
787 /* adpcm coding... */
788 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
789 aad->convert = cvtSS16imaK;
790 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
791 aad->convert = cvtMM16imaK;
794 ADPCM_Reset(adsi, aad);
796 return MMSYSERR_NOERROR;
799 HeapFree(GetProcessHeap(), 0, aad);
801 return MMSYSERR_NOTSUPPORTED;
804 /***********************************************************************
808 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
810 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
811 return MMSYSERR_NOERROR;
814 /***********************************************************************
818 static LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
822 switch (adss->fdwSize)
824 case ACM_STREAMSIZEF_DESTINATION:
825 /* cbDstLength => cbSrcLength */
826 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
827 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
829 nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign;
831 return ACMERR_NOTPOSSIBLE;
832 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
834 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
835 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
837 nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock);
839 return ACMERR_NOTPOSSIBLE;
840 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
844 return MMSYSERR_NOTSUPPORTED;
847 case ACM_STREAMSIZEF_SOURCE:
848 /* cbSrcLength => cbDstLength */
849 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
850 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
852 nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock);
854 return ACMERR_NOTPOSSIBLE;
855 if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock))
856 /* Round block count up. */
858 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign;
860 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
861 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
863 nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign;
865 return ACMERR_NOTPOSSIBLE;
866 if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
867 /* Round block count up. */
869 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
873 return MMSYSERR_NOTSUPPORTED;
877 WARN("Unsupported query %08x\n", adss->fdwSize);
878 return MMSYSERR_NOTSUPPORTED;
880 return MMSYSERR_NOERROR;
883 /***********************************************************************
884 * ADPCM_StreamConvert
887 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
889 AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver;
890 DWORD nsrc = adsh->cbSrcLength;
891 DWORD ndst = adsh->cbDstLength;
893 if (adsh->fdwConvert &
894 ~(ACM_STREAMCONVERTF_BLOCKALIGN|
895 ACM_STREAMCONVERTF_END|
896 ACM_STREAMCONVERTF_START))
898 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
900 /* ACM_STREAMCONVERTF_BLOCKALIGN
901 * currently all conversions are block aligned, so do nothing for this flag
902 * ACM_STREAMCONVERTF_END
903 * no pending data, so do nothing for this flag
905 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
907 ADPCM_Reset(adsi, aad);
910 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
911 adsh->cbSrcLengthUsed = nsrc;
912 adsh->cbDstLengthUsed = ndst;
914 return MMSYSERR_NOERROR;
917 /**************************************************************************
918 * ADPCM_DriverProc [exported]
920 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
921 LPARAM dwParam1, LPARAM dwParam2)
923 TRACE("(%08lx %p %04x %08lx %08lx);\n",
924 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
928 case DRV_LOAD: return 1;
929 case DRV_FREE: return 1;
930 case DRV_OPEN: return ADPCM_drvOpen((LPSTR)dwParam1);
931 case DRV_CLOSE: return ADPCM_drvClose(dwDevID);
932 case DRV_ENABLE: return 1;
933 case DRV_DISABLE: return 1;
934 case DRV_QUERYCONFIGURE: return 1;
935 case DRV_CONFIGURE: MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK); return 1;
936 case DRV_INSTALL: return DRVCNF_RESTART;
937 case DRV_REMOVE: return DRVCNF_RESTART;
939 case ACMDM_DRIVER_NOTIFY:
940 /* no caching from other ACM drivers is done so far */
941 return MMSYSERR_NOERROR;
943 case ACMDM_DRIVER_DETAILS:
944 return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
946 case ACMDM_FORMATTAG_DETAILS:
947 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
949 case ACMDM_FORMAT_DETAILS:
950 return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
952 case ACMDM_FORMAT_SUGGEST:
953 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
955 case ACMDM_STREAM_OPEN:
956 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
958 case ACMDM_STREAM_CLOSE:
959 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
961 case ACMDM_STREAM_SIZE:
962 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
964 case ACMDM_STREAM_CONVERT:
965 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
967 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
968 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
969 /* this converter is not a hardware driver */
970 case ACMDM_FILTERTAG_DETAILS:
971 case ACMDM_FILTER_DETAILS:
972 /* this converter is not a filter */
973 case ACMDM_STREAM_RESET:
974 /* only needed for asynchronous driver... we aren't, so just say it */
975 return MMSYSERR_NOTSUPPORTED;
976 case ACMDM_STREAM_PREPARE:
977 case ACMDM_STREAM_UNPREPARE:
978 /* nothing special to do here... so don't do anything */
979 return MMSYSERR_NOERROR;
982 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);