-- v2: dmsynth: Use time instead of position to order events. dmsynth: Preserve event order when positions are equal. dmime: Queue note-off one tick early. dmime: Requeue the note message instead of directly queueing MIDI note-off. dmime/tests: Test output tool note requeueing. dmime/tests: Move scale_music_time() and check_dmus_note_pmsg() up. dmime: Correctly requeue messages with changed time. dmime: Always queue messages with non-immediate delivery type. dmime: Don't queue messages with immediate delivery type. dmime: Factor out timeout computation.
From: Anton Baskanov baskanov@gmail.com
--- dlls/dmime/performance.c | 68 ++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 17 deletions(-)
diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index f4504c4d36f..eccc1f83683 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -110,7 +110,44 @@ static void performance_queue_message(struct performance *This, struct message * list_add_after(&prev->entry, &message->entry); }
-static HRESULT performance_process_message(struct performance *This, DMUS_PMSG *msg, DWORD *timeout) +static struct message *performance_get_message(struct performance *This, DWORD *timeout) +{ + static const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME; + IDirectMusicPerformance *performance = (IDirectMusicPerformance *)&This->IDirectMusicPerformance8_iface; + REFERENCE_TIME latency, offset = 0; + struct message *message; + struct list *ptr; + + if (!(ptr = list_head(&This->messages))) + return NULL; + message = LIST_ENTRY(ptr, struct message, entry); + + if (FAILED(IDirectMusicPerformance_GetLatencyTime(performance, &latency))) + return NULL; + + switch (message->msg.dwFlags & delivery_flags) + { + default: + WARN("No delivery flag found for message %p\n", &message->msg); + /* fallthrough */ + case DMUS_PMSGF_TOOL_IMMEDIATE: + break; + case DMUS_PMSGF_TOOL_QUEUE: + offset = This->dwBumperLength * 10000; + /* fallthrough */ + case DMUS_PMSGF_TOOL_ATTIME: + if (message->msg.rtTime >= offset && message->msg.rtTime - offset >= latency) + { + *timeout = (message->msg.rtTime - offset - latency) / 10000; + return NULL; + } + break; + } + + return message; +} + +static HRESULT performance_process_message(struct performance *This, DMUS_PMSG *msg) { static const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME; IDirectMusicPerformance *performance = (IDirectMusicPerformance *)&This->IDirectMusicPerformance8_iface; @@ -137,10 +174,7 @@ static HRESULT performance_process_message(struct performance *This, DMUS_PMSG * /* fallthrough */ case DMUS_PMSGF_TOOL_ATTIME: if (msg->rtTime >= offset && msg->rtTime - offset >= latency) - { - if (timeout) *timeout = (msg->rtTime - offset - latency) / 10000; return DMUS_S_REQUEUE; - }
hr = IDirectMusicTool_ProcessPMsg(tool, performance, msg); break; @@ -155,8 +189,7 @@ static HRESULT performance_process_message(struct performance *This, DMUS_PMSG * static DWORD WINAPI message_thread_proc(void *args) { struct performance *This = args; - HRESULT hr = DMUS_S_REQUEUE; - struct list *ptr; + HRESULT hr;
TRACE("performance %p message thread\n", This); SetThreadDescription(GetCurrentThread(), L"wine_dmime_message"); @@ -166,20 +199,21 @@ static DWORD WINAPI message_thread_proc(void *args) while (This->message_thread) { DWORD timeout = INFINITE; + struct message *message; + struct list *next;
- while ((ptr = list_head(&This->messages))) + if (!(message = performance_get_message(This, &timeout))) { - struct message *message = LIST_ENTRY(ptr, struct message, entry); - struct list *next = ptr->next; - list_remove(&message->entry); - list_init(&message->entry); - - hr = performance_process_message(This, &message->msg, &timeout); - if (hr == DMUS_S_REQUEUE) performance_queue_message(This, message, next); - if (hr != S_OK) break; + SleepConditionVariableCS(&This->cond, &This->safe, timeout); + continue; } + next = message->entry.next; + + list_remove(&message->entry); + list_init(&message->entry);
- SleepConditionVariableCS(&This->cond, &This->safe, timeout); + hr = performance_process_message(This, &message->msg); + if (hr == DMUS_S_REQUEUE) performance_queue_message(This, message, next); }
LeaveCriticalSection(&This->safe); @@ -824,7 +858,7 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS
if (msg->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) { - hr = performance_process_message(This, &message->msg, NULL); + hr = performance_process_message(This, &message->msg); if (hr != DMUS_S_REQUEUE) goto done; }
From: Anton Baskanov baskanov@gmail.com
--- dlls/dmime/performance.c | 59 ++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 26 deletions(-)
diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index eccc1f83683..58a95e825d4 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -97,19 +97,6 @@ static inline struct message *message_from_DMUS_PMSG(DMUS_PMSG *msg) return msg ? CONTAINING_RECORD(msg, struct message, msg) : NULL; }
-static void performance_queue_message(struct performance *This, struct message *message, struct list *hint) -{ - struct message *prev; - - LIST_FOR_EACH_ENTRY_REV(prev, hint ? hint : &This->messages, struct message, entry) - { - if (&prev->entry == &This->messages) break; - if (prev->msg.rtTime <= message->msg.rtTime) break; - } - - list_add_after(&prev->entry, &message->entry); -} - static struct message *performance_get_message(struct performance *This, DWORD *timeout) { static const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME; @@ -127,11 +114,6 @@ static struct message *performance_get_message(struct performance *This, DWORD *
switch (message->msg.dwFlags & delivery_flags) { - default: - WARN("No delivery flag found for message %p\n", &message->msg); - /* fallthrough */ - case DMUS_PMSGF_TOOL_IMMEDIATE: - break; case DMUS_PMSGF_TOOL_QUEUE: offset = This->dwBumperLength * 10000; /* fallthrough */ @@ -186,6 +168,38 @@ static HRESULT performance_process_message(struct performance *This, DMUS_PMSG * return hr; }
+static HRESULT performance_queue_message(struct performance *This, struct message *message, struct list *hint) +{ + static const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME; + struct message *prev; + HRESULT hr; + + for (;;) + { + if ((message->msg.dwFlags & delivery_flags) == DMUS_PMSGF_TOOL_QUEUE) + break; + if ((message->msg.dwFlags & delivery_flags) == DMUS_PMSGF_TOOL_ATTIME) + break; + if ((message->msg.dwFlags & delivery_flags) != DMUS_PMSGF_TOOL_IMMEDIATE) + WARN("No delivery flag found for message %p\n", &message->msg); + + hr = performance_process_message(This, &message->msg); + if (hr == DMUS_S_REQUEUE) + continue; + return hr; + } + + LIST_FOR_EACH_ENTRY_REV(prev, hint ? hint : &This->messages, struct message, entry) + { + if (&prev->entry == &This->messages) break; + if (prev->msg.rtTime <= message->msg.rtTime) break; + } + + list_add_after(&prev->entry, &message->entry); + + return S_OK; +} + static DWORD WINAPI message_thread_proc(void *args) { struct performance *This = args; @@ -856,14 +870,7 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS msg->dwFlags |= DMUS_PMSGF_REFTIME; }
- if (msg->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) - { - hr = performance_process_message(This, &message->msg); - if (hr != DMUS_S_REQUEUE) goto done; - } - - performance_queue_message(This, message, NULL); - hr = S_OK; + hr = performance_queue_message(This, message, NULL); }
done:
From: Anton Baskanov baskanov@gmail.com
--- dlls/dmime/performance.c | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-)
diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 58a95e825d4..35e6b90b74e 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -131,37 +131,13 @@ static struct message *performance_get_message(struct performance *This, DWORD *
static HRESULT performance_process_message(struct performance *This, DMUS_PMSG *msg) { - static const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME; IDirectMusicPerformance *performance = (IDirectMusicPerformance *)&This->IDirectMusicPerformance8_iface; + IDirectMusicTool *tool; HRESULT hr;
- do - { - REFERENCE_TIME latency, offset = 0; - IDirectMusicTool *tool; - - if (FAILED(hr = IDirectMusicPerformance_GetLatencyTime(performance, &latency))) return hr; - if (!(tool = msg->pTool)) tool = &This->IDirectMusicTool_iface; + if (!(tool = msg->pTool)) tool = &This->IDirectMusicTool_iface;
- switch (msg->dwFlags & delivery_flags) - { - default: - WARN("No delivery flag found for message %p\n", msg); - /* fallthrough */ - case DMUS_PMSGF_TOOL_IMMEDIATE: - hr = IDirectMusicTool_ProcessPMsg(tool, performance, msg); - break; - case DMUS_PMSGF_TOOL_QUEUE: - offset = This->dwBumperLength * 10000; - /* fallthrough */ - case DMUS_PMSGF_TOOL_ATTIME: - if (msg->rtTime >= offset && msg->rtTime - offset >= latency) - return DMUS_S_REQUEUE; - - hr = IDirectMusicTool_ProcessPMsg(tool, performance, msg); - break; - } - } while (hr == DMUS_S_REQUEUE); + hr = IDirectMusicTool_ProcessPMsg(tool, performance, msg);
if (hr == DMUS_S_FREE) hr = IDirectMusicPerformance_FreePMsg(performance, msg); if (FAILED(hr)) WARN("Failed to process message, hr %#lx\n", hr);
From: Anton Baskanov baskanov@gmail.com
--- dlls/dmime/performance.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 35e6b90b74e..01e0bad51b3 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -144,7 +144,7 @@ static HRESULT performance_process_message(struct performance *This, DMUS_PMSG * return hr; }
-static HRESULT performance_queue_message(struct performance *This, struct message *message, struct list *hint) +static HRESULT performance_queue_message(struct performance *This, struct message *message) { static const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME; struct message *prev; @@ -165,7 +165,7 @@ static HRESULT performance_queue_message(struct performance *This, struct messag return hr; }
- LIST_FOR_EACH_ENTRY_REV(prev, hint ? hint : &This->messages, struct message, entry) + LIST_FOR_EACH_ENTRY_REV(prev, &This->messages, struct message, entry) { if (&prev->entry == &This->messages) break; if (prev->msg.rtTime <= message->msg.rtTime) break; @@ -190,20 +190,18 @@ static DWORD WINAPI message_thread_proc(void *args) { DWORD timeout = INFINITE; struct message *message; - struct list *next;
if (!(message = performance_get_message(This, &timeout))) { SleepConditionVariableCS(&This->cond, &This->safe, timeout); continue; } - next = message->entry.next;
list_remove(&message->entry); list_init(&message->entry);
hr = performance_process_message(This, &message->msg); - if (hr == DMUS_S_REQUEUE) performance_queue_message(This, message, next); + if (hr == DMUS_S_REQUEUE) performance_queue_message(This, message); }
LeaveCriticalSection(&This->safe); @@ -846,7 +844,7 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS msg->dwFlags |= DMUS_PMSGF_REFTIME; }
- hr = performance_queue_message(This, message, NULL); + hr = performance_queue_message(This, message); }
done:
From: Anton Baskanov baskanov@gmail.com
--- dlls/dmime/tests/dmime.c | 70 ++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index e1d88c11d62..16a9a46df81 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -59,6 +59,41 @@ static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOO } }
+static double scale_music_time(MUSIC_TIME time, double tempo) +{ + return (600000000.0 * time) / (tempo * 768.0); +} + +#define check_dmus_note_pmsg(a, b, c, d, e, f) check_dmus_note_pmsg_(__LINE__, a, b, c, d, e, f) +static void check_dmus_note_pmsg_(int line, DMUS_NOTE_PMSG *msg, MUSIC_TIME time, UINT chan, + UINT duration, UINT key, UINT vel) +{ + ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize); + ok_(__FILE__, line)(!!msg->rtTime, "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 == chan, "got dwPChannel %lu\n", msg->dwPChannel); + ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID); + ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_NOTE, "got %#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->mtDuration == duration, "got mtDuration %lu\n", msg->mtDuration); + ok_(__FILE__, line)(msg->wMusicValue == key, "got wMusicValue %u\n", msg->wMusicValue); + ok_(__FILE__, line)(!msg->wMeasure, "got wMeasure %u\n", msg->wMeasure); + /* FIXME: ok_(__FILE__, line)(!msg->nOffset, "got nOffset %u\n", msg->nOffset); */ + /* FIXME: ok_(__FILE__, line)(!msg->bBeat, "got bBeat %u\n", msg->bBeat); */ + /* FIXME: ok_(__FILE__, line)(!msg->bGrid, "got bGrid %u\n", msg->bGrid); */ + ok_(__FILE__, line)(msg->bVelocity == vel, "got bVelocity %u\n", msg->bVelocity); + ok_(__FILE__, line)(msg->bFlags == 1, "got bFlags %#x\n", msg->bFlags); + ok_(__FILE__, line)(!msg->bTimeRange, "got bTimeRange %u\n", msg->bTimeRange); + ok_(__FILE__, line)(!msg->bDurRange, "got bDurRange %u\n", msg->bDurRange); + ok_(__FILE__, line)(!msg->bVelRange, "got bVelRange %u\n", msg->bVelRange); + ok_(__FILE__, line)(!msg->bPlayModeFlags, "got bPlayModeFlags %#x\n", msg->bPlayModeFlags); + ok_(__FILE__, line)(!msg->bSubChordLevel, "got bSubChordLevel %u\n", msg->bSubChordLevel); + ok_(__FILE__, line)(msg->bMidiValue == key, "got bMidiValue %u\n", msg->bMidiValue); + ok_(__FILE__, line)(!msg->cTranspose, "got cTranspose %u\n", msg->cTranspose); +} + static void load_resource(const WCHAR *name, WCHAR *filename) { static WCHAR path[MAX_PATH]; @@ -2671,11 +2706,6 @@ static void test_performance_graph(void) IDirectMusicTool_Release(tool); }
-static double scale_music_time(MUSIC_TIME time, double tempo) -{ - return (600000000.0 * time) / (tempo * 768.0); -} - #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) { @@ -3510,36 +3540,6 @@ static void test_wave_pmsg(void) IDirectMusicTool_Release(tool); }
-#define check_dmus_note_pmsg(a, b, c, d, e, f) check_dmus_note_pmsg_(__LINE__, a, b, c, d, e, f) -static void check_dmus_note_pmsg_(int line, DMUS_NOTE_PMSG *msg, MUSIC_TIME time, UINT chan, - UINT duration, UINT key, UINT vel) -{ - ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize); - ok_(__FILE__, line)(!!msg->rtTime, "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 == chan, "got dwPChannel %lu\n", msg->dwPChannel); - ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID); - ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_NOTE, "got %#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->mtDuration == duration, "got mtDuration %lu\n", msg->mtDuration); - ok_(__FILE__, line)(msg->wMusicValue == key, "got wMusicValue %u\n", msg->wMusicValue); - ok_(__FILE__, line)(!msg->wMeasure, "got wMeasure %u\n", msg->wMeasure); - /* FIXME: ok_(__FILE__, line)(!msg->nOffset, "got nOffset %u\n", msg->nOffset); */ - /* FIXME: ok_(__FILE__, line)(!msg->bBeat, "got bBeat %u\n", msg->bBeat); */ - /* FIXME: ok_(__FILE__, line)(!msg->bGrid, "got bGrid %u\n", msg->bGrid); */ - ok_(__FILE__, line)(msg->bVelocity == vel, "got bVelocity %u\n", msg->bVelocity); - ok_(__FILE__, line)(msg->bFlags == 1, "got bFlags %#x\n", msg->bFlags); - ok_(__FILE__, line)(!msg->bTimeRange, "got bTimeRange %u\n", msg->bTimeRange); - ok_(__FILE__, line)(!msg->bDurRange, "got bDurRange %u\n", msg->bDurRange); - ok_(__FILE__, line)(!msg->bVelRange, "got bVelRange %u\n", msg->bVelRange); - ok_(__FILE__, line)(!msg->bPlayModeFlags, "got bPlayModeFlags %#x\n", msg->bPlayModeFlags); - ok_(__FILE__, line)(!msg->bSubChordLevel, "got bSubChordLevel %u\n", msg->bSubChordLevel); - ok_(__FILE__, line)(msg->bMidiValue == key, "got bMidiValue %u\n", msg->bMidiValue); - ok_(__FILE__, line)(!msg->cTranspose, "got cTranspose %u\n", msg->cTranspose); -} - static void test_sequence_track(void) { static const DWORD message_types[] =
From: Anton Baskanov baskanov@gmail.com
--- dlls/dmime/tests/dmime.c | 118 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 6 deletions(-)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 16a9a46df81..94f781d2796 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -19,6 +19,7 @@ #define COBJMACROS
#include <stdarg.h> +#include <math.h> #include <windef.h> #include <wine/test.h> #include <initguid.h> @@ -64,13 +65,13 @@ static double scale_music_time(MUSIC_TIME time, double tempo) return (600000000.0 * time) / (tempo * 768.0); }
-#define check_dmus_note_pmsg(a, b, c, d, e, f) check_dmus_note_pmsg_(__LINE__, a, b, c, d, e, f) +#define check_dmus_note_pmsg(a, b, c, d, e, f, g, h, i) check_dmus_note_pmsg_(__LINE__, a, b, c, d, e, f, g, h, i) static void check_dmus_note_pmsg_(int line, DMUS_NOTE_PMSG *msg, MUSIC_TIME time, UINT chan, - UINT duration, UINT key, UINT vel) + UINT duration, UINT key, UINT vel, UINT flags, BOOL time_todo, BOOL flags_todo) { ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize); ok_(__FILE__, line)(!!msg->rtTime, "got rtTime %I64u\n", msg->rtTime); - ok_(__FILE__, line)(abs(msg->mtTime - time) < 10, "got mtTime %lu\n", msg->mtTime); + todo_wine_if(time_todo) ok_(__FILE__, line)(abs(msg->mtTime - time) < 10, "got mtTime %lu\n", msg->mtTime); ok_(__FILE__, line)(msg->dwPChannel == chan, "got dwPChannel %lu\n", msg->dwPChannel); ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID); ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_NOTE, "got %#lx\n", msg->dwType); @@ -84,7 +85,7 @@ static void check_dmus_note_pmsg_(int line, DMUS_NOTE_PMSG *msg, MUSIC_TIME time /* FIXME: ok_(__FILE__, line)(!msg->bBeat, "got bBeat %u\n", msg->bBeat); */ /* FIXME: ok_(__FILE__, line)(!msg->bGrid, "got bGrid %u\n", msg->bGrid); */ ok_(__FILE__, line)(msg->bVelocity == vel, "got bVelocity %u\n", msg->bVelocity); - ok_(__FILE__, line)(msg->bFlags == 1, "got bFlags %#x\n", msg->bFlags); + todo_wine_if(flags_todo) ok_(__FILE__, line)(msg->bFlags == flags, "got bFlags %#x\n", msg->bFlags); ok_(__FILE__, line)(!msg->bTimeRange, "got bTimeRange %u\n", msg->bTimeRange); ok_(__FILE__, line)(!msg->bDurRange, "got bDurRange %u\n", msg->bDurRange); ok_(__FILE__, line)(!msg->bVelRange, "got bVelRange %u\n", msg->bVelRange); @@ -2546,10 +2547,25 @@ static void test_performance_pchannel(void)
static void test_performance_tool(void) { + DMUS_NOTE_PMSG note60 = + { + .dwSize = sizeof(DMUS_NOTE_PMSG), + .dwFlags = DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE, + .dwVirtualTrackID = 1, + .dwType = DMUS_PMSGT_NOTE, + .dwGroupID = 1, + .mtDuration = 1000, + .wMusicValue = 60, + .bVelocity = 127, + .bFlags = DMUS_NOTEF_NOTEON, + .bPlayModeFlags = DMUS_PLAYMODE_FIXED, + .bMidiValue = 60, + }; IDirectMusicPerformance *performance; IDirectMusicGraph *graph; IDirectMusicTool *tool; DWORD value, types[1]; + DMUS_NOTE_PMSG *note; DMUS_PMSG msg = {0}; HRESULT hr;
@@ -2581,6 +2597,96 @@ static void test_performance_tool(void) hr = IDirectMusicTool_Flush(tool, performance, &msg, 0); todo_wine ok(hr == S_OK, "got %#lx\n", hr);
+ hr = IDirectMusicPerformance_Init(performance, NULL, NULL, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_AddPort(performance, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_NOTE_PMSG), (DMUS_PMSG **)¬e); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, ¬e60.rtTime); + ok(hr == S_OK, "got %#lx\n", hr); + + *note = note60; + note->bFlags = 0; + hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); + ok(hr == DMUS_S_FREE, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, ¬e60.rtTime); + ok(hr == S_OK, "got %#lx\n", hr); + + *note = note60; + note->mtDuration = 0; + hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); + ok(hr == DMUS_S_FREE, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, ¬e60.rtTime); + ok(hr == S_OK, "got %#lx\n", hr); + + *note = note60; + hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); + todo_wine ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); + todo_wine ok(fabs(note->rtTime - note60.rtTime - scale_music_time(999, 120.0)) < 10.0, + "got %I64d\n", note->rtTime - note60.rtTime); + todo_wine ok(note->mtTime - note60.mtTime == 999, "got %ld\n", note->mtTime - note60.mtTime); + check_dmus_note_pmsg(note, note60.mtTime + 999, 0, 1000, 60, 127, 0, FALSE, TRUE); + + hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, ¬e60.rtTime); + ok(hr == S_OK, "got %#lx\n", hr); + + *note = note60; + note->nOffset = 1000; + hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); + todo_wine ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); + todo_wine ok(fabs(note->rtTime - note60.rtTime - scale_music_time(999, 120.0)) < 10.0, + "got %I64d\n", note->rtTime - note60.rtTime); + todo_wine ok(note->mtTime - note60.mtTime == 999, "got %ld\n", note->mtTime - note60.mtTime); + check_dmus_note_pmsg(note, note60.mtTime + 999, 0, 1000, 60, 127, 0, TRUE, TRUE); + + hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, ¬e60.rtTime); + ok(hr == S_OK, "got %#lx\n", hr); + + *note = note60; + note->mtDuration = 2; + hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); + todo_wine ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); + todo_wine ok(fabs(note->rtTime - note60.rtTime - scale_music_time(1, 120.0)) < 10.0, + "got %I64d\n", note->rtTime - note60.rtTime); + todo_wine ok(note->mtTime - note60.mtTime == 1, "got %ld\n", note->mtTime - note60.mtTime); + check_dmus_note_pmsg(note, note60.mtTime + 1, 0, 2, 60, 127, 0, FALSE, TRUE); + + hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, ¬e60.rtTime); + ok(hr == S_OK, "got %#lx\n", hr); + + *note = note60; + note->mtDuration = 1; + hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); + todo_wine ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); + todo_wine ok(fabs(note->rtTime - note60.rtTime - scale_music_time(1, 120.0)) < 10.0, + "got %I64d\n", note->rtTime - note60.rtTime); + ok(note->mtTime - note60.mtTime == 1, "got %ld\n", note->mtTime - note60.mtTime); + check_dmus_note_pmsg(note, note60.mtTime + 1, 0, 1, 60, 127, 0, FALSE, TRUE); + + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_CloseDown(performance); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicGraph_Release(graph); IDirectMusicTool_Release(tool);
@@ -3657,13 +3763,13 @@ static void test_sequence_track(void)
ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬e); ok(!ret, "got %#lx\n", ret); - check_dmus_note_pmsg(note, 0, 0, 500, 60, 120); + check_dmus_note_pmsg(note, 0, 0, 500, 60, 120, DMUS_NOTEF_NOTEON, FALSE, FALSE); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note); ok(hr == S_OK, "got %#lx\n", hr);
ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬e); ok(!ret, "got %#lx\n", ret); - check_dmus_note_pmsg(note, 1000, 1, 200, 50, 100); + check_dmus_note_pmsg(note, 1000, 1, 200, 50, 100, DMUS_NOTEF_NOTEON, FALSE, FALSE); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note); ok(hr == S_OK, "got %#lx\n", hr);
From: Anton Baskanov baskanov@gmail.com
--- dlls/dmime/performance.c | 23 ++++++++++++++++++----- dlls/dmime/tests/dmime.c | 18 +++++++++--------- 2 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 01e0bad51b3..10f4f795432 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -2062,12 +2062,25 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, DMUS_NOTE_PMSG *note = (DMUS_NOTE_PMSG *)msg;
msg->mtTime += note->nOffset; - if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, - MIDI_NOTE_ON, note->bMidiValue, note->bVelocity))) - WARN("Failed to translate message to MIDI, hr %#lx\n", hr);
- msg->mtTime += note->mtDuration; - if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE, + if (note->bFlags & DMUS_NOTEF_NOTEON) + { + if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, + MIDI_NOTE_ON, note->bMidiValue, note->bVelocity))) + WARN("Failed to translate message to MIDI, hr %#lx\n", hr); + + if (note->mtDuration) + { + msg->mtTime -= note->nOffset; + msg->mtTime += note->mtDuration; + if (FAILED(hr = IDirectMusicPerformance8_MusicToReferenceTime(performance, msg->mtTime, &msg->rtTime))) + return hr; + note->bFlags &= ~DMUS_NOTEF_NOTEON; + return DMUS_S_REQUEUE; + } + } + + if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, MIDI_NOTE_OFF, note->bMidiValue, 0))) WARN("Failed to translate message to MIDI, hr %#lx\n", hr);
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 94f781d2796..4edab18c283 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -2633,11 +2633,11 @@ static void test_performance_tool(void)
*note = note60; hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); - todo_wine ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); + ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); todo_wine ok(fabs(note->rtTime - note60.rtTime - scale_music_time(999, 120.0)) < 10.0, "got %I64d\n", note->rtTime - note60.rtTime); todo_wine ok(note->mtTime - note60.mtTime == 999, "got %ld\n", note->mtTime - note60.mtTime); - check_dmus_note_pmsg(note, note60.mtTime + 999, 0, 1000, 60, 127, 0, FALSE, TRUE); + check_dmus_note_pmsg(note, note60.mtTime + 999, 0, 1000, 60, 127, 0, FALSE, FALSE);
hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime); ok(hr == S_OK, "got %#lx\n", hr); @@ -2647,11 +2647,11 @@ static void test_performance_tool(void) *note = note60; note->nOffset = 1000; hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); - todo_wine ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); + ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); todo_wine ok(fabs(note->rtTime - note60.rtTime - scale_music_time(999, 120.0)) < 10.0, "got %I64d\n", note->rtTime - note60.rtTime); todo_wine ok(note->mtTime - note60.mtTime == 999, "got %ld\n", note->mtTime - note60.mtTime); - check_dmus_note_pmsg(note, note60.mtTime + 999, 0, 1000, 60, 127, 0, TRUE, TRUE); + check_dmus_note_pmsg(note, note60.mtTime + 999, 0, 1000, 60, 127, 0, FALSE, FALSE);
hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime); ok(hr == S_OK, "got %#lx\n", hr); @@ -2661,11 +2661,11 @@ static void test_performance_tool(void) *note = note60; note->mtDuration = 2; hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); - todo_wine ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); + ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); todo_wine ok(fabs(note->rtTime - note60.rtTime - scale_music_time(1, 120.0)) < 10.0, "got %I64d\n", note->rtTime - note60.rtTime); todo_wine ok(note->mtTime - note60.mtTime == 1, "got %ld\n", note->mtTime - note60.mtTime); - check_dmus_note_pmsg(note, note60.mtTime + 1, 0, 2, 60, 127, 0, FALSE, TRUE); + check_dmus_note_pmsg(note, note60.mtTime + 1, 0, 2, 60, 127, 0, FALSE, FALSE);
hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime); ok(hr == S_OK, "got %#lx\n", hr); @@ -2675,11 +2675,11 @@ static void test_performance_tool(void) *note = note60; note->mtDuration = 1; hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); - todo_wine ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); - todo_wine ok(fabs(note->rtTime - note60.rtTime - scale_music_time(1, 120.0)) < 10.0, + ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); + ok(fabs(note->rtTime - note60.rtTime - scale_music_time(1, 120.0)) < 10.0, "got %I64d\n", note->rtTime - note60.rtTime); ok(note->mtTime - note60.mtTime == 1, "got %ld\n", note->mtTime - note60.mtTime); - check_dmus_note_pmsg(note, note60.mtTime + 1, 0, 1, 60, 127, 0, FALSE, TRUE); + check_dmus_note_pmsg(note, note60.mtTime + 1, 0, 1, 60, 127, 0, FALSE, FALSE);
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note); ok(hr == S_OK, "got %#lx\n", hr);
From: Anton Baskanov baskanov@gmail.com
--- dlls/dmime/performance.c | 2 +- dlls/dmime/tests/dmime.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 10f4f795432..0e780e8fe8c 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -2072,7 +2072,7 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, if (note->mtDuration) { msg->mtTime -= note->nOffset; - msg->mtTime += note->mtDuration; + msg->mtTime += max(1, note->mtDuration - 1); if (FAILED(hr = IDirectMusicPerformance8_MusicToReferenceTime(performance, msg->mtTime, &msg->rtTime))) return hr; note->bFlags &= ~DMUS_NOTEF_NOTEON; diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 4edab18c283..4d61798f417 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -2634,9 +2634,9 @@ static void test_performance_tool(void) *note = note60; hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); - todo_wine ok(fabs(note->rtTime - note60.rtTime - scale_music_time(999, 120.0)) < 10.0, + ok(fabs(note->rtTime - note60.rtTime - scale_music_time(999, 120.0)) < 10.0, "got %I64d\n", note->rtTime - note60.rtTime); - todo_wine ok(note->mtTime - note60.mtTime == 999, "got %ld\n", note->mtTime - note60.mtTime); + ok(note->mtTime - note60.mtTime == 999, "got %ld\n", note->mtTime - note60.mtTime); check_dmus_note_pmsg(note, note60.mtTime + 999, 0, 1000, 60, 127, 0, FALSE, FALSE);
hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime); @@ -2648,9 +2648,9 @@ static void test_performance_tool(void) note->nOffset = 1000; hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); - todo_wine ok(fabs(note->rtTime - note60.rtTime - scale_music_time(999, 120.0)) < 10.0, + ok(fabs(note->rtTime - note60.rtTime - scale_music_time(999, 120.0)) < 10.0, "got %I64d\n", note->rtTime - note60.rtTime); - todo_wine ok(note->mtTime - note60.mtTime == 999, "got %ld\n", note->mtTime - note60.mtTime); + ok(note->mtTime - note60.mtTime == 999, "got %ld\n", note->mtTime - note60.mtTime); check_dmus_note_pmsg(note, note60.mtTime + 999, 0, 1000, 60, 127, 0, FALSE, FALSE);
hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime); @@ -2662,9 +2662,9 @@ static void test_performance_tool(void) note->mtDuration = 2; hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note); ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr); - todo_wine ok(fabs(note->rtTime - note60.rtTime - scale_music_time(1, 120.0)) < 10.0, + ok(fabs(note->rtTime - note60.rtTime - scale_music_time(1, 120.0)) < 10.0, "got %I64d\n", note->rtTime - note60.rtTime); - todo_wine ok(note->mtTime - note60.mtTime == 1, "got %ld\n", note->mtTime - note60.mtTime); + ok(note->mtTime - note60.mtTime == 1, "got %ld\n", note->mtTime - note60.mtTime); check_dmus_note_pmsg(note, note60.mtTime + 1, 0, 2, 60, 127, 0, FALSE, FALSE);
hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime);
From: Anton Baskanov baskanov@gmail.com
Fixes hanging notes that occur when noteon gets reordered with noteoff. --- dlls/dmsynth/synth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index bbe77e43cc9..222481c8769 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -977,7 +977,7 @@ static HRESULT WINAPI synth_PlayBuffer(IDirectMusicSynth8 *iface,
EnterCriticalSection(&This->cs); LIST_FOR_EACH_ENTRY(next_event, &This->events, struct event, entry) - if (next_event->position >= event->position) break; + if (next_event->position > event->position) break; list_add_before(&next_event->entry, &event->entry); LeaveCriticalSection(&This->cs); }
From: Anton Baskanov baskanov@gmail.com
Different time values can map to the same position. --- 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 222481c8769..3eed05f35a0 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -322,6 +322,7 @@ struct preset struct event { struct list entry; + REFERENCE_TIME time; LONGLONG position; BYTE midi[3]; }; @@ -973,11 +974,12 @@ static HRESULT WINAPI synth_PlayBuffer(IDirectMusicSynth8 *iface, { if (!(event = calloc(1, sizeof(*event)))) return E_OUTOFMEMORY; memcpy(event->midi, data, head->cbEvent); + event->time = time + head->rtDelta; event->position = position;
EnterCriticalSection(&This->cs); LIST_FOR_EACH_ENTRY(next_event, &This->events, struct event, entry) - if (next_event->position > event->position) break; + if (next_event->time > event->time) break; list_add_before(&next_event->entry, &event->entry); LeaveCriticalSection(&This->cs); }
On Wed Nov 22 10:04:43 2023 +0000, Anton Baskanov wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/4438/diffs?diff_id=85143&start_sha=29e5ef31640dc0c2e3d237d3d22453f3a95d28d2#48cc44a37015b85ffde4c017dd6e790d71aa84da_100_100)
I ended up refactoring the message processing, and it no longer uses DMUS_S_REQUEUE when waiting for a message.
On Mon Nov 20 11:27:00 2023 +0000, Rémi Bernon wrote:
This doesn't look flexible enough, and the hardcoded value isn't great. I'd do something like this to leave around 1ms of leeway.
todo_wine ok(fabs(note.rtTime - rt - scale_music_time(999, 120.0)) < 10000.0, "got %I64d\n", note.rtTime - rt);
1ms is not strict enough to catch 1 MT tick difference. Otherwise, done.
On Mon Nov 20 11:27:01 2023 +0000, Rémi Bernon wrote:
hr = IDirectMusicPerformance_GetTime(performance, &rt, &mt); ok(hr == S_OK, "got %#lx\n", hr);
I also think it'd be better to get the time before each test, to avoid diverging. Fwiw, I'd just make note60 a local variable, and use its `rtTime` / `mtTime` members directly instead of `rt` / `mt`.
Done.
On Wed Nov 22 10:04:46 2023 +0000, Anton Baskanov wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/4438/diffs?diff_id=85143&start_sha=29e5ef31640dc0c2e3d237d3d22453f3a95d28d2#b32fb06c5f678bc37b3457cfa4bf2a30223d6200_2620_2651)
Done.
On Wed Nov 22 10:04:48 2023 +0000, Anton Baskanov wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/4438/diffs?diff_id=85143&start_sha=29e5ef31640dc0c2e3d237d3d22453f3a95d28d2#48cc44a37015b85ffde4c017dd6e790d71aa84da_178_205)
Thanks! This helped a lot to understand what's going on.