msxml3: Use a helper to get property values.
[wine/multimedia.git] / dlls / dmusic / instrument.c
blob8adfb999328e1eca6a8d371715e3e86ac5b21162
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);
38 return S_OK;
39 } else if (IsEqualIID (riid, &IID_IDirectMusicInstrument)) {
40 *ppobj = &This->InstrumentVtbl;
41 IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef ((LPDIRECTMUSICINSTRUMENT)&This->InstrumentVtbl);
42 return S_OK;
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);
51 return S_OK;
54 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj);
55 return E_NOINTERFACE;
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);
64 DMUSIC_LockModule();
66 return refCount;
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);
75 if (!refCount) {
76 HeapFree(GetProcessHeap(), 0, This);
79 DMUSIC_UnlockModule();
81 return refCount;
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);
110 return S_OK;
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);
117 return S_OK;
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) {
134 *ppobj = NULL;
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) {
161 case FOURCC_LIST: {
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);
165 ListCount[0] = 0;
166 switch (Chunk.fccID) {
167 case FOURCC_INS: {
168 TRACE_(dmfile)(": instrument list\n");
169 do {
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) {
174 case FOURCC_INSH: {
175 TRACE_(dmfile)(": instrument header chunk\n");
176 /* should be already initialised */
177 IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL);
178 break;
180 case FOURCC_DLID: {
181 TRACE_(dmfile)(": DLID (GUID) chunk\n");
182 /* should be already initialised */
183 IStream_Read (pStm, This->pInstrumentID, Chunk.dwSize, NULL);
184 break;
186 case FOURCC_LIST: {
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);
190 ListCount[1] = 0;
191 switch (Chunk.fccID) {
192 case FOURCC_LRGN: {
193 TRACE_(dmfile)(": regions list\n");
194 do {
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) {
199 case FOURCC_LIST: {
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);
203 ListCount[2] = 0;
204 switch (Chunk.fccID) {
205 case FOURCC_RGN: {
206 /* temporary structures */
207 RGNHEADER tmpRegionHeader;
208 WSMPL tmpWaveSample;
209 WLOOP tmpWaveLoop;
210 WAVELINK tmpWaveLink;
212 TRACE_(dmfile)(": region list\n");
213 do {
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) {
218 case FOURCC_RGNH: {
219 TRACE_(dmfile)(": region header chunk\n");
220 memset (&tmpRegionHeader, 0, sizeof(RGNHEADER)); /* reset */
221 IStream_Read (pStm, &tmpRegionHeader, Chunk.dwSize, NULL);
222 break;
224 case FOURCC_WSMP: {
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);
231 break;
233 case FOURCC_WLNK: {
234 TRACE_(dmfile)(": wave link chunk\n");
235 memset (&tmpWaveLink, 0, sizeof(WAVELINK)); /* reset */
236 IStream_Read (pStm, &tmpWaveLink, Chunk.dwSize, NULL);
237 break;
239 default: {
240 TRACE_(dmfile)(": unknown (skipping)\n");
241 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
242 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
243 break;
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");
249 break;
251 default: {
252 TRACE_(dmfile)(": unknown (skipping)\n");
253 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
254 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
255 break;
258 break;
260 default: {
261 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
262 liMove.QuadPart = Chunk.dwSize;
263 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
264 break;
267 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
268 } while (ListCount[1] < ListSize[1]);
269 break;
271 case FOURCC_LART: {
272 TRACE_(dmfile)(": articulators list\n");
273 do {
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) {
278 case FOURCC_ART1: {
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);
289 break;
291 default: {
292 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
293 liMove.QuadPart = Chunk.dwSize;
294 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
295 break;
298 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
299 } while (ListCount[1] < ListSize[1]);
300 break;
302 case mmioFOURCC('I','N','F','O'): {
303 TRACE_(dmfile)(": INFO list\n");
304 do {
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)) {
312 ListCount[1] ++;
313 Chunk.dwSize++;
315 liMove.QuadPart = Chunk.dwSize;
316 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
317 break;
319 case mmioFOURCC('I','A','R','T'): {
320 TRACE_(dmfile)(": artist chunk (ignored)\n");
321 if (even_or_odd(Chunk.dwSize)) {
322 ListCount[1] ++;
323 Chunk.dwSize++;
325 liMove.QuadPart = Chunk.dwSize;
326 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
327 break;
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)) {
336 ListCount[1] ++;
337 liMove.QuadPart = 1;
338 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
340 break;
342 case mmioFOURCC('I','S','B','J'): {
343 TRACE_(dmfile)(": subject chunk (ignored)\n");
344 if (even_or_odd(Chunk.dwSize)) {
345 ListCount[1] ++;
346 Chunk.dwSize++;
348 liMove.QuadPart = Chunk.dwSize;
349 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
350 break;
352 case mmioFOURCC('I','C','M','T'): {
353 TRACE_(dmfile)(": comment chunk (ignored)\n");
354 if (even_or_odd(Chunk.dwSize)) {
355 ListCount[1] ++;
356 Chunk.dwSize++;
358 liMove.QuadPart = Chunk.dwSize;
359 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
360 break;
362 default: {
363 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
364 if (even_or_odd(Chunk.dwSize)) {
365 ListCount[1] ++;
366 Chunk.dwSize++;
368 liMove.QuadPart = Chunk.dwSize;
369 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
370 break;
373 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
374 } while (ListCount[1] < ListSize[1]);
375 break;
378 default: {
379 TRACE_(dmfile)(": unknown (skipping)\n");
380 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
381 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
382 break;
385 break;
387 default: {
388 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
389 liMove.QuadPart = Chunk.dwSize;
390 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
391 break;
394 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
395 } while (ListCount[0] < ListSize[0]);
396 break;
398 default: {
399 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
400 liMove.QuadPart = Chunk.dwSize;
401 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
402 break;
405 break;
407 default: {
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 */
411 return E_FAIL;
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));
428 return S_OK;