kernel32: Move GlobalMemoryStatus(Ex) to a different debug channel.
[wine.git] / dlls / dmusic / instrument.c
blob1726b3b6ae60359e75039c13274b72d446813ff1
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);
24 static const GUID IID_IDirectMusicInstrumentPRIVATE = {0xbcb20080,0xa40c,0x11d1,{0x86,0xbc,0x00,0xc0,0x4f,0xbf,0x8f,0xef}};
26 static ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_AddRef (LPUNKNOWN iface);
27 static ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef (LPDIRECTMUSICINSTRUMENT iface);
29 /* IDirectMusicInstrument IUnknown part: */
30 static HRESULT WINAPI IDirectMusicInstrumentImpl_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, LPVOID *ppobj) {
31 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
32 TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
34 if (IsEqualIID (riid, &IID_IUnknown)) {
35 *ppobj = &This->UnknownVtbl;
36 IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
37 return S_OK;
38 } else if (IsEqualIID (riid, &IID_IDirectMusicInstrument)) {
39 *ppobj = &This->InstrumentVtbl;
40 IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef ((LPDIRECTMUSICINSTRUMENT)&This->InstrumentVtbl);
41 return S_OK;
42 } else if (IsEqualIID (riid, &IID_IDirectMusicInstrumentPRIVATE)) {
43 /* it seems to me that this interface is only basic IUnknown, without any
44 other inherited functions... *sigh* this is the worst scenario, since it means
45 that whoever calls it knows the layout of original implementation table and therefore
46 tries to get data by direct access... expect crashes */
47 FIXME("*sigh*... requested private/unspecified interface\n");
48 *ppobj = &This->UnknownVtbl;
49 IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
50 return S_OK;
53 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj);
54 return E_NOINTERFACE;
57 static ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_AddRef (LPUNKNOWN iface) {
58 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
59 ULONG refCount = InterlockedIncrement(&This->ref);
61 TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
63 DMUSIC_LockModule();
65 return refCount;
68 static ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_Release (LPUNKNOWN iface) {
69 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
70 ULONG refCount = InterlockedDecrement(&This->ref);
72 TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
74 if (!refCount) {
75 HeapFree(GetProcessHeap(), 0, This);
78 DMUSIC_UnlockModule();
80 return refCount;
83 static const IUnknownVtbl DirectMusicInstrument_Unknown_Vtbl = {
84 IDirectMusicInstrumentImpl_IUnknown_QueryInterface,
85 IDirectMusicInstrumentImpl_IUnknown_AddRef,
86 IDirectMusicInstrumentImpl_IUnknown_Release
89 /* IDirectMusicInstrumentImpl IDirectMusicInstrument part: */
90 static HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface (LPDIRECTMUSICINSTRUMENT iface, REFIID riid, LPVOID *ppobj) {
91 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
92 return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
95 static ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef (LPDIRECTMUSICINSTRUMENT iface) {
96 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
97 return IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
100 static ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release (LPDIRECTMUSICINSTRUMENT iface) {
101 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
102 return IDirectMusicInstrumentImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
105 static HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD* pdwPatch) {
106 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
107 TRACE("(%p, %p)\n", This, pdwPatch);
108 *pdwPatch = MIDILOCALE2Patch(&This->pHeader->Locale);
109 return S_OK;
112 static HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD dwPatch) {
113 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
114 TRACE("(%p, %d): stub\n", This, dwPatch);
115 Patch2MIDILOCALE(dwPatch, &This->pHeader->Locale);
116 return S_OK;
119 static const IDirectMusicInstrumentVtbl DirectMusicInstrument_Instrument_Vtbl = {
120 IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface,
121 IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef,
122 IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release,
123 IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch,
124 IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch
127 /* for ClassFactory */
128 HRESULT DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
129 IDirectMusicInstrumentImpl* dminst;
131 dminst = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicInstrumentImpl));
132 if (NULL == dminst) {
133 *ppobj = NULL;
134 return E_OUTOFMEMORY;
136 dminst->UnknownVtbl = &DirectMusicInstrument_Unknown_Vtbl;
137 dminst->InstrumentVtbl = &DirectMusicInstrument_Instrument_Vtbl;
138 dminst->ref = 0; /* will be inited by QueryInterface */
140 return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&dminst->UnknownVtbl, lpcGUID, ppobj);
143 static HRESULT read_from_stream(IStream *stream, void *data, ULONG size)
145 ULONG readed;
146 HRESULT hr;
148 hr = IStream_Read(stream, data, size, &readed);
149 if(FAILED(hr)){
150 TRACE("IStream_Read failed: %08x\n", hr);
151 return hr;
153 if(readed < size){
154 TRACE("Didn't read full chunk: %u < %u\n", readed, size);
155 return E_FAIL;
158 return S_OK;
161 static inline DWORD subtract_bytes(DWORD len, DWORD bytes)
163 if(bytes > len){
164 TRACE("Apparent mismatch in chunk lengths? %u bytes remaining, %u bytes read\n", len, bytes);
165 return 0;
167 return len - bytes;
170 static HRESULT load_instrument(IDirectMusicInstrumentImpl *This, IStream *stream, DWORD length)
172 HRESULT hr;
173 FOURCC fourcc;
174 DWORD bytes;
175 LARGE_INTEGER move;
177 while(length){
178 hr = read_from_stream(stream, &fourcc, sizeof(fourcc));
179 if(FAILED(hr))
180 return hr;
182 hr = read_from_stream(stream, &bytes, sizeof(bytes));
183 if(FAILED(hr))
184 return hr;
186 length = subtract_bytes(length, sizeof(fourcc) + sizeof(bytes));
188 switch(fourcc){
189 case FOURCC_INSH:
190 TRACE("INSH chunk: %u bytes\n", bytes);
191 hr = read_from_stream(stream, This->pHeader, sizeof(*This->pHeader));
192 if(FAILED(hr))
193 return hr;
195 move.QuadPart = bytes - sizeof(*This->pHeader);
196 hr = IStream_Seek(stream, move, STREAM_SEEK_CUR, NULL);
197 if(FAILED(hr)){
198 WARN("IStream_Seek failed: %08x\n", hr);
199 return hr;
202 length = subtract_bytes(length, bytes);
203 break;
205 case FOURCC_DLID:
206 TRACE("DLID chunk: %u bytes\n", bytes);
207 hr = read_from_stream(stream, This->pInstrumentID, sizeof(*This->pInstrumentID));
208 if(FAILED(hr))
209 return hr;
211 move.QuadPart = bytes - sizeof(*This->pInstrumentID);
212 hr = IStream_Seek(stream, move, STREAM_SEEK_CUR, NULL);
213 if(FAILED(hr)){
214 WARN("IStream_Seek failed: %08x\n", hr);
215 return hr;
218 length = subtract_bytes(length, bytes);
219 break;
221 default:
222 TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(fourcc), bytes);
224 move.QuadPart = bytes;
225 hr = IStream_Seek(stream, move, STREAM_SEEK_CUR, NULL);
226 if(FAILED(hr)){
227 WARN("IStream_Seek failed: %08x\n", hr);
228 return hr;
231 length = subtract_bytes(length, bytes);
232 break;
236 return S_OK;
239 /* aux. function that completely loads instrument; my tests indicate that it's
240 called somewhere around IDirectMusicCollection_GetInstrument */
241 HRESULT IDirectMusicInstrumentImpl_Custom_Load (LPDIRECTMUSICINSTRUMENT iface, LPSTREAM stream)
243 ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
244 LARGE_INTEGER move;
245 FOURCC fourcc;
246 DWORD bytes;
247 HRESULT hr;
249 TRACE("(%p, %p, offset = %s)\n", This, stream, wine_dbgstr_longlong(This->liInstrumentPosition.QuadPart));
251 hr = IStream_Seek(stream, This->liInstrumentPosition, STREAM_SEEK_SET, NULL);
252 if(FAILED(hr)){
253 WARN("IStream_Seek failed: %08x\n", hr);
254 goto load_failure;
257 hr = read_from_stream(stream, &fourcc, sizeof(fourcc));
258 if(FAILED(hr))
259 goto load_failure;
261 if(fourcc != FOURCC_LIST){
262 WARN("Loading failed: Expected LIST chunk, got: %s\n", debugstr_fourcc(fourcc));
263 goto load_failure;
266 hr = read_from_stream(stream, &bytes, sizeof(bytes));
267 if(FAILED(hr))
268 goto load_failure;
270 TRACE("LIST chunk: %u bytes\n", bytes);
271 while(1){
272 hr = read_from_stream(stream, &fourcc, sizeof(fourcc));
273 if(FAILED(hr))
274 goto load_failure;
276 switch(fourcc){
277 case FOURCC_INS:
278 TRACE("INS chunk: (no byte count)\n");
279 hr = load_instrument(This, stream, bytes - sizeof(FOURCC));
280 if(FAILED(hr))
281 goto load_failure;
282 break;
284 default:
285 hr = read_from_stream(stream, &bytes, sizeof(bytes));
286 if(FAILED(hr))
287 goto load_failure;
289 TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(fourcc), bytes);
291 move.QuadPart = bytes;
292 hr = IStream_Seek(stream, move, STREAM_SEEK_CUR, NULL);
293 if(FAILED(hr)){
294 WARN("IStream_Seek failed: %08x\n", hr);
295 return hr;
298 break;
302 return S_OK;
304 load_failure:
305 return DMUS_E_UNSUPPORTED_STREAM;