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