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