Release 20030408.
[wine/gsoc-2012-control.git] / dlls / msacm / imaadp32 / imaadp32.c
bloba8117ffa52bfd03fbb5d30ffbc75c98648393aeb
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 <string.h>
24 #include "winnls.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "msacm.h"
29 #include "mmreg.h"
30 #include "../msacmdrv.h"
31 #include "wine/debug.h"
33 /* see http://www.pcisys.net/~melanson/codecs/adpcm.txt for the details */
35 WINE_DEFAULT_DEBUG_CHANNEL(adpcm);
37 /***********************************************************************
38 * ADPCM_drvOpen
40 static DWORD ADPCM_drvOpen(LPCSTR str)
42 return 1;
45 /***********************************************************************
46 * ADPCM_drvClose
48 static DWORD ADPCM_drvClose(DWORD dwDevID)
50 return 1;
53 typedef struct tagAcmAdpcmData
55 void (*convert)(PACMDRVSTREAMINSTANCE adsi,
56 const unsigned char*, LPDWORD, unsigned char*, LPDWORD);
57 /* IMA encoding only */
58 BYTE stepIndexL;
59 BYTE stepIndexR;
60 /* short sample; */
61 } AcmAdpcmData;
63 /* table to list all supported formats... those are the basic ones. this
64 * also helps given a unique index to each of the supported formats
66 typedef struct
68 int nChannels;
69 int nBits;
70 int rate;
71 } Format;
73 static Format PCM_Formats[] =
75 {1, 8, 8000}, {2, 8, 8000}, {1, 16, 8000}, {2, 16, 8000},
76 {1, 8, 11025}, {2, 8, 11025}, {1, 16, 11025}, {2, 16, 11025},
77 {1, 8, 22050}, {2, 8, 22050}, {1, 16, 22050}, {2, 16, 22050},
78 {1, 8, 44100}, {2, 8, 44100}, {1, 16, 44100}, {2, 16, 44100},
81 static Format ADPCM_Formats[] =
83 {1, 4, 8000}, {2, 4, 8000}, {1, 4, 11025}, {2, 4, 11025},
84 {1, 4, 22050}, {2, 4, 22050}, {1, 4, 44100}, {2, 4, 44100},
87 #define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
88 #define NUM_ADPCM_FORMATS (sizeof(ADPCM_Formats) / sizeof(ADPCM_Formats[0]))
90 /***********************************************************************
91 * ADPCM_GetFormatIndex
93 static DWORD ADPCM_GetFormatIndex(LPWAVEFORMATEX wfx)
95 int i, hi;
96 Format* fmts;
98 switch (wfx->wFormatTag)
100 case WAVE_FORMAT_PCM:
101 hi = NUM_PCM_FORMATS;
102 fmts = PCM_Formats;
103 break;
104 case WAVE_FORMAT_IMA_ADPCM:
105 hi = NUM_ADPCM_FORMATS;
106 fmts = ADPCM_Formats;
107 break;
108 default:
109 return 0xFFFFFFFF;
112 for (i = 0; i < hi; i++)
114 if (wfx->nChannels == fmts[i].nChannels &&
115 wfx->nSamplesPerSec == fmts[i].rate &&
116 wfx->wBitsPerSample == fmts[i].nBits)
117 return i;
120 return 0xFFFFFFFF;
123 /***********************************************************************
124 * R16
126 * Read a 16 bit sample (correctly handles endianess)
128 static inline short R16(const unsigned char* src)
130 return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
133 /***********************************************************************
134 * W16
136 * Write a 16 bit sample (correctly handles endianess)
138 static inline void W16(unsigned char* dst, short s)
140 dst[0] = LOBYTE(s);
141 dst[1] = HIBYTE(s);
144 /* IMA (or DVI) APDCM codec routines */
146 static const unsigned IMA_StepTable[89] =
148 7, 8, 9, 10, 11, 12, 13, 14,
149 16, 17, 19, 21, 23, 25, 28, 31,
150 34, 37, 41, 45, 50, 55, 60, 66,
151 73, 80, 88, 97, 107, 118, 130, 143,
152 157, 173, 190, 209, 230, 253, 279, 307,
153 337, 371, 408, 449, 494, 544, 598, 658,
154 724, 796, 876, 963, 1060, 1166, 1282, 1411,
155 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
156 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
157 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
158 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
159 32767
162 static const int IMA_IndexTable[16] =
164 -1, -1, -1, -1, 2, 4, 6, 8,
165 -1, -1, -1, -1, 2, 4, 6, 8
168 static inline void clamp_step_index(int* stepIndex)
170 if (*stepIndex < 0 ) *stepIndex = 0;
171 if (*stepIndex > 88) *stepIndex = 88;
174 static inline void clamp_sample(int* sample)
176 if (*sample < -32768) *sample = -32768;
177 if (*sample > 32767) *sample = 32767;
180 static inline void process_nibble(unsigned char code, int* stepIndex, int* sample)
182 unsigned step;
183 int diff;
185 code &= 0x0F;
187 step = IMA_StepTable[*stepIndex];
188 diff = step >> 3;
189 if (code & 1) diff += step >> 2;
190 if (code & 2) diff += step >> 1;
191 if (code & 4) diff += step;
192 if (code & 8) *sample -= diff;
193 else *sample += diff;
194 clamp_sample(sample);
195 *stepIndex += IMA_IndexTable[code];
196 clamp_step_index(stepIndex);
199 static inline unsigned char generate_nibble(int in, int* stepIndex, int* sample)
201 int effdiff, diff = in - *sample;
202 unsigned step;
203 unsigned char code;
205 if (diff < 0)
207 diff = -diff;
208 code = 8;
210 else
212 code = 0;
215 step = IMA_StepTable[*stepIndex];
216 effdiff = (step >> 3);
217 if (diff >= step)
219 code |= 4;
220 diff -= step;
221 effdiff += step;
223 step >>= 1;
224 if (diff >= step)
226 code |= 2;
227 diff -= step;
228 effdiff += step;
230 step >>= 1;
231 if (diff >= step)
233 code |= 1;
234 effdiff += step;
236 if (code & 8) *sample -= effdiff;
237 else *sample += effdiff;
238 clamp_sample(sample);
239 *stepIndex += IMA_IndexTable[code];
240 clamp_step_index(stepIndex);
241 return code;
244 static void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi,
245 const unsigned char* src, LPDWORD nsrc,
246 unsigned char* dst, LPDWORD ndst)
248 int i;
249 int sampleL, sampleR;
250 int stepIndexL, stepIndexR;
251 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
252 int nsamp;
253 /* compute the number of entire blocks we can decode...
254 * it's the min of the number of entire blocks in source buffer and the number
255 * of entire blocks in destination buffer
257 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
258 *ndst / (nsamp_blk * 2 * 2));
260 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
261 *ndst = nblock * (nsamp_blk * 2 * 2);
263 nsamp_blk--; /* remove the sample in block header */
264 for (; nblock > 0; nblock--)
266 const unsigned char* in_src = src;
268 /* handle headers first */
269 sampleL = R16(src);
270 stepIndexL = (unsigned)*(src + 2);
271 clamp_step_index(&stepIndexL);
272 src += 4;
273 W16(dst, sampleL); dst += 2;
275 sampleR = R16(src);
276 stepIndexR = (unsigned)*(src + 2);
277 clamp_step_index(&stepIndexR);
278 src += 4;
279 W16(dst, sampleR); dst += 2;
281 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
283 for (i = 0; i < 4; i++)
285 process_nibble(*src, &stepIndexL, &sampleL);
286 W16(dst + (2 * i + 0) * 4 + 0, sampleL);
287 process_nibble(*src++ >> 4, &stepIndexL, &sampleL);
288 W16(dst + (2 * i + 1) * 4 + 0, sampleL);
290 for (i = 0; i < 4; i++)
292 process_nibble(*src , &stepIndexR, &sampleR);
293 W16(dst + (2 * i + 0) * 4 + 2, sampleR);
294 process_nibble(*src++ >>4, &stepIndexR, &sampleR);
295 W16(dst + (2 * i + 1) * 4 + 2, sampleR);
297 dst += 32;
299 /* we have now to realign the source pointer on block */
300 src = in_src + adsi->pwfxSrc->nBlockAlign;
304 static void cvtMMima16K(PACMDRVSTREAMINSTANCE adsi,
305 const unsigned char* src, LPDWORD nsrc,
306 unsigned char* dst, LPDWORD ndst)
308 int sample;
309 int stepIndex;
310 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
311 int nsamp;
312 /* compute the number of entire blocks we can decode...
313 * it's the min of the number of entire blocks in source buffer and the number
314 * of entire blocks in destination buffer
316 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
317 *ndst / (nsamp_blk * 2));
319 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
320 *ndst = nblock * nsamp_blk * 2;
322 nsamp_blk--; /* remove the sample in block header */
323 for (; nblock > 0; nblock--)
325 const unsigned char* in_src = src;
327 /* handle header first */
328 sample = R16(src);
329 stepIndex = (unsigned)*(src + 2);
330 clamp_step_index(&stepIndex);
331 src += 4;
332 W16(dst, sample); dst += 2;
334 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
336 process_nibble(*src, &stepIndex, &sample);
337 W16(dst, sample); dst += 2;
338 process_nibble(*src++ >> 4, &stepIndex, &sample);
339 W16(dst, sample); dst += 2;
341 /* we have now to realign the source pointer on block */
342 src = in_src + adsi->pwfxSrc->nBlockAlign;
346 static void cvtSS16imaK(PACMDRVSTREAMINSTANCE adsi,
347 const unsigned char* src, LPDWORD nsrc,
348 unsigned char* dst, LPDWORD ndst)
350 int stepIndexL, stepIndexR;
351 int sampleL, sampleR;
352 BYTE code1, code2;
353 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
354 int i, nsamp;
355 /* compute the number of entire blocks we can decode...
356 * it's the min of the number of entire blocks in source buffer and the number
357 * of entire blocks in destination buffer
359 DWORD nblock = min(*nsrc / (nsamp_blk * 2 * 2),
360 *ndst / adsi->pwfxDst->nBlockAlign);
362 *nsrc = nblock * (nsamp_blk * 2 * 2);
363 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
365 stepIndexL = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
366 stepIndexR = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR;
368 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
370 for (; nblock > 0; nblock--)
372 char* in_dst = dst;
374 /* generate header */
375 sampleL = R16(src); src += 2;
376 W16(dst, sampleL); dst += 2;
377 *dst = (unsigned char)(unsigned)stepIndexL;
378 dst += 2;
380 sampleR = R16(src); src += 2;
381 W16(dst, sampleR); dst += 2;
382 *dst = (unsigned char)(unsigned)stepIndexR;
383 dst += 2;
385 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
387 for (i = 0; i < 4; i++)
389 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 0),
390 &stepIndexL, &sampleL);
391 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 0),
392 &stepIndexL, &sampleL);
393 *dst++ = (code1 << 4) | code2;
395 for (i = 0; i < 4; i++)
397 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 1),
398 &stepIndexR, &sampleR);
399 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 1),
400 &stepIndexR, &sampleR);
401 *dst++ = (code1 << 4) | code2;
403 src += 32;
405 dst = in_dst + adsi->pwfxDst->nBlockAlign;
407 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndexL;
408 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR = stepIndexR;
411 static void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi,
412 const unsigned char* src, LPDWORD nsrc,
413 unsigned char* dst, LPDWORD ndst)
415 int stepIndex;
416 int sample;
417 BYTE code1, code2;
418 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
419 int nsamp;
420 /* compute the number of entire blocks we can decode...
421 * it's the min of the number of entire blocks in source buffer and the number
422 * of entire blocks in destination buffer
424 DWORD nblock = min(*nsrc / (nsamp_blk * 2),
425 *ndst / adsi->pwfxDst->nBlockAlign);
427 *nsrc = nblock * (nsamp_blk * 2);
428 *ndst = nblock * adsi->pwfxDst->nBlockAlign;
430 stepIndex = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
431 nsamp_blk--; /* so that we won't count the sample in header while filling the block */
433 for (; nblock > 0; nblock--)
435 char* in_dst = dst;
437 /* generate header */
438 /* FIXME: what about the last effective sample from previous block ??? */
439 /* perhaps something like:
440 * sample += R16(src);
441 * clamp_sample(sample);
442 * and with :
443 * + saving the sample in adsi->dwDriver when all blocks are done
444 + + reset should set the field in adsi->dwDriver to 0 too
446 sample = R16(src); src += 2;
447 W16(dst, sample); dst += 2;
448 *dst = (unsigned char)(unsigned)stepIndex;
449 dst += 2;
451 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
453 code1 = generate_nibble(R16(src), &stepIndex, &sample);
454 src += 2;
455 code2 = generate_nibble(R16(src), &stepIndex, &sample);
456 src += 2;
457 *dst++ = (code1 << 4) | code2;
459 dst = in_dst + adsi->pwfxDst->nBlockAlign;
461 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndex;
464 /***********************************************************************
465 * ADPCM_DriverDetails
468 static LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
470 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
471 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
472 add->wMid = 0xFF;
473 add->wPid = 0x00;
474 add->vdwACM = 0x01000000;
475 add->vdwDriver = 0x01000000;
476 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
477 add->cFormatTags = 2; /* PCM, IMA ADPCM */
478 add->cFilterTags = 0;
479 add->hicon = NULL;
480 MultiByteToWideChar( CP_ACP, 0, "WINE-ADPCM", -1,
481 add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
482 MultiByteToWideChar( CP_ACP, 0, "Wine IMA ADPCM converter", -1,
483 add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
484 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
485 add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
486 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
487 add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
488 add->szFeatures[0] = 0;
490 return MMSYSERR_NOERROR;
493 /***********************************************************************
494 * ADPCM_FormatTagDetails
497 static LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
499 static WCHAR szPcm[]={'P','C','M',0};
500 static WCHAR szImaAdPcm[]={'I','M','A',' ','A','d','P','C','M',0};
502 switch (dwQuery)
504 case ACM_FORMATTAGDETAILSF_INDEX:
505 if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
506 break;
507 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
508 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
510 aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
511 break;
513 /* fall thru */
514 case ACM_FORMATTAGDETAILSF_FORMATTAG:
515 switch (aftd->dwFormatTag)
517 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break;
518 case WAVE_FORMAT_IMA_ADPCM: aftd->dwFormatTagIndex = 1; break;
519 default: return ACMERR_NOTPOSSIBLE;
521 break;
522 default:
523 WARN("Unsupported query %08lx\n", dwQuery);
524 return MMSYSERR_NOTSUPPORTED;
527 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
528 switch (aftd->dwFormatTagIndex)
530 case 0:
531 aftd->dwFormatTag = WAVE_FORMAT_PCM;
532 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
533 aftd->cStandardFormats = NUM_PCM_FORMATS;
534 lstrcpyW(aftd->szFormatTag, szPcm);
535 break;
536 case 1:
537 aftd->dwFormatTag = WAVE_FORMAT_IMA_ADPCM;
538 aftd->cbFormatSize = sizeof(IMAADPCMWAVEFORMAT);
539 aftd->cStandardFormats = NUM_ADPCM_FORMATS;
540 lstrcpyW(aftd->szFormatTag, szImaAdPcm);
541 break;
543 return MMSYSERR_NOERROR;
546 /***********************************************************************
547 * ADPCM_FormatDetails
550 static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
552 switch (dwQuery)
554 case ACM_FORMATDETAILSF_FORMAT:
555 if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
556 break;
557 case ACM_FORMATDETAILSF_INDEX:
558 afd->pwfx->wFormatTag = afd->dwFormatTag;
559 switch (afd->dwFormatTag)
561 case WAVE_FORMAT_PCM:
562 if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
563 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
564 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
565 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
566 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
567 * afd->pwfx->cbSize = 0;
569 afd->pwfx->nBlockAlign =
570 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
571 afd->pwfx->nAvgBytesPerSec =
572 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
573 break;
574 case WAVE_FORMAT_IMA_ADPCM:
575 if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE;
576 afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
577 afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
578 afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
579 afd->pwfx->nBlockAlign = 1024;
580 /* we got 4 bits per sample */
581 afd->pwfx->nAvgBytesPerSec =
582 (afd->pwfx->nSamplesPerSec * 4) / 8;
583 if (afd->cbwfx >= sizeof(WAVEFORMATEX))
584 afd->pwfx->cbSize = sizeof(WORD);
585 if (afd->cbwfx >= sizeof(IMAADPCMWAVEFORMAT))
586 ((IMAADPCMWAVEFORMAT*)afd->pwfx)->wSamplesPerBlock = (1024 - 4 * afd->pwfx->nChannels) * (2 / afd->pwfx->nChannels) + 1;
587 break;
588 default:
589 WARN("Unsupported tag %08lx\n", afd->dwFormatTag);
590 return MMSYSERR_INVALPARAM;
592 break;
593 default:
594 WARN("Unsupported query %08lx\n", dwQuery);
595 return MMSYSERR_NOTSUPPORTED;
597 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
598 afd->szFormat[0] = 0; /* let MSACM format this for us... */
600 return MMSYSERR_NOERROR;
603 /***********************************************************************
604 * ADPCM_FormatSuggest
607 static LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
609 /* some tests ... */
610 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
611 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
612 ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
613 /* FIXME: should do those tests against the real size (according to format tag */
615 /* If no suggestion for destination, then copy source value */
616 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
617 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
618 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
619 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
621 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
623 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
624 adfs->pwfxDst->wBitsPerSample = 4;
625 else
626 adfs->pwfxDst->wBitsPerSample = 16;
628 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
630 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
631 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
632 else
633 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
636 /* check if result is ok */
637 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
639 /* recompute other values */
640 switch (adfs->pwfxDst->wFormatTag)
642 case WAVE_FORMAT_PCM:
643 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
644 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
645 break;
646 case WAVE_FORMAT_IMA_ADPCM:
647 adfs->pwfxDst->nBlockAlign = 1024;
648 /* FIXME: not handling header overhead */
649 adfs->pwfxDst->nAvgBytesPerSec = ((adfs->pwfxDst->nSamplesPerSec * 4) / 8) * adfs->pwfxSrc->nChannels;
650 ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock = (1024 - 4 * adfs->pwfxSrc->nChannels) * (2 / adfs->pwfxSrc->nChannels) + 1;
651 TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock);
652 break;
653 default:
654 FIXME("\n");
655 break;
658 return MMSYSERR_NOERROR;
661 /***********************************************************************
662 * ADPCM_Reset
665 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
667 aad->stepIndexL = aad->stepIndexR = 0;
670 /***********************************************************************
671 * ADPCM_StreamOpen
674 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
676 AcmAdpcmData* aad;
677 unsigned nspb;
679 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
681 if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
682 ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
683 return ACMERR_NOTPOSSIBLE;
685 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
686 if (aad == 0) return MMSYSERR_NOMEM;
688 adsi->dwDriver = (DWORD)aad;
690 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
691 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
693 goto theEnd;
695 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
696 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
698 /* resampling or mono <=> stereo not available
699 * ADPCM algo only define 16 bit per sample output
701 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
702 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
703 adsi->pwfxDst->wBitsPerSample != 16)
704 goto theEnd;
706 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
707 TRACE("spb=%u\n", nspb);
709 /* we check that in a block, after the header, samples are present on
710 * 4-sample packet pattern
711 * we also check that the block alignement is bigger than the expected size
713 if (((nspb - 1) & 3) != 0) goto theEnd;
714 if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
715 goto theEnd;
717 /* adpcm decoding... */
718 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
719 aad->convert = cvtSSima16K;
720 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
721 aad->convert = cvtMMima16K;
723 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
724 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
726 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
727 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
728 adsi->pwfxSrc->wBitsPerSample != 16)
729 goto theEnd;
731 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
732 TRACE("spb=%u\n", nspb);
734 /* we check that in a block, after the header, samples are present on
735 * 4-sample packet pattern
736 * we also check that the block alignement is bigger than the expected size
738 if (((nspb - 1) & 3) != 0) goto theEnd;
739 if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
740 goto theEnd;
742 /* adpcm coding... */
743 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
744 aad->convert = cvtSS16imaK;
745 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
746 aad->convert = cvtMM16imaK;
748 else goto theEnd;
749 ADPCM_Reset(adsi, aad);
751 return MMSYSERR_NOERROR;
753 theEnd:
754 HeapFree(GetProcessHeap(), 0, aad);
755 adsi->dwDriver = 0L;
756 return MMSYSERR_NOTSUPPORTED;
759 /***********************************************************************
760 * ADPCM_StreamClose
763 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
765 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
766 return MMSYSERR_NOERROR;
769 /***********************************************************************
770 * ADPCM_round
773 static inline DWORD ADPCM_round(DWORD a, DWORD b, DWORD c)
775 assert(a && b && c);
776 /* to be sure, always return an entire number of c... */
777 return ((double)a * (double)b + (double)c - 1) / (double)c;
780 /***********************************************************************
781 * ADPCM_StreamSize
784 static LRESULT ADPCM_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss)
786 switch (adss->fdwSize)
788 case ACM_STREAMSIZEF_DESTINATION:
789 /* cbDstLength => cbSrcLength */
790 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
791 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
793 /* don't take block overhead into account, doesn't matter too much */
794 adss->cbSrcLength = adss->cbDstLength * 4;
796 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
797 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
799 FIXME("misses the block header overhead\n");
800 adss->cbSrcLength = 256 + adss->cbDstLength / 4;
802 else
804 return MMSYSERR_NOTSUPPORTED;
806 break;
807 case ACM_STREAMSIZEF_SOURCE:
808 /* cbSrcLength => cbDstLength */
809 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
810 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
812 FIXME("misses the block header overhead\n");
813 adss->cbDstLength = 256 + adss->cbSrcLength / 4;
815 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
816 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
818 /* don't take block overhead into account, doesn't matter too much */
819 adss->cbDstLength = adss->cbSrcLength * 4;
821 else
823 return MMSYSERR_NOTSUPPORTED;
825 break;
826 default:
827 WARN("Unsupported query %08lx\n", adss->fdwSize);
828 return MMSYSERR_NOTSUPPORTED;
830 return MMSYSERR_NOERROR;
833 /***********************************************************************
834 * ADPCM_StreamConvert
837 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
839 AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver;
840 DWORD nsrc = adsh->cbSrcLength;
841 DWORD ndst = adsh->cbDstLength;
843 if (adsh->fdwConvert &
844 ~(ACM_STREAMCONVERTF_BLOCKALIGN|
845 ACM_STREAMCONVERTF_END|
846 ACM_STREAMCONVERTF_START))
848 FIXME("Unsupported fdwConvert (%08lx), ignoring it\n", adsh->fdwConvert);
850 /* ACM_STREAMCONVERTF_BLOCKALIGN
851 * currently all conversions are block aligned, so do nothing for this flag
852 * ACM_STREAMCONVERTF_END
853 * no pending data, so do nothing for this flag
855 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
857 ADPCM_Reset(adsi, aad);
860 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
861 adsh->cbSrcLengthUsed = nsrc;
862 adsh->cbDstLengthUsed = ndst;
864 return MMSYSERR_NOERROR;
867 /**************************************************************************
868 * ADPCM_DriverProc [exported]
870 LRESULT CALLBACK ADPCM_DriverProc(DWORD dwDevID, HDRVR hDriv, UINT wMsg,
871 LPARAM dwParam1, LPARAM dwParam2)
873 TRACE("(%08lx %08lx %04x %08lx %08lx);\n",
874 dwDevID, (DWORD)hDriv, wMsg, dwParam1, dwParam2);
876 switch (wMsg)
878 case DRV_LOAD: return 1;
879 case DRV_FREE: return 1;
880 case DRV_OPEN: return ADPCM_drvOpen((LPSTR)dwParam1);
881 case DRV_CLOSE: return ADPCM_drvClose(dwDevID);
882 case DRV_ENABLE: return 1;
883 case DRV_DISABLE: return 1;
884 case DRV_QUERYCONFIGURE: return 1;
885 case DRV_CONFIGURE: MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK); return 1;
886 case DRV_INSTALL: return DRVCNF_RESTART;
887 case DRV_REMOVE: return DRVCNF_RESTART;
889 case ACMDM_DRIVER_NOTIFY:
890 /* no caching from other ACM drivers is done so far */
891 return MMSYSERR_NOERROR;
893 case ACMDM_DRIVER_DETAILS:
894 return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
896 case ACMDM_FORMATTAG_DETAILS:
897 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
899 case ACMDM_FORMAT_DETAILS:
900 return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
902 case ACMDM_FORMAT_SUGGEST:
903 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
905 case ACMDM_STREAM_OPEN:
906 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
908 case ACMDM_STREAM_CLOSE:
909 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
911 case ACMDM_STREAM_SIZE:
912 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
914 case ACMDM_STREAM_CONVERT:
915 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
917 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
918 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
919 /* this converter is not a hardware driver */
920 case ACMDM_FILTERTAG_DETAILS:
921 case ACMDM_FILTER_DETAILS:
922 /* this converter is not a filter */
923 case ACMDM_STREAM_RESET:
924 /* only needed for asynchronous driver... we aren't, so just say it */
925 return MMSYSERR_NOTSUPPORTED;
926 case ACMDM_STREAM_PREPARE:
927 case ACMDM_STREAM_UNPREPARE:
928 /* nothing special to do here... so don't do anything */
929 return MMSYSERR_NOERROR;
931 default:
932 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
934 return 0;