Moved msacmdrv.h to include directory to avoid inter-dll header
[wine/multimedia.git] / dlls / msacm / imaadp32 / imaadp32.c
blob61d3d00c2bc66c6d74b5f2ad6ceb08fe358d09af
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 DWORD ADPCM_drvOpen(LPCSTR str)
45 return 1;
48 /***********************************************************************
49 * ADPCM_drvClose
51 static DWORD ADPCM_drvClose(DWORD 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 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 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(LPWAVEFORMATEX wfx)
98 int i, hi;
99 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 return 0xFFFFFFFF;
126 /***********************************************************************
127 * R16
129 * Read a 16 bit sample (correctly handles endianess)
131 static inline short R16(const unsigned char* src)
133 return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
136 /***********************************************************************
137 * W16
139 * Write a 16 bit sample (correctly handles endianess)
141 static inline void W16(unsigned char* dst, short s)
143 dst[0] = LOBYTE(s);
144 dst[1] = HIBYTE(s);
147 /* IMA (or DVI) APDCM codec routines */
149 static const unsigned IMA_StepTable[89] =
151 7, 8, 9, 10, 11, 12, 13, 14,
152 16, 17, 19, 21, 23, 25, 28, 31,
153 34, 37, 41, 45, 50, 55, 60, 66,
154 73, 80, 88, 97, 107, 118, 130, 143,
155 157, 173, 190, 209, 230, 253, 279, 307,
156 337, 371, 408, 449, 494, 544, 598, 658,
157 724, 796, 876, 963, 1060, 1166, 1282, 1411,
158 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
159 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
160 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
161 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
162 32767
165 static const int IMA_IndexTable[16] =
167 -1, -1, -1, -1, 2, 4, 6, 8,
168 -1, -1, -1, -1, 2, 4, 6, 8
171 static inline void clamp_step_index(int* stepIndex)
173 if (*stepIndex < 0 ) *stepIndex = 0;
174 if (*stepIndex > 88) *stepIndex = 88;
177 static inline void clamp_sample(int* sample)
179 if (*sample < -32768) *sample = -32768;
180 if (*sample > 32767) *sample = 32767;
183 static inline void process_nibble(unsigned char code, int* stepIndex, int* sample)
185 unsigned step;
186 int diff;
188 code &= 0x0F;
190 step = IMA_StepTable[*stepIndex];
191 diff = step >> 3;
192 if (code & 1) diff += step >> 2;
193 if (code & 2) diff += step >> 1;
194 if (code & 4) diff += step;
195 if (code & 8) *sample -= diff;
196 else *sample += diff;
197 clamp_sample(sample);
198 *stepIndex += IMA_IndexTable[code];
199 clamp_step_index(stepIndex);
202 static inline unsigned char generate_nibble(int in, int* stepIndex, int* sample)
204 int effdiff, diff = in - *sample;
205 unsigned step;
206 unsigned char code;
208 if (diff < 0)
210 diff = -diff;
211 code = 8;
213 else
215 code = 0;
218 step = IMA_StepTable[*stepIndex];
219 effdiff = (step >> 3);
220 if (diff >= step)
222 code |= 4;
223 diff -= step;
224 effdiff += step;
226 step >>= 1;
227 if (diff >= step)
229 code |= 2;
230 diff -= step;
231 effdiff += step;
233 step >>= 1;
234 if (diff >= step)
236 code |= 1;
237 effdiff += step;
239 if (code & 8) *sample -= effdiff;
240 else *sample += effdiff;
241 clamp_sample(sample);
242 *stepIndex += IMA_IndexTable[code];
243 clamp_step_index(stepIndex);
244 return code;
247 static void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi,
248 const unsigned char* src, LPDWORD nsrc,
249 unsigned char* dst, LPDWORD ndst)
251 int i;
252 int sampleL, sampleR;
253 int stepIndexL, stepIndexR;
254 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
255 int nsamp;
256 /* compute the number of entire blocks we can decode...
257 * it's the min of the number of entire blocks in source buffer and the number
258 * of entire blocks in destination buffer
260 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
261 *ndst / (nsamp_blk * 2 * 2));
263 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
264 *ndst = nblock * (nsamp_blk * 2 * 2);
266 nsamp_blk--; /* remove the sample in block header */
267 for (; nblock > 0; nblock--)
269 const unsigned char* in_src = src;
271 /* handle headers first */
272 sampleL = R16(src);
273 stepIndexL = (unsigned)*(src + 2);
274 clamp_step_index(&stepIndexL);
275 src += 4;
276 W16(dst, sampleL); dst += 2;
278 sampleR = R16(src);
279 stepIndexR = (unsigned)*(src + 2);
280 clamp_step_index(&stepIndexR);
281 src += 4;
282 W16(dst, sampleR); dst += 2;
284 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
286 for (i = 0; i < 4; i++)
288 process_nibble(*src, &stepIndexL, &sampleL);
289 W16(dst + (2 * i + 0) * 4 + 0, sampleL);
290 process_nibble(*src++ >> 4, &stepIndexL, &sampleL);
291 W16(dst + (2 * i + 1) * 4 + 0, sampleL);
293 for (i = 0; i < 4; i++)
295 process_nibble(*src , &stepIndexR, &sampleR);
296 W16(dst + (2 * i + 0) * 4 + 2, sampleR);
297 process_nibble(*src++ >>4, &stepIndexR, &sampleR);
298 W16(dst + (2 * i + 1) * 4 + 2, sampleR);
300 dst += 32;
302 /* we have now to realign the source pointer on block */
303 src = in_src + adsi->pwfxSrc->nBlockAlign;
307 static void cvtMMima16K(PACMDRVSTREAMINSTANCE adsi,
308 const unsigned char* src, LPDWORD nsrc,
309 unsigned char* dst, LPDWORD ndst)
311 int sample;
312 int stepIndex;
313 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
314 int nsamp;
315 /* compute the number of entire blocks we can decode...
316 * it's the min of the number of entire blocks in source buffer and the number
317 * of entire blocks in destination buffer
319 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
320 *ndst / (nsamp_blk * 2));
322 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
323 *ndst = nblock * nsamp_blk * 2;
325 nsamp_blk--; /* remove the sample in block header */
326 for (; nblock > 0; nblock--)
328 const unsigned char* in_src = src;
330 /* handle header first */
331 sample = R16(src);
332 stepIndex = (unsigned)*(src + 2);
333 clamp_step_index(&stepIndex);
334 src += 4;
335 W16(dst, sample); dst += 2;
337 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
339 process_nibble(*src, &stepIndex, &sample);
340 W16(dst, sample); dst += 2;
341 process_nibble(*src++ >> 4, &stepIndex, &sample);
342 W16(dst, sample); dst += 2;
344 /* we have now to realign the source pointer on block */
345 src = in_src + adsi->pwfxSrc->nBlockAlign;
349 static void cvtSS16imaK(PACMDRVSTREAMINSTANCE adsi,
350 const unsigned char* src, LPDWORD nsrc,
351 unsigned char* dst, LPDWORD ndst)
353 int stepIndexL, stepIndexR;
354 int sampleL, sampleR;
355 BYTE code1, code2;
356 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
357 int i, 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 / (nsamp_blk * 2 * 2),
363 *ndst / adsi->pwfxDst->nBlockAlign);
365 *nsrc = nblock * (nsamp_blk * 2 * 2);
366 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
368 stepIndexL = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
369 stepIndexR = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR;
371 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
373 for (; nblock > 0; nblock--)
375 char* in_dst = dst;
377 /* generate header */
378 sampleL = R16(src); src += 2;
379 W16(dst, sampleL); dst += 2;
380 *dst = (unsigned char)(unsigned)stepIndexL;
381 dst += 2;
383 sampleR = R16(src); src += 2;
384 W16(dst, sampleR); dst += 2;
385 *dst = (unsigned char)(unsigned)stepIndexR;
386 dst += 2;
388 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
390 for (i = 0; i < 4; i++)
392 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 0),
393 &stepIndexL, &sampleL);
394 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 0),
395 &stepIndexL, &sampleL);
396 *dst++ = (code1 << 4) | code2;
398 for (i = 0; i < 4; i++)
400 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 1),
401 &stepIndexR, &sampleR);
402 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 1),
403 &stepIndexR, &sampleR);
404 *dst++ = (code1 << 4) | code2;
406 src += 32;
408 dst = in_dst + adsi->pwfxDst->nBlockAlign;
410 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndexL;
411 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR = stepIndexR;
414 static void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi,
415 const unsigned char* src, LPDWORD nsrc,
416 unsigned char* dst, LPDWORD ndst)
418 int stepIndex;
419 int sample;
420 BYTE code1, code2;
421 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
422 int nsamp;
423 /* compute the number of entire blocks we can decode...
424 * it's the min of the number of entire blocks in source buffer and the number
425 * of entire blocks in destination buffer
427 DWORD nblock = min(*nsrc / (nsamp_blk * 2),
428 *ndst / adsi->pwfxDst->nBlockAlign);
430 *nsrc = nblock * (nsamp_blk * 2);
431 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
433 stepIndex = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
434 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
436 for (; nblock > 0; nblock--)
438 char* in_dst = dst;
440 /* generate header */
441 /* FIXME: what about the last effective sample from previous block ??? */
442 /* perhaps something like:
443 * sample += R16(src);
444 * clamp_sample(sample);
445 * and with :
446 * + saving the sample in adsi->dwDriver when all blocks are done
447 + + reset should set the field in adsi->dwDriver to 0 too
449 sample = R16(src); src += 2;
450 W16(dst, sample); dst += 2;
451 *dst = (unsigned char)(unsigned)stepIndex;
452 dst += 2;
454 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
456 code1 = generate_nibble(R16(src), &stepIndex, &sample);
457 src += 2;
458 code2 = generate_nibble(R16(src), &stepIndex, &sample);
459 src += 2;
460 *dst++ = (code1 << 4) | code2;
462 dst = in_dst + adsi->pwfxDst->nBlockAlign;
464 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndex;
467 /***********************************************************************
468 * ADPCM_DriverDetails
471 static LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
473 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
474 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
475 add->wMid = 0xFF;
476 add->wPid = 0x00;
477 add->vdwACM = 0x01000000;
478 add->vdwDriver = 0x01000000;
479 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
480 add->cFormatTags = 2; /* PCM, IMA ADPCM */
481 add->cFilterTags = 0;
482 add->hicon = NULL;
483 MultiByteToWideChar( CP_ACP, 0, "WINE-ADPCM", -1,
484 add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
485 MultiByteToWideChar( CP_ACP, 0, "Wine IMA ADPCM converter", -1,
486 add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
487 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
488 add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
489 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
490 add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
491 add->szFeatures[0] = 0;
493 return MMSYSERR_NOERROR;
496 /***********************************************************************
497 * ADPCM_FormatTagDetails
500 static LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
502 static WCHAR szPcm[]={'P','C','M',0};
503 static WCHAR szImaAdPcm[]={'I','M','A',' ','A','d','P','C','M',0};
505 switch (dwQuery)
507 case ACM_FORMATTAGDETAILSF_INDEX:
508 if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
509 break;
510 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
511 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
513 aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
514 break;
516 /* fall thru */
517 case ACM_FORMATTAGDETAILSF_FORMATTAG:
518 switch (aftd->dwFormatTag)
520 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break;
521 case WAVE_FORMAT_IMA_ADPCM: aftd->dwFormatTagIndex = 1; break;
522 default: return ACMERR_NOTPOSSIBLE;
524 break;
525 default:
526 WARN("Unsupported query %08lx\n", dwQuery);
527 return MMSYSERR_NOTSUPPORTED;
530 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
531 switch (aftd->dwFormatTagIndex)
533 case 0:
534 aftd->dwFormatTag = WAVE_FORMAT_PCM;
535 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
536 aftd->cStandardFormats = NUM_PCM_FORMATS;
537 lstrcpyW(aftd->szFormatTag, szPcm);
538 break;
539 case 1:
540 aftd->dwFormatTag = WAVE_FORMAT_IMA_ADPCM;
541 aftd->cbFormatSize = sizeof(IMAADPCMWAVEFORMAT);
542 aftd->cStandardFormats = NUM_ADPCM_FORMATS;
543 lstrcpyW(aftd->szFormatTag, szImaAdPcm);
544 break;
546 return MMSYSERR_NOERROR;
549 /***********************************************************************
550 * ADPCM_FormatDetails
553 static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
555 switch (dwQuery)
557 case ACM_FORMATDETAILSF_FORMAT:
558 if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
559 break;
560 case ACM_FORMATDETAILSF_INDEX:
561 afd->pwfx->wFormatTag = afd->dwFormatTag;
562 switch (afd->dwFormatTag)
564 case WAVE_FORMAT_PCM:
565 if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
566 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
567 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
568 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
569 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
570 * afd->pwfx->cbSize = 0;
572 afd->pwfx->nBlockAlign =
573 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
574 afd->pwfx->nAvgBytesPerSec =
575 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
576 break;
577 case WAVE_FORMAT_IMA_ADPCM:
578 if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE;
579 afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
580 afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
581 afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
582 afd->pwfx->nBlockAlign = 1024;
583 /* we got 4 bits per sample */
584 afd->pwfx->nAvgBytesPerSec =
585 (afd->pwfx->nSamplesPerSec * 4) / 8;
586 if (afd->cbwfx >= sizeof(WAVEFORMATEX))
587 afd->pwfx->cbSize = sizeof(WORD);
588 if (afd->cbwfx >= sizeof(IMAADPCMWAVEFORMAT))
589 ((IMAADPCMWAVEFORMAT*)afd->pwfx)->wSamplesPerBlock = (1024 - 4 * afd->pwfx->nChannels) * (2 / afd->pwfx->nChannels) + 1;
590 break;
591 default:
592 WARN("Unsupported tag %08lx\n", afd->dwFormatTag);
593 return MMSYSERR_INVALPARAM;
595 break;
596 default:
597 WARN("Unsupported query %08lx\n", dwQuery);
598 return MMSYSERR_NOTSUPPORTED;
600 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
601 afd->szFormat[0] = 0; /* let MSACM format this for us... */
603 return MMSYSERR_NOERROR;
606 /***********************************************************************
607 * ADPCM_FormatSuggest
610 static LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
612 /* some tests ... */
613 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
614 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
615 ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
616 /* FIXME: should do those tests against the real size (according to format tag */
618 /* If no suggestion for destination, then copy source value */
619 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
620 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
621 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
622 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
624 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
626 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
627 adfs->pwfxDst->wBitsPerSample = 4;
628 else
629 adfs->pwfxDst->wBitsPerSample = 16;
631 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
633 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
634 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
635 else
636 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
639 /* check if result is ok */
640 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
642 /* recompute other values */
643 switch (adfs->pwfxDst->wFormatTag)
645 case WAVE_FORMAT_PCM:
646 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
647 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
648 break;
649 case WAVE_FORMAT_IMA_ADPCM:
650 adfs->pwfxDst->nBlockAlign = 1024;
651 /* FIXME: not handling header overhead */
652 adfs->pwfxDst->nAvgBytesPerSec = ((adfs->pwfxDst->nSamplesPerSec * 4) / 8) * adfs->pwfxSrc->nChannels;
653 ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock = (1024 - 4 * adfs->pwfxSrc->nChannels) * (2 / adfs->pwfxSrc->nChannels) + 1;
654 TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock);
655 break;
656 default:
657 FIXME("\n");
658 break;
661 return MMSYSERR_NOERROR;
664 /***********************************************************************
665 * ADPCM_Reset
668 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
670 aad->stepIndexL = aad->stepIndexR = 0;
673 /***********************************************************************
674 * ADPCM_StreamOpen
677 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
679 AcmAdpcmData* aad;
680 unsigned nspb;
682 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
684 if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
685 ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
686 return ACMERR_NOTPOSSIBLE;
688 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
689 if (aad == 0) return MMSYSERR_NOMEM;
691 adsi->dwDriver = (DWORD)aad;
693 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
694 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
696 goto theEnd;
698 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
699 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
701 /* resampling or mono <=> stereo not available
702 * ADPCM algo only define 16 bit per sample output
704 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
705 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
706 adsi->pwfxDst->wBitsPerSample != 16)
707 goto theEnd;
709 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
710 TRACE("spb=%u\n", nspb);
712 /* we check that in a block, after the header, samples are present on
713 * 4-sample packet pattern
714 * we also check that the block alignement is bigger than the expected size
716 if (((nspb - 1) & 3) != 0) goto theEnd;
717 if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
718 goto theEnd;
720 /* adpcm decoding... */
721 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
722 aad->convert = cvtSSima16K;
723 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
724 aad->convert = cvtMMima16K;
726 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
727 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
729 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
730 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
731 adsi->pwfxSrc->wBitsPerSample != 16)
732 goto theEnd;
734 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
735 TRACE("spb=%u\n", nspb);
737 /* we check that in a block, after the header, samples are present on
738 * 4-sample packet pattern
739 * we also check that the block alignement is bigger than the expected size
741 if (((nspb - 1) & 3) != 0) goto theEnd;
742 if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
743 goto theEnd;
745 /* adpcm coding... */
746 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
747 aad->convert = cvtSS16imaK;
748 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
749 aad->convert = cvtMM16imaK;
751 else goto theEnd;
752 ADPCM_Reset(adsi, aad);
754 return MMSYSERR_NOERROR;
756 theEnd:
757 HeapFree(GetProcessHeap(), 0, aad);
758 adsi->dwDriver = 0L;
759 return MMSYSERR_NOTSUPPORTED;
762 /***********************************************************************
763 * ADPCM_StreamClose
766 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
768 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
769 return MMSYSERR_NOERROR;
772 /***********************************************************************
773 * ADPCM_round
776 static inline DWORD ADPCM_round(DWORD a, DWORD b, DWORD c)
778 assert(a && b && c);
779 /* to be sure, always return an entire number of c... */
780 return ((double)a * (double)b + (double)c - 1) / (double)c;
783 /***********************************************************************
784 * ADPCM_StreamSize
787 static LRESULT ADPCM_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss)
789 switch (adss->fdwSize)
791 case ACM_STREAMSIZEF_DESTINATION:
792 /* cbDstLength => cbSrcLength */
793 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
794 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
796 /* don't take block overhead into account, doesn't matter too much */
797 adss->cbSrcLength = adss->cbDstLength * 4;
799 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
800 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
802 FIXME("misses the block header overhead\n");
803 adss->cbSrcLength = 256 + adss->cbDstLength / 4;
805 else
807 return MMSYSERR_NOTSUPPORTED;
809 break;
810 case ACM_STREAMSIZEF_SOURCE:
811 /* cbSrcLength => cbDstLength */
812 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
813 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
815 FIXME("misses the block header overhead\n");
816 adss->cbDstLength = 256 + adss->cbSrcLength / 4;
818 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
819 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
821 /* don't take block overhead into account, doesn't matter too much */
822 adss->cbDstLength = adss->cbSrcLength * 4;
824 else
826 return MMSYSERR_NOTSUPPORTED;
828 break;
829 default:
830 WARN("Unsupported query %08lx\n", adss->fdwSize);
831 return MMSYSERR_NOTSUPPORTED;
833 return MMSYSERR_NOERROR;
836 /***********************************************************************
837 * ADPCM_StreamConvert
840 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
842 AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver;
843 DWORD nsrc = adsh->cbSrcLength;
844 DWORD ndst = adsh->cbDstLength;
846 if (adsh->fdwConvert &
847 ~(ACM_STREAMCONVERTF_BLOCKALIGN|
848 ACM_STREAMCONVERTF_END|
849 ACM_STREAMCONVERTF_START))
851 FIXME("Unsupported fdwConvert (%08lx), ignoring it\n", adsh->fdwConvert);
853 /* ACM_STREAMCONVERTF_BLOCKALIGN
854 * currently all conversions are block aligned, so do nothing for this flag
855 * ACM_STREAMCONVERTF_END
856 * no pending data, so do nothing for this flag
858 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
860 ADPCM_Reset(adsi, aad);
863 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
864 adsh->cbSrcLengthUsed = nsrc;
865 adsh->cbDstLengthUsed = ndst;
867 return MMSYSERR_NOERROR;
870 /**************************************************************************
871 * ADPCM_DriverProc [exported]
873 LRESULT CALLBACK ADPCM_DriverProc(DWORD dwDevID, HDRVR hDriv, UINT wMsg,
874 LPARAM dwParam1, LPARAM dwParam2)
876 TRACE("(%08lx %08lx %04x %08lx %08lx);\n",
877 dwDevID, (DWORD)hDriv, wMsg, dwParam1, dwParam2);
879 switch (wMsg)
881 case DRV_LOAD: return 1;
882 case DRV_FREE: return 1;
883 case DRV_OPEN: return ADPCM_drvOpen((LPSTR)dwParam1);
884 case DRV_CLOSE: return ADPCM_drvClose(dwDevID);
885 case DRV_ENABLE: return 1;
886 case DRV_DISABLE: return 1;
887 case DRV_QUERYCONFIGURE: return 1;
888 case DRV_CONFIGURE: MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK); return 1;
889 case DRV_INSTALL: return DRVCNF_RESTART;
890 case DRV_REMOVE: return DRVCNF_RESTART;
892 case ACMDM_DRIVER_NOTIFY:
893 /* no caching from other ACM drivers is done so far */
894 return MMSYSERR_NOERROR;
896 case ACMDM_DRIVER_DETAILS:
897 return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
899 case ACMDM_FORMATTAG_DETAILS:
900 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
902 case ACMDM_FORMAT_DETAILS:
903 return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
905 case ACMDM_FORMAT_SUGGEST:
906 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
908 case ACMDM_STREAM_OPEN:
909 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
911 case ACMDM_STREAM_CLOSE:
912 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
914 case ACMDM_STREAM_SIZE:
915 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
917 case ACMDM_STREAM_CONVERT:
918 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
920 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
921 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
922 /* this converter is not a hardware driver */
923 case ACMDM_FILTERTAG_DETAILS:
924 case ACMDM_FILTER_DETAILS:
925 /* this converter is not a filter */
926 case ACMDM_STREAM_RESET:
927 /* only needed for asynchronous driver... we aren't, so just say it */
928 return MMSYSERR_NOTSUPPORTED;
929 case ACMDM_STREAM_PREPARE:
930 case ACMDM_STREAM_UNPREPARE:
931 /* nothing special to do here... so don't do anything */
932 return MMSYSERR_NOERROR;
934 default:
935 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
937 return 0;