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
;
49 IDirectMusicDownloadedInstrument
*download
;
50 IDirectMusicPort
*download_port
;
53 static HRESULT
instrument_entry_unload(struct instrument_entry
*entry
)
57 if (!entry
->download
) return S_OK
;
59 if (FAILED(hr
= IDirectMusicPort_UnloadInstrument(entry
->download_port
, entry
->download
)))
60 WARN("Failed to unload entry instrument, hr %#lx\n", hr
);
61 IDirectMusicDownloadedInstrument_Release(entry
->download
);
62 entry
->download
= NULL
;
63 IDirectMusicPort_Release(entry
->download_port
);
64 entry
->download_port
= NULL
;
69 static void instrument_entry_destroy(struct instrument_entry
*entry
)
71 instrument_entry_unload(entry
);
72 if (entry
->collection
) IDirectMusicCollection_Release(entry
->collection
);
78 IDirectMusicBand IDirectMusicBand_iface
;
79 struct dmobject dmobj
;
81 struct list instruments
;
82 IDirectMusicCollection
*collection
;
85 static inline struct band
*impl_from_IDirectMusicBand(IDirectMusicBand
*iface
)
87 return CONTAINING_RECORD(iface
, struct band
, IDirectMusicBand_iface
);
90 static HRESULT WINAPI
band_QueryInterface(IDirectMusicBand
*iface
, REFIID riid
,
93 struct band
*This
= impl_from_IDirectMusicBand(iface
);
95 TRACE("(%p, %s, %p)\n", This
, debugstr_dmguid(riid
), ret_iface
);
99 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDirectMusicBand
))
101 else if (IsEqualIID(riid
, &IID_IDirectMusicObject
))
102 *ret_iface
= &This
->dmobj
.IDirectMusicObject_iface
;
103 else if (IsEqualIID(riid
, &IID_IPersistStream
))
104 *ret_iface
= &This
->dmobj
.IPersistStream_iface
;
106 WARN("(%p, %s, %p): not found\n", This
, debugstr_dmguid(riid
), ret_iface
);
107 return E_NOINTERFACE
;
110 IDirectMusicBand_AddRef((IUnknown
*)*ret_iface
);
114 static ULONG WINAPI
band_AddRef(IDirectMusicBand
*iface
)
116 struct band
*This
= impl_from_IDirectMusicBand(iface
);
117 LONG ref
= InterlockedIncrement(&This
->ref
);
119 TRACE("(%p) ref=%ld\n", This
, ref
);
124 static ULONG WINAPI
band_Release(IDirectMusicBand
*iface
)
126 struct band
*This
= impl_from_IDirectMusicBand(iface
);
127 LONG ref
= InterlockedDecrement(&This
->ref
);
129 TRACE("(%p) ref=%ld\n", This
, ref
);
133 struct instrument_entry
*entry
, *next
;
135 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &This
->instruments
, struct instrument_entry
, entry
)
137 list_remove(&entry
->entry
);
138 instrument_entry_destroy(entry
);
141 if (This
->collection
) IDirectMusicCollection_Release(This
->collection
);
148 static HRESULT WINAPI
band_CreateSegment(IDirectMusicBand
*iface
,
149 IDirectMusicSegment
**segment
)
151 struct band
*This
= impl_from_IDirectMusicBand(iface
);
153 DMUS_BAND_PARAM bandparam
;
155 FIXME("(%p, %p): semi-stub\n", This
, segment
);
157 hr
= CoCreateInstance(&CLSID_DirectMusicSegment
, NULL
, CLSCTX_INPROC
,
158 &IID_IDirectMusicSegment
, (void**)segment
);
162 bandparam
.mtTimePhysical
= 0;
163 bandparam
.pBand
= &This
->IDirectMusicBand_iface
;
164 IDirectMusicBand_AddRef(bandparam
.pBand
);
165 hr
= IDirectMusicSegment_SetParam(*segment
, &GUID_BandParam
, 0xffffffff, DMUS_SEG_ALLTRACKS
,
167 IDirectMusicBand_Release(bandparam
.pBand
);
172 static HRESULT WINAPI
band_Download(IDirectMusicBand
*iface
,
173 IDirectMusicPerformance
*performance
)
175 struct band
*This
= impl_from_IDirectMusicBand(iface
);
176 struct instrument_entry
*entry
;
179 TRACE("(%p, %p)\n", This
, performance
);
181 LIST_FOR_EACH_ENTRY(entry
, &This
->instruments
, struct instrument_entry
, entry
)
183 IDirectMusicCollection
*collection
;
184 IDirectMusicInstrument
*instrument
;
186 if (FAILED(hr
= instrument_entry_unload(entry
))) break;
187 if (!(collection
= entry
->collection
) && !(collection
= This
->collection
)) continue;
189 if (SUCCEEDED(hr
= IDirectMusicCollection_GetInstrument(collection
, entry
->instrument
.dwPatch
, &instrument
)))
191 hr
= IDirectMusicPerformance_DownloadInstrument(performance
, instrument
, entry
->instrument
.dwPChannel
,
192 &entry
->download
, NULL
, 0, &entry
->download_port
, NULL
, NULL
);
193 IDirectMusicInstrument_Release(instrument
);
196 if (FAILED(hr
)) break;
199 if (FAILED(hr
)) WARN("Failed to download instruments, hr %#lx\n", hr
);
203 static HRESULT WINAPI
band_Unload(IDirectMusicBand
*iface
, IDirectMusicPerformance
*performance
)
205 struct band
*This
= impl_from_IDirectMusicBand(iface
);
206 struct instrument_entry
*entry
;
209 TRACE("(%p, %p)\n", This
, performance
);
211 if (performance
) FIXME("performance parameter not implemented\n");
213 LIST_FOR_EACH_ENTRY(entry
, &This
->instruments
, struct instrument_entry
, entry
)
214 if (FAILED(hr
= instrument_entry_unload(entry
))) break;
216 if (FAILED(hr
)) WARN("Failed to unload instruments, hr %#lx\n", hr
);
220 static const IDirectMusicBandVtbl band_vtbl
=
230 static HRESULT
parse_lbin_list(struct band
*This
, IStream
*stream
, struct chunk_entry
*parent
)
232 struct chunk_entry chunk
= {.parent
= parent
};
233 IDirectMusicCollection
*collection
= NULL
;
234 struct instrument_entry
*entry
;
235 DMUS_IO_INSTRUMENT inst
= {0};
238 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
240 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
242 case DMUS_FOURCC_INSTRUMENT_CHUNK
:
244 UINT size
= sizeof(inst
);
245 if (chunk
.size
== offsetof(DMUS_IO_INSTRUMENT
, nPitchBendRange
)) size
= chunk
.size
;
246 if (FAILED(hr
= stream_chunk_get_data(stream
, &chunk
, &inst
, size
))) break;
250 case MAKE_IDTYPE(FOURCC_LIST
, DMUS_FOURCC_REF_LIST
):
252 IDirectMusicObject
*object
;
253 if (FAILED(hr
= dmobj_parsereference(stream
, &chunk
, &object
))) break;
254 hr
= IDirectMusicObject_QueryInterface(object
, &IID_IDirectMusicCollection
, (void **)&collection
);
255 IDirectMusicObject_Release(object
);
260 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
264 if (FAILED(hr
)) break;
267 if (FAILED(hr
)) return hr
;
269 if (!(entry
= calloc(1, sizeof(*entry
)))) return E_OUTOFMEMORY
;
270 memcpy(&entry
->instrument
, &inst
, sizeof(DMUS_IO_INSTRUMENT
));
271 entry
->collection
= collection
;
272 list_add_tail(&This
->instruments
, &entry
->entry
);
277 static HRESULT
parse_lbil_list(struct band
*This
, IStream
*stream
, struct chunk_entry
*parent
)
279 struct chunk_entry chunk
= {.parent
= parent
};
282 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
284 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
286 case MAKE_IDTYPE(FOURCC_LIST
, DMUS_FOURCC_INSTRUMENT_LIST
):
287 hr
= parse_lbin_list(This
, stream
, &chunk
);
291 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
295 if (FAILED(hr
)) break;
301 static HRESULT
parse_dmbd_chunk(struct band
*This
, IStream
*stream
, struct chunk_entry
*parent
)
303 struct chunk_entry chunk
= {.parent
= parent
};
306 if (FAILED(hr
= dmobj_parsedescriptor(stream
, parent
, &This
->dmobj
.desc
,
307 DMUS_OBJ_OBJECT
|DMUS_OBJ_NAME
|DMUS_OBJ_NAME_INAM
|DMUS_OBJ_CATEGORY
|DMUS_OBJ_VERSION
))
308 || FAILED(hr
= stream_reset_chunk_data(stream
, parent
)))
311 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
313 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
315 case DMUS_FOURCC_GUID_CHUNK
:
316 case DMUS_FOURCC_VERSION_CHUNK
:
317 case MAKE_IDTYPE(FOURCC_LIST
, DMUS_FOURCC_UNFO_LIST
):
318 /* already parsed by dmobj_parsedescriptor */
321 case MAKE_IDTYPE(FOURCC_LIST
, DMUS_FOURCC_INSTRUMENTS_LIST
):
322 hr
= parse_lbil_list(This
, stream
, &chunk
);
326 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
330 if (FAILED(hr
)) break;
336 static HRESULT WINAPI
band_object_ParseDescriptor(IDirectMusicObject
*iface
,
337 IStream
*stream
, DMUS_OBJECTDESC
*desc
)
339 struct chunk_entry riff
= {0};
343 TRACE("(%p, %p, %p)\n", iface
, stream
, desc
);
345 if (!stream
|| !desc
)
348 if ((hr
= stream_get_chunk(stream
, &riff
)) != S_OK
)
350 if (riff
.id
!= FOURCC_RIFF
|| riff
.type
!= DMUS_FOURCC_BAND_FORM
) {
351 TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff
));
352 stream_skip_chunk(stream
, &riff
);
353 return DMUS_E_INVALID_BAND
;
356 hr
= dmobj_parsedescriptor(stream
, &riff
, desc
,
357 DMUS_OBJ_OBJECT
|DMUS_OBJ_NAME
|DMUS_OBJ_NAME_INAM
|DMUS_OBJ_CATEGORY
|DMUS_OBJ_VERSION
);
361 desc
->guidClass
= CLSID_DirectMusicBand
;
362 desc
->dwValidData
|= DMUS_OBJ_CLASS
;
364 if (desc
->dwValidData
& DMUS_OBJ_CATEGORY
) {
365 IStream_Stat(stream
, &stat
, STATFLAG_NONAME
);
366 desc
->ftDate
= stat
.mtime
;
367 desc
->dwValidData
|= DMUS_OBJ_DATE
;
370 TRACE("returning descriptor:\n");
371 dump_DMUS_OBJECTDESC(desc
);
375 static const IDirectMusicObjectVtbl band_object_vtbl
=
377 dmobj_IDirectMusicObject_QueryInterface
,
378 dmobj_IDirectMusicObject_AddRef
,
379 dmobj_IDirectMusicObject_Release
,
380 dmobj_IDirectMusicObject_GetDescriptor
,
381 dmobj_IDirectMusicObject_SetDescriptor
,
382 band_object_ParseDescriptor
,
385 static inline struct band
*impl_from_IPersistStream(IPersistStream
*iface
)
387 return CONTAINING_RECORD(iface
, struct band
, dmobj
.IPersistStream_iface
);
390 static HRESULT WINAPI
band_persist_stream_Load(IPersistStream
*iface
, IStream
*stream
)
392 struct band
*This
= impl_from_IPersistStream(iface
);
393 DMUS_OBJECTDESC default_desc
=
395 .dwSize
= sizeof(DMUS_OBJECTDESC
),
396 .dwValidData
= DMUS_OBJ_OBJECT
| DMUS_OBJ_CLASS
,
397 .guidClass
= CLSID_DirectMusicCollection
,
398 .guidObject
= GUID_DefaultGMCollection
,
400 struct chunk_entry chunk
= {0};
403 TRACE("%p, %p\n", iface
, stream
);
405 if (This
->collection
) IDirectMusicCollection_Release(This
->collection
);
406 if (FAILED(hr
= stream_get_object(stream
, &default_desc
, &IID_IDirectMusicCollection
,
407 (void **)&This
->collection
)))
408 WARN("Failed to load default collection from loader, hr %#lx\n", hr
);
410 if ((hr
= stream_get_chunk(stream
, &chunk
)) == S_OK
)
412 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
414 case MAKE_IDTYPE(FOURCC_RIFF
, DMUS_FOURCC_BAND_FORM
):
415 hr
= parse_dmbd_chunk(This
, stream
, &chunk
);
419 WARN("Invalid band chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
420 hr
= DMUS_E_UNSUPPORTED_STREAM
;
425 stream_skip_chunk(stream
, &chunk
);
426 if (FAILED(hr
)) return hr
;
428 if (TRACE_ON(dmband
))
430 struct instrument_entry
*entry
;
432 TRACE("Loaded IDirectMusicBand %p\n", This
);
433 dump_DMUS_OBJECTDESC(&This
->dmobj
.desc
);
435 TRACE(" - Instruments:\n");
436 LIST_FOR_EACH_ENTRY(entry
, &This
->instruments
, struct instrument_entry
, entry
)
438 dump_DMUS_IO_INSTRUMENT(&entry
->instrument
);
439 TRACE(" - collection: %p\n", entry
->collection
);
446 static const IPersistStreamVtbl band_persist_stream_vtbl
=
448 dmobj_IPersistStream_QueryInterface
,
449 dmobj_IPersistStream_AddRef
,
450 dmobj_IPersistStream_Release
,
451 unimpl_IPersistStream_GetClassID
,
452 unimpl_IPersistStream_IsDirty
,
453 band_persist_stream_Load
,
454 unimpl_IPersistStream_Save
,
455 unimpl_IPersistStream_GetSizeMax
,
458 HRESULT
create_dmband(REFIID lpcGUID
, void **ppobj
)
464 if (!(obj
= calloc(1, sizeof(*obj
)))) return E_OUTOFMEMORY
;
465 obj
->IDirectMusicBand_iface
.lpVtbl
= &band_vtbl
;
467 dmobject_init(&obj
->dmobj
, &CLSID_DirectMusicBand
, (IUnknown
*)&obj
->IDirectMusicBand_iface
);
468 obj
->dmobj
.IDirectMusicObject_iface
.lpVtbl
= &band_object_vtbl
;
469 obj
->dmobj
.IPersistStream_iface
.lpVtbl
= &band_persist_stream_vtbl
;
470 list_init(&obj
->instruments
);
472 hr
= IDirectMusicBand_QueryInterface(&obj
->IDirectMusicBand_iface
, lpcGUID
, ppobj
);
473 IDirectMusicBand_Release(&obj
->IDirectMusicBand_iface
);
478 HRESULT
band_connect_to_collection(IDirectMusicBand
*iface
, IDirectMusicCollection
*collection
)
480 struct band
*This
= impl_from_IDirectMusicBand(iface
);
482 TRACE("%p, %p\n", iface
, collection
);
484 if (This
->collection
) IDirectMusicCollection_Release(This
->collection
);
485 if ((This
->collection
= collection
)) IDirectMusicCollection_AddRef(This
->collection
);
490 HRESULT
band_send_messages(IDirectMusicBand
*iface
, IDirectMusicPerformance
*performance
,
491 IDirectMusicGraph
*graph
, MUSIC_TIME time
, DWORD track_id
)
493 struct band
*This
= impl_from_IDirectMusicBand(iface
);
494 struct instrument_entry
*entry
;
497 LIST_FOR_EACH_ENTRY_REV(entry
, &This
->instruments
, struct instrument_entry
, entry
)
499 DWORD patch
= entry
->instrument
.dwPatch
;
500 DMUS_PATCH_PMSG
*msg
;
502 if (FAILED(hr
= IDirectMusicPerformance_AllocPMsg(performance
, sizeof(*msg
),
503 (DMUS_PMSG
**)&msg
)))
507 msg
->dwFlags
= DMUS_PMSGF_MUSICTIME
;
508 msg
->dwPChannel
= entry
->instrument
.dwPChannel
;
509 msg
->dwVirtualTrackID
= track_id
;
510 msg
->dwType
= DMUS_PMSGT_PATCH
;
512 msg
->byInstrument
= entry
->instrument
.dwPatch
;
514 msg
->byInstrument
= patch
& 0x7F;
516 msg
->byLSB
= patch
& 0x7f;
518 msg
->byMSB
= patch
& 0x7f;
521 if (FAILED(hr
= IDirectMusicGraph_StampPMsg(graph
, (DMUS_PMSG
*)msg
))
522 || FAILED(hr
= IDirectMusicPerformance_SendPMsg(performance
, (DMUS_PMSG
*)msg
)))
524 IDirectMusicPerformance_FreePMsg(performance
, (DMUS_PMSG
*)msg
);