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