xref: /reactos/dll/win32/msadp32.acm/msadp32.c (revision d2c71d76)
1 /*
2  * MS ADPCM handling
3  *
4  *      Copyright (C) 2002		Eric Pouech
5  *
6  *
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.
11  *
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.
16  *
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
20  */
21 
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"
35 
36 /* see http://www.pcisys.net/~melanson/codecs/adpcm.txt for the details */
37 
38 WINE_DEFAULT_DEBUG_CHANNEL(adpcm);
39 
40 /***********************************************************************
41  *           ADPCM_drvOpen
42  */
43 static LRESULT ADPCM_drvOpen(LPCSTR str)
44 {
45     return 1;
46 }
47 
48 /***********************************************************************
49  *           ADPCM_drvClose
50  */
51 static LRESULT ADPCM_drvClose(DWORD_PTR dwDevID)
52 {
53     return 1;
54 }
55 
56 typedef struct tagAcmAdpcmData
57 {
58     void (*convert)(const ACMDRVSTREAMINSTANCE *adsi,
59 		    const unsigned char*, LPDWORD, unsigned char*, LPDWORD);
60 } AcmAdpcmData;
61 
62 /* table to list all supported formats... those are the basic ones. this
63  * also helps given a unique index to each of the supported formats
64  */
65 typedef	struct
66 {
67     int		nChannels;
68     int		nBits;
69     int		rate;
70 } Format;
71 
72 static const Format PCM_Formats[] =
73 {
74     {1,  8,  8000}, {2,  8,  8000}, {1, 16,  8000}, {2, 16,  8000},
75     {1,  8, 11025}, {2,  8, 11025}, {1, 16, 11025}, {2, 16, 11025},
76     {1,  8, 22050}, {2,  8, 22050}, {1, 16, 22050}, {2, 16, 22050},
77     {1,  8, 44100}, {2,  8, 44100}, {1, 16, 44100}, {2, 16, 44100},
78 };
79 
80 static const Format ADPCM_Formats[] =
81 {
82     {1,  4,  8000}, {2,	4,  8000},  {1,  4, 11025}, {2,	 4, 11025},
83     {1,  4, 22050}, {2,	4, 22050},  {1,  4, 44100}, {2,	 4, 44100},
84 };
85 
86 static int MS_Delta[] =
87 {
88     230, 230, 230, 230, 307, 409, 512, 614,
89     768, 614, 512, 409, 307, 230, 230, 230
90 };
91 
92 
93 static ADPCMCOEFSET MSADPCM_CoeffSet[] =
94 {
95     {256, 0}, {512, -256}, {0, 0}, {192, 64}, {240, 0}, {460, -208}, {392, -232}
96 };
97 
98 /***********************************************************************
99  *           ADPCM_GetFormatIndex
100  */
101 static	DWORD	ADPCM_GetFormatIndex(const WAVEFORMATEX* wfx)
102 {
103     int             i, hi;
104     const Format*   fmts;
105 
106     switch (wfx->wFormatTag)
107     {
108     case WAVE_FORMAT_PCM:
109 	hi = ARRAY_SIZE(PCM_Formats);
110 	fmts = PCM_Formats;
111 	break;
112     case WAVE_FORMAT_ADPCM:
113 	hi = ARRAY_SIZE(ADPCM_Formats);
114 	fmts = ADPCM_Formats;
115 	break;
116     default:
117 	return 0xFFFFFFFF;
118     }
119 
120     for (i = 0; i < hi; i++)
121     {
122 	if (wfx->nChannels == fmts[i].nChannels &&
123 	    wfx->nSamplesPerSec == fmts[i].rate &&
124 	    wfx->wBitsPerSample == fmts[i].nBits)
125 	    return i;
126     }
127 
128     switch (wfx->wFormatTag)
129     {
130     case WAVE_FORMAT_PCM:
131 	if(3 > wfx->nChannels &&
132 	   wfx->nChannels > 0 &&
133 	   wfx->nAvgBytesPerSec == 2 * wfx->nSamplesPerSec * wfx->nChannels &&
134 	   wfx->nBlockAlign == 2 * wfx->nChannels &&
135 	   wfx->wBitsPerSample == 16)
136 	   return hi;
137 	break;
138     case WAVE_FORMAT_ADPCM:
139 	if(3 > wfx->nChannels &&
140 	   wfx->nChannels > 0 &&
141 	   wfx->wBitsPerSample == 4 &&
142 	   wfx->cbSize == 32)
143 	   return hi;
144 	break;
145     }
146 
147     return 0xFFFFFFFF;
148 }
149 
150 static void     init_wfx_adpcm(ADPCMWAVEFORMAT* awfx)
151 {
152     register WAVEFORMATEX*      pwfx = &awfx->wfx;
153 
154     /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample
155      * have been initialized... */
156 
157     if (pwfx->wFormatTag != WAVE_FORMAT_ADPCM) {FIXME("wrong FT\n"); return;}
158     if (ADPCM_GetFormatIndex(pwfx) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;}
159 
160     switch (pwfx->nSamplesPerSec)
161     {
162     case  8000: pwfx->nBlockAlign = 256 * pwfx->nChannels;   break;
163     case 11025: pwfx->nBlockAlign = 256 * pwfx->nChannels;   break;
164     case 22050: pwfx->nBlockAlign = 512 * pwfx->nChannels;   break;
165     case 44100: pwfx->nBlockAlign = 1024 * pwfx->nChannels;  break;
166     default:                               break;
167     }
168     pwfx->cbSize = 2 * sizeof(WORD) + 7 * sizeof(ADPCMCOEFSET);
169     /* 7 is the size of the block head (which contains two samples) */
170 
171     awfx->wSamplesPerBlock = pwfx->nBlockAlign * 2 / pwfx->nChannels - 12;
172     pwfx->nAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) / awfx->wSamplesPerBlock;
173     awfx->wNumCoef = 7;
174     memcpy(awfx->aCoef, MSADPCM_CoeffSet, 7 * sizeof(ADPCMCOEFSET));
175 }
176 
177 /***********************************************************************
178  *           R16
179  *
180  * Read a 16 bit sample (correctly handles endianness)
181  */
182 static inline short  R16(const unsigned char* src)
183 {
184     return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
185 }
186 
187 /***********************************************************************
188  *           W16
189  *
190  * Write a 16 bit sample (correctly handles endianness)
191  */
192 static inline void  W16(unsigned char* dst, short s)
193 {
194     dst[0] = LOBYTE(s);
195     dst[1] = HIBYTE(s);
196 }
197 
198 static inline void clamp_sample(int* sample)
199 {
200     if (*sample < -32768) *sample = -32768;
201     if (*sample >  32767) *sample =  32767;
202 }
203 
204 static inline void process_nibble(unsigned nibble, int* idelta,
205                                   int* sample1, int* sample2,
206                                   const ADPCMCOEFSET* coeff)
207 {
208     int sample;
209     int snibble;
210 
211     /* nibble is in fact a signed 4 bit integer => propagate sign if needed */
212     snibble = (nibble & 0x08) ? (nibble - 16) : nibble;
213     sample = ((*sample1 * coeff->iCoef1) + (*sample2 * coeff->iCoef2)) / 256 +
214         snibble * *idelta;
215     clamp_sample(&sample);
216 
217     *sample2 = *sample1;
218     *sample1 = sample;
219     *idelta = ((MS_Delta[nibble] * *idelta) / 256);
220     if (*idelta < 16) *idelta = 16;
221 }
222 
223 static inline unsigned char C168(short s)
224 {
225     return HIBYTE(s) ^ (unsigned char)0x80;
226 }
227 
228 static	void cvtSSms16K(const ACMDRVSTREAMINSTANCE *adsi,
229                         const unsigned char* src, LPDWORD nsrc,
230                         unsigned char* dst, LPDWORD ndst)
231 {
232     int                 ideltaL, ideltaR;
233     int                 sample1L, sample2L;
234     int                 sample1R, sample2R;
235     ADPCMCOEFSET        coeffL, coeffR;
236     int                 nsamp;
237     int		        nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
238     DWORD	        nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
239                                      *ndst / (nsamp_blk * adsi->pwfxDst->nBlockAlign));
240 
241     *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
242     *ndst = nblock * nsamp_blk * adsi->pwfxDst->nBlockAlign;
243 
244     nsamp_blk -= 2; /* see below for samples from block head */
245     for (; nblock > 0; nblock--)
246     {
247         const unsigned char*    in_src = src;
248 
249         /* Catch a problem from Tomb Raider III (bug 21000) where it passes
250          * invalid data after a valid sequence of blocks */
251         if (*src > 6 || *(src + 1) > 6)
252         {
253             /* Recalculate the amount of used output buffer. We are not changing
254              * nsrc, let's assume the bad data was parsed */
255             *ndst -= nblock * nsamp_blk * adsi->pwfxDst->nBlockAlign;
256             WARN("Invalid ADPCM data, stopping conversion\n");
257             break;
258         }
259         coeffL = MSADPCM_CoeffSet[*src++];
260         coeffR = MSADPCM_CoeffSet[*src++];
261 
262         ideltaL  = R16(src);    src += 2;
263         ideltaR  = R16(src);    src += 2;
264         sample1L = R16(src);    src += 2;
265         sample1R = R16(src);    src += 2;
266         sample2L = R16(src);    src += 2;
267         sample2R = R16(src);    src += 2;
268 
269         if(adsi->pwfxDst->wBitsPerSample == 8){
270             /* store samples from block head */
271             *dst = C168(sample2L);      ++dst;
272             *dst = C168(sample2R);      ++dst;
273             *dst = C168(sample1L);      ++dst;
274             *dst = C168(sample1R);      ++dst;
275 
276             for (nsamp = nsamp_blk; nsamp > 0; nsamp--)
277             {
278                 process_nibble(*src >> 4, &ideltaL, &sample1L, &sample2L, &coeffL);
279                 *dst = C168(sample1L); ++dst;
280                 process_nibble(*src++ & 0x0F, &ideltaR, &sample1R, &sample2R, &coeffR);
281                 *dst = C168(sample1R); ++dst;
282             }
283         }else if(adsi->pwfxDst->wBitsPerSample == 16){
284             /* store samples from block head */
285             W16(dst, sample2L);      dst += 2;
286             W16(dst, sample2R);      dst += 2;
287             W16(dst, sample1L);      dst += 2;
288             W16(dst, sample1R);      dst += 2;
289 
290             for (nsamp = nsamp_blk; nsamp > 0; nsamp--)
291             {
292                 process_nibble(*src >> 4, &ideltaL, &sample1L, &sample2L, &coeffL);
293                 W16(dst, sample1L); dst += 2;
294                 process_nibble(*src++ & 0x0F, &ideltaR, &sample1R, &sample2R, &coeffR);
295                 W16(dst, sample1R); dst += 2;
296             }
297         }
298         src = in_src + adsi->pwfxSrc->nBlockAlign;
299     }
300 }
301 
302 static	void cvtMMms16K(const ACMDRVSTREAMINSTANCE *adsi,
303                         const unsigned char* src, LPDWORD nsrc,
304                         unsigned char* dst, LPDWORD ndst)
305 {
306     int                 idelta;
307     int                 sample1, sample2;
308     ADPCMCOEFSET        coeff;
309     int                 nsamp;
310     int		        nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
311     DWORD	        nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
312                                      *ndst / (nsamp_blk * adsi->pwfxDst->nBlockAlign));
313 
314     *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
315     *ndst = nblock * nsamp_blk * adsi->pwfxDst->nBlockAlign;
316 
317     nsamp_blk -= 2; /* see below for samples from block head */
318     for (; nblock > 0; nblock--)
319     {
320         const unsigned char*    in_src = src;
321 
322         assert(*src <= 6);
323         coeff = MSADPCM_CoeffSet[*src++];
324 
325         idelta =  R16(src);     src += 2;
326         sample1 = R16(src);     src += 2;
327         sample2 = R16(src);     src += 2;
328 
329         /* store samples from block head */
330         if(adsi->pwfxDst->wBitsPerSample == 8){
331             *dst = C168(sample2);    ++dst;
332             *dst = C168(sample1);    ++dst;
333 
334             for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
335             {
336                 process_nibble(*src >> 4, &idelta, &sample1, &sample2, &coeff);
337                 *dst = C168(sample1); ++dst;
338                 process_nibble(*src++ & 0x0F, &idelta, &sample1, &sample2, &coeff);
339                 *dst = C168(sample1); ++dst;
340             }
341         }else if(adsi->pwfxDst->wBitsPerSample == 16){
342             W16(dst, sample2);      dst += 2;
343             W16(dst, sample1);      dst += 2;
344 
345             for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
346             {
347                 process_nibble(*src >> 4, &idelta, &sample1, &sample2, &coeff);
348                 W16(dst, sample1); dst += 2;
349                 process_nibble(*src++ & 0x0F, &idelta, &sample1, &sample2, &coeff);
350                 W16(dst, sample1); dst += 2;
351             }
352         }
353 
354         src = in_src + adsi->pwfxSrc->nBlockAlign;
355     }
356 }
357 
358 #if 0
359 static	void cvtSS16msK(PACMDRVSTREAMINSTANCE adsi,
360                         const unsigned char* src, LPDWORD nsrc,
361                         unsigned char* dst, LPDWORD ndst)
362 {
363 }
364 
365 static	void cvtMM16msK(PACMDRVSTREAMINSTANCE adsi,
366                         const unsigned char* src, LPDWORD nsrc,
367                         unsigned char* dst, LPDWORD ndst)
368 {
369 }
370 #endif
371 
372 /***********************************************************************
373  *           ADPCM_DriverDetails
374  *
375  */
376 static	LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
377 {
378     add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
379     add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
380     add->wMid = MM_MICROSOFT;
381     add->wPid = MM_MSFT_ACM_MSADPCM;
382     add->vdwACM = 0x01000000;
383     add->vdwDriver = 0x01000000;
384     add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
385     add->cFormatTags = 2; /* PCM, MS ADPCM */
386     add->cFilterTags = 0;
387     add->hicon = NULL;
388     MultiByteToWideChar( CP_ACP, 0, "MS-ADPCM", -1,
389                          add->szShortName, ARRAY_SIZE( add->szShortName ));
390     MultiByteToWideChar( CP_ACP, 0, "Wine MS ADPCM converter", -1,
391                          add->szLongName, ARRAY_SIZE( add->szLongName ));
392     MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
393                          add->szCopyright, ARRAY_SIZE( add->szCopyright ));
394     MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
395                          add->szLicensing, ARRAY_SIZE( add->szLicensing ));
396     add->szFeatures[0] = 0;
397 
398     return MMSYSERR_NOERROR;
399 }
400 
401 /***********************************************************************
402  *           ADPCM_FormatTagDetails
403  *
404  */
405 static	LRESULT	ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
406 {
407     static const WCHAR szPcm[]={'P','C','M',0};
408     static const WCHAR szMsAdPcm[]={'M','i','c','r','o','s','o','f','t',' ','A','D','P','C','M',0};
409 
410     switch (dwQuery)
411     {
412     case ACM_FORMATTAGDETAILSF_INDEX:
413 	if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
414 	break;
415     case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
416 	if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
417         {
418             aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_ADPCM is bigger than PCM */
419 	    break;
420 	}
421 	/* fall through */
422     case ACM_FORMATTAGDETAILSF_FORMATTAG:
423 	switch (aftd->dwFormatTag)
424         {
425 	case WAVE_FORMAT_PCM:	aftd->dwFormatTagIndex = 0; break;
426 	case WAVE_FORMAT_ADPCM: aftd->dwFormatTagIndex = 1; break;
427 	default:		return ACMERR_NOTPOSSIBLE;
428 	}
429 	break;
430     default:
431 	WARN("Unsupported query %08x\n", dwQuery);
432 	return MMSYSERR_NOTSUPPORTED;
433     }
434 
435     aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
436     switch (aftd->dwFormatTagIndex)
437     {
438     case 0:
439 	aftd->dwFormatTag = WAVE_FORMAT_PCM;
440 	aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
441 	aftd->cStandardFormats = ARRAY_SIZE(PCM_Formats);
442         lstrcpyW(aftd->szFormatTag, szPcm);
443         break;
444     case 1:
445 	aftd->dwFormatTag = WAVE_FORMAT_ADPCM;
446 	aftd->cbFormatSize = sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET);
447 	aftd->cStandardFormats = ARRAY_SIZE(ADPCM_Formats);
448         lstrcpyW(aftd->szFormatTag, szMsAdPcm);
449 	break;
450     }
451     return MMSYSERR_NOERROR;
452 }
453 
454 /***********************************************************************
455  *           ADPCM_FormatDetails
456  *
457  */
458 static	LRESULT	ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
459 {
460     switch (dwQuery)
461     {
462     case ACM_FORMATDETAILSF_FORMAT:
463 	if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
464 	break;
465     case ACM_FORMATDETAILSF_INDEX:
466 	afd->pwfx->wFormatTag = afd->dwFormatTag;
467 	switch (afd->dwFormatTag)
468         {
469 	case WAVE_FORMAT_PCM:
470 	    if (afd->dwFormatIndex >= ARRAY_SIZE(PCM_Formats)) return ACMERR_NOTPOSSIBLE;
471 	    afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
472 	    afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
473 	    afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
474 	    /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
475 	     * afd->pwfx->cbSize = 0;
476 	     */
477 	    afd->pwfx->nBlockAlign =
478 		(afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
479 	    afd->pwfx->nAvgBytesPerSec =
480 		afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
481 	    break;
482 	case WAVE_FORMAT_ADPCM:
483 	    if (afd->dwFormatIndex >= ARRAY_SIZE(ADPCM_Formats)) return ACMERR_NOTPOSSIBLE;
484             if (afd->cbwfx < sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET))
485                 return ACMERR_NOTPOSSIBLE;
486 	    afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
487 	    afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
488 	    afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
489             init_wfx_adpcm((ADPCMWAVEFORMAT*)afd->pwfx);
490 	    break;
491 	default:
492             WARN("Unsupported tag %08x\n", afd->dwFormatTag);
493 	    return MMSYSERR_INVALPARAM;
494 	}
495 	break;
496     default:
497 	WARN("Unsupported query %08x\n", dwQuery);
498 	return MMSYSERR_NOTSUPPORTED;
499     }
500     afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
501     afd->szFormat[0] = 0; /* let MSACM format this for us... */
502 
503     return MMSYSERR_NOERROR;
504 }
505 
506 /***********************************************************************
507  *           ADPCM_FormatSuggest
508  *
509  */
510 static	LRESULT	ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
511 {
512     /* some tests ... */
513     if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
514 	adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
515 	adfs->pwfxSrc->wFormatTag == adfs->pwfxDst->wFormatTag ||
516 	ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
517     /* FIXME: should do those tests against the real size (according to format tag */
518 
519     /* If no suggestion for destination, then copy source value */
520     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
521 	adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
522     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
523         adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
524 
525     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
526     {
527 	if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
528             adfs->pwfxDst->wBitsPerSample = 4;
529         else
530             adfs->pwfxDst->wBitsPerSample = 16;
531     }
532     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
533     {
534 	if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
535             adfs->pwfxDst->wFormatTag = WAVE_FORMAT_ADPCM;
536         else
537             adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
538     }
539 
540     /* recompute other values */
541     switch (adfs->pwfxDst->wFormatTag)
542     {
543     case WAVE_FORMAT_PCM:
544         adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
545         adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
546         /* check if result is ok */
547         if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
548         break;
549     case WAVE_FORMAT_ADPCM:
550         if (adfs->cbwfxDst < sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET))
551             return ACMERR_NOTPOSSIBLE;
552         init_wfx_adpcm((ADPCMWAVEFORMAT*)adfs->pwfxDst);
553         /* check if result is ok */
554         if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
555         break;
556     default:
557         return ACMERR_NOTPOSSIBLE;
558     }
559 
560     return MMSYSERR_NOERROR;
561 }
562 
563 /***********************************************************************
564  *           ADPCM_Reset
565  *
566  */
567 static	void	ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
568 {
569 }
570 
571 /***********************************************************************
572  *           ADPCM_StreamOpen
573  *
574  */
575 static	LRESULT	ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
576 {
577     AcmAdpcmData*	aad;
578 
579     assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
580 
581     if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
582 	ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
583 	return ACMERR_NOTPOSSIBLE;
584 
585     aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
586     if (aad == 0) return MMSYSERR_NOMEM;
587 
588     adsi->dwDriver = (DWORD_PTR)aad;
589 
590     if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
591 	adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
592     {
593 	goto theEnd;
594     }
595     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
596              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
597     {
598 	/* resampling or mono <=> stereo not available */
599 	if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
600 	    adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels)
601 	    goto theEnd;
602 
603 #if 0
604         {
605             unsigned int nspb = ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
606             FIXME("spb=%u\n", nspb);
607 
608             /* we check that in a block, after the header, samples are present on
609              * 4-sample packet pattern
610              * we also check that the block alignment is bigger than the expected size
611              */
612             if (((nspb - 1) & 3) != 0) goto theEnd;
613             if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
614                 goto theEnd;
615         }
616 #endif
617 
618 	/* adpcm decoding... */
619 	if (adsi->pwfxDst->nChannels == 2)
620 	    aad->convert = cvtSSms16K;
621 	else if (adsi->pwfxDst->nChannels == 1)
622 	    aad->convert = cvtMMms16K;
623     }
624     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
625              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM)
626     {
627 	if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
628 	    adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
629             adsi->pwfxSrc->wBitsPerSample != 16)
630 	    goto theEnd;
631 #if 0
632         nspb = ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
633         FIXME("spb=%u\n", nspb);
634 
635         /* we check that in a block, after the header, samples are present on
636          * 4-sample packet pattern
637          * we also check that the block alignment is bigger than the expected size
638          */
639         if (((nspb - 1) & 3) != 0) goto theEnd;
640         if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
641             goto theEnd;
642 #endif
643 #if 0
644 	/* adpcm coding... */
645 	if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
646 	    aad->convert = cvtSS16msK;
647 	if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
648 	    aad->convert = cvtMM16msK;
649 #endif
650         FIXME("We don't support encoding yet\n");
651         goto theEnd;
652     }
653     else goto theEnd;
654     ADPCM_Reset(adsi, aad);
655 
656     return MMSYSERR_NOERROR;
657 
658  theEnd:
659     HeapFree(GetProcessHeap(), 0, aad);
660     adsi->dwDriver = 0L;
661     return MMSYSERR_NOTSUPPORTED;
662 }
663 
664 /***********************************************************************
665  *           ADPCM_StreamClose
666  *
667  */
668 static	LRESULT	ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
669 {
670     HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
671     return MMSYSERR_NOERROR;
672 }
673 
674 /***********************************************************************
675  *           ADPCM_StreamSize
676  *
677  */
678 static	LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
679 {
680     DWORD nblocks;
681     WORD wSamplesPerBlock;
682     /* wSamplesPerBlock formula comes from MSDN ADPCMWAVEFORMAT page.*/
683     switch (adss->fdwSize)
684     {
685     case ACM_STREAMSIZEF_DESTINATION:
686 	/* cbDstLength => cbSrcLength */
687 	if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
688 	    adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM)
689         {
690 	    wSamplesPerBlock = adsi->pwfxDst->nBlockAlign * 2 / adsi->pwfxDst->nChannels - 12;
691 	    nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign;
692 	    if (nblocks == 0)
693 		return ACMERR_NOTPOSSIBLE;
694 	    adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * wSamplesPerBlock;
695 	}
696         else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
697                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
698         {
699 	    wSamplesPerBlock = adsi->pwfxSrc->nBlockAlign * 2 / adsi->pwfxSrc->nChannels - 12;
700 	    nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * wSamplesPerBlock);
701 	    if (nblocks == 0)
702 		return ACMERR_NOTPOSSIBLE;
703 	    adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
704 	}
705         else
706         {
707 	    return MMSYSERR_NOTSUPPORTED;
708 	}
709 	break;
710     case ACM_STREAMSIZEF_SOURCE:
711 	/* cbSrcLength => cbDstLength */
712 	if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
713 	    adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM)
714         {
715 	    wSamplesPerBlock = adsi->pwfxDst->nBlockAlign * 2 / adsi->pwfxDst->nChannels - 12;
716 	    nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * wSamplesPerBlock);
717 	    if (nblocks == 0)
718 		return ACMERR_NOTPOSSIBLE;
719 	    if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * wSamplesPerBlock))
720 		/* Round block count up. */
721 		nblocks++;
722 	    adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign;
723 	}
724         else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
725                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
726         {
727 	    wSamplesPerBlock = adsi->pwfxSrc->nBlockAlign * 2 / adsi->pwfxSrc->nChannels - 12;
728 	    nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign;
729 	    if (nblocks == 0)
730 		return ACMERR_NOTPOSSIBLE;
731 	    if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
732 		/* Round block count up. */
733 		nblocks++;
734 	    adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * wSamplesPerBlock;
735 	}
736         else
737         {
738 	    return MMSYSERR_NOTSUPPORTED;
739 	}
740 	break;
741     default:
742 	WARN("Unsupported query %08x\n", adss->fdwSize);
743 	return MMSYSERR_NOTSUPPORTED;
744     }
745     return MMSYSERR_NOERROR;
746 }
747 
748 /***********************************************************************
749  *           ADPCM_StreamConvert
750  *
751  */
752 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
753 {
754     AcmAdpcmData*	aad = (AcmAdpcmData*)adsi->dwDriver;
755     DWORD		nsrc = adsh->cbSrcLength;
756     DWORD		ndst = adsh->cbDstLength;
757 
758     if (adsh->fdwConvert &
759 	~(ACM_STREAMCONVERTF_BLOCKALIGN|
760 	  ACM_STREAMCONVERTF_END|
761 	  ACM_STREAMCONVERTF_START))
762     {
763 	FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
764     }
765     /* ACM_STREAMCONVERTF_BLOCKALIGN
766      *	currently all conversions are block aligned, so do nothing for this flag
767      * ACM_STREAMCONVERTF_END
768      *	no pending data, so do nothing for this flag
769      */
770     if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
771     {
772 	ADPCM_Reset(adsi, aad);
773     }
774 
775     aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
776     adsh->cbSrcLengthUsed = nsrc;
777     adsh->cbDstLengthUsed = ndst;
778 
779     return MMSYSERR_NOERROR;
780 }
781 
782 /**************************************************************************
783  * 			ADPCM_DriverProc			[exported]
784  */
785 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
786 					 LPARAM dwParam1, LPARAM dwParam2)
787 {
788     TRACE("(%08lx %p %04x %08lx %08lx);\n",
789           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
790 
791     switch (wMsg)
792     {
793     case DRV_LOAD:		return 1;
794     case DRV_FREE:		return 1;
795     case DRV_OPEN:		return ADPCM_drvOpen((LPSTR)dwParam1);
796     case DRV_CLOSE:		return ADPCM_drvClose(dwDevID);
797     case DRV_ENABLE:		return 1;
798     case DRV_DISABLE:		return 1;
799     case DRV_QUERYCONFIGURE:	return 1;
800     case DRV_CONFIGURE:		MessageBoxA(0, "MSACM MS ADPCM filter !", "Wine Driver", MB_OK); return 1;
801     case DRV_INSTALL:		return DRVCNF_RESTART;
802     case DRV_REMOVE:		return DRVCNF_RESTART;
803 
804     case ACMDM_DRIVER_NOTIFY:
805 	/* no caching from other ACM drivers is done so far */
806 	return MMSYSERR_NOERROR;
807 
808     case ACMDM_DRIVER_DETAILS:
809 	return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
810 
811     case ACMDM_FORMATTAG_DETAILS:
812 	return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
813 
814     case ACMDM_FORMAT_DETAILS:
815 	return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
816 
817     case ACMDM_FORMAT_SUGGEST:
818 	return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
819 
820     case ACMDM_STREAM_OPEN:
821 	return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
822 
823     case ACMDM_STREAM_CLOSE:
824 	return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
825 
826     case ACMDM_STREAM_SIZE:
827 	return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
828 
829     case ACMDM_STREAM_CONVERT:
830 	return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
831 
832     case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
833     case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
834 	/* this converter is not a hardware driver */
835     case ACMDM_FILTERTAG_DETAILS:
836     case ACMDM_FILTER_DETAILS:
837 	/* this converter is not a filter */
838     case ACMDM_STREAM_RESET:
839 	/* only needed for asynchronous driver... we aren't, so just say it */
840 	return MMSYSERR_NOTSUPPORTED;
841     case ACMDM_STREAM_PREPARE:
842     case ACMDM_STREAM_UNPREPARE:
843 	/* nothing special to do here... so don't do anything */
844 	return MMSYSERR_NOERROR;
845 
846     default:
847 	return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
848     }
849 }
850