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
32 * + it seems that some programs check what's installed in
33 * registry against the value returned by drivers. Wine is
34 * currently broken regarding this point.
35 * + check thread-safeness for MMSYSTEM and WINMM entry points
36 * + unicode entry points are badly supported (would require
37 * moving 32 bit drivers as Unicode as they are supposed to be)
38 * + allow joystick and timer external calls as we do for wave,
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
57 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(winmm
);
61 void (WINAPI
*pFnReleaseThunkLock
)(DWORD
*);
62 void (WINAPI
*pFnRestoreThunkLock
)(DWORD
);
64 /* ========================================================================
65 * G L O B A L S E T T I N G S
66 * ========================================================================*/
68 WINE_MM_IDATA WINMM_IData
;
70 /**************************************************************************
71 * WINMM_CreateIData [internal]
73 static BOOL
WINMM_CreateIData(HINSTANCE hInstDLL
)
75 memset( &WINMM_IData
, 0, sizeof WINMM_IData
);
77 WINMM_IData
.hWinMM32Instance
= hInstDLL
;
78 InitializeCriticalSection(&WINMM_IData
.cs
);
79 /* FIXME crashes in ReactOS
80 WINMM_IData.cs.DebugInfo->Spare[1] = (DWORD)"WINMM_IData";
82 WINMM_IData
.psStopEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
83 WINMM_IData
.psLastEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
84 TRACE("Initialized IData (%p)\n", &WINMM_IData
);
88 /**************************************************************************
89 * WINMM_DeleteIData [internal]
91 static void WINMM_DeleteIData(void)
95 /* FIXME: should also free content and resources allocated
96 * inside WINMM_IData */
97 CloseHandle(WINMM_IData
.psStopEvent
);
98 CloseHandle(WINMM_IData
.psLastEvent
);
99 DeleteCriticalSection(&WINMM_IData
.cs
);
102 /******************************************************************
107 static HANDLE (WINAPI
*pGetModuleHandle16
)(LPCSTR
);
108 static DWORD (WINAPI
*pLoadLibrary16
)(LPCSTR
);
111 BOOL
WINMM_CheckForMMSystem(void)
113 /* 0 is not checked yet, -1 is not present, 1 is present */
114 static int loaded
/* = 0 */;
118 HANDLE h
= GetModuleHandleA("kernel32");
123 pGetModuleHandle16
= (void*)GetProcAddress(h
, "GetModuleHandle16");
124 pLoadLibrary16
= (void*)GetProcAddress(h
, "LoadLibrary16");
125 if (pGetModuleHandle16
&& pLoadLibrary16
&&
126 (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL")))
127 #endif /* __REACTOS__ */
134 /******************************************************************
135 * WINMM_ErrorToString
137 const char* WINMM_ErrorToString(MMRESULT error
)
139 #define ERR_TO_STR(dev) case dev: return #dev
140 static char unknown
[32];
142 ERR_TO_STR(MMSYSERR_NOERROR
);
143 ERR_TO_STR(MMSYSERR_ERROR
);
144 ERR_TO_STR(MMSYSERR_BADDEVICEID
);
145 ERR_TO_STR(MMSYSERR_NOTENABLED
);
146 ERR_TO_STR(MMSYSERR_ALLOCATED
);
147 ERR_TO_STR(MMSYSERR_INVALHANDLE
);
148 ERR_TO_STR(MMSYSERR_NODRIVER
);
149 ERR_TO_STR(MMSYSERR_NOMEM
);
150 ERR_TO_STR(MMSYSERR_NOTSUPPORTED
);
151 ERR_TO_STR(MMSYSERR_BADERRNUM
);
152 ERR_TO_STR(MMSYSERR_INVALFLAG
);
153 ERR_TO_STR(MMSYSERR_INVALPARAM
);
154 ERR_TO_STR(MMSYSERR_HANDLEBUSY
);
155 ERR_TO_STR(MMSYSERR_INVALIDALIAS
);
156 ERR_TO_STR(MMSYSERR_BADDB
);
157 ERR_TO_STR(MMSYSERR_KEYNOTFOUND
);
158 ERR_TO_STR(MMSYSERR_READERROR
);
159 ERR_TO_STR(MMSYSERR_WRITEERROR
);
160 ERR_TO_STR(MMSYSERR_DELETEERROR
);
161 ERR_TO_STR(MMSYSERR_VALNOTFOUND
);
162 ERR_TO_STR(MMSYSERR_NODRIVERCB
);
163 ERR_TO_STR(WAVERR_BADFORMAT
);
164 ERR_TO_STR(WAVERR_STILLPLAYING
);
165 ERR_TO_STR(WAVERR_UNPREPARED
);
166 ERR_TO_STR(WAVERR_SYNC
);
168 sprintf(unknown
, "Unknown(0x%08x)", error
);
173 /**************************************************************************
174 * DllMain (WINMM.init)
176 * WINMM DLL entry point
179 BOOL WINAPI
DllMain(HINSTANCE hInstDLL
, DWORD fdwReason
, LPVOID fImpLoad
)
181 TRACE("%p 0x%lx %p\n", hInstDLL
, fdwReason
, fImpLoad
);
184 case DLL_PROCESS_ATTACH
:
185 DisableThreadLibraryCalls(hInstDLL
);
187 if (!WINMM_CreateIData(hInstDLL
))
194 case DLL_PROCESS_DETACH
:
195 /* close all opened MCI drivers */
196 MCI_SendCommand(MCI_ALL_DEVICE_ID
, MCI_CLOSE
, MCI_WAIT
, 0L, TRUE
);
198 /* now unload all remaining drivers... */
207 /**************************************************************************
208 * Mixer devices. New to Win95
211 /**************************************************************************
212 * find out the real mixer ID depending on hmix (depends on dwFlags)
214 static UINT
MIXER_GetDev(HMIXEROBJ hmix
, DWORD dwFlags
, LPWINE_MIXER
* lplpwm
)
216 LPWINE_MIXER lpwm
= NULL
;
217 UINT uRet
= MMSYSERR_NOERROR
;
219 switch (dwFlags
& 0xF0000000ul
) {
220 case MIXER_OBJECTF_MIXER
:
221 lpwm
= (LPWINE_MIXER
)MMDRV_Get(hmix
, MMDRV_MIXER
, TRUE
);
223 case MIXER_OBJECTF_HMIXER
:
224 lpwm
= (LPWINE_MIXER
)MMDRV_Get(hmix
, MMDRV_MIXER
, FALSE
);
226 case MIXER_OBJECTF_WAVEOUT
:
227 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEOUT
, TRUE
, MMDRV_MIXER
);
229 case MIXER_OBJECTF_HWAVEOUT
:
230 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEOUT
, FALSE
, MMDRV_MIXER
);
232 case MIXER_OBJECTF_WAVEIN
:
233 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEIN
, TRUE
, MMDRV_MIXER
);
235 case MIXER_OBJECTF_HWAVEIN
:
236 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_WAVEIN
, FALSE
, MMDRV_MIXER
);
238 case MIXER_OBJECTF_MIDIOUT
:
239 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIOUT
, TRUE
, MMDRV_MIXER
);
241 case MIXER_OBJECTF_HMIDIOUT
:
242 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIOUT
, FALSE
, MMDRV_MIXER
);
244 case MIXER_OBJECTF_MIDIIN
:
245 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIIN
, TRUE
, MMDRV_MIXER
);
247 case MIXER_OBJECTF_HMIDIIN
:
248 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_MIDIIN
, FALSE
, MMDRV_MIXER
);
250 case MIXER_OBJECTF_AUX
:
251 lpwm
= (LPWINE_MIXER
)MMDRV_GetRelated(hmix
, MMDRV_AUX
, TRUE
, MMDRV_MIXER
);
254 WARN("Unsupported flag (%08lx)\n", dwFlags
& 0xF0000000ul
);
256 uRet
= MMSYSERR_INVALFLAG
;
260 if (lpwm
== 0 && uRet
== MMSYSERR_NOERROR
)
261 uRet
= MMSYSERR_INVALPARAM
;
265 /**************************************************************************
266 * mixerGetNumDevs [WINMM.@]
268 UINT WINAPI
mixerGetNumDevs(void)
270 return MMDRV_GetNum(MMDRV_MIXER
);
273 /**************************************************************************
274 * mixerGetDevCapsA [WINMM.@]
276 UINT WINAPI
mixerGetDevCapsA(UINT_PTR uDeviceID
, LPMIXERCAPSA lpCaps
, UINT uSize
)
281 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
283 ret
= mixerGetDevCapsW(uDeviceID
, &micW
, sizeof(micW
));
285 if (ret
== MMSYSERR_NOERROR
) {
287 micA
.wMid
= micW
.wMid
;
288 micA
.wPid
= micW
.wPid
;
289 micA
.vDriverVersion
= micW
.vDriverVersion
;
290 WideCharToMultiByte( CP_ACP
, 0, micW
.szPname
, -1, micA
.szPname
,
291 sizeof(micA
.szPname
), NULL
, NULL
);
292 micA
.fdwSupport
= micW
.fdwSupport
;
293 micA
.cDestinations
= micW
.cDestinations
;
294 memcpy(lpCaps
, &micA
, min(uSize
, sizeof(micA
)));
299 /**************************************************************************
300 * mixerGetDevCapsW [WINMM.@]
302 UINT WINAPI
mixerGetDevCapsW(UINT_PTR uDeviceID
, LPMIXERCAPSW lpCaps
, UINT uSize
)
306 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
308 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_MIXER
, TRUE
)) == NULL
)
309 return MMSYSERR_BADDEVICEID
;
311 return MMDRV_Message(wmld
, MXDM_GETDEVCAPS
, (DWORD_PTR
)lpCaps
, uSize
, TRUE
);
314 UINT
MIXER_Open(LPHMIXER lphMix
, UINT uDeviceID
, DWORD_PTR dwCallback
,
315 DWORD_PTR dwInstance
, DWORD fdwOpen
, BOOL bFrom32
)
322 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
323 lphMix
, uDeviceID
, dwCallback
, dwInstance
, fdwOpen
);
325 wmld
= MMDRV_Alloc(sizeof(WINE_MIXER
), MMDRV_MIXER
, &hMix
, &fdwOpen
,
326 &dwCallback
, &dwInstance
, bFrom32
);
328 wmld
->uDeviceID
= uDeviceID
;
329 mod
.hmx
= (HMIXEROBJ
)hMix
;
330 mod
.dwCallback
= dwCallback
;
331 mod
.dwInstance
= dwInstance
;
333 dwRet
= MMDRV_Open(wmld
, MXDM_OPEN
, (DWORD
)&mod
, fdwOpen
);
335 if (dwRet
!= MMSYSERR_NOERROR
) {
336 MMDRV_Free(hMix
, wmld
);
339 if (lphMix
) *lphMix
= hMix
;
340 TRACE("=> %ld hMixer=%p\n", dwRet
, hMix
);
345 /**************************************************************************
346 * mixerOpen [WINMM.@]
348 UINT WINAPI
mixerOpen(LPHMIXER lphMix
, UINT uDeviceID
, DWORD_PTR dwCallback
,
349 DWORD_PTR dwInstance
, DWORD fdwOpen
)
351 return MIXER_Open(lphMix
, uDeviceID
, dwCallback
, dwInstance
, fdwOpen
, TRUE
);
354 /**************************************************************************
355 * mixerClose [WINMM.@]
357 UINT WINAPI
mixerClose(HMIXER hMix
)
362 TRACE("(%p)\n", hMix
);
364 if ((wmld
= MMDRV_Get(hMix
, MMDRV_MIXER
, FALSE
)) == NULL
) return MMSYSERR_INVALHANDLE
;
366 dwRet
= MMDRV_Close(wmld
, MXDM_CLOSE
);
367 MMDRV_Free(hMix
, wmld
);
372 /**************************************************************************
373 * mixerGetID [WINMM.@]
375 UINT WINAPI
mixerGetID(HMIXEROBJ hmix
, LPUINT lpid
, DWORD fdwID
)
378 UINT uRet
= MMSYSERR_NOERROR
;
380 TRACE("(%p %p %08lx)\n", hmix
, lpid
, fdwID
);
382 if ((uRet
= MIXER_GetDev(hmix
, fdwID
, &lpwm
)) != MMSYSERR_NOERROR
)
386 *lpid
= lpwm
->mld
.uDeviceID
;
391 /**************************************************************************
392 * mixerGetControlDetailsW [WINMM.@]
394 UINT WINAPI
mixerGetControlDetailsW(HMIXEROBJ hmix
, LPMIXERCONTROLDETAILS lpmcdW
,
398 UINT uRet
= MMSYSERR_NOERROR
;
400 TRACE("(%p, %p, %08lx)\n", hmix
, lpmcdW
, fdwDetails
);
402 if ((uRet
= MIXER_GetDev(hmix
, fdwDetails
, &lpwm
)) != MMSYSERR_NOERROR
)
405 if (lpmcdW
== NULL
|| lpmcdW
->cbStruct
!= sizeof(*lpmcdW
))
406 return MMSYSERR_INVALPARAM
;
408 return MMDRV_Message(&lpwm
->mld
, MXDM_GETCONTROLDETAILS
, (DWORD_PTR
)lpmcdW
,
412 /**************************************************************************
413 * mixerGetControlDetailsA [WINMM.@]
415 UINT WINAPI
mixerGetControlDetailsA(HMIXEROBJ hmix
, LPMIXERCONTROLDETAILS lpmcdA
,
418 DWORD ret
= MMSYSERR_NOTENABLED
;
420 TRACE("(%p, %p, %08lx)\n", hmix
, lpmcdA
, fdwDetails
);
422 if (lpmcdA
== NULL
|| lpmcdA
->cbStruct
!= sizeof(*lpmcdA
))
423 return MMSYSERR_INVALPARAM
;
425 switch (fdwDetails
& MIXER_GETCONTROLDETAILSF_QUERYMASK
) {
426 case MIXER_GETCONTROLDETAILSF_VALUE
:
427 /* can savely use A structure as it is, no string inside */
428 ret
= mixerGetControlDetailsW(hmix
, lpmcdA
, fdwDetails
);
430 case MIXER_GETCONTROLDETAILSF_LISTTEXT
:
432 MIXERCONTROLDETAILS_LISTTEXTA
*pDetailsA
= (MIXERCONTROLDETAILS_LISTTEXTA
*)lpmcdA
->paDetails
;
433 MIXERCONTROLDETAILS_LISTTEXTW
*pDetailsW
;
434 int size
= max(1, lpmcdA
->cChannels
) * sizeof(MIXERCONTROLDETAILS_LISTTEXTW
);
437 if (lpmcdA
->u
.cMultipleItems
!= 0) {
438 size
*= lpmcdA
->u
.cMultipleItems
;
440 pDetailsW
= HeapAlloc(GetProcessHeap(), 0, size
);
441 lpmcdA
->paDetails
= pDetailsW
;
442 lpmcdA
->cbDetails
= sizeof(MIXERCONTROLDETAILS_LISTTEXTW
);
443 /* set up lpmcd->paDetails */
444 ret
= mixerGetControlDetailsW(hmix
, lpmcdA
, fdwDetails
);
445 /* copy from lpmcd->paDetails back to paDetailsW; */
446 if (ret
== MMSYSERR_NOERROR
) {
447 for (i
= 0; i
< lpmcdA
->u
.cMultipleItems
* lpmcdA
->cChannels
; i
++) {
448 pDetailsA
->dwParam1
= pDetailsW
->dwParam1
;
449 pDetailsA
->dwParam2
= pDetailsW
->dwParam2
;
450 WideCharToMultiByte( CP_ACP
, 0, pDetailsW
->szName
, -1,
452 sizeof(pDetailsA
->szName
), NULL
, NULL
);
456 pDetailsA
-= lpmcdA
->u
.cMultipleItems
* lpmcdA
->cChannels
;
457 pDetailsW
-= lpmcdA
->u
.cMultipleItems
* lpmcdA
->cChannels
;
459 HeapFree(GetProcessHeap(), 0, pDetailsW
);
460 lpmcdA
->paDetails
= pDetailsA
;
461 lpmcdA
->cbDetails
= sizeof(MIXERCONTROLDETAILS_LISTTEXTA
);
465 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails
);
471 /**************************************************************************
472 * mixerGetLineControlsA [WINMM.@]
474 UINT WINAPI
mixerGetLineControlsA(HMIXEROBJ hmix
, LPMIXERLINECONTROLSA lpmlcA
,
477 MIXERLINECONTROLSW mlcW
;
481 TRACE("(%p, %p, %08lx)\n", hmix
, lpmlcA
, fdwControls
);
483 if (lpmlcA
== NULL
|| lpmlcA
->cbStruct
!= sizeof(*lpmlcA
) ||
484 lpmlcA
->cbmxctrl
!= sizeof(MIXERCONTROLA
))
485 return MMSYSERR_INVALPARAM
;
487 mlcW
.cbStruct
= sizeof(mlcW
);
488 mlcW
.dwLineID
= lpmlcA
->dwLineID
;
489 mlcW
.u
.dwControlID
= lpmlcA
->u
.dwControlID
;
490 mlcW
.u
.dwControlType
= lpmlcA
->u
.dwControlType
;
492 /* Debugging on Windows shows for MIXER_GETLINECONTROLSF_ONEBYTYPE only,
493 the control count is assumed to be 1 - This is relied upon by a game,
495 if (MIXER_GETLINECONTROLSF_ONEBYTYPE
== fdwControls
) {
498 mlcW
.cControls
= lpmlcA
->cControls
;
500 mlcW
.cbmxctrl
= sizeof(MIXERCONTROLW
);
501 mlcW
.pamxctrl
= HeapAlloc(GetProcessHeap(), 0,
502 mlcW
.cControls
* mlcW
.cbmxctrl
);
504 ret
= mixerGetLineControlsW(hmix
, &mlcW
, fdwControls
);
506 if (ret
== MMSYSERR_NOERROR
) {
507 lpmlcA
->dwLineID
= mlcW
.dwLineID
;
508 lpmlcA
->u
.dwControlID
= mlcW
.u
.dwControlID
;
509 lpmlcA
->u
.dwControlType
= mlcW
.u
.dwControlType
;
510 lpmlcA
->cControls
= mlcW
.cControls
;
512 for (i
= 0; i
< mlcW
.cControls
; i
++) {
513 lpmlcA
->pamxctrl
[i
].cbStruct
= sizeof(MIXERCONTROLA
);
514 lpmlcA
->pamxctrl
[i
].dwControlID
= mlcW
.pamxctrl
[i
].dwControlID
;
515 lpmlcA
->pamxctrl
[i
].dwControlType
= mlcW
.pamxctrl
[i
].dwControlType
;
516 lpmlcA
->pamxctrl
[i
].fdwControl
= mlcW
.pamxctrl
[i
].fdwControl
;
517 lpmlcA
->pamxctrl
[i
].cMultipleItems
= mlcW
.pamxctrl
[i
].cMultipleItems
;
518 WideCharToMultiByte( CP_ACP
, 0, mlcW
.pamxctrl
[i
].szShortName
, -1,
519 lpmlcA
->pamxctrl
[i
].szShortName
,
520 sizeof(lpmlcA
->pamxctrl
[i
].szShortName
), NULL
, NULL
);
521 WideCharToMultiByte( CP_ACP
, 0, mlcW
.pamxctrl
[i
].szName
, -1,
522 lpmlcA
->pamxctrl
[i
].szName
,
523 sizeof(lpmlcA
->pamxctrl
[i
].szName
), NULL
, NULL
);
524 /* sizeof(lpmlcA->pamxctrl[i].Bounds) ==
525 * sizeof(mlcW.pamxctrl[i].Bounds) */
526 memcpy(&lpmlcA
->pamxctrl
[i
].Bounds
, &mlcW
.pamxctrl
[i
].Bounds
,
527 sizeof(mlcW
.pamxctrl
[i
].Bounds
));
528 /* sizeof(lpmlcA->pamxctrl[i].Metrics) ==
529 * sizeof(mlcW.pamxctrl[i].Metrics) */
530 memcpy(&lpmlcA
->pamxctrl
[i
].Metrics
, &mlcW
.pamxctrl
[i
].Metrics
,
531 sizeof(mlcW
.pamxctrl
[i
].Metrics
));
535 HeapFree(GetProcessHeap(), 0, mlcW
.pamxctrl
);
540 /**************************************************************************
541 * mixerGetLineControlsW [WINMM.@]
543 UINT WINAPI
mixerGetLineControlsW(HMIXEROBJ hmix
, LPMIXERLINECONTROLSW lpmlcW
,
547 UINT uRet
= MMSYSERR_NOERROR
;
549 TRACE("(%p, %p, %08lx)\n", hmix
, lpmlcW
, fdwControls
);
551 if ((uRet
= MIXER_GetDev(hmix
, fdwControls
, &lpwm
)) != MMSYSERR_NOERROR
)
554 if (lpmlcW
== NULL
|| lpmlcW
->cbStruct
!= sizeof(*lpmlcW
))
555 return MMSYSERR_INVALPARAM
;
557 return MMDRV_Message(&lpwm
->mld
, MXDM_GETLINECONTROLS
, (DWORD_PTR
)lpmlcW
,
561 /**************************************************************************
562 * mixerGetLineInfoW [WINMM.@]
564 UINT WINAPI
mixerGetLineInfoW(HMIXEROBJ hmix
, LPMIXERLINEW lpmliW
, DWORD fdwInfo
)
567 UINT uRet
= MMSYSERR_NOERROR
;
569 TRACE("(%p, %p, %08lx)\n", hmix
, lpmliW
, fdwInfo
);
571 if ((uRet
= MIXER_GetDev(hmix
, fdwInfo
, &lpwm
)) != MMSYSERR_NOERROR
)
574 return MMDRV_Message(&lpwm
->mld
, MXDM_GETLINEINFO
, (DWORD_PTR
)lpmliW
,
578 /**************************************************************************
579 * mixerGetLineInfoA [WINMM.@]
581 UINT WINAPI
mixerGetLineInfoA(HMIXEROBJ hmix
, LPMIXERLINEA lpmliA
,
587 TRACE("(%p, %p, %08lx)\n", hmix
, lpmliA
, fdwInfo
);
589 if (lpmliA
== NULL
|| lpmliA
->cbStruct
!= sizeof(*lpmliA
))
590 return MMSYSERR_INVALPARAM
;
592 mliW
.cbStruct
= sizeof(mliW
);
593 switch (fdwInfo
& MIXER_GETLINEINFOF_QUERYMASK
) {
594 case MIXER_GETLINEINFOF_COMPONENTTYPE
:
595 mliW
.dwComponentType
= lpmliA
->dwComponentType
;
597 case MIXER_GETLINEINFOF_DESTINATION
:
598 mliW
.dwDestination
= lpmliA
->dwDestination
;
600 case MIXER_GETLINEINFOF_LINEID
:
601 mliW
.dwLineID
= lpmliA
->dwLineID
;
603 case MIXER_GETLINEINFOF_SOURCE
:
604 mliW
.dwDestination
= lpmliA
->dwDestination
;
605 mliW
.dwSource
= lpmliA
->dwSource
;
607 case MIXER_GETLINEINFOF_TARGETTYPE
:
608 mliW
.Target
.dwType
= lpmliA
->Target
.dwType
;
609 mliW
.Target
.wMid
= lpmliA
->Target
.wMid
;
610 mliW
.Target
.wPid
= lpmliA
->Target
.wPid
;
611 mliW
.Target
.vDriverVersion
= lpmliA
->Target
.vDriverVersion
;
612 MultiByteToWideChar( CP_ACP
, 0, lpmliA
->Target
.szPname
, -1, mliW
.Target
.szPname
, sizeof(mliW
.Target
.szPname
));
615 WARN("Unsupported fdwControls=0x%08lx\n", fdwInfo
);
616 return MMSYSERR_INVALFLAG
;
619 ret
= mixerGetLineInfoW(hmix
, &mliW
, fdwInfo
);
621 lpmliA
->dwDestination
= mliW
.dwDestination
;
622 lpmliA
->dwSource
= mliW
.dwSource
;
623 lpmliA
->dwLineID
= mliW
.dwLineID
;
624 lpmliA
->fdwLine
= mliW
.fdwLine
;
625 lpmliA
->dwUser
= mliW
.dwUser
;
626 lpmliA
->dwComponentType
= mliW
.dwComponentType
;
627 lpmliA
->cChannels
= mliW
.cChannels
;
628 lpmliA
->cConnections
= mliW
.cConnections
;
629 lpmliA
->cControls
= mliW
.cControls
;
630 WideCharToMultiByte( CP_ACP
, 0, mliW
.szShortName
, -1, lpmliA
->szShortName
,
631 sizeof(lpmliA
->szShortName
), NULL
, NULL
);
632 WideCharToMultiByte( CP_ACP
, 0, mliW
.szName
, -1, lpmliA
->szName
,
633 sizeof(lpmliA
->szName
), NULL
, NULL
);
634 lpmliA
->Target
.dwType
= mliW
.Target
.dwType
;
635 lpmliA
->Target
.dwDeviceID
= mliW
.Target
.dwDeviceID
;
636 lpmliA
->Target
.wMid
= mliW
.Target
.wMid
;
637 lpmliA
->Target
.wPid
= mliW
.Target
.wPid
;
638 lpmliA
->Target
.vDriverVersion
= mliW
.Target
.vDriverVersion
;
639 WideCharToMultiByte( CP_ACP
, 0, mliW
.Target
.szPname
, -1, lpmliA
->Target
.szPname
,
640 sizeof(lpmliA
->Target
.szPname
), NULL
, NULL
);
645 /**************************************************************************
646 * mixerSetControlDetails [WINMM.@]
648 UINT WINAPI
mixerSetControlDetails(HMIXEROBJ hmix
, LPMIXERCONTROLDETAILS lpmcd
,
652 UINT uRet
= MMSYSERR_NOERROR
;
654 TRACE("(%p, %p, %08lx)\n", hmix
, lpmcd
, fdwDetails
);
656 if ((uRet
= MIXER_GetDev(hmix
, fdwDetails
, &lpwm
)) != MMSYSERR_NOERROR
)
659 return MMDRV_Message(&lpwm
->mld
, MXDM_SETCONTROLDETAILS
, (DWORD_PTR
)lpmcd
,
663 /**************************************************************************
664 * mixerMessage [WINMM.@]
666 DWORD WINAPI
mixerMessage(HMIXER hmix
, UINT uMsg
, DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
670 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
671 (DWORD
)hmix
, uMsg
, dwParam1
, dwParam2
);
673 if ((wmld
= MMDRV_Get(hmix
, MMDRV_MIXER
, FALSE
)) == NULL
)
674 return MMSYSERR_INVALHANDLE
;
676 return MMDRV_Message(wmld
, uMsg
, dwParam1
, dwParam2
, TRUE
);
679 /**************************************************************************
680 * auxGetNumDevs [WINMM.@]
682 UINT WINAPI
auxGetNumDevs(void)
684 return MMDRV_GetNum(MMDRV_AUX
);
687 /**************************************************************************
688 * auxGetDevCapsW [WINMM.@]
690 UINT WINAPI
auxGetDevCapsW(UINT_PTR uDeviceID
, LPAUXCAPSW lpCaps
, UINT uSize
)
694 TRACE("(%04X, %p, %d) !\n", uDeviceID
, lpCaps
, uSize
);
696 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
698 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
699 return MMSYSERR_INVALHANDLE
;
700 return MMDRV_Message(wmld
, AUXDM_GETDEVCAPS
, (DWORD_PTR
)lpCaps
, uSize
, TRUE
);
703 /**************************************************************************
704 * auxGetDevCapsA [WINMM.@]
706 UINT WINAPI
auxGetDevCapsA(UINT_PTR uDeviceID
, LPAUXCAPSA lpCaps
, UINT uSize
)
711 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
713 ret
= auxGetDevCapsW(uDeviceID
, &acW
, sizeof(acW
));
715 if (ret
== MMSYSERR_NOERROR
) {
719 acA
.vDriverVersion
= acW
.vDriverVersion
;
720 WideCharToMultiByte( CP_ACP
, 0, acW
.szPname
, -1, acA
.szPname
,
721 sizeof(acA
.szPname
), NULL
, NULL
);
722 acA
.wTechnology
= acW
.wTechnology
;
723 acA
.dwSupport
= acW
.dwSupport
;
724 memcpy(lpCaps
, &acA
, min(uSize
, sizeof(acA
)));
729 /**************************************************************************
730 * auxGetVolume [WINMM.@]
732 UINT WINAPI
auxGetVolume(UINT uDeviceID
, DWORD
* lpdwVolume
)
736 TRACE("(%04X, %p) !\n", uDeviceID
, lpdwVolume
);
738 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
739 return MMSYSERR_INVALHANDLE
;
740 return MMDRV_Message(wmld
, AUXDM_GETVOLUME
, (DWORD_PTR
)lpdwVolume
, 0L, TRUE
);
743 /**************************************************************************
744 * auxSetVolume [WINMM.@]
746 UINT WINAPI
auxSetVolume(UINT uDeviceID
, DWORD dwVolume
)
750 TRACE("(%04X, %lu) !\n", uDeviceID
, dwVolume
);
752 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
753 return MMSYSERR_INVALHANDLE
;
754 return MMDRV_Message(wmld
, AUXDM_SETVOLUME
, dwVolume
, 0L, TRUE
);
757 /**************************************************************************
758 * auxOutMessage [WINMM.@]
760 UINT WINAPI
auxOutMessage(UINT uDeviceID
, UINT uMessage
, DWORD_PTR dw1
, DWORD_PTR dw2
)
764 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_AUX
, TRUE
)) == NULL
)
765 return MMSYSERR_INVALHANDLE
;
767 return MMDRV_Message(wmld
, uMessage
, dw1
, dw2
, TRUE
);
770 /**************************************************************************
771 * midiOutGetNumDevs [WINMM.@]
773 UINT WINAPI
midiOutGetNumDevs(void)
775 return MMDRV_GetNum(MMDRV_MIDIOUT
);
778 /**************************************************************************
779 * midiOutGetDevCapsW [WINMM.@]
781 UINT WINAPI
midiOutGetDevCapsW(UINT_PTR uDeviceID
, LPMIDIOUTCAPSW lpCaps
,
786 TRACE("(%u, %p, %u);\n", uDeviceID
, lpCaps
, uSize
);
788 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
790 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_MIDIOUT
, TRUE
)) == NULL
)
791 return MMSYSERR_INVALHANDLE
;
793 return MMDRV_Message(wmld
, MODM_GETDEVCAPS
, (DWORD_PTR
)lpCaps
, uSize
, TRUE
);
796 /**************************************************************************
797 * midiOutGetDevCapsA [WINMM.@]
799 UINT WINAPI
midiOutGetDevCapsA(UINT_PTR uDeviceID
, LPMIDIOUTCAPSA lpCaps
,
805 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
807 ret
= midiOutGetDevCapsW(uDeviceID
, &mocW
, sizeof(mocW
));
809 if (ret
== MMSYSERR_NOERROR
) {
811 mocA
.wMid
= mocW
.wMid
;
812 mocA
.wPid
= mocW
.wPid
;
813 mocA
.vDriverVersion
= mocW
.vDriverVersion
;
814 WideCharToMultiByte( CP_ACP
, 0, mocW
.szPname
, -1, mocA
.szPname
,
815 sizeof(mocA
.szPname
), NULL
, NULL
);
816 mocA
.wTechnology
= mocW
.wTechnology
;
817 mocA
.wVoices
= mocW
.wVoices
;
818 mocA
.wNotes
= mocW
.wNotes
;
819 mocA
.wChannelMask
= mocW
.wChannelMask
;
820 mocA
.dwSupport
= mocW
.dwSupport
;
821 memcpy(lpCaps
, &mocA
, min(uSize
, sizeof(mocA
)));
826 /**************************************************************************
827 * midiOutGetErrorTextA [WINMM.@]
828 * midiInGetErrorTextA [WINMM.@]
830 UINT WINAPI
midiOutGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
834 if (lpText
== NULL
) ret
= MMSYSERR_INVALPARAM
;
835 else if (uSize
== 0) ret
= MMSYSERR_NOERROR
;
838 LPWSTR xstr
= HeapAlloc(GetProcessHeap(), 0, uSize
* sizeof(WCHAR
));
839 if (!xstr
) ret
= MMSYSERR_NOMEM
;
842 ret
= midiOutGetErrorTextW(uError
, xstr
, uSize
);
843 if (ret
== MMSYSERR_NOERROR
)
844 WideCharToMultiByte(CP_ACP
, 0, xstr
, -1, lpText
, uSize
, NULL
, NULL
);
845 HeapFree(GetProcessHeap(), 0, xstr
);
851 /**************************************************************************
852 * midiOutGetErrorTextW [WINMM.@]
853 * midiInGetErrorTextW [WINMM.@]
855 UINT WINAPI
midiOutGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
857 UINT ret
= MMSYSERR_BADERRNUM
;
859 if (lpText
== NULL
) ret
= MMSYSERR_INVALPARAM
;
860 else if (uSize
== 0) ret
= MMSYSERR_NOERROR
;
862 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
863 * a warning for the test was always true */
864 (/*uError >= MMSYSERR_BASE && */ uError
<= MMSYSERR_LASTERROR
) ||
865 (uError
>= MIDIERR_BASE
&& uError
<= MIDIERR_LASTERROR
)) {
866 if (LoadStringW(WINMM_IData
.hWinMM32Instance
,
867 uError
, lpText
, uSize
) > 0) {
868 ret
= MMSYSERR_NOERROR
;
874 /**************************************************************************
875 * MIDI_OutAlloc [internal]
877 static LPWINE_MIDI
MIDI_OutAlloc(HMIDIOUT
* lphMidiOut
, LPDWORD lpdwCallback
,
878 LPDWORD lpdwInstance
, LPDWORD lpdwFlags
,
879 DWORD cIDs
, MIDIOPENSTRMID
* lpIDs
, BOOL bFrom32
)
885 size
= sizeof(WINE_MIDI
) + (cIDs
? (cIDs
-1) : 0) * sizeof(MIDIOPENSTRMID
);
887 lpwm
= (LPWINE_MIDI
)MMDRV_Alloc(size
, MMDRV_MIDIOUT
, &hMidiOut
, lpdwFlags
,
888 lpdwCallback
, lpdwInstance
, bFrom32
);
890 if (lphMidiOut
!= NULL
)
891 *lphMidiOut
= hMidiOut
;
894 lpwm
->mod
.hMidi
= (HMIDI
) hMidiOut
;
895 lpwm
->mod
.dwCallback
= *lpdwCallback
;
896 lpwm
->mod
.dwInstance
= *lpdwInstance
;
897 lpwm
->mod
.dnDevNode
= 0;
898 lpwm
->mod
.cIds
= cIDs
;
900 memcpy(&(lpwm
->mod
.rgIds
), lpIDs
, cIDs
* sizeof(MIDIOPENSTRMID
));
905 UINT
MIDI_OutOpen(LPHMIDIOUT lphMidiOut
, UINT uDeviceID
, DWORD_PTR dwCallback
,
906 DWORD_PTR dwInstance
, DWORD dwFlags
, BOOL bFrom32
)
912 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
913 lphMidiOut
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
);
915 if (lphMidiOut
!= NULL
) *lphMidiOut
= 0;
917 lpwm
= MIDI_OutAlloc(&hMidiOut
, &dwCallback
, &dwInstance
, &dwFlags
,
921 return MMSYSERR_NOMEM
;
923 lpwm
->mld
.uDeviceID
= uDeviceID
;
925 dwRet
= MMDRV_Open((LPWINE_MLD
)lpwm
, MODM_OPEN
, (DWORD
)&lpwm
->mod
, dwFlags
);
927 if (dwRet
!= MMSYSERR_NOERROR
) {
928 MMDRV_Free(hMidiOut
, (LPWINE_MLD
)lpwm
);
932 if (lphMidiOut
) *lphMidiOut
= hMidiOut
;
933 TRACE("=> %d hMidi=%p\n", dwRet
, hMidiOut
);
938 /**************************************************************************
939 * midiOutOpen [WINMM.@]
941 UINT WINAPI
midiOutOpen(LPHMIDIOUT lphMidiOut
, UINT uDeviceID
,
942 DWORD_PTR dwCallback
, DWORD_PTR dwInstance
, DWORD dwFlags
)
944 return MIDI_OutOpen(lphMidiOut
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
, TRUE
);
947 /**************************************************************************
948 * midiOutClose [WINMM.@]
950 UINT WINAPI
midiOutClose(HMIDIOUT hMidiOut
)
955 TRACE("(%p)\n", hMidiOut
);
957 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
958 return MMSYSERR_INVALHANDLE
;
960 dwRet
= MMDRV_Close(wmld
, MODM_CLOSE
);
961 MMDRV_Free(hMidiOut
, wmld
);
966 /**************************************************************************
967 * midiOutPrepareHeader [WINMM.@]
969 UINT WINAPI
midiOutPrepareHeader(HMIDIOUT hMidiOut
,
970 MIDIHDR
* lpMidiOutHdr
, UINT uSize
)
974 TRACE("(%p, %p, %d)\n", hMidiOut
, lpMidiOutHdr
, uSize
);
976 if (lpMidiOutHdr
== NULL
|| uSize
< sizeof (MIDIHDR
))
977 return MMSYSERR_INVALPARAM
;
979 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
980 return MMSYSERR_INVALHANDLE
;
982 return MMDRV_Message(wmld
, MODM_PREPARE
, (DWORD_PTR
)lpMidiOutHdr
, uSize
, TRUE
);
985 /**************************************************************************
986 * midiOutUnprepareHeader [WINMM.@]
988 UINT WINAPI
midiOutUnprepareHeader(HMIDIOUT hMidiOut
,
989 MIDIHDR
* lpMidiOutHdr
, UINT uSize
)
993 TRACE("(%p, %p, %d)\n", hMidiOut
, lpMidiOutHdr
, uSize
);
995 if (lpMidiOutHdr
== NULL
|| uSize
< sizeof (MIDIHDR
))
996 return MMSYSERR_INVALPARAM
;
998 if (!(lpMidiOutHdr
->dwFlags
& MHDR_PREPARED
)) {
999 return MMSYSERR_NOERROR
;
1002 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1003 return MMSYSERR_INVALHANDLE
;
1005 return MMDRV_Message(wmld
, MODM_UNPREPARE
, (DWORD_PTR
)lpMidiOutHdr
, uSize
, TRUE
);
1008 /**************************************************************************
1009 * midiOutShortMsg [WINMM.@]
1011 UINT WINAPI
midiOutShortMsg(HMIDIOUT hMidiOut
, DWORD dwMsg
)
1015 TRACE("(%p, %08lX)\n", hMidiOut
, dwMsg
);
1017 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1018 return MMSYSERR_INVALHANDLE
;
1020 return MMDRV_Message(wmld
, MODM_DATA
, dwMsg
, 0L, TRUE
);
1023 /**************************************************************************
1024 * midiOutLongMsg [WINMM.@]
1026 UINT WINAPI
midiOutLongMsg(HMIDIOUT hMidiOut
,
1027 MIDIHDR
* lpMidiOutHdr
, UINT uSize
)
1031 TRACE("(%p, %p, %d)\n", hMidiOut
, lpMidiOutHdr
, uSize
);
1033 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1034 return MMSYSERR_INVALHANDLE
;
1036 return MMDRV_Message(wmld
, MODM_LONGDATA
, (DWORD_PTR
)lpMidiOutHdr
, uSize
, TRUE
);
1039 /**************************************************************************
1040 * midiOutReset [WINMM.@]
1042 UINT WINAPI
midiOutReset(HMIDIOUT hMidiOut
)
1046 TRACE("(%p)\n", hMidiOut
);
1048 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1049 return MMSYSERR_INVALHANDLE
;
1051 return MMDRV_Message(wmld
, MODM_RESET
, 0L, 0L, TRUE
);
1054 /**************************************************************************
1055 * midiOutGetVolume [WINMM.@]
1057 UINT WINAPI
midiOutGetVolume(HMIDIOUT hMidiOut
, DWORD
* lpdwVolume
)
1061 TRACE("(%p, %p);\n", hMidiOut
, lpdwVolume
);
1063 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, TRUE
)) == NULL
)
1064 return MMSYSERR_INVALHANDLE
;
1066 return MMDRV_Message(wmld
, MODM_GETVOLUME
, (DWORD_PTR
)lpdwVolume
, 0L, TRUE
);
1069 /**************************************************************************
1070 * midiOutSetVolume [WINMM.@]
1072 UINT WINAPI
midiOutSetVolume(HMIDIOUT hMidiOut
, DWORD dwVolume
)
1076 TRACE("(%p, %ld);\n", hMidiOut
, dwVolume
);
1078 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, TRUE
)) == NULL
)
1079 return MMSYSERR_INVALHANDLE
;
1081 return MMDRV_Message(wmld
, MODM_SETVOLUME
, dwVolume
, 0L, TRUE
);
1084 /**************************************************************************
1085 * midiOutCachePatches [WINMM.@]
1087 UINT WINAPI
midiOutCachePatches(HMIDIOUT hMidiOut
, UINT uBank
,
1088 WORD
* lpwPatchArray
, UINT uFlags
)
1090 /* not really necessary to support this */
1091 FIXME("not supported yet\n");
1092 return MMSYSERR_NOTSUPPORTED
;
1095 /**************************************************************************
1096 * midiOutCacheDrumPatches [WINMM.@]
1098 UINT WINAPI
midiOutCacheDrumPatches(HMIDIOUT hMidiOut
, UINT uPatch
,
1099 WORD
* lpwKeyArray
, UINT uFlags
)
1101 FIXME("not supported yet\n");
1102 return MMSYSERR_NOTSUPPORTED
;
1105 /**************************************************************************
1106 * midiOutGetID [WINMM.@]
1108 UINT WINAPI
midiOutGetID(HMIDIOUT hMidiOut
, UINT
* lpuDeviceID
)
1112 TRACE("(%p, %p)\n", hMidiOut
, lpuDeviceID
);
1114 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALPARAM
;
1115 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1116 return MMSYSERR_INVALHANDLE
;
1118 *lpuDeviceID
= wmld
->uDeviceID
;
1119 return MMSYSERR_NOERROR
;
1122 /**************************************************************************
1123 * midiOutMessage [WINMM.@]
1125 UINT WINAPI
midiOutMessage(HMIDIOUT hMidiOut
, UINT uMessage
,
1126 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
1130 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut
, uMessage
, dwParam1
, dwParam2
);
1132 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, FALSE
)) == NULL
) {
1134 if (uMessage
== 0x0001) {
1135 *(LPDWORD
)dwParam1
= 1;
1138 if ((wmld
= MMDRV_Get(hMidiOut
, MMDRV_MIDIOUT
, TRUE
)) != NULL
) {
1139 return MMDRV_PhysicalFeatures(wmld
, uMessage
, dwParam1
, dwParam2
);
1141 return MMSYSERR_INVALHANDLE
;
1147 FIXME("can't handle OPEN or CLOSE message!\n");
1148 return MMSYSERR_NOTSUPPORTED
;
1150 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
1153 /**************************************************************************
1154 * midiInGetNumDevs [WINMM.@]
1156 UINT WINAPI
midiInGetNumDevs(void)
1158 return MMDRV_GetNum(MMDRV_MIDIIN
);
1161 /**************************************************************************
1162 * midiInGetDevCapsW [WINMM.@]
1164 UINT WINAPI
midiInGetDevCapsW(UINT_PTR uDeviceID
, LPMIDIINCAPSW lpCaps
, UINT uSize
)
1168 TRACE("(%d, %p, %d);\n", uDeviceID
, lpCaps
, uSize
);
1170 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
1172 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_MIDIIN
, TRUE
)) == NULL
)
1173 return MMSYSERR_INVALHANDLE
;
1175 return MMDRV_Message(wmld
, MIDM_GETDEVCAPS
, (DWORD_PTR
)lpCaps
, uSize
, TRUE
);
1178 /**************************************************************************
1179 * midiInGetDevCapsA [WINMM.@]
1181 UINT WINAPI
midiInGetDevCapsA(UINT_PTR uDeviceID
, LPMIDIINCAPSA lpCaps
, UINT uSize
)
1186 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
1188 ret
= midiInGetDevCapsW(uDeviceID
, &micW
, sizeof(micW
));
1190 if (ret
== MMSYSERR_NOERROR
) {
1192 micA
.wMid
= micW
.wMid
;
1193 micA
.wPid
= micW
.wPid
;
1194 micA
.vDriverVersion
= micW
.vDriverVersion
;
1195 WideCharToMultiByte( CP_ACP
, 0, micW
.szPname
, -1, micA
.szPname
,
1196 sizeof(micA
.szPname
), NULL
, NULL
);
1197 micA
.dwSupport
= micW
.dwSupport
;
1198 memcpy(lpCaps
, &micA
, min(uSize
, sizeof(micA
)));
1203 UINT
MIDI_InOpen(HMIDIIN
* lphMidiIn
, UINT uDeviceID
, DWORD_PTR dwCallback
,
1204 DWORD_PTR dwInstance
, DWORD dwFlags
, BOOL bFrom32
)
1210 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1211 lphMidiIn
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
);
1213 if (lphMidiIn
!= NULL
) *lphMidiIn
= 0;
1215 lpwm
= (LPWINE_MIDI
)MMDRV_Alloc(sizeof(WINE_MIDI
), MMDRV_MIDIIN
, &hMidiIn
,
1216 &dwFlags
, &dwCallback
, &dwInstance
, bFrom32
);
1219 return MMSYSERR_NOMEM
;
1221 lpwm
->mod
.hMidi
= (HMIDI
) hMidiIn
;
1222 lpwm
->mod
.dwCallback
= dwCallback
;
1223 lpwm
->mod
.dwInstance
= dwInstance
;
1225 lpwm
->mld
.uDeviceID
= uDeviceID
;
1226 dwRet
= MMDRV_Open(&lpwm
->mld
, MIDM_OPEN
, (DWORD
)&lpwm
->mod
, dwFlags
);
1228 if (dwRet
!= MMSYSERR_NOERROR
) {
1229 MMDRV_Free(hMidiIn
, &lpwm
->mld
);
1232 if (lphMidiIn
!= NULL
) *lphMidiIn
= hMidiIn
;
1233 TRACE("=> %ld hMidi=%p\n", dwRet
, hMidiIn
);
1238 /**************************************************************************
1239 * midiInOpen [WINMM.@]
1241 UINT WINAPI
midiInOpen(HMIDIIN
* lphMidiIn
, UINT uDeviceID
,
1242 DWORD_PTR dwCallback
, DWORD_PTR dwInstance
, DWORD dwFlags
)
1244 return MIDI_InOpen(lphMidiIn
, uDeviceID
, dwCallback
, dwInstance
, dwFlags
, TRUE
);
1247 /**************************************************************************
1248 * midiInClose [WINMM.@]
1250 UINT WINAPI
midiInClose(HMIDIIN hMidiIn
)
1255 TRACE("(%p)\n", hMidiIn
);
1257 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1258 return MMSYSERR_INVALHANDLE
;
1260 dwRet
= MMDRV_Close(wmld
, MIDM_CLOSE
);
1261 MMDRV_Free(hMidiIn
, wmld
);
1265 /**************************************************************************
1266 * midiInPrepareHeader [WINMM.@]
1268 UINT WINAPI
midiInPrepareHeader(HMIDIIN hMidiIn
,
1269 MIDIHDR
* lpMidiInHdr
, UINT uSize
)
1273 TRACE("(%p, %p, %d)\n", hMidiIn
, lpMidiInHdr
, uSize
);
1275 if (lpMidiInHdr
== NULL
|| uSize
< sizeof (MIDIHDR
))
1276 return MMSYSERR_INVALPARAM
;
1278 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1279 return MMSYSERR_INVALHANDLE
;
1281 return MMDRV_Message(wmld
, MIDM_PREPARE
, (DWORD_PTR
)lpMidiInHdr
, uSize
, TRUE
);
1284 /**************************************************************************
1285 * midiInUnprepareHeader [WINMM.@]
1287 UINT WINAPI
midiInUnprepareHeader(HMIDIIN hMidiIn
,
1288 MIDIHDR
* lpMidiInHdr
, UINT uSize
)
1292 TRACE("(%p, %p, %d)\n", hMidiIn
, lpMidiInHdr
, uSize
);
1294 if (lpMidiInHdr
== NULL
|| uSize
< sizeof (MIDIHDR
))
1295 return MMSYSERR_INVALPARAM
;
1297 if (!(lpMidiInHdr
->dwFlags
& MHDR_PREPARED
)) {
1298 return MMSYSERR_NOERROR
;
1301 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1302 return MMSYSERR_INVALHANDLE
;
1304 return MMDRV_Message(wmld
, MIDM_UNPREPARE
, (DWORD_PTR
)lpMidiInHdr
, uSize
, TRUE
);
1307 /**************************************************************************
1308 * midiInAddBuffer [WINMM.@]
1310 UINT WINAPI
midiInAddBuffer(HMIDIIN hMidiIn
,
1311 MIDIHDR
* lpMidiInHdr
, UINT uSize
)
1315 TRACE("(%p, %p, %d)\n", hMidiIn
, lpMidiInHdr
, uSize
);
1317 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1318 return MMSYSERR_INVALHANDLE
;
1320 return MMDRV_Message(wmld
, MIDM_ADDBUFFER
, (DWORD_PTR
)lpMidiInHdr
, uSize
, TRUE
);
1323 /**************************************************************************
1324 * midiInStart [WINMM.@]
1326 UINT WINAPI
midiInStart(HMIDIIN hMidiIn
)
1330 TRACE("(%p)\n", hMidiIn
);
1332 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1333 return MMSYSERR_INVALHANDLE
;
1335 return MMDRV_Message(wmld
, MIDM_START
, 0L, 0L, TRUE
);
1338 /**************************************************************************
1339 * midiInStop [WINMM.@]
1341 UINT WINAPI
midiInStop(HMIDIIN hMidiIn
)
1345 TRACE("(%p)\n", hMidiIn
);
1347 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1348 return MMSYSERR_INVALHANDLE
;
1350 return MMDRV_Message(wmld
, MIDM_STOP
, 0L, 0L, TRUE
);
1353 /**************************************************************************
1354 * midiInReset [WINMM.@]
1356 UINT WINAPI
midiInReset(HMIDIIN hMidiIn
)
1360 TRACE("(%p)\n", hMidiIn
);
1362 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1363 return MMSYSERR_INVALHANDLE
;
1365 return MMDRV_Message(wmld
, MIDM_RESET
, 0L, 0L, TRUE
);
1368 /**************************************************************************
1369 * midiInGetID [WINMM.@]
1371 UINT WINAPI
midiInGetID(HMIDIIN hMidiIn
, UINT
* lpuDeviceID
)
1375 TRACE("(%p, %p)\n", hMidiIn
, lpuDeviceID
);
1377 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALPARAM
;
1379 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, TRUE
)) == NULL
)
1380 return MMSYSERR_INVALHANDLE
;
1382 *lpuDeviceID
= wmld
->uDeviceID
;
1384 return MMSYSERR_NOERROR
;
1387 /**************************************************************************
1388 * midiInMessage [WINMM.@]
1390 UINT WINAPI
midiInMessage(HMIDIIN hMidiIn
, UINT uMessage
,
1391 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
1395 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn
, uMessage
, dwParam1
, dwParam2
);
1397 if ((wmld
= MMDRV_Get(hMidiIn
, MMDRV_MIDIIN
, FALSE
)) == NULL
)
1398 return MMSYSERR_INVALHANDLE
;
1403 FIXME("can't handle OPEN or CLOSE message!\n");
1404 return MMSYSERR_NOTSUPPORTED
;
1406 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
1409 typedef struct WINE_MIDIStream
{
1420 LPMIDIHDR lpMidiHdr
;
1423 #define WINE_MSM_HEADER (WM_USER+0)
1424 #define WINE_MSM_STOP (WM_USER+1)
1426 /**************************************************************************
1427 * MMSYSTEM_GetMidiStream [internal]
1429 static BOOL
MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm
, WINE_MIDIStream
** lpMidiStrm
, WINE_MIDI
** lplpwm
)
1431 WINE_MIDI
* lpwm
= (LPWINE_MIDI
)MMDRV_Get(hMidiStrm
, MMDRV_MIDIOUT
, FALSE
);
1440 *lpMidiStrm
= (WINE_MIDIStream
*)lpwm
->mod
.rgIds
.dwStreamID
;
1442 return *lpMidiStrm
!= NULL
;
1445 /**************************************************************************
1446 * MMSYSTEM_MidiStream_Convert [internal]
1448 static DWORD
MMSYSTEM_MidiStream_Convert(WINE_MIDIStream
* lpMidiStrm
, DWORD pulse
)
1452 if (lpMidiStrm
->dwTimeDiv
== 0) {
1453 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1454 } else if (lpMidiStrm
->dwTimeDiv
> 0x8000) { /* SMPTE, unchecked FIXME? */
1455 int nf
= -(char)HIBYTE(lpMidiStrm
->dwTimeDiv
); /* number of frames */
1456 int nsf
= LOBYTE(lpMidiStrm
->dwTimeDiv
); /* number of sub-frames */
1457 ret
= (pulse
* 1000) / (nf
* nsf
);
1459 ret
= (DWORD
)((double)pulse
* ((double)lpMidiStrm
->dwTempo
/ 1000) /
1460 (double)lpMidiStrm
->dwTimeDiv
);
1466 /**************************************************************************
1467 * MMSYSTEM_MidiStream_MessageHandler [internal]
1469 static BOOL
MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream
* lpMidiStrm
, LPWINE_MIDI lpwm
, LPMSG msg
)
1471 LPMIDIHDR lpMidiHdr
;
1475 switch (msg
->message
) {
1477 SetEvent(lpMidiStrm
->hEvent
);
1481 /* this is not quite what MS doc says... */
1482 midiOutReset(lpMidiStrm
->hDevice
);
1483 /* empty list of already submitted buffers */
1484 for (lpMidiHdr
= lpMidiStrm
->lpMidiHdr
; lpMidiHdr
; lpMidiHdr
= (LPMIDIHDR
)lpMidiHdr
->lpNext
) {
1485 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
1486 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1488 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1489 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_DONE
,
1490 lpwm
->mod
.dwInstance
, (DWORD
)lpMidiHdr
, 0L);
1492 lpMidiStrm
->lpMidiHdr
= 0;
1493 SetEvent(lpMidiStrm
->hEvent
);
1495 case WINE_MSM_HEADER
:
1496 /* sets initial tick count for first MIDIHDR */
1497 if (!lpMidiStrm
->dwStartTicks
)
1498 lpMidiStrm
->dwStartTicks
= GetTickCount();
1500 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1501 * by native mcimidi, it doesn't look like a correct one".
1502 * this trick allows to throw it away... but I don't like it.
1503 * It looks like part of the file I'm trying to play and definitively looks
1504 * like raw midi content
1505 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1506 * synchronization issue where native mcimidi is still processing raw MIDI
1507 * content before generating MIDIEVENTs ?
1509 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1510 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1511 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1512 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1513 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1514 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1515 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1516 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1517 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1518 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1519 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1520 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1521 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1522 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1523 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1524 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1525 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1527 lpMidiHdr
= (LPMIDIHDR
)msg
->lParam
;
1528 lpData
= lpMidiHdr
->lpData
;
1529 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1530 (lpMidiHdr
->dwFlags
& MHDR_ISSTRM
) ? "stream" : "regular", lpMidiHdr
,
1531 (DWORD
)lpMidiHdr
, lpMidiHdr
->dwBufferLength
, lpMidiHdr
->dwBytesRecorded
,
1532 lpMidiHdr
->dwFlags
, msg
->wParam
);
1534 /* dumps content of lpMidiHdr->lpData
1535 * FIXME: there should be a debug routine somewhere that already does this
1536 * I hate spreading this type of shit all around the code
1538 for (dwToGo
= 0; dwToGo
< lpMidiHdr
->dwBufferLength
; dwToGo
+= 16) {
1542 for (i
= 0; i
< min(16, lpMidiHdr
->dwBufferLength
- dwToGo
); i
++)
1543 printf("%02x ", lpData
[dwToGo
+ i
]);
1546 for (i
= 0; i
< min(16, lpMidiHdr
->dwBufferLength
- dwToGo
); i
++) {
1547 ch
= lpData
[dwToGo
+ i
];
1548 printf("%c", (ch
>= 0x20 && ch
<= 0x7F) ? ch
: '.');
1553 if (((LPMIDIEVENT
)lpData
)->dwStreamID
!= 0 &&
1554 ((LPMIDIEVENT
)lpData
)->dwStreamID
!= 0xFFFFFFFF &&
1555 ((LPMIDIEVENT
)lpData
)->dwStreamID
!= (DWORD
)lpMidiStrm
) {
1556 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
1557 (lpMidiHdr
->dwFlags
& MHDR_ISSTRM
) ? "stream" : "regular",
1558 ((LPMIDIEVENT
)lpData
)->dwStreamID
);
1559 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
1560 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1562 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1563 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_DONE
,
1564 lpwm
->mod
.dwInstance
, (DWORD
)lpMidiHdr
, 0L);
1568 for (lpmh
= &lpMidiStrm
->lpMidiHdr
; *lpmh
; lpmh
= (LPMIDIHDR
*)&((*lpmh
)->lpNext
));
1570 lpMidiHdr
= (LPMIDIHDR
)msg
->lParam
;
1571 lpMidiHdr
->lpNext
= 0;
1572 lpMidiHdr
->dwFlags
|= MHDR_INQUEUE
;
1573 lpMidiHdr
->dwFlags
&= ~MHDR_DONE
;
1574 lpMidiHdr
->dwOffset
= 0;
1578 FIXME("Unknown message %d\n", msg
->message
);
1584 /**************************************************************************
1585 * MMSYSTEM_MidiStream_Player [internal]
1587 static DWORD CALLBACK
MMSYSTEM_MidiStream_Player(LPVOID pmt
)
1589 WINE_MIDIStream
* lpMidiStrm
= pmt
;
1594 LPMIDIHDR lpMidiHdr
;
1598 TRACE("(%p)!\n", lpMidiStrm
);
1601 (lpwm
= (LPWINE_MIDI
)MMDRV_Get(lpMidiStrm
->hDevice
, MMDRV_MIDIOUT
, FALSE
)) == NULL
)
1604 /* force thread's queue creation */
1605 /* Used to be InitThreadInput16(0, 5); */
1606 /* but following works also with hack in midiStreamOpen */
1607 PeekMessageA(&msg
, 0, 0, 0, 0);
1609 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
1610 SetEvent(lpMidiStrm
->hEvent
);
1611 TRACE("Ready to go 1\n");
1612 /* thread is started in paused mode */
1613 SuspendThread(lpMidiStrm
->hThread
);
1614 TRACE("Ready to go 2\n");
1616 lpMidiStrm
->dwStartTicks
= 0;
1617 lpMidiStrm
->dwPulses
= 0;
1619 lpMidiStrm
->lpMidiHdr
= 0;
1622 lpMidiHdr
= lpMidiStrm
->lpMidiHdr
;
1624 /* for first message, block until one arrives, then process all that are available */
1625 GetMessageA(&msg
, 0, 0, 0);
1627 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm
, lpwm
, &msg
))
1629 } while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
));
1635 lpData
= lpMidiHdr
->lpData
;
1637 me
= (LPMIDIEVENT
)(lpData
+ lpMidiHdr
->dwOffset
);
1639 /* do we have to wait ? */
1640 if (me
->dwDeltaTime
) {
1641 lpMidiStrm
->dwPositionMS
+= MMSYSTEM_MidiStream_Convert(lpMidiStrm
, me
->dwDeltaTime
);
1642 lpMidiStrm
->dwPulses
+= me
->dwDeltaTime
;
1644 dwToGo
= lpMidiStrm
->dwStartTicks
+ lpMidiStrm
->dwPositionMS
;
1646 TRACE("%ld/%ld/%ld\n", dwToGo
, GetTickCount(), me
->dwDeltaTime
);
1647 while ((dwCurrTC
= GetTickCount()) < dwToGo
) {
1648 if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, dwToGo
- dwCurrTC
, QS_ALLINPUT
) == WAIT_OBJECT_0
) {
1649 /* got a message, handle it */
1650 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) {
1651 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm
, lpwm
, &msg
))
1656 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
1661 switch (MEVT_EVENTTYPE(me
->dwEvent
& ~MEVT_F_CALLBACK
)) {
1663 FIXME("NIY: MEVT_COMMENT\n");
1664 /* do nothing, skip bytes */
1667 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
1672 midiOutShortMsg(lpMidiStrm
->hDevice
, MEVT_EVENTPARM(me
->dwEvent
));
1675 lpMidiStrm
->dwTempo
= MEVT_EVENTPARM(me
->dwEvent
);
1680 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me
->dwEvent
& ~MEVT_F_CALLBACK
));
1683 if (me
->dwEvent
& MEVT_F_CALLBACK
) {
1684 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1685 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_POSITIONCB
,
1686 lpwm
->mod
.dwInstance
, (LPARAM
)lpMidiHdr
, 0L);
1688 lpMidiHdr
->dwOffset
+= sizeof(MIDIEVENT
) - sizeof(me
->dwParms
);
1689 if (me
->dwEvent
& MEVT_F_LONG
)
1690 lpMidiHdr
->dwOffset
+= (MEVT_EVENTPARM(me
->dwEvent
) + 3) & ~3;
1691 if (lpMidiHdr
->dwOffset
>= lpMidiHdr
->dwBufferLength
) {
1692 /* done with this header */
1693 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
1694 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1696 lpMidiStrm
->lpMidiHdr
= (LPMIDIHDR
)lpMidiHdr
->lpNext
;
1697 DriverCallback(lpwm
->mod
.dwCallback
, lpMidiStrm
->wFlags
,
1698 (HDRVR
)lpMidiStrm
->hDevice
, MM_MOM_DONE
,
1699 lpwm
->mod
.dwInstance
, (DWORD
)lpMidiHdr
, 0L);
1704 TRACE("End of thread\n");
1706 return 0; /* for removing the warning, never executed */
1709 /**************************************************************************
1710 * MMSYSTEM_MidiStream_PostMessage [internal]
1712 static BOOL
MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream
* lpMidiStrm
, WORD msg
, DWORD pmt1
, DWORD pmt2
)
1714 if (PostThreadMessageA(lpMidiStrm
->dwThreadID
, msg
, pmt1
, pmt2
)) {
1717 if (pFnReleaseThunkLock
) pFnReleaseThunkLock(&count
);
1718 WaitForSingleObject(lpMidiStrm
->hEvent
, INFINITE
);
1719 if (pFnRestoreThunkLock
) pFnRestoreThunkLock(count
);
1721 WARN("bad PostThreadMessageA\n");
1727 /**************************************************************************
1728 * midiStreamClose [WINMM.@]
1730 MMRESULT WINAPI
midiStreamClose(HMIDISTRM hMidiStrm
)
1732 WINE_MIDIStream
* lpMidiStrm
;
1734 TRACE("(%p)!\n", hMidiStrm
);
1736 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
))
1737 return MMSYSERR_INVALHANDLE
;
1739 midiStreamStop(hMidiStrm
);
1740 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm
, WM_QUIT
, 0, 0);
1741 HeapFree(GetProcessHeap(), 0, lpMidiStrm
);
1742 CloseHandle(lpMidiStrm
->hEvent
);
1744 return midiOutClose((HMIDIOUT
)hMidiStrm
);
1747 /**************************************************************************
1748 * MMSYSTEM_MidiStream_Open [internal]
1750 MMRESULT
MIDI_StreamOpen(HMIDISTRM
* lphMidiStrm
, LPUINT lpuDeviceID
, DWORD cMidi
,
1751 DWORD_PTR dwCallback
, DWORD_PTR dwInstance
, DWORD fdwOpen
,
1754 WINE_MIDIStream
* lpMidiStrm
;
1756 MIDIOPENSTRMID mosm
;
1760 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
1761 lphMidiStrm
, lpuDeviceID
, cMidi
, dwCallback
, dwInstance
, fdwOpen
);
1763 if (cMidi
!= 1 || lphMidiStrm
== NULL
|| lpuDeviceID
== NULL
)
1764 return MMSYSERR_INVALPARAM
;
1766 lpMidiStrm
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream
));
1768 return MMSYSERR_NOMEM
;
1770 lpMidiStrm
->dwTempo
= 500000;
1771 lpMidiStrm
->dwTimeDiv
= 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
1772 lpMidiStrm
->dwPositionMS
= 0;
1774 mosm
.dwStreamID
= (DWORD
)lpMidiStrm
;
1775 /* FIXME: the correct value is not allocated yet for MAPPER */
1776 mosm
.wDeviceID
= *lpuDeviceID
;
1777 lpwm
= MIDI_OutAlloc(&hMidiOut
, &dwCallback
, &dwInstance
, &fdwOpen
, 1, &mosm
, bFrom32
);
1778 lpMidiStrm
->hDevice
= hMidiOut
;
1780 *lphMidiStrm
= (HMIDISTRM
)hMidiOut
;
1782 lpwm
->mld
.uDeviceID
= *lpuDeviceID
;
1784 ret
= MMDRV_Open(&lpwm
->mld
, MODM_OPEN
, (DWORD
)&lpwm
->mod
, fdwOpen
);
1785 lpMidiStrm
->hEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1786 lpMidiStrm
->wFlags
= HIWORD(fdwOpen
);
1788 lpMidiStrm
->hThread
= CreateThread(NULL
, 0, MMSYSTEM_MidiStream_Player
,
1789 lpMidiStrm
, 0, &(lpMidiStrm
->dwThreadID
));
1791 if (!lpMidiStrm
->hThread
) {
1792 midiStreamClose((HMIDISTRM
)hMidiOut
);
1793 return MMSYSERR_NOMEM
;
1795 SetThreadPriority(lpMidiStrm
->hThread
, THREAD_PRIORITY_TIME_CRITICAL
);
1797 /* wait for thread to have started, and for its queue to be created */
1801 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
1802 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
1803 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
1805 if (pFnReleaseThunkLock
) pFnReleaseThunkLock(&count
);
1806 WaitForSingleObject(lpMidiStrm
->hEvent
, INFINITE
);
1807 if (pFnRestoreThunkLock
) pFnRestoreThunkLock(count
);
1810 TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n",
1811 *lpuDeviceID
, lpwm
->mld
.uDeviceID
, *lphMidiStrm
, ret
, lpMidiStrm
);
1815 /**************************************************************************
1816 * midiStreamOpen [WINMM.@]
1818 MMRESULT WINAPI
midiStreamOpen(HMIDISTRM
* lphMidiStrm
, LPUINT lpuDeviceID
,
1819 DWORD cMidi
, DWORD_PTR dwCallback
,
1820 DWORD_PTR dwInstance
, DWORD fdwOpen
)
1822 return MIDI_StreamOpen(lphMidiStrm
, lpuDeviceID
, cMidi
, dwCallback
,
1823 dwInstance
, fdwOpen
, TRUE
);
1826 /**************************************************************************
1827 * midiStreamOut [WINMM.@]
1829 MMRESULT WINAPI
midiStreamOut(HMIDISTRM hMidiStrm
, LPMIDIHDR lpMidiHdr
,
1832 WINE_MIDIStream
* lpMidiStrm
;
1833 DWORD ret
= MMSYSERR_NOERROR
;
1835 TRACE("(%p, %p, %u)!\n", hMidiStrm
, lpMidiHdr
, cbMidiHdr
);
1837 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
1838 ret
= MMSYSERR_INVALHANDLE
;
1839 } else if (!lpMidiHdr
) {
1840 ret
= MMSYSERR_INVALPARAM
;
1842 if (!PostThreadMessageA(lpMidiStrm
->dwThreadID
,
1843 WINE_MSM_HEADER
, cbMidiHdr
,
1844 (DWORD
)lpMidiHdr
)) {
1845 WARN("bad PostThreadMessageA\n");
1846 ret
= MMSYSERR_ERROR
;
1852 /**************************************************************************
1853 * midiStreamPause [WINMM.@]
1855 MMRESULT WINAPI
midiStreamPause(HMIDISTRM hMidiStrm
)
1857 WINE_MIDIStream
* lpMidiStrm
;
1858 DWORD ret
= MMSYSERR_NOERROR
;
1860 TRACE("(%p)!\n", hMidiStrm
);
1862 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
1863 ret
= MMSYSERR_INVALHANDLE
;
1865 if (SuspendThread(lpMidiStrm
->hThread
) == 0xFFFFFFFF) {
1866 WARN("bad Suspend (%ld)\n", GetLastError());
1867 ret
= MMSYSERR_ERROR
;
1873 /**************************************************************************
1874 * midiStreamPosition [WINMM.@]
1876 MMRESULT WINAPI
midiStreamPosition(HMIDISTRM hMidiStrm
, LPMMTIME lpMMT
, UINT cbmmt
)
1878 WINE_MIDIStream
* lpMidiStrm
;
1879 DWORD ret
= MMSYSERR_NOERROR
;
1881 TRACE("(%p, %p, %u)!\n", hMidiStrm
, lpMMT
, cbmmt
);
1883 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
1884 ret
= MMSYSERR_INVALHANDLE
;
1885 } else if (lpMMT
== NULL
|| cbmmt
!= sizeof(MMTIME
)) {
1886 ret
= MMSYSERR_INVALPARAM
;
1888 switch (lpMMT
->wType
) {
1890 lpMMT
->u
.ms
= lpMidiStrm
->dwPositionMS
;
1891 TRACE("=> %ld ms\n", lpMMT
->u
.ms
);
1894 lpMMT
->u
.ticks
= lpMidiStrm
->dwPulses
;
1895 TRACE("=> %ld ticks\n", lpMMT
->u
.ticks
);
1898 WARN("Unsupported time type %d\n", lpMMT
->wType
);
1899 lpMMT
->wType
= TIME_MS
;
1900 ret
= MMSYSERR_INVALPARAM
;
1907 /**************************************************************************
1908 * midiStreamProperty [WINMM.@]
1910 MMRESULT WINAPI
midiStreamProperty(HMIDISTRM hMidiStrm
, LPBYTE lpPropData
, DWORD dwProperty
)
1912 WINE_MIDIStream
* lpMidiStrm
;
1913 MMRESULT ret
= MMSYSERR_NOERROR
;
1915 TRACE("(%p, %p, %lx)\n", hMidiStrm
, lpPropData
, dwProperty
);
1917 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
1918 ret
= MMSYSERR_INVALHANDLE
;
1919 } else if ((dwProperty
& (MIDIPROP_GET
|MIDIPROP_SET
)) == 0) {
1920 ret
= MMSYSERR_INVALPARAM
;
1921 } else if (dwProperty
& MIDIPROP_TEMPO
) {
1922 MIDIPROPTEMPO
* mpt
= (MIDIPROPTEMPO
*)lpPropData
;
1924 if (sizeof(MIDIPROPTEMPO
) != mpt
->cbStruct
) {
1925 ret
= MMSYSERR_INVALPARAM
;
1926 } else if (dwProperty
& MIDIPROP_SET
) {
1927 lpMidiStrm
->dwTempo
= mpt
->dwTempo
;
1928 TRACE("Setting tempo to %ld\n", mpt
->dwTempo
);
1929 } else if (dwProperty
& MIDIPROP_GET
) {
1930 mpt
->dwTempo
= lpMidiStrm
->dwTempo
;
1931 TRACE("Getting tempo <= %ld\n", mpt
->dwTempo
);
1933 } else if (dwProperty
& MIDIPROP_TIMEDIV
) {
1934 MIDIPROPTIMEDIV
* mptd
= (MIDIPROPTIMEDIV
*)lpPropData
;
1936 if (sizeof(MIDIPROPTIMEDIV
) != mptd
->cbStruct
) {
1937 ret
= MMSYSERR_INVALPARAM
;
1938 } else if (dwProperty
& MIDIPROP_SET
) {
1939 lpMidiStrm
->dwTimeDiv
= mptd
->dwTimeDiv
;
1940 TRACE("Setting time div to %ld\n", mptd
->dwTimeDiv
);
1941 } else if (dwProperty
& MIDIPROP_GET
) {
1942 mptd
->dwTimeDiv
= lpMidiStrm
->dwTimeDiv
;
1943 TRACE("Getting time div <= %ld\n", mptd
->dwTimeDiv
);
1946 ret
= MMSYSERR_INVALPARAM
;
1952 /**************************************************************************
1953 * midiStreamRestart [WINMM.@]
1955 MMRESULT WINAPI
midiStreamRestart(HMIDISTRM hMidiStrm
)
1957 WINE_MIDIStream
* lpMidiStrm
;
1958 MMRESULT ret
= MMSYSERR_NOERROR
;
1960 TRACE("(%p)!\n", hMidiStrm
);
1962 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
1963 ret
= MMSYSERR_INVALHANDLE
;
1967 /* since we increase the thread suspend count on each midiStreamPause
1968 * there may be a need for several midiStreamResume
1971 ret
= ResumeThread(lpMidiStrm
->hThread
);
1972 } while (ret
!= 0xFFFFFFFF && ret
!= 0);
1973 if (ret
== 0xFFFFFFFF) {
1974 WARN("bad Resume (%ld)\n", GetLastError());
1975 ret
= MMSYSERR_ERROR
;
1977 lpMidiStrm
->dwStartTicks
= GetTickCount() - lpMidiStrm
->dwPositionMS
;
1983 /**************************************************************************
1984 * midiStreamStop [WINMM.@]
1986 MMRESULT WINAPI
midiStreamStop(HMIDISTRM hMidiStrm
)
1988 WINE_MIDIStream
* lpMidiStrm
;
1989 MMRESULT ret
= MMSYSERR_NOERROR
;
1991 TRACE("(%p)!\n", hMidiStrm
);
1993 if (!MMSYSTEM_GetMidiStream(hMidiStrm
, &lpMidiStrm
, NULL
)) {
1994 ret
= MMSYSERR_INVALHANDLE
;
1996 /* in case stream has been paused... FIXME is the current state correct ? */
1997 midiStreamRestart(hMidiStrm
);
1998 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm
, WINE_MSM_STOP
, 0, 0);
2003 UINT
WAVE_Open(HANDLE
* lphndl
, UINT uDeviceID
, UINT uType
,
2004 LPCWAVEFORMATEX lpFormat
, DWORD_PTR dwCallback
,
2005 DWORD_PTR dwInstance
, DWORD dwFlags
, BOOL bFrom32
)
2009 DWORD dwRet
= MMSYSERR_NOERROR
;
2012 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2013 lphndl
, (int)uDeviceID
, (uType
==MMDRV_WAVEOUT
)?"Out":"In", lpFormat
, dwCallback
,
2014 dwInstance
, dwFlags
, bFrom32
?32:16);
2016 if (dwFlags
& WAVE_FORMAT_QUERY
)
2017 TRACE("WAVE_FORMAT_QUERY requested !\n");
2019 if (lpFormat
== NULL
) {
2020 WARN("bad format\n");
2021 return WAVERR_BADFORMAT
;
2024 if ((dwFlags
& WAVE_MAPPED
) && (uDeviceID
== (UINT
)-1)) {
2025 WARN("invalid parameter\n");
2026 return MMSYSERR_INVALPARAM
;
2029 /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */
2030 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u\n",
2031 lpFormat
->wFormatTag
, lpFormat
->nChannels
, lpFormat
->nSamplesPerSec
,
2032 lpFormat
->nAvgBytesPerSec
, lpFormat
->nBlockAlign
, lpFormat
->wBitsPerSample
);
2034 if ((wmld
= MMDRV_Alloc(sizeof(WINE_WAVE
), uType
, &handle
,
2035 &dwFlags
, &dwCallback
, &dwInstance
, bFrom32
)) == NULL
) {
2036 WARN("no memory\n");
2037 return MMSYSERR_NOMEM
;
2041 wod
.lpFormat
= (LPWAVEFORMATEX
)lpFormat
; /* should the struct be copied iso pointer? */
2042 wod
.dwCallback
= dwCallback
;
2043 wod
.dwInstance
= dwInstance
;
2046 TRACE("cb=%08lx\n", wod
.dwCallback
);
2049 if (dwFlags
& WAVE_MAPPED
) {
2050 wod
.uMappedDeviceID
= uDeviceID
;
2051 uDeviceID
= WAVE_MAPPER
;
2053 wod
.uMappedDeviceID
= -1;
2055 wmld
->uDeviceID
= uDeviceID
;
2057 dwRet
= MMDRV_Open(wmld
, (uType
== MMDRV_WAVEOUT
) ? WODM_OPEN
: WIDM_OPEN
,
2058 (DWORD
)&wod
, dwFlags
);
2060 TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet
));
2061 if (dwRet
!= WAVERR_BADFORMAT
||
2062 ((dwFlags
& (WAVE_MAPPED
|WAVE_FORMAT_DIRECT
)) != 0) || (uDeviceID
== WAVE_MAPPER
)) break;
2063 /* if we ask for a format which isn't supported by the physical driver,
2064 * let's try to map it through the wave mapper (except, if we already tried
2065 * or user didn't allow us to use acm codecs or the device is already the mapper)
2067 dwFlags
|= WAVE_MAPPED
;
2068 /* we shall loop only one */
2071 if ((dwFlags
& WAVE_FORMAT_QUERY
) || dwRet
!= MMSYSERR_NOERROR
) {
2072 MMDRV_Free(handle
, wmld
);
2076 if (lphndl
!= NULL
) *lphndl
= handle
;
2077 TRACE("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet
), handle
);
2082 /**************************************************************************
2083 * waveOutGetNumDevs [WINMM.@]
2085 UINT WINAPI
waveOutGetNumDevs(void)
2087 return MMDRV_GetNum(MMDRV_WAVEOUT
);
2090 /**************************************************************************
2091 * waveOutGetDevCapsA [WINMM.@]
2093 UINT WINAPI
waveOutGetDevCapsA(UINT_PTR uDeviceID
, LPWAVEOUTCAPSA lpCaps
,
2099 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
2101 ret
= waveOutGetDevCapsW(uDeviceID
, &wocW
, sizeof(wocW
));
2103 if (ret
== MMSYSERR_NOERROR
) {
2105 wocA
.wMid
= wocW
.wMid
;
2106 wocA
.wPid
= wocW
.wPid
;
2107 wocA
.vDriverVersion
= wocW
.vDriverVersion
;
2108 WideCharToMultiByte( CP_ACP
, 0, wocW
.szPname
, -1, wocA
.szPname
,
2109 sizeof(wocA
.szPname
), NULL
, NULL
);
2110 wocA
.dwFormats
= wocW
.dwFormats
;
2111 wocA
.wChannels
= wocW
.wChannels
;
2112 wocA
.dwSupport
= wocW
.dwSupport
;
2113 memcpy(lpCaps
, &wocA
, min(uSize
, sizeof(wocA
)));
2118 /**************************************************************************
2119 * waveOutGetDevCapsW [WINMM.@]
2121 UINT WINAPI
waveOutGetDevCapsW(UINT_PTR uDeviceID
, LPWAVEOUTCAPSW lpCaps
,
2126 TRACE("(%u %p %u)!\n", uDeviceID
, lpCaps
, uSize
);
2128 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
2130 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_WAVEOUT
, TRUE
)) == NULL
)
2131 return MMSYSERR_BADDEVICEID
;
2133 return MMDRV_Message(wmld
, WODM_GETDEVCAPS
, (DWORD_PTR
)lpCaps
, uSize
, TRUE
);
2137 /**************************************************************************
2138 * waveOutGetErrorTextA [WINMM.@]
2139 * waveInGetErrorTextA [WINMM.@]
2141 UINT WINAPI
waveOutGetErrorTextA(UINT uError
, LPSTR lpText
, UINT uSize
)
2145 if (lpText
== NULL
) ret
= MMSYSERR_INVALPARAM
;
2146 else if (uSize
== 0) ret
= MMSYSERR_NOERROR
;
2149 LPWSTR xstr
= HeapAlloc(GetProcessHeap(), 0, uSize
* sizeof(WCHAR
));
2150 if (!xstr
) ret
= MMSYSERR_NOMEM
;
2153 ret
= waveOutGetErrorTextW(uError
, xstr
, uSize
);
2154 if (ret
== MMSYSERR_NOERROR
)
2155 WideCharToMultiByte(CP_ACP
, 0, xstr
, -1, lpText
, uSize
, NULL
, NULL
);
2156 HeapFree(GetProcessHeap(), 0, xstr
);
2162 /**************************************************************************
2163 * waveOutGetErrorTextW [WINMM.@]
2164 * waveInGetErrorTextW [WINMM.@]
2166 UINT WINAPI
waveOutGetErrorTextW(UINT uError
, LPWSTR lpText
, UINT uSize
)
2168 UINT ret
= MMSYSERR_BADERRNUM
;
2170 if (lpText
== NULL
) ret
= MMSYSERR_INVALPARAM
;
2171 else if (uSize
== 0) ret
= MMSYSERR_NOERROR
;
2173 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2174 * a warning for the test was always true */
2175 (/*uError >= MMSYSERR_BASE && */ uError
<= MMSYSERR_LASTERROR
) ||
2176 (uError
>= WAVERR_BASE
&& uError
<= WAVERR_LASTERROR
)) {
2177 if (LoadStringW(WINMM_IData
.hWinMM32Instance
,
2178 uError
, lpText
, uSize
) > 0) {
2179 ret
= MMSYSERR_NOERROR
;
2185 /**************************************************************************
2186 * waveOutOpen [WINMM.@]
2187 * All the args/structs have the same layout as the win16 equivalents
2189 MMRESULT WINAPI
waveOutOpen(LPHWAVEOUT lphWaveOut
, UINT uDeviceID
,
2190 LPCWAVEFORMATEX lpFormat
, DWORD_PTR dwCallback
,
2191 DWORD_PTR dwInstance
, DWORD dwFlags
)
2193 return WAVE_Open((HANDLE
*)lphWaveOut
, uDeviceID
, MMDRV_WAVEOUT
, lpFormat
,
2194 dwCallback
, dwInstance
, dwFlags
, TRUE
);
2197 /**************************************************************************
2198 * waveOutClose [WINMM.@]
2200 UINT WINAPI
waveOutClose(HWAVEOUT hWaveOut
)
2205 TRACE("(%p)\n", hWaveOut
);
2207 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2208 return MMSYSERR_INVALHANDLE
;
2210 dwRet
= MMDRV_Close(wmld
, WODM_CLOSE
);
2211 if (dwRet
!= WAVERR_STILLPLAYING
)
2212 MMDRV_Free(hWaveOut
, wmld
);
2217 /**************************************************************************
2218 * waveOutPrepareHeader [WINMM.@]
2220 UINT WINAPI
waveOutPrepareHeader(HWAVEOUT hWaveOut
,
2221 WAVEHDR
* lpWaveOutHdr
, UINT uSize
)
2226 TRACE("(%p, %p, %u);\n", hWaveOut
, lpWaveOutHdr
, uSize
);
2228 if (lpWaveOutHdr
== NULL
|| uSize
< sizeof (WAVEHDR
))
2229 return MMSYSERR_INVALPARAM
;
2231 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2232 return MMSYSERR_INVALHANDLE
;
2234 if ((result
= MMDRV_Message(wmld
, WODM_PREPARE
, (DWORD_PTR
)lpWaveOutHdr
,
2235 uSize
, TRUE
)) != MMSYSERR_NOTSUPPORTED
)
2238 if (lpWaveOutHdr
->dwFlags
& WHDR_INQUEUE
)
2239 return WAVERR_STILLPLAYING
;
2241 lpWaveOutHdr
->dwFlags
|= WHDR_PREPARED
;
2242 lpWaveOutHdr
->dwFlags
&= ~WHDR_DONE
;
2244 return MMSYSERR_NOERROR
;
2247 /**************************************************************************
2248 * waveOutUnprepareHeader [WINMM.@]
2250 UINT WINAPI
waveOutUnprepareHeader(HWAVEOUT hWaveOut
,
2251 LPWAVEHDR lpWaveOutHdr
, UINT uSize
)
2256 TRACE("(%p, %p, %u);\n", hWaveOut
, lpWaveOutHdr
, uSize
);
2258 if (lpWaveOutHdr
== NULL
|| uSize
< sizeof (WAVEHDR
))
2259 return MMSYSERR_INVALPARAM
;
2261 if (!(lpWaveOutHdr
->dwFlags
& WHDR_PREPARED
)) {
2262 return MMSYSERR_NOERROR
;
2265 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2266 return MMSYSERR_INVALHANDLE
;
2268 if ((result
= MMDRV_Message(wmld
, WODM_UNPREPARE
, (DWORD_PTR
)lpWaveOutHdr
,
2269 uSize
, TRUE
)) != MMSYSERR_NOTSUPPORTED
)
2272 if (lpWaveOutHdr
->dwFlags
& WHDR_INQUEUE
)
2273 return WAVERR_STILLPLAYING
;
2275 lpWaveOutHdr
->dwFlags
&= ~WHDR_PREPARED
;
2276 lpWaveOutHdr
->dwFlags
|= WHDR_DONE
;
2278 return MMSYSERR_NOERROR
;
2281 /**************************************************************************
2282 * waveOutWrite [WINMM.@]
2284 UINT WINAPI
waveOutWrite(HWAVEOUT hWaveOut
, LPWAVEHDR lpWaveOutHdr
,
2289 TRACE("(%p, %p, %u);\n", hWaveOut
, lpWaveOutHdr
, uSize
);
2291 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2292 return MMSYSERR_INVALHANDLE
;
2294 return MMDRV_Message(wmld
, WODM_WRITE
, (DWORD_PTR
)lpWaveOutHdr
, uSize
, TRUE
);
2297 /**************************************************************************
2298 * waveOutBreakLoop [WINMM.@]
2300 UINT WINAPI
waveOutBreakLoop(HWAVEOUT hWaveOut
)
2304 TRACE("(%p);\n", hWaveOut
);
2306 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2307 return MMSYSERR_INVALHANDLE
;
2308 return MMDRV_Message(wmld
, WODM_BREAKLOOP
, 0L, 0L, TRUE
);
2311 /**************************************************************************
2312 * waveOutPause [WINMM.@]
2314 UINT WINAPI
waveOutPause(HWAVEOUT hWaveOut
)
2318 TRACE("(%p);\n", hWaveOut
);
2320 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2321 return MMSYSERR_INVALHANDLE
;
2322 return MMDRV_Message(wmld
, WODM_PAUSE
, 0L, 0L, TRUE
);
2325 /**************************************************************************
2326 * waveOutReset [WINMM.@]
2328 UINT WINAPI
waveOutReset(HWAVEOUT hWaveOut
)
2332 TRACE("(%p);\n", hWaveOut
);
2334 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2335 return MMSYSERR_INVALHANDLE
;
2336 return MMDRV_Message(wmld
, WODM_RESET
, 0L, 0L, TRUE
);
2339 /**************************************************************************
2340 * waveOutRestart [WINMM.@]
2342 UINT WINAPI
waveOutRestart(HWAVEOUT hWaveOut
)
2346 TRACE("(%p);\n", hWaveOut
);
2348 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2349 return MMSYSERR_INVALHANDLE
;
2350 return MMDRV_Message(wmld
, WODM_RESTART
, 0L, 0L, TRUE
);
2353 /**************************************************************************
2354 * waveOutGetPosition [WINMM.@]
2356 UINT WINAPI
waveOutGetPosition(HWAVEOUT hWaveOut
, LPMMTIME lpTime
,
2361 TRACE("(%p, %p, %u);\n", hWaveOut
, lpTime
, uSize
);
2363 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2364 return MMSYSERR_INVALHANDLE
;
2366 return MMDRV_Message(wmld
, WODM_GETPOS
, (DWORD_PTR
)lpTime
, uSize
, TRUE
);
2369 /**************************************************************************
2370 * waveOutGetPitch [WINMM.@]
2372 UINT WINAPI
waveOutGetPitch(HWAVEOUT hWaveOut
, LPDWORD lpdw
)
2376 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)lpdw
);
2378 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2379 return MMSYSERR_INVALHANDLE
;
2380 return MMDRV_Message(wmld
, WODM_GETPITCH
, (DWORD_PTR
)lpdw
, 0L, TRUE
);
2383 /**************************************************************************
2384 * waveOutSetPitch [WINMM.@]
2386 UINT WINAPI
waveOutSetPitch(HWAVEOUT hWaveOut
, DWORD dw
)
2390 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)dw
);
2392 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2393 return MMSYSERR_INVALHANDLE
;
2394 return MMDRV_Message(wmld
, WODM_SETPITCH
, dw
, 0L, TRUE
);
2397 /**************************************************************************
2398 * waveOutGetPlaybackRate [WINMM.@]
2400 UINT WINAPI
waveOutGetPlaybackRate(HWAVEOUT hWaveOut
, LPDWORD lpdw
)
2404 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)lpdw
);
2406 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2407 return MMSYSERR_INVALHANDLE
;
2408 return MMDRV_Message(wmld
, WODM_GETPLAYBACKRATE
, (DWORD_PTR
)lpdw
, 0L, TRUE
);
2411 /**************************************************************************
2412 * waveOutSetPlaybackRate [WINMM.@]
2414 UINT WINAPI
waveOutSetPlaybackRate(HWAVEOUT hWaveOut
, DWORD dw
)
2418 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)dw
);
2420 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2421 return MMSYSERR_INVALHANDLE
;
2422 return MMDRV_Message(wmld
, WODM_SETPLAYBACKRATE
, dw
, 0L, TRUE
);
2425 /**************************************************************************
2426 * waveOutGetVolume [WINMM.@]
2428 UINT WINAPI
waveOutGetVolume(HWAVEOUT hWaveOut
, LPDWORD lpdw
)
2432 TRACE("(%p, %08lx);\n", hWaveOut
, (DWORD
)lpdw
);
2434 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, TRUE
)) == NULL
)
2435 return MMSYSERR_INVALHANDLE
;
2437 return MMDRV_Message(wmld
, WODM_GETVOLUME
, (DWORD_PTR
)lpdw
, 0L, TRUE
);
2440 /**************************************************************************
2441 * waveOutSetVolume [WINMM.@]
2443 UINT WINAPI
waveOutSetVolume(HWAVEOUT hWaveOut
, DWORD dw
)
2447 TRACE("(%p, %08lx);\n", hWaveOut
, dw
);
2449 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, TRUE
)) == NULL
)
2450 return MMSYSERR_INVALHANDLE
;
2452 return MMDRV_Message(wmld
, WODM_SETVOLUME
, dw
, 0L, TRUE
);
2455 /**************************************************************************
2456 * waveOutGetID [WINMM.@]
2458 UINT WINAPI
waveOutGetID(HWAVEOUT hWaveOut
, UINT
* lpuDeviceID
)
2462 TRACE("(%p, %p);\n", hWaveOut
, lpuDeviceID
);
2464 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALHANDLE
;
2466 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
)
2467 return MMSYSERR_INVALHANDLE
;
2469 *lpuDeviceID
= wmld
->uDeviceID
;
2473 /**************************************************************************
2474 * waveOutMessage [WINMM.@]
2476 UINT WINAPI
waveOutMessage(HWAVEOUT hWaveOut
, UINT uMessage
,
2477 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
2481 TRACE("(%p, %u, %ld, %ld)\n", hWaveOut
, uMessage
, dwParam1
, dwParam2
);
2483 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, FALSE
)) == NULL
) {
2484 if ((wmld
= MMDRV_Get(hWaveOut
, MMDRV_WAVEOUT
, TRUE
)) != NULL
) {
2485 return MMDRV_PhysicalFeatures(wmld
, uMessage
, dwParam1
, dwParam2
);
2487 WARN("invalid handle\n");
2488 return MMSYSERR_INVALHANDLE
;
2492 if (uMessage
< DRVM_IOCTL
|| (uMessage
>= DRVM_IOCTL_LAST
&& uMessage
< DRVM_MAPPER
)) {
2493 WARN("invalid parameter\n");
2494 return MMSYSERR_INVALPARAM
;
2497 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
2500 /**************************************************************************
2501 * waveInGetNumDevs [WINMM.@]
2503 UINT WINAPI
waveInGetNumDevs(void)
2505 return MMDRV_GetNum(MMDRV_WAVEIN
);
2508 /**************************************************************************
2509 * waveInGetDevCapsW [WINMM.@]
2511 UINT WINAPI
waveInGetDevCapsW(UINT_PTR uDeviceID
, LPWAVEINCAPSW lpCaps
, UINT uSize
)
2515 TRACE("(%u %p %u)!\n", uDeviceID
, lpCaps
, uSize
);
2517 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
2519 if ((wmld
= MMDRV_Get((HANDLE
)uDeviceID
, MMDRV_WAVEIN
, TRUE
)) == NULL
)
2520 return MMSYSERR_BADDEVICEID
;
2522 return MMDRV_Message(wmld
, WIDM_GETDEVCAPS
, (DWORD_PTR
)lpCaps
, uSize
, TRUE
);
2525 /**************************************************************************
2526 * waveInGetDevCapsA [WINMM.@]
2528 UINT WINAPI
waveInGetDevCapsA(UINT_PTR uDeviceID
, LPWAVEINCAPSA lpCaps
, UINT uSize
)
2533 if (lpCaps
== NULL
) return MMSYSERR_INVALPARAM
;
2535 ret
= waveInGetDevCapsW(uDeviceID
, &wicW
, sizeof(wicW
));
2537 if (ret
== MMSYSERR_NOERROR
) {
2539 wicA
.wMid
= wicW
.wMid
;
2540 wicA
.wPid
= wicW
.wPid
;
2541 wicA
.vDriverVersion
= wicW
.vDriverVersion
;
2542 WideCharToMultiByte( CP_ACP
, 0, wicW
.szPname
, -1, wicA
.szPname
,
2543 sizeof(wicA
.szPname
), NULL
, NULL
);
2544 wicA
.dwFormats
= wicW
.dwFormats
;
2545 wicA
.wChannels
= wicW
.wChannels
;
2546 memcpy(lpCaps
, &wicA
, min(uSize
, sizeof(wicA
)));
2551 /**************************************************************************
2552 * waveInOpen [WINMM.@]
2554 MMRESULT WINAPI
waveInOpen(HWAVEIN
* lphWaveIn
, UINT uDeviceID
,
2555 LPCWAVEFORMATEX lpFormat
, DWORD_PTR dwCallback
,
2556 DWORD_PTR dwInstance
, DWORD dwFlags
)
2558 return WAVE_Open((HANDLE
*)lphWaveIn
, uDeviceID
, MMDRV_WAVEIN
, lpFormat
,
2559 dwCallback
, dwInstance
, dwFlags
, TRUE
);
2562 /**************************************************************************
2563 * waveInClose [WINMM.@]
2565 UINT WINAPI
waveInClose(HWAVEIN hWaveIn
)
2570 TRACE("(%p)\n", hWaveIn
);
2572 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2573 return MMSYSERR_INVALHANDLE
;
2575 dwRet
= MMDRV_Message(wmld
, WIDM_CLOSE
, 0L, 0L, TRUE
);
2576 if (dwRet
!= WAVERR_STILLPLAYING
)
2577 MMDRV_Free(hWaveIn
, wmld
);
2581 /**************************************************************************
2582 * waveInPrepareHeader [WINMM.@]
2584 UINT WINAPI
waveInPrepareHeader(HWAVEIN hWaveIn
, WAVEHDR
* lpWaveInHdr
,
2590 TRACE("(%p, %p, %u);\n", hWaveIn
, lpWaveInHdr
, uSize
);
2592 if (lpWaveInHdr
== NULL
|| uSize
< sizeof (WAVEHDR
))
2593 return MMSYSERR_INVALPARAM
;
2595 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2596 return MMSYSERR_INVALHANDLE
;
2598 if ((result
= MMDRV_Message(wmld
, WIDM_PREPARE
, (DWORD_PTR
)lpWaveInHdr
,
2599 uSize
, TRUE
)) != MMSYSERR_NOTSUPPORTED
)
2602 if (lpWaveInHdr
->dwFlags
& WHDR_INQUEUE
)
2603 return WAVERR_STILLPLAYING
;
2605 lpWaveInHdr
->dwFlags
|= WHDR_PREPARED
;
2606 lpWaveInHdr
->dwFlags
&= ~WHDR_DONE
;
2607 lpWaveInHdr
->dwBytesRecorded
= 0;
2609 return MMSYSERR_NOERROR
;
2612 /**************************************************************************
2613 * waveInUnprepareHeader [WINMM.@]
2615 UINT WINAPI
waveInUnprepareHeader(HWAVEIN hWaveIn
, WAVEHDR
* lpWaveInHdr
,
2621 TRACE("(%p, %p, %u);\n", hWaveIn
, lpWaveInHdr
, uSize
);
2623 if (lpWaveInHdr
== NULL
|| uSize
< sizeof (WAVEHDR
))
2624 return MMSYSERR_INVALPARAM
;
2626 if (!(lpWaveInHdr
->dwFlags
& WHDR_PREPARED
))
2627 return MMSYSERR_NOERROR
;
2629 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2630 return MMSYSERR_INVALHANDLE
;
2632 if ((result
= MMDRV_Message(wmld
, WIDM_UNPREPARE
, (DWORD_PTR
)lpWaveInHdr
,
2633 uSize
, TRUE
)) != MMSYSERR_NOTSUPPORTED
)
2636 if (lpWaveInHdr
->dwFlags
& WHDR_INQUEUE
)
2637 return WAVERR_STILLPLAYING
;
2639 lpWaveInHdr
->dwFlags
&= ~WHDR_PREPARED
;
2640 lpWaveInHdr
->dwFlags
|= WHDR_DONE
;
2642 return MMSYSERR_NOERROR
;
2645 /**************************************************************************
2646 * waveInAddBuffer [WINMM.@]
2648 UINT WINAPI
waveInAddBuffer(HWAVEIN hWaveIn
,
2649 WAVEHDR
* lpWaveInHdr
, UINT uSize
)
2653 TRACE("(%p, %p, %u);\n", hWaveIn
, lpWaveInHdr
, uSize
);
2655 if (lpWaveInHdr
== NULL
) return MMSYSERR_INVALPARAM
;
2656 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2657 return MMSYSERR_INVALHANDLE
;
2659 return MMDRV_Message(wmld
, WIDM_ADDBUFFER
, (DWORD_PTR
)lpWaveInHdr
, uSize
, TRUE
);
2662 /**************************************************************************
2663 * waveInReset [WINMM.@]
2665 UINT WINAPI
waveInReset(HWAVEIN hWaveIn
)
2669 TRACE("(%p);\n", hWaveIn
);
2671 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2672 return MMSYSERR_INVALHANDLE
;
2674 return MMDRV_Message(wmld
, WIDM_RESET
, 0L, 0L, TRUE
);
2677 /**************************************************************************
2678 * waveInStart [WINMM.@]
2680 UINT WINAPI
waveInStart(HWAVEIN hWaveIn
)
2684 TRACE("(%p);\n", hWaveIn
);
2686 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2687 return MMSYSERR_INVALHANDLE
;
2689 return MMDRV_Message(wmld
, WIDM_START
, 0L, 0L, TRUE
);
2692 /**************************************************************************
2693 * waveInStop [WINMM.@]
2695 UINT WINAPI
waveInStop(HWAVEIN hWaveIn
)
2699 TRACE("(%p);\n", hWaveIn
);
2701 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2702 return MMSYSERR_INVALHANDLE
;
2704 return MMDRV_Message(wmld
,WIDM_STOP
, 0L, 0L, TRUE
);
2707 /**************************************************************************
2708 * waveInGetPosition [WINMM.@]
2710 UINT WINAPI
waveInGetPosition(HWAVEIN hWaveIn
, LPMMTIME lpTime
,
2715 TRACE("(%p, %p, %u);\n", hWaveIn
, lpTime
, uSize
);
2717 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2718 return MMSYSERR_INVALHANDLE
;
2720 return MMDRV_Message(wmld
, WIDM_GETPOS
, (DWORD_PTR
)lpTime
, uSize
, TRUE
);
2723 /**************************************************************************
2724 * waveInGetID [WINMM.@]
2726 UINT WINAPI
waveInGetID(HWAVEIN hWaveIn
, UINT
* lpuDeviceID
)
2730 TRACE("(%p, %p);\n", hWaveIn
, lpuDeviceID
);
2732 if (lpuDeviceID
== NULL
) return MMSYSERR_INVALHANDLE
;
2734 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
)
2735 return MMSYSERR_INVALHANDLE
;
2737 *lpuDeviceID
= wmld
->uDeviceID
;
2738 return MMSYSERR_NOERROR
;
2741 /**************************************************************************
2742 * waveInMessage [WINMM.@]
2744 UINT WINAPI
waveInMessage(HWAVEIN hWaveIn
, UINT uMessage
,
2745 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
2749 TRACE("(%p, %u, %ld, %ld)\n", hWaveIn
, uMessage
, dwParam1
, dwParam2
);
2751 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, FALSE
)) == NULL
) {
2752 if ((wmld
= MMDRV_Get(hWaveIn
, MMDRV_WAVEIN
, TRUE
)) != NULL
) {
2753 return MMDRV_PhysicalFeatures(wmld
, uMessage
, dwParam1
, dwParam2
);
2755 return MMSYSERR_INVALHANDLE
;
2759 if (uMessage
< DRVM_IOCTL
|| (uMessage
>= DRVM_IOCTL_LAST
&& uMessage
< DRVM_MAPPER
))
2760 return MMSYSERR_INVALPARAM
;
2763 return MMDRV_Message(wmld
, uMessage
, dwParam1
, dwParam2
, TRUE
);
2773 static DWORD WINAPI
mmTaskRun(void* pmt
)
2775 struct mm_starter mms
;
2777 memcpy(&mms
, pmt
, sizeof(struct mm_starter
));
2778 HeapFree(GetProcessHeap(), 0, pmt
);
2780 if (mms
.event
) SetEvent(mms
.event
);
2784 /******************************************************************
2785 * mmTaskCreate (WINMM.@)
2787 MMRESULT WINAPI
mmTaskCreate(LPTASKCALLBACK cb
, HANDLE
* ph
, DWORD client
)
2791 struct mm_starter
*mms
;
2793 mms
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct mm_starter
));
2794 if (mms
== NULL
) return TASKERR_OUTOFMEMORY
;
2797 mms
->client
= client
;
2798 if (ph
) hEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2799 mms
->event
= hEvent
;
2801 hThread
= CreateThread(0, 0, mmTaskRun
, mms
, 0, NULL
);
2803 HeapFree(GetProcessHeap(), 0, mms
);
2804 if (hEvent
) CloseHandle(hEvent
);
2805 return TASKERR_OUTOFMEMORY
;
2807 SetThreadPriority(hThread
, THREAD_PRIORITY_TIME_CRITICAL
);
2808 if (ph
) *ph
= hEvent
;
2809 CloseHandle(hThread
);
2813 /******************************************************************
2814 * mmTaskBlock (WINMM.@)
2816 void WINAPI
mmTaskBlock(HANDLE tid
)
2822 GetMessageA(&msg
, 0, 0, 0);
2823 if (msg
.hwnd
) DispatchMessageA(&msg
);
2824 } while (msg
.message
!= WM_USER
);
2827 /******************************************************************
2828 * mmTaskSignal (WINMM.@)
2830 BOOL WINAPI
mmTaskSignal(HANDLE tid
)
2832 return PostThreadMessageW((DWORD
)tid
, WM_USER
, 0, 0);
2835 /******************************************************************
2836 * mmTaskYield (WINMM.@)
2838 void WINAPI
mmTaskYield(void) {}
2840 /******************************************************************
2841 * mmGetCurrentTask (WINMM.@)
2843 HANDLE WINAPI
mmGetCurrentTask(void)
2845 return (HANDLE
)GetCurrentThreadId();