dmusic: Parse collection wave lists.

This commit is contained in:
Rémi Bernon 2023-09-15 09:00:54 +02:00 committed by Alexandre Julliard
parent 2f5608efd1
commit 82d1794cd4
4 changed files with 228 additions and 5 deletions

View file

@ -10,7 +10,8 @@ C_SRCS = \
dmusic_main.c \
download.c \
instrument.c \
port.c
port.c \
wave.c
IDL_SRCS = dmusic.idl

View file

@ -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);

View file

@ -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
*/

214
dlls/dmusic/wave.c Normal file
View file

@ -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;
}