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 Street, 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 DWORD ADPCM_drvOpen(LPCSTR str) 00044 { 00045 return 1; 00046 } 00047 00048 /*********************************************************************** 00049 * ADPCM_drvClose 00050 */ 00051 static DWORD ADPCM_drvClose(DWORD dwDevID) 00052 { 00053 return 1; 00054 } 00055 00056 typedef struct tagAcmAdpcmData 00057 { 00058 void (*convert)(PACMDRVSTREAMINSTANCE 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 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 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(WAVEFORMATEX* wfx) 00105 { 00106 int i, hi; 00107 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 return 0xFFFFFFFF; 00132 } 00133 00134 static void init_wfx_adpcm(ADPCMWAVEFORMAT* awfx) 00135 { 00136 register WAVEFORMATEX* pwfx = &awfx->wfx; 00137 00138 /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample 00139 * have been initialized... */ 00140 00141 if (pwfx->wFormatTag != WAVE_FORMAT_ADPCM) {FIXME("wrong FT\n"); return;} 00142 if (ADPCM_GetFormatIndex(pwfx) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;} 00143 00144 switch (pwfx->nSamplesPerSec) 00145 { 00146 case 8000: pwfx->nBlockAlign = 256; break; 00147 case 11025: pwfx->nBlockAlign = 256; break; 00148 case 22050: pwfx->nBlockAlign = 512; break; 00149 default: 00150 case 44100: pwfx->nBlockAlign = 1024; break; 00151 } 00152 pwfx->cbSize = 2 * sizeof(WORD) + 7 * sizeof(ADPCMCOEFSET); 00153 /* 7 is the size of the block head (which contains two samples) */ 00154 00155 awfx->wSamplesPerBlock = (pwfx->nBlockAlign - (7 * pwfx->nChannels)) * (2 / pwfx->nChannels) + 2; 00156 pwfx->nAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) / awfx->wSamplesPerBlock; 00157 awfx->wNumCoef = 7; 00158 memcpy(awfx->aCoef, MSADPCM_CoeffSet, 7 * sizeof(ADPCMCOEFSET)); 00159 } 00160 00161 /*********************************************************************** 00162 * R16 00163 * 00164 * Read a 16 bit sample (correctly handles endianess) 00165 */ 00166 static inline short R16(const unsigned char* src) 00167 { 00168 return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8)); 00169 } 00170 00171 /*********************************************************************** 00172 * W16 00173 * 00174 * Write a 16 bit sample (correctly handles endianess) 00175 */ 00176 static inline void W16(unsigned char* dst, short s) 00177 { 00178 dst[0] = LOBYTE(s); 00179 dst[1] = HIBYTE(s); 00180 } 00181 00182 static inline void clamp_sample(int* sample) 00183 { 00184 if (*sample < -32768) *sample = -32768; 00185 if (*sample > 32767) *sample = 32767; 00186 } 00187 00188 static inline void process_nibble(unsigned nibble, int* idelta, 00189 int* sample1, int* sample2, 00190 const ADPCMCOEFSET* coeff) 00191 { 00192 int sample; 00193 int snibble; 00194 00195 /* nibble is in fact a signed 4 bit integer => propagate sign if needed */ 00196 snibble = (nibble & 0x08) ? (nibble - 16) : nibble; 00197 sample = ((*sample1 * coeff->iCoef1) + (*sample2 * coeff->iCoef2)) / 256 + 00198 snibble * *idelta; 00199 clamp_sample(&sample); 00200 00201 *sample2 = *sample1; 00202 *sample1 = sample; 00203 *idelta = ((MS_Delta[nibble] * *idelta) / 256); 00204 if (*idelta < 16) *idelta = 16; 00205 } 00206 00207 static void cvtSSms16K(PACMDRVSTREAMINSTANCE adsi, 00208 const unsigned char* src, LPDWORD nsrc, 00209 unsigned char* dst, LPDWORD ndst) 00210 { 00211 int ideltaL, ideltaR; 00212 int sample1L, sample2L; 00213 int sample1R, sample2R; 00214 ADPCMCOEFSET coeffL, coeffR; 00215 int nsamp; 00216 int nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock; 00217 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign, 00218 *ndst / (nsamp_blk * 2 * 2)); 00219 00220 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign; 00221 *ndst = nblock * nsamp_blk * 2 * 2; 00222 00223 nsamp_blk -= 2; /* see below for samples from block head */ 00224 for (; nblock > 0; nblock--) 00225 { 00226 const unsigned char* in_src = src; 00227 00228 assert(*src <= 6); 00229 coeffL = MSADPCM_CoeffSet[*src++]; 00230 assert(*src <= 6); 00231 coeffR = MSADPCM_CoeffSet[*src++]; 00232 00233 ideltaL = R16(src); src += 2; 00234 ideltaR = R16(src); src += 2; 00235 sample1L = R16(src); src += 2; 00236 sample1R = R16(src); src += 2; 00237 sample2L = R16(src); src += 2; 00238 sample2R = R16(src); src += 2; 00239 00240 /* store samples from block head */ 00241 W16(dst, sample2L); dst += 2; 00242 W16(dst, sample2R); dst += 2; 00243 W16(dst, sample1L); dst += 2; 00244 W16(dst, sample1R); dst += 2; 00245 00246 for (nsamp = nsamp_blk; nsamp > 0; nsamp--) 00247 { 00248 process_nibble(*src >> 4, &ideltaL, &sample1L, &sample2L, &coeffL); 00249 W16(dst, sample1L); dst += 2; 00250 process_nibble(*src++ & 0x0F, &ideltaR, &sample1R, &sample2R, &coeffR); 00251 W16(dst, sample1R); dst += 2; 00252 } 00253 src = in_src + adsi->pwfxSrc->nBlockAlign; 00254 } 00255 } 00256 00257 static void cvtMMms16K(PACMDRVSTREAMINSTANCE adsi, 00258 const unsigned char* src, LPDWORD nsrc, 00259 unsigned char* dst, LPDWORD ndst) 00260 { 00261 int idelta; 00262 int sample1, sample2; 00263 ADPCMCOEFSET coeff; 00264 int nsamp; 00265 int nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock; 00266 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign, 00267 *ndst / (nsamp_blk * 2)); 00268 00269 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign; 00270 *ndst = nblock * nsamp_blk * 2; 00271 00272 nsamp_blk -= 2; /* see below for samples from block head */ 00273 for (; nblock > 0; nblock--) 00274 { 00275 const unsigned char* in_src = src; 00276 00277 assert(*src <= 6); 00278 coeff = MSADPCM_CoeffSet[*src++]; 00279 00280 idelta = R16(src); src += 2; 00281 sample1 = R16(src); src += 2; 00282 sample2 = R16(src); src += 2; 00283 00284 /* store samples from block head */ 00285 W16(dst, sample2); dst += 2; 00286 W16(dst, sample1); dst += 2; 00287 00288 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2) 00289 { 00290 process_nibble(*src >> 4, &idelta, &sample1, &sample2, &coeff); 00291 W16(dst, sample1); dst += 2; 00292 process_nibble(*src++ & 0x0F, &idelta, &sample1, &sample2, &coeff); 00293 W16(dst, sample1); dst += 2; 00294 } 00295 src = in_src + adsi->pwfxSrc->nBlockAlign; 00296 } 00297 } 00298 00299 #if 0 00300 static void cvtSS16msK(PACMDRVSTREAMINSTANCE adsi, 00301 const unsigned char* src, LPDWORD nsrc, 00302 unsigned char* dst, LPDWORD ndst) 00303 { 00304 } 00305 00306 static void cvtMM16msK(PACMDRVSTREAMINSTANCE adsi, 00307 const unsigned char* src, LPDWORD nsrc, 00308 unsigned char* dst, LPDWORD ndst) 00309 { 00310 } 00311 #endif 00312 00313 /*********************************************************************** 00314 * ADPCM_DriverDetails 00315 * 00316 */ 00317 static LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add) 00318 { 00319 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC; 00320 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED; 00321 add->wMid = 0xFF; 00322 add->wPid = 0x00; 00323 add->vdwACM = 0x01000000; 00324 add->vdwDriver = 0x01000000; 00325 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; 00326 add->cFormatTags = 2; /* PCM, MS ADPCM */ 00327 add->cFilterTags = 0; 00328 add->hicon = NULL; 00329 MultiByteToWideChar( CP_ACP, 0, "WINE-MS ADPCM", -1, 00330 add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) ); 00331 MultiByteToWideChar( CP_ACP, 0, "Wine MS ADPCM converter", -1, 00332 add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) ); 00333 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1, 00334 add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) ); 00335 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1, 00336 add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) ); 00337 add->szFeatures[0] = 0; 00338 00339 return MMSYSERR_NOERROR; 00340 } 00341 00342 /*********************************************************************** 00343 * ADPCM_FormatTagDetails 00344 * 00345 */ 00346 static LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery) 00347 { 00348 static WCHAR szPcm[]={'P','C','M',0}; 00349 static WCHAR szMsAdPcm[]={'M','S',' ','A','d','P','C','M',0}; 00350 00351 switch (dwQuery) 00352 { 00353 case ACM_FORMATTAGDETAILSF_INDEX: 00354 if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE; 00355 break; 00356 case ACM_FORMATTAGDETAILSF_LARGESTSIZE: 00357 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN) 00358 { 00359 aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_ADPCM is bigger than PCM */ 00360 break; 00361 } 00362 /* fall thru */ 00363 case ACM_FORMATTAGDETAILSF_FORMATTAG: 00364 switch (aftd->dwFormatTag) 00365 { 00366 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break; 00367 case WAVE_FORMAT_ADPCM: aftd->dwFormatTagIndex = 1; break; 00368 default: return ACMERR_NOTPOSSIBLE; 00369 } 00370 break; 00371 default: 00372 WARN("Unsupported query %08lx\n", dwQuery); 00373 return MMSYSERR_NOTSUPPORTED; 00374 } 00375 00376 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; 00377 switch (aftd->dwFormatTagIndex) 00378 { 00379 case 0: 00380 aftd->dwFormatTag = WAVE_FORMAT_PCM; 00381 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT); 00382 aftd->cStandardFormats = NUM_PCM_FORMATS; 00383 lstrcpyW(aftd->szFormatTag, szPcm); 00384 break; 00385 case 1: 00386 aftd->dwFormatTag = WAVE_FORMAT_ADPCM; 00387 aftd->cbFormatSize = sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET); 00388 aftd->cStandardFormats = NUM_ADPCM_FORMATS; 00389 lstrcpyW(aftd->szFormatTag, szMsAdPcm); 00390 break; 00391 } 00392 return MMSYSERR_NOERROR; 00393 } 00394 00395 /*********************************************************************** 00396 * ADPCM_FormatDetails 00397 * 00398 */ 00399 static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery) 00400 { 00401 switch (dwQuery) 00402 { 00403 case ACM_FORMATDETAILSF_FORMAT: 00404 if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00405 break; 00406 case ACM_FORMATDETAILSF_INDEX: 00407 afd->pwfx->wFormatTag = afd->dwFormatTag; 00408 switch (afd->dwFormatTag) 00409 { 00410 case WAVE_FORMAT_PCM: 00411 if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE; 00412 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels; 00413 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate; 00414 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits; 00415 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible 00416 * afd->pwfx->cbSize = 0; 00417 */ 00418 afd->pwfx->nBlockAlign = 00419 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8; 00420 afd->pwfx->nAvgBytesPerSec = 00421 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign; 00422 break; 00423 case WAVE_FORMAT_ADPCM: 00424 if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE; 00425 if (afd->cbwfx < sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET)) 00426 return ACMERR_NOTPOSSIBLE; 00427 afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels; 00428 afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate; 00429 afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits; 00430 init_wfx_adpcm((ADPCMWAVEFORMAT*)afd->pwfx); 00431 break; 00432 default: 00433 WARN("Unsupported tag %08lx\n", afd->dwFormatTag); 00434 return MMSYSERR_INVALPARAM; 00435 } 00436 break; 00437 default: 00438 WARN("Unsupported query %08lx\n", dwQuery); 00439 return MMSYSERR_NOTSUPPORTED; 00440 } 00441 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; 00442 afd->szFormat[0] = 0; /* let MSACM format this for us... */ 00443 00444 return MMSYSERR_NOERROR; 00445 } 00446 00447 /*********************************************************************** 00448 * ADPCM_FormatSuggest 00449 * 00450 */ 00451 static LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs) 00452 { 00453 /* some tests ... */ 00454 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) || 00455 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) || 00456 ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00457 /* FIXME: should do those tests against the real size (according to format tag */ 00458 00459 /* If no suggestion for destination, then copy source value */ 00460 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS)) 00461 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels; 00462 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC)) 00463 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec; 00464 00465 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE)) 00466 { 00467 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) 00468 adfs->pwfxDst->wBitsPerSample = 4; 00469 else 00470 adfs->pwfxDst->wBitsPerSample = 16; 00471 } 00472 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG)) 00473 { 00474 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) 00475 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_ADPCM; 00476 else 00477 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM; 00478 } 00479 00480 /* check if result is ok */ 00481 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00482 00483 /* recompute other values */ 00484 switch (adfs->pwfxDst->wFormatTag) 00485 { 00486 case WAVE_FORMAT_PCM: 00487 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8; 00488 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign; 00489 break; 00490 case WAVE_FORMAT_ADPCM: 00491 init_wfx_adpcm((ADPCMWAVEFORMAT*)adfs->pwfxDst); 00492 break; 00493 default: 00494 FIXME("\n"); 00495 break; 00496 } 00497 00498 return MMSYSERR_NOERROR; 00499 } 00500 00501 /*********************************************************************** 00502 * ADPCM_Reset 00503 * 00504 */ 00505 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad) 00506 { 00507 } 00508 00509 /*********************************************************************** 00510 * ADPCM_StreamOpen 00511 * 00512 */ 00513 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi) 00514 { 00515 AcmAdpcmData* aad; 00516 00517 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC)); 00518 00519 if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF || 00520 ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF) 00521 return ACMERR_NOTPOSSIBLE; 00522 00523 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData)); 00524 if (aad == 0) return MMSYSERR_NOMEM; 00525 00526 adsi->dwDriver = (DWORD)aad; 00527 00528 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00529 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00530 { 00531 goto theEnd; 00532 } 00533 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM && 00534 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00535 { 00536 /* resampling or mono <=> stereo not available 00537 * ADPCM algo only define 16 bit per sample output 00538 */ 00539 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec || 00540 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels || 00541 adsi->pwfxDst->wBitsPerSample != 16) 00542 goto theEnd; 00543 00544 #if 0 00545 { 00546 unsigned int nspb = ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock; 00547 FIXME("spb=%u\n", nspb); 00548 00549 /* we check that in a block, after the header, samples are present on 00550 * 4-sample packet pattern 00551 * we also check that the block alignement is bigger than the expected size 00552 */ 00553 if (((nspb - 1) & 3) != 0) goto theEnd; 00554 if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign) 00555 goto theEnd; 00556 } 00557 #endif 00558 00559 /* adpcm decoding... */ 00560 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2) 00561 aad->convert = cvtSSms16K; 00562 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1) 00563 aad->convert = cvtMMms16K; 00564 } 00565 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00566 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM) 00567 { 00568 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec || 00569 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels || 00570 adsi->pwfxSrc->wBitsPerSample != 16) 00571 goto theEnd; 00572 #if 0 00573 nspb = ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock; 00574 FIXME("spb=%u\n", nspb); 00575 00576 /* we check that in a block, after the header, samples are present on 00577 * 4-sample packet pattern 00578 * we also check that the block alignement is bigger than the expected size 00579 */ 00580 if (((nspb - 1) & 3) != 0) goto theEnd; 00581 if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign) 00582 goto theEnd; 00583 #endif 00584 #if 0 00585 /* adpcm coding... */ 00586 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2) 00587 aad->convert = cvtSS16msK; 00588 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1) 00589 aad->convert = cvtMM16msK; 00590 #endif 00591 FIXME("We don't support encoding yet\n"); 00592 goto theEnd; 00593 } 00594 else goto theEnd; 00595 ADPCM_Reset(adsi, aad); 00596 00597 return MMSYSERR_NOERROR; 00598 00599 theEnd: 00600 HeapFree(GetProcessHeap(), 0, aad); 00601 adsi->dwDriver = 0L; 00602 return MMSYSERR_NOTSUPPORTED; 00603 } 00604 00605 /*********************************************************************** 00606 * ADPCM_StreamClose 00607 * 00608 */ 00609 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi) 00610 { 00611 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver); 00612 return MMSYSERR_NOERROR; 00613 } 00614 00615 /*********************************************************************** 00616 * ADPCM_round 00617 * 00618 */ 00619 static inline DWORD ADPCM_round(DWORD a, DWORD b, DWORD c) 00620 { 00621 assert(a && b && c); 00622 /* to be sure, always return an entire number of c... */ 00623 return ((double)a * (double)b + (double)c - 1) / (double)c; 00624 } 00625 00626 /*********************************************************************** 00627 * ADPCM_StreamSize 00628 * 00629 */ 00630 static LRESULT ADPCM_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss) 00631 { 00632 switch (adss->fdwSize) 00633 { 00634 case ACM_STREAMSIZEF_DESTINATION: 00635 /* cbDstLength => cbSrcLength */ 00636 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00637 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM) 00638 { 00639 /* don't take block overhead into account, doesn't matter too much */ 00640 adss->cbSrcLength = adss->cbDstLength * 4; 00641 } 00642 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM && 00643 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00644 { 00645 FIXME("misses the block header overhead\n"); 00646 adss->cbSrcLength = 256 + adss->cbDstLength / 4; 00647 } 00648 else 00649 { 00650 return MMSYSERR_NOTSUPPORTED; 00651 } 00652 break; 00653 case ACM_STREAMSIZEF_SOURCE: 00654 /* cbSrcLength => cbDstLength */ 00655 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00656 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM) 00657 { 00658 FIXME("misses the block header overhead\n"); 00659 adss->cbDstLength = 256 + adss->cbSrcLength / 4; 00660 } 00661 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM && 00662 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00663 { 00664 /* don't take block overhead into account, doesn't matter too much */ 00665 adss->cbDstLength = adss->cbSrcLength * 4; 00666 } 00667 else 00668 { 00669 return MMSYSERR_NOTSUPPORTED; 00670 } 00671 break; 00672 default: 00673 WARN("Unsupported query %08lx\n", adss->fdwSize); 00674 return MMSYSERR_NOTSUPPORTED; 00675 } 00676 return MMSYSERR_NOERROR; 00677 } 00678 00679 /*********************************************************************** 00680 * ADPCM_StreamConvert 00681 * 00682 */ 00683 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh) 00684 { 00685 AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver; 00686 DWORD nsrc = adsh->cbSrcLength; 00687 DWORD ndst = adsh->cbDstLength; 00688 00689 if (adsh->fdwConvert & 00690 ~(ACM_STREAMCONVERTF_BLOCKALIGN| 00691 ACM_STREAMCONVERTF_END| 00692 ACM_STREAMCONVERTF_START)) 00693 { 00694 FIXME("Unsupported fdwConvert (%08lx), ignoring it\n", adsh->fdwConvert); 00695 } 00696 /* ACM_STREAMCONVERTF_BLOCKALIGN 00697 * currently all conversions are block aligned, so do nothing for this flag 00698 * ACM_STREAMCONVERTF_END 00699 * no pending data, so do nothing for this flag 00700 */ 00701 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START)) 00702 { 00703 ADPCM_Reset(adsi, aad); 00704 } 00705 00706 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst); 00707 adsh->cbSrcLengthUsed = nsrc; 00708 adsh->cbDstLengthUsed = ndst; 00709 00710 return MMSYSERR_NOERROR; 00711 } 00712 00713 /************************************************************************** 00714 * ADPCM_DriverProc [exported] 00715 */ 00716 LRESULT CALLBACK ADPCM_DriverProc(DWORD dwDevID, HDRVR hDriv, UINT wMsg, 00717 LPARAM dwParam1, LPARAM dwParam2) 00718 { 00719 TRACE("(%08lx %08lx %04x %08lx %08lx);\n", 00720 dwDevID, (DWORD)hDriv, wMsg, dwParam1, dwParam2); 00721 00722 switch (wMsg) 00723 { 00724 case DRV_LOAD: return 1; 00725 case DRV_FREE: return 1; 00726 case DRV_OPEN: return ADPCM_drvOpen((LPSTR)dwParam1); 00727 case DRV_CLOSE: return ADPCM_drvClose(dwDevID); 00728 case DRV_ENABLE: return 1; 00729 case DRV_DISABLE: return 1; 00730 case DRV_QUERYCONFIGURE: return 1; 00731 case DRV_CONFIGURE: MessageBoxA(0, "MSACM MS ADPCM filter !", "Wine Driver", MB_OK); return 1; 00732 case DRV_INSTALL: return DRVCNF_RESTART; 00733 case DRV_REMOVE: return DRVCNF_RESTART; 00734 00735 case ACMDM_DRIVER_NOTIFY: 00736 /* no caching from other ACM drivers is done so far */ 00737 return MMSYSERR_NOERROR; 00738 00739 case ACMDM_DRIVER_DETAILS: 00740 return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1); 00741 00742 case ACMDM_FORMATTAG_DETAILS: 00743 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2); 00744 00745 case ACMDM_FORMAT_DETAILS: 00746 return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2); 00747 00748 case ACMDM_FORMAT_SUGGEST: 00749 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1); 00750 00751 case ACMDM_STREAM_OPEN: 00752 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1); 00753 00754 case ACMDM_STREAM_CLOSE: 00755 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1); 00756 00757 case ACMDM_STREAM_SIZE: 00758 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2); 00759 00760 case ACMDM_STREAM_CONVERT: 00761 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2); 00762 00763 case ACMDM_HARDWARE_WAVE_CAPS_INPUT: 00764 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT: 00765 /* this converter is not a hardware driver */ 00766 case ACMDM_FILTERTAG_DETAILS: 00767 case ACMDM_FILTER_DETAILS: 00768 /* this converter is not a filter */ 00769 case ACMDM_STREAM_RESET: 00770 /* only needed for asynchronous driver... we aren't, so just say it */ 00771 return MMSYSERR_NOTSUPPORTED; 00772 case ACMDM_STREAM_PREPARE: 00773 case ACMDM_STREAM_UNPREPARE: 00774 /* nothing special to do here... so don't do anything */ 00775 return MMSYSERR_NOERROR; 00776 00777 default: 00778 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); 00779 } 00780 return 0; 00781 } Generated on Sat May 19 2012 04:22:32 for ReactOS by
1.7.6.1
|