From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=9027 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=34751 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45135 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48220 --- dlls/dmime/Makefile.in | 3 +- dlls/dmime/dmime_private.h | 3 + dlls/dmime/segment.c | 111 ++++++++++++++----------------------- dlls/dmime/tests/dmime.c | 2 +- dlls/dmime/wavetrack.c | 43 ++++++++++++-- dlls/dmusic/dmusic_wave.h | 1 + dlls/dmusic/wave.c | 7 +++ 7 files changed, 95 insertions(+), 75 deletions(-)
diff --git a/dlls/dmime/Makefile.in b/dlls/dmime/Makefile.in index ef4d0b9bee4..c60eb04d106 100644 --- a/dlls/dmime/Makefile.in +++ b/dlls/dmime/Makefile.in @@ -18,7 +18,8 @@ C_SRCS = \ sysextrack.c \ tempotrack.c \ timesigtrack.c \ - wavetrack.c + wavetrack.c \ + wave.c
IDL_SRCS = dmime.idl
diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 94e0efbe771..636004aed84 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -77,6 +77,9 @@ extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME sta extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance); extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface);
+extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, + IDirectMusicTrack8 **ret_iface); + /***************************************************************************** * Auxiliary definitions */ diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 1194f81b09a..fc277ba73f9 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -741,13 +741,17 @@ static inline void dump_segment_header(DMUS_IO_SEGMENT_HEADER *h, DWORD size) } }
-static HRESULT parse_segment_form(struct segment *This, IStream *stream, const struct chunk_entry *riff) +static HRESULT parse_dmsg_chunk(struct segment *This, IStream *stream, const struct chunk_entry *riff) { struct chunk_entry chunk = {.parent = riff}; HRESULT hr;
TRACE("Parsing segment form in %p: %s\n", stream, debugstr_chunk(riff));
+ if (FAILED(hr = dmobj_parsedescriptor(stream, riff, &This->dmobj.desc, DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) + || FAILED(hr = stream_reset_chunk_data(stream, riff))) + return hr; + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { switch (chunk.id) { case DMUS_FOURCC_SEGMENT_CHUNK: @@ -786,89 +790,58 @@ static inline struct segment *impl_from_IPersistStream(IPersistStream *iface) return CONTAINING_RECORD(iface, struct segment, dmobj.IPersistStream_iface); }
-static HRESULT parse_wave_form(struct segment *This, IStream *stream, const struct chunk_entry *riff) +static HRESULT WINAPI segment_persist_stream_Load(IPersistStream *iface, IStream *stream) { + struct segment *This = impl_from_IPersistStream(iface); + struct chunk_entry chunk = {0}; HRESULT hr; - struct chunk_entry chunk = {.parent = riff};
- TRACE("Parsing segment wave in %p: %s\n", stream, debugstr_chunk(riff)); + TRACE("(%p, %p): Loading\n", This, stream);
- while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - switch (chunk.id) { - case mmioFOURCC('f','m','t',' '): { - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &This->wave_format, - sizeof(This->wave_format))) ) - return hr; - TRACE("Wave Format tag %d\n", This->wave_format.wf.wFormatTag); - break; - } - case mmioFOURCC('d','a','t','a'): { - TRACE("Wave Data size %lu\n", chunk.size); - if (This->wave_data) - ERR("Multiple data streams detected\n"); - This->wave_data = malloc(chunk.size); - This->data_size = chunk.size; - if (!This->wave_data) - return E_OUTOFMEMORY; - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, This->wave_data, chunk.size))) - return hr; - break; - } - case FOURCC_LIST: { - FIXME("Skipping LIST tag\n"); - break; - } - case mmioFOURCC('I','S','F','T'): { - FIXME("Skipping ISFT tag\n"); - break; - } - case mmioFOURCC('f','a','c','t'): { - FIXME("Skipping fact tag\n"); - break; - } - } - } + if (!stream) return E_POINTER;
- return SUCCEEDED(hr) ? S_OK : hr; -} + if ((hr = stream_get_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_SEGMENT_FORM): + hr = parse_dmsg_chunk(This, stream, &chunk); + break;
-static HRESULT WINAPI segment_persist_stream_Load(IPersistStream *iface, IStream *stream) -{ - struct segment *This = impl_from_IPersistStream(iface); - struct chunk_entry riff = {0}; - HRESULT hr; + case mmioFOURCC('M','T','h','d'): + FIXME("MIDI file loading not supported\n"); + break;
- TRACE("(%p, %p): Loading\n", This, stream); + case MAKE_IDTYPE(FOURCC_RIFF, mmioFOURCC('W','A','V','E')): + { + IDirectMusicTrack8 *track; + HRESULT hr;
- if (!stream) - return E_POINTER; + TRACE("Loading segment %p from wave file\n", This);
- if (stream_get_chunk(stream, &riff) != S_OK || - (riff.id != FOURCC_RIFF && riff.id != mmioFOURCC('M','T','h','d'))) - return DMUS_E_UNSUPPORTED_STREAM; - stream_reset_chunk_start(stream, &riff); + This->header.mtLength = 1; + if (FAILED(hr = wave_track_create_from_chunk(stream, &chunk, &track))) break; + hr = segment_append_track(This, (IDirectMusicTrack *)track, 1, 0); + break; + }
- if (riff.id == mmioFOURCC('M','T','h','d')) { - FIXME("MIDI file loading not supported\n"); - return S_OK; + default: + WARN("Invalid segment chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + hr = DMUS_E_UNSUPPORTED_STREAM; + break; + } }
- hr = IDirectMusicObject_ParseDescriptor(&This->dmobj.IDirectMusicObject_iface, stream, - &This->dmobj.desc); if (FAILED(hr)) - return hr; - stream_reset_chunk_data(stream, &riff); - - if (riff.type == DMUS_FOURCC_SEGMENT_FORM) - hr = parse_segment_form(This, stream, &riff); - else if(riff.type == mmioFOURCC('W','A','V','E')) - hr = parse_wave_form(This, stream, &riff); - else { - FIXME("Unknown type %s\n", debugstr_chunk(&riff)); - hr = S_OK; + { + WARN("Failed to load segment from stream %p, hr %#lx\n", stream, hr); + return DMUS_E_UNSUPPORTED_STREAM; }
- return hr; + This->dmobj.desc.guidClass = CLSID_DirectMusicSegment; + This->dmobj.desc.dwValidData |= DMUS_OBJ_CLASS; + + return S_OK; }
static const IPersistStreamVtbl segment_persist_stream_vtbl = diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index cb35ef64ead..8468ee50dda 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3279,7 +3279,7 @@ static void test_wave_pmsg(void) length = 0xdeadbeef; hr = IDirectMusicSegment_GetLength(segment, &length); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(length == 1, "got %lu\n", length); + ok(length == 1, "got %lu\n", length);
/* without Download, no DMUS_PMSGT_WAVE is sent */ diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index 27e4d656163..d9d6334adad 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -17,13 +17,14 @@ */
#include "dmime_private.h" +#include "dmusic_wave.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmime);
struct wave_item { struct list entry; DMUS_IO_WAVE_ITEM_HEADER header; - IDirectMusicObject *object; + IUnknown *object; };
struct wave_part { @@ -100,8 +101,7 @@ static ULONG WINAPI wave_track_Release(IDirectMusicTrack8 *iface) list_remove(&part->entry); LIST_FOR_EACH_ENTRY_SAFE(item, item2, &part->items, struct wave_item, entry) { list_remove(&item->entry); - if (item->object) - IDirectMusicObject_Release(item->object); + if (item->object) IUnknown_Release(item->object); free(item); } free(part); @@ -355,7 +355,7 @@ static HRESULT parse_wave_item(struct wave_part *part, IStream *stream, struct c hr = DMUS_E_UNSUPPORTED_STREAM; goto error; } - if (FAILED(hr = dmobj_parsereference(stream, &chunk, &item->object))) + if (FAILED(hr = dmobj_parsereference(stream, &chunk, (IDirectMusicObject **)&item->object))) goto error;
list_add_tail(&part->items, &item->entry); @@ -484,3 +484,38 @@ HRESULT create_dmwavetrack(REFIID lpcGUID, void **ppobj)
return hr; } + +HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, + IDirectMusicTrack8 **ret_iface) +{ + IDirectMusicTrack8 *iface; + struct wave_track *This; + struct wave_item *item; + struct wave_part *part; + HRESULT hr; + + if (FAILED(hr = create_dmwavetrack(&IID_IDirectMusicTrack8, (void **)&iface))) return hr; + This = impl_from_IDirectMusicTrack8(iface); + + if (!(part = calloc(1, sizeof(*part)))) + { + IDirectMusicTrack8_Release(iface); + return E_OUTOFMEMORY; + } + list_init(&part->items); + list_add_tail(&This->parts, &part->entry); + + if (!(item = calloc(1, sizeof(*item))) + || FAILED(hr = wave_create_from_chunk(stream, parent, &item->object))) + { + IDirectMusicTrack8_Release(iface); + free(item); + return hr; + } + if (FAILED(hr = wave_get_duration(item->object, &item->header.rtDuration))) + WARN("Failed to get wave duration, hr %#lx\n", hr); + list_add_tail(&part->items, &item->entry); + + *ret_iface = iface; + return S_OK; +} diff --git a/dlls/dmusic/dmusic_wave.h b/dlls/dmusic/dmusic_wave.h index 0db0134ae17..3f7209e250e 100644 --- a/dlls/dmusic/dmusic_wave.h +++ b/dlls/dmusic/dmusic_wave.h @@ -32,3 +32,4 @@ struct chunk_entry; extern HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnknown **out); 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); +extern HRESULT wave_get_duration(IUnknown *iface, REFERENCE_TIME *duration); diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c index 40a8c9e129f..2f5e1409106 100644 --- a/dlls/dmusic/wave.c +++ b/dlls/dmusic/wave.c @@ -338,3 +338,10 @@ HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, D IDirectMusicDownload_Release(download); return hr; } + +HRESULT wave_get_duration(IUnknown *iface, REFERENCE_TIME *duration) +{ + struct wave *This = impl_from_IUnknown(iface); + *duration = (REFERENCE_TIME)This->data_size * 10000000 / This->format->nAvgBytesPerSec; + return S_OK; +}