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

wavemap.c
Go to the documentation of this file.
00001 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
00002 /*
00003  * Wine Wave mapper driver
00004  *
00005  * Copyright    1999,2001 Eric Pouech
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 /* TODOs
00023  *  + better protection against evilish dwUser parameters
00024  *  + use asynchronous ACM conversion
00025  *  + don't use callback functions when none is required in open
00026  *  + the buffer sizes may not be accurate, so there may be some
00027  *    remaining bytes in src and dst buffers after ACM conversions...
00028  *      those should be taken care of...
00029  */
00030 
00031 #include <stdarg.h>
00032 #include <string.h>
00033 #include "windef.h"
00034 #include "winbase.h"
00035 #include "wingdi.h"
00036 #include "winuser.h"
00037 #include "mmddk.h"
00038 #include "mmreg.h"
00039 #include "msacm.h"
00040 #include "wine/unicode.h"
00041 #include "wine/debug.h"
00042 
00043 WINE_DEFAULT_DEBUG_CHANNEL(wavemap);
00044 
00045 typedef struct tagWAVEMAPDATA {
00046     struct tagWAVEMAPDATA*  self;
00047     union {
00048         struct {
00049             HWAVEOUT    hOuterWave;
00050             HWAVEOUT    hInnerWave;
00051         } out;
00052         struct {
00053             HWAVEIN hOuterWave;
00054             HWAVEIN hInnerWave;
00055         } in;
00056     } u;
00057     HACMSTREAM  hAcmStream;
00058     /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
00059     DWORD_PTR   dwCallback;
00060     DWORD_PTR   dwClientInstance;
00061     DWORD   dwFlags;
00062     /* ratio to compute position from a PCM playback to any format */
00063     DWORD       avgSpeedOuter;
00064     DWORD       avgSpeedInner;
00065     /* channel size of inner and outer */
00066     DWORD       nSamplesPerSecOuter;
00067     DWORD       nSamplesPerSecInner;
00068 } WAVEMAPDATA;
00069 
00070 static  BOOL    WAVEMAP_IsData(const WAVEMAPDATA* wm)
00071 {
00072     return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm);
00073 }
00074 
00075 /*======================================================================*
00076  *                  WAVE OUT part                                       *
00077  *======================================================================*/
00078 
00079 static void CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwInstance,
00080                                  DWORD_PTR dwParam1, DWORD_PTR dwParam2)
00081 {
00082     WAVEMAPDATA*    wom = (WAVEMAPDATA*)dwInstance;
00083 
00084     TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
00085 
00086     if (!WAVEMAP_IsData(wom)) {
00087     ERR("Bad data\n");
00088     return;
00089     }
00090 
00091     if (uMsg != WOM_OPEN && hWave != wom->u.out.hInnerWave)
00092     ERR("Shouldn't happen (%p %p)\n", hWave, wom->u.out.hInnerWave);
00093 
00094     switch (uMsg) {
00095     case WOM_OPEN:
00096     case WOM_CLOSE:
00097     /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
00098     break;
00099     case WOM_DONE:
00100     if (wom->hAcmStream) {
00101         LPWAVEHDR       lpWaveHdrDst = (LPWAVEHDR)dwParam1;
00102         PACMSTREAMHEADER    ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER));
00103         LPWAVEHDR       lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser;
00104 
00105         lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE;
00106         lpWaveHdrSrc->dwFlags |= WHDR_DONE;
00107             dwParam1 = (DWORD_PTR)lpWaveHdrSrc;
00108     }
00109     break;
00110     default:
00111     ERR("Unknown msg %u\n", uMsg);
00112     }
00113 
00114     DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave,
00115            uMsg, wom->dwClientInstance, dwParam1, dwParam2);
00116 }
00117 
00118 /******************************************************************
00119  *      wodOpenHelper
00120  *
00121  *
00122  */
00123 static  DWORD   wodOpenHelper(WAVEMAPDATA* wom, UINT idx,
00124                   LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
00125                   DWORD dwFlags)
00126 {
00127     DWORD   ret;
00128 
00129     TRACE("(%p %04x %p %p %08x)\n", wom, idx, lpDesc, lpwfx, dwFlags);
00130 
00131     /* destination is always PCM, so the formulas below apply */
00132     lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
00133     lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
00134     if (dwFlags & WAVE_FORMAT_QUERY) {
00135     ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
00136     } else {
00137     ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L);
00138     }
00139     if (ret == MMSYSERR_NOERROR) {
00140         ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx,
00141                           (DWORD_PTR)wodCallback, (DWORD_PTR)wom,
00142                           (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
00143     if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
00144         acmStreamClose(wom->hAcmStream, 0);
00145         wom->hAcmStream = 0;
00146     }
00147     }
00148     TRACE("ret = %08x\n", ret);
00149     return ret;
00150 }
00151 
00152 static  DWORD   wodOpen(DWORD_PTR *lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
00153 {
00154     UINT        ndlo, ndhi;
00155     UINT        i;
00156     WAVEMAPDATA*    wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
00157     DWORD               res;
00158 
00159     TRACE("(%p %p %08x)\n", lpdwUser, lpDesc, dwFlags);
00160 
00161     if (!wom) {
00162         WARN("no memory\n");
00163     return MMSYSERR_NOMEM;
00164     }
00165 
00166     ndhi = waveOutGetNumDevs();
00167     if (dwFlags & WAVE_MAPPED) {
00168     if (lpDesc->uMappedDeviceID >= ndhi) {
00169             WARN("invalid parameter: dwFlags WAVE_MAPPED\n");
00170             HeapFree(GetProcessHeap(), 0, wom);
00171             return MMSYSERR_INVALPARAM;
00172         }
00173     ndlo = lpDesc->uMappedDeviceID;
00174     ndhi = ndlo + 1;
00175     dwFlags &= ~WAVE_MAPPED;
00176     } else {
00177     ndlo = 0;
00178     }
00179     wom->self = wom;
00180     wom->dwCallback = lpDesc->dwCallback;
00181     wom->dwFlags = dwFlags;
00182     wom->dwClientInstance = lpDesc->dwInstance;
00183     wom->u.out.hOuterWave = (HWAVEOUT)lpDesc->hWave;
00184     wom->avgSpeedOuter = wom->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
00185     wom->nSamplesPerSecOuter = wom->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec;
00186 
00187     for (i = ndlo; i < ndhi; i++) {
00188     /* if no ACM stuff is involved, no need to handle callbacks at this
00189      * level, this will be done transparently
00190      */
00191         if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat,
00192                         (DWORD_PTR)wodCallback, (DWORD_PTR)wom,
00193                         (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
00194         wom->hAcmStream = 0;
00195         goto found;
00196     }
00197     }
00198 
00199     if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) {
00200         WAVEFORMATEX    wfx;
00201 
00202         wfx.wFormatTag = WAVE_FORMAT_PCM;
00203         wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
00204         /* try some ACM stuff */
00205 
00206 #define TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
00207                         switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
00208                             case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; wom->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
00209                             case WAVERR_BADFORMAT: break; \
00210                             default: goto error; \
00211                         }
00212 
00213         if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
00214             /* Format changed so keep sample rate and number of channels 
00215              * the same and just change the bit depth
00216              */
00217             for (i = ndlo; i < ndhi; i++) {
00218                 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
00219                 wfx.nChannels = lpDesc->lpFormat->nChannels;
00220                 TRY(wfx.nSamplesPerSec, 16);
00221                 TRY(wfx.nSamplesPerSec, 8);
00222             }
00223         } else {
00224             /* Our resampling algorithm is quite primitive so first try
00225              * to just change the bit depth and number of channels
00226              */
00227             for (i = ndlo; i < ndhi; i++) {
00228                 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
00229                 wfx.nChannels = lpDesc->lpFormat->nChannels;
00230                 TRY(wfx.nSamplesPerSec, 16);
00231                 TRY(wfx.nSamplesPerSec, 8);
00232                 wfx.nChannels ^= 3;
00233                 TRY(wfx.nSamplesPerSec, 16);
00234                 TRY(wfx.nSamplesPerSec, 8);
00235             }
00236 
00237             for (i = ndlo; i < ndhi; i++) {
00238                 /* first try with same stereo/mono option as source */
00239                 wfx.nChannels = lpDesc->lpFormat->nChannels;
00240                 TRY(96000, 16);
00241                 TRY(48000, 16);
00242                 TRY(44100, 16);
00243                 TRY(22050, 16);
00244                 TRY(11025, 16);
00245 
00246                 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
00247                 wfx.nChannels ^= 3;
00248                 TRY(96000, 16);
00249                 TRY(48000, 16);
00250                 TRY(44100, 16);
00251                 TRY(22050, 16);
00252                 TRY(11025, 16);
00253 
00254                 /* first try with same stereo/mono option as source */
00255                 wfx.nChannels = lpDesc->lpFormat->nChannels;
00256                 TRY(96000, 8);
00257                 TRY(48000, 8);
00258                 TRY(44100, 8);
00259                 TRY(22050, 8);
00260                 TRY(11025, 8);
00261 
00262                 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
00263                 wfx.nChannels ^= 3;
00264                 TRY(96000, 8);
00265                 TRY(48000, 8);
00266                 TRY(44100, 8);
00267                 TRY(22050, 8);
00268                 TRY(11025, 8);
00269             }
00270         }
00271 #undef TRY
00272     }
00273 
00274     HeapFree(GetProcessHeap(), 0, wom);
00275     WARN("ret = WAVERR_BADFORMAT\n");
00276     return WAVERR_BADFORMAT;
00277 
00278 found:
00279     if (dwFlags & WAVE_FORMAT_QUERY) {
00280     *lpdwUser = 0L;
00281     HeapFree(GetProcessHeap(), 0, wom);
00282     } else {
00283         *lpdwUser = (DWORD_PTR)wom;
00284     }
00285     return MMSYSERR_NOERROR;
00286 error:
00287     HeapFree(GetProcessHeap(), 0, wom);
00288     if (res==ACMERR_NOTPOSSIBLE) {
00289         WARN("ret = WAVERR_BADFORMAT\n");
00290         return WAVERR_BADFORMAT;
00291     }
00292     WARN("ret = 0x%08x\n", res);
00293     return res;
00294 }
00295 
00296 static  DWORD   wodClose(WAVEMAPDATA* wom)
00297 {
00298     DWORD ret;
00299 
00300     TRACE("(%p)\n", wom);
00301 
00302     ret = waveOutClose(wom->u.out.hInnerWave);
00303     if (ret == MMSYSERR_NOERROR) {
00304     if (wom->hAcmStream) {
00305         ret = acmStreamClose(wom->hAcmStream, 0);
00306     }
00307     if (ret == MMSYSERR_NOERROR) {
00308         HeapFree(GetProcessHeap(), 0, wom);
00309     }
00310     }
00311     return ret;
00312 }
00313 
00314 static  DWORD   wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
00315 {
00316     PACMSTREAMHEADER    ash;
00317     LPWAVEHDR       lpWaveHdrDst;
00318 
00319     TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2);
00320 
00321     if (!wom->hAcmStream) {
00322     return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
00323     }
00324 
00325     lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE;
00326     ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
00327     /* acmStreamConvert will actually check that the new size is less than initial size */
00328     ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
00329     if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
00330         WARN("acmStreamConvert failed\n");
00331     return MMSYSERR_ERROR;
00332     }
00333 
00334     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
00335     if (ash->cbSrcLength > ash->cbSrcLengthUsed)
00336         FIXME("Not all src buffer has been written, expect bogus sound\n");
00337     else if (ash->cbSrcLength < ash->cbSrcLengthUsed)
00338         ERR("CoDec has read more data than it is allowed to\n");
00339 
00340     if (ash->cbDstLengthUsed == 0) {
00341         /* something went wrong in decoding */
00342         FIXME("Got 0 length\n");
00343         return MMSYSERR_ERROR;
00344     }
00345     lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed;
00346     return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
00347 }
00348 
00349 static  DWORD   wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
00350 {
00351     PACMSTREAMHEADER    ash;
00352     DWORD       size;
00353     DWORD       dwRet;
00354     LPWAVEHDR       lpWaveHdrDst;
00355 
00356     TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2);
00357 
00358     if (!wom->hAcmStream)
00359     return waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
00360 
00361     if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR) {
00362         WARN("acmStreamSize failed\n");
00363     return MMSYSERR_ERROR;
00364     }
00365 
00366     ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
00367     if (ash == NULL) {
00368         WARN("no memory\n");
00369     return MMSYSERR_NOMEM;
00370     }
00371 
00372     ash->cbStruct = sizeof(*ash);
00373     ash->fdwStatus = 0L;
00374     ash->dwUser = (DWORD_PTR)lpWaveHdrSrc;
00375     ash->pbSrc = (LPBYTE)lpWaveHdrSrc->lpData;
00376     ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
00377     /* ash->cbSrcLengthUsed */
00378     ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */
00379     ash->pbDst = (LPBYTE)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
00380     ash->cbDstLength = size;
00381     /* ash->cbDstLengthUsed */
00382     ash->dwDstUser = 0; /* FIXME ? */
00383     dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L);
00384     if (dwRet != MMSYSERR_NOERROR) {
00385         WARN("acmStreamPrepareHeader failed\n");
00386     goto errCleanUp;
00387     }
00388 
00389     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
00390     lpWaveHdrDst->lpData = (LPSTR)ash->pbDst;
00391     lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */
00392     lpWaveHdrDst->dwFlags = 0;
00393     lpWaveHdrDst->dwLoops = 0;
00394     dwRet = waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
00395     if (dwRet != MMSYSERR_NOERROR) {
00396         WARN("waveOutPrepareHeader failed\n");
00397     goto errCleanUp;
00398     }
00399 
00400     lpWaveHdrSrc->reserved = (DWORD_PTR)ash;
00401     lpWaveHdrSrc->dwFlags = WHDR_PREPARED;
00402     TRACE("=> (0)\n");
00403     return MMSYSERR_NOERROR;
00404 errCleanUp:
00405     TRACE("=> (%d)\n", dwRet);
00406     HeapFree(GetProcessHeap(), 0, ash);
00407     return dwRet;
00408 }
00409 
00410 static  DWORD   wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
00411 {
00412     PACMSTREAMHEADER    ash;
00413     LPWAVEHDR       lpWaveHdrDst;
00414     DWORD       dwRet1, dwRet2;
00415 
00416     TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2);
00417 
00418     if (!wom->hAcmStream) {
00419     return waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
00420     }
00421     ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
00422     dwRet1 = acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L);
00423 
00424     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
00425     dwRet2 = waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
00426 
00427     HeapFree(GetProcessHeap(), 0, ash);
00428 
00429     lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED;
00430     return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
00431 }
00432 
00433 static  DWORD   wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
00434 {
00435     DWORD       val;
00436     MMTIME      timepos;
00437     TRACE("(%p %p %08x)\n", wom, lpTime, dwParam2);
00438 
00439     timepos = *lpTime;
00440 
00441     /* For TIME_MS, we're going to recalculate using TIME_BYTES */
00442     if (lpTime->wType == TIME_MS)
00443         timepos.wType = TIME_BYTES;
00444 
00445     /* This can change timepos.wType if the requested type is not supported */
00446     val = waveOutGetPosition(wom->u.out.hInnerWave, &timepos, dwParam2);
00447 
00448     if (timepos.wType == TIME_BYTES)
00449     {
00450         DWORD dwInnerSamplesPerOuter = wom->nSamplesPerSecInner / wom->nSamplesPerSecOuter;
00451         if (dwInnerSamplesPerOuter > 0)
00452         {
00453             DWORD dwInnerBytesPerSample = wom->avgSpeedInner / wom->nSamplesPerSecInner;
00454             DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter;
00455             DWORD remainder = 0;
00456 
00457             /* If we are up sampling (going from lower sample rate to higher),
00458             **   we need to make a special accommodation for times when we've
00459             **   written a partial output sample.  This happens frequently
00460             **   to us because we use msacm to do our up sampling, and it
00461             **   will up sample on an unaligned basis.
00462             ** For example, if you convert a 2 byte wide 8,000 'outer'
00463             **   buffer to a 2 byte wide 48,000 inner device, you would
00464             **   expect 2 bytes of input to produce 12 bytes of output.
00465             **   Instead, msacm will produce 8 bytes of output.
00466             **   But reporting our position as 1 byte of output is
00467             **   nonsensical; the output buffer position needs to be
00468             **   aligned on outer sample size, and aggressively rounded up.
00469             */
00470             remainder = timepos.u.cb % dwInnerBytesPerOuterSample;
00471             if (remainder > 0)
00472             {
00473                 timepos.u.cb -= remainder;
00474                 timepos.u.cb += dwInnerBytesPerOuterSample;
00475             }
00476         }
00477 
00478         lpTime->u.cb = MulDiv(timepos.u.cb, wom->avgSpeedOuter, wom->avgSpeedInner);
00479 
00480         /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
00481         if (lpTime->wType == TIME_MS)
00482             lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter);
00483         else
00484             lpTime->wType = TIME_BYTES;
00485     }
00486     else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES)
00487         lpTime->u.sample = MulDiv(timepos.u.sample, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner);
00488     else
00489         /* other time types don't require conversion */
00490         lpTime->u = timepos.u;
00491 
00492     return val;
00493 }
00494 
00495 static  DWORD   wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSW lpWaveCaps, DWORD dwParam2)
00496 {
00497     static const WCHAR name[] = {'W','i','n','e',' ','w','a','v','e',' ','o','u','t',' ','m','a','p','p','e','r',0};
00498 
00499     TRACE("(%04x %p %p %08x)\n",wDevID, wom, lpWaveCaps, dwParam2);
00500 
00501     /* if opened low driver, forward message */
00502     if (WAVEMAP_IsData(wom))
00503         return waveOutGetDevCapsW((UINT_PTR)wom->u.out.hInnerWave, lpWaveCaps, dwParam2);
00504     /* else if no drivers, nothing to map so return bad device */
00505     if (waveOutGetNumDevs() == 0) {
00506         WARN("bad device id\n");
00507         return MMSYSERR_BADDEVICEID;
00508     }
00509     /* otherwise, return caps of mapper itself */
00510     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
00511     WAVEOUTCAPSW woc;
00512     woc.wMid = 0x00FF;
00513     woc.wPid = 0x0001;
00514     woc.vDriverVersion = 0x0332;
00515     lstrcpyW(woc.szPname, name);
00516     woc.dwFormats =
00517             WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
00518             WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
00519         WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
00520         WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
00521         WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
00522     woc.wChannels = 2;
00523     woc.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME;
00524         memcpy(lpWaveCaps, &woc, min(dwParam2, sizeof(woc)));
00525 
00526     return MMSYSERR_NOERROR;
00527     }
00528     ERR("This shouldn't happen\n");
00529     return MMSYSERR_ERROR;
00530 }
00531 
00532 static  DWORD   wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol)
00533 {
00534     TRACE("(%04x %p %p)\n",wDevID, wom, lpVol);
00535 
00536     if (WAVEMAP_IsData(wom))
00537     return waveOutGetVolume(wom->u.out.hInnerWave, lpVol);
00538     return MMSYSERR_NOERROR;
00539 }
00540 
00541 static  DWORD   wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol)
00542 {
00543     TRACE("(%04x %p %08x)\n",wDevID, wom, vol);
00544 
00545     if (WAVEMAP_IsData(wom))
00546     return waveOutSetVolume(wom->u.out.hInnerWave, vol);
00547     return MMSYSERR_NOERROR;
00548 }
00549 
00550 static  DWORD   wodPause(WAVEMAPDATA* wom)
00551 {
00552     TRACE("(%p)\n",wom);
00553 
00554     return waveOutPause(wom->u.out.hInnerWave);
00555 }
00556 
00557 static  DWORD   wodRestart(WAVEMAPDATA* wom)
00558 {
00559     TRACE("(%p)\n",wom);
00560 
00561     return waveOutRestart(wom->u.out.hInnerWave);
00562 }
00563 
00564 static  DWORD   wodReset(WAVEMAPDATA* wom)
00565 {
00566     TRACE("(%p)\n",wom);
00567 
00568     return waveOutReset(wom->u.out.hInnerWave);
00569 }
00570 
00571 static  DWORD   wodBreakLoop(WAVEMAPDATA* wom)
00572 {
00573     TRACE("(%p)\n",wom);
00574 
00575     return waveOutBreakLoop(wom->u.out.hInnerWave);
00576 }
00577 
00578 static  DWORD   wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr)
00579 {
00580     UINT    id;
00581     DWORD   ret = MMSYSERR_NOTSUPPORTED;
00582 
00583     TRACE("(%p %08x %p)\n",wom, flags, ptr);
00584 
00585     switch (flags) {
00586     case WAVEOUT_MAPPER_STATUS_DEVICE:
00587     ret = waveOutGetID(wom->u.out.hInnerWave, &id);
00588     *(LPDWORD)ptr = id;
00589     break;
00590     case WAVEOUT_MAPPER_STATUS_MAPPED:
00591     FIXME("Unsupported flag=%d\n", flags);
00592     *(LPDWORD)ptr = 0; /* FIXME ?? */
00593     break;
00594     case WAVEOUT_MAPPER_STATUS_FORMAT:
00595     FIXME("Unsupported flag=%d\n", flags);
00596     /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
00597     *(LPDWORD)ptr = 0;
00598     break;
00599     default:
00600     FIXME("Unsupported flag=%d\n", flags);
00601     *(LPDWORD)ptr = 0;
00602     break;
00603     }
00604     return ret;
00605 }
00606 
00607 static  DWORD   wodMapperReconfigure(WAVEMAPDATA* wom, DWORD dwParam1, DWORD dwParam2)
00608 {
00609     FIXME("(%p %08x %08x) stub!\n", wom, dwParam1, dwParam2);
00610 
00611     return MMSYSERR_NOERROR;
00612 }
00613 
00614 /**************************************************************************
00615  *              wodMessage (MSACM.@)
00616  */
00617 DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
00618                                 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
00619 {
00620     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
00621       wDevID, wMsg, dwUser, dwParam1, dwParam2);
00622 
00623     switch (wMsg) {
00624     case DRVM_INIT:
00625     case DRVM_EXIT:
00626     case DRVM_ENABLE:
00627     case DRVM_DISABLE:
00628     /* FIXME: Pretend this is supported */
00629     return 0;
00630     case WODM_OPEN:     return wodOpen      ((DWORD_PTR*)dwUser,      (LPWAVEOPENDESC)dwParam1,dwParam2);
00631     case WODM_CLOSE:        return wodClose     ((WAVEMAPDATA*)dwUser);
00632     case WODM_WRITE:        return wodWrite     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
00633     case WODM_PAUSE:        return wodPause     ((WAVEMAPDATA*)dwUser);
00634     case WODM_GETPOS:       return wodGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1,  dwParam2);
00635     case WODM_BREAKLOOP:    return wodBreakLoop ((WAVEMAPDATA*)dwUser);
00636     case WODM_PREPARE:      return wodPrepare   ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
00637     case WODM_UNPREPARE:    return wodUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
00638     case WODM_GETDEVCAPS:   return wodGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSW)dwParam1,dwParam2);
00639     case WODM_GETNUMDEVS:   return 1;
00640     case WODM_GETPITCH:     return MMSYSERR_NOTSUPPORTED;
00641     case WODM_SETPITCH:     return MMSYSERR_NOTSUPPORTED;
00642     case WODM_GETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
00643     case WODM_SETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
00644     case WODM_GETVOLUME:    return wodGetVolume (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
00645     case WODM_SETVOLUME:    return wodSetVolume (wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
00646     case WODM_RESTART:      return wodRestart   ((WAVEMAPDATA*)dwUser);
00647     case WODM_RESET:        return wodReset     ((WAVEMAPDATA*)dwUser);
00648     case WODM_MAPPER_STATUS:    return wodMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
00649     case DRVM_MAPPER_RECONFIGURE: return wodMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2);
00650     /* known but not supported */
00651     case DRV_QUERYDEVICEINTERFACESIZE:
00652     case DRV_QUERYDEVICEINTERFACE:
00653         return MMSYSERR_NOTSUPPORTED;
00654     default:
00655     FIXME("unknown message %d!\n", wMsg);
00656     }
00657     return MMSYSERR_NOTSUPPORTED;
00658 }
00659 
00660 /*======================================================================*
00661  *                  WAVE IN part                                        *
00662  *======================================================================*/
00663 
00664 static void CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD_PTR dwInstance,
00665                                  DWORD_PTR dwParam1, DWORD_PTR dwParam2)
00666 {
00667     WAVEMAPDATA* wim = (WAVEMAPDATA*)dwInstance;
00668 
00669     TRACE("(%p %u %lx %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
00670 
00671     if (!WAVEMAP_IsData(wim)) {
00672     ERR("Bad data\n");
00673     return;
00674     }
00675 
00676     if (hWave != wim->u.in.hInnerWave && uMsg != WIM_OPEN)
00677     ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave);
00678 
00679     switch (uMsg) {
00680     case WIM_OPEN:
00681     case WIM_CLOSE:
00682     /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
00683     break;
00684     case WIM_DATA:
00685     if (wim->hAcmStream) {
00686         LPWAVEHDR       lpWaveHdrSrc = (LPWAVEHDR)dwParam1;
00687         PACMSTREAMHEADER    ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER));
00688         LPWAVEHDR       lpWaveHdrDst = (LPWAVEHDR)ash->dwUser;
00689 
00690         /* convert data just gotten from waveIn into requested format */
00691         if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
00692         ERR("ACM conversion failed\n");
00693         return;
00694         } else {
00695         TRACE("Converted %d bytes into %d\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed);
00696         }
00697         /* and setup the wavehdr to return accordingly */
00698         lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE;
00699         lpWaveHdrDst->dwFlags |= WHDR_DONE;
00700         lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed;
00701             dwParam1 = (DWORD_PTR)lpWaveHdrDst;
00702     }
00703     break;
00704     default:
00705     ERR("Unknown msg %u\n", uMsg);
00706     }
00707 
00708     DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave,
00709            uMsg, wim->dwClientInstance, dwParam1, dwParam2);
00710 }
00711 
00712 static  DWORD   widOpenHelper(WAVEMAPDATA* wim, UINT idx,
00713                   LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
00714                   DWORD dwFlags)
00715 {
00716     DWORD   ret;
00717 
00718     TRACE("(%p %04x %p %p %08x)\n", wim, idx, lpDesc, lpwfx, dwFlags);
00719 
00720     /* source is always PCM, so the formulas below apply */
00721     lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
00722     lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
00723     if (dwFlags & WAVE_FORMAT_QUERY) {
00724     ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
00725     } else {
00726     ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L);
00727     }
00728     if (ret == MMSYSERR_NOERROR) {
00729         ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx,
00730                          (DWORD_PTR)widCallback, (DWORD_PTR)wim,
00731                          (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
00732     if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
00733         acmStreamClose(wim->hAcmStream, 0);
00734         wim->hAcmStream = 0;
00735     }
00736     }
00737     TRACE("ret = %08x\n", ret);
00738     return ret;
00739 }
00740 
00741 static  DWORD   widOpen(DWORD_PTR *lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
00742 {
00743     UINT        ndlo, ndhi;
00744     UINT        i;
00745     WAVEMAPDATA*    wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
00746     DWORD               res;
00747 
00748     TRACE("(%p %p %08x)\n", lpdwUser, lpDesc, dwFlags);
00749 
00750     if (!wim) {
00751         WARN("no memory\n");
00752     return MMSYSERR_NOMEM;
00753     }
00754 
00755     wim->self = wim;
00756     wim->dwCallback = lpDesc->dwCallback;
00757     wim->dwFlags = dwFlags;
00758     wim->dwClientInstance = lpDesc->dwInstance;
00759     wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave;
00760 
00761     ndhi = waveInGetNumDevs();
00762     if (dwFlags & WAVE_MAPPED) {
00763     if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM;
00764     ndlo = lpDesc->uMappedDeviceID;
00765     ndhi = ndlo + 1;
00766     dwFlags &= ~WAVE_MAPPED;
00767     } else {
00768     ndlo = 0;
00769     }
00770 
00771     wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
00772     wim->nSamplesPerSecOuter = wim->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec;
00773 
00774     for (i = ndlo; i < ndhi; i++) {
00775         if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat,
00776                        (DWORD_PTR)widCallback, (DWORD_PTR)wim,
00777                        (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
00778         wim->hAcmStream = 0;
00779         goto found;
00780     }
00781     }
00782 
00783     if ((dwFlags & WAVE_FORMAT_DIRECT) == 0)
00784     {
00785         WAVEFORMATEX    wfx;
00786 
00787         wfx.wFormatTag = WAVE_FORMAT_PCM;
00788         wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
00789         /* try some ACM stuff */
00790 
00791 #define TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
00792                         switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
00793                         case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
00794                         case WAVERR_BADFORMAT: break; \
00795                         default: goto error; \
00796                         }
00797 
00798         for (i = ndlo; i < ndhi; i++) {
00799         wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
00800             /* first try with same stereo/mono option as source */
00801             wfx.nChannels = lpDesc->lpFormat->nChannels;
00802             TRY(wfx.nSamplesPerSec, 16);
00803             TRY(wfx.nSamplesPerSec, 8);
00804             wfx.nChannels ^= 3;
00805             TRY(wfx.nSamplesPerSec, 16);
00806             TRY(wfx.nSamplesPerSec, 8);
00807     }
00808 
00809         for (i = ndlo; i < ndhi; i++) {
00810         wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
00811             /* first try with same stereo/mono option as source */
00812             wfx.nChannels = lpDesc->lpFormat->nChannels;
00813             TRY(96000, 16);
00814             TRY(48000, 16);
00815             TRY(44100, 16);
00816             TRY(22050, 16);
00817             TRY(11025, 16);
00818 
00819             /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
00820             wfx.nChannels ^= 3;
00821             TRY(96000, 16);
00822             TRY(48000, 16);
00823             TRY(44100, 16);
00824             TRY(22050, 16);
00825             TRY(11025, 16);
00826 
00827             /* first try with same stereo/mono option as source */
00828             wfx.nChannels = lpDesc->lpFormat->nChannels;
00829             TRY(96000, 8);
00830             TRY(48000, 8);
00831             TRY(44100, 8);
00832             TRY(22050, 8);
00833             TRY(11025, 8);
00834 
00835             /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
00836             wfx.nChannels ^= 3;
00837             TRY(96000, 8);
00838             TRY(48000, 8);
00839             TRY(44100, 8);
00840             TRY(22050, 8);
00841             TRY(11025, 8);
00842         }
00843 #undef TRY
00844     }
00845 
00846     HeapFree(GetProcessHeap(), 0, wim);
00847     WARN("ret = WAVERR_BADFORMAT\n");
00848     return WAVERR_BADFORMAT;
00849 found:
00850     if (dwFlags & WAVE_FORMAT_QUERY) {
00851     *lpdwUser = 0L;
00852     HeapFree(GetProcessHeap(), 0, wim);
00853     } else {
00854         *lpdwUser = (DWORD_PTR)wim;
00855     }
00856     TRACE("Ok (stream=%p)\n", wim->hAcmStream);
00857     return MMSYSERR_NOERROR;
00858 error:
00859     HeapFree(GetProcessHeap(), 0, wim);
00860     if (res==ACMERR_NOTPOSSIBLE) {
00861         WARN("ret = WAVERR_BADFORMAT\n");
00862         return WAVERR_BADFORMAT;
00863     }
00864     WARN("ret = 0x%08x\n", res);
00865     return res;
00866 }
00867 
00868 static  DWORD   widClose(WAVEMAPDATA* wim)
00869 {
00870     DWORD ret;
00871 
00872     TRACE("(%p)\n", wim);
00873 
00874     ret = waveInClose(wim->u.in.hInnerWave);
00875     if (ret == MMSYSERR_NOERROR) {
00876     if (wim->hAcmStream) {
00877         ret = acmStreamClose(wim->hAcmStream, 0);
00878     }
00879     if (ret == MMSYSERR_NOERROR) {
00880         HeapFree(GetProcessHeap(), 0, wim);
00881     }
00882     }
00883     return ret;
00884 }
00885 
00886 static  DWORD   widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
00887 {
00888     PACMSTREAMHEADER    ash;
00889     LPWAVEHDR       lpWaveHdrSrc;
00890 
00891     TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
00892 
00893     if (!wim->hAcmStream) {
00894     return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
00895     }
00896 
00897     lpWaveHdrDst->dwFlags |= WHDR_INQUEUE;
00898     ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
00899 
00900     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
00901     return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
00902 }
00903 
00904 static  DWORD   widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
00905 {
00906     PACMSTREAMHEADER    ash;
00907     DWORD       size;
00908     DWORD       dwRet;
00909     LPWAVEHDR       lpWaveHdrSrc;
00910 
00911     TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
00912 
00913     if (!wim->hAcmStream) {
00914     return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
00915     }
00916     if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size,
00917               ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR) {
00918         WARN("acmStreamSize failed\n");
00919     return MMSYSERR_ERROR;
00920     }
00921 
00922     ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
00923     if (ash == NULL) {
00924         WARN("no memory\n");
00925     return MMSYSERR_NOMEM;
00926     }
00927 
00928     ash->cbStruct = sizeof(*ash);
00929     ash->fdwStatus = 0L;
00930     ash->dwUser = (DWORD_PTR)lpWaveHdrDst;
00931     ash->pbSrc = (LPBYTE)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
00932     ash->cbSrcLength = size;
00933     /* ash->cbSrcLengthUsed */
00934     ash->dwSrcUser = 0L; /* FIXME ? */
00935     ash->pbDst = (LPBYTE)lpWaveHdrDst->lpData;
00936     ash->cbDstLength = lpWaveHdrDst->dwBufferLength;
00937     /* ash->cbDstLengthUsed */
00938     ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */
00939     dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L);
00940     if (dwRet != MMSYSERR_NOERROR) {
00941         WARN("acmStreamPrepareHeader failed\n");
00942     goto errCleanUp;
00943     }
00944 
00945     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
00946     lpWaveHdrSrc->lpData = (LPSTR)ash->pbSrc;
00947     lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */
00948     lpWaveHdrSrc->dwFlags = 0;
00949     lpWaveHdrSrc->dwLoops = 0;
00950     dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
00951     if (dwRet != MMSYSERR_NOERROR) {
00952         WARN("waveInPrepareHeader failed\n");
00953     goto errCleanUp;
00954     }
00955 
00956     lpWaveHdrDst->reserved = (DWORD_PTR)ash;
00957     lpWaveHdrDst->dwFlags = WHDR_PREPARED;
00958     TRACE("=> (0)\n");
00959     return MMSYSERR_NOERROR;
00960 errCleanUp:
00961     TRACE("=> (%d)\n", dwRet);
00962     HeapFree(GetProcessHeap(), 0, ash);
00963     return dwRet;
00964 }
00965 
00966 static  DWORD   widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
00967 {
00968     PACMSTREAMHEADER    ash;
00969     LPWAVEHDR       lpWaveHdrSrc;
00970     DWORD       dwRet1, dwRet2;
00971 
00972     TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
00973 
00974     if (!wim->hAcmStream) {
00975     return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
00976     }
00977     ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
00978     dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L);
00979 
00980     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
00981     dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
00982 
00983     HeapFree(GetProcessHeap(), 0, ash);
00984 
00985     lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED;
00986     return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
00987 }
00988 
00989 static  DWORD   widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
00990 {
00991     DWORD       val;
00992     MMTIME      timepos;
00993     TRACE("(%p %p %08x)\n", wim, lpTime, dwParam2);
00994 
00995     timepos = *lpTime;
00996 
00997     /* For TIME_MS, we're going to recalculate using TIME_BYTES */
00998     if (lpTime->wType == TIME_MS)
00999         timepos.wType = TIME_BYTES;
01000 
01001     /* This can change timepos.wType if the requested type is not supported */
01002     val = waveInGetPosition(wim->u.in.hInnerWave, &timepos, dwParam2);
01003 
01004     if (timepos.wType == TIME_BYTES)
01005     {
01006         DWORD dwInnerSamplesPerOuter = wim->nSamplesPerSecInner / wim->nSamplesPerSecOuter;
01007         if (dwInnerSamplesPerOuter > 0)
01008         {
01009             DWORD dwInnerBytesPerSample = wim->avgSpeedInner / wim->nSamplesPerSecInner;
01010             DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter;
01011             DWORD remainder = 0;
01012 
01013             /* If we are up sampling (going from lower sample rate to higher),
01014             **   we need to make a special accommodation for times when we've
01015             **   written a partial output sample.  This happens frequently
01016             **   to us because we use msacm to do our up sampling, and it
01017             **   will up sample on an unaligned basis.
01018             ** For example, if you convert a 2 byte wide 8,000 'outer'
01019             **   buffer to a 2 byte wide 48,000 inner device, you would
01020             **   expect 2 bytes of input to produce 12 bytes of output.
01021             **   Instead, msacm will produce 8 bytes of output.
01022             **   But reporting our position as 1 byte of output is
01023             **   nonsensical; the output buffer position needs to be
01024             **   aligned on outer sample size, and aggressively rounded up.
01025             */
01026             remainder = timepos.u.cb % dwInnerBytesPerOuterSample;
01027             if (remainder > 0)
01028             {
01029                 timepos.u.cb -= remainder;
01030                 timepos.u.cb += dwInnerBytesPerOuterSample;
01031             }
01032         }
01033 
01034         lpTime->u.cb = MulDiv(timepos.u.cb, wim->avgSpeedOuter, wim->avgSpeedInner);
01035 
01036         /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
01037         if (lpTime->wType == TIME_MS)
01038             lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wim->avgSpeedOuter);
01039         else
01040             lpTime->wType = TIME_BYTES;
01041     }
01042     else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES)
01043         lpTime->u.sample = MulDiv(timepos.u.sample, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner);
01044     else
01045         /* other time types don't require conversion */
01046         lpTime->u = timepos.u;
01047 
01048     return val;
01049 }
01050 
01051 static  DWORD   widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSW lpWaveCaps, DWORD dwParam2)
01052 {
01053     TRACE("(%04x, %p %p %08x)\n", wDevID, wim, lpWaveCaps, dwParam2);
01054 
01055     /* if opened low driver, forward message */
01056     if (WAVEMAP_IsData(wim))
01057         return waveInGetDevCapsW((UINT_PTR)wim->u.in.hInnerWave, lpWaveCaps, dwParam2);
01058     /* else if no drivers, nothing to map so return bad device */
01059     if (waveInGetNumDevs() == 0) {
01060         WARN("bad device id\n");
01061         return MMSYSERR_BADDEVICEID;
01062     }
01063     /* otherwise, return caps of mapper itself */
01064     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
01065         WAVEINCAPSW wic;
01066         static const WCHAR init[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0};
01067     wic.wMid = 0x00FF;
01068     wic.wPid = 0x0001;
01069     wic.vDriverVersion = 0x0001;
01070     strcpyW(wic.szPname, init);
01071     wic.dwFormats =
01072             WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
01073             WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
01074         WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
01075         WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
01076         WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
01077     wic.wChannels = 2;
01078         memcpy(lpWaveCaps, &wic, min(dwParam2, sizeof(wic)));
01079 
01080     return MMSYSERR_NOERROR;
01081     }
01082     ERR("This shouldn't happen\n");
01083     return MMSYSERR_ERROR;
01084 }
01085 
01086 static  DWORD   widStop(WAVEMAPDATA* wim)
01087 {
01088     TRACE("(%p)\n", wim);
01089 
01090     return waveInStop(wim->u.in.hInnerWave);
01091 }
01092 
01093 static  DWORD   widStart(WAVEMAPDATA* wim)
01094 {
01095     TRACE("(%p)\n", wim);
01096 
01097     return waveInStart(wim->u.in.hInnerWave);
01098 }
01099 
01100 static  DWORD   widReset(WAVEMAPDATA* wim)
01101 {
01102     TRACE("(%p)\n", wim);
01103 
01104     return waveInReset(wim->u.in.hInnerWave);
01105 }
01106 
01107 static  DWORD   widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr)
01108 {
01109     UINT    id;
01110     DWORD   ret = MMSYSERR_NOTSUPPORTED;
01111 
01112     TRACE("(%p %08x %p)\n", wim, flags, ptr);
01113 
01114     switch (flags) {
01115     case WAVEIN_MAPPER_STATUS_DEVICE:
01116     ret = waveInGetID(wim->u.in.hInnerWave, &id);
01117     *(LPDWORD)ptr = id;
01118     break;
01119     case WAVEIN_MAPPER_STATUS_MAPPED:
01120     FIXME("Unsupported yet flag=%d\n", flags);
01121     *(LPDWORD)ptr = 0; /* FIXME ?? */
01122     break;
01123     case WAVEIN_MAPPER_STATUS_FORMAT:
01124     FIXME("Unsupported flag=%d\n", flags);
01125     /* ptr points to a WAVEFORMATEX struct  - before or after streaming ? */
01126     *(LPDWORD)ptr = 0; /* FIXME ?? */
01127     break;
01128     default:
01129     FIXME("Unsupported flag=%d\n", flags);
01130     *(LPDWORD)ptr = 0;
01131     break;
01132     }
01133     return ret;
01134 }
01135 
01136 static  DWORD   widMapperReconfigure(WAVEMAPDATA* wim, DWORD dwParam1, DWORD dwParam2)
01137 {
01138     FIXME("(%p %08x %08x) stub!\n", wim, dwParam1, dwParam2);
01139 
01140     return MMSYSERR_NOERROR;
01141 }
01142 
01143 /**************************************************************************
01144  *              widMessage (MSACM.@)
01145  */
01146 DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD_PTR dwUser,
01147                                 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
01148 {
01149     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
01150       wDevID, wMsg, dwUser, dwParam1, dwParam2);
01151 
01152     switch (wMsg) {
01153     case DRVM_INIT:
01154     case DRVM_EXIT:
01155     case DRVM_ENABLE:
01156     case DRVM_DISABLE:
01157     /* FIXME: Pretend this is supported */
01158     return 0;
01159 
01160     case WIDM_OPEN:     return widOpen          ((DWORD_PTR*)dwUser,     (LPWAVEOPENDESC)dwParam1, dwParam2);
01161     case WIDM_CLOSE:        return widClose         ((WAVEMAPDATA*)dwUser);
01162 
01163     case WIDM_ADDBUFFER:    return widAddBuffer     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
01164     case WIDM_PREPARE:      return widPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
01165     case WIDM_UNPREPARE:    return widUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
01166     case WIDM_GETDEVCAPS:   return widGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSW)dwParam1, dwParam2);
01167     case WIDM_GETNUMDEVS:   return 1;
01168     case WIDM_GETPOS:       return widGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1,  dwParam2);
01169     case WIDM_RESET:        return widReset         ((WAVEMAPDATA*)dwUser);
01170     case WIDM_START:        return widStart         ((WAVEMAPDATA*)dwUser);
01171     case WIDM_STOP:     return widStop          ((WAVEMAPDATA*)dwUser);
01172     case WIDM_MAPPER_STATUS:    return widMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
01173     case DRVM_MAPPER_RECONFIGURE: return widMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2);
01174     /* known but not supported */
01175     case DRV_QUERYDEVICEINTERFACESIZE:
01176     case DRV_QUERYDEVICEINTERFACE:
01177         return MMSYSERR_NOTSUPPORTED;
01178     default:
01179     FIXME("unknown message %u!\n", wMsg);
01180     }
01181     return MMSYSERR_NOTSUPPORTED;
01182 }
01183 
01184 /*======================================================================*
01185  *                  Driver part                                         *
01186  *======================================================================*/
01187 
01188 static  struct WINE_WAVEMAP* oss = NULL;
01189 
01190 /**************************************************************************
01191  *              WAVEMAP_drvOpen         [internal]
01192  */
01193 static LRESULT WAVEMAP_drvOpen(LPSTR str)
01194 {
01195     TRACE("(%p)\n", str);
01196 
01197     if (oss)
01198     return 0;
01199 
01200     /* I know, this is ugly, but who cares... */
01201     oss = (struct WINE_WAVEMAP*)1;
01202     return 1;
01203 }
01204 
01205 /**************************************************************************
01206  *              WAVEMAP_drvClose        [internal]
01207  */
01208 static LRESULT WAVEMAP_drvClose(DWORD_PTR dwDevID)
01209 {
01210     TRACE("(%08lx)\n", dwDevID);
01211 
01212     if (oss) {
01213     oss = NULL;
01214     return 1;
01215     }
01216     return 0;
01217 }
01218 
01219 /**************************************************************************
01220  *              DriverProc (MSACM.@)
01221  */
01222 LRESULT CALLBACK WAVEMAP_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
01223                                     LPARAM dwParam1, LPARAM dwParam2)
01224 {
01225     TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
01226       dwDevID, hDriv, wMsg, dwParam1, dwParam2);
01227 
01228     switch(wMsg) {
01229     case DRV_LOAD:      return 1;
01230     case DRV_FREE:      return 1;
01231     case DRV_OPEN:      return WAVEMAP_drvOpen((LPSTR)dwParam1);
01232     case DRV_CLOSE:     return WAVEMAP_drvClose(dwDevID);
01233     case DRV_ENABLE:        return 1;
01234     case DRV_DISABLE:       return 1;
01235     case DRV_QUERYCONFIGURE:    return 1;
01236     case DRV_CONFIGURE:     MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK); return 1;
01237     case DRV_INSTALL:       return DRVCNF_RESTART;
01238     case DRV_REMOVE:        return DRVCNF_RESTART;
01239     default:
01240     return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
01241     }
01242 }

Generated on Sun May 27 2012 04:24:45 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.