wininet: Add a simple certificate dialog to InternetErrorDlg.
[wine/zf.git] / dlls / imaadp32.acm / imaadp32.c
blob4e59448295f7d16bd65da0312021f164e211c258
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;
661 /* If no suggestion for destination, then copy source value */
662 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
663 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
664 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
665 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
667 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
669 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
670 adfs->pwfxDst->wBitsPerSample = 4;
671 else
672 adfs->pwfxDst->wBitsPerSample = 16;
674 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
676 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
677 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
678 else
679 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
682 /* recompute other values */
683 switch (adfs->pwfxDst->wFormatTag)
685 case WAVE_FORMAT_PCM:
686 if (adfs->cbwfxSrc < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
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 if (adfs->cbwfxDst < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
694 init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT*)adfs->pwfxDst);
695 /* FIXME: not handling header overhead */
696 TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock);
697 /* check if result is ok */
698 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
699 break;
700 default:
701 return ACMERR_NOTPOSSIBLE;
704 return MMSYSERR_NOERROR;
707 /***********************************************************************
708 * ADPCM_Reset
711 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
713 aad->stepIndexL = aad->stepIndexR = 0;
716 /***********************************************************************
717 * ADPCM_StreamOpen
720 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
722 AcmAdpcmData* aad;
723 unsigned nspb;
725 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
727 if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
728 ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
729 return ACMERR_NOTPOSSIBLE;
731 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
732 if (aad == 0) return MMSYSERR_NOMEM;
734 adsi->dwDriver = (DWORD_PTR)aad;
736 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
737 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
739 goto theEnd;
741 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
742 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
744 /* resampling or mono <=> stereo not available
745 * ADPCM algo only define 16 bit per sample output
747 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
748 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
749 adsi->pwfxDst->wBitsPerSample != 16)
750 goto theEnd;
752 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
753 TRACE("spb=%u\n", nspb);
755 /* we check that in a block, after the header, samples are present on
756 * 4-sample packet pattern
757 * we also check that the block alignment is bigger than the expected size
759 if (((nspb - 1) & 3) != 0) goto theEnd;
760 if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
761 goto theEnd;
763 /* adpcm decoding... */
764 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
765 aad->convert = cvtSSima16K;
766 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
767 aad->convert = cvtMMima16K;
769 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
770 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
772 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
773 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
774 adsi->pwfxSrc->wBitsPerSample != 16)
775 goto theEnd;
777 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
778 TRACE("spb=%u\n", nspb);
780 /* we check that in a block, after the header, samples are present on
781 * 4-sample packet pattern
782 * we also check that the block alignment is bigger than the expected size
784 if (((nspb - 1) & 3) != 0) goto theEnd;
785 if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
786 goto theEnd;
788 /* adpcm coding... */
789 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
790 aad->convert = cvtSS16imaK;
791 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
792 aad->convert = cvtMM16imaK;
794 else goto theEnd;
795 ADPCM_Reset(adsi, aad);
797 return MMSYSERR_NOERROR;
799 theEnd:
800 HeapFree(GetProcessHeap(), 0, aad);
801 adsi->dwDriver = 0L;
802 return MMSYSERR_NOTSUPPORTED;
805 /***********************************************************************
806 * ADPCM_StreamClose
809 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
811 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
812 return MMSYSERR_NOERROR;
815 /***********************************************************************
816 * ADPCM_StreamSize
819 static LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
821 DWORD nblocks;
823 switch (adss->fdwSize)
825 case ACM_STREAMSIZEF_DESTINATION:
826 /* cbDstLength => cbSrcLength */
827 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
828 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
830 nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign;
831 if (nblocks == 0)
832 return ACMERR_NOTPOSSIBLE;
833 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
835 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
836 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
838 nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock);
839 if (nblocks == 0)
840 return ACMERR_NOTPOSSIBLE;
841 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
843 else
845 return MMSYSERR_NOTSUPPORTED;
847 break;
848 case ACM_STREAMSIZEF_SOURCE:
849 /* cbSrcLength => cbDstLength */
850 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
851 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
853 nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock);
854 if (nblocks == 0)
855 return ACMERR_NOTPOSSIBLE;
856 if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock))
857 /* Round block count up. */
858 nblocks++;
859 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign;
861 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
862 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
864 nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign;
865 if (nblocks == 0)
866 return ACMERR_NOTPOSSIBLE;
867 if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
868 /* Round block count up. */
869 nblocks++;
870 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
872 else
874 return MMSYSERR_NOTSUPPORTED;
876 break;
877 default:
878 WARN("Unsupported query %08x\n", adss->fdwSize);
879 return MMSYSERR_NOTSUPPORTED;
881 return MMSYSERR_NOERROR;
884 /***********************************************************************
885 * ADPCM_StreamConvert
888 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
890 AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver;
891 DWORD nsrc = adsh->cbSrcLength;
892 DWORD ndst = adsh->cbDstLength;
894 if (adsh->fdwConvert &
895 ~(ACM_STREAMCONVERTF_BLOCKALIGN|
896 ACM_STREAMCONVERTF_END|
897 ACM_STREAMCONVERTF_START))
899 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
901 /* ACM_STREAMCONVERTF_BLOCKALIGN
902 * currently all conversions are block aligned, so do nothing for this flag
903 * ACM_STREAMCONVERTF_END
904 * no pending data, so do nothing for this flag
906 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
908 ADPCM_Reset(adsi, aad);
911 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
912 adsh->cbSrcLengthUsed = nsrc;
913 adsh->cbDstLengthUsed = ndst;
915 return MMSYSERR_NOERROR;
918 /**************************************************************************
919 * ADPCM_DriverProc [exported]
921 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
922 LPARAM dwParam1, LPARAM dwParam2)
924 TRACE("(%08lx %p %04x %08lx %08lx);\n",
925 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
927 switch (wMsg)
929 case DRV_LOAD: return 1;
930 case DRV_FREE: return 1;
931 case DRV_OPEN: return ADPCM_drvOpen((LPSTR)dwParam1);
932 case DRV_CLOSE: return ADPCM_drvClose(dwDevID);
933 case DRV_ENABLE: return 1;
934 case DRV_DISABLE: return 1;
935 case DRV_QUERYCONFIGURE: return 1;
936 case DRV_CONFIGURE: MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK); return 1;
937 case DRV_INSTALL: return DRVCNF_RESTART;
938 case DRV_REMOVE: return DRVCNF_RESTART;
940 case ACMDM_DRIVER_NOTIFY:
941 /* no caching from other ACM drivers is done so far */
942 return MMSYSERR_NOERROR;
944 case ACMDM_DRIVER_DETAILS:
945 return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
947 case ACMDM_FORMATTAG_DETAILS:
948 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
950 case ACMDM_FORMAT_DETAILS:
951 return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
953 case ACMDM_FORMAT_SUGGEST:
954 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
956 case ACMDM_STREAM_OPEN:
957 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
959 case ACMDM_STREAM_CLOSE:
960 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
962 case ACMDM_STREAM_SIZE:
963 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
965 case ACMDM_STREAM_CONVERT:
966 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
968 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
969 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
970 /* this converter is not a hardware driver */
971 case ACMDM_FILTERTAG_DETAILS:
972 case ACMDM_FILTER_DETAILS:
973 /* this converter is not a filter */
974 case ACMDM_STREAM_RESET:
975 /* only needed for asynchronous driver... we aren't, so just say it */
976 return MMSYSERR_NOTSUPPORTED;
977 case ACMDM_STREAM_PREPARE:
978 case ACMDM_STREAM_UNPREPARE:
979 /* nothing special to do here... so don't do anything */
980 return MMSYSERR_NOERROR;
982 default:
983 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);