1 /* IDirectMusicInstrument Implementation
3 * Copyright (C) 2003-2004 Rok Mandeljc
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "dmusic_private.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
23 WINE_DECLARE_DEBUG_CHANNEL(dmfile);
25 const GUID IID_IDirectMusicInstrumentPRIVATE = {0xbcb20080,0xa40c,0x11d1,{0x86,0xbc,0x00,0xc0,0x4f,0xbf,0x8f,0xef}};
27 /* IDirectMusicInstrument IUnknown part: */
28 HRESULT WINAPI IDirectMusicInstrumentImpl_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, LPVOID *ppobj) {
29 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
30 TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
32 if (IsEqualIID (riid, &IID_IUnknown)) {
33 *ppobj = (LPVOID)&This->UnknownVtbl;
34 IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
36 } else if (IsEqualIID (riid, &IID_IDirectMusicInstrument)) {
37 *ppobj = (LPVOID)&This->InstrumentVtbl;
38 IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef ((LPDIRECTMUSICINSTRUMENT)&This->InstrumentVtbl);
40 } 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 */
45 FIXME("*sigh*... requested private/unspecified interface\n");
46 *ppobj = (LPVOID)&This->UnknownVtbl;
47 IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
51 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj);
55 ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_AddRef (LPUNKNOWN iface) {
56 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
57 ULONG refCount = InterlockedIncrement(&This->ref);
59 TRACE("(%p)->(ref before=%lu)\n", This, refCount - 1);
66 ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_Release (LPUNKNOWN iface) {
67 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
68 ULONG refCount = InterlockedDecrement(&This->ref);
70 TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1);
73 HeapFree(GetProcessHeap(), 0, This);
76 DMUSIC_UnlockModule();
81 IUnknownVtbl DirectMusicInstrument_Unknown_Vtbl = {
82 IDirectMusicInstrumentImpl_IUnknown_QueryInterface,
83 IDirectMusicInstrumentImpl_IUnknown_AddRef,
84 IDirectMusicInstrumentImpl_IUnknown_Release
87 /* IDirectMusicInstrumentImpl IDirectMusicInstrument part: */
88 HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface (LPDIRECTMUSICINSTRUMENT iface, REFIID riid, LPVOID *ppobj) {
89 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
90 return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
93 ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef (LPDIRECTMUSICINSTRUMENT iface) {
94 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
95 return IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
98 ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release (LPDIRECTMUSICINSTRUMENT iface) {
99 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
100 return IDirectMusicInstrumentImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
103 HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD* pdwPatch) {
104 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
105 TRACE("(%p, %p)\n", This, pdwPatch);
106 *pdwPatch = MIDILOCALE2Patch(&This->pHeader->Locale);
110 HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD dwPatch) {
111 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
112 TRACE("(%p, %ld): stub\n", This, dwPatch);
113 Patch2MIDILOCALE(dwPatch, &This->pHeader->Locale);
117 IDirectMusicInstrumentVtbl DirectMusicInstrument_Instrument_Vtbl = {
118 IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface,
119 IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef,
120 IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release,
121 IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch,
122 IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch
125 /* for ClassFactory */
126 HRESULT WINAPI 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->UnknownVtbl = &DirectMusicInstrument_Unknown_Vtbl;
135 dminst->InstrumentVtbl = &DirectMusicInstrument_Instrument_Vtbl;
136 dminst->ref = 0; /* will be inited by QueryInterface */
138 return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&dminst->UnknownVtbl, lpcGUID, ppobj);
141 /* aux. function that completely loads instrument; my tests indicate that it's
142 called somewhere around IDirectMusicCollection_GetInstrument */
143 HRESULT WINAPI IDirectMusicInstrumentImpl_Custom_Load (LPDIRECTMUSICINSTRUMENT iface, LPSTREAM pStm) {
144 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
146 DMUS_PRIVATE_CHUNK Chunk;
147 DWORD ListSize[4], ListCount[4];
148 LARGE_INTEGER liMove; /* used when skipping chunks */
150 TRACE("(%p, %p, offset = 0x%04llx)\n", This, pStm, This->liInstrumentPosition.QuadPart);
152 /* goto the beginning of chunk */
153 IStream_Seek (pStm, This->liInstrumentPosition, STREAM_SEEK_SET, NULL);
155 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
156 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
157 switch (Chunk.fccID) {
159 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
160 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
161 ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
163 switch (Chunk.fccID) {
165 TRACE_(dmfile)(": instrument list\n");
167 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
168 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
169 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
170 switch (Chunk.fccID) {
172 TRACE_(dmfile)(": instrument header chunk\n");
173 /* should be already initialised */
174 IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL);
178 TRACE_(dmfile)(": DLID (GUID) chunk\n");
179 /* should be already initialised */
180 IStream_Read (pStm, This->pInstrumentID, Chunk.dwSize, NULL);
184 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
185 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
186 ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
188 switch (Chunk.fccID) {
190 TRACE_(dmfile)(": regions list\n");
192 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
193 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
194 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
195 switch (Chunk.fccID) {
197 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
198 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
199 ListSize[2] = Chunk.dwSize - sizeof(FOURCC);
201 switch (Chunk.fccID) {
203 /* temporary structures */
204 RGNHEADER tmpRegionHeader;
207 WAVELINK tmpWaveLink;
209 TRACE_(dmfile)(": region list\n");
211 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
212 ListCount[2] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
213 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
214 switch (Chunk.fccID) {
216 TRACE_(dmfile)(": region header chunk\n");
217 memset (&tmpRegionHeader, 0, sizeof(RGNHEADER)); /* reset */
218 IStream_Read (pStm, &tmpRegionHeader, Chunk.dwSize, NULL);
222 TRACE_(dmfile)(": wave sample chunk\n");
223 memset (&tmpWaveSample, 0, sizeof(WSMPL)); /* reset */
224 memset (&tmpWaveLoop, 0, sizeof(WLOOP)); /* reset */
225 if (Chunk.dwSize != (sizeof(WSMPL) + sizeof(WLOOP))) ERR(": incorrect chunk size\n");
226 IStream_Read (pStm, &tmpWaveSample, sizeof(WSMPL), NULL);
227 IStream_Read (pStm, &tmpWaveLoop, sizeof(WLOOP), NULL);
231 TRACE_(dmfile)(": wave link chunk\n");
232 memset (&tmpWaveLink, 0, sizeof(WAVELINK)); /* reset */
233 IStream_Read (pStm, &tmpWaveLink, Chunk.dwSize, NULL);
237 TRACE_(dmfile)(": unknown (skipping)\n");
238 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
239 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
243 TRACE_(dmfile)(": ListCount[2] = %ld < ListSize[2] = %ld\n", ListCount[2], ListSize[2]);
244 } while (ListCount[2] < ListSize[2]);
245 FIXME(": need to write temporary data to instrument data\n");
249 TRACE_(dmfile)(": unknown (skipping)\n");
250 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
251 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
258 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
259 liMove.QuadPart = Chunk.dwSize;
260 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
264 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
265 } while (ListCount[1] < ListSize[1]);
269 TRACE_(dmfile)(": articulators list\n");
271 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
272 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
273 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
274 switch (Chunk.fccID) {
276 /* temporary structures */
277 CONNECTIONLIST tmpConnectionList;
278 LPCONNECTION tmpConnections;
280 TRACE_(dmfile)(": level 1 articulator chunk\n");
281 memset (&tmpConnectionList, 0, sizeof(CONNECTIONLIST)); /* reset */
282 tmpConnections = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(CONNECTION)*tmpConnectionList.cConnections);
283 if (Chunk.dwSize != (sizeof(CONNECTIONLIST) + sizeof(CONNECTION)*tmpConnectionList.cConnections)) ERR(": incorrect chunk size\n");
284 IStream_Read (pStm, &tmpConnectionList, sizeof(CONNECTIONLIST), NULL);
285 IStream_Read (pStm, tmpConnections, sizeof(CONNECTION)*tmpConnectionList.cConnections, NULL);
289 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
290 liMove.QuadPart = Chunk.dwSize;
291 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
295 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
296 } while (ListCount[1] < ListSize[1]);
299 case mmioFOURCC('I','N','F','O'): {
300 TRACE_(dmfile)(": INFO list\n");
302 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
303 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
304 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
305 switch (Chunk.fccID) {
306 case mmioFOURCC('I','N','A','M'): {
307 TRACE_(dmfile)(": name chunk (ignored)\n");
308 if (even_or_odd(Chunk.dwSize)) {
312 liMove.QuadPart = Chunk.dwSize;
313 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
316 case mmioFOURCC('I','A','R','T'): {
317 TRACE_(dmfile)(": artist chunk (ignored)\n");
318 if (even_or_odd(Chunk.dwSize)) {
322 liMove.QuadPart = Chunk.dwSize;
323 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
326 case mmioFOURCC('I','C','O','P'): {
327 /* temporary structures */
328 CHAR tmpCopyright[DMUS_MAX_NAME];
330 TRACE_(dmfile)(": copyright chunk\n");
331 IStream_Read (pStm, tmpCopyright, Chunk.dwSize, NULL);
332 if (even_or_odd(Chunk.dwSize)) {
335 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
339 case mmioFOURCC('I','S','B','J'): {
340 TRACE_(dmfile)(": subject chunk (ignored)\n");
341 if (even_or_odd(Chunk.dwSize)) {
345 liMove.QuadPart = Chunk.dwSize;
346 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
349 case mmioFOURCC('I','C','M','T'): {
350 TRACE_(dmfile)(": comment chunk (ignored)\n");
351 if (even_or_odd(Chunk.dwSize)) {
355 liMove.QuadPart = Chunk.dwSize;
356 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
360 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
361 if (even_or_odd(Chunk.dwSize)) {
365 liMove.QuadPart = Chunk.dwSize;
366 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
370 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
371 } while (ListCount[1] < ListSize[1]);
376 TRACE_(dmfile)(": unknown (skipping)\n");
377 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
378 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
385 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
386 liMove.QuadPart = Chunk.dwSize;
387 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
391 TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]);
392 } while (ListCount[0] < ListSize[0]);
396 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
397 liMove.QuadPart = Chunk.dwSize;
398 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
405 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
406 liMove.QuadPart = Chunk.dwSize;
407 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
411 /* DEBUG: dumps whole instrument object tree: */
412 /* if (TRACE_ON(dmusic)) {
413 TRACE("*** IDirectMusicInstrument (%p) ***\n", This);
414 if (This->pInstrumentID)
415 TRACE(" - GUID = %s\n", debugstr_dmguid(This->pInstrumentID));
417 TRACE(" - Instrument header:\n");
418 TRACE(" - cRegions: %ld\n", This->pHeader->cRegions);
419 TRACE(" - Locale:\n");
420 TRACE(" - ulBank: %ld\n", This->pHeader->Locale.ulBank);
421 TRACE(" - ulInstrument: %ld\n", This->pHeader->Locale.ulInstrument);
422 TRACE(" => dwPatch: %ld\n", MIDILOCALE2Patch(&This->pHeader->Locale));