From: Anton Baskanov baskanov@gmail.com
--- dlls/winmm/winmm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/winmm/winmm.c b/dlls/winmm/winmm.c index 73050e0affb..a99c8c4ffe8 100644 --- a/dlls/winmm/winmm.c +++ b/dlls/winmm/winmm.c @@ -1392,7 +1392,7 @@ MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, mosm.wDeviceID = *lpuDeviceID; lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm); if (!lpwm) { - free(lpMidiStrm); + wine_midi_stream_free(lpMidiStrm); return MMSYSERR_NOMEM; } lpMidiStrm->hDevice = hMidiOut; @@ -1404,7 +1404,7 @@ MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD_PTR)&lpwm->mod, CALLBACK_NULL); if (ret != MMSYSERR_NOERROR) { MMDRV_Free(hMidiOut, &lpwm->mld); - free(lpMidiStrm); + wine_midi_stream_free(lpMidiStrm); return ret; }
From: Anton Baskanov baskanov@gmail.com
--- configure | 2 + configure.ac | 1 + dlls/wineswmidi/Makefile.in | 4 ++ dlls/wineswmidi/swmidi.c | 72 +++++++++++++++++++++++++++++++++ dlls/wineswmidi/wineswmidi.spec | 3 ++ dlls/winmm/lolvldrv.c | 1 + dlls/winmm/tests/midi.c | 5 ++- 7 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 dlls/wineswmidi/Makefile.in create mode 100644 dlls/wineswmidi/swmidi.c create mode 100644 dlls/wineswmidi/wineswmidi.spec
diff --git a/configure b/configure index 928f3430e4b..b5b10ee52c4 100755 --- a/configure +++ b/configure @@ -1527,6 +1527,7 @@ enable_winemapi enable_wineoss_drv enable_wineps_drv enable_winepulse_drv +enable_wineswmidi enable_wineusb_sys enable_winevulkan enable_winewayland_drv @@ -22935,6 +22936,7 @@ wine_fn_config_makefile dlls/wineoss.drv enable_wineoss_drv wine_fn_config_makefile dlls/wineps.drv enable_wineps_drv wine_fn_config_makefile dlls/wineps16.drv16 enable_win16 wine_fn_config_makefile dlls/winepulse.drv enable_winepulse_drv +wine_fn_config_makefile dlls/wineswmidi enable_wineswmidi wine_fn_config_makefile dlls/wineusb.sys enable_wineusb_sys wine_fn_config_makefile dlls/winevulkan enable_winevulkan wine_fn_config_makefile dlls/winewayland.drv enable_winewayland_drv diff --git a/configure.ac b/configure.ac index 5f9e63b6f9f..a9ed473e727 100644 --- a/configure.ac +++ b/configure.ac @@ -3274,6 +3274,7 @@ WINE_CONFIG_MAKEFILE(dlls/wineoss.drv) WINE_CONFIG_MAKEFILE(dlls/wineps.drv) WINE_CONFIG_MAKEFILE(dlls/wineps16.drv16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/winepulse.drv) +WINE_CONFIG_MAKEFILE(dlls/wineswmidi) WINE_CONFIG_MAKEFILE(dlls/wineusb.sys) WINE_CONFIG_MAKEFILE(dlls/winevulkan) WINE_CONFIG_MAKEFILE(dlls/winewayland.drv) diff --git a/dlls/wineswmidi/Makefile.in b/dlls/wineswmidi/Makefile.in new file mode 100644 index 00000000000..26acbef4b9b --- /dev/null +++ b/dlls/wineswmidi/Makefile.in @@ -0,0 +1,4 @@ +MODULE = wineswmidi.dll + +SOURCES = \ + swmidi.c diff --git a/dlls/wineswmidi/swmidi.c b/dlls/wineswmidi/swmidi.c new file mode 100644 index 00000000000..ab098a21f2e --- /dev/null +++ b/dlls/wineswmidi/swmidi.c @@ -0,0 +1,72 @@ +/* + * MIDI driver for software synthesizer + * + * Copyright 2025 Anton Baskanov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "mmddk.h" +#include "mmdeviceapi.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(midi); + +DWORD WINAPI swmidi_modMessage(UINT dev_id, UINT msg, DWORD_PTR user, DWORD_PTR param1, + DWORD_PTR param2) +{ + TRACE("dev_id %u, msg %x, user %#Ix, param1 %#Ix, param2 %#Ix.\n", dev_id, msg, user, param1, + param2); + + switch (msg) + { + case DRVM_INIT: + case DRVM_EXIT: + return MMSYSERR_NOERROR; + case MODM_GETNUMDEVS: + return 1; + } + + return MMSYSERR_NOTSUPPORTED; +} + +LRESULT CALLBACK swmidi_DriverProc(DWORD_PTR dev_id, HDRVR drvr, UINT msg, LPARAM param1, + LPARAM param2) +{ + TRACE("dev_id %Iu, drvr %p, msg %x, param1 %#Ix, param2 %#Ix.\n", dev_id, drvr, msg, param1, + param2); + + switch(msg) + { + case DRV_LOAD: + case DRV_FREE: + case DRV_OPEN: + case DRV_CLOSE: + case DRV_ENABLE: + case DRV_DISABLE: + case DRV_QUERYCONFIGURE: + return DRV_SUCCESS; + case DRV_CONFIGURE: + case DRV_INSTALL: + case DRV_REMOVE: + return DRVCNF_OK; + } + + return DRV_FAILURE; +} diff --git a/dlls/wineswmidi/wineswmidi.spec b/dlls/wineswmidi/wineswmidi.spec new file mode 100644 index 00000000000..03b701e95c8 --- /dev/null +++ b/dlls/wineswmidi/wineswmidi.spec @@ -0,0 +1,3 @@ +# WinMM driver functions +@ stdcall -private DriverProc(long long long long long) swmidi_DriverProc +@ stdcall -private modMessage(long long long long long) swmidi_modMessage diff --git a/dlls/winmm/lolvldrv.c b/dlls/winmm/lolvldrv.c index e664021dc64..cf61fbce06d 100644 --- a/dlls/winmm/lolvldrv.c +++ b/dlls/winmm/lolvldrv.c @@ -538,6 +538,7 @@ static void MMDRV_Init(void) free(drvA); PropVariantClear(&pv);
+ MMDRV_Install("swmidi", "wineswmidi.dll", FALSE); MMDRV_Install("wavemapper", "msacm32.drv", TRUE); MMDRV_Install("midimapper", "midimap.dll", TRUE);
diff --git a/dlls/winmm/tests/midi.c b/dlls/winmm/tests/midi.c index 70a5375f1cb..8be1ace09fc 100644 --- a/dlls/winmm/tests/midi.c +++ b/dlls/winmm/tests/midi.c @@ -279,9 +279,12 @@ static void test_midiOut_device(UINT udev, HWND hwnd) DWORD ovolume; UINT udevid; MIDIHDR mhdr; + BOOL swmidi; + + swmidi = udev == midiOutGetNumDevs() - 1;
rc = midiOutGetDevCapsA(udev, &capsA, sizeof(capsA)); - ok(!rc, "midiOutGetDevCaps(dev=%d) rc=%s\n", udev, mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutGetDevCaps(dev=%d) rc=%s\n", udev, mmsys_error(rc)); if (!rc) { trace("* %s: manufacturer=%d, product=%d, tech=%d, support=%lX: %d voices, %d notes\n", capsA.szPname, capsA.wMid, capsA.wPid, capsA.wTechnology, capsA.dwSupport, capsA.wVoices, capsA.wNotes);
From: Anton Baskanov baskanov@gmail.com
--- dlls/wineswmidi/swmidi.c | 21 +++++++++++++++++++++ dlls/winmm/tests/midi.c | 5 +---- include/mmsystem.h | 2 ++ 3 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/dlls/wineswmidi/swmidi.c b/dlls/wineswmidi/swmidi.c index ab098a21f2e..038aa269ec6 100644 --- a/dlls/wineswmidi/swmidi.c +++ b/dlls/wineswmidi/swmidi.c @@ -28,6 +28,25 @@
WINE_DEFAULT_DEBUG_CHANNEL(midi);
+static DWORD swmidi_get_dev_caps(MIDIOUTCAPSW *out_caps, DWORD_PTR size) +{ + MIDIOUTCAPSW caps = { + MM_MICROSOFT, MM_MSFT_WDMAUDIO_MIDIOUT, 0x050a, + L"Wine GS Wavetable SW Synth", + MOD_SWSYNTH, 48, 48, 0xffff, + MIDICAPS_VOLUME | MIDICAPS_LRVOLUME, + }; + + TRACE("out_caps %p, size %Iu.\n", out_caps, size); + + if (!out_caps) + return MMSYSERR_INVALPARAM; + + memcpy(out_caps, &caps, min(size, sizeof(caps))); + + return MMSYSERR_NOERROR; +} + DWORD WINAPI swmidi_modMessage(UINT dev_id, UINT msg, DWORD_PTR user, DWORD_PTR param1, DWORD_PTR param2) { @@ -41,6 +60,8 @@ DWORD WINAPI swmidi_modMessage(UINT dev_id, UINT msg, DWORD_PTR user, DWORD_PTR return MMSYSERR_NOERROR; case MODM_GETNUMDEVS: return 1; + case MODM_GETDEVCAPS: + return swmidi_get_dev_caps((MIDIOUTCAPSW *)param1, param2); }
return MMSYSERR_NOTSUPPORTED; diff --git a/dlls/winmm/tests/midi.c b/dlls/winmm/tests/midi.c index 8be1ace09fc..70a5375f1cb 100644 --- a/dlls/winmm/tests/midi.c +++ b/dlls/winmm/tests/midi.c @@ -279,12 +279,9 @@ static void test_midiOut_device(UINT udev, HWND hwnd) DWORD ovolume; UINT udevid; MIDIHDR mhdr; - BOOL swmidi; - - swmidi = udev == midiOutGetNumDevs() - 1;
rc = midiOutGetDevCapsA(udev, &capsA, sizeof(capsA)); - todo_wine_if(swmidi) ok(!rc, "midiOutGetDevCaps(dev=%d) rc=%s\n", udev, mmsys_error(rc)); + ok(!rc, "midiOutGetDevCaps(dev=%d) rc=%s\n", udev, mmsys_error(rc)); if (!rc) { trace("* %s: manufacturer=%d, product=%d, tech=%d, support=%lX: %d voices, %d notes\n", capsA.szPname, capsA.wMid, capsA.wPid, capsA.wTechnology, capsA.dwSupport, capsA.wVoices, capsA.wNotes); diff --git a/include/mmsystem.h b/include/mmsystem.h index a80716ef949..c65f627c0ed 100644 --- a/include/mmsystem.h +++ b/include/mmsystem.h @@ -265,6 +265,8 @@ typedef void (CALLBACK *LPDRVCALLBACK)(HDRVR,UINT,DWORD_PTR,DWORD_PTR,DWORD_PTR)
#define MM_PC_JOYSTICK 12 /* Joystick adapter */
+#define MM_MSFT_WDMAUDIO_MIDIOUT 102 + #define MM_CREATIVE_SBP16_WAVEOUT 104
WINMMAPI UINT WINAPI mmsystemGetVersion(void);
From: Anton Baskanov baskanov@gmail.com
--- dlls/winmm/tests/midi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/winmm/tests/midi.c b/dlls/winmm/tests/midi.c index 70a5375f1cb..8f74208266c 100644 --- a/dlls/winmm/tests/midi.c +++ b/dlls/winmm/tests/midi.c @@ -903,7 +903,7 @@ static void test_midiStream(UINT udev, HWND hwnd) rc = midiStreamProperty(hm, (void*)&midiprop, MIDIPROP_SET | MIDIPROP_TIMEDIV); ok(rc == MMSYSERR_INVALPARAM, "midiStreamProperty(SET|TIMEDIV, dev=%d) rc=%s\n", udev, mmsys_error(rc));
- ret = WaitForSingleObject(records.done, INFINITE); + ret = WaitForSingleObject(records.done, 3000); ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed, got %ld\n", ret);
rc = midiStreamPause(hm);
From: Anton Baskanov baskanov@gmail.com
--- dlls/wineswmidi/Makefile.in | 1 + dlls/wineswmidi/swmidi.c | 76 +++++++++++- dlls/winmm/tests/midi.c | 226 ++++++++++++++++++------------------ 3 files changed, 192 insertions(+), 111 deletions(-)
diff --git a/dlls/wineswmidi/Makefile.in b/dlls/wineswmidi/Makefile.in index 26acbef4b9b..5e9a8995868 100644 --- a/dlls/wineswmidi/Makefile.in +++ b/dlls/wineswmidi/Makefile.in @@ -1,4 +1,5 @@ MODULE = wineswmidi.dll +DELAYIMPORTS = winmm
SOURCES = \ swmidi.c diff --git a/dlls/wineswmidi/swmidi.c b/dlls/wineswmidi/swmidi.c index 038aa269ec6..f203ad1221a 100644 --- a/dlls/wineswmidi/swmidi.c +++ b/dlls/wineswmidi/swmidi.c @@ -28,6 +28,35 @@
WINE_DEFAULT_DEBUG_CHANNEL(midi);
+struct swmidi +{ + CRITICAL_SECTION cs; + + BOOL open; + MIDIOPENDESC open_desc; + WORD flags; +}; + +static struct swmidi swmidi; + +static DWORD swmidi_init(void) +{ + TRACE("\n"); + + InitializeCriticalSection(&swmidi.cs); + + return MMSYSERR_NOERROR; +} + +static DWORD swmidi_exit(void) +{ + TRACE("\n"); + + DeleteCriticalSection(&swmidi.cs); + + return MMSYSERR_NOERROR; +} + static DWORD swmidi_get_dev_caps(MIDIOUTCAPSW *out_caps, DWORD_PTR size) { MIDIOUTCAPSW caps = { @@ -47,6 +76,46 @@ static DWORD swmidi_get_dev_caps(MIDIOUTCAPSW *out_caps, DWORD_PTR size) return MMSYSERR_NOERROR; }
+static DWORD swmidi_open(MIDIOPENDESC *desc, UINT flags) +{ + TRACE("desc %p, flags %x.\n", desc, flags); + + EnterCriticalSection(&swmidi.cs); + + if (swmidi.open) + { + LeaveCriticalSection(&swmidi.cs); + return MMSYSERR_ALLOCATED; + } + + swmidi.open = TRUE; + swmidi.open_desc = *desc; + swmidi.flags = HIWORD(flags & CALLBACK_TYPEMASK); + + LeaveCriticalSection(&swmidi.cs); + + DriverCallback(swmidi.open_desc.dwCallback, swmidi.flags, (HDRVR)swmidi.open_desc.hMidi, + MOM_OPEN, swmidi.open_desc.dwInstance, 0, 0); + + return MMSYSERR_NOERROR; +} + +static DWORD swmidi_close(void) +{ + TRACE("\n"); + + EnterCriticalSection(&swmidi.cs); + + swmidi.open = FALSE; + + LeaveCriticalSection(&swmidi.cs); + + DriverCallback(swmidi.open_desc.dwCallback, swmidi.flags, (HDRVR)swmidi.open_desc.hMidi, + MOM_CLOSE, swmidi.open_desc.dwInstance, 0, 0); + + return MMSYSERR_NOERROR; +} + DWORD WINAPI swmidi_modMessage(UINT dev_id, UINT msg, DWORD_PTR user, DWORD_PTR param1, DWORD_PTR param2) { @@ -56,12 +125,17 @@ DWORD WINAPI swmidi_modMessage(UINT dev_id, UINT msg, DWORD_PTR user, DWORD_PTR switch (msg) { case DRVM_INIT: + return swmidi_init(); case DRVM_EXIT: - return MMSYSERR_NOERROR; + return swmidi_exit(); case MODM_GETNUMDEVS: return 1; case MODM_GETDEVCAPS: return swmidi_get_dev_caps((MIDIOUTCAPSW *)param1, param2); + case MODM_OPEN: + return swmidi_open((MIDIOPENDESC *)param1, param2); + case MODM_CLOSE: + return swmidi_close(); }
return MMSYSERR_NOTSUPPORTED; diff --git a/dlls/winmm/tests/midi.c b/dlls/winmm/tests/midi.c index 8f74208266c..33a8e92cac9 100644 --- a/dlls/winmm/tests/midi.c +++ b/dlls/winmm/tests/midi.c @@ -65,8 +65,8 @@ static void CALLBACK callback_func(HWAVEOUT hwo, UINT uMsg, cbinst = dwInstance; /* MYCBINST, see midiOut/StreamOpen */ }
-#define test_notification(hwnd, command, m1, p2) test_notification_dbg(hwnd, command, m1, p2, __LINE__) -static void test_notification_dbg(HWND hwnd, const char* command, UINT m1, DWORD_PTR p2, int line) +#define test_notification(hwnd, command, m1, p2, todo) test_notification_dbg(hwnd, command, m1, p2, todo, __LINE__) +static void test_notification_dbg(HWND hwnd, const char* command, UINT m1, DWORD_PTR p2, BOOL todo, int line) { /* Use message type 0 as meaning no message */ MSG msg; if (hwnd) { @@ -82,16 +82,16 @@ static void test_notification_dbg(HWND hwnd, const char* command, UINT m1, DWORD trace_(__FILE__,line)("Waiting for delayed message %x from %s\n", m1, command); SetLastError(0xDEADBEEF); rc = MsgWaitForMultipleObjects(0, NULL, FALSE, 3000, QS_POSTMESSAGE); - ok_(__FILE__,line)(rc==WAIT_OBJECT_0, "Wait failed: %04lx %ld\n", rc, GetLastError()); + todo_wine_if(todo && rc != WAIT_OBJECT_0) ok_(__FILE__,line)(rc==WAIT_OBJECT_0, "Wait failed: %04lx %ld\n", rc, GetLastError()); seen = PeekMessageA(&msg, hwnd, 0, 0, PM_REMOVE); } if (seen) { trace_(__FILE__,line)("Message %x, wParam=%Ix, lParam=%Ix from %s\n", msg.message, msg.wParam, msg.lParam, command); - ok_(__FILE__,line)(msg.hwnd==hwnd, "Didn't get the handle to our test window\n"); - ok_(__FILE__,line)(msg.message==m1 && msg.lParam==p2, "bad message %x/%Ix from %s, expect %x/%Ix\n", msg.message, msg.lParam, command, m1, p2); + todo_wine_if(todo) ok_(__FILE__,line)(msg.hwnd==hwnd, "Didn't get the handle to our test window\n"); + todo_wine_if(todo) ok_(__FILE__,line)(msg.message==m1 && msg.lParam==p2, "bad message %x/%Ix from %s, expect %x/%Ix\n", msg.message, msg.lParam, command, m1, p2); } - else ok_(__FILE__,line)(m1==0, "Expect message %x from %s\n", m1, command); + else todo_wine_if(todo) ok_(__FILE__,line)(m1==0, "Expect message %x from %s\n", m1, command); } else { /* FIXME: MOM_POSITIONCB and MOM_DONE are so close that a queue is needed. */ @@ -129,7 +129,7 @@ static void test_midiIn_device(UINT udev, HWND hwnd) "midiInOpen(dev=%d) rc=%s\n", udev, mmsys_error(rc)); if (rc) return;
- test_notification(hwnd, "midiInOpen", MIM_OPEN, 0); + test_notification(hwnd, "midiInOpen", MIM_OPEN, 0, FALSE);
memset(&mhdr, 0, sizeof(mhdr)); mhdr.dwFlags = MHDR_DONE; @@ -192,7 +192,7 @@ static void test_midiIn_device(UINT udev, HWND hwnd) } rc = midiInReset(hm); /* Return any pending buffer */ ok(!rc, "midiInReset rc=%s\n", mmsys_error(rc)); - test_notification(hwnd, "midiInReset", MIM_LONGDATA, (DWORD_PTR)&mhdr); + test_notification(hwnd, "midiInReset", MIM_LONGDATA, (DWORD_PTR)&mhdr, FALSE);
ok(mhdr.dwFlags == (MHDR_PREPARED|MHDR_DONE), "dwFlags=%lx\n", mhdr.dwFlags); rc = midiInUnprepareHeader(hm, &mhdr, sizeof(mhdr)); @@ -205,8 +205,8 @@ static void test_midiIn_device(UINT udev, HWND hwnd)
ok(mhdr.dwUser==0x56FA552C, "MIDIHDR.dwUser changed to %Ix\n", mhdr.dwUser); free(mhdr.lpData); - test_notification(hwnd, "midiInClose", MIM_CLOSE, 0); - test_notification(hwnd, "midiIn over", 0, WHATEVER); + test_notification(hwnd, "midiInClose", MIM_CLOSE, 0, FALSE); + test_notification(hwnd, "midiIn over", 0, WHATEVER, FALSE); }
static void test_midi_infns(HWND hwnd) @@ -279,6 +279,9 @@ static void test_midiOut_device(UINT udev, HWND hwnd) DWORD ovolume; UINT udevid; MIDIHDR mhdr; + BOOL swmidi; + + swmidi = udev == midiOutGetNumDevs() - 1;
rc = midiOutGetDevCapsA(udev, &capsA, sizeof(capsA)); ok(!rc, "midiOutGetDevCaps(dev=%d) rc=%s\n", udev, mmsys_error(rc)); @@ -305,10 +308,10 @@ static void test_midiOut_device(UINT udev, HWND hwnd) ok(!rc, "midiOutOpen(dev=%d) rc=%s\n", udev, mmsys_error(rc)); if (rc) return;
- test_notification(hwnd, "midiOutOpen", MOM_OPEN, 0); + test_notification(hwnd, "midiOutOpen", MOM_OPEN, 0, FALSE);
rc = midiOutGetVolume(hm, &ovolume); - ok((capsA.dwSupport & MIDICAPS_VOLUME) ? rc==MMSYSERR_NOERROR : rc==MMSYSERR_NOTSUPPORTED, "midiOutGetVolume rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok((capsA.dwSupport & MIDICAPS_VOLUME) ? rc==MMSYSERR_NOERROR : rc==MMSYSERR_NOTSUPPORTED, "midiOutGetVolume rc=%s\n", mmsys_error(rc)); /* The native mapper responds with FFFFFFFF initially, * real devices with the volume GUI SW-synth settings. */ if (!rc) trace("Current volume %lx on device %d\n", ovolume, udev); @@ -316,10 +319,10 @@ static void test_midiOut_device(UINT udev, HWND hwnd) /* The W95 ESFM Synthesis device reports NOTENABLED although * GetVolume by handle works and music plays. */ rc = midiOutGetVolume(UlongToHandle(udev), &ovolume); - ok((capsA.dwSupport & MIDICAPS_VOLUME) ? rc==MMSYSERR_NOERROR || broken(rc==MMSYSERR_NOTENABLED) : rc==MMSYSERR_NOTSUPPORTED, "midiOutGetVolume(dev=%d) rc=%s\n", udev, mmsys_error(rc)); + todo_wine_if(swmidi) ok((capsA.dwSupport & MIDICAPS_VOLUME) ? rc==MMSYSERR_NOERROR || broken(rc==MMSYSERR_NOTENABLED) : rc==MMSYSERR_NOTSUPPORTED, "midiOutGetVolume(dev=%d) rc=%s\n", udev, mmsys_error(rc));
rc = midiOutGetVolume(hm, NULL); - ok(rc==MMSYSERR_INVALPARAM, "midiOutGetVolume NULL rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(rc==MMSYSERR_INVALPARAM, "midiOutGetVolume NULL rc=%s\n", mmsys_error(rc));
/* Tests with midiOutSetvolume show that the midi mapper forwards * the value to the real device, but Get initially always reports @@ -349,7 +352,7 @@ static void test_midiOut_device(UINT udev, HWND hwnd) { DWORD e = 0x006F4893; /* velocity, note (#69 would be 440Hz) channel */ trace("ShortMsg type %x\n", LOBYTE(LOWORD(e))); rc = midiOutShortMsg(hm, e); - ok(!rc, "midiOutShortMsg rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutShortMsg rc=%s\n", mmsys_error(rc)); if (!rc) Sleep(400); /* Hear note */ }
@@ -362,41 +365,41 @@ static void test_midiOut_device(UINT udev, HWND hwnd) ok(mhdr.lpData!=NULL, "No %ld bytes of memory!\n", mhdr.dwBufferLength); if (mhdr.lpData) { rc = midiOutLongMsg(hm, &mhdr, sizeof(mhdr)); - ok(rc==MIDIERR_UNPREPARED, "midiOutLongMsg unprepared rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(rc==MIDIERR_UNPREPARED, "midiOutLongMsg unprepared rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags == MHDR_DONE, "dwFlags=%lx\n", mhdr.dwFlags); - test_notification(hwnd, "midiOutLong unprepared", 0, WHATEVER); + test_notification(hwnd, "midiOutLong unprepared", 0, WHATEVER, FALSE);
rc = midiOutPrepareHeader(hm, &mhdr, offsetof(MIDIHDR,dwOffset)-1); - ok(rc==MMSYSERR_INVALPARAM, "midiOutPrepare tiny rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(rc==MMSYSERR_INVALPARAM, "midiOutPrepare tiny rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags == MHDR_DONE, "dwFlags=%lx\n", mhdr.dwFlags);
/* Since at least w2k, midiOutPrepare clears the DONE and INQUEUE flags. w95 didn't. */ /* mhdr.dwFlags |= MHDR_INQUEUE; would cause w95 to return STILLPLAYING from Unprepare */ rc = midiOutPrepareHeader(hm, &mhdr, offsetof(MIDIHDR,dwOffset)); - ok(!rc, "midiOutPrepare old size rc=%s\n", mmsys_error(rc)); - ok(mhdr.dwFlags == (MHDR_PREPARED|MHDR_DONE)/*w9x*/ || - mhdr.dwFlags == MHDR_PREPARED, "dwFlags=%lx\n", mhdr.dwFlags); + todo_wine_if(swmidi) ok(!rc, "midiOutPrepare old size rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(mhdr.dwFlags == (MHDR_PREPARED|MHDR_DONE)/*w9x*/ || + mhdr.dwFlags == MHDR_PREPARED, "dwFlags=%lx\n", mhdr.dwFlags); trace("MIDIHDR flags=%lx when unsent\n", mhdr.dwFlags);
/* No flag is cleared when already prepared. */ mhdr.dwFlags |= MHDR_DONE|MHDR_INQUEUE; rc = midiOutPrepareHeader(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutPrepare rc=%s\n", mmsys_error(rc)); - ok(mhdr.dwFlags == (MHDR_PREPARED|MHDR_DONE|MHDR_INQUEUE), "dwFlags=%lx\n", mhdr.dwFlags); + todo_wine_if(swmidi) ok(!rc, "midiOutPrepare rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(mhdr.dwFlags == (MHDR_PREPARED|MHDR_DONE|MHDR_INQUEUE), "dwFlags=%lx\n", mhdr.dwFlags);
mhdr.dwFlags |= MHDR_INQUEUE; rc = midiOutUnprepareHeader(hm, &mhdr, sizeof(mhdr)); - ok(rc==MIDIERR_STILLPLAYING, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); - ok(mhdr.dwFlags == (MHDR_PREPARED|MHDR_DONE|MHDR_INQUEUE), "dwFlags=%lx\n", mhdr.dwFlags); + todo_wine_if(swmidi) ok(rc==MIDIERR_STILLPLAYING, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(mhdr.dwFlags == (MHDR_PREPARED|MHDR_DONE|MHDR_INQUEUE), "dwFlags=%lx\n", mhdr.dwFlags);
mhdr.dwFlags &= ~MHDR_INQUEUE; rc = midiOutUnprepareHeader(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags == MHDR_DONE, "dwFlags=%lx\n", mhdr.dwFlags);
mhdr.dwFlags |= MHDR_INQUEUE; rc = midiOutUnprepareHeader(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags == (MHDR_INQUEUE|MHDR_DONE), "dwFlags=%lx\n", mhdr.dwFlags);
free(mhdr.lpData); @@ -409,26 +412,26 @@ static void test_midiOut_device(UINT udev, HWND hwnd) if(!rc) ok(udevid==udev, "midiOutGetID gives %d, expect %d\n", udevid, udev);
rc = midiOutReset(hm); /* Quiet everything */ - ok(!rc, "midiOutReset rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutReset rc=%s\n", mmsys_error(rc));
rc = midiOutClose(hm); ok(!rc, "midiOutClose rc=%s\n", mmsys_error(rc)); - test_notification(hwnd, "midiOutClose", MOM_CLOSE, 0); + test_notification(hwnd, "midiOutClose", MOM_CLOSE, 0, FALSE);
rc = midiOutOpen(&hm, udev, 0, (DWORD_PTR)MYCBINST, CALLBACK_WINDOW); /* w95 broken(rc==MMSYSERR_INVALPARAM) see WINMM_CheckCallback */ ok(!rc, "midiOutOpen(dev=%d) 0 CALLBACK_WINDOW rc=%s\n", udev, mmsys_error(rc)); /* PostMessage(hwnd=0) redirects to PostThreadMessage(GetCurrentThreadId()) * which PeekMessage((HWND)-1) queries. */ - test_notification((HWND)-1, "midiOutOpen WINDOW->THREAD", 0, WHATEVER); - test_notification(hwnd, "midiOutOpen WINDOW", 0, WHATEVER); + test_notification((HWND)-1, "midiOutOpen WINDOW->THREAD", 0, WHATEVER, FALSE); + test_notification(hwnd, "midiOutOpen WINDOW", 0, WHATEVER, FALSE); if (!rc) { rc = midiOutClose(hm); ok(!rc, "midiOutClose rc=%s\n", mmsys_error(rc)); - test_notification((HWND)-1, "midiOutClose WINDOW->THREAD", 0, WHATEVER); - test_notification(hwnd, "midiOutClose", 0, WHATEVER); + test_notification((HWND)-1, "midiOutClose WINDOW->THREAD", 0, WHATEVER, FALSE); + test_notification(hwnd, "midiOutClose", 0, WHATEVER, FALSE); } - test_notification(hwnd, "midiOut over", 0, WHATEVER); + test_notification(hwnd, "midiOut over", 0, WHATEVER, FALSE); if (!strncmp(capsA.szPname, fluidsynth_prefix, strlen(fluidsynth_prefix)) || (udev == MIDIMAPPER && found_fluidsynth)) { found_fluidsynth = TRUE; @@ -441,55 +444,55 @@ static void test_midiOut_device(UINT udev, HWND hwnd) else rc = midiOutOpen(&hm, udev, (DWORD_PTR)callback_func, (DWORD_PTR)MYCBINST, CALLBACK_FUNCTION); ok(!rc, "midiOutOpen(dev=%d) rc=%s\n", udev, mmsys_error(rc)); - test_notification(hwnd, "midiOutOpen", MOM_OPEN, 0); + test_notification(hwnd, "midiOutOpen", MOM_OPEN, 0, FALSE);
memset(&mhdr, 0, sizeof(mhdr)); mhdr.lpData = (LPSTR)SysEx_reset; mhdr.dwBufferLength = sizeof(SysEx_reset); rc = midiOutPrepareHeader(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutPrepareHeader rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutPrepareHeader rc=%s\n", mmsys_error(rc)); rc = midiOutLongMsg(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutLongMsg rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutLongMsg rc=%s\n", mmsys_error(rc)); rc = midiOutUnprepareHeader(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); - test_notification(hwnd, "midiOutLongMsg", MOM_DONE, (DWORD_PTR)&mhdr); + todo_wine_if(swmidi) ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); + test_notification(hwnd, "midiOutLongMsg", MOM_DONE, (DWORD_PTR)&mhdr, swmidi); Sleep(60);
mhdr.lpData = (LPSTR)SysEx_volume_off; mhdr.dwBufferLength = sizeof(SysEx_volume_off); rc = midiOutPrepareHeader(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutPrepareHeader rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutPrepareHeader rc=%s\n", mmsys_error(rc)); rc = midiOutLongMsg(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutLongMsg rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutLongMsg rc=%s\n", mmsys_error(rc)); rc = midiOutUnprepareHeader(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); - test_notification(hwnd, "midiOutLongMsg", MOM_DONE, (DWORD_PTR)&mhdr); + todo_wine_if(swmidi) ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); + test_notification(hwnd, "midiOutLongMsg", MOM_DONE, (DWORD_PTR)&mhdr, swmidi);
{ DWORD e = 0x006F4593; /* velocity 111, note #69, channel 4 */ trace("ShortMsg type %x (muted)\n", LOBYTE(LOWORD(e))); rc = midiOutShortMsg(hm, e); - ok(!rc, "midiOutShortMsg rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutShortMsg rc=%s\n", mmsys_error(rc)); /* We can't hear this voice due to volume settings */ if (!rc) Sleep(200);
rc = midiOutShortMsg(hm, 0x00004593); /* velocity 0 */ - ok(!rc, "midiOutShortMsg rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutShortMsg rc=%s\n", mmsys_error(rc)); }
mhdr.lpData = (LPSTR)SysEx_volume_full; mhdr.dwBufferLength = sizeof(SysEx_volume_full); rc = midiOutPrepareHeader(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutPrepareHeader rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutPrepareHeader rc=%s\n", mmsys_error(rc)); rc = midiOutLongMsg(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutLongMsg rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutLongMsg rc=%s\n", mmsys_error(rc)); rc = midiOutUnprepareHeader(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); - test_notification(hwnd, "midiOutLongMsg", MOM_DONE, (DWORD_PTR)&mhdr); + todo_wine_if(swmidi) ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); + test_notification(hwnd, "midiOutLongMsg", MOM_DONE, (DWORD_PTR)&mhdr, swmidi);
rc = midiOutClose(hm); ok(!rc, "midiOutClose rc=%s\n", mmsys_error(rc)); - test_notification(hwnd, "midiOuClose", MOM_CLOSE, 0); + test_notification(hwnd, "midiOuClose", MOM_CLOSE, 0, FALSE); }
static void test_position(HMIDISTRM hm, UINT typein, UINT typeout) @@ -608,6 +611,9 @@ static void test_midiStream(UINT udev, HWND hwnd) const DWORD MARGIN = 50; struct time_stamp_records records; MIDIOUTCAPSA capsA; + BOOL swmidi; + + swmidi = udev == midiOutGetNumDevs() - 1;
if (hwnd) rc = midiStreamOpen(&hm, &udev, 1, (DWORD_PTR)hwnd, (DWORD_PTR)MYCBINST, CALLBACK_WINDOW); @@ -621,7 +627,7 @@ static void test_midiStream(UINT udev, HWND hwnd) ok(!rc, "midiStreamOpen(dev=%d) rc=%s\n", udev, mmsys_error(rc)); if (rc) return;
- test_notification(hwnd, "midiStreamOpen", MOM_OPEN, 0); + test_notification(hwnd, "midiStreamOpen", MOM_OPEN, 0, FALSE);
midiprop.tempo.cbStruct = sizeof(midiprop.tempo); rc = midiStreamProperty(hm, (void*)&midiprop, MIDIPROP_GET|MIDIPROP_TEMPO); @@ -641,18 +647,18 @@ static void test_midiStream(UINT udev, HWND hwnd) mhdr.lpData = (LPSTR)&strmEvents[0]; if (mhdr.lpData) { rc = midiOutLongMsg((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(rc==MIDIERR_UNPREPARED, "midiOutLongMsg unprepared rc=%s\n", mmsys_error(rc)); - test_notification(hwnd, "midiOutLong unprepared", 0, WHATEVER); + todo_wine_if(swmidi) ok(rc==MIDIERR_UNPREPARED, "midiOutLongMsg unprepared rc=%s\n", mmsys_error(rc)); + test_notification(hwnd, "midiOutLong unprepared", 0, WHATEVER, FALSE);
rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, offsetof(MIDIHDR,dwOffset)-1); - ok(rc==MMSYSERR_INVALPARAM, "midiOutPrepare tiny rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(rc==MMSYSERR_INVALPARAM, "midiOutPrepare tiny rc=%s\n", mmsys_error(rc)); rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutPrepare size rc=%s\n", mmsys_error(rc)); - ok(mhdr.dwFlags & MHDR_PREPARED, "MHDR.dwFlags when prepared %lx\n", mhdr.dwFlags); + todo_wine_if(swmidi) ok(!rc, "midiOutPrepare size rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(mhdr.dwFlags & MHDR_PREPARED, "MHDR.dwFlags when prepared %lx\n", mhdr.dwFlags);
/* The device is still in paused mode and should queue the message. */ rc = midiStreamOut(hm, &mhdr, offsetof(MIDIHDR,dwOffset)); - ok(!rc, "midiStreamOut old size rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiStreamOut old size rc=%s\n", mmsys_error(rc)); rc2 = rc; trace("MIDIHDR flags=%lx when submitted\n", mhdr.dwFlags); /* w9X/me does not set MHDR_ISSTRM when StreamOut exits, @@ -660,7 +666,7 @@ static void test_midiStream(UINT udev, HWND hwnd)
Sleep(90); /* Wine <1.1.39 started playing immediately */ - test_notification(hwnd, "midiStream still paused", 0, WHATEVER); + test_notification(hwnd, "midiStream still paused", 0, WHATEVER, FALSE);
/* MSDN asks to use midiStreamRestart prior to midiStreamOut() * because the starting state is 'pause', but some apps seem to @@ -676,26 +682,26 @@ static void test_midiStream(UINT udev, HWND hwnd) } /* Checking INQUEUE is not the recommended way to wait for the end of a job, but we're testing. */ /* MHDR_ISSTRM is not necessarily set when midiStreamOut returns * rather than when the queue is eventually processed. */ - ok(mhdr.dwFlags & MHDR_ISSTRM, "MHDR.dwFlags %lx no ISSTRM when out of queue\n", mhdr.dwFlags); + todo_wine_if(swmidi) ok(mhdr.dwFlags & MHDR_ISSTRM, "MHDR.dwFlags %lx no ISSTRM when out of queue\n", mhdr.dwFlags); if (!rc2) while(!(mhdr.dwFlags & MHDR_DONE)) { /* Never to be seen except perhaps on multicore */ trace("async MIDI still not done\n"); Sleep(100); } - ok(mhdr.dwFlags & MHDR_DONE, "MHDR.dwFlags %lx not DONE when out of queue\n", mhdr.dwFlags); - test_notification(hwnd, "midiStream callback", MOM_POSITIONCB, (DWORD_PTR)&mhdr); - test_notification(hwnd, "midiStreamOut", MOM_DONE, (DWORD_PTR)&mhdr); + todo_wine_if(swmidi) ok(mhdr.dwFlags & MHDR_DONE, "MHDR.dwFlags %lx not DONE when out of queue\n", mhdr.dwFlags); + test_notification(hwnd, "midiStream callback", MOM_POSITIONCB, (DWORD_PTR)&mhdr, swmidi); + test_notification(hwnd, "midiStreamOut", MOM_DONE, (DWORD_PTR)&mhdr, swmidi);
/* Native fills dwOffset regardless of the cbMidiHdr size argument to midiStreamOut */ - ok(1234567890!=mhdr.dwOffset, "play left MIDIHDR.dwOffset at %lu\n", mhdr.dwOffset); + todo_wine_if(swmidi) ok(1234567890!=mhdr.dwOffset, "play left MIDIHDR.dwOffset at %lu\n", mhdr.dwOffset);
rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutUnprepare #2 rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutUnprepare #2 rc=%s\n", mmsys_error(rc));
trace("MIDIHDR stream flags=%lx when finished\n", mhdr.dwFlags); - ok(mhdr.dwFlags & MHDR_DONE, "MHDR.dwFlags when done %lx\n", mhdr.dwFlags); + todo_wine_if(swmidi) ok(mhdr.dwFlags & MHDR_DONE, "MHDR.dwFlags when done %lx\n", mhdr.dwFlags);
test_position(hm, TIME_MS, TIME_MS); test_position(hm, TIME_TICKS, TIME_TICKS); @@ -709,7 +715,7 @@ static void test_midiStream(UINT udev, HWND hwnd) midiprop.tempo.cbStruct = sizeof(midiprop.tempo); rc = midiStreamProperty(hm, (void*)&midiprop, MIDIPROP_GET|MIDIPROP_TEMPO); ok(!rc, "midiStreamProperty TEMPO rc=%s\n", mmsys_error(rc)); - ok(0x0493E0==midiprop.tempo.dwTempo, "stream set tempo %lu\n", midiprop.tdiv.dwTimeDiv); + todo_wine_if(swmidi) ok(0x0493E0==midiprop.tempo.dwTempo, "stream set tempo %lu\n", midiprop.tdiv.dwTimeDiv);
rc = midiStreamRestart(hm); ok(!rc, "midiStreamRestart #2 rc=%s\n", mmsys_error(rc)); @@ -717,9 +723,9 @@ static void test_midiStream(UINT udev, HWND hwnd) mhdr.dwFlags |= MHDR_ISSTRM; /* Preset flags (e.g. MHDR_ISSTRM) do not disturb. */ rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutPrepare used flags %lx rc=%s\n", mhdr.dwFlags, mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutPrepare used flags %lx rc=%s\n", mhdr.dwFlags, mmsys_error(rc)); rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutUnprepare used flags %lx rc=%s\n", mhdr.dwFlags, mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutUnprepare used flags %lx rc=%s\n", mhdr.dwFlags, mmsys_error(rc));
rc = midiStreamRestart(hm); ok(!rc, "midiStreamRestart #3 rc=%s\n", mmsys_error(rc)); @@ -738,13 +744,13 @@ static void test_midiStream(UINT udev, HWND hwnd) strmNops[1].dwEvent |= MEVT_F_CALLBACK;
rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutPrepare rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutPrepare rc=%s\n", mmsys_error(rc));
rc = playStream(hm, &mhdr); - ok(!rc, "midiStreamOut 0 bytes recorded rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiStreamOut 0 bytes recorded rc=%s\n", mmsys_error(rc));
- test_notification(hwnd, "midiStreamOut", MOM_DONE, (DWORD_PTR)&mhdr); - test_notification(hwnd, "0 bytes recorded", 0, WHATEVER); + test_notification(hwnd, "midiStreamOut", MOM_DONE, (DWORD_PTR)&mhdr, swmidi); + test_notification(hwnd, "0 bytes recorded", 0, WHATEVER, FALSE);
/* FIXME: check dwOffset within callback * instead of the unspecified value afterwards */ @@ -757,34 +763,34 @@ static void test_midiStream(UINT udev, HWND hwnd) mhdr.dwBytesRecorded = 1*sizeof(MIDISHORTEVENT);
rc = playStream(hm, &mhdr); - ok(!rc, "midiStreamOut 1 event out of 2 rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiStreamOut 1 event out of 2 rc=%s\n", mmsys_error(rc));
- test_notification(hwnd, "1 of 2 events", MOM_POSITIONCB, (DWORD_PTR)&mhdr); - test_notification(hwnd, "1 of 2 events", MOM_DONE, (DWORD_PTR)&mhdr); - test_notification(hwnd, "1 of 2 events", 0, WHATEVER); - ok(0==mhdr.dwOffset, "MIDIHDR.dwOffset 1/2 changed to %lu\n", mhdr.dwOffset); + test_notification(hwnd, "1 of 2 events", MOM_POSITIONCB, (DWORD_PTR)&mhdr, swmidi); + test_notification(hwnd, "1 of 2 events", MOM_DONE, (DWORD_PTR)&mhdr, swmidi); + test_notification(hwnd, "1 of 2 events", 0, WHATEVER, FALSE); + todo_wine_if(swmidi) ok(0==mhdr.dwOffset, "MIDIHDR.dwOffset 1/2 changed to %lu\n", mhdr.dwOffset);
mhdr.dwOffset = 1234123123; mhdr.dwBytesRecorded = 2*sizeof(MIDISHORTEVENT);
rc = playStream(hm, &mhdr); - ok(!rc, "midiStreamOut 1 event out of 2 rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiStreamOut 1 event out of 2 rc=%s\n", mmsys_error(rc));
- test_notification(hwnd, "2 of 2 events", MOM_POSITIONCB, (DWORD_PTR)&mhdr); - test_notification(hwnd, "2 of 2 events", MOM_POSITIONCB, (DWORD_PTR)&mhdr); - test_notification(hwnd, "2 of 2 events", MOM_DONE, (DWORD_PTR)&mhdr); - test_notification(hwnd, "2 of 2 events", 0, WHATEVER); - ok(sizeof(MIDISHORTEVENT)==mhdr.dwOffset, "MIDIHDR.dwOffset 2/2 changed to %lu\n", mhdr.dwOffset); + test_notification(hwnd, "2 of 2 events", MOM_POSITIONCB, (DWORD_PTR)&mhdr, swmidi); + test_notification(hwnd, "2 of 2 events", MOM_POSITIONCB, (DWORD_PTR)&mhdr, swmidi); + test_notification(hwnd, "2 of 2 events", MOM_DONE, (DWORD_PTR)&mhdr, swmidi); + test_notification(hwnd, "2 of 2 events", 0, WHATEVER, FALSE); + todo_wine_if(swmidi) ok(sizeof(MIDISHORTEVENT)==mhdr.dwOffset, "MIDIHDR.dwOffset 2/2 changed to %lu\n", mhdr.dwOffset); ok(mhdr.dwBytesRecorded == 2*sizeof(MIDISHORTEVENT), "dwBytesRecorded changed to %lu\n", mhdr.dwBytesRecorded);
strmNops[0].dwEvent &= ~MEVT_F_CALLBACK; strmNops[1].dwEvent &= ~MEVT_F_CALLBACK; mhdr.dwOffset = 1234123123; rc = playStream(hm, &mhdr); - ok(!rc, "midiStreamOut 1 event out of 2 rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiStreamOut 1 event out of 2 rc=%s\n", mmsys_error(rc));
- test_notification(hwnd, "0 CB in 2 events", MOM_DONE, (DWORD_PTR)&mhdr); - test_notification(hwnd, "0 CB in 2 events", 0, WHATEVER); + test_notification(hwnd, "0 CB in 2 events", MOM_DONE, (DWORD_PTR)&mhdr, swmidi); + test_notification(hwnd, "0 CB in 2 events", 0, WHATEVER, FALSE); /* w9X/me/nt set dwOffset to the position played last */ ok(1234123123==mhdr.dwOffset || broken(sizeof(MIDISHORTEVENT)==mhdr.dwOffset), "MIDIHDR.dwOffset nocb changed to %lu\n", mhdr.dwOffset);
@@ -792,20 +798,20 @@ static void test_midiStream(UINT udev, HWND hwnd) rc = playStream(hm, &mhdr); ok(rc==MMSYSERR_INVALPARAM,"midiStreamOut dwBytesRecorded modulo MIDIEVENT rc=%s\n", mmsys_error(rc)); if (!rc) { - test_notification(hwnd, "2 of 2 events", MOM_DONE, (DWORD_PTR)&mhdr); + test_notification(hwnd, "2 of 2 events", MOM_DONE, (DWORD_PTR)&mhdr, FALSE); }
mhdr.dwBytesRecorded = mhdr.dwBufferLength+1; rc = playStream(hm, &mhdr); ok(rc==MMSYSERR_INVALPARAM,"midiStreamOut dwBufferLength<dwBytesRecorded rc=%s\n", mmsys_error(rc)); - test_notification(hwnd, "past MIDIHDR tests", 0, WHATEVER); + test_notification(hwnd, "past MIDIHDR tests", 0, WHATEVER, FALSE);
rc = midiStreamStop(hm); ok(!rc, "midiStreamStop rc=%s\n", mmsys_error(rc)); ok(mhdr.dwUser==0x56FA552C, "MIDIHDR.dwUser changed to %Ix\n", mhdr.dwUser);
rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); ok(0==strmNops[0].dwStreamID, "dwStreamID[0] set to %lx\n", strmNops[0].dwStreamID); ok(0==strmNops[1].dwStreamID, "dwStreamID[1] set to %lx\n", strmNops[1].dwStreamID);
@@ -819,15 +825,15 @@ static void test_midiStream(UINT udev, HWND hwnd) todo_wine ok(rc==MMSYSERR_INVALPARAM, "midiOutPrepare stream too large rc=%s\n", mmsys_error(rc));
rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc));
free(mhdr.lpData); }
rc = midiStreamClose(hm); ok(!rc, "midiStreamClose rc=%s\n", mmsys_error(rc)); - test_notification(hwnd, "midiStreamClose", MOM_CLOSE, 0); - test_notification(hwnd, "midiStream over", 0, WHATEVER); + test_notification(hwnd, "midiStreamClose", MOM_CLOSE, 0, FALSE); + test_notification(hwnd, "midiStream over", 0, WHATEVER, FALSE);
rc = midiStreamOpen(&hm, &udev, 1, 0, (DWORD_PTR)MYCBINST, CALLBACK_FUNCTION); ok(!rc /*w2k*/|| rc==MMSYSERR_INVALPARAM/*w98*/, "midiStreamOpen NULL function rc=%s\n", mmsys_error(rc)); @@ -860,10 +866,10 @@ static void test_midiStream(UINT udev, HWND hwnd) mhdr.lpData = (LPSTR)strmNopsWithDelta; mhdr.dwBytesRecorded = mhdr.dwBufferLength = sizeof(strmNopsWithDelta); rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutPrepareHeader(dev=%d) rc=%s\n", udev, mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutPrepareHeader(dev=%d) rc=%s\n", udev, mmsys_error(rc));
rc = midiStreamOut(hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiStreamOut(dev=%d) rc=%s\n", udev, mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiStreamOut(dev=%d) rc=%s\n", udev, mmsys_error(rc));
ret = get_position(hm, TIME_MS); ok(ret == expected, "expected %lu, got %lu\n", expected, ret); @@ -904,15 +910,15 @@ static void test_midiStream(UINT udev, HWND hwnd) ok(rc == MMSYSERR_INVALPARAM, "midiStreamProperty(SET|TIMEDIV, dev=%d) rc=%s\n", udev, mmsys_error(rc));
ret = WaitForSingleObject(records.done, 3000); - ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed, got %ld\n", ret); + todo_wine_if(swmidi) ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed, got %ld\n", ret);
rc = midiStreamPause(hm); ok(!rc, "midiStreamPause(dev=%d) rc=%s\n", udev, mmsys_error(rc));
expected = 250; /* = 12 ticks in 120 BPM */ ret = get_position(hm, TIME_MS); - ok(ret >= expected - MARGIN && ret <= expected + MARGIN, - "expected greater than %lums, got %lums\n", expected, ret); + todo_wine_if(swmidi) ok(ret >= expected - MARGIN && ret <= expected + MARGIN, + "expected greater than %lums, got %lums\n", expected, ret); trace("after playing, got %lums\n", ret);
/* set tempo to 240 BPM */ @@ -923,8 +929,8 @@ static void test_midiStream(UINT udev, HWND hwnd)
/* a tempo change doesn't affect elapsed ticks */ ret = get_position(hm, TIME_TICKS); - ok(ret >= strmNopsWithDelta[1].dwDeltaTime && ret < strmNopsWithDelta[1].dwDeltaTime + 3, - "expected %lu ticks, got %lu\n", strmNopsWithDelta[1].dwDeltaTime, ret); + todo_wine_if(swmidi) ok(ret >= strmNopsWithDelta[1].dwDeltaTime && ret < strmNopsWithDelta[1].dwDeltaTime + 3, + "expected %lu ticks, got %lu\n", strmNopsWithDelta[1].dwDeltaTime, ret);
midiprop.tdiv.cbStruct = sizeof(midiprop.tdiv); rc = midiStreamProperty(hm, (void*)&midiprop, MIDIPROP_GET | MIDIPROP_TIMEDIV); @@ -936,17 +942,17 @@ static void test_midiStream(UINT udev, HWND hwnd) ret = get_position(hm, TIME_MIDI); ok(ret == expected, "expected song pointer %lu, got %lu\n", expected, ret);
- ok(records.count == 2, "expected 2 MM_MOM_DONE messages, got %d\n", records.count); + todo_wine_if(swmidi) ok(records.count == 2, "expected 2 MM_MOM_DONE messages, got %d\n", records.count);
/* Time between midiStreamPause and midiStreamRestart isn't counted. So, the second event happens at dwDeltaTime(250ms) + 100ms after the first event. */ expected = 250 + 100; diff = records.time_stamp[1] - records.time_stamp[0]; - ok(diff >= expected - MARGIN && diff <= expected + MARGIN, - "expected %lu ~ %lums, got %lums (dev=%d)\n", expected - MARGIN, expected + MARGIN, diff, udev); + todo_wine_if(swmidi) ok(diff >= expected - MARGIN && diff <= expected + MARGIN, + "expected %lu ~ %lums, got %lums (dev=%d)\n", expected - MARGIN, expected + MARGIN, diff, udev);
rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutUnprepareHeader(dev=%d) rc=%s\n", udev, mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutUnprepareHeader(dev=%d) rc=%s\n", udev, mmsys_error(rc));
rc = midiStreamStop(hm); ok(!rc, "midiStreamStop(dev=%d) rc=%s\n", udev, mmsys_error(rc)); @@ -986,7 +992,7 @@ static void test_midiStream(UINT udev, HWND hwnd) else rc = midiStreamOpen(&hm, &udev, 1, (DWORD_PTR)callback_func, (DWORD_PTR)MYCBINST, CALLBACK_FUNCTION); ok(!rc, "midiOutOpen(dev=%d) rc=%s\n", udev, mmsys_error(rc)); - test_notification(hwnd, "midiStreamOpen", MOM_OPEN, 0); + test_notification(hwnd, "midiStreamOpen", MOM_OPEN, 0, FALSE);
midiprop.tdiv.cbStruct = sizeof(midiprop.tdiv); midiprop.tdiv.dwTimeDiv = 480; @@ -1033,20 +1039,20 @@ static void test_midiStream(UINT udev, HWND hwnd) #undef ROUNDUP4
rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutPrepareHeader rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutPrepareHeader rc=%s\n", mmsys_error(rc));
rc = playStream(hm, &mhdr); - ok(!rc, "midiStreamOut rc=%s\n", mmsys_error(rc)); - test_notification(hwnd, "midiStreamOut", MOM_DONE, (DWORD_PTR)&mhdr); + todo_wine_if(swmidi) ok(!rc, "midiStreamOut rc=%s\n", mmsys_error(rc)); + test_notification(hwnd, "midiStreamOut", MOM_DONE, (DWORD_PTR)&mhdr, swmidi);
rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); - ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); + todo_wine_if(swmidi) ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc));
free(mhdr.lpData); } rc = midiStreamClose(hm); ok(!rc, "midiOutClose rc=%s\n", mmsys_error(rc)); - test_notification(hwnd, "midiStreamClose", MOM_CLOSE, 0); + test_notification(hwnd, "midiStreamClose", MOM_CLOSE, 0, FALSE); }
static BOOL scan_subkeys(HKEY parent, const LPCSTR *sub_keys)
From: Anton Baskanov baskanov@gmail.com
--- dlls/wineswmidi/Makefile.in | 1 + dlls/wineswmidi/swmidi.c | 118 ++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+)
diff --git a/dlls/wineswmidi/Makefile.in b/dlls/wineswmidi/Makefile.in index 5e9a8995868..24210437d0a 100644 --- a/dlls/wineswmidi/Makefile.in +++ b/dlls/wineswmidi/Makefile.in @@ -1,4 +1,5 @@ MODULE = wineswmidi.dll +IMPORTS = uuid ole32 DELAYIMPORTS = winmm
SOURCES = \ diff --git a/dlls/wineswmidi/swmidi.c b/dlls/wineswmidi/swmidi.c index f203ad1221a..4e8f50786ff 100644 --- a/dlls/wineswmidi/swmidi.c +++ b/dlls/wineswmidi/swmidi.c @@ -24,10 +24,16 @@ #include "mmddk.h" #include "mmdeviceapi.h"
+#include "initguid.h" +#include "dmusicc.h" + #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(midi);
+#define SWMIDI_AUDIO_CHANNELS 2 +#define SWMIDI_SAMPLE_RATE 22050 + struct swmidi { CRITICAL_SECTION cs; @@ -35,10 +41,93 @@ struct swmidi BOOL open; MIDIOPENDESC open_desc; WORD flags; + + HANDLE close_event; + HANDLE open_event; + HANDLE thread; + DWORD init_result; + + IDirectMusic *dmusic; + IDirectMusicPort *port; };
static struct swmidi swmidi;
+static HRESULT init_dmusic(void) +{ + DMUS_PORTPARAMS port_params; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic, + (void **)&swmidi.dmusic); + if (FAILED(hr)) + return hr; + + hr = IDirectMusic_SetDirectSound(swmidi.dmusic, NULL, NULL); + if (FAILED(hr)) + { + IDirectMusic_Release(swmidi.dmusic); + return hr; + } + + memset(&port_params, 0, sizeof(port_params)); + port_params.dwSize = sizeof(port_params); + port_params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS | DMUS_PORTPARAMS_AUDIOCHANNELS + | DMUS_PORTPARAMS_SAMPLERATE | DMUS_PORTPARAMS_EFFECTS; + port_params.dwChannelGroups = 1; + port_params.dwAudioChannels = SWMIDI_AUDIO_CHANNELS; + port_params.dwSampleRate = SWMIDI_SAMPLE_RATE; + port_params.dwEffectFlags = 0; + hr = IDirectMusic_CreatePort(swmidi.dmusic, &GUID_NULL, &port_params, &swmidi.port, NULL); + if (FAILED(hr)) + { + IDirectMusic_Release(swmidi.dmusic); + return hr; + } + + if (FAILED(IDirectMusicPort_Activate(swmidi.port, TRUE))) + { + IDirectMusicPort_Release(swmidi.port); + IDirectMusic_Release(swmidi.dmusic); + return hr; + } + + return S_OK; +} + +static void destroy_dmusic(void) +{ + IDirectMusicPort_Activate(swmidi.port, FALSE); + IDirectMusicPort_Release(swmidi.port); + IDirectMusic_Release(swmidi.dmusic); +} + +static DWORD WINAPI thread_proc(void *param) +{ + SetThreadDescription(GetCurrentThread(), L"swmidi"); + + CoInitialize(NULL); + + if (FAILED(init_dmusic())) + { + CoUninitialize(); + swmidi.init_result = MMSYSERR_ERROR; + SetEvent(swmidi.open_event); + return 0; + } + + swmidi.init_result = MMSYSERR_NOERROR; + SetEvent(swmidi.open_event); + + WaitForSingleObject(swmidi.close_event, INFINITE); + + destroy_dmusic(); + + CoUninitialize(); + + return 0; +} + static DWORD swmidi_init(void) { TRACE("\n"); @@ -88,6 +177,28 @@ static DWORD swmidi_open(MIDIOPENDESC *desc, UINT flags) return MMSYSERR_ALLOCATED; }
+ swmidi.close_event = CreateEventA(NULL, FALSE, FALSE, NULL); + swmidi.open_event = CreateEventA(NULL, FALSE, FALSE, NULL); + + swmidi.thread = CreateThread(NULL, 0, thread_proc, NULL, 0, NULL); + if (!swmidi.thread) + { + LeaveCriticalSection(&swmidi.cs); + return MMSYSERR_ERROR; + } + + WaitForSingleObject(swmidi.open_event, INFINITE); + + if (swmidi.init_result != MMSYSERR_NOERROR) + { + WaitForSingleObject(swmidi.thread, INFINITE); + CloseHandle(swmidi.thread); + CloseHandle(swmidi.open_event); + CloseHandle(swmidi.close_event); + LeaveCriticalSection(&swmidi.cs); + return swmidi.init_result; + } + swmidi.open = TRUE; swmidi.open_desc = *desc; swmidi.flags = HIWORD(flags & CALLBACK_TYPEMASK); @@ -106,6 +217,13 @@ static DWORD swmidi_close(void)
EnterCriticalSection(&swmidi.cs);
+ SetEvent(swmidi.close_event); + WaitForSingleObject(swmidi.thread, INFINITE); + + CloseHandle(swmidi.thread); + CloseHandle(swmidi.open_event); + CloseHandle(swmidi.close_event); + swmidi.open = FALSE;
LeaveCriticalSection(&swmidi.cs);