Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmsadp32.c
Go to the documentation of this file.
00001 /* 00002 * MS ADPCM handling 00003 * 00004 * Copyright (C) 2002 Eric Pouech 00005 * 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #include <assert.h> 00023 #include <stdarg.h> 00024 #include <string.h> 00025 #include "windef.h" 00026 #include "winbase.h" 00027 #include "wingdi.h" 00028 #include "winuser.h" 00029 #include "winnls.h" 00030 #include "mmsystem.h" 00031 #include "mmreg.h" 00032 #include "msacm.h" 00033 #include "msacmdrv.h" 00034 #include "wine/debug.h" 00035 00036 /* see http://www.pcisys.net/~melanson/codecs/adpcm.txt for the details */ 00037 00038 WINE_DEFAULT_DEBUG_CHANNEL(adpcm); 00039 00040 /*********************************************************************** 00041 * ADPCM_drvOpen 00042 */ 00043 static LRESULT ADPCM_drvOpen(LPCSTR str) 00044 { 00045 return 1; 00046 } 00047 00048 /*********************************************************************** 00049 * ADPCM_drvClose 00050 */ 00051 static LRESULT ADPCM_drvClose(DWORD_PTR dwDevID) 00052 { 00053 return 1; 00054 } 00055 00056 typedef struct tagAcmAdpcmData 00057 { 00058 void (*convert)(const ACMDRVSTREAMINSTANCE *adsi, 00059 const unsigned char*, LPDWORD, unsigned char*, LPDWORD); 00060 } AcmAdpcmData; 00061 00062 /* table to list all supported formats... those are the basic ones. this 00063 * also helps given a unique index to each of the supported formats 00064 */ 00065 typedef struct 00066 { 00067 int nChannels; 00068 int nBits; 00069 int rate; 00070 } Format; 00071 00072 static const Format PCM_Formats[] = 00073 { 00074 {1, 8, 8000}, {2, 8, 8000}, {1, 16, 8000}, {2, 16, 8000}, 00075 {1, 8, 11025}, {2, 8, 11025}, {1, 16, 11025}, {2, 16, 11025}, 00076 {1, 8, 22050}, {2, 8, 22050}, {1, 16, 22050}, {2, 16, 22050}, 00077 {1, 8, 44100}, {2, 8, 44100}, {1, 16, 44100}, {2, 16, 44100}, 00078 }; 00079 00080 static const Format ADPCM_Formats[] = 00081 { 00082 {1, 4, 8000}, {2, 4, 8000}, {1, 4, 11025}, {2, 4, 11025}, 00083 {1, 4, 22050}, {2, 4, 22050}, {1, 4, 44100}, {2, 4, 44100}, 00084 }; 00085 00086 #define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0])) 00087 #define NUM_ADPCM_FORMATS (sizeof(ADPCM_Formats) / sizeof(ADPCM_Formats[0])) 00088 00089 static int MS_Delta[] = 00090 { 00091 230, 230, 230, 230, 307, 409, 512, 614, 00092 768, 614, 512, 409, 307, 230, 230, 230 00093 }; 00094 00095 00096 static ADPCMCOEFSET MSADPCM_CoeffSet[] = 00097 { 00098 {256, 0}, {512, -256}, {0, 0}, {192, 64}, {240, 0}, {460, -208}, {392, -232} 00099 }; 00100 00101 /*********************************************************************** 00102 * ADPCM_GetFormatIndex 00103 */ 00104 static DWORD ADPCM_GetFormatIndex(const WAVEFORMATEX* wfx) 00105 { 00106 int i, hi; 00107 const Format* fmts; 00108 00109 switch (wfx->wFormatTag) 00110 { 00111 case WAVE_FORMAT_PCM: 00112 hi = NUM_PCM_FORMATS; 00113 fmts = PCM_Formats; 00114 break; 00115 case WAVE_FORMAT_ADPCM: 00116 hi = NUM_ADPCM_FORMATS; 00117 fmts = ADPCM_Formats; 00118 break; 00119 default: 00120 return 0xFFFFFFFF; 00121 } 00122 00123 for (i = 0; i < hi; i++) 00124 { 00125 if (wfx->nChannels == fmts[i].nChannels && 00126 wfx->nSamplesPerSec == fmts[i].rate && 00127 wfx->wBitsPerSample == fmts[i].nBits) 00128 return i; 00129 } 00130 00131 switch (wfx->wFormatTag) 00132 { 00133 case WAVE_FORMAT_PCM: 00134 if(3 > wfx->nChannels && 00135 wfx->nChannels > 0 && 00136 wfx->nAvgBytesPerSec == 2 * wfx->nSamplesPerSec * wfx->nChannels && 00137 wfx->nBlockAlign == 2 * wfx->nChannels && 00138 wfx->wBitsPerSample == 16) 00139 return hi; 00140 break; 00141 case WAVE_FORMAT_ADPCM: 00142 if(3 > wfx->nChannels && 00143 wfx->nChannels > 0 && 00144 wfx->wBitsPerSample == 4 && 00145 wfx->cbSize == 32) 00146 return hi; 00147 break; 00148 } 00149 00150 return 0xFFFFFFFF; 00151 } 00152 00153 static void init_wfx_adpcm(ADPCMWAVEFORMAT* awfx) 00154 { 00155 register WAVEFORMATEX* pwfx = &awfx->wfx; 00156 00157 /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample 00158 * have been initialized... */ 00159 00160 if (pwfx->wFormatTag != WAVE_FORMAT_ADPCM) {FIXME("wrong FT\n"); return;} 00161 if (ADPCM_GetFormatIndex(pwfx) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;} 00162 00163 switch (pwfx->nSamplesPerSec) 00164 { 00165 case 8000: pwfx->nBlockAlign = 256 * pwfx->nChannels; break; 00166 case 11025: pwfx->nBlockAlign = 256 * pwfx->nChannels; break; 00167 case 22050: pwfx->nBlockAlign = 512 * pwfx->nChannels; break; 00168 case 44100: pwfx->nBlockAlign = 1024 * pwfx->nChannels; break; 00169 default: break; 00170 } 00171 pwfx->cbSize = 2 * sizeof(WORD) + 7 * sizeof(ADPCMCOEFSET); 00172 /* 7 is the size of the block head (which contains two samples) */ 00173 00174 awfx->wSamplesPerBlock = pwfx->nBlockAlign * 2 / pwfx->nChannels - 12; 00175 pwfx->nAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) / awfx->wSamplesPerBlock; 00176 awfx->wNumCoef = 7; 00177 memcpy(awfx->aCoef, MSADPCM_CoeffSet, 7 * sizeof(ADPCMCOEFSET)); 00178 } 00179 00180 /*********************************************************************** 00181 * R16 00182 * 00183 * Read a 16 bit sample (correctly handles endianness) 00184 */ 00185 static inline short R16(const unsigned char* src) 00186 { 00187 return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8)); 00188 } 00189 00190 /*********************************************************************** 00191 * W16 00192 * 00193 * Write a 16 bit sample (correctly handles endianness) 00194 */ 00195 static inline void W16(unsigned char* dst, short s) 00196 { 00197 dst[0] = LOBYTE(s); 00198 dst[1] = HIBYTE(s); 00199 } 00200 00201 static inline void clamp_sample(int* sample) 00202 { 00203 if (*sample < -32768) *sample = -32768; 00204 if (*sample > 32767) *sample = 32767; 00205 } 00206 00207 static inline void process_nibble(unsigned nibble, int* idelta, 00208 int* sample1, int* sample2, 00209 const ADPCMCOEFSET* coeff) 00210 { 00211 int sample; 00212 int snibble; 00213 00214 /* nibble is in fact a signed 4 bit integer => propagate sign if needed */ 00215 snibble = (nibble & 0x08) ? (nibble - 16) : nibble; 00216 sample = ((*sample1 * coeff->iCoef1) + (*sample2 * coeff->iCoef2)) / 256 + 00217 snibble * *idelta; 00218 clamp_sample(&sample); 00219 00220 *sample2 = *sample1; 00221 *sample1 = sample; 00222 *idelta = ((MS_Delta[nibble] * *idelta) / 256); 00223 if (*idelta < 16) *idelta = 16; 00224 } 00225 00226 static void cvtSSms16K(const ACMDRVSTREAMINSTANCE *adsi, 00227 const unsigned char* src, LPDWORD nsrc, 00228 unsigned char* dst, LPDWORD ndst) 00229 { 00230 int ideltaL, ideltaR; 00231 int sample1L, sample2L; 00232 int sample1R, sample2R; 00233 ADPCMCOEFSET coeffL, coeffR; 00234 int nsamp; 00235 int nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock; 00236 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign, 00237 *ndst / (nsamp_blk * 2 * 2)); 00238 00239 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign; 00240 *ndst = nblock * nsamp_blk * 2 * 2; 00241 00242 nsamp_blk -= 2; /* see below for samples from block head */ 00243 for (; nblock > 0; nblock--) 00244 { 00245 const unsigned char* in_src = src; 00246 00247 assert(*src <= 6); 00248 coeffL = MSADPCM_CoeffSet[*src++]; 00249 assert(*src <= 6); 00250 coeffR = MSADPCM_CoeffSet[*src++]; 00251 00252 ideltaL = R16(src); src += 2; 00253 ideltaR = R16(src); src += 2; 00254 sample1L = R16(src); src += 2; 00255 sample1R = R16(src); src += 2; 00256 sample2L = R16(src); src += 2; 00257 sample2R = R16(src); src += 2; 00258 00259 /* store samples from block head */ 00260 W16(dst, sample2L); dst += 2; 00261 W16(dst, sample2R); dst += 2; 00262 W16(dst, sample1L); dst += 2; 00263 W16(dst, sample1R); dst += 2; 00264 00265 for (nsamp = nsamp_blk; nsamp > 0; nsamp--) 00266 { 00267 process_nibble(*src >> 4, &ideltaL, &sample1L, &sample2L, &coeffL); 00268 W16(dst, sample1L); dst += 2; 00269 process_nibble(*src++ & 0x0F, &ideltaR, &sample1R, &sample2R, &coeffR); 00270 W16(dst, sample1R); dst += 2; 00271 } 00272 src = in_src + adsi->pwfxSrc->nBlockAlign; 00273 } 00274 } 00275 00276 static void cvtMMms16K(const ACMDRVSTREAMINSTANCE *adsi, 00277 const unsigned char* src, LPDWORD nsrc, 00278 unsigned char* dst, LPDWORD ndst) 00279 { 00280 int idelta; 00281 int sample1, sample2; 00282 ADPCMCOEFSET coeff; 00283 int nsamp; 00284 int nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock; 00285 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign, 00286 *ndst / (nsamp_blk * 2)); 00287 00288 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign; 00289 *ndst = nblock * nsamp_blk * 2; 00290 00291 nsamp_blk -= 2; /* see below for samples from block head */ 00292 for (; nblock > 0; nblock--) 00293 { 00294 const unsigned char* in_src = src; 00295 00296 assert(*src <= 6); 00297 coeff = MSADPCM_CoeffSet[*src++]; 00298 00299 idelta = R16(src); src += 2; 00300 sample1 = R16(src); src += 2; 00301 sample2 = R16(src); src += 2; 00302 00303 /* store samples from block head */ 00304 W16(dst, sample2); dst += 2; 00305 W16(dst, sample1); dst += 2; 00306 00307 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2) 00308 { 00309 process_nibble(*src >> 4, &idelta, &sample1, &sample2, &coeff); 00310 W16(dst, sample1); dst += 2; 00311 process_nibble(*src++ & 0x0F, &idelta, &sample1, &sample2, &coeff); 00312 W16(dst, sample1); dst += 2; 00313 } 00314 src = in_src + adsi->pwfxSrc->nBlockAlign; 00315 } 00316 } 00317 00318 #if 0 00319 static void cvtSS16msK(PACMDRVSTREAMINSTANCE adsi, 00320 const unsigned char* src, LPDWORD nsrc, 00321 unsigned char* dst, LPDWORD ndst) 00322 { 00323 } 00324 00325 static void cvtMM16msK(PACMDRVSTREAMINSTANCE adsi, 00326 const unsigned char* src, LPDWORD nsrc, 00327 unsigned char* dst, LPDWORD ndst) 00328 { 00329 } 00330 #endif 00331 00332 /*********************************************************************** 00333 * ADPCM_DriverDetails 00334 * 00335 */ 00336 static LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add) 00337 { 00338 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC; 00339 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED; 00340 add->wMid = 0xFF; 00341 add->wPid = 0x00; 00342 add->vdwACM = 0x01000000; 00343 add->vdwDriver = 0x01000000; 00344 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; 00345 add->cFormatTags = 2; /* PCM, MS ADPCM */ 00346 add->cFilterTags = 0; 00347 add->hicon = NULL; 00348 MultiByteToWideChar( CP_ACP, 0, "MS-ADPCM", -1, 00349 add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) ); 00350 MultiByteToWideChar( CP_ACP, 0, "Wine MS ADPCM converter", -1, 00351 add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) ); 00352 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1, 00353 add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) ); 00354 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1, 00355 add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) ); 00356 add->szFeatures[0] = 0; 00357 00358 return MMSYSERR_NOERROR; 00359 } 00360 00361 /*********************************************************************** 00362 * ADPCM_FormatTagDetails 00363 * 00364 */ 00365 static LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery) 00366 { 00367 static const WCHAR szPcm[]={'P','C','M',0}; 00368 static const WCHAR szMsAdPcm[]={'M','i','c','r','o','s','o','f','t',' ','A','D','P','C','M',0}; 00369 00370 switch (dwQuery) 00371 { 00372 case ACM_FORMATTAGDETAILSF_INDEX: 00373 if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE; 00374 break; 00375 case ACM_FORMATTAGDETAILSF_LARGESTSIZE: 00376 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN) 00377 { 00378 aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_ADPCM is bigger than PCM */ 00379 break; 00380 } 00381 /* fall thru */ 00382 case ACM_FORMATTAGDETAILSF_FORMATTAG: 00383 switch (aftd->dwFormatTag) 00384 { 00385 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break; 00386 case WAVE_FORMAT_ADPCM: aftd->dwFormatTagIndex = 1; break; 00387 default: return ACMERR_NOTPOSSIBLE; 00388 } 00389 break; 00390 default: 00391 WARN("Unsupported query %08x\n", dwQuery); 00392 return MMSYSERR_NOTSUPPORTED; 00393 } 00394 00395 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; 00396 switch (aftd->dwFormatTagIndex) 00397 { 00398 case 0: 00399 aftd->dwFormatTag = WAVE_FORMAT_PCM; 00400 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT); 00401 aftd->cStandardFormats = NUM_PCM_FORMATS; 00402 lstrcpyW(aftd->szFormatTag, szPcm); 00403 break; 00404 case 1: 00405 aftd->dwFormatTag = WAVE_FORMAT_ADPCM; 00406 aftd->cbFormatSize = sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET); 00407 aftd->cStandardFormats = NUM_ADPCM_FORMATS; 00408 lstrcpyW(aftd->szFormatTag, szMsAdPcm); 00409 break; 00410 } 00411 return MMSYSERR_NOERROR; 00412 } 00413 00414 /*********************************************************************** 00415 * ADPCM_FormatDetails 00416 * 00417 */ 00418 static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery) 00419 { 00420 switch (dwQuery) 00421 { 00422 case ACM_FORMATDETAILSF_FORMAT: 00423 if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00424 break; 00425 case ACM_FORMATDETAILSF_INDEX: 00426 afd->pwfx->wFormatTag = afd->dwFormatTag; 00427 switch (afd->dwFormatTag) 00428 { 00429 case WAVE_FORMAT_PCM: 00430 if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE; 00431 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels; 00432 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate; 00433 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits; 00434 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible 00435 * afd->pwfx->cbSize = 0; 00436 */ 00437 afd->pwfx->nBlockAlign = 00438 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8; 00439 afd->pwfx->nAvgBytesPerSec = 00440 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign; 00441 break; 00442 case WAVE_FORMAT_ADPCM: 00443 if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE; 00444 if (afd->cbwfx < sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET)) 00445 return ACMERR_NOTPOSSIBLE; 00446 afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels; 00447 afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate; 00448 afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits; 00449 init_wfx_adpcm((ADPCMWAVEFORMAT*)afd->pwfx); 00450 break; 00451 default: 00452 WARN("Unsupported tag %08x\n", afd->dwFormatTag); 00453 return MMSYSERR_INVALPARAM; 00454 } 00455 break; 00456 default: 00457 WARN("Unsupported query %08x\n", dwQuery); 00458 return MMSYSERR_NOTSUPPORTED; 00459 } 00460 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; 00461 afd->szFormat[0] = 0; /* let MSACM format this for us... */ 00462 00463 return MMSYSERR_NOERROR; 00464 } 00465 00466 /*********************************************************************** 00467 * ADPCM_FormatSuggest 00468 * 00469 */ 00470 static LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs) 00471 { 00472 /* some tests ... */ 00473 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) || 00474 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) || 00475 adfs->pwfxSrc->wFormatTag == adfs->pwfxDst->wFormatTag || 00476 ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00477 /* FIXME: should do those tests against the real size (according to format tag */ 00478 00479 /* If no suggestion for destination, then copy source value */ 00480 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS)) 00481 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels; 00482 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC)) 00483 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec; 00484 00485 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE)) 00486 { 00487 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) 00488 adfs->pwfxDst->wBitsPerSample = 4; 00489 else 00490 adfs->pwfxDst->wBitsPerSample = 16; 00491 } 00492 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG)) 00493 { 00494 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) 00495 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_ADPCM; 00496 else 00497 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM; 00498 } 00499 00500 /* recompute other values */ 00501 switch (adfs->pwfxDst->wFormatTag) 00502 { 00503 case WAVE_FORMAT_PCM: 00504 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8; 00505 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign; 00506 /* check if result is ok */ 00507 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00508 break; 00509 case WAVE_FORMAT_ADPCM: 00510 init_wfx_adpcm((ADPCMWAVEFORMAT*)adfs->pwfxDst); 00511 /* check if result is ok */ 00512 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00513 break; 00514 default: 00515 return ACMERR_NOTPOSSIBLE; 00516 } 00517 00518 return MMSYSERR_NOERROR; 00519 } 00520 00521 /*********************************************************************** 00522 * ADPCM_Reset 00523 * 00524 */ 00525 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad) 00526 { 00527 } 00528 00529 /*********************************************************************** 00530 * ADPCM_StreamOpen 00531 * 00532 */ 00533 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi) 00534 { 00535 AcmAdpcmData* aad; 00536 00537 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC)); 00538 00539 if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF || 00540 ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF) 00541 return ACMERR_NOTPOSSIBLE; 00542 00543 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData)); 00544 if (aad == 0) return MMSYSERR_NOMEM; 00545 00546 adsi->dwDriver = (DWORD_PTR)aad; 00547 00548 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00549 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00550 { 00551 goto theEnd; 00552 } 00553 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM && 00554 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00555 { 00556 /* resampling or mono <=> stereo not available 00557 * ADPCM algo only define 16 bit per sample output 00558 */ 00559 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec || 00560 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels || 00561 adsi->pwfxDst->wBitsPerSample != 16) 00562 goto theEnd; 00563 00564 #if 0 00565 { 00566 unsigned int nspb = ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock; 00567 FIXME("spb=%u\n", nspb); 00568 00569 /* we check that in a block, after the header, samples are present on 00570 * 4-sample packet pattern 00571 * we also check that the block alignment is bigger than the expected size 00572 */ 00573 if (((nspb - 1) & 3) != 0) goto theEnd; 00574 if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign) 00575 goto theEnd; 00576 } 00577 #endif 00578 00579 /* adpcm decoding... */ 00580 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2) 00581 aad->convert = cvtSSms16K; 00582 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1) 00583 aad->convert = cvtMMms16K; 00584 } 00585 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00586 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM) 00587 { 00588 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec || 00589 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels || 00590 adsi->pwfxSrc->wBitsPerSample != 16) 00591 goto theEnd; 00592 #if 0 00593 nspb = ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock; 00594 FIXME("spb=%u\n", nspb); 00595 00596 /* we check that in a block, after the header, samples are present on 00597 * 4-sample packet pattern 00598 * we also check that the block alignment is bigger than the expected size 00599 */ 00600 if (((nspb - 1) & 3) != 0) goto theEnd; 00601 if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign) 00602 goto theEnd; 00603 #endif 00604 #if 0 00605 /* adpcm coding... */ 00606 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2) 00607 aad->convert = cvtSS16msK; 00608 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1) 00609 aad->convert = cvtMM16msK; 00610 #endif 00611 FIXME("We don't support encoding yet\n"); 00612 goto theEnd; 00613 } 00614 else goto theEnd; 00615 ADPCM_Reset(adsi, aad); 00616 00617 return MMSYSERR_NOERROR; 00618 00619 theEnd: 00620 HeapFree(GetProcessHeap(), 0, aad); 00621 adsi->dwDriver = 0L; 00622 return MMSYSERR_NOTSUPPORTED; 00623 } 00624 00625 /*********************************************************************** 00626 * ADPCM_StreamClose 00627 * 00628 */ 00629 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi) 00630 { 00631 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver); 00632 return MMSYSERR_NOERROR; 00633 } 00634 00635 /*********************************************************************** 00636 * ADPCM_StreamSize 00637 * 00638 */ 00639 static LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss) 00640 { 00641 DWORD nblocks; 00642 WORD wSamplesPerBlock; 00643 /* wSamplesPerBlock formula comes from MSDN ADPCMWAVEFORMAT page.*/ 00644 switch (adss->fdwSize) 00645 { 00646 case ACM_STREAMSIZEF_DESTINATION: 00647 /* cbDstLength => cbSrcLength */ 00648 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00649 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM) 00650 { 00651 wSamplesPerBlock = adsi->pwfxDst->nBlockAlign * 2 / adsi->pwfxDst->nChannels - 12; 00652 nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign; 00653 if (nblocks == 0) 00654 return ACMERR_NOTPOSSIBLE; 00655 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * wSamplesPerBlock; 00656 } 00657 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM && 00658 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00659 { 00660 wSamplesPerBlock = adsi->pwfxSrc->nBlockAlign * 2 / adsi->pwfxSrc->nChannels - 12; 00661 nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * wSamplesPerBlock); 00662 if (nblocks == 0) 00663 return ACMERR_NOTPOSSIBLE; 00664 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign; 00665 } 00666 else 00667 { 00668 return MMSYSERR_NOTSUPPORTED; 00669 } 00670 break; 00671 case ACM_STREAMSIZEF_SOURCE: 00672 /* cbSrcLength => cbDstLength */ 00673 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00674 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM) 00675 { 00676 wSamplesPerBlock = adsi->pwfxDst->nBlockAlign * 2 / adsi->pwfxDst->nChannels - 12; 00677 nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * wSamplesPerBlock); 00678 if (nblocks == 0) 00679 return ACMERR_NOTPOSSIBLE; 00680 if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * wSamplesPerBlock)) 00681 /* Round block count up. */ 00682 nblocks++; 00683 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign; 00684 } 00685 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM && 00686 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00687 { 00688 wSamplesPerBlock = adsi->pwfxSrc->nBlockAlign * 2 / adsi->pwfxSrc->nChannels - 12; 00689 nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign; 00690 if (nblocks == 0) 00691 return ACMERR_NOTPOSSIBLE; 00692 if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign) 00693 /* Round block count up. */ 00694 nblocks++; 00695 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * wSamplesPerBlock; 00696 } 00697 else 00698 { 00699 return MMSYSERR_NOTSUPPORTED; 00700 } 00701 break; 00702 default: 00703 WARN("Unsupported query %08x\n", adss->fdwSize); 00704 return MMSYSERR_NOTSUPPORTED; 00705 } 00706 return MMSYSERR_NOERROR; 00707 } 00708 00709 /*********************************************************************** 00710 * ADPCM_StreamConvert 00711 * 00712 */ 00713 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh) 00714 { 00715 AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver; 00716 DWORD nsrc = adsh->cbSrcLength; 00717 DWORD ndst = adsh->cbDstLength; 00718 00719 if (adsh->fdwConvert & 00720 ~(ACM_STREAMCONVERTF_BLOCKALIGN| 00721 ACM_STREAMCONVERTF_END| 00722 ACM_STREAMCONVERTF_START)) 00723 { 00724 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert); 00725 } 00726 /* ACM_STREAMCONVERTF_BLOCKALIGN 00727 * currently all conversions are block aligned, so do nothing for this flag 00728 * ACM_STREAMCONVERTF_END 00729 * no pending data, so do nothing for this flag 00730 */ 00731 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START)) 00732 { 00733 ADPCM_Reset(adsi, aad); 00734 } 00735 00736 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst); 00737 adsh->cbSrcLengthUsed = nsrc; 00738 adsh->cbDstLengthUsed = ndst; 00739 00740 return MMSYSERR_NOERROR; 00741 } 00742 00743 /************************************************************************** 00744 * ADPCM_DriverProc [exported] 00745 */ 00746 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, 00747 LPARAM dwParam1, LPARAM dwParam2) 00748 { 00749 TRACE("(%08lx %p %04x %08lx %08lx);\n", 00750 dwDevID, hDriv, wMsg, dwParam1, dwParam2); 00751 00752 switch (wMsg) 00753 { 00754 case DRV_LOAD: return 1; 00755 case DRV_FREE: return 1; 00756 case DRV_OPEN: return ADPCM_drvOpen((LPSTR)dwParam1); 00757 case DRV_CLOSE: return ADPCM_drvClose(dwDevID); 00758 case DRV_ENABLE: return 1; 00759 case DRV_DISABLE: return 1; 00760 case DRV_QUERYCONFIGURE: return 1; 00761 case DRV_CONFIGURE: MessageBoxA(0, "MSACM MS ADPCM filter !", "Wine Driver", MB_OK); return 1; 00762 case DRV_INSTALL: return DRVCNF_RESTART; 00763 case DRV_REMOVE: return DRVCNF_RESTART; 00764 00765 case ACMDM_DRIVER_NOTIFY: 00766 /* no caching from other ACM drivers is done so far */ 00767 return MMSYSERR_NOERROR; 00768 00769 case ACMDM_DRIVER_DETAILS: 00770 return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1); 00771 00772 case ACMDM_FORMATTAG_DETAILS: 00773 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2); 00774 00775 case ACMDM_FORMAT_DETAILS: 00776 return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2); 00777 00778 case ACMDM_FORMAT_SUGGEST: 00779 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1); 00780 00781 case ACMDM_STREAM_OPEN: 00782 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1); 00783 00784 case ACMDM_STREAM_CLOSE: 00785 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1); 00786 00787 case ACMDM_STREAM_SIZE: 00788 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2); 00789 00790 case ACMDM_STREAM_CONVERT: 00791 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2); 00792 00793 case ACMDM_HARDWARE_WAVE_CAPS_INPUT: 00794 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT: 00795 /* this converter is not a hardware driver */ 00796 case ACMDM_FILTERTAG_DETAILS: 00797 case ACMDM_FILTER_DETAILS: 00798 /* this converter is not a filter */ 00799 case ACMDM_STREAM_RESET: 00800 /* only needed for asynchronous driver... we aren't, so just say it */ 00801 return MMSYSERR_NOTSUPPORTED; 00802 case ACMDM_STREAM_PREPARE: 00803 case ACMDM_STREAM_UNPREPARE: 00804 /* nothing special to do here... so don't do anything */ 00805 return MMSYSERR_NOERROR; 00806 00807 default: 00808 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); 00809 } 00810 } Generated on Sun May 27 2012 04:24:45 for ReactOS by
1.7.6.1
|