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
38 #include "wine/winuser16.h" /* FIXME: should be removed */
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(winmm
);
47 /* ========================================================================
48 * T I M E C O N V E R S I O N F U N C T I O N S
49 * ========================================================================*/
51 /* FIXME: should be in mmsystem.c */
53 void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16
, const MMTIME
* mmt32
)
55 mmt16
->wType
= mmt32
->wType
;
56 /* layout of rest is the same for 32/16,
57 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
59 memcpy(&(mmt16
->u
), &(mmt32
->u
), sizeof(mmt16
->u
));
62 void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32
, const MMTIME16
* mmt16
)
64 mmt32
->wType
= mmt16
->wType
;
65 /* layout of rest is the same for 32/16,
66 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
68 memcpy(&(mmt32
->u
), &(mmt16
->u
), sizeof(mmt16
->u
));
71 /* ========================================================================
72 * G L O B A L S E T T I N G S
73 * ========================================================================*/
75 LPWINE_MM_IDATA WINMM_IData
/* = NULL */;
77 /**************************************************************************
78 * WINMM_CreateIData [internal]
80 static BOOL
WINMM_CreateIData(HINSTANCE hInstDLL
)
82 WINMM_IData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WINE_MM_IDATA
));
86 WINMM_IData
->hWinMM32Instance
= hInstDLL
;
87 InitializeCriticalSection(&WINMM_IData
->cs
);
88 WINMM_IData
->cs
.DebugInfo
= (void*)__FILE__
": WinMM";
89 WINMM_IData
->psStopEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
90 WINMM_IData
->psLastEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
91 TRACE("Created IData (%p)\n", WINMM_IData
);
95 /**************************************************************************
96 * WINMM_DeleteIData [internal]
98 static void WINMM_DeleteIData(void)
103 /* FIXME: should also free content and resources allocated
104 * inside WINMM_IData */
105 CloseHandle(WINMM_IData
->psStopEvent
);
106 CloseHandle(WINMM_IData
->psLastEvent
);
107 DeleteCriticalSection(&WINMM_IData
->cs
);
108 HeapFree(GetProcessHeap(), 0, WINMM_IData
);
113 /******************************************************************
117 BOOL
WINMM_CheckForMMSystem(void)
119 /* 0 is not checked yet, -1 is not present, 1 is present */
120 static int loaded
/* = 0 */;
124 HANDLE h
= GetModuleHandleA("kernel32");
128 HANDLE (WINAPI
*gmh
)(LPCSTR
) = (void*)GetProcAddress(h
, "GetModuleHandle16");
129 DWORD (WINAPI
*ll
)(LPCSTR
) = (void*)GetProcAddress(h
, "LoadLibrary16");
130 if (gmh
&& ll
&& (gmh("MMSYSTEM.DLL") || ll("MMSYSTEM.DLL")))
137 /**************************************************************************
138 * DllEntryPoint (WINMM.init)
140 * WINMM DLL entry point
143 BOOL WINAPI
WINMM_LibMain(HINSTANCE hInstDLL
, DWORD fdwReason
, LPVOID fImpLoad
)
145 TRACE("0x%x 0x%lx %p\n", hInstDLL
, fdwReason
, fImpLoad
);
148 case DLL_PROCESS_ATTACH
:
149 if (!WINMM_CreateIData(hInstDLL
))
151 if (!MCI_Init() || !MMDRV_Init()) {
156 case DLL_PROCESS_DETACH
:
159 case DLL_THREAD_ATTACH
:
160 case DLL_THREAD_DETACH
:
166 /**************************************************************************
167 * Mixer devices. New to Win95
170 /**************************************************************************
171 * find out the real mixer ID depending on hmix (depends on dwFlags)
173 static LPWINE_MIXER
MIXER_GetDev(HMIXEROBJ hmix
, DWORD dwFlags
)
175 LPWINE_MIXER lpwm
= NULL
;
177 switch (dwFlags
& 0xF0000000ul
) {
178 case MIXER_OBJECTF_MIXER
:
179 lpwm
= (LPWINE_MIXER
)MMDRV_Get(hmix
, MMDRV_MIXER
, TRUE
);
181 case MIXER_OBJECTF_HMIXER
:
182 lpwm
= (LPWINE_MIXER
)MMDRV_Get(hmix
, MMDRV_MIXER
, FALSE
);
184 case MIXER_OBJECTF_WAVEOUT
:
185 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEOUT
, TRUE
, MMDRV_MIXER
);
187 case MIXER_OBJECTF_HWAVEOUT
:
188 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEOUT
, FALSE
, MMDRV_MIXER
);
190 case MIXER_OBJECTF_WAVEIN
:
191 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEIN
, TRUE
, MMDRV_MIXER
);
193 case MIXER_OBJECTF_HWAVEIN
:
194 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEIN
, FALSE
, MMDRV_MIXER
);
196 case MIXER_OBJECTF_MIDIOUT
:
197 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIOUT
, TRUE
, MMDRV_MIXER
);
199 case MIXER_OBJECTF_HMIDIOUT
:
200 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIOUT
, FALSE
, MMDRV_MIXER
);
202 case MIXER_OBJECTF_MIDIIN
:
203 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIIN
, TRUE
, MMDRV_MIXER
);
205 case MIXER_OBJECTF_HMIDIIN
:
206 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIIN
, FALSE
, MMDRV_MIXER
);
208 case MIXER_OBJECTF_AUX
:
209 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_AUX
, TRUE
, MMDRV_MIXER
);
212 FIXME("Unsupported flag (%08lx)\n", dwFlags
& 0xF0000000ul
);
218 /**************************************************************************
219 * mixerGetNumDevs [WINMM.@]
221 UINT WINAPI
mixerGetNumDevs(void)
223 return MMDRV_GetNum(MMDRV_MIXER
);
226 /**************************************************************************
227 * mixerGetDevCapsA [WINMM.@]
229 UINT WINAPI
mixerGetDevCapsA(UINT devid
, LPMIXERCAPSA mixcaps
, UINT size
)
233 if ((wmld
= MMDRV_Get(devid
, MMDRV_MIXER
, TRUE
)) == NULL
)
234 return MMSYSERR_BADDEVICEID
;
236 return MMDRV_Message(wmld
, MXDM_GETDEVCAPS
, (DWORD
)mixcaps
, size
, TRUE
);
239 /**************************************************************************
240 * mixerGetDevCapsW [WINMM.@]
242 UINT WINAPI
mixerGetDevCapsW(UINT devid
, LPMIXERCAPSW mixcaps
, UINT size
)
245 UINT ret
= mixerGetDevCapsA(devid
, &micA
, sizeof(micA
));
247 if (ret
== MMSYSERR_NOERROR
) {
248 mixcaps
->wMid
= micA
.wMid
;
249 mixcaps
->wPid
= micA
.wPid
;
250 mixcaps
->vDriverVersion
= micA
.vDriverVersion
;
251 MultiByteToWideChar( CP_ACP
, 0, micA
.szPname
, -1, mixcaps
->szPname
,
252 sizeof(mixcaps
->szPname
)/sizeof(WCHAR
) );
253 mixcaps
->fdwSupport
= micA
.fdwSupport
;
254 mixcaps
->cDestinations
= micA
.cDestinations
;
259 UINT
MMSYSTEM_mixerOpen(LPHMIXER lphMix
, UINT uDeviceID
, DWORD dwCallback
,
260 DWORD dwInstance
, DWORD fdwOpen
, BOOL bFrom32
)
267 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
268 lphMix
, uDeviceID
, dwCallback
, dwInstance
, fdwOpen
);
270 wmld
= MMDRV_Alloc(sizeof(WINE_MIXER
), MMDRV_MIXER
, &hMix
, &fdwOpen
,
271 &dwCallback
, &dwInstance
, bFrom32
);
273 wmld
->uDeviceID
= uDeviceID
;
274 mod
.hmx
= (HMIXEROBJ
)hMix
;
275 mod
.dwCallback
= dwCallback
;
276 mod
.dwInstance
= dwInstance
;
278 dwRet
= MMDRV_Open(wmld
, MXDM_OPEN
, (DWORD
)&mod
, fdwOpen
);
280 if (dwRet
!= MMSYSERR_NOERROR
) {
281 MMDRV_Free(hMix
, wmld
);
284 if (lphMix
) *lphMix
= hMix
;
285 TRACE("=> %ld hMixer=%04x\n", dwRet
, hMix
);
290 /**************************************************************************
291 * mixerOpen [WINMM.@]
293 UINT WINAPI
mixerOpen(LPHMIXER lphMix
, UINT uDeviceID
, DWORD dwCallback
,
294 DWORD dwInstance
, DWORD fdwOpen
)
296 return MMSYSTEM_mixerOpen(lphMix
, uDeviceID
,
297 dwCallback
, dwInstance
, fdwOpen
, TRUE
);
300 /**************************************************************************
301 * mixerClose [WINMM.@]
303 UINT WINAPI
mixerClose(HMIXER hMix
)
308 TRACE("(%04x)\n", hMix
);
310 if ((wmld
= MMDRV_Get(hMix
, MMDRV_MIXER
, FALSE
)) == NULL
) return MMSYSERR_INVALHANDLE
;
312 dwRet
= MMDRV_Close(wmld
, MXDM_CLOSE
);
313 MMDRV_Free(hMix
, wmld
);
318 /**************************************************************************
319 * mixerGetID [WINMM.@]
321 UINT WINAPI
mixerGetID(HMIXEROBJ hmix
, LPUINT lpid
, DWORD fdwID
)
325 TRACE("(%04x %p %08lx)\n", hmix
, lpid
, fdwID
);
327 if ((lpwm
= MIXER_GetDev(hmix
, fdwID
)) == NULL
) {
328 return MMSYSERR_INVALHANDLE
;
332 *lpid
= lpwm
->mld
.uDeviceID
;
334 return MMSYSERR_NOERROR
;
337 /**************************************************************************
338 * mixerGetControlDetailsA [WINMM.@]
340 UINT WINAPI
mixerGetControlDetailsA(HMIXEROBJ hmix
, LPMIXERCONTROLDETAILS lpmcdA
,
345 TRACE("(%04x, %p, %08lx)\n", hmix
, lpmcdA
, fdwDetails
);
347 if ((lpwm
= MIXER_GetDev(hmix
, fdwDetails
)) == NULL
)
348 return MMSYSERR_INVALHANDLE
;
350 if (lpmcdA
== NULL
|| lpmcdA
->cbStruct
!= sizeof(*lpmcdA
))
351 return MMSYSERR_INVALPARAM
;
353 return MMDRV_Message(&lpwm
->mld
, MXDM_GETCONTROLDETAILS
, (DWORD
)lpmcdA
,
357 /**************************************************************************
358 * mixerGetControlDetailsW [WINMM.@]
360 UINT WINAPI
mixerGetControlDetailsW(HMIXEROBJ hmix
, LPMIXERCONTROLDETAILS lpmcd
, DWORD fdwDetails
)
362 DWORD ret
= MMSYSERR_NOTENABLED
;
364 TRACE("(%04x, %p, %08lx)\n", hmix
, lpmcd
, fdwDetails
);
366 if (lpmcd
== NULL
|| lpmcd
->cbStruct
!= sizeof(*lpmcd
))
367 return MMSYSERR_INVALPARAM
;
369 switch (fdwDetails
& MIXER_GETCONTROLDETAILSF_QUERYMASK
) {
370 case MIXER_GETCONTROLDETAILSF_VALUE
:
371 /* can savely use W structure as it is, no string inside */
372 ret
= mixerGetControlDetailsA(hmix
, lpmcd
, fdwDetails
);
374 case MIXER_GETCONTROLDETAILSF_LISTTEXT
:
376 MIXERCONTROLDETAILS_LISTTEXTW
*pDetailsW
= (MIXERCONTROLDETAILS_LISTTEXTW
*)lpmcd
->paDetails
;
377 MIXERCONTROLDETAILS_LISTTEXTA
*pDetailsA
;
378 int size
= max(1, lpmcd
->cChannels
) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA
);
381 if (lpmcd
->u
.cMultipleItems
!= 0) {
382 size
*= lpmcd
->u
.cMultipleItems
;
384 pDetailsA
= (MIXERCONTROLDETAILS_LISTTEXTA
*)HeapAlloc(GetProcessHeap(), 0, size
);
385 lpmcd
->paDetails
= pDetailsA
;
386 lpmcd
->cbDetails
= sizeof(MIXERCONTROLDETAILS_LISTTEXTA
);
387 /* set up lpmcd->paDetails */
388 ret
= mixerGetControlDetailsA(hmix
, lpmcd
, fdwDetails
);
389 /* copy from lpmcd->paDetails back to paDetailsW; */
390 if(ret
== MMSYSERR_NOERROR
) {
391 for(i
=0;i
<lpmcd
->u
.cMultipleItems
*lpmcd
->cChannels
;i
++) {
392 pDetailsW
->dwParam1
= pDetailsA
->dwParam1
;
393 pDetailsW
->dwParam2
= pDetailsA
->dwParam2
;
394 MultiByteToWideChar( CP_ACP
, 0, pDetailsA
->szName
, -1,
396 sizeof(pDetailsW
->szName
)/sizeof(WCHAR
) );
400 pDetailsA
-= lpmcd
->u
.cMultipleItems
*lpmcd
->cChannels
;
401 pDetailsW
-= lpmcd
->u
.cMultipleItems
*lpmcd
->cChannels
;
403 HeapFree(GetProcessHeap(), 0, pDetailsA
);
404 lpmcd
->paDetails
= pDetailsW
;
405 lpmcd
->cbDetails
= sizeof(MIXERCONTROLDETAILS_LISTTEXTW
);
409 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails
);
415 /**************************************************************************
416 * mixerGetLineControlsA [WINMM.@]
418 UINT WINAPI
mixerGetLineControlsA(HMIXEROBJ hmix
, LPMIXERLINECONTROLSA lpmlcA
,
423 TRACE("(%04x, %p, %08lx)\n", hmix
, lpmlcA
, fdwControls
);
425 if ((lpwm
= MIXER_GetDev(hmix
, fdwControls
)) == NULL
)
426 return MMSYSERR_INVALHANDLE
;
428 if (lpmlcA
== NULL
|| lpmlcA
->cbStruct
!= sizeof(*lpmlcA
))
429 return MMSYSERR_INVALPARAM
;
431 return MMDRV_Message(&lpwm
->mld
, MXDM_GETLINECONTROLS
, (DWORD
)lpmlcA
,
435 /**************************************************************************
436 * mixerGetLineControlsW [WINMM.@]
438 UINT WINAPI
mixerGetLineControlsW(HMIXEROBJ hmix
, LPMIXERLINECONTROLSW lpmlcW
,
441 MIXERLINECONTROLSA mlcA
;
445 TRACE("(%04x, %p, %08lx)\n", hmix
, lpmlcW
, fdwControls
);
447 if (lpmlcW
== NULL
|| lpmlcW
->cbStruct
!= sizeof(*lpmlcW
) ||
448 lpmlcW
->cbmxctrl
!= sizeof(MIXERCONTROLW
))
449 return MMSYSERR_INVALPARAM
;
451 mlcA
.cbStruct
= sizeof(mlcA
);
452 mlcA
.dwLineID
= lpmlcW
->dwLineID
;
453 mlcA
.u
.dwControlID
= lpmlcW
->u
.dwControlID
;
454 mlcA
.u
.dwControlType
= lpmlcW
->u
.dwControlType
;
455 mlcA
.cControls
= lpmlcW
->cControls
;
456 mlcA
.cbmxctrl
= sizeof(MIXERCONTROLA
);
457 mlcA
.pamxctrl
= HeapAlloc(GetProcessHeap(), 0,
458 mlcA
.cControls
* mlcA
.cbmxctrl
);
460 ret
= mixerGetLineControlsA(hmix
, &mlcA
, fdwControls
);
462 if (ret
== MMSYSERR_NOERROR
) {
463 lpmlcW
->dwLineID
= mlcA
.dwLineID
;
464 lpmlcW
->u
.dwControlID
= mlcA
.u
.dwControlID
;
465 lpmlcW
->u
.dwControlType
= mlcA
.u
.dwControlType
;
466 lpmlcW
->cControls
= mlcA
.cControls
;
468 for (i
= 0; i
< mlcA
.cControls
; i
++) {
469 lpmlcW
->pamxctrl
[i
].cbStruct
= sizeof(MIXERCONTROLW
);
470 lpmlcW
->pamxctrl
[i
].dwControlID
= mlcA
.pamxctrl
[i
].dwControlID
;
471 lpmlcW
->pamxctrl
[i
].dwControlType
= mlcA
.pamxctrl
[i
].dwControlType
;
472 lpmlcW
->pamxctrl
[i
].fdwControl
= mlcA
.pamxctrl
[i
].fdwControl
;
473 lpmlcW
->pamxctrl
[i
].cMultipleItems
= mlcA
.pamxctrl
[i
].cMultipleItems
;
474 MultiByteToWideChar( CP_ACP
, 0, mlcA
.pamxctrl
[i
].szShortName
, -1,
475 lpmlcW
->pamxctrl
[i
].szShortName
,
476 sizeof(lpmlcW
->pamxctrl
[i
].szShortName
)/sizeof(WCHAR
) );
477 MultiByteToWideChar( CP_ACP
, 0, mlcA
.pamxctrl
[i
].szName
, -1,
478 lpmlcW
->pamxctrl
[i
].szName
,
479 sizeof(lpmlcW
->pamxctrl
[i
].szName
)/sizeof(WCHAR
) );
480 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
481 * sizeof(mlcA.pamxctrl[i].Bounds) */
482 memcpy(&lpmlcW
->pamxctrl
[i
].Bounds
, &mlcA
.pamxctrl
[i
].Bounds
,
483 sizeof(mlcA
.pamxctrl
[i
].Bounds
));
484 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
485 * sizeof(mlcA.pamxctrl[i].Metrics) */
486 memcpy(&lpmlcW
->pamxctrl
[i
].Metrics
, &mlcA
.pamxctrl
[i
].Metrics
,
487 sizeof(mlcA
.pamxctrl
[i
].Metrics
));
491 HeapFree(GetProcessHeap(), 0, mlcA
.pamxctrl
);
496 /**************************************************************************
497 * mixerGetLineInfoA [WINMM.@]
499 UINT WINAPI
mixerGetLineInfoA(HMIXEROBJ hmix
, LPMIXERLINEA lpmliW
, DWORD fdwInfo
)
503 TRACE("(%04x, %p, %08lx)\n", hmix
, lpmliW
, fdwInfo
);
505 if ((lpwm
= MIXER_GetDev(hmix
, fdwInfo
)) == NULL
)
506 return MMSYSERR_INVALHANDLE
;
508 return MMDRV_Message(&lpwm
->mld
, MXDM_GETLINEINFO
, (DWORD
)lpmliW
,
512 /**************************************************************************
513 * mixerGetLineInfoW [WINMM.@]
515 UINT WINAPI
mixerGetLineInfoW(HMIXEROBJ hmix
, LPMIXERLINEW lpmliW
,
521 TRACE("(%04x, %p, %08lx)\n", hmix
, lpmliW
, fdwInfo
);
523 if (lpmliW
== NULL
|| lpmliW
->cbStruct
!= sizeof(*lpmliW
))
524 return MMSYSERR_INVALPARAM
;
526 mliA
.cbStruct
= sizeof(mliA
);
527 switch (fdwInfo
& MIXER_GETLINEINFOF_QUERYMASK
) {
528 case MIXER_GETLINEINFOF_COMPONENTTYPE
:
529 mliA
.dwComponentType
= lpmliW
->dwComponentType
;
531 case MIXER_GETLINEINFOF_DESTINATION
:
532 mliA
.dwDestination
= lpmliW
->dwDestination
;
534 case MIXER_GETLINEINFOF_LINEID
:
535 mliA
.dwLineID
= lpmliW
->dwLineID
;
537 case MIXER_GETLINEINFOF_SOURCE
:
538 mliA
.dwDestination
= lpmliW
->dwDestination
;
539 mliA
.dwSource
= lpmliW
->dwSource
;
541 case MIXER_GETLINEINFOF_TARGETTYPE
:
542 mliA
.Target
.dwType
= lpmliW
->Target
.dwType
;
543 mliA
.Target
.wMid
= lpmliW
->Target
.wMid
;
544 mliA
.Target
.wPid
= lpmliW
->Target
.wPid
;
545 mliA
.Target
.vDriverVersion
= lpmliW
->Target
.vDriverVersion
;
546 WideCharToMultiByte( CP_ACP
, 0, lpmliW
->Target
.szPname
, -1, mliA
.Target
.szPname
, sizeof(mliA
.Target
.szPname
), NULL
, NULL
);
549 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo
);
552 ret
= mixerGetLineInfoA(hmix
, &mliA
, fdwInfo
);
554 lpmliW
->dwDestination
= mliA
.dwDestination
;
555 lpmliW
->dwSource
= mliA
.dwSource
;
556 lpmliW
->dwLineID
= mliA
.dwLineID
;
557 lpmliW
->fdwLine
= mliA
.fdwLine
;
558 lpmliW
->dwUser
= mliA
.dwUser
;
559 lpmliW
->dwComponentType
= mliA
.dwComponentType
;
560 lpmliW
->cChannels
= mliA
.cChannels
;
561 lpmliW
->cConnections
= mliA
.cConnections
;
562 lpmliW
->cControls
= mliA
.cControls
;
563 MultiByteToWideChar( CP_ACP
, 0, mliA
.szShortName
, -1, lpmliW
->szShortName
,
564 sizeof(lpmliW
->szShortName
)/sizeof(WCHAR
) );
565 MultiByteToWideChar( CP_ACP
, 0, mliA
.szName
, -1, lpmliW
->szName
,
566 sizeof(lpmliW
->szName
)/sizeof(WCHAR
) );
567 lpmliW
->Target
.dwType
= mliA
.Target
.dwType
;
568 lpmliW
->Target
.dwDeviceID
= mliA
.Target
.dwDeviceID
;
569 lpmliW
->Target
.wMid
= mliA
.Target
.wMid
;
570 lpmliW
->Target
.wPid
= mliA
.Target
.wPid
;
571 lpmliW
->Target
.vDriverVersion
= mliA
.Target
.vDriverVersion
;
572 MultiByteToWideChar( CP_ACP
, 0, mliA
.Target
.szPname
, -1, lpmliW
->Target
.szPname
,
573 sizeof(lpmliW
->Target
.szPname
)/sizeof(WCHAR
) );
578 /**************************************************************************
579 * mixerSetControlDetails [WINMM.@]
581 UINT WINAPI
mixerSetControlDetails(HMIXEROBJ hmix
, LPMIXERCONTROLDETAILS lpmcdA
,
586 TRACE("(%04x, %p, %08lx)\n", hmix
, lpmcdA
, fdwDetails
);
588 if ((lpwm
= MIXER_GetDev(hmix
, fdwDetails
)) == NULL
)
589 return MMSYSERR_INVALHANDLE
;
591 return MMDRV_Message(&lpwm
->mld
, MXDM_SETCONTROLDETAILS
, (DWORD
)lpmcdA
,
595 /**************************************************************************
596 * mixerMessage [WINMM.@]
598 UINT WINAPI
mixerMessage(HMIXER hmix
, UINT uMsg
, DWORD dwParam1
, DWORD dwParam2
)
602 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
603 (DWORD
)hmix
, uMsg
, dwParam1
, dwParam2
);
605 if ((wmld
= MMDRV_Get(hmix
, MMDRV_MIXER
, FALSE
)) == NULL
)
606 return MMSYSERR_INVALHANDLE
;
608 return MMDRV_Message(wmld
, uMsg
, dwParam1
, dwParam2
, TRUE
);
611 /**************************************************************************
612 * auxGetNumDevs [WINMM.@]
614 UINT WINAPI
auxGetNumDevs(void)
616 return MMDRV_GetNum(MMDRV_AUX
);
619 /**************************************************************************
620 * auxGetDevCapsW [WINMM.@]
622 UINT WINAPI
auxGetDevCapsW(UINT uDeviceID
, LPAUXCAPSW lpCaps
, UINT uSize
)
625 UINT ret
= auxGetDevCapsA(uDeviceID
, &acA
, sizeof(acA
));
627 lpCaps
->wMid
= acA
.wMid
;
628 lpCaps
->wPid
= acA
.wPid
;
629 lpCaps
->vDriverVersion
= acA
.vDriverVersion
;
630 MultiByteToWideChar( CP_ACP
, 0, acA
.szPname
, -1, lpCaps
->szPname
,
631 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
632 lpCaps
->wTechnology
= acA
.wTechnology
;
633 lpCaps
->dwSupport
= acA
.dwSupport
;
637 /**************************************************************************
638 * auxGetDevCapsA [WINMM.@]
640 UINT WINAPI
auxGetDevCapsA(UINT uDeviceID
, LPAUXCAPSA lpCaps
, UINT uSize
)
644 TRACE("(%04X, %p, %d) !\n", uDeviceID
, lpCaps
, uSize
);
646 if ((wmld
= MMDRV_Get(uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
647 return MMSYSERR_INVALHANDLE
;
648 return MMDRV_Message(wmld
, AUXDM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
651 /**************************************************************************
652 * auxGetVolume [WINMM.@]
654 UINT WINAPI
auxGetVolume(UINT uDeviceID
, DWORD
* lpdwVolume
)
658 TRACE("(%04X, %p) !\n", uDeviceID
, lpdwVolume
);
660 if ((wmld
= MMDRV_Get(uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
661 return MMSYSERR_INVALHANDLE
;
662 return MMDRV_Message(wmld
, AUXDM_GETVOLUME
, (DWORD
)lpdwVolume
, 0L, TRUE
);
665 /**************************************************************************
666 * auxSetVolume [WINMM.@]
668 UINT WINAPI
auxSetVolume(UINT uDeviceID
, DWORD dwVolume
)
672 TRACE("(%04X, %lu) !\n", uDeviceID
, dwVolume
);
674 if ((wmld
= MMDRV_Get(uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
675 return MMSYSERR_INVALHANDLE
;
676 return MMDRV_Message(wmld
, AUXDM_SETVOLUME
, dwVolume
, 0L, TRUE
);
679 /**************************************************************************
680 * auxOutMessage [WINMM.@]
682 DWORD WINAPI
auxOutMessage(UINT uDeviceID
, UINT uMessage
, DWORD dw1
, DWORD dw2
)
686 if ((wmld
= MMDRV_Get(uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
687 return MMSYSERR_INVALHANDLE
;
689 return MMDRV_Message(wmld
, uMessage
, dw1
, dw2
, TRUE
);
692 /**************************************************************************
693 * mciGetErrorStringW [WINMM.@]
695 BOOL WINAPI
mciGetErrorStringW(DWORD wError
, LPWSTR lpstrBuffer
, UINT uLength
)
697 LPSTR bufstr
= HeapAlloc(GetProcessHeap(), 0, uLength
);
698 BOOL ret
= mciGetErrorStringA(wError
, bufstr
, uLength
);
700 MultiByteToWideChar( CP_ACP
, 0, bufstr
, -1, lpstrBuffer
, uLength
);
701 HeapFree(GetProcessHeap(), 0, bufstr
);
705 /**************************************************************************
706 * mciGetErrorStringA [WINMM.@]
708 BOOL WINAPI
mciGetErrorStringA(DWORD dwError
, LPSTR lpstrBuffer
, UINT uLength
)
712 if (lpstrBuffer
!= NULL
&& uLength
> 0 &&
713 dwError
>= MCIERR_BASE
&& dwError
<= MCIERR_CUSTOM_DRIVER_BASE
) {
715 if (LoadStringA(WINMM_IData
->hWinMM32Instance
,
716 dwError
, lpstrBuffer
, uLength
) > 0) {
723 /**************************************************************************
724 * mciDriverNotify [WINMM.@]
726 BOOL WINAPI
mciDriverNotify(HWND hWndCallBack
, UINT wDevID
, UINT wStatus
)
729 TRACE("(%08X, %04x, %04X)\n", hWndCallBack
, wDevID
, wStatus
);
731 return PostMessageA(hWndCallBack
, MM_MCINOTIFY
, wStatus
, wDevID
);
734 /**************************************************************************
735 * mciGetDriverData [WINMM.@]
737 DWORD WINAPI
mciGetDriverData(UINT uDeviceID
)
739 LPWINE_MCIDRIVER wmd
;
741 TRACE("(%04x)\n", uDeviceID
);
743 wmd
= MCI_GetDriver(uDeviceID
);
746 WARN("Bad uDeviceID\n");
750 return wmd
->dwPrivate
;
753 /**************************************************************************
754 * mciSetDriverData [WINMM.@]
756 BOOL WINAPI
mciSetDriverData(UINT uDeviceID
, DWORD data
)
758 LPWINE_MCIDRIVER wmd
;
760 TRACE("(%04x, %08lx)\n", uDeviceID
, data
);
762 wmd
= MCI_GetDriver(uDeviceID
);
765 WARN("Bad uDeviceID\n");
769 wmd
->dwPrivate
= data
;
773 /**************************************************************************
774 * mciSendCommandA [WINMM.@]
776 DWORD WINAPI
mciSendCommandA(UINT wDevID
, UINT wMsg
, DWORD dwParam1
, DWORD dwParam2
)
780 TRACE("(%08x, %s, %08lx, %08lx)\n",
781 wDevID
, MCI_MessageToString(wMsg
), dwParam1
, dwParam2
);
783 dwRet
= MCI_SendCommand(wDevID
, wMsg
, dwParam1
, dwParam2
, TRUE
);
784 dwRet
= MCI_CleanUp(dwRet
, wMsg
, dwParam2
);
785 TRACE("=> %08lx\n", dwRet
);
789 /**************************************************************************
790 * mciSendCommandW [WINMM.@]
792 DWORD WINAPI
mciSendCommandW(UINT wDevID
, UINT wMsg
, DWORD dwParam1
, DWORD dwParam2
)
794 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
795 wDevID
, MCI_MessageToString(wMsg
), dwParam1
, dwParam2
);
796 return MCIERR_UNSUPPORTED_FUNCTION
;
799 /**************************************************************************
800 * mciGetDeviceIDA [WINMM.@]
802 UINT WINAPI
mciGetDeviceIDA(LPCSTR lpstrName
)
804 return MCI_GetDriverFromString(lpstrName
);
807 /**************************************************************************
808 * mciGetDeviceIDW [WINMM.@]
810 UINT WINAPI
mciGetDeviceIDW(LPCWSTR lpwstrName
)
815 lpstrName
= HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName
);
816 ret
= MCI_GetDriverFromString(lpstrName
);
817 HeapFree(GetProcessHeap(), 0, lpstrName
);
821 /**************************************************************************
822 * MCI_DefYieldProc [internal]
824 UINT WINAPI
MCI_DefYieldProc(MCIDEVICEID wDevID
, DWORD data
)
828 TRACE("(0x%04x, 0x%08lx)\n", wDevID
, data
);
830 if ((HIWORD(data
) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data
)) ||
831 (GetAsyncKeyState(LOWORD(data
)) & 1) == 0) {
837 msg
.hwnd
= HWND_32(HIWORD(data
));
838 while (!PeekMessageA(&msg
, msg
.hwnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_REMOVE
));
844 /**************************************************************************
845 * mciSetYieldProc [WINMM.@]
847 BOOL WINAPI
mciSetYieldProc(UINT uDeviceID
, YIELDPROC fpYieldProc
, DWORD dwYieldData
)
849 LPWINE_MCIDRIVER wmd
;
851 TRACE("(%u, %p, %08lx)\n", uDeviceID
, fpYieldProc
, dwYieldData
);
853 if (!(wmd
= MCI_GetDriver(uDeviceID
))) {
854 WARN("Bad uDeviceID\n");
858 wmd
->lpfnYieldProc
= fpYieldProc
;
859 wmd
->dwYieldData
= dwYieldData
;
865 /**************************************************************************
866 * mciGetDeviceIDFromElementIDW [WINMM.@]
868 UINT WINAPI
mciGetDeviceIDFromElementIDW(DWORD dwElementID
, LPCWSTR lpstrType
)
870 /* FIXME: that's rather strange, there is no
871 * mciGetDeviceIDFromElementID32A in winmm.spec
873 FIXME("(%lu, %p) stub\n", dwElementID
, lpstrType
);
877 /**************************************************************************
878 * mciGetYieldProc [WINMM.@]
880 YIELDPROC WINAPI
mciGetYieldProc(UINT uDeviceID
, DWORD
* lpdwYieldData
)
882 LPWINE_MCIDRIVER wmd
;
884 TRACE("(%u, %p)\n", uDeviceID
, lpdwYieldData
);
886 if (!(wmd
= MCI_GetDriver(uDeviceID
))) {
887 WARN("Bad uDeviceID\n");
890 if (!wmd
->lpfnYieldProc
) {
891 WARN("No proc set\n");
895 WARN("Proc is 32 bit\n");
898 return wmd
->lpfnYieldProc
;
901 /**************************************************************************
902 * mciGetCreatorTask [WINMM.@]
904 HTASK WINAPI
mciGetCreatorTask(UINT uDeviceID
)
906 LPWINE_MCIDRIVER wmd
;
909 if ((wmd
= MCI_GetDriver(uDeviceID
))) ret
= (HTASK
)wmd
->CreatorThread
;
911 TRACE("(%u) => %08x\n", uDeviceID
, ret
);
915 /**************************************************************************
916 * mciDriverYield [WINMM.@]
918 UINT WINAPI
mciDriverYield(UINT uDeviceID
)
920 LPWINE_MCIDRIVER wmd
;
923 TRACE("(%04x)\n", uDeviceID
);
925 if (!(wmd
= MCI_GetDriver(uDeviceID
)) || !wmd
->lpfnYieldProc
|| !wmd
->bIs32
) {
928 ret
= wmd
->lpfnYieldProc(uDeviceID
, wmd
->dwYieldData
);
934 /**************************************************************************
935 * midiOutGetNumDevs [WINMM.@]
937 UINT WINAPI
midiOutGetNumDevs(void)
939 return MMDRV_GetNum(MMDRV_MIDIOUT
);
942 /**************************************************************************
943 * midiOutGetDevCapsW [WINMM.@]
945 UINT WINAPI
midiOutGetDevCapsW(UINT uDeviceID
, LPMIDIOUTCAPSW lpCaps
,
951 ret
= midiOutGetDevCapsA(uDeviceID
, &mocA
, sizeof(mocA
));
952 lpCaps
->wMid
= mocA
.wMid
;
953 lpCaps
->wPid
= mocA
.wPid
;
954 lpCaps
->vDriverVersion
= mocA
.vDriverVersion
;
955 MultiByteToWideChar( CP_ACP
, 0, mocA
.szPname
, -1, lpCaps
->szPname
,
956 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
957 lpCaps
->wTechnology
= mocA
.wTechnology
;
958 lpCaps
->wVoices
= mocA
.wVoices
;
959 lpCaps
->wNotes
= mocA
.wNotes
;
960 lpCaps
->wChannelMask
= mocA
.wChannelMask
;
961 lpCaps
->dwSupport
= mocA
.dwSupport
;
965 /**************************************************************************
966 * midiOutGetDevCapsA [WINMM.@]
968 UINT WINAPI
midiOutGetDevCapsA(UINT uDeviceID
, LPMIDIOUTCAPSA lpCaps
,
973 TRACE("(%u, %p, %u);\n", uDeviceID
, lpCaps
, uSize
);
975 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
977 if ((wmld
= MMDRV_Get(uDeviceID
, MMDRV_MIDIOUT
, TRUE
)) == NULL
)
978 return MMSYSERR_INVALHANDLE
;
980 return MMDRV_Message(wmld
, MODM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
983 /**************************************************************************
984 * MIDI_GetErrorText [internal]
986 static UINT16
MIDI_GetErrorText(UINT16 uError
, LPSTR lpText
, UINT16 uSize
)
988 UINT16 ret
= MMSYSERR_BADERRNUM
;
990 if (lpText
== NULL
) {
991 ret
= MMSYSERR_INVALPARAM
;
992 } else if (uSize
== 0) {
993 ret
= MMSYSERR_NOERROR
;
995 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
996 * a warning for the test was always true */
997 (/*uError >= MMSYSERR_BASE && */ uError
<= MMSYSERR_LASTERROR
) ||
998 (uError
>= MIDIERR_BASE
&& uError
<= MIDIERR_LASTERROR
)) {
1000 if (LoadStringA(WINMM_IData
->hWinMM32Instance
,
1001 uError
, lpText
, uSize
) > 0) {
1002 ret
= MMSYSERR_NOERROR
;
1008 /**************************************************************************
1009 * midiOutGetErrorTextA [WINMM.@]
1011 UINT WINAPI
midiOutGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
1013 return MIDI_GetErrorText(uError
, lpText
, uSize
);
1016 /**************************************************************************
1017 * midiOutGetErrorTextW [WINMM.@]
1019 UINT WINAPI
midiOutGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
1021 LPSTR xstr
= HeapAlloc(GetProcessHeap(), 0, uSize
);
1024 ret
= MIDI_GetErrorText(uError
, xstr
, uSize
);
1025 MultiByteToWideChar( CP_ACP
, 0, xstr
, -1, lpText
, uSize
);
1026 HeapFree(GetProcessHeap(), 0, xstr
);
1030 /**************************************************************************
1031 * MIDI_OutAlloc [internal]
1033 static LPWINE_MIDI
MIDI_OutAlloc(HMIDIOUT
* lphMidiOut
, LPDWORD lpdwCallback
,
1034 LPDWORD lpdwInstance
, LPDWORD lpdwFlags
,
1035 DWORD cIDs
, MIDIOPENSTRMID
* lpIDs
, BOOL bFrom32
)
1041 size
= sizeof(WINE_MIDI
) + (cIDs
? (cIDs
-1) : 0) * sizeof(MIDIOPENSTRMID
);
1043 lpwm
= (LPWINE_MIDI
)MMDRV_Alloc(size
, MMDRV_MIDIOUT
, &hMidiOut
, lpdwFlags
,
1044 lpdwCallback
, lpdwInstance
, bFrom32
);
1046 if (lphMidiOut
!= NULL
)
1047 *lphMidiOut
= hMidiOut
;
1050 lpwm
->mod
.hMidi
= (HMIDI
) hMidiOut
;
1051 lpwm
->mod
.dwCallback
= *lpdwCallback
;
1052 lpwm
->mod
.dwInstance
= *lpdwInstance
;
1053 lpwm
->mod
.dnDevNode
= 0;
1054 lpwm
->mod
.cIds
= cIDs
;
1056 memcpy(&(lpwm
->mod
.rgIds
), lpIDs
, cIDs
* sizeof(MIDIOPENSTRMID
));
1061 UINT
MMSYSTEM_midiOutOpen(HMIDIOUT
* lphMidiOut
, UINT uDeviceID
, DWORD dwCallback
,
1062 DWORD dwInstance
, DWORD dwFlags
, BOOL bFrom32
)
1068 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1069 lphMidiOut
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
);
1071 if (lphMidiOut
!= NULL
) *lphMidiOut
= 0;
1073 lpwm
= MIDI_OutAlloc(&hMidiOut
, &dwCallback
, &dwInstance
, &dwFlags
,
1077 return MMSYSERR_NOMEM
;
1079 lpwm
->mld
.uDeviceID
= uDeviceID
;
1081 dwRet
= MMDRV_Open((LPWINE_MLD
)lpwm
, MODM_OPEN
, (DWORD
)&lpwm
->mod
,
1084 if (dwRet
!= MMSYSERR_NOERROR
) {
1085 MMDRV_Free(hMidiOut
, (LPWINE_MLD
)lpwm
);
1089 if (lphMidiOut
) *lphMidiOut
= hMidiOut
;
1090 TRACE("=> %d hMidi=%04x\n", dwRet
, hMidiOut
);
1095 /**************************************************************************
1096 * midiOutOpen [WINMM.@]
1098 UINT WINAPI
midiOutOpen(HMIDIOUT
* lphMidiOut
, UINT uDeviceID
,
1099 DWORD dwCallback
, DWORD dwInstance
, DWORD dwFlags
)
1101 return MMSYSTEM_midiOutOpen(lphMidiOut
, uDeviceID
, dwCallback
,
1102 dwInstance
, dwFlags
, TRUE
);
1105 /**************************************************************************
1106 * midiOutClose [WINMM.@]
1108 UINT WINAPI
midiOutClose(HMIDIOUT hMidiOut
)
1113 TRACE("(%04X)\n", hMidiOut
);
1115 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1116 return MMSYSERR_INVALHANDLE
;
1118 dwRet
= MMDRV_Close(wmld
, MODM_CLOSE
);
1119 MMDRV_Free(hMidiOut
, wmld
);
1124 /**************************************************************************
1125 * midiOutPrepareHeader [WINMM.@]
1127 UINT WINAPI
midiOutPrepareHeader(HMIDIOUT hMidiOut
,
1128 MIDIHDR
* lpMidiOutHdr
, UINT uSize
)
1132 TRACE("(%04X, %p, %d)\n", hMidiOut
, lpMidiOutHdr
, uSize
);
1134 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1135 return MMSYSERR_INVALHANDLE
;
1137 return MMDRV_Message(wmld
, MODM_PREPARE
, (DWORD
)lpMidiOutHdr
, uSize
, TRUE
);
1140 /**************************************************************************
1141 * midiOutUnprepareHeader [WINMM.@]
1143 UINT WINAPI
midiOutUnprepareHeader(HMIDIOUT hMidiOut
,
1144 MIDIHDR
* lpMidiOutHdr
, UINT uSize
)
1148 TRACE("(%04X, %p, %d)\n", hMidiOut
, lpMidiOutHdr
, uSize
);
1150 if (!(lpMidiOutHdr
->dwFlags
& MHDR_PREPARED
)) {
1151 return MMSYSERR_NOERROR
;
1154 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1155 return MMSYSERR_INVALHANDLE
;
1157 return MMDRV_Message(wmld
, MODM_UNPREPARE
, (DWORD
)lpMidiOutHdr
, uSize
, TRUE
);
1160 /**************************************************************************
1161 * midiOutShortMsg [WINMM.@]
1163 UINT WINAPI
midiOutShortMsg(HMIDIOUT hMidiOut
, DWORD dwMsg
)
1167 TRACE("(%04X, %08lX)\n", hMidiOut
, dwMsg
);
1169 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1170 return MMSYSERR_INVALHANDLE
;
1172 return MMDRV_Message(wmld
, MODM_DATA
, dwMsg
, 0L, FALSE
);
1175 /**************************************************************************
1176 * midiOutLongMsg [WINMM.@]
1178 UINT WINAPI
midiOutLongMsg(HMIDIOUT hMidiOut
,
1179 MIDIHDR
* lpMidiOutHdr
, UINT uSize
)
1183 TRACE("(%04X, %p, %d)\n", hMidiOut
, lpMidiOutHdr
, uSize
);
1185 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1186 return MMSYSERR_INVALHANDLE
;
1188 return MMDRV_Message(wmld
, MODM_LONGDATA
, (DWORD
)lpMidiOutHdr
, uSize
, TRUE
);
1191 /**************************************************************************
1192 * midiOutReset [WINMM.@]
1194 UINT WINAPI
midiOutReset(HMIDIOUT hMidiOut
)
1198 TRACE("(%04X)\n", hMidiOut
);
1200 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1201 return MMSYSERR_INVALHANDLE
;
1203 return MMDRV_Message(wmld
, MODM_RESET
, 0L, 0L, TRUE
);
1206 /**************************************************************************
1207 * midiOutGetVolume [WINMM.@]
1209 UINT WINAPI
midiOutGetVolume(UINT uDeviceID
, DWORD
* lpdwVolume
)
1213 TRACE("(%04X, %p);\n", uDeviceID
, lpdwVolume
);
1215 if ((wmld
= MMDRV_Get(uDeviceID
, MMDRV_MIDIOUT
, TRUE
)) == NULL
)
1216 return MMSYSERR_INVALHANDLE
;
1218 return MMDRV_Message(wmld
, MODM_GETVOLUME
, (DWORD
)lpdwVolume
, 0L, TRUE
);
1221 /**************************************************************************
1222 * midiOutSetVolume [WINMM.@]
1224 UINT WINAPI
midiOutSetVolume(UINT uDeviceID
, DWORD dwVolume
)
1228 TRACE("(%04X, %ld);\n", uDeviceID
, dwVolume
);
1230 if ((wmld
= MMDRV_Get(uDeviceID
, MMDRV_MIDIOUT
, TRUE
)) == NULL
)
1231 return MMSYSERR_INVALHANDLE
;
1233 return MMDRV_Message(wmld
, MODM_SETVOLUME
, dwVolume
, 0L, TRUE
);
1236 /**************************************************************************
1237 * midiOutCachePatches [WINMM.@]
1239 UINT WINAPI
midiOutCachePatches(HMIDIOUT hMidiOut
, UINT uBank
,
1240 WORD
* lpwPatchArray
, UINT uFlags
)
1242 /* not really necessary to support this */
1243 FIXME("not supported yet\n");
1244 return MMSYSERR_NOTSUPPORTED
;
1247 /**************************************************************************
1248 * midiOutCacheDrumPatches [WINMM.@]
1250 UINT WINAPI
midiOutCacheDrumPatches(HMIDIOUT hMidiOut
, UINT uPatch
,
1251 WORD
* lpwKeyArray
, UINT uFlags
)
1253 FIXME("not supported yet\n");
1254 return MMSYSERR_NOTSUPPORTED
;
1257 /**************************************************************************
1258 * midiOutGetID [WINMM.@]
1260 UINT WINAPI
midiOutGetID(HMIDIOUT hMidiOut
, UINT
* lpuDeviceID
)
1264 TRACE("(%04X, %p)\n", hMidiOut
, lpuDeviceID
);
1266 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALPARAM
;
1267 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1268 return MMSYSERR_INVALHANDLE
;
1270 *lpuDeviceID
= wmld
->uDeviceID
;
1271 return MMSYSERR_NOERROR
;
1274 /**************************************************************************
1275 * midiOutMessage [WINMM.@]
1277 DWORD WINAPI
midiOutMessage(HMIDIOUT hMidiOut
, UINT uMessage
,
1278 DWORD dwParam1
, DWORD dwParam2
)
1282 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut
, uMessage
, dwParam1
, dwParam2
);
1284 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
) {
1286 if (uMessage
== 0x0001) {
1287 *(LPDWORD
)dwParam1
= 1;
1290 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, TRUE
)) != NULL
) {
1291 return MMDRV_PhysicalFeatures(wmld
, uMessage
, dwParam1
, dwParam2
);
1293 return MMSYSERR_INVALHANDLE
;
1299 FIXME("can't handle OPEN or CLOSE message!\n");
1300 return MMSYSERR_NOTSUPPORTED
;
1302 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
1305 /**************************************************************************
1306 * midiInGetNumDevs [WINMM.@]
1308 UINT WINAPI
midiInGetNumDevs(void)
1310 return MMDRV_GetNum(MMDRV_MIDIIN
);
1313 /**************************************************************************
1314 * midiInGetDevCapsW [WINMM.@]
1316 UINT WINAPI
midiInGetDevCapsW(UINT uDeviceID
, LPMIDIINCAPSW lpCaps
, UINT uSize
)
1319 UINT ret
= midiInGetDevCapsA(uDeviceID
, &micA
, uSize
);
1321 if (ret
== MMSYSERR_NOERROR
) {
1322 lpCaps
->wMid
= micA
.wMid
;
1323 lpCaps
->wPid
= micA
.wPid
;
1324 lpCaps
->vDriverVersion
= micA
.vDriverVersion
;
1325 MultiByteToWideChar( CP_ACP
, 0, micA
.szPname
, -1, lpCaps
->szPname
,
1326 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
1327 lpCaps
->dwSupport
= micA
.dwSupport
;
1332 /**************************************************************************
1333 * midiInGetDevCapsA [WINMM.@]
1335 UINT WINAPI
midiInGetDevCapsA(UINT uDeviceID
, LPMIDIINCAPSA lpCaps
, UINT uSize
)
1339 TRACE("(%d, %p, %d);\n", uDeviceID
, lpCaps
, uSize
);
1341 if ((wmld
= MMDRV_Get(uDeviceID
, MMDRV_MIDIIN
, TRUE
)) == NULL
)
1342 return MMSYSERR_INVALHANDLE
;
1344 return MMDRV_Message(wmld
, MIDM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
1347 /**************************************************************************
1348 * midiInGetErrorTextW [WINMM.@]
1350 UINT WINAPI
midiInGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
1352 LPSTR xstr
= HeapAlloc(GetProcessHeap(), 0, uSize
);
1353 UINT ret
= MIDI_GetErrorText(uError
, xstr
, uSize
);
1355 MultiByteToWideChar( CP_ACP
, 0, xstr
, -1, lpText
, uSize
);
1356 HeapFree(GetProcessHeap(), 0, xstr
);
1360 /**************************************************************************
1361 * midiInGetErrorTextA [WINMM.@]
1363 UINT WINAPI
midiInGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
1365 return MIDI_GetErrorText(uError
, lpText
, uSize
);
1368 UINT
MMSYSTEM_midiInOpen(HMIDIIN
* lphMidiIn
, UINT uDeviceID
, DWORD dwCallback
,
1369 DWORD dwInstance
, DWORD dwFlags
, BOOL bFrom32
)
1375 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1376 lphMidiIn
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
);
1378 if (lphMidiIn
!= NULL
) *lphMidiIn
= 0;
1380 lpwm
= (LPWINE_MIDI
)MMDRV_Alloc(sizeof(WINE_MIDI
), MMDRV_MIDIIN
, &hMidiIn
,
1381 &dwFlags
, &dwCallback
, &dwInstance
, bFrom32
);
1384 return MMSYSERR_NOMEM
;
1386 lpwm
->mod
.hMidi
= (HMIDI
) hMidiIn
;
1387 lpwm
->mod
.dwCallback
= dwCallback
;
1388 lpwm
->mod
.dwInstance
= dwInstance
;
1390 lpwm
->mld
.uDeviceID
= uDeviceID
;
1391 dwRet
= MMDRV_Open(&lpwm
->mld
, MIDM_OPEN
, (DWORD
)&lpwm
->mod
, dwFlags
);
1393 if (dwRet
!= MMSYSERR_NOERROR
) {
1394 MMDRV_Free(hMidiIn
, &lpwm
->mld
);
1397 if (lphMidiIn
!= NULL
) *lphMidiIn
= hMidiIn
;
1398 TRACE("=> %ld hMidi=%04x\n", dwRet
, hMidiIn
);
1403 /**************************************************************************
1404 * midiInOpen [WINMM.@]
1406 UINT WINAPI
midiInOpen(HMIDIIN
* lphMidiIn
, UINT uDeviceID
,
1407 DWORD dwCallback
, DWORD dwInstance
, DWORD dwFlags
)
1409 return MMSYSTEM_midiInOpen(lphMidiIn
, uDeviceID
, dwCallback
,
1410 dwInstance
, dwFlags
, TRUE
);
1413 /**************************************************************************
1414 * midiInClose [WINMM.@]
1416 UINT WINAPI
midiInClose(HMIDIIN hMidiIn
)
1421 TRACE("(%04X)\n", hMidiIn
);
1423 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1424 return MMSYSERR_INVALHANDLE
;
1426 dwRet
= MMDRV_Close(wmld
, MIDM_CLOSE
);
1427 MMDRV_Free(hMidiIn
, wmld
);
1431 /**************************************************************************
1432 * midiInPrepareHeader [WINMM.@]
1434 UINT WINAPI
midiInPrepareHeader(HMIDIIN hMidiIn
,
1435 MIDIHDR
* lpMidiInHdr
, UINT uSize
)
1439 TRACE("(%04X, %p, %d)\n", hMidiIn
, lpMidiInHdr
, uSize
);
1441 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1442 return MMSYSERR_INVALHANDLE
;
1444 return MMDRV_Message(wmld
, MIDM_PREPARE
, (DWORD
)lpMidiInHdr
, uSize
, TRUE
);
1447 /**************************************************************************
1448 * midiInUnprepareHeader [WINMM.@]
1450 UINT WINAPI
midiInUnprepareHeader(HMIDIIN hMidiIn
,
1451 MIDIHDR
* lpMidiInHdr
, UINT uSize
)
1455 TRACE("(%04X, %p, %d)\n", hMidiIn
, lpMidiInHdr
, uSize
);
1457 if (!(lpMidiInHdr
->dwFlags
& MHDR_PREPARED
)) {
1458 return MMSYSERR_NOERROR
;
1461 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1462 return MMSYSERR_INVALHANDLE
;
1464 return MMDRV_Message(wmld
, MIDM_UNPREPARE
, (DWORD
)lpMidiInHdr
, uSize
, TRUE
);
1467 /**************************************************************************
1468 * midiInAddBuffer [WINMM.@]
1470 UINT WINAPI
midiInAddBuffer(HMIDIIN hMidiIn
,
1471 MIDIHDR
* lpMidiInHdr
, UINT uSize
)
1475 TRACE("(%04X, %p, %d)\n", hMidiIn
, lpMidiInHdr
, uSize
);
1477 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1478 return MMSYSERR_INVALHANDLE
;
1480 return MMDRV_Message(wmld
, MIDM_ADDBUFFER
, (DWORD
)lpMidiInHdr
, uSize
, TRUE
);
1483 /**************************************************************************
1484 * midiInStart [WINMM.@]
1486 UINT WINAPI
midiInStart(HMIDIIN hMidiIn
)
1490 TRACE("(%04X)\n", hMidiIn
);
1492 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1493 return MMSYSERR_INVALHANDLE
;
1495 return MMDRV_Message(wmld
, MIDM_START
, 0L, 0L, TRUE
);
1498 /**************************************************************************
1499 * midiInStop [WINMM.@]
1501 UINT WINAPI
midiInStop(HMIDIIN hMidiIn
)
1505 TRACE("(%04X)\n", hMidiIn
);
1507 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1508 return MMSYSERR_INVALHANDLE
;
1510 return MMDRV_Message(wmld
, MIDM_STOP
, 0L, 0L, TRUE
);
1513 /**************************************************************************
1514 * midiInReset [WINMM.@]
1516 UINT WINAPI
midiInReset(HMIDIIN hMidiIn
)
1520 TRACE("(%04X)\n", hMidiIn
);
1522 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1523 return MMSYSERR_INVALHANDLE
;
1525 return MMDRV_Message(wmld
, MIDM_RESET
, 0L, 0L, TRUE
);
1528 /**************************************************************************
1529 * midiInGetID [WINMM.@]
1531 UINT WINAPI
midiInGetID(HMIDIIN hMidiIn
, UINT
* lpuDeviceID
)
1535 TRACE("(%04X, %p)\n", hMidiIn
, lpuDeviceID
);
1537 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALPARAM
;
1539 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, TRUE
)) == NULL
)
1540 return MMSYSERR_INVALHANDLE
;
1542 *lpuDeviceID
= wmld
->uDeviceID
;
1544 return MMSYSERR_NOERROR
;
1547 /**************************************************************************
1548 * midiInMessage [WINMM.@]
1550 DWORD WINAPI
midiInMessage(HMIDIIN hMidiIn
, UINT uMessage
,
1551 DWORD dwParam1
, DWORD dwParam2
)
1555 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn
, uMessage
, dwParam1
, dwParam2
);
1557 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1558 return MMSYSERR_INVALHANDLE
;
1563 FIXME("can't handle OPEN or CLOSE message!\n");
1564 return MMSYSERR_NOTSUPPORTED
;
1566 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
1569 typedef struct WINE_MIDIStream
{
1580 LPMIDIHDR lpMidiHdr
;
1583 #define WINE_MSM_HEADER (WM_USER+0)
1584 #define WINE_MSM_STOP (WM_USER+1)
1586 /**************************************************************************
1587 * MMSYSTEM_GetMidiStream [internal]
1589 static BOOL
MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm
, WINE_MIDIStream
** lpMidiStrm
, WINE_MIDI
** lplpwm
)
1591 WINE_MIDI
* lpwm
= (LPWINE_MIDI
)MMDRV_Get(hMidiStrm
, MMDRV_MIDIOUT
, FALSE
);
1600 *lpMidiStrm
= (WINE_MIDIStream
*)lpwm
->mod
.rgIds
.dwStreamID
;
1602 return *lpMidiStrm
!= NULL
;
1605 /**************************************************************************
1606 * MMSYSTEM_MidiStream_Convert [internal]
1608 static DWORD
MMSYSTEM_MidiStream_Convert(WINE_MIDIStream
* lpMidiStrm
, DWORD pulse
)
1612 if (lpMidiStrm
->dwTimeDiv
== 0) {
1613 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1614 } else if (lpMidiStrm
->dwTimeDiv
> 0x8000) { /* SMPTE, unchecked FIXME? */
1615 int nf
= -(char)HIBYTE(lpMidiStrm
->dwTimeDiv
); /* number of frames */
1616 int nsf
= LOBYTE(lpMidiStrm
->dwTimeDiv
); /* number of sub-frames */
1617 ret
= (pulse
* 1000) / (nf
* nsf
);
1619 ret
= (DWORD
)((double)pulse
* ((double)lpMidiStrm
->dwTempo
/ 1000) /
1620 (double)lpMidiStrm
->dwTimeDiv
);
1626 /**************************************************************************
1627 * MMSYSTEM_MidiStream_MessageHandler [internal]
1629 static BOOL
MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream
* lpMidiStrm
, LPWINE_MIDI lpwm
, LPMSG msg
)
1631 LPMIDIHDR lpMidiHdr
;
1635 switch (msg
->message
) {
1637 SetEvent(lpMidiStrm
->hEvent
);
1641 /* this is not quite what MS doc says... */
1642 midiOutReset(lpMidiStrm
->hDevice
);
1643 /* empty list of already submitted buffers */
1644 for (lpMidiHdr
= lpMidiStrm
->lpMidiHdr
; lpMidiHdr
; lpMidiHdr
= (LPMIDIHDR
)lpMidiHdr
->lpNext
) {
1645 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
1646 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1648 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1649 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_DONE
,
1650 lpwm
->mod
.dwInstance
, (DWORD
)lpMidiHdr
, 0L);
1652 lpMidiStrm
->lpMidiHdr
= 0;
1653 SetEvent(lpMidiStrm
->hEvent
);
1655 case WINE_MSM_HEADER
:
1656 /* sets initial tick count for first MIDIHDR */
1657 if (!lpMidiStrm
->dwStartTicks
)
1658 lpMidiStrm
->dwStartTicks
= GetTickCount();
1660 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1661 * by native mcimidi, it doesn't look like a correct one".
1662 * this trick allows to throw it away... but I don't like it.
1663 * It looks like part of the file I'm trying to play and definitively looks
1664 * like raw midi content
1665 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1666 * synchronization issue where native mcimidi is still processing raw MIDI
1667 * content before generating MIDIEVENTs ?
1669 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1670 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1671 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1672 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1673 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1674 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1675 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1676 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1677 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1678 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1679 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1680 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1681 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1682 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1683 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1684 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1685 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1687 lpMidiHdr
= (LPMIDIHDR
)msg
->lParam
;
1688 lpData
= lpMidiHdr
->lpData
;
1689 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1690 (lpMidiHdr
->dwFlags
& MHDR_ISSTRM
) ? "stream" : "regular", lpMidiHdr
,
1691 (DWORD
)lpMidiHdr
, lpMidiHdr
->dwBufferLength
, lpMidiHdr
->dwBytesRecorded
,
1692 lpMidiHdr
->dwFlags
, msg
->wParam
);
1694 /* dumps content of lpMidiHdr->lpData
1695 * FIXME: there should be a debug routine somewhere that already does this
1696 * I hate spreading this type of shit all around the code
1698 for (dwToGo
= 0; dwToGo
< lpMidiHdr
->dwBufferLength
; dwToGo
+= 16) {
1702 for (i
= 0; i
< min(16, lpMidiHdr
->dwBufferLength
- dwToGo
); i
++)
1703 printf("%02x ", lpData
[dwToGo
+ i
]);
1706 for (i
= 0; i
< min(16, lpMidiHdr
->dwBufferLength
- dwToGo
); i
++) {
1707 ch
= lpData
[dwToGo
+ i
];
1708 printf("%c", (ch
>= 0x20 && ch
<= 0x7F) ? ch
: '.');
1713 if (((LPMIDIEVENT
)lpData
)->dwStreamID
!= 0 &&
1714 ((LPMIDIEVENT
)lpData
)->dwStreamID
!= 0xFFFFFFFF &&
1715 ((LPMIDIEVENT
)lpData
)->dwStreamID
!= (DWORD
)lpMidiStrm
) {
1716 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
1717 (lpMidiHdr
->dwFlags
& MHDR_ISSTRM
) ? "stream" : "regular",
1718 ((LPMIDIEVENT
)lpData
)->dwStreamID
);
1719 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
1720 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1722 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1723 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_DONE
,
1724 lpwm
->mod
.dwInstance
, (DWORD
)lpMidiHdr
, 0L);
1728 for (lpmh
= &lpMidiStrm
->lpMidiHdr
; *lpmh
; lpmh
= (LPMIDIHDR
*)&((*lpmh
)->lpNext
));
1730 lpMidiHdr
= (LPMIDIHDR
)msg
->lParam
;
1731 lpMidiHdr
->lpNext
= 0;
1732 lpMidiHdr
->dwFlags
|= MHDR_INQUEUE
;
1733 lpMidiHdr
->dwFlags
&= MHDR_DONE
;
1734 lpMidiHdr
->dwOffset
= 0;
1738 FIXME("Unknown message %d\n", msg
->message
);
1744 /**************************************************************************
1745 * MMSYSTEM_MidiStream_Player [internal]
1747 static DWORD CALLBACK
MMSYSTEM_MidiStream_Player(LPVOID pmt
)
1749 WINE_MIDIStream
* lpMidiStrm
= pmt
;
1754 LPMIDIHDR lpMidiHdr
;
1758 TRACE("(%p)!\n", lpMidiStrm
);
1761 (lpwm
= (LPWINE_MIDI
)MMDRV_Get(lpMidiStrm
->hDevice
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1764 /* force thread's queue creation */
1765 /* Used to be InitThreadInput16(0, 5); */
1766 /* but following works also with hack in midiStreamOpen */
1767 PeekMessageA(&msg
, 0, 0, 0, 0);
1769 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
1770 SetEvent(lpMidiStrm
->hEvent
);
1771 TRACE("Ready to go 1\n");
1772 /* thread is started in paused mode */
1773 SuspendThread(lpMidiStrm
->hThread
);
1774 TRACE("Ready to go 2\n");
1776 lpMidiStrm
->dwStartTicks
= 0;
1777 lpMidiStrm
->dwPulses
= 0;
1779 lpMidiStrm
->lpMidiHdr
= 0;
1782 lpMidiHdr
= lpMidiStrm
->lpMidiHdr
;
1784 /* for first message, block until one arrives, then process all that are available */
1785 GetMessageA(&msg
, 0, 0, 0);
1787 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm
, lpwm
, &msg
))
1789 } while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
));
1795 lpData
= lpMidiHdr
->lpData
;
1797 me
= (LPMIDIEVENT
)(lpData
+ lpMidiHdr
->dwOffset
);
1799 /* do we have to wait ? */
1800 if (me
->dwDeltaTime
) {
1801 lpMidiStrm
->dwPositionMS
+= MMSYSTEM_MidiStream_Convert(lpMidiStrm
, me
->dwDeltaTime
);
1802 lpMidiStrm
->dwPulses
+= me
->dwDeltaTime
;
1804 dwToGo
= lpMidiStrm
->dwStartTicks
+ lpMidiStrm
->dwPositionMS
;
1806 TRACE("%ld/%ld/%ld\n", dwToGo
, GetTickCount(), me
->dwDeltaTime
);
1807 while ((dwCurrTC
= GetTickCount()) < dwToGo
) {
1808 if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, dwToGo
- dwCurrTC
, QS_ALLINPUT
) == WAIT_OBJECT_0
) {
1809 /* got a message, handle it */
1810 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) {
1811 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm
, lpwm
, &msg
))
1816 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
1821 switch (MEVT_EVENTTYPE(me
->dwEvent
& ~MEVT_F_CALLBACK
)) {
1823 FIXME("NIY: MEVT_COMMENT\n");
1824 /* do nothing, skip bytes */
1827 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
1832 midiOutShortMsg(lpMidiStrm
->hDevice
, MEVT_EVENTPARM(me
->dwEvent
));
1835 lpMidiStrm
->dwTempo
= MEVT_EVENTPARM(me
->dwEvent
);
1840 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me
->dwEvent
& ~MEVT_F_CALLBACK
));
1843 if (me
->dwEvent
& MEVT_F_CALLBACK
) {
1844 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1845 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_POSITIONCB
,
1846 lpwm
->mod
.dwInstance
, (LPARAM
)lpMidiHdr
, 0L);
1848 lpMidiHdr
->dwOffset
+= sizeof(MIDIEVENT
) - sizeof(me
->dwParms
);
1849 if (me
->dwEvent
& MEVT_F_LONG
)
1850 lpMidiHdr
->dwOffset
+= (MEVT_EVENTPARM(me
->dwEvent
) + 3) & ~3;
1851 if (lpMidiHdr
->dwOffset
>= lpMidiHdr
->dwBufferLength
) {
1852 /* done with this header */
1853 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
1854 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1856 lpMidiStrm
->lpMidiHdr
= (LPMIDIHDR
)lpMidiHdr
->lpNext
;
1857 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1858 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_DONE
,
1859 lpwm
->mod
.dwInstance
, (DWORD
)lpMidiHdr
, 0L);
1864 TRACE("End of thread\n");
1866 return 0; /* for removing the warning, never executed */
1869 /**************************************************************************
1870 * MMSYSTEM_MidiStream_PostMessage [internal]
1872 static BOOL
MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream
* lpMidiStrm
, WORD msg
, DWORD pmt1
, DWORD pmt2
)
1874 if (PostThreadMessageA(lpMidiStrm
->dwThreadID
, msg
, pmt1
, pmt2
)) {
1877 ReleaseThunkLock(&count
);
1878 WaitForSingleObject(lpMidiStrm
->hEvent
, INFINITE
);
1879 RestoreThunkLock(count
);
1881 WARN("bad PostThreadMessageA\n");
1887 /**************************************************************************
1888 * midiStreamClose [WINMM.@]
1890 MMRESULT WINAPI
midiStreamClose(HMIDISTRM hMidiStrm
)
1892 WINE_MIDIStream
* lpMidiStrm
;
1894 TRACE("(%08x)!\n", hMidiStrm
);
1896 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
))
1897 return MMSYSERR_INVALHANDLE
;
1899 midiStreamStop(hMidiStrm
);
1900 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm
, WM_QUIT
, 0, 0);
1901 HeapFree(GetProcessHeap(), 0, lpMidiStrm
);
1902 CloseHandle(lpMidiStrm
->hEvent
);
1904 return midiOutClose((HMIDIOUT
)hMidiStrm
);
1907 /**************************************************************************
1908 * MMSYSTEM_MidiStream_Open [internal]
1910 MMRESULT
MMSYSTEM_MidiStream_Open(HMIDISTRM
* lphMidiStrm
, LPUINT lpuDeviceID
,
1911 DWORD cMidi
, DWORD dwCallback
,
1912 DWORD dwInstance
, DWORD fdwOpen
, BOOL bFrom32
)
1914 WINE_MIDIStream
* lpMidiStrm
;
1916 MIDIOPENSTRMID mosm
;
1920 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
1921 lphMidiStrm
, lpuDeviceID
, cMidi
, dwCallback
, dwInstance
, fdwOpen
);
1923 if (cMidi
!= 1 || lphMidiStrm
== NULL
|| lpuDeviceID
== NULL
)
1924 return MMSYSERR_INVALPARAM
;
1926 lpMidiStrm
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream
));
1928 return MMSYSERR_NOMEM
;
1930 lpMidiStrm
->dwTempo
= 500000;
1931 lpMidiStrm
->dwTimeDiv
= 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
1932 lpMidiStrm
->dwPositionMS
= 0;
1934 mosm
.dwStreamID
= (DWORD
)lpMidiStrm
;
1935 /* FIXME: the correct value is not allocated yet for MAPPER */
1936 mosm
.wDeviceID
= *lpuDeviceID
;
1937 lpwm
= MIDI_OutAlloc(&hMidiOut
, &dwCallback
, &dwInstance
, &fdwOpen
, 1, &mosm
, bFrom32
);
1938 lpMidiStrm
->hDevice
= hMidiOut
;
1940 *lphMidiStrm
= (HMIDISTRM
)hMidiOut
;
1942 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
1943 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID
);
1944 lpwm
->mld
.uDeviceID
= *lpuDeviceID
= 0;
1946 ret
= MMDRV_Open(&lpwm
->mld
, MODM_OPEN
, (DWORD
)&lpwm
->mod
, fdwOpen
);
1947 lpMidiStrm
->hEvent
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
1948 lpMidiStrm
->wFlags
= HIWORD(fdwOpen
);
1950 lpMidiStrm
->hThread
= CreateThread(NULL
, 0, MMSYSTEM_MidiStream_Player
,
1951 lpMidiStrm
, 0, &(lpMidiStrm
->dwThreadID
));
1953 if (!lpMidiStrm
->hThread
) {
1954 midiStreamClose((HMIDISTRM
)hMidiOut
);
1955 return MMSYSERR_NOMEM
;
1958 /* wait for thread to have started, and for its queue to be created */
1962 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
1963 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
1964 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
1966 ReleaseThunkLock(&count
);
1967 WaitForSingleObject(lpMidiStrm
->hEvent
, INFINITE
);
1968 RestoreThunkLock(count
);
1971 TRACE("=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n",
1972 *lpuDeviceID
, lpwm
->mld
.uDeviceID
, *lphMidiStrm
, ret
, lpMidiStrm
);
1976 /**************************************************************************
1977 * midiStreamOpen [WINMM.@]
1979 MMRESULT WINAPI
midiStreamOpen(HMIDISTRM
* lphMidiStrm
, LPUINT lpuDeviceID
,
1980 DWORD cMidi
, DWORD dwCallback
,
1981 DWORD dwInstance
, DWORD fdwOpen
)
1983 return MMSYSTEM_MidiStream_Open(lphMidiStrm
, lpuDeviceID
, cMidi
, dwCallback
,
1984 dwInstance
, fdwOpen
, TRUE
);
1987 /**************************************************************************
1988 * midiStreamOut [WINMM.@]
1990 MMRESULT WINAPI
midiStreamOut(HMIDISTRM hMidiStrm
, LPMIDIHDR lpMidiHdr
,
1993 WINE_MIDIStream
* lpMidiStrm
;
1994 DWORD ret
= MMSYSERR_NOERROR
;
1996 TRACE("(%08x, %p, %u)!\n", hMidiStrm
, lpMidiHdr
, cbMidiHdr
);
1998 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
1999 ret
= MMSYSERR_INVALHANDLE
;
2000 } else if (!lpMidiHdr
) {
2001 ret
= MMSYSERR_INVALPARAM
;
2003 if (!PostThreadMessageA(lpMidiStrm
->dwThreadID
,
2004 WINE_MSM_HEADER
, cbMidiHdr
,
2005 (DWORD
)lpMidiHdr
)) {
2006 WARN("bad PostThreadMessageA\n");
2007 ret
= MMSYSERR_ERROR
;
2013 /**************************************************************************
2014 * midiStreamPause [WINMM.@]
2016 MMRESULT WINAPI
midiStreamPause(HMIDISTRM hMidiStrm
)
2018 WINE_MIDIStream
* lpMidiStrm
;
2019 DWORD ret
= MMSYSERR_NOERROR
;
2021 TRACE("(%08x)!\n", hMidiStrm
);
2023 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2024 ret
= MMSYSERR_INVALHANDLE
;
2026 if (SuspendThread(lpMidiStrm
->hThread
) == 0xFFFFFFFF) {
2027 WARN("bad Suspend (%ld)\n", GetLastError());
2028 ret
= MMSYSERR_ERROR
;
2034 /**************************************************************************
2035 * midiStreamPosition [WINMM.@]
2037 MMRESULT WINAPI
midiStreamPosition(HMIDISTRM hMidiStrm
, LPMMTIME lpMMT
, UINT cbmmt
)
2039 WINE_MIDIStream
* lpMidiStrm
;
2040 DWORD ret
= MMSYSERR_NOERROR
;
2042 TRACE("(%08x, %p, %u)!\n", hMidiStrm
, lpMMT
, cbmmt
);
2044 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2045 ret
= MMSYSERR_INVALHANDLE
;
2046 } else if (lpMMT
== NULL
|| cbmmt
!= sizeof(MMTIME
)) {
2047 ret
= MMSYSERR_INVALPARAM
;
2049 switch (lpMMT
->wType
) {
2051 lpMMT
->u
.ms
= lpMidiStrm
->dwPositionMS
;
2052 TRACE("=> %ld ms\n", lpMMT
->u
.ms
);
2055 lpMMT
->u
.ticks
= lpMidiStrm
->dwPulses
;
2056 TRACE("=> %ld ticks\n", lpMMT
->u
.ticks
);
2059 WARN("Unsupported time type %d\n", lpMMT
->wType
);
2060 lpMMT
->wType
= TIME_MS
;
2061 ret
= MMSYSERR_INVALPARAM
;
2068 /**************************************************************************
2069 * midiStreamProperty [WINMM.@]
2071 MMRESULT WINAPI
midiStreamProperty(HMIDISTRM hMidiStrm
, LPBYTE lpPropData
, DWORD dwProperty
)
2073 WINE_MIDIStream
* lpMidiStrm
;
2074 MMRESULT ret
= MMSYSERR_NOERROR
;
2076 TRACE("(%08x, %p, %lx)\n", hMidiStrm
, lpPropData
, dwProperty
);
2078 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2079 ret
= MMSYSERR_INVALHANDLE
;
2080 } else if ((dwProperty
& (MIDIPROP_GET
|MIDIPROP_SET
)) == 0) {
2081 ret
= MMSYSERR_INVALPARAM
;
2082 } else if (dwProperty
& MIDIPROP_TEMPO
) {
2083 MIDIPROPTEMPO
* mpt
= (MIDIPROPTEMPO
*)lpPropData
;
2085 if (sizeof(MIDIPROPTEMPO
) != mpt
->cbStruct
) {
2086 ret
= MMSYSERR_INVALPARAM
;
2087 } else if (dwProperty
& MIDIPROP_SET
) {
2088 lpMidiStrm
->dwTempo
= mpt
->dwTempo
;
2089 TRACE("Setting tempo to %ld\n", mpt
->dwTempo
);
2090 } else if (dwProperty
& MIDIPROP_GET
) {
2091 mpt
->dwTempo
= lpMidiStrm
->dwTempo
;
2092 TRACE("Getting tempo <= %ld\n", mpt
->dwTempo
);
2094 } else if (dwProperty
& MIDIPROP_TIMEDIV
) {
2095 MIDIPROPTIMEDIV
* mptd
= (MIDIPROPTIMEDIV
*)lpPropData
;
2097 if (sizeof(MIDIPROPTIMEDIV
) != mptd
->cbStruct
) {
2098 ret
= MMSYSERR_INVALPARAM
;
2099 } else if (dwProperty
& MIDIPROP_SET
) {
2100 lpMidiStrm
->dwTimeDiv
= mptd
->dwTimeDiv
;
2101 TRACE("Setting time div to %ld\n", mptd
->dwTimeDiv
);
2102 } else if (dwProperty
& MIDIPROP_GET
) {
2103 mptd
->dwTimeDiv
= lpMidiStrm
->dwTimeDiv
;
2104 TRACE("Getting time div <= %ld\n", mptd
->dwTimeDiv
);
2107 ret
= MMSYSERR_INVALPARAM
;
2113 /**************************************************************************
2114 * midiStreamRestart [WINMM.@]
2116 MMRESULT WINAPI
midiStreamRestart(HMIDISTRM hMidiStrm
)
2118 WINE_MIDIStream
* lpMidiStrm
;
2119 MMRESULT ret
= MMSYSERR_NOERROR
;
2121 TRACE("(%08x)!\n", hMidiStrm
);
2123 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2124 ret
= MMSYSERR_INVALHANDLE
;
2128 /* since we increase the thread suspend count on each midiStreamPause
2129 * there may be a need for several midiStreamResume
2132 ret
= ResumeThread(lpMidiStrm
->hThread
);
2133 } while (ret
!= 0xFFFFFFFF && ret
!= 0);
2134 if (ret
== 0xFFFFFFFF) {
2135 WARN("bad Resume (%ld)\n", GetLastError());
2136 ret
= MMSYSERR_ERROR
;
2138 lpMidiStrm
->dwStartTicks
= GetTickCount() - lpMidiStrm
->dwPositionMS
;
2144 /**************************************************************************
2145 * midiStreamStop [WINMM.@]
2147 MMRESULT WINAPI
midiStreamStop(HMIDISTRM hMidiStrm
)
2149 WINE_MIDIStream
* lpMidiStrm
;
2150 MMRESULT ret
= MMSYSERR_NOERROR
;
2152 TRACE("(%08x)!\n", hMidiStrm
);
2154 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
2155 ret
= MMSYSERR_INVALHANDLE
;
2157 /* in case stream has been paused... FIXME is the current state correct ? */
2158 midiStreamRestart(hMidiStrm
);
2159 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm
, WINE_MSM_STOP
, 0, 0);
2164 UINT
MMSYSTEM_waveOpen(HANDLE
* lphndl
, UINT uDeviceID
, UINT uType
,
2165 const LPWAVEFORMATEX lpFormat
, DWORD dwCallback
,
2166 DWORD dwInstance
, DWORD dwFlags
, BOOL bFrom32
)
2170 DWORD dwRet
= MMSYSERR_NOERROR
;
2173 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2174 lphndl
, (int)uDeviceID
, (uType
==MMDRV_WAVEOUT
)?"Out":"In", lpFormat
, dwCallback
,
2175 dwInstance
, dwFlags
, bFrom32
?32:16);
2177 if (dwFlags
& WAVE_FORMAT_QUERY
) TRACE("WAVE_FORMAT_QUERY requested !\n");
2179 if (lpFormat
== NULL
) return WAVERR_BADFORMAT
;
2180 if ((dwFlags
& WAVE_MAPPED
) && (uDeviceID
== (UINT
)-1))
2181 return MMSYSERR_INVALPARAM
;
2183 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
2184 lpFormat
->wFormatTag
, lpFormat
->nChannels
, lpFormat
->nSamplesPerSec
,
2185 lpFormat
->nAvgBytesPerSec
, lpFormat
->nBlockAlign
, lpFormat
->wBitsPerSample
, lpFormat
->cbSize
);
2187 if ((wmld
= MMDRV_Alloc(sizeof(WINE_WAVE
), uType
, &handle
,
2188 &dwFlags
, &dwCallback
, &dwInstance
, bFrom32
)) == NULL
)
2189 return MMSYSERR_NOMEM
;
2192 wod
.lpFormat
= lpFormat
; /* should the struct be copied iso pointer? */
2193 wod
.dwCallback
= dwCallback
;
2194 wod
.dwInstance
= dwInstance
;
2198 if (dwFlags
& WAVE_MAPPED
) {
2199 wod
.uMappedDeviceID
= uDeviceID
;
2200 uDeviceID
= WAVE_MAPPER
;
2202 wod
.uMappedDeviceID
= -1;
2204 wmld
->uDeviceID
= uDeviceID
;
2206 dwRet
= MMDRV_Open(wmld
, (uType
== MMDRV_WAVEOUT
) ? WODM_OPEN
: WIDM_OPEN
,
2207 (DWORD
)&wod
, dwFlags
);
2209 if (dwRet
!= WAVERR_BADFORMAT
||
2210 (dwFlags
& (WAVE_MAPPED
|WAVE_FORMAT_DIRECT
)) != 0) break;
2211 /* if we ask for a format which isn't supported by the physical driver,
2212 * let's try to map it through the wave mapper (except, if we already tried
2213 * or user didn't allow us to use acm codecs)
2215 dwFlags
|= WAVE_MAPPED
;
2216 /* we shall loop only one */
2219 if ((dwFlags
& WAVE_FORMAT_QUERY
) || dwRet
!= MMSYSERR_NOERROR
) {
2220 MMDRV_Free(handle
, wmld
);
2224 if (lphndl
!= NULL
) *lphndl
= handle
;
2225 TRACE("=> %ld hWave=%04x\n", dwRet
, handle
);
2230 /**************************************************************************
2231 * waveOutGetNumDevs [WINMM.@]
2233 UINT WINAPI
waveOutGetNumDevs(void)
2235 return MMDRV_GetNum(MMDRV_WAVEOUT
);
2238 /**************************************************************************
2239 * waveOutGetDevCapsA [WINMM.@]
2241 UINT WINAPI
waveOutGetDevCapsA(UINT uDeviceID
, LPWAVEOUTCAPSA lpCaps
,
2246 TRACE("(%u %p %u)!\n", uDeviceID
, lpCaps
, uSize
);
2248 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
2250 if ((wmld
= MMDRV_Get(uDeviceID
, MMDRV_WAVEOUT
, TRUE
)) == NULL
)
2251 return MMSYSERR_INVALHANDLE
;
2253 return MMDRV_Message(wmld
, WODM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
2257 /**************************************************************************
2258 * waveOutGetDevCapsW [WINMM.@]
2260 UINT WINAPI
waveOutGetDevCapsW(UINT uDeviceID
, LPWAVEOUTCAPSW lpCaps
,
2266 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
2268 ret
= waveOutGetDevCapsA(uDeviceID
, &wocA
, sizeof(wocA
));
2270 if (ret
== MMSYSERR_NOERROR
) {
2271 lpCaps
->wMid
= wocA
.wMid
;
2272 lpCaps
->wPid
= wocA
.wPid
;
2273 lpCaps
->vDriverVersion
= wocA
.vDriverVersion
;
2274 MultiByteToWideChar( CP_ACP
, 0, wocA
.szPname
, -1, lpCaps
->szPname
,
2275 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
2276 lpCaps
->dwFormats
= wocA
.dwFormats
;
2277 lpCaps
->wChannels
= wocA
.wChannels
;
2278 lpCaps
->dwSupport
= wocA
.dwSupport
;
2283 /**************************************************************************
2284 * WAVE_GetErrorText [internal]
2286 static UINT16
WAVE_GetErrorText(UINT16 uError
, LPSTR lpText
, UINT16 uSize
)
2288 UINT16 ret
= MMSYSERR_BADERRNUM
;
2290 if (lpText
== NULL
) {
2291 ret
= MMSYSERR_INVALPARAM
;
2292 } else if (uSize
== 0) {
2293 ret
= MMSYSERR_NOERROR
;
2295 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2296 * a warning for the test was always true */
2297 (/*uError >= MMSYSERR_BASE && */uError
<= MMSYSERR_LASTERROR
) ||
2298 (uError
>= WAVERR_BASE
&& uError
<= WAVERR_LASTERROR
)) {
2300 if (LoadStringA(WINMM_IData
->hWinMM32Instance
,
2301 uError
, lpText
, uSize
) > 0) {
2302 ret
= MMSYSERR_NOERROR
;
2308 /**************************************************************************
2309 * waveOutGetErrorTextA [WINMM.@]
2311 UINT WINAPI
waveOutGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
2313 return WAVE_GetErrorText(uError
, lpText
, uSize
);
2316 /**************************************************************************
2317 * waveOutGetErrorTextW [WINMM.@]
2319 UINT WINAPI
waveOutGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
2321 LPSTR xstr
= HeapAlloc(GetProcessHeap(), 0, uSize
);
2322 UINT ret
= WAVE_GetErrorText(uError
, xstr
, uSize
);
2324 MultiByteToWideChar( CP_ACP
, 0, xstr
, -1, lpText
, uSize
);
2325 HeapFree(GetProcessHeap(), 0, xstr
);
2329 /**************************************************************************
2330 * waveOutOpen [WINMM.@]
2331 * All the args/structs have the same layout as the win16 equivalents
2333 UINT WINAPI
waveOutOpen(HWAVEOUT
* lphWaveOut
, UINT uDeviceID
,
2334 const LPWAVEFORMATEX lpFormat
, DWORD dwCallback
,
2335 DWORD dwInstance
, DWORD dwFlags
)
2337 return MMSYSTEM_waveOpen(lphWaveOut
, uDeviceID
, MMDRV_WAVEOUT
, lpFormat
,
2338 dwCallback
, dwInstance
, dwFlags
, TRUE
);
2341 /**************************************************************************
2342 * waveOutClose [WINMM.@]
2344 UINT WINAPI
waveOutClose(HWAVEOUT hWaveOut
)
2349 TRACE("(%04X)\n", hWaveOut
);
2351 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2352 return MMSYSERR_INVALHANDLE
;
2354 dwRet
= MMDRV_Close(wmld
, WODM_CLOSE
);
2355 MMDRV_Free(hWaveOut
, wmld
);
2360 /**************************************************************************
2361 * waveOutPrepareHeader [WINMM.@]
2363 UINT WINAPI
waveOutPrepareHeader(HWAVEOUT hWaveOut
,
2364 WAVEHDR
* lpWaveOutHdr
, UINT uSize
)
2368 TRACE("(%04X, %p, %u);\n", hWaveOut
, lpWaveOutHdr
, uSize
);
2370 if (lpWaveOutHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2372 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2373 return MMSYSERR_INVALHANDLE
;
2375 return MMDRV_Message(wmld
, WODM_PREPARE
, (DWORD
)lpWaveOutHdr
, uSize
, TRUE
);
2378 /**************************************************************************
2379 * waveOutUnprepareHeader [WINMM.@]
2381 UINT WINAPI
waveOutUnprepareHeader(HWAVEOUT hWaveOut
,
2382 LPWAVEHDR lpWaveOutHdr
, UINT uSize
)
2386 TRACE("(%04X, %p, %u);\n", hWaveOut
, lpWaveOutHdr
, uSize
);
2388 if (!(lpWaveOutHdr
->dwFlags
& WHDR_PREPARED
)) {
2389 return MMSYSERR_NOERROR
;
2392 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2393 return MMSYSERR_INVALHANDLE
;
2395 return MMDRV_Message(wmld
, WODM_UNPREPARE
, (DWORD
)lpWaveOutHdr
, uSize
, TRUE
);
2398 /**************************************************************************
2399 * waveOutWrite [WINMM.@]
2401 UINT WINAPI
waveOutWrite(HWAVEOUT hWaveOut
, LPWAVEHDR lpWaveOutHdr
,
2406 TRACE("(%04X, %p, %u);\n", hWaveOut
, lpWaveOutHdr
, uSize
);
2408 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2409 return MMSYSERR_INVALHANDLE
;
2411 return MMDRV_Message(wmld
, WODM_WRITE
, (DWORD
)lpWaveOutHdr
, uSize
, TRUE
);
2414 /**************************************************************************
2415 * waveOutBreakLoop [WINMM.@]
2417 UINT WINAPI
waveOutBreakLoop(HWAVEOUT hWaveOut
)
2421 TRACE("(%04X);\n", hWaveOut
);
2423 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2424 return MMSYSERR_INVALHANDLE
;
2425 return MMDRV_Message(wmld
, WODM_BREAKLOOP
, 0L, 0L, TRUE
);
2428 /**************************************************************************
2429 * waveOutPause [WINMM.@]
2431 UINT WINAPI
waveOutPause(HWAVEOUT hWaveOut
)
2435 TRACE("(%04X);\n", hWaveOut
);
2437 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2438 return MMSYSERR_INVALHANDLE
;
2439 return MMDRV_Message(wmld
, WODM_PAUSE
, 0L, 0L, TRUE
);
2442 /**************************************************************************
2443 * waveOutReset [WINMM.@]
2445 UINT WINAPI
waveOutReset(HWAVEOUT hWaveOut
)
2449 TRACE("(%04X);\n", hWaveOut
);
2451 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2452 return MMSYSERR_INVALHANDLE
;
2453 return MMDRV_Message(wmld
, WODM_RESET
, 0L, 0L, TRUE
);
2456 /**************************************************************************
2457 * waveOutRestart [WINMM.@]
2459 UINT WINAPI
waveOutRestart(HWAVEOUT hWaveOut
)
2463 TRACE("(%04X);\n", hWaveOut
);
2465 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2466 return MMSYSERR_INVALHANDLE
;
2467 return MMDRV_Message(wmld
, WODM_RESTART
, 0L, 0L, TRUE
);
2470 /**************************************************************************
2471 * waveOutGetPosition [WINMM.@]
2473 UINT WINAPI
waveOutGetPosition(HWAVEOUT hWaveOut
, LPMMTIME lpTime
,
2478 TRACE("(%04X, %p, %u);\n", hWaveOut
, lpTime
, uSize
);
2480 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2481 return MMSYSERR_INVALHANDLE
;
2483 return MMDRV_Message(wmld
, WODM_GETPOS
, (DWORD
)lpTime
, uSize
, TRUE
);
2486 /**************************************************************************
2487 * waveOutGetPitch [WINMM.@]
2489 UINT WINAPI
waveOutGetPitch(HWAVEOUT hWaveOut
, LPDWORD lpdw
)
2493 TRACE("(%04X, %08lx);\n", hWaveOut
, (DWORD
)lpdw
);
2495 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2496 return MMSYSERR_INVALHANDLE
;
2497 return MMDRV_Message(wmld
, WODM_GETPITCH
, (DWORD
)lpdw
, 0L, TRUE
);
2500 /**************************************************************************
2501 * waveOutSetPitch [WINMM.@]
2503 UINT WINAPI
waveOutSetPitch(HWAVEOUT hWaveOut
, DWORD dw
)
2507 TRACE("(%04X, %08lx);\n", hWaveOut
, (DWORD
)dw
);
2509 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2510 return MMSYSERR_INVALHANDLE
;
2511 return MMDRV_Message(wmld
, WODM_SETPITCH
, dw
, 0L, TRUE
);
2514 /**************************************************************************
2515 * waveOutGetPlaybackRate [WINMM.@]
2517 UINT WINAPI
waveOutGetPlaybackRate(HWAVEOUT hWaveOut
, LPDWORD lpdw
)
2521 TRACE("(%04X, %08lx);\n", hWaveOut
, (DWORD
)lpdw
);
2523 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2524 return MMSYSERR_INVALHANDLE
;
2525 return MMDRV_Message(wmld
, WODM_GETPLAYBACKRATE
, (DWORD
)lpdw
, 0L, TRUE
);
2528 /**************************************************************************
2529 * waveOutSetPlaybackRate [WINMM.@]
2531 UINT WINAPI
waveOutSetPlaybackRate(HWAVEOUT hWaveOut
, DWORD dw
)
2535 TRACE("(%04X, %08lx);\n", hWaveOut
, (DWORD
)dw
);
2537 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2538 return MMSYSERR_INVALHANDLE
;
2539 return MMDRV_Message(wmld
, WODM_SETPLAYBACKRATE
, dw
, 0L, TRUE
);
2542 /**************************************************************************
2543 * waveOutGetVolume [WINMM.@]
2545 UINT WINAPI
waveOutGetVolume(UINT devid
, LPDWORD lpdw
)
2549 TRACE("(%04X, %08lx);\n", devid
, (DWORD
)lpdw
);
2551 if ((wmld
= MMDRV_Get(devid
, MMDRV_WAVEOUT
, TRUE
)) == NULL
)
2552 return MMSYSERR_INVALHANDLE
;
2554 return MMDRV_Message(wmld
, WODM_GETVOLUME
, (DWORD
)lpdw
, 0L, TRUE
);
2557 /**************************************************************************
2558 * waveOutSetVolume [WINMM.@]
2560 UINT WINAPI
waveOutSetVolume(UINT devid
, DWORD dw
)
2564 TRACE("(%04X, %08lx);\n", devid
, dw
);
2566 if ((wmld
= MMDRV_Get(devid
, MMDRV_WAVEOUT
, TRUE
)) == NULL
)
2567 return MMSYSERR_INVALHANDLE
;
2569 return MMDRV_Message(wmld
, WODM_SETVOLUME
, dw
, 0L, TRUE
);
2572 /**************************************************************************
2573 * waveOutGetID [WINMM.@]
2575 UINT WINAPI
waveOutGetID(HWAVEOUT hWaveOut
, UINT
* lpuDeviceID
)
2579 TRACE("(%04X, %p);\n", hWaveOut
, lpuDeviceID
);
2581 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALHANDLE
;
2583 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2584 return MMSYSERR_INVALHANDLE
;
2586 *lpuDeviceID
= wmld
->uDeviceID
;
2590 /**************************************************************************
2591 * waveOutMessage [WINMM.@]
2593 DWORD WINAPI
waveOutMessage(HWAVEOUT hWaveOut
, UINT uMessage
,
2594 DWORD dwParam1
, DWORD dwParam2
)
2598 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut
, uMessage
, dwParam1
, dwParam2
);
2600 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
) {
2601 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, TRUE
)) != NULL
) {
2602 return MMDRV_PhysicalFeatures(wmld
, uMessage
, dwParam1
, dwParam2
);
2604 return MMSYSERR_INVALHANDLE
;
2608 if (uMessage
< DRVM_IOCTL
|| (uMessage
>= DRVM_IOCTL_LAST
&& uMessage
< DRVM_MAPPER
))
2609 return MMSYSERR_INVALPARAM
;
2611 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
2614 /**************************************************************************
2615 * waveInGetNumDevs [WINMM.@]
2617 UINT WINAPI
waveInGetNumDevs(void)
2619 return MMDRV_GetNum(MMDRV_WAVEIN
);
2622 /**************************************************************************
2623 * waveInGetDevCapsW [WINMM.@]
2625 UINT WINAPI
waveInGetDevCapsW(UINT uDeviceID
, LPWAVEINCAPSW lpCaps
, UINT uSize
)
2628 UINT ret
= waveInGetDevCapsA(uDeviceID
, &wicA
, uSize
);
2630 if (ret
== MMSYSERR_NOERROR
) {
2631 lpCaps
->wMid
= wicA
.wMid
;
2632 lpCaps
->wPid
= wicA
.wPid
;
2633 lpCaps
->vDriverVersion
= wicA
.vDriverVersion
;
2634 MultiByteToWideChar( CP_ACP
, 0, wicA
.szPname
, -1, lpCaps
->szPname
,
2635 sizeof(lpCaps
->szPname
)/sizeof(WCHAR
) );
2636 lpCaps
->dwFormats
= wicA
.dwFormats
;
2637 lpCaps
->wChannels
= wicA
.wChannels
;
2643 /**************************************************************************
2644 * waveInGetDevCapsA [WINMM.@]
2646 UINT WINAPI
waveInGetDevCapsA(UINT uDeviceID
, LPWAVEINCAPSA lpCaps
, UINT uSize
)
2650 TRACE("(%u %p %u)!\n", uDeviceID
, lpCaps
, uSize
);
2652 if ((wmld
= MMDRV_Get(uDeviceID
, MMDRV_WAVEIN
, TRUE
)) == NULL
)
2653 return MMSYSERR_INVALHANDLE
;
2655 return MMDRV_Message(wmld
, WIDM_GETDEVCAPS
, (DWORD
)lpCaps
, uSize
, TRUE
);
2658 /**************************************************************************
2659 * waveInGetErrorTextA [WINMM.@]
2661 UINT WINAPI
waveInGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
2663 return WAVE_GetErrorText(uError
, lpText
, uSize
);
2666 /**************************************************************************
2667 * waveInGetErrorTextW [WINMM.@]
2669 UINT WINAPI
waveInGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
2671 LPSTR txt
= HeapAlloc(GetProcessHeap(), 0, uSize
);
2672 UINT ret
= WAVE_GetErrorText(uError
, txt
, uSize
);
2674 MultiByteToWideChar( CP_ACP
, 0, txt
, -1, lpText
, uSize
);
2675 HeapFree(GetProcessHeap(), 0, txt
);
2679 /**************************************************************************
2680 * waveInOpen [WINMM.@]
2682 UINT WINAPI
waveInOpen(HWAVEIN
* lphWaveIn
, UINT uDeviceID
,
2683 const LPWAVEFORMATEX lpFormat
, DWORD dwCallback
,
2684 DWORD dwInstance
, DWORD dwFlags
)
2686 return MMSYSTEM_waveOpen(lphWaveIn
, uDeviceID
, MMDRV_WAVEIN
, lpFormat
,
2687 dwCallback
, dwInstance
, dwFlags
, TRUE
);
2690 /**************************************************************************
2691 * waveInClose [WINMM.@]
2693 UINT WINAPI
waveInClose(HWAVEIN hWaveIn
)
2698 TRACE("(%04X)\n", hWaveIn
);
2700 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2701 return MMSYSERR_INVALHANDLE
;
2703 dwRet
= MMDRV_Message(wmld
, WIDM_CLOSE
, 0L, 0L, TRUE
);
2704 MMDRV_Free(hWaveIn
, wmld
);
2708 /**************************************************************************
2709 * waveInPrepareHeader [WINMM.@]
2711 UINT WINAPI
waveInPrepareHeader(HWAVEIN hWaveIn
, WAVEHDR
* lpWaveInHdr
,
2716 TRACE("(%04X, %p, %u);\n", hWaveIn
, lpWaveInHdr
, uSize
);
2718 if (lpWaveInHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2719 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2720 return MMSYSERR_INVALHANDLE
;
2722 lpWaveInHdr
->dwBytesRecorded
= 0;
2724 return MMDRV_Message(wmld
, WIDM_PREPARE
, (DWORD
)lpWaveInHdr
, uSize
, TRUE
);
2727 /**************************************************************************
2728 * waveInUnprepareHeader [WINMM.@]
2730 UINT WINAPI
waveInUnprepareHeader(HWAVEIN hWaveIn
, WAVEHDR
* lpWaveInHdr
,
2735 TRACE("(%04X, %p, %u);\n", hWaveIn
, lpWaveInHdr
, uSize
);
2737 if (lpWaveInHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2738 if (!(lpWaveInHdr
->dwFlags
& WHDR_PREPARED
)) {
2739 return MMSYSERR_NOERROR
;
2742 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2743 return MMSYSERR_INVALHANDLE
;
2745 return MMDRV_Message(wmld
, WIDM_UNPREPARE
, (DWORD
)lpWaveInHdr
, uSize
, TRUE
);
2748 /**************************************************************************
2749 * waveInAddBuffer [WINMM.@]
2751 UINT WINAPI
waveInAddBuffer(HWAVEIN hWaveIn
,
2752 WAVEHDR
* lpWaveInHdr
, UINT uSize
)
2756 TRACE("(%04X, %p, %u);\n", hWaveIn
, lpWaveInHdr
, uSize
);
2758 if (lpWaveInHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2759 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2760 return MMSYSERR_INVALHANDLE
;
2762 return MMDRV_Message(wmld
, WIDM_ADDBUFFER
, (DWORD
)lpWaveInHdr
, uSize
, TRUE
);
2765 /**************************************************************************
2766 * waveInReset [WINMM.@]
2768 UINT WINAPI
waveInReset(HWAVEIN hWaveIn
)
2772 TRACE("(%04X);\n", hWaveIn
);
2774 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2775 return MMSYSERR_INVALHANDLE
;
2777 return MMDRV_Message(wmld
, WIDM_RESET
, 0L, 0L, TRUE
);
2780 /**************************************************************************
2781 * waveInStart [WINMM.@]
2783 UINT WINAPI
waveInStart(HWAVEIN hWaveIn
)
2787 TRACE("(%04X);\n", hWaveIn
);
2789 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2790 return MMSYSERR_INVALHANDLE
;
2792 return MMDRV_Message(wmld
, WIDM_START
, 0L, 0L, TRUE
);
2795 /**************************************************************************
2796 * waveInStop [WINMM.@]
2798 UINT WINAPI
waveInStop(HWAVEIN hWaveIn
)
2802 TRACE("(%04X);\n", hWaveIn
);
2804 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2805 return MMSYSERR_INVALHANDLE
;
2807 return MMDRV_Message(wmld
,WIDM_STOP
, 0L, 0L, TRUE
);
2810 /**************************************************************************
2811 * waveInGetPosition [WINMM.@]
2813 UINT WINAPI
waveInGetPosition(HWAVEIN hWaveIn
, LPMMTIME lpTime
,
2818 TRACE("(%04X, %p, %u);\n", hWaveIn
, lpTime
, uSize
);
2820 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2821 return MMSYSERR_INVALHANDLE
;
2823 return MMDRV_Message(wmld
, WIDM_GETPOS
, (DWORD
)lpTime
, uSize
, TRUE
);
2826 /**************************************************************************
2827 * waveInGetID [WINMM.@]
2829 UINT WINAPI
waveInGetID(HWAVEIN hWaveIn
, UINT
* lpuDeviceID
)
2833 TRACE("(%04X, %p);\n", hWaveIn
, lpuDeviceID
);
2835 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALHANDLE
;
2837 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2838 return MMSYSERR_INVALHANDLE
;
2840 *lpuDeviceID
= wmld
->uDeviceID
;
2841 return MMSYSERR_NOERROR
;
2844 /**************************************************************************
2845 * waveInMessage [WINMM.@]
2847 DWORD WINAPI
waveInMessage(HWAVEIN hWaveIn
, UINT uMessage
,
2848 DWORD dwParam1
, DWORD dwParam2
)
2852 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn
, uMessage
, dwParam1
, dwParam2
);
2855 if (uMessage
< DRVM_IOCTL
|| (uMessage
>= DRVM_IOCTL_LAST
&& uMessage
< DRVM_MAPPER
))
2856 return MMSYSERR_INVALPARAM
;
2858 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2859 return MMSYSERR_INVALHANDLE
;
2861 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);