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 /* ========================================================================
66 * G L O B A L S E T T I N G S
67 * ========================================================================*/
69 LPWINE_MM_IDATA WINMM_IData /* = NULL */;
71 /**************************************************************************
72 * WINMM_CreateIData [internal]
74 static BOOL WINMM_CreateIData(HINSTANCE hInstDLL)
76 WINMM_IData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA));
80 WINMM_IData->hWinMM32Instance = hInstDLL;
81 InitializeCriticalSection(&WINMM_IData->cs);
82 WINMM_IData->cs.DebugInfo = (void*)__FILE__ ": WinMM";
83 WINMM_IData->psStopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
84 WINMM_IData->psLastEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
85 TRACE("Created IData (%p)\n", WINMM_IData);
89 /**************************************************************************
90 * WINMM_DeleteIData [internal]
92 static void WINMM_DeleteIData(void)
97 /* FIXME: should also free content and resources allocated
98 * inside WINMM_IData */
99 CloseHandle(WINMM_IData->psStopEvent);
100 CloseHandle(WINMM_IData->psLastEvent);
101 DeleteCriticalSection(&WINMM_IData->cs);
102 HeapFree(GetProcessHeap(), 0, WINMM_IData);
107 /******************************************************************
111 static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR);
112 static DWORD (WINAPI *pLoadLibrary16)(LPCSTR);
114 BOOL WINMM_CheckForMMSystem(void)
116 /* 0 is not checked yet, -1 is not present, 1 is present */
117 static int loaded /* = 0 */;
121 HANDLE h = GetModuleHandleA("kernel32");
125 pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16");
126 pLoadLibrary16 = (void*)GetProcAddress(h, "LoadLibrary16");
127 if (pGetModuleHandle16 && pLoadLibrary16 &&
128 (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL")))
135 /**************************************************************************
136 * DllMain (WINMM.init)
138 * WINMM DLL entry point
141 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
143 TRACE("%p 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
146 case DLL_PROCESS_ATTACH:
147 DisableThreadLibraryCalls(hInstDLL);
149 if (!WINMM_CreateIData(hInstDLL))
151 if (!MCI_Init() || !MMDRV_Init()) {
156 case DLL_PROCESS_DETACH:
157 /* close all opened MCI drivers */
158 MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L, TRUE);
160 /* now unload all remaining drivers... */
169 /**************************************************************************
170 * Mixer devices. New to Win95
173 /**************************************************************************
174 * find out the real mixer ID depending on hmix (depends on dwFlags)
176 static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags)
178 LPWINE_MIXER lpwm = NULL;
180 switch (dwFlags & 0xF0000000ul) {
181 case MIXER_OBJECTF_MIXER:
182 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
184 case MIXER_OBJECTF_HMIXER:
185 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
187 case MIXER_OBJECTF_WAVEOUT:
188 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
190 case MIXER_OBJECTF_HWAVEOUT:
191 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
193 case MIXER_OBJECTF_WAVEIN:
194 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
196 case MIXER_OBJECTF_HWAVEIN:
197 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
199 case MIXER_OBJECTF_MIDIOUT:
200 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
202 case MIXER_OBJECTF_HMIDIOUT:
203 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
205 case MIXER_OBJECTF_MIDIIN:
206 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
208 case MIXER_OBJECTF_HMIDIIN:
209 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
211 case MIXER_OBJECTF_AUX:
212 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
215 FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
221 /**************************************************************************
222 * mixerGetNumDevs [WINMM.@]
224 UINT WINAPI mixerGetNumDevs(void)
226 return MMDRV_GetNum(MMDRV_MIXER);
229 /**************************************************************************
230 * mixerGetDevCapsA [WINMM.@]
232 UINT WINAPI mixerGetDevCapsA(UINT uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize)
236 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
238 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL)
239 return MMSYSERR_BADDEVICEID;
241 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
244 /**************************************************************************
245 * mixerGetDevCapsW [WINMM.@]
247 UINT WINAPI mixerGetDevCapsW(UINT uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize)
250 UINT ret = mixerGetDevCapsA(uDeviceID, &micA, sizeof(micA));
252 if (ret == MMSYSERR_NOERROR) {
254 micW.wMid = micA.wMid;
255 micW.wPid = micA.wPid;
256 micW.vDriverVersion = micA.vDriverVersion;
257 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname,
258 sizeof(micW.szPname)/sizeof(WCHAR) );
259 micW.fdwSupport = micA.fdwSupport;
260 micW.cDestinations = micA.cDestinations;
261 memcpy(lpCaps, &micW, min(uSize, sizeof(micW)));
266 UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
267 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
274 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
275 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
277 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
278 &dwCallback, &dwInstance, bFrom32);
280 wmld->uDeviceID = uDeviceID;
281 mod.hmx = (HMIXEROBJ)hMix;
282 mod.dwCallback = dwCallback;
283 mod.dwInstance = dwInstance;
285 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
287 if (dwRet != MMSYSERR_NOERROR) {
288 MMDRV_Free(hMix, wmld);
291 if (lphMix) *lphMix = hMix;
292 TRACE("=> %ld hMixer=%p\n", dwRet, hMix);
297 /**************************************************************************
298 * mixerOpen [WINMM.@]
300 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
301 DWORD dwInstance, DWORD fdwOpen)
303 return MIXER_Open(lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen, TRUE);
306 /**************************************************************************
307 * mixerClose [WINMM.@]
309 UINT WINAPI mixerClose(HMIXER hMix)
314 TRACE("(%p)\n", hMix);
316 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
318 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
319 MMDRV_Free(hMix, wmld);
324 /**************************************************************************
325 * mixerGetID [WINMM.@]
327 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
331 TRACE("(%p %p %08lx)\n", hmix, lpid, fdwID);
333 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
334 return MMSYSERR_INVALHANDLE;
338 *lpid = lpwm->mld.uDeviceID;
340 return MMSYSERR_NOERROR;
343 /**************************************************************************
344 * mixerGetControlDetailsA [WINMM.@]
346 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
351 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
353 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
354 return MMSYSERR_INVALHANDLE;
356 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
357 return MMSYSERR_INVALPARAM;
359 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD)lpmcdA,
363 /**************************************************************************
364 * mixerGetControlDetailsW [WINMM.@]
366 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
368 DWORD ret = MMSYSERR_NOTENABLED;
370 TRACE("(%p, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
372 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
373 return MMSYSERR_INVALPARAM;
375 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
376 case MIXER_GETCONTROLDETAILSF_VALUE:
377 /* can savely use W structure as it is, no string inside */
378 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
380 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
382 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
383 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
384 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
387 if (lpmcd->u.cMultipleItems != 0) {
388 size *= lpmcd->u.cMultipleItems;
390 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
391 lpmcd->paDetails = pDetailsA;
392 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
393 /* set up lpmcd->paDetails */
394 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
395 /* copy from lpmcd->paDetails back to paDetailsW; */
396 if(ret == MMSYSERR_NOERROR) {
397 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
398 pDetailsW->dwParam1 = pDetailsA->dwParam1;
399 pDetailsW->dwParam2 = pDetailsA->dwParam2;
400 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
402 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
406 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
407 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
409 HeapFree(GetProcessHeap(), 0, pDetailsA);
410 lpmcd->paDetails = pDetailsW;
411 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
415 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
421 /**************************************************************************
422 * mixerGetLineControlsA [WINMM.@]
424 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
429 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
431 if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
432 return MMSYSERR_INVALHANDLE;
434 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
435 return MMSYSERR_INVALPARAM;
437 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD)lpmlcA,
441 /**************************************************************************
442 * mixerGetLineControlsW [WINMM.@]
444 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
447 MIXERLINECONTROLSA mlcA;
451 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
453 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
454 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
455 return MMSYSERR_INVALPARAM;
457 mlcA.cbStruct = sizeof(mlcA);
458 mlcA.dwLineID = lpmlcW->dwLineID;
459 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
460 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
461 mlcA.cControls = lpmlcW->cControls;
462 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
463 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
464 mlcA.cControls * mlcA.cbmxctrl);
466 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
468 if (ret == MMSYSERR_NOERROR) {
469 lpmlcW->dwLineID = mlcA.dwLineID;
470 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
471 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
472 lpmlcW->cControls = mlcA.cControls;
474 for (i = 0; i < mlcA.cControls; i++) {
475 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
476 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
477 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
478 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
479 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
480 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
481 lpmlcW->pamxctrl[i].szShortName,
482 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
483 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
484 lpmlcW->pamxctrl[i].szName,
485 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
486 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
487 * sizeof(mlcA.pamxctrl[i].Bounds) */
488 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
489 sizeof(mlcA.pamxctrl[i].Bounds));
490 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
491 * sizeof(mlcA.pamxctrl[i].Metrics) */
492 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
493 sizeof(mlcA.pamxctrl[i].Metrics));
497 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
502 /**************************************************************************
503 * mixerGetLineInfoA [WINMM.@]
505 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
509 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
511 if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
512 return MMSYSERR_INVALHANDLE;
514 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD)lpmliW,
518 /**************************************************************************
519 * mixerGetLineInfoW [WINMM.@]
521 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
527 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
529 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
530 return MMSYSERR_INVALPARAM;
532 mliA.cbStruct = sizeof(mliA);
533 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
534 case MIXER_GETLINEINFOF_COMPONENTTYPE:
535 mliA.dwComponentType = lpmliW->dwComponentType;
537 case MIXER_GETLINEINFOF_DESTINATION:
538 mliA.dwDestination = lpmliW->dwDestination;
540 case MIXER_GETLINEINFOF_LINEID:
541 mliA.dwLineID = lpmliW->dwLineID;
543 case MIXER_GETLINEINFOF_SOURCE:
544 mliA.dwDestination = lpmliW->dwDestination;
545 mliA.dwSource = lpmliW->dwSource;
547 case MIXER_GETLINEINFOF_TARGETTYPE:
548 mliA.Target.dwType = lpmliW->Target.dwType;
549 mliA.Target.wMid = lpmliW->Target.wMid;
550 mliA.Target.wPid = lpmliW->Target.wPid;
551 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
552 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
555 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
558 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
560 lpmliW->dwDestination = mliA.dwDestination;
561 lpmliW->dwSource = mliA.dwSource;
562 lpmliW->dwLineID = mliA.dwLineID;
563 lpmliW->fdwLine = mliA.fdwLine;
564 lpmliW->dwUser = mliA.dwUser;
565 lpmliW->dwComponentType = mliA.dwComponentType;
566 lpmliW->cChannels = mliA.cChannels;
567 lpmliW->cConnections = mliA.cConnections;
568 lpmliW->cControls = mliA.cControls;
569 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
570 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
571 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
572 sizeof(lpmliW->szName)/sizeof(WCHAR) );
573 lpmliW->Target.dwType = mliA.Target.dwType;
574 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
575 lpmliW->Target.wMid = mliA.Target.wMid;
576 lpmliW->Target.wPid = mliA.Target.wPid;
577 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
578 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
579 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
584 /**************************************************************************
585 * mixerSetControlDetails [WINMM.@]
587 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
592 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
594 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
595 return MMSYSERR_INVALHANDLE;
597 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD)lpmcdA,
601 /**************************************************************************
602 * mixerMessage [WINMM.@]
604 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
608 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
609 (DWORD)hmix, uMsg, dwParam1, dwParam2);
611 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
612 return MMSYSERR_INVALHANDLE;
614 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
617 /**************************************************************************
618 * auxGetNumDevs [WINMM.@]
620 UINT WINAPI auxGetNumDevs(void)
622 return MMDRV_GetNum(MMDRV_AUX);
625 /**************************************************************************
626 * auxGetDevCapsW [WINMM.@]
628 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
631 UINT ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
633 if (ret == MMSYSERR_NOERROR) {
637 acW.vDriverVersion = acA.vDriverVersion;
638 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, acW.szPname,
639 sizeof(acW.szPname)/sizeof(WCHAR) );
640 acW.wTechnology = acA.wTechnology;
641 acW.dwSupport = acA.dwSupport;
642 memcpy(lpCaps, &acW, min(uSize, sizeof(acW)));
647 /**************************************************************************
648 * auxGetDevCapsA [WINMM.@]
650 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
654 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
656 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
658 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
659 return MMSYSERR_INVALHANDLE;
660 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
663 /**************************************************************************
664 * auxGetVolume [WINMM.@]
666 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
670 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
672 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
673 return MMSYSERR_INVALHANDLE;
674 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
677 /**************************************************************************
678 * auxSetVolume [WINMM.@]
680 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
684 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
686 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
687 return MMSYSERR_INVALHANDLE;
688 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
691 /**************************************************************************
692 * auxOutMessage [WINMM.@]
694 UINT WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
698 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
699 return MMSYSERR_INVALHANDLE;
701 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
704 /**************************************************************************
705 * mciGetErrorStringW [WINMM.@]
707 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
709 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
710 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
712 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
713 HeapFree(GetProcessHeap(), 0, bufstr);
717 /**************************************************************************
718 * mciGetErrorStringA [WINMM.@]
720 BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength)
724 if (lpstrBuffer != NULL && uLength > 0 &&
725 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
727 if (LoadStringA(WINMM_IData->hWinMM32Instance,
728 dwError, lpstrBuffer, uLength) > 0) {
735 /**************************************************************************
736 * mciDriverNotify [WINMM.@]
738 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
741 TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
743 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
746 /**************************************************************************
747 * mciGetDriverData [WINMM.@]
749 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
751 LPWINE_MCIDRIVER wmd;
753 TRACE("(%04x)\n", uDeviceID);
755 wmd = MCI_GetDriver(uDeviceID);
758 WARN("Bad uDeviceID\n");
762 return wmd->dwPrivate;
765 /**************************************************************************
766 * mciSetDriverData [WINMM.@]
768 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
770 LPWINE_MCIDRIVER wmd;
772 TRACE("(%04x, %08lx)\n", uDeviceID, data);
774 wmd = MCI_GetDriver(uDeviceID);
777 WARN("Bad uDeviceID\n");
781 wmd->dwPrivate = data;
785 /**************************************************************************
786 * mciSendCommandA [WINMM.@]
788 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
792 TRACE("(%08x, %s, %08lx, %08lx)\n",
793 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
795 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
796 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2);
797 TRACE("=> %08lx\n", dwRet);
801 /**************************************************************************
802 * mciSendCommandW [WINMM.@]
804 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
806 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
807 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
808 return MCIERR_UNSUPPORTED_FUNCTION;
811 /**************************************************************************
812 * mciGetDeviceIDA [WINMM.@]
814 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
816 return MCI_GetDriverFromString(lpstrName);
819 /**************************************************************************
820 * mciGetDeviceIDW [WINMM.@]
822 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
824 LPSTR lpstrName = NULL;
829 len = WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, NULL, 0, NULL, NULL );
830 lpstrName = HeapAlloc( GetProcessHeap(), 0, len );
831 if (lpstrName) WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, lpstrName, len, NULL, NULL );
833 ret = MCI_GetDriverFromString(lpstrName);
834 HeapFree(GetProcessHeap(), 0, lpstrName);
838 /**************************************************************************
839 * MCI_DefYieldProc [internal]
841 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
845 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
847 if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
848 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
854 msg.hwnd = HWND_32(HIWORD(data));
855 while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
861 /**************************************************************************
862 * mciSetYieldProc [WINMM.@]
864 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
866 LPWINE_MCIDRIVER wmd;
868 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
870 if (!(wmd = MCI_GetDriver(uDeviceID))) {
871 WARN("Bad uDeviceID\n");
875 wmd->lpfnYieldProc = fpYieldProc;
876 wmd->dwYieldData = dwYieldData;
882 /**************************************************************************
883 * mciGetDeviceIDFromElementIDW [WINMM.@]
885 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
887 /* FIXME: that's rather strange, there is no
888 * mciGetDeviceIDFromElementID32A in winmm.spec
890 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
894 /**************************************************************************
895 * mciGetYieldProc [WINMM.@]
897 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
899 LPWINE_MCIDRIVER wmd;
901 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
903 if (!(wmd = MCI_GetDriver(uDeviceID))) {
904 WARN("Bad uDeviceID\n");
907 if (!wmd->lpfnYieldProc) {
908 WARN("No proc set\n");
912 WARN("Proc is 32 bit\n");
915 return wmd->lpfnYieldProc;
918 /**************************************************************************
919 * mciGetCreatorTask [WINMM.@]
921 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
923 LPWINE_MCIDRIVER wmd;
926 if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
928 TRACE("(%u) => %p\n", uDeviceID, ret);
932 /**************************************************************************
933 * mciDriverYield [WINMM.@]
935 UINT WINAPI mciDriverYield(UINT uDeviceID)
937 LPWINE_MCIDRIVER wmd;
940 TRACE("(%04x)\n", uDeviceID);
942 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
945 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
951 /**************************************************************************
952 * midiOutGetNumDevs [WINMM.@]
954 UINT WINAPI midiOutGetNumDevs(void)
956 return MMDRV_GetNum(MMDRV_MIDIOUT);
959 /**************************************************************************
960 * midiOutGetDevCapsW [WINMM.@]
962 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps,
966 UINT ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
968 if (ret == MMSYSERR_NOERROR) {
970 mocW.wMid = mocA.wMid;
971 mocW.wPid = mocA.wPid;
972 mocW.vDriverVersion = mocA.vDriverVersion;
973 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, mocW.szPname,
974 sizeof(mocW.szPname)/sizeof(WCHAR) );
975 mocW.wTechnology = mocA.wTechnology;
976 mocW.wVoices = mocA.wVoices;
977 mocW.wNotes = mocA.wNotes;
978 mocW.wChannelMask = mocA.wChannelMask;
979 mocW.dwSupport = mocA.dwSupport;
980 memcpy(lpCaps, &mocW, min(uSize, sizeof(mocW)));
985 /**************************************************************************
986 * midiOutGetDevCapsA [WINMM.@]
988 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
993 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
995 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
997 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
998 return MMSYSERR_INVALHANDLE;
1000 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1003 /**************************************************************************
1004 * MIDI_GetErrorText [internal]
1006 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
1008 UINT16 ret = MMSYSERR_BADERRNUM;
1010 if (lpText == NULL) {
1011 ret = MMSYSERR_INVALPARAM;
1012 } else if (uSize == 0) {
1013 ret = MMSYSERR_NOERROR;
1015 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
1016 * a warning for the test was always true */
1017 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
1018 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
1020 if (LoadStringA(WINMM_IData->hWinMM32Instance,
1021 uError, lpText, uSize) > 0) {
1022 ret = MMSYSERR_NOERROR;
1028 /**************************************************************************
1029 * midiOutGetErrorTextA [WINMM.@]
1031 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1033 return MIDI_GetErrorText(uError, lpText, uSize);
1036 /**************************************************************************
1037 * midiOutGetErrorTextW [WINMM.@]
1039 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1041 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1044 ret = MIDI_GetErrorText(uError, xstr, uSize);
1045 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1046 HeapFree(GetProcessHeap(), 0, xstr);
1050 /**************************************************************************
1051 * MIDI_OutAlloc [internal]
1053 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
1054 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
1055 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
1061 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
1063 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
1064 lpdwCallback, lpdwInstance, bFrom32);
1066 if (lphMidiOut != NULL)
1067 *lphMidiOut = hMidiOut;
1070 lpwm->mod.hMidi = (HMIDI) hMidiOut;
1071 lpwm->mod.dwCallback = *lpdwCallback;
1072 lpwm->mod.dwInstance = *lpdwInstance;
1073 lpwm->mod.dnDevNode = 0;
1074 lpwm->mod.cIds = cIDs;
1076 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
1081 UINT MIDI_OutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
1082 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1088 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1089 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
1091 if (lphMidiOut != NULL) *lphMidiOut = 0;
1093 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
1097 return MMSYSERR_NOMEM;
1099 lpwm->mld.uDeviceID = uDeviceID;
1101 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1103 if (dwRet != MMSYSERR_NOERROR) {
1104 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
1108 if (lphMidiOut) *lphMidiOut = hMidiOut;
1109 TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut);
1114 /**************************************************************************
1115 * midiOutOpen [WINMM.@]
1117 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
1118 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1120 return MIDI_OutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1123 /**************************************************************************
1124 * midiOutClose [WINMM.@]
1126 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
1131 TRACE("(%p)\n", hMidiOut);
1133 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1134 return MMSYSERR_INVALHANDLE;
1136 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
1137 MMDRV_Free(hMidiOut, wmld);
1142 /**************************************************************************
1143 * midiOutPrepareHeader [WINMM.@]
1145 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
1146 MIDIHDR* lpMidiOutHdr, UINT uSize)
1150 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1152 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1153 return MMSYSERR_INVALHANDLE;
1155 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
1158 /**************************************************************************
1159 * midiOutUnprepareHeader [WINMM.@]
1161 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
1162 MIDIHDR* lpMidiOutHdr, UINT uSize)
1166 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1168 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
1169 return MMSYSERR_NOERROR;
1172 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1173 return MMSYSERR_INVALHANDLE;
1175 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
1178 /**************************************************************************
1179 * midiOutShortMsg [WINMM.@]
1181 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
1185 TRACE("(%p, %08lX)\n", hMidiOut, dwMsg);
1187 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1188 return MMSYSERR_INVALHANDLE;
1190 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, TRUE);
1193 /**************************************************************************
1194 * midiOutLongMsg [WINMM.@]
1196 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
1197 MIDIHDR* lpMidiOutHdr, UINT uSize)
1201 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1203 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1204 return MMSYSERR_INVALHANDLE;
1206 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE);
1209 /**************************************************************************
1210 * midiOutReset [WINMM.@]
1212 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
1216 TRACE("(%p)\n", hMidiOut);
1218 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1219 return MMSYSERR_INVALHANDLE;
1221 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
1224 /**************************************************************************
1225 * midiOutGetVolume [WINMM.@]
1227 UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume)
1231 TRACE("(%p, %p);\n", hMidiOut, lpdwVolume);
1233 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1234 return MMSYSERR_INVALHANDLE;
1236 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1239 /**************************************************************************
1240 * midiOutSetVolume [WINMM.@]
1242 UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume)
1246 TRACE("(%p, %ld);\n", hMidiOut, dwVolume);
1248 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1249 return MMSYSERR_INVALHANDLE;
1251 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
1254 /**************************************************************************
1255 * midiOutCachePatches [WINMM.@]
1257 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
1258 WORD* lpwPatchArray, UINT uFlags)
1260 /* not really necessary to support this */
1261 FIXME("not supported yet\n");
1262 return MMSYSERR_NOTSUPPORTED;
1265 /**************************************************************************
1266 * midiOutCacheDrumPatches [WINMM.@]
1268 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
1269 WORD* lpwKeyArray, UINT uFlags)
1271 FIXME("not supported yet\n");
1272 return MMSYSERR_NOTSUPPORTED;
1275 /**************************************************************************
1276 * midiOutGetID [WINMM.@]
1278 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
1282 TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID);
1284 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1285 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1286 return MMSYSERR_INVALHANDLE;
1288 *lpuDeviceID = wmld->uDeviceID;
1289 return MMSYSERR_NOERROR;
1292 /**************************************************************************
1293 * midiOutMessage [WINMM.@]
1295 UINT WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
1296 DWORD dwParam1, DWORD dwParam2)
1300 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
1302 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
1304 if (uMessage == 0x0001) {
1305 *(LPDWORD)dwParam1 = 1;
1308 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
1309 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2, TRUE);
1311 return MMSYSERR_INVALHANDLE;
1317 FIXME("can't handle OPEN or CLOSE message!\n");
1318 return MMSYSERR_NOTSUPPORTED;
1320 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1323 /**************************************************************************
1324 * midiInGetNumDevs [WINMM.@]
1326 UINT WINAPI midiInGetNumDevs(void)
1328 return MMDRV_GetNum(MMDRV_MIDIIN);
1331 /**************************************************************************
1332 * midiInGetDevCapsW [WINMM.@]
1334 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
1337 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
1339 if (ret == MMSYSERR_NOERROR) {
1341 micW.wMid = micA.wMid;
1342 micW.wPid = micA.wPid;
1343 micW.vDriverVersion = micA.vDriverVersion;
1344 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname,
1345 sizeof(micW.szPname)/sizeof(WCHAR) );
1346 micW.dwSupport = micA.dwSupport;
1347 memcpy(lpCaps, &micW, min(uSize, sizeof(micW)));
1352 /**************************************************************************
1353 * midiInGetDevCapsA [WINMM.@]
1355 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
1359 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
1361 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1363 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
1364 return MMSYSERR_INVALHANDLE;
1366 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1369 /**************************************************************************
1370 * midiInGetErrorTextW [WINMM.@]
1372 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1374 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1375 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
1377 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1378 HeapFree(GetProcessHeap(), 0, xstr);
1382 /**************************************************************************
1383 * midiInGetErrorTextA [WINMM.@]
1385 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1387 return MIDI_GetErrorText(uError, lpText, uSize);
1390 UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
1391 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1397 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1398 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
1400 if (lphMidiIn != NULL) *lphMidiIn = 0;
1402 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
1403 &dwFlags, &dwCallback, &dwInstance, bFrom32);
1406 return MMSYSERR_NOMEM;
1408 lpwm->mod.hMidi = (HMIDI) hMidiIn;
1409 lpwm->mod.dwCallback = dwCallback;
1410 lpwm->mod.dwInstance = dwInstance;
1412 lpwm->mld.uDeviceID = uDeviceID;
1413 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1415 if (dwRet != MMSYSERR_NOERROR) {
1416 MMDRV_Free(hMidiIn, &lpwm->mld);
1419 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
1420 TRACE("=> %ld hMidi=%p\n", dwRet, hMidiIn);
1425 /**************************************************************************
1426 * midiInOpen [WINMM.@]
1428 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
1429 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1431 return MIDI_InOpen(lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1434 /**************************************************************************
1435 * midiInClose [WINMM.@]
1437 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
1442 TRACE("(%p)\n", hMidiIn);
1444 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1445 return MMSYSERR_INVALHANDLE;
1447 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
1448 MMDRV_Free(hMidiIn, wmld);
1452 /**************************************************************************
1453 * midiInPrepareHeader [WINMM.@]
1455 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
1456 MIDIHDR* lpMidiInHdr, UINT uSize)
1460 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1462 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1463 return MMSYSERR_INVALHANDLE;
1465 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
1468 /**************************************************************************
1469 * midiInUnprepareHeader [WINMM.@]
1471 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
1472 MIDIHDR* lpMidiInHdr, UINT uSize)
1476 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1478 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
1479 return MMSYSERR_NOERROR;
1482 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1483 return MMSYSERR_INVALHANDLE;
1485 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
1488 /**************************************************************************
1489 * midiInAddBuffer [WINMM.@]
1491 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
1492 MIDIHDR* lpMidiInHdr, UINT uSize)
1496 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1498 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1499 return MMSYSERR_INVALHANDLE;
1501 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE);
1504 /**************************************************************************
1505 * midiInStart [WINMM.@]
1507 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
1511 TRACE("(%p)\n", hMidiIn);
1513 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1514 return MMSYSERR_INVALHANDLE;
1516 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
1519 /**************************************************************************
1520 * midiInStop [WINMM.@]
1522 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
1526 TRACE("(%p)\n", hMidiIn);
1528 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1529 return MMSYSERR_INVALHANDLE;
1531 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
1534 /**************************************************************************
1535 * midiInReset [WINMM.@]
1537 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
1541 TRACE("(%p)\n", hMidiIn);
1543 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1544 return MMSYSERR_INVALHANDLE;
1546 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
1549 /**************************************************************************
1550 * midiInGetID [WINMM.@]
1552 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
1556 TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID);
1558 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1560 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
1561 return MMSYSERR_INVALHANDLE;
1563 *lpuDeviceID = wmld->uDeviceID;
1565 return MMSYSERR_NOERROR;
1568 /**************************************************************************
1569 * midiInMessage [WINMM.@]
1571 UINT WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
1572 DWORD dwParam1, DWORD dwParam2)
1576 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
1578 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1579 return MMSYSERR_INVALHANDLE;
1584 FIXME("can't handle OPEN or CLOSE message!\n");
1585 return MMSYSERR_NOTSUPPORTED;
1587 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1590 typedef struct WINE_MIDIStream {
1601 LPMIDIHDR lpMidiHdr;
1604 #define WINE_MSM_HEADER (WM_USER+0)
1605 #define WINE_MSM_STOP (WM_USER+1)
1607 /**************************************************************************
1608 * MMSYSTEM_GetMidiStream [internal]
1610 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
1612 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
1621 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
1623 return *lpMidiStrm != NULL;
1626 /**************************************************************************
1627 * MMSYSTEM_MidiStream_Convert [internal]
1629 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
1633 if (lpMidiStrm->dwTimeDiv == 0) {
1634 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1635 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
1636 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
1637 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
1638 ret = (pulse * 1000) / (nf * nsf);
1640 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
1641 (double)lpMidiStrm->dwTimeDiv);
1647 /**************************************************************************
1648 * MMSYSTEM_MidiStream_MessageHandler [internal]
1650 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
1652 LPMIDIHDR lpMidiHdr;
1656 switch (msg->message) {
1658 SetEvent(lpMidiStrm->hEvent);
1662 /* this is not quite what MS doc says... */
1663 midiOutReset(lpMidiStrm->hDevice);
1664 /* empty list of already submitted buffers */
1665 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
1666 lpMidiHdr->dwFlags |= MHDR_DONE;
1667 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1669 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1670 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1671 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1673 lpMidiStrm->lpMidiHdr = 0;
1674 SetEvent(lpMidiStrm->hEvent);
1676 case WINE_MSM_HEADER:
1677 /* sets initial tick count for first MIDIHDR */
1678 if (!lpMidiStrm->dwStartTicks)
1679 lpMidiStrm->dwStartTicks = GetTickCount();
1681 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1682 * by native mcimidi, it doesn't look like a correct one".
1683 * this trick allows to throw it away... but I don't like it.
1684 * It looks like part of the file I'm trying to play and definitively looks
1685 * like raw midi content
1686 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1687 * synchronization issue where native mcimidi is still processing raw MIDI
1688 * content before generating MIDIEVENTs ?
1690 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1691 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1692 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1693 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1694 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1695 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1696 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1697 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1698 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1699 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1700 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1701 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1702 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1703 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1704 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1705 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1706 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1708 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1709 lpData = lpMidiHdr->lpData;
1710 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1711 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
1712 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
1713 lpMidiHdr->dwFlags, msg->wParam);
1715 /* dumps content of lpMidiHdr->lpData
1716 * FIXME: there should be a debug routine somewhere that already does this
1717 * I hate spreading this type of shit all around the code
1719 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
1723 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
1724 printf("%02x ", lpData[dwToGo + i]);
1727 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
1728 ch = lpData[dwToGo + i];
1729 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
1734 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
1735 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
1736 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
1737 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
1738 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
1739 ((LPMIDIEVENT)lpData)->dwStreamID);
1740 lpMidiHdr->dwFlags |= MHDR_DONE;
1741 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1743 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1744 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1745 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1749 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
1751 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1752 lpMidiHdr->lpNext = 0;
1753 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
1754 lpMidiHdr->dwFlags &= MHDR_DONE;
1755 lpMidiHdr->dwOffset = 0;
1759 FIXME("Unknown message %d\n", msg->message);
1765 /**************************************************************************
1766 * MMSYSTEM_MidiStream_Player [internal]
1768 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
1770 WINE_MIDIStream* lpMidiStrm = pmt;
1775 LPMIDIHDR lpMidiHdr;
1779 TRACE("(%p)!\n", lpMidiStrm);
1782 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
1785 /* force thread's queue creation */
1786 /* Used to be InitThreadInput16(0, 5); */
1787 /* but following works also with hack in midiStreamOpen */
1788 PeekMessageA(&msg, 0, 0, 0, 0);
1790 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
1791 SetEvent(lpMidiStrm->hEvent);
1792 TRACE("Ready to go 1\n");
1793 /* thread is started in paused mode */
1794 SuspendThread(lpMidiStrm->hThread);
1795 TRACE("Ready to go 2\n");
1797 lpMidiStrm->dwStartTicks = 0;
1798 lpMidiStrm->dwPulses = 0;
1800 lpMidiStrm->lpMidiHdr = 0;
1803 lpMidiHdr = lpMidiStrm->lpMidiHdr;
1805 /* for first message, block until one arrives, then process all that are available */
1806 GetMessageA(&msg, 0, 0, 0);
1808 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1810 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
1816 lpData = lpMidiHdr->lpData;
1818 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
1820 /* do we have to wait ? */
1821 if (me->dwDeltaTime) {
1822 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
1823 lpMidiStrm->dwPulses += me->dwDeltaTime;
1825 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
1827 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
1828 while ((dwCurrTC = GetTickCount()) < dwToGo) {
1829 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
1830 /* got a message, handle it */
1831 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
1832 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1837 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
1842 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
1844 FIXME("NIY: MEVT_COMMENT\n");
1845 /* do nothing, skip bytes */
1848 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
1853 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
1856 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
1861 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
1864 if (me->dwEvent & MEVT_F_CALLBACK) {
1865 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1866 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
1867 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
1869 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
1870 if (me->dwEvent & MEVT_F_LONG)
1871 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
1872 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
1873 /* done with this header */
1874 lpMidiHdr->dwFlags |= MHDR_DONE;
1875 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1877 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
1878 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1879 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1880 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1885 TRACE("End of thread\n");
1887 return 0; /* for removing the warning, never executed */
1890 /**************************************************************************
1891 * MMSYSTEM_MidiStream_PostMessage [internal]
1893 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
1895 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
1898 ReleaseThunkLock(&count);
1899 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1900 RestoreThunkLock(count);
1902 WARN("bad PostThreadMessageA\n");
1908 /**************************************************************************
1909 * midiStreamClose [WINMM.@]
1911 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
1913 WINE_MIDIStream* lpMidiStrm;
1915 TRACE("(%p)!\n", hMidiStrm);
1917 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
1918 return MMSYSERR_INVALHANDLE;
1920 midiStreamStop(hMidiStrm);
1921 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
1922 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
1923 CloseHandle(lpMidiStrm->hEvent);
1925 return midiOutClose((HMIDIOUT)hMidiStrm);
1928 /**************************************************************************
1929 * MMSYSTEM_MidiStream_Open [internal]
1931 MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, DWORD cMidi,
1932 DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen,
1935 WINE_MIDIStream* lpMidiStrm;
1937 MIDIOPENSTRMID mosm;
1941 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
1942 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
1944 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
1945 return MMSYSERR_INVALPARAM;
1947 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
1949 return MMSYSERR_NOMEM;
1951 lpMidiStrm->dwTempo = 500000;
1952 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
1953 lpMidiStrm->dwPositionMS = 0;
1955 mosm.dwStreamID = (DWORD)lpMidiStrm;
1956 /* FIXME: the correct value is not allocated yet for MAPPER */
1957 mosm.wDeviceID = *lpuDeviceID;
1958 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
1959 lpMidiStrm->hDevice = hMidiOut;
1961 *lphMidiStrm = (HMIDISTRM)hMidiOut;
1963 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
1964 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID);
1965 lpwm->mld.uDeviceID = *lpuDeviceID = 0;
1967 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
1968 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1969 lpMidiStrm->wFlags = HIWORD(fdwOpen);
1971 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
1972 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
1974 if (!lpMidiStrm->hThread) {
1975 midiStreamClose((HMIDISTRM)hMidiOut);
1976 return MMSYSERR_NOMEM;
1979 /* wait for thread to have started, and for its queue to be created */
1983 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
1984 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
1985 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
1987 ReleaseThunkLock(&count);
1988 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1989 RestoreThunkLock(count);
1992 TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n",
1993 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
1997 /**************************************************************************
1998 * midiStreamOpen [WINMM.@]
2000 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
2001 DWORD cMidi, DWORD dwCallback,
2002 DWORD dwInstance, DWORD fdwOpen)
2004 return MIDI_StreamOpen(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
2005 dwInstance, fdwOpen, TRUE);
2008 /**************************************************************************
2009 * midiStreamOut [WINMM.@]
2011 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
2014 WINE_MIDIStream* lpMidiStrm;
2015 DWORD ret = MMSYSERR_NOERROR;
2017 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
2019 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2020 ret = MMSYSERR_INVALHANDLE;
2021 } else if (!lpMidiHdr) {
2022 ret = MMSYSERR_INVALPARAM;
2024 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
2025 WINE_MSM_HEADER, cbMidiHdr,
2026 (DWORD)lpMidiHdr)) {
2027 WARN("bad PostThreadMessageA\n");
2028 ret = MMSYSERR_ERROR;
2034 /**************************************************************************
2035 * midiStreamPause [WINMM.@]
2037 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
2039 WINE_MIDIStream* lpMidiStrm;
2040 DWORD ret = MMSYSERR_NOERROR;
2042 TRACE("(%p)!\n", hMidiStrm);
2044 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2045 ret = MMSYSERR_INVALHANDLE;
2047 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
2048 WARN("bad Suspend (%ld)\n", GetLastError());
2049 ret = MMSYSERR_ERROR;
2055 /**************************************************************************
2056 * midiStreamPosition [WINMM.@]
2058 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
2060 WINE_MIDIStream* lpMidiStrm;
2061 DWORD ret = MMSYSERR_NOERROR;
2063 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
2065 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2066 ret = MMSYSERR_INVALHANDLE;
2067 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
2068 ret = MMSYSERR_INVALPARAM;
2070 switch (lpMMT->wType) {
2072 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
2073 TRACE("=> %ld ms\n", lpMMT->u.ms);
2076 lpMMT->u.ticks = lpMidiStrm->dwPulses;
2077 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
2080 WARN("Unsupported time type %d\n", lpMMT->wType);
2081 lpMMT->wType = TIME_MS;
2082 ret = MMSYSERR_INVALPARAM;
2089 /**************************************************************************
2090 * midiStreamProperty [WINMM.@]
2092 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
2094 WINE_MIDIStream* lpMidiStrm;
2095 MMRESULT ret = MMSYSERR_NOERROR;
2097 TRACE("(%p, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
2099 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2100 ret = MMSYSERR_INVALHANDLE;
2101 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
2102 ret = MMSYSERR_INVALPARAM;
2103 } else if (dwProperty & MIDIPROP_TEMPO) {
2104 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
2106 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
2107 ret = MMSYSERR_INVALPARAM;
2108 } else if (dwProperty & MIDIPROP_SET) {
2109 lpMidiStrm->dwTempo = mpt->dwTempo;
2110 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
2111 } else if (dwProperty & MIDIPROP_GET) {
2112 mpt->dwTempo = lpMidiStrm->dwTempo;
2113 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
2115 } else if (dwProperty & MIDIPROP_TIMEDIV) {
2116 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
2118 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
2119 ret = MMSYSERR_INVALPARAM;
2120 } else if (dwProperty & MIDIPROP_SET) {
2121 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
2122 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
2123 } else if (dwProperty & MIDIPROP_GET) {
2124 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
2125 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
2128 ret = MMSYSERR_INVALPARAM;
2134 /**************************************************************************
2135 * midiStreamRestart [WINMM.@]
2137 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
2139 WINE_MIDIStream* lpMidiStrm;
2140 MMRESULT ret = MMSYSERR_NOERROR;
2142 TRACE("(%p)!\n", hMidiStrm);
2144 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2145 ret = MMSYSERR_INVALHANDLE;
2149 /* since we increase the thread suspend count on each midiStreamPause
2150 * there may be a need for several midiStreamResume
2153 ret = ResumeThread(lpMidiStrm->hThread);
2154 } while (ret != 0xFFFFFFFF && ret != 0);
2155 if (ret == 0xFFFFFFFF) {
2156 WARN("bad Resume (%ld)\n", GetLastError());
2157 ret = MMSYSERR_ERROR;
2159 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
2165 /**************************************************************************
2166 * midiStreamStop [WINMM.@]
2168 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
2170 WINE_MIDIStream* lpMidiStrm;
2171 MMRESULT ret = MMSYSERR_NOERROR;
2173 TRACE("(%p)!\n", hMidiStrm);
2175 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2176 ret = MMSYSERR_INVALHANDLE;
2178 /* in case stream has been paused... FIXME is the current state correct ? */
2179 midiStreamRestart(hMidiStrm);
2180 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
2185 UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType,
2186 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2187 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2191 DWORD dwRet = MMSYSERR_NOERROR;
2194 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2195 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
2196 dwInstance, dwFlags, bFrom32?32:16);
2198 if (dwFlags & WAVE_FORMAT_QUERY) TRACE("WAVE_FORMAT_QUERY requested !\n");
2200 if (lpFormat == NULL) return WAVERR_BADFORMAT;
2201 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1))
2202 return MMSYSERR_INVALPARAM;
2204 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
2205 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
2206 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize);
2208 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
2209 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL)
2210 return MMSYSERR_NOMEM;
2213 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
2214 wod.dwCallback = dwCallback;
2215 wod.dwInstance = dwInstance;
2218 TRACE("cb=%08lx\n", wod.dwCallback);
2221 if (dwFlags & WAVE_MAPPED) {
2222 wod.uMappedDeviceID = uDeviceID;
2223 uDeviceID = WAVE_MAPPER;
2225 wod.uMappedDeviceID = -1;
2227 wmld->uDeviceID = uDeviceID;
2229 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN,
2230 (DWORD)&wod, dwFlags);
2232 if (dwRet != WAVERR_BADFORMAT ||
2233 (dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) break;
2234 /* if we ask for a format which isn't supported by the physical driver,
2235 * let's try to map it through the wave mapper (except, if we already tried
2236 * or user didn't allow us to use acm codecs)
2238 dwFlags |= WAVE_MAPPED;
2239 /* we shall loop only one */
2242 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
2243 MMDRV_Free(handle, wmld);
2247 if (lphndl != NULL) *lphndl = handle;
2248 TRACE("=> %ld hWave=%p\n", dwRet, handle);
2253 /**************************************************************************
2254 * waveOutGetNumDevs [WINMM.@]
2256 UINT WINAPI waveOutGetNumDevs(void)
2258 return MMDRV_GetNum(MMDRV_WAVEOUT);
2261 /**************************************************************************
2262 * waveOutGetDevCapsA [WINMM.@]
2264 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
2269 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2271 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2273 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
2274 return MMSYSERR_BADDEVICEID;
2276 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2280 /**************************************************************************
2281 * waveOutGetDevCapsW [WINMM.@]
2283 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
2287 UINT ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
2289 if (ret == MMSYSERR_NOERROR) {
2291 wocW.wMid = wocA.wMid;
2292 wocW.wPid = wocA.wPid;
2293 wocW.vDriverVersion = wocA.vDriverVersion;
2294 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, wocW.szPname,
2295 sizeof(wocW.szPname)/sizeof(WCHAR) );
2296 wocW.dwFormats = wocA.dwFormats;
2297 wocW.wChannels = wocA.wChannels;
2298 wocW.dwSupport = wocA.dwSupport;
2299 memcpy(lpCaps, &wocW, min(uSize, sizeof(wocW)));
2304 /**************************************************************************
2305 * WAVE_GetErrorText [internal]
2307 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2309 UINT16 ret = MMSYSERR_BADERRNUM;
2311 if (lpText == NULL) {
2312 ret = MMSYSERR_INVALPARAM;
2313 } else if (uSize == 0) {
2314 ret = MMSYSERR_NOERROR;
2316 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2317 * a warning for the test was always true */
2318 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
2319 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
2321 if (LoadStringA(WINMM_IData->hWinMM32Instance,
2322 uError, lpText, uSize) > 0) {
2323 ret = MMSYSERR_NOERROR;
2329 /**************************************************************************
2330 * waveOutGetErrorTextA [WINMM.@]
2332 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2334 return WAVE_GetErrorText(uError, lpText, uSize);
2337 /**************************************************************************
2338 * waveOutGetErrorTextW [WINMM.@]
2340 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2342 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2343 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
2345 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2346 HeapFree(GetProcessHeap(), 0, xstr);
2350 /**************************************************************************
2351 * waveOutOpen [WINMM.@]
2352 * All the args/structs have the same layout as the win16 equivalents
2354 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
2355 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2356 DWORD dwInstance, DWORD dwFlags)
2358 return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
2359 dwCallback, dwInstance, dwFlags, TRUE);
2362 /**************************************************************************
2363 * waveOutClose [WINMM.@]
2365 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
2370 TRACE("(%p)\n", hWaveOut);
2372 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2373 return MMSYSERR_INVALHANDLE;
2375 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
2376 if (dwRet != WAVERR_STILLPLAYING)
2377 MMDRV_Free(hWaveOut, wmld);
2382 /**************************************************************************
2383 * waveOutPrepareHeader [WINMM.@]
2385 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
2386 WAVEHDR* lpWaveOutHdr, UINT uSize)
2390 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2392 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
2394 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2395 return MMSYSERR_INVALHANDLE;
2397 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2400 /**************************************************************************
2401 * waveOutUnprepareHeader [WINMM.@]
2403 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
2404 LPWAVEHDR lpWaveOutHdr, UINT uSize)
2408 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2410 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
2411 return MMSYSERR_NOERROR;
2414 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2415 return MMSYSERR_INVALHANDLE;
2417 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2420 /**************************************************************************
2421 * waveOutWrite [WINMM.@]
2423 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
2428 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2430 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2431 return MMSYSERR_INVALHANDLE;
2433 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2436 /**************************************************************************
2437 * waveOutBreakLoop [WINMM.@]
2439 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
2443 TRACE("(%p);\n", hWaveOut);
2445 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2446 return MMSYSERR_INVALHANDLE;
2447 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
2450 /**************************************************************************
2451 * waveOutPause [WINMM.@]
2453 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
2457 TRACE("(%p);\n", hWaveOut);
2459 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2460 return MMSYSERR_INVALHANDLE;
2461 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
2464 /**************************************************************************
2465 * waveOutReset [WINMM.@]
2467 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
2471 TRACE("(%p);\n", hWaveOut);
2473 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2474 return MMSYSERR_INVALHANDLE;
2475 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
2478 /**************************************************************************
2479 * waveOutRestart [WINMM.@]
2481 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
2485 TRACE("(%p);\n", hWaveOut);
2487 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2488 return MMSYSERR_INVALHANDLE;
2489 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
2492 /**************************************************************************
2493 * waveOutGetPosition [WINMM.@]
2495 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
2500 TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize);
2502 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2503 return MMSYSERR_INVALHANDLE;
2505 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE);
2508 /**************************************************************************
2509 * waveOutGetPitch [WINMM.@]
2511 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
2515 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2517 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2518 return MMSYSERR_INVALHANDLE;
2519 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE);
2522 /**************************************************************************
2523 * waveOutSetPitch [WINMM.@]
2525 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
2529 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2531 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2532 return MMSYSERR_INVALHANDLE;
2533 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
2536 /**************************************************************************
2537 * waveOutGetPlaybackRate [WINMM.@]
2539 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
2543 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2545 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2546 return MMSYSERR_INVALHANDLE;
2547 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE);
2550 /**************************************************************************
2551 * waveOutSetPlaybackRate [WINMM.@]
2553 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
2557 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2559 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2560 return MMSYSERR_INVALHANDLE;
2561 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
2564 /**************************************************************************
2565 * waveOutGetVolume [WINMM.@]
2567 UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw)
2571 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2573 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2574 return MMSYSERR_INVALHANDLE;
2576 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE);
2579 /**************************************************************************
2580 * waveOutSetVolume [WINMM.@]
2582 UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw)
2586 TRACE("(%p, %08lx);\n", hWaveOut, dw);
2588 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2589 return MMSYSERR_INVALHANDLE;
2591 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
2594 /**************************************************************************
2595 * waveOutGetID [WINMM.@]
2597 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
2601 TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID);
2603 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2605 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2606 return MMSYSERR_INVALHANDLE;
2608 *lpuDeviceID = wmld->uDeviceID;
2612 /**************************************************************************
2613 * waveOutMessage [WINMM.@]
2615 UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
2616 DWORD dwParam1, DWORD dwParam2)
2620 TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
2622 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
2623 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
2624 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2, TRUE);
2626 return MMSYSERR_INVALHANDLE;
2630 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
2631 return MMSYSERR_INVALPARAM;
2633 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2636 /**************************************************************************
2637 * waveInGetNumDevs [WINMM.@]
2639 UINT WINAPI waveInGetNumDevs(void)
2641 return MMDRV_GetNum(MMDRV_WAVEIN);
2644 /**************************************************************************
2645 * waveInGetDevCapsW [WINMM.@]
2647 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
2650 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize);
2652 if (ret == MMSYSERR_NOERROR) {
2654 wicW.wMid = wicA.wMid;
2655 wicW.wPid = wicA.wPid;
2656 wicW.vDriverVersion = wicA.vDriverVersion;
2657 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, wicW.szPname,
2658 sizeof(wicW.szPname)/sizeof(WCHAR) );
2659 wicW.dwFormats = wicA.dwFormats;
2660 wicW.wChannels = wicA.wChannels;
2661 memcpy(lpCaps, &wicW, min(uSize, sizeof(wicW)));
2666 /**************************************************************************
2667 * waveInGetDevCapsA [WINMM.@]
2669 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
2673 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2675 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2677 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
2678 return MMSYSERR_BADDEVICEID;
2680 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2683 /**************************************************************************
2684 * waveInGetErrorTextA [WINMM.@]
2686 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2688 return WAVE_GetErrorText(uError, lpText, uSize);
2691 /**************************************************************************
2692 * waveInGetErrorTextW [WINMM.@]
2694 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2696 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
2697 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
2699 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
2700 HeapFree(GetProcessHeap(), 0, txt);
2704 /**************************************************************************
2705 * waveInOpen [WINMM.@]
2707 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
2708 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2709 DWORD dwInstance, DWORD dwFlags)
2711 return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
2712 dwCallback, dwInstance, dwFlags, TRUE);
2715 /**************************************************************************
2716 * waveInClose [WINMM.@]
2718 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
2723 TRACE("(%p)\n", hWaveIn);
2725 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2726 return MMSYSERR_INVALHANDLE;
2728 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
2729 if (dwRet != WAVERR_STILLPLAYING)
2730 MMDRV_Free(hWaveIn, wmld);
2734 /**************************************************************************
2735 * waveInPrepareHeader [WINMM.@]
2737 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2742 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2744 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2745 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2746 return MMSYSERR_INVALHANDLE;
2748 lpWaveInHdr->dwBytesRecorded = 0;
2750 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
2753 /**************************************************************************
2754 * waveInUnprepareHeader [WINMM.@]
2756 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2761 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2763 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2764 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
2765 return MMSYSERR_NOERROR;
2768 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2769 return MMSYSERR_INVALHANDLE;
2771 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
2774 /**************************************************************************
2775 * waveInAddBuffer [WINMM.@]
2777 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
2778 WAVEHDR* lpWaveInHdr, UINT uSize)
2782 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2784 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2785 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2786 return MMSYSERR_INVALHANDLE;
2788 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE);
2791 /**************************************************************************
2792 * waveInReset [WINMM.@]
2794 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
2798 TRACE("(%p);\n", hWaveIn);
2800 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2801 return MMSYSERR_INVALHANDLE;
2803 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
2806 /**************************************************************************
2807 * waveInStart [WINMM.@]
2809 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
2813 TRACE("(%p);\n", hWaveIn);
2815 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2816 return MMSYSERR_INVALHANDLE;
2818 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
2821 /**************************************************************************
2822 * waveInStop [WINMM.@]
2824 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
2828 TRACE("(%p);\n", hWaveIn);
2830 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2831 return MMSYSERR_INVALHANDLE;
2833 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
2836 /**************************************************************************
2837 * waveInGetPosition [WINMM.@]
2839 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
2844 TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize);
2846 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2847 return MMSYSERR_INVALHANDLE;
2849 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE);
2852 /**************************************************************************
2853 * waveInGetID [WINMM.@]
2855 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
2859 TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID);
2861 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2863 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2864 return MMSYSERR_INVALHANDLE;
2866 *lpuDeviceID = wmld->uDeviceID;
2867 return MMSYSERR_NOERROR;
2870 /**************************************************************************
2871 * waveInMessage [WINMM.@]
2873 UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
2874 DWORD dwParam1, DWORD dwParam2)
2878 TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
2880 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) {
2881 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) {
2882 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2, TRUE);
2884 return MMSYSERR_INVALHANDLE;
2888 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
2889 return MMSYSERR_INVALPARAM;
2892 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);