rpcrt4: Initialise pStubMsg->MemorySize to zero before calling ComplexStructMemorySiz...
[wine/multimedia.git] / dlls / dmusic / instrument.c
blob91465f1759fa89863b146ac8278e0548ab270dca
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., 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 /* 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);
35 return S_OK;
36 } else if (IsEqualIID (riid, &IID_IDirectMusicInstrument)) {
37 *ppobj = (LPVOID)&This->InstrumentVtbl;
38 IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef ((LPDIRECTMUSICINSTRUMENT)&This->InstrumentVtbl);
39 return S_OK;
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);
48 return S_OK;
51 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj);
52 return E_NOINTERFACE;
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);
61 DMUSIC_LockModule();
63 return refCount;
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);
72 if (!refCount) {
73 HeapFree(GetProcessHeap(), 0, This);
76 DMUSIC_UnlockModule();
78 return refCount;
81 static const 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);
107 return S_OK;
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);
114 return S_OK;
117 static const 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) {
131 *ppobj = NULL;
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) {
158 case FOURCC_LIST: {
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);
162 ListCount[0] = 0;
163 switch (Chunk.fccID) {
164 case FOURCC_INS: {
165 TRACE_(dmfile)(": instrument list\n");
166 do {
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) {
171 case FOURCC_INSH: {
172 TRACE_(dmfile)(": instrument header chunk\n");
173 /* should be already initialised */
174 IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL);
175 break;
177 case FOURCC_DLID: {
178 TRACE_(dmfile)(": DLID (GUID) chunk\n");
179 /* should be already initialised */
180 IStream_Read (pStm, This->pInstrumentID, Chunk.dwSize, NULL);
181 break;
183 case FOURCC_LIST: {
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);
187 ListCount[1] = 0;
188 switch (Chunk.fccID) {
189 case FOURCC_LRGN: {
190 TRACE_(dmfile)(": regions list\n");
191 do {
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) {
196 case FOURCC_LIST: {
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);
200 ListCount[2] = 0;
201 switch (Chunk.fccID) {
202 case FOURCC_RGN: {
203 /* temporary structures */
204 RGNHEADER tmpRegionHeader;
205 WSMPL tmpWaveSample;
206 WLOOP tmpWaveLoop;
207 WAVELINK tmpWaveLink;
209 TRACE_(dmfile)(": region list\n");
210 do {
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) {
215 case FOURCC_RGNH: {
216 TRACE_(dmfile)(": region header chunk\n");
217 memset (&tmpRegionHeader, 0, sizeof(RGNHEADER)); /* reset */
218 IStream_Read (pStm, &tmpRegionHeader, Chunk.dwSize, NULL);
219 break;
221 case FOURCC_WSMP: {
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);
228 break;
230 case FOURCC_WLNK: {
231 TRACE_(dmfile)(": wave link chunk\n");
232 memset (&tmpWaveLink, 0, sizeof(WAVELINK)); /* reset */
233 IStream_Read (pStm, &tmpWaveLink, Chunk.dwSize, NULL);
234 break;
236 default: {
237 TRACE_(dmfile)(": unknown (skipping)\n");
238 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
239 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
240 break;
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");
246 break;
248 default: {
249 TRACE_(dmfile)(": unknown (skipping)\n");
250 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
251 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
252 break;
255 break;
257 default: {
258 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
259 liMove.QuadPart = Chunk.dwSize;
260 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
261 break;
264 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
265 } while (ListCount[1] < ListSize[1]);
266 break;
268 case FOURCC_LART: {
269 TRACE_(dmfile)(": articulators list\n");
270 do {
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) {
275 case FOURCC_ART1: {
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);
286 break;
288 default: {
289 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
290 liMove.QuadPart = Chunk.dwSize;
291 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
292 break;
295 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
296 } while (ListCount[1] < ListSize[1]);
297 break;
299 case mmioFOURCC('I','N','F','O'): {
300 TRACE_(dmfile)(": INFO list\n");
301 do {
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)) {
309 ListCount[1] ++;
310 Chunk.dwSize++;
312 liMove.QuadPart = Chunk.dwSize;
313 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
314 break;
316 case mmioFOURCC('I','A','R','T'): {
317 TRACE_(dmfile)(": artist chunk (ignored)\n");
318 if (even_or_odd(Chunk.dwSize)) {
319 ListCount[1] ++;
320 Chunk.dwSize++;
322 liMove.QuadPart = Chunk.dwSize;
323 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
324 break;
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)) {
333 ListCount[1] ++;
334 liMove.QuadPart = 1;
335 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
337 break;
339 case mmioFOURCC('I','S','B','J'): {
340 TRACE_(dmfile)(": subject chunk (ignored)\n");
341 if (even_or_odd(Chunk.dwSize)) {
342 ListCount[1] ++;
343 Chunk.dwSize++;
345 liMove.QuadPart = Chunk.dwSize;
346 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
347 break;
349 case mmioFOURCC('I','C','M','T'): {
350 TRACE_(dmfile)(": comment chunk (ignored)\n");
351 if (even_or_odd(Chunk.dwSize)) {
352 ListCount[1] ++;
353 Chunk.dwSize++;
355 liMove.QuadPart = Chunk.dwSize;
356 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
357 break;
359 default: {
360 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
361 if (even_or_odd(Chunk.dwSize)) {
362 ListCount[1] ++;
363 Chunk.dwSize++;
365 liMove.QuadPart = Chunk.dwSize;
366 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
367 break;
370 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
371 } while (ListCount[1] < ListSize[1]);
372 break;
375 default: {
376 TRACE_(dmfile)(": unknown (skipping)\n");
377 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
378 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
379 break;
382 break;
384 default: {
385 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
386 liMove.QuadPart = Chunk.dwSize;
387 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
388 break;
391 TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]);
392 } while (ListCount[0] < ListSize[0]);
393 break;
395 default: {
396 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
397 liMove.QuadPart = Chunk.dwSize;
398 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
399 break;
402 break;
404 default: {
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 */
408 return E_FAIL;
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));
425 return S_OK;