user32/tests: Use wine_dbgstr_rect() to print RECTs.
[wine.git] / dlls / imaadp32.acm / imaadp32.c
blob4684f3034939faddb4911183b0f2dd3de9fc9cd4
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 *dst = (unsigned char)(unsigned)stepIndexL;
435 dst += 2;
437 sampleR = R16(src); src += 2;
438 W16(dst, sampleR); dst += 2;
439 *dst = (unsigned char)(unsigned)stepIndexR;
440 dst += 2;
442 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
444 for (i = 0; i < 4; i++)
446 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 0),
447 &stepIndexL, &sampleL);
448 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 0),
449 &stepIndexL, &sampleL);
450 *dst++ = (code1 << 4) | code2;
452 for (i = 0; i < 4; i++)
454 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 1),
455 &stepIndexR, &sampleR);
456 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 1),
457 &stepIndexR, &sampleR);
458 *dst++ = (code1 << 4) | code2;
460 src += 32;
462 dst = in_dst + adsi->pwfxDst->nBlockAlign;
464 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndexL;
465 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR = stepIndexR;
468 static void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi,
469 const unsigned char* src, LPDWORD nsrc,
470 unsigned char* dst, LPDWORD ndst)
472 int stepIndex;
473 int sample;
474 BYTE code1, code2;
475 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
476 int nsamp;
477 /* compute the number of entire blocks we can decode...
478 * it's the min of the number of entire blocks in source buffer and the number
479 * of entire blocks in destination buffer
481 DWORD nblock = min(*nsrc / (nsamp_blk * 2),
482 *ndst / adsi->pwfxDst->nBlockAlign);
484 *nsrc = nblock * (nsamp_blk * 2);
485 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
487 stepIndex = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
488 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
490 for (; nblock > 0; nblock--)
492 unsigned char* in_dst = dst;
494 /* generate header */
495 /* FIXME: what about the last effective sample from previous block ??? */
496 /* perhaps something like:
497 * sample += R16(src);
498 * clamp_sample(sample);
499 * and with :
500 * + saving the sample in adsi->dwDriver when all blocks are done
501 + + reset should set the field in adsi->dwDriver to 0 too
503 sample = R16(src); src += 2;
504 W16(dst, sample); dst += 2;
505 *dst = (unsigned char)(unsigned)stepIndex;
506 dst += 2;
508 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
510 code1 = generate_nibble(R16(src), &stepIndex, &sample);
511 src += 2;
512 code2 = generate_nibble(R16(src), &stepIndex, &sample);
513 src += 2;
514 *dst++ = (code1 << 4) | code2;
516 dst = in_dst + adsi->pwfxDst->nBlockAlign;
518 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndex;
521 /***********************************************************************
522 * ADPCM_DriverDetails
525 static LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
527 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
528 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
529 add->wMid = MM_MICROSOFT;
530 add->wPid = MM_MSFT_ACM_IMAADPCM;
531 add->vdwACM = 0x3320000;
532 add->vdwDriver = 0x04000000;
533 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
534 add->cFormatTags = 2; /* PCM, IMA ADPCM */
535 add->cFilterTags = 0;
536 add->hicon = NULL;
537 MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM", -1,
538 add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
539 MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM CODEC", -1,
540 add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
541 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
542 add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
543 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
544 add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
545 add->szFeatures[0] = 0;
547 return MMSYSERR_NOERROR;
550 /***********************************************************************
551 * ADPCM_FormatTagDetails
554 static LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
556 static const WCHAR szPcm[]={'P','C','M',0};
557 static const WCHAR szImaAdPcm[]={'I','M','A',' ','A','D','P','C','M',0};
559 switch (dwQuery)
561 case ACM_FORMATTAGDETAILSF_INDEX:
562 if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
563 break;
564 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
565 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
567 aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
568 break;
570 /* fall through */
571 case ACM_FORMATTAGDETAILSF_FORMATTAG:
572 switch (aftd->dwFormatTag)
574 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break;
575 case WAVE_FORMAT_IMA_ADPCM: aftd->dwFormatTagIndex = 1; break;
576 default: return ACMERR_NOTPOSSIBLE;
578 break;
579 default:
580 WARN("Unsupported query %08x\n", dwQuery);
581 return MMSYSERR_NOTSUPPORTED;
584 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
585 switch (aftd->dwFormatTagIndex)
587 case 0:
588 aftd->dwFormatTag = WAVE_FORMAT_PCM;
589 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
590 aftd->cStandardFormats = NUM_PCM_FORMATS;
591 lstrcpyW(aftd->szFormatTag, szPcm);
592 break;
593 case 1:
594 aftd->dwFormatTag = WAVE_FORMAT_IMA_ADPCM;
595 aftd->cbFormatSize = sizeof(IMAADPCMWAVEFORMAT);
596 aftd->cStandardFormats = NUM_ADPCM_FORMATS;
597 lstrcpyW(aftd->szFormatTag, szImaAdPcm);
598 break;
600 return MMSYSERR_NOERROR;
603 /***********************************************************************
604 * ADPCM_FormatDetails
607 static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
609 switch (dwQuery)
611 case ACM_FORMATDETAILSF_FORMAT:
612 if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
613 break;
614 case ACM_FORMATDETAILSF_INDEX:
615 afd->pwfx->wFormatTag = afd->dwFormatTag;
616 switch (afd->dwFormatTag)
618 case WAVE_FORMAT_PCM:
619 if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
620 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
621 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
622 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
623 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
624 * afd->pwfx->cbSize = 0;
626 afd->pwfx->nBlockAlign =
627 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
628 afd->pwfx->nAvgBytesPerSec =
629 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
630 break;
631 case WAVE_FORMAT_IMA_ADPCM:
632 if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE;
633 afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
634 afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
635 afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
636 afd->pwfx->nBlockAlign = 1024;
637 /* we got 4 bits per sample */
638 afd->pwfx->nAvgBytesPerSec =
639 (afd->pwfx->nSamplesPerSec * 4) / 8;
640 if (afd->cbwfx >= sizeof(WAVEFORMATEX))
641 afd->pwfx->cbSize = sizeof(WORD);
642 if (afd->cbwfx >= sizeof(IMAADPCMWAVEFORMAT))
643 ((IMAADPCMWAVEFORMAT*)afd->pwfx)->wSamplesPerBlock = (1024 - 4 * afd->pwfx->nChannels) * (2 / afd->pwfx->nChannels) + 1;
644 break;
645 default:
646 WARN("Unsupported tag %08x\n", afd->dwFormatTag);
647 return MMSYSERR_INVALPARAM;
649 break;
650 default:
651 WARN("Unsupported query %08x\n", dwQuery);
652 return MMSYSERR_NOTSUPPORTED;
654 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
655 afd->szFormat[0] = 0; /* let MSACM format this for us... */
657 return MMSYSERR_NOERROR;
660 /***********************************************************************
661 * ADPCM_FormatSuggest
664 static LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
666 /* some tests ... */
667 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
668 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
669 adfs->pwfxSrc->wFormatTag == adfs->pwfxDst->wFormatTag ||
670 ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
672 /* If no suggestion for destination, then copy source value */
673 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
674 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
675 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
676 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
678 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
680 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
681 adfs->pwfxDst->wBitsPerSample = 4;
682 else
683 adfs->pwfxDst->wBitsPerSample = 16;
685 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
687 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
688 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
689 else
690 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
693 /* recompute other values */
694 switch (adfs->pwfxDst->wFormatTag)
696 case WAVE_FORMAT_PCM:
697 if (adfs->cbwfxSrc < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
698 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
699 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
700 /* check if result is ok */
701 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
702 break;
703 case WAVE_FORMAT_IMA_ADPCM:
704 if (adfs->cbwfxDst < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
705 init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT*)adfs->pwfxDst);
706 /* FIXME: not handling header overhead */
707 TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock);
708 /* check if result is ok */
709 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
710 break;
711 default:
712 return ACMERR_NOTPOSSIBLE;
715 return MMSYSERR_NOERROR;
718 /***********************************************************************
719 * ADPCM_Reset
722 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
724 aad->stepIndexL = aad->stepIndexR = 0;
727 /***********************************************************************
728 * ADPCM_StreamOpen
731 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
733 AcmAdpcmData* aad;
734 unsigned nspb;
736 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
738 if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
739 ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
740 return ACMERR_NOTPOSSIBLE;
742 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
743 if (aad == 0) return MMSYSERR_NOMEM;
745 adsi->dwDriver = (DWORD_PTR)aad;
747 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
748 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
750 goto theEnd;
752 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
753 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
755 /* resampling or mono <=> stereo not available
756 * ADPCM algo only define 16 bit per sample output
757 * (The API seems to still allow 8 bit per sample output)
759 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
760 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
761 (adsi->pwfxDst->wBitsPerSample != 16 && adsi->pwfxDst->wBitsPerSample != 8))
762 goto theEnd;
764 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
765 TRACE("spb=%u\n", nspb);
767 /* we check that in a block, after the header, samples are present on
768 * 4-sample packet pattern
769 * we also check that the block alignment is bigger than the expected size
771 if (((nspb - 1) & 3) != 0) goto theEnd;
772 if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
773 goto theEnd;
775 /* adpcm decoding... */
776 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
777 aad->convert = cvtSSima16K;
778 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
779 aad->convert = cvtMMimaK;
780 if (adsi->pwfxDst->wBitsPerSample == 8 && adsi->pwfxDst->nChannels == 1)
781 aad->convert = cvtMMimaK;
782 /* FIXME: Stereo support for 8bit samples*/
783 if (adsi->pwfxDst->wBitsPerSample == 8 && adsi->pwfxDst->nChannels == 2)
784 goto theEnd;
786 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
787 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
789 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
790 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
791 adsi->pwfxSrc->wBitsPerSample != 16)
792 goto theEnd;
794 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
795 TRACE("spb=%u\n", nspb);
797 /* we check that in a block, after the header, samples are present on
798 * 4-sample packet pattern
799 * we also check that the block alignment is bigger than the expected size
801 if (((nspb - 1) & 3) != 0) goto theEnd;
802 if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
803 goto theEnd;
805 /* adpcm coding... */
806 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
807 aad->convert = cvtSS16imaK;
808 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
809 aad->convert = cvtMM16imaK;
811 else goto theEnd;
812 ADPCM_Reset(adsi, aad);
814 return MMSYSERR_NOERROR;
816 theEnd:
817 HeapFree(GetProcessHeap(), 0, aad);
818 adsi->dwDriver = 0L;
819 return MMSYSERR_NOTSUPPORTED;
822 /***********************************************************************
823 * ADPCM_StreamClose
826 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
828 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
829 return MMSYSERR_NOERROR;
832 /***********************************************************************
833 * ADPCM_StreamSize
836 static LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
838 DWORD nblocks;
840 switch (adss->fdwSize)
842 case ACM_STREAMSIZEF_DESTINATION:
843 /* cbDstLength => cbSrcLength */
844 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
845 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
847 nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign;
848 if (nblocks == 0)
849 return ACMERR_NOTPOSSIBLE;
850 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
852 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
853 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
855 nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock);
856 if (nblocks == 0)
857 return ACMERR_NOTPOSSIBLE;
858 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
860 else
862 return MMSYSERR_NOTSUPPORTED;
864 break;
865 case ACM_STREAMSIZEF_SOURCE:
866 /* cbSrcLength => cbDstLength */
867 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
868 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
870 nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock);
871 if (nblocks == 0)
872 return ACMERR_NOTPOSSIBLE;
873 if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock))
874 /* Round block count up. */
875 nblocks++;
876 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign;
878 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
879 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
881 nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign;
882 if (nblocks == 0)
883 return ACMERR_NOTPOSSIBLE;
884 if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
885 /* Round block count up. */
886 nblocks++;
887 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
889 else
891 return MMSYSERR_NOTSUPPORTED;
893 break;
894 default:
895 WARN("Unsupported query %08x\n", adss->fdwSize);
896 return MMSYSERR_NOTSUPPORTED;
898 return MMSYSERR_NOERROR;
901 /***********************************************************************
902 * ADPCM_StreamConvert
905 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
907 AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver;
908 DWORD nsrc = adsh->cbSrcLength;
909 DWORD ndst = adsh->cbDstLength;
911 if (adsh->fdwConvert &
912 ~(ACM_STREAMCONVERTF_BLOCKALIGN|
913 ACM_STREAMCONVERTF_END|
914 ACM_STREAMCONVERTF_START))
916 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
918 /* ACM_STREAMCONVERTF_BLOCKALIGN
919 * currently all conversions are block aligned, so do nothing for this flag
920 * ACM_STREAMCONVERTF_END
921 * no pending data, so do nothing for this flag
923 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
925 ADPCM_Reset(adsi, aad);
928 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
929 adsh->cbSrcLengthUsed = nsrc;
930 adsh->cbDstLengthUsed = ndst;
932 return MMSYSERR_NOERROR;
935 /**************************************************************************
936 * ADPCM_DriverProc [exported]
938 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
939 LPARAM dwParam1, LPARAM dwParam2)
941 TRACE("(%08lx %p %04x %08lx %08lx);\n",
942 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
944 switch (wMsg)
946 case DRV_LOAD: return 1;
947 case DRV_FREE: return 1;
948 case DRV_OPEN: return 1;
949 case DRV_CLOSE: return ADPCM_drvClose(dwDevID);
950 case DRV_ENABLE: return 1;
951 case DRV_DISABLE: return 1;
952 case DRV_QUERYCONFIGURE: return 1;
953 case DRV_CONFIGURE: MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK); return 1;
954 case DRV_INSTALL: return DRVCNF_RESTART;
955 case DRV_REMOVE: return DRVCNF_RESTART;
957 case ACMDM_DRIVER_NOTIFY:
958 /* no caching from other ACM drivers is done so far */
959 return MMSYSERR_NOERROR;
961 case ACMDM_DRIVER_DETAILS:
962 return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
964 case ACMDM_FORMATTAG_DETAILS:
965 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
967 case ACMDM_FORMAT_DETAILS:
968 return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
970 case ACMDM_FORMAT_SUGGEST:
971 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
973 case ACMDM_STREAM_OPEN:
974 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
976 case ACMDM_STREAM_CLOSE:
977 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
979 case ACMDM_STREAM_SIZE:
980 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
982 case ACMDM_STREAM_CONVERT:
983 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
985 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
986 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
987 /* this converter is not a hardware driver */
988 case ACMDM_FILTERTAG_DETAILS:
989 case ACMDM_FILTER_DETAILS:
990 /* this converter is not a filter */
991 case ACMDM_STREAM_RESET:
992 /* only needed for asynchronous driver... we aren't, so just say it */
993 return MMSYSERR_NOTSUPPORTED;
994 case ACMDM_STREAM_PREPARE:
995 case ACMDM_STREAM_UNPREPARE:
996 /* nothing special to do here... so don't do anything */
997 return MMSYSERR_NOERROR;
999 default:
1000 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);