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 static LPWINE_MM_IDATA S_IData = NULL;
77 /**************************************************************************
78 * MULTIMEDIA_GetIData [internal]
80 LPWINE_MM_IDATA MULTIMEDIA_GetIData(void)
83 ERR("IData not found for pid=%08lx. Suicide !!!\n", GetCurrentProcessId());
90 /**************************************************************************
91 * MULTIMEDIA_CreateIData [internal]
93 static BOOL MULTIMEDIA_CreateIData(HINSTANCE hInstDLL)
95 S_IData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA));
99 S_IData->hWinMM32Instance = hInstDLL;
100 InitializeCriticalSection(&S_IData->cs);
101 S_IData->cs.DebugInfo = (void*)__FILE__ ": WinMM";
102 S_IData->psStopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
103 S_IData->psLastEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
104 TRACE("Created IData (%p)\n", S_IData);
108 /**************************************************************************
109 * MULTIMEDIA_DeleteIData [internal]
111 static void MULTIMEDIA_DeleteIData(void)
116 /* FIXME: should also free content and resources allocated
118 CloseHandle(S_IData->psStopEvent);
119 CloseHandle(S_IData->psLastEvent);
120 DeleteCriticalSection(&S_IData->cs);
121 HeapFree(GetProcessHeap(), 0, S_IData);
126 /**************************************************************************
127 * DllEntryPoint (WINMM.init)
129 * WINMM DLL entry point
132 BOOL WINAPI WINMM_LibMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
134 TRACE("0x%x 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
137 case DLL_PROCESS_ATTACH:
138 if (!MULTIMEDIA_CreateIData(hInstDLL))
140 if (!MULTIMEDIA_MciInit() || !MMDRV_Init()) {
141 MULTIMEDIA_DeleteIData();
145 case DLL_PROCESS_DETACH:
146 MULTIMEDIA_DeleteIData();
148 case DLL_THREAD_ATTACH:
149 case DLL_THREAD_DETACH:
155 /**************************************************************************
156 * Mixer devices. New to Win95
159 /**************************************************************************
160 * find out the real mixer ID depending on hmix (depends on dwFlags)
162 static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags)
164 LPWINE_MIXER lpwm = NULL;
166 switch (dwFlags & 0xF0000000ul) {
167 case MIXER_OBJECTF_MIXER:
168 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
170 case MIXER_OBJECTF_HMIXER:
171 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
173 case MIXER_OBJECTF_WAVEOUT:
174 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
176 case MIXER_OBJECTF_HWAVEOUT:
177 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
179 case MIXER_OBJECTF_WAVEIN:
180 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
182 case MIXER_OBJECTF_HWAVEIN:
183 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
185 case MIXER_OBJECTF_MIDIOUT:
186 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
188 case MIXER_OBJECTF_HMIDIOUT:
189 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
191 case MIXER_OBJECTF_MIDIIN:
192 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
194 case MIXER_OBJECTF_HMIDIIN:
195 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
197 case MIXER_OBJECTF_AUX:
198 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
201 FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
207 /**************************************************************************
208 * mixerGetNumDevs [WINMM.@]
210 UINT WINAPI mixerGetNumDevs(void)
212 return MMDRV_GetNum(MMDRV_MIXER);
215 /**************************************************************************
216 * mixerGetDevCapsA [WINMM.@]
218 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size)
222 if ((wmld = MMDRV_Get(devid, MMDRV_MIXER, TRUE)) == NULL)
223 return MMSYSERR_BADDEVICEID;
225 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD)mixcaps, size, TRUE);
228 /**************************************************************************
229 * mixerGetDevCapsW [WINMM.@]
231 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size)
234 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
236 if (ret == MMSYSERR_NOERROR) {
237 mixcaps->wMid = micA.wMid;
238 mixcaps->wPid = micA.wPid;
239 mixcaps->vDriverVersion = micA.vDriverVersion;
240 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, mixcaps->szPname,
241 sizeof(mixcaps->szPname)/sizeof(WCHAR) );
242 mixcaps->fdwSupport = micA.fdwSupport;
243 mixcaps->cDestinations = micA.cDestinations;
248 UINT MMSYSTEM_mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
249 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
256 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
257 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
259 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
260 &dwCallback, &dwInstance, bFrom32);
262 wmld->uDeviceID = uDeviceID;
263 mod.hmx = (HMIXEROBJ)hMix;
264 mod.dwCallback = dwCallback;
265 mod.dwInstance = dwInstance;
267 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
269 if (dwRet != MMSYSERR_NOERROR) {
270 MMDRV_Free(hMix, wmld);
273 if (lphMix) *lphMix = hMix;
274 TRACE("=> %ld hMixer=%04x\n", dwRet, hMix);
279 /**************************************************************************
280 * mixerOpen [WINMM.@]
282 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
283 DWORD dwInstance, DWORD fdwOpen)
285 return MMSYSTEM_mixerOpen(lphMix, uDeviceID,
286 dwCallback, dwInstance, fdwOpen, TRUE);
289 /**************************************************************************
290 * mixerClose [WINMM.@]
292 UINT WINAPI mixerClose(HMIXER hMix)
297 TRACE("(%04x)\n", hMix);
299 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
301 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
302 MMDRV_Free(hMix, wmld);
307 /**************************************************************************
308 * mixerGetID [WINMM.@]
310 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
314 TRACE("(%04x %p %08lx)\n", hmix, lpid, fdwID);
316 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
317 return MMSYSERR_INVALHANDLE;
321 *lpid = lpwm->mld.uDeviceID;
323 return MMSYSERR_NOERROR;
326 /**************************************************************************
327 * mixerGetControlDetailsA [WINMM.@]
329 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
334 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
336 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
337 return MMSYSERR_INVALHANDLE;
339 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
340 return MMSYSERR_INVALPARAM;
342 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD)lpmcdA,
346 /**************************************************************************
347 * mixerGetControlDetailsW [WINMM.@]
349 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
351 DWORD ret = MMSYSERR_NOTENABLED;
353 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
355 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
356 return MMSYSERR_INVALPARAM;
358 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
359 case MIXER_GETCONTROLDETAILSF_VALUE:
360 /* can savely use W structure as it is, no string inside */
361 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
363 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
365 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
366 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
367 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
370 if (lpmcd->u.cMultipleItems != 0) {
371 size *= lpmcd->u.cMultipleItems;
373 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
374 lpmcd->paDetails = pDetailsA;
375 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
376 /* set up lpmcd->paDetails */
377 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
378 /* copy from lpmcd->paDetails back to paDetailsW; */
379 if(ret == MMSYSERR_NOERROR) {
380 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
381 pDetailsW->dwParam1 = pDetailsA->dwParam1;
382 pDetailsW->dwParam2 = pDetailsA->dwParam2;
383 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
385 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
389 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
390 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
392 HeapFree(GetProcessHeap(), 0, pDetailsA);
393 lpmcd->paDetails = pDetailsW;
394 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
398 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
404 /**************************************************************************
405 * mixerGetLineControlsA [WINMM.@]
407 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
412 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
414 if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
415 return MMSYSERR_INVALHANDLE;
417 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
418 return MMSYSERR_INVALPARAM;
420 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD)lpmlcA,
424 /**************************************************************************
425 * mixerGetLineControlsW [WINMM.@]
427 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
430 MIXERLINECONTROLSA mlcA;
434 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
436 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
437 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
438 return MMSYSERR_INVALPARAM;
440 mlcA.cbStruct = sizeof(mlcA);
441 mlcA.dwLineID = lpmlcW->dwLineID;
442 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
443 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
444 mlcA.cControls = lpmlcW->cControls;
445 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
446 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
447 mlcA.cControls * mlcA.cbmxctrl);
449 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
451 if (ret == MMSYSERR_NOERROR) {
452 lpmlcW->dwLineID = mlcA.dwLineID;
453 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
454 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
455 lpmlcW->cControls = mlcA.cControls;
457 for (i = 0; i < mlcA.cControls; i++) {
458 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
459 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
460 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
461 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
462 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
463 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
464 lpmlcW->pamxctrl[i].szShortName,
465 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
466 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
467 lpmlcW->pamxctrl[i].szName,
468 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
469 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
470 * sizeof(mlcA.pamxctrl[i].Bounds) */
471 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
472 sizeof(mlcA.pamxctrl[i].Bounds));
473 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
474 * sizeof(mlcA.pamxctrl[i].Metrics) */
475 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
476 sizeof(mlcA.pamxctrl[i].Metrics));
480 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
485 /**************************************************************************
486 * mixerGetLineInfoA [WINMM.@]
488 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
492 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
494 if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
495 return MMSYSERR_INVALHANDLE;
497 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD)lpmliW,
501 /**************************************************************************
502 * mixerGetLineInfoW [WINMM.@]
504 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
510 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
512 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
513 return MMSYSERR_INVALPARAM;
515 mliA.cbStruct = sizeof(mliA);
516 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
517 case MIXER_GETLINEINFOF_COMPONENTTYPE:
518 mliA.dwComponentType = lpmliW->dwComponentType;
520 case MIXER_GETLINEINFOF_DESTINATION:
521 mliA.dwDestination = lpmliW->dwDestination;
523 case MIXER_GETLINEINFOF_LINEID:
524 mliA.dwLineID = lpmliW->dwLineID;
526 case MIXER_GETLINEINFOF_SOURCE:
527 mliA.dwDestination = lpmliW->dwDestination;
528 mliA.dwSource = lpmliW->dwSource;
530 case MIXER_GETLINEINFOF_TARGETTYPE:
531 mliA.Target.dwType = lpmliW->Target.dwType;
532 mliA.Target.wMid = lpmliW->Target.wMid;
533 mliA.Target.wPid = lpmliW->Target.wPid;
534 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
535 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
538 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
541 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
543 lpmliW->dwDestination = mliA.dwDestination;
544 lpmliW->dwSource = mliA.dwSource;
545 lpmliW->dwLineID = mliA.dwLineID;
546 lpmliW->fdwLine = mliA.fdwLine;
547 lpmliW->dwUser = mliA.dwUser;
548 lpmliW->dwComponentType = mliA.dwComponentType;
549 lpmliW->cChannels = mliA.cChannels;
550 lpmliW->cConnections = mliA.cConnections;
551 lpmliW->cControls = mliA.cControls;
552 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
553 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
554 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
555 sizeof(lpmliW->szName)/sizeof(WCHAR) );
556 lpmliW->Target.dwType = mliA.Target.dwType;
557 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
558 lpmliW->Target.wMid = mliA.Target.wMid;
559 lpmliW->Target.wPid = mliA.Target.wPid;
560 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
561 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
562 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
567 /**************************************************************************
568 * mixerSetControlDetails [WINMM.@]
570 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
575 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
577 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
578 return MMSYSERR_INVALHANDLE;
580 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD)lpmcdA,
584 /**************************************************************************
585 * mixerMessage [WINMM.@]
587 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
591 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
592 (DWORD)hmix, uMsg, dwParam1, dwParam2);
594 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
595 return MMSYSERR_INVALHANDLE;
597 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
600 /**************************************************************************
601 * auxGetNumDevs [WINMM.@]
603 UINT WINAPI auxGetNumDevs(void)
605 return MMDRV_GetNum(MMDRV_AUX);
608 /**************************************************************************
609 * auxGetDevCapsW [WINMM.@]
611 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
614 UINT ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
616 lpCaps->wMid = acA.wMid;
617 lpCaps->wPid = acA.wPid;
618 lpCaps->vDriverVersion = acA.vDriverVersion;
619 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, lpCaps->szPname,
620 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
621 lpCaps->wTechnology = acA.wTechnology;
622 lpCaps->dwSupport = acA.dwSupport;
626 /**************************************************************************
627 * auxGetDevCapsA [WINMM.@]
629 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
633 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
635 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
636 return MMSYSERR_INVALHANDLE;
637 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
640 /**************************************************************************
641 * auxGetVolume [WINMM.@]
643 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
647 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
649 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
650 return MMSYSERR_INVALHANDLE;
651 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
654 /**************************************************************************
655 * auxSetVolume [WINMM.@]
657 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
661 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
663 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
664 return MMSYSERR_INVALHANDLE;
665 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
668 /**************************************************************************
669 * auxOutMessage [WINMM.@]
671 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
675 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
676 return MMSYSERR_INVALHANDLE;
678 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
681 /**************************************************************************
682 * mciGetErrorStringW [WINMM.@]
684 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
686 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
687 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
689 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
690 HeapFree(GetProcessHeap(), 0, bufstr);
694 /**************************************************************************
695 * mciGetErrorStringA [WINMM.@]
697 BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength)
701 if (lpstrBuffer != NULL && uLength > 0 &&
702 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
704 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
705 dwError, lpstrBuffer, uLength) > 0) {
712 /**************************************************************************
713 * mciDriverNotify [WINMM.@]
715 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
718 TRACE("(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
720 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
723 /**************************************************************************
724 * mciGetDriverData [WINMM.@]
726 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
728 LPWINE_MCIDRIVER wmd;
730 TRACE("(%04x)\n", uDeviceID);
732 wmd = MCI_GetDriver(uDeviceID);
735 WARN("Bad uDeviceID\n");
739 return wmd->dwPrivate;
742 /**************************************************************************
743 * mciSetDriverData [WINMM.@]
745 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
747 LPWINE_MCIDRIVER wmd;
749 TRACE("(%04x, %08lx)\n", uDeviceID, data);
751 wmd = MCI_GetDriver(uDeviceID);
754 WARN("Bad uDeviceID\n");
758 wmd->dwPrivate = data;
762 /**************************************************************************
763 * mciSendCommandA [WINMM.@]
765 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
769 TRACE("(%08x, %s, %08lx, %08lx)\n",
770 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
772 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
773 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
774 TRACE("=> %08lx\n", dwRet);
778 /**************************************************************************
779 * mciSendCommandW [WINMM.@]
781 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
783 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
784 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
785 return MCIERR_UNSUPPORTED_FUNCTION;
788 /**************************************************************************
789 * mciGetDeviceIDA [WINMM.@]
791 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
793 return MCI_GetDriverFromString(lpstrName);
796 /**************************************************************************
797 * mciGetDeviceIDW [WINMM.@]
799 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
804 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
805 ret = MCI_GetDriverFromString(lpstrName);
806 HeapFree(GetProcessHeap(), 0, lpstrName);
810 /**************************************************************************
811 * MCI_DefYieldProc [internal]
813 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
817 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
819 if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
820 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
826 msg.hwnd = HWND_32(HIWORD(data));
827 while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
833 /**************************************************************************
834 * mciSetYieldProc [WINMM.@]
836 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
838 LPWINE_MCIDRIVER wmd;
840 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
842 if (!(wmd = MCI_GetDriver(uDeviceID))) {
843 WARN("Bad uDeviceID\n");
847 wmd->lpfnYieldProc = fpYieldProc;
848 wmd->dwYieldData = dwYieldData;
854 /**************************************************************************
855 * mciGetDeviceIDFromElementIDW [WINMM.@]
857 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
859 /* FIXME: that's rather strange, there is no
860 * mciGetDeviceIDFromElementID32A in winmm.spec
862 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
866 /**************************************************************************
867 * mciGetYieldProc [WINMM.@]
869 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
871 LPWINE_MCIDRIVER wmd;
873 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
875 if (!(wmd = MCI_GetDriver(uDeviceID))) {
876 WARN("Bad uDeviceID\n");
879 if (!wmd->lpfnYieldProc) {
880 WARN("No proc set\n");
884 WARN("Proc is 32 bit\n");
887 return wmd->lpfnYieldProc;
890 /**************************************************************************
891 * mciGetCreatorTask [WINMM.@]
893 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
895 LPWINE_MCIDRIVER wmd;
898 if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
900 TRACE("(%u) => %08x\n", uDeviceID, ret);
904 /**************************************************************************
905 * mciDriverYield [WINMM.@]
907 UINT WINAPI mciDriverYield(UINT uDeviceID)
909 LPWINE_MCIDRIVER wmd;
912 TRACE("(%04x)\n", uDeviceID);
914 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
917 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
923 /**************************************************************************
924 * midiOutGetNumDevs [WINMM.@]
926 UINT WINAPI midiOutGetNumDevs(void)
928 return MMDRV_GetNum(MMDRV_MIDIOUT);
931 /**************************************************************************
932 * midiOutGetDevCapsW [WINMM.@]
934 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps,
940 ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
941 lpCaps->wMid = mocA.wMid;
942 lpCaps->wPid = mocA.wPid;
943 lpCaps->vDriverVersion = mocA.vDriverVersion;
944 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, lpCaps->szPname,
945 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
946 lpCaps->wTechnology = mocA.wTechnology;
947 lpCaps->wVoices = mocA.wVoices;
948 lpCaps->wNotes = mocA.wNotes;
949 lpCaps->wChannelMask = mocA.wChannelMask;
950 lpCaps->dwSupport = mocA.dwSupport;
954 /**************************************************************************
955 * midiOutGetDevCapsA [WINMM.@]
957 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
962 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
964 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
966 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
967 return MMSYSERR_INVALHANDLE;
969 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
972 /**************************************************************************
973 * MIDI_GetErrorText [internal]
975 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
977 UINT16 ret = MMSYSERR_BADERRNUM;
979 if (lpText == NULL) {
980 ret = MMSYSERR_INVALPARAM;
981 } else if (uSize == 0) {
982 ret = MMSYSERR_NOERROR;
984 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
985 * a warning for the test was always true */
986 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
987 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
989 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
990 uError, lpText, uSize) > 0) {
991 ret = MMSYSERR_NOERROR;
997 /**************************************************************************
998 * midiOutGetErrorTextA [WINMM.@]
1000 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1002 return MIDI_GetErrorText(uError, lpText, uSize);
1005 /**************************************************************************
1006 * midiOutGetErrorTextW [WINMM.@]
1008 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1010 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1013 ret = MIDI_GetErrorText(uError, xstr, uSize);
1014 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1015 HeapFree(GetProcessHeap(), 0, xstr);
1019 /**************************************************************************
1020 * MIDI_OutAlloc [internal]
1022 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
1023 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
1024 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
1030 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
1032 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
1033 lpdwCallback, lpdwInstance, bFrom32);
1035 if (lphMidiOut != NULL)
1036 *lphMidiOut = hMidiOut;
1039 lpwm->mod.hMidi = (HMIDI) hMidiOut;
1040 lpwm->mod.dwCallback = *lpdwCallback;
1041 lpwm->mod.dwInstance = *lpdwInstance;
1042 lpwm->mod.dnDevNode = 0;
1043 lpwm->mod.cIds = cIDs;
1045 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
1050 UINT MMSYSTEM_midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
1051 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1057 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1058 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
1060 if (lphMidiOut != NULL) *lphMidiOut = 0;
1062 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
1066 return MMSYSERR_NOMEM;
1068 lpwm->mld.uDeviceID = uDeviceID;
1070 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod,
1073 if (dwRet != MMSYSERR_NOERROR) {
1074 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
1078 if (lphMidiOut) *lphMidiOut = hMidiOut;
1079 TRACE("=> %d hMidi=%04x\n", dwRet, hMidiOut);
1084 /**************************************************************************
1085 * midiOutOpen [WINMM.@]
1087 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
1088 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1090 return MMSYSTEM_midiOutOpen(lphMidiOut, uDeviceID, dwCallback,
1091 dwInstance, dwFlags, TRUE);
1094 /**************************************************************************
1095 * midiOutClose [WINMM.@]
1097 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
1102 TRACE("(%04X)\n", hMidiOut);
1104 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1105 return MMSYSERR_INVALHANDLE;
1107 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
1108 MMDRV_Free(hMidiOut, wmld);
1113 /**************************************************************************
1114 * midiOutPrepareHeader [WINMM.@]
1116 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
1117 MIDIHDR* lpMidiOutHdr, UINT uSize)
1121 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1123 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1124 return MMSYSERR_INVALHANDLE;
1126 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
1129 /**************************************************************************
1130 * midiOutUnprepareHeader [WINMM.@]
1132 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
1133 MIDIHDR* lpMidiOutHdr, UINT uSize)
1137 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1139 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
1140 return MMSYSERR_NOERROR;
1143 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1144 return MMSYSERR_INVALHANDLE;
1146 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
1149 /**************************************************************************
1150 * midiOutShortMsg [WINMM.@]
1152 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
1156 TRACE("(%04X, %08lX)\n", hMidiOut, dwMsg);
1158 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1159 return MMSYSERR_INVALHANDLE;
1161 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, FALSE);
1164 /**************************************************************************
1165 * midiOutLongMsg [WINMM.@]
1167 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
1168 MIDIHDR* lpMidiOutHdr, UINT uSize)
1172 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1174 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1175 return MMSYSERR_INVALHANDLE;
1177 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE);
1180 /**************************************************************************
1181 * midiOutReset [WINMM.@]
1183 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
1187 TRACE("(%04X)\n", hMidiOut);
1189 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1190 return MMSYSERR_INVALHANDLE;
1192 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
1195 /**************************************************************************
1196 * midiOutGetVolume [WINMM.@]
1198 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
1202 TRACE("(%04X, %p);\n", uDeviceID, lpdwVolume);
1204 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
1205 return MMSYSERR_INVALHANDLE;
1207 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1210 /**************************************************************************
1211 * midiOutSetVolume [WINMM.@]
1213 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
1217 TRACE("(%04X, %ld);\n", uDeviceID, dwVolume);
1219 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
1220 return MMSYSERR_INVALHANDLE;
1222 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
1225 /**************************************************************************
1226 * midiOutCachePatches [WINMM.@]
1228 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
1229 WORD* lpwPatchArray, UINT uFlags)
1231 /* not really necessary to support this */
1232 FIXME("not supported yet\n");
1233 return MMSYSERR_NOTSUPPORTED;
1236 /**************************************************************************
1237 * midiOutCacheDrumPatches [WINMM.@]
1239 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
1240 WORD* lpwKeyArray, UINT uFlags)
1242 FIXME("not supported yet\n");
1243 return MMSYSERR_NOTSUPPORTED;
1246 /**************************************************************************
1247 * midiOutGetID [WINMM.@]
1249 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
1253 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
1255 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1256 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1257 return MMSYSERR_INVALHANDLE;
1259 *lpuDeviceID = wmld->uDeviceID;
1260 return MMSYSERR_NOERROR;
1263 /**************************************************************************
1264 * midiOutMessage [WINMM.@]
1266 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
1267 DWORD dwParam1, DWORD dwParam2)
1271 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
1273 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
1275 if (uMessage == 0x0001) {
1276 *(LPDWORD)dwParam1 = 1;
1279 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
1280 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
1282 return MMSYSERR_INVALHANDLE;
1288 FIXME("can't handle OPEN or CLOSE message!\n");
1289 return MMSYSERR_NOTSUPPORTED;
1291 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1294 /**************************************************************************
1295 * midiInGetNumDevs [WINMM.@]
1297 UINT WINAPI midiInGetNumDevs(void)
1299 return MMDRV_GetNum(MMDRV_MIDIIN);
1302 /**************************************************************************
1303 * midiInGetDevCapsW [WINMM.@]
1305 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
1308 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
1310 if (ret == MMSYSERR_NOERROR) {
1311 lpCaps->wMid = micA.wMid;
1312 lpCaps->wPid = micA.wPid;
1313 lpCaps->vDriverVersion = micA.vDriverVersion;
1314 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, lpCaps->szPname,
1315 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
1316 lpCaps->dwSupport = micA.dwSupport;
1321 /**************************************************************************
1322 * midiInGetDevCapsA [WINMM.@]
1324 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
1328 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
1330 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
1331 return MMSYSERR_INVALHANDLE;
1333 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1336 /**************************************************************************
1337 * midiInGetErrorTextW [WINMM.@]
1339 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1341 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1342 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
1344 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1345 HeapFree(GetProcessHeap(), 0, xstr);
1349 /**************************************************************************
1350 * midiInGetErrorTextA [WINMM.@]
1352 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1354 return MIDI_GetErrorText(uError, lpText, uSize);
1357 UINT MMSYSTEM_midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
1358 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1364 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1365 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
1367 if (lphMidiIn != NULL) *lphMidiIn = 0;
1369 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
1370 &dwFlags, &dwCallback, &dwInstance, bFrom32);
1373 return MMSYSERR_NOMEM;
1375 lpwm->mod.hMidi = (HMIDI) hMidiIn;
1376 lpwm->mod.dwCallback = dwCallback;
1377 lpwm->mod.dwInstance = dwInstance;
1379 lpwm->mld.uDeviceID = uDeviceID;
1380 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1382 if (dwRet != MMSYSERR_NOERROR) {
1383 MMDRV_Free(hMidiIn, &lpwm->mld);
1386 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
1387 TRACE("=> %ld hMidi=%04x\n", dwRet, hMidiIn);
1392 /**************************************************************************
1393 * midiInOpen [WINMM.@]
1395 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
1396 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1398 return MMSYSTEM_midiInOpen(lphMidiIn, uDeviceID, dwCallback,
1399 dwInstance, dwFlags, TRUE);
1402 /**************************************************************************
1403 * midiInClose [WINMM.@]
1405 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
1410 TRACE("(%04X)\n", hMidiIn);
1412 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1413 return MMSYSERR_INVALHANDLE;
1415 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
1416 MMDRV_Free(hMidiIn, wmld);
1420 /**************************************************************************
1421 * midiInPrepareHeader [WINMM.@]
1423 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
1424 MIDIHDR* lpMidiInHdr, UINT uSize)
1428 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1430 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1431 return MMSYSERR_INVALHANDLE;
1433 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
1436 /**************************************************************************
1437 * midiInUnprepareHeader [WINMM.@]
1439 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
1440 MIDIHDR* lpMidiInHdr, UINT uSize)
1444 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1446 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
1447 return MMSYSERR_NOERROR;
1450 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1451 return MMSYSERR_INVALHANDLE;
1453 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
1456 /**************************************************************************
1457 * midiInAddBuffer [WINMM.@]
1459 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
1460 MIDIHDR* lpMidiInHdr, UINT uSize)
1464 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1466 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1467 return MMSYSERR_INVALHANDLE;
1469 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE);
1472 /**************************************************************************
1473 * midiInStart [WINMM.@]
1475 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
1479 TRACE("(%04X)\n", hMidiIn);
1481 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1482 return MMSYSERR_INVALHANDLE;
1484 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
1487 /**************************************************************************
1488 * midiInStop [WINMM.@]
1490 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
1494 TRACE("(%04X)\n", hMidiIn);
1496 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1497 return MMSYSERR_INVALHANDLE;
1499 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
1502 /**************************************************************************
1503 * midiInReset [WINMM.@]
1505 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
1509 TRACE("(%04X)\n", hMidiIn);
1511 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1512 return MMSYSERR_INVALHANDLE;
1514 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
1517 /**************************************************************************
1518 * midiInGetID [WINMM.@]
1520 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
1524 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
1526 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1528 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
1529 return MMSYSERR_INVALHANDLE;
1531 *lpuDeviceID = wmld->uDeviceID;
1533 return MMSYSERR_NOERROR;
1536 /**************************************************************************
1537 * midiInMessage [WINMM.@]
1539 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
1540 DWORD dwParam1, DWORD dwParam2)
1544 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
1546 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1547 return MMSYSERR_INVALHANDLE;
1552 FIXME("can't handle OPEN or CLOSE message!\n");
1553 return MMSYSERR_NOTSUPPORTED;
1555 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1558 typedef struct WINE_MIDIStream {
1569 LPMIDIHDR lpMidiHdr;
1572 #define WINE_MSM_HEADER (WM_USER+0)
1573 #define WINE_MSM_STOP (WM_USER+1)
1575 /**************************************************************************
1576 * MMSYSTEM_GetMidiStream [internal]
1578 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
1580 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
1589 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
1591 return *lpMidiStrm != NULL;
1594 /**************************************************************************
1595 * MMSYSTEM_MidiStream_Convert [internal]
1597 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
1601 if (lpMidiStrm->dwTimeDiv == 0) {
1602 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1603 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
1604 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
1605 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
1606 ret = (pulse * 1000) / (nf * nsf);
1608 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
1609 (double)lpMidiStrm->dwTimeDiv);
1615 /**************************************************************************
1616 * MMSYSTEM_MidiStream_MessageHandler [internal]
1618 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
1620 LPMIDIHDR lpMidiHdr;
1624 switch (msg->message) {
1626 SetEvent(lpMidiStrm->hEvent);
1630 /* this is not quite what MS doc says... */
1631 midiOutReset(lpMidiStrm->hDevice);
1632 /* empty list of already submitted buffers */
1633 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
1634 lpMidiHdr->dwFlags |= MHDR_DONE;
1635 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1637 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1638 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1639 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1641 lpMidiStrm->lpMidiHdr = 0;
1642 SetEvent(lpMidiStrm->hEvent);
1644 case WINE_MSM_HEADER:
1645 /* sets initial tick count for first MIDIHDR */
1646 if (!lpMidiStrm->dwStartTicks)
1647 lpMidiStrm->dwStartTicks = GetTickCount();
1649 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1650 * by native mcimidi, it doesn't look like a correct one".
1651 * this trick allows to throw it away... but I don't like it.
1652 * It looks like part of the file I'm trying to play and definitively looks
1653 * like raw midi content
1654 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1655 * synchronization issue where native mcimidi is still processing raw MIDI
1656 * content before generating MIDIEVENTs ?
1658 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1659 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1660 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1661 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1662 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1663 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1664 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1665 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1666 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1667 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1668 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1669 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1670 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1671 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1672 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1673 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1674 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1676 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1677 lpData = lpMidiHdr->lpData;
1678 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1679 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
1680 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
1681 lpMidiHdr->dwFlags, msg->wParam);
1683 /* dumps content of lpMidiHdr->lpData
1684 * FIXME: there should be a debug routine somewhere that already does this
1685 * I hate spreading this type of shit all around the code
1687 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
1691 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
1692 printf("%02x ", lpData[dwToGo + i]);
1695 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
1696 ch = lpData[dwToGo + i];
1697 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
1702 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
1703 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
1704 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
1705 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
1706 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
1707 ((LPMIDIEVENT)lpData)->dwStreamID);
1708 lpMidiHdr->dwFlags |= MHDR_DONE;
1709 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1711 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1712 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1713 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1717 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
1719 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1720 lpMidiHdr->lpNext = 0;
1721 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
1722 lpMidiHdr->dwFlags &= MHDR_DONE;
1723 lpMidiHdr->dwOffset = 0;
1727 FIXME("Unknown message %d\n", msg->message);
1733 /**************************************************************************
1734 * MMSYSTEM_MidiStream_Player [internal]
1736 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
1738 WINE_MIDIStream* lpMidiStrm = pmt;
1743 LPMIDIHDR lpMidiHdr;
1747 TRACE("(%p)!\n", lpMidiStrm);
1750 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
1753 /* force thread's queue creation */
1754 /* Used to be InitThreadInput16(0, 5); */
1755 /* but following works also with hack in midiStreamOpen */
1756 PeekMessageA(&msg, 0, 0, 0, 0);
1758 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
1759 SetEvent(lpMidiStrm->hEvent);
1760 TRACE("Ready to go 1\n");
1761 /* thread is started in paused mode */
1762 SuspendThread(lpMidiStrm->hThread);
1763 TRACE("Ready to go 2\n");
1765 lpMidiStrm->dwStartTicks = 0;
1766 lpMidiStrm->dwPulses = 0;
1768 lpMidiStrm->lpMidiHdr = 0;
1771 lpMidiHdr = lpMidiStrm->lpMidiHdr;
1773 /* for first message, block until one arrives, then process all that are available */
1774 GetMessageA(&msg, 0, 0, 0);
1776 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1778 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
1784 lpData = lpMidiHdr->lpData;
1786 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
1788 /* do we have to wait ? */
1789 if (me->dwDeltaTime) {
1790 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
1791 lpMidiStrm->dwPulses += me->dwDeltaTime;
1793 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
1795 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
1796 while ((dwCurrTC = GetTickCount()) < dwToGo) {
1797 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
1798 /* got a message, handle it */
1799 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
1800 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1805 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
1810 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
1812 FIXME("NIY: MEVT_COMMENT\n");
1813 /* do nothing, skip bytes */
1816 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
1821 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
1824 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
1829 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
1832 if (me->dwEvent & MEVT_F_CALLBACK) {
1833 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1834 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
1835 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
1837 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
1838 if (me->dwEvent & MEVT_F_LONG)
1839 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
1840 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
1841 /* done with this header */
1842 lpMidiHdr->dwFlags |= MHDR_DONE;
1843 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1845 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
1846 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1847 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1848 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1853 TRACE("End of thread\n");
1855 return 0; /* for removing the warning, never executed */
1858 /**************************************************************************
1859 * MMSYSTEM_MidiStream_PostMessage [internal]
1861 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
1863 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
1866 ReleaseThunkLock(&count);
1867 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1868 RestoreThunkLock(count);
1870 WARN("bad PostThreadMessageA\n");
1876 /**************************************************************************
1877 * midiStreamClose [WINMM.@]
1879 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
1881 WINE_MIDIStream* lpMidiStrm;
1883 TRACE("(%08x)!\n", hMidiStrm);
1885 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
1886 return MMSYSERR_INVALHANDLE;
1888 midiStreamStop(hMidiStrm);
1889 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
1890 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
1891 CloseHandle(lpMidiStrm->hEvent);
1893 return midiOutClose((HMIDIOUT)hMidiStrm);
1896 /**************************************************************************
1897 * MMSYSTEM_MidiStream_Open [internal]
1899 MMRESULT MMSYSTEM_MidiStream_Open(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
1900 DWORD cMidi, DWORD dwCallback,
1901 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
1903 WINE_MIDIStream* lpMidiStrm;
1905 MIDIOPENSTRMID mosm;
1909 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
1910 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
1912 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
1913 return MMSYSERR_INVALPARAM;
1915 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
1917 return MMSYSERR_NOMEM;
1919 lpMidiStrm->dwTempo = 500000;
1920 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
1921 lpMidiStrm->dwPositionMS = 0;
1923 mosm.dwStreamID = (DWORD)lpMidiStrm;
1924 /* FIXME: the correct value is not allocated yet for MAPPER */
1925 mosm.wDeviceID = *lpuDeviceID;
1926 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
1927 lpMidiStrm->hDevice = hMidiOut;
1929 *lphMidiStrm = (HMIDISTRM)hMidiOut;
1931 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
1932 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID);
1933 lpwm->mld.uDeviceID = *lpuDeviceID = 0;
1935 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
1936 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1937 lpMidiStrm->wFlags = HIWORD(fdwOpen);
1939 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
1940 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
1942 if (!lpMidiStrm->hThread) {
1943 midiStreamClose((HMIDISTRM)hMidiOut);
1944 return MMSYSERR_NOMEM;
1947 /* wait for thread to have started, and for its queue to be created */
1951 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
1952 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
1953 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
1955 ReleaseThunkLock(&count);
1956 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1957 RestoreThunkLock(count);
1960 TRACE("=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n",
1961 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
1965 /**************************************************************************
1966 * midiStreamOpen [WINMM.@]
1968 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
1969 DWORD cMidi, DWORD dwCallback,
1970 DWORD dwInstance, DWORD fdwOpen)
1972 return MMSYSTEM_MidiStream_Open(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
1973 dwInstance, fdwOpen, TRUE);
1976 /**************************************************************************
1977 * midiStreamOut [WINMM.@]
1979 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
1982 WINE_MIDIStream* lpMidiStrm;
1983 DWORD ret = MMSYSERR_NOERROR;
1985 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
1987 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
1988 ret = MMSYSERR_INVALHANDLE;
1989 } else if (!lpMidiHdr) {
1990 ret = MMSYSERR_INVALPARAM;
1992 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
1993 WINE_MSM_HEADER, cbMidiHdr,
1994 (DWORD)lpMidiHdr)) {
1995 WARN("bad PostThreadMessageA\n");
1996 ret = MMSYSERR_ERROR;
2002 /**************************************************************************
2003 * midiStreamPause [WINMM.@]
2005 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
2007 WINE_MIDIStream* lpMidiStrm;
2008 DWORD ret = MMSYSERR_NOERROR;
2010 TRACE("(%08x)!\n", hMidiStrm);
2012 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2013 ret = MMSYSERR_INVALHANDLE;
2015 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
2016 WARN("bad Suspend (%ld)\n", GetLastError());
2017 ret = MMSYSERR_ERROR;
2023 /**************************************************************************
2024 * midiStreamPosition [WINMM.@]
2026 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
2028 WINE_MIDIStream* lpMidiStrm;
2029 DWORD ret = MMSYSERR_NOERROR;
2031 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
2033 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2034 ret = MMSYSERR_INVALHANDLE;
2035 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
2036 ret = MMSYSERR_INVALPARAM;
2038 switch (lpMMT->wType) {
2040 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
2041 TRACE("=> %ld ms\n", lpMMT->u.ms);
2044 lpMMT->u.ticks = lpMidiStrm->dwPulses;
2045 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
2048 WARN("Unsupported time type %d\n", lpMMT->wType);
2049 lpMMT->wType = TIME_MS;
2050 ret = MMSYSERR_INVALPARAM;
2057 /**************************************************************************
2058 * midiStreamProperty [WINMM.@]
2060 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
2062 WINE_MIDIStream* lpMidiStrm;
2063 MMRESULT ret = MMSYSERR_NOERROR;
2065 TRACE("(%08x, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
2067 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2068 ret = MMSYSERR_INVALHANDLE;
2069 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
2070 ret = MMSYSERR_INVALPARAM;
2071 } else if (dwProperty & MIDIPROP_TEMPO) {
2072 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
2074 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
2075 ret = MMSYSERR_INVALPARAM;
2076 } else if (dwProperty & MIDIPROP_SET) {
2077 lpMidiStrm->dwTempo = mpt->dwTempo;
2078 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
2079 } else if (dwProperty & MIDIPROP_GET) {
2080 mpt->dwTempo = lpMidiStrm->dwTempo;
2081 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
2083 } else if (dwProperty & MIDIPROP_TIMEDIV) {
2084 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
2086 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
2087 ret = MMSYSERR_INVALPARAM;
2088 } else if (dwProperty & MIDIPROP_SET) {
2089 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
2090 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
2091 } else if (dwProperty & MIDIPROP_GET) {
2092 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
2093 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
2096 ret = MMSYSERR_INVALPARAM;
2102 /**************************************************************************
2103 * midiStreamRestart [WINMM.@]
2105 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
2107 WINE_MIDIStream* lpMidiStrm;
2108 MMRESULT ret = MMSYSERR_NOERROR;
2110 TRACE("(%08x)!\n", hMidiStrm);
2112 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2113 ret = MMSYSERR_INVALHANDLE;
2117 /* since we increase the thread suspend count on each midiStreamPause
2118 * there may be a need for several midiStreamResume
2121 ret = ResumeThread(lpMidiStrm->hThread);
2122 } while (ret != 0xFFFFFFFF && ret != 0);
2123 if (ret == 0xFFFFFFFF) {
2124 WARN("bad Resume (%ld)\n", GetLastError());
2125 ret = MMSYSERR_ERROR;
2127 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
2133 /**************************************************************************
2134 * midiStreamStop [WINMM.@]
2136 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
2138 WINE_MIDIStream* lpMidiStrm;
2139 MMRESULT ret = MMSYSERR_NOERROR;
2141 TRACE("(%08x)!\n", hMidiStrm);
2143 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2144 ret = MMSYSERR_INVALHANDLE;
2146 /* in case stream has been paused... FIXME is the current state correct ? */
2147 midiStreamRestart(hMidiStrm);
2148 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
2153 UINT MMSYSTEM_waveOpen(HANDLE* lphndl, UINT uDeviceID, UINT uType,
2154 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2155 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2159 DWORD dwRet = MMSYSERR_NOERROR;
2162 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2163 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
2164 dwInstance, dwFlags, bFrom32?32:16);
2166 if (dwFlags & WAVE_FORMAT_QUERY) TRACE("WAVE_FORMAT_QUERY requested !\n");
2168 if (lpFormat == NULL) return WAVERR_BADFORMAT;
2169 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1))
2170 return MMSYSERR_INVALPARAM;
2172 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
2173 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
2174 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize);
2176 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
2177 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL)
2178 return MMSYSERR_NOMEM;
2181 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
2182 wod.dwCallback = dwCallback;
2183 wod.dwInstance = dwInstance;
2187 if (dwFlags & WAVE_MAPPED) {
2188 wod.uMappedDeviceID = uDeviceID;
2189 uDeviceID = WAVE_MAPPER;
2191 wod.uMappedDeviceID = -1;
2193 wmld->uDeviceID = uDeviceID;
2195 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN,
2196 (DWORD)&wod, dwFlags);
2198 if (dwRet != WAVERR_BADFORMAT ||
2199 (dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) break;
2200 /* if we ask for a format which isn't supported by the physical driver,
2201 * let's try to map it through the wave mapper (except, if we already tried
2202 * or user didn't allow us to use acm codecs)
2204 dwFlags |= WAVE_MAPPED;
2205 /* we shall loop only one */
2208 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
2209 MMDRV_Free(handle, wmld);
2213 if (lphndl != NULL) *lphndl = handle;
2214 TRACE("=> %ld hWave=%04x\n", dwRet, handle);
2219 /**************************************************************************
2220 * waveOutGetNumDevs [WINMM.@]
2222 UINT WINAPI waveOutGetNumDevs(void)
2224 return MMDRV_GetNum(MMDRV_WAVEOUT);
2227 /**************************************************************************
2228 * waveOutGetDevCapsA [WINMM.@]
2230 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
2235 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2237 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2239 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
2240 return MMSYSERR_INVALHANDLE;
2242 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2246 /**************************************************************************
2247 * waveOutGetDevCapsW [WINMM.@]
2249 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
2255 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2257 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
2259 if (ret == MMSYSERR_NOERROR) {
2260 lpCaps->wMid = wocA.wMid;
2261 lpCaps->wPid = wocA.wPid;
2262 lpCaps->vDriverVersion = wocA.vDriverVersion;
2263 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, lpCaps->szPname,
2264 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2265 lpCaps->dwFormats = wocA.dwFormats;
2266 lpCaps->wChannels = wocA.wChannels;
2267 lpCaps->dwSupport = wocA.dwSupport;
2272 /**************************************************************************
2273 * WAVE_GetErrorText [internal]
2275 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2277 UINT16 ret = MMSYSERR_BADERRNUM;
2279 if (lpText == NULL) {
2280 ret = MMSYSERR_INVALPARAM;
2281 } else if (uSize == 0) {
2282 ret = MMSYSERR_NOERROR;
2284 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2285 * a warning for the test was always true */
2286 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
2287 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
2289 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
2290 uError, lpText, uSize) > 0) {
2291 ret = MMSYSERR_NOERROR;
2297 /**************************************************************************
2298 * waveOutGetErrorTextA [WINMM.@]
2300 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2302 return WAVE_GetErrorText(uError, lpText, uSize);
2305 /**************************************************************************
2306 * waveOutGetErrorTextW [WINMM.@]
2308 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2310 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2311 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
2313 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2314 HeapFree(GetProcessHeap(), 0, xstr);
2318 /**************************************************************************
2319 * waveOutOpen [WINMM.@]
2320 * All the args/structs have the same layout as the win16 equivalents
2322 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
2323 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2324 DWORD dwInstance, DWORD dwFlags)
2326 return MMSYSTEM_waveOpen(lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
2327 dwCallback, dwInstance, dwFlags, TRUE);
2330 /**************************************************************************
2331 * waveOutClose [WINMM.@]
2333 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
2338 TRACE("(%04X)\n", hWaveOut);
2340 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2341 return MMSYSERR_INVALHANDLE;
2343 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
2344 MMDRV_Free(hWaveOut, wmld);
2349 /**************************************************************************
2350 * waveOutPrepareHeader [WINMM.@]
2352 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
2353 WAVEHDR* lpWaveOutHdr, UINT uSize)
2357 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2359 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
2361 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2362 return MMSYSERR_INVALHANDLE;
2364 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2367 /**************************************************************************
2368 * waveOutUnprepareHeader [WINMM.@]
2370 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
2371 LPWAVEHDR lpWaveOutHdr, UINT uSize)
2375 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2377 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
2378 return MMSYSERR_NOERROR;
2381 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2382 return MMSYSERR_INVALHANDLE;
2384 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2387 /**************************************************************************
2388 * waveOutWrite [WINMM.@]
2390 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
2395 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2397 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2398 return MMSYSERR_INVALHANDLE;
2400 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2403 /**************************************************************************
2404 * waveOutBreakLoop [WINMM.@]
2406 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
2410 TRACE("(%04X);\n", hWaveOut);
2412 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2413 return MMSYSERR_INVALHANDLE;
2414 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
2417 /**************************************************************************
2418 * waveOutPause [WINMM.@]
2420 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
2424 TRACE("(%04X);\n", hWaveOut);
2426 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2427 return MMSYSERR_INVALHANDLE;
2428 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
2431 /**************************************************************************
2432 * waveOutReset [WINMM.@]
2434 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
2438 TRACE("(%04X);\n", hWaveOut);
2440 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2441 return MMSYSERR_INVALHANDLE;
2442 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
2445 /**************************************************************************
2446 * waveOutRestart [WINMM.@]
2448 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
2452 TRACE("(%04X);\n", hWaveOut);
2454 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2455 return MMSYSERR_INVALHANDLE;
2456 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
2459 /**************************************************************************
2460 * waveOutGetPosition [WINMM.@]
2462 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
2467 TRACE("(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
2469 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2470 return MMSYSERR_INVALHANDLE;
2472 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE);
2475 /**************************************************************************
2476 * waveOutGetPitch [WINMM.@]
2478 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
2482 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
2484 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2485 return MMSYSERR_INVALHANDLE;
2486 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE);
2489 /**************************************************************************
2490 * waveOutSetPitch [WINMM.@]
2492 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
2496 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
2498 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2499 return MMSYSERR_INVALHANDLE;
2500 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
2503 /**************************************************************************
2504 * waveOutGetPlaybackRate [WINMM.@]
2506 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
2510 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
2512 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2513 return MMSYSERR_INVALHANDLE;
2514 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE);
2517 /**************************************************************************
2518 * waveOutSetPlaybackRate [WINMM.@]
2520 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
2524 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
2526 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2527 return MMSYSERR_INVALHANDLE;
2528 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
2531 /**************************************************************************
2532 * waveOutGetVolume [WINMM.@]
2534 UINT WINAPI waveOutGetVolume(UINT devid, LPDWORD lpdw)
2538 TRACE("(%04X, %08lx);\n", devid, (DWORD)lpdw);
2540 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
2541 return MMSYSERR_INVALHANDLE;
2543 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE);
2546 /**************************************************************************
2547 * waveOutSetVolume [WINMM.@]
2549 UINT WINAPI waveOutSetVolume(UINT devid, DWORD dw)
2553 TRACE("(%04X, %08lx);\n", devid, dw);
2555 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
2556 return MMSYSERR_INVALHANDLE;
2558 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
2561 /**************************************************************************
2562 * waveOutGetID [WINMM.@]
2564 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
2568 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
2570 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2572 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2573 return MMSYSERR_INVALHANDLE;
2575 *lpuDeviceID = wmld->uDeviceID;
2579 /**************************************************************************
2580 * waveOutMessage [WINMM.@]
2582 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
2583 DWORD dwParam1, DWORD dwParam2)
2587 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
2589 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
2590 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
2591 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2593 return MMSYSERR_INVALHANDLE;
2597 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
2598 return MMSYSERR_INVALPARAM;
2600 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2603 /**************************************************************************
2604 * waveInGetNumDevs [WINMM.@]
2606 UINT WINAPI waveInGetNumDevs(void)
2608 return MMDRV_GetNum(MMDRV_WAVEIN);
2611 /**************************************************************************
2612 * waveInGetDevCapsW [WINMM.@]
2614 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
2617 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize);
2619 if (ret == MMSYSERR_NOERROR) {
2620 lpCaps->wMid = wicA.wMid;
2621 lpCaps->wPid = wicA.wPid;
2622 lpCaps->vDriverVersion = wicA.vDriverVersion;
2623 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, lpCaps->szPname,
2624 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2625 lpCaps->dwFormats = wicA.dwFormats;
2626 lpCaps->wChannels = wicA.wChannels;
2632 /**************************************************************************
2633 * waveInGetDevCapsA [WINMM.@]
2635 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
2639 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2641 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
2642 return MMSYSERR_INVALHANDLE;
2644 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2647 /**************************************************************************
2648 * waveInGetErrorTextA [WINMM.@]
2650 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2652 return WAVE_GetErrorText(uError, lpText, uSize);
2655 /**************************************************************************
2656 * waveInGetErrorTextW [WINMM.@]
2658 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2660 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
2661 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
2663 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
2664 HeapFree(GetProcessHeap(), 0, txt);
2668 /**************************************************************************
2669 * waveInOpen [WINMM.@]
2671 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
2672 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2673 DWORD dwInstance, DWORD dwFlags)
2675 return MMSYSTEM_waveOpen(lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
2676 dwCallback, dwInstance, dwFlags, TRUE);
2679 /**************************************************************************
2680 * waveInClose [WINMM.@]
2682 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
2687 TRACE("(%04X)\n", hWaveIn);
2689 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2690 return MMSYSERR_INVALHANDLE;
2692 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
2693 MMDRV_Free(hWaveIn, wmld);
2697 /**************************************************************************
2698 * waveInPrepareHeader [WINMM.@]
2700 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2705 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2707 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2708 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2709 return MMSYSERR_INVALHANDLE;
2711 lpWaveInHdr->dwBytesRecorded = 0;
2713 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
2716 /**************************************************************************
2717 * waveInUnprepareHeader [WINMM.@]
2719 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2724 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2726 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2727 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
2728 return MMSYSERR_NOERROR;
2731 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2732 return MMSYSERR_INVALHANDLE;
2734 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
2737 /**************************************************************************
2738 * waveInAddBuffer [WINMM.@]
2740 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
2741 WAVEHDR* lpWaveInHdr, UINT uSize)
2745 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2747 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2748 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2749 return MMSYSERR_INVALHANDLE;
2751 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE);
2754 /**************************************************************************
2755 * waveInReset [WINMM.@]
2757 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
2761 TRACE("(%04X);\n", hWaveIn);
2763 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2764 return MMSYSERR_INVALHANDLE;
2766 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
2769 /**************************************************************************
2770 * waveInStart [WINMM.@]
2772 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
2776 TRACE("(%04X);\n", hWaveIn);
2778 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2779 return MMSYSERR_INVALHANDLE;
2781 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
2784 /**************************************************************************
2785 * waveInStop [WINMM.@]
2787 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
2791 TRACE("(%04X);\n", hWaveIn);
2793 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2794 return MMSYSERR_INVALHANDLE;
2796 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
2799 /**************************************************************************
2800 * waveInGetPosition [WINMM.@]
2802 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
2807 TRACE("(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
2809 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2810 return MMSYSERR_INVALHANDLE;
2812 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE);
2815 /**************************************************************************
2816 * waveInGetID [WINMM.@]
2818 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
2822 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
2824 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2826 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2827 return MMSYSERR_INVALHANDLE;
2829 *lpuDeviceID = wmld->uDeviceID;
2830 return MMSYSERR_NOERROR;
2833 /**************************************************************************
2834 * waveInMessage [WINMM.@]
2836 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
2837 DWORD dwParam1, DWORD dwParam2)
2841 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
2844 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
2845 return MMSYSERR_INVALPARAM;
2847 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2848 return MMSYSERR_INVALHANDLE;
2850 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);