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 TRACE("(%p): AddRef from %ld\n", This, This->ref);
61 ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_Release (LPUNKNOWN iface) {
62 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
63 ULONG ref = --This->ref;
64 TRACE("(%p): ReleaseRef to %ld\n", This, This->ref);
66 HeapFree(GetProcessHeap(), 0, This);
71 IUnknownVtbl DirectMusicInstrument_Unknown_Vtbl = {
72 IDirectMusicInstrumentImpl_IUnknown_QueryInterface,
73 IDirectMusicInstrumentImpl_IUnknown_AddRef,
74 IDirectMusicInstrumentImpl_IUnknown_Release
77 /* IDirectMusicInstrumentImpl IDirectMusicInstrument part: */
78 HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface (LPDIRECTMUSICINSTRUMENT iface, REFIID riid, LPVOID *ppobj) {
79 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
80 return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
83 ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef (LPDIRECTMUSICINSTRUMENT iface) {
84 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
85 return IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
88 ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release (LPDIRECTMUSICINSTRUMENT iface) {
89 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
90 return IDirectMusicInstrumentImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
93 HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD* pdwPatch) {
94 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
95 TRACE("(%p, %p)\n", This, pdwPatch);
96 *pdwPatch = MIDILOCALE2Patch(&This->pHeader->Locale);
100 HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD dwPatch) {
101 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
102 TRACE("(%p, %ld): stub\n", This, dwPatch);
103 Patch2MIDILOCALE(dwPatch, &This->pHeader->Locale);
107 IDirectMusicInstrumentVtbl DirectMusicInstrument_Instrument_Vtbl = {
108 IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface,
109 IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef,
110 IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release,
111 IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch,
112 IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch
115 /* for ClassFactory */
116 HRESULT WINAPI DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
117 IDirectMusicInstrumentImpl* dminst;
119 dminst = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicInstrumentImpl));
120 if (NULL == dminst) {
121 *ppobj = (LPVOID) NULL;
122 return E_OUTOFMEMORY;
124 dminst->UnknownVtbl = &DirectMusicInstrument_Unknown_Vtbl;
125 dminst->InstrumentVtbl = &DirectMusicInstrument_Instrument_Vtbl;
126 dminst->ref = 0; /* will be inited by QueryInterface */
128 return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&dminst->UnknownVtbl, lpcGUID, ppobj);
131 /* aux. function that completely loads instrument; my tests indicate that it's
132 called somewhere around IDirectMusicCollection_GetInstrument */
133 HRESULT WINAPI IDirectMusicInstrumentImpl_Custom_Load (LPDIRECTMUSICINSTRUMENT iface, LPSTREAM pStm) {
134 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
136 DMUS_PRIVATE_CHUNK Chunk;
137 DWORD ListSize[4], ListCount[4];
138 LARGE_INTEGER liMove; /* used when skipping chunks */
140 TRACE("(%p, %p, offset = 0x%04llx)\n", This, pStm, This->liInstrumentPosition.QuadPart);
142 /* goto the beginning of chunk */
143 IStream_Seek (pStm, This->liInstrumentPosition, STREAM_SEEK_SET, NULL);
145 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
146 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
147 switch (Chunk.fccID) {
149 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
150 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
151 ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
153 switch (Chunk.fccID) {
155 TRACE_(dmfile)(": instrument list\n");
157 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
158 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
159 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
160 switch (Chunk.fccID) {
162 TRACE_(dmfile)(": instrument header chunk\n");
163 /* should be already initialised */
164 IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL);
168 TRACE_(dmfile)(": DLID (GUID) chunk\n");
169 /* should be already initialised */
170 IStream_Read (pStm, This->pInstrumentID, Chunk.dwSize, NULL);
174 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
175 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
176 ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
178 switch (Chunk.fccID) {
180 TRACE_(dmfile)(": regions list\n");
182 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
183 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
184 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
185 switch (Chunk.fccID) {
187 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
188 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
189 ListSize[2] = Chunk.dwSize - sizeof(FOURCC);
191 switch (Chunk.fccID) {
193 /* temporary structures */
194 RGNHEADER tmpRegionHeader;
197 WAVELINK tmpWaveLink;
199 TRACE_(dmfile)(": region list\n");
201 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
202 ListCount[2] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
203 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
204 switch (Chunk.fccID) {
206 TRACE_(dmfile)(": region header chunk\n");
207 memset (&tmpRegionHeader, 0, sizeof(RGNHEADER)); /* reset */
208 IStream_Read (pStm, &tmpRegionHeader, Chunk.dwSize, NULL);
212 TRACE_(dmfile)(": wave sample chunk\n");
213 memset (&tmpWaveSample, 0, sizeof(WSMPL)); /* reset */
214 memset (&tmpWaveLoop, 0, sizeof(WLOOP)); /* reset */
215 if (Chunk.dwSize != (sizeof(WSMPL) + sizeof(WLOOP))) ERR(": incorrect chunk size\n");
216 IStream_Read (pStm, &tmpWaveSample, sizeof(WSMPL), NULL);
217 IStream_Read (pStm, &tmpWaveLoop, sizeof(WLOOP), NULL);
221 TRACE_(dmfile)(": wave link chunk\n");
222 memset (&tmpWaveLink, 0, sizeof(WAVELINK)); /* reset */
223 IStream_Read (pStm, &tmpWaveLink, Chunk.dwSize, NULL);
227 TRACE_(dmfile)(": unknown (skipping)\n");
228 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
229 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
233 TRACE_(dmfile)(": ListCount[2] = %ld < ListSize[2] = %ld\n", ListCount[2], ListSize[2]);
234 } while (ListCount[2] < ListSize[2]);
235 FIXME(": need to write temporary data to instrument data\n");
239 TRACE_(dmfile)(": unknown (skipping)\n");
240 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
241 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
248 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
249 liMove.QuadPart = Chunk.dwSize;
250 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
254 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
255 } while (ListCount[1] < ListSize[1]);
259 TRACE_(dmfile)(": articulators list\n");
261 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
262 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
263 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
264 switch (Chunk.fccID) {
266 /* temporary structures */
267 CONNECTIONLIST tmpConnectionList;
268 LPCONNECTION tmpConnections;
270 TRACE_(dmfile)(": level 1 articulator chunk\n");
271 memset (&tmpConnectionList, 0, sizeof(CONNECTIONLIST)); /* reset */
272 tmpConnections = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(CONNECTION)*tmpConnectionList.cConnections);
273 if (Chunk.dwSize != (sizeof(CONNECTIONLIST) + sizeof(CONNECTION)*tmpConnectionList.cConnections)) ERR(": incorrect chunk size\n");
274 IStream_Read (pStm, &tmpConnectionList, sizeof(CONNECTIONLIST), NULL);
275 IStream_Read (pStm, tmpConnections, sizeof(CONNECTION)*tmpConnectionList.cConnections, NULL);
279 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
280 liMove.QuadPart = Chunk.dwSize;
281 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
285 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
286 } while (ListCount[1] < ListSize[1]);
289 case mmioFOURCC('I','N','F','O'): {
290 TRACE_(dmfile)(": INFO list\n");
292 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
293 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
294 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
295 switch (Chunk.fccID) {
296 case mmioFOURCC('I','N','A','M'): {
297 TRACE_(dmfile)(": name chunk (ignored)\n");
298 if (even_or_odd(Chunk.dwSize)) {
302 liMove.QuadPart = Chunk.dwSize;
303 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
306 case mmioFOURCC('I','A','R','T'): {
307 TRACE_(dmfile)(": artist 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','C','O','P'): {
317 /* temporary structures */
318 CHAR tmpCopyright[DMUS_MAX_NAME];
320 TRACE_(dmfile)(": copyright chunk\n");
321 IStream_Read (pStm, tmpCopyright, Chunk.dwSize, NULL);
322 if (even_or_odd(Chunk.dwSize)) {
325 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
329 case mmioFOURCC('I','S','B','J'): {
330 TRACE_(dmfile)(": subject chunk (ignored)\n");
331 if (even_or_odd(Chunk.dwSize)) {
335 liMove.QuadPart = Chunk.dwSize;
336 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
339 case mmioFOURCC('I','C','M','T'): {
340 TRACE_(dmfile)(": comment chunk (ignored)\n");
341 if (even_or_odd(Chunk.dwSize)) {
345 liMove.QuadPart = Chunk.dwSize;
346 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
350 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\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)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
361 } while (ListCount[1] < ListSize[1]);
366 TRACE_(dmfile)(": unknown (skipping)\n");
367 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
368 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
375 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
376 liMove.QuadPart = Chunk.dwSize;
377 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
381 TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]);
382 } while (ListCount[0] < ListSize[0]);
386 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
387 liMove.QuadPart = Chunk.dwSize;
388 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
395 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
396 liMove.QuadPart = Chunk.dwSize;
397 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
401 /* DEBUG: dumps whole instrument object tree: */
402 /* if (TRACE_ON(dmusic)) {
403 TRACE("*** IDirectMusicInstrument (%p) ***\n", This);
404 if (This->pInstrumentID)
405 TRACE(" - GUID = %s\n", debugstr_dmguid(This->pInstrumentID));
407 TRACE(" - Instrument header:\n");
408 TRACE(" - cRegions: %ld\n", This->pHeader->cRegions);
409 TRACE(" - Locale:\n");
410 TRACE(" - ulBank: %ld\n", This->pHeader->Locale.ulBank);
411 TRACE(" - ulInstrument: %ld\n", This->pHeader->Locale.ulInstrument);
412 TRACE(" => dwPatch: %ld\n", MIDILOCALE2Patch(&This->pHeader->Locale));