webservices: Add asynchronous support for WsReceiveMessage.
[wine.git] / dlls / imaadp32.acm / imaadp32.c
blob474f5485820985f003329055230cc8d4950ca2de
1 /*
2 * IMA ADPCM handling
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
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
30 #include "mmsystem.h"
31 #include "mmreg.h"
32 #include "msacm.h"
33 #include "msacmdrv.h"
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 /***********************************************************************
41 * ADPCM_drvClose
43 static LRESULT ADPCM_drvClose(DWORD_PTR dwDevID)
45 return 1;
48 typedef struct tagAcmAdpcmData
50 void (*convert)(PACMDRVSTREAMINSTANCE adsi,
51 const unsigned char*, LPDWORD, unsigned char*, LPDWORD);
52 /* IMA encoding only */
53 BYTE stepIndexL;
54 BYTE stepIndexR;
55 /* short sample; */
56 } AcmAdpcmData;
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
61 typedef struct
63 int nChannels;
64 int nBits;
65 int rate;
66 } Format;
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)
90 int i, hi;
91 const Format* fmts;
93 switch (wfx->wFormatTag)
95 case WAVE_FORMAT_PCM:
96 hi = NUM_PCM_FORMATS;
97 fmts = PCM_Formats;
98 break;
99 case WAVE_FORMAT_IMA_ADPCM:
100 hi = NUM_ADPCM_FORMATS;
101 fmts = ADPCM_Formats;
102 break;
103 default:
104 return 0xFFFFFFFF;
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)
112 return i;
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)
123 return hi;
124 break;
125 case WAVE_FORMAT_IMA_ADPCM:
126 if(3 > wfx->nChannels &&
127 wfx->nChannels > 0 &&
128 wfx->wBitsPerSample == 4 &&
129 wfx->cbSize == 2)
130 return hi;
131 break;
134 return 0xFFFFFFFF;
137 static void init_wfx_ima_adpcm(IMAADPCMWAVEFORMAT* awfx/*, DWORD nba*/)
139 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 /***********************************************************************
162 * R16
164 * Read a 16 bit sample (correctly handles endianness)
166 static inline short R16(const unsigned char* src)
168 return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
171 /***********************************************************************
172 * W16
174 * Write a 16 bit sample (correctly handles endianness)
176 static inline void W16(unsigned char* dst, short s)
178 dst[0] = LOBYTE(s);
179 dst[1] = HIBYTE(s);
182 /***********************************************************************
183 * W8
185 * Write a 8 bit sample
187 static inline void W8(unsigned char* dst, short s)
189 dst[0] = (unsigned char)((s + 32768) >> 8);
193 static inline void W8_16(unsigned char* dst, short s, int bytes)
195 if(bytes == 1)
196 W8(dst, s);
197 else
198 W16(dst, s);
201 /* IMA (or DVI) APDCM codec routines */
203 static const unsigned IMA_StepTable[89] =
205 7, 8, 9, 10, 11, 12, 13, 14,
206 16, 17, 19, 21, 23, 25, 28, 31,
207 34, 37, 41, 45, 50, 55, 60, 66,
208 73, 80, 88, 97, 107, 118, 130, 143,
209 157, 173, 190, 209, 230, 253, 279, 307,
210 337, 371, 408, 449, 494, 544, 598, 658,
211 724, 796, 876, 963, 1060, 1166, 1282, 1411,
212 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
213 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
214 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
215 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
216 32767
219 static const int IMA_IndexTable[16] =
221 -1, -1, -1, -1, 2, 4, 6, 8,
222 -1, -1, -1, -1, 2, 4, 6, 8
225 static inline void clamp_step_index(int* stepIndex)
227 if (*stepIndex < 0 ) *stepIndex = 0;
228 if (*stepIndex > 88) *stepIndex = 88;
231 static inline void clamp_sample(int* sample)
233 if (*sample < -32768) *sample = -32768;
234 if (*sample > 32767) *sample = 32767;
237 static inline void process_nibble(unsigned char code, int* stepIndex, int* sample)
239 unsigned step;
240 int diff;
242 code &= 0x0F;
244 step = IMA_StepTable[*stepIndex];
245 diff = step >> 3;
246 if (code & 1) diff += step >> 2;
247 if (code & 2) diff += step >> 1;
248 if (code & 4) diff += step;
249 if (code & 8) *sample -= diff;
250 else *sample += diff;
251 clamp_sample(sample);
252 *stepIndex += IMA_IndexTable[code];
253 clamp_step_index(stepIndex);
256 static inline unsigned char generate_nibble(int in, int* stepIndex, int* sample)
258 int effdiff, diff = in - *sample;
259 unsigned step;
260 unsigned char code;
262 if (diff < 0)
264 diff = -diff;
265 code = 8;
267 else
269 code = 0;
272 step = IMA_StepTable[*stepIndex];
273 effdiff = (step >> 3);
274 if (diff >= step)
276 code |= 4;
277 diff -= step;
278 effdiff += step;
280 step >>= 1;
281 if (diff >= step)
283 code |= 2;
284 diff -= step;
285 effdiff += step;
287 step >>= 1;
288 if (diff >= step)
290 code |= 1;
291 effdiff += step;
293 if (code & 8) *sample -= effdiff;
294 else *sample += effdiff;
295 clamp_sample(sample);
296 *stepIndex += IMA_IndexTable[code];
297 clamp_step_index(stepIndex);
298 return code;
301 static void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi,
302 const unsigned char* src, LPDWORD nsrc,
303 unsigned char* dst, LPDWORD ndst)
305 int i;
306 int sampleL, sampleR;
307 int stepIndexL, stepIndexR;
308 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
309 int nsamp;
310 /* compute the number of entire blocks we can decode...
311 * it's the min of the number of entire blocks in source buffer and the number
312 * of entire blocks in destination buffer
314 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
315 *ndst / (nsamp_blk * 2 * 2));
317 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
318 *ndst = nblock * (nsamp_blk * 2 * 2);
320 nsamp_blk--; /* remove the sample in block header */
321 for (; nblock > 0; nblock--)
323 const unsigned char* in_src = src;
325 /* handle headers first */
326 sampleL = R16(src);
327 stepIndexL = (unsigned)*(src + 2);
328 clamp_step_index(&stepIndexL);
329 src += 4;
330 W16(dst, sampleL); dst += 2;
332 sampleR = R16(src);
333 stepIndexR = (unsigned)*(src + 2);
334 clamp_step_index(&stepIndexR);
335 src += 4;
336 W16(dst, sampleR); dst += 2;
338 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
340 for (i = 0; i < 4; i++)
342 process_nibble(*src, &stepIndexL, &sampleL);
343 W16(dst + (2 * i + 0) * 4 + 0, sampleL);
344 process_nibble(*src++ >> 4, &stepIndexL, &sampleL);
345 W16(dst + (2 * i + 1) * 4 + 0, sampleL);
347 for (i = 0; i < 4; i++)
349 process_nibble(*src , &stepIndexR, &sampleR);
350 W16(dst + (2 * i + 0) * 4 + 2, sampleR);
351 process_nibble(*src++ >>4, &stepIndexR, &sampleR);
352 W16(dst + (2 * i + 1) * 4 + 2, sampleR);
354 dst += 32;
356 /* we have now to realign the source pointer on block */
357 src = in_src + adsi->pwfxSrc->nBlockAlign;
361 static void cvtMMimaK(PACMDRVSTREAMINSTANCE adsi,
362 const unsigned char* src, LPDWORD nsrc,
363 unsigned char* dst, LPDWORD ndst)
365 int sample;
366 int stepIndex;
367 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
368 int nsamp;
369 int bytesPerSample = adsi->pwfxDst->wBitsPerSample / 8;
370 /* compute the number of entire blocks we can decode...
371 * it's the min of the number of entire blocks in source buffer and the number
372 * of entire blocks in destination buffer
374 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign, *ndst / (nsamp_blk * bytesPerSample));
376 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
377 *ndst = nblock * nsamp_blk * bytesPerSample;
379 nsamp_blk--; /* remove the sample in block header */
380 for (; nblock > 0; nblock--)
382 const unsigned char* in_src = src;
384 /* handle header first */
385 sample = R16(src);
386 stepIndex = (unsigned)*(src + 2);
387 clamp_step_index(&stepIndex);
388 src += 4;
389 W8_16(dst, sample, bytesPerSample); dst += bytesPerSample;
391 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
393 process_nibble(*src, &stepIndex, &sample);
394 W8_16(dst, sample, bytesPerSample); dst += bytesPerSample;
395 process_nibble(*src++ >> 4, &stepIndex, &sample);
396 W8_16(dst, sample, bytesPerSample); dst += bytesPerSample;
398 /* we have now to realign the source pointer on block */
399 src = in_src + adsi->pwfxSrc->nBlockAlign;
403 static void cvtSS16imaK(PACMDRVSTREAMINSTANCE adsi,
404 const unsigned char* src, LPDWORD nsrc,
405 unsigned char* dst, LPDWORD ndst)
407 int stepIndexL, stepIndexR;
408 int sampleL, sampleR;
409 BYTE code1, code2;
410 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
411 int i, nsamp;
412 /* compute the number of entire blocks we can decode...
413 * it's the min of the number of entire blocks in source buffer and the number
414 * of entire blocks in destination buffer
416 DWORD nblock = min(*nsrc / (nsamp_blk * 2 * 2),
417 *ndst / adsi->pwfxDst->nBlockAlign);
419 *nsrc = nblock * (nsamp_blk * 2 * 2);
420 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
422 stepIndexL = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
423 stepIndexR = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR;
425 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
427 for (; nblock > 0; nblock--)
429 unsigned char* in_dst = dst;
431 /* generate header */
432 sampleL = R16(src); src += 2;
433 W16(dst, sampleL); dst += 2;
434 W16(dst, stepIndexL); dst += 2;
436 sampleR = R16(src); src += 2;
437 W16(dst, sampleR); dst += 2;
438 W16(dst, stepIndexR); dst += 2;
440 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
442 for (i = 0; i < 4; i++)
444 code1 = generate_nibble(R16(src + (4 * i + 0) * 2),
445 &stepIndexL, &sampleL);
446 code2 = generate_nibble(R16(src + (4 * i + 2) * 2),
447 &stepIndexL, &sampleL);
448 *dst++ = (code2 << 4) | code1;
450 for (i = 0; i < 4; i++)
452 code1 = generate_nibble(R16(src + (4 * i + 1) * 2),
453 &stepIndexR, &sampleR);
454 code2 = generate_nibble(R16(src + (4 * i + 3) * 2),
455 &stepIndexR, &sampleR);
456 *dst++ = (code2 << 4) | code1;
458 src += 32;
460 dst = in_dst + adsi->pwfxDst->nBlockAlign;
462 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndexL;
463 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR = stepIndexR;
466 static void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi,
467 const unsigned char* src, LPDWORD nsrc,
468 unsigned char* dst, LPDWORD ndst)
470 int stepIndex;
471 int sample;
472 BYTE code1, code2;
473 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
474 int nsamp;
475 /* compute the number of entire blocks we can decode...
476 * it's the min of the number of entire blocks in source buffer and the number
477 * of entire blocks in destination buffer
479 DWORD nblock = min(*nsrc / (nsamp_blk * 2),
480 *ndst / adsi->pwfxDst->nBlockAlign);
482 *nsrc = nblock * (nsamp_blk * 2);
483 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
485 stepIndex = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
486 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
488 for (; nblock > 0; nblock--)
490 unsigned char* in_dst = dst;
492 /* generate header */
493 /* FIXME: what about the last effective sample from previous block ??? */
494 /* perhaps something like:
495 * sample += R16(src);
496 * clamp_sample(sample);
497 * and with :
498 * + saving the sample in adsi->dwDriver when all blocks are done
499 + + reset should set the field in adsi->dwDriver to 0 too
501 sample = R16(src); src += 2;
502 W16(dst, sample); dst += 2;
503 *dst = (unsigned char)(unsigned)stepIndex;
504 dst += 2;
506 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
508 code1 = generate_nibble(R16(src), &stepIndex, &sample);
509 src += 2;
510 code2 = generate_nibble(R16(src), &stepIndex, &sample);
511 src += 2;
512 *dst++ = (code2 << 4) | code1;
514 dst = in_dst + adsi->pwfxDst->nBlockAlign;
516 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndex;
519 /***********************************************************************
520 * ADPCM_DriverDetails
523 static LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
525 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
526 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
527 add->wMid = MM_MICROSOFT;
528 add->wPid = MM_MSFT_ACM_IMAADPCM;
529 add->vdwACM = 0x3320000;
530 add->vdwDriver = 0x04000000;
531 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
532 add->cFormatTags = 2; /* PCM, IMA ADPCM */
533 add->cFilterTags = 0;
534 add->hicon = NULL;
535 MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM", -1,
536 add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
537 MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM CODEC", -1,
538 add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
539 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
540 add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
541 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
542 add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
543 add->szFeatures[0] = 0;
545 return MMSYSERR_NOERROR;
548 /***********************************************************************
549 * ADPCM_FormatTagDetails
552 static LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
554 static const WCHAR szPcm[]={'P','C','M',0};
555 static const WCHAR szImaAdPcm[]={'I','M','A',' ','A','D','P','C','M',0};
557 switch (dwQuery)
559 case ACM_FORMATTAGDETAILSF_INDEX:
560 if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
561 break;
562 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
563 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
565 aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
566 break;
568 /* fall through */
569 case ACM_FORMATTAGDETAILSF_FORMATTAG:
570 switch (aftd->dwFormatTag)
572 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break;
573 case WAVE_FORMAT_IMA_ADPCM: aftd->dwFormatTagIndex = 1; break;
574 default: return ACMERR_NOTPOSSIBLE;
576 break;
577 default:
578 WARN("Unsupported query %08x\n", dwQuery);
579 return MMSYSERR_NOTSUPPORTED;
582 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
583 switch (aftd->dwFormatTagIndex)
585 case 0:
586 aftd->dwFormatTag = WAVE_FORMAT_PCM;
587 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
588 aftd->cStandardFormats = NUM_PCM_FORMATS;
589 lstrcpyW(aftd->szFormatTag, szPcm);
590 break;
591 case 1:
592 aftd->dwFormatTag = WAVE_FORMAT_IMA_ADPCM;
593 aftd->cbFormatSize = sizeof(IMAADPCMWAVEFORMAT);
594 aftd->cStandardFormats = NUM_ADPCM_FORMATS;
595 lstrcpyW(aftd->szFormatTag, szImaAdPcm);
596 break;
598 return MMSYSERR_NOERROR;
601 /***********************************************************************
602 * ADPCM_FormatDetails
605 static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
607 switch (dwQuery)
609 case ACM_FORMATDETAILSF_FORMAT:
610 if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
611 break;
612 case ACM_FORMATDETAILSF_INDEX:
613 afd->pwfx->wFormatTag = afd->dwFormatTag;
614 switch (afd->dwFormatTag)
616 case WAVE_FORMAT_PCM:
617 if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
618 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
619 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
620 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
621 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
622 * afd->pwfx->cbSize = 0;
624 afd->pwfx->nBlockAlign =
625 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
626 afd->pwfx->nAvgBytesPerSec =
627 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
628 break;
629 case WAVE_FORMAT_IMA_ADPCM:
630 if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE;
631 afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
632 afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
633 afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
634 init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT *)afd->pwfx);
635 break;
636 default:
637 WARN("Unsupported tag %08x\n", afd->dwFormatTag);
638 return MMSYSERR_INVALPARAM;
640 break;
641 default:
642 WARN("Unsupported query %08x\n", dwQuery);
643 return MMSYSERR_NOTSUPPORTED;
645 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
646 afd->szFormat[0] = 0; /* let MSACM format this for us... */
648 return MMSYSERR_NOERROR;
651 /***********************************************************************
652 * ADPCM_FormatSuggest
655 static LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
657 /* some tests ... */
658 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
659 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
660 adfs->pwfxSrc->wFormatTag == adfs->pwfxDst->wFormatTag ||
661 ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
663 /* If no suggestion for destination, then copy source value */
664 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
665 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
666 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
667 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
669 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
671 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
672 adfs->pwfxDst->wBitsPerSample = 4;
673 else
674 adfs->pwfxDst->wBitsPerSample = 16;
676 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
678 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
679 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
680 else
681 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
684 /* recompute other values */
685 switch (adfs->pwfxDst->wFormatTag)
687 case WAVE_FORMAT_PCM:
688 if (adfs->cbwfxSrc < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
689 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
690 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
691 /* check if result is ok */
692 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
693 break;
694 case WAVE_FORMAT_IMA_ADPCM:
695 if (adfs->cbwfxDst < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
696 init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT*)adfs->pwfxDst);
697 /* FIXME: not handling header overhead */
698 TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock);
699 /* check if result is ok */
700 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
701 break;
702 default:
703 return ACMERR_NOTPOSSIBLE;
706 return MMSYSERR_NOERROR;
709 /***********************************************************************
710 * ADPCM_Reset
713 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
715 aad->stepIndexL = aad->stepIndexR = 0;
718 /***********************************************************************
719 * ADPCM_StreamOpen
722 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
724 AcmAdpcmData* aad;
725 unsigned nspb;
727 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
729 if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
730 ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
731 return ACMERR_NOTPOSSIBLE;
733 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
734 if (aad == 0) return MMSYSERR_NOMEM;
736 adsi->dwDriver = (DWORD_PTR)aad;
738 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
739 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
741 goto theEnd;
743 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
744 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
746 /* resampling or mono <=> stereo not available
747 * ADPCM algo only define 16 bit per sample output
748 * (The API seems to still allow 8 bit per sample output)
750 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
751 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
752 (adsi->pwfxDst->wBitsPerSample != 16 && adsi->pwfxDst->wBitsPerSample != 8))
753 goto theEnd;
755 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
756 TRACE("spb=%u\n", nspb);
758 /* we check that in a block, after the header, samples are present on
759 * 4-sample packet pattern
760 * we also check that the block alignment is bigger than the expected size
762 if (((nspb - 1) & 3) != 0) goto theEnd;
763 if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
764 goto theEnd;
766 /* adpcm decoding... */
767 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
768 aad->convert = cvtSSima16K;
769 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
770 aad->convert = cvtMMimaK;
771 if (adsi->pwfxDst->wBitsPerSample == 8 && adsi->pwfxDst->nChannels == 1)
772 aad->convert = cvtMMimaK;
773 /* FIXME: Stereo support for 8bit samples*/
774 if (adsi->pwfxDst->wBitsPerSample == 8 && adsi->pwfxDst->nChannels == 2)
775 goto theEnd;
777 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
778 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
780 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
781 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
782 adsi->pwfxSrc->wBitsPerSample != 16)
783 goto theEnd;
785 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
786 TRACE("spb=%u\n", nspb);
788 /* we check that in a block, after the header, samples are present on
789 * 4-sample packet pattern
790 * we also check that the block alignment is bigger than the expected size
792 if (((nspb - 1) & 3) != 0) goto theEnd;
793 if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
794 goto theEnd;
796 /* adpcm coding... */
797 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
798 aad->convert = cvtSS16imaK;
799 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
800 aad->convert = cvtMM16imaK;
802 else goto theEnd;
803 ADPCM_Reset(adsi, aad);
805 return MMSYSERR_NOERROR;
807 theEnd:
808 HeapFree(GetProcessHeap(), 0, aad);
809 adsi->dwDriver = 0L;
810 return MMSYSERR_NOTSUPPORTED;
813 /***********************************************************************
814 * ADPCM_StreamClose
817 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
819 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
820 return MMSYSERR_NOERROR;
823 /***********************************************************************
824 * ADPCM_StreamSize
827 static LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
829 DWORD nblocks;
831 switch (adss->fdwSize)
833 case ACM_STREAMSIZEF_DESTINATION:
834 /* cbDstLength => cbSrcLength */
835 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
836 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
838 nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign;
839 if (nblocks == 0)
840 return ACMERR_NOTPOSSIBLE;
841 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
843 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
844 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
846 nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock);
847 if (nblocks == 0)
848 return ACMERR_NOTPOSSIBLE;
849 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
851 else
853 return MMSYSERR_NOTSUPPORTED;
855 break;
856 case ACM_STREAMSIZEF_SOURCE:
857 /* cbSrcLength => cbDstLength */
858 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
859 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
861 nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock);
862 if (nblocks == 0)
863 return ACMERR_NOTPOSSIBLE;
864 if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock))
865 /* Round block count up. */
866 nblocks++;
867 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign;
869 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
870 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
872 nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign;
873 if (nblocks == 0)
874 return ACMERR_NOTPOSSIBLE;
875 if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
876 /* Round block count up. */
877 nblocks++;
878 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
880 else
882 return MMSYSERR_NOTSUPPORTED;
884 break;
885 default:
886 WARN("Unsupported query %08x\n", adss->fdwSize);
887 return MMSYSERR_NOTSUPPORTED;
889 return MMSYSERR_NOERROR;
892 /***********************************************************************
893 * ADPCM_StreamConvert
896 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
898 AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver;
899 DWORD nsrc = adsh->cbSrcLength;
900 DWORD ndst = adsh->cbDstLength;
902 if (adsh->fdwConvert &
903 ~(ACM_STREAMCONVERTF_BLOCKALIGN|
904 ACM_STREAMCONVERTF_END|
905 ACM_STREAMCONVERTF_START))
907 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
909 /* ACM_STREAMCONVERTF_BLOCKALIGN
910 * currently all conversions are block aligned, so do nothing for this flag
911 * ACM_STREAMCONVERTF_END
912 * no pending data, so do nothing for this flag
914 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
916 ADPCM_Reset(adsi, aad);
919 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
920 adsh->cbSrcLengthUsed = nsrc;
921 adsh->cbDstLengthUsed = ndst;
923 return MMSYSERR_NOERROR;
926 /**************************************************************************
927 * ADPCM_DriverProc [exported]
929 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
930 LPARAM dwParam1, LPARAM dwParam2)
932 TRACE("(%08lx %p %04x %08lx %08lx);\n",
933 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
935 switch (wMsg)
937 case DRV_LOAD: return 1;
938 case DRV_FREE: return 1;
939 case DRV_OPEN: return 1;
940 case DRV_CLOSE: return ADPCM_drvClose(dwDevID);
941 case DRV_ENABLE: return 1;
942 case DRV_DISABLE: return 1;
943 case DRV_QUERYCONFIGURE: return 1;
944 case DRV_CONFIGURE: MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK); return 1;
945 case DRV_INSTALL: return DRVCNF_RESTART;
946 case DRV_REMOVE: return DRVCNF_RESTART;
948 case ACMDM_DRIVER_NOTIFY:
949 /* no caching from other ACM drivers is done so far */
950 return MMSYSERR_NOERROR;
952 case ACMDM_DRIVER_DETAILS:
953 return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
955 case ACMDM_FORMATTAG_DETAILS:
956 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
958 case ACMDM_FORMAT_DETAILS:
959 return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
961 case ACMDM_FORMAT_SUGGEST:
962 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
964 case ACMDM_STREAM_OPEN:
965 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
967 case ACMDM_STREAM_CLOSE:
968 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
970 case ACMDM_STREAM_SIZE:
971 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
973 case ACMDM_STREAM_CONVERT:
974 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
976 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
977 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
978 /* this converter is not a hardware driver */
979 case ACMDM_FILTERTAG_DETAILS:
980 case ACMDM_FILTER_DETAILS:
981 /* this converter is not a filter */
982 case ACMDM_STREAM_RESET:
983 /* only needed for asynchronous driver... we aren't, so just say it */
984 return MMSYSERR_NOTSUPPORTED;
985 case ACMDM_STREAM_PREPARE:
986 case ACMDM_STREAM_UNPREPARE:
987 /* nothing special to do here... so don't do anything */
988 return MMSYSERR_NOERROR;
990 default:
991 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);