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