-- v3: dmime: Implement segment state repeat and looping. dmsynth: Reset synthesizer defaults on MIDI_SYSTEM_RESET. dmime: Send MIDI_SYSTEM_RESET message on performance reset. dmime: Clear all pending messages in IDirectMusicPerformance_Stop. dmime/tests: Test that IDirectMusicPerformance_Stop clears messages. dmime/tests: Avoid discarding old notifications in test.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/tests/dmime.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 7613b82c893..e181a6b1299 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3176,6 +3176,10 @@ static void test_notification_pmsg(void) hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); ok(hr == S_FALSE, "got %#lx\n", hr);
+ /* avoid discarding older notifications */ + hr = IDirectMusicPerformance_SetNotificationHandle(performance, 0, 100000000); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, &state); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/tests/dmime.c | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index e181a6b1299..e70fbfd5f1b 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3294,6 +3294,55 @@ static void test_notification_pmsg(void) ok(hr == S_FALSE, "got %#lx\n", hr);
+ /* Stop finishes segment immediately and skips notification messages */ + + hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, &state); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); + ok(!ret, "got %#lx\n", ret); + check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT, + DMUS_NOTIFICATION_SEGSTART, state); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_Stop(performance, NULL, NULL, 0, DMUS_SEGF_DEFAULT); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 50, &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, 50, (DMUS_PMSG **)¬if); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT, + DMUS_NOTIFICATION_SEGABORT, state); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + 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 dwType %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 100, &msg); + ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); + + IDirectMusicSegmentState_Release(state); + + /* CloseDown removes all notifications and notification messages */
hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/dmime_private.h | 4 +- dlls/dmime/performance.c | 165 +++++++++++++++++++++++++++++-------- dlls/dmime/segmentstate.c | 23 +++++- dlls/dmime/tests/dmime.c | 5 +- 4 files changed, 158 insertions(+), 39 deletions(-)
diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 3c7fc1e332b..ed1589ece1a 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -76,8 +76,10 @@ extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME sta IDirectMusicPerformance8 *performance, IDirectMusicSegmentState **ret_iface); extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT segment_state_tick(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); +extern HRESULT segment_state_stop(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 BOOL segment_state_has_track(IDirectMusicSegmentState *iface, DWORD track_id);
extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, IDirectMusicTrack8 **ret_iface); @@ -88,7 +90,7 @@ extern HRESULT performance_send_segment_start(IDirectMusicPerformance8 *iface, M extern HRESULT performance_send_segment_tick(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, IDirectMusicSegmentState *state); extern HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, - IDirectMusicSegmentState *state); + IDirectMusicSegmentState *state, BOOL abort);
/***************************************************************************** * Auxiliary definitions diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 94d7d8aeea3..494f9acbe1d 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -318,24 +318,28 @@ HRESULT performance_send_segment_tick(IDirectMusicPerformance8 *iface, MUSIC_TIM }
HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, - IDirectMusicSegmentState *state) + IDirectMusicSegmentState *state, BOOL abort) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); HRESULT hr;
- if (FAILED(hr = performance_send_notification_pmsg(This, music_time - 1450, This->notification_segment, - GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, (IUnknown *)state))) - return hr; - if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_segment, - GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, (IUnknown *)state))) - return hr; + if (!abort) + { + if (FAILED(hr = performance_send_notification_pmsg(This, music_time - 1450, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, (IUnknown *)state))) + return hr; + if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, (IUnknown *)state))) + return hr; + } + if (FAILED(hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGT_DIRTY, NULL))) return hr; if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_performance, GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED, NULL))) return hr; - if (FAILED(hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_ATTIME, + if (FAILED(hr = performance_send_pmsg(This, music_time, abort ? DMUS_PMSGF_TOOL_IMMEDIATE : DMUS_PMSGF_TOOL_ATTIME, DMUS_PMSGT_INTERNAL_SEGMENT_END, (IUnknown *)state))) return hr;
@@ -539,13 +543,118 @@ static void enum_segment_states(struct performance *This, IDirectMusicSegment *s } }
-static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, - IDirectMusicSegmentState *pSegmentState, MUSIC_TIME mtTime, DWORD dwFlags) +static BOOL message_needs_flushing(struct message *message, IDirectMusicSegmentState *state) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + if (!state) return TRUE;
- FIXME("(%p, %p, %p, %ld, %ld): stub\n", This, pSegment, pSegmentState, mtTime, dwFlags); - return S_OK; + switch (message->msg.dwType) + { + case DMUS_PMSGT_MIDI: + case DMUS_PMSGT_NOTE: + case DMUS_PMSGT_CURVE: + case DMUS_PMSGT_PATCH: + case DMUS_PMSGT_WAVE: + if (!segment_state_has_track(state, message->msg.dwVirtualTrackID)) return FALSE; + break; + + case DMUS_PMSGT_NOTIFICATION: + { + DMUS_NOTIFICATION_PMSG *notif = (DMUS_NOTIFICATION_PMSG *)&message->msg; + if (!IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_SEGMENT)) return FALSE; + if ((IDirectMusicSegmentState *)message->msg.punkUser != state) return FALSE; + break; + } + + case DMUS_PMSGT_INTERNAL_SEGMENT_TICK: + case DMUS_PMSGT_INTERNAL_SEGMENT_END: + if ((IDirectMusicSegmentState *)message->msg.punkUser != state) return FALSE; + break; + + default: + FIXME("Unhandled message type %#lx\n", message->msg.dwType); + break; + } + + return TRUE; +} + +static void performance_flush_messages(struct performance *This, IDirectMusicSegmentState *state) +{ + IDirectMusicPerformance *iface = (IDirectMusicPerformance *)&This->IDirectMusicPerformance8_iface; + struct message *message, *next; + HRESULT hr; + + LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->messages, struct message, entry) + { + if (!message_needs_flushing(message, state)) continue; + + list_remove(&message->entry); + list_init(&message->entry); + + if (FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) + ERR("Failed to free message %p, hr %#lx\n", message, hr); + } + + LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->notifications, struct message, entry) + { + if (!message_needs_flushing(message, state)) continue; + + list_remove(&message->entry); + list_init(&message->entry); + + if (FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) + ERR("Failed to free message %p, hr %#lx\n", message, hr); + } +} + +static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectMusicSegment *segment, + IDirectMusicSegmentState *state, MUSIC_TIME music_time, DWORD flags) +{ + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct list states = LIST_INIT(states); + struct state_entry *entry, *next; + HRESULT hr; + + FIXME("(%p, %p, %p, %ld, %ld): semi-stub\n", This, segment, state, music_time, flags); + + if (music_time) FIXME("time parameter %lu not implemented\n", music_time); + if (flags != DMUS_SEGF_DEFAULT) FIXME("flags parameter %#lx not implemented\n", flags); + + if (!music_time && FAILED(hr = IDirectMusicPerformance8_GetTime(iface, NULL, &music_time))) + return hr; + + EnterCriticalSection(&This->safe); + + if (!state) + enum_segment_states(This, segment, &states); + else if ((entry = malloc(sizeof(*entry)))) + { + entry->state = state; + IDirectMusicSegmentState_AddRef(entry->state); + list_add_tail(&states, &entry->entry); + } + + if (!segment && !state) + performance_flush_messages(This, NULL); + else LIST_FOR_EACH_ENTRY(entry, &states, struct state_entry, entry) + performance_flush_messages(This, entry->state); + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &states, struct state_entry, entry) + { + if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGABORT, (IUnknown *)entry->state))) + ERR("Failed to send DMUS_NOTIFICATION_SEGABORT, hr %#lx\n", hr); + if (FAILED(hr = segment_state_stop(entry->state, iface))) + ERR("Failed to stop segment state, hr %#lx\n", hr); + + IDirectMusicSegmentState_Release(entry->state); + list_remove(&entry->entry); + free(entry); + } + + LeaveCriticalSection(&This->safe); + + return S_OK; }
static HRESULT WINAPI performance_GetSegmentState(IDirectMusicPerformance8 *iface, @@ -1234,7 +1343,8 @@ static HRESULT WINAPI performance_AdjustTime(IDirectMusicPerformance8 *iface, RE static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - struct message *message, *next; + struct list states = LIST_INIT(states); + struct state_entry *entry, *next; HANDLE message_thread; HRESULT hr;
@@ -1254,28 +1364,17 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) This->notification_performance = FALSE; This->notification_segment = FALSE;
- LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->messages, struct message, entry) - { - list_remove(&message->entry); - list_init(&message->entry); - - if (message->msg.dwType == DMUS_PMSGT_INTERNAL_SEGMENT_END) - hr = IDirectMusicTool_ProcessPMsg(&This->IDirectMusicTool_iface, - (IDirectMusicPerformance *)iface, &message->msg); - else - hr = DMUS_S_FREE; + enum_segment_states(This, NULL, &states); + performance_flush_messages(This, NULL);
- if (hr == DMUS_S_FREE && FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) - WARN("Failed to free message %p, hr %#lx\n", message, hr); - } - - LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->notifications, struct message, entry) + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &states, struct state_entry, entry) { - list_remove(&message->entry); - list_init(&message->entry); + if (FAILED(hr = segment_state_end_play(entry->state, iface))) + ERR("Failed to stop segment state, hr %#lx\n", hr);
- if (FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) - WARN("Failed to free message %p, hr %#lx\n", message, hr); + IDirectMusicSegmentState_Release(entry->state); + list_remove(&entry->entry); + free(entry); }
performance_set_primary_segment(This, NULL); diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 3e13687254e..544620b0045 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -303,7 +303,7 @@ static HRESULT segment_state_play_chunk(struct segment_state *This, IDirectMusic { MUSIC_TIME end_time = This->start_time + This->played;
- if (FAILED(hr = performance_send_segment_end(performance, end_time, iface))) + if (FAILED(hr = performance_send_segment_end(performance, end_time, iface, FALSE))) { ERR("Failed to send segment end, hr %#lx\n", hr); return hr; @@ -345,6 +345,16 @@ HRESULT segment_state_tick(IDirectMusicSegmentState *iface, IDirectMusicPerforma return segment_state_play_chunk(This, performance, 10000000, 0); }
+HRESULT segment_state_stop(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + + TRACE("%p %p\n", iface, performance); + + This->played = This->end_point - This->start_point; + return performance_send_segment_end(performance, This->start_time + This->played, iface, TRUE); +} + HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) { struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); @@ -369,3 +379,14 @@ BOOL segment_state_has_segment(IDirectMusicSegmentState *iface, IDirectMusicSegm struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); return !segment || This->segment == segment; } + +BOOL segment_state_has_track(IDirectMusicSegmentState *iface, DWORD track_id) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + struct track_entry *entry; + + LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) + if (entry->track_id == track_id) return TRUE; + + return FALSE; +} diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index e70fbfd5f1b..bfb41d322e8 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3322,14 +3322,11 @@ static void test_notification_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr);
ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGABORT, state); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - }
ret = test_tool_wait_message(tool, 500, &msg); ok(!ret, "got %#lx\n", ret);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/performance.c | 71 +++++++++++++++++++++++---------------- dlls/dmusic/dmusic_midi.h | 1 + 2 files changed, 43 insertions(+), 29 deletions(-)
diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 494f9acbe1d..23aa2f23d3b 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -454,6 +454,35 @@ static HRESULT performance_init_dmusic(struct performance *This, IDirectSound *d return hr; }
+static HRESULT performance_send_midi_pmsg(struct performance *This, DMUS_PMSG *msg, UINT flags, + BYTE status, BYTE byte1, BYTE byte2) +{ + IDirectMusicPerformance8 *performance = &This->IDirectMusicPerformance8_iface; + DMUS_MIDI_PMSG *midi; + HRESULT hr; + + if (FAILED(hr = IDirectMusicPerformance8_AllocPMsg(performance, sizeof(*midi), + (DMUS_PMSG **)&midi))) + return hr; + + if (flags & DMUS_PMSGF_REFTIME) midi->rtTime = msg->rtTime; + if (flags & DMUS_PMSGF_MUSICTIME) midi->mtTime = msg->mtTime; + midi->dwFlags = flags; + midi->dwPChannel = msg->dwPChannel; + midi->dwVirtualTrackID = msg->dwVirtualTrackID; + midi->dwVoiceID = msg->dwVoiceID; + midi->dwGroupID = msg->dwGroupID; + midi->dwType = DMUS_PMSGT_MIDI; + midi->bStatus = status; + midi->bByte1 = byte1; + midi->bByte2 = byte2; + + if (FAILED(hr = IDirectMusicPerformance8_SendPMsg(performance, (DMUS_PMSG *)midi))) + IDirectMusicPerformance8_FreePMsg(performance, (DMUS_PMSG *)midi); + + return hr; +} + static HRESULT WINAPI performance_Init(IDirectMusicPerformance8 *iface, IDirectMusic **dmusic, IDirectSound *dsound, HWND hwnd) { @@ -613,6 +642,7 @@ static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectM struct performance *This = impl_from_IDirectMusicPerformance8(iface); struct list states = LIST_INIT(states); struct state_entry *entry, *next; + DMUS_PMSG msg = {.mtTime = -1}; HRESULT hr;
FIXME("(%p, %p, %p, %ld, %ld): semi-stub\n", This, segment, state, music_time, flags); @@ -652,6 +682,13 @@ static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectM free(entry); }
+ if (!state && !segment) + { + if (FAILED(hr = performance_send_midi_pmsg(This, &msg, DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, + MIDI_SYSTEM_RESET, 0, 0))) + ERR("Failed to send MIDI_SYSTEM_RESET message, hr %#lx\n", hr); + } + LeaveCriticalSection(&This->safe);
return S_OK; @@ -1345,6 +1382,7 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) struct performance *This = impl_from_IDirectMusicPerformance8(iface); struct list states = LIST_INIT(states); struct state_entry *entry, *next; + DMUS_PMSG msg = {.mtTime = -1}; HANDLE message_thread; HRESULT hr;
@@ -1377,6 +1415,10 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) free(entry); }
+ if (FAILED(hr = performance_send_midi_pmsg(This, &msg, DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, + MIDI_SYSTEM_RESET, 0, 0))) + ERR("Failed to send MIDI_SYSTEM_RESET message, hr %#lx\n", hr); + performance_set_primary_segment(This, NULL); performance_set_control_segment(This, NULL);
@@ -1930,35 +1972,6 @@ static HRESULT WINAPI performance_tool_GetMediaTypes(IDirectMusicTool *iface, DW return E_NOTIMPL; }
-static HRESULT performance_send_midi_pmsg(struct performance *This, DMUS_PMSG *msg, UINT flags, - BYTE status, BYTE byte1, BYTE byte2) -{ - IDirectMusicPerformance8 *performance = &This->IDirectMusicPerformance8_iface; - DMUS_MIDI_PMSG *midi; - HRESULT hr; - - if (FAILED(hr = IDirectMusicPerformance8_AllocPMsg(performance, sizeof(*midi), - (DMUS_PMSG **)&midi))) - return hr; - - if (flags & DMUS_PMSGF_REFTIME) midi->rtTime = msg->rtTime; - if (flags & DMUS_PMSGF_MUSICTIME) midi->mtTime = msg->mtTime; - midi->dwFlags = flags; - midi->dwPChannel = msg->dwPChannel; - midi->dwVirtualTrackID = msg->dwVirtualTrackID; - midi->dwVoiceID = msg->dwVoiceID; - midi->dwGroupID = msg->dwGroupID; - midi->dwType = DMUS_PMSGT_MIDI; - midi->bStatus = status; - midi->bByte1 = byte1; - midi->bByte2 = byte2; - - if (FAILED(hr = IDirectMusicPerformance8_SendPMsg(performance, (DMUS_PMSG *)midi))) - IDirectMusicPerformance8_FreePMsg(performance, (DMUS_PMSG *)midi); - - return hr; -} - static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, IDirectMusicPerformance *performance, DMUS_PMSG *msg) { diff --git a/dlls/dmusic/dmusic_midi.h b/dlls/dmusic/dmusic_midi.h index e545bcaf8cb..574961c12d0 100644 --- a/dlls/dmusic/dmusic_midi.h +++ b/dlls/dmusic/dmusic_midi.h @@ -31,6 +31,7 @@ enum midi_message MIDI_PROGRAM_CHANGE = 0xc0, MIDI_CHANNEL_PRESSURE = 0xd0, MIDI_PITCH_BEND_CHANGE = 0xe0, + MIDI_SYSTEM_RESET = 0xff, };
enum midi_control
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/synth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 410fb59089e..51271e48b2a 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1125,7 +1125,9 @@ static HRESULT WINAPI synth_Render(IDirectMusicSynth8 *iface, short *buffer,
TRACE("status %#x chan %#x midi %#x %#x\n", status, chan, event->midi[1], event->midi[2]);
- switch (status) + if (event->midi[0] == MIDI_SYSTEM_RESET) + synth_reset_default_values(This); + else switch (status) { case MIDI_NOTE_OFF: fluid_synth_noteoff(This->fluid_synth, chan, event->midi[1]);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/segmentstate.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 544620b0045..39a8874c724 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -53,6 +53,7 @@ struct segment_state MUSIC_TIME end_point; MUSIC_TIME played; BOOL auto_download; + DWORD repeats;
struct list tracks; }; @@ -234,6 +235,7 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time This->start_time = start_time; if (SUCCEEDED(hr)) hr = IDirectMusicSegment_GetStartPoint(segment, &This->start_point); if (SUCCEEDED(hr)) hr = IDirectMusicSegment_GetLength(segment, &This->end_point); + if (SUCCEEDED(hr)) hr = IDirectMusicSegment_GetRepeats(segment, &This->repeats);
for (i = 0; SUCCEEDED(hr); i++) { @@ -284,6 +286,7 @@ static HRESULT segment_state_play_chunk(struct segment_state *This, IDirectMusic if (FAILED(hr = IDirectMusicPerformance8_ReferenceToMusicTime(performance, time + duration, &next_time))) return hr; +play_more: played = min(next_time - This->start_time, This->end_point - This->start_point);
LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) @@ -303,6 +306,21 @@ static HRESULT segment_state_play_chunk(struct segment_state *This, IDirectMusic { MUSIC_TIME end_time = This->start_time + This->played;
+ if (This->repeats) + { + if (FAILED(hr = IDirectMusicSegment_GetLoopPoints(This->segment, + &This->played, &This->end_point))) + { + ERR("Failed to get segment loop points, hr %#lx\n", hr); + return hr; + } + This->start_time += This->end_point - This->start_point; + This->repeats--; + + if (next_time - This->start_time > 0 && This->end_point - This->start_point > 0) goto play_more; + return S_OK; + } + if (FAILED(hr = performance_send_segment_end(performance, end_time, iface, FALSE))) { ERR("Failed to send segment end, hr %#lx\n", hr);
v3: Drop 2607ee2beb3a471ef44a0c5677a04d950c4f93eb which sneaked its way in.
Indentation here is missing.
On Fri Nov 10 19:40:15 2023 +0000, Michael Stefaniuc wrote:
Indentation here is missing.
Never mind, just goes away with the todo_wine in the next commit
Michael Stefaniuc (@mstefani) commented about dlls/dmime/segmentstate.c:
{ MUSIC_TIME end_time = This->start_time + This->played;
if (This->repeats)
{
if (FAILED(hr = IDirectMusicSegment_GetLoopPoints(This->segment,
&This->played, &This->end_point)))
{
ERR("Failed to get segment loop points, hr %#lx\n", hr);
return hr;
}
This->start_time += This->end_point - This->start_point;
This->repeats--;
if (next_time - This->start_time > 0 && This->end_point - This->start_point > 0) goto play_more;
Not a fan of goto for flow control outside of error handling.\ Here a do while loop should work too.
On Fri Nov 10 19:54:02 2023 +0000, Michael Stefaniuc wrote:
Not a fan of goto for flow control outside of error handling.\ Here a do while loop should work too.
Yeah, I was a bit lazy trying to figure how to make it work with all the nested ifs, and wanted to reduce the diff but I get it, will see what I can come up with.