1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
4 * ADPCM handling (includes both MS and IMA forms)
6 * Copyright (C) 2001 Eric Pouech
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.
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.
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
32 #include "../msacmdrv.h"
33 #include "wine/debug.h"
35 /* see http://www.pcisys.net/~melanson/codecs/adpcm.txt for the details */
37 WINE_DEFAULT_DEBUG_CHANNEL(adpcm
);
39 /***********************************************************************
42 static DWORD
ADPCM_drvOpen(LPCSTR str
)
47 /***********************************************************************
50 static DWORD
ADPCM_drvClose(DWORD dwDevID
)
55 typedef struct tagAcmAdpcmData
57 void (*convert
)(PACMDRVSTREAMINSTANCE adsi
,
58 const unsigned char*, LPDWORD
, unsigned char*, LPDWORD
);
59 /* IMA encoding only */
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
75 static Format PCM_Formats
[] =
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},
83 static Format ADPCM_Formats
[] =
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},
89 #define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
90 #define NUM_ADPCM_FORMATS (sizeof(ADPCM_Formats) / sizeof(ADPCM_Formats[0]))
92 /***********************************************************************
93 * ADPCM_GetFormatIndex
95 static DWORD
ADPCM_GetFormatIndex(LPWAVEFORMATEX wfx
)
100 switch (wfx
->wFormatTag
)
102 case WAVE_FORMAT_PCM
:
103 hi
= NUM_PCM_FORMATS
;
106 case WAVE_FORMAT_IMA_ADPCM
:
107 hi
= NUM_ADPCM_FORMATS
;
108 fmts
= ADPCM_Formats
;
114 for (i
= 0; i
< hi
; i
++)
116 if (wfx
->nChannels
== fmts
[i
].nChannels
&&
117 wfx
->nSamplesPerSec
== fmts
[i
].rate
&&
118 wfx
->wBitsPerSample
== fmts
[i
].nBits
)
125 /***********************************************************************
128 * Read a 16 bit sample (correctly handles endianess)
130 static inline short R16(const unsigned char* src
)
132 return (short)((unsigned short)src
[0] | ((unsigned short)src
[1] << 8));
135 /***********************************************************************
138 * Write a 16 bit sample (correctly handles endianess)
140 static inline void W16(unsigned char* dst
, short s
)
146 /* IMA (or DVI) APDCM codec routines */
148 static const unsigned IMA_StepTable
[89] =
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,
164 static const int IMA_IndexTable
[16] =
166 -1, -1, -1, -1, 2, 4, 6, 8,
167 -1, -1, -1, -1, 2, 4, 6, 8
170 static inline void clamp_step_index(int* stepIndex
)
172 if (*stepIndex
< 0 ) *stepIndex
= 0;
173 if (*stepIndex
> 88) *stepIndex
= 88;
176 static inline void clamp_sample(int* sample
)
178 if (*sample
< -32768) *sample
= -32768;
179 if (*sample
> 32767) *sample
= 32767;
182 static inline void process_nibble(unsigned char code
, int* stepIndex
, int* sample
)
189 step
= IMA_StepTable
[*stepIndex
];
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
);
201 static inline unsigned char generate_nibble(int in
, int* stepIndex
, int* sample
)
203 int effdiff
, diff
= in
- *sample
;
217 step
= IMA_StepTable
[*stepIndex
];
218 effdiff
= (step
>> 3);
238 if (code
& 8) *sample
-= effdiff
;
239 else *sample
+= effdiff
;
240 clamp_sample(sample
);
241 *stepIndex
+= IMA_IndexTable
[code
];
242 clamp_step_index(stepIndex
);
246 static void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi
,
247 const unsigned char* src
, LPDWORD nsrc
,
248 unsigned char* dst
, LPDWORD ndst
)
251 int sampleL
, sampleR
;
252 int stepIndexL
, stepIndexR
;
253 int nsamp_blk
= ((LPIMAADPCMWAVEFORMAT
)adsi
->pwfxSrc
)->wSamplesPerBlock
;
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
259 DWORD nblock
= min(*nsrc
/ adsi
->pwfxSrc
->nBlockAlign
,
260 *ndst
/ (nsamp_blk
* 2 * 2));
262 *nsrc
= nblock
* adsi
->pwfxSrc
->nBlockAlign
;
263 *ndst
= nblock
* (nsamp_blk
* 2 * 2);
265 nsamp_blk
--; /* remove the sample in block header */
266 for (; nblock
> 0; nblock
--)
268 const unsigned char* in_src
= src
;
270 /* handle headers first */
272 stepIndexL
= (unsigned)*(src
+ 2);
273 clamp_step_index(&stepIndexL
);
275 W16(dst
, sampleL
); dst
+= 2;
278 stepIndexR
= (unsigned)*(src
+ 2);
279 clamp_step_index(&stepIndexR
);
281 W16(dst
, sampleR
); dst
+= 2;
283 for (nsamp
= nsamp_blk
; nsamp
> 0; nsamp
-= 8)
285 for (i
= 0; i
< 4; i
++)
287 process_nibble(*src
>> 4, &stepIndexL
, &sampleL
);
288 W16(dst
+ (2 * i
+ 0) * 4 + 0, sampleL
);
289 process_nibble(*src
++, &stepIndexL
, &sampleL
);
290 W16(dst
+ (2 * i
+ 1) * 4 + 0, sampleL
);
292 for (i
= 0; i
< 4; i
++)
294 process_nibble(*src
>> 4, &stepIndexR
, &sampleR
);
295 W16(dst
+ (2 * i
+ 0) * 4 + 2, sampleR
);
296 process_nibble(*src
++, &stepIndexR
, &sampleR
);
297 W16(dst
+ (2 * i
+ 1) * 4 + 2, sampleR
);
301 /* we have now to realign the source pointer on block */
302 src
= in_src
+ adsi
->pwfxSrc
->nBlockAlign
;
306 static void cvtMMima16K(PACMDRVSTREAMINSTANCE adsi
,
307 const unsigned char* src
, LPDWORD nsrc
,
308 unsigned char* dst
, LPDWORD ndst
)
312 int nsamp_blk
= ((LPIMAADPCMWAVEFORMAT
)adsi
->pwfxSrc
)->wSamplesPerBlock
;
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
318 DWORD nblock
= min(*nsrc
/ adsi
->pwfxSrc
->nBlockAlign
,
319 *ndst
/ (nsamp_blk
* 2));
321 *nsrc
= nblock
* adsi
->pwfxSrc
->nBlockAlign
;
322 *ndst
= nblock
* nsamp_blk
* 2;
324 nsamp_blk
--; /* remove the sample in block header */
325 for (; nblock
> 0; nblock
--)
327 const unsigned char* in_src
= src
;
329 /* handle header first */
331 stepIndex
= (unsigned)*(src
+ 2);
332 clamp_step_index(&stepIndex
);
334 W16(dst
, sample
); dst
+= 2;
336 for (nsamp
= nsamp_blk
; nsamp
> 0; nsamp
-= 2)
338 process_nibble(*src
>> 4, &stepIndex
, &sample
);
339 W16(dst
, sample
); dst
+= 2;
340 process_nibble(*src
++, &stepIndex
, &sample
);
341 W16(dst
, sample
); dst
+= 2;
343 /* we have now to realign the source pointer on block */
344 src
= in_src
+ adsi
->pwfxSrc
->nBlockAlign
;
348 static void cvtSS16imaK(PACMDRVSTREAMINSTANCE adsi
,
349 const unsigned char* src
, LPDWORD nsrc
,
350 unsigned char* dst
, LPDWORD ndst
)
352 int stepIndexL
, stepIndexR
;
353 int sampleL
, sampleR
;
355 int nsamp_blk
= ((LPIMAADPCMWAVEFORMAT
)adsi
->pwfxDst
)->wSamplesPerBlock
;
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
361 DWORD nblock
= min(*nsrc
/ (nsamp_blk
* 2 * 2),
362 *ndst
/ adsi
->pwfxDst
->nBlockAlign
);
364 *nsrc
= nblock
* (nsamp_blk
* 2 * 2);
365 *ndst
= nblock
* adsi
->pwfxDst
->nBlockAlign
;
367 stepIndexL
= ((AcmAdpcmData
*)adsi
->dwDriver
)->stepIndexL
;
368 stepIndexR
= ((AcmAdpcmData
*)adsi
->dwDriver
)->stepIndexR
;
370 nsamp_blk
--; /* so that we won't count the sample in header while filling the block */
372 for (; nblock
> 0; nblock
--)
376 /* generate header */
377 sampleL
= R16(src
); src
+= 2;
378 W16(dst
, sampleL
); dst
+= 2;
379 *dst
= (unsigned char)(unsigned)stepIndexL
;
382 sampleR
= R16(src
); src
+= 2;
383 W16(dst
, sampleR
); dst
+= 2;
384 *dst
= (unsigned char)(unsigned)stepIndexR
;
387 for (nsamp
= nsamp_blk
; nsamp
> 0; nsamp
-= 8)
389 for (i
= 0; i
< 4; i
++)
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
;
397 for (i
= 0; i
< 4; i
++)
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
;
407 dst
= in_dst
+ adsi
->pwfxDst
->nBlockAlign
;
409 ((AcmAdpcmData
*)adsi
->dwDriver
)->stepIndexL
= stepIndexL
;
410 ((AcmAdpcmData
*)adsi
->dwDriver
)->stepIndexR
= stepIndexR
;
413 static void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi
,
414 const unsigned char* src
, LPDWORD nsrc
,
415 unsigned char* dst
, LPDWORD ndst
)
420 int nsamp_blk
= ((LPIMAADPCMWAVEFORMAT
)adsi
->pwfxDst
)->wSamplesPerBlock
;
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
426 DWORD nblock
= min(*nsrc
/ (nsamp_blk
* 2),
427 *ndst
/ adsi
->pwfxDst
->nBlockAlign
);
429 *nsrc
= nblock
* (nsamp_blk
* 2);
430 *ndst
= nblock
* adsi
->pwfxDst
->nBlockAlign
;
432 stepIndex
= ((AcmAdpcmData
*)adsi
->dwDriver
)->stepIndexL
;
433 nsamp_blk
--; /* so that we won't count the sample in header while filling the block */
435 for (; nblock
> 0; nblock
--)
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);
445 * + saving the sample in adsi->dwDriver when all blocks are done
446 + + reset should set the field in adsi->dwDriver to 0 too
448 sample
= R16(src
); src
+= 2;
449 W16(dst
, sample
); dst
+= 2;
450 *dst
= (unsigned char)(unsigned)stepIndex
;
453 for (nsamp
= nsamp_blk
; nsamp
> 0; nsamp
-= 2)
455 code1
= generate_nibble(R16(src
), &stepIndex
, &sample
);
457 code2
= generate_nibble(R16(src
), &stepIndex
, &sample
);
459 *dst
++ = (code1
<< 4) | code2
;
461 dst
= in_dst
+ adsi
->pwfxDst
->nBlockAlign
;
463 ((AcmAdpcmData
*)adsi
->dwDriver
)->stepIndexL
= stepIndex
;
466 /***********************************************************************
467 * ADPCM_DriverDetails
470 static LRESULT
ADPCM_DriverDetails(PACMDRIVERDETAILSW add
)
472 add
->fccType
= ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC
;
473 add
->fccComp
= ACMDRIVERDETAILS_FCCCOMP_UNDEFINED
;
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;
492 return MMSYSERR_NOERROR
;
495 /***********************************************************************
496 * ADPCM_FormatTagDetails
499 static LRESULT
ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd
, DWORD dwQuery
)
501 static WCHAR szPcm
[]={'P','C','M',0};
502 static WCHAR szImaAdPcm
[]={'I','M','A',' ','A','d','P','C','M',0};
506 case ACM_FORMATTAGDETAILSF_INDEX
:
507 if (aftd
->dwFormatTagIndex
>= 2) return ACMERR_NOTPOSSIBLE
;
509 case ACM_FORMATTAGDETAILSF_LARGESTSIZE
:
510 if (aftd
->dwFormatTag
== WAVE_FORMAT_UNKNOWN
)
512 aftd
->dwFormatTagIndex
= 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
516 case ACM_FORMATTAGDETAILSF_FORMATTAG
:
517 switch (aftd
->dwFormatTag
)
519 case WAVE_FORMAT_PCM
: aftd
->dwFormatTagIndex
= 0; break;
520 case WAVE_FORMAT_IMA_ADPCM
: aftd
->dwFormatTagIndex
= 1; break;
521 default: return ACMERR_NOTPOSSIBLE
;
525 WARN("Unsupported query %08lx\n", dwQuery
);
526 return MMSYSERR_NOTSUPPORTED
;
529 aftd
->fdwSupport
= ACMDRIVERDETAILS_SUPPORTF_CODEC
;
530 switch (aftd
->dwFormatTagIndex
)
533 aftd
->dwFormatTag
= WAVE_FORMAT_PCM
;
534 aftd
->cbFormatSize
= sizeof(PCMWAVEFORMAT
);
535 aftd
->cStandardFormats
= NUM_PCM_FORMATS
;
536 lstrcpyW(aftd
->szFormatTag
, szPcm
);
539 aftd
->dwFormatTag
= WAVE_FORMAT_IMA_ADPCM
;
540 aftd
->cbFormatSize
= sizeof(IMAADPCMWAVEFORMAT
);
541 aftd
->cStandardFormats
= NUM_ADPCM_FORMATS
;
542 lstrcpyW(aftd
->szFormatTag
, szImaAdPcm
);
545 return MMSYSERR_NOERROR
;
548 /***********************************************************************
549 * ADPCM_FormatDetails
552 static LRESULT
ADPCM_FormatDetails(PACMFORMATDETAILSW afd
, DWORD dwQuery
)
556 case ACM_FORMATDETAILSF_FORMAT
:
557 if (ADPCM_GetFormatIndex(afd
->pwfx
) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE
;
559 case ACM_FORMATDETAILSF_INDEX
:
560 afd
->pwfx
->wFormatTag
= afd
->dwFormatTag
;
561 switch (afd
->dwFormatTag
)
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;
571 afd
->pwfx
->nBlockAlign
=
572 (afd
->pwfx
->nChannels
* afd
->pwfx
->wBitsPerSample
) / 8;
573 afd
->pwfx
->nAvgBytesPerSec
=
574 afd
->pwfx
->nSamplesPerSec
* afd
->pwfx
->nBlockAlign
;
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;
591 WARN("Unsupported tag %08lx\n", afd
->dwFormatTag
);
592 return MMSYSERR_INVALPARAM
;
596 WARN("Unsupported query %08lx\n", dwQuery
);
597 return MMSYSERR_NOTSUPPORTED
;
599 afd
->fdwSupport
= ACMDRIVERDETAILS_SUPPORTF_CODEC
;
600 afd
->szFormat
[0] = 0; /* let MSACM format this for us... */
602 return MMSYSERR_NOERROR
;
605 /***********************************************************************
606 * ADPCM_FormatSuggest
609 static LRESULT
ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs
)
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 */
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
;
623 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_WBITSPERSAMPLE
))
625 if (adfs
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
)
626 adfs
->pwfxDst
->wBitsPerSample
= 4;
628 adfs
->pwfxDst
->wBitsPerSample
= 16;
630 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_WFORMATTAG
))
632 if (adfs
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
)
633 adfs
->pwfxDst
->wFormatTag
= WAVE_FORMAT_IMA_ADPCM
;
635 adfs
->pwfxDst
->wFormatTag
= WAVE_FORMAT_PCM
;
638 /* check if result is ok */
639 if (ADPCM_GetFormatIndex(adfs
->pwfxDst
) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE
;
641 /* recompute other values */
642 switch (adfs
->pwfxDst
->wFormatTag
)
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
;
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
);
660 return MMSYSERR_NOERROR
;
663 /***********************************************************************
667 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi
, AcmAdpcmData
* aad
)
669 aad
->stepIndexL
= aad
->stepIndexR
= 0;
672 /***********************************************************************
676 static LRESULT
ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi
)
681 assert(!(adsi
->fdwOpen
& ACM_STREAMOPENF_ASYNC
));
683 if (ADPCM_GetFormatIndex(adsi
->pwfxSrc
) == 0xFFFFFFFF ||
684 ADPCM_GetFormatIndex(adsi
->pwfxDst
) == 0xFFFFFFFF)
685 return ACMERR_NOTPOSSIBLE
;
687 aad
= HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData
));
688 if (aad
== 0) return MMSYSERR_NOMEM
;
690 adsi
->dwDriver
= (DWORD
)aad
;
692 if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
&&
693 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
)
697 else if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_IMA_ADPCM
&&
698 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
)
700 /* resampling or mono <=> stereo not available
701 * ADPCM algo only define 16 bit per sample output
703 if (adsi
->pwfxSrc
->nSamplesPerSec
!= adsi
->pwfxDst
->nSamplesPerSec
||
704 adsi
->pwfxSrc
->nChannels
!= adsi
->pwfxDst
->nChannels
||
705 adsi
->pwfxDst
->wBitsPerSample
!= 16)
708 nspb
= ((LPIMAADPCMWAVEFORMAT
)adsi
->pwfxSrc
)->wSamplesPerBlock
;
709 FIXME("spb=%u\n", nspb
);
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
715 if (((nspb
- 1) & 3) != 0) goto theEnd
;
716 if ((((nspb
- 1) / 2) + 4) * adsi
->pwfxSrc
->nChannels
< adsi
->pwfxSrc
->nBlockAlign
)
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
;
725 else if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
&&
726 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_IMA_ADPCM
)
728 if (adsi
->pwfxSrc
->nSamplesPerSec
!= adsi
->pwfxDst
->nSamplesPerSec
||
729 adsi
->pwfxSrc
->nChannels
!= adsi
->pwfxDst
->nChannels
||
730 adsi
->pwfxSrc
->wBitsPerSample
!= 16)
733 nspb
= ((LPIMAADPCMWAVEFORMAT
)adsi
->pwfxDst
)->wSamplesPerBlock
;
734 FIXME("spb=%u\n", nspb
);
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
740 if (((nspb
- 1) & 3) != 0) goto theEnd
;
741 if ((((nspb
- 1) / 2) + 4) * adsi
->pwfxDst
->nChannels
< adsi
->pwfxDst
->nBlockAlign
)
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
;
751 ADPCM_Reset(adsi
, aad
);
753 return MMSYSERR_NOERROR
;
756 HeapFree(GetProcessHeap(), 0, aad
);
758 return MMSYSERR_NOTSUPPORTED
;
761 /***********************************************************************
765 static LRESULT
ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi
)
767 HeapFree(GetProcessHeap(), 0, (void*)adsi
->dwDriver
);
768 return MMSYSERR_NOERROR
;
771 /***********************************************************************
775 static inline DWORD
ADPCM_round(DWORD a
, DWORD b
, DWORD c
)
778 /* to be sure, always return an entire number of c... */
779 return ((double)a
* (double)b
+ (double)c
- 1) / (double)c
;
782 /***********************************************************************
786 static LRESULT
ADPCM_StreamSize(PACMDRVSTREAMINSTANCE adsi
, PACMDRVSTREAMSIZE adss
)
788 switch (adss
->fdwSize
)
790 case ACM_STREAMSIZEF_DESTINATION
:
791 /* cbDstLength => cbSrcLength */
792 if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
&&
793 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_IMA_ADPCM
)
795 /* don't take block overhead into account, doesn't matter too much */
796 adss
->cbSrcLength
= adss
->cbDstLength
* 4;
798 else if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_IMA_ADPCM
&&
799 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
)
801 FIXME("misses the block header overhead\n");
802 adss
->cbSrcLength
= 256 + adss
->cbDstLength
/ 4;
806 return MMSYSERR_NOTSUPPORTED
;
809 case ACM_STREAMSIZEF_SOURCE
:
810 /* cbSrcLength => cbDstLength */
811 if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
&&
812 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_IMA_ADPCM
)
814 FIXME("misses the block header overhead\n");
815 adss
->cbDstLength
= 256 + adss
->cbSrcLength
/ 4;
817 else if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_IMA_ADPCM
&&
818 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
)
820 /* don't take block overhead into account, doesn't matter too much */
821 adss
->cbDstLength
= adss
->cbSrcLength
* 4;
825 return MMSYSERR_NOTSUPPORTED
;
829 WARN("Unsupported query %08lx\n", adss
->fdwSize
);
830 return MMSYSERR_NOTSUPPORTED
;
832 return MMSYSERR_NOERROR
;
835 /***********************************************************************
836 * ADPCM_StreamConvert
839 static LRESULT
ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi
, PACMDRVSTREAMHEADER adsh
)
841 AcmAdpcmData
* aad
= (AcmAdpcmData
*)adsi
->dwDriver
;
842 DWORD nsrc
= adsh
->cbSrcLength
;
843 DWORD ndst
= adsh
->cbDstLength
;
845 if (adsh
->fdwConvert
&
846 ~(ACM_STREAMCONVERTF_BLOCKALIGN
|
847 ACM_STREAMCONVERTF_END
|
848 ACM_STREAMCONVERTF_START
))
850 FIXME("Unsupported fdwConvert (%08lx), ignoring it\n", adsh
->fdwConvert
);
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
857 if ((adsh
->fdwConvert
& ACM_STREAMCONVERTF_START
))
859 ADPCM_Reset(adsi
, aad
);
862 aad
->convert(adsi
, adsh
->pbSrc
, &nsrc
, adsh
->pbDst
, &ndst
);
863 adsh
->cbSrcLengthUsed
= nsrc
;
864 adsh
->cbDstLengthUsed
= ndst
;
866 return MMSYSERR_NOERROR
;
869 /**************************************************************************
870 * ADPCM_DriverProc [exported]
872 LRESULT CALLBACK
ADPCM_DriverProc(DWORD dwDevID
, HDRVR hDriv
, UINT wMsg
,
873 LPARAM dwParam1
, LPARAM dwParam2
)
875 TRACE("(%08lx %08lx %04x %08lx %08lx);\n",
876 dwDevID
, (DWORD
)hDriv
, wMsg
, dwParam1
, dwParam2
);
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
;
891 case ACMDM_DRIVER_NOTIFY
:
892 /* no caching from other ACM drivers is done so far */
893 return MMSYSERR_NOERROR
;
895 case ACMDM_DRIVER_DETAILS
:
896 return ADPCM_DriverDetails((PACMDRIVERDETAILSW
)dwParam1
);
898 case ACMDM_FORMATTAG_DETAILS
:
899 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW
)dwParam1
, dwParam2
);
901 case ACMDM_FORMAT_DETAILS
:
902 return ADPCM_FormatDetails((PACMFORMATDETAILSW
)dwParam1
, dwParam2
);
904 case ACMDM_FORMAT_SUGGEST
:
905 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST
)dwParam1
);
907 case ACMDM_STREAM_OPEN
:
908 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE
)dwParam1
);
910 case ACMDM_STREAM_CLOSE
:
911 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE
)dwParam1
);
913 case ACMDM_STREAM_SIZE
:
914 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE
)dwParam1
, (PACMDRVSTREAMSIZE
)dwParam2
);
916 case ACMDM_STREAM_CONVERT
:
917 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE
)dwParam1
, (PACMDRVSTREAMHEADER
)dwParam2
);
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
;
934 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);