1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */ 2 /* 3 * Wine Wave mapper driver 4 * 5 * Copyright 1999,2001 Eric Pouech 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * 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 /* TODOs 23 * + better protection against evilish dwUser parameters 24 * + use asynchronous ACM conversion 25 * + don't use callback functions when none is required in open 26 * + the buffer sizes may not be accurate, so there may be some 27 * remaining bytes in src and dst buffers after ACM conversions... 28 * 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 #include "winuser.h" 37 #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 union { 48 struct { 49 HWAVEOUT hOuterWave; 50 HWAVEOUT hInnerWave; 51 } out; 52 struct { 53 HWAVEIN hOuterWave; 54 HWAVEIN hInnerWave; 55 } in; 56 } u; 57 HACMSTREAM hAcmStream; 58 /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */ 59 DWORD_PTR dwCallback; 60 DWORD_PTR dwClientInstance; 61 DWORD dwFlags; 62 /* ratio to compute position from a PCM playback to any format */ 63 DWORD avgSpeedOuter; 64 DWORD avgSpeedInner; 65 /* channel size of inner and outer */ 66 DWORD nSamplesPerSecOuter; 67 DWORD nSamplesPerSecInner; 68 } WAVEMAPDATA; 69 70 static BOOL WAVEMAP_IsData(const WAVEMAPDATA* wm) 71 { 72 return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm); 73 } 74 75 /*======================================================================* 76 * WAVE OUT part * 77 *======================================================================*/ 78 79 static void CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwInstance, 80 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 81 { 82 WAVEMAPDATA* wom = (WAVEMAPDATA*)dwInstance; 83 84 TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2); 85 86 if (!WAVEMAP_IsData(wom)) { 87 ERR("Bad data\n"); 88 return; 89 } 90 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 switch (uMsg) { 95 case WOM_OPEN: 96 case WOM_CLOSE: 97 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ 98 break; 99 case WOM_DONE: 100 if (wom->hAcmStream) { 101 LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)dwParam1; 102 PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER)); 103 LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser; 104 105 lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE; 106 lpWaveHdrSrc->dwFlags |= WHDR_DONE; 107 dwParam1 = (DWORD_PTR)lpWaveHdrSrc; 108 } 109 break; 110 default: 111 ERR("Unknown msg %u\n", uMsg); 112 } 113 114 DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave, 115 uMsg, wom->dwClientInstance, dwParam1, dwParam2); 116 } 117 118 /****************************************************************** 119 * wodOpenHelper 120 * 121 * 122 */ 123 static DWORD wodOpenHelper(WAVEMAPDATA* wom, UINT idx, 124 LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, 125 DWORD dwFlags) 126 { 127 DWORD ret; 128 129 TRACE("(%p %04x %p %p %08x)\n", wom, idx, lpDesc, lpwfx, dwFlags); 130 131 /* destination is always PCM, so the formulas below apply */ 132 lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8; 133 lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign; 134 if (dwFlags & WAVE_FORMAT_QUERY) { 135 ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY); 136 } else { 137 ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L); 138 } 139 if (ret == MMSYSERR_NOERROR) { 140 ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx, 141 (DWORD_PTR)wodCallback, (DWORD_PTR)wom, 142 (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION); 143 if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) { 144 acmStreamClose(wom->hAcmStream, 0); 145 wom->hAcmStream = 0; 146 } 147 } 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 UINT i; 156 WAVEMAPDATA* wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA)); 157 DWORD res; 158 159 TRACE("(%p %p %08x)\n", lpdwUser, lpDesc, dwFlags); 160 161 if (!wom) { 162 WARN("no memory\n"); 163 return MMSYSERR_NOMEM; 164 } 165 166 ndhi = waveOutGetNumDevs(); 167 if (dwFlags & WAVE_MAPPED) { 168 if (lpDesc->uMappedDeviceID >= ndhi) { 169 WARN("invalid parameter: dwFlags WAVE_MAPPED\n"); 170 HeapFree(GetProcessHeap(), 0, wom); 171 return MMSYSERR_INVALPARAM; 172 } 173 ndlo = lpDesc->uMappedDeviceID; 174 ndhi = ndlo + 1; 175 dwFlags &= ~WAVE_MAPPED; 176 } else { 177 ndlo = 0; 178 } 179 wom->self = wom; 180 wom->dwCallback = lpDesc->dwCallback; 181 wom->dwFlags = dwFlags; 182 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 /* if no ACM stuff is involved, no need to handle callbacks at this 189 * level, this will be done transparently 190 */ 191 if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat, 192 (DWORD_PTR)wodCallback, (DWORD_PTR)wom, 193 (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) { 194 wom->hAcmStream = 0; 195 goto found; 196 } 197 } 198 199 if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) { 200 WAVEFORMATEX wfx; 201 202 wfx.wFormatTag = WAVE_FORMAT_PCM; 203 wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */ 204 /* 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 case WAVERR_BADFORMAT: break; \ 210 default: goto error; \ 211 } 212 213 if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM) { 214 /* Format changed so keep sample rate and number of channels 215 * the same and just change the bit depth 216 */ 217 for (i = ndlo; i < ndhi; i++) { 218 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; 219 wfx.nChannels = lpDesc->lpFormat->nChannels; 220 TRY(wfx.nSamplesPerSec, 16); 221 TRY(wfx.nSamplesPerSec, 8); 222 } 223 } else { 224 /* Our resampling algorithm is quite primitive so first try 225 * to just change the bit depth and number of channels 226 */ 227 for (i = ndlo; i < ndhi; i++) { 228 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; 229 wfx.nChannels = lpDesc->lpFormat->nChannels; 230 TRY(wfx.nSamplesPerSec, 16); 231 TRY(wfx.nSamplesPerSec, 8); 232 wfx.nChannels ^= 3; 233 TRY(wfx.nSamplesPerSec, 16); 234 TRY(wfx.nSamplesPerSec, 8); 235 } 236 237 for (i = ndlo; i < ndhi; i++) { 238 /* first try with same stereo/mono option as source */ 239 wfx.nChannels = lpDesc->lpFormat->nChannels; 240 TRY(96000, 16); 241 TRY(48000, 16); 242 TRY(44100, 16); 243 TRY(22050, 16); 244 TRY(11025, 16); 245 246 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ 247 wfx.nChannels ^= 3; 248 TRY(96000, 16); 249 TRY(48000, 16); 250 TRY(44100, 16); 251 TRY(22050, 16); 252 TRY(11025, 16); 253 254 /* first try with same stereo/mono option as source */ 255 wfx.nChannels = lpDesc->lpFormat->nChannels; 256 TRY(96000, 8); 257 TRY(48000, 8); 258 TRY(44100, 8); 259 TRY(22050, 8); 260 TRY(11025, 8); 261 262 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ 263 wfx.nChannels ^= 3; 264 TRY(96000, 8); 265 TRY(48000, 8); 266 TRY(44100, 8); 267 TRY(22050, 8); 268 TRY(11025, 8); 269 } 270 } 271 #undef TRY 272 } 273 274 HeapFree(GetProcessHeap(), 0, wom); 275 WARN("ret = WAVERR_BADFORMAT\n"); 276 return WAVERR_BADFORMAT; 277 278 found: 279 if (dwFlags & WAVE_FORMAT_QUERY) { 280 *lpdwUser = 0L; 281 HeapFree(GetProcessHeap(), 0, wom); 282 } else { 283 *lpdwUser = (DWORD_PTR)wom; 284 } 285 return MMSYSERR_NOERROR; 286 error: 287 HeapFree(GetProcessHeap(), 0, wom); 288 if (res==ACMERR_NOTPOSSIBLE) { 289 WARN("ret = WAVERR_BADFORMAT\n"); 290 return WAVERR_BADFORMAT; 291 } 292 WARN("ret = 0x%08x\n", res); 293 return res; 294 } 295 296 static DWORD wodClose(WAVEMAPDATA* wom) 297 { 298 DWORD ret; 299 300 TRACE("(%p)\n", wom); 301 302 ret = waveOutClose(wom->u.out.hInnerWave); 303 if (ret == MMSYSERR_NOERROR) { 304 if (wom->hAcmStream) { 305 ret = acmStreamClose(wom->hAcmStream, 0); 306 } 307 if (ret == MMSYSERR_NOERROR) { 308 HeapFree(GetProcessHeap(), 0, wom); 309 } 310 } 311 return ret; 312 } 313 314 static DWORD wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) 315 { 316 PACMSTREAMHEADER ash; 317 LPWAVEHDR lpWaveHdrDst; 318 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 lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE; 326 ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved; 327 /* acmStreamConvert will actually check that the new size is less than initial size */ 328 ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength; 329 if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) { 330 WARN("acmStreamConvert failed\n"); 331 return MMSYSERR_ERROR; 332 } 333 334 lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); 335 if (ash->cbSrcLength > ash->cbSrcLengthUsed) 336 FIXME("Not all src buffer has been written, expect bogus sound\n"); 337 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 /* something went wrong in decoding */ 342 FIXME("Got 0 length\n"); 343 return MMSYSERR_ERROR; 344 } 345 lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed; 346 return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); 347 } 348 349 static DWORD wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) 350 { 351 PACMSTREAMHEADER ash; 352 DWORD size; 353 DWORD dwRet; 354 LPWAVEHDR lpWaveHdrDst; 355 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 if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR) { 362 WARN("acmStreamSize failed\n"); 363 return MMSYSERR_ERROR; 364 } 365 366 ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size); 367 if (ash == NULL) { 368 WARN("no memory\n"); 369 return MMSYSERR_NOMEM; 370 } 371 372 ash->cbStruct = sizeof(*ash); 373 ash->fdwStatus = 0L; 374 ash->dwUser = (DWORD_PTR)lpWaveHdrSrc; 375 ash->pbSrc = (LPBYTE)lpWaveHdrSrc->lpData; 376 ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength; 377 /* ash->cbSrcLengthUsed */ 378 ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */ 379 ash->pbDst = (LPBYTE)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR); 380 ash->cbDstLength = size; 381 /* ash->cbDstLengthUsed */ 382 ash->dwDstUser = 0; /* FIXME ? */ 383 dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L); 384 if (dwRet != MMSYSERR_NOERROR) { 385 WARN("acmStreamPrepareHeader failed\n"); 386 goto errCleanUp; 387 } 388 389 lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); 390 lpWaveHdrDst->lpData = (LPSTR)ash->pbDst; 391 lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */ 392 lpWaveHdrDst->dwFlags = 0; 393 lpWaveHdrDst->dwLoops = 0; 394 dwRet = waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); 395 if (dwRet != MMSYSERR_NOERROR) { 396 WARN("waveOutPrepareHeader failed\n"); 397 goto errCleanUp; 398 } 399 400 lpWaveHdrSrc->reserved = (DWORD_PTR)ash; 401 lpWaveHdrSrc->dwFlags = WHDR_PREPARED; 402 TRACE("=> (0)\n"); 403 return MMSYSERR_NOERROR; 404 errCleanUp: 405 TRACE("=> (%d)\n", dwRet); 406 HeapFree(GetProcessHeap(), 0, ash); 407 return dwRet; 408 } 409 410 static DWORD wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) 411 { 412 PACMSTREAMHEADER ash; 413 LPWAVEHDR lpWaveHdrDst; 414 DWORD dwRet1, dwRet2; 415 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 lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED; 430 return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1; 431 } 432 433 static DWORD wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2) 434 { 435 DWORD val; 436 MMTIME timepos; 437 TRACE("(%p %p %08x)\n", wom, lpTime, dwParam2); 438 439 timepos = *lpTime; 440 441 /* For TIME_MS, we're going to recalculate using TIME_BYTES */ 442 if (lpTime->wType == TIME_MS) 443 timepos.wType = TIME_BYTES; 444 445 /* This can change timepos.wType if the requested type is not supported */ 446 val = waveOutGetPosition(wom->u.out.hInnerWave, &timepos, dwParam2); 447 448 if (timepos.wType == TIME_BYTES) 449 { 450 DWORD dwInnerSamplesPerOuter = wom->nSamplesPerSecInner / wom->nSamplesPerSecOuter; 451 if (dwInnerSamplesPerOuter > 0) 452 { 453 DWORD dwInnerBytesPerSample = wom->avgSpeedInner / wom->nSamplesPerSecInner; 454 DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter; 455 DWORD remainder = 0; 456 457 /* 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 ** written a partial output sample. This happens frequently 460 ** to us because we use msacm to do our up sampling, and it 461 ** will up sample on an unaligned basis. 462 ** For example, if you convert a 2 byte wide 8,000 'outer' 463 ** buffer to a 2 byte wide 48,000 inner device, you would 464 ** expect 2 bytes of input to produce 12 bytes of output. 465 ** Instead, msacm will produce 8 bytes of output. 466 ** But reporting our position as 1 byte of output is 467 ** nonsensical; the output buffer position needs to be 468 ** aligned on outer sample size, and aggressively rounded up. 469 */ 470 remainder = timepos.u.cb % dwInnerBytesPerOuterSample; 471 if (remainder > 0) 472 { 473 timepos.u.cb -= remainder; 474 timepos.u.cb += dwInnerBytesPerOuterSample; 475 } 476 } 477 478 lpTime->u.cb = MulDiv(timepos.u.cb, wom->avgSpeedOuter, wom->avgSpeedInner); 479 480 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */ 481 if (lpTime->wType == TIME_MS) 482 lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter); 483 else 484 lpTime->wType = TIME_BYTES; 485 } 486 else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES) 487 lpTime->u.sample = MulDiv(timepos.u.sample, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner); 488 else 489 /* other time types don't require conversion */ 490 lpTime->u = timepos.u; 491 492 return val; 493 } 494 495 static DWORD wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSW lpWaveCaps, DWORD dwParam2) 496 { 497 static const WCHAR name[] = {'W','i','n','e',' ','w','a','v','e',' ','o','u','t',' ','m','a','p','p','e','r',0}; 498 499 TRACE("(%04x %p %p %08x)\n",wDevID, wom, lpWaveCaps, dwParam2); 500 501 /* if opened low driver, forward message */ 502 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 if (waveOutGetNumDevs() == 0) { 506 WARN("bad device id\n"); 507 return MMSYSERR_BADDEVICEID; 508 } 509 /* otherwise, return caps of mapper itself */ 510 if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) { 511 WAVEOUTCAPSW woc; 512 woc.wMid = 0x00FF; 513 woc.wPid = 0x0001; 514 woc.vDriverVersion = 0x0332; 515 lstrcpyW(woc.szPname, name); 516 woc.dwFormats = 517 WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 | 518 WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | 519 WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | 520 WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | 521 WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16; 522 woc.wChannels = 2; 523 woc.wReserved1 = 0; 524 woc.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME; 525 memcpy(lpWaveCaps, &woc, min(dwParam2, sizeof(woc))); 526 527 return MMSYSERR_NOERROR; 528 } 529 ERR("This shouldn't happen\n"); 530 return MMSYSERR_ERROR; 531 } 532 533 static DWORD wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol) 534 { 535 TRACE("(%04x %p %p)\n",wDevID, wom, lpVol); 536 537 if (WAVEMAP_IsData(wom)) 538 return waveOutGetVolume(wom->u.out.hInnerWave, lpVol); 539 return MMSYSERR_NOERROR; 540 } 541 542 static DWORD wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol) 543 { 544 TRACE("(%04x %p %08x)\n",wDevID, wom, vol); 545 546 if (WAVEMAP_IsData(wom)) 547 return waveOutSetVolume(wom->u.out.hInnerWave, vol); 548 return MMSYSERR_NOERROR; 549 } 550 551 static DWORD wodPause(WAVEMAPDATA* wom) 552 { 553 TRACE("(%p)\n",wom); 554 555 return waveOutPause(wom->u.out.hInnerWave); 556 } 557 558 static DWORD wodRestart(WAVEMAPDATA* wom) 559 { 560 TRACE("(%p)\n",wom); 561 562 return waveOutRestart(wom->u.out.hInnerWave); 563 } 564 565 static DWORD wodReset(WAVEMAPDATA* wom) 566 { 567 TRACE("(%p)\n",wom); 568 569 return waveOutReset(wom->u.out.hInnerWave); 570 } 571 572 static DWORD wodBreakLoop(WAVEMAPDATA* wom) 573 { 574 TRACE("(%p)\n",wom); 575 576 return waveOutBreakLoop(wom->u.out.hInnerWave); 577 } 578 579 static DWORD wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr) 580 { 581 UINT id; 582 DWORD ret = MMSYSERR_NOTSUPPORTED; 583 584 TRACE("(%p %08x %p)\n",wom, flags, ptr); 585 586 switch (flags) { 587 case WAVEOUT_MAPPER_STATUS_DEVICE: 588 ret = waveOutGetID(wom->u.out.hInnerWave, &id); 589 *(LPDWORD)ptr = id; 590 break; 591 case WAVEOUT_MAPPER_STATUS_MAPPED: 592 FIXME("Unsupported flag=%d\n", flags); 593 *(LPDWORD)ptr = 0; /* FIXME ?? */ 594 break; 595 case WAVEOUT_MAPPER_STATUS_FORMAT: 596 FIXME("Unsupported flag=%d\n", flags); 597 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */ 598 *(LPDWORD)ptr = 0; 599 break; 600 default: 601 FIXME("Unsupported flag=%d\n", flags); 602 *(LPDWORD)ptr = 0; 603 break; 604 } 605 return ret; 606 } 607 608 static DWORD wodMapperReconfigure(WAVEMAPDATA* wom, DWORD dwParam1, DWORD dwParam2) 609 { 610 FIXME("(%p %08x %08x) stub!\n", wom, dwParam1, dwParam2); 611 612 return MMSYSERR_NOERROR; 613 } 614 615 /************************************************************************** 616 * wodMessage (MSACM.@) 617 */ 618 DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser, 619 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 620 { 621 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", 622 wDevID, wMsg, dwUser, dwParam1, dwParam2); 623 624 switch (wMsg) { 625 case DRVM_INIT: 626 case DRVM_EXIT: 627 case DRVM_ENABLE: 628 case DRVM_DISABLE: 629 /* FIXME: Pretend this is supported */ 630 return 0; 631 case WODM_OPEN: return wodOpen ((DWORD_PTR*)dwUser, (LPWAVEOPENDESC)dwParam1,dwParam2); 632 case WODM_CLOSE: return wodClose ((WAVEMAPDATA*)dwUser); 633 case WODM_WRITE: return wodWrite ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); 634 case WODM_PAUSE: return wodPause ((WAVEMAPDATA*)dwUser); 635 case WODM_GETPOS: return wodGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2); 636 case WODM_BREAKLOOP: return wodBreakLoop ((WAVEMAPDATA*)dwUser); 637 case WODM_PREPARE: return wodPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); 638 case WODM_UNPREPARE: return wodUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); 639 case WODM_GETDEVCAPS: return wodGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSW)dwParam1,dwParam2); 640 case WODM_GETNUMDEVS: return 1; 641 case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED; 642 case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED; 643 case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; 644 case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; 645 case WODM_GETVOLUME: return wodGetVolume (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1); 646 case WODM_SETVOLUME: return wodSetVolume (wDevID, (WAVEMAPDATA*)dwUser, dwParam1); 647 case WODM_RESTART: return wodRestart ((WAVEMAPDATA*)dwUser); 648 case WODM_RESET: return wodReset ((WAVEMAPDATA*)dwUser); 649 case WODM_MAPPER_STATUS: return wodMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2); 650 case DRVM_MAPPER_RECONFIGURE: return wodMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2); 651 /* known but not supported */ 652 case DRV_QUERYDEVICEINTERFACESIZE: 653 case DRV_QUERYDEVICEINTERFACE: 654 return MMSYSERR_NOTSUPPORTED; 655 default: 656 FIXME("unknown message %d!\n", wMsg); 657 } 658 return MMSYSERR_NOTSUPPORTED; 659 } 660 661 /*======================================================================* 662 * WAVE IN part * 663 *======================================================================*/ 664 665 static void CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD_PTR dwInstance, 666 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 667 { 668 WAVEMAPDATA* wim = (WAVEMAPDATA*)dwInstance; 669 670 TRACE("(%p %u %lx %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2); 671 672 if (!WAVEMAP_IsData(wim)) { 673 ERR("Bad data\n"); 674 return; 675 } 676 677 if (uMsg != WIM_OPEN && hWave != wim->u.in.hInnerWave) 678 ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave); 679 680 switch (uMsg) { 681 case WIM_OPEN: 682 case WIM_CLOSE: 683 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ 684 break; 685 case WIM_DATA: 686 if (wim->hAcmStream) { 687 LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)dwParam1; 688 PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER)); 689 LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)ash->dwUser; 690 691 /* convert data just gotten from waveIn into requested format */ 692 if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) { 693 ERR("ACM conversion failed\n"); 694 return; 695 } else { 696 TRACE("Converted %d bytes into %d\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed); 697 } 698 /* and setup the wavehdr to return accordingly */ 699 lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE; 700 lpWaveHdrDst->dwFlags |= WHDR_DONE; 701 lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed; 702 dwParam1 = (DWORD_PTR)lpWaveHdrDst; 703 } 704 break; 705 default: 706 ERR("Unknown msg %u\n", uMsg); 707 } 708 709 DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave, 710 uMsg, wim->dwClientInstance, dwParam1, dwParam2); 711 } 712 713 static DWORD widOpenHelper(WAVEMAPDATA* wim, UINT idx, 714 LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, 715 DWORD dwFlags) 716 { 717 DWORD ret; 718 719 TRACE("(%p %04x %p %p %08x)\n", wim, idx, lpDesc, lpwfx, dwFlags); 720 721 /* source is always PCM, so the formulas below apply */ 722 lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8; 723 lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign; 724 if (dwFlags & WAVE_FORMAT_QUERY) { 725 ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY); 726 } else { 727 ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L); 728 } 729 if (ret == MMSYSERR_NOERROR) { 730 ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx, 731 (DWORD_PTR)widCallback, (DWORD_PTR)wim, 732 (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION); 733 if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) { 734 acmStreamClose(wim->hAcmStream, 0); 735 wim->hAcmStream = 0; 736 } 737 } 738 TRACE("ret = %08x\n", ret); 739 return ret; 740 } 741 742 static DWORD widOpen(DWORD_PTR *lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags) 743 { 744 UINT ndlo, ndhi; 745 UINT i; 746 WAVEMAPDATA* wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA)); 747 DWORD res; 748 749 TRACE("(%p %p %08x)\n", lpdwUser, lpDesc, dwFlags); 750 751 if (!wim) { 752 WARN("no memory\n"); 753 return MMSYSERR_NOMEM; 754 } 755 756 wim->self = wim; 757 wim->dwCallback = lpDesc->dwCallback; 758 wim->dwFlags = dwFlags; 759 wim->dwClientInstance = lpDesc->dwInstance; 760 wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave; 761 762 ndhi = waveInGetNumDevs(); 763 if (dwFlags & WAVE_MAPPED) { 764 if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM; 765 ndlo = lpDesc->uMappedDeviceID; 766 ndhi = ndlo + 1; 767 dwFlags &= ~WAVE_MAPPED; 768 } else { 769 ndlo = 0; 770 } 771 772 wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec; 773 wim->nSamplesPerSecOuter = wim->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec; 774 775 for (i = ndlo; i < ndhi; i++) { 776 if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat, 777 (DWORD_PTR)widCallback, (DWORD_PTR)wim, 778 (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) { 779 wim->hAcmStream = 0; 780 goto found; 781 } 782 } 783 784 if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) 785 { 786 WAVEFORMATEX wfx; 787 788 wfx.wFormatTag = WAVE_FORMAT_PCM; 789 wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */ 790 /* try some ACM stuff */ 791 792 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \ 793 switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \ 794 case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \ 795 case WAVERR_BADFORMAT: break; \ 796 default: goto error; \ 797 } 798 799 for (i = ndlo; i < ndhi; i++) { 800 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; 801 /* first try with same stereo/mono option as source */ 802 wfx.nChannels = lpDesc->lpFormat->nChannels; 803 TRY(wfx.nSamplesPerSec, 16); 804 TRY(wfx.nSamplesPerSec, 8); 805 wfx.nChannels ^= 3; 806 TRY(wfx.nSamplesPerSec, 16); 807 TRY(wfx.nSamplesPerSec, 8); 808 } 809 810 for (i = ndlo; i < ndhi; i++) { 811 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; 812 /* first try with same stereo/mono option as source */ 813 wfx.nChannels = lpDesc->lpFormat->nChannels; 814 TRY(96000, 16); 815 TRY(48000, 16); 816 TRY(44100, 16); 817 TRY(22050, 16); 818 TRY(11025, 16); 819 820 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ 821 wfx.nChannels ^= 3; 822 TRY(96000, 16); 823 TRY(48000, 16); 824 TRY(44100, 16); 825 TRY(22050, 16); 826 TRY(11025, 16); 827 828 /* first try with same stereo/mono option as source */ 829 wfx.nChannels = lpDesc->lpFormat->nChannels; 830 TRY(96000, 8); 831 TRY(48000, 8); 832 TRY(44100, 8); 833 TRY(22050, 8); 834 TRY(11025, 8); 835 836 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ 837 wfx.nChannels ^= 3; 838 TRY(96000, 8); 839 TRY(48000, 8); 840 TRY(44100, 8); 841 TRY(22050, 8); 842 TRY(11025, 8); 843 } 844 #undef TRY 845 } 846 847 HeapFree(GetProcessHeap(), 0, wim); 848 WARN("ret = WAVERR_BADFORMAT\n"); 849 return WAVERR_BADFORMAT; 850 found: 851 if (dwFlags & WAVE_FORMAT_QUERY) { 852 *lpdwUser = 0L; 853 HeapFree(GetProcessHeap(), 0, wim); 854 } else { 855 *lpdwUser = (DWORD_PTR)wim; 856 TRACE("Ok (stream=%p)\n", wim->hAcmStream); 857 } 858 return MMSYSERR_NOERROR; 859 error: 860 HeapFree(GetProcessHeap(), 0, wim); 861 if (res==ACMERR_NOTPOSSIBLE) { 862 WARN("ret = WAVERR_BADFORMAT\n"); 863 return WAVERR_BADFORMAT; 864 } 865 WARN("ret = 0x%08x\n", res); 866 return res; 867 } 868 869 static DWORD widClose(WAVEMAPDATA* wim) 870 { 871 DWORD ret; 872 873 TRACE("(%p)\n", wim); 874 875 ret = waveInClose(wim->u.in.hInnerWave); 876 if (ret == MMSYSERR_NOERROR) { 877 if (wim->hAcmStream) { 878 ret = acmStreamClose(wim->hAcmStream, 0); 879 } 880 if (ret == MMSYSERR_NOERROR) { 881 HeapFree(GetProcessHeap(), 0, wim); 882 } 883 } 884 return ret; 885 } 886 887 static DWORD widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) 888 { 889 PACMSTREAMHEADER ash; 890 LPWAVEHDR lpWaveHdrSrc; 891 892 TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2); 893 894 if (!wim->hAcmStream) { 895 return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); 896 } 897 898 lpWaveHdrDst->dwFlags |= WHDR_INQUEUE; 899 ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved; 900 901 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); 902 return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); 903 } 904 905 static DWORD widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) 906 { 907 PACMSTREAMHEADER ash; 908 DWORD size; 909 DWORD dwRet; 910 LPWAVEHDR lpWaveHdrSrc; 911 912 TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2); 913 914 if (!wim->hAcmStream) { 915 return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); 916 } 917 if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size, 918 ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR) { 919 WARN("acmStreamSize failed\n"); 920 return MMSYSERR_ERROR; 921 } 922 923 ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size); 924 if (ash == NULL) { 925 WARN("no memory\n"); 926 return MMSYSERR_NOMEM; 927 } 928 929 ash->cbStruct = sizeof(*ash); 930 ash->fdwStatus = 0L; 931 ash->dwUser = (DWORD_PTR)lpWaveHdrDst; 932 ash->pbSrc = (LPBYTE)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR); 933 ash->cbSrcLength = size; 934 /* ash->cbSrcLengthUsed */ 935 ash->dwSrcUser = 0L; /* FIXME ? */ 936 ash->pbDst = (LPBYTE)lpWaveHdrDst->lpData; 937 ash->cbDstLength = lpWaveHdrDst->dwBufferLength; 938 /* ash->cbDstLengthUsed */ 939 ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */ 940 dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L); 941 if (dwRet != MMSYSERR_NOERROR) { 942 WARN("acmStreamPrepareHeader failed\n"); 943 goto errCleanUp; 944 } 945 946 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); 947 lpWaveHdrSrc->lpData = (LPSTR)ash->pbSrc; 948 lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */ 949 lpWaveHdrSrc->dwFlags = 0; 950 lpWaveHdrSrc->dwLoops = 0; 951 dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); 952 if (dwRet != MMSYSERR_NOERROR) { 953 WARN("waveInPrepareHeader failed\n"); 954 goto errCleanUp; 955 } 956 957 lpWaveHdrDst->reserved = (DWORD_PTR)ash; 958 lpWaveHdrDst->dwFlags = WHDR_PREPARED; 959 TRACE("=> (0)\n"); 960 return MMSYSERR_NOERROR; 961 errCleanUp: 962 TRACE("=> (%d)\n", dwRet); 963 HeapFree(GetProcessHeap(), 0, ash); 964 return dwRet; 965 } 966 967 static DWORD widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) 968 { 969 PACMSTREAMHEADER ash; 970 LPWAVEHDR lpWaveHdrSrc; 971 DWORD dwRet1, dwRet2; 972 973 TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2); 974 975 if (!wim->hAcmStream) { 976 return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); 977 } 978 ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved; 979 dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L); 980 981 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); 982 dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); 983 984 HeapFree(GetProcessHeap(), 0, ash); 985 986 lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED; 987 return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1; 988 } 989 990 static DWORD widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2) 991 { 992 DWORD val; 993 MMTIME timepos; 994 TRACE("(%p %p %08x)\n", wim, lpTime, dwParam2); 995 996 timepos = *lpTime; 997 998 /* For TIME_MS, we're going to recalculate using TIME_BYTES */ 999 if (lpTime->wType == TIME_MS) 1000 timepos.wType = TIME_BYTES; 1001 1002 /* This can change timepos.wType if the requested type is not supported */ 1003 val = waveInGetPosition(wim->u.in.hInnerWave, &timepos, dwParam2); 1004 1005 if (timepos.wType == TIME_BYTES) 1006 { 1007 DWORD dwInnerSamplesPerOuter = wim->nSamplesPerSecInner / wim->nSamplesPerSecOuter; 1008 if (dwInnerSamplesPerOuter > 0) 1009 { 1010 DWORD dwInnerBytesPerSample = wim->avgSpeedInner / wim->nSamplesPerSecInner; 1011 DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter; 1012 DWORD remainder = 0; 1013 1014 /* If we are up sampling (going from lower sample rate to higher), 1015 ** we need to make a special accommodation for times when we've 1016 ** written a partial output sample. This happens frequently 1017 ** to us because we use msacm to do our up sampling, and it 1018 ** will up sample on an unaligned basis. 1019 ** For example, if you convert a 2 byte wide 8,000 'outer' 1020 ** buffer to a 2 byte wide 48,000 inner device, you would 1021 ** expect 2 bytes of input to produce 12 bytes of output. 1022 ** Instead, msacm will produce 8 bytes of output. 1023 ** But reporting our position as 1 byte of output is 1024 ** nonsensical; the output buffer position needs to be 1025 ** aligned on outer sample size, and aggressively rounded up. 1026 */ 1027 remainder = timepos.u.cb % dwInnerBytesPerOuterSample; 1028 if (remainder > 0) 1029 { 1030 timepos.u.cb -= remainder; 1031 timepos.u.cb += dwInnerBytesPerOuterSample; 1032 } 1033 } 1034 1035 lpTime->u.cb = MulDiv(timepos.u.cb, wim->avgSpeedOuter, wim->avgSpeedInner); 1036 1037 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */ 1038 if (lpTime->wType == TIME_MS) 1039 lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wim->avgSpeedOuter); 1040 else 1041 lpTime->wType = TIME_BYTES; 1042 } 1043 else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES) 1044 lpTime->u.sample = MulDiv(timepos.u.sample, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner); 1045 else 1046 /* other time types don't require conversion */ 1047 lpTime->u = timepos.u; 1048 1049 return val; 1050 } 1051 1052 static DWORD widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSW lpWaveCaps, DWORD dwParam2) 1053 { 1054 TRACE("(%04x, %p %p %08x)\n", wDevID, wim, lpWaveCaps, dwParam2); 1055 1056 /* if opened low driver, forward message */ 1057 if (WAVEMAP_IsData(wim)) 1058 return waveInGetDevCapsW((UINT_PTR)wim->u.in.hInnerWave, lpWaveCaps, dwParam2); 1059 /* else if no drivers, nothing to map so return bad device */ 1060 if (waveInGetNumDevs() == 0) { 1061 WARN("bad device id\n"); 1062 return MMSYSERR_BADDEVICEID; 1063 } 1064 /* otherwise, return caps of mapper itself */ 1065 if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) { 1066 WAVEINCAPSW wic; 1067 static const WCHAR init[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0}; 1068 wic.wMid = 0x00FF; 1069 wic.wPid = 0x0001; 1070 wic.vDriverVersion = 0x0001; 1071 strcpyW(wic.szPname, init); 1072 wic.dwFormats = 1073 WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 | 1074 WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | 1075 WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | 1076 WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | 1077 WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16; 1078 wic.wChannels = 2; 1079 wic.wReserved1 = 0; 1080 memcpy(lpWaveCaps, &wic, min(dwParam2, sizeof(wic))); 1081 1082 return MMSYSERR_NOERROR; 1083 } 1084 ERR("This shouldn't happen\n"); 1085 return MMSYSERR_ERROR; 1086 } 1087 1088 static DWORD widStop(WAVEMAPDATA* wim) 1089 { 1090 TRACE("(%p)\n", wim); 1091 1092 return waveInStop(wim->u.in.hInnerWave); 1093 } 1094 1095 static DWORD widStart(WAVEMAPDATA* wim) 1096 { 1097 TRACE("(%p)\n", wim); 1098 1099 return waveInStart(wim->u.in.hInnerWave); 1100 } 1101 1102 static DWORD widReset(WAVEMAPDATA* wim) 1103 { 1104 TRACE("(%p)\n", wim); 1105 1106 return waveInReset(wim->u.in.hInnerWave); 1107 } 1108 1109 static DWORD widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr) 1110 { 1111 UINT id; 1112 DWORD ret = MMSYSERR_NOTSUPPORTED; 1113 1114 TRACE("(%p %08x %p)\n", wim, flags, ptr); 1115 1116 switch (flags) { 1117 case WAVEIN_MAPPER_STATUS_DEVICE: 1118 ret = waveInGetID(wim->u.in.hInnerWave, &id); 1119 *(LPDWORD)ptr = id; 1120 break; 1121 case WAVEIN_MAPPER_STATUS_MAPPED: 1122 FIXME("Unsupported yet flag=%d\n", flags); 1123 *(LPDWORD)ptr = 0; /* FIXME ?? */ 1124 break; 1125 case WAVEIN_MAPPER_STATUS_FORMAT: 1126 FIXME("Unsupported flag=%d\n", flags); 1127 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */ 1128 *(LPDWORD)ptr = 0; /* FIXME ?? */ 1129 break; 1130 default: 1131 FIXME("Unsupported flag=%d\n", flags); 1132 *(LPDWORD)ptr = 0; 1133 break; 1134 } 1135 return ret; 1136 } 1137 1138 static DWORD widMapperReconfigure(WAVEMAPDATA* wim, DWORD dwParam1, DWORD dwParam2) 1139 { 1140 FIXME("(%p %08x %08x) stub!\n", wim, dwParam1, dwParam2); 1141 1142 return MMSYSERR_NOERROR; 1143 } 1144 1145 /************************************************************************** 1146 * widMessage (MSACM.@) 1147 */ 1148 DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD_PTR dwUser, 1149 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 1150 { 1151 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", 1152 wDevID, wMsg, dwUser, dwParam1, dwParam2); 1153 1154 switch (wMsg) { 1155 case DRVM_INIT: 1156 case DRVM_EXIT: 1157 case DRVM_ENABLE: 1158 case DRVM_DISABLE: 1159 /* FIXME: Pretend this is supported */ 1160 return 0; 1161 1162 case WIDM_OPEN: return widOpen ((DWORD_PTR*)dwUser, (LPWAVEOPENDESC)dwParam1, dwParam2); 1163 case WIDM_CLOSE: return widClose ((WAVEMAPDATA*)dwUser); 1164 1165 case WIDM_ADDBUFFER: return widAddBuffer ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); 1166 case WIDM_PREPARE: return widPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); 1167 case WIDM_UNPREPARE: return widUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); 1168 case WIDM_GETDEVCAPS: return widGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSW)dwParam1, dwParam2); 1169 case WIDM_GETNUMDEVS: return 1; 1170 case WIDM_GETPOS: return widGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2); 1171 case WIDM_RESET: return widReset ((WAVEMAPDATA*)dwUser); 1172 case WIDM_START: return widStart ((WAVEMAPDATA*)dwUser); 1173 case WIDM_STOP: return widStop ((WAVEMAPDATA*)dwUser); 1174 case WIDM_MAPPER_STATUS: return widMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2); 1175 case DRVM_MAPPER_RECONFIGURE: return widMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2); 1176 /* known but not supported */ 1177 case DRV_QUERYDEVICEINTERFACESIZE: 1178 case DRV_QUERYDEVICEINTERFACE: 1179 return MMSYSERR_NOTSUPPORTED; 1180 default: 1181 FIXME("unknown message %u!\n", wMsg); 1182 } 1183 return MMSYSERR_NOTSUPPORTED; 1184 } 1185 1186 /*======================================================================* 1187 * Driver part * 1188 *======================================================================*/ 1189 1190 static struct WINE_WAVEMAP* oss = NULL; 1191 1192 /************************************************************************** 1193 * WAVEMAP_drvOpen [internal] 1194 */ 1195 static LRESULT WAVEMAP_drvOpen(LPSTR str) 1196 { 1197 TRACE("(%p)\n", str); 1198 1199 if (oss) 1200 return 0; 1201 1202 /* I know, this is ugly, but who cares... */ 1203 oss = (struct WINE_WAVEMAP*)1; 1204 return 1; 1205 } 1206 1207 /************************************************************************** 1208 * WAVEMAP_drvClose [internal] 1209 */ 1210 static LRESULT WAVEMAP_drvClose(DWORD_PTR dwDevID) 1211 { 1212 TRACE("(%08lx)\n", dwDevID); 1213 1214 if (oss) { 1215 oss = NULL; 1216 return 1; 1217 } 1218 return 0; 1219 } 1220 1221 /************************************************************************** 1222 * DriverProc (MSACM.@) 1223 */ 1224 LRESULT CALLBACK WAVEMAP_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, 1225 LPARAM dwParam1, LPARAM dwParam2) 1226 { 1227 TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n", 1228 dwDevID, hDriv, wMsg, dwParam1, dwParam2); 1229 1230 switch(wMsg) { 1231 case DRV_LOAD: return 1; 1232 case DRV_FREE: return 1; 1233 case DRV_OPEN: return WAVEMAP_drvOpen((LPSTR)dwParam1); 1234 case DRV_CLOSE: return WAVEMAP_drvClose(dwDevID); 1235 case DRV_ENABLE: return 1; 1236 case DRV_DISABLE: return 1; 1237 case DRV_QUERYCONFIGURE: return 1; 1238 case DRV_CONFIGURE: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK); return 1; 1239 case DRV_INSTALL: return DRVCNF_RESTART; 1240 case DRV_REMOVE: return DRVCNF_RESTART; 1241 default: 1242 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); 1243 } 1244 } 1245