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