Get rid of the no longer used ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
[wine/multimedia.git] / dlls / dmusic / instrument.c
blob7bbe59a70d2fdc6a066a3596c38fabadeb2be9b4
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);
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 TRACE("(%p): AddRef from %ld\n", This, This->ref);
58 return ++(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);
65 if (ref == 0) {
66 HeapFree(GetProcessHeap(), 0, This);
68 return ref;
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);
97 return S_OK;
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);
104 return S_OK;
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) {
148 case FOURCC_LIST: {
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);
152 ListCount[0] = 0;
153 switch (Chunk.fccID) {
154 case FOURCC_INS: {
155 TRACE_(dmfile)(": instrument list\n");
156 do {
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) {
161 case FOURCC_INSH: {
162 TRACE_(dmfile)(": instrument header chunk\n");
163 /* should be already initialised */
164 IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL);
165 break;
167 case FOURCC_DLID: {
168 TRACE_(dmfile)(": DLID (GUID) chunk\n");
169 /* should be already initialised */
170 IStream_Read (pStm, This->pInstrumentID, Chunk.dwSize, NULL);
171 break;
173 case FOURCC_LIST: {
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);
177 ListCount[1] = 0;
178 switch (Chunk.fccID) {
179 case FOURCC_LRGN: {
180 TRACE_(dmfile)(": regions list\n");
181 do {
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) {
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[2] = Chunk.dwSize - sizeof(FOURCC);
190 ListCount[2] = 0;
191 switch (Chunk.fccID) {
192 case FOURCC_RGN: {
193 /* temporary structures */
194 RGNHEADER tmpRegionHeader;
195 WSMPL tmpWaveSample;
196 WLOOP tmpWaveLoop;
197 WAVELINK tmpWaveLink;
199 TRACE_(dmfile)(": region list\n");
200 do {
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) {
205 case FOURCC_RGNH: {
206 TRACE_(dmfile)(": region header chunk\n");
207 memset (&tmpRegionHeader, 0, sizeof(RGNHEADER)); /* reset */
208 IStream_Read (pStm, &tmpRegionHeader, Chunk.dwSize, NULL);
209 break;
211 case FOURCC_WSMP: {
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);
218 break;
220 case FOURCC_WLNK: {
221 TRACE_(dmfile)(": wave link chunk\n");
222 memset (&tmpWaveLink, 0, sizeof(WAVELINK)); /* reset */
223 IStream_Read (pStm, &tmpWaveLink, Chunk.dwSize, NULL);
224 break;
226 default: {
227 TRACE_(dmfile)(": unknown (skipping)\n");
228 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
229 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
230 break;
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");
236 break;
238 default: {
239 TRACE_(dmfile)(": unknown (skipping)\n");
240 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
241 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
242 break;
245 break;
247 default: {
248 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
249 liMove.QuadPart = Chunk.dwSize;
250 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
251 break;
254 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
255 } while (ListCount[1] < ListSize[1]);
256 break;
258 case FOURCC_LART: {
259 TRACE_(dmfile)(": articulators list\n");
260 do {
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) {
265 case FOURCC_ART1: {
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);
276 break;
278 default: {
279 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
280 liMove.QuadPart = Chunk.dwSize;
281 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
282 break;
285 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
286 } while (ListCount[1] < ListSize[1]);
287 break;
289 case mmioFOURCC('I','N','F','O'): {
290 TRACE_(dmfile)(": INFO list\n");
291 do {
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)) {
299 ListCount[1] ++;
300 Chunk.dwSize++;
302 liMove.QuadPart = Chunk.dwSize;
303 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
304 break;
306 case mmioFOURCC('I','A','R','T'): {
307 TRACE_(dmfile)(": artist 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','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)) {
323 ListCount[1] ++;
324 liMove.QuadPart = 1;
325 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
327 break;
329 case mmioFOURCC('I','S','B','J'): {
330 TRACE_(dmfile)(": subject chunk (ignored)\n");
331 if (even_or_odd(Chunk.dwSize)) {
332 ListCount[1] ++;
333 Chunk.dwSize++;
335 liMove.QuadPart = Chunk.dwSize;
336 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
337 break;
339 case mmioFOURCC('I','C','M','T'): {
340 TRACE_(dmfile)(": comment 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 default: {
350 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\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;
360 TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
361 } while (ListCount[1] < ListSize[1]);
362 break;
365 default: {
366 TRACE_(dmfile)(": unknown (skipping)\n");
367 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
368 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
369 break;
372 break;
374 default: {
375 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
376 liMove.QuadPart = Chunk.dwSize;
377 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
378 break;
381 TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]);
382 } while (ListCount[0] < ListSize[0]);
383 break;
385 default: {
386 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
387 liMove.QuadPart = Chunk.dwSize;
388 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
389 break;
392 break;
394 default: {
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 */
398 return E_FAIL;
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));
415 return S_OK;