4 * Copyright (C) 2001,2002 Eric Pouech
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.
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.
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
34 #include "wine/debug.h"
36 /* see http://www.pcisys.net/~melanson/codecs/adpcm.txt for the details */
38 WINE_DEFAULT_DEBUG_CHANNEL(adpcm
);
40 /***********************************************************************
43 static LRESULT
ADPCM_drvClose(DWORD_PTR dwDevID
)
48 typedef struct tagAcmAdpcmData
50 void (*convert
)(PACMDRVSTREAMINSTANCE adsi
,
51 const unsigned char*, LPDWORD
, unsigned char*, LPDWORD
);
52 /* IMA encoding only */
58 /* table to list all supported formats... those are the basic ones. this
59 * also helps given a unique index to each of the supported formats
68 static const Format PCM_Formats
[] =
70 {1, 8, 8000}, {2, 8, 8000}, {1, 16, 8000}, {2, 16, 8000},
71 {1, 8, 11025}, {2, 8, 11025}, {1, 16, 11025}, {2, 16, 11025},
72 {1, 8, 22050}, {2, 8, 22050}, {1, 16, 22050}, {2, 16, 22050},
73 {1, 8, 44100}, {2, 8, 44100}, {1, 16, 44100}, {2, 16, 44100},
76 static const Format ADPCM_Formats
[] =
78 {1, 4, 8000}, {2, 4, 8000}, {1, 4, 11025}, {2, 4, 11025},
79 {1, 4, 22050}, {2, 4, 22050}, {1, 4, 44100}, {2, 4, 44100},
82 #define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
83 #define NUM_ADPCM_FORMATS (sizeof(ADPCM_Formats) / sizeof(ADPCM_Formats[0]))
85 /***********************************************************************
86 * ADPCM_GetFormatIndex
88 static DWORD
ADPCM_GetFormatIndex(const WAVEFORMATEX
*wfx
)
93 switch (wfx
->wFormatTag
)
99 case WAVE_FORMAT_IMA_ADPCM
:
100 hi
= NUM_ADPCM_FORMATS
;
101 fmts
= ADPCM_Formats
;
107 for (i
= 0; i
< hi
; i
++)
109 if (wfx
->nChannels
== fmts
[i
].nChannels
&&
110 wfx
->nSamplesPerSec
== fmts
[i
].rate
&&
111 wfx
->wBitsPerSample
== fmts
[i
].nBits
)
115 switch (wfx
->wFormatTag
)
117 case WAVE_FORMAT_PCM
:
118 if(3 > wfx
->nChannels
&&
119 wfx
->nChannels
> 0 &&
120 wfx
->nAvgBytesPerSec
== 2 * wfx
->nSamplesPerSec
* wfx
->nChannels
&&
121 wfx
->nBlockAlign
== 2 * wfx
->nChannels
&&
122 wfx
->wBitsPerSample
== 16)
125 case WAVE_FORMAT_IMA_ADPCM
:
126 if(3 > wfx
->nChannels
&&
127 wfx
->nChannels
> 0 &&
128 wfx
->wBitsPerSample
== 4 &&
137 static void init_wfx_ima_adpcm(IMAADPCMWAVEFORMAT
* awfx
/*, DWORD nba*/)
139 WAVEFORMATEX
* pwfx
= &awfx
->wfx
;
141 /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample
142 * have been initialized... */
144 if (pwfx
->wFormatTag
!= WAVE_FORMAT_IMA_ADPCM
) {FIXME("wrong FT\n"); return;}
145 if (ADPCM_GetFormatIndex(pwfx
) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;}
147 switch (pwfx
->nSamplesPerSec
)
149 case 8000: pwfx
->nBlockAlign
= 256 * pwfx
->nChannels
; break;
150 case 11025: pwfx
->nBlockAlign
= 256 * pwfx
->nChannels
; break;
151 case 22050: pwfx
->nBlockAlign
= 512 * pwfx
->nChannels
; break;
152 case 44100: pwfx
->nBlockAlign
= 1024 * pwfx
->nChannels
; break;
153 default: /*pwfx->nBlockAlign = nba;*/ break;
155 pwfx
->cbSize
= sizeof(WORD
);
157 awfx
->wSamplesPerBlock
= (pwfx
->nBlockAlign
- (4 * pwfx
->nChannels
)) * (2 / pwfx
->nChannels
) + 1;
158 pwfx
->nAvgBytesPerSec
= (pwfx
->nSamplesPerSec
* pwfx
->nBlockAlign
) / awfx
->wSamplesPerBlock
;
161 /***********************************************************************
164 * Read a 16 bit sample (correctly handles endianness)
166 static inline short R16(const unsigned char* src
)
168 return (short)((unsigned short)src
[0] | ((unsigned short)src
[1] << 8));
171 /***********************************************************************
174 * Write a 16 bit sample (correctly handles endianness)
176 static inline void W16(unsigned char* dst
, short s
)
182 /***********************************************************************
185 * Write a 8 bit sample
187 static inline void W8(unsigned char* dst
, short s
)
189 dst
[0] = (unsigned char)((s
+ 32768) >> 8);
193 static inline void W8_16(unsigned char* dst
, short s
, int bytes
)
201 /* IMA (or DVI) APDCM codec routines */
203 static const unsigned IMA_StepTable
[89] =
205 7, 8, 9, 10, 11, 12, 13, 14,
206 16, 17, 19, 21, 23, 25, 28, 31,
207 34, 37, 41, 45, 50, 55, 60, 66,
208 73, 80, 88, 97, 107, 118, 130, 143,
209 157, 173, 190, 209, 230, 253, 279, 307,
210 337, 371, 408, 449, 494, 544, 598, 658,
211 724, 796, 876, 963, 1060, 1166, 1282, 1411,
212 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
213 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
214 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
215 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
219 static const int IMA_IndexTable
[16] =
221 -1, -1, -1, -1, 2, 4, 6, 8,
222 -1, -1, -1, -1, 2, 4, 6, 8
225 static inline void clamp_step_index(int* stepIndex
)
227 if (*stepIndex
< 0 ) *stepIndex
= 0;
228 if (*stepIndex
> 88) *stepIndex
= 88;
231 static inline void clamp_sample(int* sample
)
233 if (*sample
< -32768) *sample
= -32768;
234 if (*sample
> 32767) *sample
= 32767;
237 static inline void process_nibble(unsigned char code
, int* stepIndex
, int* sample
)
244 step
= IMA_StepTable
[*stepIndex
];
246 if (code
& 1) diff
+= step
>> 2;
247 if (code
& 2) diff
+= step
>> 1;
248 if (code
& 4) diff
+= step
;
249 if (code
& 8) *sample
-= diff
;
250 else *sample
+= diff
;
251 clamp_sample(sample
);
252 *stepIndex
+= IMA_IndexTable
[code
];
253 clamp_step_index(stepIndex
);
256 static inline unsigned char generate_nibble(int in
, int* stepIndex
, int* sample
)
258 int effdiff
, diff
= in
- *sample
;
272 step
= IMA_StepTable
[*stepIndex
];
273 effdiff
= (step
>> 3);
293 if (code
& 8) *sample
-= effdiff
;
294 else *sample
+= effdiff
;
295 clamp_sample(sample
);
296 *stepIndex
+= IMA_IndexTable
[code
];
297 clamp_step_index(stepIndex
);
301 static void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi
,
302 const unsigned char* src
, LPDWORD nsrc
,
303 unsigned char* dst
, LPDWORD ndst
)
306 int sampleL
, sampleR
;
307 int stepIndexL
, stepIndexR
;
308 int nsamp_blk
= ((LPIMAADPCMWAVEFORMAT
)adsi
->pwfxSrc
)->wSamplesPerBlock
;
310 /* compute the number of entire blocks we can decode...
311 * it's the min of the number of entire blocks in source buffer and the number
312 * of entire blocks in destination buffer
314 DWORD nblock
= min(*nsrc
/ adsi
->pwfxSrc
->nBlockAlign
,
315 *ndst
/ (nsamp_blk
* 2 * 2));
317 *nsrc
= nblock
* adsi
->pwfxSrc
->nBlockAlign
;
318 *ndst
= nblock
* (nsamp_blk
* 2 * 2);
320 nsamp_blk
--; /* remove the sample in block header */
321 for (; nblock
> 0; nblock
--)
323 const unsigned char* in_src
= src
;
325 /* handle headers first */
327 stepIndexL
= (unsigned)*(src
+ 2);
328 clamp_step_index(&stepIndexL
);
330 W16(dst
, sampleL
); dst
+= 2;
333 stepIndexR
= (unsigned)*(src
+ 2);
334 clamp_step_index(&stepIndexR
);
336 W16(dst
, sampleR
); dst
+= 2;
338 for (nsamp
= nsamp_blk
; nsamp
> 0; nsamp
-= 8)
340 for (i
= 0; i
< 4; i
++)
342 process_nibble(*src
, &stepIndexL
, &sampleL
);
343 W16(dst
+ (2 * i
+ 0) * 4 + 0, sampleL
);
344 process_nibble(*src
++ >> 4, &stepIndexL
, &sampleL
);
345 W16(dst
+ (2 * i
+ 1) * 4 + 0, sampleL
);
347 for (i
= 0; i
< 4; i
++)
349 process_nibble(*src
, &stepIndexR
, &sampleR
);
350 W16(dst
+ (2 * i
+ 0) * 4 + 2, sampleR
);
351 process_nibble(*src
++ >>4, &stepIndexR
, &sampleR
);
352 W16(dst
+ (2 * i
+ 1) * 4 + 2, sampleR
);
356 /* we have now to realign the source pointer on block */
357 src
= in_src
+ adsi
->pwfxSrc
->nBlockAlign
;
361 static void cvtMMimaK(PACMDRVSTREAMINSTANCE adsi
,
362 const unsigned char* src
, LPDWORD nsrc
,
363 unsigned char* dst
, LPDWORD ndst
)
367 int nsamp_blk
= ((LPIMAADPCMWAVEFORMAT
)adsi
->pwfxSrc
)->wSamplesPerBlock
;
369 int bytesPerSample
= adsi
->pwfxDst
->wBitsPerSample
/ 8;
370 /* compute the number of entire blocks we can decode...
371 * it's the min of the number of entire blocks in source buffer and the number
372 * of entire blocks in destination buffer
374 DWORD nblock
= min(*nsrc
/ adsi
->pwfxSrc
->nBlockAlign
, *ndst
/ (nsamp_blk
* bytesPerSample
));
376 *nsrc
= nblock
* adsi
->pwfxSrc
->nBlockAlign
;
377 *ndst
= nblock
* nsamp_blk
* bytesPerSample
;
379 nsamp_blk
--; /* remove the sample in block header */
380 for (; nblock
> 0; nblock
--)
382 const unsigned char* in_src
= src
;
384 /* handle header first */
386 stepIndex
= (unsigned)*(src
+ 2);
387 clamp_step_index(&stepIndex
);
389 W8_16(dst
, sample
, bytesPerSample
); dst
+= bytesPerSample
;
391 for (nsamp
= nsamp_blk
; nsamp
> 0; nsamp
-= 2)
393 process_nibble(*src
, &stepIndex
, &sample
);
394 W8_16(dst
, sample
, bytesPerSample
); dst
+= bytesPerSample
;
395 process_nibble(*src
++ >> 4, &stepIndex
, &sample
);
396 W8_16(dst
, sample
, bytesPerSample
); dst
+= bytesPerSample
;
398 /* we have now to realign the source pointer on block */
399 src
= in_src
+ adsi
->pwfxSrc
->nBlockAlign
;
403 static void cvtSS16imaK(PACMDRVSTREAMINSTANCE adsi
,
404 const unsigned char* src
, LPDWORD nsrc
,
405 unsigned char* dst
, LPDWORD ndst
)
407 int stepIndexL
, stepIndexR
;
408 int sampleL
, sampleR
;
410 int nsamp_blk
= ((LPIMAADPCMWAVEFORMAT
)adsi
->pwfxDst
)->wSamplesPerBlock
;
412 /* compute the number of entire blocks we can decode...
413 * it's the min of the number of entire blocks in source buffer and the number
414 * of entire blocks in destination buffer
416 DWORD nblock
= min(*nsrc
/ (nsamp_blk
* 2 * 2),
417 *ndst
/ adsi
->pwfxDst
->nBlockAlign
);
419 *nsrc
= nblock
* (nsamp_blk
* 2 * 2);
420 *ndst
= nblock
* adsi
->pwfxDst
->nBlockAlign
;
422 stepIndexL
= ((AcmAdpcmData
*)adsi
->dwDriver
)->stepIndexL
;
423 stepIndexR
= ((AcmAdpcmData
*)adsi
->dwDriver
)->stepIndexR
;
425 nsamp_blk
--; /* so that we won't count the sample in header while filling the block */
427 for (; nblock
> 0; nblock
--)
429 unsigned char* in_dst
= dst
;
431 /* generate header */
432 sampleL
= R16(src
); src
+= 2;
433 W16(dst
, sampleL
); dst
+= 2;
434 W16(dst
, stepIndexL
); dst
+= 2;
436 sampleR
= R16(src
); src
+= 2;
437 W16(dst
, sampleR
); dst
+= 2;
438 W16(dst
, stepIndexR
); dst
+= 2;
440 for (nsamp
= nsamp_blk
; nsamp
> 0; nsamp
-= 8)
442 for (i
= 0; i
< 4; i
++)
444 code1
= generate_nibble(R16(src
+ (4 * i
+ 0) * 2),
445 &stepIndexL
, &sampleL
);
446 code2
= generate_nibble(R16(src
+ (4 * i
+ 2) * 2),
447 &stepIndexL
, &sampleL
);
448 *dst
++ = (code2
<< 4) | code1
;
450 for (i
= 0; i
< 4; i
++)
452 code1
= generate_nibble(R16(src
+ (4 * i
+ 1) * 2),
453 &stepIndexR
, &sampleR
);
454 code2
= generate_nibble(R16(src
+ (4 * i
+ 3) * 2),
455 &stepIndexR
, &sampleR
);
456 *dst
++ = (code2
<< 4) | code1
;
460 dst
= in_dst
+ adsi
->pwfxDst
->nBlockAlign
;
462 ((AcmAdpcmData
*)adsi
->dwDriver
)->stepIndexL
= stepIndexL
;
463 ((AcmAdpcmData
*)adsi
->dwDriver
)->stepIndexR
= stepIndexR
;
466 static void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi
,
467 const unsigned char* src
, LPDWORD nsrc
,
468 unsigned char* dst
, LPDWORD ndst
)
473 int nsamp_blk
= ((LPIMAADPCMWAVEFORMAT
)adsi
->pwfxDst
)->wSamplesPerBlock
;
475 /* compute the number of entire blocks we can decode...
476 * it's the min of the number of entire blocks in source buffer and the number
477 * of entire blocks in destination buffer
479 DWORD nblock
= min(*nsrc
/ (nsamp_blk
* 2),
480 *ndst
/ adsi
->pwfxDst
->nBlockAlign
);
482 *nsrc
= nblock
* (nsamp_blk
* 2);
483 *ndst
= nblock
* adsi
->pwfxDst
->nBlockAlign
;
485 stepIndex
= ((AcmAdpcmData
*)adsi
->dwDriver
)->stepIndexL
;
486 nsamp_blk
--; /* so that we won't count the sample in header while filling the block */
488 for (; nblock
> 0; nblock
--)
490 unsigned char* in_dst
= dst
;
492 /* generate header */
493 /* FIXME: what about the last effective sample from previous block ??? */
494 /* perhaps something like:
495 * sample += R16(src);
496 * clamp_sample(sample);
498 * + saving the sample in adsi->dwDriver when all blocks are done
499 + + reset should set the field in adsi->dwDriver to 0 too
501 sample
= R16(src
); src
+= 2;
502 W16(dst
, sample
); dst
+= 2;
503 *dst
= (unsigned char)(unsigned)stepIndex
;
506 for (nsamp
= nsamp_blk
; nsamp
> 0; nsamp
-= 2)
508 code1
= generate_nibble(R16(src
), &stepIndex
, &sample
);
510 code2
= generate_nibble(R16(src
), &stepIndex
, &sample
);
512 *dst
++ = (code2
<< 4) | code1
;
514 dst
= in_dst
+ adsi
->pwfxDst
->nBlockAlign
;
516 ((AcmAdpcmData
*)adsi
->dwDriver
)->stepIndexL
= stepIndex
;
519 /***********************************************************************
520 * ADPCM_DriverDetails
523 static LRESULT
ADPCM_DriverDetails(PACMDRIVERDETAILSW add
)
525 add
->fccType
= ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC
;
526 add
->fccComp
= ACMDRIVERDETAILS_FCCCOMP_UNDEFINED
;
527 add
->wMid
= MM_MICROSOFT
;
528 add
->wPid
= MM_MSFT_ACM_IMAADPCM
;
529 add
->vdwACM
= 0x3320000;
530 add
->vdwDriver
= 0x04000000;
531 add
->fdwSupport
= ACMDRIVERDETAILS_SUPPORTF_CODEC
;
532 add
->cFormatTags
= 2; /* PCM, IMA ADPCM */
533 add
->cFilterTags
= 0;
535 MultiByteToWideChar( CP_ACP
, 0, "Microsoft IMA ADPCM", -1,
536 add
->szShortName
, sizeof(add
->szShortName
)/sizeof(WCHAR
) );
537 MultiByteToWideChar( CP_ACP
, 0, "Microsoft IMA ADPCM CODEC", -1,
538 add
->szLongName
, sizeof(add
->szLongName
)/sizeof(WCHAR
) );
539 MultiByteToWideChar( CP_ACP
, 0, "Brought to you by the Wine team...", -1,
540 add
->szCopyright
, sizeof(add
->szCopyright
)/sizeof(WCHAR
) );
541 MultiByteToWideChar( CP_ACP
, 0, "Refer to LICENSE file", -1,
542 add
->szLicensing
, sizeof(add
->szLicensing
)/sizeof(WCHAR
) );
543 add
->szFeatures
[0] = 0;
545 return MMSYSERR_NOERROR
;
548 /***********************************************************************
549 * ADPCM_FormatTagDetails
552 static LRESULT
ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd
, DWORD dwQuery
)
554 static const WCHAR szPcm
[]={'P','C','M',0};
555 static const WCHAR szImaAdPcm
[]={'I','M','A',' ','A','D','P','C','M',0};
559 case ACM_FORMATTAGDETAILSF_INDEX
:
560 if (aftd
->dwFormatTagIndex
>= 2) return ACMERR_NOTPOSSIBLE
;
562 case ACM_FORMATTAGDETAILSF_LARGESTSIZE
:
563 if (aftd
->dwFormatTag
== WAVE_FORMAT_UNKNOWN
)
565 aftd
->dwFormatTagIndex
= 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
569 case ACM_FORMATTAGDETAILSF_FORMATTAG
:
570 switch (aftd
->dwFormatTag
)
572 case WAVE_FORMAT_PCM
: aftd
->dwFormatTagIndex
= 0; break;
573 case WAVE_FORMAT_IMA_ADPCM
: aftd
->dwFormatTagIndex
= 1; break;
574 default: return ACMERR_NOTPOSSIBLE
;
578 WARN("Unsupported query %08x\n", dwQuery
);
579 return MMSYSERR_NOTSUPPORTED
;
582 aftd
->fdwSupport
= ACMDRIVERDETAILS_SUPPORTF_CODEC
;
583 switch (aftd
->dwFormatTagIndex
)
586 aftd
->dwFormatTag
= WAVE_FORMAT_PCM
;
587 aftd
->cbFormatSize
= sizeof(PCMWAVEFORMAT
);
588 aftd
->cStandardFormats
= NUM_PCM_FORMATS
;
589 lstrcpyW(aftd
->szFormatTag
, szPcm
);
592 aftd
->dwFormatTag
= WAVE_FORMAT_IMA_ADPCM
;
593 aftd
->cbFormatSize
= sizeof(IMAADPCMWAVEFORMAT
);
594 aftd
->cStandardFormats
= NUM_ADPCM_FORMATS
;
595 lstrcpyW(aftd
->szFormatTag
, szImaAdPcm
);
598 return MMSYSERR_NOERROR
;
601 /***********************************************************************
602 * ADPCM_FormatDetails
605 static LRESULT
ADPCM_FormatDetails(PACMFORMATDETAILSW afd
, DWORD dwQuery
)
609 case ACM_FORMATDETAILSF_FORMAT
:
610 if (ADPCM_GetFormatIndex(afd
->pwfx
) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE
;
612 case ACM_FORMATDETAILSF_INDEX
:
613 afd
->pwfx
->wFormatTag
= afd
->dwFormatTag
;
614 switch (afd
->dwFormatTag
)
616 case WAVE_FORMAT_PCM
:
617 if (afd
->dwFormatIndex
>= NUM_PCM_FORMATS
) return ACMERR_NOTPOSSIBLE
;
618 afd
->pwfx
->nChannels
= PCM_Formats
[afd
->dwFormatIndex
].nChannels
;
619 afd
->pwfx
->nSamplesPerSec
= PCM_Formats
[afd
->dwFormatIndex
].rate
;
620 afd
->pwfx
->wBitsPerSample
= PCM_Formats
[afd
->dwFormatIndex
].nBits
;
621 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
622 * afd->pwfx->cbSize = 0;
624 afd
->pwfx
->nBlockAlign
=
625 (afd
->pwfx
->nChannels
* afd
->pwfx
->wBitsPerSample
) / 8;
626 afd
->pwfx
->nAvgBytesPerSec
=
627 afd
->pwfx
->nSamplesPerSec
* afd
->pwfx
->nBlockAlign
;
629 case WAVE_FORMAT_IMA_ADPCM
:
630 if (afd
->dwFormatIndex
>= NUM_ADPCM_FORMATS
) return ACMERR_NOTPOSSIBLE
;
631 afd
->pwfx
->nChannels
= ADPCM_Formats
[afd
->dwFormatIndex
].nChannels
;
632 afd
->pwfx
->nSamplesPerSec
= ADPCM_Formats
[afd
->dwFormatIndex
].rate
;
633 afd
->pwfx
->wBitsPerSample
= ADPCM_Formats
[afd
->dwFormatIndex
].nBits
;
634 init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT
*)afd
->pwfx
);
637 WARN("Unsupported tag %08x\n", afd
->dwFormatTag
);
638 return MMSYSERR_INVALPARAM
;
642 WARN("Unsupported query %08x\n", dwQuery
);
643 return MMSYSERR_NOTSUPPORTED
;
645 afd
->fdwSupport
= ACMDRIVERDETAILS_SUPPORTF_CODEC
;
646 afd
->szFormat
[0] = 0; /* let MSACM format this for us... */
648 return MMSYSERR_NOERROR
;
651 /***********************************************************************
652 * ADPCM_FormatSuggest
655 static LRESULT
ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs
)
658 if (adfs
->cbwfxSrc
< sizeof(PCMWAVEFORMAT
) ||
659 adfs
->cbwfxDst
< sizeof(PCMWAVEFORMAT
) ||
660 adfs
->pwfxSrc
->wFormatTag
== adfs
->pwfxDst
->wFormatTag
||
661 ADPCM_GetFormatIndex(adfs
->pwfxSrc
) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE
;
663 /* If no suggestion for destination, then copy source value */
664 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_NCHANNELS
))
665 adfs
->pwfxDst
->nChannels
= adfs
->pwfxSrc
->nChannels
;
666 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_NSAMPLESPERSEC
))
667 adfs
->pwfxDst
->nSamplesPerSec
= adfs
->pwfxSrc
->nSamplesPerSec
;
669 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_WBITSPERSAMPLE
))
671 if (adfs
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
)
672 adfs
->pwfxDst
->wBitsPerSample
= 4;
674 adfs
->pwfxDst
->wBitsPerSample
= 16;
676 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_WFORMATTAG
))
678 if (adfs
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
)
679 adfs
->pwfxDst
->wFormatTag
= WAVE_FORMAT_IMA_ADPCM
;
681 adfs
->pwfxDst
->wFormatTag
= WAVE_FORMAT_PCM
;
684 /* recompute other values */
685 switch (adfs
->pwfxDst
->wFormatTag
)
687 case WAVE_FORMAT_PCM
:
688 if (adfs
->cbwfxSrc
< sizeof(IMAADPCMWAVEFORMAT
)) return ACMERR_NOTPOSSIBLE
;
689 adfs
->pwfxDst
->nBlockAlign
= (adfs
->pwfxDst
->nChannels
* adfs
->pwfxDst
->wBitsPerSample
) / 8;
690 adfs
->pwfxDst
->nAvgBytesPerSec
= adfs
->pwfxDst
->nSamplesPerSec
* adfs
->pwfxDst
->nBlockAlign
;
691 /* check if result is ok */
692 if (ADPCM_GetFormatIndex(adfs
->pwfxDst
) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE
;
694 case WAVE_FORMAT_IMA_ADPCM
:
695 if (adfs
->cbwfxDst
< sizeof(IMAADPCMWAVEFORMAT
)) return ACMERR_NOTPOSSIBLE
;
696 init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT
*)adfs
->pwfxDst
);
697 /* FIXME: not handling header overhead */
698 TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT
*)adfs
->pwfxDst
)->wSamplesPerBlock
);
699 /* check if result is ok */
700 if (ADPCM_GetFormatIndex(adfs
->pwfxDst
) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE
;
703 return ACMERR_NOTPOSSIBLE
;
706 return MMSYSERR_NOERROR
;
709 /***********************************************************************
713 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi
, AcmAdpcmData
* aad
)
715 aad
->stepIndexL
= aad
->stepIndexR
= 0;
718 /***********************************************************************
722 static LRESULT
ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi
)
727 assert(!(adsi
->fdwOpen
& ACM_STREAMOPENF_ASYNC
));
729 if (ADPCM_GetFormatIndex(adsi
->pwfxSrc
) == 0xFFFFFFFF ||
730 ADPCM_GetFormatIndex(adsi
->pwfxDst
) == 0xFFFFFFFF)
731 return ACMERR_NOTPOSSIBLE
;
733 aad
= HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData
));
734 if (aad
== 0) return MMSYSERR_NOMEM
;
736 adsi
->dwDriver
= (DWORD_PTR
)aad
;
738 if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
&&
739 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
)
743 else if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_IMA_ADPCM
&&
744 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
)
746 /* resampling or mono <=> stereo not available
747 * ADPCM algo only define 16 bit per sample output
748 * (The API seems to still allow 8 bit per sample output)
750 if (adsi
->pwfxSrc
->nSamplesPerSec
!= adsi
->pwfxDst
->nSamplesPerSec
||
751 adsi
->pwfxSrc
->nChannels
!= adsi
->pwfxDst
->nChannels
||
752 (adsi
->pwfxDst
->wBitsPerSample
!= 16 && adsi
->pwfxDst
->wBitsPerSample
!= 8))
755 nspb
= ((LPIMAADPCMWAVEFORMAT
)adsi
->pwfxSrc
)->wSamplesPerBlock
;
756 TRACE("spb=%u\n", nspb
);
758 /* we check that in a block, after the header, samples are present on
759 * 4-sample packet pattern
760 * we also check that the block alignment is bigger than the expected size
762 if (((nspb
- 1) & 3) != 0) goto theEnd
;
763 if ((((nspb
- 1) / 2) + 4) * adsi
->pwfxSrc
->nChannels
< adsi
->pwfxSrc
->nBlockAlign
)
766 /* adpcm decoding... */
767 if (adsi
->pwfxDst
->wBitsPerSample
== 16 && adsi
->pwfxDst
->nChannels
== 2)
768 aad
->convert
= cvtSSima16K
;
769 if (adsi
->pwfxDst
->wBitsPerSample
== 16 && adsi
->pwfxDst
->nChannels
== 1)
770 aad
->convert
= cvtMMimaK
;
771 if (adsi
->pwfxDst
->wBitsPerSample
== 8 && adsi
->pwfxDst
->nChannels
== 1)
772 aad
->convert
= cvtMMimaK
;
773 /* FIXME: Stereo support for 8bit samples*/
774 if (adsi
->pwfxDst
->wBitsPerSample
== 8 && adsi
->pwfxDst
->nChannels
== 2)
777 else if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
&&
778 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_IMA_ADPCM
)
780 if (adsi
->pwfxSrc
->nSamplesPerSec
!= adsi
->pwfxDst
->nSamplesPerSec
||
781 adsi
->pwfxSrc
->nChannels
!= adsi
->pwfxDst
->nChannels
||
782 adsi
->pwfxSrc
->wBitsPerSample
!= 16)
785 nspb
= ((LPIMAADPCMWAVEFORMAT
)adsi
->pwfxDst
)->wSamplesPerBlock
;
786 TRACE("spb=%u\n", nspb
);
788 /* we check that in a block, after the header, samples are present on
789 * 4-sample packet pattern
790 * we also check that the block alignment is bigger than the expected size
792 if (((nspb
- 1) & 3) != 0) goto theEnd
;
793 if ((((nspb
- 1) / 2) + 4) * adsi
->pwfxDst
->nChannels
< adsi
->pwfxDst
->nBlockAlign
)
796 /* adpcm coding... */
797 if (adsi
->pwfxSrc
->wBitsPerSample
== 16 && adsi
->pwfxSrc
->nChannels
== 2)
798 aad
->convert
= cvtSS16imaK
;
799 if (adsi
->pwfxSrc
->wBitsPerSample
== 16 && adsi
->pwfxSrc
->nChannels
== 1)
800 aad
->convert
= cvtMM16imaK
;
803 ADPCM_Reset(adsi
, aad
);
805 return MMSYSERR_NOERROR
;
808 HeapFree(GetProcessHeap(), 0, aad
);
810 return MMSYSERR_NOTSUPPORTED
;
813 /***********************************************************************
817 static LRESULT
ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi
)
819 HeapFree(GetProcessHeap(), 0, (void*)adsi
->dwDriver
);
820 return MMSYSERR_NOERROR
;
823 /***********************************************************************
827 static LRESULT
ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE
*adsi
, PACMDRVSTREAMSIZE adss
)
831 switch (adss
->fdwSize
)
833 case ACM_STREAMSIZEF_DESTINATION
:
834 /* cbDstLength => cbSrcLength */
835 if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
&&
836 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_IMA_ADPCM
)
838 nblocks
= adss
->cbDstLength
/ adsi
->pwfxDst
->nBlockAlign
;
840 return ACMERR_NOTPOSSIBLE
;
841 adss
->cbSrcLength
= nblocks
* adsi
->pwfxSrc
->nBlockAlign
* ((IMAADPCMWAVEFORMAT
*)adsi
->pwfxDst
)->wSamplesPerBlock
;
843 else if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_IMA_ADPCM
&&
844 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
)
846 nblocks
= adss
->cbDstLength
/ (adsi
->pwfxDst
->nBlockAlign
* ((IMAADPCMWAVEFORMAT
*)adsi
->pwfxSrc
)->wSamplesPerBlock
);
848 return ACMERR_NOTPOSSIBLE
;
849 adss
->cbSrcLength
= nblocks
* adsi
->pwfxSrc
->nBlockAlign
;
853 return MMSYSERR_NOTSUPPORTED
;
856 case ACM_STREAMSIZEF_SOURCE
:
857 /* cbSrcLength => cbDstLength */
858 if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
&&
859 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_IMA_ADPCM
)
861 nblocks
= adss
->cbSrcLength
/ (adsi
->pwfxSrc
->nBlockAlign
* ((IMAADPCMWAVEFORMAT
*)adsi
->pwfxDst
)->wSamplesPerBlock
);
863 return ACMERR_NOTPOSSIBLE
;
864 if (adss
->cbSrcLength
% (adsi
->pwfxSrc
->nBlockAlign
* ((IMAADPCMWAVEFORMAT
*)adsi
->pwfxDst
)->wSamplesPerBlock
))
865 /* Round block count up. */
867 adss
->cbDstLength
= nblocks
* adsi
->pwfxDst
->nBlockAlign
;
869 else if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_IMA_ADPCM
&&
870 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
)
872 nblocks
= adss
->cbSrcLength
/ adsi
->pwfxSrc
->nBlockAlign
;
874 return ACMERR_NOTPOSSIBLE
;
875 if (adss
->cbSrcLength
% adsi
->pwfxSrc
->nBlockAlign
)
876 /* Round block count up. */
878 adss
->cbDstLength
= nblocks
* adsi
->pwfxDst
->nBlockAlign
* ((IMAADPCMWAVEFORMAT
*)adsi
->pwfxSrc
)->wSamplesPerBlock
;
882 return MMSYSERR_NOTSUPPORTED
;
886 WARN("Unsupported query %08x\n", adss
->fdwSize
);
887 return MMSYSERR_NOTSUPPORTED
;
889 return MMSYSERR_NOERROR
;
892 /***********************************************************************
893 * ADPCM_StreamConvert
896 static LRESULT
ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi
, PACMDRVSTREAMHEADER adsh
)
898 AcmAdpcmData
* aad
= (AcmAdpcmData
*)adsi
->dwDriver
;
899 DWORD nsrc
= adsh
->cbSrcLength
;
900 DWORD ndst
= adsh
->cbDstLength
;
902 if (adsh
->fdwConvert
&
903 ~(ACM_STREAMCONVERTF_BLOCKALIGN
|
904 ACM_STREAMCONVERTF_END
|
905 ACM_STREAMCONVERTF_START
))
907 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh
->fdwConvert
);
909 /* ACM_STREAMCONVERTF_BLOCKALIGN
910 * currently all conversions are block aligned, so do nothing for this flag
911 * ACM_STREAMCONVERTF_END
912 * no pending data, so do nothing for this flag
914 if ((adsh
->fdwConvert
& ACM_STREAMCONVERTF_START
))
916 ADPCM_Reset(adsi
, aad
);
919 aad
->convert(adsi
, adsh
->pbSrc
, &nsrc
, adsh
->pbDst
, &ndst
);
920 adsh
->cbSrcLengthUsed
= nsrc
;
921 adsh
->cbDstLengthUsed
= ndst
;
923 return MMSYSERR_NOERROR
;
926 /**************************************************************************
927 * ADPCM_DriverProc [exported]
929 LRESULT CALLBACK
ADPCM_DriverProc(DWORD_PTR dwDevID
, HDRVR hDriv
, UINT wMsg
,
930 LPARAM dwParam1
, LPARAM dwParam2
)
932 TRACE("(%08lx %p %04x %08lx %08lx);\n",
933 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
937 case DRV_LOAD
: return 1;
938 case DRV_FREE
: return 1;
939 case DRV_OPEN
: return 1;
940 case DRV_CLOSE
: return ADPCM_drvClose(dwDevID
);
941 case DRV_ENABLE
: return 1;
942 case DRV_DISABLE
: return 1;
943 case DRV_QUERYCONFIGURE
: return 1;
944 case DRV_CONFIGURE
: MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK
); return 1;
945 case DRV_INSTALL
: return DRVCNF_RESTART
;
946 case DRV_REMOVE
: return DRVCNF_RESTART
;
948 case ACMDM_DRIVER_NOTIFY
:
949 /* no caching from other ACM drivers is done so far */
950 return MMSYSERR_NOERROR
;
952 case ACMDM_DRIVER_DETAILS
:
953 return ADPCM_DriverDetails((PACMDRIVERDETAILSW
)dwParam1
);
955 case ACMDM_FORMATTAG_DETAILS
:
956 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW
)dwParam1
, dwParam2
);
958 case ACMDM_FORMAT_DETAILS
:
959 return ADPCM_FormatDetails((PACMFORMATDETAILSW
)dwParam1
, dwParam2
);
961 case ACMDM_FORMAT_SUGGEST
:
962 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST
)dwParam1
);
964 case ACMDM_STREAM_OPEN
:
965 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE
)dwParam1
);
967 case ACMDM_STREAM_CLOSE
:
968 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE
)dwParam1
);
970 case ACMDM_STREAM_SIZE
:
971 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE
)dwParam1
, (PACMDRVSTREAMSIZE
)dwParam2
);
973 case ACMDM_STREAM_CONVERT
:
974 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE
)dwParam1
, (PACMDRVSTREAMHEADER
)dwParam2
);
976 case ACMDM_HARDWARE_WAVE_CAPS_INPUT
:
977 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT
:
978 /* this converter is not a hardware driver */
979 case ACMDM_FILTERTAG_DETAILS
:
980 case ACMDM_FILTER_DETAILS
:
981 /* this converter is not a filter */
982 case ACMDM_STREAM_RESET
:
983 /* only needed for asynchronous driver... we aren't, so just say it */
984 return MMSYSERR_NOTSUPPORTED
;
985 case ACMDM_STREAM_PREPARE
:
986 case ACMDM_STREAM_UNPREPARE
:
987 /* nothing special to do here... so don't do anything */
988 return MMSYSERR_NOERROR
;
991 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);