dmband: Rewrite band IPersistStream_Load.
[wine.git] / dlls / dmband / band.c
blobd91775681bb5294166dfc9f1745b92aeb320caf2
1 /* IDirectMusicBand 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 "dmband_private.h"
21 #include "dmobject.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(dmband);
25 void dump_DMUS_IO_INSTRUMENT(DMUS_IO_INSTRUMENT *inst)
27 TRACE("DMUS_IO_INSTRUMENT: %p\n", inst);
28 TRACE(" - dwPatch: %lu\n", inst->dwPatch);
29 TRACE(" - dwAssignPatch: %lu\n", inst->dwAssignPatch);
30 TRACE(" - dwNoteRanges[0]: %lu\n", inst->dwNoteRanges[0]);
31 TRACE(" - dwNoteRanges[1]: %lu\n", inst->dwNoteRanges[1]);
32 TRACE(" - dwNoteRanges[2]: %lu\n", inst->dwNoteRanges[2]);
33 TRACE(" - dwNoteRanges[3]: %lu\n", inst->dwNoteRanges[3]);
34 TRACE(" - dwPChannel: %lu\n", inst->dwPChannel);
35 TRACE(" - dwFlags: %lx\n", inst->dwFlags);
36 TRACE(" - bPan: %u\n", inst->bPan);
37 TRACE(" - bVolume: %u\n", inst->bVolume);
38 TRACE(" - nTranspose: %d\n", inst->nTranspose);
39 TRACE(" - dwChannelPriority: %lu\n", inst->dwChannelPriority);
40 TRACE(" - nPitchBendRange: %d\n", inst->nPitchBendRange);
43 struct instrument_entry
45 struct list entry;
46 DMUS_IO_INSTRUMENT instrument;
47 IDirectMusicCollection *collection;
50 static void instrument_entry_destroy(struct instrument_entry *entry)
52 if (entry->collection) IDirectMusicCollection_Release(entry->collection);
53 free(entry);
56 struct band
58 IDirectMusicBand IDirectMusicBand_iface;
59 struct dmobject dmobj;
60 LONG ref;
61 struct list instruments;
64 static inline struct band *impl_from_IDirectMusicBand(IDirectMusicBand *iface)
66 return CONTAINING_RECORD(iface, struct band, IDirectMusicBand_iface);
69 static HRESULT WINAPI band_QueryInterface(IDirectMusicBand *iface, REFIID riid,
70 void **ret_iface)
72 struct band *This = impl_from_IDirectMusicBand(iface);
74 TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface);
76 *ret_iface = NULL;
78 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicBand))
79 *ret_iface = iface;
80 else if (IsEqualIID(riid, &IID_IDirectMusicObject))
81 *ret_iface = &This->dmobj.IDirectMusicObject_iface;
82 else if (IsEqualIID(riid, &IID_IPersistStream))
83 *ret_iface = &This->dmobj.IPersistStream_iface;
84 else {
85 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface);
86 return E_NOINTERFACE;
89 IDirectMusicBand_AddRef((IUnknown*)*ret_iface);
90 return S_OK;
93 static ULONG WINAPI band_AddRef(IDirectMusicBand *iface)
95 struct band *This = impl_from_IDirectMusicBand(iface);
96 LONG ref = InterlockedIncrement(&This->ref);
98 TRACE("(%p) ref=%ld\n", This, ref);
100 return ref;
103 static ULONG WINAPI band_Release(IDirectMusicBand *iface)
105 struct band *This = impl_from_IDirectMusicBand(iface);
106 LONG ref = InterlockedDecrement(&This->ref);
108 TRACE("(%p) ref=%ld\n", This, ref);
110 if (!ref)
112 struct instrument_entry *entry, *next;
114 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &This->instruments, struct instrument_entry, entry)
116 list_remove(&entry->entry);
117 instrument_entry_destroy(entry);
120 free(This);
123 return ref;
126 static HRESULT WINAPI band_CreateSegment(IDirectMusicBand *iface,
127 IDirectMusicSegment **segment)
129 struct band *This = impl_from_IDirectMusicBand(iface);
130 HRESULT hr;
131 DMUS_BAND_PARAM bandparam;
133 FIXME("(%p, %p): semi-stub\n", This, segment);
135 hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC,
136 &IID_IDirectMusicSegment, (void**)segment);
137 if (FAILED(hr))
138 return hr;
140 bandparam.mtTimePhysical = 0;
141 bandparam.pBand = &This->IDirectMusicBand_iface;
142 IDirectMusicBand_AddRef(bandparam.pBand);
143 hr = IDirectMusicSegment_SetParam(*segment, &GUID_BandParam, 0xffffffff, DMUS_SEG_ALLTRACKS,
144 0, &bandparam);
145 IDirectMusicBand_Release(bandparam.pBand);
147 return hr;
150 static HRESULT WINAPI band_Download(IDirectMusicBand *iface,
151 IDirectMusicPerformance *pPerformance)
153 struct band *This = impl_from_IDirectMusicBand(iface);
154 FIXME("(%p, %p): stub\n", This, pPerformance);
155 return S_OK;
158 static HRESULT WINAPI band_Unload(IDirectMusicBand *iface,
159 IDirectMusicPerformance *pPerformance)
161 struct band *This = impl_from_IDirectMusicBand(iface);
162 FIXME("(%p, %p): stub\n", This, pPerformance);
163 return S_OK;
166 static const IDirectMusicBandVtbl band_vtbl =
168 band_QueryInterface,
169 band_AddRef,
170 band_Release,
171 band_CreateSegment,
172 band_Download,
173 band_Unload,
176 static HRESULT parse_lbin_list(struct band *This, IStream *stream, struct chunk_entry *parent)
178 struct chunk_entry chunk = {.parent = parent};
179 IDirectMusicCollection *collection = NULL;
180 struct instrument_entry *entry;
181 DMUS_IO_INSTRUMENT inst = {0};
182 HRESULT hr;
184 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
186 switch (MAKE_IDTYPE(chunk.id, chunk.type))
188 case DMUS_FOURCC_INSTRUMENT_CHUNK:
190 UINT size = sizeof(inst);
191 if (chunk.size == offsetof(DMUS_IO_INSTRUMENT, nPitchBendRange)) size = chunk.size;
192 if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &inst, size))) break;
193 break;
196 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_REF_LIST):
198 IDirectMusicObject *object;
199 if (FAILED(hr = dmobj_parsereference(stream, &chunk, &object))) break;
200 hr = IDirectMusicObject_QueryInterface(object, &IID_IDirectMusicCollection, (void **)&collection);
201 IDirectMusicObject_Release(object);
202 break;
205 default:
206 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
207 break;
210 if (FAILED(hr)) break;
213 if (FAILED(hr)) return hr;
215 if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY;
216 memcpy(&entry->instrument, &inst, sizeof(DMUS_IO_INSTRUMENT));
217 entry->collection = collection;
218 list_add_tail(&This->instruments, &entry->entry);
220 return hr;
223 static HRESULT parse_lbil_list(struct band *This, IStream *stream, struct chunk_entry *parent)
225 struct chunk_entry chunk = {.parent = parent};
226 HRESULT hr;
228 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
230 switch (MAKE_IDTYPE(chunk.id, chunk.type))
232 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_INSTRUMENT_LIST):
233 hr = parse_lbin_list(This, stream, &chunk);
234 break;
236 default:
237 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
238 break;
241 if (FAILED(hr)) break;
244 return hr;
247 static HRESULT parse_dmbd_chunk(struct band *This, IStream *stream, struct chunk_entry *parent)
249 struct chunk_entry chunk = {.parent = parent};
250 HRESULT hr;
252 if (FAILED(hr = dmobj_parsedescriptor(stream, parent, &This->dmobj.desc,
253 DMUS_OBJ_OBJECT|DMUS_OBJ_NAME|DMUS_OBJ_NAME_INAM|DMUS_OBJ_CATEGORY|DMUS_OBJ_VERSION))
254 || FAILED(hr = stream_reset_chunk_data(stream, parent)))
255 return hr;
257 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
259 switch (MAKE_IDTYPE(chunk.id, chunk.type))
261 case DMUS_FOURCC_GUID_CHUNK:
262 case DMUS_FOURCC_VERSION_CHUNK:
263 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_UNFO_LIST):
264 /* already parsed by dmobj_parsedescriptor */
265 break;
267 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_INSTRUMENTS_LIST):
268 hr = parse_lbil_list(This, stream, &chunk);
269 break;
271 default:
272 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
273 break;
276 if (FAILED(hr)) break;
279 return hr;
282 static HRESULT WINAPI band_object_ParseDescriptor(IDirectMusicObject *iface,
283 IStream *stream, DMUS_OBJECTDESC *desc)
285 struct chunk_entry riff = {0};
286 STATSTG stat;
287 HRESULT hr;
289 TRACE("(%p, %p, %p)\n", iface, stream, desc);
291 if (!stream || !desc)
292 return E_POINTER;
294 if ((hr = stream_get_chunk(stream, &riff)) != S_OK)
295 return hr;
296 if (riff.id != FOURCC_RIFF || riff.type != DMUS_FOURCC_BAND_FORM) {
297 TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff));
298 stream_skip_chunk(stream, &riff);
299 return DMUS_E_INVALID_BAND;
302 hr = dmobj_parsedescriptor(stream, &riff, desc,
303 DMUS_OBJ_OBJECT|DMUS_OBJ_NAME|DMUS_OBJ_NAME_INAM|DMUS_OBJ_CATEGORY|DMUS_OBJ_VERSION);
304 if (FAILED(hr))
305 return hr;
307 desc->guidClass = CLSID_DirectMusicBand;
308 desc->dwValidData |= DMUS_OBJ_CLASS;
310 if (desc->dwValidData & DMUS_OBJ_CATEGORY) {
311 IStream_Stat(stream, &stat, STATFLAG_NONAME);
312 desc->ftDate = stat.mtime;
313 desc->dwValidData |= DMUS_OBJ_DATE;
316 TRACE("returning descriptor:\n");
317 dump_DMUS_OBJECTDESC(desc);
318 return S_OK;
321 static const IDirectMusicObjectVtbl band_object_vtbl =
323 dmobj_IDirectMusicObject_QueryInterface,
324 dmobj_IDirectMusicObject_AddRef,
325 dmobj_IDirectMusicObject_Release,
326 dmobj_IDirectMusicObject_GetDescriptor,
327 dmobj_IDirectMusicObject_SetDescriptor,
328 band_object_ParseDescriptor,
331 static inline struct band *impl_from_IPersistStream(IPersistStream *iface)
333 return CONTAINING_RECORD(iface, struct band, dmobj.IPersistStream_iface);
336 static HRESULT WINAPI band_persist_stream_Load(IPersistStream *iface, IStream *stream)
338 struct band *This = impl_from_IPersistStream(iface);
339 struct chunk_entry chunk = {0};
340 HRESULT hr;
342 TRACE("%p, %p\n", iface, stream);
344 if ((hr = stream_get_chunk(stream, &chunk)) == S_OK)
346 switch (MAKE_IDTYPE(chunk.id, chunk.type))
348 case MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_BAND_FORM):
349 hr = parse_dmbd_chunk(This, stream, &chunk);
350 break;
352 default:
353 WARN("Invalid band chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
354 hr = DMUS_E_UNSUPPORTED_STREAM;
355 break;
359 if (FAILED(hr)) return hr;
361 if (TRACE_ON(dmband))
363 struct instrument_entry *entry;
365 TRACE("Loaded IDirectMusicBand %p\n", This);
366 dump_DMUS_OBJECTDESC(&This->dmobj.desc);
368 TRACE(" - Instruments:\n");
369 LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry)
371 dump_DMUS_IO_INSTRUMENT(&entry->instrument);
372 TRACE(" - collection: %p\n", entry->collection);
376 stream_skip_chunk(stream, &chunk);
377 return S_OK;
380 static const IPersistStreamVtbl band_persist_stream_vtbl =
382 dmobj_IPersistStream_QueryInterface,
383 dmobj_IPersistStream_AddRef,
384 dmobj_IPersistStream_Release,
385 unimpl_IPersistStream_GetClassID,
386 unimpl_IPersistStream_IsDirty,
387 band_persist_stream_Load,
388 unimpl_IPersistStream_Save,
389 unimpl_IPersistStream_GetSizeMax,
392 HRESULT create_dmband(REFIID lpcGUID, void **ppobj)
394 struct band* obj;
395 HRESULT hr;
397 *ppobj = NULL;
398 if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY;
399 obj->IDirectMusicBand_iface.lpVtbl = &band_vtbl;
400 obj->ref = 1;
401 dmobject_init(&obj->dmobj, &CLSID_DirectMusicBand, (IUnknown *)&obj->IDirectMusicBand_iface);
402 obj->dmobj.IDirectMusicObject_iface.lpVtbl = &band_object_vtbl;
403 obj->dmobj.IPersistStream_iface.lpVtbl = &band_persist_stream_vtbl;
404 list_init(&obj->instruments);
406 hr = IDirectMusicBand_QueryInterface(&obj->IDirectMusicBand_iface, lpcGUID, ppobj);
407 IDirectMusicBand_Release(&obj->IDirectMusicBand_iface);
409 return hr;