From: Yuxuan Shui yshui@codeweavers.com
So that instrument downloading etc. could work. --- dlls/dmime/midi.c | 557 +++++++++++++++++++++++++++++++++++++++++++ dlls/dmime/segment.c | 1 + 2 files changed, 558 insertions(+)
diff --git a/dlls/dmime/midi.c b/dlls/dmime/midi.c index 1df1b9b15fd..882ba6c801b 100644 --- a/dlls/dmime/midi.c +++ b/dlls/dmime/midi.c @@ -662,15 +662,572 @@ struct midi_parser { IStream *stream; DWORD division; + BOOL bandtrack_created; WORD number_of_tracks, current_track; };
+struct downloaded_instrument_entry +{ + struct list entry; + IDirectMusicPort *port; + IDirectMusicDownloadedInstrument *downloaded; +}; + +struct midi_band_track +{ + IDirectMusicTrack8 IDirectMusicTrack8_iface; + IDirectMusicBand IDirectMusicBand_iface; + struct dmobject dmobj; /* IPersistStream only */ + LONG ref; + IDirectMusicCollection *collection; + BOOL auto_download; + struct list downloaded_instruments; +}; + +static inline void midi_band_track_unload(struct midi_band_track *This) +{ + struct downloaded_instrument_entry *entry, *next_entry; + + LIST_FOR_EACH_ENTRY_SAFE(entry, next_entry, &This->downloaded_instruments, + struct downloaded_instrument_entry, entry) + { + IDirectMusicPort_UnloadInstrument(entry->port, entry->downloaded); + IDirectMusicDownloadedInstrument_Release(entry->downloaded); + IDirectMusicPort_Release(entry->port); + list_remove(&entry->entry); + free(entry); + } +} + +static inline void midi_band_track_destroy(struct midi_band_track *This) +{ + midi_band_track_unload(This); + if (This->collection) IDirectMusicCollection_Release(This->collection); + free(This); +} + +static inline struct midi_band_track *impl_from_IDirectMusicBand(IDirectMusicBand *iface) +{ + return CONTAINING_RECORD(iface, struct midi_band_track, IDirectMusicBand_iface); +} + +static HRESULT WINAPI midi_band_track_band_QueryInterface(IDirectMusicBand *iface, REFIID riid, void **ret_iface) +{ + struct midi_band_track *This = impl_from_IDirectMusicBand(iface); + TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface); + return IDirectMusicTrack8_QueryInterface(&This->IDirectMusicTrack8_iface, riid, ret_iface); +} + +static ULONG WINAPI midi_band_track_band_AddRef(IDirectMusicBand *iface) +{ + struct midi_band_track *This = impl_from_IDirectMusicBand(iface); + LONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p) ref=%ld\n", This, ref); + return ref; +} + +static ULONG WINAPI midi_band_track_band_Release(IDirectMusicBand *iface) +{ + struct midi_band_track *This = impl_from_IDirectMusicBand(iface); + LONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p) ref=%ld\n", This, ref); + if (!ref) midi_band_track_destroy(This); + return ref; +} + +static HRESULT WINAPI midi_band_track_band_CreateSegment(IDirectMusicBand *iface, IDirectMusicSegment **segment) +{ + struct midi_band_track *This = impl_from_IDirectMusicBand(iface); + + FIXME("(%p, %p): stub\n", This, segment); + return E_NOTIMPL; +} + +static HRESULT WINAPI midi_band_track_band_Download(IDirectMusicBand *iface, IDirectMusicPerformance *performance) +{ + struct midi_band_track *This = impl_from_IDirectMusicBand(iface); + struct downloaded_instrument_entry *entry; + HRESULT hr = S_OK; + ULONG i; + + TRACE("(%p, %p)\n", This, performance); + if (!This->collection) return S_OK; + + for (i = 0;; i++) + { + DWORD dwPatch; + WCHAR wszName[128]; + IDirectMusicInstrument *instrument; + IDirectMusicDownloadedInstrument *downloaded_instrument; + IDirectMusicPort *download_port; + + if ((hr = IDirectMusicCollection_EnumInstrument(This->collection, i, &dwPatch, wszName, 128)) != S_OK) + break; + + if (FAILED(hr = IDirectMusicCollection_GetInstrument(This->collection, dwPatch, &instrument))) + { + WARN("Failed to get instrument %lu, hr %#lx\n", dwPatch, hr); + continue; + } + hr = IDirectMusicPerformance_DownloadInstrument(performance, instrument, 0, + &downloaded_instrument, NULL, 0, &download_port, NULL, NULL); + IDirectMusicInstrument_Release(instrument); + if (FAILED(hr)) WARN("Failed to download instrument %lu, hr %#lx\n", dwPatch, hr); + else + { + if (!(entry = calloc(1, sizeof(*entry)))) + { + IDirectMusicDownloadedInstrument_Release(downloaded_instrument); + IDirectMusicPort_Release(download_port); + return E_OUTOFMEMORY; + } + entry->port = download_port; + entry->downloaded = downloaded_instrument; + list_add_tail(&This->downloaded_instruments, &entry->entry); + } + } + return hr; +} + +static HRESULT WINAPI midi_band_track_band_Unload(IDirectMusicBand *iface, IDirectMusicPerformance *performance) +{ + struct midi_band_track *This = impl_from_IDirectMusicBand(iface); + + TRACE("(%p, %p)\n", This, performance); + if (performance) FIXME("performance parameter not implemented\n"); + + midi_band_track_unload(This); + return S_OK; +} + +static const IDirectMusicBandVtbl midi_band_vtbl = +{ + midi_band_track_band_QueryInterface, + midi_band_track_band_AddRef, + midi_band_track_band_Release, + midi_band_track_band_CreateSegment, + midi_band_track_band_Download, + midi_band_track_band_Unload, +}; + +static HRESULT WINAPI midi_band_track_object_ParseDescriptor(IDirectMusicObject *iface, + IStream *stream, DMUS_OBJECTDESC *desc) +{ + TRACE("(%p, %p, %p)\n", iface, stream, desc); + + if (!stream || !desc) return E_POINTER; + + return E_NOTIMPL; +} + +static const IDirectMusicObjectVtbl midi_band_object_vtbl = +{ + dmobj_IDirectMusicObject_QueryInterface, + dmobj_IDirectMusicObject_AddRef, + dmobj_IDirectMusicObject_Release, + dmobj_IDirectMusicObject_GetDescriptor, + dmobj_IDirectMusicObject_SetDescriptor, + midi_band_track_object_ParseDescriptor, +}; + +static inline struct midi_band_track *midi_band_track_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface) +{ + return CONTAINING_RECORD(iface, struct midi_band_track, IDirectMusicTrack8_iface); +} + +static HRESULT WINAPI midi_band_track_QueryInterface(IDirectMusicTrack8 *iface, REFIID riid, void **ret_iface) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + + TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface); + + *ret_iface = NULL; + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicTrack) || + IsEqualIID(riid, &IID_IDirectMusicTrack8)) + *ret_iface = iface; + else if (IsEqualIID(riid, &IID_IDirectMusicObject)) + *ret_iface = &This->dmobj.IDirectMusicObject_iface; + else if (IsEqualIID(riid, &IID_IPersistStream)) *ret_iface = &This->dmobj.IPersistStream_iface; + else if (IsEqualGUID(riid, &IID_IDirectMusicBand8) || IsEqualGUID(riid, &IID_IDirectMusicBand)) + *ret_iface = &This->IDirectMusicBand_iface; + else + { + WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*ret_iface); + return S_OK; +} + +static ULONG WINAPI midi_band_track_AddRef(IDirectMusicTrack8 *iface) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI midi_band_track_Release(IDirectMusicTrack8 *iface) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if (!ref) midi_band_track_destroy(This); + + return ref; +} + +static HRESULT WINAPI midi_band_track_Init(IDirectMusicTrack8 *iface, IDirectMusicSegment *segment) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + + FIXME("(%p, %p): stub\n", This, segment); + + if (!segment) return E_POINTER; + return S_OK; +} + +static HRESULT WINAPI midi_band_track_InitPlay(IDirectMusicTrack8 *iface, IDirectMusicSegmentState *segment_state, + IDirectMusicPerformance *performance, void **state_data, DWORD virtual_track8id, DWORD flags) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + IDirectMusicBand *band; + HRESULT hr = S_OK; + + FIXME("(%p, %p, %p, %p, %ld, %lx): semi-stub\n", This, segment_state, performance, state_data, + virtual_track8id, flags); + + if (!performance) return E_POINTER; + + if (This->auto_download) + { + hr = IDirectMusicTrack8_QueryInterface(iface, &IID_IDirectMusicBand, (void **)&band); + if (SUCCEEDED(hr)) + { + hr = IDirectMusicBand_Download(band, performance); + IDirectMusicBand_Release(band); + } + } + + return hr; +} + +static HRESULT WINAPI midi_band_track_EndPlay(IDirectMusicTrack8 *iface, void *state_data) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + IDirectMusicBand *band; + HRESULT hr = S_OK; + + FIXME("(%p, %p): semi-stub\n", This, state_data); + + if (This->auto_download) + { + hr = IDirectMusicTrack8_QueryInterface(iface, &IID_IDirectMusicBand, (void **)&band); + if (SUCCEEDED(hr)) + { + hr = IDirectMusicBand_Unload(band, NULL); + IDirectMusicBand_Release(band); + } + } + + return hr; +} + +static HRESULT WINAPI midi_band_track_Play(IDirectMusicTrack8 *iface, void *state_data, + MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD track_flags, + IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD track_id) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + + TRACE("(%p, %p, %ld, %ld, %ld, %#lx, %p, %p, %ld): stub\n", This, state_data, start_time, + end_time, time_offset, track_flags, performance, segment_state, track_id); + + if (!performance) return DMUS_S_END; + return S_OK; +} + +static HRESULT WINAPI midi_band_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, + MUSIC_TIME time, MUSIC_TIME *out_next, void *param) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + DMUS_BAND_PARAM *bandparam = param; + + TRACE("(%p, %s, %ld, %p, %p)\n", This, debugstr_dmguid(type), time, out_next, param); + + if (!type || !param) return E_POINTER; + if (IsEqualGUID(type, &GUID_BandParam)) + { + bandparam->mtTimePhysical = 0; + IDirectMusicTrack8_QueryInterface(iface, &IID_IDirectMusicBand, (void **)&bandparam->pBand); + return S_OK; + } + + return DMUS_E_GET_UNSUPPORTED; +} + +static HRESULT WINAPI midi_band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time, void *param) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + + TRACE("(%p, %s, %ld, %p): semi-stub\n", This, debugstr_dmguid(type), time, param); + + if (!type) return E_POINTER; + if (FAILED(IDirectMusicTrack8_IsParamSupported(iface, type))) return DMUS_E_TYPE_UNSUPPORTED; + + if (IsEqualGUID(type, &GUID_ConnectToDLSCollection)) + { + if (This->collection) IDirectMusicCollection_Release(This->collection); + This->collection = param; + IDirectMusicCollection_AddRef(This->collection); + } + else if (IsEqualGUID(type, &GUID_Disable_Auto_Download)) This->auto_download = FALSE; + else if (IsEqualGUID(type, &GUID_Enable_Auto_Download)) This->auto_download = TRUE; + else if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) + { + IDirectMusicPerformance *performance; + IDirectMusicAudioPath *audio_path; + IUnknown *object = param; + IDirectMusicBand *band; + HRESULT hr; + + if (FAILED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicPerformance8, + (void **)&performance)) && + SUCCEEDED(hr = IDirectMusicAudioPath_QueryInterface(object, + &IID_IDirectMusicAudioPath, (void **)&audio_path))) + { + hr = IDirectMusicAudioPath_GetObjectInPath(audio_path, DMUS_PCHANNEL_ALL, DMUS_PATH_PERFORMANCE, + 0, &GUID_All_Objects, 0, &IID_IDirectMusicPerformance8, (void **)&performance); + IDirectMusicAudioPath_Release(audio_path); + } + + if (FAILED(hr)) + { + WARN("Failed to get IDirectMusicPerformance from param %p\n", param); + return hr; + } + + hr = IDirectMusicTrack8_QueryInterface(iface, &IID_IDirectMusicBand, (void **)&band); + if (SUCCEEDED(hr)) + { + hr = IDirectMusicBand_Download(band, performance); + IDirectMusicBand_Release(band); + } + + IDirectMusicPerformance_Release(performance); + } + else if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) + { + IDirectMusicBand *band; + HRESULT hr; + + hr = IDirectMusicTrack8_QueryInterface(iface, &IID_IDirectMusicBand, (void **)&band); + if (SUCCEEDED(hr)) + { + hr = IDirectMusicBand_Unload(band, NULL); + IDirectMusicBand_Release(band); + } + } + else FIXME("Unhandled parameter type %s\n", debugstr_dmguid(type)); + + return S_OK; +} + +static HRESULT WINAPI midi_band_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID rguidType) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + + TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidType)); + + if (!rguidType) return E_POINTER; + + if (IsEqualGUID(rguidType, &GUID_BandParam) || IsEqualGUID(rguidType, &GUID_Clear_All_Bands) || + IsEqualGUID(rguidType, &GUID_ConnectToDLSCollection) || + IsEqualGUID(rguidType, &GUID_Disable_Auto_Download) || + IsEqualGUID(rguidType, &GUID_Download) || IsEqualGUID(rguidType, &GUID_DownloadToAudioPath) || + IsEqualGUID(rguidType, &GUID_Enable_Auto_Download) || + IsEqualGUID(rguidType, &GUID_IDirectMusicBand) || IsEqualGUID(rguidType, &GUID_StandardMIDIFile) || + IsEqualGUID(rguidType, &GUID_Unload) || IsEqualGUID(rguidType, &GUID_UnloadFromAudioPath)) + { + TRACE("param supported\n"); + return S_OK; + } + + TRACE("param unsupported\n"); + return DMUS_E_TYPE_UNSUPPORTED; +} + +static HRESULT WINAPI midi_band_track_AddNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + + TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype)); + return E_NOTIMPL; +} + +static HRESULT WINAPI midi_band_track_RemoveNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + + TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype)); + return E_NOTIMPL; +} + +static HRESULT WINAPI midi_band_track_Clone(IDirectMusicTrack8 *iface, MUSIC_TIME mtStart, + MUSIC_TIME mtEnd, IDirectMusicTrack **ppTrack) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + FIXME("(%p, %ld, %ld, %p): stub\n", This, mtStart, mtEnd, ppTrack); + return S_OK; +} + +static HRESULT WINAPI midi_band_track_PlayEx(IDirectMusicTrack8 *iface, void *state_data, + REFERENCE_TIME rtStart, REFERENCE_TIME rtEnd, REFERENCE_TIME rtOffset, DWORD flags, + IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD virtual_id) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + + FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %lx, %p, %p, %ld): stub\n", This, state_data, + wine_dbgstr_longlong(rtStart), wine_dbgstr_longlong(rtEnd), + wine_dbgstr_longlong(rtOffset), flags, performance, segment_state, virtual_id); + + return S_OK; +} + +static HRESULT WINAPI midi_band_track_GetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType, + REFERENCE_TIME rtTime, REFERENCE_TIME *rtNext, void *param, void *state_data, DWORD flags) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + + FIXME("(%p, %s, 0x%s, %p, %p, %p, %lx): stub\n", This, debugstr_dmguid(rguidType), + wine_dbgstr_longlong(rtTime), rtNext, param, state_data, flags); + + return S_OK; +} + +static HRESULT WINAPI midi_band_track_SetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType, + REFERENCE_TIME rtTime, void *param, void *state_data, DWORD flags) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + + FIXME("(%p, %s, 0x%s, %p, %p, %lx): stub\n", This, debugstr_dmguid(rguidType), + wine_dbgstr_longlong(rtTime), param, state_data, flags); + + return S_OK; +} + +static HRESULT WINAPI midi_band_track_Compose(IDirectMusicTrack8 *iface, IUnknown *context, + DWORD trackgroup, IDirectMusicTrack **track) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + + TRACE("(%p, %p, %ld, %p): method not implemented\n", This, context, trackgroup, track); + return E_NOTIMPL; +} + +static HRESULT WINAPI midi_band_track_Join(IDirectMusicTrack8 *iface, IDirectMusicTrack *pNewTrack, + MUSIC_TIME mtJoin, IUnknown *pContext, DWORD dwTrackGroup, IDirectMusicTrack **ppResultTrack) +{ + struct midi_band_track *This = midi_band_track_from_IDirectMusicTrack8(iface); + FIXME("(%p, %p, %ld, %p, %ld, %p): stub\n", This, pNewTrack, mtJoin, pContext, dwTrackGroup, ppResultTrack); + return S_OK; +} + +static const IDirectMusicTrack8Vtbl midi_band_track_vtbl = +{ + midi_band_track_QueryInterface, + midi_band_track_AddRef, + midi_band_track_Release, + midi_band_track_Init, + midi_band_track_InitPlay, + midi_band_track_EndPlay, + midi_band_track_Play, + midi_band_track_GetParam, + midi_band_track_SetParam, + midi_band_track_IsParamSupported, + midi_band_track_AddNotificationType, + midi_band_track_RemoveNotificationType, + midi_band_track_Clone, + midi_band_track_PlayEx, + midi_band_track_GetParamEx, + midi_band_track_SetParamEx, + midi_band_track_Compose, + midi_band_track_Join, +}; +static HRESULT WINAPI midi_band_track_persist_stream_Load(IPersistStream *iface, IStream *stream) +{ + TRACE("(%p, %p): stub\n", iface, stream); + return S_OK; +} + +static const IPersistStreamVtbl midi_band_track_persist_stream_vtbl = +{ + dmobj_IPersistStream_QueryInterface, + dmobj_IPersistStream_AddRef, + dmobj_IPersistStream_Release, + dmobj_IPersistStream_GetClassID, + unimpl_IPersistStream_IsDirty, + midi_band_track_persist_stream_Load, + unimpl_IPersistStream_Save, + unimpl_IPersistStream_GetSizeMax, +}; + +static HRESULT create_midi_band_track(IStream *stream, IDirectMusicTrack **track) +{ + DMUS_OBJECTDESC default_desc = + { + .dwSize = sizeof(DMUS_OBJECTDESC), + .dwValidData = DMUS_OBJ_OBJECT | DMUS_OBJ_CLASS, + .guidClass = CLSID_DirectMusicCollection, + .guidObject = GUID_DefaultGMCollection, + }; + HRESULT hr; + IDirectMusicCollection *collection = NULL; + struct midi_band_track *This; + + if (!(This = calloc(1, sizeof(*This)))) return E_OUTOFMEMORY; + This->IDirectMusicTrack8_iface.lpVtbl = &midi_band_track_vtbl; + This->IDirectMusicBand_iface.lpVtbl = &midi_band_vtbl; + This->ref = 1; + dmobject_init(&This->dmobj, &CLSID_DirectMusicBandTrack, (IUnknown *)&This->IDirectMusicTrack8_iface); + This->dmobj.IPersistStream_iface.lpVtbl = &midi_band_track_persist_stream_vtbl; + This->dmobj.IDirectMusicObject_iface.lpVtbl = &midi_band_object_vtbl; + list_init(&This->downloaded_instruments); + + hr = stream_get_object(stream, &default_desc, &IID_IDirectMusicCollection, (void **)&collection); + if (FAILED(hr)) WARN("Failed to load default collection from loader, hr %#lx\n", hr); + + if (collection) + { + This->collection = collection; + IDirectMusicCollection_AddRef(collection); + } + + *track = (IDirectMusicTrack *)&This->IDirectMusicTrack8_iface; + if (collection) IDirectMusicCollection_Release(collection); + return S_OK; +} + HRESULT midi_parser_next_track(struct midi_parser *parser, IDirectMusicTrack **out_track, MUSIC_TIME *out_length) { IPersistStream *pstream; HRESULT hr; MUSIC_TIME midi_length;
+ if (!parser->bandtrack_created) + { + hr = create_midi_band_track(parser->stream, out_track); + if (FAILED(hr)) return hr; + parser->bandtrack_created = TRUE; + *out_length = 0; + return S_OK; + } + if (parser->current_track >= parser->number_of_tracks) return S_FALSE;
hr = create_midiseqtrack(&IID_IPersistStream, (void **)&pstream, parser->division); diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index c37e76b91cb..dfd5c9c1c53 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -17,6 +17,7 @@ * License along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ + #include "dmime_private.h"
#ifdef WORDS_BIGENDIAN