-- v2: dmusic: Implement instrument articulation downloads. dmusic: Parse instrument regions articulation lists. dmusic: Implement downloading wave to port. dmusic: Keep an internal ref on the instrument's collection. dmusic: Parse collection wave lists. dmusic: Parse collection wave table. dmusic: Rewrite downloading instrument to port. dmusic: Avoid swallowing collection Load failures.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmusic/collection.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index cbcdabb37c1..5d6b533d649 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -331,7 +331,9 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *str } }
- if (SUCCEEDED(hr) && TRACE_ON(dmusic)) + if (FAILED(hr)) return hr; + + if (TRACE_ON(dmusic)) { struct instrument_entry *entry; int i = 0;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmusic/dmusic_private.h | 43 +-------- dlls/dmusic/instrument.c | 174 +++++++++++++++++++++++++++++++++++ dlls/dmusic/port.c | 172 +--------------------------------- 3 files changed, 180 insertions(+), 209 deletions(-)
diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 31ff63a954d..2d195574b89 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -48,7 +48,6 @@ */ typedef struct IDirectMusic8Impl IDirectMusic8Impl; typedef struct IDirectMusicBufferImpl IDirectMusicBufferImpl; -typedef struct IDirectMusicDownloadedInstrumentImpl IDirectMusicDownloadedInstrumentImpl; typedef struct IReferenceClockImpl IReferenceClockImpl;
/***************************************************************************** @@ -73,16 +72,6 @@ typedef struct port_info { ULONG device; } port_info;
-struct region -{ - struct list entry; - RGNHEADER header; - WAVELINK wave_link; - WSMPL wave_sample; - WLOOP wave_loop; - BOOL loop_present; -}; - /***************************************************************************** * ClassFactory */ @@ -99,6 +88,9 @@ extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface);
extern HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface); +extern HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicPortDownload *port, + IDirectMusicDownloadedInstrument **downloaded); +extern HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port);
/***************************************************************************** * IDirectMusic8Impl implementation structure @@ -130,19 +122,6 @@ struct IDirectMusicBufferImpl { REFERENCE_TIME start_time; };
-/***************************************************************************** - * IDirectMusicDownloadedInstrumentImpl implementation structure - */ -struct IDirectMusicDownloadedInstrumentImpl { - /* IUnknown fields */ - IDirectMusicDownloadedInstrument IDirectMusicDownloadedInstrument_iface; - LONG ref; - - /* IDirectMusicDownloadedInstrumentImpl fields */ - BOOL downloaded; - void *data; -}; - /** Internal factory */ extern HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_params, DMUS_PORTCAPS *port_caps, IDirectMusicPort **port); @@ -168,22 +147,6 @@ typedef struct _DMUS_PRIVATE_POOLCUE { struct list entry; /* for listing elements */ } DMUS_PRIVATE_POOLCUE, *LPDMUS_PRIVATE_POOLCUE;
-struct instrument -{ - IDirectMusicInstrument IDirectMusicInstrument_iface; - LONG ref; - - INSTHEADER header; - - struct list articulations; - struct list regions; -}; - -static inline struct instrument *impl_from_IDirectMusicInstrument(IDirectMusicInstrument *iface) -{ - return CONTAINING_RECORD(iface, struct instrument, IDirectMusicInstrument_iface); -} - /***************************************************************************** * Misc. */ diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 025bba940e5..24b3c0305f8 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -33,6 +33,33 @@ struct articulation
C_ASSERT(sizeof(struct articulation) == offsetof(struct articulation, connections[0]));
+struct region +{ + struct list entry; + RGNHEADER header; + WAVELINK wave_link; + WSMPL wave_sample; + WLOOP wave_loop; + BOOL loop_present; +}; + +struct instrument +{ + IDirectMusicInstrument IDirectMusicInstrument_iface; + IDirectMusicDownloadedInstrument IDirectMusicDownloadedInstrument_iface; + LONG ref; + + INSTHEADER header; + IDirectMusicDownload *download; + struct list articulations; + struct list regions; +}; + +static inline struct instrument *impl_from_IDirectMusicInstrument(IDirectMusicInstrument *iface) +{ + return CONTAINING_RECORD(iface, struct instrument, IDirectMusicInstrument_iface); +} + static HRESULT WINAPI instrument_QueryInterface(LPDIRECTMUSICINSTRUMENT iface, REFIID riid, LPVOID *ret_iface) { TRACE("(%p)->(%s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); @@ -134,6 +161,46 @@ static const IDirectMusicInstrumentVtbl instrument_vtbl = instrument_SetPatch, };
+static inline struct instrument* impl_from_IDirectMusicDownloadedInstrument(IDirectMusicDownloadedInstrument *iface) +{ + return CONTAINING_RECORD(iface, struct instrument, IDirectMusicDownloadedInstrument_iface); +} + +static HRESULT WINAPI downloaded_instrument_QueryInterface(IDirectMusicDownloadedInstrument *iface, REFIID riid, VOID **ret_iface) +{ + TRACE("(%p, %s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicDownloadedInstrument)) + { + IDirectMusicDownloadedInstrument_AddRef(iface); + *ret_iface = iface; + return S_OK; + } + + WARN("(%p, %s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface); + + return E_NOINTERFACE; +} + +static ULONG WINAPI downloaded_instrument_AddRef(IDirectMusicDownloadedInstrument *iface) +{ + struct instrument *This = impl_from_IDirectMusicDownloadedInstrument(iface); + return IDirectMusicInstrument_AddRef(&This->IDirectMusicInstrument_iface); +} + +static ULONG WINAPI downloaded_instrument_Release(IDirectMusicDownloadedInstrument *iface) +{ + struct instrument *This = impl_from_IDirectMusicDownloadedInstrument(iface); + return IDirectMusicInstrument_Release(&This->IDirectMusicInstrument_iface); +} + +static const IDirectMusicDownloadedInstrumentVtbl downloaded_instrument_vtbl = +{ + downloaded_instrument_QueryInterface, + downloaded_instrument_AddRef, + downloaded_instrument_Release, +}; + static HRESULT instrument_create(IDirectMusicInstrument **ret_iface) { struct instrument *instrument; @@ -141,6 +208,7 @@ static HRESULT instrument_create(IDirectMusicInstrument **ret_iface) *ret_iface = NULL; if (!(instrument = calloc(1, sizeof(*instrument)))) return E_OUTOFMEMORY; instrument->IDirectMusicInstrument_iface.lpVtbl = &instrument_vtbl; + instrument->IDirectMusicDownloadedInstrument_iface.lpVtbl = &downloaded_instrument_vtbl; instrument->ref = 1; list_init(&instrument->articulations); list_init(&instrument->regions); @@ -365,3 +433,109 @@ HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent *ret_iface = iface; return S_OK; } + +struct download_buffer +{ + DMUS_DOWNLOADINFO info; + ULONG offsets[]; +}; + +C_ASSERT(sizeof(struct download_buffer) == offsetof(struct download_buffer, offsets[0])); + +HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicPortDownload *port, + IDirectMusicDownloadedInstrument **downloaded) +{ + struct instrument *This = impl_from_IDirectMusicInstrument(iface); + struct download_buffer *buffer; + IDirectMusicDownload *download; + DWORD size, offset_count; + struct region *region; + HRESULT hr; + + if (This->download) goto done; + + size = sizeof(DMUS_DOWNLOADINFO); + size += sizeof(ULONG) + sizeof(DMUS_INSTRUMENT); + offset_count = 1; + + LIST_FOR_EACH_ENTRY(region, &This->regions, struct region, entry) + { + size += sizeof(ULONG) + sizeof(DMUS_REGION); + offset_count++; + } + + if (FAILED(hr = IDirectMusicPortDownload_AllocateBuffer(port, size, &download))) return hr; + + if (SUCCEEDED(hr = IDirectMusicDownload_GetBuffer(download, (void **)&buffer, &size)) + && SUCCEEDED(hr = IDirectMusicPortDownload_GetDLId(port, &buffer->info.dwDLId, 1))) + { + BYTE *ptr = (BYTE *)&buffer->offsets[offset_count]; + DMUS_INSTRUMENT *dmus_instrument; + DMUS_REGION *dmus_region = NULL; + UINT index = 0; + + buffer->info.dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT2; + buffer->info.dwNumOffsetTableEntries = offset_count; + buffer->info.cbSize = size; + + buffer->offsets[index++] = ptr - (BYTE *)buffer; + dmus_instrument = (DMUS_INSTRUMENT *)ptr; + ptr += sizeof(DMUS_INSTRUMENT); + + dmus_instrument->ulPatch = MIDILOCALE2Patch(&This->header.Locale); + dmus_instrument->ulFirstRegionIdx = 0; + dmus_instrument->ulCopyrightIdx = 0; + dmus_instrument->ulGlobalArtIdx = 0; + + LIST_FOR_EACH_ENTRY(region, &This->regions, struct region, entry) + { + if (dmus_region) dmus_region->ulNextRegionIdx = index; + else dmus_instrument->ulFirstRegionIdx = index; + + buffer->offsets[index++] = ptr - (BYTE *)buffer; + dmus_region = (DMUS_REGION *)ptr; + ptr += sizeof(DMUS_REGION); + + dmus_region->RangeKey = region->header.RangeKey; + dmus_region->RangeVelocity = region->header.RangeVelocity; + dmus_region->fusOptions = region->header.fusOptions; + dmus_region->usKeyGroup = region->header.usKeyGroup; + dmus_region->ulRegionArtIdx = 0; + dmus_region->ulNextRegionIdx = 0; + dmus_region->ulFirstExtCkIdx = 0; + dmus_region->WaveLink = region->wave_link; + dmus_region->WSMP = region->wave_sample; + dmus_region->WLOOP[0] = region->wave_loop; + } + + if (FAILED(hr = IDirectMusicPortDownload_Download(port, download))) goto failed; + } + + This->download = download; + +done: + *downloaded = &This->IDirectMusicDownloadedInstrument_iface; + IDirectMusicDownloadedInstrument_AddRef(*downloaded); + return S_OK; + +failed: + WARN("Failed to download instrument to port, hr %#lx\n", hr); + IDirectMusicDownload_Release(download); + return hr; +} + +HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port) +{ + struct instrument *This = impl_from_IDirectMusicDownloadedInstrument(iface); + HRESULT hr; + + if (!This->download) return DMUS_E_NOT_DOWNLOADED_TO_PORT; + + if (FAILED(hr = IDirectMusicPortDownload_Unload(port, This->download))) + WARN("Failed to unload instrument download buffer, hr %#lx\n", hr); + + IDirectMusicDownload_Release(This->download); + This->download = NULL; + + return hr; +} diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 675cf05a003..b23a3f5d4dd 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -52,11 +52,6 @@ struct synth_port { DWORD next_dlid; };
-static inline IDirectMusicDownloadedInstrumentImpl* impl_from_IDirectMusicDownloadedInstrument(IDirectMusicDownloadedInstrument *iface) -{ - return CONTAINING_RECORD(iface, IDirectMusicDownloadedInstrumentImpl, IDirectMusicDownloadedInstrument_iface); -} - static inline struct synth_port *synth_from_IDirectMusicPort(IDirectMusicPort *iface) { return CONTAINING_RECORD(iface, struct synth_port, IDirectMusicPort_iface); @@ -77,83 +72,6 @@ static inline struct synth_port *synth_from_IKsControl(IKsControl *iface) return CONTAINING_RECORD(iface, struct synth_port, IKsControl_iface); }
-/* IDirectMusicDownloadedInstrument IUnknown part follows: */ -static HRESULT WINAPI IDirectMusicDownloadedInstrumentImpl_QueryInterface(IDirectMusicDownloadedInstrument *iface, REFIID riid, VOID **ret_iface) -{ - TRACE("(%p, %s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); - - if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicDownloadedInstrument)) - { - IDirectMusicDownloadedInstrument_AddRef(iface); - *ret_iface = iface; - return S_OK; - } - - WARN("(%p, %s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface); - - return E_NOINTERFACE; -} - -static ULONG WINAPI IDirectMusicDownloadedInstrumentImpl_AddRef(LPDIRECTMUSICDOWNLOADEDINSTRUMENT iface) -{ - IDirectMusicDownloadedInstrumentImpl *This = impl_from_IDirectMusicDownloadedInstrument(iface); - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p): new ref = %lu\n", iface, ref); - - return ref; -} - -static ULONG WINAPI IDirectMusicDownloadedInstrumentImpl_Release(LPDIRECTMUSICDOWNLOADEDINSTRUMENT iface) -{ - IDirectMusicDownloadedInstrumentImpl *This = impl_from_IDirectMusicDownloadedInstrument(iface); - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p): new ref = %lu\n", iface, ref); - - if (!ref) - { - free(This->data); - free(This); - } - - return ref; -} - -static const IDirectMusicDownloadedInstrumentVtbl DirectMusicDownloadedInstrument_Vtbl = { - IDirectMusicDownloadedInstrumentImpl_QueryInterface, - IDirectMusicDownloadedInstrumentImpl_AddRef, - IDirectMusicDownloadedInstrumentImpl_Release -}; - -static inline IDirectMusicDownloadedInstrumentImpl* unsafe_impl_from_IDirectMusicDownloadedInstrument(IDirectMusicDownloadedInstrument *iface) -{ - if (!iface) - return NULL; - assert(iface->lpVtbl == &DirectMusicDownloadedInstrument_Vtbl); - - return impl_from_IDirectMusicDownloadedInstrument(iface); -} - -static HRESULT DMUSIC_CreateDirectMusicDownloadedInstrumentImpl(IDirectMusicDownloadedInstrument **instrument) -{ - IDirectMusicDownloadedInstrumentImpl *object; - - object = calloc(1, sizeof(*object)); - if (!object) - { - *instrument = NULL; - return E_OUTOFMEMORY; - } - - object->IDirectMusicDownloadedInstrument_iface.lpVtbl = &DirectMusicDownloadedInstrument_Vtbl; - object->ref = 1; - - *instrument = &object->IDirectMusicDownloadedInstrument_iface; - - return S_OK; -} - static HRESULT WINAPI synth_port_QueryInterface(IDirectMusicPort *iface, REFIID riid, void **ret_iface) { struct synth_port *This = synth_from_IDirectMusicPort(iface); @@ -265,110 +183,26 @@ static HRESULT WINAPI synth_port_DownloadInstrument(IDirectMusicPort *iface, IDi IDirectMusicDownloadedInstrument **downloaded_instrument, DMUS_NOTERANGE *note_ranges, DWORD num_note_ranges) { struct synth_port *This = synth_from_IDirectMusicPort(iface); - struct instrument *instrument_object; - struct region *instrument_region; - HRESULT ret; - BOOL on_heap; - HANDLE download; - DMUS_DOWNLOADINFO *info; - DMUS_OFFSETTABLE *offset_table; - DMUS_INSTRUMENT *instrument_info; - BYTE *data; - ULONG offset; - ULONG nb_regions; - ULONG size; - ULONG i;
TRACE("(%p, %p, %p, %p, %ld)\n", iface, instrument, downloaded_instrument, note_ranges, num_note_ranges);
if (!instrument || !downloaded_instrument || (num_note_ranges && !note_ranges)) return E_POINTER;
- instrument_object = impl_from_IDirectMusicInstrument(instrument); - - nb_regions = instrument_object->header.cRegions; - size = sizeof(DMUS_DOWNLOADINFO) + sizeof(ULONG) * (1 + nb_regions) + sizeof(DMUS_INSTRUMENT) + sizeof(DMUS_REGION) * nb_regions; - - data = malloc(size); - if (!data) - return E_OUTOFMEMORY; - - info = (DMUS_DOWNLOADINFO*)data; - offset_table = (DMUS_OFFSETTABLE*)(data + sizeof(DMUS_DOWNLOADINFO)); - offset = sizeof(DMUS_DOWNLOADINFO) + sizeof(ULONG) * (1 + nb_regions); - - info->dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT2; - info->dwDLId = 0; - info->dwNumOffsetTableEntries = 1 + instrument_object->header.cRegions; - info->cbSize = size; - - offset_table->ulOffsetTable[0] = offset; - instrument_info = (DMUS_INSTRUMENT*)(data + offset); - offset += sizeof(DMUS_INSTRUMENT); - instrument_info->ulPatch = MIDILOCALE2Patch(&instrument_object->header.Locale); - instrument_info->ulFirstRegionIdx = 1; - instrument_info->ulGlobalArtIdx = 0; /* FIXME */ - instrument_info->ulFirstExtCkIdx = 0; /* FIXME */ - instrument_info->ulCopyrightIdx = 0; /* FIXME */ - instrument_info->ulFlags = 0; /* FIXME */ - - i = 0; - LIST_FOR_EACH_ENTRY(instrument_region, &instrument_object->regions, struct region, entry) - { - DMUS_REGION *region = (DMUS_REGION*)(data + offset); - - offset_table->ulOffsetTable[1 + i] = offset; - offset += sizeof(DMUS_REGION); - region->RangeKey = instrument_region->header.RangeKey; - region->RangeVelocity = instrument_region->header.RangeVelocity; - region->fusOptions = instrument_region->header.fusOptions; - region->usKeyGroup = instrument_region->header.usKeyGroup; - region->ulRegionArtIdx = 0; /* FIXME */ - region->ulNextRegionIdx = i != (nb_regions - 1) ? (i + 2) : 0; - region->ulFirstExtCkIdx = 0; /* FIXME */ - region->WaveLink = instrument_region->wave_link; - region->WSMP = instrument_region->wave_sample; - region->WLOOP[0] = instrument_region->wave_loop; - i++; - } - - ret = IDirectMusicSynth8_Download(This->synth, &download, (void*)data, &on_heap); - - if (SUCCEEDED(ret)) - ret = DMUSIC_CreateDirectMusicDownloadedInstrumentImpl(downloaded_instrument); - - if (SUCCEEDED(ret)) - { - IDirectMusicDownloadedInstrumentImpl *downloaded_object = impl_from_IDirectMusicDownloadedInstrument(*downloaded_instrument); - - downloaded_object->data = data; - downloaded_object->downloaded = TRUE; - } - - *downloaded_instrument = NULL; - free(data); - - return E_FAIL; + return instrument_download_to_port(instrument, &This->IDirectMusicPortDownload_iface, downloaded_instrument); }
static HRESULT WINAPI synth_port_UnloadInstrument(IDirectMusicPort *iface, IDirectMusicDownloadedInstrument *downloaded_instrument) { - IDirectMusicDownloadedInstrumentImpl *downloaded_object = unsafe_impl_from_IDirectMusicDownloadedInstrument(downloaded_instrument); + struct synth_port *This = synth_from_IDirectMusicPort(iface);
TRACE("(%p, %p)\n", iface, downloaded_instrument);
if (!downloaded_instrument) return E_POINTER;
- if (!downloaded_object->downloaded) - return DMUS_E_NOT_DOWNLOADED_TO_PORT; - - free(downloaded_object->data); - downloaded_object->data = NULL; - downloaded_object->downloaded = FALSE; - - return S_OK; + return instrument_unload_from_port(downloaded_instrument, &This->IDirectMusicPortDownload_iface); }
static HRESULT WINAPI synth_port_GetLatencyClock(IDirectMusicPort *iface, IReferenceClock **clock)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmusic/collection.c | 60 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-)
diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 5d6b533d649..3bcca3c4b8a 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -37,6 +37,12 @@ struct pool
C_ASSERT(sizeof(struct pool) == offsetof(struct pool, cues[0]));
+struct wave_entry +{ + struct list entry; + DWORD offset; +}; + struct collection { IDirectMusicCollection IDirectMusicCollection_iface; @@ -46,6 +52,7 @@ struct collection DLSHEADER header; struct pool *pool; struct list instruments; + struct list waves; };
static inline struct collection *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface) @@ -103,6 +110,7 @@ static ULONG WINAPI collection_Release(IDirectMusicCollection *iface) if (!ref) { struct instrument_entry *instrument_entry; + struct wave_entry *wave_entry; void *next;
LIST_FOR_EACH_ENTRY_SAFE(instrument_entry, next, &This->instruments, struct instrument_entry, entry) @@ -112,6 +120,12 @@ static ULONG WINAPI collection_Release(IDirectMusicCollection *iface) free(instrument_entry); }
+ LIST_FOR_EACH_ENTRY_SAFE(wave_entry, next, &This->waves, struct wave_entry, entry) + { + list_remove(&wave_entry->entry); + free(wave_entry); + } + free(This); }
@@ -201,6 +215,33 @@ static HRESULT parse_lins_list(struct collection *This, IStream *stream, struct return hr; }
+static HRESULT parse_wvpl_list(struct collection *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + struct wave_entry *entry; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_LIST, FOURCC_wave): + if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY; + entry->offset = chunk.offset.QuadPart - parent->offset.QuadPart - 12; + list_add_tail(&This->waves, &entry->entry); + break; + + default: + FIXME("Skipping unknown chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + return hr; +} + static HRESULT parse_ptbl_chunk(struct collection *This, IStream *stream, struct chunk_entry *chunk) { struct pool *pool; @@ -256,6 +297,10 @@ static HRESULT parse_dls_chunk(struct collection *This, IStream *stream, struct hr = parse_lins_list(This, stream, &chunk); break;
+ case MAKE_IDTYPE(FOURCC_LIST, FOURCC_WVPL): + hr = parse_wvpl_list(This, stream, &chunk); + break; + default: FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); break; @@ -336,6 +381,7 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *str if (TRACE_ON(dmusic)) { struct instrument_entry *entry; + struct wave_entry *wave_entry; int i = 0;
TRACE("*** IDirectMusicCollection (%p) ***\n", &This->IDirectMusicCollection_iface); @@ -346,7 +392,18 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *str TRACE(" - Instruments:\n");
LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) - TRACE(" - Instrument[%i]: %p\n", i++, entry->instrument); + { + TRACE(" - Instrument[%i]: %p\n", i, entry->instrument); + i++; + } + + TRACE(" - cues: size %lu\n", This->pool->table.cbSize); + for (i = 0; i < This->pool->table.cCues; i++) + TRACE(" - index: %u, offset: %lu\n", i, This->pool->cues[i].ulOffset); + + TRACE(" - waves:\n"); + LIST_FOR_EACH_ENTRY(wave_entry, &This->waves, struct wave_entry, entry) + TRACE(" - offset: %lu\n", wave_entry->offset); }
stream_skip_chunk(stream, &chunk); @@ -378,6 +435,7 @@ HRESULT collection_create(IUnknown **ret_iface) collection->dmobj.IDirectMusicObject_iface.lpVtbl = &collection_object_vtbl; collection->dmobj.IPersistStream_iface.lpVtbl = &collection_stream_vtbl; list_init(&collection->instruments); + list_init(&collection->waves);
TRACE("Created DirectMusicCollection %p\n", collection); *ret_iface = (IUnknown *)&collection->IDirectMusicCollection_iface;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmusic/Makefile.in | 3 +- dlls/dmusic/collection.c | 14 ++- dlls/dmusic/dmusic_private.h | 2 + dlls/dmusic/wave.c | 214 +++++++++++++++++++++++++++++++++++ 4 files changed, 228 insertions(+), 5 deletions(-) create mode 100644 dlls/dmusic/wave.c
diff --git a/dlls/dmusic/Makefile.in b/dlls/dmusic/Makefile.in index a8955a2ab42..d9438af0d18 100644 --- a/dlls/dmusic/Makefile.in +++ b/dlls/dmusic/Makefile.in @@ -10,7 +10,8 @@ C_SRCS = \ dmusic_main.c \ download.c \ instrument.c \ - port.c + port.c \ + wave.c
IDL_SRCS = dmusic.idl
diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 3bcca3c4b8a..1c36f0b202d 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -40,6 +40,7 @@ C_ASSERT(sizeof(struct pool) == offsetof(struct pool, cues[0])); struct wave_entry { struct list entry; + IUnknown *wave; DWORD offset; };
@@ -123,6 +124,7 @@ static ULONG WINAPI collection_Release(IDirectMusicCollection *iface) LIST_FOR_EACH_ENTRY_SAFE(wave_entry, next, &This->waves, struct wave_entry, entry) { list_remove(&wave_entry->entry); + IDirectMusicInstrument_Release(wave_entry->wave); free(wave_entry); }
@@ -227,8 +229,12 @@ static HRESULT parse_wvpl_list(struct collection *This, IStream *stream, struct { case MAKE_IDTYPE(FOURCC_LIST, FOURCC_wave): if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY; - entry->offset = chunk.offset.QuadPart - parent->offset.QuadPart - 12; - list_add_tail(&This->waves, &entry->entry); + if (FAILED(hr = wave_create_from_chunk(stream, &chunk, &entry->wave))) free(entry); + else + { + entry->offset = chunk.offset.QuadPart - parent->offset.QuadPart - 12; + list_add_tail(&This->waves, &entry->entry); + } break;
default: @@ -397,13 +403,13 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *str i++; }
- TRACE(" - cues: size %lu\n", This->pool->table.cbSize); + TRACE(" - cues:\n"); for (i = 0; i < This->pool->table.cCues; i++) TRACE(" - index: %u, offset: %lu\n", i, This->pool->cues[i].ulOffset);
TRACE(" - waves:\n"); LIST_FOR_EACH_ENTRY(wave_entry, &This->waves, struct wave_entry, entry) - TRACE(" - offset: %lu\n", wave_entry->offset); + TRACE(" - offset: %lu, wave %p\n", wave_entry->offset, wave_entry->wave); }
stream_skip_chunk(stream, &chunk); diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 2d195574b89..2fe6afde643 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -92,6 +92,8 @@ extern HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirec IDirectMusicDownloadedInstrument **downloaded); extern HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port);
+extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **out); + /***************************************************************************** * IDirectMusic8Impl implementation structure */ diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c new file mode 100644 index 00000000000..cda895484cb --- /dev/null +++ b/dlls/dmusic/wave.c @@ -0,0 +1,214 @@ +/* + * Copyright 2023 Rémi Bernon for CodeWeavers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "dmusic_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dmusic); + +struct sample +{ + WSMPL head; + WLOOP loops[]; +}; + +C_ASSERT(sizeof(struct sample) == offsetof(struct sample, loops[0])); + +struct wave +{ + IUnknown IUnknown_iface; + LONG ref; + + struct sample *sample; + WAVEFORMATEX *format; + UINT data_size; + void *data; +}; + +static inline struct wave *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct wave, IUnknown_iface); +} + +static HRESULT WINAPI wave_QueryInterface(IUnknown *iface, REFIID riid, void **ret_iface) +{ + struct wave *This = impl_from_IUnknown(iface); + + TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface); + + if (IsEqualIID(riid, &IID_IUnknown)) + { + *ret_iface = &This->IUnknown_iface; + IUnknown_AddRef(&This->IUnknown_iface); + return S_OK; + } + + WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface); + *ret_iface = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI wave_AddRef(IUnknown *iface) +{ + struct wave *This = impl_from_IUnknown(iface); + LONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p) ref=%ld\n", This, ref); + return ref; +} + +static ULONG WINAPI wave_Release(IUnknown *iface) +{ + struct wave *This = impl_from_IUnknown(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if (!ref) + { + free(This->format); + free(This->data); + free(This->sample); + free(This); + } + + return ref; +} + +static const IUnknownVtbl unknown_vtbl = +{ + wave_QueryInterface, + wave_AddRef, + wave_Release, +}; + +static HRESULT wave_create(IUnknown **ret_iface) +{ + struct wave *obj; + + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; + obj->IUnknown_iface.lpVtbl = &unknown_vtbl; + obj->ref = 1; + + *ret_iface = &obj->IUnknown_iface; + return S_OK; +} + +static HRESULT parse_wsmp_chunk(struct wave *This, IStream *stream, struct chunk_entry *chunk) +{ + struct sample *sample; + WSMPL wsmpl; + HRESULT hr; + UINT size; + + if (chunk->size < sizeof(wsmpl)) return E_INVALIDARG; + if (FAILED(hr = stream_read(stream, &wsmpl, sizeof(wsmpl)))) return hr; + if (chunk->size != wsmpl.cbSize + sizeof(WLOOP) * wsmpl.cSampleLoops) return E_INVALIDARG; + if (wsmpl.cbSize != sizeof(wsmpl)) return E_INVALIDARG; + if (wsmpl.cSampleLoops > 1) FIXME("Not implemented: found more than one wave loop\n"); + + size = offsetof(struct sample, loops[wsmpl.cSampleLoops]); + if (!(sample = malloc(size))) return E_OUTOFMEMORY; + sample->head = wsmpl; + + size = sizeof(WLOOP) * wsmpl.cSampleLoops; + if (FAILED(hr = stream_read(stream, sample->loops, size))) free(sample); + else This->sample = sample; + + return hr; +} + +static HRESULT parse_wave_chunk(struct wave *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case mmioFOURCC('f','m','t',' '): + if (!(This->format = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, This->format, chunk.size); + break; + + case mmioFOURCC('d','a','t','a'): + if (!(This->data = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, This->data, chunk.size); + if (SUCCEEDED(hr)) This->data_size = chunk.size; + break; + + case FOURCC_WSMP: + hr = parse_wsmp_chunk(This, stream, &chunk); + break; + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + return hr; +} + +HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **ret_iface) +{ + struct wave *This; + IUnknown *iface; + HRESULT hr; + + TRACE("(%p, %p, %p)\n", stream, parent, ret_iface); + + if (FAILED(hr = wave_create(&iface))) return hr; + This = impl_from_IUnknown(iface); + + if (FAILED(hr = parse_wave_chunk(This, stream, parent))) + { + IUnknown_Release(iface); + return DMUS_E_UNSUPPORTED_STREAM; + } + + if (TRACE_ON(dmusic)) + { + UINT i; + + TRACE("*** Created DirectMusicWave %p\n", This); + TRACE(" - format: %p\n", This->format); + if (This->format) + { + TRACE(" - wFormatTag: %u\n", This->format->wFormatTag); + TRACE(" - nChannels: %u\n", This->format->nChannels); + TRACE(" - nSamplesPerSec: %lu\n", This->format->nSamplesPerSec); + TRACE(" - nAvgBytesPerSec: %lu\n", This->format->nAvgBytesPerSec); + TRACE(" - nBlockAlign: %u\n", This->format->nBlockAlign); + TRACE(" - wBitsPerSample: %u\n", This->format->wBitsPerSample); + TRACE(" - cbSize: %u\n", This->format->cbSize); + } + TRACE(" - sample: {size: %lu, unity_note: %u, fine_tune: %d, attenuation: %ld, options: %#lx, loops: %lu}\n", + This->sample->head.cbSize, This->sample->head.usUnityNote, + This->sample->head.sFineTune, This->sample->head.lAttenuation, + This->sample->head.fulOptions, This->sample->head.cSampleLoops); + for (i = 0; i < This->sample->head.cSampleLoops; i++) + TRACE(" - loops[%u]: {size: %lu, type: %lu, start: %lu, length: %lu}\n", i, + This->sample->loops[i].cbSize, This->sample->loops[i].ulType, + This->sample->loops[i].ulStart, This->sample->loops[i].ulLength); + } + + *ret_iface = iface; + return S_OK; +}
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmusic/collection.c | 21 +++++++++++++++++++-- dlls/dmusic/dmusic_private.h | 6 +++++- dlls/dmusic/instrument.c | 11 +++++++---- 3 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 1c36f0b202d..cfe7589485d 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -48,6 +48,7 @@ struct collection { IDirectMusicCollection IDirectMusicCollection_iface; struct dmobject dmobj; + LONG internal_ref; LONG ref;
DLSHEADER header; @@ -56,6 +57,21 @@ struct collection struct list waves; };
+extern void collection_internal_addref(struct collection *collection) +{ + ULONG ref = InterlockedIncrement( &collection->internal_ref ); + TRACE( "collection %p, internal ref %lu.\n", collection, ref ); +} + +extern void collection_internal_release(struct collection *collection) +{ + ULONG ref = InterlockedDecrement( &collection->internal_ref ); + TRACE( "collection %p, internal ref %lu.\n", collection, ref ); + + if (!ref) + free(collection); +} + static inline struct collection *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface) { return CONTAINING_RECORD(iface, struct collection, IDirectMusicCollection_iface); @@ -128,7 +144,7 @@ static ULONG WINAPI collection_Release(IDirectMusicCollection *iface) free(wave_entry); }
- free(This); + collection_internal_release(This); }
return ref; @@ -201,7 +217,7 @@ static HRESULT parse_lins_list(struct collection *This, IStream *stream, struct { case MAKE_IDTYPE(FOURCC_LIST, FOURCC_INS): if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY; - hr = instrument_create_from_chunk(stream, &chunk, &entry->desc, &entry->instrument); + hr = instrument_create_from_chunk(stream, &chunk, This, &entry->desc, &entry->instrument); if (SUCCEEDED(hr)) list_add_tail(&This->instruments, &entry->entry); else free(entry); break; @@ -435,6 +451,7 @@ HRESULT collection_create(IUnknown **ret_iface) *ret_iface = NULL; if (!(collection = calloc(1, sizeof(*collection)))) return E_OUTOFMEMORY; collection->IDirectMusicCollection_iface.lpVtbl = &collection_vtbl; + collection->internal_ref = 1; collection->ref = 1; dmobject_init(&collection->dmobj, &CLSID_DirectMusicCollection, (IUnknown *)&collection->IDirectMusicCollection_iface); diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 2fe6afde643..1f6b33ec34d 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -76,6 +76,10 @@ typedef struct port_info { * ClassFactory */
+struct collection; +extern void collection_internal_addref(struct collection *collection); +extern void collection_internal_release(struct collection *collection); + /* CLSID */ extern HRESULT music_create(IUnknown **ret_iface); extern HRESULT collection_create(IUnknown **ret_iface); @@ -87,7 +91,7 @@ extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface);
extern HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, - DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface); + struct collection *collection, DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface); extern HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicPortDownload *port, IDirectMusicDownloadedInstrument **downloaded); extern HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port); diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 24b3c0305f8..b79e7671c5b 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -51,6 +51,7 @@ struct instrument
INSTHEADER header; IDirectMusicDownload *download; + struct collection *collection; struct list articulations; struct list regions; }; @@ -124,6 +125,7 @@ static ULONG WINAPI instrument_Release(LPDIRECTMUSICINSTRUMENT iface) free(region); }
+ collection_internal_release(This->collection); free(This); }
@@ -201,7 +203,7 @@ static const IDirectMusicDownloadedInstrumentVtbl downloaded_instrument_vtbl = downloaded_instrument_Release, };
-static HRESULT instrument_create(IDirectMusicInstrument **ret_iface) +static HRESULT instrument_create(struct collection *collection, IDirectMusicInstrument **ret_iface) { struct instrument *instrument;
@@ -210,6 +212,7 @@ static HRESULT instrument_create(IDirectMusicInstrument **ret_iface) instrument->IDirectMusicInstrument_iface.lpVtbl = &instrument_vtbl; instrument->IDirectMusicDownloadedInstrument_iface.lpVtbl = &downloaded_instrument_vtbl; instrument->ref = 1; + collection_internal_addref((instrument->collection = collection)); list_init(&instrument->articulations); list_init(&instrument->regions);
@@ -377,15 +380,15 @@ static HRESULT parse_ins_chunk(struct instrument *This, IStream *stream, struct }
HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, - DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface) + struct collection *collection, DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface) { IDirectMusicInstrument *iface; struct instrument *This; HRESULT hr;
- TRACE("(%p, %p)\n", stream, ret_iface); + TRACE("(%p, %p, %p, %p, %p)\n", stream, parent, collection, desc, ret_iface);
- if (FAILED(hr = instrument_create(&iface))) return hr; + if (FAILED(hr = instrument_create(collection, &iface))) return hr; This = impl_from_IDirectMusicInstrument(iface);
if (FAILED(hr = parse_ins_chunk(This, stream, parent, desc)))
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmusic/collection.c | 21 ++++++++++++++++++ dlls/dmusic/dmusic_private.h | 2 ++ dlls/dmusic/instrument.c | 33 +++++++++++++++++++++++++++ dlls/dmusic/tests/dmusic.c | 4 +--- dlls/dmusic/wave.c | 43 ++++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 3 deletions(-)
diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index cfe7589485d..b7c11dacb77 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -72,6 +72,27 @@ extern void collection_internal_release(struct collection *collection) free(collection); }
+extern HRESULT collection_get_wave(struct collection *collection, DWORD index, IUnknown **out) +{ + struct wave_entry *wave_entry; + DWORD offset; + + if (index >= collection->pool->table.cCues) return E_INVALIDARG; + offset = collection->pool->cues[index].ulOffset; + + LIST_FOR_EACH_ENTRY(wave_entry, &collection->waves, struct wave_entry, entry) + { + if (offset == wave_entry->offset) + { + *out = wave_entry->wave; + IUnknown_AddRef(wave_entry->wave); + return S_OK; + } + } + + return E_FAIL; +} + static inline struct collection *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface) { return CONTAINING_RECORD(iface, struct collection, IDirectMusicCollection_iface); diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 1f6b33ec34d..0b000fb6f1c 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -79,6 +79,7 @@ typedef struct port_info { struct collection; extern void collection_internal_addref(struct collection *collection); extern void collection_internal_release(struct collection *collection); +extern HRESULT collection_get_wave(struct collection *collection, DWORD index, IUnknown **out);
/* CLSID */ extern HRESULT music_create(IUnknown **ret_iface); @@ -97,6 +98,7 @@ extern HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirec extern HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port);
extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **out); +extern HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD *id);
/***************************************************************************** * IDirectMusic8Impl implementation structure diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index b79e7671c5b..663e2112a06 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -453,6 +453,7 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP IDirectMusicDownload *download; DWORD size, offset_count; struct region *region; + IUnknown *wave; HRESULT hr;
if (This->download) goto done; @@ -509,6 +510,13 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP dmus_region->WaveLink = region->wave_link; dmus_region->WSMP = region->wave_sample; dmus_region->WLOOP[0] = region->wave_loop; + + if (SUCCEEDED(hr = collection_get_wave(This->collection, region->wave_link.ulTableIndex, &wave))) + { + hr = wave_download_to_port(wave, port, &dmus_region->WaveLink.ulTableIndex); + IUnknown_Release(wave); + } + if (FAILED(hr)) goto failed; }
if (FAILED(hr = IDirectMusicPortDownload_Download(port, download))) goto failed; @@ -530,12 +538,37 @@ failed: HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port) { struct instrument *This = impl_from_IDirectMusicDownloadedInstrument(iface); + struct download_buffer *buffer; + DWORD size; HRESULT hr;
if (!This->download) return DMUS_E_NOT_DOWNLOADED_TO_PORT;
if (FAILED(hr = IDirectMusicPortDownload_Unload(port, This->download))) WARN("Failed to unload instrument download buffer, hr %#lx\n", hr); + else if (SUCCEEDED(hr = IDirectMusicDownload_GetBuffer(This->download, (void **)&buffer, &size))) + { + IDirectMusicDownload *wave_download; + DMUS_INSTRUMENT *instrument; + BYTE *ptr = (BYTE *)buffer; + DMUS_REGION *region; + UINT index; + + instrument = (DMUS_INSTRUMENT *)(ptr + buffer->offsets[0]); + for (index = instrument->ulFirstRegionIdx; index; index = region->ulNextRegionIdx) + { + region = (DMUS_REGION *)(ptr + buffer->offsets[index]); + + if (FAILED(hr = IDirectMusicPortDownload_GetBuffer(port, region->WaveLink.ulTableIndex, &wave_download))) + WARN("Failed to get wave download with id %#lx, hr %#lx\n", region->WaveLink.ulTableIndex, hr); + else + { + if (FAILED(hr = IDirectMusicPortDownload_Unload(port, wave_download))) + WARN("Failed to unload wave download buffer, hr %#lx\n", hr); + IDirectMusicDownload_Release(wave_download); + } + } + }
IDirectMusicDownload_Release(This->download); This->download = NULL; diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 1561c51df76..879a6f800cd 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1300,8 +1300,7 @@ static void test_download_instrument(void) check_interface(instrument, &IID_IDirectMusicDownloadedInstrument, FALSE);
hr = IDirectMusicPort_DownloadInstrument(port, instrument, &downloaded, NULL, 0); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (hr != S_OK) goto skip_tests; + ok(hr == S_OK, "got %#lx\n", hr);
check_interface(downloaded, &IID_IDirectMusicObject, FALSE); check_interface(downloaded, &IID_IDirectMusicDownload, FALSE); @@ -1313,7 +1312,6 @@ static void test_download_instrument(void)
IDirectMusicInstrument_Release(instrument);
-skip_tests: IDirectMusicCollection_Release(collection); IDirectMusicPort_Release(port); IDirectMusic_Release(dmusic); diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c index cda895484cb..08146db0d1c 100644 --- a/dlls/dmusic/wave.c +++ b/dlls/dmusic/wave.c @@ -212,3 +212,46 @@ HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnk *ret_iface = iface; return S_OK; } + +HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD *id) +{ + struct download_buffer + { + DMUS_DOWNLOADINFO info; + ULONG offsets[2]; + DMUS_WAVE wave; + DMUS_WAVEDATA data; + } *buffer; + + struct wave *This = impl_from_IUnknown(iface); + DWORD size = offsetof(struct download_buffer, data.byData[This->data_size]); + IDirectMusicDownload *download; + HRESULT hr; + + if (FAILED(hr = IDirectMusicPortDownload_AllocateBuffer(port, size, &download))) return hr; + + if (SUCCEEDED(hr = IDirectMusicDownload_GetBuffer(download, (void **)&buffer, &size)) + && SUCCEEDED(hr = IDirectMusicPortDownload_GetDLId(port, &buffer->info.dwDLId, 1))) + { + buffer->info.dwDLType = DMUS_DOWNLOADINFO_WAVE; + buffer->info.dwNumOffsetTableEntries = 2; + buffer->info.cbSize = size; + + buffer->offsets[0] = offsetof(struct download_buffer, wave); + buffer->offsets[1] = offsetof(struct download_buffer, data); + + buffer->wave.WaveformatEx = *This->format; + buffer->wave.ulWaveDataIdx = 1; + buffer->wave.ulCopyrightIdx = 0; + buffer->wave.ulFirstExtCkIdx = 0; + + buffer->data.cbSize = This->data_size; + memcpy(buffer->data.byData, This->data, This->data_size); + + if (SUCCEEDED(hr = IDirectMusicPortDownload_Download(port, download))) *id = buffer->info.dwDLId; + else WARN("Failed to download wave to port, hr %#lx\n", hr); + } + + IDirectMusicDownload_Release(download); + return hr; +}
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmusic/instrument.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 663e2112a06..a15a8d4e84f 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -36,6 +36,7 @@ C_ASSERT(sizeof(struct articulation) == offsetof(struct articulation, connection struct region { struct list entry; + struct list articulations; RGNHEADER header; WAVELINK wave_link; WSMPL wave_sample; @@ -121,6 +122,13 @@ static ULONG WINAPI instrument_Release(LPDIRECTMUSICINSTRUMENT iface)
LIST_FOR_EACH_ENTRY_SAFE(region, next_region, &This->regions, struct region, entry) { + LIST_FOR_EACH_ENTRY_SAFE(articulation, next_articulation, ®ion->articulations, + struct articulation, entry) + { + list_remove(&articulation->entry); + free(articulation); + } + list_remove(®ion->entry); free(region); } @@ -221,7 +229,8 @@ static HRESULT instrument_create(struct collection *collection, IDirectMusicInst return S_OK; }
-static HRESULT parse_art1_chunk(struct instrument *This, IStream *stream, struct chunk_entry *chunk) +static HRESULT parse_art1_chunk(struct instrument *This, IStream *stream, struct chunk_entry *chunk, + struct list *articulations) { struct articulation *articulation; CONNECTIONLIST list; @@ -239,12 +248,13 @@ static HRESULT parse_art1_chunk(struct instrument *This, IStream *stream, struct
size = sizeof(CONNECTION) * list.cConnections; if (FAILED(hr = stream_read(stream, articulation->connections, size))) free(articulation); - else list_add_tail(&This->articulations, &articulation->entry); + else list_add_tail(articulations, &articulation->entry);
return hr; }
-static HRESULT parse_lart_list(struct instrument *This, IStream *stream, struct chunk_entry *parent) +static HRESULT parse_lart_list(struct instrument *This, IStream *stream, struct chunk_entry *parent, + struct list *articulations) { struct chunk_entry chunk = {.parent = parent}; HRESULT hr; @@ -254,7 +264,7 @@ static HRESULT parse_lart_list(struct instrument *This, IStream *stream, struct switch (MAKE_IDTYPE(chunk.id, chunk.type)) { case FOURCC_ART1: - hr = parse_art1_chunk(This, stream, &chunk); + hr = parse_art1_chunk(This, stream, &chunk, articulations); break;
default: @@ -275,6 +285,7 @@ static HRESULT parse_rgn_chunk(struct instrument *This, IStream *stream, struct HRESULT hr;
if (!(region = malloc(sizeof(*region)))) return E_OUTOFMEMORY; + list_init(®ion->articulations);
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { @@ -299,6 +310,10 @@ static HRESULT parse_rgn_chunk(struct instrument *This, IStream *stream, struct hr = stream_chunk_get_data(stream, &chunk, ®ion->wave_link, sizeof(region->wave_link)); break;
+ case MAKE_IDTYPE(FOURCC_LIST, FOURCC_LART): + hr = parse_lart_list(This, stream, &chunk, ®ion->articulations); + break; + default: FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); break; @@ -365,7 +380,7 @@ static HRESULT parse_ins_chunk(struct instrument *This, IStream *stream, struct break;
case MAKE_IDTYPE(FOURCC_LIST, FOURCC_LART): - hr = parse_lart_list(This, stream, &chunk); + hr = parse_lart_list(This, stream, &chunk, &This->articulations); break;
default:
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmusic/instrument.c | 56 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+)
diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index a15a8d4e84f..8ce3c0bc979 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -452,6 +452,39 @@ HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent return S_OK; }
+static void write_articulation_download(struct list *articulations, ULONG *offsets, + BYTE **ptr, UINT index, DWORD *first, UINT *end) +{ + DMUS_ARTICULATION2 *dmus_articulation2 = NULL; + struct articulation *articulation; + CONNECTIONLIST *list; + UINT size; + + LIST_FOR_EACH_ENTRY(articulation, articulations, struct articulation, entry) + { + if (dmus_articulation2) dmus_articulation2->ulNextArtIdx = index; + else *first = index; + + offsets[index++] = sizeof(DMUS_DOWNLOADINFO) + *ptr - (BYTE *)offsets; + dmus_articulation2 = (DMUS_ARTICULATION2 *)*ptr; + (*ptr) += sizeof(DMUS_ARTICULATION2); + + dmus_articulation2->ulArtIdx = index; + dmus_articulation2->ulFirstExtCkIdx = 0; + dmus_articulation2->ulNextArtIdx = 0; + + size = articulation->list.cConnections * sizeof(CONNECTION); + offsets[index++] = sizeof(DMUS_DOWNLOADINFO) + *ptr - (BYTE *)offsets; + list = (CONNECTIONLIST *)*ptr; + (*ptr) += sizeof(CONNECTIONLIST) + size; + + *list = articulation->list; + memcpy(list + 1, articulation->connections, size); + } + + *end = index; +} + struct download_buffer { DMUS_DOWNLOADINFO info; @@ -464,6 +497,7 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP IDirectMusicDownloadedInstrument **downloaded) { struct instrument *This = impl_from_IDirectMusicInstrument(iface); + struct articulation *articulation; struct download_buffer *buffer; IDirectMusicDownload *download; DWORD size, offset_count; @@ -477,10 +511,26 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP size += sizeof(ULONG) + sizeof(DMUS_INSTRUMENT); offset_count = 1;
+ LIST_FOR_EACH_ENTRY(articulation, &This->articulations, struct articulation, entry) + { + size += sizeof(ULONG) + sizeof(DMUS_ARTICULATION2); + size += sizeof(ULONG) + sizeof(CONNECTIONLIST); + size += articulation->list.cConnections * sizeof(CONNECTION); + offset_count += 2; + } + LIST_FOR_EACH_ENTRY(region, &This->regions, struct region, entry) { size += sizeof(ULONG) + sizeof(DMUS_REGION); offset_count++; + + LIST_FOR_EACH_ENTRY(articulation, ®ion->articulations, struct articulation, entry) + { + size += sizeof(ULONG) + sizeof(DMUS_ARTICULATION2); + size += sizeof(ULONG) + sizeof(CONNECTIONLIST); + size += articulation->list.cConnections * sizeof(CONNECTION); + offset_count += 2; + } }
if (FAILED(hr = IDirectMusicPortDownload_AllocateBuffer(port, size, &download))) return hr; @@ -506,6 +556,9 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP dmus_instrument->ulCopyrightIdx = 0; dmus_instrument->ulGlobalArtIdx = 0;
+ write_articulation_download(&This->articulations, buffer->offsets, &ptr, index, + &dmus_instrument->ulGlobalArtIdx, &index); + LIST_FOR_EACH_ENTRY(region, &This->regions, struct region, entry) { if (dmus_region) dmus_region->ulNextRegionIdx = index; @@ -532,6 +585,9 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP IUnknown_Release(wave); } if (FAILED(hr)) goto failed; + + write_articulation_download(®ion->articulations, buffer->offsets, &ptr, index, + &dmus_region->ulRegionArtIdx, &index); }
if (FAILED(hr = IDirectMusicPortDownload_Download(port, download))) goto failed;
v2: Avoid swallowing errors and fix one inconsistent return path.
This merge request was approved by Michael Stefaniuc.