All MCI functions are now cleanly separated.
[wine/hacks.git] / dlls / winmm / winmm.c
blobdbae8b2ca2bee8aef0bd8db85ac96038a0faed93
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MMSYTEM functions
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
25 * Eric POUECH :
26 * 98/9 added Win32 MCI support
27 * 99/4 added midiStream support
28 * 99/9 added support for loadable low level drivers
31 #include <string.h>
33 #include "mmsystem.h"
34 #include "winbase.h"
35 #include "wingdi.h"
37 #include "winuser.h"
38 #include "wine/winuser16.h" /* FIXME: should be removed */
39 #include "heap.h"
40 #include "winternl.h"
41 #include "winemm.h"
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));
84 if (!WINMM_IData)
85 return FALSE;
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);
92 return TRUE;
95 /**************************************************************************
96 * WINMM_DeleteIData [internal]
98 static void WINMM_DeleteIData(void)
100 if (WINMM_IData) {
101 TIME_MMTimeStop();
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);
109 WINMM_IData = NULL;
113 /******************************************************************
114 * WINMM_LoadMMSystem
117 BOOL WINMM_CheckForMMSystem(void)
119 /* 0 is not checked yet, -1 is not present, 1 is present */
120 static int loaded /* = 0 */;
122 if (loaded == 0)
124 HANDLE h = GetModuleHandleA("kernel32");
125 loaded = -1;
126 if (h)
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")))
131 loaded = 1;
134 return loaded > 0;
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);
147 switch (fdwReason) {
148 case DLL_PROCESS_ATTACH:
149 if (!WINMM_CreateIData(hInstDLL))
150 return FALSE;
151 if (!MCI_Init() || !MMDRV_Init()) {
152 WINMM_DeleteIData();
153 return FALSE;
155 break;
156 case DLL_PROCESS_DETACH:
157 WINMM_DeleteIData();
158 break;
159 case DLL_THREAD_ATTACH:
160 case DLL_THREAD_DETACH:
161 break;
163 return TRUE;
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);
180 break;
181 case MIXER_OBJECTF_HMIXER:
182 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
183 break;
184 case MIXER_OBJECTF_WAVEOUT:
185 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
186 break;
187 case MIXER_OBJECTF_HWAVEOUT:
188 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
189 break;
190 case MIXER_OBJECTF_WAVEIN:
191 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
192 break;
193 case MIXER_OBJECTF_HWAVEIN:
194 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
195 break;
196 case MIXER_OBJECTF_MIDIOUT:
197 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
198 break;
199 case MIXER_OBJECTF_HMIDIOUT:
200 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
201 break;
202 case MIXER_OBJECTF_MIDIIN:
203 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
204 break;
205 case MIXER_OBJECTF_HMIDIIN:
206 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
207 break;
208 case MIXER_OBJECTF_AUX:
209 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
210 break;
211 default:
212 FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
213 break;
215 return lpwm;
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)
231 LPWINE_MLD wmld;
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)
244 MIXERCAPSA micA;
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;
256 return ret;
259 UINT MMSYSTEM_mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
260 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
262 HMIXER hMix;
263 LPWINE_MLD wmld;
264 DWORD dwRet = 0;
265 MIXEROPENDESC mod;
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);
282 hMix = 0;
284 if (lphMix) *lphMix = hMix;
285 TRACE("=> %ld hMixer=%04x\n", dwRet, hMix);
287 return dwRet;
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)
305 LPWINE_MLD wmld;
306 DWORD dwRet;
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);
315 return dwRet;
318 /**************************************************************************
319 * mixerGetID [WINMM.@]
321 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
323 LPWINE_MIXER lpwm;
325 TRACE("(%04x %p %08lx)\n", hmix, lpid, fdwID);
327 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
328 return MMSYSERR_INVALHANDLE;
331 if (lpid)
332 *lpid = lpwm->mld.uDeviceID;
334 return MMSYSERR_NOERROR;
337 /**************************************************************************
338 * mixerGetControlDetailsA [WINMM.@]
340 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
341 DWORD fdwDetails)
343 LPWINE_MIXER lpwm;
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,
354 fdwDetails, TRUE);
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);
373 break;
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);
379 int i;
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,
395 pDetailsW->szName,
396 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
397 pDetailsA++;
398 pDetailsW++;
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);
407 break;
408 default:
409 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
412 return ret;
415 /**************************************************************************
416 * mixerGetLineControlsA [WINMM.@]
418 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
419 DWORD fdwControls)
421 LPWINE_MIXER lpwm;
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,
432 fdwControls, TRUE);
435 /**************************************************************************
436 * mixerGetLineControlsW [WINMM.@]
438 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
439 DWORD fdwControls)
441 MIXERLINECONTROLSA mlcA;
442 DWORD ret;
443 int i;
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);
493 return ret;
496 /**************************************************************************
497 * mixerGetLineInfoA [WINMM.@]
499 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
501 LPWINE_MIXER lpwm;
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,
509 fdwInfo, TRUE);
512 /**************************************************************************
513 * mixerGetLineInfoW [WINMM.@]
515 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
516 DWORD fdwInfo)
518 MIXERLINEA mliA;
519 UINT ret;
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;
530 break;
531 case MIXER_GETLINEINFOF_DESTINATION:
532 mliA.dwDestination = lpmliW->dwDestination;
533 break;
534 case MIXER_GETLINEINFOF_LINEID:
535 mliA.dwLineID = lpmliW->dwLineID;
536 break;
537 case MIXER_GETLINEINFOF_SOURCE:
538 mliA.dwDestination = lpmliW->dwDestination;
539 mliA.dwSource = lpmliW->dwSource;
540 break;
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);
547 break;
548 default:
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) );
575 return ret;
578 /**************************************************************************
579 * mixerSetControlDetails [WINMM.@]
581 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
582 DWORD fdwDetails)
584 LPWINE_MIXER lpwm;
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,
592 fdwDetails, TRUE);
595 /**************************************************************************
596 * mixerMessage [WINMM.@]
598 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
600 LPWINE_MLD wmld;
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)
624 AUXCAPSA acA;
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;
634 return ret;
637 /**************************************************************************
638 * auxGetDevCapsA [WINMM.@]
640 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
642 LPWINE_MLD wmld;
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)
656 LPWINE_MLD wmld;
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)
670 LPWINE_MLD wmld;
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)
684 LPWINE_MLD wmld;
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);
702 return ret;
705 /**************************************************************************
706 * mciGetErrorStringA [WINMM.@]
708 BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength)
710 BOOL16 ret = FALSE;
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) {
717 ret = TRUE;
720 return ret;
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);
745 if (!wmd) {
746 WARN("Bad uDeviceID\n");
747 return 0L;
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);
764 if (!wmd) {
765 WARN("Bad uDeviceID\n");
766 return FALSE;
769 wmd->dwPrivate = data;
770 return TRUE;
773 /**************************************************************************
774 * mciSendCommandA [WINMM.@]
776 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
778 DWORD dwRet;
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);
786 return 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)
812 LPSTR lpstrName;
813 UINT ret;
815 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
816 ret = MCI_GetDriverFromString(lpstrName);
817 HeapFree(GetProcessHeap(), 0, lpstrName);
818 return ret;
821 /**************************************************************************
822 * MCI_DefYieldProc [internal]
824 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
826 INT16 ret;
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) {
832 UserYield16();
833 ret = 0;
834 } else {
835 MSG msg;
837 msg.hwnd = HWND_32(HIWORD(data));
838 while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
839 ret = -1;
841 return ret;
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");
855 return FALSE;
858 wmd->lpfnYieldProc = fpYieldProc;
859 wmd->dwYieldData = dwYieldData;
860 wmd->bIs32 = TRUE;
862 return TRUE;
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);
874 return 0;
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");
888 return NULL;
890 if (!wmd->lpfnYieldProc) {
891 WARN("No proc set\n");
892 return NULL;
894 if (!wmd->bIs32) {
895 WARN("Proc is 32 bit\n");
896 return NULL;
898 return wmd->lpfnYieldProc;
901 /**************************************************************************
902 * mciGetCreatorTask [WINMM.@]
904 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
906 LPWINE_MCIDRIVER wmd;
907 HTASK ret = 0;
909 if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
911 TRACE("(%u) => %08x\n", uDeviceID, ret);
912 return ret;
915 /**************************************************************************
916 * mciDriverYield [WINMM.@]
918 UINT WINAPI mciDriverYield(UINT uDeviceID)
920 LPWINE_MCIDRIVER wmd;
921 UINT ret = 0;
923 TRACE("(%04x)\n", uDeviceID);
925 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
926 UserYield16();
927 } else {
928 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
931 return ret;
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,
946 UINT uSize)
948 MIDIOUTCAPSA mocA;
949 UINT ret;
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;
962 return ret;
965 /**************************************************************************
966 * midiOutGetDevCapsA [WINMM.@]
968 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
969 UINT uSize)
971 LPWINE_MLD wmld;
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;
994 } else if (
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;
1005 return ret;
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);
1022 UINT ret;
1024 ret = MIDI_GetErrorText(uError, xstr, uSize);
1025 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1026 HeapFree(GetProcessHeap(), 0, xstr);
1027 return ret;
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)
1037 HMIDIOUT hMidiOut;
1038 LPWINE_MIDI lpwm;
1039 UINT size;
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;
1049 if (lpwm) {
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;
1055 if (cIDs)
1056 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
1058 return lpwm;
1061 UINT MMSYSTEM_midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
1062 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1064 HMIDIOUT hMidiOut;
1065 LPWINE_MIDI lpwm;
1066 UINT dwRet = 0;
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,
1074 0, NULL, bFrom32);
1076 if (lpwm == NULL)
1077 return MMSYSERR_NOMEM;
1079 lpwm->mld.uDeviceID = uDeviceID;
1081 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod,
1082 dwFlags);
1084 if (dwRet != MMSYSERR_NOERROR) {
1085 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
1086 hMidiOut = 0;
1089 if (lphMidiOut) *lphMidiOut = hMidiOut;
1090 TRACE("=> %d hMidi=%04x\n", dwRet, hMidiOut);
1092 return dwRet;
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)
1110 LPWINE_MLD wmld;
1111 DWORD dwRet;
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);
1121 return dwRet;
1124 /**************************************************************************
1125 * midiOutPrepareHeader [WINMM.@]
1127 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
1128 MIDIHDR* lpMidiOutHdr, UINT uSize)
1130 LPWINE_MLD wmld;
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)
1146 LPWINE_MLD wmld;
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)
1165 LPWINE_MLD wmld;
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)
1181 LPWINE_MLD wmld;
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)
1196 LPWINE_MLD wmld;
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)
1211 LPWINE_MLD wmld;
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)
1226 LPWINE_MLD wmld;
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)
1262 LPWINE_MLD wmld;
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)
1280 LPWINE_MLD wmld;
1282 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
1284 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
1285 /* HACK... */
1286 if (uMessage == 0x0001) {
1287 *(LPDWORD)dwParam1 = 1;
1288 return 0;
1290 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
1291 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
1293 return MMSYSERR_INVALHANDLE;
1296 switch (uMessage) {
1297 case MODM_OPEN:
1298 case MODM_CLOSE:
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)
1318 MIDIINCAPSA micA;
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;
1329 return ret;
1332 /**************************************************************************
1333 * midiInGetDevCapsA [WINMM.@]
1335 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
1337 LPWINE_MLD wmld;
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);
1357 return ret;
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)
1371 HMIDIIN hMidiIn;
1372 LPWINE_MIDI lpwm;
1373 DWORD dwRet = 0;
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);
1383 if (lpwm == NULL)
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);
1395 hMidiIn = 0;
1397 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
1398 TRACE("=> %ld hMidi=%04x\n", dwRet, hMidiIn);
1400 return dwRet;
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)
1418 LPWINE_MLD wmld;
1419 DWORD dwRet;
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);
1428 return dwRet;
1431 /**************************************************************************
1432 * midiInPrepareHeader [WINMM.@]
1434 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
1435 MIDIHDR* lpMidiInHdr, UINT uSize)
1437 LPWINE_MLD wmld;
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)
1453 LPWINE_MLD wmld;
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)
1473 LPWINE_MLD wmld;
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)
1488 LPWINE_MLD wmld;
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)
1503 LPWINE_MLD wmld;
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)
1518 LPWINE_MLD wmld;
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)
1533 LPWINE_MLD wmld;
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)
1553 LPWINE_MLD wmld;
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;
1560 switch (uMessage) {
1561 case MIDM_OPEN:
1562 case MIDM_CLOSE:
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 {
1570 HMIDIOUT hDevice;
1571 HANDLE hThread;
1572 DWORD dwThreadID;
1573 DWORD dwTempo;
1574 DWORD dwTimeDiv;
1575 DWORD dwPositionMS;
1576 DWORD dwPulses;
1577 DWORD dwStartTicks;
1578 WORD wFlags;
1579 HANDLE hEvent;
1580 LPMIDIHDR lpMidiHdr;
1581 } WINE_MIDIStream;
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);
1593 if (lplpwm)
1594 *lplpwm = lpwm;
1596 if (lpwm == NULL) {
1597 return 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)
1610 DWORD ret = 0;
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);
1618 } else {
1619 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
1620 (double)lpMidiStrm->dwTimeDiv);
1623 return ret;
1626 /**************************************************************************
1627 * MMSYSTEM_MidiStream_MessageHandler [internal]
1629 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
1631 LPMIDIHDR lpMidiHdr;
1632 LPMIDIHDR* lpmh;
1633 LPBYTE lpData;
1635 switch (msg->message) {
1636 case WM_QUIT:
1637 SetEvent(lpMidiStrm->hEvent);
1638 return FALSE;
1639 case WINE_MSM_STOP:
1640 TRACE("STOP\n");
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);
1654 break;
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);
1693 #if 0
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) {
1699 DWORD i;
1700 BYTE ch;
1702 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
1703 printf("%02x ", lpData[dwToGo + i]);
1704 for (; i < 16; i++)
1705 printf(" ");
1706 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
1707 ch = lpData[dwToGo + i];
1708 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
1710 printf("\n");
1712 #endif
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);
1725 break;
1728 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
1729 *lpmh = lpMidiHdr;
1730 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1731 lpMidiHdr->lpNext = 0;
1732 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
1733 lpMidiHdr->dwFlags &= MHDR_DONE;
1734 lpMidiHdr->dwOffset = 0;
1736 break;
1737 default:
1738 FIXME("Unknown message %d\n", msg->message);
1739 break;
1741 return TRUE;
1744 /**************************************************************************
1745 * MMSYSTEM_MidiStream_Player [internal]
1747 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
1749 WINE_MIDIStream* lpMidiStrm = pmt;
1750 WINE_MIDI* lpwm;
1751 MSG msg;
1752 DWORD dwToGo;
1753 DWORD dwCurrTC;
1754 LPMIDIHDR lpMidiHdr;
1755 LPMIDIEVENT me;
1756 LPBYTE lpData = 0;
1758 TRACE("(%p)!\n", lpMidiStrm);
1760 if (!lpMidiStrm ||
1761 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
1762 goto the_end;
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;
1781 for (;;) {
1782 lpMidiHdr = lpMidiStrm->lpMidiHdr;
1783 if (!lpMidiHdr) {
1784 /* for first message, block until one arrives, then process all that are available */
1785 GetMessageA(&msg, 0, 0, 0);
1786 do {
1787 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1788 goto the_end;
1789 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
1790 lpData = 0;
1791 continue;
1794 if (!lpData)
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))
1812 goto the_end;
1814 lpData = 0;
1815 } else {
1816 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
1817 break;
1821 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
1822 case MEVT_COMMENT:
1823 FIXME("NIY: MEVT_COMMENT\n");
1824 /* do nothing, skip bytes */
1825 break;
1826 case MEVT_LONGMSG:
1827 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
1828 break;
1829 case MEVT_NOP:
1830 break;
1831 case MEVT_SHORTMSG:
1832 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
1833 break;
1834 case MEVT_TEMPO:
1835 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
1836 break;
1837 case MEVT_VERSION:
1838 break;
1839 default:
1840 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
1841 break;
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);
1860 lpData = 0;
1863 the_end:
1864 TRACE("End of thread\n");
1865 ExitThread(0);
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)) {
1875 DWORD count;
1877 ReleaseThunkLock(&count);
1878 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1879 RestoreThunkLock(count);
1880 } else {
1881 WARN("bad PostThreadMessageA\n");
1882 return FALSE;
1884 return TRUE;
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;
1915 MMRESULT ret;
1916 MIDIOPENSTRMID mosm;
1917 LPWINE_MIDI lpwm;
1918 HMIDIOUT hMidiOut;
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));
1927 if (!lpMidiStrm)
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;
1939 if (lphMidiStrm)
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 */
1960 DWORD count;
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);
1973 return ret;
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,
1991 UINT cbMidiHdr)
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;
2002 } else {
2003 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
2004 WINE_MSM_HEADER, cbMidiHdr,
2005 (DWORD)lpMidiHdr)) {
2006 WARN("bad PostThreadMessageA\n");
2007 ret = MMSYSERR_ERROR;
2010 return ret;
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;
2025 } else {
2026 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
2027 WARN("bad Suspend (%ld)\n", GetLastError());
2028 ret = MMSYSERR_ERROR;
2031 return ret;
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;
2048 } else {
2049 switch (lpMMT->wType) {
2050 case TIME_MS:
2051 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
2052 TRACE("=> %ld ms\n", lpMMT->u.ms);
2053 break;
2054 case TIME_TICKS:
2055 lpMMT->u.ticks = lpMidiStrm->dwPulses;
2056 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
2057 break;
2058 default:
2059 WARN("Unsupported time type %d\n", lpMMT->wType);
2060 lpMMT->wType = TIME_MS;
2061 ret = MMSYSERR_INVALPARAM;
2062 break;
2065 return ret;
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);
2106 } else {
2107 ret = MMSYSERR_INVALPARAM;
2110 return ret;
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;
2125 } else {
2126 DWORD ret;
2128 /* since we increase the thread suspend count on each midiStreamPause
2129 * there may be a need for several midiStreamResume
2131 do {
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;
2137 } else {
2138 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
2141 return ret;
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;
2156 } else {
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);
2161 return ret;
2164 UINT MMSYSTEM_waveOpen(HANDLE* lphndl, UINT uDeviceID, UINT uType,
2165 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2166 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2168 HANDLE handle;
2169 LPWINE_MLD wmld;
2170 DWORD dwRet = MMSYSERR_NOERROR;
2171 WAVEOPENDESC wod;
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;
2191 wod.hWave = handle;
2192 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
2193 wod.dwCallback = dwCallback;
2194 wod.dwInstance = dwInstance;
2195 wod.dnDevNode = 0L;
2197 for (;;) {
2198 if (dwFlags & WAVE_MAPPED) {
2199 wod.uMappedDeviceID = uDeviceID;
2200 uDeviceID = WAVE_MAPPER;
2201 } else {
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);
2221 handle = 0;
2224 if (lphndl != NULL) *lphndl = handle;
2225 TRACE("=> %ld hWave=%04x\n", dwRet, handle);
2227 return dwRet;
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,
2242 UINT uSize)
2244 LPWINE_MLD wmld;
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,
2261 UINT uSize)
2263 WAVEOUTCAPSA wocA;
2264 UINT ret;
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;
2280 return ret;
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;
2294 } else if (
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;
2305 return ret;
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);
2326 return ret;
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)
2346 LPWINE_MLD wmld;
2347 DWORD dwRet;
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);
2357 return dwRet;
2360 /**************************************************************************
2361 * waveOutPrepareHeader [WINMM.@]
2363 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
2364 WAVEHDR* lpWaveOutHdr, UINT uSize)
2366 LPWINE_MLD wmld;
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)
2384 LPWINE_MLD wmld;
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,
2402 UINT uSize)
2404 LPWINE_MLD wmld;
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)
2419 LPWINE_MLD wmld;
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)
2433 LPWINE_MLD wmld;
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)
2447 LPWINE_MLD wmld;
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)
2461 LPWINE_MLD wmld;
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,
2474 UINT uSize)
2476 LPWINE_MLD wmld;
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)
2491 LPWINE_MLD wmld;
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)
2505 LPWINE_MLD wmld;
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)
2519 LPWINE_MLD wmld;
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)
2533 LPWINE_MLD wmld;
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)
2547 LPWINE_MLD wmld;
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)
2562 LPWINE_MLD wmld;
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)
2577 LPWINE_MLD wmld;
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;
2587 return 0;
2590 /**************************************************************************
2591 * waveOutMessage [WINMM.@]
2593 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
2594 DWORD dwParam1, DWORD dwParam2)
2596 LPWINE_MLD wmld;
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;
2607 /* from M$ KB */
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)
2627 WAVEINCAPSA wicA;
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;
2640 return ret;
2643 /**************************************************************************
2644 * waveInGetDevCapsA [WINMM.@]
2646 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
2648 LPWINE_MLD wmld;
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);
2676 return ret;
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)
2695 LPWINE_MLD wmld;
2696 DWORD dwRet;
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);
2705 return dwRet;
2708 /**************************************************************************
2709 * waveInPrepareHeader [WINMM.@]
2711 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2712 UINT uSize)
2714 LPWINE_MLD wmld;
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,
2731 UINT uSize)
2733 LPWINE_MLD wmld;
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)
2754 LPWINE_MLD wmld;
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)
2770 LPWINE_MLD wmld;
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)
2785 LPWINE_MLD wmld;
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)
2800 LPWINE_MLD wmld;
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,
2814 UINT uSize)
2816 LPWINE_MLD wmld;
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)
2831 LPWINE_MLD wmld;
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)
2850 LPWINE_MLD wmld;
2852 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
2854 /* from M$ KB */
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);