wined3d: Implement independent color write masks.
[wine/multimedia.git] / dlls / imaadp32.acm / imaadp32.c
blob9a2fb537c90244a340d444ba651f43e119b22247
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_drvOpen
43 static LRESULT ADPCM_drvOpen(LPCSTR str)
45 return 1;
48 /***********************************************************************
49 * ADPCM_drvClose
51 static LRESULT ADPCM_drvClose(DWORD_PTR dwDevID)
53 return 1;
56 typedef struct tagAcmAdpcmData
58 void (*convert)(PACMDRVSTREAMINSTANCE adsi,
59 const unsigned char*, LPDWORD, unsigned char*, LPDWORD);
60 /* IMA encoding only */
61 BYTE stepIndexL;
62 BYTE stepIndexR;
63 /* short sample; */
64 } AcmAdpcmData;
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
69 typedef struct
71 int nChannels;
72 int nBits;
73 int rate;
74 } Format;
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)
98 int i, hi;
99 const Format* fmts;
101 switch (wfx->wFormatTag)
103 case WAVE_FORMAT_PCM:
104 hi = NUM_PCM_FORMATS;
105 fmts = PCM_Formats;
106 break;
107 case WAVE_FORMAT_IMA_ADPCM:
108 hi = NUM_ADPCM_FORMATS;
109 fmts = ADPCM_Formats;
110 break;
111 default:
112 return 0xFFFFFFFF;
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)
120 return i;
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)
131 return hi;
132 break;
133 case WAVE_FORMAT_IMA_ADPCM:
134 if(3 > wfx->nChannels &&
135 wfx->nChannels > 0 &&
136 wfx->wBitsPerSample == 4 &&
137 wfx->cbSize == 2)
138 return hi;
139 break;
142 return 0xFFFFFFFF;
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 /***********************************************************************
170 * R16
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 /***********************************************************************
180 * W16
182 * Write a 16 bit sample (correctly handles endianess)
184 static inline void W16(unsigned char* dst, short s)
186 dst[0] = LOBYTE(s);
187 dst[1] = HIBYTE(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,
205 32767
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)
228 unsigned step;
229 int diff;
231 code &= 0x0F;
233 step = IMA_StepTable[*stepIndex];
234 diff = step >> 3;
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;
248 unsigned step;
249 unsigned char code;
251 if (diff < 0)
253 diff = -diff;
254 code = 8;
256 else
258 code = 0;
261 step = IMA_StepTable[*stepIndex];
262 effdiff = (step >> 3);
263 if (diff >= step)
265 code |= 4;
266 diff -= step;
267 effdiff += step;
269 step >>= 1;
270 if (diff >= step)
272 code |= 2;
273 diff -= step;
274 effdiff += step;
276 step >>= 1;
277 if (diff >= step)
279 code |= 1;
280 effdiff += step;
282 if (code & 8) *sample -= effdiff;
283 else *sample += effdiff;
284 clamp_sample(sample);
285 *stepIndex += IMA_IndexTable[code];
286 clamp_step_index(stepIndex);
287 return code;
290 static void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi,
291 const unsigned char* src, LPDWORD nsrc,
292 unsigned char* dst, LPDWORD ndst)
294 int i;
295 int sampleL, sampleR;
296 int stepIndexL, stepIndexR;
297 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
298 int nsamp;
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 */
315 sampleL = R16(src);
316 stepIndexL = (unsigned)*(src + 2);
317 clamp_step_index(&stepIndexL);
318 src += 4;
319 W16(dst, sampleL); dst += 2;
321 sampleR = R16(src);
322 stepIndexR = (unsigned)*(src + 2);
323 clamp_step_index(&stepIndexR);
324 src += 4;
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);
343 dst += 32;
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)
354 int sample;
355 int stepIndex;
356 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
357 int nsamp;
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 */
374 sample = R16(src);
375 stepIndex = (unsigned)*(src + 2);
376 clamp_step_index(&stepIndex);
377 src += 4;
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;
398 BYTE code1, code2;
399 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
400 int i, nsamp;
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;
424 dst += 2;
426 sampleR = R16(src); src += 2;
427 W16(dst, sampleR); dst += 2;
428 *dst = (unsigned char)(unsigned)stepIndexR;
429 dst += 2;
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;
449 src += 32;
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)
461 int stepIndex;
462 int sample;
463 BYTE code1, code2;
464 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
465 int nsamp;
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);
488 * and with :
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;
495 dst += 2;
497 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
499 code1 = generate_nibble(R16(src), &stepIndex, &sample);
500 src += 2;
501 code2 = generate_nibble(R16(src), &stepIndex, &sample);
502 src += 2;
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;
518 add->wMid = 0x1;
519 add->wPid = 0x22;
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;
525 add->hicon = NULL;
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};
548 switch (dwQuery)
550 case ACM_FORMATTAGDETAILSF_INDEX:
551 if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
552 break;
553 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
554 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
556 aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
557 break;
559 /* fall thru */
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;
567 break;
568 default:
569 WARN("Unsupported query %08x\n", dwQuery);
570 return MMSYSERR_NOTSUPPORTED;
573 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
574 switch (aftd->dwFormatTagIndex)
576 case 0:
577 aftd->dwFormatTag = WAVE_FORMAT_PCM;
578 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
579 aftd->cStandardFormats = NUM_PCM_FORMATS;
580 lstrcpyW(aftd->szFormatTag, szPcm);
581 break;
582 case 1:
583 aftd->dwFormatTag = WAVE_FORMAT_IMA_ADPCM;
584 aftd->cbFormatSize = sizeof(IMAADPCMWAVEFORMAT);
585 aftd->cStandardFormats = NUM_ADPCM_FORMATS;
586 lstrcpyW(aftd->szFormatTag, szImaAdPcm);
587 break;
589 return MMSYSERR_NOERROR;
592 /***********************************************************************
593 * ADPCM_FormatDetails
596 static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
598 switch (dwQuery)
600 case ACM_FORMATDETAILSF_FORMAT:
601 if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
602 break;
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;
619 break;
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;
633 break;
634 default:
635 WARN("Unsupported tag %08x\n", afd->dwFormatTag);
636 return MMSYSERR_INVALPARAM;
638 break;
639 default:
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)
655 /* some tests ... */
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;
672 else
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;
679 else
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;
691 break;
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;
698 break;
699 default:
700 return ACMERR_NOTPOSSIBLE;
703 return MMSYSERR_NOERROR;
706 /***********************************************************************
707 * ADPCM_Reset
710 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
712 aad->stepIndexL = aad->stepIndexR = 0;
715 /***********************************************************************
716 * ADPCM_StreamOpen
719 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
721 AcmAdpcmData* aad;
722 unsigned nspb;
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)
738 goto theEnd;
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)
749 goto theEnd;
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)
760 goto theEnd;
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)
774 goto theEnd;
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)
785 goto theEnd;
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;
793 else goto theEnd;
794 ADPCM_Reset(adsi, aad);
796 return MMSYSERR_NOERROR;
798 theEnd:
799 HeapFree(GetProcessHeap(), 0, aad);
800 adsi->dwDriver = 0L;
801 return MMSYSERR_NOTSUPPORTED;
804 /***********************************************************************
805 * ADPCM_StreamClose
808 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
810 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
811 return MMSYSERR_NOERROR;
814 /***********************************************************************
815 * ADPCM_StreamSize
818 static LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
820 DWORD nblocks;
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;
830 if (nblocks == 0)
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);
838 if (nblocks == 0)
839 return ACMERR_NOTPOSSIBLE;
840 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
842 else
844 return MMSYSERR_NOTSUPPORTED;
846 break;
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);
853 if (nblocks == 0)
854 return ACMERR_NOTPOSSIBLE;
855 if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock))
856 /* Round block count up. */
857 nblocks++;
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;
864 if (nblocks == 0)
865 return ACMERR_NOTPOSSIBLE;
866 if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
867 /* Round block count up. */
868 nblocks++;
869 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
871 else
873 return MMSYSERR_NOTSUPPORTED;
875 break;
876 default:
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);
926 switch (wMsg)
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;
981 default:
982 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);