1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
6 * Copyright 1993 Martin Ayotte
7 * 1998-2002 Eric Pouech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * 98/9 added Win32 MCI support
27 * 99/4 added midiStream support
28 * 99/9 added support for loadable low level drivers
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
50 /******************************************************************
53 * Internal wrapper to call USER.UserYield16 (in fact through a Wine only export from USER32).
55 static void MyUserYield(void)
57 HMODULE mod = GetModuleHandleA( "user32.dll" );
60 FARPROC proc = GetProcAddress( mod, "UserYield16" );
65 void (WINAPI *pFnReleaseThunkLock)(DWORD*);
66 void (WINAPI *pFnRestoreThunkLock)(DWORD);
68 /* ========================================================================
69 * G L O B A L S E T T I N G S
70 * ========================================================================*/
72 LPWINE_MM_IDATA WINMM_IData /* = NULL */;
74 /**************************************************************************
75 * WINMM_CreateIData [internal]
77 static BOOL WINMM_CreateIData(HINSTANCE hInstDLL)
79 WINMM_IData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA));
83 WINMM_IData->hWinMM32Instance = hInstDLL;
84 InitializeCriticalSection(&WINMM_IData->cs);
85 WINMM_IData->cs.DebugInfo = (void*)__FILE__ ": WinMM";
86 WINMM_IData->psStopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
87 WINMM_IData->psLastEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
88 TRACE("Created IData (%p)\n", WINMM_IData);
92 /**************************************************************************
93 * WINMM_DeleteIData [internal]
95 static void WINMM_DeleteIData(void)
100 /* FIXME: should also free content and resources allocated
101 * inside WINMM_IData */
102 CloseHandle(WINMM_IData->psStopEvent);
103 CloseHandle(WINMM_IData->psLastEvent);
104 DeleteCriticalSection(&WINMM_IData->cs);
105 HeapFree(GetProcessHeap(), 0, WINMM_IData);
110 /******************************************************************
114 static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR);
115 static DWORD (WINAPI *pLoadLibrary16)(LPCSTR);
117 BOOL WINMM_CheckForMMSystem(void)
119 /* 0 is not checked yet, -1 is not present, 1 is present */
120 static int loaded /* = 0 */;
124 HANDLE h = GetModuleHandleA("kernel32");
128 pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16");
129 pLoadLibrary16 = (void*)GetProcAddress(h, "LoadLibrary16");
130 if (pGetModuleHandle16 && pLoadLibrary16 &&
131 (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL")))
138 /**************************************************************************
139 * DllMain (WINMM.init)
141 * WINMM DLL entry point
144 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
146 TRACE("%p 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
149 case DLL_PROCESS_ATTACH:
150 DisableThreadLibraryCalls(hInstDLL);
152 if (!WINMM_CreateIData(hInstDLL))
154 if (!MCI_Init() || !MMDRV_Init()) {
159 case DLL_PROCESS_DETACH:
160 /* close all opened MCI drivers */
161 MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L, TRUE);
163 /* now unload all remaining drivers... */
172 /**************************************************************************
173 * Mixer devices. New to Win95
176 /**************************************************************************
177 * find out the real mixer ID depending on hmix (depends on dwFlags)
179 static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags)
181 LPWINE_MIXER lpwm = NULL;
183 switch (dwFlags & 0xF0000000ul) {
184 case MIXER_OBJECTF_MIXER:
185 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
187 case MIXER_OBJECTF_HMIXER:
188 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
190 case MIXER_OBJECTF_WAVEOUT:
191 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
193 case MIXER_OBJECTF_HWAVEOUT:
194 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
196 case MIXER_OBJECTF_WAVEIN:
197 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
199 case MIXER_OBJECTF_HWAVEIN:
200 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
202 case MIXER_OBJECTF_MIDIOUT:
203 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
205 case MIXER_OBJECTF_HMIDIOUT:
206 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
208 case MIXER_OBJECTF_MIDIIN:
209 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
211 case MIXER_OBJECTF_HMIDIIN:
212 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
214 case MIXER_OBJECTF_AUX:
215 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
218 FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
224 /**************************************************************************
225 * mixerGetNumDevs [WINMM.@]
227 UINT WINAPI mixerGetNumDevs(void)
229 return MMDRV_GetNum(MMDRV_MIXER);
232 /**************************************************************************
233 * mixerGetDevCapsA [WINMM.@]
235 UINT WINAPI mixerGetDevCapsA(UINT uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize)
239 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
241 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL)
242 return MMSYSERR_BADDEVICEID;
244 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
247 /**************************************************************************
248 * mixerGetDevCapsW [WINMM.@]
250 UINT WINAPI mixerGetDevCapsW(UINT uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize)
253 UINT ret = mixerGetDevCapsA(uDeviceID, &micA, sizeof(micA));
255 if (ret == MMSYSERR_NOERROR) {
257 micW.wMid = micA.wMid;
258 micW.wPid = micA.wPid;
259 micW.vDriverVersion = micA.vDriverVersion;
260 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname,
261 sizeof(micW.szPname)/sizeof(WCHAR) );
262 micW.fdwSupport = micA.fdwSupport;
263 micW.cDestinations = micA.cDestinations;
264 memcpy(lpCaps, &micW, min(uSize, sizeof(micW)));
269 UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
270 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
277 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
278 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
280 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
281 &dwCallback, &dwInstance, bFrom32);
283 wmld->uDeviceID = uDeviceID;
284 mod.hmx = (HMIXEROBJ)hMix;
285 mod.dwCallback = dwCallback;
286 mod.dwInstance = dwInstance;
288 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
290 if (dwRet != MMSYSERR_NOERROR) {
291 MMDRV_Free(hMix, wmld);
294 if (lphMix) *lphMix = hMix;
295 TRACE("=> %ld hMixer=%p\n", dwRet, hMix);
300 /**************************************************************************
301 * mixerOpen [WINMM.@]
303 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
304 DWORD dwInstance, DWORD fdwOpen)
306 return MIXER_Open(lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen, TRUE);
309 /**************************************************************************
310 * mixerClose [WINMM.@]
312 UINT WINAPI mixerClose(HMIXER hMix)
317 TRACE("(%p)\n", hMix);
319 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
321 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
322 MMDRV_Free(hMix, wmld);
327 /**************************************************************************
328 * mixerGetID [WINMM.@]
330 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
334 TRACE("(%p %p %08lx)\n", hmix, lpid, fdwID);
336 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
337 return MMSYSERR_INVALHANDLE;
341 *lpid = lpwm->mld.uDeviceID;
343 return MMSYSERR_NOERROR;
346 /**************************************************************************
347 * mixerGetControlDetailsA [WINMM.@]
349 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
354 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
356 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
357 return MMSYSERR_INVALHANDLE;
359 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
360 return MMSYSERR_INVALPARAM;
362 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD)lpmcdA,
366 /**************************************************************************
367 * mixerGetControlDetailsW [WINMM.@]
369 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
371 DWORD ret = MMSYSERR_NOTENABLED;
373 TRACE("(%p, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
375 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
376 return MMSYSERR_INVALPARAM;
378 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
379 case MIXER_GETCONTROLDETAILSF_VALUE:
380 /* can savely use W structure as it is, no string inside */
381 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
383 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
385 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
386 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
387 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
390 if (lpmcd->u.cMultipleItems != 0) {
391 size *= lpmcd->u.cMultipleItems;
393 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
394 lpmcd->paDetails = pDetailsA;
395 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
396 /* set up lpmcd->paDetails */
397 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
398 /* copy from lpmcd->paDetails back to paDetailsW; */
399 if(ret == MMSYSERR_NOERROR) {
400 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
401 pDetailsW->dwParam1 = pDetailsA->dwParam1;
402 pDetailsW->dwParam2 = pDetailsA->dwParam2;
403 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
405 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
409 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
410 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
412 HeapFree(GetProcessHeap(), 0, pDetailsA);
413 lpmcd->paDetails = pDetailsW;
414 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
418 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
424 /**************************************************************************
425 * mixerGetLineControlsA [WINMM.@]
427 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
432 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
434 if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
435 return MMSYSERR_INVALHANDLE;
437 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
438 return MMSYSERR_INVALPARAM;
440 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD)lpmlcA,
444 /**************************************************************************
445 * mixerGetLineControlsW [WINMM.@]
447 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
450 MIXERLINECONTROLSA mlcA;
454 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
456 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
457 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
458 return MMSYSERR_INVALPARAM;
460 mlcA.cbStruct = sizeof(mlcA);
461 mlcA.dwLineID = lpmlcW->dwLineID;
462 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
463 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
464 mlcA.cControls = lpmlcW->cControls;
465 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
466 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
467 mlcA.cControls * mlcA.cbmxctrl);
469 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
471 if (ret == MMSYSERR_NOERROR) {
472 lpmlcW->dwLineID = mlcA.dwLineID;
473 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
474 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
475 lpmlcW->cControls = mlcA.cControls;
477 for (i = 0; i < mlcA.cControls; i++) {
478 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
479 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
480 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
481 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
482 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
483 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
484 lpmlcW->pamxctrl[i].szShortName,
485 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
486 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
487 lpmlcW->pamxctrl[i].szName,
488 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
489 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
490 * sizeof(mlcA.pamxctrl[i].Bounds) */
491 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
492 sizeof(mlcA.pamxctrl[i].Bounds));
493 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
494 * sizeof(mlcA.pamxctrl[i].Metrics) */
495 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
496 sizeof(mlcA.pamxctrl[i].Metrics));
500 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
505 /**************************************************************************
506 * mixerGetLineInfoA [WINMM.@]
508 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
512 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
514 if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
515 return MMSYSERR_INVALHANDLE;
517 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD)lpmliW,
521 /**************************************************************************
522 * mixerGetLineInfoW [WINMM.@]
524 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
530 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
532 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
533 return MMSYSERR_INVALPARAM;
535 mliA.cbStruct = sizeof(mliA);
536 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
537 case MIXER_GETLINEINFOF_COMPONENTTYPE:
538 mliA.dwComponentType = lpmliW->dwComponentType;
540 case MIXER_GETLINEINFOF_DESTINATION:
541 mliA.dwDestination = lpmliW->dwDestination;
543 case MIXER_GETLINEINFOF_LINEID:
544 mliA.dwLineID = lpmliW->dwLineID;
546 case MIXER_GETLINEINFOF_SOURCE:
547 mliA.dwDestination = lpmliW->dwDestination;
548 mliA.dwSource = lpmliW->dwSource;
550 case MIXER_GETLINEINFOF_TARGETTYPE:
551 mliA.Target.dwType = lpmliW->Target.dwType;
552 mliA.Target.wMid = lpmliW->Target.wMid;
553 mliA.Target.wPid = lpmliW->Target.wPid;
554 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
555 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
558 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
561 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
563 lpmliW->dwDestination = mliA.dwDestination;
564 lpmliW->dwSource = mliA.dwSource;
565 lpmliW->dwLineID = mliA.dwLineID;
566 lpmliW->fdwLine = mliA.fdwLine;
567 lpmliW->dwUser = mliA.dwUser;
568 lpmliW->dwComponentType = mliA.dwComponentType;
569 lpmliW->cChannels = mliA.cChannels;
570 lpmliW->cConnections = mliA.cConnections;
571 lpmliW->cControls = mliA.cControls;
572 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
573 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
574 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
575 sizeof(lpmliW->szName)/sizeof(WCHAR) );
576 lpmliW->Target.dwType = mliA.Target.dwType;
577 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
578 lpmliW->Target.wMid = mliA.Target.wMid;
579 lpmliW->Target.wPid = mliA.Target.wPid;
580 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
581 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
582 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
587 /**************************************************************************
588 * mixerSetControlDetails [WINMM.@]
590 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
595 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
597 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
598 return MMSYSERR_INVALHANDLE;
600 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD)lpmcdA,
604 /**************************************************************************
605 * mixerMessage [WINMM.@]
607 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
611 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
612 (DWORD)hmix, uMsg, dwParam1, dwParam2);
614 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
615 return MMSYSERR_INVALHANDLE;
617 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
620 /**************************************************************************
621 * auxGetNumDevs [WINMM.@]
623 UINT WINAPI auxGetNumDevs(void)
625 return MMDRV_GetNum(MMDRV_AUX);
628 /**************************************************************************
629 * auxGetDevCapsW [WINMM.@]
631 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
634 UINT ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
636 if (ret == MMSYSERR_NOERROR) {
640 acW.vDriverVersion = acA.vDriverVersion;
641 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, acW.szPname,
642 sizeof(acW.szPname)/sizeof(WCHAR) );
643 acW.wTechnology = acA.wTechnology;
644 acW.dwSupport = acA.dwSupport;
645 memcpy(lpCaps, &acW, min(uSize, sizeof(acW)));
650 /**************************************************************************
651 * auxGetDevCapsA [WINMM.@]
653 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
657 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
659 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
661 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
662 return MMSYSERR_INVALHANDLE;
663 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
666 /**************************************************************************
667 * auxGetVolume [WINMM.@]
669 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
673 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
675 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
676 return MMSYSERR_INVALHANDLE;
677 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
680 /**************************************************************************
681 * auxSetVolume [WINMM.@]
683 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
687 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
689 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
690 return MMSYSERR_INVALHANDLE;
691 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
694 /**************************************************************************
695 * auxOutMessage [WINMM.@]
697 UINT WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
701 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
702 return MMSYSERR_INVALHANDLE;
704 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
707 /**************************************************************************
708 * mciGetErrorStringW [WINMM.@]
710 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
712 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
713 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
715 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
716 HeapFree(GetProcessHeap(), 0, bufstr);
720 /**************************************************************************
721 * mciGetErrorStringA [WINMM.@]
723 BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength)
727 if (lpstrBuffer != NULL && uLength > 0 &&
728 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
730 if (LoadStringA(WINMM_IData->hWinMM32Instance,
731 dwError, lpstrBuffer, uLength) > 0) {
738 /**************************************************************************
739 * mciDriverNotify [WINMM.@]
741 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
744 TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
746 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
749 /**************************************************************************
750 * mciGetDriverData [WINMM.@]
752 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
754 LPWINE_MCIDRIVER wmd;
756 TRACE("(%04x)\n", uDeviceID);
758 wmd = MCI_GetDriver(uDeviceID);
761 WARN("Bad uDeviceID\n");
765 return wmd->dwPrivate;
768 /**************************************************************************
769 * mciSetDriverData [WINMM.@]
771 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
773 LPWINE_MCIDRIVER wmd;
775 TRACE("(%04x, %08lx)\n", uDeviceID, data);
777 wmd = MCI_GetDriver(uDeviceID);
780 WARN("Bad uDeviceID\n");
784 wmd->dwPrivate = data;
788 /**************************************************************************
789 * mciSendCommandA [WINMM.@]
791 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
795 TRACE("(%08x, %s, %08lx, %08lx)\n",
796 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
798 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
799 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2);
800 TRACE("=> %08lx\n", dwRet);
804 /**************************************************************************
805 * mciSendCommandW [WINMM.@]
807 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
809 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
810 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
811 return MCIERR_UNSUPPORTED_FUNCTION;
814 /**************************************************************************
815 * mciGetDeviceIDA [WINMM.@]
817 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
819 return MCI_GetDriverFromString(lpstrName);
822 /**************************************************************************
823 * mciGetDeviceIDW [WINMM.@]
825 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
827 LPSTR lpstrName = NULL;
832 len = WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, NULL, 0, NULL, NULL );
833 lpstrName = HeapAlloc( GetProcessHeap(), 0, len );
834 if (lpstrName) WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, lpstrName, len, NULL, NULL );
836 ret = MCI_GetDriverFromString(lpstrName);
837 HeapFree(GetProcessHeap(), 0, lpstrName);
841 /**************************************************************************
842 * MCI_DefYieldProc [internal]
844 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
848 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
850 if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
851 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
857 msg.hwnd = HWND_32(HIWORD(data));
858 while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
864 /**************************************************************************
865 * mciSetYieldProc [WINMM.@]
867 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
869 LPWINE_MCIDRIVER wmd;
871 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
873 if (!(wmd = MCI_GetDriver(uDeviceID))) {
874 WARN("Bad uDeviceID\n");
878 wmd->lpfnYieldProc = fpYieldProc;
879 wmd->dwYieldData = dwYieldData;
885 /**************************************************************************
886 * mciGetDeviceIDFromElementIDW [WINMM.@]
888 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
890 /* FIXME: that's rather strange, there is no
891 * mciGetDeviceIDFromElementID32A in winmm.spec
893 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
897 /**************************************************************************
898 * mciGetYieldProc [WINMM.@]
900 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
902 LPWINE_MCIDRIVER wmd;
904 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
906 if (!(wmd = MCI_GetDriver(uDeviceID))) {
907 WARN("Bad uDeviceID\n");
910 if (!wmd->lpfnYieldProc) {
911 WARN("No proc set\n");
915 WARN("Proc is 32 bit\n");
918 return wmd->lpfnYieldProc;
921 /**************************************************************************
922 * mciGetCreatorTask [WINMM.@]
924 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
926 LPWINE_MCIDRIVER wmd;
929 if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
931 TRACE("(%u) => %p\n", uDeviceID, ret);
935 /**************************************************************************
936 * mciDriverYield [WINMM.@]
938 UINT WINAPI mciDriverYield(UINT uDeviceID)
940 LPWINE_MCIDRIVER wmd;
943 TRACE("(%04x)\n", uDeviceID);
945 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
948 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
954 /**************************************************************************
955 * midiOutGetNumDevs [WINMM.@]
957 UINT WINAPI midiOutGetNumDevs(void)
959 return MMDRV_GetNum(MMDRV_MIDIOUT);
962 /**************************************************************************
963 * midiOutGetDevCapsW [WINMM.@]
965 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps,
969 UINT ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
971 if (ret == MMSYSERR_NOERROR) {
973 mocW.wMid = mocA.wMid;
974 mocW.wPid = mocA.wPid;
975 mocW.vDriverVersion = mocA.vDriverVersion;
976 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, mocW.szPname,
977 sizeof(mocW.szPname)/sizeof(WCHAR) );
978 mocW.wTechnology = mocA.wTechnology;
979 mocW.wVoices = mocA.wVoices;
980 mocW.wNotes = mocA.wNotes;
981 mocW.wChannelMask = mocA.wChannelMask;
982 mocW.dwSupport = mocA.dwSupport;
983 memcpy(lpCaps, &mocW, min(uSize, sizeof(mocW)));
988 /**************************************************************************
989 * midiOutGetDevCapsA [WINMM.@]
991 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
996 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
998 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1000 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
1001 return MMSYSERR_INVALHANDLE;
1003 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1006 /**************************************************************************
1007 * MIDI_GetErrorText [internal]
1009 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
1011 UINT16 ret = MMSYSERR_BADERRNUM;
1013 if (lpText == NULL) {
1014 ret = MMSYSERR_INVALPARAM;
1015 } else if (uSize == 0) {
1016 ret = MMSYSERR_NOERROR;
1018 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
1019 * a warning for the test was always true */
1020 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
1021 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
1023 if (LoadStringA(WINMM_IData->hWinMM32Instance,
1024 uError, lpText, uSize) > 0) {
1025 ret = MMSYSERR_NOERROR;
1031 /**************************************************************************
1032 * midiOutGetErrorTextA [WINMM.@]
1034 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1036 return MIDI_GetErrorText(uError, lpText, uSize);
1039 /**************************************************************************
1040 * midiOutGetErrorTextW [WINMM.@]
1042 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1044 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1047 ret = MIDI_GetErrorText(uError, xstr, uSize);
1048 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1049 HeapFree(GetProcessHeap(), 0, xstr);
1053 /**************************************************************************
1054 * MIDI_OutAlloc [internal]
1056 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
1057 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
1058 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
1064 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
1066 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
1067 lpdwCallback, lpdwInstance, bFrom32);
1069 if (lphMidiOut != NULL)
1070 *lphMidiOut = hMidiOut;
1073 lpwm->mod.hMidi = (HMIDI) hMidiOut;
1074 lpwm->mod.dwCallback = *lpdwCallback;
1075 lpwm->mod.dwInstance = *lpdwInstance;
1076 lpwm->mod.dnDevNode = 0;
1077 lpwm->mod.cIds = cIDs;
1079 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
1084 UINT MIDI_OutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
1085 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1091 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1092 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
1094 if (lphMidiOut != NULL) *lphMidiOut = 0;
1096 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
1100 return MMSYSERR_NOMEM;
1102 lpwm->mld.uDeviceID = uDeviceID;
1104 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1106 if (dwRet != MMSYSERR_NOERROR) {
1107 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
1111 if (lphMidiOut) *lphMidiOut = hMidiOut;
1112 TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut);
1117 /**************************************************************************
1118 * midiOutOpen [WINMM.@]
1120 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
1121 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1123 return MIDI_OutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1126 /**************************************************************************
1127 * midiOutClose [WINMM.@]
1129 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
1134 TRACE("(%p)\n", hMidiOut);
1136 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1137 return MMSYSERR_INVALHANDLE;
1139 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
1140 MMDRV_Free(hMidiOut, wmld);
1145 /**************************************************************************
1146 * midiOutPrepareHeader [WINMM.@]
1148 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
1149 MIDIHDR* lpMidiOutHdr, UINT uSize)
1153 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1155 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1156 return MMSYSERR_INVALHANDLE;
1158 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
1161 /**************************************************************************
1162 * midiOutUnprepareHeader [WINMM.@]
1164 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
1165 MIDIHDR* lpMidiOutHdr, UINT uSize)
1169 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1171 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
1172 return MMSYSERR_NOERROR;
1175 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1176 return MMSYSERR_INVALHANDLE;
1178 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
1181 /**************************************************************************
1182 * midiOutShortMsg [WINMM.@]
1184 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
1188 TRACE("(%p, %08lX)\n", hMidiOut, dwMsg);
1190 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1191 return MMSYSERR_INVALHANDLE;
1193 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, TRUE);
1196 /**************************************************************************
1197 * midiOutLongMsg [WINMM.@]
1199 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
1200 MIDIHDR* lpMidiOutHdr, UINT uSize)
1204 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1206 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1207 return MMSYSERR_INVALHANDLE;
1209 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE);
1212 /**************************************************************************
1213 * midiOutReset [WINMM.@]
1215 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
1219 TRACE("(%p)\n", hMidiOut);
1221 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1222 return MMSYSERR_INVALHANDLE;
1224 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
1227 /**************************************************************************
1228 * midiOutGetVolume [WINMM.@]
1230 UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume)
1234 TRACE("(%p, %p);\n", hMidiOut, lpdwVolume);
1236 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1237 return MMSYSERR_INVALHANDLE;
1239 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1242 /**************************************************************************
1243 * midiOutSetVolume [WINMM.@]
1245 UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume)
1249 TRACE("(%p, %ld);\n", hMidiOut, dwVolume);
1251 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1252 return MMSYSERR_INVALHANDLE;
1254 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
1257 /**************************************************************************
1258 * midiOutCachePatches [WINMM.@]
1260 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
1261 WORD* lpwPatchArray, UINT uFlags)
1263 /* not really necessary to support this */
1264 FIXME("not supported yet\n");
1265 return MMSYSERR_NOTSUPPORTED;
1268 /**************************************************************************
1269 * midiOutCacheDrumPatches [WINMM.@]
1271 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
1272 WORD* lpwKeyArray, UINT uFlags)
1274 FIXME("not supported yet\n");
1275 return MMSYSERR_NOTSUPPORTED;
1278 /**************************************************************************
1279 * midiOutGetID [WINMM.@]
1281 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
1285 TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID);
1287 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1288 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1289 return MMSYSERR_INVALHANDLE;
1291 *lpuDeviceID = wmld->uDeviceID;
1292 return MMSYSERR_NOERROR;
1295 /**************************************************************************
1296 * midiOutMessage [WINMM.@]
1298 UINT WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
1299 DWORD dwParam1, DWORD dwParam2)
1303 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
1305 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
1307 if (uMessage == 0x0001) {
1308 *(LPDWORD)dwParam1 = 1;
1311 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
1312 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
1314 return MMSYSERR_INVALHANDLE;
1320 FIXME("can't handle OPEN or CLOSE message!\n");
1321 return MMSYSERR_NOTSUPPORTED;
1323 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1326 /**************************************************************************
1327 * midiInGetNumDevs [WINMM.@]
1329 UINT WINAPI midiInGetNumDevs(void)
1331 return MMDRV_GetNum(MMDRV_MIDIIN);
1334 /**************************************************************************
1335 * midiInGetDevCapsW [WINMM.@]
1337 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
1340 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
1342 if (ret == MMSYSERR_NOERROR) {
1344 micW.wMid = micA.wMid;
1345 micW.wPid = micA.wPid;
1346 micW.vDriverVersion = micA.vDriverVersion;
1347 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname,
1348 sizeof(micW.szPname)/sizeof(WCHAR) );
1349 micW.dwSupport = micA.dwSupport;
1350 memcpy(lpCaps, &micW, min(uSize, sizeof(micW)));
1355 /**************************************************************************
1356 * midiInGetDevCapsA [WINMM.@]
1358 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
1362 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
1364 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1366 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
1367 return MMSYSERR_INVALHANDLE;
1369 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1372 /**************************************************************************
1373 * midiInGetErrorTextW [WINMM.@]
1375 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1377 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1378 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
1380 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1381 HeapFree(GetProcessHeap(), 0, xstr);
1385 /**************************************************************************
1386 * midiInGetErrorTextA [WINMM.@]
1388 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1390 return MIDI_GetErrorText(uError, lpText, uSize);
1393 UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
1394 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1400 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1401 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
1403 if (lphMidiIn != NULL) *lphMidiIn = 0;
1405 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
1406 &dwFlags, &dwCallback, &dwInstance, bFrom32);
1409 return MMSYSERR_NOMEM;
1411 lpwm->mod.hMidi = (HMIDI) hMidiIn;
1412 lpwm->mod.dwCallback = dwCallback;
1413 lpwm->mod.dwInstance = dwInstance;
1415 lpwm->mld.uDeviceID = uDeviceID;
1416 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1418 if (dwRet != MMSYSERR_NOERROR) {
1419 MMDRV_Free(hMidiIn, &lpwm->mld);
1422 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
1423 TRACE("=> %ld hMidi=%p\n", dwRet, hMidiIn);
1428 /**************************************************************************
1429 * midiInOpen [WINMM.@]
1431 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
1432 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1434 return MIDI_InOpen(lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1437 /**************************************************************************
1438 * midiInClose [WINMM.@]
1440 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
1445 TRACE("(%p)\n", hMidiIn);
1447 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1448 return MMSYSERR_INVALHANDLE;
1450 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
1451 MMDRV_Free(hMidiIn, wmld);
1455 /**************************************************************************
1456 * midiInPrepareHeader [WINMM.@]
1458 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
1459 MIDIHDR* lpMidiInHdr, UINT uSize)
1463 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1465 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1466 return MMSYSERR_INVALHANDLE;
1468 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
1471 /**************************************************************************
1472 * midiInUnprepareHeader [WINMM.@]
1474 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
1475 MIDIHDR* lpMidiInHdr, UINT uSize)
1479 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1481 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
1482 return MMSYSERR_NOERROR;
1485 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1486 return MMSYSERR_INVALHANDLE;
1488 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
1491 /**************************************************************************
1492 * midiInAddBuffer [WINMM.@]
1494 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
1495 MIDIHDR* lpMidiInHdr, UINT uSize)
1499 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1501 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1502 return MMSYSERR_INVALHANDLE;
1504 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE);
1507 /**************************************************************************
1508 * midiInStart [WINMM.@]
1510 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
1514 TRACE("(%p)\n", hMidiIn);
1516 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1517 return MMSYSERR_INVALHANDLE;
1519 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
1522 /**************************************************************************
1523 * midiInStop [WINMM.@]
1525 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
1529 TRACE("(%p)\n", hMidiIn);
1531 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1532 return MMSYSERR_INVALHANDLE;
1534 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
1537 /**************************************************************************
1538 * midiInReset [WINMM.@]
1540 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
1544 TRACE("(%p)\n", hMidiIn);
1546 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1547 return MMSYSERR_INVALHANDLE;
1549 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
1552 /**************************************************************************
1553 * midiInGetID [WINMM.@]
1555 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
1559 TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID);
1561 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1563 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
1564 return MMSYSERR_INVALHANDLE;
1566 *lpuDeviceID = wmld->uDeviceID;
1568 return MMSYSERR_NOERROR;
1571 /**************************************************************************
1572 * midiInMessage [WINMM.@]
1574 UINT WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
1575 DWORD dwParam1, DWORD dwParam2)
1579 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
1581 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1582 return MMSYSERR_INVALHANDLE;
1587 FIXME("can't handle OPEN or CLOSE message!\n");
1588 return MMSYSERR_NOTSUPPORTED;
1590 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1593 typedef struct WINE_MIDIStream {
1604 LPMIDIHDR lpMidiHdr;
1607 #define WINE_MSM_HEADER (WM_USER+0)
1608 #define WINE_MSM_STOP (WM_USER+1)
1610 /**************************************************************************
1611 * MMSYSTEM_GetMidiStream [internal]
1613 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
1615 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
1624 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
1626 return *lpMidiStrm != NULL;
1629 /**************************************************************************
1630 * MMSYSTEM_MidiStream_Convert [internal]
1632 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
1636 if (lpMidiStrm->dwTimeDiv == 0) {
1637 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1638 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
1639 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
1640 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
1641 ret = (pulse * 1000) / (nf * nsf);
1643 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
1644 (double)lpMidiStrm->dwTimeDiv);
1650 /**************************************************************************
1651 * MMSYSTEM_MidiStream_MessageHandler [internal]
1653 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
1655 LPMIDIHDR lpMidiHdr;
1659 switch (msg->message) {
1661 SetEvent(lpMidiStrm->hEvent);
1665 /* this is not quite what MS doc says... */
1666 midiOutReset(lpMidiStrm->hDevice);
1667 /* empty list of already submitted buffers */
1668 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
1669 lpMidiHdr->dwFlags |= MHDR_DONE;
1670 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1672 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1673 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1674 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1676 lpMidiStrm->lpMidiHdr = 0;
1677 SetEvent(lpMidiStrm->hEvent);
1679 case WINE_MSM_HEADER:
1680 /* sets initial tick count for first MIDIHDR */
1681 if (!lpMidiStrm->dwStartTicks)
1682 lpMidiStrm->dwStartTicks = GetTickCount();
1684 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1685 * by native mcimidi, it doesn't look like a correct one".
1686 * this trick allows to throw it away... but I don't like it.
1687 * It looks like part of the file I'm trying to play and definitively looks
1688 * like raw midi content
1689 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1690 * synchronization issue where native mcimidi is still processing raw MIDI
1691 * content before generating MIDIEVENTs ?
1693 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1694 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1695 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1696 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1697 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1698 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1699 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1700 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1701 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1702 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1703 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1704 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1705 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1706 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1707 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1708 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1709 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1711 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1712 lpData = lpMidiHdr->lpData;
1713 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1714 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
1715 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
1716 lpMidiHdr->dwFlags, msg->wParam);
1718 /* dumps content of lpMidiHdr->lpData
1719 * FIXME: there should be a debug routine somewhere that already does this
1720 * I hate spreading this type of shit all around the code
1722 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
1726 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
1727 printf("%02x ", lpData[dwToGo + i]);
1730 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
1731 ch = lpData[dwToGo + i];
1732 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
1737 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
1738 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
1739 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
1740 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
1741 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
1742 ((LPMIDIEVENT)lpData)->dwStreamID);
1743 lpMidiHdr->dwFlags |= MHDR_DONE;
1744 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1746 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1747 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1748 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1752 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
1754 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1755 lpMidiHdr->lpNext = 0;
1756 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
1757 lpMidiHdr->dwFlags &= MHDR_DONE;
1758 lpMidiHdr->dwOffset = 0;
1762 FIXME("Unknown message %d\n", msg->message);
1768 /**************************************************************************
1769 * MMSYSTEM_MidiStream_Player [internal]
1771 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
1773 WINE_MIDIStream* lpMidiStrm = pmt;
1778 LPMIDIHDR lpMidiHdr;
1782 TRACE("(%p)!\n", lpMidiStrm);
1785 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
1788 /* force thread's queue creation */
1789 /* Used to be InitThreadInput16(0, 5); */
1790 /* but following works also with hack in midiStreamOpen */
1791 PeekMessageA(&msg, 0, 0, 0, 0);
1793 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
1794 SetEvent(lpMidiStrm->hEvent);
1795 TRACE("Ready to go 1\n");
1796 /* thread is started in paused mode */
1797 SuspendThread(lpMidiStrm->hThread);
1798 TRACE("Ready to go 2\n");
1800 lpMidiStrm->dwStartTicks = 0;
1801 lpMidiStrm->dwPulses = 0;
1803 lpMidiStrm->lpMidiHdr = 0;
1806 lpMidiHdr = lpMidiStrm->lpMidiHdr;
1808 /* for first message, block until one arrives, then process all that are available */
1809 GetMessageA(&msg, 0, 0, 0);
1811 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1813 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
1819 lpData = lpMidiHdr->lpData;
1821 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
1823 /* do we have to wait ? */
1824 if (me->dwDeltaTime) {
1825 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
1826 lpMidiStrm->dwPulses += me->dwDeltaTime;
1828 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
1830 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
1831 while ((dwCurrTC = GetTickCount()) < dwToGo) {
1832 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
1833 /* got a message, handle it */
1834 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
1835 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1840 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
1845 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
1847 FIXME("NIY: MEVT_COMMENT\n");
1848 /* do nothing, skip bytes */
1851 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
1856 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
1859 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
1864 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
1867 if (me->dwEvent & MEVT_F_CALLBACK) {
1868 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1869 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
1870 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
1872 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
1873 if (me->dwEvent & MEVT_F_LONG)
1874 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
1875 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
1876 /* done with this header */
1877 lpMidiHdr->dwFlags |= MHDR_DONE;
1878 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1880 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
1881 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1882 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1883 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1888 TRACE("End of thread\n");
1890 return 0; /* for removing the warning, never executed */
1893 /**************************************************************************
1894 * MMSYSTEM_MidiStream_PostMessage [internal]
1896 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
1898 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
1901 if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
1902 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1903 if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
1905 WARN("bad PostThreadMessageA\n");
1911 /**************************************************************************
1912 * midiStreamClose [WINMM.@]
1914 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
1916 WINE_MIDIStream* lpMidiStrm;
1918 TRACE("(%p)!\n", hMidiStrm);
1920 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
1921 return MMSYSERR_INVALHANDLE;
1923 midiStreamStop(hMidiStrm);
1924 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
1925 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
1926 CloseHandle(lpMidiStrm->hEvent);
1928 return midiOutClose((HMIDIOUT)hMidiStrm);
1931 /**************************************************************************
1932 * MMSYSTEM_MidiStream_Open [internal]
1934 MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, DWORD cMidi,
1935 DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen,
1938 WINE_MIDIStream* lpMidiStrm;
1940 MIDIOPENSTRMID mosm;
1944 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
1945 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
1947 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
1948 return MMSYSERR_INVALPARAM;
1950 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
1952 return MMSYSERR_NOMEM;
1954 lpMidiStrm->dwTempo = 500000;
1955 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
1956 lpMidiStrm->dwPositionMS = 0;
1958 mosm.dwStreamID = (DWORD)lpMidiStrm;
1959 /* FIXME: the correct value is not allocated yet for MAPPER */
1960 mosm.wDeviceID = *lpuDeviceID;
1961 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
1962 lpMidiStrm->hDevice = hMidiOut;
1964 *lphMidiStrm = (HMIDISTRM)hMidiOut;
1966 lpwm->mld.uDeviceID = *lpuDeviceID;
1968 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
1969 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1970 lpMidiStrm->wFlags = HIWORD(fdwOpen);
1972 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
1973 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
1975 if (!lpMidiStrm->hThread) {
1976 midiStreamClose((HMIDISTRM)hMidiOut);
1977 return MMSYSERR_NOMEM;
1980 /* wait for thread to have started, and for its queue to be created */
1984 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
1985 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
1986 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
1988 if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
1989 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1990 if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
1993 TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n",
1994 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
1998 /**************************************************************************
1999 * midiStreamOpen [WINMM.@]
2001 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
2002 DWORD cMidi, DWORD dwCallback,
2003 DWORD dwInstance, DWORD fdwOpen)
2005 return MIDI_StreamOpen(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
2006 dwInstance, fdwOpen, TRUE);
2009 /**************************************************************************
2010 * midiStreamOut [WINMM.@]
2012 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
2015 WINE_MIDIStream* lpMidiStrm;
2016 DWORD ret = MMSYSERR_NOERROR;
2018 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
2020 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2021 ret = MMSYSERR_INVALHANDLE;
2022 } else if (!lpMidiHdr) {
2023 ret = MMSYSERR_INVALPARAM;
2025 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
2026 WINE_MSM_HEADER, cbMidiHdr,
2027 (DWORD)lpMidiHdr)) {
2028 WARN("bad PostThreadMessageA\n");
2029 ret = MMSYSERR_ERROR;
2035 /**************************************************************************
2036 * midiStreamPause [WINMM.@]
2038 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
2040 WINE_MIDIStream* lpMidiStrm;
2041 DWORD ret = MMSYSERR_NOERROR;
2043 TRACE("(%p)!\n", hMidiStrm);
2045 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2046 ret = MMSYSERR_INVALHANDLE;
2048 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
2049 WARN("bad Suspend (%ld)\n", GetLastError());
2050 ret = MMSYSERR_ERROR;
2056 /**************************************************************************
2057 * midiStreamPosition [WINMM.@]
2059 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
2061 WINE_MIDIStream* lpMidiStrm;
2062 DWORD ret = MMSYSERR_NOERROR;
2064 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
2066 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2067 ret = MMSYSERR_INVALHANDLE;
2068 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
2069 ret = MMSYSERR_INVALPARAM;
2071 switch (lpMMT->wType) {
2073 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
2074 TRACE("=> %ld ms\n", lpMMT->u.ms);
2077 lpMMT->u.ticks = lpMidiStrm->dwPulses;
2078 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
2081 WARN("Unsupported time type %d\n", lpMMT->wType);
2082 lpMMT->wType = TIME_MS;
2083 ret = MMSYSERR_INVALPARAM;
2090 /**************************************************************************
2091 * midiStreamProperty [WINMM.@]
2093 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
2095 WINE_MIDIStream* lpMidiStrm;
2096 MMRESULT ret = MMSYSERR_NOERROR;
2098 TRACE("(%p, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
2100 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2101 ret = MMSYSERR_INVALHANDLE;
2102 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
2103 ret = MMSYSERR_INVALPARAM;
2104 } else if (dwProperty & MIDIPROP_TEMPO) {
2105 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
2107 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
2108 ret = MMSYSERR_INVALPARAM;
2109 } else if (dwProperty & MIDIPROP_SET) {
2110 lpMidiStrm->dwTempo = mpt->dwTempo;
2111 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
2112 } else if (dwProperty & MIDIPROP_GET) {
2113 mpt->dwTempo = lpMidiStrm->dwTempo;
2114 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
2116 } else if (dwProperty & MIDIPROP_TIMEDIV) {
2117 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
2119 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
2120 ret = MMSYSERR_INVALPARAM;
2121 } else if (dwProperty & MIDIPROP_SET) {
2122 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
2123 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
2124 } else if (dwProperty & MIDIPROP_GET) {
2125 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
2126 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
2129 ret = MMSYSERR_INVALPARAM;
2135 /**************************************************************************
2136 * midiStreamRestart [WINMM.@]
2138 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
2140 WINE_MIDIStream* lpMidiStrm;
2141 MMRESULT ret = MMSYSERR_NOERROR;
2143 TRACE("(%p)!\n", hMidiStrm);
2145 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2146 ret = MMSYSERR_INVALHANDLE;
2150 /* since we increase the thread suspend count on each midiStreamPause
2151 * there may be a need for several midiStreamResume
2154 ret = ResumeThread(lpMidiStrm->hThread);
2155 } while (ret != 0xFFFFFFFF && ret != 0);
2156 if (ret == 0xFFFFFFFF) {
2157 WARN("bad Resume (%ld)\n", GetLastError());
2158 ret = MMSYSERR_ERROR;
2160 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
2166 /**************************************************************************
2167 * midiStreamStop [WINMM.@]
2169 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
2171 WINE_MIDIStream* lpMidiStrm;
2172 MMRESULT ret = MMSYSERR_NOERROR;
2174 TRACE("(%p)!\n", hMidiStrm);
2176 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2177 ret = MMSYSERR_INVALHANDLE;
2179 /* in case stream has been paused... FIXME is the current state correct ? */
2180 midiStreamRestart(hMidiStrm);
2181 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
2186 UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType,
2187 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2188 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2192 DWORD dwRet = MMSYSERR_NOERROR;
2195 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2196 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
2197 dwInstance, dwFlags, bFrom32?32:16);
2199 if (dwFlags & WAVE_FORMAT_QUERY) TRACE("WAVE_FORMAT_QUERY requested !\n");
2201 if (lpFormat == NULL) return WAVERR_BADFORMAT;
2202 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1))
2203 return MMSYSERR_INVALPARAM;
2205 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
2206 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
2207 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize);
2209 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
2210 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL)
2211 return MMSYSERR_NOMEM;
2214 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
2215 wod.dwCallback = dwCallback;
2216 wod.dwInstance = dwInstance;
2219 TRACE("cb=%08lx\n", wod.dwCallback);
2222 if (dwFlags & WAVE_MAPPED) {
2223 wod.uMappedDeviceID = uDeviceID;
2224 uDeviceID = WAVE_MAPPER;
2226 wod.uMappedDeviceID = -1;
2228 wmld->uDeviceID = uDeviceID;
2230 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN,
2231 (DWORD)&wod, dwFlags);
2233 if (dwRet != WAVERR_BADFORMAT ||
2234 (dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) break;
2235 /* if we ask for a format which isn't supported by the physical driver,
2236 * let's try to map it through the wave mapper (except, if we already tried
2237 * or user didn't allow us to use acm codecs)
2239 dwFlags |= WAVE_MAPPED;
2240 /* we shall loop only one */
2243 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
2244 MMDRV_Free(handle, wmld);
2248 if (lphndl != NULL) *lphndl = handle;
2249 TRACE("=> %ld hWave=%p\n", dwRet, handle);
2254 /**************************************************************************
2255 * waveOutGetNumDevs [WINMM.@]
2257 UINT WINAPI waveOutGetNumDevs(void)
2259 return MMDRV_GetNum(MMDRV_WAVEOUT);
2262 /**************************************************************************
2263 * waveOutGetDevCapsA [WINMM.@]
2265 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
2270 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2272 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2274 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
2275 return MMSYSERR_BADDEVICEID;
2277 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2281 /**************************************************************************
2282 * waveOutGetDevCapsW [WINMM.@]
2284 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
2288 UINT ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
2290 if (ret == MMSYSERR_NOERROR) {
2292 wocW.wMid = wocA.wMid;
2293 wocW.wPid = wocA.wPid;
2294 wocW.vDriverVersion = wocA.vDriverVersion;
2295 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, wocW.szPname,
2296 sizeof(wocW.szPname)/sizeof(WCHAR) );
2297 wocW.dwFormats = wocA.dwFormats;
2298 wocW.wChannels = wocA.wChannels;
2299 wocW.dwSupport = wocA.dwSupport;
2300 memcpy(lpCaps, &wocW, min(uSize, sizeof(wocW)));
2305 /**************************************************************************
2306 * WAVE_GetErrorText [internal]
2308 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2310 UINT16 ret = MMSYSERR_BADERRNUM;
2312 if (lpText == NULL) {
2313 ret = MMSYSERR_INVALPARAM;
2314 } else if (uSize == 0) {
2315 ret = MMSYSERR_NOERROR;
2317 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2318 * a warning for the test was always true */
2319 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
2320 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
2322 if (LoadStringA(WINMM_IData->hWinMM32Instance,
2323 uError, lpText, uSize) > 0) {
2324 ret = MMSYSERR_NOERROR;
2330 /**************************************************************************
2331 * waveOutGetErrorTextA [WINMM.@]
2333 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2335 return WAVE_GetErrorText(uError, lpText, uSize);
2338 /**************************************************************************
2339 * waveOutGetErrorTextW [WINMM.@]
2341 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2343 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2344 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
2346 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2347 HeapFree(GetProcessHeap(), 0, xstr);
2351 /**************************************************************************
2352 * waveOutOpen [WINMM.@]
2353 * All the args/structs have the same layout as the win16 equivalents
2355 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
2356 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2357 DWORD dwInstance, DWORD dwFlags)
2359 return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
2360 dwCallback, dwInstance, dwFlags, TRUE);
2363 /**************************************************************************
2364 * waveOutClose [WINMM.@]
2366 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
2371 TRACE("(%p)\n", hWaveOut);
2373 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2374 return MMSYSERR_INVALHANDLE;
2376 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
2377 if (dwRet != WAVERR_STILLPLAYING)
2378 MMDRV_Free(hWaveOut, wmld);
2383 /**************************************************************************
2384 * waveOutPrepareHeader [WINMM.@]
2386 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
2387 WAVEHDR* lpWaveOutHdr, UINT uSize)
2391 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2393 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
2395 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2396 return MMSYSERR_INVALHANDLE;
2398 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2401 /**************************************************************************
2402 * waveOutUnprepareHeader [WINMM.@]
2404 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
2405 LPWAVEHDR lpWaveOutHdr, UINT uSize)
2409 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2411 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
2412 return MMSYSERR_NOERROR;
2415 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2416 return MMSYSERR_INVALHANDLE;
2418 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2421 /**************************************************************************
2422 * waveOutWrite [WINMM.@]
2424 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
2429 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2431 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2432 return MMSYSERR_INVALHANDLE;
2434 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2437 /**************************************************************************
2438 * waveOutBreakLoop [WINMM.@]
2440 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
2444 TRACE("(%p);\n", hWaveOut);
2446 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2447 return MMSYSERR_INVALHANDLE;
2448 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
2451 /**************************************************************************
2452 * waveOutPause [WINMM.@]
2454 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
2458 TRACE("(%p);\n", hWaveOut);
2460 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2461 return MMSYSERR_INVALHANDLE;
2462 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
2465 /**************************************************************************
2466 * waveOutReset [WINMM.@]
2468 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
2472 TRACE("(%p);\n", hWaveOut);
2474 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2475 return MMSYSERR_INVALHANDLE;
2476 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
2479 /**************************************************************************
2480 * waveOutRestart [WINMM.@]
2482 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
2486 TRACE("(%p);\n", hWaveOut);
2488 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2489 return MMSYSERR_INVALHANDLE;
2490 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
2493 /**************************************************************************
2494 * waveOutGetPosition [WINMM.@]
2496 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
2501 TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize);
2503 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2504 return MMSYSERR_INVALHANDLE;
2506 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE);
2509 /**************************************************************************
2510 * waveOutGetPitch [WINMM.@]
2512 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
2516 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2518 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2519 return MMSYSERR_INVALHANDLE;
2520 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE);
2523 /**************************************************************************
2524 * waveOutSetPitch [WINMM.@]
2526 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
2530 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2532 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2533 return MMSYSERR_INVALHANDLE;
2534 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
2537 /**************************************************************************
2538 * waveOutGetPlaybackRate [WINMM.@]
2540 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
2544 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2546 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2547 return MMSYSERR_INVALHANDLE;
2548 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE);
2551 /**************************************************************************
2552 * waveOutSetPlaybackRate [WINMM.@]
2554 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
2558 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2560 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2561 return MMSYSERR_INVALHANDLE;
2562 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
2565 /**************************************************************************
2566 * waveOutGetVolume [WINMM.@]
2568 UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw)
2572 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2574 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2575 return MMSYSERR_INVALHANDLE;
2577 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE);
2580 /**************************************************************************
2581 * waveOutSetVolume [WINMM.@]
2583 UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw)
2587 TRACE("(%p, %08lx);\n", hWaveOut, dw);
2589 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2590 return MMSYSERR_INVALHANDLE;
2592 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
2595 /**************************************************************************
2596 * waveOutGetID [WINMM.@]
2598 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
2602 TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID);
2604 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2606 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2607 return MMSYSERR_INVALHANDLE;
2609 *lpuDeviceID = wmld->uDeviceID;
2613 /**************************************************************************
2614 * waveOutMessage [WINMM.@]
2616 UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
2617 DWORD dwParam1, DWORD dwParam2)
2621 TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
2623 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
2624 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
2625 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2627 return MMSYSERR_INVALHANDLE;
2631 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
2632 return MMSYSERR_INVALPARAM;
2634 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2637 /**************************************************************************
2638 * waveInGetNumDevs [WINMM.@]
2640 UINT WINAPI waveInGetNumDevs(void)
2642 return MMDRV_GetNum(MMDRV_WAVEIN);
2645 /**************************************************************************
2646 * waveInGetDevCapsW [WINMM.@]
2648 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
2651 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize);
2653 if (ret == MMSYSERR_NOERROR) {
2655 wicW.wMid = wicA.wMid;
2656 wicW.wPid = wicA.wPid;
2657 wicW.vDriverVersion = wicA.vDriverVersion;
2658 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, wicW.szPname,
2659 sizeof(wicW.szPname)/sizeof(WCHAR) );
2660 wicW.dwFormats = wicA.dwFormats;
2661 wicW.wChannels = wicA.wChannels;
2662 memcpy(lpCaps, &wicW, min(uSize, sizeof(wicW)));
2667 /**************************************************************************
2668 * waveInGetDevCapsA [WINMM.@]
2670 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
2674 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2676 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2678 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
2679 return MMSYSERR_BADDEVICEID;
2681 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2684 /**************************************************************************
2685 * waveInGetErrorTextA [WINMM.@]
2687 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2689 return WAVE_GetErrorText(uError, lpText, uSize);
2692 /**************************************************************************
2693 * waveInGetErrorTextW [WINMM.@]
2695 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2697 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
2698 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
2700 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
2701 HeapFree(GetProcessHeap(), 0, txt);
2705 /**************************************************************************
2706 * waveInOpen [WINMM.@]
2708 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
2709 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2710 DWORD dwInstance, DWORD dwFlags)
2712 return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
2713 dwCallback, dwInstance, dwFlags, TRUE);
2716 /**************************************************************************
2717 * waveInClose [WINMM.@]
2719 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
2724 TRACE("(%p)\n", hWaveIn);
2726 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2727 return MMSYSERR_INVALHANDLE;
2729 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
2730 if (dwRet != WAVERR_STILLPLAYING)
2731 MMDRV_Free(hWaveIn, wmld);
2735 /**************************************************************************
2736 * waveInPrepareHeader [WINMM.@]
2738 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2743 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2745 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2746 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2747 return MMSYSERR_INVALHANDLE;
2749 lpWaveInHdr->dwBytesRecorded = 0;
2751 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
2754 /**************************************************************************
2755 * waveInUnprepareHeader [WINMM.@]
2757 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2762 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2764 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2765 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
2766 return MMSYSERR_NOERROR;
2769 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2770 return MMSYSERR_INVALHANDLE;
2772 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
2775 /**************************************************************************
2776 * waveInAddBuffer [WINMM.@]
2778 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
2779 WAVEHDR* lpWaveInHdr, UINT uSize)
2783 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2785 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2786 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2787 return MMSYSERR_INVALHANDLE;
2789 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE);
2792 /**************************************************************************
2793 * waveInReset [WINMM.@]
2795 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
2799 TRACE("(%p);\n", hWaveIn);
2801 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2802 return MMSYSERR_INVALHANDLE;
2804 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
2807 /**************************************************************************
2808 * waveInStart [WINMM.@]
2810 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
2814 TRACE("(%p);\n", hWaveIn);
2816 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2817 return MMSYSERR_INVALHANDLE;
2819 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
2822 /**************************************************************************
2823 * waveInStop [WINMM.@]
2825 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
2829 TRACE("(%p);\n", hWaveIn);
2831 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2832 return MMSYSERR_INVALHANDLE;
2834 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
2837 /**************************************************************************
2838 * waveInGetPosition [WINMM.@]
2840 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
2845 TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize);
2847 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2848 return MMSYSERR_INVALHANDLE;
2850 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE);
2853 /**************************************************************************
2854 * waveInGetID [WINMM.@]
2856 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
2860 TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID);
2862 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2864 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2865 return MMSYSERR_INVALHANDLE;
2867 *lpuDeviceID = wmld->uDeviceID;
2868 return MMSYSERR_NOERROR;
2871 /**************************************************************************
2872 * waveInMessage [WINMM.@]
2874 UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
2875 DWORD dwParam1, DWORD dwParam2)
2879 TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
2881 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) {
2882 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) {
2883 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2885 return MMSYSERR_INVALHANDLE;
2889 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
2890 return MMSYSERR_INVALPARAM;
2893 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);