wavemap.c 41.8 KB
Newer Older
1
/* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
/*
3 4
 * Wine Wave mapper driver
 *
5
 * Copyright 	1999,2001 Eric Pouech
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21 22 23 24
 */

/* TODOs
 *	+ better protection against evilish dwUser parameters
 *	+ use asynchronous ACM conversion
25 26 27 28
 *	+ don't use callback functions when none is required in open
 *	+ the buffer sizes may not be accurate, so there may be some
 *	  remaining bytes in src and dst buffers after ACM conversions...
 *		those should be taken care of...
29 30
 */

31
#include <stdarg.h>
32
#include <string.h>
33
#include "windef.h"
34
#include "winbase.h"
35
#include "wingdi.h"
36 37
#include "winuser.h"
#include "mmddk.h"
38
#include "mmreg.h"
39
#include "msacm.h"
40
#include "wine/unicode.h"
41
#include "wine/debug.h"
42

43
WINE_DEFAULT_DEBUG_CHANNEL(wavemap);
44 45

typedef	struct tagWAVEMAPDATA {
46
    struct tagWAVEMAPDATA*	self;
47 48 49 50 51 52 53 54 55 56
    union {
        struct {
            HWAVEOUT	hOuterWave;
            HWAVEOUT	hInnerWave;
        } out;
        struct {
            HWAVEIN	hOuterWave;
            HWAVEIN	hInnerWave;
        } in;
    } u;
57 58
    HACMSTREAM	hAcmStream;
    /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
59 60
    DWORD_PTR	dwCallback;
    DWORD_PTR	dwClientInstance;
61
    DWORD	dwFlags;
62 63 64
    /* ratio to compute position from a PCM playback to any format */
    DWORD       avgSpeedOuter;
    DWORD       avgSpeedInner;
65 66 67
    /* channel size of inner and outer */
    DWORD       nSamplesPerSecOuter;
    DWORD       nSamplesPerSecInner;
68 69
} WAVEMAPDATA;

70
static	BOOL	WAVEMAP_IsData(const WAVEMAPDATA* wm)
71 72 73 74
{
    return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm);
}

75 76 77 78
/*======================================================================*
 *                  WAVE OUT part                                       *
 *======================================================================*/

79
static void CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwInstance,
80
                                 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
81 82 83
{
    WAVEMAPDATA*	wom = (WAVEMAPDATA*)dwInstance;

84
    TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
85 86 87 88 89 90

    if (!WAVEMAP_IsData(wom)) {
	ERR("Bad data\n");
	return;
    }

91
    if (uMsg != WOM_OPEN && hWave != wom->u.out.hInnerWave)
92
	ERR("Shouldn't happen (%p %p)\n", hWave, wom->u.out.hInnerWave);
93 94 95 96 97 98 99

    switch (uMsg) {
    case WOM_OPEN:
    case WOM_CLOSE:
	/* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
	break;
    case WOM_DONE:
100
	if (wom->hAcmStream) {
101 102 103 104 105 106
	    LPWAVEHDR		lpWaveHdrDst = (LPWAVEHDR)dwParam1;
	    PACMSTREAMHEADER	ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER));
	    LPWAVEHDR		lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser;

	    lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE;
	    lpWaveHdrSrc->dwFlags |= WHDR_DONE;
107
            dwParam1 = (DWORD_PTR)lpWaveHdrSrc;
108 109 110 111 112 113
	}
	break;
    default:
	ERR("Unknown msg %u\n", uMsg);
    }

114
    DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave,
115
		   uMsg, wom->dwClientInstance, dwParam1, dwParam2);
116 117
}

118 119 120 121 122
/******************************************************************
 *		wodOpenHelper
 *
 *
 */
123 124
static	DWORD	wodOpenHelper(WAVEMAPDATA* wom, UINT idx,
			      LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
125 126 127
			      DWORD dwFlags)
{
    DWORD	ret;
128

129
    TRACE("(%p %04x %p %p %08x)\n", wom, idx, lpDesc, lpwfx, dwFlags);
130 131 132 133

    /* destination is always PCM, so the formulas below apply */
    lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
    lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
134 135 136 137 138 139
    if (dwFlags & WAVE_FORMAT_QUERY) {
	ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
    } else {
	ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L);
    }
    if (ret == MMSYSERR_NOERROR) {
140 141 142
        ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx,
                          (DWORD_PTR)wodCallback, (DWORD_PTR)wom,
                          (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
143 144 145 146 147
	if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
	    acmStreamClose(wom->hAcmStream, 0);
	    wom->hAcmStream = 0;
	}
    }
148
    TRACE("ret = %08x\n", ret);
149
    return ret;
150 151
}

152
static	DWORD	wodOpen(DWORD_PTR *lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
153
{
154
    UINT 		ndlo, ndhi;
155 156
    UINT		i;
    WAVEMAPDATA*	wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
157
    DWORD               res;
158

159
    TRACE("(%p %p %08x)\n", lpdwUser, lpDesc, dwFlags);
160

161 162
    if (!wom) {
        WARN("no memory\n");
163
	return MMSYSERR_NOMEM;
164
    }
165

166 167
    ndhi = waveOutGetNumDevs();
    if (dwFlags & WAVE_MAPPED) {
168 169
	if (lpDesc->uMappedDeviceID >= ndhi) {
            WARN("invalid parameter: dwFlags WAVE_MAPPED\n");
170
            HeapFree(GetProcessHeap(), 0, wom);
171 172
            return MMSYSERR_INVALPARAM;
        }
173 174 175 176 177 178
	ndlo = lpDesc->uMappedDeviceID;
	ndhi = ndlo + 1;
	dwFlags &= ~WAVE_MAPPED;
    } else {
	ndlo = 0;
    }
179
    wom->self = wom;
180 181 182
    wom->dwCallback = lpDesc->dwCallback;
    wom->dwFlags = dwFlags;
    wom->dwClientInstance = lpDesc->dwInstance;
183
    wom->u.out.hOuterWave = (HWAVEOUT)lpDesc->hWave;
184
    wom->avgSpeedOuter = wom->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
185
    wom->nSamplesPerSecOuter = wom->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec;
186

187
    for (i = ndlo; i < ndhi; i++) {
188 189 190
	/* if no ACM stuff is involved, no need to handle callbacks at this
	 * level, this will be done transparently
	 */
191 192 193
        if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat,
                        (DWORD_PTR)wodCallback, (DWORD_PTR)wom,
                        (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
194 195 196 197 198
	    wom->hAcmStream = 0;
	    goto found;
	}
    }

199
    if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) {
200
        WAVEFORMATEX	wfx;
201

202 203 204
        wfx.wFormatTag = WAVE_FORMAT_PCM;
        wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
        /* try some ACM stuff */
205

206
#define	TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
207
                        switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
208
                            case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; wom->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
209 210 211
                            case WAVERR_BADFORMAT: break; \
                            default: goto error; \
                        }
212

213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
        if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
            /* Format changed so keep sample rate and number of channels 
             * the same and just change the bit depth
             */
            for (i = ndlo; i < ndhi; i++) {
                wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
                wfx.nChannels = lpDesc->lpFormat->nChannels;
                TRY(wfx.nSamplesPerSec, 16);
                TRY(wfx.nSamplesPerSec, 8);
            }
        } else {
            /* Our resampling algorithm is quite primitive so first try
             * to just change the bit depth and number of channels
             */
            for (i = ndlo; i < ndhi; i++) {
                wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
                wfx.nChannels = lpDesc->lpFormat->nChannels;
                TRY(wfx.nSamplesPerSec, 16);
                TRY(wfx.nSamplesPerSec, 8);
                wfx.nChannels ^= 3;
                TRY(wfx.nSamplesPerSec, 16);
                TRY(wfx.nSamplesPerSec, 8);
            }
236

237 238 239 240 241 242 243 244
            for (i = ndlo; i < ndhi; i++) {
                /* first try with same stereo/mono option as source */
                wfx.nChannels = lpDesc->lpFormat->nChannels;
                TRY(96000, 16);
                TRY(48000, 16);
                TRY(44100, 16);
                TRY(22050, 16);
                TRY(11025, 16);
245

246 247 248 249 250 251 252
                /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
                wfx.nChannels ^= 3;
                TRY(96000, 16);
                TRY(48000, 16);
                TRY(44100, 16);
                TRY(22050, 16);
                TRY(11025, 16);
253

254 255 256 257 258 259 260
                /* first try with same stereo/mono option as source */
                wfx.nChannels = lpDesc->lpFormat->nChannels;
                TRY(96000, 8);
                TRY(48000, 8);
                TRY(44100, 8);
                TRY(22050, 8);
                TRY(11025, 8);
261

262 263 264 265 266 267 268 269
                /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
                wfx.nChannels ^= 3;
                TRY(96000, 8);
                TRY(48000, 8);
                TRY(44100, 8);
                TRY(22050, 8);
                TRY(11025, 8);
            }
270
        }
271
#undef TRY
272
    }
273

274
    HeapFree(GetProcessHeap(), 0, wom);
275
    WARN("ret = WAVERR_BADFORMAT\n");
276 277
    return WAVERR_BADFORMAT;

278
found:
279 280 281 282
    if (dwFlags & WAVE_FORMAT_QUERY) {
	*lpdwUser = 0L;
	HeapFree(GetProcessHeap(), 0, wom);
    } else {
283
        *lpdwUser = (DWORD_PTR)wom;
284
    }
285
    return MMSYSERR_NOERROR;
286 287
error:
    HeapFree(GetProcessHeap(), 0, wom);
288 289 290 291
    if (res==ACMERR_NOTPOSSIBLE) {
        WARN("ret = WAVERR_BADFORMAT\n");
        return WAVERR_BADFORMAT;
    }
292
    WARN("ret = 0x%08x\n", res);
293
    return res;
294 295 296 297
}

static	DWORD	wodClose(WAVEMAPDATA* wom)
{
298 299 300
    DWORD ret;

    TRACE("(%p)\n", wom);
301

302
    ret = waveOutClose(wom->u.out.hInnerWave);
303 304
    if (ret == MMSYSERR_NOERROR) {
	if (wom->hAcmStream) {
305
	    ret = acmStreamClose(wom->hAcmStream, 0);
306 307 308 309 310 311 312 313 314 315 316 317 318
	}
	if (ret == MMSYSERR_NOERROR) {
	    HeapFree(GetProcessHeap(), 0, wom);
	}
    }
    return ret;
}

static	DWORD	wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
{
    PACMSTREAMHEADER	ash;
    LPWAVEHDR		lpWaveHdrDst;

319
    TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2);
320

321
    if (!wom->hAcmStream) {
322
	return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
323
    }
324

325 326
    lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE;
    ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
327 328
    /* acmStreamConvert will actually check that the new size is less than initial size */
    ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
329 330
    if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
        WARN("acmStreamConvert failed\n");
331
	return MMSYSERR_ERROR;
332
    }
333

334
    lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
335 336 337
    if (ash->cbSrcLength > ash->cbSrcLengthUsed)
        FIXME("Not all src buffer has been written, expect bogus sound\n");
    else if (ash->cbSrcLength < ash->cbSrcLengthUsed)
338
        ERR("Codec has read more data than it is allowed to\n");
339

340
    if (ash->cbDstLengthUsed == 0) {
341 342 343 344
        /* something went wrong in decoding */
        FIXME("Got 0 length\n");
        return MMSYSERR_ERROR;
    }
345
    lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed;
346
    return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
347 348 349 350 351 352 353 354 355
}

static	DWORD	wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
{
    PACMSTREAMHEADER	ash;
    DWORD		size;
    DWORD		dwRet;
    LPWAVEHDR		lpWaveHdrDst;

356
    TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2);
357 358

    if (!wom->hAcmStream)
359
	return waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
360 361 362

    if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR) {
        WARN("acmStreamSize failed\n");
363
	return MMSYSERR_ERROR;
364
    }
365 366

    ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
367 368
    if (ash == NULL) {
        WARN("no memory\n");
369
	return MMSYSERR_NOMEM;
370
    }
371 372 373

    ash->cbStruct = sizeof(*ash);
    ash->fdwStatus = 0L;
374
    ash->dwUser = (DWORD_PTR)lpWaveHdrSrc;
Mike McCormack's avatar
Mike McCormack committed
375
    ash->pbSrc = (LPBYTE)lpWaveHdrSrc->lpData;
376 377 378
    ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
    /* ash->cbSrcLengthUsed */
    ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */
Mike McCormack's avatar
Mike McCormack committed
379
    ash->pbDst = (LPBYTE)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
380 381 382
    ash->cbDstLength = size;
    /* ash->cbDstLengthUsed */
    ash->dwDstUser = 0; /* FIXME ? */
383
    dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L);
384 385
    if (dwRet != MMSYSERR_NOERROR) {
        WARN("acmStreamPrepareHeader failed\n");
386
	goto errCleanUp;
387
    }
388 389

    lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
Mike McCormack's avatar
Mike McCormack committed
390
    lpWaveHdrDst->lpData = (LPSTR)ash->pbDst;
391 392 393
    lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */
    lpWaveHdrDst->dwFlags = 0;
    lpWaveHdrDst->dwLoops = 0;
394
    dwRet = waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
395 396
    if (dwRet != MMSYSERR_NOERROR) {
        WARN("waveOutPrepareHeader failed\n");
397
	goto errCleanUp;
398
    }
399

400
    lpWaveHdrSrc->reserved = (DWORD_PTR)ash;
401 402 403 404
    lpWaveHdrSrc->dwFlags = WHDR_PREPARED;
    TRACE("=> (0)\n");
    return MMSYSERR_NOERROR;
errCleanUp:
405
    TRACE("=> (%d)\n", dwRet);
406 407 408 409 410 411 412 413 414 415
    HeapFree(GetProcessHeap(), 0, ash);
    return dwRet;
}

static	DWORD	wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
{
    PACMSTREAMHEADER	ash;
    LPWAVEHDR		lpWaveHdrDst;
    DWORD		dwRet1, dwRet2;

416
    TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2);
417

418
    if (!wom->hAcmStream) {
419
	return waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
420 421
    }
    ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
422
    dwRet1 = acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L);
423

424
    lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
425
    dwRet2 = waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
426 427

    HeapFree(GetProcessHeap(), 0, ash);
428

429 430 431 432 433 434
    lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED;
    return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
}

static	DWORD	wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
{
435
    DWORD       val;
436
    MMTIME      timepos;
437
    TRACE("(%p %p %08x)\n", wom, lpTime, dwParam2);
438

439
    timepos = *lpTime;
440 441 442 443 444

    /* For TIME_MS, we're going to recalculate using TIME_BYTES */
    if (lpTime->wType == TIME_MS)
        timepos.wType = TIME_BYTES;

445
    /* This can change timepos.wType if the requested type is not supported */
446 447
    val = waveOutGetPosition(wom->u.out.hInnerWave, &timepos, dwParam2);

448
    if (timepos.wType == TIME_BYTES)
449 450 451 452 453 454 455 456 457
    {
        DWORD dwInnerSamplesPerOuter = wom->nSamplesPerSecInner / wom->nSamplesPerSecOuter;
        if (dwInnerSamplesPerOuter > 0)
        {
            DWORD dwInnerBytesPerSample = wom->avgSpeedInner / wom->nSamplesPerSecInner;
            DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter;
            DWORD remainder = 0;

            /* If we are up sampling (going from lower sample rate to higher),
458
            **   we need to make a special accommodation for times when we've
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
            **   written a partial output sample.  This happens frequently
            **   to us because we use msacm to do our up sampling, and it
            **   will up sample on an unaligned basis.
            ** For example, if you convert a 2 byte wide 8,000 'outer'
            **   buffer to a 2 byte wide 48,000 inner device, you would
            **   expect 2 bytes of input to produce 12 bytes of output.
            **   Instead, msacm will produce 8 bytes of output.
            **   But reporting our position as 1 byte of output is
            **   nonsensical; the output buffer position needs to be
            **   aligned on outer sample size, and aggressively rounded up.
            */
            remainder = timepos.u.cb % dwInnerBytesPerOuterSample;
            if (remainder > 0)
            {
                timepos.u.cb -= remainder;
                timepos.u.cb += dwInnerBytesPerOuterSample;
            }
        }

        lpTime->u.cb = MulDiv(timepos.u.cb, wom->avgSpeedOuter, wom->avgSpeedInner);

        /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
        if (lpTime->wType == TIME_MS)
482 483 484
            lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter);
        else
            lpTime->wType = TIME_BYTES;
485
    }
486 487
    else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES)
        lpTime->u.sample = MulDiv(timepos.u.sample, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner);
488 489 490 491
    else
        /* other time types don't require conversion */
        lpTime->u = timepos.u;

492
    return val;
493 494
}

495
static	DWORD	wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSW lpWaveCaps, DWORD dwParam2)
496
{
497 498
    static const WCHAR name[] = {'W','i','n','e',' ','w','a','v','e',' ','o','u','t',' ','m','a','p','p','e','r',0};

499
    TRACE("(%04x %p %p %08x)\n",wDevID, wom, lpWaveCaps, dwParam2);
500

501 502
    /* if opened low driver, forward message */
    if (WAVEMAP_IsData(wom))
503
        return waveOutGetDevCapsW((UINT_PTR)wom->u.out.hInnerWave, lpWaveCaps, dwParam2);
504
    /* else if no drivers, nothing to map so return bad device */
505 506
    if (waveOutGetNumDevs() == 0) {
        WARN("bad device id\n");
507
        return MMSYSERR_BADDEVICEID;
508
    }
509 510
    /* otherwise, return caps of mapper itself */
    if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
511
	WAVEOUTCAPSW woc;
512 513
	woc.wMid = 0x00FF;
	woc.wPid = 0x0001;
514
	woc.vDriverVersion = 0x0332;
515
	lstrcpyW(woc.szPname, name);
516
	woc.dwFormats =
517 518
            WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
            WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
519 520 521
	    WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
	    WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
	    WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
522 523 524
	woc.wChannels = 2;
	woc.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME;
        memcpy(lpWaveCaps, &woc, min(dwParam2, sizeof(woc)));
525 526 527 528

	return MMSYSERR_NOERROR;
    }
    ERR("This shouldn't happen\n");
529
    return MMSYSERR_ERROR;
530 531
}

532
static	DWORD	wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol)
533
{
534 535
    TRACE("(%04x %p %p)\n",wDevID, wom, lpVol);

536
    if (WAVEMAP_IsData(wom))
537
	return waveOutGetVolume(wom->u.out.hInnerWave, lpVol);
538
    return MMSYSERR_NOERROR;
539 540
}

541
static	DWORD	wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol)
542
{
543
    TRACE("(%04x %p %08x)\n",wDevID, wom, vol);
544

545
    if (WAVEMAP_IsData(wom))
546
	return waveOutSetVolume(wom->u.out.hInnerWave, vol);
547
    return MMSYSERR_NOERROR;
548 549 550 551
}

static	DWORD	wodPause(WAVEMAPDATA* wom)
{
552 553
    TRACE("(%p)\n",wom);

554
    return waveOutPause(wom->u.out.hInnerWave);
555 556 557 558
}

static	DWORD	wodRestart(WAVEMAPDATA* wom)
{
559 560
    TRACE("(%p)\n",wom);

561
    return waveOutRestart(wom->u.out.hInnerWave);
562 563 564 565
}

static	DWORD	wodReset(WAVEMAPDATA* wom)
{
566 567
    TRACE("(%p)\n",wom);

568
    return waveOutReset(wom->u.out.hInnerWave);
569 570
}

571 572
static	DWORD	wodBreakLoop(WAVEMAPDATA* wom)
{
573 574
    TRACE("(%p)\n",wom);

575
    return waveOutBreakLoop(wom->u.out.hInnerWave);
576 577
}

578 579 580 581 582
static  DWORD	wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr)
{
    UINT	id;
    DWORD	ret = MMSYSERR_NOTSUPPORTED;

583
    TRACE("(%p %08x %p)\n",wom, flags, ptr);
584

585
    switch (flags) {
586
    case WAVEOUT_MAPPER_STATUS_DEVICE:
587
	ret = waveOutGetID(wom->u.out.hInnerWave, &id);
588 589 590
	*(LPDWORD)ptr = id;
	break;
    case WAVEOUT_MAPPER_STATUS_MAPPED:
591
	FIXME("Unsupported flag=%d\n", flags);
592
	*(LPDWORD)ptr = 0; /* FIXME ?? */
593 594
	break;
    case WAVEOUT_MAPPER_STATUS_FORMAT:
595
	FIXME("Unsupported flag=%d\n", flags);
596 597 598 599
	/* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
	*(LPDWORD)ptr = 0;
	break;
    default:
600
	FIXME("Unsupported flag=%d\n", flags);
601 602 603 604 605 606
	*(LPDWORD)ptr = 0;
	break;
    }
    return ret;
}

607 608
static  DWORD   wodMapperReconfigure(WAVEMAPDATA* wom, DWORD dwParam1, DWORD dwParam2)
{
609
    FIXME("(%p %08x %08x) stub!\n", wom, dwParam1, dwParam2);
610 611 612 613

    return MMSYSERR_NOERROR;
}

614
/**************************************************************************
615
 * 				wodMessage (MSACM.@)
616
 */
617 618
DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
                                DWORD_PTR dwParam1, DWORD_PTR dwParam2)
619
{
620
    TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
621
	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
622

623 624 625 626 627 628 629
    switch (wMsg) {
    case DRVM_INIT:
    case DRVM_EXIT:
    case DRVM_ENABLE:
    case DRVM_DISABLE:
	/* FIXME: Pretend this is supported */
	return 0;
630
    case WODM_OPEN:	 	return wodOpen		((DWORD_PTR*)dwUser,      (LPWAVEOPENDESC)dwParam1,dwParam2);
631 632 633 634
    case WODM_CLOSE:	 	return wodClose		((WAVEMAPDATA*)dwUser);
    case WODM_WRITE:	 	return wodWrite		((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,	dwParam2);
    case WODM_PAUSE:	 	return wodPause		((WAVEMAPDATA*)dwUser);
    case WODM_GETPOS:	 	return wodGetPosition	((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, 	dwParam2);
635
    case WODM_BREAKLOOP: 	return wodBreakLoop	((WAVEMAPDATA*)dwUser);
636 637
    case WODM_PREPARE:	 	return wodPrepare	((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
    case WODM_UNPREPARE: 	return wodUnprepare	((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
638
    case WODM_GETDEVCAPS:	return wodGetDevCaps	(wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSW)dwParam1,dwParam2);
639 640 641 642 643
    case WODM_GETNUMDEVS:	return 1;
    case WODM_GETPITCH:	 	return MMSYSERR_NOTSUPPORTED;
    case WODM_SETPITCH:	 	return MMSYSERR_NOTSUPPORTED;
    case WODM_GETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;
    case WODM_SETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;
644 645
    case WODM_GETVOLUME:	return wodGetVolume	(wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
    case WODM_SETVOLUME:	return wodSetVolume	(wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
646 647
    case WODM_RESTART:		return wodRestart	((WAVEMAPDATA*)dwUser);
    case WODM_RESET:		return wodReset		((WAVEMAPDATA*)dwUser);
648
    case WODM_MAPPER_STATUS:	return wodMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
649
    case DRVM_MAPPER_RECONFIGURE: return wodMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2);
650 651 652 653
    /* known but not supported */
    case DRV_QUERYDEVICEINTERFACESIZE:
    case DRV_QUERYDEVICEINTERFACE:
        return MMSYSERR_NOTSUPPORTED;
654 655 656 657 658 659 660 661 662 663
    default:
	FIXME("unknown message %d!\n", wMsg);
    }
    return MMSYSERR_NOTSUPPORTED;
}

/*======================================================================*
 *                  WAVE IN part                                        *
 *======================================================================*/

664 665
static void CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD_PTR dwInstance,
                                 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
666
{
667
    WAVEMAPDATA* wim = (WAVEMAPDATA*)dwInstance;
668

669
    TRACE("(%p %u %lx %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
670 671

    if (!WAVEMAP_IsData(wim)) {
672
	ERR("Bad data\n");
673 674 675
	return;
    }

676
    if (uMsg != WIM_OPEN && hWave != wim->u.in.hInnerWave)
677
	ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave);
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694

    switch (uMsg) {
    case WIM_OPEN:
    case WIM_CLOSE:
	/* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
	break;
    case WIM_DATA:
	if (wim->hAcmStream) {
	    LPWAVEHDR		lpWaveHdrSrc = (LPWAVEHDR)dwParam1;
	    PACMSTREAMHEADER	ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER));
	    LPWAVEHDR		lpWaveHdrDst = (LPWAVEHDR)ash->dwUser;

	    /* convert data just gotten from waveIn into requested format */
	    if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
		ERR("ACM conversion failed\n");
		return;
	    } else {
695
		TRACE("Converted %d bytes into %d\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed);
696 697 698 699 700
	    }
	    /* and setup the wavehdr to return accordingly */
	    lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE;
	    lpWaveHdrDst->dwFlags |= WHDR_DONE;
	    lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed;
701
            dwParam1 = (DWORD_PTR)lpWaveHdrDst;
702 703 704 705 706 707
	}
	break;
    default:
	ERR("Unknown msg %u\n", uMsg);
    }

708
    DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave,
709
		   uMsg, wim->dwClientInstance, dwParam1, dwParam2);
710 711
}

712 713
static	DWORD	widOpenHelper(WAVEMAPDATA* wim, UINT idx,
			      LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
714 715 716 717
			      DWORD dwFlags)
{
    DWORD	ret;

718
    TRACE("(%p %04x %p %p %08x)\n", wim, idx, lpDesc, lpwfx, dwFlags);
719

720 721 722
    /* source is always PCM, so the formulas below apply */
    lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
    lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
723 724 725 726 727 728
    if (dwFlags & WAVE_FORMAT_QUERY) {
	ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
    } else {
	ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L);
    }
    if (ret == MMSYSERR_NOERROR) {
729 730 731
        ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx,
                         (DWORD_PTR)widCallback, (DWORD_PTR)wim,
                         (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
732 733 734 735 736
	if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
	    acmStreamClose(wim->hAcmStream, 0);
	    wim->hAcmStream = 0;
	}
    }
737
    TRACE("ret = %08x\n", ret);
738
    return ret;
739 740
}

741
static	DWORD	widOpen(DWORD_PTR *lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
742
{
743
    UINT 		ndlo, ndhi;
744 745
    UINT		i;
    WAVEMAPDATA*	wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
746
    DWORD               res;
747

748
    TRACE("(%p %p %08x)\n", lpdwUser, lpDesc, dwFlags);
749

750 751
    if (!wim) {
        WARN("no memory\n");
752
	return MMSYSERR_NOMEM;
753
    }
754

755 756 757 758
    wim->self = wim;
    wim->dwCallback = lpDesc->dwCallback;
    wim->dwFlags = dwFlags;
    wim->dwClientInstance = lpDesc->dwInstance;
759
    wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave;
760

Robert Reif's avatar
Robert Reif committed
761
    ndhi = waveInGetNumDevs();
762 763 764 765 766 767 768 769 770
    if (dwFlags & WAVE_MAPPED) {
	if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM;
	ndlo = lpDesc->uMappedDeviceID;
	ndhi = ndlo + 1;
	dwFlags &= ~WAVE_MAPPED;
    } else {
	ndlo = 0;
    }

771
    wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
772
    wim->nSamplesPerSecOuter = wim->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec;
773

774
    for (i = ndlo; i < ndhi; i++) {
775 776 777
        if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat,
                       (DWORD_PTR)widCallback, (DWORD_PTR)wim,
                       (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
778 779
	    wim->hAcmStream = 0;
	    goto found;
780 781
	}
    }
782

783 784 785
    if ((dwFlags & WAVE_FORMAT_DIRECT) == 0)
    {
        WAVEFORMATEX	wfx;
786

787 788 789
        wfx.wFormatTag = WAVE_FORMAT_PCM;
        wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
        /* try some ACM stuff */
790

791
#define	TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
792
                        switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
793
                        case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
794 795 796
                        case WAVERR_BADFORMAT: break; \
                        default: goto error; \
                        }
797

798
        for (i = ndlo; i < ndhi; i++) {
Robert Reif's avatar
Robert Reif committed
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817
	    wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
            /* first try with same stereo/mono option as source */
            wfx.nChannels = lpDesc->lpFormat->nChannels;
			TRY(wfx.nSamplesPerSec, 16);
			TRY(wfx.nSamplesPerSec, 8);
			wfx.nChannels ^= 3;
			TRY(wfx.nSamplesPerSec, 16);
			TRY(wfx.nSamplesPerSec, 8);
	}

        for (i = ndlo; i < ndhi; i++) {
	    wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
            /* first try with same stereo/mono option as source */
            wfx.nChannels = lpDesc->lpFormat->nChannels;
            TRY(96000, 16);
            TRY(48000, 16);
            TRY(44100, 16);
            TRY(22050, 16);
            TRY(11025, 16);
818

Robert Reif's avatar
Robert Reif committed
819 820 821 822 823 824 825 826
            /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
            wfx.nChannels ^= 3;
            TRY(96000, 16);
            TRY(48000, 16);
            TRY(44100, 16);
            TRY(22050, 16);
            TRY(11025, 16);

827 828
            /* first try with same stereo/mono option as source */
            wfx.nChannels = lpDesc->lpFormat->nChannels;
Robert Reif's avatar
Robert Reif committed
829 830
            TRY(96000, 8);
            TRY(48000, 8);
831 832 833
            TRY(44100, 8);
            TRY(22050, 8);
            TRY(11025, 8);
834

835 836
            /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
            wfx.nChannels ^= 3;
Robert Reif's avatar
Robert Reif committed
837 838
            TRY(96000, 8);
            TRY(48000, 8);
839 840 841 842
            TRY(44100, 8);
            TRY(22050, 8);
            TRY(11025, 8);
        }
843
#undef TRY
844
    }
845

846
    HeapFree(GetProcessHeap(), 0, wim);
847
    WARN("ret = WAVERR_BADFORMAT\n");
848
    return WAVERR_BADFORMAT;
849 850 851 852 853
found:
    if (dwFlags & WAVE_FORMAT_QUERY) {
	*lpdwUser = 0L;
	HeapFree(GetProcessHeap(), 0, wim);
    } else {
854
        *lpdwUser = (DWORD_PTR)wim;
855
    }
856
    TRACE("Ok (stream=%p)\n", wim->hAcmStream);
857
    return MMSYSERR_NOERROR;
858 859
error:
    HeapFree(GetProcessHeap(), 0, wim);
860 861 862 863
    if (res==ACMERR_NOTPOSSIBLE) {
        WARN("ret = WAVERR_BADFORMAT\n");
        return WAVERR_BADFORMAT;
    }
864
    WARN("ret = 0x%08x\n", res);
865
    return res;
866 867 868 869
}

static	DWORD	widClose(WAVEMAPDATA* wim)
{
870 871 872
    DWORD ret;

    TRACE("(%p)\n", wim);
873

874
    ret = waveInClose(wim->u.in.hInnerWave);
875 876 877 878 879 880 881 882
    if (ret == MMSYSERR_NOERROR) {
	if (wim->hAcmStream) {
	    ret = acmStreamClose(wim->hAcmStream, 0);
	}
	if (ret == MMSYSERR_NOERROR) {
	    HeapFree(GetProcessHeap(), 0, wim);
	}
    }
883 884 885
    return ret;
}

886
static	DWORD	widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
887
{
888 889 890
    PACMSTREAMHEADER	ash;
    LPWAVEHDR		lpWaveHdrSrc;

891
    TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
892

893
    if (!wim->hAcmStream) {
894
	return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
895 896 897 898
    }

    lpWaveHdrDst->dwFlags |= WHDR_INQUEUE;
    ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
899

900
    lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
901
    return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
902 903
}

904
static	DWORD	widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
905
{
906 907 908 909 910
    PACMSTREAMHEADER	ash;
    DWORD		size;
    DWORD		dwRet;
    LPWAVEHDR		lpWaveHdrSrc;

911
    TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
912

913
    if (!wim->hAcmStream) {
914
	return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
915
    }
916
    if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size,
917 918
		      ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR) {
        WARN("acmStreamSize failed\n");
919
	return MMSYSERR_ERROR;
920
    }
921 922

    ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
923 924
    if (ash == NULL) {
        WARN("no memory\n");
925
	return MMSYSERR_NOMEM;
926
    }
927 928 929

    ash->cbStruct = sizeof(*ash);
    ash->fdwStatus = 0L;
930
    ash->dwUser = (DWORD_PTR)lpWaveHdrDst;
Mike McCormack's avatar
Mike McCormack committed
931
    ash->pbSrc = (LPBYTE)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
932 933 934
    ash->cbSrcLength = size;
    /* ash->cbSrcLengthUsed */
    ash->dwSrcUser = 0L; /* FIXME ? */
Mike McCormack's avatar
Mike McCormack committed
935
    ash->pbDst = (LPBYTE)lpWaveHdrDst->lpData;
936 937 938 939
    ash->cbDstLength = lpWaveHdrDst->dwBufferLength;
    /* ash->cbDstLengthUsed */
    ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */
    dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L);
940 941
    if (dwRet != MMSYSERR_NOERROR) {
        WARN("acmStreamPrepareHeader failed\n");
942
	goto errCleanUp;
943
    }
944 945

    lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
Mike McCormack's avatar
Mike McCormack committed
946
    lpWaveHdrSrc->lpData = (LPSTR)ash->pbSrc;
947 948 949
    lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */
    lpWaveHdrSrc->dwFlags = 0;
    lpWaveHdrSrc->dwLoops = 0;
950
    dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
951 952
    if (dwRet != MMSYSERR_NOERROR) {
        WARN("waveInPrepareHeader failed\n");
953
	goto errCleanUp;
954
    }
955

956
    lpWaveHdrDst->reserved = (DWORD_PTR)ash;
957 958 959 960
    lpWaveHdrDst->dwFlags = WHDR_PREPARED;
    TRACE("=> (0)\n");
    return MMSYSERR_NOERROR;
errCleanUp:
961
    TRACE("=> (%d)\n", dwRet);
962 963
    HeapFree(GetProcessHeap(), 0, ash);
    return dwRet;
964 965
}

966
static	DWORD	widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
967
{
968 969 970 971
    PACMSTREAMHEADER	ash;
    LPWAVEHDR		lpWaveHdrSrc;
    DWORD		dwRet1, dwRet2;

972
    TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
973

974
    if (!wim->hAcmStream) {
975
	return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
976 977 978
    }
    ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
    dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L);
979

980
    lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
981
    dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
982 983

    HeapFree(GetProcessHeap(), 0, ash);
984

985 986
    lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED;
    return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
987 988 989 990
}

static	DWORD	widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
{
991
    DWORD       val;
992
    MMTIME      timepos;
993
    TRACE("(%p %p %08x)\n", wim, lpTime, dwParam2);
994

995
    timepos = *lpTime;
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013

    /* For TIME_MS, we're going to recalculate using TIME_BYTES */
    if (lpTime->wType == TIME_MS)
        timepos.wType = TIME_BYTES;

    /* This can change timepos.wType if the requested type is not supported */
    val = waveInGetPosition(wim->u.in.hInnerWave, &timepos, dwParam2);

    if (timepos.wType == TIME_BYTES)
    {
        DWORD dwInnerSamplesPerOuter = wim->nSamplesPerSecInner / wim->nSamplesPerSecOuter;
        if (dwInnerSamplesPerOuter > 0)
        {
            DWORD dwInnerBytesPerSample = wim->avgSpeedInner / wim->nSamplesPerSecInner;
            DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter;
            DWORD remainder = 0;

            /* If we are up sampling (going from lower sample rate to higher),
1014
            **   we need to make a special accommodation for times when we've
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
            **   written a partial output sample.  This happens frequently
            **   to us because we use msacm to do our up sampling, and it
            **   will up sample on an unaligned basis.
            ** For example, if you convert a 2 byte wide 8,000 'outer'
            **   buffer to a 2 byte wide 48,000 inner device, you would
            **   expect 2 bytes of input to produce 12 bytes of output.
            **   Instead, msacm will produce 8 bytes of output.
            **   But reporting our position as 1 byte of output is
            **   nonsensical; the output buffer position needs to be
            **   aligned on outer sample size, and aggressively rounded up.
            */
            remainder = timepos.u.cb % dwInnerBytesPerOuterSample;
            if (remainder > 0)
            {
                timepos.u.cb -= remainder;
                timepos.u.cb += dwInnerBytesPerOuterSample;
            }
        }

        lpTime->u.cb = MulDiv(timepos.u.cb, wim->avgSpeedOuter, wim->avgSpeedInner);

        /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
        if (lpTime->wType == TIME_MS)
            lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wim->avgSpeedOuter);
        else
            lpTime->wType = TIME_BYTES;
    }
    else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES)
        lpTime->u.sample = MulDiv(timepos.u.sample, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner);
    else
        /* other time types don't require conversion */
        lpTime->u = timepos.u;

1048
    return val;
1049 1050
}

1051
static	DWORD	widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSW lpWaveCaps, DWORD dwParam2)
1052
{
1053
    TRACE("(%04x, %p %p %08x)\n", wDevID, wim, lpWaveCaps, dwParam2);
1054

1055 1056
    /* if opened low driver, forward message */
    if (WAVEMAP_IsData(wim))
1057
        return waveInGetDevCapsW((UINT_PTR)wim->u.in.hInnerWave, lpWaveCaps, dwParam2);
1058
    /* else if no drivers, nothing to map so return bad device */
1059 1060
    if (waveInGetNumDevs() == 0) {
        WARN("bad device id\n");
1061
        return MMSYSERR_BADDEVICEID;
1062
    }
1063 1064
    /* otherwise, return caps of mapper itself */
    if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
1065 1066
        WAVEINCAPSW wic;
        static const WCHAR init[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0};
1067 1068 1069
	wic.wMid = 0x00FF;
	wic.wPid = 0x0001;
	wic.vDriverVersion = 0x0001;
1070
	strcpyW(wic.szPname, init);
1071
	wic.dwFormats =
1072 1073
            WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
            WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
1074 1075
	    WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
	    WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
1076
	    WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
1077 1078 1079
	wic.wChannels = 2;
        memcpy(lpWaveCaps, &wic, min(dwParam2, sizeof(wic)));

1080 1081 1082
	return MMSYSERR_NOERROR;
    }
    ERR("This shouldn't happen\n");
1083
    return MMSYSERR_ERROR;
1084 1085 1086 1087
}

static	DWORD	widStop(WAVEMAPDATA* wim)
{
1088 1089
    TRACE("(%p)\n", wim);

1090
    return waveInStop(wim->u.in.hInnerWave);
1091 1092 1093 1094
}

static	DWORD	widStart(WAVEMAPDATA* wim)
{
1095 1096
    TRACE("(%p)\n", wim);

1097
    return waveInStart(wim->u.in.hInnerWave);
1098 1099 1100 1101
}

static	DWORD	widReset(WAVEMAPDATA* wim)
{
1102 1103
    TRACE("(%p)\n", wim);

1104
    return waveInReset(wim->u.in.hInnerWave);
1105 1106
}

1107 1108 1109 1110 1111
static  DWORD	widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr)
{
    UINT	id;
    DWORD	ret = MMSYSERR_NOTSUPPORTED;

1112
    TRACE("(%p %08x %p)\n", wim, flags, ptr);
1113

1114
    switch (flags) {
1115
    case WAVEIN_MAPPER_STATUS_DEVICE:
1116
	ret = waveInGetID(wim->u.in.hInnerWave, &id);
1117 1118 1119
	*(LPDWORD)ptr = id;
	break;
    case WAVEIN_MAPPER_STATUS_MAPPED:
1120
	FIXME("Unsupported yet flag=%d\n", flags);
1121
	*(LPDWORD)ptr = 0; /* FIXME ?? */
1122 1123
	break;
    case WAVEIN_MAPPER_STATUS_FORMAT:
1124
	FIXME("Unsupported flag=%d\n", flags);
1125
	/* ptr points to a WAVEFORMATEX struct  - before or after streaming ? */
1126
	*(LPDWORD)ptr = 0; /* FIXME ?? */
1127 1128
	break;
    default:
1129
	FIXME("Unsupported flag=%d\n", flags);
1130 1131 1132 1133 1134 1135
	*(LPDWORD)ptr = 0;
	break;
    }
    return ret;
}

1136 1137
static  DWORD   widMapperReconfigure(WAVEMAPDATA* wim, DWORD dwParam1, DWORD dwParam2)
{
1138
    FIXME("(%p %08x %08x) stub!\n", wim, dwParam1, dwParam2);
1139 1140 1141 1142

    return MMSYSERR_NOERROR;
}

1143
/**************************************************************************
1144
 * 				widMessage (MSACM.@)
1145
 */
1146 1147
DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD_PTR dwUser,
                                DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1148
{
1149
    TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
	  wDevID, wMsg, dwUser, dwParam1, dwParam2);

    switch (wMsg) {
    case DRVM_INIT:
    case DRVM_EXIT:
    case DRVM_ENABLE:
    case DRVM_DISABLE:
	/* FIXME: Pretend this is supported */
	return 0;

1160
    case WIDM_OPEN:		return widOpen          ((DWORD_PTR*)dwUser,     (LPWAVEOPENDESC)dwParam1, dwParam2);
1161 1162 1163 1164 1165
    case WIDM_CLOSE:		return widClose         ((WAVEMAPDATA*)dwUser);

    case WIDM_ADDBUFFER:	return widAddBuffer     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
    case WIDM_PREPARE:		return widPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
    case WIDM_UNPREPARE:	return widUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
1166
    case WIDM_GETDEVCAPS:	return widGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSW)dwParam1, dwParam2);
1167 1168 1169 1170 1171
    case WIDM_GETNUMDEVS:	return 1;
    case WIDM_GETPOS:		return widGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, 	dwParam2);
    case WIDM_RESET:		return widReset         ((WAVEMAPDATA*)dwUser);
    case WIDM_START:		return widStart         ((WAVEMAPDATA*)dwUser);
    case WIDM_STOP:		return widStop          ((WAVEMAPDATA*)dwUser);
1172
    case WIDM_MAPPER_STATUS:	return widMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
1173
    case DRVM_MAPPER_RECONFIGURE: return widMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2);
1174 1175 1176 1177
    /* known but not supported */
    case DRV_QUERYDEVICEINTERFACESIZE:
    case DRV_QUERYDEVICEINTERFACE:
        return MMSYSERR_NOTSUPPORTED;
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
    default:
	FIXME("unknown message %u!\n", wMsg);
    }
    return MMSYSERR_NOTSUPPORTED;
}

/*======================================================================*
 *                  Driver part                                         *
 *======================================================================*/

static	struct WINE_WAVEMAP* oss = NULL;

/**************************************************************************
1191
 * 				WAVEMAP_drvOpen			[internal]
1192
 */
1193
static LRESULT WAVEMAP_drvOpen(LPSTR str)
1194
{
1195 1196
    TRACE("(%p)\n", str);

1197 1198
    if (oss)
	return 0;
1199

1200 1201 1202 1203 1204 1205
    /* I know, this is ugly, but who cares... */
    oss = (struct WINE_WAVEMAP*)1;
    return 1;
}

/**************************************************************************
1206
 * 				WAVEMAP_drvClose		[internal]
1207
 */
1208
static LRESULT WAVEMAP_drvClose(DWORD_PTR dwDevID)
1209
{
1210 1211
    TRACE("(%08lx)\n", dwDevID);

1212 1213 1214 1215 1216 1217 1218 1219
    if (oss) {
	oss = NULL;
	return 1;
    }
    return 0;
}

/**************************************************************************
1220
 * 				DriverProc (MSACM.@)
1221
 */
1222 1223
LRESULT CALLBACK WAVEMAP_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
                                    LPARAM dwParam1, LPARAM dwParam2)
1224
{
1225
    TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1226
	  dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1227

1228 1229 1230 1231 1232 1233 1234 1235
    switch(wMsg) {
    case DRV_LOAD:		return 1;
    case DRV_FREE:		return 1;
    case DRV_OPEN:		return WAVEMAP_drvOpen((LPSTR)dwParam1);
    case DRV_CLOSE:		return WAVEMAP_drvClose(dwDevID);
    case DRV_ENABLE:		return 1;
    case DRV_DISABLE:		return 1;
    case DRV_QUERYCONFIGURE:	return 1;
1236
    case DRV_CONFIGURE:		MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK);	return 1;
1237 1238 1239 1240 1241 1242
    case DRV_INSTALL:		return DRVCNF_RESTART;
    case DRV_REMOVE:		return DRVCNF_RESTART;
    default:
	return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
    }
}