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