1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
6 * Copyright 1993 Martin Ayotte
7 * 1998-2002 Eric Pouech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * 98/9 added Win32 MCI support
27 * 99/4 added midiStream support
28 * 99/9 added support for loadable low level drivers
38 #include "wine/winuser16.h" /* FIXME: should be removed */
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
47 /* ========================================================================
48 * T I M E C O N V E R S I O N F U N C T I O N S
49 * ========================================================================*/
51 /* FIXME: should be in mmsystem.c */
53 void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32)
55 mmt16->wType = mmt32->wType;
56 /* layout of rest is the same for 32/16,
57 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
59 memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u));
62 void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16)
64 mmt32->wType = mmt16->wType;
65 /* layout of rest is the same for 32/16,
66 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
68 memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u));
71 /* ========================================================================
72 * G L O B A L S E T T I N G S
73 * ========================================================================*/
75 LPWINE_MM_IDATA WINMM_IData /* = NULL */;
77 /**************************************************************************
78 * MULTIMEDIA_CreateIData [internal]
80 static BOOL MULTIMEDIA_CreateIData(HINSTANCE hInstDLL)
82 WINMM_IData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA));
86 WINMM_IData->hWinMM32Instance = hInstDLL;
87 InitializeCriticalSection(&WINMM_IData->cs);
88 WINMM_IData->cs.DebugInfo = (void*)__FILE__ ": WinMM";
89 WINMM_IData->psStopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
90 WINMM_IData->psLastEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
91 TRACE("Created IData (%p)\n", WINMM_IData);
95 /**************************************************************************
96 * MULTIMEDIA_DeleteIData [internal]
98 static void MULTIMEDIA_DeleteIData(void)
103 /* FIXME: should also free content and resources allocated
104 * inside WINMM_IData */
105 CloseHandle(WINMM_IData->psStopEvent);
106 CloseHandle(WINMM_IData->psLastEvent);
107 DeleteCriticalSection(&WINMM_IData->cs);
108 HeapFree(GetProcessHeap(), 0, WINMM_IData);
113 /**************************************************************************
114 * DllEntryPoint (WINMM.init)
116 * WINMM DLL entry point
119 BOOL WINAPI WINMM_LibMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
121 TRACE("0x%x 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
124 case DLL_PROCESS_ATTACH:
125 if (!MULTIMEDIA_CreateIData(hInstDLL))
127 if (!MULTIMEDIA_MciInit() || !MMDRV_Init()) {
128 MULTIMEDIA_DeleteIData();
132 case DLL_PROCESS_DETACH:
133 MULTIMEDIA_DeleteIData();
135 case DLL_THREAD_ATTACH:
136 case DLL_THREAD_DETACH:
142 /**************************************************************************
143 * Mixer devices. New to Win95
146 /**************************************************************************
147 * find out the real mixer ID depending on hmix (depends on dwFlags)
149 static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags)
151 LPWINE_MIXER lpwm = NULL;
153 switch (dwFlags & 0xF0000000ul) {
154 case MIXER_OBJECTF_MIXER:
155 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
157 case MIXER_OBJECTF_HMIXER:
158 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
160 case MIXER_OBJECTF_WAVEOUT:
161 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
163 case MIXER_OBJECTF_HWAVEOUT:
164 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
166 case MIXER_OBJECTF_WAVEIN:
167 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
169 case MIXER_OBJECTF_HWAVEIN:
170 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
172 case MIXER_OBJECTF_MIDIOUT:
173 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
175 case MIXER_OBJECTF_HMIDIOUT:
176 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
178 case MIXER_OBJECTF_MIDIIN:
179 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
181 case MIXER_OBJECTF_HMIDIIN:
182 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
184 case MIXER_OBJECTF_AUX:
185 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
188 FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
194 /**************************************************************************
195 * mixerGetNumDevs [WINMM.@]
197 UINT WINAPI mixerGetNumDevs(void)
199 return MMDRV_GetNum(MMDRV_MIXER);
202 /**************************************************************************
203 * mixerGetDevCapsA [WINMM.@]
205 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size)
209 if ((wmld = MMDRV_Get(devid, MMDRV_MIXER, TRUE)) == NULL)
210 return MMSYSERR_BADDEVICEID;
212 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD)mixcaps, size, TRUE);
215 /**************************************************************************
216 * mixerGetDevCapsW [WINMM.@]
218 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size)
221 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
223 if (ret == MMSYSERR_NOERROR) {
224 mixcaps->wMid = micA.wMid;
225 mixcaps->wPid = micA.wPid;
226 mixcaps->vDriverVersion = micA.vDriverVersion;
227 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, mixcaps->szPname,
228 sizeof(mixcaps->szPname)/sizeof(WCHAR) );
229 mixcaps->fdwSupport = micA.fdwSupport;
230 mixcaps->cDestinations = micA.cDestinations;
235 UINT MMSYSTEM_mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
236 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
243 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
244 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
246 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
247 &dwCallback, &dwInstance, bFrom32);
249 wmld->uDeviceID = uDeviceID;
250 mod.hmx = (HMIXEROBJ)hMix;
251 mod.dwCallback = dwCallback;
252 mod.dwInstance = dwInstance;
254 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
256 if (dwRet != MMSYSERR_NOERROR) {
257 MMDRV_Free(hMix, wmld);
260 if (lphMix) *lphMix = hMix;
261 TRACE("=> %ld hMixer=%04x\n", dwRet, hMix);
266 /**************************************************************************
267 * mixerOpen [WINMM.@]
269 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
270 DWORD dwInstance, DWORD fdwOpen)
272 return MMSYSTEM_mixerOpen(lphMix, uDeviceID,
273 dwCallback, dwInstance, fdwOpen, TRUE);
276 /**************************************************************************
277 * mixerClose [WINMM.@]
279 UINT WINAPI mixerClose(HMIXER hMix)
284 TRACE("(%04x)\n", hMix);
286 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
288 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
289 MMDRV_Free(hMix, wmld);
294 /**************************************************************************
295 * mixerGetID [WINMM.@]
297 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
301 TRACE("(%04x %p %08lx)\n", hmix, lpid, fdwID);
303 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
304 return MMSYSERR_INVALHANDLE;
308 *lpid = lpwm->mld.uDeviceID;
310 return MMSYSERR_NOERROR;
313 /**************************************************************************
314 * mixerGetControlDetailsA [WINMM.@]
316 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
321 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
323 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
324 return MMSYSERR_INVALHANDLE;
326 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
327 return MMSYSERR_INVALPARAM;
329 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD)lpmcdA,
333 /**************************************************************************
334 * mixerGetControlDetailsW [WINMM.@]
336 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
338 DWORD ret = MMSYSERR_NOTENABLED;
340 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
342 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
343 return MMSYSERR_INVALPARAM;
345 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
346 case MIXER_GETCONTROLDETAILSF_VALUE:
347 /* can savely use W structure as it is, no string inside */
348 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
350 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
352 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
353 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
354 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
357 if (lpmcd->u.cMultipleItems != 0) {
358 size *= lpmcd->u.cMultipleItems;
360 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
361 lpmcd->paDetails = pDetailsA;
362 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
363 /* set up lpmcd->paDetails */
364 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
365 /* copy from lpmcd->paDetails back to paDetailsW; */
366 if(ret == MMSYSERR_NOERROR) {
367 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
368 pDetailsW->dwParam1 = pDetailsA->dwParam1;
369 pDetailsW->dwParam2 = pDetailsA->dwParam2;
370 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
372 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
376 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
377 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
379 HeapFree(GetProcessHeap(), 0, pDetailsA);
380 lpmcd->paDetails = pDetailsW;
381 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
385 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
391 /**************************************************************************
392 * mixerGetLineControlsA [WINMM.@]
394 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
399 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
401 if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
402 return MMSYSERR_INVALHANDLE;
404 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
405 return MMSYSERR_INVALPARAM;
407 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD)lpmlcA,
411 /**************************************************************************
412 * mixerGetLineControlsW [WINMM.@]
414 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
417 MIXERLINECONTROLSA mlcA;
421 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
423 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
424 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
425 return MMSYSERR_INVALPARAM;
427 mlcA.cbStruct = sizeof(mlcA);
428 mlcA.dwLineID = lpmlcW->dwLineID;
429 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
430 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
431 mlcA.cControls = lpmlcW->cControls;
432 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
433 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
434 mlcA.cControls * mlcA.cbmxctrl);
436 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
438 if (ret == MMSYSERR_NOERROR) {
439 lpmlcW->dwLineID = mlcA.dwLineID;
440 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
441 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
442 lpmlcW->cControls = mlcA.cControls;
444 for (i = 0; i < mlcA.cControls; i++) {
445 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
446 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
447 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
448 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
449 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
450 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
451 lpmlcW->pamxctrl[i].szShortName,
452 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
453 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
454 lpmlcW->pamxctrl[i].szName,
455 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
456 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
457 * sizeof(mlcA.pamxctrl[i].Bounds) */
458 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
459 sizeof(mlcA.pamxctrl[i].Bounds));
460 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
461 * sizeof(mlcA.pamxctrl[i].Metrics) */
462 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
463 sizeof(mlcA.pamxctrl[i].Metrics));
467 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
472 /**************************************************************************
473 * mixerGetLineInfoA [WINMM.@]
475 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
479 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
481 if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
482 return MMSYSERR_INVALHANDLE;
484 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD)lpmliW,
488 /**************************************************************************
489 * mixerGetLineInfoW [WINMM.@]
491 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
497 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
499 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
500 return MMSYSERR_INVALPARAM;
502 mliA.cbStruct = sizeof(mliA);
503 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
504 case MIXER_GETLINEINFOF_COMPONENTTYPE:
505 mliA.dwComponentType = lpmliW->dwComponentType;
507 case MIXER_GETLINEINFOF_DESTINATION:
508 mliA.dwDestination = lpmliW->dwDestination;
510 case MIXER_GETLINEINFOF_LINEID:
511 mliA.dwLineID = lpmliW->dwLineID;
513 case MIXER_GETLINEINFOF_SOURCE:
514 mliA.dwDestination = lpmliW->dwDestination;
515 mliA.dwSource = lpmliW->dwSource;
517 case MIXER_GETLINEINFOF_TARGETTYPE:
518 mliA.Target.dwType = lpmliW->Target.dwType;
519 mliA.Target.wMid = lpmliW->Target.wMid;
520 mliA.Target.wPid = lpmliW->Target.wPid;
521 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
522 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
525 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
528 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
530 lpmliW->dwDestination = mliA.dwDestination;
531 lpmliW->dwSource = mliA.dwSource;
532 lpmliW->dwLineID = mliA.dwLineID;
533 lpmliW->fdwLine = mliA.fdwLine;
534 lpmliW->dwUser = mliA.dwUser;
535 lpmliW->dwComponentType = mliA.dwComponentType;
536 lpmliW->cChannels = mliA.cChannels;
537 lpmliW->cConnections = mliA.cConnections;
538 lpmliW->cControls = mliA.cControls;
539 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
540 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
541 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
542 sizeof(lpmliW->szName)/sizeof(WCHAR) );
543 lpmliW->Target.dwType = mliA.Target.dwType;
544 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
545 lpmliW->Target.wMid = mliA.Target.wMid;
546 lpmliW->Target.wPid = mliA.Target.wPid;
547 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
548 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
549 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
554 /**************************************************************************
555 * mixerSetControlDetails [WINMM.@]
557 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
562 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
564 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
565 return MMSYSERR_INVALHANDLE;
567 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD)lpmcdA,
571 /**************************************************************************
572 * mixerMessage [WINMM.@]
574 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
578 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
579 (DWORD)hmix, uMsg, dwParam1, dwParam2);
581 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
582 return MMSYSERR_INVALHANDLE;
584 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
587 /**************************************************************************
588 * auxGetNumDevs [WINMM.@]
590 UINT WINAPI auxGetNumDevs(void)
592 return MMDRV_GetNum(MMDRV_AUX);
595 /**************************************************************************
596 * auxGetDevCapsW [WINMM.@]
598 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
601 UINT ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
603 lpCaps->wMid = acA.wMid;
604 lpCaps->wPid = acA.wPid;
605 lpCaps->vDriverVersion = acA.vDriverVersion;
606 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, lpCaps->szPname,
607 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
608 lpCaps->wTechnology = acA.wTechnology;
609 lpCaps->dwSupport = acA.dwSupport;
613 /**************************************************************************
614 * auxGetDevCapsA [WINMM.@]
616 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
620 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
622 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
623 return MMSYSERR_INVALHANDLE;
624 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
627 /**************************************************************************
628 * auxGetVolume [WINMM.@]
630 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
634 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
636 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
637 return MMSYSERR_INVALHANDLE;
638 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
641 /**************************************************************************
642 * auxSetVolume [WINMM.@]
644 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
648 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
650 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
651 return MMSYSERR_INVALHANDLE;
652 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
655 /**************************************************************************
656 * auxOutMessage [WINMM.@]
658 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
662 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
663 return MMSYSERR_INVALHANDLE;
665 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
668 /**************************************************************************
669 * mciGetErrorStringW [WINMM.@]
671 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
673 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
674 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
676 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
677 HeapFree(GetProcessHeap(), 0, bufstr);
681 /**************************************************************************
682 * mciGetErrorStringA [WINMM.@]
684 BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength)
688 if (lpstrBuffer != NULL && uLength > 0 &&
689 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
691 if (LoadStringA(WINMM_IData->hWinMM32Instance,
692 dwError, lpstrBuffer, uLength) > 0) {
699 /**************************************************************************
700 * mciDriverNotify [WINMM.@]
702 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
705 TRACE("(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
707 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
710 /**************************************************************************
711 * mciGetDriverData [WINMM.@]
713 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
715 LPWINE_MCIDRIVER wmd;
717 TRACE("(%04x)\n", uDeviceID);
719 wmd = MCI_GetDriver(uDeviceID);
722 WARN("Bad uDeviceID\n");
726 return wmd->dwPrivate;
729 /**************************************************************************
730 * mciSetDriverData [WINMM.@]
732 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
734 LPWINE_MCIDRIVER wmd;
736 TRACE("(%04x, %08lx)\n", uDeviceID, data);
738 wmd = MCI_GetDriver(uDeviceID);
741 WARN("Bad uDeviceID\n");
745 wmd->dwPrivate = data;
749 /**************************************************************************
750 * mciSendCommandA [WINMM.@]
752 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
756 TRACE("(%08x, %s, %08lx, %08lx)\n",
757 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
759 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
760 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
761 TRACE("=> %08lx\n", dwRet);
765 /**************************************************************************
766 * mciSendCommandW [WINMM.@]
768 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
770 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
771 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
772 return MCIERR_UNSUPPORTED_FUNCTION;
775 /**************************************************************************
776 * mciGetDeviceIDA [WINMM.@]
778 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
780 return MCI_GetDriverFromString(lpstrName);
783 /**************************************************************************
784 * mciGetDeviceIDW [WINMM.@]
786 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
791 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
792 ret = MCI_GetDriverFromString(lpstrName);
793 HeapFree(GetProcessHeap(), 0, lpstrName);
797 /**************************************************************************
798 * MCI_DefYieldProc [internal]
800 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
804 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
806 if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
807 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
813 msg.hwnd = HWND_32(HIWORD(data));
814 while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
820 /**************************************************************************
821 * mciSetYieldProc [WINMM.@]
823 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
825 LPWINE_MCIDRIVER wmd;
827 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
829 if (!(wmd = MCI_GetDriver(uDeviceID))) {
830 WARN("Bad uDeviceID\n");
834 wmd->lpfnYieldProc = fpYieldProc;
835 wmd->dwYieldData = dwYieldData;
841 /**************************************************************************
842 * mciGetDeviceIDFromElementIDW [WINMM.@]
844 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
846 /* FIXME: that's rather strange, there is no
847 * mciGetDeviceIDFromElementID32A in winmm.spec
849 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
853 /**************************************************************************
854 * mciGetYieldProc [WINMM.@]
856 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
858 LPWINE_MCIDRIVER wmd;
860 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
862 if (!(wmd = MCI_GetDriver(uDeviceID))) {
863 WARN("Bad uDeviceID\n");
866 if (!wmd->lpfnYieldProc) {
867 WARN("No proc set\n");
871 WARN("Proc is 32 bit\n");
874 return wmd->lpfnYieldProc;
877 /**************************************************************************
878 * mciGetCreatorTask [WINMM.@]
880 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
882 LPWINE_MCIDRIVER wmd;
885 if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
887 TRACE("(%u) => %08x\n", uDeviceID, ret);
891 /**************************************************************************
892 * mciDriverYield [WINMM.@]
894 UINT WINAPI mciDriverYield(UINT uDeviceID)
896 LPWINE_MCIDRIVER wmd;
899 TRACE("(%04x)\n", uDeviceID);
901 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
904 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
910 /**************************************************************************
911 * midiOutGetNumDevs [WINMM.@]
913 UINT WINAPI midiOutGetNumDevs(void)
915 return MMDRV_GetNum(MMDRV_MIDIOUT);
918 /**************************************************************************
919 * midiOutGetDevCapsW [WINMM.@]
921 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps,
927 ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
928 lpCaps->wMid = mocA.wMid;
929 lpCaps->wPid = mocA.wPid;
930 lpCaps->vDriverVersion = mocA.vDriverVersion;
931 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, lpCaps->szPname,
932 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
933 lpCaps->wTechnology = mocA.wTechnology;
934 lpCaps->wVoices = mocA.wVoices;
935 lpCaps->wNotes = mocA.wNotes;
936 lpCaps->wChannelMask = mocA.wChannelMask;
937 lpCaps->dwSupport = mocA.dwSupport;
941 /**************************************************************************
942 * midiOutGetDevCapsA [WINMM.@]
944 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
949 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
951 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
953 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
954 return MMSYSERR_INVALHANDLE;
956 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
959 /**************************************************************************
960 * MIDI_GetErrorText [internal]
962 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
964 UINT16 ret = MMSYSERR_BADERRNUM;
966 if (lpText == NULL) {
967 ret = MMSYSERR_INVALPARAM;
968 } else if (uSize == 0) {
969 ret = MMSYSERR_NOERROR;
971 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
972 * a warning for the test was always true */
973 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
974 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
976 if (LoadStringA(WINMM_IData->hWinMM32Instance,
977 uError, lpText, uSize) > 0) {
978 ret = MMSYSERR_NOERROR;
984 /**************************************************************************
985 * midiOutGetErrorTextA [WINMM.@]
987 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
989 return MIDI_GetErrorText(uError, lpText, uSize);
992 /**************************************************************************
993 * midiOutGetErrorTextW [WINMM.@]
995 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
997 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1000 ret = MIDI_GetErrorText(uError, xstr, uSize);
1001 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1002 HeapFree(GetProcessHeap(), 0, xstr);
1006 /**************************************************************************
1007 * MIDI_OutAlloc [internal]
1009 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
1010 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
1011 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
1017 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
1019 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
1020 lpdwCallback, lpdwInstance, bFrom32);
1022 if (lphMidiOut != NULL)
1023 *lphMidiOut = hMidiOut;
1026 lpwm->mod.hMidi = (HMIDI) hMidiOut;
1027 lpwm->mod.dwCallback = *lpdwCallback;
1028 lpwm->mod.dwInstance = *lpdwInstance;
1029 lpwm->mod.dnDevNode = 0;
1030 lpwm->mod.cIds = cIDs;
1032 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
1037 UINT MMSYSTEM_midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
1038 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1044 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1045 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
1047 if (lphMidiOut != NULL) *lphMidiOut = 0;
1049 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
1053 return MMSYSERR_NOMEM;
1055 lpwm->mld.uDeviceID = uDeviceID;
1057 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod,
1060 if (dwRet != MMSYSERR_NOERROR) {
1061 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
1065 if (lphMidiOut) *lphMidiOut = hMidiOut;
1066 TRACE("=> %d hMidi=%04x\n", dwRet, hMidiOut);
1071 /**************************************************************************
1072 * midiOutOpen [WINMM.@]
1074 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
1075 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1077 return MMSYSTEM_midiOutOpen(lphMidiOut, uDeviceID, dwCallback,
1078 dwInstance, dwFlags, TRUE);
1081 /**************************************************************************
1082 * midiOutClose [WINMM.@]
1084 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
1089 TRACE("(%04X)\n", hMidiOut);
1091 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1092 return MMSYSERR_INVALHANDLE;
1094 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
1095 MMDRV_Free(hMidiOut, wmld);
1100 /**************************************************************************
1101 * midiOutPrepareHeader [WINMM.@]
1103 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
1104 MIDIHDR* lpMidiOutHdr, UINT uSize)
1108 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1110 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1111 return MMSYSERR_INVALHANDLE;
1113 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
1116 /**************************************************************************
1117 * midiOutUnprepareHeader [WINMM.@]
1119 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
1120 MIDIHDR* lpMidiOutHdr, UINT uSize)
1124 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1126 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
1127 return MMSYSERR_NOERROR;
1130 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1131 return MMSYSERR_INVALHANDLE;
1133 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
1136 /**************************************************************************
1137 * midiOutShortMsg [WINMM.@]
1139 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
1143 TRACE("(%04X, %08lX)\n", hMidiOut, dwMsg);
1145 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1146 return MMSYSERR_INVALHANDLE;
1148 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, FALSE);
1151 /**************************************************************************
1152 * midiOutLongMsg [WINMM.@]
1154 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
1155 MIDIHDR* lpMidiOutHdr, UINT uSize)
1159 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1161 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1162 return MMSYSERR_INVALHANDLE;
1164 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE);
1167 /**************************************************************************
1168 * midiOutReset [WINMM.@]
1170 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
1174 TRACE("(%04X)\n", hMidiOut);
1176 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1177 return MMSYSERR_INVALHANDLE;
1179 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
1182 /**************************************************************************
1183 * midiOutGetVolume [WINMM.@]
1185 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
1189 TRACE("(%04X, %p);\n", uDeviceID, lpdwVolume);
1191 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
1192 return MMSYSERR_INVALHANDLE;
1194 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1197 /**************************************************************************
1198 * midiOutSetVolume [WINMM.@]
1200 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
1204 TRACE("(%04X, %ld);\n", uDeviceID, dwVolume);
1206 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
1207 return MMSYSERR_INVALHANDLE;
1209 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
1212 /**************************************************************************
1213 * midiOutCachePatches [WINMM.@]
1215 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
1216 WORD* lpwPatchArray, UINT uFlags)
1218 /* not really necessary to support this */
1219 FIXME("not supported yet\n");
1220 return MMSYSERR_NOTSUPPORTED;
1223 /**************************************************************************
1224 * midiOutCacheDrumPatches [WINMM.@]
1226 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
1227 WORD* lpwKeyArray, UINT uFlags)
1229 FIXME("not supported yet\n");
1230 return MMSYSERR_NOTSUPPORTED;
1233 /**************************************************************************
1234 * midiOutGetID [WINMM.@]
1236 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
1240 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
1242 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1243 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1244 return MMSYSERR_INVALHANDLE;
1246 *lpuDeviceID = wmld->uDeviceID;
1247 return MMSYSERR_NOERROR;
1250 /**************************************************************************
1251 * midiOutMessage [WINMM.@]
1253 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
1254 DWORD dwParam1, DWORD dwParam2)
1258 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
1260 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
1262 if (uMessage == 0x0001) {
1263 *(LPDWORD)dwParam1 = 1;
1266 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
1267 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
1269 return MMSYSERR_INVALHANDLE;
1275 FIXME("can't handle OPEN or CLOSE message!\n");
1276 return MMSYSERR_NOTSUPPORTED;
1278 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1281 /**************************************************************************
1282 * midiInGetNumDevs [WINMM.@]
1284 UINT WINAPI midiInGetNumDevs(void)
1286 return MMDRV_GetNum(MMDRV_MIDIIN);
1289 /**************************************************************************
1290 * midiInGetDevCapsW [WINMM.@]
1292 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
1295 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
1297 if (ret == MMSYSERR_NOERROR) {
1298 lpCaps->wMid = micA.wMid;
1299 lpCaps->wPid = micA.wPid;
1300 lpCaps->vDriverVersion = micA.vDriverVersion;
1301 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, lpCaps->szPname,
1302 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
1303 lpCaps->dwSupport = micA.dwSupport;
1308 /**************************************************************************
1309 * midiInGetDevCapsA [WINMM.@]
1311 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
1315 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
1317 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
1318 return MMSYSERR_INVALHANDLE;
1320 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1323 /**************************************************************************
1324 * midiInGetErrorTextW [WINMM.@]
1326 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1328 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1329 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
1331 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1332 HeapFree(GetProcessHeap(), 0, xstr);
1336 /**************************************************************************
1337 * midiInGetErrorTextA [WINMM.@]
1339 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1341 return MIDI_GetErrorText(uError, lpText, uSize);
1344 UINT MMSYSTEM_midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
1345 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1351 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1352 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
1354 if (lphMidiIn != NULL) *lphMidiIn = 0;
1356 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
1357 &dwFlags, &dwCallback, &dwInstance, bFrom32);
1360 return MMSYSERR_NOMEM;
1362 lpwm->mod.hMidi = (HMIDI) hMidiIn;
1363 lpwm->mod.dwCallback = dwCallback;
1364 lpwm->mod.dwInstance = dwInstance;
1366 lpwm->mld.uDeviceID = uDeviceID;
1367 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1369 if (dwRet != MMSYSERR_NOERROR) {
1370 MMDRV_Free(hMidiIn, &lpwm->mld);
1373 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
1374 TRACE("=> %ld hMidi=%04x\n", dwRet, hMidiIn);
1379 /**************************************************************************
1380 * midiInOpen [WINMM.@]
1382 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
1383 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1385 return MMSYSTEM_midiInOpen(lphMidiIn, uDeviceID, dwCallback,
1386 dwInstance, dwFlags, TRUE);
1389 /**************************************************************************
1390 * midiInClose [WINMM.@]
1392 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
1397 TRACE("(%04X)\n", hMidiIn);
1399 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1400 return MMSYSERR_INVALHANDLE;
1402 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
1403 MMDRV_Free(hMidiIn, wmld);
1407 /**************************************************************************
1408 * midiInPrepareHeader [WINMM.@]
1410 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
1411 MIDIHDR* lpMidiInHdr, UINT uSize)
1415 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1417 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1418 return MMSYSERR_INVALHANDLE;
1420 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
1423 /**************************************************************************
1424 * midiInUnprepareHeader [WINMM.@]
1426 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
1427 MIDIHDR* lpMidiInHdr, UINT uSize)
1431 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1433 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
1434 return MMSYSERR_NOERROR;
1437 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1438 return MMSYSERR_INVALHANDLE;
1440 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
1443 /**************************************************************************
1444 * midiInAddBuffer [WINMM.@]
1446 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
1447 MIDIHDR* lpMidiInHdr, UINT uSize)
1451 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1453 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1454 return MMSYSERR_INVALHANDLE;
1456 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE);
1459 /**************************************************************************
1460 * midiInStart [WINMM.@]
1462 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
1466 TRACE("(%04X)\n", hMidiIn);
1468 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1469 return MMSYSERR_INVALHANDLE;
1471 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
1474 /**************************************************************************
1475 * midiInStop [WINMM.@]
1477 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
1481 TRACE("(%04X)\n", hMidiIn);
1483 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1484 return MMSYSERR_INVALHANDLE;
1486 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
1489 /**************************************************************************
1490 * midiInReset [WINMM.@]
1492 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
1496 TRACE("(%04X)\n", hMidiIn);
1498 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1499 return MMSYSERR_INVALHANDLE;
1501 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
1504 /**************************************************************************
1505 * midiInGetID [WINMM.@]
1507 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
1511 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
1513 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1515 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
1516 return MMSYSERR_INVALHANDLE;
1518 *lpuDeviceID = wmld->uDeviceID;
1520 return MMSYSERR_NOERROR;
1523 /**************************************************************************
1524 * midiInMessage [WINMM.@]
1526 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
1527 DWORD dwParam1, DWORD dwParam2)
1531 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
1533 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1534 return MMSYSERR_INVALHANDLE;
1539 FIXME("can't handle OPEN or CLOSE message!\n");
1540 return MMSYSERR_NOTSUPPORTED;
1542 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1545 typedef struct WINE_MIDIStream {
1556 LPMIDIHDR lpMidiHdr;
1559 #define WINE_MSM_HEADER (WM_USER+0)
1560 #define WINE_MSM_STOP (WM_USER+1)
1562 /**************************************************************************
1563 * MMSYSTEM_GetMidiStream [internal]
1565 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
1567 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
1576 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
1578 return *lpMidiStrm != NULL;
1581 /**************************************************************************
1582 * MMSYSTEM_MidiStream_Convert [internal]
1584 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
1588 if (lpMidiStrm->dwTimeDiv == 0) {
1589 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1590 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
1591 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
1592 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
1593 ret = (pulse * 1000) / (nf * nsf);
1595 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
1596 (double)lpMidiStrm->dwTimeDiv);
1602 /**************************************************************************
1603 * MMSYSTEM_MidiStream_MessageHandler [internal]
1605 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
1607 LPMIDIHDR lpMidiHdr;
1611 switch (msg->message) {
1613 SetEvent(lpMidiStrm->hEvent);
1617 /* this is not quite what MS doc says... */
1618 midiOutReset(lpMidiStrm->hDevice);
1619 /* empty list of already submitted buffers */
1620 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
1621 lpMidiHdr->dwFlags |= MHDR_DONE;
1622 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1624 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1625 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1626 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1628 lpMidiStrm->lpMidiHdr = 0;
1629 SetEvent(lpMidiStrm->hEvent);
1631 case WINE_MSM_HEADER:
1632 /* sets initial tick count for first MIDIHDR */
1633 if (!lpMidiStrm->dwStartTicks)
1634 lpMidiStrm->dwStartTicks = GetTickCount();
1636 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1637 * by native mcimidi, it doesn't look like a correct one".
1638 * this trick allows to throw it away... but I don't like it.
1639 * It looks like part of the file I'm trying to play and definitively looks
1640 * like raw midi content
1641 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1642 * synchronization issue where native mcimidi is still processing raw MIDI
1643 * content before generating MIDIEVENTs ?
1645 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1646 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1647 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1648 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1649 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1650 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1651 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1652 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1653 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1654 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1655 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1656 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1657 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1658 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1659 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1660 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1661 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1663 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1664 lpData = lpMidiHdr->lpData;
1665 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1666 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
1667 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
1668 lpMidiHdr->dwFlags, msg->wParam);
1670 /* dumps content of lpMidiHdr->lpData
1671 * FIXME: there should be a debug routine somewhere that already does this
1672 * I hate spreading this type of shit all around the code
1674 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
1678 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
1679 printf("%02x ", lpData[dwToGo + i]);
1682 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
1683 ch = lpData[dwToGo + i];
1684 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
1689 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
1690 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
1691 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
1692 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
1693 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
1694 ((LPMIDIEVENT)lpData)->dwStreamID);
1695 lpMidiHdr->dwFlags |= MHDR_DONE;
1696 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1698 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1699 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1700 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1704 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
1706 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1707 lpMidiHdr->lpNext = 0;
1708 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
1709 lpMidiHdr->dwFlags &= MHDR_DONE;
1710 lpMidiHdr->dwOffset = 0;
1714 FIXME("Unknown message %d\n", msg->message);
1720 /**************************************************************************
1721 * MMSYSTEM_MidiStream_Player [internal]
1723 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
1725 WINE_MIDIStream* lpMidiStrm = pmt;
1730 LPMIDIHDR lpMidiHdr;
1734 TRACE("(%p)!\n", lpMidiStrm);
1737 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
1740 /* force thread's queue creation */
1741 /* Used to be InitThreadInput16(0, 5); */
1742 /* but following works also with hack in midiStreamOpen */
1743 PeekMessageA(&msg, 0, 0, 0, 0);
1745 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
1746 SetEvent(lpMidiStrm->hEvent);
1747 TRACE("Ready to go 1\n");
1748 /* thread is started in paused mode */
1749 SuspendThread(lpMidiStrm->hThread);
1750 TRACE("Ready to go 2\n");
1752 lpMidiStrm->dwStartTicks = 0;
1753 lpMidiStrm->dwPulses = 0;
1755 lpMidiStrm->lpMidiHdr = 0;
1758 lpMidiHdr = lpMidiStrm->lpMidiHdr;
1760 /* for first message, block until one arrives, then process all that are available */
1761 GetMessageA(&msg, 0, 0, 0);
1763 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1765 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
1771 lpData = lpMidiHdr->lpData;
1773 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
1775 /* do we have to wait ? */
1776 if (me->dwDeltaTime) {
1777 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
1778 lpMidiStrm->dwPulses += me->dwDeltaTime;
1780 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
1782 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
1783 while ((dwCurrTC = GetTickCount()) < dwToGo) {
1784 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
1785 /* got a message, handle it */
1786 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
1787 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1792 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
1797 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
1799 FIXME("NIY: MEVT_COMMENT\n");
1800 /* do nothing, skip bytes */
1803 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
1808 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
1811 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
1816 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
1819 if (me->dwEvent & MEVT_F_CALLBACK) {
1820 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1821 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
1822 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
1824 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
1825 if (me->dwEvent & MEVT_F_LONG)
1826 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
1827 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
1828 /* done with this header */
1829 lpMidiHdr->dwFlags |= MHDR_DONE;
1830 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1832 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
1833 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1834 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1835 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1840 TRACE("End of thread\n");
1842 return 0; /* for removing the warning, never executed */
1845 /**************************************************************************
1846 * MMSYSTEM_MidiStream_PostMessage [internal]
1848 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
1850 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
1853 ReleaseThunkLock(&count);
1854 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1855 RestoreThunkLock(count);
1857 WARN("bad PostThreadMessageA\n");
1863 /**************************************************************************
1864 * midiStreamClose [WINMM.@]
1866 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
1868 WINE_MIDIStream* lpMidiStrm;
1870 TRACE("(%08x)!\n", hMidiStrm);
1872 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
1873 return MMSYSERR_INVALHANDLE;
1875 midiStreamStop(hMidiStrm);
1876 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
1877 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
1878 CloseHandle(lpMidiStrm->hEvent);
1880 return midiOutClose((HMIDIOUT)hMidiStrm);
1883 /**************************************************************************
1884 * MMSYSTEM_MidiStream_Open [internal]
1886 MMRESULT MMSYSTEM_MidiStream_Open(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
1887 DWORD cMidi, DWORD dwCallback,
1888 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
1890 WINE_MIDIStream* lpMidiStrm;
1892 MIDIOPENSTRMID mosm;
1896 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
1897 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
1899 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
1900 return MMSYSERR_INVALPARAM;
1902 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
1904 return MMSYSERR_NOMEM;
1906 lpMidiStrm->dwTempo = 500000;
1907 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
1908 lpMidiStrm->dwPositionMS = 0;
1910 mosm.dwStreamID = (DWORD)lpMidiStrm;
1911 /* FIXME: the correct value is not allocated yet for MAPPER */
1912 mosm.wDeviceID = *lpuDeviceID;
1913 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
1914 lpMidiStrm->hDevice = hMidiOut;
1916 *lphMidiStrm = (HMIDISTRM)hMidiOut;
1918 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
1919 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID);
1920 lpwm->mld.uDeviceID = *lpuDeviceID = 0;
1922 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
1923 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1924 lpMidiStrm->wFlags = HIWORD(fdwOpen);
1926 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
1927 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
1929 if (!lpMidiStrm->hThread) {
1930 midiStreamClose((HMIDISTRM)hMidiOut);
1931 return MMSYSERR_NOMEM;
1934 /* wait for thread to have started, and for its queue to be created */
1938 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
1939 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
1940 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
1942 ReleaseThunkLock(&count);
1943 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1944 RestoreThunkLock(count);
1947 TRACE("=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n",
1948 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
1952 /**************************************************************************
1953 * midiStreamOpen [WINMM.@]
1955 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
1956 DWORD cMidi, DWORD dwCallback,
1957 DWORD dwInstance, DWORD fdwOpen)
1959 return MMSYSTEM_MidiStream_Open(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
1960 dwInstance, fdwOpen, TRUE);
1963 /**************************************************************************
1964 * midiStreamOut [WINMM.@]
1966 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
1969 WINE_MIDIStream* lpMidiStrm;
1970 DWORD ret = MMSYSERR_NOERROR;
1972 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
1974 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
1975 ret = MMSYSERR_INVALHANDLE;
1976 } else if (!lpMidiHdr) {
1977 ret = MMSYSERR_INVALPARAM;
1979 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
1980 WINE_MSM_HEADER, cbMidiHdr,
1981 (DWORD)lpMidiHdr)) {
1982 WARN("bad PostThreadMessageA\n");
1983 ret = MMSYSERR_ERROR;
1989 /**************************************************************************
1990 * midiStreamPause [WINMM.@]
1992 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
1994 WINE_MIDIStream* lpMidiStrm;
1995 DWORD ret = MMSYSERR_NOERROR;
1997 TRACE("(%08x)!\n", hMidiStrm);
1999 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2000 ret = MMSYSERR_INVALHANDLE;
2002 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
2003 WARN("bad Suspend (%ld)\n", GetLastError());
2004 ret = MMSYSERR_ERROR;
2010 /**************************************************************************
2011 * midiStreamPosition [WINMM.@]
2013 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
2015 WINE_MIDIStream* lpMidiStrm;
2016 DWORD ret = MMSYSERR_NOERROR;
2018 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
2020 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2021 ret = MMSYSERR_INVALHANDLE;
2022 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
2023 ret = MMSYSERR_INVALPARAM;
2025 switch (lpMMT->wType) {
2027 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
2028 TRACE("=> %ld ms\n", lpMMT->u.ms);
2031 lpMMT->u.ticks = lpMidiStrm->dwPulses;
2032 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
2035 WARN("Unsupported time type %d\n", lpMMT->wType);
2036 lpMMT->wType = TIME_MS;
2037 ret = MMSYSERR_INVALPARAM;
2044 /**************************************************************************
2045 * midiStreamProperty [WINMM.@]
2047 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
2049 WINE_MIDIStream* lpMidiStrm;
2050 MMRESULT ret = MMSYSERR_NOERROR;
2052 TRACE("(%08x, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
2054 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2055 ret = MMSYSERR_INVALHANDLE;
2056 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
2057 ret = MMSYSERR_INVALPARAM;
2058 } else if (dwProperty & MIDIPROP_TEMPO) {
2059 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
2061 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
2062 ret = MMSYSERR_INVALPARAM;
2063 } else if (dwProperty & MIDIPROP_SET) {
2064 lpMidiStrm->dwTempo = mpt->dwTempo;
2065 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
2066 } else if (dwProperty & MIDIPROP_GET) {
2067 mpt->dwTempo = lpMidiStrm->dwTempo;
2068 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
2070 } else if (dwProperty & MIDIPROP_TIMEDIV) {
2071 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
2073 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
2074 ret = MMSYSERR_INVALPARAM;
2075 } else if (dwProperty & MIDIPROP_SET) {
2076 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
2077 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
2078 } else if (dwProperty & MIDIPROP_GET) {
2079 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
2080 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
2083 ret = MMSYSERR_INVALPARAM;
2089 /**************************************************************************
2090 * midiStreamRestart [WINMM.@]
2092 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
2094 WINE_MIDIStream* lpMidiStrm;
2095 MMRESULT ret = MMSYSERR_NOERROR;
2097 TRACE("(%08x)!\n", hMidiStrm);
2099 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2100 ret = MMSYSERR_INVALHANDLE;
2104 /* since we increase the thread suspend count on each midiStreamPause
2105 * there may be a need for several midiStreamResume
2108 ret = ResumeThread(lpMidiStrm->hThread);
2109 } while (ret != 0xFFFFFFFF && ret != 0);
2110 if (ret == 0xFFFFFFFF) {
2111 WARN("bad Resume (%ld)\n", GetLastError());
2112 ret = MMSYSERR_ERROR;
2114 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
2120 /**************************************************************************
2121 * midiStreamStop [WINMM.@]
2123 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
2125 WINE_MIDIStream* lpMidiStrm;
2126 MMRESULT ret = MMSYSERR_NOERROR;
2128 TRACE("(%08x)!\n", hMidiStrm);
2130 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2131 ret = MMSYSERR_INVALHANDLE;
2133 /* in case stream has been paused... FIXME is the current state correct ? */
2134 midiStreamRestart(hMidiStrm);
2135 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
2140 UINT MMSYSTEM_waveOpen(HANDLE* lphndl, UINT uDeviceID, UINT uType,
2141 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2142 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2146 DWORD dwRet = MMSYSERR_NOERROR;
2149 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2150 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
2151 dwInstance, dwFlags, bFrom32?32:16);
2153 if (dwFlags & WAVE_FORMAT_QUERY) TRACE("WAVE_FORMAT_QUERY requested !\n");
2155 if (lpFormat == NULL) return WAVERR_BADFORMAT;
2156 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1))
2157 return MMSYSERR_INVALPARAM;
2159 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
2160 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
2161 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize);
2163 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
2164 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL)
2165 return MMSYSERR_NOMEM;
2168 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
2169 wod.dwCallback = dwCallback;
2170 wod.dwInstance = dwInstance;
2174 if (dwFlags & WAVE_MAPPED) {
2175 wod.uMappedDeviceID = uDeviceID;
2176 uDeviceID = WAVE_MAPPER;
2178 wod.uMappedDeviceID = -1;
2180 wmld->uDeviceID = uDeviceID;
2182 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN,
2183 (DWORD)&wod, dwFlags);
2185 if (dwRet != WAVERR_BADFORMAT ||
2186 (dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) break;
2187 /* if we ask for a format which isn't supported by the physical driver,
2188 * let's try to map it through the wave mapper (except, if we already tried
2189 * or user didn't allow us to use acm codecs)
2191 dwFlags |= WAVE_MAPPED;
2192 /* we shall loop only one */
2195 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
2196 MMDRV_Free(handle, wmld);
2200 if (lphndl != NULL) *lphndl = handle;
2201 TRACE("=> %ld hWave=%04x\n", dwRet, handle);
2206 /**************************************************************************
2207 * waveOutGetNumDevs [WINMM.@]
2209 UINT WINAPI waveOutGetNumDevs(void)
2211 return MMDRV_GetNum(MMDRV_WAVEOUT);
2214 /**************************************************************************
2215 * waveOutGetDevCapsA [WINMM.@]
2217 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
2222 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2224 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2226 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
2227 return MMSYSERR_INVALHANDLE;
2229 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2233 /**************************************************************************
2234 * waveOutGetDevCapsW [WINMM.@]
2236 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
2242 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2244 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
2246 if (ret == MMSYSERR_NOERROR) {
2247 lpCaps->wMid = wocA.wMid;
2248 lpCaps->wPid = wocA.wPid;
2249 lpCaps->vDriverVersion = wocA.vDriverVersion;
2250 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, lpCaps->szPname,
2251 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2252 lpCaps->dwFormats = wocA.dwFormats;
2253 lpCaps->wChannels = wocA.wChannels;
2254 lpCaps->dwSupport = wocA.dwSupport;
2259 /**************************************************************************
2260 * WAVE_GetErrorText [internal]
2262 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2264 UINT16 ret = MMSYSERR_BADERRNUM;
2266 if (lpText == NULL) {
2267 ret = MMSYSERR_INVALPARAM;
2268 } else if (uSize == 0) {
2269 ret = MMSYSERR_NOERROR;
2271 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2272 * a warning for the test was always true */
2273 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
2274 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
2276 if (LoadStringA(WINMM_IData->hWinMM32Instance,
2277 uError, lpText, uSize) > 0) {
2278 ret = MMSYSERR_NOERROR;
2284 /**************************************************************************
2285 * waveOutGetErrorTextA [WINMM.@]
2287 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2289 return WAVE_GetErrorText(uError, lpText, uSize);
2292 /**************************************************************************
2293 * waveOutGetErrorTextW [WINMM.@]
2295 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2297 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2298 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
2300 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2301 HeapFree(GetProcessHeap(), 0, xstr);
2305 /**************************************************************************
2306 * waveOutOpen [WINMM.@]
2307 * All the args/structs have the same layout as the win16 equivalents
2309 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
2310 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2311 DWORD dwInstance, DWORD dwFlags)
2313 return MMSYSTEM_waveOpen(lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
2314 dwCallback, dwInstance, dwFlags, TRUE);
2317 /**************************************************************************
2318 * waveOutClose [WINMM.@]
2320 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
2325 TRACE("(%04X)\n", hWaveOut);
2327 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2328 return MMSYSERR_INVALHANDLE;
2330 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
2331 MMDRV_Free(hWaveOut, wmld);
2336 /**************************************************************************
2337 * waveOutPrepareHeader [WINMM.@]
2339 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
2340 WAVEHDR* lpWaveOutHdr, UINT uSize)
2344 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2346 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
2348 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2349 return MMSYSERR_INVALHANDLE;
2351 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2354 /**************************************************************************
2355 * waveOutUnprepareHeader [WINMM.@]
2357 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
2358 LPWAVEHDR lpWaveOutHdr, UINT uSize)
2362 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2364 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
2365 return MMSYSERR_NOERROR;
2368 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2369 return MMSYSERR_INVALHANDLE;
2371 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2374 /**************************************************************************
2375 * waveOutWrite [WINMM.@]
2377 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
2382 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2384 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2385 return MMSYSERR_INVALHANDLE;
2387 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2390 /**************************************************************************
2391 * waveOutBreakLoop [WINMM.@]
2393 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
2397 TRACE("(%04X);\n", hWaveOut);
2399 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2400 return MMSYSERR_INVALHANDLE;
2401 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
2404 /**************************************************************************
2405 * waveOutPause [WINMM.@]
2407 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
2411 TRACE("(%04X);\n", hWaveOut);
2413 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2414 return MMSYSERR_INVALHANDLE;
2415 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
2418 /**************************************************************************
2419 * waveOutReset [WINMM.@]
2421 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
2425 TRACE("(%04X);\n", hWaveOut);
2427 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2428 return MMSYSERR_INVALHANDLE;
2429 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
2432 /**************************************************************************
2433 * waveOutRestart [WINMM.@]
2435 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
2439 TRACE("(%04X);\n", hWaveOut);
2441 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2442 return MMSYSERR_INVALHANDLE;
2443 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
2446 /**************************************************************************
2447 * waveOutGetPosition [WINMM.@]
2449 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
2454 TRACE("(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
2456 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2457 return MMSYSERR_INVALHANDLE;
2459 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE);
2462 /**************************************************************************
2463 * waveOutGetPitch [WINMM.@]
2465 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
2469 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
2471 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2472 return MMSYSERR_INVALHANDLE;
2473 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE);
2476 /**************************************************************************
2477 * waveOutSetPitch [WINMM.@]
2479 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
2483 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
2485 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2486 return MMSYSERR_INVALHANDLE;
2487 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
2490 /**************************************************************************
2491 * waveOutGetPlaybackRate [WINMM.@]
2493 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
2497 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
2499 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2500 return MMSYSERR_INVALHANDLE;
2501 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE);
2504 /**************************************************************************
2505 * waveOutSetPlaybackRate [WINMM.@]
2507 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
2511 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
2513 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2514 return MMSYSERR_INVALHANDLE;
2515 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
2518 /**************************************************************************
2519 * waveOutGetVolume [WINMM.@]
2521 UINT WINAPI waveOutGetVolume(UINT devid, LPDWORD lpdw)
2525 TRACE("(%04X, %08lx);\n", devid, (DWORD)lpdw);
2527 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
2528 return MMSYSERR_INVALHANDLE;
2530 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE);
2533 /**************************************************************************
2534 * waveOutSetVolume [WINMM.@]
2536 UINT WINAPI waveOutSetVolume(UINT devid, DWORD dw)
2540 TRACE("(%04X, %08lx);\n", devid, dw);
2542 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
2543 return MMSYSERR_INVALHANDLE;
2545 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
2548 /**************************************************************************
2549 * waveOutGetID [WINMM.@]
2551 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
2555 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
2557 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2559 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2560 return MMSYSERR_INVALHANDLE;
2562 *lpuDeviceID = wmld->uDeviceID;
2566 /**************************************************************************
2567 * waveOutMessage [WINMM.@]
2569 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
2570 DWORD dwParam1, DWORD dwParam2)
2574 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
2576 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
2577 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
2578 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2580 return MMSYSERR_INVALHANDLE;
2584 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
2585 return MMSYSERR_INVALPARAM;
2587 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2590 /**************************************************************************
2591 * waveInGetNumDevs [WINMM.@]
2593 UINT WINAPI waveInGetNumDevs(void)
2595 return MMDRV_GetNum(MMDRV_WAVEIN);
2598 /**************************************************************************
2599 * waveInGetDevCapsW [WINMM.@]
2601 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
2604 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize);
2606 if (ret == MMSYSERR_NOERROR) {
2607 lpCaps->wMid = wicA.wMid;
2608 lpCaps->wPid = wicA.wPid;
2609 lpCaps->vDriverVersion = wicA.vDriverVersion;
2610 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, lpCaps->szPname,
2611 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2612 lpCaps->dwFormats = wicA.dwFormats;
2613 lpCaps->wChannels = wicA.wChannels;
2619 /**************************************************************************
2620 * waveInGetDevCapsA [WINMM.@]
2622 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
2626 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2628 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
2629 return MMSYSERR_INVALHANDLE;
2631 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2634 /**************************************************************************
2635 * waveInGetErrorTextA [WINMM.@]
2637 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2639 return WAVE_GetErrorText(uError, lpText, uSize);
2642 /**************************************************************************
2643 * waveInGetErrorTextW [WINMM.@]
2645 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2647 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
2648 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
2650 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
2651 HeapFree(GetProcessHeap(), 0, txt);
2655 /**************************************************************************
2656 * waveInOpen [WINMM.@]
2658 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
2659 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2660 DWORD dwInstance, DWORD dwFlags)
2662 return MMSYSTEM_waveOpen(lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
2663 dwCallback, dwInstance, dwFlags, TRUE);
2666 /**************************************************************************
2667 * waveInClose [WINMM.@]
2669 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
2674 TRACE("(%04X)\n", hWaveIn);
2676 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2677 return MMSYSERR_INVALHANDLE;
2679 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
2680 MMDRV_Free(hWaveIn, wmld);
2684 /**************************************************************************
2685 * waveInPrepareHeader [WINMM.@]
2687 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2692 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2694 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2695 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2696 return MMSYSERR_INVALHANDLE;
2698 lpWaveInHdr->dwBytesRecorded = 0;
2700 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
2703 /**************************************************************************
2704 * waveInUnprepareHeader [WINMM.@]
2706 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2711 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2713 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2714 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
2715 return MMSYSERR_NOERROR;
2718 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2719 return MMSYSERR_INVALHANDLE;
2721 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
2724 /**************************************************************************
2725 * waveInAddBuffer [WINMM.@]
2727 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
2728 WAVEHDR* lpWaveInHdr, UINT uSize)
2732 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2734 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2735 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2736 return MMSYSERR_INVALHANDLE;
2738 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE);
2741 /**************************************************************************
2742 * waveInReset [WINMM.@]
2744 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
2748 TRACE("(%04X);\n", hWaveIn);
2750 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2751 return MMSYSERR_INVALHANDLE;
2753 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
2756 /**************************************************************************
2757 * waveInStart [WINMM.@]
2759 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
2763 TRACE("(%04X);\n", hWaveIn);
2765 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2766 return MMSYSERR_INVALHANDLE;
2768 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
2771 /**************************************************************************
2772 * waveInStop [WINMM.@]
2774 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
2778 TRACE("(%04X);\n", hWaveIn);
2780 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2781 return MMSYSERR_INVALHANDLE;
2783 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
2786 /**************************************************************************
2787 * waveInGetPosition [WINMM.@]
2789 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
2794 TRACE("(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
2796 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2797 return MMSYSERR_INVALHANDLE;
2799 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE);
2802 /**************************************************************************
2803 * waveInGetID [WINMM.@]
2805 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
2809 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
2811 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2813 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2814 return MMSYSERR_INVALHANDLE;
2816 *lpuDeviceID = wmld->uDeviceID;
2817 return MMSYSERR_NOERROR;
2820 /**************************************************************************
2821 * waveInMessage [WINMM.@]
2823 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
2824 DWORD dwParam1, DWORD dwParam2)
2828 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
2831 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
2832 return MMSYSERR_INVALPARAM;
2834 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2835 return MMSYSERR_INVALHANDLE;
2837 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);