From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/tests/dmsynth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index f21e543705a..a948cf08b53 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -57,7 +57,7 @@ static void test_synth_getformat(IDirectMusicSynth *synth, DMUS_PORTPARAMS *para DWORD size; HRESULT hr;
- winetest_push_context(context); + winetest_push_context("%s", context);
size = sizeof(format); hr = IDirectMusicSynth_GetFormat(synth, &format, &size);
From: Rémi Bernon rbernon@codeweavers.com
Checking that all interfaces share the same refcount is a standard COM object thing, not really worth checking it here. --- dlls/dmsynth/tests/dmsynth.c | 64 +++++++++++++----------------------- 1 file changed, 23 insertions(+), 41 deletions(-)
diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index a948cf08b53..4c47cecfbf3 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -30,6 +30,19 @@ #include "dmusici.h" #include "dmksctrl.h"
+#define check_interface( a, b, c ) check_interface_( __LINE__, a, b, c ) +static void check_interface_( unsigned int line, void *iface_ptr, REFIID iid, BOOL supported ) +{ + IUnknown *iface = iface_ptr; + HRESULT hr, expected; + IUnknown *unk; + + expected = supported ? S_OK : E_NOINTERFACE; + hr = IUnknown_QueryInterface( iface, iid, (void **)&unk ); + ok_(__FILE__, line)( hr == expected, "got hr %#lx, expected %#lx.\n", hr, expected ); + if (SUCCEEDED(hr)) IUnknown_Release( unk ); +} + static BOOL missing_dmsynth(void) { IDirectMusicSynth *dms; @@ -317,9 +330,6 @@ static void test_dmsynth(void) static void test_COM(void) { IDirectMusicSynth8 *dms8 = (IDirectMusicSynth8*)0xdeadbeef; - IKsControl *iksc; - IUnknown *unk; - ULONG refcount; HRESULT hr;
/* COM aggregation */ @@ -334,40 +344,23 @@ static void test_COM(void) &IID_IDirectMusicObject, (void**)&dms8); ok(hr == E_NOINTERFACE, "DirectMusicSynth create failed: %#lx, expected E_NOINTERFACE\n", hr);
- /* Same refcount for all DirectMusicSynth interfaces */ hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynth8, (void**)&dms8); ok(hr == S_OK, "DirectMusicSynth create failed: %#lx, expected S_OK\n", hr); - refcount = IDirectMusicSynth8_AddRef(dms8); - ok(refcount == 2, "refcount == %lu, expected 2\n", refcount); - - hr = IDirectMusicSynth8_QueryInterface(dms8, &IID_IKsControl, (void**)&iksc); - ok(hr == S_OK, "QueryInterface for IID_IKsControl failed: %#lx\n", hr); - refcount = IKsControl_AddRef(iksc); - ok(refcount == 4, "refcount == %lu, expected 4\n", refcount); - IKsControl_Release(iksc);
- hr = IDirectMusicSynth8_QueryInterface(dms8, &IID_IUnknown, (void**)&unk); - ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr); - refcount = IUnknown_AddRef(unk); - ok(refcount == 5, "refcount == %lu, expected 5\n", refcount); - IUnknown_Release(unk); + check_interface(dms8, &IID_IUnknown, TRUE); + check_interface(dms8, &IID_IKsControl, TRUE);
/* Unsupported interfaces */ - hr = IDirectMusicSynth8_QueryInterface(dms8, &IID_IDirectMusicSynthSink, (void**)&unk); - ok(hr == E_NOINTERFACE, "QueryInterface for IID_IDirectMusicSynthSink failed: %#lx\n", hr); - hr = IDirectMusicSynth8_QueryInterface(dms8, &IID_IReferenceClock, (void**)&unk); - ok(hr == E_NOINTERFACE, "QueryInterface for IID_IReferenceClock failed: %#lx\n", hr); + check_interface(dms8, &IID_IDirectMusicSynthSink, FALSE); + check_interface(dms8, &IID_IReferenceClock, FALSE);
- while (IDirectMusicSynth8_Release(dms8)); + IDirectMusicSynth8_Release(dms8); }
static void test_COM_synthsink(void) { IDirectMusicSynthSink *dmss = (IDirectMusicSynthSink*)0xdeadbeef; - IKsControl *iksc; - IUnknown *unk; - ULONG refcount; HRESULT hr;
/* COM aggregation */ @@ -386,27 +379,16 @@ static void test_COM_synthsink(void) hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynthSink, (void**)&dmss); ok(hr == S_OK, "DirectMusicSynthSink create failed: %#lx, expected S_OK\n", hr); - refcount = IDirectMusicSynthSink_AddRef(dmss); - ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
- hr = IDirectMusicSynthSink_QueryInterface(dmss, &IID_IKsControl, (void**)&iksc); - ok(hr == S_OK, "QueryInterface for IID_IKsControl failed: %#lx\n", hr); - refcount = IKsControl_AddRef(iksc); - ok(refcount == 4, "refcount == %lu, expected 4\n", refcount); - IKsControl_Release(iksc); - - hr = IDirectMusicSynthSink_QueryInterface(dmss, &IID_IUnknown, (void**)&unk); - ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr); - refcount = IUnknown_AddRef(unk); - ok(refcount == 5, "refcount == %lu, expected 5\n", refcount); - IUnknown_Release(unk); + check_interface(dmss, &IID_IUnknown, TRUE); + check_interface(dmss, &IID_IKsControl, TRUE);
/* Unsupported interfaces */ - hr = IDirectMusicSynthSink_QueryInterface(dmss, &IID_IReferenceClock, (void**)&unk); - ok(hr == E_NOINTERFACE, "QueryInterface for IID_IReferenceClock failed: %#lx\n", hr); + check_interface(dmss, &IID_IReferenceClock, FALSE);
- while (IDirectMusicSynthSink_Release(dmss)); + IDirectMusicSynthSink_Release(dmss); } + START_TEST(dmsynth) { CoInitializeEx(NULL, COINIT_MULTITHREADED);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/tests/Makefile.in | 2 +- dlls/dmsynth/tests/dmsynth.c | 373 +++++++++++++++++++++++++++++++++ 2 files changed, 374 insertions(+), 1 deletion(-)
diff --git a/dlls/dmsynth/tests/Makefile.in b/dlls/dmsynth/tests/Makefile.in index 5f2fce7b8b1..1119bb09ce7 100644 --- a/dlls/dmsynth/tests/Makefile.in +++ b/dlls/dmsynth/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = dmsynth.dll -IMPORTS = oleaut32 ole32 uuid +IMPORTS = oleaut32 ole32 uuid dsound user32
C_SRCS = \ dmsynth.c diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 4c47cecfbf3..34fed3fab8e 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -64,6 +64,212 @@ static ULONG get_refcount(void *iface) return IUnknown_Release(unknown); }
+struct test_synth +{ + IDirectMusicSynth8 IDirectMusicSynth8_iface; + LONG refcount; +}; + +static HRESULT WINAPI test_synth_QueryInterface(IDirectMusicSynth8 *iface, REFIID riid, void** ppvObject) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static ULONG WINAPI test_synth_AddRef(IDirectMusicSynth8 *iface) +{ + struct test_synth *sink = CONTAINING_RECORD(iface, struct test_synth, IDirectMusicSynth8_iface); + return InterlockedIncrement(&sink->refcount); +} + +static ULONG WINAPI test_synth_Release(IDirectMusicSynth8 *iface) +{ + struct test_synth *sink = CONTAINING_RECORD(iface, struct test_synth, IDirectMusicSynth8_iface); + ULONG ref = InterlockedDecrement(&sink->refcount); + if (!ref) free(sink); + return ref; +} + +static HRESULT WINAPI test_synth_Open(IDirectMusicSynth8 *iface, LPDMUS_PORTPARAMS pPortParams) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_Close(IDirectMusicSynth8 *iface) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_SetNumChannelGroups(IDirectMusicSynth8 *iface, DWORD dwGroups) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_Download(IDirectMusicSynth8 *iface, LPHANDLE phDownload, LPVOID pvData, LPBOOL pbFree) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_Unload(IDirectMusicSynth8 *iface, HANDLE hDownload, HRESULT (CALLBACK* lpFreeHandle)(HANDLE,HANDLE), HANDLE hUserData) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_PlayBuffer(IDirectMusicSynth8 *iface, REFERENCE_TIME rt, LPBYTE pbBuffer, DWORD cbBuffer) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_GetRunningStats(IDirectMusicSynth8 *iface, LPDMUS_SYNTHSTATS pStats) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_GetPortCaps(IDirectMusicSynth8 *iface, LPDMUS_PORTCAPS pCaps) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_SetMasterClock(IDirectMusicSynth8 *iface, IReferenceClock *pClock) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_GetLatencyClock(IDirectMusicSynth8 *iface, IReferenceClock **ppClock) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_Activate(IDirectMusicSynth8 *iface, BOOL fEnable) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_SetSynthSink(IDirectMusicSynth8 *iface, IDirectMusicSynthSink *pSynthSink) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_Render(IDirectMusicSynth8 *iface, short *buffer, DWORD length, LONGLONG position) +{ + return S_OK; +} + +static HRESULT WINAPI test_synth_SetChannelPriority(IDirectMusicSynth8 *iface, DWORD dwChannelGroup, DWORD dwChannel, DWORD dwPriority) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_GetChannelPriority(IDirectMusicSynth8 *iface, DWORD dwChannelGroup, DWORD dwChannel, LPDWORD pdwPriority) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_GetFormat(IDirectMusicSynth8 *iface, WAVEFORMATEX *format, DWORD *ext_size) +{ + *ext_size = 0; + memset(format, 0, sizeof(*format)); + format->wFormatTag = WAVE_FORMAT_PCM; + format->nChannels = 2; + format->wBitsPerSample = 16; + format->nSamplesPerSec = 44100; + format->nBlockAlign = format->nChannels * format->wBitsPerSample / 8; + format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign; + return S_OK; +} + +static HRESULT WINAPI test_synth_GetAppend(IDirectMusicSynth8 *iface, DWORD *pdwAppend) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_PlayVoice(IDirectMusicSynth8 *iface, REFERENCE_TIME rt, DWORD dwVoiceId, DWORD dwChannelGroup, DWORD dwChannel, DWORD dwDLId, LONG prPitch, LONG vrVolume, SAMPLE_TIME stVoiceStart, SAMPLE_TIME stLoopStart, SAMPLE_TIME stLoopEnd) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_StopVoice(IDirectMusicSynth8 *iface, REFERENCE_TIME rt, DWORD dwVoiceId) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_GetVoiceState(IDirectMusicSynth8 *iface, DWORD dwVoice[], DWORD cbVoice, DMUS_VOICE_STATE dwVoiceState[]) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_Refresh(IDirectMusicSynth8 *iface, DWORD dwDownloadID, DWORD dwFlags) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_AssignChannelToBuses(IDirectMusicSynth8 *iface, DWORD dwChannelGroup, DWORD dwChannel, LPDWORD pdwBuses, DWORD cBuses) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static const IDirectMusicSynth8Vtbl test_synth_vtbl = +{ + test_synth_QueryInterface, + test_synth_AddRef, + test_synth_Release, + test_synth_Open, + test_synth_Close, + test_synth_SetNumChannelGroups, + test_synth_Download, + test_synth_Unload, + test_synth_PlayBuffer, + test_synth_GetRunningStats, + test_synth_GetPortCaps, + test_synth_SetMasterClock, + test_synth_GetLatencyClock, + test_synth_Activate, + test_synth_SetSynthSink, + test_synth_Render, + test_synth_SetChannelPriority, + test_synth_GetChannelPriority, + test_synth_GetFormat, + test_synth_GetAppend, + test_synth_PlayVoice, + test_synth_StopVoice, + test_synth_GetVoiceState, + test_synth_Refresh, + test_synth_AssignChannelToBuses, +}; + +static HRESULT test_synth_create(IDirectMusicSynth8 **out) +{ + struct test_synth *synth; + + *out = NULL; + if (!(synth = calloc(1, sizeof(*synth)))) return E_OUTOFMEMORY; + synth->IDirectMusicSynth8_iface.lpVtbl = &test_synth_vtbl; + synth->refcount = 1; + + *out = &synth->IDirectMusicSynth8_iface; + return S_OK; +} + static void test_synth_getformat(IDirectMusicSynth *synth, DMUS_PORTPARAMS *params, const char *context) { WAVEFORMATEX format; @@ -389,6 +595,172 @@ static void test_COM_synthsink(void) IDirectMusicSynthSink_Release(dmss); }
+static void test_IDirectMusicSynthSink(void) +{ + IReferenceClock *latency_clock; + REFERENCE_TIME time, tmp_time; + IDirectMusicSynthSink *sink; + IDirectMusicSynth8 *synth; + IReferenceClock *clock; + IDirectSound *dsound; + IDirectMusic *music; + LONGLONG sample; + HRESULT hr; + DWORD size; + ULONG ref; + + hr = DirectSoundCreate(NULL, &dsound, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectSound_SetCooperativeLevel(dsound, GetDesktopWindow(), DSSCL_PRIORITY); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusic, (void **)&music); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusic_GetMasterClock(music, NULL, &clock); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusic_Release(music); + + hr = test_synth_create(&synth); + ok(hr == S_OK, "got %#lx\n", hr); + + + hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSynthSink, (void **)&sink); + ok(hr == S_OK, "got %#lx\n", hr); + + /* sink is not configured */ + hr = IDirectMusicSynthSink_Activate(sink, TRUE); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_Activate(sink, FALSE); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSynthSink_SampleToRefTime(sink, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + time = 0xdeadbeef; + hr = IDirectMusicSynthSink_SampleToRefTime(sink, 10, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 4000, "got %I64d\n", time); + + hr = IDirectMusicSynthSink_RefTimeToSample(sink, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + sample = 0xdeadbeef; + hr = IDirectMusicSynthSink_RefTimeToSample(sink, 4000, &sample); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(sample == 8, "got %I64d\n", sample); + + hr = IDirectMusicSynthSink_GetDesiredBufferSize(sink, &size); + ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + /* latency clock is available but not usable */ + hr = IDirectMusicSynthSink_GetLatencyClock(sink, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + ref = get_refcount(sink); + ok(ref == 1, "got %#lx\n", ref); + hr = IDirectMusicSynthSink_GetLatencyClock(sink, &latency_clock); + ok(hr == S_OK, "got %#lx\n", hr); + ok(latency_clock != clock, "got same clock\n"); + ref = get_refcount(sink); + todo_wine ok(ref == 2, "got %#lx\n", ref); + + hr = IReferenceClock_GetTime(latency_clock, NULL); + todo_wine ok(hr == E_INVALIDARG, "got %#lx\n", hr); + hr = IReferenceClock_GetTime(latency_clock, &time); + todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + + hr = IDirectMusicSynthSink_Init(sink, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetDirectSound(sink, NULL, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetDirectSound(sink, dsound, NULL); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + /* Activate requires a synth, dsound and a clock */ + ref = get_refcount(synth); + ok(ref == 1, "got %#lx\n", ref); + hr = IDirectMusicSynthSink_Init(sink, (IDirectMusicSynth *)synth); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(synth); + ok(ref == 1, "got %#lx\n", ref); + hr = IDirectMusicSynthSink_GetDesiredBufferSize(sink, &size); + ok(hr == S_OK, "got %#lx\n", hr); + ok(size == 352800, "got %lu\n", size); + hr = IDirectMusicSynthSink_Activate(sink, TRUE); + todo_wine ok(hr == DMUS_E_DSOUND_NOT_SET, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetDirectSound(sink, dsound, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_Activate(sink, TRUE); + todo_wine ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetMasterClock(sink, clock); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IReferenceClock_GetTime(latency_clock, &time); + todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_Activate(sink, TRUE); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_Activate(sink, TRUE); + todo_wine ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); + ref = get_refcount(synth); + ok(ref == 1, "got %#lx\n", ref); + + hr = IDirectMusicSynthSink_GetDesiredBufferSize(sink, &size); + ok(hr == S_OK, "got %#lx\n", hr); + ok(size == 352800, "got %lu\n", size); + + /* conversion functions now use the activation time and master clock */ + hr = IReferenceClock_GetTime(clock, &time); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_RefTimeToSample(sink, time, &sample); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(sample <= 3000, "got %I64d\n", sample); + hr = IDirectMusicSynthSink_SampleToRefTime(sink, sample, &tmp_time); + ok(hr == S_OK, "got %#lx\n", hr); + ok(tmp_time <= time, "got %I64d\n", tmp_time - time); + todo_wine ok(time - tmp_time <= 5000, "got %I64d\n", tmp_time); + + /* latency clock now works fine */ + hr = IReferenceClock_GetTime(latency_clock, &tmp_time); + todo_wine_if(hr == S_FALSE) ok(hr == S_OK, "got %#lx\n", hr); + todo_wine_if(hr == S_FALSE) ok(tmp_time > time, "got %I64d\n", tmp_time - time); + ok(tmp_time - time <= 2000000, "got %I64d\n", tmp_time - time); + + /* setting the clock while active is fine */ + hr = IDirectMusicSynthSink_SetMasterClock(sink, clock); + ok(hr == S_OK, "got %#lx\n", hr); + + /* removing synth while active is fine */ + hr = IDirectMusicSynthSink_Init(sink, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(synth); + ok(ref == 1, "got %#lx\n", ref); + hr = IDirectMusicSynthSink_Activate(sink, TRUE); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + /* changing dsound while active fails */ + hr = IDirectMusicSynthSink_SetDirectSound(sink, dsound, NULL); + todo_wine ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetDirectSound(sink, NULL, NULL); + todo_wine ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_Activate(sink, FALSE); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetDirectSound(sink, NULL, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + /* SetMasterClock doesn't need the sink to be configured */ + hr = IDirectMusicSynthSink_SetMasterClock(sink, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetMasterClock(sink, clock); + ok(hr == S_OK, "got %#lx\n", hr); + + IReferenceClock_Release(latency_clock); + IDirectMusicSynthSink_Release(sink); + + + IDirectMusicSynth8_Release(synth); + IReferenceClock_Release(clock); + + IDirectSound_Release(dsound); +} + START_TEST(dmsynth) { CoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -402,6 +774,7 @@ START_TEST(dmsynth) test_dmsynth(); test_COM(); test_COM_synthsink(); + test_IDirectMusicSynthSink();
CoUninitialize(); }
From: Rémi Bernon rbernon@codeweavers.com
And more specifically how generating samples with Render works. --- dlls/dmsynth/tests/dmsynth.c | 542 +++++++++++++++++++++++++++++++++++ 1 file changed, 542 insertions(+)
diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 34fed3fab8e..1d3d50dfbf5 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -595,6 +595,547 @@ static void test_COM_synthsink(void) IDirectMusicSynthSink_Release(dmss); }
+struct test_sink +{ + IDirectMusicSynthSink IDirectMusicSynthSink_iface; + IReferenceClock IReferenceClock_iface; + LONG refcount; + + IReferenceClock *clock; + IDirectMusicSynth *synth; + REFERENCE_TIME activate_time; + REFERENCE_TIME latency_time; + DWORD written; +}; + +static HRESULT WINAPI test_sink_QueryInterface(IDirectMusicSynthSink *iface, REFIID riid, void** ppvObject) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static ULONG WINAPI test_sink_AddRef(IDirectMusicSynthSink *iface) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + return InterlockedIncrement(&sink->refcount); +} + +static ULONG WINAPI test_sink_Release(IDirectMusicSynthSink *iface) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + ULONG ref = InterlockedDecrement(&sink->refcount); + if (!ref) free(sink); + return ref; +} + +static HRESULT WINAPI test_sink_Init(IDirectMusicSynthSink *iface, IDirectMusicSynth *synth) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + sink->synth = synth; + return S_OK; +} + +static HRESULT WINAPI test_sink_SetMasterClock(IDirectMusicSynthSink *iface, IReferenceClock *clock) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + if (sink->clock) + IReferenceClock_Release(sink->clock); + if ((sink->clock = clock)) + IReferenceClock_AddRef(sink->clock); + return S_OK; +} + +static HRESULT WINAPI test_sink_GetLatencyClock(IDirectMusicSynthSink *iface, IReferenceClock **clock) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + *clock = &sink->IReferenceClock_iface; + IReferenceClock_AddRef(*clock); + return S_OK; +} + +static HRESULT WINAPI test_sink_Activate(IDirectMusicSynthSink *iface, BOOL fEnable) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + + if (!sink->clock) + return DMUS_E_NO_MASTER_CLOCK; + + IReferenceClock_GetTime(sink->clock, &sink->activate_time); + sink->latency_time = sink->activate_time; + return S_OK; +} + +static HRESULT WINAPI test_sink_SampleToRefTime(IDirectMusicSynthSink *iface, LONGLONG sample, REFERENCE_TIME *time) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + WAVEFORMATEX format; + DWORD format_size = sizeof(format); + HRESULT hr; + + hr = IDirectMusicSynth_GetFormat(sink->synth, &format, &format_size); + ok(hr == S_OK, "got %#lx\n", hr); + + *time = sink->activate_time + ((sample * 10000) / format.nSamplesPerSec) * 1000; + return S_OK; +} + +static HRESULT WINAPI test_sink_RefTimeToSample(IDirectMusicSynthSink *iface, REFERENCE_TIME time, LONGLONG *sample) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + WAVEFORMATEX format; + DWORD format_size = sizeof(format); + HRESULT hr; + + hr = IDirectMusicSynth_GetFormat(sink->synth, &format, &format_size); + ok(hr == S_OK, "got %#lx\n", hr); + + *sample = (((time - sink->activate_time) / 1000) * format.nSamplesPerSec) / 10000; + return S_OK; +} + +static HRESULT WINAPI test_sink_SetDirectSound(IDirectMusicSynthSink *iface, LPDIRECTSOUND pDirectSound, LPDIRECTSOUNDBUFFER buffer) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_sink_GetDesiredBufferSize(IDirectMusicSynthSink *iface, LPDWORD pdwBufferSizeInSamples) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static const IDirectMusicSynthSinkVtbl test_sink_vtbl = +{ + test_sink_QueryInterface, + test_sink_AddRef, + test_sink_Release, + test_sink_Init, + test_sink_SetMasterClock, + test_sink_GetLatencyClock, + test_sink_Activate, + test_sink_SampleToRefTime, + test_sink_RefTimeToSample, + test_sink_SetDirectSound, + test_sink_GetDesiredBufferSize, +}; + +static HRESULT WINAPI test_sink_latency_clock_QueryInterface(IReferenceClock *iface, REFIID iid, void **out) +{ + ok(0, "unexpected %s\n", __func__); + return E_NOINTERFACE; +} + +static ULONG WINAPI test_sink_latency_clock_AddRef(IReferenceClock *iface) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IReferenceClock_iface); + return IDirectMusicSynthSink_AddRef(&sink->IDirectMusicSynthSink_iface); +} + +static ULONG WINAPI test_sink_latency_clock_Release(IReferenceClock *iface) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IReferenceClock_iface); + return IDirectMusicSynthSink_Release(&sink->IDirectMusicSynthSink_iface); +} + +static HRESULT WINAPI test_sink_latency_clock_GetTime(IReferenceClock *iface, REFERENCE_TIME *time) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IReferenceClock_iface); + *time = sink->latency_time; + return S_OK; +} + +static HRESULT WINAPI test_sink_latency_clock_AdviseTime(IReferenceClock *iface, + REFERENCE_TIME base, REFERENCE_TIME offset, HANDLE event, DWORD *cookie) +{ + ok(0, "unexpected %s\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_sink_latency_clock_AdvisePeriodic(IReferenceClock *iface, + REFERENCE_TIME start, REFERENCE_TIME period, HANDLE semaphore, DWORD *cookie) +{ + ok(0, "unexpected %s\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_sink_latency_clock_Unadvise(IReferenceClock *iface, DWORD cookie) +{ + ok(0, "unexpected %s\n", __func__); + return E_NOTIMPL; +} + +static const IReferenceClockVtbl test_sink_latency_clock_vtbl = +{ + test_sink_latency_clock_QueryInterface, + test_sink_latency_clock_AddRef, + test_sink_latency_clock_Release, + test_sink_latency_clock_GetTime, + test_sink_latency_clock_AdviseTime, + test_sink_latency_clock_AdvisePeriodic, + test_sink_latency_clock_Unadvise, +}; + +static HRESULT test_sink_create(IDirectMusicSynthSink **out) +{ + struct test_sink *sink; + + *out = NULL; + if (!(sink = calloc(1, sizeof(*sink)))) return E_OUTOFMEMORY; + sink->IDirectMusicSynthSink_iface.lpVtbl = &test_sink_vtbl; + sink->IReferenceClock_iface.lpVtbl = &test_sink_latency_clock_vtbl; + sink->refcount = 1; + + *out = &sink->IDirectMusicSynthSink_iface; + return S_OK; +} + +static void test_sink_render(IDirectMusicSynthSink *iface, void *buffer, DWORD buffer_size, HANDLE output) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + DWORD written, format_size; + WAVEFORMATEX format; + HRESULT hr; + + format_size = sizeof(format); + hr = IDirectMusicSynth_GetFormat(sink->synth, &format, &format_size); + ok(hr == S_OK, "got %#lx\n", hr); + + memset(buffer, 0, buffer_size); + hr = IDirectMusicSynth_Render(sink->synth, buffer, buffer_size / format.nBlockAlign, sink->written / format.nBlockAlign); + ok(hr == S_OK, "got %#lx\n", hr); + sink->written += buffer_size; + + hr = IDirectMusicSynthSink_SampleToRefTime(iface, sink->written / format.nBlockAlign, &sink->latency_time); + ok(hr == S_OK, "got %#lx\n", hr); + + if (output) + { + BOOL ret = WriteFile(output, buffer, buffer_size, &written, NULL); + ok(!!ret, "WriteFile failed, error %lu.\n", GetLastError()); + } +} + +static void test_IDirectMusicSynth(void) +{ + static const UINT RENDER_ITERATIONS = 8; + + struct wave_download + { + DMUS_DOWNLOADINFO info; + ULONG offsets[2]; + DMUS_WAVE wave; + union + { + DMUS_WAVEDATA wave_data; + struct + { + ULONG size; + BYTE samples[256]; + }; + }; + } wave_download = + { + .info = + { + .dwDLType = DMUS_DOWNLOADINFO_WAVE, + .dwDLId = 1, + .dwNumOffsetTableEntries = 2, + .cbSize = sizeof(struct wave_download), + }, + .offsets = + { + offsetof(struct wave_download, wave), + offsetof(struct wave_download, wave_data), + }, + .wave = + { + .ulWaveDataIdx = 1, + .WaveformatEx = + { + .wFormatTag = WAVE_FORMAT_PCM, + .nChannels = 1, + .wBitsPerSample = 8, + .nSamplesPerSec = 44100, + .nAvgBytesPerSec = 44100, + .nBlockAlign = 1, + }, + }, + .wave_data = + { + .cbSize = sizeof(wave_download.samples), + }, + }; + struct instrument_download + { + DMUS_DOWNLOADINFO info; + ULONG offsets[4]; + DMUS_INSTRUMENT instrument; + DMUS_REGION region; + DMUS_ARTICULATION articulation; + DMUS_ARTICPARAMS artic_params; + } instrument_download = + { + .info = + { + .dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT, + .dwDLId = 2, + .dwNumOffsetTableEntries = 4, + .cbSize = sizeof(struct instrument_download), + }, + .offsets = + { + offsetof(struct instrument_download, instrument), + offsetof(struct instrument_download, region), + offsetof(struct instrument_download, articulation), + offsetof(struct instrument_download, artic_params), + }, + .instrument = + { + .ulPatch = 0, + .ulFirstRegionIdx = 1, + .ulGlobalArtIdx = 2, + }, + .region = + { + .RangeKey = {.usLow = 0, .usHigh = 127}, + .RangeVelocity = {.usLow = 0, .usHigh = 127}, + .fusOptions = F_RGN_OPTION_SELFNONEXCLUSIVE, + .WaveLink = {.ulChannel = 1, .ulTableIndex = 1}, + .WSMP = {.cbSize = sizeof(WSMPL), .usUnityNote = 60, .fulOptions = F_WSMP_NO_TRUNCATION}, + .WLOOP[0] = {.cbSize = sizeof(WLOOP), .ulType = WLOOP_TYPE_FORWARD}, + }, + .articulation = {.ulArt1Idx = 3}, + .artic_params = + { + .VolEG = {.tcAttack = 32768u << 16, .tcDecay = 32768u << 16, .ptSustain = 10000 << 16, .tcRelease = 32768u << 16}, + }, + }; + DMUS_BUFFERDESC buffer_desc = + { + .dwSize = sizeof(DMUS_BUFFERDESC), + .cbBuffer = 4096, + }; + DMUS_PORTPARAMS port_params = + { + .dwSize = sizeof(DMUS_PORTPARAMS), + .dwValidParams = DMUS_PORTPARAMS_AUDIOCHANNELS | DMUS_PORTPARAMS_SAMPLERATE, + .dwAudioChannels = 2, + .dwSampleRate = 44100, + }; + WCHAR temp_path[MAX_PATH], temp_file[MAX_PATH]; + IReferenceClock *latency_clock; + IDirectMusicSynthSink *sink; + IDirectMusicBuffer *buffer; + DWORD format_size, written; + IDirectMusicSynth *synth; + HANDLE wave_file, handle; + IReferenceClock *clock; + BOOL can_free = FALSE; + REFERENCE_TIME time; + WAVEFORMATEX format; + IDirectMusic *music; + short samples[256]; + ULONG i, ref; + HRESULT hr; + DWORD len; + BYTE *raw; + BOOL ret; + + hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusic, (void **)&music); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusic_GetMasterClock(music, NULL, &clock); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = test_sink_create(&sink); + ok(hr == S_OK, "got %#lx\n", hr); + + + hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSynth, (void **)&synth); + ok(hr == S_OK, "got %#lx\n", hr); + + /* SetNumChannelGroups needs Open */ + hr = IDirectMusicSynth_SetNumChannelGroups(synth, 1); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + /* GetFormat needs Open */ + hr = IDirectMusicSynth_GetFormat(synth, NULL, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicSynth_GetFormat(synth, NULL, &format_size); + ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + /* Open / Close don't need a sink */ + hr = IDirectMusicSynth_Open(synth, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Open(synth, NULL); + ok(hr == DMUS_E_ALREADYOPEN, "got %#lx\n", hr); + hr = IDirectMusicSynth_SetNumChannelGroups(synth, 1); + ok(hr == S_OK, "got %#lx\n", hr); + format_size = sizeof(format); + hr = IDirectMusicSynth_GetFormat(synth, NULL, &format_size); + ok(hr == S_OK, "got %#lx\n", hr); + ok(format_size == sizeof(format), "got %lu\n", format_size); + hr = IDirectMusicSynth_Close(synth); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Close(synth); + ok(hr == DMUS_E_ALREADYCLOSED, "got %#lx\n", hr); + + /* GetLatencyClock needs a sink */ + hr = IDirectMusicSynth_GetLatencyClock(synth, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicSynth_GetLatencyClock(synth, &latency_clock); + ok(hr == DMUS_E_NOSYNTHSINK, "got %#lx\n", hr); + + /* Activate needs a sink, synth to be open, and a master clock on the sink */ + hr = IDirectMusicSynth_Open(synth, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Activate(synth, TRUE); + ok(hr == DMUS_E_NOSYNTHSINK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Activate(synth, FALSE); + todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + + hr = IDirectMusicSynth_SetSynthSink(synth, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_SetSynthSink(synth, sink); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(sink); + todo_wine ok(ref == 2, "got %lu\n", ref); + hr = IDirectMusicSynth_Activate(synth, TRUE); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + /* SetMasterClock does nothing */ + hr = IDirectMusicSynth_SetMasterClock(synth, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicSynth_SetMasterClock(synth, clock); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(clock); + todo_wine ok(ref == 1, "got %lu\n", ref); + hr = IDirectMusicSynth_Activate(synth, TRUE); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + /* SetMasterClock needs to be called on the sink */ + hr = IDirectMusicSynthSink_SetMasterClock(sink, clock); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Activate(synth, TRUE); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Activate(synth, TRUE); + todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + + /* Close is fine while active */ + hr = IDirectMusicSynth_Close(synth); + ok(hr == S_OK, "got %#lx\n", hr); + /* Removing the sink is fine while active */ + hr = IDirectMusicSynth_SetSynthSink(synth, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(sink); + ok(ref == 1, "got %lu\n", ref); + + /* but Activate might fail then */ + hr = IDirectMusicSynth_Activate(synth, FALSE); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + hr = IDirectMusicSynth_Activate(synth, FALSE); + todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + + + /* Test generating some samples */ + hr = IDirectMusicSynth_Open(synth, &port_params); + ok(hr == S_OK, "got %#lx\n", hr); + + format_size = sizeof(format); + hr = IDirectMusicSynth_GetFormat(synth, &format, &format_size); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_SetSynthSink(synth, sink); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(sink); + todo_wine ok(ref == 2, "got %lu\n", ref); + hr = IDirectMusicSynth_Activate(synth, TRUE); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + + GetTempPathW(MAX_PATH, temp_path); + GetTempFileNameW(temp_path, L"synth", 0, temp_file); + wave_file = CreateFileW(temp_file, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(wave_file != INVALID_HANDLE_VALUE, "CreateFileW failed, error %lu.\n", GetLastError()); + ret = WriteFile(wave_file, "RIFF", 4, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + format_size = (RENDER_ITERATIONS + 1) * sizeof(samples) + sizeof(format) + 20; + ret = WriteFile(wave_file, &format_size, 4, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + ret = WriteFile(wave_file, "WAVEfmt ", 8, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + format_size = sizeof(format); + ret = WriteFile(wave_file, &format_size, 4, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + ret = WriteFile(wave_file, &format, format_size, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + ret = WriteFile(wave_file, "data", 4, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + format_size = (RENDER_ITERATIONS + 1) * sizeof(samples); + ret = WriteFile(wave_file, &format_size, 4, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + + /* native needs to render at least once before producing samples */ + test_sink_render(sink, samples, sizeof(samples), wave_file); + + for (i = 0; i < ARRAY_SIZE(wave_download.samples); i++) + wave_download.samples[i] = i; + + can_free = 0xdeadbeef; + handle = (HANDLE)0xdeadbeef; + hr = IDirectMusicSynth_Download(synth, &handle, &wave_download, &can_free); + ok(hr == S_OK, "got %#lx\n", hr); + ok(handle != 0, "got %p\n", handle); + todo_wine ok(can_free == FALSE, "got %u\n", can_free); + + can_free = 0xdeadbeef; + handle = (HANDLE)0xdeadbeef; + hr = IDirectMusicSynth_Download(synth, &handle, &instrument_download, &can_free); + ok(hr == S_OK, "got %#lx\n", hr); + ok(handle != 0, "got %p\n", handle); + todo_wine ok(can_free == TRUE, "got %u\n", can_free); + + /* add a MIDI note to a buffer and play it */ + hr = IDirectMusicSynth_GetLatencyClock(synth, &latency_clock); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusic_CreateMusicBuffer(music, &buffer_desc, &buffer, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + /* status = 0x90 (NOTEON / channel 0), key = 0x27 (39), vel = 0x78 (120) */ + hr = IDirectMusicBuffer_PackStructured(buffer, 0, 1, 0x782790); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IReferenceClock_GetTime(latency_clock, &time); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicBuffer_GetRawBufferPtr(buffer, (BYTE **)&raw); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicBuffer_GetUsedBytes(buffer, &len); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_PlayBuffer(synth, time, (BYTE *)raw, len); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicBuffer_Release(buffer); + IReferenceClock_Release(latency_clock); + + for (i = 0; i < RENDER_ITERATIONS; i++) + test_sink_render(sink, samples, sizeof(samples), wave_file); + + CloseHandle(wave_file); + trace("Rendered samples to %s\n", debugstr_w(temp_file)); + + hr = IDirectMusicSynth_Activate(synth, FALSE); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_SetSynthSink(synth, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(sink); + ok(ref == 1, "got %lu\n", ref); + hr = IDirectMusicSynth_Close(synth); + ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicSynth_Release(synth); + + + if (strcmp(winetest_platform, "wine")) IDirectMusicSynthSink_Release(sink); + IReferenceClock_Release(clock); + IDirectMusic_Release(music); +} + static void test_IDirectMusicSynthSink(void) { IReferenceClock *latency_clock; @@ -774,6 +1315,7 @@ START_TEST(dmsynth) test_dmsynth(); test_COM(); test_COM_synthsink(); + test_IDirectMusicSynth(); test_IDirectMusicSynthSink();
CoUninitialize();
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=136804
Your paranoid android.
=== w11pro64_amd (64 bit report) ===
dmsynth: dmsynth.c:1154: Test failed: got 0x88780078 0724:dmsynth: unhandled exception c0000005 at 0000000000405146
=== debian11b (64 bit WoW report) ===
dmsynth: dmsynth.c:1264: Test failed: got -130
Fwiw I'm able to get a similar result as native on this synth test with a local rough implementation based on FluidSynth.