1 /* IDirectMusicInstrument Implementation
3 * Copyright (C) 2003-2004 Rok Mandeljc
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (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 GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "dmusic_private.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
23 WINE_DECLARE_DEBUG_CHANNEL(dmfile);
25 static const GUID IID_IDirectMusicInstrumentPRIVATE = {0xbcb20080,0xa40c,0x11d1,{0x86,0xbc,0x00,0xc0,0x4f,0xbf,0x8f,0xef}};
27 static ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_AddRef (LPUNKNOWN iface);
28 static ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef (LPDIRECTMUSICINSTRUMENT iface);
30 /* IDirectMusicInstrument IUnknown part: */
31 static HRESULT WINAPI IDirectMusicInstrumentImpl_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, LPVOID *ppobj) {
32 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
33 TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
35 if (IsEqualIID (riid, &IID_IUnknown)) {
36 *ppobj = &This->UnknownVtbl;
37 IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
39 } else if (IsEqualIID (riid, &IID_IDirectMusicInstrument)) {
40 *ppobj = &This->InstrumentVtbl;
41 IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef ((LPDIRECTMUSICINSTRUMENT)&This->InstrumentVtbl);
43 } else if (IsEqualIID (riid, &IID_IDirectMusicInstrumentPRIVATE)) {
44 /* it seems to me that this interface is only basic IUnknown, without any
45 other inherited functions... *sigh* this is the worst scenario, since it means
46 that whoever calls it knows the layout of original implementation table and therefore
47 tries to get data by direct access... expect crashes */
48 FIXME("*sigh*... requested private/unspecified interface\n");
49 *ppobj = &This->UnknownVtbl;
50 IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
54 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj);
58 static ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_AddRef (LPUNKNOWN iface) {
59 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
60 ULONG refCount = InterlockedIncrement(&This->ref);
62 TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
69 static ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_Release (LPUNKNOWN iface) {
70 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
71 ULONG refCount = InterlockedDecrement(&This->ref);
73 TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
76 HeapFree(GetProcessHeap(), 0, This);
79 DMUSIC_UnlockModule();
84 static const IUnknownVtbl DirectMusicInstrument_Unknown_Vtbl = {
85 IDirectMusicInstrumentImpl_IUnknown_QueryInterface,
86 IDirectMusicInstrumentImpl_IUnknown_AddRef,
87 IDirectMusicInstrumentImpl_IUnknown_Release
90 /* IDirectMusicInstrumentImpl IDirectMusicInstrument part: */
91 static HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface (LPDIRECTMUSICINSTRUMENT iface, REFIID riid, LPVOID *ppobj) {
92 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
93 return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
96 static ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef (LPDIRECTMUSICINSTRUMENT iface) {
97 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
98 return IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
101 static ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release (LPDIRECTMUSICINSTRUMENT iface) {
102 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
103 return IDirectMusicInstrumentImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
106 static HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD* pdwPatch) {
107 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
108 TRACE("(%p, %p)\n", This, pdwPatch);
109 *pdwPatch = MIDILOCALE2Patch(&This->pHeader->Locale);
113 static HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD dwPatch) {
114 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
115 TRACE("(%p, %d): stub\n", This, dwPatch);
116 Patch2MIDILOCALE(dwPatch, &This->pHeader->Locale);
120 static const IDirectMusicInstrumentVtbl DirectMusicInstrument_Instrument_Vtbl = {
121 IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface,
122 IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef,
123 IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release,
124 IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch,
125 IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch
128 /* for ClassFactory */
129 HRESULT WINAPI DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
130 IDirectMusicInstrumentImpl* dminst;
132 dminst = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicInstrumentImpl));
133 if (NULL == dminst) {
135 return E_OUTOFMEMORY;
137 dminst->UnknownVtbl = &DirectMusicInstrument_Unknown_Vtbl;
138 dminst->InstrumentVtbl = &DirectMusicInstrument_Instrument_Vtbl;
139 dminst->ref = 0; /* will be inited by QueryInterface */
141 return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&dminst->UnknownVtbl, lpcGUID, ppobj);
144 /* aux. function that completely loads instrument; my tests indicate that it's
145 called somewhere around IDirectMusicCollection_GetInstrument */
146 HRESULT WINAPI IDirectMusicInstrumentImpl_Custom_Load (LPDIRECTMUSICINSTRUMENT iface, LPSTREAM pStm) {
147 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
149 DMUS_PRIVATE_CHUNK Chunk;
150 DWORD ListSize[4], ListCount[4];
151 LARGE_INTEGER liMove; /* used when skipping chunks */
153 TRACE("(%p, %p, offset = %s)\n", This, pStm, wine_dbgstr_longlong(This->liInstrumentPosition.QuadPart));
155 /* goto the beginning of chunk */
156 IStream_Seek (pStm, This->liInstrumentPosition, STREAM_SEEK_SET, NULL);
158 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
159 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
160 switch (Chunk.fccID) {
162 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
163 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
164 ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
166 switch (Chunk.fccID) {
168 TRACE_(dmfile)(": instrument list\n");
170 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
171 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
172 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
173 switch (Chunk.fccID) {
175 TRACE_(dmfile)(": instrument header chunk\n");
176 /* should be already initialised */
177 IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL);
181 TRACE_(dmfile)(": DLID (GUID) chunk\n");
182 /* should be already initialised */
183 IStream_Read (pStm, This->pInstrumentID, Chunk.dwSize, NULL);
187 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
188 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
189 ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
191 switch (Chunk.fccID) {
193 TRACE_(dmfile)(": regions list\n");
195 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
196 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
197 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
198 switch (Chunk.fccID) {
200 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
201 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
202 ListSize[2] = Chunk.dwSize - sizeof(FOURCC);
204 switch (Chunk.fccID) {
206 /* temporary structures */
207 RGNHEADER tmpRegionHeader;
210 WAVELINK tmpWaveLink;
212 TRACE_(dmfile)(": region list\n");
214 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
215 ListCount[2] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
216 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
217 switch (Chunk.fccID) {
219 TRACE_(dmfile)(": region header chunk\n");
220 memset (&tmpRegionHeader, 0, sizeof(RGNHEADER)); /* reset */
221 IStream_Read (pStm, &tmpRegionHeader, Chunk.dwSize, NULL);
225 TRACE_(dmfile)(": wave sample chunk\n");
226 memset (&tmpWaveSample, 0, sizeof(WSMPL)); /* reset */
227 memset (&tmpWaveLoop, 0, sizeof(WLOOP)); /* reset */
228 if (Chunk.dwSize != (sizeof(WSMPL) + sizeof(WLOOP))) ERR(": incorrect chunk size\n");
229 IStream_Read (pStm, &tmpWaveSample, sizeof(WSMPL), NULL);
230 IStream_Read (pStm, &tmpWaveLoop, sizeof(WLOOP), NULL);
234 TRACE_(dmfile)(": wave link chunk\n");
235 memset (&tmpWaveLink, 0, sizeof(WAVELINK)); /* reset */
236 IStream_Read (pStm, &tmpWaveLink, Chunk.dwSize, NULL);
240 TRACE_(dmfile)(": unknown (skipping)\n");
241 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
242 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
246 TRACE_(dmfile)(": ListCount[2] = %d < ListSize[2] = %d\n", ListCount[2], ListSize[2]);
247 } while (ListCount[2] < ListSize[2]);
248 FIXME(": need to write temporary data to instrument data\n");
252 TRACE_(dmfile)(": unknown (skipping)\n");
253 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
254 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
261 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
262 liMove.QuadPart = Chunk.dwSize;
263 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
267 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
268 } while (ListCount[1] < ListSize[1]);
272 TRACE_(dmfile)(": articulators list\n");
274 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
275 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
276 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
277 switch (Chunk.fccID) {
279 /* temporary structures */
280 CONNECTIONLIST tmpConnectionList;
281 LPCONNECTION tmpConnections;
283 TRACE_(dmfile)(": level 1 articulator chunk\n");
284 memset (&tmpConnectionList, 0, sizeof(CONNECTIONLIST)); /* reset */
285 tmpConnections = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(CONNECTION)*tmpConnectionList.cConnections);
286 if (Chunk.dwSize != (sizeof(CONNECTIONLIST) + sizeof(CONNECTION)*tmpConnectionList.cConnections)) ERR(": incorrect chunk size\n");
287 IStream_Read (pStm, &tmpConnectionList, sizeof(CONNECTIONLIST), NULL);
288 IStream_Read (pStm, tmpConnections, sizeof(CONNECTION)*tmpConnectionList.cConnections, NULL);
292 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
293 liMove.QuadPart = Chunk.dwSize;
294 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
298 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
299 } while (ListCount[1] < ListSize[1]);
302 case mmioFOURCC('I','N','F','O'): {
303 TRACE_(dmfile)(": INFO list\n");
305 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
306 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
307 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
308 switch (Chunk.fccID) {
309 case mmioFOURCC('I','N','A','M'): {
310 TRACE_(dmfile)(": name chunk (ignored)\n");
311 if (even_or_odd(Chunk.dwSize)) {
315 liMove.QuadPart = Chunk.dwSize;
316 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
319 case mmioFOURCC('I','A','R','T'): {
320 TRACE_(dmfile)(": artist chunk (ignored)\n");
321 if (even_or_odd(Chunk.dwSize)) {
325 liMove.QuadPart = Chunk.dwSize;
326 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
329 case mmioFOURCC('I','C','O','P'): {
330 /* temporary structures */
331 CHAR tmpCopyright[DMUS_MAX_NAME];
333 TRACE_(dmfile)(": copyright chunk\n");
334 IStream_Read (pStm, tmpCopyright, Chunk.dwSize, NULL);
335 if (even_or_odd(Chunk.dwSize)) {
338 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
342 case mmioFOURCC('I','S','B','J'): {
343 TRACE_(dmfile)(": subject chunk (ignored)\n");
344 if (even_or_odd(Chunk.dwSize)) {
348 liMove.QuadPart = Chunk.dwSize;
349 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
352 case mmioFOURCC('I','C','M','T'): {
353 TRACE_(dmfile)(": comment chunk (ignored)\n");
354 if (even_or_odd(Chunk.dwSize)) {
358 liMove.QuadPart = Chunk.dwSize;
359 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
363 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
364 if (even_or_odd(Chunk.dwSize)) {
368 liMove.QuadPart = Chunk.dwSize;
369 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
373 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
374 } while (ListCount[1] < ListSize[1]);
379 TRACE_(dmfile)(": unknown (skipping)\n");
380 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
381 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
388 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
389 liMove.QuadPart = Chunk.dwSize;
390 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
394 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
395 } while (ListCount[0] < ListSize[0]);
399 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
400 liMove.QuadPart = Chunk.dwSize;
401 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
408 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
409 liMove.QuadPart = Chunk.dwSize;
410 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
414 /* DEBUG: dumps whole instrument object tree: */
415 /* if (TRACE_ON(dmusic)) {
416 TRACE("*** IDirectMusicInstrument (%p) ***\n", This);
417 if (This->pInstrumentID)
418 TRACE(" - GUID = %s\n", debugstr_dmguid(This->pInstrumentID));
420 TRACE(" - Instrument header:\n");
421 TRACE(" - cRegions: %ld\n", This->pHeader->cRegions);
422 TRACE(" - Locale:\n");
423 TRACE(" - ulBank: %ld\n", This->pHeader->Locale.ulBank);
424 TRACE(" - ulInstrument: %ld\n", This->pHeader->Locale.ulInstrument);
425 TRACE(" => dwPatch: %ld\n", MIDILOCALE2Patch(&This->pHeader->Locale));