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