wow64: In wow64_NtSetInformationToken forward TokenIntegrityLevel.
[wine.git] / dlls / imaadp32.acm / imaadp32.c
blob0b5e6a83ae601d1b16d7abd8f30bc0b59f9b012a
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 /***********************************************************************
83 * ADPCM_GetFormatIndex
85 static DWORD ADPCM_GetFormatIndex(const WAVEFORMATEX *wfx)
87 int i, hi;
88 const Format* fmts;
90 switch (wfx->wFormatTag)
92 case WAVE_FORMAT_PCM:
93 hi = ARRAY_SIZE(PCM_Formats);
94 fmts = PCM_Formats;
95 break;
96 case WAVE_FORMAT_IMA_ADPCM:
97 hi = ARRAY_SIZE(ADPCM_Formats);
98 fmts = ADPCM_Formats;
99 break;
100 default:
101 return 0xFFFFFFFF;
104 for (i = 0; i < hi; i++)
106 if (wfx->nChannels == fmts[i].nChannels &&
107 wfx->nSamplesPerSec == fmts[i].rate &&
108 wfx->wBitsPerSample == fmts[i].nBits)
109 return i;
112 switch (wfx->wFormatTag)
114 case WAVE_FORMAT_PCM:
115 if(3 > wfx->nChannels &&
116 wfx->nChannels > 0 &&
117 wfx->nAvgBytesPerSec == 2 * wfx->nSamplesPerSec * wfx->nChannels &&
118 wfx->nBlockAlign == 2 * wfx->nChannels &&
119 wfx->wBitsPerSample == 16)
120 return hi;
121 break;
122 case WAVE_FORMAT_IMA_ADPCM:
123 if(3 > wfx->nChannels &&
124 wfx->nChannels > 0 &&
125 wfx->wBitsPerSample == 4 &&
126 wfx->cbSize == 2)
127 return hi;
128 break;
131 return 0xFFFFFFFF;
134 static void init_wfx_ima_adpcm(IMAADPCMWAVEFORMAT* awfx/*, DWORD nba*/)
136 WAVEFORMATEX* pwfx = &awfx->wfx;
138 /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample
139 * have been initialized... */
141 if (pwfx->wFormatTag != WAVE_FORMAT_IMA_ADPCM) {FIXME("wrong FT\n"); return;}
142 if (ADPCM_GetFormatIndex(pwfx) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;}
144 switch (pwfx->nSamplesPerSec)
146 case 8000: pwfx->nBlockAlign = 256 * pwfx->nChannels; break;
147 case 11025: pwfx->nBlockAlign = 256 * pwfx->nChannels; break;
148 case 22050: pwfx->nBlockAlign = 512 * pwfx->nChannels; break;
149 case 44100: pwfx->nBlockAlign = 1024 * pwfx->nChannels; break;
150 default: /*pwfx->nBlockAlign = nba;*/ break;
152 pwfx->cbSize = sizeof(WORD);
154 awfx->wSamplesPerBlock = (pwfx->nBlockAlign - (4 * pwfx->nChannels)) * (2 / pwfx->nChannels) + 1;
155 pwfx->nAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) / awfx->wSamplesPerBlock;
158 /***********************************************************************
159 * R16
161 * Read a 16 bit sample (correctly handles endianness)
163 static inline short R16(const unsigned char* src)
165 return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
168 /***********************************************************************
169 * W16
171 * Write a 16 bit sample (correctly handles endianness)
173 static inline void W16(unsigned char* dst, short s)
175 dst[0] = LOBYTE(s);
176 dst[1] = HIBYTE(s);
179 /***********************************************************************
180 * W8
182 * Write a 8 bit sample
184 static inline void W8(unsigned char* dst, short s)
186 dst[0] = (unsigned char)((s + 32768) >> 8);
190 static inline void W8_16(unsigned char* dst, short s, int bytes)
192 if(bytes == 1)
193 W8(dst, s);
194 else
195 W16(dst, s);
198 /* IMA (or DVI) APDCM codec routines */
200 static const unsigned IMA_StepTable[89] =
202 7, 8, 9, 10, 11, 12, 13, 14,
203 16, 17, 19, 21, 23, 25, 28, 31,
204 34, 37, 41, 45, 50, 55, 60, 66,
205 73, 80, 88, 97, 107, 118, 130, 143,
206 157, 173, 190, 209, 230, 253, 279, 307,
207 337, 371, 408, 449, 494, 544, 598, 658,
208 724, 796, 876, 963, 1060, 1166, 1282, 1411,
209 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
210 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
211 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
212 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
213 32767
216 static const int IMA_IndexTable[16] =
218 -1, -1, -1, -1, 2, 4, 6, 8,
219 -1, -1, -1, -1, 2, 4, 6, 8
222 static inline void clamp_step_index(int* stepIndex)
224 if (*stepIndex < 0 ) *stepIndex = 0;
225 if (*stepIndex > 88) *stepIndex = 88;
228 static inline void clamp_sample(int* sample)
230 if (*sample < -32768) *sample = -32768;
231 if (*sample > 32767) *sample = 32767;
234 static inline void process_nibble(unsigned char code, int* stepIndex, int* sample)
236 unsigned step;
237 int diff;
239 code &= 0x0F;
241 step = IMA_StepTable[*stepIndex];
242 diff = step >> 3;
243 if (code & 1) diff += step >> 2;
244 if (code & 2) diff += step >> 1;
245 if (code & 4) diff += step;
246 if (code & 8) *sample -= diff;
247 else *sample += diff;
248 clamp_sample(sample);
249 *stepIndex += IMA_IndexTable[code];
250 clamp_step_index(stepIndex);
253 static inline unsigned char generate_nibble(int in, int* stepIndex, int* sample)
255 int effdiff, diff = in - *sample;
256 unsigned step;
257 unsigned char code;
259 if (diff < 0)
261 diff = -diff;
262 code = 8;
264 else
266 code = 0;
269 step = IMA_StepTable[*stepIndex];
270 effdiff = (step >> 3);
271 if (diff >= step)
273 code |= 4;
274 diff -= step;
275 effdiff += step;
277 step >>= 1;
278 if (diff >= step)
280 code |= 2;
281 diff -= step;
282 effdiff += step;
284 step >>= 1;
285 if (diff >= step)
287 code |= 1;
288 effdiff += step;
290 if (code & 8) *sample -= effdiff;
291 else *sample += effdiff;
292 clamp_sample(sample);
293 *stepIndex += IMA_IndexTable[code];
294 clamp_step_index(stepIndex);
295 return code;
298 static void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi,
299 const unsigned char* src, LPDWORD nsrc,
300 unsigned char* dst, LPDWORD ndst)
302 int i;
303 int sampleL, sampleR;
304 int stepIndexL, stepIndexR;
305 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
306 int nsamp;
307 /* compute the number of entire blocks we can decode...
308 * it's the min of the number of entire blocks in source buffer and the number
309 * of entire blocks in destination buffer
311 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
312 *ndst / (nsamp_blk * 2 * 2));
314 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
315 *ndst = nblock * (nsamp_blk * 2 * 2);
317 nsamp_blk--; /* remove the sample in block header */
318 for (; nblock > 0; nblock--)
320 const unsigned char* in_src = src;
322 /* handle headers first */
323 sampleL = R16(src);
324 stepIndexL = (unsigned)*(src + 2);
325 clamp_step_index(&stepIndexL);
326 src += 4;
327 W16(dst, sampleL); dst += 2;
329 sampleR = R16(src);
330 stepIndexR = (unsigned)*(src + 2);
331 clamp_step_index(&stepIndexR);
332 src += 4;
333 W16(dst, sampleR); dst += 2;
335 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
337 for (i = 0; i < 4; i++)
339 process_nibble(*src, &stepIndexL, &sampleL);
340 W16(dst + (2 * i + 0) * 4 + 0, sampleL);
341 process_nibble(*src++ >> 4, &stepIndexL, &sampleL);
342 W16(dst + (2 * i + 1) * 4 + 0, sampleL);
344 for (i = 0; i < 4; i++)
346 process_nibble(*src , &stepIndexR, &sampleR);
347 W16(dst + (2 * i + 0) * 4 + 2, sampleR);
348 process_nibble(*src++ >>4, &stepIndexR, &sampleR);
349 W16(dst + (2 * i + 1) * 4 + 2, sampleR);
351 dst += 32;
353 /* we have now to realign the source pointer on block */
354 src = in_src + adsi->pwfxSrc->nBlockAlign;
358 static void cvtMMimaK(PACMDRVSTREAMINSTANCE adsi,
359 const unsigned char* src, LPDWORD nsrc,
360 unsigned char* dst, LPDWORD ndst)
362 int sample;
363 int stepIndex;
364 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
365 int nsamp;
366 int bytesPerSample = adsi->pwfxDst->wBitsPerSample / 8;
367 /* compute the number of entire blocks we can decode...
368 * it's the min of the number of entire blocks in source buffer and the number
369 * of entire blocks in destination buffer
371 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign, *ndst / (nsamp_blk * bytesPerSample));
373 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
374 *ndst = nblock * nsamp_blk * bytesPerSample;
376 nsamp_blk--; /* remove the sample in block header */
377 for (; nblock > 0; nblock--)
379 const unsigned char* in_src = src;
381 /* handle header first */
382 sample = R16(src);
383 stepIndex = (unsigned)*(src + 2);
384 clamp_step_index(&stepIndex);
385 src += 4;
386 W8_16(dst, sample, bytesPerSample); dst += bytesPerSample;
388 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
390 process_nibble(*src, &stepIndex, &sample);
391 W8_16(dst, sample, bytesPerSample); dst += bytesPerSample;
392 process_nibble(*src++ >> 4, &stepIndex, &sample);
393 W8_16(dst, sample, bytesPerSample); dst += bytesPerSample;
395 /* we have now to realign the source pointer on block */
396 src = in_src + adsi->pwfxSrc->nBlockAlign;
400 static void cvtSS16imaK(PACMDRVSTREAMINSTANCE adsi,
401 const unsigned char* src, LPDWORD nsrc,
402 unsigned char* dst, LPDWORD ndst)
404 int stepIndexL, stepIndexR;
405 int sampleL, sampleR;
406 BYTE code1, code2;
407 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
408 int i, nsamp;
409 /* compute the number of entire blocks we can decode...
410 * it's the min of the number of entire blocks in source buffer and the number
411 * of entire blocks in destination buffer
413 DWORD nblock = min(*nsrc / (nsamp_blk * 2 * 2),
414 *ndst / adsi->pwfxDst->nBlockAlign);
416 *nsrc = nblock * (nsamp_blk * 2 * 2);
417 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
419 stepIndexL = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
420 stepIndexR = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR;
422 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
424 for (; nblock > 0; nblock--)
426 unsigned char* in_dst = dst;
428 /* generate header */
429 sampleL = R16(src); src += 2;
430 W16(dst, sampleL); dst += 2;
431 W16(dst, stepIndexL); dst += 2;
433 sampleR = R16(src); src += 2;
434 W16(dst, sampleR); dst += 2;
435 W16(dst, stepIndexR); dst += 2;
437 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
439 for (i = 0; i < 4; i++)
441 code1 = generate_nibble(R16(src + (4 * i + 0) * 2),
442 &stepIndexL, &sampleL);
443 code2 = generate_nibble(R16(src + (4 * i + 2) * 2),
444 &stepIndexL, &sampleL);
445 *dst++ = (code2 << 4) | code1;
447 for (i = 0; i < 4; i++)
449 code1 = generate_nibble(R16(src + (4 * i + 1) * 2),
450 &stepIndexR, &sampleR);
451 code2 = generate_nibble(R16(src + (4 * i + 3) * 2),
452 &stepIndexR, &sampleR);
453 *dst++ = (code2 << 4) | code1;
455 src += 32;
457 dst = in_dst + adsi->pwfxDst->nBlockAlign;
459 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndexL;
460 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR = stepIndexR;
463 static void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi,
464 const unsigned char* src, LPDWORD nsrc,
465 unsigned char* dst, LPDWORD ndst)
467 int stepIndex;
468 int sample;
469 BYTE code1, code2;
470 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
471 int nsamp;
472 /* compute the number of entire blocks we can decode...
473 * it's the min of the number of entire blocks in source buffer and the number
474 * of entire blocks in destination buffer
476 DWORD nblock = min(*nsrc / (nsamp_blk * 2),
477 *ndst / adsi->pwfxDst->nBlockAlign);
479 *nsrc = nblock * (nsamp_blk * 2);
480 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
482 stepIndex = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
483 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
485 for (; nblock > 0; nblock--)
487 unsigned char* in_dst = dst;
489 /* generate header */
490 /* FIXME: what about the last effective sample from previous block ??? */
491 /* perhaps something like:
492 * sample += R16(src);
493 * clamp_sample(sample);
494 * and with :
495 * + saving the sample in adsi->dwDriver when all blocks are done
496 + + reset should set the field in adsi->dwDriver to 0 too
498 sample = R16(src); src += 2;
499 W16(dst, sample); dst += 2;
500 *dst = (unsigned char)(unsigned)stepIndex;
501 dst += 2;
503 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
505 code1 = generate_nibble(R16(src), &stepIndex, &sample);
506 src += 2;
507 code2 = generate_nibble(R16(src), &stepIndex, &sample);
508 src += 2;
509 *dst++ = (code2 << 4) | code1;
511 dst = in_dst + adsi->pwfxDst->nBlockAlign;
513 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndex;
516 /***********************************************************************
517 * ADPCM_DriverDetails
520 static LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
522 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
523 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
524 add->wMid = MM_MICROSOFT;
525 add->wPid = MM_MSFT_ACM_IMAADPCM;
526 add->vdwACM = 0x3320000;
527 add->vdwDriver = 0x04000000;
528 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
529 add->cFormatTags = 2; /* PCM, IMA ADPCM */
530 add->cFilterTags = 0;
531 add->hicon = NULL;
532 MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM", -1,
533 add->szShortName, ARRAY_SIZE(add->szShortName) );
534 MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM CODEC", -1,
535 add->szLongName, ARRAY_SIZE(add->szLongName) );
536 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
537 add->szCopyright, ARRAY_SIZE(add->szCopyright) );
538 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
539 add->szLicensing, ARRAY_SIZE(add->szLicensing) );
540 add->szFeatures[0] = 0;
542 return MMSYSERR_NOERROR;
545 /***********************************************************************
546 * ADPCM_FormatTagDetails
549 static LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
551 switch (dwQuery)
553 case ACM_FORMATTAGDETAILSF_INDEX:
554 if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
555 break;
556 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
557 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
559 aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
560 break;
562 /* fall through */
563 case ACM_FORMATTAGDETAILSF_FORMATTAG:
564 switch (aftd->dwFormatTag)
566 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break;
567 case WAVE_FORMAT_IMA_ADPCM: aftd->dwFormatTagIndex = 1; break;
568 default: return ACMERR_NOTPOSSIBLE;
570 break;
571 default:
572 WARN("Unsupported query %08lx\n", dwQuery);
573 return MMSYSERR_NOTSUPPORTED;
576 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
577 switch (aftd->dwFormatTagIndex)
579 case 0:
580 aftd->dwFormatTag = WAVE_FORMAT_PCM;
581 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
582 aftd->cStandardFormats = ARRAY_SIZE(PCM_Formats);
583 lstrcpyW(aftd->szFormatTag, L"PCM");
584 break;
585 case 1:
586 aftd->dwFormatTag = WAVE_FORMAT_IMA_ADPCM;
587 aftd->cbFormatSize = sizeof(IMAADPCMWAVEFORMAT);
588 aftd->cStandardFormats = ARRAY_SIZE(ADPCM_Formats);
589 lstrcpyW(aftd->szFormatTag, L"IMA ADPCM");
590 break;
592 return MMSYSERR_NOERROR;
595 /***********************************************************************
596 * ADPCM_FormatDetails
599 static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
601 switch (dwQuery)
603 case ACM_FORMATDETAILSF_FORMAT:
604 if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
605 break;
606 case ACM_FORMATDETAILSF_INDEX:
607 afd->pwfx->wFormatTag = afd->dwFormatTag;
608 switch (afd->dwFormatTag)
610 case WAVE_FORMAT_PCM:
611 if (afd->dwFormatIndex >= ARRAY_SIZE(PCM_Formats)) return ACMERR_NOTPOSSIBLE;
612 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
613 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
614 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
615 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
616 * afd->pwfx->cbSize = 0;
618 afd->pwfx->nBlockAlign =
619 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
620 afd->pwfx->nAvgBytesPerSec =
621 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
622 break;
623 case WAVE_FORMAT_IMA_ADPCM:
624 if (afd->dwFormatIndex >= ARRAY_SIZE(ADPCM_Formats)) return ACMERR_NOTPOSSIBLE;
625 afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
626 afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
627 afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
628 init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT *)afd->pwfx);
629 break;
630 default:
631 WARN("Unsupported tag %08lx\n", afd->dwFormatTag);
632 return MMSYSERR_INVALPARAM;
634 break;
635 default:
636 WARN("Unsupported query %08lx\n", dwQuery);
637 return MMSYSERR_NOTSUPPORTED;
639 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
640 afd->szFormat[0] = 0; /* let MSACM format this for us... */
642 return MMSYSERR_NOERROR;
645 /***********************************************************************
646 * ADPCM_FormatSuggest
649 static LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
651 /* some tests ... */
652 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
653 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
654 adfs->pwfxSrc->wFormatTag == adfs->pwfxDst->wFormatTag ||
655 ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
657 /* If no suggestion for destination, then copy source value */
658 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
659 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
660 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
661 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
663 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
665 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
666 adfs->pwfxDst->wBitsPerSample = 4;
667 else
668 adfs->pwfxDst->wBitsPerSample = 16;
670 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
672 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
673 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
674 else
675 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
678 /* recompute other values */
679 switch (adfs->pwfxDst->wFormatTag)
681 case WAVE_FORMAT_PCM:
682 if (adfs->cbwfxSrc < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
683 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
684 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
685 /* check if result is ok */
686 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
687 break;
688 case WAVE_FORMAT_IMA_ADPCM:
689 if (adfs->cbwfxDst < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
690 init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT*)adfs->pwfxDst);
691 /* FIXME: not handling header overhead */
692 TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock);
693 /* check if result is ok */
694 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
695 break;
696 default:
697 return ACMERR_NOTPOSSIBLE;
700 return MMSYSERR_NOERROR;
703 /***********************************************************************
704 * ADPCM_Reset
707 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
709 aad->stepIndexL = aad->stepIndexR = 0;
712 /***********************************************************************
713 * ADPCM_StreamOpen
716 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
718 AcmAdpcmData* aad;
719 unsigned nspb;
721 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
723 if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
724 ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
725 return ACMERR_NOTPOSSIBLE;
727 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
728 if (aad == 0) return MMSYSERR_NOMEM;
730 adsi->dwDriver = (DWORD_PTR)aad;
732 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
733 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
735 goto theEnd;
737 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
738 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
740 /* resampling or mono <=> stereo not available
741 * ADPCM algo only define 16 bit per sample output
742 * (The API seems to still allow 8 bit per sample output)
744 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
745 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
746 (adsi->pwfxDst->wBitsPerSample != 16 && adsi->pwfxDst->wBitsPerSample != 8))
747 goto theEnd;
749 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
750 TRACE("spb=%u\n", nspb);
752 /* we check that in a block, after the header, samples are present on
753 * 4-sample packet pattern
754 * we also check that the block alignment is bigger than the expected size
756 if (((nspb - 1) & 3) != 0) goto theEnd;
757 if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
758 goto theEnd;
760 /* adpcm decoding... */
761 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
762 aad->convert = cvtSSima16K;
763 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
764 aad->convert = cvtMMimaK;
765 if (adsi->pwfxDst->wBitsPerSample == 8 && adsi->pwfxDst->nChannels == 1)
766 aad->convert = cvtMMimaK;
767 /* FIXME: Stereo support for 8bit samples*/
768 if (adsi->pwfxDst->wBitsPerSample == 8 && adsi->pwfxDst->nChannels == 2)
769 goto theEnd;
771 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
772 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
774 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
775 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
776 adsi->pwfxSrc->wBitsPerSample != 16)
777 goto theEnd;
779 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
780 TRACE("spb=%u\n", nspb);
782 /* we check that in a block, after the header, samples are present on
783 * 4-sample packet pattern
784 * we also check that the block alignment is bigger than the expected size
786 if (((nspb - 1) & 3) != 0) goto theEnd;
787 if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
788 goto theEnd;
790 /* adpcm coding... */
791 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
792 aad->convert = cvtSS16imaK;
793 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
794 aad->convert = cvtMM16imaK;
796 else goto theEnd;
797 ADPCM_Reset(adsi, aad);
799 return MMSYSERR_NOERROR;
801 theEnd:
802 HeapFree(GetProcessHeap(), 0, aad);
803 adsi->dwDriver = 0L;
804 return MMSYSERR_NOTSUPPORTED;
807 /***********************************************************************
808 * ADPCM_StreamClose
811 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
813 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
814 return MMSYSERR_NOERROR;
817 /***********************************************************************
818 * ADPCM_StreamSize
821 static LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
823 DWORD nblocks;
825 switch (adss->fdwSize)
827 case ACM_STREAMSIZEF_DESTINATION:
828 /* cbDstLength => cbSrcLength */
829 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
830 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
832 nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign;
833 if (nblocks == 0)
834 return ACMERR_NOTPOSSIBLE;
835 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
837 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
838 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
840 nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock);
841 if (nblocks == 0)
842 return ACMERR_NOTPOSSIBLE;
843 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
845 else
847 return MMSYSERR_NOTSUPPORTED;
849 break;
850 case ACM_STREAMSIZEF_SOURCE:
851 /* cbSrcLength => cbDstLength */
852 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
853 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
855 nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock);
856 if (nblocks == 0)
857 return ACMERR_NOTPOSSIBLE;
858 if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock))
859 /* Round block count up. */
860 nblocks++;
861 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign;
863 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
864 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
866 nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign;
867 if (nblocks == 0)
868 return ACMERR_NOTPOSSIBLE;
869 if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
870 /* Round block count up. */
871 nblocks++;
872 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
874 else
876 return MMSYSERR_NOTSUPPORTED;
878 break;
879 default:
880 WARN("Unsupported query %08lx\n", adss->fdwSize);
881 return MMSYSERR_NOTSUPPORTED;
883 return MMSYSERR_NOERROR;
886 /***********************************************************************
887 * ADPCM_StreamConvert
890 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
892 AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver;
893 DWORD nsrc = adsh->cbSrcLength;
894 DWORD ndst = adsh->cbDstLength;
896 if (adsh->fdwConvert &
897 ~(ACM_STREAMCONVERTF_BLOCKALIGN|
898 ACM_STREAMCONVERTF_END|
899 ACM_STREAMCONVERTF_START))
901 FIXME("Unsupported fdwConvert (%08lx), ignoring it\n", adsh->fdwConvert);
903 /* ACM_STREAMCONVERTF_BLOCKALIGN
904 * currently all conversions are block aligned, so do nothing for this flag
905 * ACM_STREAMCONVERTF_END
906 * no pending data, so do nothing for this flag
908 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
910 ADPCM_Reset(adsi, aad);
913 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
914 adsh->cbSrcLengthUsed = nsrc;
915 adsh->cbDstLengthUsed = ndst;
917 return MMSYSERR_NOERROR;
920 /**************************************************************************
921 * ADPCM_DriverProc [exported]
923 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
924 LPARAM dwParam1, LPARAM dwParam2)
926 TRACE("(%08Ix %p %04x %08Ix %08Ix);\n",
927 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
929 switch (wMsg)
931 case DRV_LOAD: return 1;
932 case DRV_FREE: return 1;
933 case DRV_OPEN: return 1;
934 case DRV_CLOSE: return ADPCM_drvClose(dwDevID);
935 case DRV_ENABLE: return 1;
936 case DRV_DISABLE: return 1;
937 case DRV_QUERYCONFIGURE: return 1;
938 case DRV_CONFIGURE: MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK); return 1;
939 case DRV_INSTALL: return DRVCNF_RESTART;
940 case DRV_REMOVE: return DRVCNF_RESTART;
942 case ACMDM_DRIVER_NOTIFY:
943 /* no caching from other ACM drivers is done so far */
944 return MMSYSERR_NOERROR;
946 case ACMDM_DRIVER_DETAILS:
947 return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
949 case ACMDM_FORMATTAG_DETAILS:
950 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
952 case ACMDM_FORMAT_DETAILS:
953 return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
955 case ACMDM_FORMAT_SUGGEST:
956 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
958 case ACMDM_STREAM_OPEN:
959 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
961 case ACMDM_STREAM_CLOSE:
962 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
964 case ACMDM_STREAM_SIZE:
965 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
967 case ACMDM_STREAM_CONVERT:
968 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
970 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
971 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
972 /* this converter is not a hardware driver */
973 case ACMDM_FILTERTAG_DETAILS:
974 case ACMDM_FILTER_DETAILS:
975 /* this converter is not a filter */
976 case ACMDM_STREAM_RESET:
977 /* only needed for asynchronous driver... we aren't, so just say it */
978 return MMSYSERR_NOTSUPPORTED;
979 case ACMDM_STREAM_PREPARE:
980 case ACMDM_STREAM_UNPREPARE:
981 /* nothing special to do here... so don't do anything */
982 return MMSYSERR_NOERROR;
984 default:
985 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);