From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/tests/dmime.c | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 119bfc74fc5..59809c54785 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3627,6 +3627,51 @@ static void test_band_track_play(void) IDirectMusicTool_Release(tool); }
+static void test_connect_to_collection(void) +{ + IDirectMusicCollection *collection; + IDirectMusicSegment *segment; + IDirectMusicTrack *track; + void *param; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_DirectMusicCollection, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicCollection, (void **)&collection); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSegment, (void **)&segment); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CoCreateInstance(&CLSID_DirectMusicBandTrack, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicTrack, (void **)&track); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSegment_InsertTrack(segment, track, 1); + ok(hr == S_OK, "got %#lx\n", hr); + + /* it is possible to connect the band track to another collection, but not to disconnect it */ + hr = IDirectMusicTrack_IsParamSupported(track, &GUID_ConnectToDLSCollection); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicTrack_SetParam(track, &GUID_ConnectToDLSCollection, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicTrack_SetParam(track, &GUID_ConnectToDLSCollection, 0, collection); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicTrack_GetParam(track, &GUID_ConnectToDLSCollection, 0, NULL, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicTrack_GetParam(track, &GUID_ConnectToDLSCollection, 0, NULL, ¶m); + ok(hr == DMUS_E_GET_UNSUPPORTED, "got %#lx\n", hr); + + hr = IDirectMusicSegment_SetParam(segment, &GUID_ConnectToDLSCollection, -1, DMUS_SEG_ALLTRACKS, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetParam(segment, &GUID_ConnectToDLSCollection, -1, DMUS_SEG_ALLTRACKS, 0, collection); + ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicTrack_Release(track); + IDirectMusicSegment_Release(segment); + IDirectMusicCollection_Release(collection); +} + START_TEST(dmime) { CoInitialize(NULL); @@ -3662,6 +3707,7 @@ START_TEST(dmime) test_wave_pmsg(); test_sequence_track(); test_band_track_play(); + test_connect_to_collection();
CoUninitialize(); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/tests/dmime.c | 443 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 443 insertions(+)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 59809c54785..af807693413 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -555,6 +555,228 @@ static HRESULT test_loader_stream_create(IStream *stream, IDirectMusicLoader *lo return S_OK; }
+struct test_track +{ + /* Implementing IDirectMusicTrack8 will cause native to call PlayEx */ + IDirectMusicTrack IDirectMusicTrack_iface; + LONG ref; + + DWORD data; + BOOL inserted; + BOOL initialized; + BOOL downloaded; + BOOL playing; + HANDLE playing_event; +}; + +#define check_track_state(track, state, value) \ + do \ + { \ + DWORD ret = impl_from_IDirectMusicTrack(track)->state; \ + ok(ret == (value), "got %#lx\n", ret); \ + } while (0); + +static inline struct test_track *impl_from_IDirectMusicTrack(IDirectMusicTrack *iface) +{ + return CONTAINING_RECORD(iface, struct test_track, IDirectMusicTrack_iface); +} + +static HRESULT WINAPI test_track_QueryInterface(IDirectMusicTrack *iface, REFIID riid, + void **ret_iface) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + + if (IsEqualIID(riid, &IID_IUnknown) + || IsEqualIID(riid, &IID_IDirectMusicTrack)) + { + *ret_iface = &This->IDirectMusicTrack_iface; + IDirectMusicTrack_AddRef(&This->IDirectMusicTrack_iface); + return S_OK; + } + + ok(IsEqualGUID(riid, &IID_IDirectMusicTrack8) || IsEqualGUID(riid, &IID_IPersistStream), + "unexpected %s %p %s\n", __func__, This, debugstr_guid(riid)); + *ret_iface = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_track_AddRef(IDirectMusicTrack *iface) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI test_track_Release(IDirectMusicTrack *iface) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + if (!ref) + { + CloseHandle(This->playing_event); + free(This); + } + + return ref; +} + +static HRESULT WINAPI test_track_Init(IDirectMusicTrack *iface, IDirectMusicSegment *segment) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + This->inserted = TRUE; + return S_OK; +} + +static HRESULT WINAPI test_track_InitPlay(IDirectMusicTrack *iface, IDirectMusicSegmentState *segment_state, + IDirectMusicPerformance *performance, void **state_data, DWORD track_id, DWORD segment_flags) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + + ok(!!segment_state, "got %p\n", segment_state); + ok(!!performance, "got %p\n", performance); + ok(!!state_data, "got %p\n", state_data); + ok(!!track_id, "got %lu\n", track_id); + ok(!segment_flags, "got %#lx\n", segment_flags); + This->initialized = TRUE; + + *state_data = &This->data; + return S_OK; +} + +static HRESULT WINAPI test_track_EndPlay(IDirectMusicTrack *iface, void *state_data) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + + ok(state_data == &This->data, "got %p\n", state_data); + This->playing = FALSE; + + return S_OK; +} + +static HRESULT WINAPI test_track_Play(IDirectMusicTrack *iface, void *state_data, + MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD segment_flags, + IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD track_id) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + + ok(state_data == &This->data, "got %p\n", state_data); + ok(start_time == 50, "got %lu\n", start_time); + ok(end_time == 100, "got %lu\n", end_time); + ok(time_offset < 0, "got %lu\n", time_offset); + ok(segment_flags == (DMUS_TRACKF_DIRTY|DMUS_TRACKF_START|DMUS_TRACKF_SEEK), + "got %#lx\n", segment_flags); + ok(!!performance, "got %p\n", performance); + ok(!!segment_state, "got %p\n", segment_state); + ok(!!track_id, "got %lu\n", track_id); + This->playing = TRUE; + SetEvent(This->playing_event); + + return S_OK; +} + +static HRESULT WINAPI test_track_GetParam(IDirectMusicTrack *iface, REFGUID type, MUSIC_TIME time, + MUSIC_TIME *next, void *param) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + ok(0, "unexpected %s %p\n", __func__, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_track_SetParam(IDirectMusicTrack *iface, REFGUID type, MUSIC_TIME time, void *param) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + + if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) + { + This->downloaded = TRUE; + return S_OK; + } + + if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) + { + This->downloaded = FALSE; + return S_OK; + } + + ok(0, "unexpected %s %p %s %lu %p\n", __func__, This, debugstr_guid(type), time, param); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_track_IsParamSupported(IDirectMusicTrack *iface, REFGUID type) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + + if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) return S_OK; + if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) return S_OK; + if (IsEqualGUID(type, &GUID_TimeSignature)) return DMUS_E_TYPE_UNSUPPORTED; + if (IsEqualGUID(type, &GUID_TempoParam)) return DMUS_E_TYPE_UNSUPPORTED; + + ok(broken(type->Data1 == 0xe8dbd832), /* native also checks some unknown parameter */ + "unexpected %s %p %s\n", __func__, This, debugstr_guid(type)); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_track_AddNotificationType(IDirectMusicTrack *iface, REFGUID type) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + ok(0, "unexpected %s %p\n", __func__, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_track_RemoveNotificationType(IDirectMusicTrack *iface, REFGUID type) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + ok(0, "unexpected %s %p\n", __func__, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_track_Clone(IDirectMusicTrack *iface, MUSIC_TIME start_time, + MUSIC_TIME end_time, IDirectMusicTrack **ret_track) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + ok(0, "unexpected %s %p\n", __func__, This); + return E_NOTIMPL; +} + +static const IDirectMusicTrackVtbl test_track_vtbl = +{ + test_track_QueryInterface, + test_track_AddRef, + test_track_Release, + test_track_Init, + test_track_InitPlay, + test_track_EndPlay, + test_track_Play, + test_track_GetParam, + test_track_SetParam, + test_track_IsParamSupported, + test_track_AddNotificationType, + test_track_RemoveNotificationType, + test_track_Clone, +}; + +static HRESULT test_track_create(IDirectMusicTrack **ret_iface) +{ + struct test_track *track; + + *ret_iface = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; + track->IDirectMusicTrack_iface.lpVtbl = &test_track_vtbl; + track->ref = 1; + + track->playing_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!track->playing_event, "CreateEventW failed, error %lu\n", GetLastError()); + + *ret_iface = &track->IDirectMusicTrack_iface; + return S_OK; +} + +static DWORD test_track_wait_playing(IDirectMusicTrack *iface, DWORD timeout) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + return WaitForSingleObject(This->playing_event, timeout); +} + static void create_performance(IDirectMusicPerformance8 **performance, IDirectMusic **dmusic, IDirectSound **dsound, BOOL set_cooplevel) { @@ -3672,6 +3894,226 @@ static void test_connect_to_collection(void) IDirectMusicCollection_Release(collection); }
+static void test_segment_state(void) +{ + static const DWORD message_types[] = + { + DMUS_PMSGT_DIRTY, + DMUS_PMSGT_NOTIFICATION, + DMUS_PMSGT_WAVE, + }; + IDirectMusicSegmentState *state, *tmp_state; + IDirectMusicSegment *segment, *tmp_segment; + IDirectMusicPerformance *performance; + IDirectMusicTrack *track; + IDirectMusicGraph *graph; + IDirectMusicTool *tool; + DWORD value, ret; + MUSIC_TIME time; + HRESULT hr; + + hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool); + ok(hr == S_OK, "got %#lx\n", hr); + hr = test_track_create(&track); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance, (void **)&performance); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicGraph, (void **)&graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SetGraph(performance, graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicGraph_Release(graph); + + + hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSegment, (void **)&segment); + ok(hr == S_OK, "got %#lx\n", hr); + + check_track_state(track, inserted, FALSE); + hr = IDirectMusicSegment_InsertTrack(segment, track, 1); + ok(hr == S_OK, "got %#lx\n", hr); + check_track_state(track, inserted, TRUE); + + check_track_state(track, downloaded, FALSE); + hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine check_track_state(track, downloaded, TRUE); + hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance); + ok(hr == S_OK, "got %#lx\n", hr); + check_track_state(track, downloaded, FALSE); + + + /* by default the segment length is 1 */ + + time = 0xdeadbeef; + hr = IDirectMusicSegment_GetLength(segment, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 1, "got %lu\n", time); + hr = IDirectMusicSegment_SetStartPoint(segment, 50); + ok(hr == DMUS_E_OUT_OF_RANGE, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetRepeats(segment, 10); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetLoopPoints(segment, 10, 70); + ok(hr == DMUS_E_OUT_OF_RANGE, "got %#lx\n", hr); + + /* Setting a larger length will cause PlayEx to be called multiple times, + * as native splits the segment into chunks and play each chunk separately */ + hr = IDirectMusicSegment_SetLength(segment, 100); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetStartPoint(segment, 50); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetRepeats(segment, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetLoopPoints(segment, 0, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + + /* InitPlay returns a dummy segment state */ + + state = (void *)0xdeadbeef; + hr = IDirectMusicSegment_InitPlay(segment, &state, performance, 0); + ok(hr == S_OK, "got %#lx\n", hr); + ok(state != NULL, "got %p\n", state); + ok(state != (void *)0xdeadbeef, "got %p\n", state); + check_track_state(track, initialized, FALSE); + + tmp_segment = (void *)0xdeadbeef; + hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment); + todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + todo_wine ok(tmp_segment == NULL, "got %p\n", tmp_segment); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetStartPoint(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 0, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetRepeats(state, &value); + ok(hr == S_OK, "got %#lx\n", hr); + ok(time == 0xdeadbeef, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetStartTime(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == -1, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetSeek(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 0, "got %#lx\n", time); + + + /* PlaySegment returns a different, genuine segment state */ + + hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + check_track_state(track, downloaded, FALSE); + check_track_state(track, initialized, FALSE); + check_track_state(track, playing, FALSE); + + tmp_state = state; + state = (void *)0xdeadbeef; + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 20, &state); + ok(hr == S_OK, "got %#lx\n", hr); + ok(state != NULL, "got %p\n", state); + ok(state != (void *)0xdeadbeef, "got %p\n", state); + ok(state != tmp_state, "got %p\n", state); + IDirectMusicSegmentState_Release(tmp_state); + + check_track_state(track, downloaded, FALSE); + todo_wine check_track_state(track, initialized, TRUE); + + + /* The track can be removed from the segment */ + hr = IDirectMusicSegment_RemoveTrack(segment, track); + ok(hr == S_OK, "got %#lx\n", hr); + + + /* This might be timing dependent and if PlaySegment is already + * late, the tracks are played synchronously and right away. + */ + check_track_state(track, playing, FALSE); + + ret = test_track_wait_playing(track, 50); + todo_wine ok(ret == 0, "got %#lx\n", ret); + + + tmp_segment = (void *)0xdeadbeef; + hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(tmp_segment == segment, "got %p\n", tmp_segment); + if (tmp_segment != (void *)0xdeadbeef) IDirectMusicSegment_Release(tmp_segment); + + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetStartPoint(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 50, "got %lu\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetRepeats(state, &value); + ok(hr == S_OK, "got %#lx\n", hr); + ok(time == 0xdeadbeef, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetStartTime(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 20, "got %#lx\n", time); + time = 0xdeadbeef; + + /* The seek value is also dependent on whether the tracks are playing. + * It is initially 0, then start_point right before playing, then length. + */ + hr = IDirectMusicSegmentState_GetSeek(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 100, "got %#lx\n", time); + + /* changing the segment values doesn't change the segment state */ + + hr = IDirectMusicSegment_SetStartPoint(segment, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetRepeats(segment, 10); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetLoopPoints(segment, 50, 70); + ok(hr == S_OK, "got %#lx\n", hr); + + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetStartPoint(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 50, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetRepeats(state, &value); + ok(hr == S_OK, "got %#lx\n", hr); + ok(time == 0xdeadbeef, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetStartTime(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 20, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetSeek(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 100, "got %#lx\n", time); + + IDirectMusicSegment_Release(segment); + + + check_track_state(track, downloaded, FALSE); + todo_wine check_track_state(track, initialized, TRUE); + todo_wine check_track_state(track, playing, TRUE); + + hr = IDirectMusicPerformance_CloseDown(performance); + ok(hr == S_OK, "got %#lx\n", hr); + + check_track_state(track, downloaded, FALSE); + todo_wine check_track_state(track, initialized, TRUE); + check_track_state(track, playing, FALSE); + + + IDirectMusicPerformance_Release(performance); + IDirectMusicTrack_Release(track); + IDirectMusicTool_Release(tool); +} + START_TEST(dmime) { CoInitialize(NULL); @@ -3708,6 +4150,7 @@ START_TEST(dmime) test_sequence_track(); test_band_track_play(); test_connect_to_collection(); + test_segment_state();
CoUninitialize(); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/segment.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index a72ec786623..bc52931f667 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -392,12 +392,28 @@ static HRESULT WINAPI segment_GetParam(IDirectMusicSegment8 *iface, REFGUID type return hr; }
-static HRESULT WINAPI segment_SetParam(IDirectMusicSegment8 *iface, REFGUID rguidType, - DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam) +static HRESULT WINAPI segment_SetParam(IDirectMusicSegment8 *iface, REFGUID type, + DWORD group, DWORD index, MUSIC_TIME music_time, void *param) { struct segment *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %s, %#lx, %ld, %ld, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, - dwIndex, mtTime, pParam); + struct track_entry *entry; + HRESULT hr; + + TRACE("(%p, %s, %#lx, %ld, %ld, %p)\n", This, debugstr_dmguid(type), group, + index, music_time, param); + + LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) + { + if (group != -1 && !(group & entry->dwGroupBits)) continue; + if (index != DMUS_SEG_ALLTRACKS && index--) continue; + + hr = IDirectMusicTrack_IsParamSupported(entry->pTrack, type); + if (hr == DMUS_E_TYPE_UNSUPPORTED) continue; + + hr = IDirectMusicTrack_SetParam(entry->pTrack, type, music_time, param); + if (FAILED(hr)) break; + } + return S_OK; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmband/band.c | 26 ++++++++++++++++++++++ dlls/dmband/bandtrack.c | 7 +++++- dlls/dmband/dmband_private.h | 2 ++ dlls/dmusic/dmobject.c | 43 +++++++++++++++++++++++++----------- dlls/dmusic/dmobject.h | 3 +++ 5 files changed, 67 insertions(+), 14 deletions(-)
diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index d91775681bb..361df5f8986 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -59,6 +59,7 @@ struct band struct dmobject dmobj; LONG ref; struct list instruments; + IDirectMusicCollection *collection; };
static inline struct band *impl_from_IDirectMusicBand(IDirectMusicBand *iface) @@ -117,6 +118,7 @@ static ULONG WINAPI band_Release(IDirectMusicBand *iface) instrument_entry_destroy(entry); }
+ if (This->collection) IDirectMusicCollection_Release(This->collection); free(This); }
@@ -336,11 +338,23 @@ static inline struct band *impl_from_IPersistStream(IPersistStream *iface) static HRESULT WINAPI band_persist_stream_Load(IPersistStream *iface, IStream *stream) { struct band *This = impl_from_IPersistStream(iface); + DMUS_OBJECTDESC default_desc = + { + .dwSize = sizeof(DMUS_OBJECTDESC), + .dwValidData = DMUS_OBJ_OBJECT | DMUS_OBJ_CLASS, + .guidClass = CLSID_DirectMusicCollection, + .guidObject = GUID_DefaultGMCollection, + }; struct chunk_entry chunk = {0}; HRESULT hr;
TRACE("%p, %p\n", iface, stream);
+ if (This->collection) IDirectMusicCollection_Release(This->collection); + if (FAILED(hr = stream_get_object(stream, &default_desc, &IID_IDirectMusicCollection, + (void **)&This->collection))) + WARN("Failed to load default collection from loader, hr %#lx\n", hr); + if ((hr = stream_get_chunk(stream, &chunk)) == S_OK) { switch (MAKE_IDTYPE(chunk.id, chunk.type)) @@ -408,3 +422,15 @@ HRESULT create_dmband(REFIID lpcGUID, void **ppobj)
return hr; } + +HRESULT band_connect_to_collection(IDirectMusicBand *iface, IDirectMusicCollection *collection) +{ + struct band *This = impl_from_IDirectMusicBand(iface); + + TRACE("%p, %p\n", iface, collection); + + if (This->collection) IDirectMusicCollection_Release(This->collection); + if ((This->collection = collection)) IDirectMusicCollection_AddRef(This->collection); + + return S_OK; +} diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index ab12e1f1355..45dc7ace86a 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -182,7 +182,12 @@ static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ else if (IsEqualGUID(type, &GUID_Clear_All_Bands)) FIXME("GUID_Clear_All_Bands not handled yet\n"); else if (IsEqualGUID(type, &GUID_ConnectToDLSCollection)) - FIXME("GUID_ConnectToDLSCollection not handled yet\n"); + { + struct band_entry *entry; + + LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry) + band_connect_to_collection(entry->band, param); + } else if (IsEqualGUID(type, &GUID_Disable_Auto_Download)) FIXME("GUID_Disable_Auto_Download not handled yet\n"); else if (IsEqualGUID(type, &GUID_Download)) diff --git a/dlls/dmband/dmband_private.h b/dlls/dmband/dmband_private.h index 444fe5ccf55..a12b9f8cc82 100644 --- a/dlls/dmband/dmband_private.h +++ b/dlls/dmband/dmband_private.h @@ -47,4 +47,6 @@ extern HRESULT create_dmband(REFIID riid, void **ret_iface); extern HRESULT create_dmbandtrack(REFIID riid, void **ret_iface);
+extern HRESULT band_connect_to_collection(IDirectMusicBand *iface, IDirectMusicCollection *collection); + #endif /* __WINE_DMBAND_PRIVATE_H */ diff --git a/dlls/dmusic/dmobject.c b/dlls/dmusic/dmobject.c index 3007aceef3e..8cb4719c4e6 100644 --- a/dlls/dmusic/dmobject.c +++ b/dlls/dmusic/dmobject.c @@ -444,6 +444,35 @@ HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, return S_OK; }
+HRESULT stream_get_loader(IStream *stream, IDirectMusicLoader **ret_loader) +{ + IDirectMusicGetLoader *getter; + HRESULT hr; + + if (SUCCEEDED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getter))) + { + hr = IDirectMusicGetLoader_GetLoader(getter, ret_loader); + IDirectMusicGetLoader_Release(getter); + } + + if (FAILED(hr)) *ret_loader = NULL; + return hr; +} + +HRESULT stream_get_object(IStream *stream, DMUS_OBJECTDESC *desc, REFIID iid, void **ret_iface) +{ + IDirectMusicLoader *loader; + HRESULT hr; + + if (SUCCEEDED(hr = stream_get_loader(stream, &loader))) + { + hr = IDirectMusicLoader_GetObject(loader, desc, iid, (void **)ret_iface); + IDirectMusicLoader_Release(loader); + } + + if (FAILED(hr)) *ret_iface = NULL; + return hr; +}
/* Generic IDirectMusicObject methods */ @@ -626,8 +655,6 @@ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, IDirectMusicObject **dmobj) { struct chunk_entry chunk = {.parent = list}; - IDirectMusicGetLoader *getloader; - IDirectMusicLoader *loader; DMUS_OBJECTDESC desc; DMUS_IO_REFERENCE reference; HRESULT hr; @@ -650,17 +677,7 @@ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, desc.dwValidData |= DMUS_OBJ_CLASS; dump_DMUS_OBJECTDESC(&desc);
- if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader))) - return hr; - hr = IDirectMusicGetLoader_GetLoader(getloader, &loader); - IDirectMusicGetLoader_Release(getloader); - if (FAILED(hr)) - return hr; - - hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj); - IDirectMusicLoader_Release(loader); - - return hr; + return stream_get_object(stream, &desc, &IID_IDirectMusicObject, (void **)dmobj); }
/* Generic IPersistStream methods */ diff --git a/dlls/dmusic/dmobject.h b/dlls/dmusic/dmobject.h index ae06935dfea..82ac05f31b9 100644 --- a/dlls/dmusic/dmobject.h +++ b/dlls/dmusic/dmobject.h @@ -44,6 +44,9 @@ HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, ULONG size);
+HRESULT stream_get_loader(IStream *stream, IDirectMusicLoader **ret_loader); +HRESULT stream_get_object(IStream *stream, DMUS_OBJECTDESC *desc, REFIID riid, void **ret_iface); + static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) { LARGE_INTEGER offset;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/segment.c | 12 ++++++------ dlls/dmime/tests/dmime.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index bc52931f667..af7729f34b9 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -530,18 +530,18 @@ static HRESULT WINAPI segment_Compose(IDirectMusicSegment8 *iface, MUSIC_TIME mt return S_OK; }
-static HRESULT WINAPI segment_Download(IDirectMusicSegment8 *iface, IUnknown *pAudioPath) +static HRESULT WINAPI segment_Download(IDirectMusicSegment8 *iface, IUnknown *audio_path) { struct segment *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %p): stub\n", This, pAudioPath); - return S_OK; + TRACE("(%p, %p)\n", This, audio_path); + return IDirectMusicSegment8_SetParam(iface, &GUID_DownloadToAudioPath, -1, DMUS_SEG_ALLTRACKS, 0, audio_path); }
-static HRESULT WINAPI segment_Unload(IDirectMusicSegment8 *iface, IUnknown *pAudioPath) +static HRESULT WINAPI segment_Unload(IDirectMusicSegment8 *iface, IUnknown *audio_path) { struct segment *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %p): stub\n", This, pAudioPath); - return S_OK; + TRACE("(%p, %p)\n", This, audio_path); + return IDirectMusicSegment8_SetParam(iface, &GUID_UnloadFromAudioPath, -1, DMUS_SEG_ALLTRACKS, 0, audio_path); }
static const IDirectMusicSegment8Vtbl segment_vtbl = diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index af807693413..864a749eff6 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3943,7 +3943,7 @@ static void test_segment_state(void) check_track_state(track, downloaded, FALSE); hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_track_state(track, downloaded, TRUE); + check_track_state(track, downloaded, TRUE); hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance); ok(hr == S_OK, "got %#lx\n", hr); check_track_state(track, downloaded, FALSE);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmband/band.c | 70 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 9 deletions(-)
diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index 361df5f8986..4b3c053c586 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -45,10 +45,30 @@ struct instrument_entry struct list entry; DMUS_IO_INSTRUMENT instrument; IDirectMusicCollection *collection; + + IDirectMusicDownloadedInstrument *download; + IDirectMusicPort *download_port; };
+static HRESULT instrument_entry_unload(struct instrument_entry *entry) +{ + HRESULT hr; + + if (!entry->download) return S_OK; + + if (FAILED(hr = IDirectMusicPort_UnloadInstrument(entry->download_port, entry->download))) + WARN("Failed to unload entry instrument, hr %#lx\n", hr); + IDirectMusicDownloadedInstrument_Release(entry->download); + entry->download = NULL; + IDirectMusicPort_Release(entry->download_port); + entry->download_port = NULL; + + return hr; +} + static void instrument_entry_destroy(struct instrument_entry *entry) { + instrument_entry_unload(entry); if (entry->collection) IDirectMusicCollection_Release(entry->collection); free(entry); } @@ -150,19 +170,51 @@ static HRESULT WINAPI band_CreateSegment(IDirectMusicBand *iface, }
static HRESULT WINAPI band_Download(IDirectMusicBand *iface, - IDirectMusicPerformance *pPerformance) + IDirectMusicPerformance *performance) { - struct band *This = impl_from_IDirectMusicBand(iface); - FIXME("(%p, %p): stub\n", This, pPerformance); - return S_OK; + struct band *This = impl_from_IDirectMusicBand(iface); + struct instrument_entry *entry; + HRESULT hr = S_OK; + + TRACE("(%p, %p)\n", This, performance); + + LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) + { + IDirectMusicCollection *collection; + IDirectMusicInstrument *instrument; + + if (FAILED(hr = instrument_entry_unload(entry))) break; + if (!(collection = entry->collection) && !(collection = This->collection)) continue; + + if (SUCCEEDED(hr = IDirectMusicCollection_GetInstrument(collection, entry->instrument.dwPatch, &instrument))) + { + hr = IDirectMusicPerformance_DownloadInstrument(performance, instrument, entry->instrument.dwPChannel, + &entry->download, NULL, 0, &entry->download_port, NULL, NULL); + IDirectMusicInstrument_Release(instrument); + } + + if (FAILED(hr)) break; + } + + if (FAILED(hr)) WARN("Failed to download instruments, hr %#lx\n", hr); + return hr; }
-static HRESULT WINAPI band_Unload(IDirectMusicBand *iface, - IDirectMusicPerformance *pPerformance) +static HRESULT WINAPI band_Unload(IDirectMusicBand *iface, IDirectMusicPerformance *performance) { - struct band *This = impl_from_IDirectMusicBand(iface); - FIXME("(%p, %p): stub\n", This, pPerformance); - return S_OK; + struct band *This = impl_from_IDirectMusicBand(iface); + struct instrument_entry *entry; + HRESULT hr = S_OK; + + TRACE("(%p, %p)\n", This, performance); + + if (performance) FIXME("performance parameter not implemented\n"); + + LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) + if (FAILED(hr = instrument_entry_unload(entry))) break; + + if (FAILED(hr)) WARN("Failed to unload instruments, hr %#lx\n", hr); + return hr; }
static const IDirectMusicBandVtbl band_vtbl =
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmband/bandtrack.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index 45dc7ace86a..b808faaf567 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -201,7 +201,13 @@ static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ else if (IsEqualGUID(type, &GUID_StandardMIDIFile)) FIXME("GUID_StandardMIDIFile not handled yet\n"); else if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) - FIXME("GUID_UnloadFromAudioPath not handled yet\n"); + { + struct band_entry *entry; + HRESULT hr; + + LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry) + if (FAILED(hr = IDirectMusicBand_Unload(entry->band, NULL))) break; + }
return S_OK; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmband/bandtrack.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index b808faaf567..845345a9fa2 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -193,7 +193,32 @@ static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ else if (IsEqualGUID(type, &GUID_Download)) FIXME("GUID_Download not handled yet\n"); else if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) - FIXME("GUID_DownloadToAudioPath not handled yet\n"); + { + IDirectMusicPerformance *performance; + IDirectMusicAudioPath *audio_path; + IUnknown *object = param; + struct band_entry *entry; + HRESULT hr; + + if (FAILED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicPerformance8, (void **)&performance)) + && SUCCEEDED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicAudioPath, (void **)&audio_path))) + { + hr = IDirectMusicAudioPath_GetObjectInPath(audio_path, DMUS_PCHANNEL_ALL, DMUS_PATH_PERFORMANCE, 0, + &GUID_All_Objects, 0, &IID_IDirectMusicPerformance8, (void **)&performance); + IDirectMusicAudioPath_Release(audio_path); + } + + if (FAILED(hr)) + { + WARN("Failed to get IDirectMusicPerformance from param %p\n", param); + return hr; + } + + LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry) + if (FAILED(hr = IDirectMusicBand_Download(entry->band, performance))) break; + + IDirectMusicPerformance_Release(performance); + } else if (IsEqualGUID(type, &GUID_Enable_Auto_Download)) FIXME("GUID_Enable_Auto_Download not handled yet\n"); else if (IsEqualGUID(type, &GUID_IDirectMusicBand))
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/performance.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index bdb7475370a..111d7c60568 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -828,14 +828,24 @@ static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, }
static HRESULT WINAPI performance_DownloadInstrument(IDirectMusicPerformance8 *iface, - IDirectMusicInstrument *pInst, DWORD dwPChannel, - IDirectMusicDownloadedInstrument **ppDownInst, DMUS_NOTERANGE *pNoteRanges, - DWORD dwNumNoteRanges, IDirectMusicPort **ppPort, DWORD *pdwGroup, DWORD *pdwMChannel) + IDirectMusicInstrument *instrument, DWORD port_channel, + IDirectMusicDownloadedInstrument **downloaded, DMUS_NOTERANGE *note_ranges, + DWORD note_range_count, IDirectMusicPort **port, DWORD *group, DWORD *music_channel) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + IDirectMusicPort *tmp_port = NULL; + HRESULT hr;
- FIXME("(%p, %p, %ld, %p, %p, %ld, %p, %p, %p): stub\n", This, pInst, dwPChannel, ppDownInst, pNoteRanges, dwNumNoteRanges, ppPort, pdwGroup, pdwMChannel); - return S_OK; + TRACE("(%p, %p, %ld, %p, %p, %ld, %p, %p, %p)\n", This, instrument, port_channel, downloaded, + note_ranges, note_range_count, port, group, music_channel); + + if (!port) port = &tmp_port; + if (FAILED(hr = IDirectMusicPerformance_PChannelInfo(iface, port_channel, port, group, music_channel))) + return hr; + + hr = IDirectMusicPort_DownloadInstrument(*port, instrument, downloaded, note_ranges, note_range_count); + if (tmp_port) IDirectMusicPort_Release(tmp_port); + return hr; }
static HRESULT WINAPI performance_Invalidate(IDirectMusicPerformance8 *iface, MUSIC_TIME mtTime, DWORD dwFlags)
This merge request was approved by Michael Stefaniuc.