dmusic: Implement instrument regions loading.

This commit is contained in:
Christian Costa 2012-12-21 10:27:38 +01:00 committed by Alexandre Julliard
parent fd269e4dca
commit bf0605c08a
2 changed files with 173 additions and 13 deletions

View File

@ -77,6 +77,13 @@ typedef struct port_info {
ULONG device; ULONG device;
} port_info; } port_info;
typedef struct instrument_region {
RGNHEADER header;
WAVELINK wave_link;
WSMPL wave_sample;
WLOOP wave_loop;
BOOL loop_present;
} instrument_region;
/***************************************************************************** /*****************************************************************************
* ClassFactory * ClassFactory
@ -224,17 +231,19 @@ struct IDirectMusicCollectionImpl {
* IDirectMusicInstrumentImpl implementation structure * IDirectMusicInstrumentImpl implementation structure
*/ */
struct IDirectMusicInstrumentImpl { struct IDirectMusicInstrumentImpl {
/* IUnknown fields */ /* IUnknown fields */
IDirectMusicInstrument IDirectMusicInstrument_iface; IDirectMusicInstrument IDirectMusicInstrument_iface;
LONG ref; LONG ref;
/* IDirectMusicInstrumentImpl fields */ /* IDirectMusicInstrumentImpl fields */
LARGE_INTEGER liInstrumentPosition; /* offset in a stream where instrument chunk can be found */ LARGE_INTEGER liInstrumentPosition; /* offset in a stream where instrument chunk can be found */
ULONG length; /* Length of the instrument in the stream */ ULONG length; /* Length of the instrument in the stream */
LPGUID pInstrumentID; LPGUID pInstrumentID;
LPINSTHEADER pHeader; LPINSTHEADER pHeader;
WCHAR wszName[DMUS_MAX_NAME]; WCHAR wszName[DMUS_MAX_NAME];
/* instrument data */ /* instrument data */
BOOL loaded;
instrument_region *regions;
}; };
static inline IDirectMusicInstrumentImpl *impl_from_IDirectMusicInstrument(IDirectMusicInstrument *iface) static inline IDirectMusicInstrumentImpl *impl_from_IDirectMusicInstrument(IDirectMusicInstrument *iface)

View File

@ -75,7 +75,10 @@ static ULONG WINAPI IDirectMusicInstrumentImpl_Release(LPDIRECTMUSICINSTRUMENT i
TRACE("(%p)->(): new ref = %u\n", iface, ref); TRACE("(%p)->(): new ref = %u\n", iface, ref);
if (!ref) if (!ref)
{
HeapFree(GetProcessHeap(), 0, This->regions);
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
}
DMUSIC_UnlockModule(); DMUSIC_UnlockModule();
@ -170,16 +173,90 @@ static inline HRESULT advance_stream(IStream *stream, ULONG bytes)
return ret; return ret;
} }
static HRESULT load_region(IDirectMusicInstrumentImpl *This, IStream *stream, instrument_region *region, ULONG length)
{
HRESULT ret;
DMUS_PRIVATE_CHUNK chunk;
TRACE("(%p, %p, %p, %u)\n", This, stream, region, length);
while (length)
{
ret = read_from_stream(stream, &chunk, sizeof(chunk));
if (FAILED(ret))
return ret;
length = subtract_bytes(length, sizeof(chunk));
switch (chunk.fccID)
{
case FOURCC_RGNH:
TRACE("RGNH chunk (region header): %u bytes\n", chunk.dwSize);
ret = read_from_stream(stream, &region->header, sizeof(region->header));
if (FAILED(ret))
return ret;
length = subtract_bytes(length, sizeof(region->header));
break;
case FOURCC_WSMP:
TRACE("WSMP chunk (wave sample): %u bytes\n", chunk.dwSize);
ret = read_from_stream(stream, &region->wave_sample, sizeof(region->wave_sample));
if (FAILED(ret))
return ret;
length = subtract_bytes(length, sizeof(region->wave_sample));
if (!(region->loop_present = (chunk.dwSize != sizeof(region->wave_sample))))
break;
ret = read_from_stream(stream, &region->wave_loop, sizeof(region->wave_loop));
if (FAILED(ret))
return ret;
length = subtract_bytes(length, sizeof(region->wave_loop));
break;
case FOURCC_WLNK:
TRACE("WLNK chunk (wave link): %u bytes\n", chunk.dwSize);
ret = read_from_stream(stream, &region->wave_link, sizeof(region->wave_link));
if (FAILED(ret))
return ret;
length = subtract_bytes(length, sizeof(region->wave_link));
break;
default:
TRACE("Unknown chunk %s (skipping): %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize);
ret = advance_stream(stream, chunk.dwSize);
if (FAILED(ret))
return ret;
length = subtract_bytes(length, chunk.dwSize);
break;
}
}
return S_OK;
}
/* Function that loads all instrument data and which is called from IDirectMusicCollection_GetInstrument as in native */ /* Function that loads all instrument data and which is called from IDirectMusicCollection_GetInstrument as in native */
HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, IStream *stream) HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, IStream *stream)
{ {
IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface); IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface);
HRESULT hr; HRESULT hr;
DMUS_PRIVATE_CHUNK chunk; DMUS_PRIVATE_CHUNK chunk;
ULONG i = 0;
ULONG length = This->length; ULONG length = This->length;
TRACE("(%p, %p): offset = 0x%s, length = %u)\n", This, stream, wine_dbgstr_longlong(This->liInstrumentPosition.QuadPart), This->length); TRACE("(%p, %p): offset = 0x%s, length = %u)\n", This, stream, wine_dbgstr_longlong(This->liInstrumentPosition.QuadPart), This->length);
if (This->loaded)
return S_OK;
hr = IStream_Seek(stream, This->liInstrumentPosition, STREAM_SEEK_SET, NULL); hr = IStream_Seek(stream, This->liInstrumentPosition, STREAM_SEEK_SET, NULL);
if (FAILED(hr)) if (FAILED(hr))
{ {
@ -187,11 +264,15 @@ HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, ISt
return DMUS_E_UNSUPPORTED_STREAM; return DMUS_E_UNSUPPORTED_STREAM;
} }
This->regions = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->regions) * This->pHeader->cRegions);
if (!This->regions)
return E_OUTOFMEMORY;
while (length) while (length)
{ {
hr = read_from_stream(stream, &chunk, sizeof(chunk)); hr = read_from_stream(stream, &chunk, sizeof(chunk));
if (FAILED(hr)) if (FAILED(hr))
return DMUS_E_UNSUPPORTED_STREAM; goto error;
length = subtract_bytes(length, sizeof(chunk) + chunk.dwSize); length = subtract_bytes(length, sizeof(chunk) + chunk.dwSize);
@ -204,20 +285,90 @@ HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, ISt
/* Instrument header and id are already set so just skip */ /* Instrument header and id are already set so just skip */
hr = advance_stream(stream, chunk.dwSize); hr = advance_stream(stream, chunk.dwSize);
if (FAILED(hr)) if (FAILED(hr))
return DMUS_E_UNSUPPORTED_STREAM; goto error;
break; break;
case FOURCC_LIST: {
DWORD size = chunk.dwSize;
TRACE("LIST chunk: %u bytes\n", chunk.dwSize);
hr = read_from_stream(stream, &chunk.fccID, sizeof(chunk.fccID));
if (FAILED(hr))
goto error;
size = subtract_bytes(size, sizeof(chunk.fccID));
switch (chunk.fccID)
{
case FOURCC_LRGN:
TRACE("LRGN chunk (regions list): %u bytes\n", size);
while (size)
{
hr = read_from_stream(stream, &chunk, sizeof(chunk));
if (FAILED(hr))
goto error;
if (chunk.fccID != FOURCC_LIST)
{
TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize);
goto error;
}
hr = read_from_stream(stream, &chunk.fccID, sizeof(chunk.fccID));
if (FAILED(hr))
goto error;
if (chunk.fccID == FOURCC_RGN)
{
TRACE("RGN chunk (region list): %u bytes\n", chunk.dwSize);
hr = load_region(This, stream, &This->regions[i++], chunk.dwSize - sizeof(chunk.fccID));
}
else
{
TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize);
hr = advance_stream(stream, chunk.dwSize - sizeof(chunk.fccID));
}
if (FAILED(hr))
goto error;
size = subtract_bytes(size, chunk.dwSize + sizeof(chunk));
}
break;
default:
TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize);
hr = advance_stream(stream, chunk.dwSize - sizeof(chunk.fccID));
if (FAILED(hr))
goto error;
size = subtract_bytes(size, chunk.dwSize - sizeof(chunk.fccID));
break;
}
break;
}
default: default:
TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize);
hr = advance_stream(stream, chunk.dwSize); hr = advance_stream(stream, chunk.dwSize);
if (FAILED(hr)) if (FAILED(hr))
return DMUS_E_UNSUPPORTED_STREAM; goto error;
break; break;
} }
} }
This->loaded = TRUE;
return S_OK; return S_OK;
error:
HeapFree(GetProcessHeap(), 0, This->regions);
This->regions = NULL;
return DMUS_E_UNSUPPORTED_STREAM;
} }