From: Yuxuan Shui yshui@codeweavers.com
--- dlls/dmime/miditracks.c | 73 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 5 deletions(-)
diff --git a/dlls/dmime/miditracks.c b/dlls/dmime/miditracks.c index 2db583376b3..f82380692c1 100644 --- a/dlls/dmime/miditracks.c +++ b/dlls/dmime/miditracks.c @@ -85,6 +85,7 @@ struct midi_sequence_track UINT ticks_per_quarter_note; UINT ticks_per_second; UINT event_count; + BOOL has_tempo_events;
struct list events; }; @@ -221,9 +222,41 @@ static HRESULT WINAPI midi_sequence_track_GetParam(IDirectMusicTrack8 *iface, RE MUSIC_TIME time, MUSIC_TIME *next, void *param) { struct midi_sequence_track *This = impl_from_IDirectMusicTrack8(iface); + struct event *event; + ULONG ticks = 0; + MUSIC_TIME music_time; + DMUS_TEMPO_PARAM *tempo = param; + + TRACE("(%p, %s, %ld, %p, %p): semi-stub\n", This, debugstr_dmguid(type), time, next, param); + if (!param) return E_POINTER; + if (!IsEqualGUID(type, &GUID_TempoParam)) return DMUS_E_GET_UNSUPPORTED; + if (!This->has_tempo_events) return DMUS_E_NOT_FOUND; + if (This->ticks_per_quarter_note == 0) + { + /* Return a "fake" tempo to make MIDI time and MUSIC_TIME equivalent. */ + tempo->mtTime = -time; /* set since the start of MUSIC_TIME. */ + if (next) *next = 0; /* always valid. */ + tempo->dblTempo = (double)This->ticks_per_second / DMUS_PPQ; + return S_OK; + }
- TRACE("(%p, %s, %ld, %p, %p): method not implemented\n", This, debugstr_dmguid(type), time, next, param); - return E_NOTIMPL; + if (next) *next = 0; + tempo->dblTempo = 0; + LIST_FOR_EACH_ENTRY(event, &This->events, struct event, entry) + { + ticks += event->deltaTime; + music_time = (ULONGLONG)ticks * DMUS_PPQ / This->ticks_per_quarter_note; + if (event->status == 0xff && event->type == MIDI_META_SET_TEMPO) + { + if (next) *next = music_time - time; + if (music_time > time) break; + tempo->mtTime = music_time - time; + tempo->dblTempo = 6e7 / event->data.integer; + } + } + if (tempo->dblTempo == 0) return DMUS_E_NOT_FOUND; + TRACE("Found tempo %f at time offset %ld\n", tempo->dblTempo, tempo->mtTime); + return S_OK; }
static HRESULT WINAPI midi_sequence_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, @@ -232,15 +265,42 @@ static HRESULT WINAPI midi_sequence_track_SetParam(IDirectMusicTrack8 *iface, RE struct midi_sequence_track *This = impl_from_IDirectMusicTrack8(iface);
TRACE("(%p, %s, %ld, %p): method not implemented\n", This, debugstr_dmguid(type), time, param); - return E_NOTIMPL; + if (!This->has_tempo_events) return DMUS_E_SET_UNSUPPORTED; + + if (IsEqualGUID(type, &GUID_DisableTempo)) + { + if (!param) return DMUS_E_TYPE_DISABLED; + FIXME("GUID_DisableTempo not handled yet\n"); + return S_OK; + } + if (IsEqualGUID(type, &GUID_EnableTempo)) + { + if (!param) return DMUS_E_TYPE_DISABLED; + FIXME("GUID_EnableTempo not handled yet\n"); + return S_OK; + } + if (IsEqualGUID(type, &GUID_TempoParam)) + { + if (!param) return E_POINTER; + FIXME("GUID_TempoParam not handled yet\n"); + return S_OK; + } + + return DMUS_E_SET_UNSUPPORTED; }
static HRESULT WINAPI midi_sequence_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID type) { struct midi_sequence_track *This = impl_from_IDirectMusicTrack8(iface);
- TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(type)); - return E_NOTIMPL; + TRACE("(%p, %s): semi-sub\n", This, debugstr_dmguid(type)); + + if (!This->has_tempo_events) return DMUS_E_GET_UNSUPPORTED; + + if (IsEqualGUID(type, &GUID_DisableTempo) || IsEqualGUID(type, &GUID_EnableTempo) || + IsEqualGUID(type, &GUID_TempoParam)) + return S_OK; + return DMUS_E_TYPE_UNSUPPORTED; }
static HRESULT WINAPI midi_sequence_track_AddNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype) @@ -465,6 +525,7 @@ static HRESULT WINAPI midi_sequence_track_IPersistStream_Load(IPersistStream *if
TRACE("(%p, %p): stub\n", This, stream);
+ This->has_tempo_events = FALSE; hr = IStream_Read(stream, &magic, sizeof(magic), NULL); if (FAILED(hr)) return hr; if (magic != MAKEFOURCC('M', 'T', 'r', 'k')) @@ -488,6 +549,8 @@ static HRESULT WINAPI midi_sequence_track_IPersistStream_Load(IPersistStream *if This->event_count++; last_status = event->status; is_end_of_track = event->status == 0xff && event->type == MIDI_META_END_OF_TRACK; + if (event->status == 0xff && event->type == MIDI_META_SET_TEMPO) + This->has_tempo_events = TRUE; event = NULL; }