Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenimaadp32.c
Go to the documentation of this file.
00001 /* 00002 * IMA ADPCM handling 00003 * 00004 * Copyright (C) 2001,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_drvClose 00042 */ 00043 static LRESULT ADPCM_drvClose(DWORD_PTR dwDevID) 00044 { 00045 return 1; 00046 } 00047 00048 typedef struct tagAcmAdpcmData 00049 { 00050 void (*convert)(PACMDRVSTREAMINSTANCE adsi, 00051 const unsigned char*, LPDWORD, unsigned char*, LPDWORD); 00052 /* IMA encoding only */ 00053 BYTE stepIndexL; 00054 BYTE stepIndexR; 00055 /* short sample; */ 00056 } AcmAdpcmData; 00057 00058 /* table to list all supported formats... those are the basic ones. this 00059 * also helps given a unique index to each of the supported formats 00060 */ 00061 typedef struct 00062 { 00063 int nChannels; 00064 int nBits; 00065 int rate; 00066 } Format; 00067 00068 static const Format PCM_Formats[] = 00069 { 00070 {1, 8, 8000}, {2, 8, 8000}, {1, 16, 8000}, {2, 16, 8000}, 00071 {1, 8, 11025}, {2, 8, 11025}, {1, 16, 11025}, {2, 16, 11025}, 00072 {1, 8, 22050}, {2, 8, 22050}, {1, 16, 22050}, {2, 16, 22050}, 00073 {1, 8, 44100}, {2, 8, 44100}, {1, 16, 44100}, {2, 16, 44100}, 00074 }; 00075 00076 static const Format ADPCM_Formats[] = 00077 { 00078 {1, 4, 8000}, {2, 4, 8000}, {1, 4, 11025}, {2, 4, 11025}, 00079 {1, 4, 22050}, {2, 4, 22050}, {1, 4, 44100}, {2, 4, 44100}, 00080 }; 00081 00082 #define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0])) 00083 #define NUM_ADPCM_FORMATS (sizeof(ADPCM_Formats) / sizeof(ADPCM_Formats[0])) 00084 00085 /*********************************************************************** 00086 * ADPCM_GetFormatIndex 00087 */ 00088 static DWORD ADPCM_GetFormatIndex(const WAVEFORMATEX *wfx) 00089 { 00090 int i, hi; 00091 const Format* fmts; 00092 00093 switch (wfx->wFormatTag) 00094 { 00095 case WAVE_FORMAT_PCM: 00096 hi = NUM_PCM_FORMATS; 00097 fmts = PCM_Formats; 00098 break; 00099 case WAVE_FORMAT_IMA_ADPCM: 00100 hi = NUM_ADPCM_FORMATS; 00101 fmts = ADPCM_Formats; 00102 break; 00103 default: 00104 return 0xFFFFFFFF; 00105 } 00106 00107 for (i = 0; i < hi; i++) 00108 { 00109 if (wfx->nChannels == fmts[i].nChannels && 00110 wfx->nSamplesPerSec == fmts[i].rate && 00111 wfx->wBitsPerSample == fmts[i].nBits) 00112 return i; 00113 } 00114 00115 switch (wfx->wFormatTag) 00116 { 00117 case WAVE_FORMAT_PCM: 00118 if(3 > wfx->nChannels && 00119 wfx->nChannels > 0 && 00120 wfx->nAvgBytesPerSec == 2 * wfx->nSamplesPerSec * wfx->nChannels && 00121 wfx->nBlockAlign == 2 * wfx->nChannels && 00122 wfx->wBitsPerSample == 16) 00123 return hi; 00124 break; 00125 case WAVE_FORMAT_IMA_ADPCM: 00126 if(3 > wfx->nChannels && 00127 wfx->nChannels > 0 && 00128 wfx->wBitsPerSample == 4 && 00129 wfx->cbSize == 2) 00130 return hi; 00131 break; 00132 } 00133 00134 return 0xFFFFFFFF; 00135 } 00136 00137 static void init_wfx_ima_adpcm(IMAADPCMWAVEFORMAT* awfx/*, DWORD nba*/) 00138 { 00139 register WAVEFORMATEX* pwfx = &awfx->wfx; 00140 00141 /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample 00142 * have been initialized... */ 00143 00144 if (pwfx->wFormatTag != WAVE_FORMAT_IMA_ADPCM) {FIXME("wrong FT\n"); return;} 00145 if (ADPCM_GetFormatIndex(pwfx) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;} 00146 00147 switch (pwfx->nSamplesPerSec) 00148 { 00149 case 8000: pwfx->nBlockAlign = 256 * pwfx->nChannels; break; 00150 case 11025: pwfx->nBlockAlign = 256 * pwfx->nChannels; break; 00151 case 22050: pwfx->nBlockAlign = 512 * pwfx->nChannels; break; 00152 case 44100: pwfx->nBlockAlign = 1024 * pwfx->nChannels; break; 00153 default: /*pwfx->nBlockAlign = nba;*/ break; 00154 } 00155 pwfx->cbSize = sizeof(WORD); 00156 00157 awfx->wSamplesPerBlock = (pwfx->nBlockAlign - (4 * pwfx->nChannels) * 2) / pwfx->nChannels + 1; 00158 pwfx->nAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) / awfx->wSamplesPerBlock; 00159 } 00160 00161 /*********************************************************************** 00162 * R16 00163 * 00164 * Read a 16 bit sample (correctly handles endianness) 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 endianness) 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 /* IMA (or DVI) APDCM codec routines */ 00183 00184 static const unsigned IMA_StepTable[89] = 00185 { 00186 7, 8, 9, 10, 11, 12, 13, 14, 00187 16, 17, 19, 21, 23, 25, 28, 31, 00188 34, 37, 41, 45, 50, 55, 60, 66, 00189 73, 80, 88, 97, 107, 118, 130, 143, 00190 157, 173, 190, 209, 230, 253, 279, 307, 00191 337, 371, 408, 449, 494, 544, 598, 658, 00192 724, 796, 876, 963, 1060, 1166, 1282, 1411, 00193 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 00194 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 00195 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 00196 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 00197 32767 00198 }; 00199 00200 static const int IMA_IndexTable[16] = 00201 { 00202 -1, -1, -1, -1, 2, 4, 6, 8, 00203 -1, -1, -1, -1, 2, 4, 6, 8 00204 }; 00205 00206 static inline void clamp_step_index(int* stepIndex) 00207 { 00208 if (*stepIndex < 0 ) *stepIndex = 0; 00209 if (*stepIndex > 88) *stepIndex = 88; 00210 } 00211 00212 static inline void clamp_sample(int* sample) 00213 { 00214 if (*sample < -32768) *sample = -32768; 00215 if (*sample > 32767) *sample = 32767; 00216 } 00217 00218 static inline void process_nibble(unsigned char code, int* stepIndex, int* sample) 00219 { 00220 unsigned step; 00221 int diff; 00222 00223 code &= 0x0F; 00224 00225 step = IMA_StepTable[*stepIndex]; 00226 diff = step >> 3; 00227 if (code & 1) diff += step >> 2; 00228 if (code & 2) diff += step >> 1; 00229 if (code & 4) diff += step; 00230 if (code & 8) *sample -= diff; 00231 else *sample += diff; 00232 clamp_sample(sample); 00233 *stepIndex += IMA_IndexTable[code]; 00234 clamp_step_index(stepIndex); 00235 } 00236 00237 static inline unsigned char generate_nibble(int in, int* stepIndex, int* sample) 00238 { 00239 int effdiff, diff = in - *sample; 00240 unsigned step; 00241 unsigned char code; 00242 00243 if (diff < 0) 00244 { 00245 diff = -diff; 00246 code = 8; 00247 } 00248 else 00249 { 00250 code = 0; 00251 } 00252 00253 step = IMA_StepTable[*stepIndex]; 00254 effdiff = (step >> 3); 00255 if (diff >= step) 00256 { 00257 code |= 4; 00258 diff -= step; 00259 effdiff += step; 00260 } 00261 step >>= 1; 00262 if (diff >= step) 00263 { 00264 code |= 2; 00265 diff -= step; 00266 effdiff += step; 00267 } 00268 step >>= 1; 00269 if (diff >= step) 00270 { 00271 code |= 1; 00272 effdiff += step; 00273 } 00274 if (code & 8) *sample -= effdiff; 00275 else *sample += effdiff; 00276 clamp_sample(sample); 00277 *stepIndex += IMA_IndexTable[code]; 00278 clamp_step_index(stepIndex); 00279 return code; 00280 } 00281 00282 static void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi, 00283 const unsigned char* src, LPDWORD nsrc, 00284 unsigned char* dst, LPDWORD ndst) 00285 { 00286 int i; 00287 int sampleL, sampleR; 00288 int stepIndexL, stepIndexR; 00289 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock; 00290 int nsamp; 00291 /* compute the number of entire blocks we can decode... 00292 * it's the min of the number of entire blocks in source buffer and the number 00293 * of entire blocks in destination buffer 00294 */ 00295 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign, 00296 *ndst / (nsamp_blk * 2 * 2)); 00297 00298 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign; 00299 *ndst = nblock * (nsamp_blk * 2 * 2); 00300 00301 nsamp_blk--; /* remove the sample in block header */ 00302 for (; nblock > 0; nblock--) 00303 { 00304 const unsigned char* in_src = src; 00305 00306 /* handle headers first */ 00307 sampleL = R16(src); 00308 stepIndexL = (unsigned)*(src + 2); 00309 clamp_step_index(&stepIndexL); 00310 src += 4; 00311 W16(dst, sampleL); dst += 2; 00312 00313 sampleR = R16(src); 00314 stepIndexR = (unsigned)*(src + 2); 00315 clamp_step_index(&stepIndexR); 00316 src += 4; 00317 W16(dst, sampleR); dst += 2; 00318 00319 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8) 00320 { 00321 for (i = 0; i < 4; i++) 00322 { 00323 process_nibble(*src, &stepIndexL, &sampleL); 00324 W16(dst + (2 * i + 0) * 4 + 0, sampleL); 00325 process_nibble(*src++ >> 4, &stepIndexL, &sampleL); 00326 W16(dst + (2 * i + 1) * 4 + 0, sampleL); 00327 } 00328 for (i = 0; i < 4; i++) 00329 { 00330 process_nibble(*src , &stepIndexR, &sampleR); 00331 W16(dst + (2 * i + 0) * 4 + 2, sampleR); 00332 process_nibble(*src++ >>4, &stepIndexR, &sampleR); 00333 W16(dst + (2 * i + 1) * 4 + 2, sampleR); 00334 } 00335 dst += 32; 00336 } 00337 /* we have now to realign the source pointer on block */ 00338 src = in_src + adsi->pwfxSrc->nBlockAlign; 00339 } 00340 } 00341 00342 static void cvtMMima16K(PACMDRVSTREAMINSTANCE adsi, 00343 const unsigned char* src, LPDWORD nsrc, 00344 unsigned char* dst, LPDWORD ndst) 00345 { 00346 int sample; 00347 int stepIndex; 00348 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock; 00349 int nsamp; 00350 /* compute the number of entire blocks we can decode... 00351 * it's the min of the number of entire blocks in source buffer and the number 00352 * of entire blocks in destination buffer 00353 */ 00354 DWORD nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign, 00355 *ndst / (nsamp_blk * 2)); 00356 00357 *nsrc = nblock * adsi->pwfxSrc->nBlockAlign; 00358 *ndst = nblock * nsamp_blk * 2; 00359 00360 nsamp_blk--; /* remove the sample in block header */ 00361 for (; nblock > 0; nblock--) 00362 { 00363 const unsigned char* in_src = src; 00364 00365 /* handle header first */ 00366 sample = R16(src); 00367 stepIndex = (unsigned)*(src + 2); 00368 clamp_step_index(&stepIndex); 00369 src += 4; 00370 W16(dst, sample); dst += 2; 00371 00372 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2) 00373 { 00374 process_nibble(*src, &stepIndex, &sample); 00375 W16(dst, sample); dst += 2; 00376 process_nibble(*src++ >> 4, &stepIndex, &sample); 00377 W16(dst, sample); dst += 2; 00378 } 00379 /* we have now to realign the source pointer on block */ 00380 src = in_src + adsi->pwfxSrc->nBlockAlign; 00381 } 00382 } 00383 00384 static void cvtSS16imaK(PACMDRVSTREAMINSTANCE adsi, 00385 const unsigned char* src, LPDWORD nsrc, 00386 unsigned char* dst, LPDWORD ndst) 00387 { 00388 int stepIndexL, stepIndexR; 00389 int sampleL, sampleR; 00390 BYTE code1, code2; 00391 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock; 00392 int i, nsamp; 00393 /* compute the number of entire blocks we can decode... 00394 * it's the min of the number of entire blocks in source buffer and the number 00395 * of entire blocks in destination buffer 00396 */ 00397 DWORD nblock = min(*nsrc / (nsamp_blk * 2 * 2), 00398 *ndst / adsi->pwfxDst->nBlockAlign); 00399 00400 *nsrc = nblock * (nsamp_blk * 2 * 2); 00401 *ndst = nblock * adsi->pwfxDst->nBlockAlign; 00402 00403 stepIndexL = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL; 00404 stepIndexR = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR; 00405 00406 nsamp_blk--; /* so that we won't count the sample in header while filling the block */ 00407 00408 for (; nblock > 0; nblock--) 00409 { 00410 unsigned char* in_dst = dst; 00411 00412 /* generate header */ 00413 sampleL = R16(src); src += 2; 00414 W16(dst, sampleL); dst += 2; 00415 *dst = (unsigned char)(unsigned)stepIndexL; 00416 dst += 2; 00417 00418 sampleR = R16(src); src += 2; 00419 W16(dst, sampleR); dst += 2; 00420 *dst = (unsigned char)(unsigned)stepIndexR; 00421 dst += 2; 00422 00423 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8) 00424 { 00425 for (i = 0; i < 4; i++) 00426 { 00427 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 0), 00428 &stepIndexL, &sampleL); 00429 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 0), 00430 &stepIndexL, &sampleL); 00431 *dst++ = (code1 << 4) | code2; 00432 } 00433 for (i = 0; i < 4; i++) 00434 { 00435 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 1), 00436 &stepIndexR, &sampleR); 00437 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 1), 00438 &stepIndexR, &sampleR); 00439 *dst++ = (code1 << 4) | code2; 00440 } 00441 src += 32; 00442 } 00443 dst = in_dst + adsi->pwfxDst->nBlockAlign; 00444 } 00445 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndexL; 00446 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR = stepIndexR; 00447 } 00448 00449 static void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi, 00450 const unsigned char* src, LPDWORD nsrc, 00451 unsigned char* dst, LPDWORD ndst) 00452 { 00453 int stepIndex; 00454 int sample; 00455 BYTE code1, code2; 00456 int nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock; 00457 int nsamp; 00458 /* compute the number of entire blocks we can decode... 00459 * it's the min of the number of entire blocks in source buffer and the number 00460 * of entire blocks in destination buffer 00461 */ 00462 DWORD nblock = min(*nsrc / (nsamp_blk * 2), 00463 *ndst / adsi->pwfxDst->nBlockAlign); 00464 00465 *nsrc = nblock * (nsamp_blk * 2); 00466 *ndst = nblock * adsi->pwfxDst->nBlockAlign; 00467 00468 stepIndex = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL; 00469 nsamp_blk--; /* so that we won't count the sample in header while filling the block */ 00470 00471 for (; nblock > 0; nblock--) 00472 { 00473 unsigned char* in_dst = dst; 00474 00475 /* generate header */ 00476 /* FIXME: what about the last effective sample from previous block ??? */ 00477 /* perhaps something like: 00478 * sample += R16(src); 00479 * clamp_sample(sample); 00480 * and with : 00481 * + saving the sample in adsi->dwDriver when all blocks are done 00482 + + reset should set the field in adsi->dwDriver to 0 too 00483 */ 00484 sample = R16(src); src += 2; 00485 W16(dst, sample); dst += 2; 00486 *dst = (unsigned char)(unsigned)stepIndex; 00487 dst += 2; 00488 00489 for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2) 00490 { 00491 code1 = generate_nibble(R16(src), &stepIndex, &sample); 00492 src += 2; 00493 code2 = generate_nibble(R16(src), &stepIndex, &sample); 00494 src += 2; 00495 *dst++ = (code1 << 4) | code2; 00496 } 00497 dst = in_dst + adsi->pwfxDst->nBlockAlign; 00498 } 00499 ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndex; 00500 } 00501 00502 /*********************************************************************** 00503 * ADPCM_DriverDetails 00504 * 00505 */ 00506 static LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add) 00507 { 00508 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC; 00509 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED; 00510 add->wMid = 0x1; 00511 add->wPid = 0x22; 00512 add->vdwACM = 0x3320000; 00513 add->vdwDriver = 0x04000000; 00514 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; 00515 add->cFormatTags = 2; /* PCM, IMA ADPCM */ 00516 add->cFilterTags = 0; 00517 add->hicon = NULL; 00518 MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM", -1, 00519 add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) ); 00520 MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM CODEC", -1, 00521 add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) ); 00522 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1, 00523 add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) ); 00524 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1, 00525 add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) ); 00526 add->szFeatures[0] = 0; 00527 00528 return MMSYSERR_NOERROR; 00529 } 00530 00531 /*********************************************************************** 00532 * ADPCM_FormatTagDetails 00533 * 00534 */ 00535 static LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery) 00536 { 00537 static const WCHAR szPcm[]={'P','C','M',0}; 00538 static const WCHAR szImaAdPcm[]={'I','M','A',' ','A','D','P','C','M',0}; 00539 00540 switch (dwQuery) 00541 { 00542 case ACM_FORMATTAGDETAILSF_INDEX: 00543 if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE; 00544 break; 00545 case ACM_FORMATTAGDETAILSF_LARGESTSIZE: 00546 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN) 00547 { 00548 aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */ 00549 break; 00550 } 00551 /* fall thru */ 00552 case ACM_FORMATTAGDETAILSF_FORMATTAG: 00553 switch (aftd->dwFormatTag) 00554 { 00555 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break; 00556 case WAVE_FORMAT_IMA_ADPCM: aftd->dwFormatTagIndex = 1; break; 00557 default: return ACMERR_NOTPOSSIBLE; 00558 } 00559 break; 00560 default: 00561 WARN("Unsupported query %08x\n", dwQuery); 00562 return MMSYSERR_NOTSUPPORTED; 00563 } 00564 00565 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; 00566 switch (aftd->dwFormatTagIndex) 00567 { 00568 case 0: 00569 aftd->dwFormatTag = WAVE_FORMAT_PCM; 00570 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT); 00571 aftd->cStandardFormats = NUM_PCM_FORMATS; 00572 lstrcpyW(aftd->szFormatTag, szPcm); 00573 break; 00574 case 1: 00575 aftd->dwFormatTag = WAVE_FORMAT_IMA_ADPCM; 00576 aftd->cbFormatSize = sizeof(IMAADPCMWAVEFORMAT); 00577 aftd->cStandardFormats = NUM_ADPCM_FORMATS; 00578 lstrcpyW(aftd->szFormatTag, szImaAdPcm); 00579 break; 00580 } 00581 return MMSYSERR_NOERROR; 00582 } 00583 00584 /*********************************************************************** 00585 * ADPCM_FormatDetails 00586 * 00587 */ 00588 static LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery) 00589 { 00590 switch (dwQuery) 00591 { 00592 case ACM_FORMATDETAILSF_FORMAT: 00593 if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00594 break; 00595 case ACM_FORMATDETAILSF_INDEX: 00596 afd->pwfx->wFormatTag = afd->dwFormatTag; 00597 switch (afd->dwFormatTag) 00598 { 00599 case WAVE_FORMAT_PCM: 00600 if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE; 00601 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels; 00602 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate; 00603 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits; 00604 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible 00605 * afd->pwfx->cbSize = 0; 00606 */ 00607 afd->pwfx->nBlockAlign = 00608 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8; 00609 afd->pwfx->nAvgBytesPerSec = 00610 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign; 00611 break; 00612 case WAVE_FORMAT_IMA_ADPCM: 00613 if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE; 00614 afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels; 00615 afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate; 00616 afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits; 00617 afd->pwfx->nBlockAlign = 1024; 00618 /* we got 4 bits per sample */ 00619 afd->pwfx->nAvgBytesPerSec = 00620 (afd->pwfx->nSamplesPerSec * 4) / 8; 00621 if (afd->cbwfx >= sizeof(WAVEFORMATEX)) 00622 afd->pwfx->cbSize = sizeof(WORD); 00623 if (afd->cbwfx >= sizeof(IMAADPCMWAVEFORMAT)) 00624 ((IMAADPCMWAVEFORMAT*)afd->pwfx)->wSamplesPerBlock = (1024 - 4 * afd->pwfx->nChannels) * (2 / afd->pwfx->nChannels) + 1; 00625 break; 00626 default: 00627 WARN("Unsupported tag %08x\n", afd->dwFormatTag); 00628 return MMSYSERR_INVALPARAM; 00629 } 00630 break; 00631 default: 00632 WARN("Unsupported query %08x\n", dwQuery); 00633 return MMSYSERR_NOTSUPPORTED; 00634 } 00635 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; 00636 afd->szFormat[0] = 0; /* let MSACM format this for us... */ 00637 00638 return MMSYSERR_NOERROR; 00639 } 00640 00641 /*********************************************************************** 00642 * ADPCM_FormatSuggest 00643 * 00644 */ 00645 static LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs) 00646 { 00647 /* some tests ... */ 00648 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) || 00649 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) || 00650 adfs->pwfxSrc->wFormatTag == adfs->pwfxDst->wFormatTag || 00651 ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00652 00653 /* If no suggestion for destination, then copy source value */ 00654 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS)) 00655 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels; 00656 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC)) 00657 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec; 00658 00659 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE)) 00660 { 00661 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) 00662 adfs->pwfxDst->wBitsPerSample = 4; 00663 else 00664 adfs->pwfxDst->wBitsPerSample = 16; 00665 } 00666 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG)) 00667 { 00668 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) 00669 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM; 00670 else 00671 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM; 00672 } 00673 00674 /* recompute other values */ 00675 switch (adfs->pwfxDst->wFormatTag) 00676 { 00677 case WAVE_FORMAT_PCM: 00678 if (adfs->cbwfxSrc < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE; 00679 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8; 00680 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign; 00681 /* check if result is ok */ 00682 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00683 break; 00684 case WAVE_FORMAT_IMA_ADPCM: 00685 if (adfs->cbwfxDst < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE; 00686 init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT*)adfs->pwfxDst); 00687 /* FIXME: not handling header overhead */ 00688 TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock); 00689 /* check if result is ok */ 00690 if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00691 break; 00692 default: 00693 return ACMERR_NOTPOSSIBLE; 00694 } 00695 00696 return MMSYSERR_NOERROR; 00697 } 00698 00699 /*********************************************************************** 00700 * ADPCM_Reset 00701 * 00702 */ 00703 static void ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad) 00704 { 00705 aad->stepIndexL = aad->stepIndexR = 0; 00706 } 00707 00708 /*********************************************************************** 00709 * ADPCM_StreamOpen 00710 * 00711 */ 00712 static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi) 00713 { 00714 AcmAdpcmData* aad; 00715 unsigned nspb; 00716 00717 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC)); 00718 00719 if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF || 00720 ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF) 00721 return ACMERR_NOTPOSSIBLE; 00722 00723 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData)); 00724 if (aad == 0) return MMSYSERR_NOMEM; 00725 00726 adsi->dwDriver = (DWORD_PTR)aad; 00727 00728 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00729 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00730 { 00731 goto theEnd; 00732 } 00733 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM && 00734 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00735 { 00736 /* resampling or mono <=> stereo not available 00737 * ADPCM algo only define 16 bit per sample output 00738 */ 00739 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec || 00740 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels || 00741 adsi->pwfxDst->wBitsPerSample != 16) 00742 goto theEnd; 00743 00744 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock; 00745 TRACE("spb=%u\n", nspb); 00746 00747 /* we check that in a block, after the header, samples are present on 00748 * 4-sample packet pattern 00749 * we also check that the block alignment is bigger than the expected size 00750 */ 00751 if (((nspb - 1) & 3) != 0) goto theEnd; 00752 if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign) 00753 goto theEnd; 00754 00755 /* adpcm decoding... */ 00756 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2) 00757 aad->convert = cvtSSima16K; 00758 if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1) 00759 aad->convert = cvtMMima16K; 00760 } 00761 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00762 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM) 00763 { 00764 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec || 00765 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels || 00766 adsi->pwfxSrc->wBitsPerSample != 16) 00767 goto theEnd; 00768 00769 nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock; 00770 TRACE("spb=%u\n", nspb); 00771 00772 /* we check that in a block, after the header, samples are present on 00773 * 4-sample packet pattern 00774 * we also check that the block alignment is bigger than the expected size 00775 */ 00776 if (((nspb - 1) & 3) != 0) goto theEnd; 00777 if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign) 00778 goto theEnd; 00779 00780 /* adpcm coding... */ 00781 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2) 00782 aad->convert = cvtSS16imaK; 00783 if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1) 00784 aad->convert = cvtMM16imaK; 00785 } 00786 else goto theEnd; 00787 ADPCM_Reset(adsi, aad); 00788 00789 return MMSYSERR_NOERROR; 00790 00791 theEnd: 00792 HeapFree(GetProcessHeap(), 0, aad); 00793 adsi->dwDriver = 0L; 00794 return MMSYSERR_NOTSUPPORTED; 00795 } 00796 00797 /*********************************************************************** 00798 * ADPCM_StreamClose 00799 * 00800 */ 00801 static LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi) 00802 { 00803 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver); 00804 return MMSYSERR_NOERROR; 00805 } 00806 00807 /*********************************************************************** 00808 * ADPCM_StreamSize 00809 * 00810 */ 00811 static LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss) 00812 { 00813 DWORD nblocks; 00814 00815 switch (adss->fdwSize) 00816 { 00817 case ACM_STREAMSIZEF_DESTINATION: 00818 /* cbDstLength => cbSrcLength */ 00819 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00820 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM) 00821 { 00822 nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign; 00823 if (nblocks == 0) 00824 return ACMERR_NOTPOSSIBLE; 00825 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock; 00826 } 00827 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM && 00828 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00829 { 00830 nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock); 00831 if (nblocks == 0) 00832 return ACMERR_NOTPOSSIBLE; 00833 adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign; 00834 } 00835 else 00836 { 00837 return MMSYSERR_NOTSUPPORTED; 00838 } 00839 break; 00840 case ACM_STREAMSIZEF_SOURCE: 00841 /* cbSrcLength => cbDstLength */ 00842 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00843 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM) 00844 { 00845 nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock); 00846 if (nblocks == 0) 00847 return ACMERR_NOTPOSSIBLE; 00848 if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock)) 00849 /* Round block count up. */ 00850 nblocks++; 00851 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign; 00852 } 00853 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM && 00854 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00855 { 00856 nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign; 00857 if (nblocks == 0) 00858 return ACMERR_NOTPOSSIBLE; 00859 if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign) 00860 /* Round block count up. */ 00861 nblocks++; 00862 adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock; 00863 } 00864 else 00865 { 00866 return MMSYSERR_NOTSUPPORTED; 00867 } 00868 break; 00869 default: 00870 WARN("Unsupported query %08x\n", adss->fdwSize); 00871 return MMSYSERR_NOTSUPPORTED; 00872 } 00873 return MMSYSERR_NOERROR; 00874 } 00875 00876 /*********************************************************************** 00877 * ADPCM_StreamConvert 00878 * 00879 */ 00880 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh) 00881 { 00882 AcmAdpcmData* aad = (AcmAdpcmData*)adsi->dwDriver; 00883 DWORD nsrc = adsh->cbSrcLength; 00884 DWORD ndst = adsh->cbDstLength; 00885 00886 if (adsh->fdwConvert & 00887 ~(ACM_STREAMCONVERTF_BLOCKALIGN| 00888 ACM_STREAMCONVERTF_END| 00889 ACM_STREAMCONVERTF_START)) 00890 { 00891 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert); 00892 } 00893 /* ACM_STREAMCONVERTF_BLOCKALIGN 00894 * currently all conversions are block aligned, so do nothing for this flag 00895 * ACM_STREAMCONVERTF_END 00896 * no pending data, so do nothing for this flag 00897 */ 00898 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START)) 00899 { 00900 ADPCM_Reset(adsi, aad); 00901 } 00902 00903 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst); 00904 adsh->cbSrcLengthUsed = nsrc; 00905 adsh->cbDstLengthUsed = ndst; 00906 00907 return MMSYSERR_NOERROR; 00908 } 00909 00910 /************************************************************************** 00911 * ADPCM_DriverProc [exported] 00912 */ 00913 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, 00914 LPARAM dwParam1, LPARAM dwParam2) 00915 { 00916 TRACE("(%08lx %p %04x %08lx %08lx);\n", 00917 dwDevID, hDriv, wMsg, dwParam1, dwParam2); 00918 00919 switch (wMsg) 00920 { 00921 case DRV_LOAD: return 1; 00922 case DRV_FREE: return 1; 00923 case DRV_OPEN: return 1; 00924 case DRV_CLOSE: return ADPCM_drvClose(dwDevID); 00925 case DRV_ENABLE: return 1; 00926 case DRV_DISABLE: return 1; 00927 case DRV_QUERYCONFIGURE: return 1; 00928 case DRV_CONFIGURE: MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK); return 1; 00929 case DRV_INSTALL: return DRVCNF_RESTART; 00930 case DRV_REMOVE: return DRVCNF_RESTART; 00931 00932 case ACMDM_DRIVER_NOTIFY: 00933 /* no caching from other ACM drivers is done so far */ 00934 return MMSYSERR_NOERROR; 00935 00936 case ACMDM_DRIVER_DETAILS: 00937 return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1); 00938 00939 case ACMDM_FORMATTAG_DETAILS: 00940 return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2); 00941 00942 case ACMDM_FORMAT_DETAILS: 00943 return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2); 00944 00945 case ACMDM_FORMAT_SUGGEST: 00946 return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1); 00947 00948 case ACMDM_STREAM_OPEN: 00949 return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1); 00950 00951 case ACMDM_STREAM_CLOSE: 00952 return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1); 00953 00954 case ACMDM_STREAM_SIZE: 00955 return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2); 00956 00957 case ACMDM_STREAM_CONVERT: 00958 return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2); 00959 00960 case ACMDM_HARDWARE_WAVE_CAPS_INPUT: 00961 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT: 00962 /* this converter is not a hardware driver */ 00963 case ACMDM_FILTERTAG_DETAILS: 00964 case ACMDM_FILTER_DETAILS: 00965 /* this converter is not a filter */ 00966 case ACMDM_STREAM_RESET: 00967 /* only needed for asynchronous driver... we aren't, so just say it */ 00968 return MMSYSERR_NOTSUPPORTED; 00969 case ACMDM_STREAM_PREPARE: 00970 case ACMDM_STREAM_UNPREPARE: 00971 /* nothing special to do here... so don't do anything */ 00972 return MMSYSERR_NOERROR; 00973 00974 default: 00975 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); 00976 } 00977 } Generated on Sun May 27 2012 04:24:02 for ReactOS by
1.7.6.1
|