mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
dmusic: Parse collection wave lists.
This commit is contained in:
parent
2f5608efd1
commit
82d1794cd4
4 changed files with 228 additions and 5 deletions
|
@ -10,7 +10,8 @@ C_SRCS = \
|
|||
dmusic_main.c \
|
||||
download.c \
|
||||
instrument.c \
|
||||
port.c
|
||||
port.c \
|
||||
wave.c
|
||||
|
||||
IDL_SRCS = dmusic.idl
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
214
dlls/dmusic/wave.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue