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);
64 ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_Release (LPUNKNOWN iface) {
65 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
66 ULONG refCount = InterlockedDecrement(&This->ref);
68 TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1);
71 HeapFree(GetProcessHeap(), 0, This);
76 IUnknownVtbl DirectMusicInstrument_Unknown_Vtbl = {
77 IDirectMusicInstrumentImpl_IUnknown_QueryInterface,
78 IDirectMusicInstrumentImpl_IUnknown_AddRef,
79 IDirectMusicInstrumentImpl_IUnknown_Release
82 /* IDirectMusicInstrumentImpl IDirectMusicInstrument part: */
83 HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface (LPDIRECTMUSICINSTRUMENT iface, REFIID riid, LPVOID *ppobj) {
84 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
85 return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
88 ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef (LPDIRECTMUSICINSTRUMENT iface) {
89 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
90 return IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
93 ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release (LPDIRECTMUSICINSTRUMENT iface) {
94 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
95 return IDirectMusicInstrumentImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
98 HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD* pdwPatch) {
99 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
100 TRACE("(%p, %p)\n", This, pdwPatch);
101 *pdwPatch = MIDILOCALE2Patch(&This->pHeader->Locale);
105 HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD dwPatch) {
106 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
107 TRACE("(%p, %ld): stub\n", This, dwPatch);
108 Patch2MIDILOCALE(dwPatch, &This->pHeader->Locale);
112 IDirectMusicInstrumentVtbl DirectMusicInstrument_Instrument_Vtbl = {
113 IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface,
114 IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef,
115 IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release,
116 IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch,
117 IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch
120 /* for ClassFactory */
121 HRESULT WINAPI DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
122 IDirectMusicInstrumentImpl* dminst;
124 dminst = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicInstrumentImpl));
125 if (NULL == dminst) {
127 return E_OUTOFMEMORY;
129 dminst->UnknownVtbl = &DirectMusicInstrument_Unknown_Vtbl;
130 dminst->InstrumentVtbl = &DirectMusicInstrument_Instrument_Vtbl;
131 dminst->ref = 0; /* will be inited by QueryInterface */
133 return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&dminst->UnknownVtbl, lpcGUID, ppobj);
136 /* aux. function that completely loads instrument; my tests indicate that it's
137 called somewhere around IDirectMusicCollection_GetInstrument */
138 HRESULT WINAPI IDirectMusicInstrumentImpl_Custom_Load (LPDIRECTMUSICINSTRUMENT iface, LPSTREAM pStm) {
139 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
141 DMUS_PRIVATE_CHUNK Chunk;
142 DWORD ListSize[4], ListCount[4];
143 LARGE_INTEGER liMove; /* used when skipping chunks */
145 TRACE("(%p, %p, offset = 0x%04llx)\n", This, pStm, This->liInstrumentPosition.QuadPart);
147 /* goto the beginning of chunk */
148 IStream_Seek (pStm, This->liInstrumentPosition, STREAM_SEEK_SET, NULL);
150 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
151 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
152 switch (Chunk.fccID) {
154 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
155 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
156 ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
158 switch (Chunk.fccID) {
160 TRACE_(dmfile)(": instrument list\n");
162 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
163 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
164 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
165 switch (Chunk.fccID) {
167 TRACE_(dmfile)(": instrument header chunk\n");
168 /* should be already initialised */
169 IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL);
173 TRACE_(dmfile)(": DLID (GUID) chunk\n");
174 /* should be already initialised */
175 IStream_Read (pStm, This->pInstrumentID, Chunk.dwSize, NULL);
179 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
180 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
181 ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
183 switch (Chunk.fccID) {
185 TRACE_(dmfile)(": regions list\n");
187 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
188 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
189 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
190 switch (Chunk.fccID) {
192 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
193 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
194 ListSize[2] = Chunk.dwSize - sizeof(FOURCC);
196 switch (Chunk.fccID) {
198 /* temporary structures */
199 RGNHEADER tmpRegionHeader;
202 WAVELINK tmpWaveLink;
204 TRACE_(dmfile)(": region list\n");
206 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
207 ListCount[2] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
208 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
209 switch (Chunk.fccID) {
211 TRACE_(dmfile)(": region header chunk\n");
212 memset (&tmpRegionHeader, 0, sizeof(RGNHEADER)); /* reset */
213 IStream_Read (pStm, &tmpRegionHeader, Chunk.dwSize, NULL);
217 TRACE_(dmfile)(": wave sample chunk\n");
218 memset (&tmpWaveSample, 0, sizeof(WSMPL)); /* reset */
219 memset (&tmpWaveLoop, 0, sizeof(WLOOP)); /* reset */
220 if (Chunk.dwSize != (sizeof(WSMPL) + sizeof(WLOOP))) ERR(": incorrect chunk size\n");
221 IStream_Read (pStm, &tmpWaveSample, sizeof(WSMPL), NULL);
222 IStream_Read (pStm, &tmpWaveLoop, sizeof(WLOOP), NULL);
226 TRACE_(dmfile)(": wave link chunk\n");
227 memset (&tmpWaveLink, 0, sizeof(WAVELINK)); /* reset */
228 IStream_Read (pStm, &tmpWaveLink, Chunk.dwSize, NULL);
232 TRACE_(dmfile)(": unknown (skipping)\n");
233 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
234 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
238 TRACE_(dmfile)(": ListCount[2] = %ld < ListSize[2] = %ld\n", ListCount[2], ListSize[2]);
239 } while (ListCount[2] < ListSize[2]);
240 FIXME(": need to write temporary data to instrument data\n");
244 TRACE_(dmfile)(": unknown (skipping)\n");
245 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
246 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
253 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
254 liMove.QuadPart = Chunk.dwSize;
255 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
259 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
260 } while (ListCount[1] < ListSize[1]);
264 TRACE_(dmfile)(": articulators list\n");
266 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
267 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
268 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
269 switch (Chunk.fccID) {
271 /* temporary structures */
272 CONNECTIONLIST tmpConnectionList;
273 LPCONNECTION tmpConnections;
275 TRACE_(dmfile)(": level 1 articulator chunk\n");
276 memset (&tmpConnectionList, 0, sizeof(CONNECTIONLIST)); /* reset */
277 tmpConnections = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(CONNECTION)*tmpConnectionList.cConnections);
278 if (Chunk.dwSize != (sizeof(CONNECTIONLIST) + sizeof(CONNECTION)*tmpConnectionList.cConnections)) ERR(": incorrect chunk size\n");
279 IStream_Read (pStm, &tmpConnectionList, sizeof(CONNECTIONLIST), NULL);
280 IStream_Read (pStm, tmpConnections, sizeof(CONNECTION)*tmpConnectionList.cConnections, NULL);
284 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
285 liMove.QuadPart = Chunk.dwSize;
286 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
290 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
291 } while (ListCount[1] < ListSize[1]);
294 case mmioFOURCC('I','N','F','O'): {
295 TRACE_(dmfile)(": INFO list\n");
297 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
298 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
299 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
300 switch (Chunk.fccID) {
301 case mmioFOURCC('I','N','A','M'): {
302 TRACE_(dmfile)(": name chunk (ignored)\n");
303 if (even_or_odd(Chunk.dwSize)) {
307 liMove.QuadPart = Chunk.dwSize;
308 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
311 case mmioFOURCC('I','A','R','T'): {
312 TRACE_(dmfile)(": artist chunk (ignored)\n");
313 if (even_or_odd(Chunk.dwSize)) {
317 liMove.QuadPart = Chunk.dwSize;
318 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
321 case mmioFOURCC('I','C','O','P'): {
322 /* temporary structures */
323 CHAR tmpCopyright[DMUS_MAX_NAME];
325 TRACE_(dmfile)(": copyright chunk\n");
326 IStream_Read (pStm, tmpCopyright, Chunk.dwSize, NULL);
327 if (even_or_odd(Chunk.dwSize)) {
330 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
334 case mmioFOURCC('I','S','B','J'): {
335 TRACE_(dmfile)(": subject chunk (ignored)\n");
336 if (even_or_odd(Chunk.dwSize)) {
340 liMove.QuadPart = Chunk.dwSize;
341 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
344 case mmioFOURCC('I','C','M','T'): {
345 TRACE_(dmfile)(": comment chunk (ignored)\n");
346 if (even_or_odd(Chunk.dwSize)) {
350 liMove.QuadPart = Chunk.dwSize;
351 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
355 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
356 if (even_or_odd(Chunk.dwSize)) {
360 liMove.QuadPart = Chunk.dwSize;
361 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
365 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
366 } while (ListCount[1] < ListSize[1]);
371 TRACE_(dmfile)(": unknown (skipping)\n");
372 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
373 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
380 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
381 liMove.QuadPart = Chunk.dwSize;
382 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
386 TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]);
387 } while (ListCount[0] < ListSize[0]);
391 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
392 liMove.QuadPart = Chunk.dwSize;
393 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
400 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
401 liMove.QuadPart = Chunk.dwSize;
402 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
406 /* DEBUG: dumps whole instrument object tree: */
407 /* if (TRACE_ON(dmusic)) {
408 TRACE("*** IDirectMusicInstrument (%p) ***\n", This);
409 if (This->pInstrumentID)
410 TRACE(" - GUID = %s\n", debugstr_dmguid(This->pInstrumentID));
412 TRACE(" - Instrument header:\n");
413 TRACE(" - cRegions: %ld\n", This->pHeader->cRegions);
414 TRACE(" - Locale:\n");
415 TRACE(" - ulBank: %ld\n", This->pHeader->Locale.ulBank);
416 TRACE(" - ulInstrument: %ld\n", This->pHeader->Locale.ulInstrument);
417 TRACE(" => dwPatch: %ld\n", MIDILOCALE2Patch(&This->pHeader->Locale));