2 * IDirectMusicInstrument Implementation
4 * Copyright (C) 2003-2004 Rok Mandeljc
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "dmusic_private.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(dmusic
);
25 static const GUID IID_IDirectMusicInstrumentPRIVATE
= { 0xbcb20080, 0xa40c, 0x11d1, { 0x86, 0xbc, 0x00, 0xc0, 0x4f, 0xbf, 0x8f, 0xef } };
27 /* IDirectMusicInstrument IUnknown part: */
28 static HRESULT WINAPI
IDirectMusicInstrumentImpl_QueryInterface(LPDIRECTMUSICINSTRUMENT iface
, REFIID riid
, LPVOID
*ret_iface
)
30 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_dmguid(riid
), ret_iface
);
32 if (IsEqualIID(riid
, &IID_IUnknown
) ||
33 IsEqualIID(riid
, &IID_IDirectMusicInstrument
))
36 IDirectMusicInstrument_AddRef(iface
);
39 else if (IsEqualIID(riid
, &IID_IDirectMusicInstrumentPRIVATE
))
41 /* it seems to me that this interface is only basic IUnknown, without any
42 * other inherited functions... *sigh* this is the worst scenario, since it means
43 * that whoever calls it knows the layout of original implementation table and therefore
44 * tries to get data by direct access... expect crashes
46 FIXME("*sigh*... requested private/unspecified interface\n");
49 IDirectMusicInstrument_AddRef(iface
);
53 WARN("(%p)->(%s, %p): not found\n", iface
, debugstr_dmguid(riid
), ret_iface
);
58 static ULONG WINAPI
IDirectMusicInstrumentImpl_AddRef(LPDIRECTMUSICINSTRUMENT iface
)
60 IDirectMusicInstrumentImpl
*This
= impl_from_IDirectMusicInstrument(iface
);
61 ULONG ref
= InterlockedIncrement(&This
->ref
);
63 TRACE("(%p)->(): new ref = %u\n", iface
, ref
);
70 static ULONG WINAPI
IDirectMusicInstrumentImpl_Release(LPDIRECTMUSICINSTRUMENT iface
)
72 IDirectMusicInstrumentImpl
*This
= impl_from_IDirectMusicInstrument(iface
);
73 ULONG ref
= InterlockedDecrement(&This
->ref
);
75 TRACE("(%p)->(): new ref = %u\n", iface
, ref
);
81 HeapFree(GetProcessHeap(), 0, This
->regions
);
82 for (i
= 0; i
< This
->nb_articulations
; i
++)
83 HeapFree(GetProcessHeap(), 0, This
->articulations
->connections
);
84 HeapFree(GetProcessHeap(), 0, This
->articulations
);
85 HeapFree(GetProcessHeap(), 0, This
);
88 DMUSIC_UnlockModule();
93 /* IDirectMusicInstrumentImpl IDirectMusicInstrument part: */
94 static HRESULT WINAPI
IDirectMusicInstrumentImpl_GetPatch(LPDIRECTMUSICINSTRUMENT iface
, DWORD
* pdwPatch
)
96 IDirectMusicInstrumentImpl
*This
= impl_from_IDirectMusicInstrument(iface
);
98 TRACE("(%p)->(%p)\n", This
, pdwPatch
);
100 *pdwPatch
= MIDILOCALE2Patch(&This
->header
.Locale
);
105 static HRESULT WINAPI
IDirectMusicInstrumentImpl_SetPatch(LPDIRECTMUSICINSTRUMENT iface
, DWORD dwPatch
)
107 IDirectMusicInstrumentImpl
*This
= impl_from_IDirectMusicInstrument(iface
);
109 TRACE("(%p)->(%d): stub\n", This
, dwPatch
);
111 Patch2MIDILOCALE(dwPatch
, &This
->header
.Locale
);
116 static const IDirectMusicInstrumentVtbl DirectMusicInstrument_Vtbl
=
118 IDirectMusicInstrumentImpl_QueryInterface
,
119 IDirectMusicInstrumentImpl_AddRef
,
120 IDirectMusicInstrumentImpl_Release
,
121 IDirectMusicInstrumentImpl_GetPatch
,
122 IDirectMusicInstrumentImpl_SetPatch
125 /* for ClassFactory */
126 HRESULT
DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID
, LPVOID
* ppobj
, LPUNKNOWN pUnkOuter
) {
127 IDirectMusicInstrumentImpl
* dminst
;
129 dminst
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IDirectMusicInstrumentImpl
));
130 if (NULL
== dminst
) {
132 return E_OUTOFMEMORY
;
134 dminst
->IDirectMusicInstrument_iface
.lpVtbl
= &DirectMusicInstrument_Vtbl
;
135 dminst
->ref
= 0; /* will be inited by QueryInterface */
137 return IDirectMusicInstrument_QueryInterface(&dminst
->IDirectMusicInstrument_iface
, lpcGUID
, ppobj
);
140 static HRESULT
read_from_stream(IStream
*stream
, void *data
, ULONG size
)
145 hr
= IStream_Read(stream
, data
, size
, &bytes_read
);
147 TRACE("IStream_Read failed: %08x\n", hr
);
150 if (bytes_read
< size
) {
151 TRACE("Didn't read full chunk: %u < %u\n", bytes_read
, size
);
158 static inline DWORD
subtract_bytes(DWORD len
, DWORD bytes
)
161 TRACE("Apparent mismatch in chunk lengths? %u bytes remaining, %u bytes read\n", len
, bytes
);
167 static inline HRESULT
advance_stream(IStream
*stream
, ULONG bytes
)
172 move
.QuadPart
= bytes
;
174 ret
= IStream_Seek(stream
, move
, STREAM_SEEK_CUR
, NULL
);
176 WARN("IStream_Seek failed: %08x\n", ret
);
181 static HRESULT
load_region(IDirectMusicInstrumentImpl
*This
, IStream
*stream
, instrument_region
*region
, ULONG length
)
184 DMUS_PRIVATE_CHUNK chunk
;
186 TRACE("(%p, %p, %p, %u)\n", This
, stream
, region
, length
);
190 ret
= read_from_stream(stream
, &chunk
, sizeof(chunk
));
194 length
= subtract_bytes(length
, sizeof(chunk
));
199 TRACE("RGNH chunk (region header): %u bytes\n", chunk
.dwSize
);
201 ret
= read_from_stream(stream
, ®ion
->header
, sizeof(region
->header
));
205 length
= subtract_bytes(length
, sizeof(region
->header
));
209 TRACE("WSMP chunk (wave sample): %u bytes\n", chunk
.dwSize
);
211 ret
= read_from_stream(stream
, ®ion
->wave_sample
, sizeof(region
->wave_sample
));
214 length
= subtract_bytes(length
, sizeof(region
->wave_sample
));
216 if (!(region
->loop_present
= (chunk
.dwSize
!= sizeof(region
->wave_sample
))))
219 ret
= read_from_stream(stream
, ®ion
->wave_loop
, sizeof(region
->wave_loop
));
223 length
= subtract_bytes(length
, sizeof(region
->wave_loop
));
227 TRACE("WLNK chunk (wave link): %u bytes\n", chunk
.dwSize
);
229 ret
= read_from_stream(stream
, ®ion
->wave_link
, sizeof(region
->wave_link
));
233 length
= subtract_bytes(length
, sizeof(region
->wave_link
));
237 TRACE("Unknown chunk %s (skipping): %u bytes\n", debugstr_fourcc(chunk
.fccID
), chunk
.dwSize
);
239 ret
= advance_stream(stream
, chunk
.dwSize
);
243 length
= subtract_bytes(length
, chunk
.dwSize
);
251 static HRESULT
load_articulation(IDirectMusicInstrumentImpl
*This
, IStream
*stream
, ULONG length
)
254 instrument_articulation
*articulation
;
256 if (!This
->articulations
)
257 This
->articulations
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
->articulations
));
259 This
->articulations
= HeapReAlloc(GetProcessHeap(), 0, This
->articulations
, sizeof(*This
->articulations
) * (This
->nb_articulations
+ 1));
260 if (!This
->articulations
)
261 return E_OUTOFMEMORY
;
263 articulation
= &This
->articulations
[This
->nb_articulations
];
265 ret
= read_from_stream(stream
, &articulation
->connections_list
, sizeof(CONNECTIONLIST
));
269 articulation
->connections
= HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTION
) * articulation
->connections_list
.cConnections
);
270 if (!articulation
->connections
)
271 return E_OUTOFMEMORY
;
273 ret
= read_from_stream(stream
, articulation
->connections
, sizeof(CONNECTION
) * articulation
->connections_list
.cConnections
);
276 HeapFree(GetProcessHeap(), 0, articulation
->connections
);
280 subtract_bytes(length
, sizeof(CONNECTIONLIST
) + sizeof(CONNECTION
) * articulation
->connections_list
.cConnections
);
282 This
->nb_articulations
++;
287 /* Function that loads all instrument data and which is called from IDirectMusicCollection_GetInstrument as in native */
288 HRESULT
IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument
*iface
, IStream
*stream
)
290 IDirectMusicInstrumentImpl
*This
= impl_from_IDirectMusicInstrument(iface
);
292 DMUS_PRIVATE_CHUNK chunk
;
294 ULONG length
= This
->length
;
296 TRACE("(%p, %p): offset = 0x%s, length = %u)\n", This
, stream
, wine_dbgstr_longlong(This
->liInstrumentPosition
.QuadPart
), This
->length
);
301 hr
= IStream_Seek(stream
, This
->liInstrumentPosition
, STREAM_SEEK_SET
, NULL
);
304 WARN("IStream_Seek failed: %08x\n", hr
);
305 return DMUS_E_UNSUPPORTED_STREAM
;
308 This
->regions
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
->regions
) * This
->header
.cRegions
);
310 return E_OUTOFMEMORY
;
314 hr
= read_from_stream(stream
, &chunk
, sizeof(chunk
));
318 length
= subtract_bytes(length
, sizeof(chunk
) + chunk
.dwSize
);
324 TRACE("Chunk %s: %u bytes\n", debugstr_fourcc(chunk
.fccID
), chunk
.dwSize
);
326 /* Instrument header and id are already set so just skip */
327 hr
= advance_stream(stream
, chunk
.dwSize
);
334 DWORD size
= chunk
.dwSize
;
336 TRACE("LIST chunk: %u bytes\n", chunk
.dwSize
);
338 hr
= read_from_stream(stream
, &chunk
.fccID
, sizeof(chunk
.fccID
));
342 size
= subtract_bytes(size
, sizeof(chunk
.fccID
));
347 TRACE("LRGN chunk (regions list): %u bytes\n", size
);
351 hr
= read_from_stream(stream
, &chunk
, sizeof(chunk
));
355 if (chunk
.fccID
!= FOURCC_LIST
)
357 TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk
.fccID
), chunk
.dwSize
);
361 hr
= read_from_stream(stream
, &chunk
.fccID
, sizeof(chunk
.fccID
));
365 if (chunk
.fccID
== FOURCC_RGN
)
367 TRACE("RGN chunk (region): %u bytes\n", chunk
.dwSize
);
368 hr
= load_region(This
, stream
, &This
->regions
[i
++], chunk
.dwSize
- sizeof(chunk
.fccID
));
372 TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk
.fccID
), chunk
.dwSize
);
373 hr
= advance_stream(stream
, chunk
.dwSize
- sizeof(chunk
.fccID
));
378 size
= subtract_bytes(size
, chunk
.dwSize
+ sizeof(chunk
));
383 TRACE("LART chunk (articulations list): %u bytes\n", size
);
387 hr
= read_from_stream(stream
, &chunk
, sizeof(chunk
));
391 if (chunk
.fccID
== FOURCC_ART1
)
393 TRACE("ART1 chunk (level 1 articulation): %u bytes\n", chunk
.dwSize
);
394 hr
= load_articulation(This
, stream
, chunk
.dwSize
);
398 TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk
.fccID
), chunk
.dwSize
);
399 hr
= advance_stream(stream
, chunk
.dwSize
);
404 size
= subtract_bytes(size
, chunk
.dwSize
+ sizeof(chunk
));
409 TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk
.fccID
), chunk
.dwSize
);
411 hr
= advance_stream(stream
, chunk
.dwSize
- sizeof(chunk
.fccID
));
415 size
= subtract_bytes(size
, chunk
.dwSize
- sizeof(chunk
.fccID
));
422 TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk
.fccID
), chunk
.dwSize
);
424 hr
= advance_stream(stream
, chunk
.dwSize
);
437 HeapFree(GetProcessHeap(), 0, This
->regions
);
438 This
->regions
= NULL
;
440 return DMUS_E_UNSUPPORTED_STREAM
;