dmime: Create a wave track when loading a segment from a .wav.
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
This commit is contained in:
parent
15c4c02eeb
commit
7bbd4be52a
7 changed files with 95 additions and 75 deletions
|
@ -18,6 +18,7 @@ C_SRCS = \
|
|||
sysextrack.c \
|
||||
tempotrack.c \
|
||||
timesigtrack.c \
|
||||
wave.c \
|
||||
wavetrack.c
|
||||
|
||||
IDL_SRCS = dmime.idl
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
HRESULT hr;
|
||||
struct chunk_entry chunk = {.parent = riff};
|
||||
|
||||
TRACE("Parsing segment wave in %p: %s\n", stream, debugstr_chunk(riff));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr) ? S_OK : hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI segment_persist_stream_Load(IPersistStream *iface, IStream *stream)
|
||||
{
|
||||
struct segment *This = impl_from_IPersistStream(iface);
|
||||
struct chunk_entry riff = {0};
|
||||
struct chunk_entry chunk = {0};
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p, %p): Loading\n", This, stream);
|
||||
|
||||
if (!stream)
|
||||
return E_POINTER;
|
||||
if (!stream) return E_POINTER;
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
if (riff.id == mmioFOURCC('M','T','h','d')) {
|
||||
FIXME("MIDI file loading not supported\n");
|
||||
return S_OK;
|
||||
case mmioFOURCC('M','T','h','d'):
|
||||
FIXME("MIDI file loading not supported\n");
|
||||
break;
|
||||
|
||||
case MAKE_IDTYPE(FOURCC_RIFF, mmioFOURCC('W','A','V','E')):
|
||||
{
|
||||
IDirectMusicTrack8 *track;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("Loading segment %p from wave file\n", This);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 =
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue