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
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(winmm
);
46 /******************************************************************
49 * Internal wrapper to call USER.UserYield16 (in fact through a Wine only export from USER32).
51 static void MyUserYield(void)
53 HMODULE mod
= GetModuleHandleA( "user32.dll" );
56 FARPROC proc
= GetProcAddress( mod
, "UserYield16" );
61 /* ========================================================================
62 * G L O B A L S E T T I N G S
63 * ========================================================================*/
65 LPWINE_MM_IDATA WINMM_IData
/* = NULL */;
67 /**************************************************************************
68 * WINMM_CreateIData [internal]
70 static BOOL
WINMM_CreateIData(HINSTANCE hInstDLL
)
72 WINMM_IData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WINE_MM_IDATA
));
76 WINMM_IData
->hWinMM32Instance
= hInstDLL
;
77 InitializeCriticalSection(&WINMM_IData
->cs
);
78 WINMM_IData
->cs
.DebugInfo
= (void*)__FILE__
": WinMM";
79 WINMM_IData
->psStopEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
80 WINMM_IData
->psLastEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
81 TRACE("Created IData (%p)\n", WINMM_IData
);
85 /**************************************************************************
86 * WINMM_DeleteIData [internal]
88 static void WINMM_DeleteIData(void)
93 /* FIXME: should also free content and resources allocated
94 * inside WINMM_IData */
95 CloseHandle(WINMM_IData
->psStopEvent
);
96 CloseHandle(WINMM_IData
->psLastEvent
);
97 DeleteCriticalSection(&WINMM_IData
->cs
);
98 HeapFree(GetProcessHeap(), 0, WINMM_IData
);
103 /******************************************************************
107 static HANDLE (WINAPI
*pGetModuleHandle16
)(LPCSTR
);
108 static DWORD (WINAPI
*pLoadLibrary16
)(LPCSTR
);
110 BOOL
WINMM_CheckForMMSystem(void)
112 /* 0 is not checked yet, -1 is not present, 1 is present */
113 static int loaded
/* = 0 */;
117 HANDLE h
= GetModuleHandleA("kernel32");
121 pGetModuleHandle16
= (void*)GetProcAddress(h
, "GetModuleHandle16");
122 pLoadLibrary16
= (void*)GetProcAddress(h
, "LoadLibrary16");
123 if (pGetModuleHandle16
&& pLoadLibrary16
&&
124 (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL")))
131 /**************************************************************************
132 * DllMain (WINMM.init)
134 * WINMM DLL entry point
137 BOOL WINAPI
DllMain(HINSTANCE hInstDLL
, DWORD fdwReason
, LPVOID fImpLoad
)
139 TRACE("%p 0x%lx %p\n", hInstDLL
, fdwReason
, fImpLoad
);
142 case DLL_PROCESS_ATTACH
:
143 DisableThreadLibraryCalls(hInstDLL
);
145 if (!WINMM_CreateIData(hInstDLL
))
147 if (!MCI_Init() || !MMDRV_Init()) {
152 case DLL_PROCESS_DETACH
:
153 /* close all opened MCI drivers */
154 MCI_SendCommand(MCI_ALL_DEVICE_ID
, MCI_CLOSE
, MCI_WAIT
, 0L, TRUE
);
156 /* now unload all remaining drivers... */
165 /**************************************************************************
166 * Mixer devices. New to Win95
169 /**************************************************************************
170 * find out the real mixer ID depending on hmix (depends on dwFlags)
172 static LPWINE_MIXER
MIXER_GetDev(HMIXEROBJ hmix
, DWORD dwFlags
)
174 LPWINE_MIXER lpwm
= NULL
;
176 switch (dwFlags
& 0xF0000000ul
) {
177 case MIXER_OBJECTF_MIXER
:
178 lpwm
= (LPWINE_MIXER
)MMDRV_Get(hmix
, MMDRV_MIXER
, TRUE
);
180 case MIXER_OBJECTF_HMIXER
:
181 lpwm
= (LPWINE_MIXER
)MMDRV_Get(hmix
, MMDRV_MIXER
, FALSE
);
183 case MIXER_OBJECTF_WAVEOUT
:
184 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEOUT
, TRUE
, MMDRV_MIXER
);
186 case MIXER_OBJECTF_HWAVEOUT
:
187 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEOUT
, FALSE
, MMDRV_MIXER
);
189 case MIXER_OBJECTF_WAVEIN
:
190 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEIN
, TRUE
, MMDRV_MIXER
);
192 case MIXER_OBJECTF_HWAVEIN
:
193 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEIN
, FALSE
, MMDRV_MIXER
);
195 case MIXER_OBJECTF_MIDIOUT
:
196 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIOUT
, TRUE
, MMDRV_MIXER
);
198 case MIXER_OBJECTF_HMIDIOUT
:
199 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIOUT
, FALSE
, MMDRV_MIXER
);
201 case MIXER_OBJECTF_MIDIIN
:
202 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIIN
, TRUE
, MMDRV_MIXER
);
204 case MIXER_OBJECTF_HMIDIIN
:
205 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIIN
, FALSE
, MMDRV_MIXER
);
207 case MIXER_OBJECTF_AUX
:
208 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_AUX
, TRUE
, MMDRV_MIXER
);
211 FIXME("Unsupported flag (%08lx)\n", dwFlags
& 0xF0000000ul
);
217 /**************************************************************************
218 * mixerGetNumDevs [WINMM.@]
220 UINT WINAPI
mixerGetNumDevs(void)
222 return MMDRV_GetNum(MMDRV_MIXER
);
225 /**************************************************************************
226 * mixerGetDevCapsA [WINMM.@]
228 UINT WINAPI
mixerGetDevCapsA(UINT devid
, LPMIXERCAPSA mixcaps
, UINT size
)
232 if ((wmld
= MMDRV_Get((HANDLE
)devid
, MMDRV_MIXER
, TRUE
)) == NULL
)
233 return MMSYSERR_BADDEVICEID
;
235 return MMDRV_Message(wmld
, MXDM_GETDEVCAPS
, (DWORD
)mixcaps
, size
, TRUE
);
238 /**************************************************************************
239 * mixerGetDevCapsW [WINMM.@]
241 UINT WINAPI
mixerGetDevCapsW(UINT devid
, LPMIXERCAPSW mixcaps
, UINT size
)
244 UINT ret
= mixerGetDevCapsA(devid
, &micA
, sizeof(micA
));
246 if (ret
== MMSYSERR_NOERROR
) {
247 mixcaps
->wMid
= micA
.wMid
;
248 mixcaps
->wPid
= micA
.wPid
;
249 mixcaps
->vDriverVersion
= micA
.vDriverVersion
;
250 MultiByteToWideChar( CP_ACP
, 0, micA
.szPname
, -1, mixcaps
->szPname
,
251 sizeof(mixcaps
->szPname
)/sizeof(WCHAR
) );
252 mixcaps
->fdwSupport
= micA
.fdwSupport
;
253 mixcaps
->cDestinations
= micA
.cDestinations
;
258 UINT
MIXER_Open(LPHMIXER lphMix
, UINT uDeviceID
, DWORD dwCallback
,
259 DWORD dwInstance
, DWORD fdwOpen
, BOOL bFrom32
)
266 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
267 lphMix
, uDeviceID
, dwCallback
, dwInstance
, fdwOpen
);
269 wmld
= MMDRV_Alloc(sizeof(WINE_MIXER
), MMDRV_MIXER
, &hMix
, &fdwOpen
,
270 &dwCallback
, &dwInstance
, bFrom32
);
272 wmld
->uDeviceID
= uDeviceID
;
273 mod
.hmx
= (HMIXEROBJ
)hMix
;
274 mod
.dwCallback
= dwCallback
;
275 mod
.dwInstance
= dwInstance
;
277 dwRet
= MMDRV_Open(wmld
, MXDM_OPEN
, (DWORD
)&mod
, fdwOpen
);
279 if (dwRet
!= MMSYSERR_NOERROR
) {
280 MMDRV_Free(hMix
, wmld
);
283 if (lphMix
) *lphMix
= hMix
;
284 TRACE("=> %ld hMixer=%p\n", dwRet
, hMix
);
289 /**************************************************************************
290 * mixerOpen [WINMM.@]
292 UINT WINAPI
mixerOpen(LPHMIXER lphMix
, UINT uDeviceID
, DWORD dwCallback
,
293 DWORD dwInstance
, DWORD fdwOpen
)
295 return MIXER_Open(lphMix
, uDeviceID
, dwCallback
, dwInstance
, fdwOpen
, TRUE
);
298 /**************************************************************************
299 * mixerClose [WINMM.@]
301 UINT WINAPI
mixerClose(HMIXER hMix
)
306 TRACE("(%p)\n", hMix
);
308 if ((wmld
= MMDRV_Get(hMix
, MMDRV_MIXER
, FALSE
)) == NULL
) return MMSYSERR_INVALHANDLE
;
310 dwRet
= MMDRV_Close(wmld
, MXDM_CLOSE
);
311 MMDRV_Free(hMix
, wmld
);
316 /**************************************************************************
317 * mixerGetID [WINMM.@]
319 UINT WINAPI
mixerGetID(HMIXEROBJ hmix
, LPUINT lpid
, DWORD fdwID
)
323 TRACE("(%p %p %08lx)\n", hmix
, lpid
, fdwID
);
325 if ((lpwm
= MIXER_GetDev(hmix
, fdwID
)) == NULL
) {
326 return MMSYSERR_INVALHANDLE
;
330 *lpid
= lpwm
->mld
.uDeviceID
;
332 return MMSYSERR_NOERROR
;
335 /**************************************************************************
336 * mixerGetControlDetailsA [WINMM.@]
338 UINT WINAPI
mixerGetControlDetailsA(HMIXEROBJ hmix
, LPMIXERCONTROLDETAILS lpmcdA
,
343 TRACE("(%p, %p, %08lx)\n", hmix
, lpmcdA
, fdwDetails
);
345 if ((lpwm
= MIXER_GetDev(hmix
, fdwDetails
)) == NULL
)
346 return MMSYSERR_INVALHANDLE
;
348 if (lpmcdA
== NULL
|| lpmcdA
->cbStruct
!= sizeof(*lpmcdA
))
349 return MMSYSERR_INVALPARAM
;
351 return MMDRV_Message(&lpwm
->mld
, MXDM_GETCONTROLDETAILS
, (DWORD
)lpmcdA
,
355 /**************************************************************************
356 * mixerGetControlDetailsW [WINMM.@]
358 UINT WINAPI
mixerGetControlDetailsW(HMIXEROBJ hmix
, LPMIXERCONTROLDETAILS lpmcd
, DWORD fdwDetails
)
360 DWORD ret
= MMSYSERR_NOTENABLED
;
362 TRACE("(%p, %p, %08lx)\n", hmix
, lpmcd
, fdwDetails
);
364 if (lpmcd
== NULL
|| lpmcd
->cbStruct
!= sizeof(*lpmcd
))
365 return MMSYSERR_INVALPARAM
;
367 switch (fdwDetails
& MIXER_GETCONTROLDETAILSF_QUERYMASK
) {
368 case MIXER_GETCONTROLDETAILSF_VALUE
:
369 /* can savely use W structure as it is, no string inside */
370 ret
= mixerGetControlDetailsA(hmix
, lpmcd
, fdwDetails
);
372 case MIXER_GETCONTROLDETAILSF_LISTTEXT
:
374 MIXERCONTROLDETAILS_LISTTEXTW
*pDetailsW
= (MIXERCONTROLDETAILS_LISTTEXTW
*)lpmcd
->paDetails
;
375 MIXERCONTROLDETAILS_LISTTEXTA
*pDetailsA
;
376 int size
= max(1, lpmcd
->cChannels
) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA
);
379 if (lpmcd
->u
.cMultipleItems
!= 0) {
380 size
*= lpmcd
->u
.cMultipleItems
;
382 pDetailsA
= (MIXERCONTROLDETAILS_LISTTEXTA
*)HeapAlloc(GetProcessHeap(), 0, size
);
383 lpmcd
->paDetails
= pDetailsA
;
384 lpmcd
->cbDetails
= sizeof(MIXERCONTROLDETAILS_LISTTEXTA
);
385 /* set up lpmcd->paDetails */
386 ret
= mixerGetControlDetailsA(hmix
, lpmcd
, fdwDetails
);
387 /* copy from lpmcd->paDetails back to paDetailsW; */
388 if(ret
== MMSYSERR_NOERROR
) {
389 for(i
=0;i
<lpmcd
->u
.cMultipleItems
*lpmcd
->cChannels
;i
++) {
390 pDetailsW
->dwParam1
= pDetailsA
->dwParam1
;
391 pDetailsW
->dwParam2
= pDetailsA
->dwParam2
;
392 MultiByteToWideChar( CP_ACP
, 0, pDetailsA
->szName
, -1,
394 sizeof(pDetailsW
->szName
)/sizeof(WCHAR
) );
398 pDetailsA
-= lpmcd
->u
.cMultipleItems
*lpmcd
->cChannels
;
399 pDetailsW
-= lpmcd
->u
.cMultipleItems
*lpmcd
->cChannels
;
401 HeapFree(GetProcessHeap(), 0, pDetailsA
);
402 lpmcd
->paDetails
= pDetailsW
;
403 lpmcd
->cbDetails
= sizeof(MIXERCONTROLDETAILS_LISTTEXTW
);
407 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails
);
413 /**************************************************************************
414 * mixerGetLineControlsA [WINMM.@]
416 UINT WINAPI
mixerGetLineControlsA(HMIXEROBJ hmix
, LPMIXERLINECONTROLSA lpmlcA
,
421 TRACE("(%p, %p, %08lx)\n", hmix
, lpmlcA
, fdwControls
);
423 if ((lpwm
= MIXER_GetDev(hmix
, fdwControls
)) == NULL
)
424 return MMSYSERR_INVALHANDLE
;
426 if (lpmlcA
== NULL
|| lpmlcA
->cbStruct
!= sizeof(*lpmlcA
))
427 return MMSYSERR_INVALPARAM
;
429 return MMDRV_Message(&lpwm
->mld
, MXDM_GETLINECONTROLS
, (DWORD
)lpmlcA
,
433 /**************************************************************************
434 * mixerGetLineControlsW [WINMM.@]
436 UINT WINAPI
mixerGetLineControlsW(HMIXEROBJ hmix
, LPMIXERLINECONTROLSW lpmlcW
,
439 MIXERLINECONTROLSA mlcA
;
443 TRACE("(%p, %p, %08lx)\n", hmix
, lpmlcW
, fdwControls
);
445 if (lpmlcW
== NULL
|| lpmlcW
->cbStruct
!= sizeof(*lpmlcW
) ||
446 lpmlcW
->cbmxctrl
!= sizeof(MIXERCONTROLW
))
447 return MMSYSERR_INVALPARAM
;
449 mlcA
.cbStruct
= sizeof(mlcA
);
450 mlcA
.dwLineID
= lpmlcW
->dwLineID
;
451 mlcA
.u
.dwControlID
= lpmlcW
->u
.dwControlID
;
452 mlcA
.u
.dwControlType
= lpmlcW
->u
.dwControlType
;
453 mlcA
.cControls
= lpmlcW
->cControls
;
454 mlcA
.cbmxctrl
= sizeof(MIXERCONTROLA
);
455 mlcA
.pamxctrl
= HeapAlloc(GetProcessHeap(), 0,
456 mlcA
.cControls
* mlcA
.cbmxctrl
);
458 ret
= mixerGetLineControlsA(hmix
, &mlcA
, fdwControls
);
460 if (ret
== MMSYSERR_NOERROR
) {
461 lpmlcW
->dwLineID
= mlcA
.dwLineID
;
462 lpmlcW
->u
.dwControlID
= mlcA
.u
.dwControlID
;
463 lpmlcW
->u
.dwControlType
= mlcA
.u
.dwControlType
;
464 lpmlcW
->cControls
= mlcA
.cControls
;
466 for (i
= 0; i
< mlcA
.cControls
; i
++) {
467 lpmlcW
->pamxctrl
[i
].cbStruct
= sizeof(MIXERCONTROLW
);
468 lpmlcW
->pamxctrl
[i
].dwControlID
= mlcA
.pamxctrl
[i
].dwControlID
;
469 lpmlcW
->pamxctrl
[i
].dwControlType
= mlcA
.pamxctrl
[i
].dwControlType
;
470 lpmlcW
->pamxctrl
[i
].fdwControl
= mlcA
.pamxctrl
[i
].fdwControl
;
471 lpmlcW
->pamxctrl
[i
].cMultipleItems
= mlcA
.pamxctrl
[i
].cMultipleItems
;
472 MultiByteToWideChar( CP_ACP
, 0, mlcA
.pamxctrl
[i
].szShortName
, -1,
473 lpmlcW
->pamxctrl
[i
].szShortName
,
474 sizeof(lpmlcW
->pamxctrl
[i
].szShortName
)/sizeof(WCHAR
) );
475 MultiByteToWideChar( CP_ACP
, 0, mlcA
.pamxctrl
[i
].szName
, -1,
476 lpmlcW
->pamxctrl
[i
].szName
,
477 sizeof(lpmlcW
->pamxctrl
[i
].szName
)/sizeof(WCHAR
) );
478 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
479 * sizeof(mlcA.pamxctrl[i].Bounds) */
480 memcpy(&lpmlcW
->pamxctrl
[i
].Bounds
, &mlcA
.pamxctrl
[i
].Bounds
,
481 sizeof(mlcA
.pamxctrl
[i
].Bounds
));
482 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
483 * sizeof(mlcA.pamxctrl[i].Metrics) */
484 memcpy(&lpmlcW
->pamxctrl
[i
].Metrics
, &mlcA
.pamxctrl
[i
].Metrics
,
485 sizeof(mlcA
.pamxctrl
[i
].Metrics
));
489 HeapFree(GetProcessHeap(), 0, mlcA
.pamxctrl
);
494 /**************************************************************************
495 * mixerGetLineInfoA [WINMM.@]
497 UINT WINAPI
mixerGetLineInfoA(HMIXEROBJ hmix
, LPMIXERLINEA lpmliW
, DWORD fdwInfo
)
501 TRACE("(%p, %p, %08lx)\n", hmix
, lpmliW
, fdwInfo
);
503 if ((lpwm
= MIXER_GetDev(hmix
, fdwInfo
)) == NULL
)
504 return MMSYSERR_INVALHANDLE
;
506 return MMDRV_Message(&lpwm
->mld
, MXDM_GETLINEINFO
, (DWORD
)lpmliW
,
510 /**************************************************************************
511 * mixerGetLineInfoW [WINMM.@]
513 UINT WINAPI
mixerGetLineInfoW(HMIXEROBJ hmix
, LPMIXERLINEW lpmliW
,
519 TRACE("(%p, %p, %08lx)\n", hmix
, lpmliW
, fdwInfo
);
521 if (lpmliW
== NULL
|| lpmliW
->cbStruct
!= sizeof(*lpmliW
))
522 return MMSYSERR_INVALPARAM
;
524 mliA
.cbStruct
= sizeof(mliA
);
525 switch (fdwInfo
& MIXER_GETLINEINFOF_QUERYMASK
) {
526 case MIXER_GETLINEINFOF_COMPONENTTYPE
:
527 mliA
.dwComponentType
= lpmliW
->dwComponentType
;
529 case MIXER_GETLINEINFOF_DESTINATION
:
530 mliA
.dwDestination
= lpmliW
->dwDestination
;
532 case MIXER_GETLINEINFOF_LINEID
:
533 mliA
.dwLineID
= lpmliW
->dwLineID
;
535 case MIXER_GETLINEINFOF_SOURCE
:
536 mliA
.dwDestination
= lpmliW
->dwDestination
;
537 mliA
.dwSource
= lpmliW
->dwSource
;
539 case MIXER_GETLINEINFOF_TARGETTYPE
:
540 mliA
.Target
.dwType
= lpmliW
->Target
.dwType
;
541 mliA
.Target
.wMid
= lpmliW
->Target
.wMid
;
542 mliA
.Target
.wPid
= lpmliW
->Target
.wPid
;
543 mliA
.Target
.vDriverVersion
= lpmliW
->Target
.vDriverVersion
;
544 WideCharToMultiByte( CP_ACP
, 0, lpmliW
->Target
.szPname
, -1, mliA
.Target
.szPname
, sizeof(mliA
.Target
.szPname
), NULL
, NULL
);
547 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo
);
550 ret
= mixerGetLineInfoA(hmix
, &mliA
, fdwInfo
);
552 lpmliW
->dwDestination
= mliA
.dwDestination
;
553 lpmliW
->dwSource
= mliA
.dwSource
;
554 lpmliW
->dwLineID
= mliA
.dwLineID
;
555 lpmliW
->fdwLine
= mliA
.fdwLine
;
556 lpmliW
->dwUser
= mliA
.dwUser
;
557 lpmliW
->dwComponentType
= mliA
.dwComponentType
;
558 lpmliW
->cChannels
= mliA
.cChannels
;
559 lpmliW
->cConnections
= mliA
.cConnections
;
560 lpmliW
->cControls
= mliA
.cControls
;
561 MultiByteToWideChar( CP_ACP
, 0, mliA
.szShortName
, -1, lpmliW
->szShortName
,
562 sizeof(lpmliW
->szShortName
)/sizeof(WCHAR
) );
563 MultiByteToWideChar( CP_ACP
, 0, mliA
.szName
, -1, lpmliW
->szName
,
564 sizeof(lpmliW
->szName
)/sizeof(WCHAR
) );
565 lpmliW
->Target
.dwType
= mliA
.Target
.dwType
;
566 lpmliW
->Target
.dwDeviceID
= mliA
.Target
.dwDeviceID
;
567 lpmliW
->Target
.wMid
= mliA
.Target
.wMid
;
568 lpmliW
->Target
.wPid
= mliA
.Target
.wPid
;
569 lpmliW
->Target
.vDriverVersion
= mliA
.Target
.vDriverVersion
;
570 MultiByteToWideChar( CP_ACP
, 0, mliA
.Target
.szPname
, -1, lpmliW
->Target
.szPname
,
571 sizeof(lpmliW
->Target
.szPname
)/sizeof(WCHAR
) );
576 /**************************************************************************
577 * mixerSetControlDetails [WINMM.@]
579 UINT WINAPI
mixerSetControlDetails(HMIXEROBJ hmix
, LPMIXERCONTROLDETAILS lpmcdA
,
584 TRACE("(%p, %p, %08lx)\n", hmix
, lpmcdA
, fdwDetails
);
586 if ((lpwm
= MIXER_GetDev(hmix
, fdwDetails
)) == NULL
)
587 return MMSYSERR_INVALHANDLE
;
589 return MMDRV_Message(&lpwm
->mld
, MXDM_SETCONTROLDETAILS
, (DWORD
)lpmcdA
,
593 /**************************************************************************
594 * mixerMessage [WINMM.@]
596 UINT WINAPI
mixerMessage(HMIXER hmix
, UINT uMsg
, DWORD dwParam1
, DWORD dwParam2
)
600 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
601 (DWORD
)hmix
, uMsg
, dwParam1
, dwParam2
);
603 if ((wmld
= MMDRV_Get(hmix
, MMDRV_MIXER
, FALSE
)) == NULL
)
604 return MMSYSERR_INVALHANDLE
;
606 return MMDRV_Message(wmld
, uMsg
, dwParam1
, dwParam2
, TRUE
);
609 /**************************************************************************
610 * auxGetNumDevs [WINMM.@]
612 UINT WINAPI
auxGetNumDevs(void)
614 return MMDRV_GetNum(MMDRV_AUX
);
617 /**************************************************************************
618 * auxGetDevCapsW [WINMM.@]
620 UINT WINAPI
auxGetDevCapsW(UINT uDeviceID
, LPAUXCAPSW lpCaps
, UINT uSize
)
623 UINT ret
= auxGetDevCapsA(uDeviceID
, &acA
, sizeof(acA
));
625 lpCaps
->wMid
= acA
.wMid
;
626 lpCaps
->wPid
= acA
.wPid
;
627 lpCaps
->vDriverVersion
= acA
.vDriverVersion
;
628 MultiByteToWideChar( CP_ACP
, 0, acA
.szPname
, -1, lpCaps
->szPname
,
629 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
630 lpCaps
->wTechnology
= acA
.wTechnology
;
631 lpCaps
->dwSupport
= acA
.dwSupport
;
635 /**************************************************************************
636 * auxGetDevCapsA [WINMM.@]
638 UINT WINAPI
auxGetDevCapsA(UINT uDeviceID
, LPAUXCAPSA lpCaps
, UINT uSize
)
642 TRACE("(%04X, %p, %d) !\n", uDeviceID
, lpCaps
, uSize
);
644 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
645 return MMSYSERR_INVALHANDLE
;
646 return MMDRV_Message(wmld
, AUXDM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
649 /**************************************************************************
650 * auxGetVolume [WINMM.@]
652 UINT WINAPI
auxGetVolume(UINT uDeviceID
, DWORD
* lpdwVolume
)
656 TRACE("(%04X, %p) !\n", uDeviceID
, lpdwVolume
);
658 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
659 return MMSYSERR_INVALHANDLE
;
660 return MMDRV_Message(wmld
, AUXDM_GETVOLUME
, (DWORD
)lpdwVolume
, 0L, TRUE
);
663 /**************************************************************************
664 * auxSetVolume [WINMM.@]
666 UINT WINAPI
auxSetVolume(UINT uDeviceID
, DWORD dwVolume
)
670 TRACE("(%04X, %lu) !\n", uDeviceID
, dwVolume
);
672 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
673 return MMSYSERR_INVALHANDLE
;
674 return MMDRV_Message(wmld
, AUXDM_SETVOLUME
, dwVolume
, 0L, TRUE
);
677 /**************************************************************************
678 * auxOutMessage [WINMM.@]
680 DWORD WINAPI
auxOutMessage(UINT uDeviceID
, UINT uMessage
, DWORD dw1
, DWORD dw2
)
684 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
685 return MMSYSERR_INVALHANDLE
;
687 return MMDRV_Message(wmld
, uMessage
, dw1
, dw2
, TRUE
);
690 /**************************************************************************
691 * mciGetErrorStringW [WINMM.@]
693 BOOL WINAPI
mciGetErrorStringW(DWORD wError
, LPWSTR lpstrBuffer
, UINT uLength
)
695 LPSTR bufstr
= HeapAlloc(GetProcessHeap(), 0, uLength
);
696 BOOL ret
= mciGetErrorStringA(wError
, bufstr
, uLength
);
698 MultiByteToWideChar( CP_ACP
, 0, bufstr
, -1, lpstrBuffer
, uLength
);
699 HeapFree(GetProcessHeap(), 0, bufstr
);
703 /**************************************************************************
704 * mciGetErrorStringA [WINMM.@]
706 BOOL WINAPI
mciGetErrorStringA(DWORD dwError
, LPSTR lpstrBuffer
, UINT uLength
)
710 if (lpstrBuffer
!= NULL
&& uLength
> 0 &&
711 dwError
>= MCIERR_BASE
&& dwError
<= MCIERR_CUSTOM_DRIVER_BASE
) {
713 if (LoadStringA(WINMM_IData
->hWinMM32Instance
,
714 dwError
, lpstrBuffer
, uLength
) > 0) {
721 /**************************************************************************
722 * mciDriverNotify [WINMM.@]
724 BOOL WINAPI
mciDriverNotify(HWND hWndCallBack
, UINT wDevID
, UINT wStatus
)
727 TRACE("(%p, %04x, %04X)\n", hWndCallBack
, wDevID
, wStatus
);
729 return PostMessageA(hWndCallBack
, MM_MCINOTIFY
, wStatus
, wDevID
);
732 /**************************************************************************
733 * mciGetDriverData [WINMM.@]
735 DWORD WINAPI
mciGetDriverData(UINT uDeviceID
)
737 LPWINE_MCIDRIVER wmd
;
739 TRACE("(%04x)\n", uDeviceID
);
741 wmd
= MCI_GetDriver(uDeviceID
);
744 WARN("Bad uDeviceID\n");
748 return wmd
->dwPrivate
;
751 /**************************************************************************
752 * mciSetDriverData [WINMM.@]
754 BOOL WINAPI
mciSetDriverData(UINT uDeviceID
, DWORD data
)
756 LPWINE_MCIDRIVER wmd
;
758 TRACE("(%04x, %08lx)\n", uDeviceID
, data
);
760 wmd
= MCI_GetDriver(uDeviceID
);
763 WARN("Bad uDeviceID\n");
767 wmd
->dwPrivate
= data
;
771 /**************************************************************************
772 * mciSendCommandA [WINMM.@]
774 DWORD WINAPI
mciSendCommandA(UINT wDevID
, UINT wMsg
, DWORD dwParam1
, DWORD dwParam2
)
778 TRACE("(%08x, %s, %08lx, %08lx)\n",
779 wDevID
, MCI_MessageToString(wMsg
), dwParam1
, dwParam2
);
781 dwRet
= MCI_SendCommand(wDevID
, wMsg
, dwParam1
, dwParam2
, TRUE
);
782 dwRet
= MCI_CleanUp(dwRet
, wMsg
, dwParam2
);
783 TRACE("=> %08lx\n", dwRet
);
787 /**************************************************************************
788 * mciSendCommandW [WINMM.@]
790 DWORD WINAPI
mciSendCommandW(UINT wDevID
, UINT wMsg
, DWORD dwParam1
, DWORD dwParam2
)
792 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
793 wDevID
, MCI_MessageToString(wMsg
), dwParam1
, dwParam2
);
794 return MCIERR_UNSUPPORTED_FUNCTION
;
797 /**************************************************************************
798 * mciGetDeviceIDA [WINMM.@]
800 UINT WINAPI
mciGetDeviceIDA(LPCSTR lpstrName
)
802 return MCI_GetDriverFromString(lpstrName
);
805 /**************************************************************************
806 * mciGetDeviceIDW [WINMM.@]
808 UINT WINAPI
mciGetDeviceIDW(LPCWSTR lpwstrName
)
813 lpstrName
= HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName
);
814 ret
= MCI_GetDriverFromString(lpstrName
);
815 HeapFree(GetProcessHeap(), 0, lpstrName
);
819 /**************************************************************************
820 * MCI_DefYieldProc [internal]
822 UINT WINAPI
MCI_DefYieldProc(MCIDEVICEID wDevID
, DWORD data
)
826 TRACE("(0x%04x, 0x%08lx)\n", wDevID
, data
);
828 if ((HIWORD(data
) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data
)) ||
829 (GetAsyncKeyState(LOWORD(data
)) & 1) == 0) {
835 msg
.hwnd
= HWND_32(HIWORD(data
));
836 while (!PeekMessageA(&msg
, msg
.hwnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_REMOVE
));
842 /**************************************************************************
843 * mciSetYieldProc [WINMM.@]
845 BOOL WINAPI
mciSetYieldProc(UINT uDeviceID
, YIELDPROC fpYieldProc
, DWORD dwYieldData
)
847 LPWINE_MCIDRIVER wmd
;
849 TRACE("(%u, %p, %08lx)\n", uDeviceID
, fpYieldProc
, dwYieldData
);
851 if (!(wmd
= MCI_GetDriver(uDeviceID
))) {
852 WARN("Bad uDeviceID\n");
856 wmd
->lpfnYieldProc
= fpYieldProc
;
857 wmd
->dwYieldData
= dwYieldData
;
863 /**************************************************************************
864 * mciGetDeviceIDFromElementIDW [WINMM.@]
866 UINT WINAPI
mciGetDeviceIDFromElementIDW(DWORD dwElementID
, LPCWSTR lpstrType
)
868 /* FIXME: that's rather strange, there is no
869 * mciGetDeviceIDFromElementID32A in winmm.spec
871 FIXME("(%lu, %p) stub\n", dwElementID
, lpstrType
);
875 /**************************************************************************
876 * mciGetYieldProc [WINMM.@]
878 YIELDPROC WINAPI
mciGetYieldProc(UINT uDeviceID
, DWORD
* lpdwYieldData
)
880 LPWINE_MCIDRIVER wmd
;
882 TRACE("(%u, %p)\n", uDeviceID
, lpdwYieldData
);
884 if (!(wmd
= MCI_GetDriver(uDeviceID
))) {
885 WARN("Bad uDeviceID\n");
888 if (!wmd
->lpfnYieldProc
) {
889 WARN("No proc set\n");
893 WARN("Proc is 32 bit\n");
896 return wmd
->lpfnYieldProc
;
899 /**************************************************************************
900 * mciGetCreatorTask [WINMM.@]
902 HTASK WINAPI
mciGetCreatorTask(UINT uDeviceID
)
904 LPWINE_MCIDRIVER wmd
;
907 if ((wmd
= MCI_GetDriver(uDeviceID
))) ret
= (HTASK
)wmd
->CreatorThread
;
909 TRACE("(%u) => %p\n", uDeviceID
, ret
);
913 /**************************************************************************
914 * mciDriverYield [WINMM.@]
916 UINT WINAPI
mciDriverYield(UINT uDeviceID
)
918 LPWINE_MCIDRIVER wmd
;
921 TRACE("(%04x)\n", uDeviceID
);
923 if (!(wmd
= MCI_GetDriver(uDeviceID
)) || !wmd
->lpfnYieldProc
|| !wmd
->bIs32
) {
926 ret
= wmd
->lpfnYieldProc(uDeviceID
, wmd
->dwYieldData
);
932 /**************************************************************************
933 * midiOutGetNumDevs [WINMM.@]
935 UINT WINAPI
midiOutGetNumDevs(void)
937 return MMDRV_GetNum(MMDRV_MIDIOUT
);
940 /**************************************************************************
941 * midiOutGetDevCapsW [WINMM.@]
943 UINT WINAPI
midiOutGetDevCapsW(UINT uDeviceID
, LPMIDIOUTCAPSW lpCaps
,
949 ret
= midiOutGetDevCapsA(uDeviceID
, &mocA
, sizeof(mocA
));
950 lpCaps
->wMid
= mocA
.wMid
;
951 lpCaps
->wPid
= mocA
.wPid
;
952 lpCaps
->vDriverVersion
= mocA
.vDriverVersion
;
953 MultiByteToWideChar( CP_ACP
, 0, mocA
.szPname
, -1, lpCaps
->szPname
,
954 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
955 lpCaps
->wTechnology
= mocA
.wTechnology
;
956 lpCaps
->wVoices
= mocA
.wVoices
;
957 lpCaps
->wNotes
= mocA
.wNotes
;
958 lpCaps
->wChannelMask
= mocA
.wChannelMask
;
959 lpCaps
->dwSupport
= mocA
.dwSupport
;
963 /**************************************************************************
964 * midiOutGetDevCapsA [WINMM.@]
966 UINT WINAPI
midiOutGetDevCapsA(UINT uDeviceID
, LPMIDIOUTCAPSA lpCaps
,
971 TRACE("(%u, %p, %u);\n", uDeviceID
, lpCaps
, uSize
);
973 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
975 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_MIDIOUT
, TRUE
)) == NULL
)
976 return MMSYSERR_INVALHANDLE
;
978 return MMDRV_Message(wmld
, MODM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
981 /**************************************************************************
982 * MIDI_GetErrorText [internal]
984 static UINT16
MIDI_GetErrorText(UINT16 uError
, LPSTR lpText
, UINT16 uSize
)
986 UINT16 ret
= MMSYSERR_BADERRNUM
;
988 if (lpText
== NULL
) {
989 ret
= MMSYSERR_INVALPARAM
;
990 } else if (uSize
== 0) {
991 ret
= MMSYSERR_NOERROR
;
993 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
994 * a warning for the test was always true */
995 (/*uError >= MMSYSERR_BASE && */ uError
<= MMSYSERR_LASTERROR
) ||
996 (uError
>= MIDIERR_BASE
&& uError
<= MIDIERR_LASTERROR
)) {
998 if (LoadStringA(WINMM_IData
->hWinMM32Instance
,
999 uError
, lpText
, uSize
) > 0) {
1000 ret
= MMSYSERR_NOERROR
;
1006 /**************************************************************************
1007 * midiOutGetErrorTextA [WINMM.@]
1009 UINT WINAPI
midiOutGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
1011 return MIDI_GetErrorText(uError
, lpText
, uSize
);
1014 /**************************************************************************
1015 * midiOutGetErrorTextW [WINMM.@]
1017 UINT WINAPI
midiOutGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
1019 LPSTR xstr
= HeapAlloc(GetProcessHeap(), 0, uSize
);
1022 ret
= MIDI_GetErrorText(uError
, xstr
, uSize
);
1023 MultiByteToWideChar( CP_ACP
, 0, xstr
, -1, lpText
, uSize
);
1024 HeapFree(GetProcessHeap(), 0, xstr
);
1028 /**************************************************************************
1029 * MIDI_OutAlloc [internal]
1031 static LPWINE_MIDI
MIDI_OutAlloc(HMIDIOUT
* lphMidiOut
, LPDWORD lpdwCallback
,
1032 LPDWORD lpdwInstance
, LPDWORD lpdwFlags
,
1033 DWORD cIDs
, MIDIOPENSTRMID
* lpIDs
, BOOL bFrom32
)
1039 size
= sizeof(WINE_MIDI
) + (cIDs
? (cIDs
-1) : 0) * sizeof(MIDIOPENSTRMID
);
1041 lpwm
= (LPWINE_MIDI
)MMDRV_Alloc(size
, MMDRV_MIDIOUT
, &hMidiOut
, lpdwFlags
,
1042 lpdwCallback
, lpdwInstance
, bFrom32
);
1044 if (lphMidiOut
!= NULL
)
1045 *lphMidiOut
= hMidiOut
;
1048 lpwm
->mod
.hMidi
= (HMIDI
) hMidiOut
;
1049 lpwm
->mod
.dwCallback
= *lpdwCallback
;
1050 lpwm
->mod
.dwInstance
= *lpdwInstance
;
1051 lpwm
->mod
.dnDevNode
= 0;
1052 lpwm
->mod
.cIds
= cIDs
;
1054 memcpy(&(lpwm
->mod
.rgIds
), lpIDs
, cIDs
* sizeof(MIDIOPENSTRMID
));
1059 UINT
MIDI_OutOpen(HMIDIOUT
* lphMidiOut
, UINT uDeviceID
, DWORD dwCallback
,
1060 DWORD dwInstance
, DWORD dwFlags
, BOOL bFrom32
)
1066 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1067 lphMidiOut
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
);
1069 if (lphMidiOut
!= NULL
) *lphMidiOut
= 0;
1071 lpwm
= MIDI_OutAlloc(&hMidiOut
, &dwCallback
, &dwInstance
, &dwFlags
,
1075 return MMSYSERR_NOMEM
;
1077 lpwm
->mld
.uDeviceID
= uDeviceID
;
1079 dwRet
= MMDRV_Open((LPWINE_MLD
)lpwm
, MODM_OPEN
, (DWORD
)&lpwm
->mod
, dwFlags
);
1081 if (dwRet
!= MMSYSERR_NOERROR
) {
1082 MMDRV_Free(hMidiOut
, (LPWINE_MLD
)lpwm
);
1086 if (lphMidiOut
) *lphMidiOut
= hMidiOut
;
1087 TRACE("=> %d hMidi=%p\n", dwRet
, hMidiOut
);
1092 /**************************************************************************
1093 * midiOutOpen [WINMM.@]
1095 UINT WINAPI
midiOutOpen(HMIDIOUT
* lphMidiOut
, UINT uDeviceID
,
1096 DWORD dwCallback
, DWORD dwInstance
, DWORD dwFlags
)
1098 return MIDI_OutOpen(lphMidiOut
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
, TRUE
);
1101 /**************************************************************************
1102 * midiOutClose [WINMM.@]
1104 UINT WINAPI
midiOutClose(HMIDIOUT hMidiOut
)
1109 TRACE("(%p)\n", hMidiOut
);
1111 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1112 return MMSYSERR_INVALHANDLE
;
1114 dwRet
= MMDRV_Close(wmld
, MODM_CLOSE
);
1115 MMDRV_Free(hMidiOut
, wmld
);
1120 /**************************************************************************
1121 * midiOutPrepareHeader [WINMM.@]
1123 UINT WINAPI
midiOutPrepareHeader(HMIDIOUT hMidiOut
,
1124 MIDIHDR
* lpMidiOutHdr
, UINT uSize
)
1128 TRACE("(%p, %p, %d)\n", hMidiOut
, lpMidiOutHdr
, uSize
);
1130 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1131 return MMSYSERR_INVALHANDLE
;
1133 return MMDRV_Message(wmld
, MODM_PREPARE
, (DWORD
)lpMidiOutHdr
, uSize
, TRUE
);
1136 /**************************************************************************
1137 * midiOutUnprepareHeader [WINMM.@]
1139 UINT WINAPI
midiOutUnprepareHeader(HMIDIOUT hMidiOut
,
1140 MIDIHDR
* lpMidiOutHdr
, UINT uSize
)
1144 TRACE("(%p, %p, %d)\n", hMidiOut
, lpMidiOutHdr
, uSize
);
1146 if (!(lpMidiOutHdr
->dwFlags
& MHDR_PREPARED
)) {
1147 return MMSYSERR_NOERROR
;
1150 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1151 return MMSYSERR_INVALHANDLE
;
1153 return MMDRV_Message(wmld
, MODM_UNPREPARE
, (DWORD
)lpMidiOutHdr
, uSize
, TRUE
);
1156 /**************************************************************************
1157 * midiOutShortMsg [WINMM.@]
1159 UINT WINAPI
midiOutShortMsg(HMIDIOUT hMidiOut
, DWORD dwMsg
)
1163 TRACE("(%p, %08lX)\n", hMidiOut
, dwMsg
);
1165 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1166 return MMSYSERR_INVALHANDLE
;
1168 return MMDRV_Message(wmld
, MODM_DATA
, dwMsg
, 0L, TRUE
);
1171 /**************************************************************************
1172 * midiOutLongMsg [WINMM.@]
1174 UINT WINAPI
midiOutLongMsg(HMIDIOUT hMidiOut
,
1175 MIDIHDR
* lpMidiOutHdr
, UINT uSize
)
1179 TRACE("(%p, %p, %d)\n", hMidiOut
, lpMidiOutHdr
, uSize
);
1181 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1182 return MMSYSERR_INVALHANDLE
;
1184 return MMDRV_Message(wmld
, MODM_LONGDATA
, (DWORD
)lpMidiOutHdr
, uSize
, TRUE
);
1187 /**************************************************************************
1188 * midiOutReset [WINMM.@]
1190 UINT WINAPI
midiOutReset(HMIDIOUT hMidiOut
)
1194 TRACE("(%p)\n", hMidiOut
);
1196 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1197 return MMSYSERR_INVALHANDLE
;
1199 return MMDRV_Message(wmld
, MODM_RESET
, 0L, 0L, TRUE
);
1202 /**************************************************************************
1203 * midiOutGetVolume [WINMM.@]
1205 UINT WINAPI
midiOutGetVolume(HMIDIOUT hMidiOut
, DWORD
* lpdwVolume
)
1209 TRACE("(%p, %p);\n", hMidiOut
, lpdwVolume
);
1211 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, TRUE
)) == NULL
)
1212 return MMSYSERR_INVALHANDLE
;
1214 return MMDRV_Message(wmld
, MODM_GETVOLUME
, (DWORD
)lpdwVolume
, 0L, TRUE
);
1217 /**************************************************************************
1218 * midiOutSetVolume [WINMM.@]
1220 UINT WINAPI
midiOutSetVolume(HMIDIOUT hMidiOut
, DWORD dwVolume
)
1224 TRACE("(%p, %ld);\n", hMidiOut
, dwVolume
);
1226 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, TRUE
)) == NULL
)
1227 return MMSYSERR_INVALHANDLE
;
1229 return MMDRV_Message(wmld
, MODM_SETVOLUME
, dwVolume
, 0L, TRUE
);
1232 /**************************************************************************
1233 * midiOutCachePatches [WINMM.@]
1235 UINT WINAPI
midiOutCachePatches(HMIDIOUT hMidiOut
, UINT uBank
,
1236 WORD
* lpwPatchArray
, UINT uFlags
)
1238 /* not really necessary to support this */
1239 FIXME("not supported yet\n");
1240 return MMSYSERR_NOTSUPPORTED
;
1243 /**************************************************************************
1244 * midiOutCacheDrumPatches [WINMM.@]
1246 UINT WINAPI
midiOutCacheDrumPatches(HMIDIOUT hMidiOut
, UINT uPatch
,
1247 WORD
* lpwKeyArray
, UINT uFlags
)
1249 FIXME("not supported yet\n");
1250 return MMSYSERR_NOTSUPPORTED
;
1253 /**************************************************************************
1254 * midiOutGetID [WINMM.@]
1256 UINT WINAPI
midiOutGetID(HMIDIOUT hMidiOut
, UINT
* lpuDeviceID
)
1260 TRACE("(%p, %p)\n", hMidiOut
, lpuDeviceID
);
1262 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALPARAM
;
1263 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1264 return MMSYSERR_INVALHANDLE
;
1266 *lpuDeviceID
= wmld
->uDeviceID
;
1267 return MMSYSERR_NOERROR
;
1270 /**************************************************************************
1271 * midiOutMessage [WINMM.@]
1273 DWORD WINAPI
midiOutMessage(HMIDIOUT hMidiOut
, UINT uMessage
,
1274 DWORD dwParam1
, DWORD dwParam2
)
1278 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut
, uMessage
, dwParam1
, dwParam2
);
1280 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
) {
1282 if (uMessage
== 0x0001) {
1283 *(LPDWORD
)dwParam1
= 1;
1286 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, TRUE
)) != NULL
) {
1287 return MMDRV_PhysicalFeatures(wmld
, uMessage
, dwParam1
, dwParam2
);
1289 return MMSYSERR_INVALHANDLE
;
1295 FIXME("can't handle OPEN or CLOSE message!\n");
1296 return MMSYSERR_NOTSUPPORTED
;
1298 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
1301 /**************************************************************************
1302 * midiInGetNumDevs [WINMM.@]
1304 UINT WINAPI
midiInGetNumDevs(void)
1306 return MMDRV_GetNum(MMDRV_MIDIIN
);
1309 /**************************************************************************
1310 * midiInGetDevCapsW [WINMM.@]
1312 UINT WINAPI
midiInGetDevCapsW(UINT uDeviceID
, LPMIDIINCAPSW lpCaps
, UINT uSize
)
1315 UINT ret
= midiInGetDevCapsA(uDeviceID
, &micA
, uSize
);
1317 if (ret
== MMSYSERR_NOERROR
) {
1318 lpCaps
->wMid
= micA
.wMid
;
1319 lpCaps
->wPid
= micA
.wPid
;
1320 lpCaps
->vDriverVersion
= micA
.vDriverVersion
;
1321 MultiByteToWideChar( CP_ACP
, 0, micA
.szPname
, -1, lpCaps
->szPname
,
1322 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
1323 lpCaps
->dwSupport
= micA
.dwSupport
;
1328 /**************************************************************************
1329 * midiInGetDevCapsA [WINMM.@]
1331 UINT WINAPI
midiInGetDevCapsA(UINT uDeviceID
, LPMIDIINCAPSA lpCaps
, UINT uSize
)
1335 TRACE("(%d, %p, %d);\n", uDeviceID
, lpCaps
, uSize
);
1337 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_MIDIIN
, TRUE
)) == NULL
)
1338 return MMSYSERR_INVALHANDLE
;
1340 return MMDRV_Message(wmld
, MIDM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
1343 /**************************************************************************
1344 * midiInGetErrorTextW [WINMM.@]
1346 UINT WINAPI
midiInGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
1348 LPSTR xstr
= HeapAlloc(GetProcessHeap(), 0, uSize
);
1349 UINT ret
= MIDI_GetErrorText(uError
, xstr
, uSize
);
1351 MultiByteToWideChar( CP_ACP
, 0, xstr
, -1, lpText
, uSize
);
1352 HeapFree(GetProcessHeap(), 0, xstr
);
1356 /**************************************************************************
1357 * midiInGetErrorTextA [WINMM.@]
1359 UINT WINAPI
midiInGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
1361 return MIDI_GetErrorText(uError
, lpText
, uSize
);
1364 UINT
MIDI_InOpen(HMIDIIN
* lphMidiIn
, UINT uDeviceID
, DWORD dwCallback
,
1365 DWORD dwInstance
, DWORD dwFlags
, BOOL bFrom32
)
1371 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1372 lphMidiIn
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
);
1374 if (lphMidiIn
!= NULL
) *lphMidiIn
= 0;
1376 lpwm
= (LPWINE_MIDI
)MMDRV_Alloc(sizeof(WINE_MIDI
), MMDRV_MIDIIN
, &hMidiIn
,
1377 &dwFlags
, &dwCallback
, &dwInstance
, bFrom32
);
1380 return MMSYSERR_NOMEM
;
1382 lpwm
->mod
.hMidi
= (HMIDI
) hMidiIn
;
1383 lpwm
->mod
.dwCallback
= dwCallback
;
1384 lpwm
->mod
.dwInstance
= dwInstance
;
1386 lpwm
->mld
.uDeviceID
= uDeviceID
;
1387 dwRet
= MMDRV_Open(&lpwm
->mld
, MIDM_OPEN
, (DWORD
)&lpwm
->mod
, dwFlags
);
1389 if (dwRet
!= MMSYSERR_NOERROR
) {
1390 MMDRV_Free(hMidiIn
, &lpwm
->mld
);
1393 if (lphMidiIn
!= NULL
) *lphMidiIn
= hMidiIn
;
1394 TRACE("=> %ld hMidi=%p\n", dwRet
, hMidiIn
);
1399 /**************************************************************************
1400 * midiInOpen [WINMM.@]
1402 UINT WINAPI
midiInOpen(HMIDIIN
* lphMidiIn
, UINT uDeviceID
,
1403 DWORD dwCallback
, DWORD dwInstance
, DWORD dwFlags
)
1405 return MIDI_InOpen(lphMidiIn
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
, TRUE
);
1408 /**************************************************************************
1409 * midiInClose [WINMM.@]
1411 UINT WINAPI
midiInClose(HMIDIIN hMidiIn
)
1416 TRACE("(%p)\n", hMidiIn
);
1418 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1419 return MMSYSERR_INVALHANDLE
;
1421 dwRet
= MMDRV_Close(wmld
, MIDM_CLOSE
);
1422 MMDRV_Free(hMidiIn
, wmld
);
1426 /**************************************************************************
1427 * midiInPrepareHeader [WINMM.@]
1429 UINT WINAPI
midiInPrepareHeader(HMIDIIN hMidiIn
,
1430 MIDIHDR
* lpMidiInHdr
, UINT uSize
)
1434 TRACE("(%p, %p, %d)\n", hMidiIn
, lpMidiInHdr
, uSize
);
1436 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1437 return MMSYSERR_INVALHANDLE
;
1439 return MMDRV_Message(wmld
, MIDM_PREPARE
, (DWORD
)lpMidiInHdr
, uSize
, TRUE
);
1442 /**************************************************************************
1443 * midiInUnprepareHeader [WINMM.@]
1445 UINT WINAPI
midiInUnprepareHeader(HMIDIIN hMidiIn
,
1446 MIDIHDR
* lpMidiInHdr
, UINT uSize
)
1450 TRACE("(%p, %p, %d)\n", hMidiIn
, lpMidiInHdr
, uSize
);
1452 if (!(lpMidiInHdr
->dwFlags
& MHDR_PREPARED
)) {
1453 return MMSYSERR_NOERROR
;
1456 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1457 return MMSYSERR_INVALHANDLE
;
1459 return MMDRV_Message(wmld
, MIDM_UNPREPARE
, (DWORD
)lpMidiInHdr
, uSize
, TRUE
);
1462 /**************************************************************************
1463 * midiInAddBuffer [WINMM.@]
1465 UINT WINAPI
midiInAddBuffer(HMIDIIN hMidiIn
,
1466 MIDIHDR
* lpMidiInHdr
, UINT uSize
)
1470 TRACE("(%p, %p, %d)\n", hMidiIn
, lpMidiInHdr
, uSize
);
1472 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1473 return MMSYSERR_INVALHANDLE
;
1475 return MMDRV_Message(wmld
, MIDM_ADDBUFFER
, (DWORD
)lpMidiInHdr
, uSize
, TRUE
);
1478 /**************************************************************************
1479 * midiInStart [WINMM.@]
1481 UINT WINAPI
midiInStart(HMIDIIN hMidiIn
)
1485 TRACE("(%p)\n", hMidiIn
);
1487 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1488 return MMSYSERR_INVALHANDLE
;
1490 return MMDRV_Message(wmld
, MIDM_START
, 0L, 0L, TRUE
);
1493 /**************************************************************************
1494 * midiInStop [WINMM.@]
1496 UINT WINAPI
midiInStop(HMIDIIN hMidiIn
)
1500 TRACE("(%p)\n", hMidiIn
);
1502 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1503 return MMSYSERR_INVALHANDLE
;
1505 return MMDRV_Message(wmld
, MIDM_STOP
, 0L, 0L, TRUE
);
1508 /**************************************************************************
1509 * midiInReset [WINMM.@]
1511 UINT WINAPI
midiInReset(HMIDIIN hMidiIn
)
1515 TRACE("(%p)\n", hMidiIn
);
1517 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1518 return MMSYSERR_INVALHANDLE
;
1520 return MMDRV_Message(wmld
, MIDM_RESET
, 0L, 0L, TRUE
);
1523 /**************************************************************************
1524 * midiInGetID [WINMM.@]
1526 UINT WINAPI
midiInGetID(HMIDIIN hMidiIn
, UINT
* lpuDeviceID
)
1530 TRACE("(%p, %p)\n", hMidiIn
, lpuDeviceID
);
1532 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALPARAM
;
1534 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, TRUE
)) == NULL
)
1535 return MMSYSERR_INVALHANDLE
;
1537 *lpuDeviceID
= wmld
->uDeviceID
;
1539 return MMSYSERR_NOERROR
;
1542 /**************************************************************************
1543 * midiInMessage [WINMM.@]
1545 DWORD WINAPI
midiInMessage(HMIDIIN hMidiIn
, UINT uMessage
,
1546 DWORD dwParam1
, DWORD dwParam2
)
1550 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn
, uMessage
, dwParam1
, dwParam2
);
1552 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1553 return MMSYSERR_INVALHANDLE
;
1558 FIXME("can't handle OPEN or CLOSE message!\n");
1559 return MMSYSERR_NOTSUPPORTED
;
1561 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
1564 typedef struct WINE_MIDIStream
{
1575 LPMIDIHDR lpMidiHdr
;
1578 #define WINE_MSM_HEADER (WM_USER+0)
1579 #define WINE_MSM_STOP (WM_USER+1)
1581 /**************************************************************************
1582 * MMSYSTEM_GetMidiStream [internal]
1584 static BOOL
MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm
, WINE_MIDIStream
** lpMidiStrm
, WINE_MIDI
** lplpwm
)
1586 WINE_MIDI
* lpwm
= (LPWINE_MIDI
)MMDRV_Get(hMidiStrm
, MMDRV_MIDIOUT
, FALSE
);
1595 *lpMidiStrm
= (WINE_MIDIStream
*)lpwm
->mod
.rgIds
.dwStreamID
;
1597 return *lpMidiStrm
!= NULL
;
1600 /**************************************************************************
1601 * MMSYSTEM_MidiStream_Convert [internal]
1603 static DWORD
MMSYSTEM_MidiStream_Convert(WINE_MIDIStream
* lpMidiStrm
, DWORD pulse
)
1607 if (lpMidiStrm
->dwTimeDiv
== 0) {
1608 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1609 } else if (lpMidiStrm
->dwTimeDiv
> 0x8000) { /* SMPTE, unchecked FIXME? */
1610 int nf
= -(char)HIBYTE(lpMidiStrm
->dwTimeDiv
); /* number of frames */
1611 int nsf
= LOBYTE(lpMidiStrm
->dwTimeDiv
); /* number of sub-frames */
1612 ret
= (pulse
* 1000) / (nf
* nsf
);
1614 ret
= (DWORD
)((double)pulse
* ((double)lpMidiStrm
->dwTempo
/ 1000) /
1615 (double)lpMidiStrm
->dwTimeDiv
);
1621 /**************************************************************************
1622 * MMSYSTEM_MidiStream_MessageHandler [internal]
1624 static BOOL
MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream
* lpMidiStrm
, LPWINE_MIDI lpwm
, LPMSG msg
)
1626 LPMIDIHDR lpMidiHdr
;
1630 switch (msg
->message
) {
1632 SetEvent(lpMidiStrm
->hEvent
);
1636 /* this is not quite what MS doc says... */
1637 midiOutReset(lpMidiStrm
->hDevice
);
1638 /* empty list of already submitted buffers */
1639 for (lpMidiHdr
= lpMidiStrm
->lpMidiHdr
; lpMidiHdr
; lpMidiHdr
= (LPMIDIHDR
)lpMidiHdr
->lpNext
) {
1640 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
1641 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1643 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1644 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_DONE
,
1645 lpwm
->mod
.dwInstance
, (DWORD
)lpMidiHdr
, 0L);
1647 lpMidiStrm
->lpMidiHdr
= 0;
1648 SetEvent(lpMidiStrm
->hEvent
);
1650 case WINE_MSM_HEADER
:
1651 /* sets initial tick count for first MIDIHDR */
1652 if (!lpMidiStrm
->dwStartTicks
)
1653 lpMidiStrm
->dwStartTicks
= GetTickCount();
1655 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1656 * by native mcimidi, it doesn't look like a correct one".
1657 * this trick allows to throw it away... but I don't like it.
1658 * It looks like part of the file I'm trying to play and definitively looks
1659 * like raw midi content
1660 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1661 * synchronization issue where native mcimidi is still processing raw MIDI
1662 * content before generating MIDIEVENTs ?
1664 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1665 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1666 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1667 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1668 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1669 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1670 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1671 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1672 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1673 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1674 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1675 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1676 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1677 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1678 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1679 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1680 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1682 lpMidiHdr
= (LPMIDIHDR
)msg
->lParam
;
1683 lpData
= lpMidiHdr
->lpData
;
1684 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1685 (lpMidiHdr
->dwFlags
& MHDR_ISSTRM
) ? "stream" : "regular", lpMidiHdr
,
1686 (DWORD
)lpMidiHdr
, lpMidiHdr
->dwBufferLength
, lpMidiHdr
->dwBytesRecorded
,
1687 lpMidiHdr
->dwFlags
, msg
->wParam
);
1689 /* dumps content of lpMidiHdr->lpData
1690 * FIXME: there should be a debug routine somewhere that already does this
1691 * I hate spreading this type of shit all around the code
1693 for (dwToGo
= 0; dwToGo
< lpMidiHdr
->dwBufferLength
; dwToGo
+= 16) {
1697 for (i
= 0; i
< min(16, lpMidiHdr
->dwBufferLength
- dwToGo
); i
++)
1698 printf("%02x ", lpData
[dwToGo
+ i
]);
1701 for (i
= 0; i
< min(16, lpMidiHdr
->dwBufferLength
- dwToGo
); i
++) {
1702 ch
= lpData
[dwToGo
+ i
];
1703 printf("%c", (ch
>= 0x20 && ch
<= 0x7F) ? ch
: '.');
1708 if (((LPMIDIEVENT
)lpData
)->dwStreamID
!= 0 &&
1709 ((LPMIDIEVENT
)lpData
)->dwStreamID
!= 0xFFFFFFFF &&
1710 ((LPMIDIEVENT
)lpData
)->dwStreamID
!= (DWORD
)lpMidiStrm
) {
1711 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
1712 (lpMidiHdr
->dwFlags
& MHDR_ISSTRM
) ? "stream" : "regular",
1713 ((LPMIDIEVENT
)lpData
)->dwStreamID
);
1714 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
1715 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1717 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1718 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_DONE
,
1719 lpwm
->mod
.dwInstance
, (DWORD
)lpMidiHdr
, 0L);
1723 for (lpmh
= &lpMidiStrm
->lpMidiHdr
; *lpmh
; lpmh
= (LPMIDIHDR
*)&((*lpmh
)->lpNext
));
1725 lpMidiHdr
= (LPMIDIHDR
)msg
->lParam
;
1726 lpMidiHdr
->lpNext
= 0;
1727 lpMidiHdr
->dwFlags
|= MHDR_INQUEUE
;
1728 lpMidiHdr
->dwFlags
&= MHDR_DONE
;
1729 lpMidiHdr
->dwOffset
= 0;
1733 FIXME("Unknown message %d\n", msg
->message
);
1739 /**************************************************************************
1740 * MMSYSTEM_MidiStream_Player [internal]
1742 static DWORD CALLBACK
MMSYSTEM_MidiStream_Player(LPVOID pmt
)
1744 WINE_MIDIStream
* lpMidiStrm
= pmt
;
1749 LPMIDIHDR lpMidiHdr
;
1753 TRACE("(%p)!\n", lpMidiStrm
);
1756 (lpwm
= (LPWINE_MIDI
)MMDRV_Get(lpMidiStrm
->hDevice
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1759 /* force thread's queue creation */
1760 /* Used to be InitThreadInput16(0, 5); */
1761 /* but following works also with hack in midiStreamOpen */
1762 PeekMessageA(&msg
, 0, 0, 0, 0);
1764 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
1765 SetEvent(lpMidiStrm
->hEvent
);
1766 TRACE("Ready to go 1\n");
1767 /* thread is started in paused mode */
1768 SuspendThread(lpMidiStrm
->hThread
);
1769 TRACE("Ready to go 2\n");
1771 lpMidiStrm
->dwStartTicks
= 0;
1772 lpMidiStrm
->dwPulses
= 0;
1774 lpMidiStrm
->lpMidiHdr
= 0;
1777 lpMidiHdr
= lpMidiStrm
->lpMidiHdr
;
1779 /* for first message, block until one arrives, then process all that are available */
1780 GetMessageA(&msg
, 0, 0, 0);
1782 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm
, lpwm
, &msg
))
1784 } while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
));
1790 lpData
= lpMidiHdr
->lpData
;
1792 me
= (LPMIDIEVENT
)(lpData
+ lpMidiHdr
->dwOffset
);
1794 /* do we have to wait ? */
1795 if (me
->dwDeltaTime
) {
1796 lpMidiStrm
->dwPositionMS
+= MMSYSTEM_MidiStream_Convert(lpMidiStrm
, me
->dwDeltaTime
);
1797 lpMidiStrm
->dwPulses
+= me
->dwDeltaTime
;
1799 dwToGo
= lpMidiStrm
->dwStartTicks
+ lpMidiStrm
->dwPositionMS
;
1801 TRACE("%ld/%ld/%ld\n", dwToGo
, GetTickCount(), me
->dwDeltaTime
);
1802 while ((dwCurrTC
= GetTickCount()) < dwToGo
) {
1803 if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, dwToGo
- dwCurrTC
, QS_ALLINPUT
) == WAIT_OBJECT_0
) {
1804 /* got a message, handle it */
1805 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) {
1806 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm
, lpwm
, &msg
))
1811 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
1816 switch (MEVT_EVENTTYPE(me
->dwEvent
& ~MEVT_F_CALLBACK
)) {
1818 FIXME("NIY: MEVT_COMMENT\n");
1819 /* do nothing, skip bytes */
1822 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
1827 midiOutShortMsg(lpMidiStrm
->hDevice
, MEVT_EVENTPARM(me
->dwEvent
));
1830 lpMidiStrm
->dwTempo
= MEVT_EVENTPARM(me
->dwEvent
);
1835 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me
->dwEvent
& ~MEVT_F_CALLBACK
));
1838 if (me
->dwEvent
& MEVT_F_CALLBACK
) {
1839 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1840 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_POSITIONCB
,
1841 lpwm
->mod
.dwInstance
, (LPARAM
)lpMidiHdr
, 0L);
1843 lpMidiHdr
->dwOffset
+= sizeof(MIDIEVENT
) - sizeof(me
->dwParms
);
1844 if (me
->dwEvent
& MEVT_F_LONG
)
1845 lpMidiHdr
->dwOffset
+= (MEVT_EVENTPARM(me
->dwEvent
) + 3) & ~3;
1846 if (lpMidiHdr
->dwOffset
>= lpMidiHdr
->dwBufferLength
) {
1847 /* done with this header */
1848 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
1849 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1851 lpMidiStrm
->lpMidiHdr
= (LPMIDIHDR
)lpMidiHdr
->lpNext
;
1852 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1853 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_DONE
,
1854 lpwm
->mod
.dwInstance
, (DWORD
)lpMidiHdr
, 0L);
1859 TRACE("End of thread\n");
1861 return 0; /* for removing the warning, never executed */
1864 /**************************************************************************
1865 * MMSYSTEM_MidiStream_PostMessage [internal]
1867 static BOOL
MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream
* lpMidiStrm
, WORD msg
, DWORD pmt1
, DWORD pmt2
)
1869 if (PostThreadMessageA(lpMidiStrm
->dwThreadID
, msg
, pmt1
, pmt2
)) {
1872 ReleaseThunkLock(&count
);
1873 WaitForSingleObject(lpMidiStrm
->hEvent
, INFINITE
);
1874 RestoreThunkLock(count
);
1876 WARN("bad PostThreadMessageA\n");
1882 /**************************************************************************
1883 * midiStreamClose [WINMM.@]
1885 MMRESULT WINAPI
midiStreamClose(HMIDISTRM hMidiStrm
)
1887 WINE_MIDIStream
* lpMidiStrm
;
1889 TRACE("(%p)!\n", hMidiStrm
);
1891 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
))
1892 return MMSYSERR_INVALHANDLE
;
1894 midiStreamStop(hMidiStrm
);
1895 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm
, WM_QUIT
, 0, 0);
1896 HeapFree(GetProcessHeap(), 0, lpMidiStrm
);
1897 CloseHandle(lpMidiStrm
->hEvent
);
1899 return midiOutClose((HMIDIOUT
)hMidiStrm
);
1902 /**************************************************************************
1903 * MMSYSTEM_MidiStream_Open [internal]
1905 MMRESULT
MIDI_StreamOpen(HMIDISTRM
* lphMidiStrm
, LPUINT lpuDeviceID
, DWORD cMidi
,
1906 DWORD dwCallback
, DWORD dwInstance
, DWORD fdwOpen
,
1909 WINE_MIDIStream
* lpMidiStrm
;
1911 MIDIOPENSTRMID mosm
;
1915 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
1916 lphMidiStrm
, lpuDeviceID
, cMidi
, dwCallback
, dwInstance
, fdwOpen
);
1918 if (cMidi
!= 1 || lphMidiStrm
== NULL
|| lpuDeviceID
== NULL
)
1919 return MMSYSERR_INVALPARAM
;
1921 lpMidiStrm
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream
));
1923 return MMSYSERR_NOMEM
;
1925 lpMidiStrm
->dwTempo
= 500000;
1926 lpMidiStrm
->dwTimeDiv
= 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
1927 lpMidiStrm
->dwPositionMS
= 0;
1929 mosm
.dwStreamID
= (DWORD
)lpMidiStrm
;
1930 /* FIXME: the correct value is not allocated yet for MAPPER */
1931 mosm
.wDeviceID
= *lpuDeviceID
;
1932 lpwm
= MIDI_OutAlloc(&hMidiOut
, &dwCallback
, &dwInstance
, &fdwOpen
, 1, &mosm
, bFrom32
);
1933 lpMidiStrm
->hDevice
= hMidiOut
;
1935 *lphMidiStrm
= (HMIDISTRM
)hMidiOut
;
1937 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
1938 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID
);
1939 lpwm
->mld
.uDeviceID
= *lpuDeviceID
= 0;
1941 ret
= MMDRV_Open(&lpwm
->mld
, MODM_OPEN
, (DWORD
)&lpwm
->mod
, fdwOpen
);
1942 lpMidiStrm
->hEvent
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
1943 lpMidiStrm
->wFlags
= HIWORD(fdwOpen
);
1945 lpMidiStrm
->hThread
= CreateThread(NULL
, 0, MMSYSTEM_MidiStream_Player
,
1946 lpMidiStrm
, 0, &(lpMidiStrm
->dwThreadID
));
1948 if (!lpMidiStrm
->hThread
) {
1949 midiStreamClose((HMIDISTRM
)hMidiOut
);
1950 return MMSYSERR_NOMEM
;
1953 /* wait for thread to have started, and for its queue to be created */
1957 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
1958 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
1959 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
1961 ReleaseThunkLock(&count
);
1962 WaitForSingleObject(lpMidiStrm
->hEvent
, INFINITE
);
1963 RestoreThunkLock(count
);
1966 TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n",
1967 *lpuDeviceID
, lpwm
->mld
.uDeviceID
, *lphMidiStrm
, ret
, lpMidiStrm
);
1971 /**************************************************************************
1972 * midiStreamOpen [WINMM.@]
1974 MMRESULT WINAPI
midiStreamOpen(HMIDISTRM
* lphMidiStrm
, LPUINT lpuDeviceID
,
1975 DWORD cMidi
, DWORD dwCallback
,
1976 DWORD dwInstance
, DWORD fdwOpen
)
1978 return MIDI_StreamOpen(lphMidiStrm
, lpuDeviceID
, cMidi
, dwCallback
,
1979 dwInstance
, fdwOpen
, TRUE
);
1982 /**************************************************************************
1983 * midiStreamOut [WINMM.@]
1985 MMRESULT WINAPI
midiStreamOut(HMIDISTRM hMidiStrm
, LPMIDIHDR lpMidiHdr
,
1988 WINE_MIDIStream
* lpMidiStrm
;
1989 DWORD ret
= MMSYSERR_NOERROR
;
1991 TRACE("(%p, %p, %u)!\n", hMidiStrm
, lpMidiHdr
, cbMidiHdr
);
1993 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
1994 ret
= MMSYSERR_INVALHANDLE
;
1995 } else if (!lpMidiHdr
) {
1996 ret
= MMSYSERR_INVALPARAM
;
1998 if (!PostThreadMessageA(lpMidiStrm
->dwThreadID
,
1999 WINE_MSM_HEADER
, cbMidiHdr
,
2000 (DWORD
)lpMidiHdr
)) {
2001 WARN("bad PostThreadMessageA\n");
2002 ret
= MMSYSERR_ERROR
;
2008 /**************************************************************************
2009 * midiStreamPause [WINMM.@]
2011 MMRESULT WINAPI
midiStreamPause(HMIDISTRM hMidiStrm
)
2013 WINE_MIDIStream
* lpMidiStrm
;
2014 DWORD ret
= MMSYSERR_NOERROR
;
2016 TRACE("(%p)!\n", hMidiStrm
);
2018 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2019 ret
= MMSYSERR_INVALHANDLE
;
2021 if (SuspendThread(lpMidiStrm
->hThread
) == 0xFFFFFFFF) {
2022 WARN("bad Suspend (%ld)\n", GetLastError());
2023 ret
= MMSYSERR_ERROR
;
2029 /**************************************************************************
2030 * midiStreamPosition [WINMM.@]
2032 MMRESULT WINAPI
midiStreamPosition(HMIDISTRM hMidiStrm
, LPMMTIME lpMMT
, UINT cbmmt
)
2034 WINE_MIDIStream
* lpMidiStrm
;
2035 DWORD ret
= MMSYSERR_NOERROR
;
2037 TRACE("(%p, %p, %u)!\n", hMidiStrm
, lpMMT
, cbmmt
);
2039 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2040 ret
= MMSYSERR_INVALHANDLE
;
2041 } else if (lpMMT
== NULL
|| cbmmt
!= sizeof(MMTIME
)) {
2042 ret
= MMSYSERR_INVALPARAM
;
2044 switch (lpMMT
->wType
) {
2046 lpMMT
->u
.ms
= lpMidiStrm
->dwPositionMS
;
2047 TRACE("=> %ld ms\n", lpMMT
->u
.ms
);
2050 lpMMT
->u
.ticks
= lpMidiStrm
->dwPulses
;
2051 TRACE("=> %ld ticks\n", lpMMT
->u
.ticks
);
2054 WARN("Unsupported time type %d\n", lpMMT
->wType
);
2055 lpMMT
->wType
= TIME_MS
;
2056 ret
= MMSYSERR_INVALPARAM
;
2063 /**************************************************************************
2064 * midiStreamProperty [WINMM.@]
2066 MMRESULT WINAPI
midiStreamProperty(HMIDISTRM hMidiStrm
, LPBYTE lpPropData
, DWORD dwProperty
)
2068 WINE_MIDIStream
* lpMidiStrm
;
2069 MMRESULT ret
= MMSYSERR_NOERROR
;
2071 TRACE("(%p, %p, %lx)\n", hMidiStrm
, lpPropData
, dwProperty
);
2073 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2074 ret
= MMSYSERR_INVALHANDLE
;
2075 } else if ((dwProperty
& (MIDIPROP_GET
|MIDIPROP_SET
)) == 0) {
2076 ret
= MMSYSERR_INVALPARAM
;
2077 } else if (dwProperty
& MIDIPROP_TEMPO
) {
2078 MIDIPROPTEMPO
* mpt
= (MIDIPROPTEMPO
*)lpPropData
;
2080 if (sizeof(MIDIPROPTEMPO
) != mpt
->cbStruct
) {
2081 ret
= MMSYSERR_INVALPARAM
;
2082 } else if (dwProperty
& MIDIPROP_SET
) {
2083 lpMidiStrm
->dwTempo
= mpt
->dwTempo
;
2084 TRACE("Setting tempo to %ld\n", mpt
->dwTempo
);
2085 } else if (dwProperty
& MIDIPROP_GET
) {
2086 mpt
->dwTempo
= lpMidiStrm
->dwTempo
;
2087 TRACE("Getting tempo <= %ld\n", mpt
->dwTempo
);
2089 } else if (dwProperty
& MIDIPROP_TIMEDIV
) {
2090 MIDIPROPTIMEDIV
* mptd
= (MIDIPROPTIMEDIV
*)lpPropData
;
2092 if (sizeof(MIDIPROPTIMEDIV
) != mptd
->cbStruct
) {
2093 ret
= MMSYSERR_INVALPARAM
;
2094 } else if (dwProperty
& MIDIPROP_SET
) {
2095 lpMidiStrm
->dwTimeDiv
= mptd
->dwTimeDiv
;
2096 TRACE("Setting time div to %ld\n", mptd
->dwTimeDiv
);
2097 } else if (dwProperty
& MIDIPROP_GET
) {
2098 mptd
->dwTimeDiv
= lpMidiStrm
->dwTimeDiv
;
2099 TRACE("Getting time div <= %ld\n", mptd
->dwTimeDiv
);
2102 ret
= MMSYSERR_INVALPARAM
;
2108 /**************************************************************************
2109 * midiStreamRestart [WINMM.@]
2111 MMRESULT WINAPI
midiStreamRestart(HMIDISTRM hMidiStrm
)
2113 WINE_MIDIStream
* lpMidiStrm
;
2114 MMRESULT ret
= MMSYSERR_NOERROR
;
2116 TRACE("(%p)!\n", hMidiStrm
);
2118 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2119 ret
= MMSYSERR_INVALHANDLE
;
2123 /* since we increase the thread suspend count on each midiStreamPause
2124 * there may be a need for several midiStreamResume
2127 ret
= ResumeThread(lpMidiStrm
->hThread
);
2128 } while (ret
!= 0xFFFFFFFF && ret
!= 0);
2129 if (ret
== 0xFFFFFFFF) {
2130 WARN("bad Resume (%ld)\n", GetLastError());
2131 ret
= MMSYSERR_ERROR
;
2133 lpMidiStrm
->dwStartTicks
= GetTickCount() - lpMidiStrm
->dwPositionMS
;
2139 /**************************************************************************
2140 * midiStreamStop [WINMM.@]
2142 MMRESULT WINAPI
midiStreamStop(HMIDISTRM hMidiStrm
)
2144 WINE_MIDIStream
* lpMidiStrm
;
2145 MMRESULT ret
= MMSYSERR_NOERROR
;
2147 TRACE("(%p)!\n", hMidiStrm
);
2149 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2150 ret
= MMSYSERR_INVALHANDLE
;
2152 /* in case stream has been paused... FIXME is the current state correct ? */
2153 midiStreamRestart(hMidiStrm
);
2154 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm
, WINE_MSM_STOP
, 0, 0);
2159 UINT
WAVE_Open(HANDLE
* lphndl
, UINT uDeviceID
, UINT uType
,
2160 const LPWAVEFORMATEX lpFormat
, DWORD dwCallback
,
2161 DWORD dwInstance
, DWORD dwFlags
, BOOL bFrom32
)
2165 DWORD dwRet
= MMSYSERR_NOERROR
;
2168 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2169 lphndl
, (int)uDeviceID
, (uType
==MMDRV_WAVEOUT
)?"Out":"In", lpFormat
, dwCallback
,
2170 dwInstance
, dwFlags
, bFrom32
?32:16);
2172 if (dwFlags
& WAVE_FORMAT_QUERY
) TRACE("WAVE_FORMAT_QUERY requested !\n");
2174 if (lpFormat
== NULL
) return WAVERR_BADFORMAT
;
2175 if ((dwFlags
& WAVE_MAPPED
) && (uDeviceID
== (UINT
)-1))
2176 return MMSYSERR_INVALPARAM
;
2178 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
2179 lpFormat
->wFormatTag
, lpFormat
->nChannels
, lpFormat
->nSamplesPerSec
,
2180 lpFormat
->nAvgBytesPerSec
, lpFormat
->nBlockAlign
, lpFormat
->wBitsPerSample
, lpFormat
->cbSize
);
2182 if ((wmld
= MMDRV_Alloc(sizeof(WINE_WAVE
), uType
, &handle
,
2183 &dwFlags
, &dwCallback
, &dwInstance
, bFrom32
)) == NULL
)
2184 return MMSYSERR_NOMEM
;
2187 wod
.lpFormat
= lpFormat
; /* should the struct be copied iso pointer? */
2188 wod
.dwCallback
= dwCallback
;
2189 wod
.dwInstance
= dwInstance
;
2192 TRACE("cb=%08lx\n", wod
.dwCallback
);
2195 if (dwFlags
& WAVE_MAPPED
) {
2196 wod
.uMappedDeviceID
= uDeviceID
;
2197 uDeviceID
= WAVE_MAPPER
;
2199 wod
.uMappedDeviceID
= -1;
2201 wmld
->uDeviceID
= uDeviceID
;
2203 dwRet
= MMDRV_Open(wmld
, (uType
== MMDRV_WAVEOUT
) ? WODM_OPEN
: WIDM_OPEN
,
2204 (DWORD
)&wod
, dwFlags
);
2206 if (dwRet
!= WAVERR_BADFORMAT
||
2207 (dwFlags
& (WAVE_MAPPED
|WAVE_FORMAT_DIRECT
)) != 0) break;
2208 /* if we ask for a format which isn't supported by the physical driver,
2209 * let's try to map it through the wave mapper (except, if we already tried
2210 * or user didn't allow us to use acm codecs)
2212 dwFlags
|= WAVE_MAPPED
;
2213 /* we shall loop only one */
2216 if ((dwFlags
& WAVE_FORMAT_QUERY
) || dwRet
!= MMSYSERR_NOERROR
) {
2217 MMDRV_Free(handle
, wmld
);
2221 if (lphndl
!= NULL
) *lphndl
= handle
;
2222 TRACE("=> %ld hWave=%p\n", dwRet
, handle
);
2227 /**************************************************************************
2228 * waveOutGetNumDevs [WINMM.@]
2230 UINT WINAPI
waveOutGetNumDevs(void)
2232 return MMDRV_GetNum(MMDRV_WAVEOUT
);
2235 /**************************************************************************
2236 * waveOutGetDevCapsA [WINMM.@]
2238 UINT WINAPI
waveOutGetDevCapsA(UINT uDeviceID
, LPWAVEOUTCAPSA lpCaps
,
2243 TRACE("(%u %p %u)!\n", uDeviceID
, lpCaps
, uSize
);
2245 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
2247 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_WAVEOUT
, TRUE
)) == NULL
)
2248 return MMSYSERR_BADDEVICEID
;
2250 return MMDRV_Message(wmld
, WODM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
2254 /**************************************************************************
2255 * waveOutGetDevCapsW [WINMM.@]
2257 UINT WINAPI
waveOutGetDevCapsW(UINT uDeviceID
, LPWAVEOUTCAPSW lpCaps
,
2263 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
2265 ret
= waveOutGetDevCapsA(uDeviceID
, &wocA
, sizeof(wocA
));
2267 if (ret
== MMSYSERR_NOERROR
) {
2268 lpCaps
->wMid
= wocA
.wMid
;
2269 lpCaps
->wPid
= wocA
.wPid
;
2270 lpCaps
->vDriverVersion
= wocA
.vDriverVersion
;
2271 MultiByteToWideChar( CP_ACP
, 0, wocA
.szPname
, -1, lpCaps
->szPname
,
2272 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
2273 lpCaps
->dwFormats
= wocA
.dwFormats
;
2274 lpCaps
->wChannels
= wocA
.wChannels
;
2275 lpCaps
->dwSupport
= wocA
.dwSupport
;
2280 /**************************************************************************
2281 * WAVE_GetErrorText [internal]
2283 static UINT16
WAVE_GetErrorText(UINT16 uError
, LPSTR lpText
, UINT16 uSize
)
2285 UINT16 ret
= MMSYSERR_BADERRNUM
;
2287 if (lpText
== NULL
) {
2288 ret
= MMSYSERR_INVALPARAM
;
2289 } else if (uSize
== 0) {
2290 ret
= MMSYSERR_NOERROR
;
2292 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2293 * a warning for the test was always true */
2294 (/*uError >= MMSYSERR_BASE && */uError
<= MMSYSERR_LASTERROR
) ||
2295 (uError
>= WAVERR_BASE
&& uError
<= WAVERR_LASTERROR
)) {
2297 if (LoadStringA(WINMM_IData
->hWinMM32Instance
,
2298 uError
, lpText
, uSize
) > 0) {
2299 ret
= MMSYSERR_NOERROR
;
2305 /**************************************************************************
2306 * waveOutGetErrorTextA [WINMM.@]
2308 UINT WINAPI
waveOutGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
2310 return WAVE_GetErrorText(uError
, lpText
, uSize
);
2313 /**************************************************************************
2314 * waveOutGetErrorTextW [WINMM.@]
2316 UINT WINAPI
waveOutGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
2318 LPSTR xstr
= HeapAlloc(GetProcessHeap(), 0, uSize
);
2319 UINT ret
= WAVE_GetErrorText(uError
, xstr
, uSize
);
2321 MultiByteToWideChar( CP_ACP
, 0, xstr
, -1, lpText
, uSize
);
2322 HeapFree(GetProcessHeap(), 0, xstr
);
2326 /**************************************************************************
2327 * waveOutOpen [WINMM.@]
2328 * All the args/structs have the same layout as the win16 equivalents
2330 UINT WINAPI
waveOutOpen(HWAVEOUT
* lphWaveOut
, UINT uDeviceID
,
2331 const LPWAVEFORMATEX lpFormat
, DWORD dwCallback
,
2332 DWORD dwInstance
, DWORD dwFlags
)
2334 return WAVE_Open((HANDLE
*)lphWaveOut
, uDeviceID
, MMDRV_WAVEOUT
, lpFormat
,
2335 dwCallback
, dwInstance
, dwFlags
, TRUE
);
2338 /**************************************************************************
2339 * waveOutClose [WINMM.@]
2341 UINT WINAPI
waveOutClose(HWAVEOUT hWaveOut
)
2346 TRACE("(%p)\n", hWaveOut
);
2348 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2349 return MMSYSERR_INVALHANDLE
;
2351 dwRet
= MMDRV_Close(wmld
, WODM_CLOSE
);
2352 MMDRV_Free(hWaveOut
, wmld
);
2357 /**************************************************************************
2358 * waveOutPrepareHeader [WINMM.@]
2360 UINT WINAPI
waveOutPrepareHeader(HWAVEOUT hWaveOut
,
2361 WAVEHDR
* lpWaveOutHdr
, UINT uSize
)
2365 TRACE("(%p, %p, %u);\n", hWaveOut
, lpWaveOutHdr
, uSize
);
2367 if (lpWaveOutHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2369 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2370 return MMSYSERR_INVALHANDLE
;
2372 return MMDRV_Message(wmld
, WODM_PREPARE
, (DWORD
)lpWaveOutHdr
, uSize
, TRUE
);
2375 /**************************************************************************
2376 * waveOutUnprepareHeader [WINMM.@]
2378 UINT WINAPI
waveOutUnprepareHeader(HWAVEOUT hWaveOut
,
2379 LPWAVEHDR lpWaveOutHdr
, UINT uSize
)
2383 TRACE("(%p, %p, %u);\n", hWaveOut
, lpWaveOutHdr
, uSize
);
2385 if (!(lpWaveOutHdr
->dwFlags
& WHDR_PREPARED
)) {
2386 return MMSYSERR_NOERROR
;
2389 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2390 return MMSYSERR_INVALHANDLE
;
2392 return MMDRV_Message(wmld
, WODM_UNPREPARE
, (DWORD
)lpWaveOutHdr
, uSize
, TRUE
);
2395 /**************************************************************************
2396 * waveOutWrite [WINMM.@]
2398 UINT WINAPI
waveOutWrite(HWAVEOUT hWaveOut
, LPWAVEHDR lpWaveOutHdr
,
2403 TRACE("(%p, %p, %u);\n", hWaveOut
, lpWaveOutHdr
, uSize
);
2405 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2406 return MMSYSERR_INVALHANDLE
;
2408 return MMDRV_Message(wmld
, WODM_WRITE
, (DWORD
)lpWaveOutHdr
, uSize
, TRUE
);
2411 /**************************************************************************
2412 * waveOutBreakLoop [WINMM.@]
2414 UINT WINAPI
waveOutBreakLoop(HWAVEOUT hWaveOut
)
2418 TRACE("(%p);\n", hWaveOut
);
2420 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2421 return MMSYSERR_INVALHANDLE
;
2422 return MMDRV_Message(wmld
, WODM_BREAKLOOP
, 0L, 0L, TRUE
);
2425 /**************************************************************************
2426 * waveOutPause [WINMM.@]
2428 UINT WINAPI
waveOutPause(HWAVEOUT hWaveOut
)
2432 TRACE("(%p);\n", hWaveOut
);
2434 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2435 return MMSYSERR_INVALHANDLE
;
2436 return MMDRV_Message(wmld
, WODM_PAUSE
, 0L, 0L, TRUE
);
2439 /**************************************************************************
2440 * waveOutReset [WINMM.@]
2442 UINT WINAPI
waveOutReset(HWAVEOUT hWaveOut
)
2446 TRACE("(%p);\n", hWaveOut
);
2448 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2449 return MMSYSERR_INVALHANDLE
;
2450 return MMDRV_Message(wmld
, WODM_RESET
, 0L, 0L, TRUE
);
2453 /**************************************************************************
2454 * waveOutRestart [WINMM.@]
2456 UINT WINAPI
waveOutRestart(HWAVEOUT hWaveOut
)
2460 TRACE("(%p);\n", hWaveOut
);
2462 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2463 return MMSYSERR_INVALHANDLE
;
2464 return MMDRV_Message(wmld
, WODM_RESTART
, 0L, 0L, TRUE
);
2467 /**************************************************************************
2468 * waveOutGetPosition [WINMM.@]
2470 UINT WINAPI
waveOutGetPosition(HWAVEOUT hWaveOut
, LPMMTIME lpTime
,
2475 TRACE("(%p, %p, %u);\n", hWaveOut
, lpTime
, uSize
);
2477 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2478 return MMSYSERR_INVALHANDLE
;
2480 return MMDRV_Message(wmld
, WODM_GETPOS
, (DWORD
)lpTime
, uSize
, TRUE
);
2483 /**************************************************************************
2484 * waveOutGetPitch [WINMM.@]
2486 UINT WINAPI
waveOutGetPitch(HWAVEOUT hWaveOut
, LPDWORD lpdw
)
2490 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)lpdw
);
2492 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2493 return MMSYSERR_INVALHANDLE
;
2494 return MMDRV_Message(wmld
, WODM_GETPITCH
, (DWORD
)lpdw
, 0L, TRUE
);
2497 /**************************************************************************
2498 * waveOutSetPitch [WINMM.@]
2500 UINT WINAPI
waveOutSetPitch(HWAVEOUT hWaveOut
, DWORD dw
)
2504 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)dw
);
2506 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2507 return MMSYSERR_INVALHANDLE
;
2508 return MMDRV_Message(wmld
, WODM_SETPITCH
, dw
, 0L, TRUE
);
2511 /**************************************************************************
2512 * waveOutGetPlaybackRate [WINMM.@]
2514 UINT WINAPI
waveOutGetPlaybackRate(HWAVEOUT hWaveOut
, LPDWORD lpdw
)
2518 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)lpdw
);
2520 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2521 return MMSYSERR_INVALHANDLE
;
2522 return MMDRV_Message(wmld
, WODM_GETPLAYBACKRATE
, (DWORD
)lpdw
, 0L, TRUE
);
2525 /**************************************************************************
2526 * waveOutSetPlaybackRate [WINMM.@]
2528 UINT WINAPI
waveOutSetPlaybackRate(HWAVEOUT hWaveOut
, DWORD dw
)
2532 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)dw
);
2534 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2535 return MMSYSERR_INVALHANDLE
;
2536 return MMDRV_Message(wmld
, WODM_SETPLAYBACKRATE
, dw
, 0L, TRUE
);
2539 /**************************************************************************
2540 * waveOutGetVolume [WINMM.@]
2542 UINT WINAPI
waveOutGetVolume(HWAVEOUT hWaveOut
, LPDWORD lpdw
)
2546 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)lpdw
);
2548 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, TRUE
)) == NULL
)
2549 return MMSYSERR_INVALHANDLE
;
2551 return MMDRV_Message(wmld
, WODM_GETVOLUME
, (DWORD
)lpdw
, 0L, TRUE
);
2554 /**************************************************************************
2555 * waveOutSetVolume [WINMM.@]
2557 UINT WINAPI
waveOutSetVolume(HWAVEOUT hWaveOut
, DWORD dw
)
2561 TRACE("(%p, %08lx);\n", hWaveOut
, dw
);
2563 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, TRUE
)) == NULL
)
2564 return MMSYSERR_INVALHANDLE
;
2566 return MMDRV_Message(wmld
, WODM_SETVOLUME
, dw
, 0L, TRUE
);
2569 /**************************************************************************
2570 * waveOutGetID [WINMM.@]
2572 UINT WINAPI
waveOutGetID(HWAVEOUT hWaveOut
, UINT
* lpuDeviceID
)
2576 TRACE("(%p, %p);\n", hWaveOut
, lpuDeviceID
);
2578 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALHANDLE
;
2580 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2581 return MMSYSERR_INVALHANDLE
;
2583 *lpuDeviceID
= wmld
->uDeviceID
;
2587 /**************************************************************************
2588 * waveOutMessage [WINMM.@]
2590 DWORD WINAPI
waveOutMessage(HWAVEOUT hWaveOut
, UINT uMessage
,
2591 DWORD dwParam1
, DWORD dwParam2
)
2595 TRACE("(%p, %u, %ld, %ld)\n", hWaveOut
, uMessage
, dwParam1
, dwParam2
);
2597 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
) {
2598 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, TRUE
)) != NULL
) {
2599 return MMDRV_PhysicalFeatures(wmld
, uMessage
, dwParam1
, dwParam2
);
2601 return MMSYSERR_INVALHANDLE
;
2605 if (uMessage
< DRVM_IOCTL
|| (uMessage
>= DRVM_IOCTL_LAST
&& uMessage
< DRVM_MAPPER
))
2606 return MMSYSERR_INVALPARAM
;
2608 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
2611 /**************************************************************************
2612 * waveInGetNumDevs [WINMM.@]
2614 UINT WINAPI
waveInGetNumDevs(void)
2616 return MMDRV_GetNum(MMDRV_WAVEIN
);
2619 /**************************************************************************
2620 * waveInGetDevCapsW [WINMM.@]
2622 UINT WINAPI
waveInGetDevCapsW(UINT uDeviceID
, LPWAVEINCAPSW lpCaps
, UINT uSize
)
2625 UINT ret
= waveInGetDevCapsA(uDeviceID
, &wicA
, uSize
);
2627 if (ret
== MMSYSERR_NOERROR
) {
2628 lpCaps
->wMid
= wicA
.wMid
;
2629 lpCaps
->wPid
= wicA
.wPid
;
2630 lpCaps
->vDriverVersion
= wicA
.vDriverVersion
;
2631 MultiByteToWideChar( CP_ACP
, 0, wicA
.szPname
, -1, lpCaps
->szPname
,
2632 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
2633 lpCaps
->dwFormats
= wicA
.dwFormats
;
2634 lpCaps
->wChannels
= wicA
.wChannels
;
2640 /**************************************************************************
2641 * waveInGetDevCapsA [WINMM.@]
2643 UINT WINAPI
waveInGetDevCapsA(UINT uDeviceID
, LPWAVEINCAPSA lpCaps
, UINT uSize
)
2647 TRACE("(%u %p %u)!\n", uDeviceID
, lpCaps
, uSize
);
2649 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_WAVEIN
, TRUE
)) == NULL
)
2650 return MMSYSERR_BADDEVICEID
;
2652 return MMDRV_Message(wmld
, WIDM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
2655 /**************************************************************************
2656 * waveInGetErrorTextA [WINMM.@]
2658 UINT WINAPI
waveInGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
2660 return WAVE_GetErrorText(uError
, lpText
, uSize
);
2663 /**************************************************************************
2664 * waveInGetErrorTextW [WINMM.@]
2666 UINT WINAPI
waveInGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
2668 LPSTR txt
= HeapAlloc(GetProcessHeap(), 0, uSize
);
2669 UINT ret
= WAVE_GetErrorText(uError
, txt
, uSize
);
2671 MultiByteToWideChar( CP_ACP
, 0, txt
, -1, lpText
, uSize
);
2672 HeapFree(GetProcessHeap(), 0, txt
);
2676 /**************************************************************************
2677 * waveInOpen [WINMM.@]
2679 UINT WINAPI
waveInOpen(HWAVEIN
* lphWaveIn
, UINT uDeviceID
,
2680 const LPWAVEFORMATEX lpFormat
, DWORD dwCallback
,
2681 DWORD dwInstance
, DWORD dwFlags
)
2683 return WAVE_Open((HANDLE
*)lphWaveIn
, uDeviceID
, MMDRV_WAVEIN
, lpFormat
,
2684 dwCallback
, dwInstance
, dwFlags
, TRUE
);
2687 /**************************************************************************
2688 * waveInClose [WINMM.@]
2690 UINT WINAPI
waveInClose(HWAVEIN hWaveIn
)
2695 TRACE("(%p)\n", hWaveIn
);
2697 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2698 return MMSYSERR_INVALHANDLE
;
2700 dwRet
= MMDRV_Message(wmld
, WIDM_CLOSE
, 0L, 0L, TRUE
);
2701 MMDRV_Free(hWaveIn
, wmld
);
2705 /**************************************************************************
2706 * waveInPrepareHeader [WINMM.@]
2708 UINT WINAPI
waveInPrepareHeader(HWAVEIN hWaveIn
, WAVEHDR
* lpWaveInHdr
,
2713 TRACE("(%p, %p, %u);\n", hWaveIn
, lpWaveInHdr
, uSize
);
2715 if (lpWaveInHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2716 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2717 return MMSYSERR_INVALHANDLE
;
2719 lpWaveInHdr
->dwBytesRecorded
= 0;
2721 return MMDRV_Message(wmld
, WIDM_PREPARE
, (DWORD
)lpWaveInHdr
, uSize
, TRUE
);
2724 /**************************************************************************
2725 * waveInUnprepareHeader [WINMM.@]
2727 UINT WINAPI
waveInUnprepareHeader(HWAVEIN hWaveIn
, WAVEHDR
* lpWaveInHdr
,
2732 TRACE("(%p, %p, %u);\n", hWaveIn
, lpWaveInHdr
, uSize
);
2734 if (lpWaveInHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2735 if (!(lpWaveInHdr
->dwFlags
& WHDR_PREPARED
)) {
2736 return MMSYSERR_NOERROR
;
2739 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2740 return MMSYSERR_INVALHANDLE
;
2742 return MMDRV_Message(wmld
, WIDM_UNPREPARE
, (DWORD
)lpWaveInHdr
, uSize
, TRUE
);
2745 /**************************************************************************
2746 * waveInAddBuffer [WINMM.@]
2748 UINT WINAPI
waveInAddBuffer(HWAVEIN hWaveIn
,
2749 WAVEHDR
* lpWaveInHdr
, UINT uSize
)
2753 TRACE("(%p, %p, %u);\n", hWaveIn
, lpWaveInHdr
, uSize
);
2755 if (lpWaveInHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2756 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2757 return MMSYSERR_INVALHANDLE
;
2759 return MMDRV_Message(wmld
, WIDM_ADDBUFFER
, (DWORD
)lpWaveInHdr
, uSize
, TRUE
);
2762 /**************************************************************************
2763 * waveInReset [WINMM.@]
2765 UINT WINAPI
waveInReset(HWAVEIN hWaveIn
)
2769 TRACE("(%p);\n", hWaveIn
);
2771 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2772 return MMSYSERR_INVALHANDLE
;
2774 return MMDRV_Message(wmld
, WIDM_RESET
, 0L, 0L, TRUE
);
2777 /**************************************************************************
2778 * waveInStart [WINMM.@]
2780 UINT WINAPI
waveInStart(HWAVEIN hWaveIn
)
2784 TRACE("(%p);\n", hWaveIn
);
2786 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2787 return MMSYSERR_INVALHANDLE
;
2789 return MMDRV_Message(wmld
, WIDM_START
, 0L, 0L, TRUE
);
2792 /**************************************************************************
2793 * waveInStop [WINMM.@]
2795 UINT WINAPI
waveInStop(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_STOP
, 0L, 0L, TRUE
);
2807 /**************************************************************************
2808 * waveInGetPosition [WINMM.@]
2810 UINT WINAPI
waveInGetPosition(HWAVEIN hWaveIn
, LPMMTIME lpTime
,
2815 TRACE("(%p, %p, %u);\n", hWaveIn
, lpTime
, uSize
);
2817 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2818 return MMSYSERR_INVALHANDLE
;
2820 return MMDRV_Message(wmld
, WIDM_GETPOS
, (DWORD
)lpTime
, uSize
, TRUE
);
2823 /**************************************************************************
2824 * waveInGetID [WINMM.@]
2826 UINT WINAPI
waveInGetID(HWAVEIN hWaveIn
, UINT
* lpuDeviceID
)
2830 TRACE("(%p, %p);\n", hWaveIn
, lpuDeviceID
);
2832 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALHANDLE
;
2834 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2835 return MMSYSERR_INVALHANDLE
;
2837 *lpuDeviceID
= wmld
->uDeviceID
;
2838 return MMSYSERR_NOERROR
;
2841 /**************************************************************************
2842 * waveInMessage [WINMM.@]
2844 DWORD WINAPI
waveInMessage(HWAVEIN hWaveIn
, UINT uMessage
,
2845 DWORD dwParam1
, DWORD dwParam2
)
2849 TRACE("(%p, %u, %ld, %ld)\n", hWaveIn
, uMessage
, dwParam1
, dwParam2
);
2851 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
) {
2852 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, TRUE
)) != NULL
) {
2853 return MMDRV_PhysicalFeatures(wmld
, uMessage
, dwParam1
, dwParam2
);
2855 return MMSYSERR_INVALHANDLE
;
2859 if (uMessage
< DRVM_IOCTL
|| (uMessage
>= DRVM_IOCTL_LAST
&& uMessage
< DRVM_MAPPER
))
2860 return MMSYSERR_INVALPARAM
;
2863 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);