ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pcmconverter.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.