From 18a81b3cb2fbf9a14a69ac30809f9265e274ab3a Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 15:25:40 +0200 Subject: [PATCH] dmime: Better implement performance times with tempo track. --- 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..94d7d8aeea3 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 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.0, 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.0 * next) / (tempo * DMUS_PPQ); + music_time -= next; + } + + duration += (600000000.0 * 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.0, 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.0 * next) / (tempo * DMUS_PPQ); + if (!next || duration < step) break; + *music_time = *music_time + next; + } + + *music_time = *music_time + round((duration * tempo * DMUS_PPQ) / 600000000.0); + + 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 a0c298fe994..7613b82c893 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; -- 2.11.4.GIT