wavemap.c 41.3 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 59 60 61
    HACMSTREAM	hAcmStream;
    /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
    DWORD	dwCallback;
    DWORD	dwClientInstance;
    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 71 72 73 74
static	BOOL	WAVEMAP_IsData(WAVEMAPDATA* wm)
{
    return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm);
}

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

79 80
static void CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwInstance,
				     LPARAM dwParam1, LPARAM 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 92
    if (hWave != wom->u.out.hInnerWave && uMsg != WOM_OPEN)
	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 107 108 109 110 111 112 113
	    LPWAVEHDR		lpWaveHdrDst = (LPWAVEHDR)dwParam1;
	    PACMSTREAMHEADER	ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER));
	    LPWAVEHDR		lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser;

	    lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE;
	    lpWaveHdrSrc->dwFlags |= WHDR_DONE;
	    dwParam1 = (DWORD)lpWaveHdrSrc;
	}
	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
	ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx, (DWORD)wodCallback,
141 142 143 144 145 146
			  (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
	if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
	    acmStreamClose(wom->hAcmStream, 0);
	    wom->hAcmStream = 0;
	}
    }
147
    TRACE("ret = %08x\n", ret);
148
    return ret;
149 150 151 152
}

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

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

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

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

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

197
    if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) {
198
        WAVEFORMATEX	wfx;
199

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

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

211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
        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);
            }
234

235 236 237 238 239 240 241 242
            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);
243

244 245 246 247 248 249 250
                /* 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);
251

252 253 254 255 256 257 258
                /* 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);
259

260 261 262 263 264 265 266 267
                /* 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);
            }
268
        }
269
#undef TRY
270
    }
271

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

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

static	DWORD	wodClose(WAVEMAPDATA* wom)
{
296 297 298
    DWORD ret;

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

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

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

317
    TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2);
318

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

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

332
    lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
333 334 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)
        ERR("CoDec has read more data than it is allowed to\n");

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

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

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

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

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

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

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

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

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

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

414
    TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2);
415

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

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

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

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

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

437 438 439 440 441 442
    memcpy(&timepos, lpTime, sizeof(timepos));

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

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

446
    if (timepos.wType == TIME_BYTES)
447 448 449 450 451 452 453 454 455
    {
        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),
456
            **   we need to make a special accommodation for times when we've
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
            **   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)
480 481 482
            lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter);
        else
            lpTime->wType = TIME_BYTES;
483
    }
484 485
    else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES)
        lpTime->u.sample = MulDiv(timepos.u.sample, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner);
486 487 488 489
    else
        /* other time types don't require conversion */
        lpTime->u = timepos.u;

490
    return val;
491 492
}

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

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

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

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

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

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

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

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

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

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

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

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

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

566
    return waveOutReset(wom->u.out.hInnerWave);
567 568
}

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

573
    return waveOutBreakLoop(wom->u.out.hInnerWave);
574 575
}

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

581
    TRACE("(%p %08x %p)\n",wom, flags, ptr);
582

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

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

    return MMSYSERR_NOERROR;
}

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

621 622 623 624 625 626 627 628 629 630 631 632
    switch (wMsg) {
    case DRVM_INIT:
    case DRVM_EXIT:
    case DRVM_ENABLE:
    case DRVM_DISABLE:
	/* FIXME: Pretend this is supported */
	return 0;
    case WODM_OPEN:	 	return wodOpen		((LPDWORD)dwUser,      (LPWAVEOPENDESC)dwParam1,dwParam2);
    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);
633
    case WODM_BREAKLOOP: 	return wodBreakLoop	((WAVEMAPDATA*)dwUser);
634 635
    case WODM_PREPARE:	 	return wodPrepare	((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
    case WODM_UNPREPARE: 	return wodUnprepare	((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
636
    case WODM_GETDEVCAPS:	return wodGetDevCaps	(wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSW)dwParam1,dwParam2);
637 638 639 640 641
    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;
642 643
    case WODM_GETVOLUME:	return wodGetVolume	(wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
    case WODM_SETVOLUME:	return wodSetVolume	(wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
644 645
    case WODM_RESTART:		return wodRestart	((WAVEMAPDATA*)dwUser);
    case WODM_RESET:		return wodReset		((WAVEMAPDATA*)dwUser);
646
    case WODM_MAPPER_STATUS:	return wodMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
647
    case DRVM_MAPPER_RECONFIGURE: return wodMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2);
648 649 650 651
    /* known but not supported */
    case DRV_QUERYDEVICEINTERFACESIZE:
    case DRV_QUERYDEVICEINTERFACE:
        return MMSYSERR_NOTSUPPORTED;
652 653 654 655 656 657 658 659 660 661
    default:
	FIXME("unknown message %d!\n", wMsg);
    }
    return MMSYSERR_NOTSUPPORTED;
}

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

662
static void	CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD dwInstance,
663 664 665 666
				     DWORD dwParam1, DWORD dwParam2)
{
    WAVEMAPDATA*	wim = (WAVEMAPDATA*)dwInstance;

667
    TRACE("(%p %u %d %x %x);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
668 669

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

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

    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 {
693
		TRACE("Converted %d bytes into %d\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed);
694 695 696 697 698 699 700 701 702 703 704 705
	    }
	    /* and setup the wavehdr to return accordingly */
	    lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE;
	    lpWaveHdrDst->dwFlags |= WHDR_DONE;
	    lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed;
	    dwParam1 = (DWORD)lpWaveHdrDst;
	}
	break;
    default:
	ERR("Unknown msg %u\n", uMsg);
    }

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

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

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

718 719 720
    /* source is always PCM, so the formulas below apply */
    lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
    lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
721 722 723 724 725 726
    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) {
727
	ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx, (DWORD)widCallback,
728 729 730 731 732 733
			 (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
	if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
	    acmStreamClose(wim->hAcmStream, 0);
	    wim->hAcmStream = 0;
	}
    }
734
    TRACE("ret = %08x\n", ret);
735
    return ret;
736 737
}

738 739
static	DWORD	widOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
{
740
    UINT 		ndlo, ndhi;
741 742
    UINT		i;
    WAVEMAPDATA*	wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
743
    DWORD               res;
744

745
    TRACE("(%p %p %08x)\n", lpdwUser, lpDesc, dwFlags);
746

747 748
    if (!wim) {
        WARN("no memory\n");
749
	return MMSYSERR_NOMEM;
750
    }
751

752 753 754 755
    wim->self = wim;
    wim->dwCallback = lpDesc->dwCallback;
    wim->dwFlags = dwFlags;
    wim->dwClientInstance = lpDesc->dwInstance;
756
    wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave;
757

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

768
    wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
769
    wim->nSamplesPerSecOuter = wim->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec;
770

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

779 780 781
    if ((dwFlags & WAVE_FORMAT_DIRECT) == 0)
    {
        WAVEFORMATEX	wfx;
782

783 784 785
        wfx.wFormatTag = WAVE_FORMAT_PCM;
        wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
        /* try some ACM stuff */
786

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

794
        for (i = ndlo; i < ndhi; i++) {
Robert Reif's avatar
Robert Reif committed
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
	    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);
814

Robert Reif's avatar
Robert Reif committed
815 816 817 818 819 820 821 822
            /* 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);

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

831 832
            /* 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
833 834
            TRY(96000, 8);
            TRY(48000, 8);
835 836 837 838
            TRY(44100, 8);
            TRY(22050, 8);
            TRY(11025, 8);
        }
839
#undef TRY
840
    }
841

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

static	DWORD	widClose(WAVEMAPDATA* wim)
{
866 867 868
    DWORD ret;

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

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

882
static	DWORD	widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
883
{
884 885 886
    PACMSTREAMHEADER	ash;
    LPWAVEHDR		lpWaveHdrSrc;

887
    TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
888

889
    if (!wim->hAcmStream) {
890
	return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
891 892 893 894
    }

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

896
    lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
897
    return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
898 899
}

900
static	DWORD	widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
901
{
902 903 904 905 906
    PACMSTREAMHEADER	ash;
    DWORD		size;
    DWORD		dwRet;
    LPWAVEHDR		lpWaveHdrSrc;

907
    TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
908

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

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

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

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

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

962
static	DWORD	widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
963
{
964 965 966 967
    PACMSTREAMHEADER	ash;
    LPWAVEHDR		lpWaveHdrSrc;
    DWORD		dwRet1, dwRet2;

968
    TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
969

970
    if (!wim->hAcmStream) {
971
	return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
972 973 974
    }
    ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
    dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L);
975

976
    lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
977
    dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
978 979

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

981 982
    lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED;
    return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
983 984 985 986
}

static	DWORD	widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
{
987
    DWORD       val;
988
    MMTIME      timepos;
989
    TRACE("(%p %p %08x)\n", wim, lpTime, dwParam2);
990

991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
    memcpy(&timepos, lpTime, sizeof(timepos));

    /* 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),
1010
            **   we need to make a special accommodation for times when we've
1011 1012 1013 1014 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
            **   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;

1044
    return val;
1045 1046
}

1047
static	DWORD	widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSW lpWaveCaps, DWORD dwParam2)
1048
{
1049
    TRACE("(%04x, %p %p %08x)\n", wDevID, wim, lpWaveCaps, dwParam2);
1050

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

1076 1077 1078
	return MMSYSERR_NOERROR;
    }
    ERR("This shouldn't happen\n");
1079
    return MMSYSERR_ERROR;
1080 1081 1082 1083
}

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

1086
    return waveInStop(wim->u.in.hInnerWave);
1087 1088 1089 1090
}

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

1093
    return waveInStart(wim->u.in.hInnerWave);
1094 1095 1096 1097
}

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

1100
    return waveInReset(wim->u.in.hInnerWave);
1101 1102
}

1103 1104 1105 1106 1107
static  DWORD	widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr)
{
    UINT	id;
    DWORD	ret = MMSYSERR_NOTSUPPORTED;

1108
    TRACE("(%p %08x %p)\n", wim, flags, ptr);
1109

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

1132 1133
static  DWORD   widMapperReconfigure(WAVEMAPDATA* wim, DWORD dwParam1, DWORD dwParam2)
{
1134
    FIXME("(%p %08x %08x) stub!\n", wim, dwParam1, dwParam2);
1135 1136 1137 1138

    return MMSYSERR_NOERROR;
}

1139
/**************************************************************************
1140
 * 				widMessage (MSACM.@)
1141
 */
1142
DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1143 1144
				DWORD dwParam1, DWORD dwParam2)
{
1145
    TRACE("(%u, %04X, %08X, %08X, %08X);\n",
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
	  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;

    case WIDM_OPEN:		return widOpen          ((LPDWORD)dwUser,     (LPWAVEOPENDESC)dwParam1, dwParam2);
    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);
1162
    case WIDM_GETDEVCAPS:	return widGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSW)dwParam1, dwParam2);
1163 1164 1165 1166 1167
    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);
1168
    case WIDM_MAPPER_STATUS:	return widMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
1169
    case DRVM_MAPPER_RECONFIGURE: return widMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2);
1170 1171 1172 1173
    /* known but not supported */
    case DRV_QUERYDEVICEINTERFACESIZE:
    case DRV_QUERYDEVICEINTERFACE:
        return MMSYSERR_NOTSUPPORTED;
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
    default:
	FIXME("unknown message %u!\n", wMsg);
    }
    return MMSYSERR_NOTSUPPORTED;
}

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

static	struct WINE_WAVEMAP* oss = NULL;

/**************************************************************************
1187
 * 				WAVEMAP_drvOpen			[internal]
1188
 */
1189
static LRESULT WAVEMAP_drvOpen(LPSTR str)
1190
{
1191 1192
    TRACE("(%p)\n", str);

1193 1194
    if (oss)
	return 0;
1195

1196 1197 1198 1199 1200 1201
    /* I know, this is ugly, but who cares... */
    oss = (struct WINE_WAVEMAP*)1;
    return 1;
}

/**************************************************************************
1202
 * 				WAVEMAP_drvClose		[internal]
1203
 */
1204
static LRESULT WAVEMAP_drvClose(DWORD_PTR dwDevID)
1205
{
1206 1207
    TRACE("(%08lx)\n", dwDevID);

1208 1209 1210 1211 1212 1213 1214 1215
    if (oss) {
	oss = NULL;
	return 1;
    }
    return 0;
}

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

1224 1225 1226 1227 1228 1229 1230 1231
    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;
1232
    case DRV_CONFIGURE:		MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK);	return 1;
1233 1234 1235 1236 1237 1238
    case DRV_INSTALL:		return DRVCNF_RESTART;
    case DRV_REMOVE:		return DRVCNF_RESTART;
    default:
	return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
    }
}