dmusic: Implement instrument regions loading.
This commit is contained in:
parent
fd269e4dca
commit
bf0605c08a
|
@ -77,6 +77,13 @@ typedef struct port_info {
|
|||
ULONG device;
|
||||
} port_info;
|
||||
|
||||
typedef struct instrument_region {
|
||||
RGNHEADER header;
|
||||
WAVELINK wave_link;
|
||||
WSMPL wave_sample;
|
||||
WLOOP wave_loop;
|
||||
BOOL loop_present;
|
||||
} instrument_region;
|
||||
|
||||
/*****************************************************************************
|
||||
* ClassFactory
|
||||
|
@ -224,17 +231,19 @@ struct IDirectMusicCollectionImpl {
|
|||
* IDirectMusicInstrumentImpl implementation structure
|
||||
*/
|
||||
struct IDirectMusicInstrumentImpl {
|
||||
/* IUnknown fields */
|
||||
IDirectMusicInstrument IDirectMusicInstrument_iface;
|
||||
LONG ref;
|
||||
/* IUnknown fields */
|
||||
IDirectMusicInstrument IDirectMusicInstrument_iface;
|
||||
LONG ref;
|
||||
|
||||
/* IDirectMusicInstrumentImpl fields */
|
||||
LARGE_INTEGER liInstrumentPosition; /* offset in a stream where instrument chunk can be found */
|
||||
ULONG length; /* Length of the instrument in the stream */
|
||||
LPGUID pInstrumentID;
|
||||
LPINSTHEADER pHeader;
|
||||
WCHAR wszName[DMUS_MAX_NAME];
|
||||
/* instrument data */
|
||||
/* IDirectMusicInstrumentImpl fields */
|
||||
LARGE_INTEGER liInstrumentPosition; /* offset in a stream where instrument chunk can be found */
|
||||
ULONG length; /* Length of the instrument in the stream */
|
||||
LPGUID pInstrumentID;
|
||||
LPINSTHEADER pHeader;
|
||||
WCHAR wszName[DMUS_MAX_NAME];
|
||||
/* instrument data */
|
||||
BOOL loaded;
|
||||
instrument_region *regions;
|
||||
};
|
||||
|
||||
static inline IDirectMusicInstrumentImpl *impl_from_IDirectMusicInstrument(IDirectMusicInstrument *iface)
|
||||
|
|
|
@ -75,7 +75,10 @@ static ULONG WINAPI IDirectMusicInstrumentImpl_Release(LPDIRECTMUSICINSTRUMENT i
|
|||
TRACE("(%p)->(): new ref = %u\n", iface, ref);
|
||||
|
||||
if (!ref)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, This->regions);
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
}
|
||||
|
||||
DMUSIC_UnlockModule();
|
||||
|
||||
|
@ -170,16 +173,90 @@ static inline HRESULT advance_stream(IStream *stream, ULONG bytes)
|
|||
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, ®ion->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, ®ion->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, ®ion->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, ®ion->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 */
|
||||
HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, IStream *stream)
|
||||
{
|
||||
IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface);
|
||||
HRESULT hr;
|
||||
DMUS_PRIVATE_CHUNK chunk;
|
||||
ULONG i = 0;
|
||||
ULONG length = 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);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
|
@ -187,11 +264,15 @@ HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, ISt
|
|||
return DMUS_E_UNSUPPORTED_STREAM;
|
||||
}
|
||||
|
||||
This->regions = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->regions) * This->pHeader->cRegions);
|
||||
if (!This->regions)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
while (length)
|
||||
{
|
||||
hr = read_from_stream(stream, &chunk, sizeof(chunk));
|
||||
if (FAILED(hr))
|
||||
return DMUS_E_UNSUPPORTED_STREAM;
|
||||
goto error;
|
||||
|
||||
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 */
|
||||
hr = advance_stream(stream, chunk.dwSize);
|
||||
if (FAILED(hr))
|
||||
return DMUS_E_UNSUPPORTED_STREAM;
|
||||
goto error;
|
||||
|
||||
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:
|
||||
TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize);
|
||||
|
||||
hr = advance_stream(stream, chunk.dwSize);
|
||||
if (FAILED(hr))
|
||||
return DMUS_E_UNSUPPORTED_STREAM;
|
||||
goto error;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
This->loaded = TRUE;
|
||||
|
||||
return S_OK;
|
||||
|
||||
error:
|
||||
HeapFree(GetProcessHeap(), 0, This->regions);
|
||||
This->regions = NULL;
|
||||
|
||||
return DMUS_E_UNSUPPORTED_STREAM;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue