From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/tests/dmime.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 79fbb902868..b15c3a1ac37 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -4053,6 +4053,12 @@ static void test_segment_state(void) check_track_state(track, initialized, FALSE); check_track_state(track, playing, FALSE);
+ hr = IDirectMusicPerformance_GetSegmentState(performance, NULL, 0); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0); + todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + + tmp_state = state; state = (void *)0xdeadbeef; hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 20, &state); @@ -4062,6 +4068,22 @@ static void test_segment_state(void) ok(state != tmp_state, "got %p\n", state); IDirectMusicSegmentState_Release(tmp_state);
+ tmp_state = (void *)0xdeadbeef; + hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(state == tmp_state, "got %p\n", state); + if (tmp_state != (void *)0xdeadbeef) IDirectMusicSegmentState_Release(tmp_state); + + tmp_state = (void *)0xdeadbeef; + hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 69); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(state == tmp_state, "got %p\n", state); + if (tmp_state != (void *)0xdeadbeef) IDirectMusicSegmentState_Release(tmp_state); + + hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 70); + todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + + check_track_state(track, downloaded, FALSE); check_track_state(track, initialized, TRUE);
@@ -4074,6 +4096,9 @@ static void test_segment_state(void) ret = test_track_wait_playing(track, 50); ok(ret == 0, "got %#lx\n", ret);
+ hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0); + todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); +
tmp_segment = (void *)0xdeadbeef; hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/dmime_private.h | 1 + dlls/dmime/performance.c | 91 +++++++++++++++++++++++++++++++++++--- dlls/dmime/segmentstate.c | 6 +++ dlls/dmime/tests/dmime.c | 12 ++--- 4 files changed, 98 insertions(+), 12 deletions(-)
diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index e1a2374facf..3c7fc1e332b 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -77,6 +77,7 @@ extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME sta extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT segment_state_tick(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); +extern BOOL segment_state_has_segment(IDirectMusicSegmentState *iface, IDirectMusicSegment *segment);
extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, IDirectMusicTrack8 **ret_iface); diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index a08c00502d9..17fbe772f5b 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -76,6 +76,8 @@ struct performance HANDLE notification_event; BOOL notification_performance; BOOL notification_segment; + + IDirectMusicSegment *primary_segment; };
struct message @@ -338,6 +340,12 @@ HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME return S_OK; }
+static void performance_set_primary_segment(struct performance *This, IDirectMusicSegment *segment) +{ + if (This->primary_segment) IDirectMusicSegment_Release(This->primary_segment); + if ((This->primary_segment = segment)) IDirectMusicSegment_AddRef(This->primary_segment); +} + /* IDirectMusicPerformance8 IUnknown part: */ static HRESULT WINAPI performance_QueryInterface(IDirectMusicPerformance8 *iface, REFIID riid, void **ret_iface) { @@ -487,6 +495,42 @@ static HRESULT WINAPI performance_PlaySegment(IDirectMusicPerformance8 *iface, I segment_flags, start_time, ret_state, NULL, NULL); }
+struct state_entry +{ + struct list entry; + IDirectMusicSegmentState *state; +}; + +static void state_entry_destroy(struct state_entry *entry) +{ + list_remove(&entry->entry); + IDirectMusicSegmentState_Release(entry->state); + free(entry); +} + +static void enum_segment_states(struct performance *This, IDirectMusicSegment *segment, struct list *list) +{ + struct state_entry *entry; + struct message *message; + + LIST_FOR_EACH_ENTRY(message, &This->messages, struct message, entry) + { + IDirectMusicSegmentState *message_state; + + if (message->msg.dwType != DMUS_PMSGT_INTERNAL_SEGMENT_TICK + && message->msg.dwType != DMUS_PMSGT_INTERNAL_SEGMENT_END) + continue; + + message_state = (IDirectMusicSegmentState *)message->msg.punkUser; + if (segment && !segment_state_has_segment(message_state, segment)) continue; + + if (!(entry = malloc(sizeof(*entry)))) return; + entry->state = message_state; + IDirectMusicSegmentState_AddRef(entry->state); + list_add_tail(list, &entry->entry); + } +} + static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegmentState, MUSIC_TIME mtTime, DWORD dwFlags) { @@ -497,12 +541,36 @@ static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectM }
static HRESULT WINAPI performance_GetSegmentState(IDirectMusicPerformance8 *iface, - IDirectMusicSegmentState **ppSegmentState, MUSIC_TIME mtTime) + IDirectMusicSegmentState **state, MUSIC_TIME time) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct list *ptr, states = LIST_INIT(states); + struct state_entry *entry, *next; + HRESULT hr = S_OK;
- FIXME("(%p,%p, %ld): stub\n", This, ppSegmentState, mtTime); - return S_OK; + TRACE("(%p, %p, %ld)\n", This, state, time); + + if (!state) return E_POINTER; + + EnterCriticalSection(&This->safe); + + enum_segment_states(This, This->primary_segment, &states); + + if (!(ptr = list_head(&states))) hr = DMUS_E_NOT_FOUND; + else + { + entry = LIST_ENTRY(ptr, struct state_entry, entry); + + *state = entry->state; + IDirectMusicSegmentState_AddRef(entry->state); + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &states, struct state_entry, entry) + state_entry_destroy(entry); + } + + LeaveCriticalSection(&This->safe); + + return hr; }
static HRESULT WINAPI performance_SetPrepareTime(IDirectMusicPerformance8 *iface, DWORD dwMilliSeconds) @@ -1152,6 +1220,8 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) WARN("Failed to free message %p, hr %#lx\n", message, hr); }
+ performance_set_primary_segment(This, NULL); + if (This->master_clock) { IReferenceClock_Release(This->master_clock); @@ -1278,17 +1348,26 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface,
if (FAILED(hr = IUnknown_QueryInterface(source, &IID_IDirectMusicSegment, (void **)&segment))) return hr; + + EnterCriticalSection(&This->safe); + + performance_set_primary_segment(This, segment); + if ((!(music_time = start_time) && FAILED(hr = IDirectMusicPerformance8_GetTime(iface, NULL, &music_time))) || FAILED(hr = segment_state_create(segment, music_time, iface, &state))) { + performance_set_primary_segment(This, NULL); + LeaveCriticalSection(&This->safe); + IDirectMusicSegment_Release(segment); return hr; }
- EnterCriticalSection(&This->safe); - if (FAILED(hr = segment_state_play(state, iface))) + { ERR("Failed to play segment state, hr %#lx\n", hr); + performance_set_primary_segment(This, NULL); + } else if (segment_state) { *segment_state = state; diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index f2f895de881..3e13687254e 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -363,3 +363,9 @@ HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerf
return S_OK; } + +BOOL segment_state_has_segment(IDirectMusicSegmentState *iface, IDirectMusicSegment *segment) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + return !segment || This->segment == segment; +} diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index b15c3a1ac37..7d2dd912237 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -4054,9 +4054,9 @@ static void test_segment_state(void) check_track_state(track, playing, FALSE);
hr = IDirectMusicPerformance_GetSegmentState(performance, NULL, 0); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0); - todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
tmp_state = state; @@ -4071,14 +4071,14 @@ static void test_segment_state(void) tmp_state = (void *)0xdeadbeef; hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(state == tmp_state, "got %p\n", state); - if (tmp_state != (void *)0xdeadbeef) IDirectMusicSegmentState_Release(tmp_state); + ok(state == tmp_state, "got %p\n", state); + IDirectMusicSegmentState_Release(tmp_state);
tmp_state = (void *)0xdeadbeef; hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 69); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(state == tmp_state, "got %p\n", state); - if (tmp_state != (void *)0xdeadbeef) IDirectMusicSegmentState_Release(tmp_state); + ok(state == tmp_state, "got %p\n", state); + IDirectMusicSegmentState_Release(tmp_state);
hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 70); todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/tests/dmime.c | 174 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 7d2dd912237..344571d2801 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3888,6 +3888,179 @@ static void test_band_track_play(void) IDirectMusicTool_Release(tool); }
+#define check_dmus_tempo_pmsg(a, b, c) check_dmus_tempo_pmsg_(__LINE__, a, b, c) +static void check_dmus_tempo_pmsg_(int line, DMUS_TEMPO_PMSG *msg, MUSIC_TIME time, double tempo) +{ + ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize); + ok_(__FILE__, line)(msg->rtTime != 0, "got rtTime %I64u\n", msg->rtTime); + ok_(__FILE__, line)(abs(msg->mtTime - time) < 10, "got mtTime %lu\n", msg->mtTime); + ok_(__FILE__, line)(!msg->dwPChannel, "got dwPChannel %lu\n", msg->dwPChannel); + ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID); + ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_TEMPO, "got dwType %#lx\n", msg->dwType); + ok_(__FILE__, line)(!msg->dwVoiceID, "got dwVoiceID %lu\n", msg->dwVoiceID); + ok_(__FILE__, line)(msg->dwGroupID == -1, "got dwGroupID %lu\n", msg->dwGroupID); + ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser); + ok_(__FILE__, line)(msg->dblTempo == tempo, "got tempo %f\n", msg->dblTempo); +} + +static void test_tempo_track_play(void) +{ + static const DWORD message_types[] = + { + DMUS_PMSGT_MIDI, + DMUS_PMSGT_NOTE, + DMUS_PMSGT_SYSEX, + DMUS_PMSGT_NOTIFICATION, + DMUS_PMSGT_TEMPO, + DMUS_PMSGT_CURVE, + DMUS_PMSGT_TIMESIG, + DMUS_PMSGT_PATCH, + DMUS_PMSGT_TRANSPOSE, + DMUS_PMSGT_CHANNEL_PRIORITY, + DMUS_PMSGT_STOP, + DMUS_PMSGT_DIRTY, + DMUS_PMSGT_WAVE, + DMUS_PMSGT_LYRIC, + DMUS_PMSGT_SCRIPTLYRIC, + DMUS_PMSGT_USER, + }; + static const LARGE_INTEGER zero = {0}; + DMUS_IO_TEMPO_ITEM tempo_items[] = + { + {.lTime = 100, .dblTempo = 80}, + {.lTime = 300, .dblTempo = 60}, + {.lTime = 200, .dblTempo = 20}, + {.lTime = 4000, .dblTempo = 50}, + }; + IDirectMusicPerformance *performance; + IDirectMusicSegment *segment; + IDirectMusicGraph *graph; + IDirectMusicTrack *track; + IPersistStream *persist; + IDirectMusicTool *tool; + DMUS_TEMPO_PMSG *tempo; + DMUS_TEMPO_PARAM param; + IStream *stream; + DMUS_PMSG *msg; + HRESULT hr; + DWORD ret; + + hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool); + 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 = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SetGraph(performance, graph); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicGraph_Release(graph); + + + /* create a segment and load a simple RIFF stream */ + + hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSegment, (void **)&segment); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSegment_QueryInterface(segment, &IID_IPersistStream, (void **)&persist); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CreateStreamOnHGlobal(0, TRUE, &stream); + ok(hr == S_OK, "got %#lx\n", hr); + + CHUNK_RIFF(stream, "DMSG") + { + /* set a non-zero segment length, or nothing will be played */ + DMUS_IO_SEGMENT_HEADER head = {.mtLength = 1000}; + CHUNK_DATA(stream, "segh", head); + CHUNK_DATA(stream, "guid", CLSID_DirectMusicSegment); + } + CHUNK_END; + + hr = IStream_Seek(stream, zero, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IPersistStream_Load(persist, stream); + ok(hr == S_OK, "got %#lx\n", hr); + IPersistStream_Release(persist); + IStream_Release(stream); + + + /* add a tempo track to our segment */ + + hr = CoCreateInstance(&CLSID_DirectMusicTempoTrack, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicTrack, (void **)&track); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSegment_QueryInterface(track, &IID_IPersistStream, (void **)&persist); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CreateStreamOnHGlobal(0, TRUE, &stream); + ok(hr == S_OK, "got %#lx\n", hr); + CHUNK_ARRAY(stream, "tetr", tempo_items); + hr = IStream_Seek(stream, zero, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IPersistStream_Load(persist, stream); + ok(hr == S_OK, "got %#lx\n", hr); + IPersistStream_Release(persist); + IStream_Release(stream); + + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, ¶m); + ok(hr == DMUS_E_TRACK_NOT_FOUND, "got %#lx\n", hr); + + hr = IDirectMusicSegment_InsertTrack(segment, (IDirectMusicTrack *)track, 1); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicTrack_Release(track); + + + /* now play the segment, and check produced messages */ + + hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0x800, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, &msg); + ok(!ret, "got %#lx\n", ret); + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&tempo); + ok(!ret, "got %#lx\n", ret); + todo_wine ok(tempo->dwType == DMUS_PMSGT_TEMPO, "got %#lx\n", tempo->dwType); + if (tempo->dwType != DMUS_PMSGT_TEMPO) goto skip_tests; + check_dmus_tempo_pmsg(tempo, 100, 80); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)tempo); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&tempo); + todo_wine ok(!ret, "got %#lx\n", ret); + check_dmus_tempo_pmsg(tempo, 300, 60); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)tempo); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + +skip_tests: + IDirectMusicSegment_Release(segment); + + + hr = IDirectMusicPerformance_CloseDown(performance); + ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicPerformance_Release(performance); + IDirectMusicTool_Release(tool); +} + static void test_connect_to_collection(void) { IDirectMusicCollection *collection; @@ -4208,6 +4381,7 @@ START_TEST(dmime) test_wave_pmsg(); test_sequence_track(); test_band_track_play(); + test_tempo_track_play(); test_connect_to_collection(); test_segment_state();
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/tests/dmime.c | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 344571d2801..2f2592da6fe 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3933,6 +3933,7 @@ static void test_tempo_track_play(void) {.lTime = 4000, .dblTempo = 50}, }; IDirectMusicPerformance *performance; + MUSIC_TIME next_time; IDirectMusicSegment *segment; IDirectMusicGraph *graph; IDirectMusicTrack *track; @@ -4015,6 +4016,49 @@ static void test_tempo_track_play(void) ok(hr == S_OK, "got %#lx\n", hr); IDirectMusicTrack_Release(track);
+ hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + + memset(¶m, 0xcd, sizeof(param)); + next_time = 0xdeadbeef; + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(next_time == 100, "got next_time %lu\n", next_time); + todo_wine ok(param.mtTime == 100, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 100, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(next_time == 200, "got next_time %lu\n", next_time); + ok(param.mtTime == 0, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 199, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(next_time == 101, "got next_time %lu\n", next_time); + todo_wine ok(param.mtTime == -99, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 200, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(next_time == 100, "got next_time %lu\n", next_time); + todo_wine ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 299, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(next_time == 1, "got next_time %lu\n", next_time); + todo_wine ok(param.mtTime == -199, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 300, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(next_time == 3700, "got next_time %lu\n", next_time); + todo_wine ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 20, "got dblTempo %f\n", param.dblTempo); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 5000, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 0, "got next_time %lu\n", next_time); + todo_wine ok(param.mtTime == -1000, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 50, "got dblTempo %f\n", param.dblTempo); +
/* now play the segment, and check produced messages */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/tempotrack.c | 46 ++++++++++++++-------------------- dlls/dmime/tests/dmime.c | 54 ++++++++++++++++++++-------------------- 2 files changed, 45 insertions(+), 55 deletions(-)
diff --git a/dlls/dmime/tempotrack.c b/dlls/dmime/tempotrack.c index 07f410118fe..028ebc8879c 100644 --- a/dlls/dmime/tempotrack.c +++ b/dlls/dmime/tempotrack.c @@ -140,42 +140,32 @@ static HRESULT WINAPI tempo_track_Play(IDirectMusicTrack8 *iface, void *pStateDa return S_OK; }
-static HRESULT WINAPI tempo_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time, - MUSIC_TIME *next, void *param) +static HRESULT WINAPI tempo_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME music_time, + MUSIC_TIME *next_time, void *param) { IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface); - DMUS_TEMPO_PARAM *prm = param; - unsigned int i; - - TRACE("(%p, %s, %ld, %p, %p)\n", This, debugstr_dmguid(type), time, next, param); + DMUS_IO_TEMPO_ITEM *item = This->items, *end = item + This->count; + DMUS_TEMPO_PARAM *tempo = param;
- if (!param) - return E_POINTER; - if (!IsEqualGUID(type, &GUID_TempoParam)) - return DMUS_E_GET_UNSUPPORTED; + TRACE("(%p, %s, %ld, %p, %p)\n", This, debugstr_dmguid(type), music_time, next_time, param);
- FIXME("Partial support for GUID_TempoParam\n"); + if (!param) return E_POINTER; + if (!IsEqualGUID(type, &GUID_TempoParam)) return DMUS_E_GET_UNSUPPORTED; + if (item == end) return DMUS_E_NOT_FOUND;
- if (next) - *next = 0; - prm->mtTime = 0; - prm->dblTempo = 0.123456; + tempo->mtTime = item->lTime - music_time; + tempo->dblTempo = item->dblTempo;
- for (i = 0; i < This->count; i++) { - if (This->items[i].lTime <= time) { - MUSIC_TIME ofs = This->items[i].lTime - time; - if (ofs > prm->mtTime) { - prm->mtTime = ofs; - prm->dblTempo = This->items[i].dblTempo; - } - if (next && This->items[i].lTime > time && This->items[i].lTime < *next) - *next = This->items[i].lTime; - } + for (; item < end; item++) + { + MUSIC_TIME time = item->lTime - music_time; + if (next_time) *next_time = item->lTime - music_time; + if (time > 0) break; + tempo->mtTime = time; + tempo->dblTempo = item->dblTempo; }
- if (0.123456 == prm->dblTempo) - return DMUS_E_NOT_FOUND; - + if (next_time && item == end) *next_time = 0; return S_OK; }
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 2f2592da6fe..8be73d93b54 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -4019,45 +4019,45 @@ static void test_tempo_track_play(void) hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, NULL); ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr);
memset(¶m, 0xcd, sizeof(param)); next_time = 0xdeadbeef; hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(next_time == 100, "got next_time %lu\n", next_time); - todo_wine ok(param.mtTime == 100, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 100, "got next_time %lu\n", next_time); + ok(param.mtTime == 100, "got mtTime %ld\n", param.mtTime); + ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 100, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(next_time == 200, "got next_time %lu\n", next_time); + ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 200, "got next_time %lu\n", next_time); ok(param.mtTime == 0, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 199, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(next_time == 101, "got next_time %lu\n", next_time); - todo_wine ok(param.mtTime == -99, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 101, "got next_time %lu\n", next_time); + ok(param.mtTime == -99, "got mtTime %ld\n", param.mtTime); + ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 200, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(next_time == 100, "got next_time %lu\n", next_time); - todo_wine ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 100, "got next_time %lu\n", next_time); + ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime); + ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 299, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(next_time == 1, "got next_time %lu\n", next_time); - todo_wine ok(param.mtTime == -199, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 1, "got next_time %lu\n", next_time); + ok(param.mtTime == -199, "got mtTime %ld\n", param.mtTime); + ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 300, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(next_time == 3700, "got next_time %lu\n", next_time); - todo_wine ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 20, "got dblTempo %f\n", param.dblTempo); + ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 3700, "got next_time %lu\n", next_time); + ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime); + ok(param.dblTempo == 20, "got dblTempo %f\n", param.dblTempo); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 5000, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); ok(next_time == 0, "got next_time %lu\n", next_time); - todo_wine ok(param.mtTime == -1000, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 50, "got dblTempo %f\n", param.dblTempo); + ok(param.mtTime == -1000, "got mtTime %ld\n", param.mtTime); + ok(param.dblTempo == 50, "got dblTempo %f\n", param.dblTempo);
/* now play the segment, and check produced messages */
From: Rémi Bernon rbernon@codeweavers.com
Be flexible on the comparison to ignore rounding errors. --- dlls/dmime/tests/dmime.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 8be73d93b54..953dac5ed2e 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -2671,6 +2671,17 @@ static void test_performance_graph(void) IDirectMusicTool_Release(tool); }
+static double scale_music_time(MUSIC_TIME time, double tempo) +{ + return (600000000. * time) / (tempo * 768.); +} + +#define check_music_time(a, b) check_music_time_(__LINE__, a, b) +static void check_music_time_(int line, MUSIC_TIME time, MUSIC_TIME expect) +{ + ok_(__FILE__, line)(abs(time - expect) <= 1, "got %ld, expected %ld\n", time, expect); +} + static void test_performance_time(void) { IDirectMusicPerformance *performance; @@ -2720,29 +2731,26 @@ static void test_performance_time(void) time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1, &time); ok(hr == S_OK, "got %#lx\n", hr); - ok(time - init_time >= 6505, "got %I64d\n", time - init_time); - ok(time - init_time <= 6515, "got %I64d\n", time - init_time); + check_music_time(time - init_time, scale_music_time(1, 120)); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1000, &time); ok(hr == S_OK, "got %#lx\n", hr); - ok(time - init_time >= 1000 * 6505, "got %I64d\n", time - init_time); - ok(time - init_time <= 1000 * 6515, "got %I64d\n", time - init_time); + todo_wine check_music_time(time - init_time, scale_music_time(1000, 120)); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 2000, &time); ok(hr == S_OK, "got %#lx\n", hr); - ok(time - init_time >= 2000 * 6505, "got %I64d\n", time - init_time); - ok(time - init_time <= 2000 * 6515, "got %I64d\n", time - init_time); + todo_wine check_music_time(time - init_time, scale_music_time(2000, 120));
music_time = 0xdeadbeef; hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time); ok(hr == S_OK, "got %#lx\n", hr); ok(music_time == 0, "got %ld\n", music_time); music_time = 0xdeadbeef; - hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + 1000 * 6510, &music_time); + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + scale_music_time(1000, 120), &music_time); ok(hr == S_OK, "got %#lx\n", hr); ok(music_time == 1000, "got %ld\n", music_time); music_time = 0xdeadbeef; - hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + 2000 * 6510, &music_time); + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + scale_music_time(2000, 120), &music_time); ok(hr == S_OK, "got %#lx\n", hr); ok(music_time == 2000, "got %ld\n", music_time);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/tests/dmime.c | 48 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 953dac5ed2e..5dbc7ece8d7 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3941,7 +3941,8 @@ static void test_tempo_track_play(void) {.lTime = 4000, .dblTempo = 50}, }; IDirectMusicPerformance *performance; - MUSIC_TIME next_time; + MUSIC_TIME music_time, next_time; + REFERENCE_TIME init_time, time; IDirectMusicSegment *segment; IDirectMusicGraph *graph; IDirectMusicTrack *track; @@ -4076,12 +4077,57 @@ static void test_tempo_track_play(void) hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0x800, 0, NULL); ok(hr == S_OK, "got %#lx\n", hr);
+ /* the tempo track only takes effect after DMUS_PMSGT_DIRTY */ + ret = test_tool_wait_message(tool, 500, &msg); ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr);
+ + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, &time); + ok(hr == S_OK, "got %#lx\n", hr); + init_time = time; + + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1, &time); + ok(hr == S_OK, "got %#lx\n", hr); + check_music_time(time - init_time, scale_music_time(1, 120)); + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 100, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine check_music_time(time - init_time, scale_music_time(100, 120)); + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 150, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(50, 80)); + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 200, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(100, 80)); + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 400, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20)); + + music_time = 0xdeadbeef; + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + ok(music_time == 0, "got %ld\n", music_time); + music_time = 0xdeadbeef; + time = scale_music_time(100, 120) + scale_music_time(50, 80); + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + time, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(music_time == 150, "got %ld\n", music_time); + music_time = 0xdeadbeef; + time = scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20); + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + time, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(music_time == 400, "got %ld\n", music_time); + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&tempo); ok(!ret, "got %#lx\n", ret); todo_wine ok(tempo->dwType == DMUS_PMSGT_TEMPO, "got %#lx\n", tempo->dwType);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/performance.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 17fbe772f5b..06d541efb7e 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -78,6 +78,7 @@ struct performance BOOL notification_segment;
IDirectMusicSegment *primary_segment; + IDirectMusicSegment *control_segment; };
struct message @@ -346,6 +347,12 @@ static void performance_set_primary_segment(struct performance *This, IDirectMus if ((This->primary_segment = segment)) IDirectMusicSegment_AddRef(This->primary_segment); }
+static void performance_set_control_segment(struct performance *This, IDirectMusicSegment *segment) +{ + if (This->control_segment) IDirectMusicSegment_Release(This->control_segment); + if ((This->control_segment = segment)) IDirectMusicSegment_AddRef(This->control_segment); +} + /* IDirectMusicPerformance8 IUnknown part: */ static HRESULT WINAPI performance_QueryInterface(IDirectMusicPerformance8 *iface, REFIID riid, void **ret_iface) { @@ -1221,6 +1228,7 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) }
performance_set_primary_segment(This, NULL); + performance_set_control_segment(This, NULL);
if (This->master_clock) { @@ -1333,6 +1341,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, WCHAR *segment_name, IUnknown *transition, DWORD segment_flags, INT64 start_time, IDirectMusicSegmentState **segment_state, IUnknown *from, IUnknown *audio_path) { + BOOL primary = !(segment_flags & DMUS_SEGF_SECONDARY), control = (segment_flags & DMUS_SEGF_CONTROL); struct performance *This = impl_from_IDirectMusicPerformance8(iface); IDirectMusicSegmentState *state; IDirectMusicSegment *segment; @@ -1351,12 +1360,14 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface,
EnterCriticalSection(&This->safe);
- performance_set_primary_segment(This, segment); + if (primary) performance_set_primary_segment(This, segment); + if (control) performance_set_control_segment(This, segment);
if ((!(music_time = start_time) && FAILED(hr = IDirectMusicPerformance8_GetTime(iface, NULL, &music_time))) || FAILED(hr = segment_state_create(segment, music_time, iface, &state))) { - performance_set_primary_segment(This, NULL); + if (primary) performance_set_primary_segment(This, NULL); + if (control) performance_set_control_segment(This, NULL); LeaveCriticalSection(&This->safe);
IDirectMusicSegment_Release(segment); @@ -1366,7 +1377,8 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, if (FAILED(hr = segment_state_play(state, iface))) { ERR("Failed to play segment state, hr %#lx\n", hr); - performance_set_primary_segment(This, NULL); + if (primary) performance_set_primary_segment(This, NULL); + if (control) performance_set_control_segment(This, NULL); } else if (segment_state) {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/performance.c | 85 ++++++++++++++++++++++++++++++++-------- dlls/dmime/tests/dmime.c | 18 ++++----- 2 files changed, 77 insertions(+), 26 deletions(-)
diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 06d541efb7e..624b7e6bf70 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -21,6 +21,7 @@ #include "dmime_private.h" #include "dmusic_midi.h" #include "wine/rbtree.h" +#include <math.h>
WINE_DEFAULT_DEBUG_CHANNEL(dmime);
@@ -677,20 +678,39 @@ done: static HRESULT WINAPI performance_MusicToReferenceTime(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, REFERENCE_TIME *time) { - static int once; struct performance *This = impl_from_IDirectMusicPerformance8(iface); + MUSIC_TIME tempo_time, next = 0; + DMUS_TEMPO_PARAM param; + double tempo, duration; + HRESULT hr;
- if (!once++) FIXME("(%p, %ld, %p): semi-stub\n", This, music_time, time); - else TRACE("(%p, %ld, %p)\n", This, music_time, time); + TRACE("(%p, %ld, %p)\n", This, music_time, time);
if (!time) return E_POINTER; *time = 0;
if (!This->master_clock) return DMUS_E_NO_MASTER_CLOCK;
- /* FIXME: This should be (music_time * 60) / (DMUS_PPQ * tempo) - * but it gives innacurate results */ - *time = This->init_time + (music_time * 6510); + EnterCriticalSection(&This->safe); + + for (tempo = 120., duration = tempo_time = 0; music_time > 0; tempo_time += next) + { + if (FAILED(hr = IDirectMusicPerformance_GetParam(iface, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, + tempo_time, &next, ¶m))) + break; + + if (!next) next = music_time; + else next = min(next, music_time); + + if (param.mtTime <= 0) tempo = param.dblTempo; + duration += (600000000. * next) / (tempo * DMUS_PPQ); + music_time -= next; + } + + duration += (600000000. * music_time) / (tempo * DMUS_PPQ); + *time = This->init_time + duration; + + LeaveCriticalSection(&This->safe);
return S_OK; } @@ -698,20 +718,38 @@ static HRESULT WINAPI performance_MusicToReferenceTime(IDirectMusicPerformance8 static HRESULT WINAPI performance_ReferenceToMusicTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME time, MUSIC_TIME *music_time) { - static int once; struct performance *This = impl_from_IDirectMusicPerformance8(iface); + MUSIC_TIME tempo_time, next = 0; + double tempo, duration, step; + DMUS_TEMPO_PARAM param; + HRESULT hr;
- if (!once++) FIXME("(%p, %I64d, %p): semi-stub\n", This, time, music_time); - else TRACE("(%p, %I64d, %p)\n", This, time, music_time); + TRACE("(%p, %I64d, %p)\n", This, time, music_time);
if (!music_time) return E_POINTER; *music_time = 0;
if (!This->master_clock) return DMUS_E_NO_MASTER_CLOCK;
- /* FIXME: This should be (time * DMUS_PPQ * tempo) / 60 - * but it gives innacurate results */ - *music_time = (time - This->init_time) / 6510; + EnterCriticalSection(&This->safe); + + duration = time - This->init_time; + + for (tempo = 120., tempo_time = 0; duration > 0; tempo_time += next, duration -= step) + { + if (FAILED(hr = IDirectMusicPerformance_GetParam(iface, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, + tempo_time, &next, ¶m))) + break; + + if (param.mtTime <= 0) tempo = param.dblTempo; + step = (600000000. * next) / (tempo * DMUS_PPQ); + if (!next || duration < step) break; + *music_time = *music_time + next; + } + + *music_time = *music_time + round((duration * tempo * DMUS_PPQ) / 600000000.); + + LeaveCriticalSection(&This->safe);
return S_OK; } @@ -1085,13 +1123,26 @@ static HRESULT WINAPI performance_Invalidate(IDirectMusicPerformance8 *iface, MU return S_OK; }
-static HRESULT WINAPI performance_GetParam(IDirectMusicPerformance8 *iface, REFGUID rguidType, - DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam) +static HRESULT WINAPI performance_GetParam(IDirectMusicPerformance8 *iface, REFGUID type, + DWORD group, DWORD index, MUSIC_TIME music_time, MUSIC_TIME *next_time, void *param) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + HRESULT hr;
- FIXME("(%p, %s, %ld, %ld, %ld, %p, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pmtNext, pParam); - return S_OK; + TRACE("(%p, %s, %ld, %ld, %ld, %p, %p)\n", This, debugstr_dmguid(type), group, index, music_time, next_time, param); + + if (next_time) *next_time = 0; + + if (!This->control_segment) hr = DMUS_E_NOT_FOUND; + else hr = IDirectMusicSegment_GetParam(This->control_segment, type, group, index, music_time, next_time, param); + + if (FAILED(hr)) + { + if (!This->primary_segment) hr = DMUS_E_NOT_FOUND; + else hr = IDirectMusicSegment_GetParam(This->primary_segment, type, group, index, music_time, next_time, param); + } + + return hr; }
static HRESULT WINAPI performance_SetParam(IDirectMusicPerformance8 *iface, REFGUID rguidType, diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 5dbc7ece8d7..2745fd94db9 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -2735,11 +2735,11 @@ static void test_performance_time(void) time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1000, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_music_time(time - init_time, scale_music_time(1000, 120)); + check_music_time(time - init_time, scale_music_time(1000, 120)); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 2000, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_music_time(time - init_time, scale_music_time(2000, 120)); + check_music_time(time - init_time, scale_music_time(2000, 120));
music_time = 0xdeadbeef; hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time); @@ -4098,19 +4098,19 @@ static void test_tempo_track_play(void) time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 100, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_music_time(time - init_time, scale_music_time(100, 120)); + check_music_time(time - init_time, scale_music_time(100, 120)); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 150, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(50, 80)); + check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(50, 80)); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 200, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(100, 80)); + check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(100, 80)); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 400, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20)); + check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20));
music_time = 0xdeadbeef; hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time); @@ -4120,15 +4120,15 @@ static void test_tempo_track_play(void) time = scale_music_time(100, 120) + scale_music_time(50, 80); hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + time, &music_time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(music_time == 150, "got %ld\n", music_time); + ok(music_time == 150, "got %ld\n", music_time); music_time = 0xdeadbeef; time = scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20); hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + time, &music_time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(music_time == 400, "got %ld\n", music_time); + ok(music_time == 400, "got %ld\n", music_time);
- ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&tempo); + ret = test_tool_wait_message(tool, 2000, (DMUS_PMSG **)&tempo); ok(!ret, "got %#lx\n", ret); todo_wine ok(tempo->dwType == DMUS_PMSGT_TEMPO, "got %#lx\n", tempo->dwType); if (tempo->dwType != DMUS_PMSGT_TEMPO) goto skip_tests;
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 tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=139670
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
dmime: dmime.c:3243: Test failed: got punkUser 01746CF8
=== w7u_adm (32 bit report) ===
dmime: dmime.c:3243: Test failed: got mtTime 454 dmime.c:3243: Test failed: got punkUser 009CDCB8 dmime.c:3250: Test failed: got mtTime 1837 dmime.c:3257: Test failed: got mtTime 1837
=== w7u_el (32 bit report) ===
dmime: dmime.c:3243: Test failed: got mtTime 1836 dmime.c:3243: Test failed: got punkUser 009F81B0 dmime.c:3250: Test failed: got mtTime 1836
=== w1064v1507 (32 bit report) ===
dmime: dmime.c:3243: Test failed: got mtTime 463 dmime.c:3243: Test failed: got punkUser 04055180 dmime.c:3250: Test failed: got mtTime 1845 dmime.c:3257: Test failed: got mtTime 1845
=== w1064_tsign (32 bit report) ===
dmime: dmime.c:3243: Test failed: got mtTime 463 dmime.c:3243: Test failed: got punkUser 03BF0BD0 dmime.c:3250: Test failed: got mtTime 1846 dmime.c:3257: Test failed: got mtTime 1846
=== w10pro64 (32 bit report) ===
dmime: dmime.c:3243: Test failed: got mtTime 463 dmime.c:3243: Test failed: got punkUser 03805088 dmime.c:3250: Test failed: got mtTime 1847 dmime.c:3257: Test failed: got mtTime 1847 dmime.c:3257: Test failed: got punkUser 00000000
=== w10pro64_en_AE_u8 (32 bit report) ===
dmime: dmime.c:3243: Test failed: got mtTime 462 dmime.c:3243: Test failed: got punkUser 04CC8560 dmime.c:3250: Test failed: got mtTime 1845 dmime.c:3257: Test failed: got mtTime 1845
=== w11pro64 (32 bit report) ===
dmime: dmime.c:3243: Test failed: got punkUser 045F1490
I'm approving but going forward please avoid the floating point numeric literals ending just in a dot.\ Just append the 0; IMHO much more pleasant to read that way.\ E.g. `0.0` instead of just `0.`.
This merge request was approved by Michael Stefaniuc.
Test failures are unrelated, mostly in ddraw or D3D.