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