2 * IDirectMusicCollection Implementation
4 * Copyright (C) 2003-2004 Rok Mandeljc
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "dmusic_private.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(dmusic
);
25 struct instrument_entry
29 IDirectMusicInstrument
*instrument
;
38 C_ASSERT(sizeof(struct pool
) == offsetof(struct pool
, cues
[0]));
42 IDirectMusicCollection IDirectMusicCollection_iface
;
43 struct dmobject dmobj
;
48 struct list instruments
;
51 static inline struct collection
*impl_from_IDirectMusicCollection(IDirectMusicCollection
*iface
)
53 return CONTAINING_RECORD(iface
, struct collection
, IDirectMusicCollection_iface
);
56 static inline struct collection
*impl_from_IPersistStream(IPersistStream
*iface
)
58 return CONTAINING_RECORD(iface
, struct collection
, dmobj
.IPersistStream_iface
);
61 static HRESULT WINAPI
collection_QueryInterface(IDirectMusicCollection
*iface
,
62 REFIID riid
, void **ret_iface
)
64 struct collection
*This
= impl_from_IDirectMusicCollection(iface
);
66 TRACE("(%p, %s, %p)\n", iface
, debugstr_dmguid(riid
), ret_iface
);
70 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDirectMusicCollection
))
72 else if (IsEqualIID(riid
, &IID_IDirectMusicObject
))
73 *ret_iface
= &This
->dmobj
.IDirectMusicObject_iface
;
74 else if (IsEqualIID(riid
, &IID_IPersistStream
))
75 *ret_iface
= &This
->dmobj
.IPersistStream_iface
;
78 WARN("(%p, %s, %p): not found\n", iface
, debugstr_dmguid(riid
), ret_iface
);
82 IUnknown_AddRef((IUnknown
*)*ret_iface
);
86 static ULONG WINAPI
collection_AddRef(IDirectMusicCollection
*iface
)
88 struct collection
*This
= impl_from_IDirectMusicCollection(iface
);
89 ULONG ref
= InterlockedIncrement(&This
->ref
);
91 TRACE("(%p): new ref = %lu\n", iface
, ref
);
96 static ULONG WINAPI
collection_Release(IDirectMusicCollection
*iface
)
98 struct collection
*This
= impl_from_IDirectMusicCollection(iface
);
99 ULONG ref
= InterlockedDecrement(&This
->ref
);
101 TRACE("(%p): new ref = %lu\n", iface
, ref
);
105 struct instrument_entry
*instrument_entry
;
108 LIST_FOR_EACH_ENTRY_SAFE(instrument_entry
, next
, &This
->instruments
, struct instrument_entry
, entry
)
110 list_remove(&instrument_entry
->entry
);
111 IDirectMusicInstrument_Release(instrument_entry
->instrument
);
112 free(instrument_entry
);
121 static HRESULT WINAPI
collection_GetInstrument(IDirectMusicCollection
*iface
,
122 DWORD patch
, IDirectMusicInstrument
**instrument
)
124 struct collection
*This
= impl_from_IDirectMusicCollection(iface
);
125 struct instrument_entry
*entry
;
129 TRACE("(%p, %lu, %p)\n", iface
, patch
, instrument
);
131 LIST_FOR_EACH_ENTRY(entry
, &This
->instruments
, struct instrument_entry
, entry
)
133 if (FAILED(hr
= IDirectMusicInstrument_GetPatch(entry
->instrument
, &inst_patch
))) return hr
;
134 if (patch
== inst_patch
)
136 *instrument
= entry
->instrument
;
137 IDirectMusicInstrument_AddRef(entry
->instrument
);
138 TRACE(": returning instrument %p\n", entry
->instrument
);
143 TRACE(": instrument not found\n");
144 return DMUS_E_INVALIDPATCH
;
147 static HRESULT WINAPI
collection_EnumInstrument(IDirectMusicCollection
*iface
,
148 DWORD index
, DWORD
*patch
, LPWSTR name
, DWORD name_length
)
150 struct collection
*This
= impl_from_IDirectMusicCollection(iface
);
151 struct instrument_entry
*entry
;
154 TRACE("(%p, %ld, %p, %p, %ld)\n", iface
, index
, patch
, name
, name_length
);
156 LIST_FOR_EACH_ENTRY(entry
, &This
->instruments
, struct instrument_entry
, entry
)
158 if (index
--) continue;
159 if (FAILED(hr
= IDirectMusicInstrument_GetPatch(entry
->instrument
, patch
))) return hr
;
160 if (name
) lstrcpynW(name
, entry
->desc
.wszName
, name_length
);
167 static const IDirectMusicCollectionVtbl collection_vtbl
=
169 collection_QueryInterface
,
172 collection_GetInstrument
,
173 collection_EnumInstrument
,
176 static HRESULT
parse_lins_list(struct collection
*This
, IStream
*stream
, struct chunk_entry
*parent
)
178 struct chunk_entry chunk
= {.parent
= parent
};
179 struct instrument_entry
*entry
;
182 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
184 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
186 case MAKE_IDTYPE(FOURCC_LIST
, FOURCC_INS
):
187 if (!(entry
= malloc(sizeof(*entry
)))) return E_OUTOFMEMORY
;
188 hr
= instrument_create_from_chunk(stream
, &chunk
, &entry
->desc
, &entry
->instrument
);
189 if (SUCCEEDED(hr
)) list_add_tail(&This
->instruments
, &entry
->entry
);
194 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
198 if (FAILED(hr
)) break;
204 static HRESULT
parse_ptbl_chunk(struct collection
*This
, IStream
*stream
, struct chunk_entry
*chunk
)
211 if (chunk
->size
< sizeof(table
)) return E_INVALIDARG
;
212 if (FAILED(hr
= stream_read(stream
, &table
, sizeof(table
)))) return hr
;
213 if (chunk
->size
!= table
.cbSize
+ sizeof(POOLCUE
) * table
.cCues
) return E_INVALIDARG
;
214 if (table
.cbSize
!= sizeof(table
)) return E_INVALIDARG
;
216 size
= offsetof(struct pool
, cues
[table
.cCues
]);
217 if (!(pool
= malloc(size
))) return E_OUTOFMEMORY
;
220 size
= sizeof(POOLCUE
) * table
.cCues
;
221 if (FAILED(hr
= stream_read(stream
, pool
->cues
, size
))) free(pool
);
222 else This
->pool
= pool
;
227 static HRESULT
parse_dls_chunk(struct collection
*This
, IStream
*stream
, struct chunk_entry
*parent
)
229 struct chunk_entry chunk
= {.parent
= parent
};
232 if (FAILED(hr
= dmobj_parsedescriptor(stream
, parent
, &This
->dmobj
.desc
,
233 DMUS_OBJ_NAME_INFO
|DMUS_OBJ_VERSION
|DMUS_OBJ_OBJECT
|DMUS_OBJ_GUID_DLID
))
234 || FAILED(hr
= stream_reset_chunk_data(stream
, parent
)))
237 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
239 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
243 case MAKE_IDTYPE(FOURCC_LIST
, DMUS_FOURCC_INFO_LIST
):
244 /* already parsed by dmobj_parsedescriptor */
248 hr
= stream_chunk_get_data(stream
, &chunk
, &This
->header
, sizeof(This
->header
));
252 hr
= parse_ptbl_chunk(This
, stream
, &chunk
);
255 case MAKE_IDTYPE(FOURCC_LIST
, FOURCC_LINS
):
256 hr
= parse_lins_list(This
, stream
, &chunk
);
260 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
264 if (FAILED(hr
)) break;
270 static HRESULT WINAPI
collection_object_ParseDescriptor(IDirectMusicObject
*iface
,
271 IStream
*stream
, DMUS_OBJECTDESC
*desc
)
273 struct chunk_entry riff
= {0};
276 TRACE("(%p, %p, %p)\n", iface
, stream
, desc
);
278 if (!stream
|| !desc
)
281 if ((hr
= stream_get_chunk(stream
, &riff
)) != S_OK
)
283 if (riff
.id
!= FOURCC_RIFF
|| riff
.type
!= FOURCC_DLS
) {
284 TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff
));
285 stream_skip_chunk(stream
, &riff
);
286 return DMUS_E_NOTADLSCOL
;
289 hr
= dmobj_parsedescriptor(stream
, &riff
, desc
, DMUS_OBJ_NAME_INFO
|DMUS_OBJ_VERSION
);
293 desc
->guidClass
= CLSID_DirectMusicCollection
;
294 desc
->dwValidData
|= DMUS_OBJ_CLASS
;
296 TRACE("returning descriptor:\n");
297 dump_DMUS_OBJECTDESC(desc
);
301 static const IDirectMusicObjectVtbl collection_object_vtbl
=
303 dmobj_IDirectMusicObject_QueryInterface
,
304 dmobj_IDirectMusicObject_AddRef
,
305 dmobj_IDirectMusicObject_Release
,
306 dmobj_IDirectMusicObject_GetDescriptor
,
307 dmobj_IDirectMusicObject_SetDescriptor
,
308 collection_object_ParseDescriptor
,
311 static HRESULT WINAPI
collection_stream_Load(IPersistStream
*iface
, IStream
*stream
)
313 struct collection
*This
= impl_from_IPersistStream(iface
);
314 struct chunk_entry chunk
= {0};
317 TRACE("(%p, %p)\n", This
, stream
);
319 if ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
321 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
323 case MAKE_IDTYPE(FOURCC_RIFF
, FOURCC_DLS
):
324 hr
= parse_dls_chunk(This
, stream
, &chunk
);
328 WARN("Invalid collection chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
329 hr
= DMUS_E_UNSUPPORTED_STREAM
;
334 if (FAILED(hr
)) return hr
;
336 if (TRACE_ON(dmusic
))
338 struct instrument_entry
*entry
;
341 TRACE("*** IDirectMusicCollection (%p) ***\n", &This
->IDirectMusicCollection_iface
);
342 dump_DMUS_OBJECTDESC(&This
->dmobj
.desc
);
344 TRACE(" - Collection header:\n");
345 TRACE(" - cInstruments: %ld\n", This
->header
.cInstruments
);
346 TRACE(" - Instruments:\n");
348 LIST_FOR_EACH_ENTRY(entry
, &This
->instruments
, struct instrument_entry
, entry
)
349 TRACE(" - Instrument[%i]: %p\n", i
++, entry
->instrument
);
352 stream_skip_chunk(stream
, &chunk
);
356 static const IPersistStreamVtbl collection_stream_vtbl
=
358 dmobj_IPersistStream_QueryInterface
,
359 dmobj_IPersistStream_AddRef
,
360 dmobj_IPersistStream_Release
,
361 unimpl_IPersistStream_GetClassID
,
362 unimpl_IPersistStream_IsDirty
,
363 collection_stream_Load
,
364 unimpl_IPersistStream_Save
,
365 unimpl_IPersistStream_GetSizeMax
,
368 HRESULT
collection_create(IUnknown
**ret_iface
)
370 struct collection
*collection
;
373 if (!(collection
= calloc(1, sizeof(*collection
)))) return E_OUTOFMEMORY
;
374 collection
->IDirectMusicCollection_iface
.lpVtbl
= &collection_vtbl
;
376 dmobject_init(&collection
->dmobj
, &CLSID_DirectMusicCollection
,
377 (IUnknown
*)&collection
->IDirectMusicCollection_iface
);
378 collection
->dmobj
.IDirectMusicObject_iface
.lpVtbl
= &collection_object_vtbl
;
379 collection
->dmobj
.IPersistStream_iface
.lpVtbl
= &collection_stream_vtbl
;
380 list_init(&collection
->instruments
);
382 TRACE("Created DirectMusicCollection %p\n", collection
);
383 *ret_iface
= (IUnknown
*)&collection
->IDirectMusicCollection_iface
;