Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpcmconverter.c
Go to the documentation of this file.
00001 /* -*- tab-width: 8; c-basic-offset: 4 -*- */ 00002 00003 /* 00004 * MSACM32 library 00005 * 00006 * Copyright 2000 Eric Pouech 00007 * Copyright 2004 Robert Reif 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00022 * 00023 * FIXME / TODO list 00024 * + get rid of hack for PCM_DriverProc (msacm32.dll shouldn't export 00025 * a DriverProc, but this would require implementing a generic 00026 * embedded driver handling scheme in msacm32.dll which isn't done yet 00027 */ 00028 00029 #include "config.h" 00030 00031 #include <assert.h> 00032 #include <stdarg.h> 00033 #include <string.h> 00034 00035 #include "windef.h" 00036 #include "winbase.h" 00037 #include "mmsystem.h" 00038 #define NOBITMAP 00039 #include "mmreg.h" 00040 #include "msacm.h" 00041 #include "wingdi.h" 00042 #include "winnls.h" 00043 #include "winuser.h" 00044 00045 #include "msacmdrv.h" 00046 #include "wineacm.h" 00047 00048 #include "wine/debug.h" 00049 00050 WINE_DEFAULT_DEBUG_CHANNEL(msacm); 00051 00052 /*********************************************************************** 00053 * PCM_drvOpen 00054 */ 00055 static DWORD PCM_drvOpen(LPCSTR str, PACMDRVOPENDESCW adod) 00056 { 00057 TRACE("(%p, %p)\n", str, adod); 00058 00059 return (adod == NULL) || 00060 (adod->fccType == ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC && 00061 adod->fccComp == ACMDRIVERDETAILS_FCCCOMP_UNDEFINED); 00062 } 00063 00064 /*********************************************************************** 00065 * PCM_drvClose 00066 */ 00067 static DWORD PCM_drvClose(DWORD dwDevID) 00068 { 00069 TRACE("(%d)\n", dwDevID); 00070 00071 return 1; 00072 } 00073 00074 #define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0])) 00075 #define NUM_OF(a,b) ((a)/(b)) 00076 00077 /* flags for fdwDriver */ 00078 #define PCM_RESAMPLE 1 00079 00080 /* data used while converting */ 00081 typedef struct tagAcmPcmData { 00082 /* conversion routine, depending if rate conversion is required */ 00083 union { 00084 void (*cvtKeepRate)(const unsigned char*, int, unsigned char*); 00085 void (*cvtChangeRate)(DWORD, const unsigned char*, LPDWORD, 00086 DWORD, unsigned char*, LPDWORD); 00087 } cvt; 00088 } AcmPcmData; 00089 00090 /* table to list all supported formats... those are the basic ones. this 00091 * also helps given a unique index to each of the supported formats 00092 */ 00093 static const struct { 00094 int nChannels; 00095 int nBits; 00096 int rate; 00097 } PCM_Formats[] = { 00098 {1, 8, 8000}, {2, 8, 8000}, {1, 16, 8000}, {2, 16, 8000}, 00099 {1, 8, 11025}, {2, 8, 11025}, {1, 16, 11025}, {2, 16, 11025}, 00100 {1, 8, 22050}, {2, 8, 22050}, {1, 16, 22050}, {2, 16, 22050}, 00101 {1, 8, 44100}, {2, 8, 44100}, {1, 16, 44100}, {2, 16, 44100}, 00102 {1, 8, 48000}, {2, 8, 48000}, {1, 16, 48000}, {2, 16, 48000}, 00103 {1, 8, 96000}, {2, 8, 96000}, {1, 16, 96000}, {2, 16, 96000} 00104 }; 00105 00106 /*********************************************************************** 00107 * PCM_GetFormatIndex 00108 */ 00109 static DWORD PCM_GetFormatIndex(LPWAVEFORMATEX wfx) 00110 { 00111 unsigned int i; 00112 TRACE("(%p)\n", wfx); 00113 00114 for (i = 0; i < NUM_PCM_FORMATS; i++) { 00115 if (wfx->nChannels == PCM_Formats[i].nChannels && 00116 wfx->nSamplesPerSec == PCM_Formats[i].rate && 00117 wfx->wBitsPerSample == PCM_Formats[i].nBits) 00118 return i; 00119 } 00120 return 0xFFFFFFFF; 00121 } 00122 00123 /* PCM Conversions: 00124 * 00125 * parameters: 00126 * + 8 bit unsigned vs 16 bit signed 00127 * + mono vs stereo (1 or 2 channels) 00128 * + sampling rate (8.0, 11.025, 22.05, 44.1 kHz are defined, but algo 00129 * shall work in all cases) 00130 * 00131 * mono => stereo: copy the same sample on Left & Right channels 00132 * stereo => mono: use the sum of Left & Right channels 00133 */ 00134 00135 /*********************************************************************** 00136 * C816 00137 * 00138 * Converts a 8 bit sample to a 16 bit one 00139 */ 00140 static inline short C816(unsigned char b) 00141 { 00142 return (b - 128) << 8; 00143 } 00144 00145 /*********************************************************************** 00146 * C168 00147 * 00148 * Converts a 16 bit sample to a 8 bit one (data loss !!) 00149 */ 00150 static inline unsigned char C168(short s) 00151 { 00152 return HIBYTE(s) ^ (unsigned char)0x80; 00153 } 00154 00155 /*********************************************************************** 00156 * R16 00157 * 00158 * Read a 16 bit sample (correctly handles endianess) 00159 */ 00160 static inline short R16(const unsigned char* src) 00161 { 00162 return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8)); 00163 } 00164 00165 /*********************************************************************** 00166 * W16 00167 * 00168 * Write a 16 bit sample (correctly handles endianess) 00169 */ 00170 static inline void W16(unsigned char* dst, short s) 00171 { 00172 dst[0] = LOBYTE(s); 00173 dst[1] = HIBYTE(s); 00174 } 00175 00176 /*********************************************************************** 00177 * M16 00178 * 00179 * Convert the (l,r) 16 bit stereo sample into a 16 bit mono 00180 * (takes the sum of the two values) 00181 */ 00182 static inline short M16(short l, short r) 00183 { 00184 int sum = l + r; 00185 00186 /* clip sum to saturation */ 00187 if (sum > 32767) 00188 sum = 32767; 00189 else if (sum < -32768) 00190 sum = -32768; 00191 00192 return sum; 00193 } 00194 00195 /*********************************************************************** 00196 * M8 00197 * 00198 * Convert the (l,r) 8 bit stereo sample into a 8 bit mono 00199 * (takes the sum of the two values) 00200 */ 00201 static inline unsigned char M8(unsigned char a, unsigned char b) 00202 { 00203 int l = a - 128; 00204 int r = b - 128; 00205 int sum = (l + r) + 128; 00206 00207 /* clip sum to saturation */ 00208 if (sum > 0xff) 00209 sum = 0xff; 00210 else if (sum < 0) 00211 sum = 0; 00212 00213 return sum; 00214 } 00215 00216 /* the conversion routines without rate conversion are labelled cvt<X><Y><N><M>K 00217 * where : 00218 * <X> is the (M)ono/(S)tereo configuration of input channel 00219 * <Y> is the (M)ono/(S)tereo configuration of output channel 00220 * <N> is the number of bits of input channel (8 or 16) 00221 * <M> is the number of bits of output channel (8 or 16) 00222 * 00223 * in the parameters, ns is always the number of samples, so the size of input 00224 * buffer (resp output buffer) is ns * (<X> == 'Mono' ? 1:2) * (<N> == 8 ? 1:2) 00225 */ 00226 00227 static void cvtMM88K(const unsigned char* src, int ns, unsigned char* dst) 00228 { 00229 TRACE("(%p, %d, %p)\n", src, ns, dst); 00230 memcpy(dst, src, ns); 00231 } 00232 00233 static void cvtSS88K(const unsigned char* src, int ns, unsigned char* dst) 00234 { 00235 TRACE("(%p, %d, %p)\n", src, ns, dst); 00236 memcpy(dst, src, ns * 2); 00237 } 00238 00239 static void cvtMM1616K(const unsigned char* src, int ns, unsigned char* dst) 00240 { 00241 TRACE("(%p, %d, %p)\n", src, ns, dst); 00242 memcpy(dst, src, ns * 2); 00243 } 00244 00245 static void cvtSS1616K(const unsigned char* src, int ns, unsigned char* dst) 00246 { 00247 TRACE("(%p, %d, %p)\n", src, ns, dst); 00248 memcpy(dst, src, ns * 4); 00249 } 00250 00251 static void cvtMS88K(const unsigned char* src, int ns, unsigned char* dst) 00252 { 00253 TRACE("(%p, %d, %p)\n", src, ns, dst); 00254 00255 while (ns--) { 00256 *dst++ = *src; 00257 *dst++ = *src++; 00258 } 00259 } 00260 00261 static void cvtMS816K(const unsigned char* src, int ns, unsigned char* dst) 00262 { 00263 short v; 00264 TRACE("(%p, %d, %p)\n", src, ns, dst); 00265 00266 while (ns--) { 00267 v = C816(*src++); 00268 W16(dst, v); dst += 2; 00269 W16(dst, v); dst += 2; 00270 } 00271 } 00272 00273 static void cvtMS168K(const unsigned char* src, int ns, unsigned char* dst) 00274 { 00275 unsigned char v; 00276 TRACE("(%p, %d, %p)\n", src, ns, dst); 00277 00278 while (ns--) { 00279 v = C168(R16(src)); src += 2; 00280 *dst++ = v; 00281 *dst++ = v; 00282 } 00283 } 00284 00285 static void cvtMS1616K(const unsigned char* src, int ns, unsigned char* dst) 00286 { 00287 short v; 00288 TRACE("(%p, %d, %p)\n", src, ns, dst); 00289 00290 while (ns--) { 00291 v = R16(src); src += 2; 00292 W16(dst, v); dst += 2; 00293 W16(dst, v); dst += 2; 00294 } 00295 } 00296 00297 static void cvtSM88K(const unsigned char* src, int ns, unsigned char* dst) 00298 { 00299 TRACE("(%p, %d, %p)\n", src, ns, dst); 00300 00301 while (ns--) { 00302 *dst++ = M8(src[0], src[1]); 00303 src += 2; 00304 } 00305 } 00306 00307 static void cvtSM816K(const unsigned char* src, int ns, unsigned char* dst) 00308 { 00309 short v; 00310 TRACE("(%p, %d, %p)\n", src, ns, dst); 00311 00312 while (ns--) { 00313 v = M16(C816(src[0]), C816(src[1])); 00314 src += 2; 00315 W16(dst, v); dst += 2; 00316 } 00317 } 00318 00319 static void cvtSM168K(const unsigned char* src, int ns, unsigned char* dst) 00320 { 00321 TRACE("(%p, %d, %p)\n", src, ns, dst); 00322 00323 while (ns--) { 00324 *dst++ = C168(M16(R16(src), R16(src + 2))); 00325 src += 4; 00326 } 00327 } 00328 00329 static void cvtSM1616K(const unsigned char* src, int ns, unsigned char* dst) 00330 { 00331 TRACE("(%p, %d, %p)\n", src, ns, dst); 00332 00333 while (ns--) { 00334 W16(dst, M16(R16(src),R16(src+2))); dst += 2; 00335 src += 4; 00336 } 00337 } 00338 00339 static void cvtMM816K(const unsigned char* src, int ns, unsigned char* dst) 00340 { 00341 TRACE("(%p, %d, %p)\n", src, ns, dst); 00342 00343 while (ns--) { 00344 W16(dst, C816(*src++)); dst += 2; 00345 } 00346 } 00347 00348 static void cvtSS816K(const unsigned char* src, int ns, unsigned char* dst) 00349 { 00350 TRACE("(%p, %d, %p)\n", src, ns, dst); 00351 00352 while (ns--) { 00353 W16(dst, C816(*src++)); dst += 2; 00354 W16(dst, C816(*src++)); dst += 2; 00355 } 00356 } 00357 00358 static void cvtMM168K(const unsigned char* src, int ns, unsigned char* dst) 00359 { 00360 TRACE("(%p, %d, %p)\n", src, ns, dst); 00361 00362 while (ns--) { 00363 *dst++ = C168(R16(src)); src += 2; 00364 } 00365 } 00366 00367 static void cvtSS168K(const unsigned char* src, int ns, unsigned char* dst) 00368 { 00369 TRACE("(%p, %d, %p)\n", src, ns, dst); 00370 00371 while (ns--) { 00372 *dst++ = C168(R16(src)); src += 2; 00373 *dst++ = C168(R16(src)); src += 2; 00374 } 00375 } 00376 00377 00378 typedef void (*PCM_CONVERT_KEEP_RATE)(const unsigned char*, int, unsigned char*); 00379 00380 static const PCM_CONVERT_KEEP_RATE PCM_ConvertKeepRate[16] = { 00381 cvtSS88K, cvtSM88K, cvtMS88K, cvtMM88K, 00382 cvtSS816K, cvtSM816K, cvtMS816K, cvtMM816K, 00383 cvtSS168K, cvtSM168K, cvtMS168K, cvtMM168K, 00384 cvtSS1616K, cvtSM1616K, cvtMS1616K, cvtMM1616K, 00385 }; 00386 00387 /* the conversion routines with rate conversion are labelled cvt<X><Y><N><M>C 00388 * where : 00389 * <X> is the (M)ono/(S)tereo configuration of input channel 00390 * <Y> is the (M)ono/(S)tereo configuration of output channel 00391 * <N> is the number of bits of input channel (8 or 16) 00392 * <M> is the number of bits of output channel (8 or 16) 00393 * 00394 */ 00395 static void cvtSS88C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00396 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00397 { 00398 DWORD error = dstRate / 2; 00399 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00400 00401 while ((*ndst)--) { 00402 *dst++ = *src; 00403 *dst++ = *src; 00404 error = error + srcRate; 00405 while (error > dstRate) { 00406 src += 2; 00407 (*nsrc)--; 00408 if (*nsrc == 0) 00409 return; 00410 error = error - dstRate; 00411 } 00412 } 00413 } 00414 00415 static void cvtSM88C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00416 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00417 { 00418 DWORD error = dstRate / 2; 00419 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00420 00421 while ((*ndst)--) { 00422 *dst++ = M8(src[0], src[1]); 00423 error = error + srcRate; 00424 while (error > dstRate) { 00425 src += 2; 00426 (*nsrc)--; 00427 if (*nsrc == 0) 00428 return; 00429 error = error - dstRate; 00430 } 00431 } 00432 } 00433 00434 static void cvtMS88C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00435 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00436 { 00437 DWORD error = dstRate / 2; 00438 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00439 00440 while ((*ndst)--) { 00441 *dst++ = *src; 00442 *dst++ = *src; 00443 error = error + srcRate; 00444 while (error > dstRate) { 00445 src++; 00446 (*nsrc)--; 00447 if (*nsrc == 0) 00448 return; 00449 error = error - dstRate; 00450 } 00451 } 00452 } 00453 00454 static void cvtMM88C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00455 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00456 { 00457 DWORD error = dstRate / 2; 00458 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00459 00460 while ((*ndst)--) { 00461 *dst++ = *src; 00462 error = error + srcRate; 00463 while (error > dstRate) { 00464 src++; 00465 (*nsrc)--; 00466 if (*nsrc==0) 00467 return; 00468 error = error - dstRate; 00469 } 00470 } 00471 } 00472 00473 static void cvtSS816C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00474 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00475 { 00476 DWORD error = dstRate / 2; 00477 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00478 00479 while ((*ndst)--) { 00480 W16(dst, C816(src[0])); dst += 2; 00481 W16(dst, C816(src[1])); dst += 2; 00482 error = error + srcRate; 00483 while (error > dstRate) { 00484 src += 2; 00485 (*nsrc)--; 00486 if (*nsrc==0) 00487 return; 00488 error = error - dstRate; 00489 } 00490 } 00491 } 00492 00493 static void cvtSM816C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00494 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00495 { 00496 DWORD error = dstRate / 2; 00497 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00498 00499 while ((*ndst)--) { 00500 W16(dst, M16(C816(src[0]), C816(src[1]))); dst += 2; 00501 error = error + srcRate; 00502 while (error > dstRate) { 00503 src += 2; 00504 (*nsrc)--; 00505 if (*nsrc==0) 00506 return; 00507 error = error - dstRate; 00508 } 00509 } 00510 } 00511 00512 static void cvtMS816C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00513 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00514 { 00515 DWORD error = dstRate / 2; 00516 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00517 00518 while ((*ndst)--) { 00519 W16(dst, C816(*src)); dst += 2; 00520 W16(dst, C816(*src)); dst += 2; 00521 error = error + srcRate; 00522 while (error > dstRate) { 00523 src++; 00524 (*nsrc)--; 00525 if (*nsrc==0) 00526 return; 00527 error = error - dstRate; 00528 } 00529 } 00530 } 00531 00532 static void cvtMM816C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00533 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00534 { 00535 DWORD error = dstRate / 2; 00536 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00537 00538 while ((*ndst)--) { 00539 W16(dst, C816(*src)); dst += 2; 00540 error = error + srcRate; 00541 while (error > dstRate) { 00542 src++; 00543 (*nsrc)--; 00544 if (*nsrc==0) 00545 return; 00546 error = error - dstRate; 00547 } 00548 } 00549 } 00550 00551 static void cvtSS168C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00552 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00553 { 00554 DWORD error = dstRate / 2; 00555 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00556 00557 while ((*ndst)--) { 00558 *dst++ = C168(R16(src)); 00559 *dst++ = C168(R16(src + 2)); 00560 error = error + srcRate; 00561 while (error > dstRate) { 00562 src += 4; 00563 (*nsrc)--; 00564 if (*nsrc==0) 00565 return; 00566 error = error - dstRate; 00567 } 00568 } 00569 } 00570 00571 static void cvtSM168C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00572 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00573 { 00574 DWORD error = dstRate / 2; 00575 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00576 00577 while ((*ndst)--) { 00578 *dst++ = C168(M16(R16(src), R16(src + 2))); 00579 error = error + srcRate; 00580 while (error > dstRate) { 00581 src += 4; 00582 (*nsrc)--; 00583 if (*nsrc==0) 00584 return; 00585 error = error - dstRate; 00586 } 00587 } 00588 } 00589 00590 static void cvtMS168C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00591 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00592 { 00593 DWORD error = dstRate / 2; 00594 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00595 00596 while ((*ndst)--) { 00597 *dst++ = C168(R16(src)); 00598 *dst++ = C168(R16(src)); 00599 error = error + srcRate; 00600 while (error > dstRate) { 00601 src += 2; 00602 (*nsrc)--; 00603 if (*nsrc==0) 00604 return; 00605 error = error - dstRate; 00606 } 00607 } 00608 } 00609 00610 static void cvtMM168C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00611 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00612 { 00613 DWORD error = dstRate / 2; 00614 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00615 00616 while ((*ndst)--) { 00617 *dst++ = C168(R16(src)); 00618 error = error + srcRate; 00619 while (error > dstRate) { 00620 src += 2; 00621 (*nsrc)--; 00622 if (*nsrc == 0) 00623 return; 00624 error = error - dstRate; 00625 } 00626 } 00627 } 00628 00629 static void cvtSS1616C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00630 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00631 { 00632 DWORD error = dstRate / 2; 00633 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00634 00635 while ((*ndst)--) { 00636 W16(dst, R16(src)); dst += 2; 00637 W16(dst, R16(src)); dst += 2; 00638 error = error + srcRate; 00639 while (error > dstRate) { 00640 src += 4; 00641 (*nsrc)--; 00642 if (*nsrc == 0) 00643 return; 00644 error = error - dstRate; 00645 } 00646 } 00647 } 00648 00649 static void cvtSM1616C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00650 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00651 { 00652 DWORD error = dstRate / 2; 00653 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00654 00655 while ((*ndst)--) { 00656 W16(dst, M16(R16(src), R16(src + 2))); dst += 2; 00657 error = error + srcRate; 00658 while (error > dstRate) { 00659 src += 4; 00660 (*nsrc)--; 00661 if (*nsrc == 0) 00662 return; 00663 error = error - dstRate; 00664 } 00665 } 00666 } 00667 00668 static void cvtMS1616C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00669 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00670 { 00671 DWORD error = dstRate / 2; 00672 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00673 00674 while((*ndst)--) { 00675 W16(dst, R16(src)); dst += 2; 00676 W16(dst, R16(src)); dst += 2; 00677 error = error + srcRate; 00678 while (error > dstRate) { 00679 src += 2; 00680 (*nsrc)--; 00681 if (*nsrc == 0) 00682 return; 00683 error = error - dstRate; 00684 } 00685 } 00686 } 00687 00688 static void cvtMM1616C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc, 00689 DWORD dstRate, unsigned char* dst, LPDWORD ndst) 00690 { 00691 DWORD error = dstRate / 2; 00692 TRACE("(%d, %p, %p, %d, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst); 00693 00694 while ((*ndst)--) { 00695 W16(dst, R16(src)); dst += 2; 00696 error = error + srcRate; 00697 while (error > dstRate) { 00698 src += 2; 00699 (*nsrc)--; 00700 if (*nsrc == 0) 00701 return; 00702 error = error - dstRate; 00703 } 00704 } 00705 } 00706 00707 typedef void (*PCM_CONVERT_CHANGE_RATE)(DWORD, const unsigned char*, LPDWORD, DWORD, unsigned char*, LPDWORD); 00708 00709 static const PCM_CONVERT_CHANGE_RATE PCM_ConvertChangeRate[16] = { 00710 cvtSS88C, cvtSM88C, cvtMS88C, cvtMM88C, 00711 cvtSS816C, cvtSM816C, cvtMS816C, cvtMM816C, 00712 cvtSS168C, cvtSM168C, cvtMS168C, cvtMM168C, 00713 cvtSS1616C, cvtSM1616C, cvtMS1616C, cvtMM1616C, 00714 }; 00715 00716 /*********************************************************************** 00717 * PCM_DriverDetails 00718 * 00719 */ 00720 static LRESULT PCM_DriverDetails(PACMDRIVERDETAILSW add) 00721 { 00722 TRACE("(%p)\n", add); 00723 00724 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC; 00725 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED; 00726 add->wMid = 0xFF; 00727 add->wPid = 0x00; 00728 add->vdwACM = 0x01000000; 00729 add->vdwDriver = 0x01000000; 00730 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER; 00731 add->cFormatTags = 1; 00732 add->cFilterTags = 0; 00733 add->hicon = NULL; 00734 MultiByteToWideChar( CP_ACP, 0, "WINE-PCM", -1, 00735 add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) ); 00736 MultiByteToWideChar( CP_ACP, 0, "Wine PCM converter", -1, 00737 add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) ); 00738 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1, 00739 add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) ); 00740 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1, 00741 add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) ); 00742 add->szFeatures[0] = 0; 00743 00744 return MMSYSERR_NOERROR; 00745 } 00746 00747 /*********************************************************************** 00748 * PCM_FormatTagDetails 00749 * 00750 */ 00751 static LRESULT PCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery) 00752 { 00753 TRACE("(%p, %08x)\n", aftd, dwQuery); 00754 00755 switch (dwQuery) { 00756 case ACM_FORMATTAGDETAILSF_INDEX: 00757 if (aftd->dwFormatTagIndex != 0) { 00758 WARN("not possible\n"); 00759 return ACMERR_NOTPOSSIBLE; 00760 } 00761 break; 00762 case ACM_FORMATTAGDETAILSF_FORMATTAG: 00763 if (aftd->dwFormatTag != WAVE_FORMAT_PCM) { 00764 WARN("not possible\n"); 00765 return ACMERR_NOTPOSSIBLE; 00766 } 00767 break; 00768 case ACM_FORMATTAGDETAILSF_LARGESTSIZE: 00769 if (aftd->dwFormatTag != WAVE_FORMAT_UNKNOWN && 00770 aftd->dwFormatTag != WAVE_FORMAT_PCM) { 00771 WARN("not possible\n"); 00772 return ACMERR_NOTPOSSIBLE; 00773 } 00774 break; 00775 default: 00776 WARN("Unsupported query %08x\n", dwQuery); 00777 return MMSYSERR_NOTSUPPORTED; 00778 } 00779 00780 aftd->dwFormatTagIndex = 0; 00781 aftd->dwFormatTag = WAVE_FORMAT_PCM; 00782 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT); 00783 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER; 00784 aftd->cStandardFormats = NUM_PCM_FORMATS; 00785 aftd->szFormatTag[0] = 0; 00786 00787 return MMSYSERR_NOERROR; 00788 } 00789 00790 /*********************************************************************** 00791 * PCM_FormatDetails 00792 * 00793 */ 00794 static LRESULT PCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery) 00795 { 00796 TRACE("(%p, %08x)\n", afd, dwQuery); 00797 00798 switch (dwQuery) { 00799 case ACM_FORMATDETAILSF_FORMAT: 00800 if (PCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) { 00801 WARN("not possible\n"); 00802 return ACMERR_NOTPOSSIBLE; 00803 } 00804 break; 00805 case ACM_FORMATDETAILSF_INDEX: 00806 assert(afd->dwFormatIndex < NUM_PCM_FORMATS); 00807 afd->pwfx->wFormatTag = WAVE_FORMAT_PCM; 00808 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels; 00809 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate; 00810 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits; 00811 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not 00812 * accessible afd->pwfx->cbSize = 0; 00813 */ 00814 afd->pwfx->nBlockAlign = 00815 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8; 00816 afd->pwfx->nAvgBytesPerSec = 00817 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign; 00818 break; 00819 default: 00820 WARN("Unsupported query %08x\n", dwQuery); 00821 return MMSYSERR_NOTSUPPORTED; 00822 } 00823 00824 afd->dwFormatTag = WAVE_FORMAT_PCM; 00825 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER; 00826 afd->szFormat[0] = 0; /* let MSACM format this for us... */ 00827 afd->cbwfx = sizeof(PCMWAVEFORMAT); 00828 00829 return MMSYSERR_NOERROR; 00830 } 00831 00832 /*********************************************************************** 00833 * PCM_FormatSuggest 00834 * 00835 */ 00836 static LRESULT PCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs) 00837 { 00838 TRACE("(%p)\n", adfs); 00839 00840 /* some tests ... */ 00841 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) || 00842 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) || 00843 PCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) { 00844 WARN("not possible\n"); 00845 return ACMERR_NOTPOSSIBLE; 00846 } 00847 00848 /* is no suggestion for destination, then copy source value */ 00849 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS)) { 00850 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels; 00851 } 00852 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC)) { 00853 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec; 00854 } 00855 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE)) { 00856 adfs->pwfxDst->wBitsPerSample = adfs->pwfxSrc->wBitsPerSample; 00857 } 00858 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG)) { 00859 if (adfs->pwfxSrc->wFormatTag != WAVE_FORMAT_PCM) { 00860 WARN("not possible\n"); 00861 return ACMERR_NOTPOSSIBLE; 00862 } 00863 adfs->pwfxDst->wFormatTag = adfs->pwfxSrc->wFormatTag; 00864 } 00865 /* check if result is ok */ 00866 if (PCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) { 00867 WARN("not possible\n"); 00868 return ACMERR_NOTPOSSIBLE; 00869 } 00870 00871 /* recompute other values */ 00872 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8; 00873 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign; 00874 00875 return MMSYSERR_NOERROR; 00876 } 00877 00878 /*********************************************************************** 00879 * PCM_StreamOpen 00880 * 00881 */ 00882 static LRESULT PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi) 00883 { 00884 AcmPcmData* apd; 00885 int idx = 0; 00886 00887 TRACE("(%p)\n", adsi); 00888 00889 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC)); 00890 00891 apd = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmPcmData)); 00892 if (apd == 0) { 00893 WARN("no memory\n"); 00894 return MMSYSERR_NOMEM; 00895 } 00896 00897 adsi->dwDriver = (DWORD_PTR)apd; 00898 adsi->fdwDriver = 0; 00899 00900 if (adsi->pwfxSrc->wBitsPerSample == 16) idx += 8; 00901 if (adsi->pwfxDst->wBitsPerSample == 16) idx += 4; 00902 if (adsi->pwfxSrc->nChannels == 1) idx += 2; 00903 if (adsi->pwfxDst->nChannels == 1) idx += 1; 00904 00905 if (adsi->pwfxSrc->nSamplesPerSec == adsi->pwfxDst->nSamplesPerSec) { 00906 apd->cvt.cvtKeepRate = PCM_ConvertKeepRate[idx]; 00907 } else { 00908 adsi->fdwDriver |= PCM_RESAMPLE; 00909 apd->cvt.cvtChangeRate = PCM_ConvertChangeRate[idx]; 00910 } 00911 00912 return MMSYSERR_NOERROR; 00913 } 00914 00915 /*********************************************************************** 00916 * PCM_StreamClose 00917 * 00918 */ 00919 static LRESULT PCM_StreamClose(PACMDRVSTREAMINSTANCE adsi) 00920 { 00921 TRACE("(%p)\n", adsi); 00922 00923 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver); 00924 return MMSYSERR_NOERROR; 00925 } 00926 00927 /*********************************************************************** 00928 * PCM_round 00929 * 00930 */ 00931 static inline DWORD PCM_round(DWORD a, DWORD b, DWORD c) 00932 { 00933 assert(c); 00934 /* to be sure, always return an entire number of c... */ 00935 return ((double)a * (double)b + (double)c - 1) / (double)c; 00936 } 00937 00938 /*********************************************************************** 00939 * PCM_StreamSize 00940 * 00941 */ 00942 static LRESULT PCM_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss) 00943 { 00944 DWORD srcMask = ~(adsi->pwfxSrc->nBlockAlign - 1); 00945 DWORD dstMask = ~(adsi->pwfxDst->nBlockAlign - 1); 00946 00947 TRACE("(%p, %p)\n", adsi, adss); 00948 00949 switch (adss->fdwSize) { 00950 case ACM_STREAMSIZEF_DESTINATION: 00951 /* cbDstLength => cbSrcLength */ 00952 adss->cbSrcLength = PCM_round(adss->cbDstLength & dstMask, 00953 adsi->pwfxSrc->nAvgBytesPerSec, 00954 adsi->pwfxDst->nAvgBytesPerSec) & srcMask; 00955 break; 00956 case ACM_STREAMSIZEF_SOURCE: 00957 /* cbSrcLength => cbDstLength */ 00958 adss->cbDstLength = PCM_round(adss->cbSrcLength & srcMask, 00959 adsi->pwfxDst->nAvgBytesPerSec, 00960 adsi->pwfxSrc->nAvgBytesPerSec) & dstMask; 00961 break; 00962 default: 00963 WARN("Unsupported query %08x\n", adss->fdwSize); 00964 return MMSYSERR_NOTSUPPORTED; 00965 } 00966 return MMSYSERR_NOERROR; 00967 } 00968 00969 /*********************************************************************** 00970 * PCM_StreamConvert 00971 * 00972 */ 00973 static LRESULT PCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh) 00974 { 00975 AcmPcmData* apd = (AcmPcmData*)adsi->dwDriver; 00976 DWORD nsrc = NUM_OF(adsh->cbSrcLength, adsi->pwfxSrc->nBlockAlign); 00977 DWORD ndst = NUM_OF(adsh->cbDstLength, adsi->pwfxDst->nBlockAlign); 00978 00979 TRACE("(%p, %p)\n", adsi, adsh); 00980 00981 TRACE("nsrc=%d,adsh->cbSrcLength=%d\n", nsrc, adsh->cbSrcLength); 00982 TRACE("ndst=%d,adsh->cbDstLength=%d\n", ndst, adsh->cbDstLength); 00983 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", 00984 adsi->pwfxSrc->wFormatTag, adsi->pwfxSrc->nChannels, adsi->pwfxSrc->nSamplesPerSec, adsi->pwfxSrc->nAvgBytesPerSec, 00985 adsi->pwfxSrc->nBlockAlign, adsi->pwfxSrc->wBitsPerSample, adsi->pwfxSrc->cbSize); 00986 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", 00987 adsi->pwfxDst->wFormatTag, adsi->pwfxDst->nChannels, adsi->pwfxDst->nSamplesPerSec, adsi->pwfxDst->nAvgBytesPerSec, 00988 adsi->pwfxDst->nBlockAlign, adsi->pwfxDst->wBitsPerSample, adsi->pwfxDst->cbSize); 00989 00990 if (adsh->fdwConvert & 00991 ~(ACM_STREAMCONVERTF_BLOCKALIGN| 00992 ACM_STREAMCONVERTF_END| 00993 ACM_STREAMCONVERTF_START)) { 00994 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert); 00995 } 00996 /* ACM_STREAMCONVERTF_BLOCKALIGN 00997 * currently all conversions are block aligned, so do nothing for this flag 00998 * ACM_STREAMCONVERTF_END 00999 * no pending data, so do nothing for this flag 01000 */ 01001 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START) && 01002 (adsi->fdwDriver & PCM_RESAMPLE)) { 01003 } 01004 01005 /* do the job */ 01006 if (adsi->fdwDriver & PCM_RESAMPLE) { 01007 DWORD nsrc2 = nsrc; 01008 DWORD ndst2 = ndst; 01009 apd->cvt.cvtChangeRate(adsi->pwfxSrc->nSamplesPerSec, adsh->pbSrc, &nsrc2, 01010 adsi->pwfxDst->nSamplesPerSec, adsh->pbDst, &ndst2); 01011 nsrc -= nsrc2; 01012 ndst -= ndst2; 01013 } else { 01014 if (nsrc < ndst) ndst = nsrc; else nsrc = ndst; 01015 01016 /* nsrc is now equal to ndst */ 01017 apd->cvt.cvtKeepRate(adsh->pbSrc, nsrc, adsh->pbDst); 01018 } 01019 01020 adsh->cbSrcLengthUsed = nsrc * adsi->pwfxSrc->nBlockAlign; 01021 adsh->cbDstLengthUsed = ndst * adsi->pwfxDst->nBlockAlign; 01022 01023 return MMSYSERR_NOERROR; 01024 } 01025 01026 /************************************************************************** 01027 * DriverProc (MSACM32.@) 01028 */ 01029 LRESULT CALLBACK PCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, 01030 LPARAM dwParam1, LPARAM dwParam2) 01031 { 01032 TRACE("(%08lx %p %u %08lx %08lx);\n", 01033 dwDevID, hDriv, wMsg, dwParam1, dwParam2); 01034 01035 switch (wMsg) { 01036 case DRV_LOAD: return 1; 01037 case DRV_FREE: return 1; 01038 case DRV_OPEN: return PCM_drvOpen((LPSTR)dwParam1, (PACMDRVOPENDESCW)dwParam2); 01039 case DRV_CLOSE: return PCM_drvClose(dwDevID); 01040 case DRV_ENABLE: return 1; 01041 case DRV_DISABLE: return 1; 01042 case DRV_QUERYCONFIGURE: return 1; 01043 case DRV_CONFIGURE: MessageBoxA(0, "MSACM PCM filter !", "Wine Driver", MB_OK); return 1; 01044 case DRV_INSTALL: return DRVCNF_RESTART; 01045 case DRV_REMOVE: return DRVCNF_RESTART; 01046 01047 case ACMDM_DRIVER_NOTIFY: 01048 /* no caching from other ACM drivers is done so far */ 01049 return MMSYSERR_NOERROR; 01050 01051 case ACMDM_DRIVER_DETAILS: 01052 return PCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1); 01053 01054 case ACMDM_FORMATTAG_DETAILS: 01055 return PCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2); 01056 01057 case ACMDM_FORMAT_DETAILS: 01058 return PCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2); 01059 01060 case ACMDM_FORMAT_SUGGEST: 01061 return PCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1); 01062 01063 case ACMDM_STREAM_OPEN: 01064 return PCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1); 01065 01066 case ACMDM_STREAM_CLOSE: 01067 return PCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1); 01068 01069 case ACMDM_STREAM_SIZE: 01070 return PCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2); 01071 01072 case ACMDM_STREAM_CONVERT: 01073 return PCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2); 01074 01075 case ACMDM_HARDWARE_WAVE_CAPS_INPUT: 01076 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT: 01077 /* this converter is not a hardware driver */ 01078 case ACMDM_FILTERTAG_DETAILS: 01079 case ACMDM_FILTER_DETAILS: 01080 /* this converter is not a filter */ 01081 case ACMDM_STREAM_RESET: 01082 /* only needed for asynchronous driver... we aren't, so just say it */ 01083 case ACMDM_STREAM_PREPARE: 01084 case ACMDM_STREAM_UNPREPARE: 01085 /* nothing special to do here... so don't do anything */ 01086 return MMSYSERR_NOTSUPPORTED; 01087 01088 default: 01089 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); 01090 } 01091 } Generated on Sun May 27 2012 04:24:46 for ReactOS by
1.7.6.1
|