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"
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
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
);
58 IDirectMusicBand IDirectMusicBand_iface
;
59 struct dmobject dmobj
;
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
,
72 struct band
*This
= impl_from_IDirectMusicBand(iface
);
74 TRACE("(%p, %s, %p)\n", This
, debugstr_dmguid(riid
), ret_iface
);
78 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDirectMusicBand
))
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
;
85 WARN("(%p, %s, %p): not found\n", This
, debugstr_dmguid(riid
), ret_iface
);
89 IDirectMusicBand_AddRef((IUnknown
*)*ret_iface
);
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
);
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
);
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
);
126 static HRESULT WINAPI
band_CreateSegment(IDirectMusicBand
*iface
,
127 IDirectMusicSegment
**segment
)
129 struct band
*This
= impl_from_IDirectMusicBand(iface
);
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
);
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
,
145 IDirectMusicBand_Release(bandparam
.pBand
);
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
);
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
);
166 static const IDirectMusicBandVtbl band_vtbl
=
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};
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;
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
);
206 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
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
);
223 static HRESULT
parse_lbil_list(struct band
*This
, IStream
*stream
, struct chunk_entry
*parent
)
225 struct chunk_entry chunk
= {.parent
= parent
};
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
);
237 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
241 if (FAILED(hr
)) break;
247 static HRESULT
parse_dmbd_chunk(struct band
*This
, IStream
*stream
, struct chunk_entry
*parent
)
249 struct chunk_entry chunk
= {.parent
= parent
};
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
)))
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 */
267 case MAKE_IDTYPE(FOURCC_LIST
, DMUS_FOURCC_INSTRUMENTS_LIST
):
268 hr
= parse_lbil_list(This
, stream
, &chunk
);
272 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
276 if (FAILED(hr
)) break;
282 static HRESULT WINAPI
band_object_ParseDescriptor(IDirectMusicObject
*iface
,
283 IStream
*stream
, DMUS_OBJECTDESC
*desc
)
285 struct chunk_entry riff
= {0};
289 TRACE("(%p, %p, %p)\n", iface
, stream
, desc
);
291 if (!stream
|| !desc
)
294 if ((hr
= stream_get_chunk(stream
, &riff
)) != S_OK
)
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
);
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
);
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};
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
);
353 WARN("Invalid band chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
354 hr
= DMUS_E_UNSUPPORTED_STREAM
;
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
);
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
)
398 if (!(obj
= calloc(1, sizeof(*obj
)))) return E_OUTOFMEMORY
;
399 obj
->IDirectMusicBand_iface
.lpVtbl
= &band_vtbl
;
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
);