ReactOS  0.4.14-dev-384-g5b37caa
msadp32.c
Go to the documentation of this file.
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 
39 
40 /***********************************************************************
41  * ADPCM_drvOpen
42  */
44 {
45  return 1;
46 }
47 
48 /***********************************************************************
49  * ADPCM_drvClose
50  */
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 static int MS_Delta[] =
87 {
88  230, 230, 230, 230, 307, 409, 512, 614,
89  768, 614, 512, 409, 307, 230, 230, 230
90 };
91 
92 
94 {
95  {256, 0}, {512, -256}, {0, 0}, {192, 64}, {240, 0}, {460, -208}, {392, -232}
96 };
97 
98 /***********************************************************************
99  * ADPCM_GetFormatIndex
100  */
102 {
103  int i, hi;
104  const Format* fmts;
105 
106  switch (wfx->wFormatTag)
107  {
108  case WAVE_FORMAT_PCM:
109  hi = ARRAY_SIZE(PCM_Formats);
110  fmts = PCM_Formats;
111  break;
112  case WAVE_FORMAT_ADPCM:
115  break;
116  default:
117  return 0xFFFFFFFF;
118  }
119 
120  for (i = 0; i < hi; i++)
121  {
122  if (wfx->nChannels == fmts[i].nChannels &&
123  wfx->nSamplesPerSec == fmts[i].rate &&
124  wfx->wBitsPerSample == fmts[i].nBits)
125  return i;
126  }
127 
128  switch (wfx->wFormatTag)
129  {
130  case WAVE_FORMAT_PCM:
131  if(3 > wfx->nChannels &&
132  wfx->nChannels > 0 &&
133  wfx->nAvgBytesPerSec == 2 * wfx->nSamplesPerSec * wfx->nChannels &&
134  wfx->nBlockAlign == 2 * wfx->nChannels &&
135  wfx->wBitsPerSample == 16)
136  return hi;
137  break;
138  case WAVE_FORMAT_ADPCM:
139  if(3 > wfx->nChannels &&
140  wfx->nChannels > 0 &&
141  wfx->wBitsPerSample == 4 &&
142  wfx->cbSize == 32)
143  return hi;
144  break;
145  }
146 
147  return 0xFFFFFFFF;
148 }
149 
150 static void init_wfx_adpcm(ADPCMWAVEFORMAT* awfx)
151 {
152  register WAVEFORMATEX* pwfx = &awfx->wfx;
153 
154  /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample
155  * have been initialized... */
156 
157  if (pwfx->wFormatTag != WAVE_FORMAT_ADPCM) {FIXME("wrong FT\n"); return;}
158  if (ADPCM_GetFormatIndex(pwfx) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;}
159 
160  switch (pwfx->nSamplesPerSec)
161  {
162  case 8000: pwfx->nBlockAlign = 256 * pwfx->nChannels; break;
163  case 11025: pwfx->nBlockAlign = 256 * pwfx->nChannels; break;
164  case 22050: pwfx->nBlockAlign = 512 * pwfx->nChannels; break;
165  case 44100: pwfx->nBlockAlign = 1024 * pwfx->nChannels; break;
166  default: break;
167  }
168  pwfx->cbSize = 2 * sizeof(WORD) + 7 * sizeof(ADPCMCOEFSET);
169  /* 7 is the size of the block head (which contains two samples) */
170 
171  awfx->wSamplesPerBlock = pwfx->nBlockAlign * 2 / pwfx->nChannels - 12;
172  pwfx->nAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) / awfx->wSamplesPerBlock;
173  awfx->wNumCoef = 7;
174  memcpy(awfx->aCoef, MSADPCM_CoeffSet, 7 * sizeof(ADPCMCOEFSET));
175 }
176 
177 /***********************************************************************
178  * R16
179  *
180  * Read a 16 bit sample (correctly handles endianness)
181  */
182 static inline short R16(const unsigned char* src)
183 {
184  return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
185 }
186 
187 /***********************************************************************
188  * W16
189  *
190  * Write a 16 bit sample (correctly handles endianness)
191  */
192 static inline void W16(unsigned char* dst, short s)
193 {
194  dst[0] = LOBYTE(s);
195  dst[1] = HIBYTE(s);
196 }
197 
198 static inline void clamp_sample(int* sample)
199 {
200  if (*sample < -32768) *sample = -32768;
201  if (*sample > 32767) *sample = 32767;
202 }
203 
204 static inline void process_nibble(unsigned nibble, int* idelta,
205  int* sample1, int* sample2,
206  const ADPCMCOEFSET* coeff)
207 {
208  int sample;
209  int snibble;
210 
211  /* nibble is in fact a signed 4 bit integer => propagate sign if needed */
212  snibble = (nibble & 0x08) ? (nibble - 16) : nibble;
213  sample = ((*sample1 * coeff->iCoef1) + (*sample2 * coeff->iCoef2)) / 256 +
214  snibble * *idelta;
215  clamp_sample(&sample);
216 
217  *sample2 = *sample1;
218  *sample1 = sample;
219  *idelta = ((MS_Delta[nibble] * *idelta) / 256);
220  if (*idelta < 16) *idelta = 16;
221 }
222 
223 static inline unsigned char C168(short s)
224 {
225  return HIBYTE(s) ^ (unsigned char)0x80;
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 * adsi->pwfxDst->nBlockAlign));
240 
241  *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
242  *ndst = nblock * nsamp_blk * adsi->pwfxDst->nBlockAlign;
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  /* Catch a problem from Tomb Raider III (bug 21000) where it passes
250  * invalid data after a valid sequence of blocks */
251  if (*src > 6 || *(src + 1) > 6)
252  {
253  /* Recalculate the amount of used output buffer. We are not changing
254  * nsrc, let's assume the bad data was parsed */
255  *ndst -= nblock * nsamp_blk * adsi->pwfxDst->nBlockAlign;
256  WARN("Invalid ADPCM data, stopping conversion\n");
257  break;
258  }
259  coeffL = MSADPCM_CoeffSet[*src++];
260  coeffR = MSADPCM_CoeffSet[*src++];
261 
262  ideltaL = R16(src); src += 2;
263  ideltaR = R16(src); src += 2;
264  sample1L = R16(src); src += 2;
265  sample1R = R16(src); src += 2;
266  sample2L = R16(src); src += 2;
267  sample2R = R16(src); src += 2;
268 
269  if(adsi->pwfxDst->wBitsPerSample == 8){
270  /* store samples from block head */
271  *dst = C168(sample2L); ++dst;
272  *dst = C168(sample2R); ++dst;
273  *dst = C168(sample1L); ++dst;
274  *dst = C168(sample1R); ++dst;
275 
276  for (nsamp = nsamp_blk; nsamp > 0; nsamp--)
277  {
278  process_nibble(*src >> 4, &ideltaL, &sample1L, &sample2L, &coeffL);
279  *dst = C168(sample1L); ++dst;
280  process_nibble(*src++ & 0x0F, &ideltaR, &sample1R, &sample2R, &coeffR);
281  *dst = C168(sample1R); ++dst;
282  }
283  }else if(adsi->pwfxDst->wBitsPerSample == 16){
284  /* store samples from block head */
285  W16(dst, sample2L); dst += 2;
286  W16(dst, sample2R); dst += 2;
287  W16(dst, sample1L); dst += 2;
288  W16(dst, sample1R); dst += 2;
289 
290  for (nsamp = nsamp_blk; nsamp > 0; nsamp--)
291  {
292  process_nibble(*src >> 4, &ideltaL, &sample1L, &sample2L, &coeffL);
293  W16(dst, sample1L); dst += 2;
294  process_nibble(*src++ & 0x0F, &ideltaR, &sample1R, &sample2R, &coeffR);
295  W16(dst, sample1R); dst += 2;
296  }
297  }
298  src = in_src + adsi->pwfxSrc->nBlockAlign;
299  }
300 }
301 
302 static void cvtMMms16K(const ACMDRVSTREAMINSTANCE *adsi,
303  const unsigned char* src, LPDWORD nsrc,
304  unsigned char* dst, LPDWORD ndst)
305 {
306  int idelta;
307  int sample1, sample2;
308  ADPCMCOEFSET coeff;
309  int nsamp;
310  int nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
311  DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
312  *ndst / (nsamp_blk * adsi->pwfxDst->nBlockAlign));
313 
314  *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
315  *ndst = nblock * nsamp_blk * adsi->pwfxDst->nBlockAlign;
316 
317  nsamp_blk -= 2; /* see below for samples from block head */
318  for (; nblock > 0; nblock--)
319  {
320  const unsigned char* in_src = src;
321 
322  assert(*src <= 6);
323  coeff = MSADPCM_CoeffSet[*src++];
324 
325  idelta = R16(src); src += 2;
326  sample1 = R16(src); src += 2;
327  sample2 = R16(src); src += 2;
328 
329  /* store samples from block head */
330  if(adsi->pwfxDst->wBitsPerSample == 8){
331  *dst = C168(sample2); ++dst;
332  *dst = C168(sample1); ++dst;
333 
334  for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
335  {
336  process_nibble(*src >> 4, &idelta, &sample1, &sample2, &coeff);
337  *dst = C168(sample1); ++dst;
338  process_nibble(*src++ & 0x0F, &idelta, &sample1, &sample2, &coeff);
339  *dst = C168(sample1); ++dst;
340  }
341  }else if(adsi->pwfxDst->wBitsPerSample == 16){
342  W16(dst, sample2); dst += 2;
343  W16(dst, sample1); dst += 2;
344 
345  for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
346  {
347  process_nibble(*src >> 4, &idelta, &sample1, &sample2, &coeff);
348  W16(dst, sample1); dst += 2;
349  process_nibble(*src++ & 0x0F, &idelta, &sample1, &sample2, &coeff);
350  W16(dst, sample1); dst += 2;
351  }
352  }
353 
354  src = in_src + adsi->pwfxSrc->nBlockAlign;
355  }
356 }
357 
358 #if 0
359 static void cvtSS16msK(PACMDRVSTREAMINSTANCE adsi,
360  const unsigned char* src, LPDWORD nsrc,
361  unsigned char* dst, LPDWORD ndst)
362 {
363 }
364 
365 static void cvtMM16msK(PACMDRVSTREAMINSTANCE adsi,
366  const unsigned char* src, LPDWORD nsrc,
367  unsigned char* dst, LPDWORD ndst)
368 {
369 }
370 #endif
371 
372 /***********************************************************************
373  * ADPCM_DriverDetails
374  *
375  */
377 {
380  add->wMid = MM_MICROSOFT;
381  add->wPid = MM_MSFT_ACM_MSADPCM;
382  add->vdwACM = 0x01000000;
383  add->vdwDriver = 0x01000000;
384  add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
385  add->cFormatTags = 2; /* PCM, MS ADPCM */
386  add->cFilterTags = 0;
387  add->hicon = NULL;
388  MultiByteToWideChar( CP_ACP, 0, "MS-ADPCM", -1,
389  add->szShortName, ARRAY_SIZE( add->szShortName ));
390  MultiByteToWideChar( CP_ACP, 0, "Wine MS ADPCM converter", -1,
391  add->szLongName, ARRAY_SIZE( add->szLongName ));
392  MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
393  add->szCopyright, ARRAY_SIZE( add->szCopyright ));
394  MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
395  add->szLicensing, ARRAY_SIZE( add->szLicensing ));
396  add->szFeatures[0] = 0;
397 
398  return MMSYSERR_NOERROR;
399 }
400 
401 /***********************************************************************
402  * ADPCM_FormatTagDetails
403  *
404  */
406 {
407  static const WCHAR szPcm[]={'P','C','M',0};
408  static const WCHAR szMsAdPcm[]={'M','i','c','r','o','s','o','f','t',' ','A','D','P','C','M',0};
409 
410  switch (dwQuery)
411  {
413  if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
414  break;
416  if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
417  {
418  aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_ADPCM is bigger than PCM */
419  break;
420  }
421  /* fall through */
423  switch (aftd->dwFormatTag)
424  {
425  case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break;
426  case WAVE_FORMAT_ADPCM: aftd->dwFormatTagIndex = 1; break;
427  default: return ACMERR_NOTPOSSIBLE;
428  }
429  break;
430  default:
431  WARN("Unsupported query %08x\n", dwQuery);
432  return MMSYSERR_NOTSUPPORTED;
433  }
434 
436  switch (aftd->dwFormatTagIndex)
437  {
438  case 0:
440  aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
442  lstrcpyW(aftd->szFormatTag, szPcm);
443  break;
444  case 1:
446  aftd->cbFormatSize = sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET);
448  lstrcpyW(aftd->szFormatTag, szMsAdPcm);
449  break;
450  }
451  return MMSYSERR_NOERROR;
452 }
453 
454 /***********************************************************************
455  * ADPCM_FormatDetails
456  *
457  */
459 {
460  switch (dwQuery)
461  {
463  if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
464  break;
466  afd->pwfx->wFormatTag = afd->dwFormatTag;
467  switch (afd->dwFormatTag)
468  {
469  case WAVE_FORMAT_PCM:
474  /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
475  * afd->pwfx->cbSize = 0;
476  */
477  afd->pwfx->nBlockAlign =
478  (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
479  afd->pwfx->nAvgBytesPerSec =
480  afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
481  break;
482  case WAVE_FORMAT_ADPCM:
484  if (afd->cbwfx < sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET))
485  return ACMERR_NOTPOSSIBLE;
490  break;
491  default:
492  WARN("Unsupported tag %08x\n", afd->dwFormatTag);
493  return MMSYSERR_INVALPARAM;
494  }
495  break;
496  default:
497  WARN("Unsupported query %08x\n", dwQuery);
498  return MMSYSERR_NOTSUPPORTED;
499  }
501  afd->szFormat[0] = 0; /* let MSACM format this for us... */
502 
503  return MMSYSERR_NOERROR;
504 }
505 
506 /***********************************************************************
507  * ADPCM_FormatSuggest
508  *
509  */
511 {
512  /* some tests ... */
513  if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
514  adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
515  adfs->pwfxSrc->wFormatTag == adfs->pwfxDst->wFormatTag ||
516  ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
517  /* FIXME: should do those tests against the real size (according to format tag */
518 
519  /* If no suggestion for destination, then copy source value */
521  adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
524 
526  {
527  if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
528  adfs->pwfxDst->wBitsPerSample = 4;
529  else
530  adfs->pwfxDst->wBitsPerSample = 16;
531  }
533  {
534  if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
536  else
538  }
539 
540  /* recompute other values */
541  switch (adfs->pwfxDst->wFormatTag)
542  {
543  case WAVE_FORMAT_PCM:
544  adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
546  /* check if result is ok */
547  if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
548  break;
549  case WAVE_FORMAT_ADPCM:
550  if (adfs->cbwfxDst < sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET))
551  return ACMERR_NOTPOSSIBLE;
553  /* check if result is ok */
554  if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
555  break;
556  default:
557  return ACMERR_NOTPOSSIBLE;
558  }
559 
560  return MMSYSERR_NOERROR;
561 }
562 
563 /***********************************************************************
564  * ADPCM_Reset
565  *
566  */
568 {
569 }
570 
571 /***********************************************************************
572  * ADPCM_StreamOpen
573  *
574  */
576 {
577  AcmAdpcmData* aad;
578 
580 
581  if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
582  ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
583  return ACMERR_NOTPOSSIBLE;
584 
585  aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
586  if (aad == 0) return MMSYSERR_NOMEM;
587 
588  adsi->dwDriver = (DWORD_PTR)aad;
589 
590  if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
592  {
593  goto theEnd;
594  }
595  else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
597  {
598  /* resampling or mono <=> stereo not available */
599  if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
600  adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels)
601  goto theEnd;
602 
603 #if 0
604  {
605  unsigned int nspb = ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
606  FIXME("spb=%u\n", nspb);
607 
608  /* we check that in a block, after the header, samples are present on
609  * 4-sample packet pattern
610  * we also check that the block alignment is bigger than the expected size
611  */
612  if (((nspb - 1) & 3) != 0) goto theEnd;
613  if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
614  goto theEnd;
615  }
616 #endif
617 
618  /* adpcm decoding... */
619  if (adsi->pwfxDst->nChannels == 2)
620  aad->convert = cvtSSms16K;
621  else if (adsi->pwfxDst->nChannels == 1)
622  aad->convert = cvtMMms16K;
623  }
624  else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
626  {
627  if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
628  adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
629  adsi->pwfxSrc->wBitsPerSample != 16)
630  goto theEnd;
631 #if 0
632  nspb = ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
633  FIXME("spb=%u\n", nspb);
634 
635  /* we check that in a block, after the header, samples are present on
636  * 4-sample packet pattern
637  * we also check that the block alignment is bigger than the expected size
638  */
639  if (((nspb - 1) & 3) != 0) goto theEnd;
640  if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
641  goto theEnd;
642 #endif
643 #if 0
644  /* adpcm coding... */
645  if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
646  aad->convert = cvtSS16msK;
647  if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
648  aad->convert = cvtMM16msK;
649 #endif
650  FIXME("We don't support encoding yet\n");
651  goto theEnd;
652  }
653  else goto theEnd;
654  ADPCM_Reset(adsi, aad);
655 
656  return MMSYSERR_NOERROR;
657 
658  theEnd:
659  HeapFree(GetProcessHeap(), 0, aad);
660  adsi->dwDriver = 0L;
661  return MMSYSERR_NOTSUPPORTED;
662 }
663 
664 /***********************************************************************
665  * ADPCM_StreamClose
666  *
667  */
669 {
670  HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
671  return MMSYSERR_NOERROR;
672 }
673 
674 /***********************************************************************
675  * ADPCM_StreamSize
676  *
677  */
679 {
680  DWORD nblocks;
681  WORD wSamplesPerBlock;
682  /* wSamplesPerBlock formula comes from MSDN ADPCMWAVEFORMAT page.*/
683  switch (adss->fdwSize)
684  {
686  /* cbDstLength => cbSrcLength */
687  if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
689  {
690  wSamplesPerBlock = adsi->pwfxDst->nBlockAlign * 2 / adsi->pwfxDst->nChannels - 12;
691  nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign;
692  if (nblocks == 0)
693  return ACMERR_NOTPOSSIBLE;
694  adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * wSamplesPerBlock;
695  }
696  else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
698  {
699  wSamplesPerBlock = adsi->pwfxSrc->nBlockAlign * 2 / adsi->pwfxSrc->nChannels - 12;
700  nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * wSamplesPerBlock);
701  if (nblocks == 0)
702  return ACMERR_NOTPOSSIBLE;
703  adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
704  }
705  else
706  {
707  return MMSYSERR_NOTSUPPORTED;
708  }
709  break;
711  /* cbSrcLength => cbDstLength */
712  if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
714  {
715  wSamplesPerBlock = adsi->pwfxDst->nBlockAlign * 2 / adsi->pwfxDst->nChannels - 12;
716  nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * wSamplesPerBlock);
717  if (nblocks == 0)
718  return ACMERR_NOTPOSSIBLE;
719  if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * wSamplesPerBlock))
720  /* Round block count up. */
721  nblocks++;
722  adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign;
723  }
724  else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
726  {
727  wSamplesPerBlock = adsi->pwfxSrc->nBlockAlign * 2 / adsi->pwfxSrc->nChannels - 12;
728  nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign;
729  if (nblocks == 0)
730  return ACMERR_NOTPOSSIBLE;
731  if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
732  /* Round block count up. */
733  nblocks++;
734  adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * wSamplesPerBlock;
735  }
736  else
737  {
738  return MMSYSERR_NOTSUPPORTED;
739  }
740  break;
741  default:
742  WARN("Unsupported query %08x\n", adss->fdwSize);
743  return MMSYSERR_NOTSUPPORTED;
744  }
745  return MMSYSERR_NOERROR;
746 }
747 
748 /***********************************************************************
749  * ADPCM_StreamConvert
750  *
751  */
753 {
754  AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver;
755  DWORD nsrc = adsh->cbSrcLength;
756  DWORD ndst = adsh->cbDstLength;
757 
758  if (adsh->fdwConvert &
762  {
763  FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
764  }
765  /* ACM_STREAMCONVERTF_BLOCKALIGN
766  * currently all conversions are block aligned, so do nothing for this flag
767  * ACM_STREAMCONVERTF_END
768  * no pending data, so do nothing for this flag
769  */
770  if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
771  {
772  ADPCM_Reset(adsi, aad);
773  }
774 
775  aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
776  adsh->cbSrcLengthUsed = nsrc;
777  adsh->cbDstLengthUsed = ndst;
778 
779  return MMSYSERR_NOERROR;
780 }
781 
782 /**************************************************************************
783  * ADPCM_DriverProc [exported]
784  */
785 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
786  LPARAM dwParam1, LPARAM dwParam2)
787 {
788  TRACE("(%08lx %p %04x %08lx %08lx);\n",
789  dwDevID, hDriv, wMsg, dwParam1, dwParam2);
790 
791  switch (wMsg)
792  {
793  case DRV_LOAD: return 1;
794  case DRV_FREE: return 1;
795  case DRV_OPEN: return ADPCM_drvOpen((LPSTR)dwParam1);
796  case DRV_CLOSE: return ADPCM_drvClose(dwDevID);
797  case DRV_ENABLE: return 1;
798  case DRV_DISABLE: return 1;
799  case DRV_QUERYCONFIGURE: return 1;
800  case DRV_CONFIGURE: MessageBoxA(0, "MSACM MS ADPCM filter !", "Wine Driver", MB_OK); return 1;
801  case DRV_INSTALL: return DRVCNF_RESTART;
802  case DRV_REMOVE: return DRVCNF_RESTART;
803 
804  case ACMDM_DRIVER_NOTIFY:
805  /* no caching from other ACM drivers is done so far */
806  return MMSYSERR_NOERROR;
807 
809  return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
810 
812  return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
813 
815  return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
816 
818  return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
819 
820  case ACMDM_STREAM_OPEN:
821  return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
822 
823  case ACMDM_STREAM_CLOSE:
824  return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
825 
826  case ACMDM_STREAM_SIZE:
827  return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
828 
831 
834  /* this converter is not a hardware driver */
837  /* this converter is not a filter */
838  case ACMDM_STREAM_RESET:
839  /* only needed for asynchronous driver... we aren't, so just say it */
840  return MMSYSERR_NOTSUPPORTED;
843  /* nothing special to do here... so don't do anything */
844  return MMSYSERR_NOERROR;
845 
846  default:
847  return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
848  }
849 }
short iCoef2
Definition: mmreg.h:164
PWAVEFORMATEX pwfx
Definition: msacm.h:507
#define DRV_DISABLE
Definition: mmsystem.h:123
#define WAVE_FORMAT_UNKNOWN
Definition: mmreg.h:95
int add
Definition: i386-dis.c:3122
struct tagAcmAdpcmData AcmAdpcmData
#define ACM_STREAMSIZEF_DESTINATION
Definition: msacm.h:218
static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData *aad)
Definition: msadp32.c:567
static LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
Definition: msadp32.c:376
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
#define ACM_FORMATSUGGESTF_NSAMPLESPERSEC
Definition: msacm.h:176
#define MM_MSFT_ACM_MSADPCM
Definition: mmreg.h:146
#define DWORD_PTR
Definition: treelist.c:76
#define ACM_STREAMCONVERTF_BLOCKALIGN
Definition: msacm.h:205
#define LOBYTE(W)
Definition: jmemdos.c:487
PWAVEFORMATEX pwfxDst
Definition: msacmdrv.h:153
#define CP_ACP
Definition: compat.h:99
DWORD nAvgBytesPerSec
Definition: mmreg.h:81
WORD nChannels
Definition: mmreg.h:79
#define WARN(fmt,...)
Definition: debug.h:111
#define ACMDRIVERDETAILS_SUPPORTF_CODEC
Definition: msacm.h:61
#define ACMDM_STREAM_RESET
Definition: msacmdrv.h:62
#define CALLBACK
Definition: compat.h:27
#define HIBYTE(W)
Definition: jmemdos.c:486
#define ACM_FORMATSUGGESTF_WFORMATTAG
Definition: msacm.h:174
int nChannels
Definition: imaadp32.c:63
static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
Definition: msadp32.c:752
#define assert(x)
Definition: debug.h:53
#define DRV_CLOSE
Definition: mmsystem.h:122
static LRESULT ADPCM_drvClose(DWORD_PTR dwDevID)
Definition: msadp32.c:51
static const Format ADPCM_Formats[]
Definition: msadp32.c:80
int nBits
Definition: imaadp32.c:64
int rate
Definition: pcmconverter.c:97
#define ACMDM_STREAM_OPEN
Definition: msacmdrv.h:58
static void init_wfx_adpcm(ADPCMWAVEFORMAT *awfx)
Definition: msadp32.c:150
#define ACMDM_FORMATTAG_DETAILS
Definition: msacmdrv.h:51
char * LPSTR
Definition: xmlstorage.h:182
#define ACMDM_STREAM_PREPARE
Definition: msacmdrv.h:63
struct pcmwaveformat_tag PCMWAVEFORMAT
int nChannels
Definition: pcmconverter.c:95
#define ACM_STREAMCONVERTF_END
Definition: msacm.h:207
#define ACMDM_STREAM_CLOSE
Definition: msacmdrv.h:59
#define DRV_QUERYCONFIGURE
Definition: mmsystem.h:126
#define DRV_OPEN
Definition: mmsystem.h:121
int WINAPI MessageBoxA(_In_opt_ HWND, _In_opt_ LPCSTR, _In_opt_ LPCSTR, _In_ UINT)
#define ACMDM_DRIVER_NOTIFY
Definition: msacmdrv.h:45
#define ACMDM_FORMAT_SUGGEST
Definition: msacmdrv.h:53
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:93
#define MMSYSERR_NOMEM
Definition: mmsystem.h:103
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define WAVE_FORMAT_PCM
Definition: constants.h:425
#define ACM_FORMATDETAILSF_FORMAT
Definition: msacm.h:161
#define ACMDM_DRIVER_DETAILS
Definition: msacmdrv.h:46
#define ACMDM_STREAM_CONVERT
Definition: msacmdrv.h:61
#define FIXME(fmt,...)
Definition: debug.h:110
WORD wBitsPerSample
Definition: audioclient.idl:45
static struct fmt fmts[]
DWORD cStandardFormats
Definition: msacm.h:534
#define ACMDRIVERDETAILS_FCCCOMP_UNDEFINED
Definition: msacm.h:59
const WCHAR * str
smooth NULL
Definition: ftsmooth.c:416
unsigned char
Definition: typeof.h:29
LONG_PTR LPARAM
Definition: windef.h:208
#define ACM_FORMATSUGGESTF_NCHANNELS
Definition: msacm.h:175
#define DRV_LOAD(x)
static void W16(unsigned char *dst, short s)
Definition: msadp32.c:192
int nBits
Definition: pcmconverter.c:96
const char * LPCSTR
Definition: xmlstorage.h:183
#define DRVCNF_RESTART
Definition: mmsystem.h:135
#define DRV_REMOVE
Definition: mmsystem.h:128
static LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
Definition: msadp32.c:678
DWORD nSamplesPerSec
Definition: audioclient.idl:42
#define ACMDM_HARDWARE_WAVE_CAPS_OUTPUT
Definition: msacmdrv.h:49
#define ACMDM_HARDWARE_WAVE_CAPS_INPUT
Definition: msacmdrv.h:48
short iCoef1
Definition: mmreg.h:163
void(* convert)(PACMDRVSTREAMINSTANCE adsi, const unsigned char *, LPDWORD, unsigned char *, LPDWORD)
Definition: imaadp32.c:50
PWAVEFORMATEX pwfxDst
Definition: msacmdrv.h:101
#define TRACE(s)
Definition: solgame.cpp:4
#define ACM_FORMATTAGDETAILSF_FORMATTAG
Definition: msacm.h:183
static void cvtMMms16K(const ACMDRVSTREAMINSTANCE *adsi, const unsigned char *src, LPDWORD nsrc, unsigned char *dst, LPDWORD ndst)
Definition: msadp32.c:302
WORD wSamplesPerBlock
Definition: mmreg.h:171
#define MMSYSERR_NOERROR
Definition: mmsystem.h:96
#define GetProcessHeap()
Definition: compat.h:403
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
#define DRV_CONFIGURE
Definition: mmsystem.h:125
if(!(yy_init))
Definition: macro.lex.yy.c:714
static const Format PCM_Formats[]
Definition: msadp32.c:72
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define ACM_STREAMSIZEF_SOURCE
Definition: msacm.h:217
#define ACM_FORMATTAGDETAILSF_INDEX
Definition: msacm.h:182
static short R16(const unsigned char *src)
Definition: msadp32.c:182
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
WCHAR szFormat[ACMFORMATDETAILS_FORMAT_CHARS]
Definition: msacm.h:509
#define ACM_STREAMOPENF_ASYNC
Definition: msacm.h:214
static LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
Definition: msadp32.c:510
#define DRV_FREE
Definition: mmsystem.h:124
#define MMSYSERR_NOTSUPPORTED
Definition: mmsystem.h:104
static int MS_Delta[]
Definition: msadp32.c:86
struct adpcmwaveformat_tag ADPCMWAVEFORMAT
static LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
Definition: msadp32.c:405
WORD wFormatTag
Definition: mmreg.h:78
#define ACMDM_FILTERTAG_DETAILS
Definition: msacmdrv.h:55
DWORD dwFormatIndex
Definition: msacm.h:504
#define LPDWORD
Definition: nt_native.h:46
static const WCHAR L[]
Definition: oid.c:1250
#define MM_MICROSOFT
Definition: mmreg.h:144
WAVEFORMATEX wfx
Definition: mmreg.h:170
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLdouble s
Definition: gl.h:2039
#define ACM_FORMATTAGDETAILSF_LARGESTSIZE
Definition: msacm.h:184
GLenum src
Definition: glext.h:6340
static ADPCMCOEFSET MSADPCM_CoeffSet[]
Definition: msadp32.c:93
DWORD dwFormatTagIndex
Definition: msacm.h:530
uint32_t DWORD_PTR
Definition: typedefs.h:63
#define ACMERR_NOTPOSSIBLE
Definition: msacm.h:36
#define ACMDM_STREAM_UNPREPARE
Definition: msacmdrv.h:64
#define WAVE_FORMAT_ADPCM
Definition: constants.h:426
#define DRV_ENABLE
Definition: mmsystem.h:120
static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
Definition: msadp32.c:575
#define ACM_STREAMCONVERTF_START
Definition: msacm.h:206
#define lstrcpyW
Definition: compat.h:414
#define MMSYSERR_INVALPARAM
Definition: mmsystem.h:107
#define ARRAY_SIZE(a)
Definition: main.h:24
DWORD fdwSupport
Definition: msacm.h:506
DWORD nAvgBytesPerSec
Definition: audioclient.idl:43
PWAVEFORMATEX pwfxSrc
Definition: msacmdrv.h:151
GLenum GLenum dst
Definition: glext.h:6340
DWORD_PTR dwDriver
Definition: msacmdrv.h:107
static unsigned char C168(short s)
Definition: msadp32.c:223
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
#define MB_OK
Definition: winuser.h:784
WCHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]
Definition: msacm.h:535
#define MultiByteToWideChar
Definition: compat.h:100
static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
Definition: msadp32.c:458
static void process_nibble(unsigned nibble, int *idelta, int *sample1, int *sample2, const ADPCMCOEFSET *coeff)
Definition: msadp32.c:204
DWORD nSamplesPerSec
Definition: mmreg.h:80
WORD nBlockAlign
Definition: mmreg.h:82
#define ACM_FORMATDETAILSF_INDEX
Definition: msacm.h:160
int rate
Definition: imaadp32.c:65
uint32_t * LPDWORD
Definition: typedefs.h:57
WORD wBitsPerSample
Definition: mmreg.h:83
PWAVEFORMATEX pwfxSrc
Definition: msacmdrv.h:100
#define DRV_INSTALL
Definition: mmsystem.h:127
LRESULT WINAPI DefDriverProc(DWORD_PTR dwDriverIdentifier, HDRVR hDrv, UINT Msg, LPARAM lParam1, LPARAM lParam2)
Definition: driver.c:554
static DWORD ADPCM_GetFormatIndex(const WAVEFORMATEX *wfx)
Definition: msadp32.c:101
static void cvtSSms16K(const ACMDRVSTREAMINSTANCE *adsi, const unsigned char *src, LPDWORD nsrc, unsigned char *dst, LPDWORD ndst)
Definition: msadp32.c:228
LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, LPARAM dwParam1, LPARAM dwParam2)
Definition: msadp32.c:785
LONG_PTR LRESULT
Definition: windef.h:209
static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
Definition: msadp32.c:668
DWORD dwFormatTag
Definition: msacm.h:505
static void clamp_sample(int *sample)
Definition: msadp32.c:198
#define HeapFree(x, y, z)
Definition: compat.h:402
#define ACM_FORMATSUGGESTF_WBITSPERSAMPLE
Definition: msacm.h:177
#define ACMDM_FORMAT_DETAILS
Definition: msacmdrv.h:52
WINE_DEFAULT_DEBUG_CHANNEL(adpcm)
ADPCMCOEFSET aCoef[1]
Definition: mmreg.h:174
static LRESULT ADPCM_drvOpen(LPCSTR str)
Definition: msadp32.c:43
#define ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC
Definition: msacm.h:58
struct adpcmcoef_tag ADPCMCOEFSET
ACPI_BUFFER *RetBuffer ACPI_BUFFER *RetBuffer char ACPI_WALK_RESOURCE_CALLBACK void *Context ACPI_BUFFER *RetBuffer UINT16 ACPI_RESOURCE **ResourcePtr ACPI_GENERIC_ADDRESS *Reg UINT32 *ReturnValue UINT8 UINT8 *Slp_TypB ACPI_PHYSICAL_ADDRESS PhysicalAddress64 UINT32 UINT32 *TimeElapsed UINT32 ACPI_STATUS const char * Format
Definition: acpixf.h:1212
#define ACMDM_STREAM_SIZE
Definition: msacmdrv.h:60
#define ACMDM_FILTER_DETAILS
Definition: msacmdrv.h:56