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
37 #include "wine/winuser16.h" /* FIXME: should be removed, only used for UserYield16 */
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(winmm
);
46 /* ========================================================================
47 * G L O B A L S E T T I N G S
48 * ========================================================================*/
50 LPWINE_MM_IDATA WINMM_IData
/* = NULL */;
52 /**************************************************************************
53 * WINMM_CreateIData [internal]
55 static BOOL
WINMM_CreateIData(HINSTANCE hInstDLL
)
57 WINMM_IData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WINE_MM_IDATA
));
61 WINMM_IData
->hWinMM32Instance
= hInstDLL
;
62 InitializeCriticalSection(&WINMM_IData
->cs
);
63 WINMM_IData
->cs
.DebugInfo
= (void*)__FILE__
": WinMM";
64 WINMM_IData
->psStopEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
65 WINMM_IData
->psLastEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
66 TRACE("Created IData (%p)\n", WINMM_IData
);
70 /**************************************************************************
71 * WINMM_DeleteIData [internal]
73 static void WINMM_DeleteIData(void)
78 /* FIXME: should also free content and resources allocated
79 * inside WINMM_IData */
80 CloseHandle(WINMM_IData
->psStopEvent
);
81 CloseHandle(WINMM_IData
->psLastEvent
);
82 DeleteCriticalSection(&WINMM_IData
->cs
);
83 HeapFree(GetProcessHeap(), 0, WINMM_IData
);
88 /******************************************************************
92 static HANDLE (WINAPI
*pGetModuleHandle16
)(LPCSTR
);
93 static DWORD (WINAPI
*pLoadLibrary16
)(LPCSTR
);
95 BOOL
WINMM_CheckForMMSystem(void)
97 /* 0 is not checked yet, -1 is not present, 1 is present */
98 static int loaded
/* = 0 */;
102 HANDLE h
= GetModuleHandleA("kernel32");
106 pGetModuleHandle16
= (void*)GetProcAddress(h
, "GetModuleHandle16");
107 pLoadLibrary16
= (void*)GetProcAddress(h
, "LoadLibrary16");
108 if (pGetModuleHandle16
&& pLoadLibrary16
&&
109 (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL")))
116 /**************************************************************************
117 * DllMain (WINMM.init)
119 * WINMM DLL entry point
122 BOOL WINAPI
DllMain(HINSTANCE hInstDLL
, DWORD fdwReason
, LPVOID fImpLoad
)
124 TRACE("%p 0x%lx %p\n", hInstDLL
, fdwReason
, fImpLoad
);
127 case DLL_PROCESS_ATTACH
:
128 if (!WINMM_CreateIData(hInstDLL
))
130 if (!MCI_Init() || !MMDRV_Init()) {
135 case DLL_PROCESS_DETACH
:
136 /* close all opened MCI drivers */
137 MCI_SendCommand(MCI_ALL_DEVICE_ID
, MCI_CLOSE
, MCI_WAIT
, 0L, TRUE
);
139 /* now unload all remaining drivers... */
144 case DLL_THREAD_ATTACH
:
145 case DLL_THREAD_DETACH
:
151 /**************************************************************************
152 * Mixer devices. New to Win95
155 /**************************************************************************
156 * find out the real mixer ID depending on hmix (depends on dwFlags)
158 static LPWINE_MIXER
MIXER_GetDev(HMIXEROBJ hmix
, DWORD dwFlags
)
160 LPWINE_MIXER lpwm
= NULL
;
162 switch (dwFlags
& 0xF0000000ul
) {
163 case MIXER_OBJECTF_MIXER
:
164 lpwm
= (LPWINE_MIXER
)MMDRV_Get(hmix
, MMDRV_MIXER
, TRUE
);
166 case MIXER_OBJECTF_HMIXER
:
167 lpwm
= (LPWINE_MIXER
)MMDRV_Get(hmix
, MMDRV_MIXER
, FALSE
);
169 case MIXER_OBJECTF_WAVEOUT
:
170 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEOUT
, TRUE
, MMDRV_MIXER
);
172 case MIXER_OBJECTF_HWAVEOUT
:
173 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEOUT
, FALSE
, MMDRV_MIXER
);
175 case MIXER_OBJECTF_WAVEIN
:
176 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEIN
, TRUE
, MMDRV_MIXER
);
178 case MIXER_OBJECTF_HWAVEIN
:
179 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEIN
, FALSE
, MMDRV_MIXER
);
181 case MIXER_OBJECTF_MIDIOUT
:
182 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIOUT
, TRUE
, MMDRV_MIXER
);
184 case MIXER_OBJECTF_HMIDIOUT
:
185 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIOUT
, FALSE
, MMDRV_MIXER
);
187 case MIXER_OBJECTF_MIDIIN
:
188 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIIN
, TRUE
, MMDRV_MIXER
);
190 case MIXER_OBJECTF_HMIDIIN
:
191 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIIN
, FALSE
, MMDRV_MIXER
);
193 case MIXER_OBJECTF_AUX
:
194 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_AUX
, TRUE
, MMDRV_MIXER
);
197 FIXME("Unsupported flag (%08lx)\n", dwFlags
& 0xF0000000ul
);
203 /**************************************************************************
204 * mixerGetNumDevs [WINMM.@]
206 UINT WINAPI
mixerGetNumDevs(void)
208 return MMDRV_GetNum(MMDRV_MIXER
);
211 /**************************************************************************
212 * mixerGetDevCapsA [WINMM.@]
214 UINT WINAPI
mixerGetDevCapsA(UINT devid
, LPMIXERCAPSA mixcaps
, UINT size
)
218 if ((wmld
= MMDRV_Get((HANDLE
)devid
, MMDRV_MIXER
, TRUE
)) == NULL
)
219 return MMSYSERR_BADDEVICEID
;
221 return MMDRV_Message(wmld
, MXDM_GETDEVCAPS
, (DWORD
)mixcaps
, size
, TRUE
);
224 /**************************************************************************
225 * mixerGetDevCapsW [WINMM.@]
227 UINT WINAPI
mixerGetDevCapsW(UINT devid
, LPMIXERCAPSW mixcaps
, UINT size
)
230 UINT ret
= mixerGetDevCapsA(devid
, &micA
, sizeof(micA
));
232 if (ret
== MMSYSERR_NOERROR
) {
233 mixcaps
->wMid
= micA
.wMid
;
234 mixcaps
->wPid
= micA
.wPid
;
235 mixcaps
->vDriverVersion
= micA
.vDriverVersion
;
236 MultiByteToWideChar( CP_ACP
, 0, micA
.szPname
, -1, mixcaps
->szPname
,
237 sizeof(mixcaps
->szPname
)/sizeof(WCHAR
) );
238 mixcaps
->fdwSupport
= micA
.fdwSupport
;
239 mixcaps
->cDestinations
= micA
.cDestinations
;
244 UINT
MIXER_Open(LPHMIXER lphMix
, UINT uDeviceID
, DWORD dwCallback
,
245 DWORD dwInstance
, DWORD fdwOpen
, BOOL bFrom32
)
252 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
253 lphMix
, uDeviceID
, dwCallback
, dwInstance
, fdwOpen
);
255 wmld
= MMDRV_Alloc(sizeof(WINE_MIXER
), MMDRV_MIXER
, &hMix
, &fdwOpen
,
256 &dwCallback
, &dwInstance
, bFrom32
);
258 wmld
->uDeviceID
= uDeviceID
;
259 mod
.hmx
= (HMIXEROBJ
)hMix
;
260 mod
.dwCallback
= dwCallback
;
261 mod
.dwInstance
= dwInstance
;
263 dwRet
= MMDRV_Open(wmld
, MXDM_OPEN
, (DWORD
)&mod
, fdwOpen
);
265 if (dwRet
!= MMSYSERR_NOERROR
) {
266 MMDRV_Free(hMix
, wmld
);
269 if (lphMix
) *lphMix
= hMix
;
270 TRACE("=> %ld hMixer=%p\n", dwRet
, hMix
);
275 /**************************************************************************
276 * mixerOpen [WINMM.@]
278 UINT WINAPI
mixerOpen(LPHMIXER lphMix
, UINT uDeviceID
, DWORD dwCallback
,
279 DWORD dwInstance
, DWORD fdwOpen
)
281 return MIXER_Open(lphMix
, uDeviceID
, dwCallback
, dwInstance
, fdwOpen
, TRUE
);
284 /**************************************************************************
285 * mixerClose [WINMM.@]
287 UINT WINAPI
mixerClose(HMIXER hMix
)
292 TRACE("(%p)\n", hMix
);
294 if ((wmld
= MMDRV_Get(hMix
, MMDRV_MIXER
, FALSE
)) == NULL
) return MMSYSERR_INVALHANDLE
;
296 dwRet
= MMDRV_Close(wmld
, MXDM_CLOSE
);
297 MMDRV_Free(hMix
, wmld
);
302 /**************************************************************************
303 * mixerGetID [WINMM.@]
305 UINT WINAPI
mixerGetID(HMIXEROBJ hmix
, LPUINT lpid
, DWORD fdwID
)
309 TRACE("(%p %p %08lx)\n", hmix
, lpid
, fdwID
);
311 if ((lpwm
= MIXER_GetDev(hmix
, fdwID
)) == NULL
) {
312 return MMSYSERR_INVALHANDLE
;
316 *lpid
= lpwm
->mld
.uDeviceID
;
318 return MMSYSERR_NOERROR
;
321 /**************************************************************************
322 * mixerGetControlDetailsA [WINMM.@]
324 UINT WINAPI
mixerGetControlDetailsA(HMIXEROBJ hmix
, LPMIXERCONTROLDETAILS lpmcdA
,
329 TRACE("(%p, %p, %08lx)\n", hmix
, lpmcdA
, fdwDetails
);
331 if ((lpwm
= MIXER_GetDev(hmix
, fdwDetails
)) == NULL
)
332 return MMSYSERR_INVALHANDLE
;
334 if (lpmcdA
== NULL
|| lpmcdA
->cbStruct
!= sizeof(*lpmcdA
))
335 return MMSYSERR_INVALPARAM
;
337 return MMDRV_Message(&lpwm
->mld
, MXDM_GETCONTROLDETAILS
, (DWORD
)lpmcdA
,
341 /**************************************************************************
342 * mixerGetControlDetailsW [WINMM.@]
344 UINT WINAPI
mixerGetControlDetailsW(HMIXEROBJ hmix
, LPMIXERCONTROLDETAILS lpmcd
, DWORD fdwDetails
)
346 DWORD ret
= MMSYSERR_NOTENABLED
;
348 TRACE("(%p, %p, %08lx)\n", hmix
, lpmcd
, fdwDetails
);
350 if (lpmcd
== NULL
|| lpmcd
->cbStruct
!= sizeof(*lpmcd
))
351 return MMSYSERR_INVALPARAM
;
353 switch (fdwDetails
& MIXER_GETCONTROLDETAILSF_QUERYMASK
) {
354 case MIXER_GETCONTROLDETAILSF_VALUE
:
355 /* can savely use W structure as it is, no string inside */
356 ret
= mixerGetControlDetailsA(hmix
, lpmcd
, fdwDetails
);
358 case MIXER_GETCONTROLDETAILSF_LISTTEXT
:
360 MIXERCONTROLDETAILS_LISTTEXTW
*pDetailsW
= (MIXERCONTROLDETAILS_LISTTEXTW
*)lpmcd
->paDetails
;
361 MIXERCONTROLDETAILS_LISTTEXTA
*pDetailsA
;
362 int size
= max(1, lpmcd
->cChannels
) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA
);
365 if (lpmcd
->u
.cMultipleItems
!= 0) {
366 size
*= lpmcd
->u
.cMultipleItems
;
368 pDetailsA
= (MIXERCONTROLDETAILS_LISTTEXTA
*)HeapAlloc(GetProcessHeap(), 0, size
);
369 lpmcd
->paDetails
= pDetailsA
;
370 lpmcd
->cbDetails
= sizeof(MIXERCONTROLDETAILS_LISTTEXTA
);
371 /* set up lpmcd->paDetails */
372 ret
= mixerGetControlDetailsA(hmix
, lpmcd
, fdwDetails
);
373 /* copy from lpmcd->paDetails back to paDetailsW; */
374 if(ret
== MMSYSERR_NOERROR
) {
375 for(i
=0;i
<lpmcd
->u
.cMultipleItems
*lpmcd
->cChannels
;i
++) {
376 pDetailsW
->dwParam1
= pDetailsA
->dwParam1
;
377 pDetailsW
->dwParam2
= pDetailsA
->dwParam2
;
378 MultiByteToWideChar( CP_ACP
, 0, pDetailsA
->szName
, -1,
380 sizeof(pDetailsW
->szName
)/sizeof(WCHAR
) );
384 pDetailsA
-= lpmcd
->u
.cMultipleItems
*lpmcd
->cChannels
;
385 pDetailsW
-= lpmcd
->u
.cMultipleItems
*lpmcd
->cChannels
;
387 HeapFree(GetProcessHeap(), 0, pDetailsA
);
388 lpmcd
->paDetails
= pDetailsW
;
389 lpmcd
->cbDetails
= sizeof(MIXERCONTROLDETAILS_LISTTEXTW
);
393 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails
);
399 /**************************************************************************
400 * mixerGetLineControlsA [WINMM.@]
402 UINT WINAPI
mixerGetLineControlsA(HMIXEROBJ hmix
, LPMIXERLINECONTROLSA lpmlcA
,
407 TRACE("(%p, %p, %08lx)\n", hmix
, lpmlcA
, fdwControls
);
409 if ((lpwm
= MIXER_GetDev(hmix
, fdwControls
)) == NULL
)
410 return MMSYSERR_INVALHANDLE
;
412 if (lpmlcA
== NULL
|| lpmlcA
->cbStruct
!= sizeof(*lpmlcA
))
413 return MMSYSERR_INVALPARAM
;
415 return MMDRV_Message(&lpwm
->mld
, MXDM_GETLINECONTROLS
, (DWORD
)lpmlcA
,
419 /**************************************************************************
420 * mixerGetLineControlsW [WINMM.@]
422 UINT WINAPI
mixerGetLineControlsW(HMIXEROBJ hmix
, LPMIXERLINECONTROLSW lpmlcW
,
425 MIXERLINECONTROLSA mlcA
;
429 TRACE("(%p, %p, %08lx)\n", hmix
, lpmlcW
, fdwControls
);
431 if (lpmlcW
== NULL
|| lpmlcW
->cbStruct
!= sizeof(*lpmlcW
) ||
432 lpmlcW
->cbmxctrl
!= sizeof(MIXERCONTROLW
))
433 return MMSYSERR_INVALPARAM
;
435 mlcA
.cbStruct
= sizeof(mlcA
);
436 mlcA
.dwLineID
= lpmlcW
->dwLineID
;
437 mlcA
.u
.dwControlID
= lpmlcW
->u
.dwControlID
;
438 mlcA
.u
.dwControlType
= lpmlcW
->u
.dwControlType
;
439 mlcA
.cControls
= lpmlcW
->cControls
;
440 mlcA
.cbmxctrl
= sizeof(MIXERCONTROLA
);
441 mlcA
.pamxctrl
= HeapAlloc(GetProcessHeap(), 0,
442 mlcA
.cControls
* mlcA
.cbmxctrl
);
444 ret
= mixerGetLineControlsA(hmix
, &mlcA
, fdwControls
);
446 if (ret
== MMSYSERR_NOERROR
) {
447 lpmlcW
->dwLineID
= mlcA
.dwLineID
;
448 lpmlcW
->u
.dwControlID
= mlcA
.u
.dwControlID
;
449 lpmlcW
->u
.dwControlType
= mlcA
.u
.dwControlType
;
450 lpmlcW
->cControls
= mlcA
.cControls
;
452 for (i
= 0; i
< mlcA
.cControls
; i
++) {
453 lpmlcW
->pamxctrl
[i
].cbStruct
= sizeof(MIXERCONTROLW
);
454 lpmlcW
->pamxctrl
[i
].dwControlID
= mlcA
.pamxctrl
[i
].dwControlID
;
455 lpmlcW
->pamxctrl
[i
].dwControlType
= mlcA
.pamxctrl
[i
].dwControlType
;
456 lpmlcW
->pamxctrl
[i
].fdwControl
= mlcA
.pamxctrl
[i
].fdwControl
;
457 lpmlcW
->pamxctrl
[i
].cMultipleItems
= mlcA
.pamxctrl
[i
].cMultipleItems
;
458 MultiByteToWideChar( CP_ACP
, 0, mlcA
.pamxctrl
[i
].szShortName
, -1,
459 lpmlcW
->pamxctrl
[i
].szShortName
,
460 sizeof(lpmlcW
->pamxctrl
[i
].szShortName
)/sizeof(WCHAR
) );
461 MultiByteToWideChar( CP_ACP
, 0, mlcA
.pamxctrl
[i
].szName
, -1,
462 lpmlcW
->pamxctrl
[i
].szName
,
463 sizeof(lpmlcW
->pamxctrl
[i
].szName
)/sizeof(WCHAR
) );
464 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
465 * sizeof(mlcA.pamxctrl[i].Bounds) */
466 memcpy(&lpmlcW
->pamxctrl
[i
].Bounds
, &mlcA
.pamxctrl
[i
].Bounds
,
467 sizeof(mlcA
.pamxctrl
[i
].Bounds
));
468 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
469 * sizeof(mlcA.pamxctrl[i].Metrics) */
470 memcpy(&lpmlcW
->pamxctrl
[i
].Metrics
, &mlcA
.pamxctrl
[i
].Metrics
,
471 sizeof(mlcA
.pamxctrl
[i
].Metrics
));
475 HeapFree(GetProcessHeap(), 0, mlcA
.pamxctrl
);
480 /**************************************************************************
481 * mixerGetLineInfoA [WINMM.@]
483 UINT WINAPI
mixerGetLineInfoA(HMIXEROBJ hmix
, LPMIXERLINEA lpmliW
, DWORD fdwInfo
)
487 TRACE("(%p, %p, %08lx)\n", hmix
, lpmliW
, fdwInfo
);
489 if ((lpwm
= MIXER_GetDev(hmix
, fdwInfo
)) == NULL
)
490 return MMSYSERR_INVALHANDLE
;
492 return MMDRV_Message(&lpwm
->mld
, MXDM_GETLINEINFO
, (DWORD
)lpmliW
,
496 /**************************************************************************
497 * mixerGetLineInfoW [WINMM.@]
499 UINT WINAPI
mixerGetLineInfoW(HMIXEROBJ hmix
, LPMIXERLINEW lpmliW
,
505 TRACE("(%p, %p, %08lx)\n", hmix
, lpmliW
, fdwInfo
);
507 if (lpmliW
== NULL
|| lpmliW
->cbStruct
!= sizeof(*lpmliW
))
508 return MMSYSERR_INVALPARAM
;
510 mliA
.cbStruct
= sizeof(mliA
);
511 switch (fdwInfo
& MIXER_GETLINEINFOF_QUERYMASK
) {
512 case MIXER_GETLINEINFOF_COMPONENTTYPE
:
513 mliA
.dwComponentType
= lpmliW
->dwComponentType
;
515 case MIXER_GETLINEINFOF_DESTINATION
:
516 mliA
.dwDestination
= lpmliW
->dwDestination
;
518 case MIXER_GETLINEINFOF_LINEID
:
519 mliA
.dwLineID
= lpmliW
->dwLineID
;
521 case MIXER_GETLINEINFOF_SOURCE
:
522 mliA
.dwDestination
= lpmliW
->dwDestination
;
523 mliA
.dwSource
= lpmliW
->dwSource
;
525 case MIXER_GETLINEINFOF_TARGETTYPE
:
526 mliA
.Target
.dwType
= lpmliW
->Target
.dwType
;
527 mliA
.Target
.wMid
= lpmliW
->Target
.wMid
;
528 mliA
.Target
.wPid
= lpmliW
->Target
.wPid
;
529 mliA
.Target
.vDriverVersion
= lpmliW
->Target
.vDriverVersion
;
530 WideCharToMultiByte( CP_ACP
, 0, lpmliW
->Target
.szPname
, -1, mliA
.Target
.szPname
, sizeof(mliA
.Target
.szPname
), NULL
, NULL
);
533 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo
);
536 ret
= mixerGetLineInfoA(hmix
, &mliA
, fdwInfo
);
538 lpmliW
->dwDestination
= mliA
.dwDestination
;
539 lpmliW
->dwSource
= mliA
.dwSource
;
540 lpmliW
->dwLineID
= mliA
.dwLineID
;
541 lpmliW
->fdwLine
= mliA
.fdwLine
;
542 lpmliW
->dwUser
= mliA
.dwUser
;
543 lpmliW
->dwComponentType
= mliA
.dwComponentType
;
544 lpmliW
->cChannels
= mliA
.cChannels
;
545 lpmliW
->cConnections
= mliA
.cConnections
;
546 lpmliW
->cControls
= mliA
.cControls
;
547 MultiByteToWideChar( CP_ACP
, 0, mliA
.szShortName
, -1, lpmliW
->szShortName
,
548 sizeof(lpmliW
->szShortName
)/sizeof(WCHAR
) );
549 MultiByteToWideChar( CP_ACP
, 0, mliA
.szName
, -1, lpmliW
->szName
,
550 sizeof(lpmliW
->szName
)/sizeof(WCHAR
) );
551 lpmliW
->Target
.dwType
= mliA
.Target
.dwType
;
552 lpmliW
->Target
.dwDeviceID
= mliA
.Target
.dwDeviceID
;
553 lpmliW
->Target
.wMid
= mliA
.Target
.wMid
;
554 lpmliW
->Target
.wPid
= mliA
.Target
.wPid
;
555 lpmliW
->Target
.vDriverVersion
= mliA
.Target
.vDriverVersion
;
556 MultiByteToWideChar( CP_ACP
, 0, mliA
.Target
.szPname
, -1, lpmliW
->Target
.szPname
,
557 sizeof(lpmliW
->Target
.szPname
)/sizeof(WCHAR
) );
562 /**************************************************************************
563 * mixerSetControlDetails [WINMM.@]
565 UINT WINAPI
mixerSetControlDetails(HMIXEROBJ hmix
, LPMIXERCONTROLDETAILS lpmcdA
,
570 TRACE("(%p, %p, %08lx)\n", hmix
, lpmcdA
, fdwDetails
);
572 if ((lpwm
= MIXER_GetDev(hmix
, fdwDetails
)) == NULL
)
573 return MMSYSERR_INVALHANDLE
;
575 return MMDRV_Message(&lpwm
->mld
, MXDM_SETCONTROLDETAILS
, (DWORD
)lpmcdA
,
579 /**************************************************************************
580 * mixerMessage [WINMM.@]
582 UINT WINAPI
mixerMessage(HMIXER hmix
, UINT uMsg
, DWORD dwParam1
, DWORD dwParam2
)
586 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
587 (DWORD
)hmix
, uMsg
, dwParam1
, dwParam2
);
589 if ((wmld
= MMDRV_Get(hmix
, MMDRV_MIXER
, FALSE
)) == NULL
)
590 return MMSYSERR_INVALHANDLE
;
592 return MMDRV_Message(wmld
, uMsg
, dwParam1
, dwParam2
, TRUE
);
595 /**************************************************************************
596 * auxGetNumDevs [WINMM.@]
598 UINT WINAPI
auxGetNumDevs(void)
600 return MMDRV_GetNum(MMDRV_AUX
);
603 /**************************************************************************
604 * auxGetDevCapsW [WINMM.@]
606 UINT WINAPI
auxGetDevCapsW(UINT uDeviceID
, LPAUXCAPSW lpCaps
, UINT uSize
)
609 UINT ret
= auxGetDevCapsA(uDeviceID
, &acA
, sizeof(acA
));
611 lpCaps
->wMid
= acA
.wMid
;
612 lpCaps
->wPid
= acA
.wPid
;
613 lpCaps
->vDriverVersion
= acA
.vDriverVersion
;
614 MultiByteToWideChar( CP_ACP
, 0, acA
.szPname
, -1, lpCaps
->szPname
,
615 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
616 lpCaps
->wTechnology
= acA
.wTechnology
;
617 lpCaps
->dwSupport
= acA
.dwSupport
;
621 /**************************************************************************
622 * auxGetDevCapsA [WINMM.@]
624 UINT WINAPI
auxGetDevCapsA(UINT uDeviceID
, LPAUXCAPSA lpCaps
, UINT uSize
)
628 TRACE("(%04X, %p, %d) !\n", uDeviceID
, lpCaps
, uSize
);
630 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
631 return MMSYSERR_INVALHANDLE
;
632 return MMDRV_Message(wmld
, AUXDM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
635 /**************************************************************************
636 * auxGetVolume [WINMM.@]
638 UINT WINAPI
auxGetVolume(UINT uDeviceID
, DWORD
* lpdwVolume
)
642 TRACE("(%04X, %p) !\n", uDeviceID
, lpdwVolume
);
644 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
645 return MMSYSERR_INVALHANDLE
;
646 return MMDRV_Message(wmld
, AUXDM_GETVOLUME
, (DWORD
)lpdwVolume
, 0L, TRUE
);
649 /**************************************************************************
650 * auxSetVolume [WINMM.@]
652 UINT WINAPI
auxSetVolume(UINT uDeviceID
, DWORD dwVolume
)
656 TRACE("(%04X, %lu) !\n", uDeviceID
, dwVolume
);
658 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
659 return MMSYSERR_INVALHANDLE
;
660 return MMDRV_Message(wmld
, AUXDM_SETVOLUME
, dwVolume
, 0L, TRUE
);
663 /**************************************************************************
664 * auxOutMessage [WINMM.@]
666 DWORD WINAPI
auxOutMessage(UINT uDeviceID
, UINT uMessage
, DWORD dw1
, DWORD dw2
)
670 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
671 return MMSYSERR_INVALHANDLE
;
673 return MMDRV_Message(wmld
, uMessage
, dw1
, dw2
, TRUE
);
676 /**************************************************************************
677 * mciGetErrorStringW [WINMM.@]
679 BOOL WINAPI
mciGetErrorStringW(DWORD wError
, LPWSTR lpstrBuffer
, UINT uLength
)
681 LPSTR bufstr
= HeapAlloc(GetProcessHeap(), 0, uLength
);
682 BOOL ret
= mciGetErrorStringA(wError
, bufstr
, uLength
);
684 MultiByteToWideChar( CP_ACP
, 0, bufstr
, -1, lpstrBuffer
, uLength
);
685 HeapFree(GetProcessHeap(), 0, bufstr
);
689 /**************************************************************************
690 * mciGetErrorStringA [WINMM.@]
692 BOOL WINAPI
mciGetErrorStringA(DWORD dwError
, LPSTR lpstrBuffer
, UINT uLength
)
696 if (lpstrBuffer
!= NULL
&& uLength
> 0 &&
697 dwError
>= MCIERR_BASE
&& dwError
<= MCIERR_CUSTOM_DRIVER_BASE
) {
699 if (LoadStringA(WINMM_IData
->hWinMM32Instance
,
700 dwError
, lpstrBuffer
, uLength
) > 0) {
707 /**************************************************************************
708 * mciDriverNotify [WINMM.@]
710 BOOL WINAPI
mciDriverNotify(HWND hWndCallBack
, UINT wDevID
, UINT wStatus
)
713 TRACE("(%p, %04x, %04X)\n", hWndCallBack
, wDevID
, wStatus
);
715 return PostMessageA(hWndCallBack
, MM_MCINOTIFY
, wStatus
, wDevID
);
718 /**************************************************************************
719 * mciGetDriverData [WINMM.@]
721 DWORD WINAPI
mciGetDriverData(UINT uDeviceID
)
723 LPWINE_MCIDRIVER wmd
;
725 TRACE("(%04x)\n", uDeviceID
);
727 wmd
= MCI_GetDriver(uDeviceID
);
730 WARN("Bad uDeviceID\n");
734 return wmd
->dwPrivate
;
737 /**************************************************************************
738 * mciSetDriverData [WINMM.@]
740 BOOL WINAPI
mciSetDriverData(UINT uDeviceID
, DWORD data
)
742 LPWINE_MCIDRIVER wmd
;
744 TRACE("(%04x, %08lx)\n", uDeviceID
, data
);
746 wmd
= MCI_GetDriver(uDeviceID
);
749 WARN("Bad uDeviceID\n");
753 wmd
->dwPrivate
= data
;
757 /**************************************************************************
758 * mciSendCommandA [WINMM.@]
760 DWORD WINAPI
mciSendCommandA(UINT wDevID
, UINT wMsg
, DWORD dwParam1
, DWORD dwParam2
)
764 TRACE("(%08x, %s, %08lx, %08lx)\n",
765 wDevID
, MCI_MessageToString(wMsg
), dwParam1
, dwParam2
);
767 dwRet
= MCI_SendCommand(wDevID
, wMsg
, dwParam1
, dwParam2
, TRUE
);
768 dwRet
= MCI_CleanUp(dwRet
, wMsg
, dwParam2
);
769 TRACE("=> %08lx\n", dwRet
);
773 /**************************************************************************
774 * mciSendCommandW [WINMM.@]
776 DWORD WINAPI
mciSendCommandW(UINT wDevID
, UINT wMsg
, DWORD dwParam1
, DWORD dwParam2
)
778 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
779 wDevID
, MCI_MessageToString(wMsg
), dwParam1
, dwParam2
);
780 return MCIERR_UNSUPPORTED_FUNCTION
;
783 /**************************************************************************
784 * mciGetDeviceIDA [WINMM.@]
786 UINT WINAPI
mciGetDeviceIDA(LPCSTR lpstrName
)
788 return MCI_GetDriverFromString(lpstrName
);
791 /**************************************************************************
792 * mciGetDeviceIDW [WINMM.@]
794 UINT WINAPI
mciGetDeviceIDW(LPCWSTR lpwstrName
)
799 lpstrName
= HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName
);
800 ret
= MCI_GetDriverFromString(lpstrName
);
801 HeapFree(GetProcessHeap(), 0, lpstrName
);
805 /**************************************************************************
806 * MCI_DefYieldProc [internal]
808 UINT WINAPI
MCI_DefYieldProc(MCIDEVICEID wDevID
, DWORD data
)
812 TRACE("(0x%04x, 0x%08lx)\n", wDevID
, data
);
814 if ((HIWORD(data
) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data
)) ||
815 (GetAsyncKeyState(LOWORD(data
)) & 1) == 0) {
821 msg
.hwnd
= HWND_32(HIWORD(data
));
822 while (!PeekMessageA(&msg
, msg
.hwnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_REMOVE
));
828 /**************************************************************************
829 * mciSetYieldProc [WINMM.@]
831 BOOL WINAPI
mciSetYieldProc(UINT uDeviceID
, YIELDPROC fpYieldProc
, DWORD dwYieldData
)
833 LPWINE_MCIDRIVER wmd
;
835 TRACE("(%u, %p, %08lx)\n", uDeviceID
, fpYieldProc
, dwYieldData
);
837 if (!(wmd
= MCI_GetDriver(uDeviceID
))) {
838 WARN("Bad uDeviceID\n");
842 wmd
->lpfnYieldProc
= fpYieldProc
;
843 wmd
->dwYieldData
= dwYieldData
;
849 /**************************************************************************
850 * mciGetDeviceIDFromElementIDW [WINMM.@]
852 UINT WINAPI
mciGetDeviceIDFromElementIDW(DWORD dwElementID
, LPCWSTR lpstrType
)
854 /* FIXME: that's rather strange, there is no
855 * mciGetDeviceIDFromElementID32A in winmm.spec
857 FIXME("(%lu, %p) stub\n", dwElementID
, lpstrType
);
861 /**************************************************************************
862 * mciGetYieldProc [WINMM.@]
864 YIELDPROC WINAPI
mciGetYieldProc(UINT uDeviceID
, DWORD
* lpdwYieldData
)
866 LPWINE_MCIDRIVER wmd
;
868 TRACE("(%u, %p)\n", uDeviceID
, lpdwYieldData
);
870 if (!(wmd
= MCI_GetDriver(uDeviceID
))) {
871 WARN("Bad uDeviceID\n");
874 if (!wmd
->lpfnYieldProc
) {
875 WARN("No proc set\n");
879 WARN("Proc is 32 bit\n");
882 return wmd
->lpfnYieldProc
;
885 /**************************************************************************
886 * mciGetCreatorTask [WINMM.@]
888 HTASK WINAPI
mciGetCreatorTask(UINT uDeviceID
)
890 LPWINE_MCIDRIVER wmd
;
893 if ((wmd
= MCI_GetDriver(uDeviceID
))) ret
= (HTASK
)wmd
->CreatorThread
;
895 TRACE("(%u) => %p\n", uDeviceID
, ret
);
899 /**************************************************************************
900 * mciDriverYield [WINMM.@]
902 UINT WINAPI
mciDriverYield(UINT uDeviceID
)
904 LPWINE_MCIDRIVER wmd
;
907 TRACE("(%04x)\n", uDeviceID
);
909 if (!(wmd
= MCI_GetDriver(uDeviceID
)) || !wmd
->lpfnYieldProc
|| !wmd
->bIs32
) {
912 ret
= wmd
->lpfnYieldProc(uDeviceID
, wmd
->dwYieldData
);
918 /**************************************************************************
919 * midiOutGetNumDevs [WINMM.@]
921 UINT WINAPI
midiOutGetNumDevs(void)
923 return MMDRV_GetNum(MMDRV_MIDIOUT
);
926 /**************************************************************************
927 * midiOutGetDevCapsW [WINMM.@]
929 UINT WINAPI
midiOutGetDevCapsW(UINT uDeviceID
, LPMIDIOUTCAPSW lpCaps
,
935 ret
= midiOutGetDevCapsA(uDeviceID
, &mocA
, sizeof(mocA
));
936 lpCaps
->wMid
= mocA
.wMid
;
937 lpCaps
->wPid
= mocA
.wPid
;
938 lpCaps
->vDriverVersion
= mocA
.vDriverVersion
;
939 MultiByteToWideChar( CP_ACP
, 0, mocA
.szPname
, -1, lpCaps
->szPname
,
940 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
941 lpCaps
->wTechnology
= mocA
.wTechnology
;
942 lpCaps
->wVoices
= mocA
.wVoices
;
943 lpCaps
->wNotes
= mocA
.wNotes
;
944 lpCaps
->wChannelMask
= mocA
.wChannelMask
;
945 lpCaps
->dwSupport
= mocA
.dwSupport
;
949 /**************************************************************************
950 * midiOutGetDevCapsA [WINMM.@]
952 UINT WINAPI
midiOutGetDevCapsA(UINT uDeviceID
, LPMIDIOUTCAPSA lpCaps
,
957 TRACE("(%u, %p, %u);\n", uDeviceID
, lpCaps
, uSize
);
959 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
961 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_MIDIOUT
, TRUE
)) == NULL
)
962 return MMSYSERR_INVALHANDLE
;
964 return MMDRV_Message(wmld
, MODM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
967 /**************************************************************************
968 * MIDI_GetErrorText [internal]
970 static UINT16
MIDI_GetErrorText(UINT16 uError
, LPSTR lpText
, UINT16 uSize
)
972 UINT16 ret
= MMSYSERR_BADERRNUM
;
974 if (lpText
== NULL
) {
975 ret
= MMSYSERR_INVALPARAM
;
976 } else if (uSize
== 0) {
977 ret
= MMSYSERR_NOERROR
;
979 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
980 * a warning for the test was always true */
981 (/*uError >= MMSYSERR_BASE && */ uError
<= MMSYSERR_LASTERROR
) ||
982 (uError
>= MIDIERR_BASE
&& uError
<= MIDIERR_LASTERROR
)) {
984 if (LoadStringA(WINMM_IData
->hWinMM32Instance
,
985 uError
, lpText
, uSize
) > 0) {
986 ret
= MMSYSERR_NOERROR
;
992 /**************************************************************************
993 * midiOutGetErrorTextA [WINMM.@]
995 UINT WINAPI
midiOutGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
997 return MIDI_GetErrorText(uError
, lpText
, uSize
);
1000 /**************************************************************************
1001 * midiOutGetErrorTextW [WINMM.@]
1003 UINT WINAPI
midiOutGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
1005 LPSTR xstr
= HeapAlloc(GetProcessHeap(), 0, uSize
);
1008 ret
= MIDI_GetErrorText(uError
, xstr
, uSize
);
1009 MultiByteToWideChar( CP_ACP
, 0, xstr
, -1, lpText
, uSize
);
1010 HeapFree(GetProcessHeap(), 0, xstr
);
1014 /**************************************************************************
1015 * MIDI_OutAlloc [internal]
1017 static LPWINE_MIDI
MIDI_OutAlloc(HMIDIOUT
* lphMidiOut
, LPDWORD lpdwCallback
,
1018 LPDWORD lpdwInstance
, LPDWORD lpdwFlags
,
1019 DWORD cIDs
, MIDIOPENSTRMID
* lpIDs
, BOOL bFrom32
)
1025 size
= sizeof(WINE_MIDI
) + (cIDs
? (cIDs
-1) : 0) * sizeof(MIDIOPENSTRMID
);
1027 lpwm
= (LPWINE_MIDI
)MMDRV_Alloc(size
, MMDRV_MIDIOUT
, &hMidiOut
, lpdwFlags
,
1028 lpdwCallback
, lpdwInstance
, bFrom32
);
1030 if (lphMidiOut
!= NULL
)
1031 *lphMidiOut
= hMidiOut
;
1034 lpwm
->mod
.hMidi
= (HMIDI
) hMidiOut
;
1035 lpwm
->mod
.dwCallback
= *lpdwCallback
;
1036 lpwm
->mod
.dwInstance
= *lpdwInstance
;
1037 lpwm
->mod
.dnDevNode
= 0;
1038 lpwm
->mod
.cIds
= cIDs
;
1040 memcpy(&(lpwm
->mod
.rgIds
), lpIDs
, cIDs
* sizeof(MIDIOPENSTRMID
));
1045 UINT
MIDI_OutOpen(HMIDIOUT
* lphMidiOut
, UINT uDeviceID
, DWORD dwCallback
,
1046 DWORD dwInstance
, DWORD dwFlags
, BOOL bFrom32
)
1052 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1053 lphMidiOut
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
);
1055 if (lphMidiOut
!= NULL
) *lphMidiOut
= 0;
1057 lpwm
= MIDI_OutAlloc(&hMidiOut
, &dwCallback
, &dwInstance
, &dwFlags
,
1061 return MMSYSERR_NOMEM
;
1063 lpwm
->mld
.uDeviceID
= uDeviceID
;
1065 dwRet
= MMDRV_Open((LPWINE_MLD
)lpwm
, MODM_OPEN
, (DWORD
)&lpwm
->mod
, dwFlags
);
1067 if (dwRet
!= MMSYSERR_NOERROR
) {
1068 MMDRV_Free(hMidiOut
, (LPWINE_MLD
)lpwm
);
1072 if (lphMidiOut
) *lphMidiOut
= hMidiOut
;
1073 TRACE("=> %d hMidi=%p\n", dwRet
, hMidiOut
);
1078 /**************************************************************************
1079 * midiOutOpen [WINMM.@]
1081 UINT WINAPI
midiOutOpen(HMIDIOUT
* lphMidiOut
, UINT uDeviceID
,
1082 DWORD dwCallback
, DWORD dwInstance
, DWORD dwFlags
)
1084 return MIDI_OutOpen(lphMidiOut
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
, TRUE
);
1087 /**************************************************************************
1088 * midiOutClose [WINMM.@]
1090 UINT WINAPI
midiOutClose(HMIDIOUT hMidiOut
)
1095 TRACE("(%p)\n", hMidiOut
);
1097 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1098 return MMSYSERR_INVALHANDLE
;
1100 dwRet
= MMDRV_Close(wmld
, MODM_CLOSE
);
1101 MMDRV_Free(hMidiOut
, wmld
);
1106 /**************************************************************************
1107 * midiOutPrepareHeader [WINMM.@]
1109 UINT WINAPI
midiOutPrepareHeader(HMIDIOUT hMidiOut
,
1110 MIDIHDR
* lpMidiOutHdr
, UINT uSize
)
1114 TRACE("(%p, %p, %d)\n", hMidiOut
, lpMidiOutHdr
, uSize
);
1116 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1117 return MMSYSERR_INVALHANDLE
;
1119 return MMDRV_Message(wmld
, MODM_PREPARE
, (DWORD
)lpMidiOutHdr
, uSize
, TRUE
);
1122 /**************************************************************************
1123 * midiOutUnprepareHeader [WINMM.@]
1125 UINT WINAPI
midiOutUnprepareHeader(HMIDIOUT hMidiOut
,
1126 MIDIHDR
* lpMidiOutHdr
, UINT uSize
)
1130 TRACE("(%p, %p, %d)\n", hMidiOut
, lpMidiOutHdr
, uSize
);
1132 if (!(lpMidiOutHdr
->dwFlags
& MHDR_PREPARED
)) {
1133 return MMSYSERR_NOERROR
;
1136 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1137 return MMSYSERR_INVALHANDLE
;
1139 return MMDRV_Message(wmld
, MODM_UNPREPARE
, (DWORD
)lpMidiOutHdr
, uSize
, TRUE
);
1142 /**************************************************************************
1143 * midiOutShortMsg [WINMM.@]
1145 UINT WINAPI
midiOutShortMsg(HMIDIOUT hMidiOut
, DWORD dwMsg
)
1149 TRACE("(%p, %08lX)\n", hMidiOut
, dwMsg
);
1151 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1152 return MMSYSERR_INVALHANDLE
;
1154 return MMDRV_Message(wmld
, MODM_DATA
, dwMsg
, 0L, TRUE
);
1157 /**************************************************************************
1158 * midiOutLongMsg [WINMM.@]
1160 UINT WINAPI
midiOutLongMsg(HMIDIOUT hMidiOut
,
1161 MIDIHDR
* lpMidiOutHdr
, UINT uSize
)
1165 TRACE("(%p, %p, %d)\n", hMidiOut
, lpMidiOutHdr
, uSize
);
1167 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1168 return MMSYSERR_INVALHANDLE
;
1170 return MMDRV_Message(wmld
, MODM_LONGDATA
, (DWORD
)lpMidiOutHdr
, uSize
, TRUE
);
1173 /**************************************************************************
1174 * midiOutReset [WINMM.@]
1176 UINT WINAPI
midiOutReset(HMIDIOUT hMidiOut
)
1180 TRACE("(%p)\n", hMidiOut
);
1182 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1183 return MMSYSERR_INVALHANDLE
;
1185 return MMDRV_Message(wmld
, MODM_RESET
, 0L, 0L, TRUE
);
1188 /**************************************************************************
1189 * midiOutGetVolume [WINMM.@]
1191 UINT WINAPI
midiOutGetVolume(HMIDIOUT hMidiOut
, DWORD
* lpdwVolume
)
1195 TRACE("(%p, %p);\n", hMidiOut
, lpdwVolume
);
1197 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, TRUE
)) == NULL
)
1198 return MMSYSERR_INVALHANDLE
;
1200 return MMDRV_Message(wmld
, MODM_GETVOLUME
, (DWORD
)lpdwVolume
, 0L, TRUE
);
1203 /**************************************************************************
1204 * midiOutSetVolume [WINMM.@]
1206 UINT WINAPI
midiOutSetVolume(HMIDIOUT hMidiOut
, DWORD dwVolume
)
1210 TRACE("(%p, %ld);\n", hMidiOut
, dwVolume
);
1212 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, TRUE
)) == NULL
)
1213 return MMSYSERR_INVALHANDLE
;
1215 return MMDRV_Message(wmld
, MODM_SETVOLUME
, dwVolume
, 0L, TRUE
);
1218 /**************************************************************************
1219 * midiOutCachePatches [WINMM.@]
1221 UINT WINAPI
midiOutCachePatches(HMIDIOUT hMidiOut
, UINT uBank
,
1222 WORD
* lpwPatchArray
, UINT uFlags
)
1224 /* not really necessary to support this */
1225 FIXME("not supported yet\n");
1226 return MMSYSERR_NOTSUPPORTED
;
1229 /**************************************************************************
1230 * midiOutCacheDrumPatches [WINMM.@]
1232 UINT WINAPI
midiOutCacheDrumPatches(HMIDIOUT hMidiOut
, UINT uPatch
,
1233 WORD
* lpwKeyArray
, UINT uFlags
)
1235 FIXME("not supported yet\n");
1236 return MMSYSERR_NOTSUPPORTED
;
1239 /**************************************************************************
1240 * midiOutGetID [WINMM.@]
1242 UINT WINAPI
midiOutGetID(HMIDIOUT hMidiOut
, UINT
* lpuDeviceID
)
1246 TRACE("(%p, %p)\n", hMidiOut
, lpuDeviceID
);
1248 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALPARAM
;
1249 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1250 return MMSYSERR_INVALHANDLE
;
1252 *lpuDeviceID
= wmld
->uDeviceID
;
1253 return MMSYSERR_NOERROR
;
1256 /**************************************************************************
1257 * midiOutMessage [WINMM.@]
1259 DWORD WINAPI
midiOutMessage(HMIDIOUT hMidiOut
, UINT uMessage
,
1260 DWORD dwParam1
, DWORD dwParam2
)
1264 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut
, uMessage
, dwParam1
, dwParam2
);
1266 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
) {
1268 if (uMessage
== 0x0001) {
1269 *(LPDWORD
)dwParam1
= 1;
1272 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, TRUE
)) != NULL
) {
1273 return MMDRV_PhysicalFeatures(wmld
, uMessage
, dwParam1
, dwParam2
);
1275 return MMSYSERR_INVALHANDLE
;
1281 FIXME("can't handle OPEN or CLOSE message!\n");
1282 return MMSYSERR_NOTSUPPORTED
;
1284 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
1287 /**************************************************************************
1288 * midiInGetNumDevs [WINMM.@]
1290 UINT WINAPI
midiInGetNumDevs(void)
1292 return MMDRV_GetNum(MMDRV_MIDIIN
);
1295 /**************************************************************************
1296 * midiInGetDevCapsW [WINMM.@]
1298 UINT WINAPI
midiInGetDevCapsW(UINT uDeviceID
, LPMIDIINCAPSW lpCaps
, UINT uSize
)
1301 UINT ret
= midiInGetDevCapsA(uDeviceID
, &micA
, uSize
);
1303 if (ret
== MMSYSERR_NOERROR
) {
1304 lpCaps
->wMid
= micA
.wMid
;
1305 lpCaps
->wPid
= micA
.wPid
;
1306 lpCaps
->vDriverVersion
= micA
.vDriverVersion
;
1307 MultiByteToWideChar( CP_ACP
, 0, micA
.szPname
, -1, lpCaps
->szPname
,
1308 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
1309 lpCaps
->dwSupport
= micA
.dwSupport
;
1314 /**************************************************************************
1315 * midiInGetDevCapsA [WINMM.@]
1317 UINT WINAPI
midiInGetDevCapsA(UINT uDeviceID
, LPMIDIINCAPSA lpCaps
, UINT uSize
)
1321 TRACE("(%d, %p, %d);\n", uDeviceID
, lpCaps
, uSize
);
1323 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_MIDIIN
, TRUE
)) == NULL
)
1324 return MMSYSERR_INVALHANDLE
;
1326 return MMDRV_Message(wmld
, MIDM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
1329 /**************************************************************************
1330 * midiInGetErrorTextW [WINMM.@]
1332 UINT WINAPI
midiInGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
1334 LPSTR xstr
= HeapAlloc(GetProcessHeap(), 0, uSize
);
1335 UINT ret
= MIDI_GetErrorText(uError
, xstr
, uSize
);
1337 MultiByteToWideChar( CP_ACP
, 0, xstr
, -1, lpText
, uSize
);
1338 HeapFree(GetProcessHeap(), 0, xstr
);
1342 /**************************************************************************
1343 * midiInGetErrorTextA [WINMM.@]
1345 UINT WINAPI
midiInGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
1347 return MIDI_GetErrorText(uError
, lpText
, uSize
);
1350 UINT
MIDI_InOpen(HMIDIIN
* lphMidiIn
, UINT uDeviceID
, DWORD dwCallback
,
1351 DWORD dwInstance
, DWORD dwFlags
, BOOL bFrom32
)
1357 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1358 lphMidiIn
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
);
1360 if (lphMidiIn
!= NULL
) *lphMidiIn
= 0;
1362 lpwm
= (LPWINE_MIDI
)MMDRV_Alloc(sizeof(WINE_MIDI
), MMDRV_MIDIIN
, &hMidiIn
,
1363 &dwFlags
, &dwCallback
, &dwInstance
, bFrom32
);
1366 return MMSYSERR_NOMEM
;
1368 lpwm
->mod
.hMidi
= (HMIDI
) hMidiIn
;
1369 lpwm
->mod
.dwCallback
= dwCallback
;
1370 lpwm
->mod
.dwInstance
= dwInstance
;
1372 lpwm
->mld
.uDeviceID
= uDeviceID
;
1373 dwRet
= MMDRV_Open(&lpwm
->mld
, MIDM_OPEN
, (DWORD
)&lpwm
->mod
, dwFlags
);
1375 if (dwRet
!= MMSYSERR_NOERROR
) {
1376 MMDRV_Free(hMidiIn
, &lpwm
->mld
);
1379 if (lphMidiIn
!= NULL
) *lphMidiIn
= hMidiIn
;
1380 TRACE("=> %ld hMidi=%p\n", dwRet
, hMidiIn
);
1385 /**************************************************************************
1386 * midiInOpen [WINMM.@]
1388 UINT WINAPI
midiInOpen(HMIDIIN
* lphMidiIn
, UINT uDeviceID
,
1389 DWORD dwCallback
, DWORD dwInstance
, DWORD dwFlags
)
1391 return MIDI_InOpen(lphMidiIn
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
, TRUE
);
1394 /**************************************************************************
1395 * midiInClose [WINMM.@]
1397 UINT WINAPI
midiInClose(HMIDIIN hMidiIn
)
1402 TRACE("(%p)\n", hMidiIn
);
1404 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1405 return MMSYSERR_INVALHANDLE
;
1407 dwRet
= MMDRV_Close(wmld
, MIDM_CLOSE
);
1408 MMDRV_Free(hMidiIn
, wmld
);
1412 /**************************************************************************
1413 * midiInPrepareHeader [WINMM.@]
1415 UINT WINAPI
midiInPrepareHeader(HMIDIIN hMidiIn
,
1416 MIDIHDR
* lpMidiInHdr
, UINT uSize
)
1420 TRACE("(%p, %p, %d)\n", hMidiIn
, lpMidiInHdr
, uSize
);
1422 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1423 return MMSYSERR_INVALHANDLE
;
1425 return MMDRV_Message(wmld
, MIDM_PREPARE
, (DWORD
)lpMidiInHdr
, uSize
, TRUE
);
1428 /**************************************************************************
1429 * midiInUnprepareHeader [WINMM.@]
1431 UINT WINAPI
midiInUnprepareHeader(HMIDIIN hMidiIn
,
1432 MIDIHDR
* lpMidiInHdr
, UINT uSize
)
1436 TRACE("(%p, %p, %d)\n", hMidiIn
, lpMidiInHdr
, uSize
);
1438 if (!(lpMidiInHdr
->dwFlags
& MHDR_PREPARED
)) {
1439 return MMSYSERR_NOERROR
;
1442 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1443 return MMSYSERR_INVALHANDLE
;
1445 return MMDRV_Message(wmld
, MIDM_UNPREPARE
, (DWORD
)lpMidiInHdr
, uSize
, TRUE
);
1448 /**************************************************************************
1449 * midiInAddBuffer [WINMM.@]
1451 UINT WINAPI
midiInAddBuffer(HMIDIIN hMidiIn
,
1452 MIDIHDR
* lpMidiInHdr
, UINT uSize
)
1456 TRACE("(%p, %p, %d)\n", hMidiIn
, lpMidiInHdr
, uSize
);
1458 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1459 return MMSYSERR_INVALHANDLE
;
1461 return MMDRV_Message(wmld
, MIDM_ADDBUFFER
, (DWORD
)lpMidiInHdr
, uSize
, TRUE
);
1464 /**************************************************************************
1465 * midiInStart [WINMM.@]
1467 UINT WINAPI
midiInStart(HMIDIIN hMidiIn
)
1471 TRACE("(%p)\n", hMidiIn
);
1473 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1474 return MMSYSERR_INVALHANDLE
;
1476 return MMDRV_Message(wmld
, MIDM_START
, 0L, 0L, TRUE
);
1479 /**************************************************************************
1480 * midiInStop [WINMM.@]
1482 UINT WINAPI
midiInStop(HMIDIIN hMidiIn
)
1486 TRACE("(%p)\n", hMidiIn
);
1488 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1489 return MMSYSERR_INVALHANDLE
;
1491 return MMDRV_Message(wmld
, MIDM_STOP
, 0L, 0L, TRUE
);
1494 /**************************************************************************
1495 * midiInReset [WINMM.@]
1497 UINT WINAPI
midiInReset(HMIDIIN hMidiIn
)
1501 TRACE("(%p)\n", hMidiIn
);
1503 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1504 return MMSYSERR_INVALHANDLE
;
1506 return MMDRV_Message(wmld
, MIDM_RESET
, 0L, 0L, TRUE
);
1509 /**************************************************************************
1510 * midiInGetID [WINMM.@]
1512 UINT WINAPI
midiInGetID(HMIDIIN hMidiIn
, UINT
* lpuDeviceID
)
1516 TRACE("(%p, %p)\n", hMidiIn
, lpuDeviceID
);
1518 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALPARAM
;
1520 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, TRUE
)) == NULL
)
1521 return MMSYSERR_INVALHANDLE
;
1523 *lpuDeviceID
= wmld
->uDeviceID
;
1525 return MMSYSERR_NOERROR
;
1528 /**************************************************************************
1529 * midiInMessage [WINMM.@]
1531 DWORD WINAPI
midiInMessage(HMIDIIN hMidiIn
, UINT uMessage
,
1532 DWORD dwParam1
, DWORD dwParam2
)
1536 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn
, uMessage
, dwParam1
, dwParam2
);
1538 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1539 return MMSYSERR_INVALHANDLE
;
1544 FIXME("can't handle OPEN or CLOSE message!\n");
1545 return MMSYSERR_NOTSUPPORTED
;
1547 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
1550 typedef struct WINE_MIDIStream
{
1561 LPMIDIHDR lpMidiHdr
;
1564 #define WINE_MSM_HEADER (WM_USER+0)
1565 #define WINE_MSM_STOP (WM_USER+1)
1567 /**************************************************************************
1568 * MMSYSTEM_GetMidiStream [internal]
1570 static BOOL
MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm
, WINE_MIDIStream
** lpMidiStrm
, WINE_MIDI
** lplpwm
)
1572 WINE_MIDI
* lpwm
= (LPWINE_MIDI
)MMDRV_Get(hMidiStrm
, MMDRV_MIDIOUT
, FALSE
);
1581 *lpMidiStrm
= (WINE_MIDIStream
*)lpwm
->mod
.rgIds
.dwStreamID
;
1583 return *lpMidiStrm
!= NULL
;
1586 /**************************************************************************
1587 * MMSYSTEM_MidiStream_Convert [internal]
1589 static DWORD
MMSYSTEM_MidiStream_Convert(WINE_MIDIStream
* lpMidiStrm
, DWORD pulse
)
1593 if (lpMidiStrm
->dwTimeDiv
== 0) {
1594 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1595 } else if (lpMidiStrm
->dwTimeDiv
> 0x8000) { /* SMPTE, unchecked FIXME? */
1596 int nf
= -(char)HIBYTE(lpMidiStrm
->dwTimeDiv
); /* number of frames */
1597 int nsf
= LOBYTE(lpMidiStrm
->dwTimeDiv
); /* number of sub-frames */
1598 ret
= (pulse
* 1000) / (nf
* nsf
);
1600 ret
= (DWORD
)((double)pulse
* ((double)lpMidiStrm
->dwTempo
/ 1000) /
1601 (double)lpMidiStrm
->dwTimeDiv
);
1607 /**************************************************************************
1608 * MMSYSTEM_MidiStream_MessageHandler [internal]
1610 static BOOL
MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream
* lpMidiStrm
, LPWINE_MIDI lpwm
, LPMSG msg
)
1612 LPMIDIHDR lpMidiHdr
;
1616 switch (msg
->message
) {
1618 SetEvent(lpMidiStrm
->hEvent
);
1622 /* this is not quite what MS doc says... */
1623 midiOutReset(lpMidiStrm
->hDevice
);
1624 /* empty list of already submitted buffers */
1625 for (lpMidiHdr
= lpMidiStrm
->lpMidiHdr
; lpMidiHdr
; lpMidiHdr
= (LPMIDIHDR
)lpMidiHdr
->lpNext
) {
1626 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
1627 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1629 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1630 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_DONE
,
1631 lpwm
->mod
.dwInstance
, (DWORD
)lpMidiHdr
, 0L);
1633 lpMidiStrm
->lpMidiHdr
= 0;
1634 SetEvent(lpMidiStrm
->hEvent
);
1636 case WINE_MSM_HEADER
:
1637 /* sets initial tick count for first MIDIHDR */
1638 if (!lpMidiStrm
->dwStartTicks
)
1639 lpMidiStrm
->dwStartTicks
= GetTickCount();
1641 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1642 * by native mcimidi, it doesn't look like a correct one".
1643 * this trick allows to throw it away... but I don't like it.
1644 * It looks like part of the file I'm trying to play and definitively looks
1645 * like raw midi content
1646 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1647 * synchronization issue where native mcimidi is still processing raw MIDI
1648 * content before generating MIDIEVENTs ?
1650 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1651 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1652 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1653 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1654 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1655 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1656 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1657 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1658 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1659 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1660 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1661 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1662 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1663 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1664 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1665 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1666 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1668 lpMidiHdr
= (LPMIDIHDR
)msg
->lParam
;
1669 lpData
= lpMidiHdr
->lpData
;
1670 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1671 (lpMidiHdr
->dwFlags
& MHDR_ISSTRM
) ? "stream" : "regular", lpMidiHdr
,
1672 (DWORD
)lpMidiHdr
, lpMidiHdr
->dwBufferLength
, lpMidiHdr
->dwBytesRecorded
,
1673 lpMidiHdr
->dwFlags
, msg
->wParam
);
1675 /* dumps content of lpMidiHdr->lpData
1676 * FIXME: there should be a debug routine somewhere that already does this
1677 * I hate spreading this type of shit all around the code
1679 for (dwToGo
= 0; dwToGo
< lpMidiHdr
->dwBufferLength
; dwToGo
+= 16) {
1683 for (i
= 0; i
< min(16, lpMidiHdr
->dwBufferLength
- dwToGo
); i
++)
1684 printf("%02x ", lpData
[dwToGo
+ i
]);
1687 for (i
= 0; i
< min(16, lpMidiHdr
->dwBufferLength
- dwToGo
); i
++) {
1688 ch
= lpData
[dwToGo
+ i
];
1689 printf("%c", (ch
>= 0x20 && ch
<= 0x7F) ? ch
: '.');
1694 if (((LPMIDIEVENT
)lpData
)->dwStreamID
!= 0 &&
1695 ((LPMIDIEVENT
)lpData
)->dwStreamID
!= 0xFFFFFFFF &&
1696 ((LPMIDIEVENT
)lpData
)->dwStreamID
!= (DWORD
)lpMidiStrm
) {
1697 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
1698 (lpMidiHdr
->dwFlags
& MHDR_ISSTRM
) ? "stream" : "regular",
1699 ((LPMIDIEVENT
)lpData
)->dwStreamID
);
1700 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
1701 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1703 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1704 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_DONE
,
1705 lpwm
->mod
.dwInstance
, (DWORD
)lpMidiHdr
, 0L);
1709 for (lpmh
= &lpMidiStrm
->lpMidiHdr
; *lpmh
; lpmh
= (LPMIDIHDR
*)&((*lpmh
)->lpNext
));
1711 lpMidiHdr
= (LPMIDIHDR
)msg
->lParam
;
1712 lpMidiHdr
->lpNext
= 0;
1713 lpMidiHdr
->dwFlags
|= MHDR_INQUEUE
;
1714 lpMidiHdr
->dwFlags
&= MHDR_DONE
;
1715 lpMidiHdr
->dwOffset
= 0;
1719 FIXME("Unknown message %d\n", msg
->message
);
1725 /**************************************************************************
1726 * MMSYSTEM_MidiStream_Player [internal]
1728 static DWORD CALLBACK
MMSYSTEM_MidiStream_Player(LPVOID pmt
)
1730 WINE_MIDIStream
* lpMidiStrm
= pmt
;
1735 LPMIDIHDR lpMidiHdr
;
1739 TRACE("(%p)!\n", lpMidiStrm
);
1742 (lpwm
= (LPWINE_MIDI
)MMDRV_Get(lpMidiStrm
->hDevice
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1745 /* force thread's queue creation */
1746 /* Used to be InitThreadInput16(0, 5); */
1747 /* but following works also with hack in midiStreamOpen */
1748 PeekMessageA(&msg
, 0, 0, 0, 0);
1750 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
1751 SetEvent(lpMidiStrm
->hEvent
);
1752 TRACE("Ready to go 1\n");
1753 /* thread is started in paused mode */
1754 SuspendThread(lpMidiStrm
->hThread
);
1755 TRACE("Ready to go 2\n");
1757 lpMidiStrm
->dwStartTicks
= 0;
1758 lpMidiStrm
->dwPulses
= 0;
1760 lpMidiStrm
->lpMidiHdr
= 0;
1763 lpMidiHdr
= lpMidiStrm
->lpMidiHdr
;
1765 /* for first message, block until one arrives, then process all that are available */
1766 GetMessageA(&msg
, 0, 0, 0);
1768 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm
, lpwm
, &msg
))
1770 } while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
));
1776 lpData
= lpMidiHdr
->lpData
;
1778 me
= (LPMIDIEVENT
)(lpData
+ lpMidiHdr
->dwOffset
);
1780 /* do we have to wait ? */
1781 if (me
->dwDeltaTime
) {
1782 lpMidiStrm
->dwPositionMS
+= MMSYSTEM_MidiStream_Convert(lpMidiStrm
, me
->dwDeltaTime
);
1783 lpMidiStrm
->dwPulses
+= me
->dwDeltaTime
;
1785 dwToGo
= lpMidiStrm
->dwStartTicks
+ lpMidiStrm
->dwPositionMS
;
1787 TRACE("%ld/%ld/%ld\n", dwToGo
, GetTickCount(), me
->dwDeltaTime
);
1788 while ((dwCurrTC
= GetTickCount()) < dwToGo
) {
1789 if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, dwToGo
- dwCurrTC
, QS_ALLINPUT
) == WAIT_OBJECT_0
) {
1790 /* got a message, handle it */
1791 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) {
1792 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm
, lpwm
, &msg
))
1797 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
1802 switch (MEVT_EVENTTYPE(me
->dwEvent
& ~MEVT_F_CALLBACK
)) {
1804 FIXME("NIY: MEVT_COMMENT\n");
1805 /* do nothing, skip bytes */
1808 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
1813 midiOutShortMsg(lpMidiStrm
->hDevice
, MEVT_EVENTPARM(me
->dwEvent
));
1816 lpMidiStrm
->dwTempo
= MEVT_EVENTPARM(me
->dwEvent
);
1821 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me
->dwEvent
& ~MEVT_F_CALLBACK
));
1824 if (me
->dwEvent
& MEVT_F_CALLBACK
) {
1825 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1826 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_POSITIONCB
,
1827 lpwm
->mod
.dwInstance
, (LPARAM
)lpMidiHdr
, 0L);
1829 lpMidiHdr
->dwOffset
+= sizeof(MIDIEVENT
) - sizeof(me
->dwParms
);
1830 if (me
->dwEvent
& MEVT_F_LONG
)
1831 lpMidiHdr
->dwOffset
+= (MEVT_EVENTPARM(me
->dwEvent
) + 3) & ~3;
1832 if (lpMidiHdr
->dwOffset
>= lpMidiHdr
->dwBufferLength
) {
1833 /* done with this header */
1834 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
1835 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1837 lpMidiStrm
->lpMidiHdr
= (LPMIDIHDR
)lpMidiHdr
->lpNext
;
1838 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1839 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_DONE
,
1840 lpwm
->mod
.dwInstance
, (DWORD
)lpMidiHdr
, 0L);
1845 TRACE("End of thread\n");
1847 return 0; /* for removing the warning, never executed */
1850 /**************************************************************************
1851 * MMSYSTEM_MidiStream_PostMessage [internal]
1853 static BOOL
MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream
* lpMidiStrm
, WORD msg
, DWORD pmt1
, DWORD pmt2
)
1855 if (PostThreadMessageA(lpMidiStrm
->dwThreadID
, msg
, pmt1
, pmt2
)) {
1858 ReleaseThunkLock(&count
);
1859 WaitForSingleObject(lpMidiStrm
->hEvent
, INFINITE
);
1860 RestoreThunkLock(count
);
1862 WARN("bad PostThreadMessageA\n");
1868 /**************************************************************************
1869 * midiStreamClose [WINMM.@]
1871 MMRESULT WINAPI
midiStreamClose(HMIDISTRM hMidiStrm
)
1873 WINE_MIDIStream
* lpMidiStrm
;
1875 TRACE("(%p)!\n", hMidiStrm
);
1877 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
))
1878 return MMSYSERR_INVALHANDLE
;
1880 midiStreamStop(hMidiStrm
);
1881 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm
, WM_QUIT
, 0, 0);
1882 HeapFree(GetProcessHeap(), 0, lpMidiStrm
);
1883 CloseHandle(lpMidiStrm
->hEvent
);
1885 return midiOutClose((HMIDIOUT
)hMidiStrm
);
1888 /**************************************************************************
1889 * MMSYSTEM_MidiStream_Open [internal]
1891 MMRESULT
MIDI_StreamOpen(HMIDISTRM
* lphMidiStrm
, LPUINT lpuDeviceID
, DWORD cMidi
,
1892 DWORD dwCallback
, DWORD dwInstance
, DWORD fdwOpen
,
1895 WINE_MIDIStream
* lpMidiStrm
;
1897 MIDIOPENSTRMID mosm
;
1901 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
1902 lphMidiStrm
, lpuDeviceID
, cMidi
, dwCallback
, dwInstance
, fdwOpen
);
1904 if (cMidi
!= 1 || lphMidiStrm
== NULL
|| lpuDeviceID
== NULL
)
1905 return MMSYSERR_INVALPARAM
;
1907 lpMidiStrm
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream
));
1909 return MMSYSERR_NOMEM
;
1911 lpMidiStrm
->dwTempo
= 500000;
1912 lpMidiStrm
->dwTimeDiv
= 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
1913 lpMidiStrm
->dwPositionMS
= 0;
1915 mosm
.dwStreamID
= (DWORD
)lpMidiStrm
;
1916 /* FIXME: the correct value is not allocated yet for MAPPER */
1917 mosm
.wDeviceID
= *lpuDeviceID
;
1918 lpwm
= MIDI_OutAlloc(&hMidiOut
, &dwCallback
, &dwInstance
, &fdwOpen
, 1, &mosm
, bFrom32
);
1919 lpMidiStrm
->hDevice
= hMidiOut
;
1921 *lphMidiStrm
= (HMIDISTRM
)hMidiOut
;
1923 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
1924 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID
);
1925 lpwm
->mld
.uDeviceID
= *lpuDeviceID
= 0;
1927 ret
= MMDRV_Open(&lpwm
->mld
, MODM_OPEN
, (DWORD
)&lpwm
->mod
, fdwOpen
);
1928 lpMidiStrm
->hEvent
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
1929 lpMidiStrm
->wFlags
= HIWORD(fdwOpen
);
1931 lpMidiStrm
->hThread
= CreateThread(NULL
, 0, MMSYSTEM_MidiStream_Player
,
1932 lpMidiStrm
, 0, &(lpMidiStrm
->dwThreadID
));
1934 if (!lpMidiStrm
->hThread
) {
1935 midiStreamClose((HMIDISTRM
)hMidiOut
);
1936 return MMSYSERR_NOMEM
;
1939 /* wait for thread to have started, and for its queue to be created */
1943 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
1944 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
1945 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
1947 ReleaseThunkLock(&count
);
1948 WaitForSingleObject(lpMidiStrm
->hEvent
, INFINITE
);
1949 RestoreThunkLock(count
);
1952 TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n",
1953 *lpuDeviceID
, lpwm
->mld
.uDeviceID
, *lphMidiStrm
, ret
, lpMidiStrm
);
1957 /**************************************************************************
1958 * midiStreamOpen [WINMM.@]
1960 MMRESULT WINAPI
midiStreamOpen(HMIDISTRM
* lphMidiStrm
, LPUINT lpuDeviceID
,
1961 DWORD cMidi
, DWORD dwCallback
,
1962 DWORD dwInstance
, DWORD fdwOpen
)
1964 return MIDI_StreamOpen(lphMidiStrm
, lpuDeviceID
, cMidi
, dwCallback
,
1965 dwInstance
, fdwOpen
, TRUE
);
1968 /**************************************************************************
1969 * midiStreamOut [WINMM.@]
1971 MMRESULT WINAPI
midiStreamOut(HMIDISTRM hMidiStrm
, LPMIDIHDR lpMidiHdr
,
1974 WINE_MIDIStream
* lpMidiStrm
;
1975 DWORD ret
= MMSYSERR_NOERROR
;
1977 TRACE("(%p, %p, %u)!\n", hMidiStrm
, lpMidiHdr
, cbMidiHdr
);
1979 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
1980 ret
= MMSYSERR_INVALHANDLE
;
1981 } else if (!lpMidiHdr
) {
1982 ret
= MMSYSERR_INVALPARAM
;
1984 if (!PostThreadMessageA(lpMidiStrm
->dwThreadID
,
1985 WINE_MSM_HEADER
, cbMidiHdr
,
1986 (DWORD
)lpMidiHdr
)) {
1987 WARN("bad PostThreadMessageA\n");
1988 ret
= MMSYSERR_ERROR
;
1994 /**************************************************************************
1995 * midiStreamPause [WINMM.@]
1997 MMRESULT WINAPI
midiStreamPause(HMIDISTRM hMidiStrm
)
1999 WINE_MIDIStream
* lpMidiStrm
;
2000 DWORD ret
= MMSYSERR_NOERROR
;
2002 TRACE("(%p)!\n", hMidiStrm
);
2004 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2005 ret
= MMSYSERR_INVALHANDLE
;
2007 if (SuspendThread(lpMidiStrm
->hThread
) == 0xFFFFFFFF) {
2008 WARN("bad Suspend (%ld)\n", GetLastError());
2009 ret
= MMSYSERR_ERROR
;
2015 /**************************************************************************
2016 * midiStreamPosition [WINMM.@]
2018 MMRESULT WINAPI
midiStreamPosition(HMIDISTRM hMidiStrm
, LPMMTIME lpMMT
, UINT cbmmt
)
2020 WINE_MIDIStream
* lpMidiStrm
;
2021 DWORD ret
= MMSYSERR_NOERROR
;
2023 TRACE("(%p, %p, %u)!\n", hMidiStrm
, lpMMT
, cbmmt
);
2025 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2026 ret
= MMSYSERR_INVALHANDLE
;
2027 } else if (lpMMT
== NULL
|| cbmmt
!= sizeof(MMTIME
)) {
2028 ret
= MMSYSERR_INVALPARAM
;
2030 switch (lpMMT
->wType
) {
2032 lpMMT
->u
.ms
= lpMidiStrm
->dwPositionMS
;
2033 TRACE("=> %ld ms\n", lpMMT
->u
.ms
);
2036 lpMMT
->u
.ticks
= lpMidiStrm
->dwPulses
;
2037 TRACE("=> %ld ticks\n", lpMMT
->u
.ticks
);
2040 WARN("Unsupported time type %d\n", lpMMT
->wType
);
2041 lpMMT
->wType
= TIME_MS
;
2042 ret
= MMSYSERR_INVALPARAM
;
2049 /**************************************************************************
2050 * midiStreamProperty [WINMM.@]
2052 MMRESULT WINAPI
midiStreamProperty(HMIDISTRM hMidiStrm
, LPBYTE lpPropData
, DWORD dwProperty
)
2054 WINE_MIDIStream
* lpMidiStrm
;
2055 MMRESULT ret
= MMSYSERR_NOERROR
;
2057 TRACE("(%p, %p, %lx)\n", hMidiStrm
, lpPropData
, dwProperty
);
2059 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2060 ret
= MMSYSERR_INVALHANDLE
;
2061 } else if ((dwProperty
& (MIDIPROP_GET
|MIDIPROP_SET
)) == 0) {
2062 ret
= MMSYSERR_INVALPARAM
;
2063 } else if (dwProperty
& MIDIPROP_TEMPO
) {
2064 MIDIPROPTEMPO
* mpt
= (MIDIPROPTEMPO
*)lpPropData
;
2066 if (sizeof(MIDIPROPTEMPO
) != mpt
->cbStruct
) {
2067 ret
= MMSYSERR_INVALPARAM
;
2068 } else if (dwProperty
& MIDIPROP_SET
) {
2069 lpMidiStrm
->dwTempo
= mpt
->dwTempo
;
2070 TRACE("Setting tempo to %ld\n", mpt
->dwTempo
);
2071 } else if (dwProperty
& MIDIPROP_GET
) {
2072 mpt
->dwTempo
= lpMidiStrm
->dwTempo
;
2073 TRACE("Getting tempo <= %ld\n", mpt
->dwTempo
);
2075 } else if (dwProperty
& MIDIPROP_TIMEDIV
) {
2076 MIDIPROPTIMEDIV
* mptd
= (MIDIPROPTIMEDIV
*)lpPropData
;
2078 if (sizeof(MIDIPROPTIMEDIV
) != mptd
->cbStruct
) {
2079 ret
= MMSYSERR_INVALPARAM
;
2080 } else if (dwProperty
& MIDIPROP_SET
) {
2081 lpMidiStrm
->dwTimeDiv
= mptd
->dwTimeDiv
;
2082 TRACE("Setting time div to %ld\n", mptd
->dwTimeDiv
);
2083 } else if (dwProperty
& MIDIPROP_GET
) {
2084 mptd
->dwTimeDiv
= lpMidiStrm
->dwTimeDiv
;
2085 TRACE("Getting time div <= %ld\n", mptd
->dwTimeDiv
);
2088 ret
= MMSYSERR_INVALPARAM
;
2094 /**************************************************************************
2095 * midiStreamRestart [WINMM.@]
2097 MMRESULT WINAPI
midiStreamRestart(HMIDISTRM hMidiStrm
)
2099 WINE_MIDIStream
* lpMidiStrm
;
2100 MMRESULT ret
= MMSYSERR_NOERROR
;
2102 TRACE("(%p)!\n", hMidiStrm
);
2104 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2105 ret
= MMSYSERR_INVALHANDLE
;
2109 /* since we increase the thread suspend count on each midiStreamPause
2110 * there may be a need for several midiStreamResume
2113 ret
= ResumeThread(lpMidiStrm
->hThread
);
2114 } while (ret
!= 0xFFFFFFFF && ret
!= 0);
2115 if (ret
== 0xFFFFFFFF) {
2116 WARN("bad Resume (%ld)\n", GetLastError());
2117 ret
= MMSYSERR_ERROR
;
2119 lpMidiStrm
->dwStartTicks
= GetTickCount() - lpMidiStrm
->dwPositionMS
;
2125 /**************************************************************************
2126 * midiStreamStop [WINMM.@]
2128 MMRESULT WINAPI
midiStreamStop(HMIDISTRM hMidiStrm
)
2130 WINE_MIDIStream
* lpMidiStrm
;
2131 MMRESULT ret
= MMSYSERR_NOERROR
;
2133 TRACE("(%p)!\n", hMidiStrm
);
2135 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2136 ret
= MMSYSERR_INVALHANDLE
;
2138 /* in case stream has been paused... FIXME is the current state correct ? */
2139 midiStreamRestart(hMidiStrm
);
2140 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm
, WINE_MSM_STOP
, 0, 0);
2145 UINT
WAVE_Open(HANDLE
* lphndl
, UINT uDeviceID
, UINT uType
,
2146 const LPWAVEFORMATEX lpFormat
, DWORD dwCallback
,
2147 DWORD dwInstance
, DWORD dwFlags
, BOOL bFrom32
)
2151 DWORD dwRet
= MMSYSERR_NOERROR
;
2154 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2155 lphndl
, (int)uDeviceID
, (uType
==MMDRV_WAVEOUT
)?"Out":"In", lpFormat
, dwCallback
,
2156 dwInstance
, dwFlags
, bFrom32
?32:16);
2158 if (dwFlags
& WAVE_FORMAT_QUERY
) TRACE("WAVE_FORMAT_QUERY requested !\n");
2160 if (lpFormat
== NULL
) return WAVERR_BADFORMAT
;
2161 if ((dwFlags
& WAVE_MAPPED
) && (uDeviceID
== (UINT
)-1))
2162 return MMSYSERR_INVALPARAM
;
2164 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
2165 lpFormat
->wFormatTag
, lpFormat
->nChannels
, lpFormat
->nSamplesPerSec
,
2166 lpFormat
->nAvgBytesPerSec
, lpFormat
->nBlockAlign
, lpFormat
->wBitsPerSample
, lpFormat
->cbSize
);
2168 if ((wmld
= MMDRV_Alloc(sizeof(WINE_WAVE
), uType
, &handle
,
2169 &dwFlags
, &dwCallback
, &dwInstance
, bFrom32
)) == NULL
)
2170 return MMSYSERR_NOMEM
;
2173 wod
.lpFormat
= lpFormat
; /* should the struct be copied iso pointer? */
2174 wod
.dwCallback
= dwCallback
;
2175 wod
.dwInstance
= dwInstance
;
2178 TRACE("cb=%08lx\n", wod
.dwCallback
);
2181 if (dwFlags
& WAVE_MAPPED
) {
2182 wod
.uMappedDeviceID
= uDeviceID
;
2183 uDeviceID
= WAVE_MAPPER
;
2185 wod
.uMappedDeviceID
= -1;
2187 wmld
->uDeviceID
= uDeviceID
;
2189 dwRet
= MMDRV_Open(wmld
, (uType
== MMDRV_WAVEOUT
) ? WODM_OPEN
: WIDM_OPEN
,
2190 (DWORD
)&wod
, dwFlags
);
2192 if (dwRet
!= WAVERR_BADFORMAT
||
2193 (dwFlags
& (WAVE_MAPPED
|WAVE_FORMAT_DIRECT
)) != 0) break;
2194 /* if we ask for a format which isn't supported by the physical driver,
2195 * let's try to map it through the wave mapper (except, if we already tried
2196 * or user didn't allow us to use acm codecs)
2198 dwFlags
|= WAVE_MAPPED
;
2199 /* we shall loop only one */
2202 if ((dwFlags
& WAVE_FORMAT_QUERY
) || dwRet
!= MMSYSERR_NOERROR
) {
2203 MMDRV_Free(handle
, wmld
);
2207 if (lphndl
!= NULL
) *lphndl
= handle
;
2208 TRACE("=> %ld hWave=%p\n", dwRet
, handle
);
2213 /**************************************************************************
2214 * waveOutGetNumDevs [WINMM.@]
2216 UINT WINAPI
waveOutGetNumDevs(void)
2218 return MMDRV_GetNum(MMDRV_WAVEOUT
);
2221 /**************************************************************************
2222 * waveOutGetDevCapsA [WINMM.@]
2224 UINT WINAPI
waveOutGetDevCapsA(UINT uDeviceID
, LPWAVEOUTCAPSA lpCaps
,
2229 TRACE("(%u %p %u)!\n", uDeviceID
, lpCaps
, uSize
);
2231 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
2233 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_WAVEOUT
, TRUE
)) == NULL
)
2234 return MMSYSERR_BADDEVICEID
;
2236 return MMDRV_Message(wmld
, WODM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
2240 /**************************************************************************
2241 * waveOutGetDevCapsW [WINMM.@]
2243 UINT WINAPI
waveOutGetDevCapsW(UINT uDeviceID
, LPWAVEOUTCAPSW lpCaps
,
2249 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
2251 ret
= waveOutGetDevCapsA(uDeviceID
, &wocA
, sizeof(wocA
));
2253 if (ret
== MMSYSERR_NOERROR
) {
2254 lpCaps
->wMid
= wocA
.wMid
;
2255 lpCaps
->wPid
= wocA
.wPid
;
2256 lpCaps
->vDriverVersion
= wocA
.vDriverVersion
;
2257 MultiByteToWideChar( CP_ACP
, 0, wocA
.szPname
, -1, lpCaps
->szPname
,
2258 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
2259 lpCaps
->dwFormats
= wocA
.dwFormats
;
2260 lpCaps
->wChannels
= wocA
.wChannels
;
2261 lpCaps
->dwSupport
= wocA
.dwSupport
;
2266 /**************************************************************************
2267 * WAVE_GetErrorText [internal]
2269 static UINT16
WAVE_GetErrorText(UINT16 uError
, LPSTR lpText
, UINT16 uSize
)
2271 UINT16 ret
= MMSYSERR_BADERRNUM
;
2273 if (lpText
== NULL
) {
2274 ret
= MMSYSERR_INVALPARAM
;
2275 } else if (uSize
== 0) {
2276 ret
= MMSYSERR_NOERROR
;
2278 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2279 * a warning for the test was always true */
2280 (/*uError >= MMSYSERR_BASE && */uError
<= MMSYSERR_LASTERROR
) ||
2281 (uError
>= WAVERR_BASE
&& uError
<= WAVERR_LASTERROR
)) {
2283 if (LoadStringA(WINMM_IData
->hWinMM32Instance
,
2284 uError
, lpText
, uSize
) > 0) {
2285 ret
= MMSYSERR_NOERROR
;
2291 /**************************************************************************
2292 * waveOutGetErrorTextA [WINMM.@]
2294 UINT WINAPI
waveOutGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
2296 return WAVE_GetErrorText(uError
, lpText
, uSize
);
2299 /**************************************************************************
2300 * waveOutGetErrorTextW [WINMM.@]
2302 UINT WINAPI
waveOutGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
2304 LPSTR xstr
= HeapAlloc(GetProcessHeap(), 0, uSize
);
2305 UINT ret
= WAVE_GetErrorText(uError
, xstr
, uSize
);
2307 MultiByteToWideChar( CP_ACP
, 0, xstr
, -1, lpText
, uSize
);
2308 HeapFree(GetProcessHeap(), 0, xstr
);
2312 /**************************************************************************
2313 * waveOutOpen [WINMM.@]
2314 * All the args/structs have the same layout as the win16 equivalents
2316 UINT WINAPI
waveOutOpen(HWAVEOUT
* lphWaveOut
, UINT uDeviceID
,
2317 const LPWAVEFORMATEX lpFormat
, DWORD dwCallback
,
2318 DWORD dwInstance
, DWORD dwFlags
)
2320 return WAVE_Open((HANDLE
*)lphWaveOut
, uDeviceID
, MMDRV_WAVEOUT
, lpFormat
,
2321 dwCallback
, dwInstance
, dwFlags
, TRUE
);
2324 /**************************************************************************
2325 * waveOutClose [WINMM.@]
2327 UINT WINAPI
waveOutClose(HWAVEOUT hWaveOut
)
2332 TRACE("(%p)\n", hWaveOut
);
2334 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2335 return MMSYSERR_INVALHANDLE
;
2337 dwRet
= MMDRV_Close(wmld
, WODM_CLOSE
);
2338 MMDRV_Free(hWaveOut
, wmld
);
2343 /**************************************************************************
2344 * waveOutPrepareHeader [WINMM.@]
2346 UINT WINAPI
waveOutPrepareHeader(HWAVEOUT hWaveOut
,
2347 WAVEHDR
* lpWaveOutHdr
, UINT uSize
)
2351 TRACE("(%p, %p, %u);\n", hWaveOut
, lpWaveOutHdr
, uSize
);
2353 if (lpWaveOutHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2355 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2356 return MMSYSERR_INVALHANDLE
;
2358 return MMDRV_Message(wmld
, WODM_PREPARE
, (DWORD
)lpWaveOutHdr
, uSize
, TRUE
);
2361 /**************************************************************************
2362 * waveOutUnprepareHeader [WINMM.@]
2364 UINT WINAPI
waveOutUnprepareHeader(HWAVEOUT hWaveOut
,
2365 LPWAVEHDR lpWaveOutHdr
, UINT uSize
)
2369 TRACE("(%p, %p, %u);\n", hWaveOut
, lpWaveOutHdr
, uSize
);
2371 if (!(lpWaveOutHdr
->dwFlags
& WHDR_PREPARED
)) {
2372 return MMSYSERR_NOERROR
;
2375 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2376 return MMSYSERR_INVALHANDLE
;
2378 return MMDRV_Message(wmld
, WODM_UNPREPARE
, (DWORD
)lpWaveOutHdr
, uSize
, TRUE
);
2381 /**************************************************************************
2382 * waveOutWrite [WINMM.@]
2384 UINT WINAPI
waveOutWrite(HWAVEOUT hWaveOut
, LPWAVEHDR lpWaveOutHdr
,
2389 TRACE("(%p, %p, %u);\n", hWaveOut
, lpWaveOutHdr
, uSize
);
2391 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2392 return MMSYSERR_INVALHANDLE
;
2394 return MMDRV_Message(wmld
, WODM_WRITE
, (DWORD
)lpWaveOutHdr
, uSize
, TRUE
);
2397 /**************************************************************************
2398 * waveOutBreakLoop [WINMM.@]
2400 UINT WINAPI
waveOutBreakLoop(HWAVEOUT hWaveOut
)
2404 TRACE("(%p);\n", hWaveOut
);
2406 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2407 return MMSYSERR_INVALHANDLE
;
2408 return MMDRV_Message(wmld
, WODM_BREAKLOOP
, 0L, 0L, TRUE
);
2411 /**************************************************************************
2412 * waveOutPause [WINMM.@]
2414 UINT WINAPI
waveOutPause(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_PAUSE
, 0L, 0L, TRUE
);
2425 /**************************************************************************
2426 * waveOutReset [WINMM.@]
2428 UINT WINAPI
waveOutReset(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_RESET
, 0L, 0L, TRUE
);
2439 /**************************************************************************
2440 * waveOutRestart [WINMM.@]
2442 UINT WINAPI
waveOutRestart(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_RESTART
, 0L, 0L, TRUE
);
2453 /**************************************************************************
2454 * waveOutGetPosition [WINMM.@]
2456 UINT WINAPI
waveOutGetPosition(HWAVEOUT hWaveOut
, LPMMTIME lpTime
,
2461 TRACE("(%p, %p, %u);\n", hWaveOut
, lpTime
, uSize
);
2463 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2464 return MMSYSERR_INVALHANDLE
;
2466 return MMDRV_Message(wmld
, WODM_GETPOS
, (DWORD
)lpTime
, uSize
, TRUE
);
2469 /**************************************************************************
2470 * waveOutGetPitch [WINMM.@]
2472 UINT WINAPI
waveOutGetPitch(HWAVEOUT hWaveOut
, LPDWORD lpdw
)
2476 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)lpdw
);
2478 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2479 return MMSYSERR_INVALHANDLE
;
2480 return MMDRV_Message(wmld
, WODM_GETPITCH
, (DWORD
)lpdw
, 0L, TRUE
);
2483 /**************************************************************************
2484 * waveOutSetPitch [WINMM.@]
2486 UINT WINAPI
waveOutSetPitch(HWAVEOUT hWaveOut
, DWORD dw
)
2490 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)dw
);
2492 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2493 return MMSYSERR_INVALHANDLE
;
2494 return MMDRV_Message(wmld
, WODM_SETPITCH
, dw
, 0L, TRUE
);
2497 /**************************************************************************
2498 * waveOutGetPlaybackRate [WINMM.@]
2500 UINT WINAPI
waveOutGetPlaybackRate(HWAVEOUT hWaveOut
, LPDWORD lpdw
)
2504 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)lpdw
);
2506 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2507 return MMSYSERR_INVALHANDLE
;
2508 return MMDRV_Message(wmld
, WODM_GETPLAYBACKRATE
, (DWORD
)lpdw
, 0L, TRUE
);
2511 /**************************************************************************
2512 * waveOutSetPlaybackRate [WINMM.@]
2514 UINT WINAPI
waveOutSetPlaybackRate(HWAVEOUT hWaveOut
, DWORD dw
)
2518 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)dw
);
2520 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2521 return MMSYSERR_INVALHANDLE
;
2522 return MMDRV_Message(wmld
, WODM_SETPLAYBACKRATE
, dw
, 0L, TRUE
);
2525 /**************************************************************************
2526 * waveOutGetVolume [WINMM.@]
2528 UINT WINAPI
waveOutGetVolume(HWAVEOUT hWaveOut
, LPDWORD lpdw
)
2532 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)lpdw
);
2534 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, TRUE
)) == NULL
)
2535 return MMSYSERR_INVALHANDLE
;
2537 return MMDRV_Message(wmld
, WODM_GETVOLUME
, (DWORD
)lpdw
, 0L, TRUE
);
2540 /**************************************************************************
2541 * waveOutSetVolume [WINMM.@]
2543 UINT WINAPI
waveOutSetVolume(HWAVEOUT hWaveOut
, DWORD dw
)
2547 TRACE("(%p, %08lx);\n", hWaveOut
, dw
);
2549 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, TRUE
)) == NULL
)
2550 return MMSYSERR_INVALHANDLE
;
2552 return MMDRV_Message(wmld
, WODM_SETVOLUME
, dw
, 0L, TRUE
);
2555 /**************************************************************************
2556 * waveOutGetID [WINMM.@]
2558 UINT WINAPI
waveOutGetID(HWAVEOUT hWaveOut
, UINT
* lpuDeviceID
)
2562 TRACE("(%p, %p);\n", hWaveOut
, lpuDeviceID
);
2564 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALHANDLE
;
2566 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2567 return MMSYSERR_INVALHANDLE
;
2569 *lpuDeviceID
= wmld
->uDeviceID
;
2573 /**************************************************************************
2574 * waveOutMessage [WINMM.@]
2576 DWORD WINAPI
waveOutMessage(HWAVEOUT hWaveOut
, UINT uMessage
,
2577 DWORD dwParam1
, DWORD dwParam2
)
2581 TRACE("(%p, %u, %ld, %ld)\n", hWaveOut
, uMessage
, dwParam1
, dwParam2
);
2583 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
) {
2584 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, TRUE
)) != NULL
) {
2585 return MMDRV_PhysicalFeatures(wmld
, uMessage
, dwParam1
, dwParam2
);
2587 return MMSYSERR_INVALHANDLE
;
2591 if (uMessage
< DRVM_IOCTL
|| (uMessage
>= DRVM_IOCTL_LAST
&& uMessage
< DRVM_MAPPER
))
2592 return MMSYSERR_INVALPARAM
;
2594 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
2597 /**************************************************************************
2598 * waveInGetNumDevs [WINMM.@]
2600 UINT WINAPI
waveInGetNumDevs(void)
2602 return MMDRV_GetNum(MMDRV_WAVEIN
);
2605 /**************************************************************************
2606 * waveInGetDevCapsW [WINMM.@]
2608 UINT WINAPI
waveInGetDevCapsW(UINT uDeviceID
, LPWAVEINCAPSW lpCaps
, UINT uSize
)
2611 UINT ret
= waveInGetDevCapsA(uDeviceID
, &wicA
, uSize
);
2613 if (ret
== MMSYSERR_NOERROR
) {
2614 lpCaps
->wMid
= wicA
.wMid
;
2615 lpCaps
->wPid
= wicA
.wPid
;
2616 lpCaps
->vDriverVersion
= wicA
.vDriverVersion
;
2617 MultiByteToWideChar( CP_ACP
, 0, wicA
.szPname
, -1, lpCaps
->szPname
,
2618 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
2619 lpCaps
->dwFormats
= wicA
.dwFormats
;
2620 lpCaps
->wChannels
= wicA
.wChannels
;
2626 /**************************************************************************
2627 * waveInGetDevCapsA [WINMM.@]
2629 UINT WINAPI
waveInGetDevCapsA(UINT uDeviceID
, LPWAVEINCAPSA lpCaps
, UINT uSize
)
2633 TRACE("(%u %p %u)!\n", uDeviceID
, lpCaps
, uSize
);
2635 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_WAVEIN
, TRUE
)) == NULL
)
2636 return MMSYSERR_BADDEVICEID
;
2638 return MMDRV_Message(wmld
, WIDM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
2641 /**************************************************************************
2642 * waveInGetErrorTextA [WINMM.@]
2644 UINT WINAPI
waveInGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
2646 return WAVE_GetErrorText(uError
, lpText
, uSize
);
2649 /**************************************************************************
2650 * waveInGetErrorTextW [WINMM.@]
2652 UINT WINAPI
waveInGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
2654 LPSTR txt
= HeapAlloc(GetProcessHeap(), 0, uSize
);
2655 UINT ret
= WAVE_GetErrorText(uError
, txt
, uSize
);
2657 MultiByteToWideChar( CP_ACP
, 0, txt
, -1, lpText
, uSize
);
2658 HeapFree(GetProcessHeap(), 0, txt
);
2662 /**************************************************************************
2663 * waveInOpen [WINMM.@]
2665 UINT WINAPI
waveInOpen(HWAVEIN
* lphWaveIn
, UINT uDeviceID
,
2666 const LPWAVEFORMATEX lpFormat
, DWORD dwCallback
,
2667 DWORD dwInstance
, DWORD dwFlags
)
2669 return WAVE_Open((HANDLE
*)lphWaveIn
, uDeviceID
, MMDRV_WAVEIN
, lpFormat
,
2670 dwCallback
, dwInstance
, dwFlags
, TRUE
);
2673 /**************************************************************************
2674 * waveInClose [WINMM.@]
2676 UINT WINAPI
waveInClose(HWAVEIN hWaveIn
)
2681 TRACE("(%p)\n", hWaveIn
);
2683 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2684 return MMSYSERR_INVALHANDLE
;
2686 dwRet
= MMDRV_Message(wmld
, WIDM_CLOSE
, 0L, 0L, TRUE
);
2687 MMDRV_Free(hWaveIn
, wmld
);
2691 /**************************************************************************
2692 * waveInPrepareHeader [WINMM.@]
2694 UINT WINAPI
waveInPrepareHeader(HWAVEIN hWaveIn
, WAVEHDR
* lpWaveInHdr
,
2699 TRACE("(%p, %p, %u);\n", hWaveIn
, lpWaveInHdr
, uSize
);
2701 if (lpWaveInHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2702 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2703 return MMSYSERR_INVALHANDLE
;
2705 lpWaveInHdr
->dwBytesRecorded
= 0;
2707 return MMDRV_Message(wmld
, WIDM_PREPARE
, (DWORD
)lpWaveInHdr
, uSize
, TRUE
);
2710 /**************************************************************************
2711 * waveInUnprepareHeader [WINMM.@]
2713 UINT WINAPI
waveInUnprepareHeader(HWAVEIN hWaveIn
, WAVEHDR
* lpWaveInHdr
,
2718 TRACE("(%p, %p, %u);\n", hWaveIn
, lpWaveInHdr
, uSize
);
2720 if (lpWaveInHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2721 if (!(lpWaveInHdr
->dwFlags
& WHDR_PREPARED
)) {
2722 return MMSYSERR_NOERROR
;
2725 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2726 return MMSYSERR_INVALHANDLE
;
2728 return MMDRV_Message(wmld
, WIDM_UNPREPARE
, (DWORD
)lpWaveInHdr
, uSize
, TRUE
);
2731 /**************************************************************************
2732 * waveInAddBuffer [WINMM.@]
2734 UINT WINAPI
waveInAddBuffer(HWAVEIN hWaveIn
,
2735 WAVEHDR
* lpWaveInHdr
, UINT uSize
)
2739 TRACE("(%p, %p, %u);\n", hWaveIn
, lpWaveInHdr
, uSize
);
2741 if (lpWaveInHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2742 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2743 return MMSYSERR_INVALHANDLE
;
2745 return MMDRV_Message(wmld
, WIDM_ADDBUFFER
, (DWORD
)lpWaveInHdr
, uSize
, TRUE
);
2748 /**************************************************************************
2749 * waveInReset [WINMM.@]
2751 UINT WINAPI
waveInReset(HWAVEIN hWaveIn
)
2755 TRACE("(%p);\n", hWaveIn
);
2757 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2758 return MMSYSERR_INVALHANDLE
;
2760 return MMDRV_Message(wmld
, WIDM_RESET
, 0L, 0L, TRUE
);
2763 /**************************************************************************
2764 * waveInStart [WINMM.@]
2766 UINT WINAPI
waveInStart(HWAVEIN hWaveIn
)
2770 TRACE("(%p);\n", hWaveIn
);
2772 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2773 return MMSYSERR_INVALHANDLE
;
2775 return MMDRV_Message(wmld
, WIDM_START
, 0L, 0L, TRUE
);
2778 /**************************************************************************
2779 * waveInStop [WINMM.@]
2781 UINT WINAPI
waveInStop(HWAVEIN hWaveIn
)
2785 TRACE("(%p);\n", hWaveIn
);
2787 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2788 return MMSYSERR_INVALHANDLE
;
2790 return MMDRV_Message(wmld
,WIDM_STOP
, 0L, 0L, TRUE
);
2793 /**************************************************************************
2794 * waveInGetPosition [WINMM.@]
2796 UINT WINAPI
waveInGetPosition(HWAVEIN hWaveIn
, LPMMTIME lpTime
,
2801 TRACE("(%p, %p, %u);\n", hWaveIn
, lpTime
, uSize
);
2803 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2804 return MMSYSERR_INVALHANDLE
;
2806 return MMDRV_Message(wmld
, WIDM_GETPOS
, (DWORD
)lpTime
, uSize
, TRUE
);
2809 /**************************************************************************
2810 * waveInGetID [WINMM.@]
2812 UINT WINAPI
waveInGetID(HWAVEIN hWaveIn
, UINT
* lpuDeviceID
)
2816 TRACE("(%p, %p);\n", hWaveIn
, lpuDeviceID
);
2818 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALHANDLE
;
2820 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2821 return MMSYSERR_INVALHANDLE
;
2823 *lpuDeviceID
= wmld
->uDeviceID
;
2824 return MMSYSERR_NOERROR
;
2827 /**************************************************************************
2828 * waveInMessage [WINMM.@]
2830 DWORD WINAPI
waveInMessage(HWAVEIN hWaveIn
, UINT uMessage
,
2831 DWORD dwParam1
, DWORD dwParam2
)
2835 TRACE("(%p, %u, %ld, %ld)\n", hWaveIn
, uMessage
, dwParam1
, dwParam2
);
2837 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
) {
2838 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, TRUE
)) != NULL
) {
2839 return MMDRV_PhysicalFeatures(wmld
, uMessage
, dwParam1
, dwParam2
);
2841 return MMSYSERR_INVALHANDLE
;
2845 if (uMessage
< DRVM_IOCTL
|| (uMessage
>= DRVM_IOCTL_LAST
&& uMessage
< DRVM_MAPPER
))
2846 return MMSYSERR_INVALPARAM
;
2849 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);