xref: /reactos/dll/win32/imaadp32.acm/imaadp32.c (revision 5100859e)
1 /*
2  * IMA ADPCM handling
3  *
4  *      Copyright (C) 2001,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_drvClose
42  */
43 static LRESULT ADPCM_drvClose(DWORD_PTR dwDevID)
44 {
45     return 1;
46 }
47 
48 typedef struct tagAcmAdpcmData
49 {
50     void (*convert)(PACMDRVSTREAMINSTANCE adsi,
51 		    const unsigned char*, LPDWORD, unsigned char*, LPDWORD);
52     /* IMA encoding only */
53     BYTE	stepIndexL;
54     BYTE	stepIndexR;
55     /* short	sample; */
56 } AcmAdpcmData;
57 
58 /* table to list all supported formats... those are the basic ones. this
59  * also helps given a unique index to each of the supported formats
60  */
61 typedef	struct
62 {
63     int		nChannels;
64     int		nBits;
65     int		rate;
66 } Format;
67 
68 static const Format PCM_Formats[] =
69 {
70     {1,  8,  8000}, {2,  8,  8000}, {1, 16,  8000}, {2, 16,  8000},
71     {1,  8, 11025}, {2,  8, 11025}, {1, 16, 11025}, {2, 16, 11025},
72     {1,  8, 22050}, {2,  8, 22050}, {1, 16, 22050}, {2, 16, 22050},
73     {1,  8, 44100}, {2,  8, 44100}, {1, 16, 44100}, {2, 16, 44100},
74 };
75 
76 static const Format ADPCM_Formats[] =
77 {
78     {1,  4,  8000}, {2,	4,  8000},  {1,  4, 11025}, {2,	 4, 11025},
79     {1,  4, 22050}, {2,	4, 22050},  {1,  4, 44100}, {2,	 4, 44100},
80 };
81 
82 #define	NUM_PCM_FORMATS		(sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
83 #define	NUM_ADPCM_FORMATS	(sizeof(ADPCM_Formats) / sizeof(ADPCM_Formats[0]))
84 
85 /***********************************************************************
86  *           ADPCM_GetFormatIndex
87  */
88 static	DWORD	ADPCM_GetFormatIndex(const WAVEFORMATEX *wfx)
89 {
90     int             i, hi;
91     const Format*   fmts;
92 
93     switch (wfx->wFormatTag)
94     {
95     case WAVE_FORMAT_PCM:
96 	hi = NUM_PCM_FORMATS;
97 	fmts = PCM_Formats;
98 	break;
99     case WAVE_FORMAT_IMA_ADPCM:
100 	hi = NUM_ADPCM_FORMATS;
101 	fmts = ADPCM_Formats;
102 	break;
103     default:
104 	return 0xFFFFFFFF;
105     }
106 
107     for (i = 0; i < hi; i++)
108     {
109 	if (wfx->nChannels == fmts[i].nChannels &&
110 	    wfx->nSamplesPerSec == fmts[i].rate &&
111 	    wfx->wBitsPerSample == fmts[i].nBits)
112 	    return i;
113     }
114 
115     switch (wfx->wFormatTag)
116     {
117     case WAVE_FORMAT_PCM:
118 	if(3 > wfx->nChannels &&
119 	   wfx->nChannels > 0 &&
120 	   wfx->nAvgBytesPerSec == 2 * wfx->nSamplesPerSec * wfx->nChannels &&
121 	   wfx->nBlockAlign == 2 * wfx->nChannels &&
122 	   wfx->wBitsPerSample == 16)
123 	   return hi;
124 	break;
125     case WAVE_FORMAT_IMA_ADPCM:
126 	if(3 > wfx->nChannels &&
127 	   wfx->nChannels > 0 &&
128 	   wfx->wBitsPerSample == 4 &&
129 	   wfx->cbSize == 2)
130 	   return hi;
131 	break;
132     }
133 
134     return 0xFFFFFFFF;
135 }
136 
137 static void     init_wfx_ima_adpcm(IMAADPCMWAVEFORMAT* awfx/*, DWORD nba*/)
138 {
139     WAVEFORMATEX* pwfx = &awfx->wfx;
140 
141     /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample
142      * have been initialized... */
143 
144     if (pwfx->wFormatTag != WAVE_FORMAT_IMA_ADPCM) {FIXME("wrong FT\n"); return;}
145     if (ADPCM_GetFormatIndex(pwfx) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;}
146 
147     switch (pwfx->nSamplesPerSec)
148     {
149     case  8000: pwfx->nBlockAlign = 256 * pwfx->nChannels;   break;
150     case 11025: pwfx->nBlockAlign = 256 * pwfx->nChannels;   break;
151     case 22050: pwfx->nBlockAlign = 512 * pwfx->nChannels;   break;
152     case 44100: pwfx->nBlockAlign = 1024 * pwfx->nChannels;  break;
153     default: /*pwfx->nBlockAlign = nba;*/  break;
154     }
155     pwfx->cbSize = sizeof(WORD);
156 
157     awfx->wSamplesPerBlock = (pwfx->nBlockAlign - (4 * pwfx->nChannels)) * (2 / pwfx->nChannels) + 1;
158     pwfx->nAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) / awfx->wSamplesPerBlock;
159 }
160 
161 /***********************************************************************
162  *           R16
163  *
164  * Read a 16 bit sample (correctly handles endianness)
165  */
166 static inline short  R16(const unsigned char* src)
167 {
168     return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
169 }
170 
171 /***********************************************************************
172  *           W16
173  *
174  * Write a 16 bit sample (correctly handles endianness)
175  */
176 static inline void  W16(unsigned char* dst, short s)
177 {
178     dst[0] = LOBYTE(s);
179     dst[1] = HIBYTE(s);
180 }
181 
182 /***********************************************************************
183  *           W8
184  *
185  * Write a 8 bit sample
186  */
187 static inline void W8(unsigned char* dst, short s)
188 {
189     dst[0] = (unsigned char)((s + 32768) >> 8);
190 }
191 
192 
193 static inline void W8_16(unsigned char* dst, short s, int bytes)
194 {
195     if(bytes == 1)
196         W8(dst, s);
197     else
198         W16(dst, s);
199 }
200 
201 /* IMA (or DVI) APDCM codec routines */
202 
203 static const unsigned IMA_StepTable[89] =
204 {
205     7, 8, 9, 10, 11, 12, 13, 14,
206     16, 17, 19, 21, 23, 25, 28, 31,
207     34, 37, 41, 45, 50, 55, 60, 66,
208     73, 80, 88, 97, 107, 118, 130, 143,
209     157, 173, 190, 209, 230, 253, 279, 307,
210     337, 371, 408, 449, 494, 544, 598, 658,
211     724, 796, 876, 963, 1060, 1166, 1282, 1411,
212     1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
213     3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
214     7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
215     15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
216     32767
217 };
218 
219 static const int IMA_IndexTable[16] =
220 {
221     -1, -1, -1, -1, 2, 4, 6, 8,
222     -1, -1, -1, -1, 2, 4, 6, 8
223 };
224 
225 static inline void clamp_step_index(int* stepIndex)
226 {
227     if (*stepIndex < 0 ) *stepIndex = 0;
228     if (*stepIndex > 88) *stepIndex = 88;
229 }
230 
231 static inline void clamp_sample(int* sample)
232 {
233     if (*sample < -32768) *sample = -32768;
234     if (*sample >  32767) *sample =  32767;
235 }
236 
237 static inline void process_nibble(unsigned char code, int* stepIndex, int* sample)
238 {
239     unsigned step;
240     int diff;
241 
242     code &= 0x0F;
243 
244     step = IMA_StepTable[*stepIndex];
245     diff = step >> 3;
246     if (code & 1) diff += step >> 2;
247     if (code & 2) diff += step >> 1;
248     if (code & 4) diff += step;
249     if (code & 8)	*sample -= diff;
250     else 		*sample += diff;
251     clamp_sample(sample);
252     *stepIndex += IMA_IndexTable[code];
253     clamp_step_index(stepIndex);
254 }
255 
256 static inline unsigned char generate_nibble(int in, int* stepIndex, int* sample)
257 {
258     int effdiff, diff = in - *sample;
259     unsigned step;
260     unsigned char code;
261 
262     if (diff < 0)
263     {
264         diff = -diff;
265         code = 8;
266     }
267     else
268     {
269         code = 0;
270     }
271 
272     step = IMA_StepTable[*stepIndex];
273     effdiff = (step >> 3);
274     if (diff >= step)
275     {
276         code |= 4;
277         diff -= step;
278         effdiff += step;
279     }
280     step >>= 1;
281     if (diff >= step)
282     {
283         code |= 2;
284         diff -= step;
285         effdiff += step;
286     }
287     step >>= 1;
288     if (diff >= step)
289     {
290         code |= 1;
291         effdiff += step;
292     }
293     if (code & 8)       *sample -= effdiff;
294     else                *sample += effdiff;
295     clamp_sample(sample);
296     *stepIndex += IMA_IndexTable[code];
297     clamp_step_index(stepIndex);
298     return code;
299 }
300 
301 static	void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi,
302                          const unsigned char* src, LPDWORD nsrc,
303                          unsigned char* dst, LPDWORD ndst)
304 {
305     int         i;
306     int         sampleL, sampleR;
307     int		stepIndexL, stepIndexR;
308     int		nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
309     int		nsamp;
310     /* compute the number of entire blocks we can decode...
311      * it's the min of the number of entire blocks in source buffer and the number
312      * of entire blocks in destination buffer
313      */
314     DWORD	nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
315                              *ndst / (nsamp_blk * 2 * 2));
316 
317     *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
318     *ndst = nblock * (nsamp_blk * 2 * 2);
319 
320     nsamp_blk--; /* remove the sample in block header */
321     for (; nblock > 0; nblock--)
322     {
323         const unsigned char* in_src = src;
324 
325 	/* handle headers first */
326 	sampleL = R16(src);
327 	stepIndexL = (unsigned)*(src + 2);
328         clamp_step_index(&stepIndexL);
329 	src += 4;
330 	W16(dst, sampleL);	dst += 2;
331 
332 	sampleR = R16(src);
333 	stepIndexR = (unsigned)*(src + 2);
334         clamp_step_index(&stepIndexR);
335 	src += 4;
336 	W16(dst, sampleR);	dst += 2;
337 
338 	for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
339         {
340             for (i = 0; i < 4; i++)
341             {
342                 process_nibble(*src, &stepIndexL, &sampleL);
343                 W16(dst + (2 * i + 0) * 4 + 0, sampleL);
344                 process_nibble(*src++ >> 4, &stepIndexL, &sampleL);
345                 W16(dst + (2 * i + 1) * 4 + 0, sampleL);
346             }
347             for (i = 0; i < 4; i++)
348             {
349                 process_nibble(*src , &stepIndexR, &sampleR);
350                 W16(dst + (2 * i + 0) * 4 + 2, sampleR);
351                 process_nibble(*src++ >>4, &stepIndexR, &sampleR);
352                 W16(dst + (2 * i + 1) * 4 + 2, sampleR);
353             }
354             dst += 32;
355         }
356         /* we have now to realign the source pointer on block */
357         src = in_src + adsi->pwfxSrc->nBlockAlign;
358     }
359 }
360 
361 static void cvtMMimaK(PACMDRVSTREAMINSTANCE adsi,
362                     const unsigned char* src, LPDWORD nsrc,
363                     unsigned char* dst, LPDWORD ndst)
364 {
365     int sample;
366     int stepIndex;
367     int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
368     int nsamp;
369     int bytesPerSample = adsi->pwfxDst->wBitsPerSample / 8;
370     /* compute the number of entire blocks we can decode...
371      * it's the min of the number of entire blocks in source buffer and the number
372      * of entire blocks in destination buffer
373      */
374     DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign, *ndst / (nsamp_blk * bytesPerSample));
375 
376     *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
377     *ndst = nblock * nsamp_blk * bytesPerSample;
378 
379     nsamp_blk--; /* remove the sample in block header */
380     for (; nblock > 0; nblock--)
381     {
382         const unsigned char* in_src = src;
383 
384         /* handle header first */
385         sample = R16(src);
386         stepIndex = (unsigned)*(src + 2);
387         clamp_step_index(&stepIndex);
388         src += 4;
389         W8_16(dst, sample, bytesPerSample); dst += bytesPerSample;
390 
391         for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
392         {
393             process_nibble(*src, &stepIndex, &sample);
394             W8_16(dst, sample, bytesPerSample); dst += bytesPerSample;
395             process_nibble(*src++ >> 4, &stepIndex, &sample);
396             W8_16(dst, sample, bytesPerSample); dst += bytesPerSample;
397         }
398         /* we have now to realign the source pointer on block */
399         src = in_src + adsi->pwfxSrc->nBlockAlign;
400     }
401 }
402 
403 static	void cvtSS16imaK(PACMDRVSTREAMINSTANCE adsi,
404                          const unsigned char* src, LPDWORD nsrc,
405                          unsigned char* dst, LPDWORD ndst)
406 {
407     int		stepIndexL, stepIndexR;
408     int		sampleL, sampleR;
409     BYTE 	code1, code2;
410     int		nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
411     int		i, nsamp;
412     /* compute the number of entire blocks we can decode...
413      * it's the min of the number of entire blocks in source buffer and the number
414      * of entire blocks in destination buffer
415      */
416     DWORD	nblock = min(*nsrc / (nsamp_blk * 2 * 2),
417                              *ndst / adsi->pwfxDst->nBlockAlign);
418 
419     *nsrc = nblock * (nsamp_blk * 2 * 2);
420     *ndst = nblock * adsi->pwfxDst->nBlockAlign;
421 
422     stepIndexL = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
423     stepIndexR = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR;
424 
425     nsamp_blk--; /* so that we won't count the sample in header while filling the block */
426 
427     for (; nblock > 0; nblock--)
428     {
429         unsigned char*   in_dst = dst;
430 
431         /* generate header */
432     	sampleL = R16(src);  src += 2;
433 	W16(dst, sampleL); dst += 2;
434 	W16(dst, stepIndexL); dst += 2;
435 
436     	sampleR = R16(src); src += 2;
437 	W16(dst, sampleR); dst += 2;
438 	W16(dst, stepIndexR); dst += 2;
439 
440 	for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
441         {
442             for (i = 0; i < 4; i++)
443             {
444                 code1 = generate_nibble(R16(src + (4 * i + 0) * 2),
445                                         &stepIndexL, &sampleL);
446                 code2 = generate_nibble(R16(src + (4 * i + 2) * 2),
447                                         &stepIndexL, &sampleL);
448                 *dst++ = (code2 << 4) | code1;
449             }
450             for (i = 0; i < 4; i++)
451             {
452                 code1 = generate_nibble(R16(src + (4 * i + 1) * 2),
453                                         &stepIndexR, &sampleR);
454                 code2 = generate_nibble(R16(src + (4 * i + 3) * 2),
455                                         &stepIndexR, &sampleR);
456                 *dst++ = (code2 << 4) | code1;
457             }
458             src += 32;
459 	}
460 	dst = in_dst + adsi->pwfxDst->nBlockAlign;
461     }
462     ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndexL;
463     ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR = stepIndexR;
464 }
465 
466 static	void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi,
467                          const unsigned char* src, LPDWORD nsrc,
468                          unsigned char* dst, LPDWORD ndst)
469 {
470     int		stepIndex;
471     int		sample;
472     BYTE 	code1, code2;
473     int		nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
474     int		nsamp;
475     /* compute the number of entire blocks we can decode...
476      * it's the min of the number of entire blocks in source buffer and the number
477      * of entire blocks in destination buffer
478      */
479     DWORD	nblock = min(*nsrc / (nsamp_blk * 2),
480                              *ndst / adsi->pwfxDst->nBlockAlign);
481 
482     *nsrc = nblock * (nsamp_blk * 2);
483     *ndst = nblock * adsi->pwfxDst->nBlockAlign;
484 
485     stepIndex = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
486     nsamp_blk--; /* so that we won't count the sample in header while filling the block */
487 
488     for (; nblock > 0; nblock--)
489     {
490         unsigned char*   in_dst = dst;
491 
492         /* generate header */
493         /* FIXME: what about the last effective sample from previous block ??? */
494         /* perhaps something like:
495          *      sample += R16(src);
496          *      clamp_sample(sample);
497          * and with :
498          *      + saving the sample in adsi->dwDriver when all blocks are done
499          +      + reset should set the field in adsi->dwDriver to 0 too
500          */
501     	sample = R16(src); src += 2;
502 	W16(dst, sample); dst += 2;
503 	*dst = (unsigned char)(unsigned)stepIndex;
504 	dst += 2;
505 
506 	for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
507         {
508             code1 = generate_nibble(R16(src), &stepIndex, &sample);
509             src += 2;
510             code2 = generate_nibble(R16(src), &stepIndex, &sample);
511             src += 2;
512             *dst++ = (code2 << 4) | code1;
513 	}
514 	dst = in_dst + adsi->pwfxDst->nBlockAlign;
515     }
516     ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndex;
517 }
518 
519 /***********************************************************************
520  *           ADPCM_DriverDetails
521  *
522  */
523 static	LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
524 {
525     add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
526     add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
527     add->wMid = MM_MICROSOFT;
528     add->wPid = MM_MSFT_ACM_IMAADPCM;
529     add->vdwACM = 0x3320000;
530     add->vdwDriver = 0x04000000;
531     add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
532     add->cFormatTags = 2; /* PCM, IMA ADPCM */
533     add->cFilterTags = 0;
534     add->hicon = NULL;
535     MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM", -1,
536                          add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
537     MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM CODEC", -1,
538                          add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
539     MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
540                          add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
541     MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
542                          add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
543     add->szFeatures[0] = 0;
544 
545     return MMSYSERR_NOERROR;
546 }
547 
548 /***********************************************************************
549  *           ADPCM_FormatTagDetails
550  *
551  */
552 static	LRESULT	ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
553 {
554     static const WCHAR szPcm[]={'P','C','M',0};
555     static const WCHAR szImaAdPcm[]={'I','M','A',' ','A','D','P','C','M',0};
556 
557     switch (dwQuery)
558     {
559     case ACM_FORMATTAGDETAILSF_INDEX:
560 	if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
561 	break;
562     case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
563 	if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
564         {
565             aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
566 	    break;
567 	}
568 	/* fall through */
569     case ACM_FORMATTAGDETAILSF_FORMATTAG:
570 	switch (aftd->dwFormatTag)
571         {
572 	case WAVE_FORMAT_PCM:		aftd->dwFormatTagIndex = 0; break;
573 	case WAVE_FORMAT_IMA_ADPCM:     aftd->dwFormatTagIndex = 1; break;
574 	default:			return ACMERR_NOTPOSSIBLE;
575 	}
576 	break;
577     default:
578 	WARN("Unsupported query %08x\n", dwQuery);
579 	return MMSYSERR_NOTSUPPORTED;
580     }
581 
582     aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
583     switch (aftd->dwFormatTagIndex)
584     {
585     case 0:
586 	aftd->dwFormatTag = WAVE_FORMAT_PCM;
587 	aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
588 	aftd->cStandardFormats = NUM_PCM_FORMATS;
589         lstrcpyW(aftd->szFormatTag, szPcm);
590         break;
591     case 1:
592 	aftd->dwFormatTag = WAVE_FORMAT_IMA_ADPCM;
593 	aftd->cbFormatSize = sizeof(IMAADPCMWAVEFORMAT);
594 	aftd->cStandardFormats = NUM_ADPCM_FORMATS;
595         lstrcpyW(aftd->szFormatTag, szImaAdPcm);
596 	break;
597     }
598     return MMSYSERR_NOERROR;
599 }
600 
601 /***********************************************************************
602  *           ADPCM_FormatDetails
603  *
604  */
605 static	LRESULT	ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
606 {
607     switch (dwQuery)
608     {
609     case ACM_FORMATDETAILSF_FORMAT:
610 	if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
611 	break;
612     case ACM_FORMATDETAILSF_INDEX:
613 	afd->pwfx->wFormatTag = afd->dwFormatTag;
614 	switch (afd->dwFormatTag)
615         {
616 	case WAVE_FORMAT_PCM:
617 	    if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
618 	    afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
619 	    afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
620 	    afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
621 	    /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
622 	     * afd->pwfx->cbSize = 0;
623 	     */
624 	    afd->pwfx->nBlockAlign =
625 		(afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
626 	    afd->pwfx->nAvgBytesPerSec =
627 		afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
628 	    break;
629 	case WAVE_FORMAT_IMA_ADPCM:
630 	    if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE;
631 	    afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
632 	    afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
633 	    afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
634 	    init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT *)afd->pwfx);
635 	    break;
636 	default:
637             WARN("Unsupported tag %08x\n", afd->dwFormatTag);
638 	    return MMSYSERR_INVALPARAM;
639 	}
640 	break;
641     default:
642 	WARN("Unsupported query %08x\n", dwQuery);
643 	return MMSYSERR_NOTSUPPORTED;
644     }
645     afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
646     afd->szFormat[0] = 0; /* let MSACM format this for us... */
647 
648     return MMSYSERR_NOERROR;
649 }
650 
651 /***********************************************************************
652  *           ADPCM_FormatSuggest
653  *
654  */
655 static	LRESULT	ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
656 {
657     /* some tests ... */
658     if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
659 	adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
660 	adfs->pwfxSrc->wFormatTag == adfs->pwfxDst->wFormatTag ||
661 	ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
662 
663     /* If no suggestion for destination, then copy source value */
664     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
665 	adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
666     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
667         adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
668 
669     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
670     {
671 	if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
672             adfs->pwfxDst->wBitsPerSample = 4;
673         else
674             adfs->pwfxDst->wBitsPerSample = 16;
675     }
676     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
677     {
678 	if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
679             adfs->pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
680         else
681             adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
682     }
683 
684     /* recompute other values */
685     switch (adfs->pwfxDst->wFormatTag)
686     {
687     case WAVE_FORMAT_PCM:
688         if (adfs->cbwfxSrc < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
689         adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
690         adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
691         /* check if result is ok */
692         if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
693         break;
694     case WAVE_FORMAT_IMA_ADPCM:
695         if (adfs->cbwfxDst < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
696         init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT*)adfs->pwfxDst);
697         /* FIXME: not handling header overhead */
698         TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock);
699         /* check if result is ok */
700         if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
701         break;
702     default:
703         return ACMERR_NOTPOSSIBLE;
704     }
705 
706     return MMSYSERR_NOERROR;
707 }
708 
709 /***********************************************************************
710  *           ADPCM_Reset
711  *
712  */
713 static	void	ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
714 {
715     aad->stepIndexL = aad->stepIndexR = 0;
716 }
717 
718 /***********************************************************************
719  *           ADPCM_StreamOpen
720  *
721  */
722 static	LRESULT	ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
723 {
724     AcmAdpcmData*	aad;
725     unsigned            nspb;
726 
727     assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
728 
729     if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
730 	ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
731 	return ACMERR_NOTPOSSIBLE;
732 
733     aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
734     if (aad == 0) return MMSYSERR_NOMEM;
735 
736     adsi->dwDriver = (DWORD_PTR)aad;
737 
738     if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
739 	adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
740     {
741 	goto theEnd;
742     }
743     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
744              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
745     {
746         /* resampling or mono <=> stereo not available
747          * ADPCM algo only define 16 bit per sample output
748          * (The API seems to still allow 8 bit per sample output)
749          */
750         if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
751             adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
752             (adsi->pwfxDst->wBitsPerSample != 16 && adsi->pwfxDst->wBitsPerSample != 8))
753             goto theEnd;
754 
755         nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
756         TRACE("spb=%u\n", nspb);
757 
758         /* we check that in a block, after the header, samples are present on
759          * 4-sample packet pattern
760          * we also check that the block alignment is bigger than the expected size
761          */
762         if (((nspb - 1) & 3) != 0) goto theEnd;
763         if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
764             goto theEnd;
765 
766         /* adpcm decoding... */
767         if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
768             aad->convert = cvtSSima16K;
769         if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
770             aad->convert = cvtMMimaK;
771         if (adsi->pwfxDst->wBitsPerSample == 8 && adsi->pwfxDst->nChannels == 1)
772             aad->convert = cvtMMimaK;
773         /* FIXME: Stereo support for 8bit samples*/
774         if (adsi->pwfxDst->wBitsPerSample == 8 && adsi->pwfxDst->nChannels == 2)
775             goto theEnd;
776     }
777     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
778              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
779     {
780 	if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
781 	    adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
782             adsi->pwfxSrc->wBitsPerSample != 16)
783 	    goto theEnd;
784 
785         nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
786         TRACE("spb=%u\n", nspb);
787 
788         /* we check that in a block, after the header, samples are present on
789          * 4-sample packet pattern
790          * we also check that the block alignment is bigger than the expected size
791          */
792         if (((nspb - 1) & 3) != 0) goto theEnd;
793         if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
794             goto theEnd;
795 
796 	/* adpcm coding... */
797 	if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
798 	    aad->convert = cvtSS16imaK;
799 	if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
800 	    aad->convert = cvtMM16imaK;
801     }
802     else goto theEnd;
803     ADPCM_Reset(adsi, aad);
804 
805     return MMSYSERR_NOERROR;
806 
807  theEnd:
808     HeapFree(GetProcessHeap(), 0, aad);
809     adsi->dwDriver = 0L;
810     return MMSYSERR_NOTSUPPORTED;
811 }
812 
813 /***********************************************************************
814  *           ADPCM_StreamClose
815  *
816  */
817 static	LRESULT	ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
818 {
819     HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
820     return MMSYSERR_NOERROR;
821 }
822 
823 /***********************************************************************
824  *           ADPCM_StreamSize
825  *
826  */
827 static	LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
828 {
829     DWORD nblocks;
830 
831     switch (adss->fdwSize)
832     {
833     case ACM_STREAMSIZEF_DESTINATION:
834 	/* cbDstLength => cbSrcLength */
835 	if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
836 	    adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
837         {
838             nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign;
839             if (nblocks == 0)
840                 return ACMERR_NOTPOSSIBLE;
841             adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
842 	}
843         else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
844                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
845         {
846             nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock);
847             if (nblocks == 0)
848                 return ACMERR_NOTPOSSIBLE;
849             adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
850 	}
851         else
852         {
853 	    return MMSYSERR_NOTSUPPORTED;
854 	}
855 	break;
856     case ACM_STREAMSIZEF_SOURCE:
857 	/* cbSrcLength => cbDstLength */
858 	if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
859 	    adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
860         {
861             nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock);
862             if (nblocks == 0)
863                 return ACMERR_NOTPOSSIBLE;
864             if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock))
865                 /* Round block count up. */
866                 nblocks++;
867             adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign;
868 	}
869         else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
870                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
871         {
872             nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign;
873             if (nblocks == 0)
874                 return ACMERR_NOTPOSSIBLE;
875             if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
876                 /* Round block count up. */
877                 nblocks++;
878             adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
879 	}
880         else
881         {
882 	    return MMSYSERR_NOTSUPPORTED;
883 	}
884 	break;
885     default:
886 	WARN("Unsupported query %08x\n", adss->fdwSize);
887 	return MMSYSERR_NOTSUPPORTED;
888     }
889     return MMSYSERR_NOERROR;
890 }
891 
892 /***********************************************************************
893  *           ADPCM_StreamConvert
894  *
895  */
896 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
897 {
898     AcmAdpcmData*	aad = (AcmAdpcmData*)adsi->dwDriver;
899     DWORD		nsrc = adsh->cbSrcLength;
900     DWORD		ndst = adsh->cbDstLength;
901 
902     if (adsh->fdwConvert &
903 	~(ACM_STREAMCONVERTF_BLOCKALIGN|
904 	  ACM_STREAMCONVERTF_END|
905 	  ACM_STREAMCONVERTF_START))
906     {
907 	FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
908     }
909     /* ACM_STREAMCONVERTF_BLOCKALIGN
910      *	currently all conversions are block aligned, so do nothing for this flag
911      * ACM_STREAMCONVERTF_END
912      *	no pending data, so do nothing for this flag
913      */
914     if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
915     {
916 	ADPCM_Reset(adsi, aad);
917     }
918 
919     aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
920     adsh->cbSrcLengthUsed = nsrc;
921     adsh->cbDstLengthUsed = ndst;
922 
923     return MMSYSERR_NOERROR;
924 }
925 
926 /**************************************************************************
927  * 			ADPCM_DriverProc			[exported]
928  */
929 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
930 					 LPARAM dwParam1, LPARAM dwParam2)
931 {
932     TRACE("(%08lx %p %04x %08lx %08lx);\n",
933 	  dwDevID, hDriv, wMsg, dwParam1, dwParam2);
934 
935     switch (wMsg)
936     {
937     case DRV_LOAD:		return 1;
938     case DRV_FREE:		return 1;
939     case DRV_OPEN:		return 1;
940     case DRV_CLOSE:		return ADPCM_drvClose(dwDevID);
941     case DRV_ENABLE:		return 1;
942     case DRV_DISABLE:		return 1;
943     case DRV_QUERYCONFIGURE:	return 1;
944     case DRV_CONFIGURE:		MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK); return 1;
945     case DRV_INSTALL:		return DRVCNF_RESTART;
946     case DRV_REMOVE:		return DRVCNF_RESTART;
947 
948     case ACMDM_DRIVER_NOTIFY:
949 	/* no caching from other ACM drivers is done so far */
950 	return MMSYSERR_NOERROR;
951 
952     case ACMDM_DRIVER_DETAILS:
953 	return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
954 
955     case ACMDM_FORMATTAG_DETAILS:
956 	return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
957 
958     case ACMDM_FORMAT_DETAILS:
959 	return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
960 
961     case ACMDM_FORMAT_SUGGEST:
962 	return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
963 
964     case ACMDM_STREAM_OPEN:
965 	return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
966 
967     case ACMDM_STREAM_CLOSE:
968 	return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
969 
970     case ACMDM_STREAM_SIZE:
971 	return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
972 
973     case ACMDM_STREAM_CONVERT:
974 	return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
975 
976     case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
977     case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
978 	/* this converter is not a hardware driver */
979     case ACMDM_FILTERTAG_DETAILS:
980     case ACMDM_FILTER_DETAILS:
981 	/* this converter is not a filter */
982     case ACMDM_STREAM_RESET:
983 	/* only needed for asynchronous driver... we aren't, so just say it */
984 	return MMSYSERR_NOTSUPPORTED;
985     case ACMDM_STREAM_PREPARE:
986     case ACMDM_STREAM_UNPREPARE:
987 	/* nothing special to do here... so don't do anything */
988 	return MMSYSERR_NOERROR;
989 
990     default:
991 	return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
992     }
993 }
994