dmband: Implement band track GUID_UnloadFromAudioPath parameter.
[wine.git] / dlls / dmband / bandtrack.c
blobb808faaf567784d7f10456a6039b66f0bf59a708
1 /*
2 * Copyright (C) 2003-2004 Rok Mandeljc
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "dmband_private.h"
20 #include "dmobject.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(dmband);
24 struct band_entry
26 struct list entry;
27 DMUS_IO_BAND_ITEM_HEADER2 head;
28 IDirectMusicBand *band;
31 static void band_entry_destroy(struct band_entry *entry)
33 IDirectMusicTrack_Release(entry->band);
34 free(entry);
37 struct band_track
39 IDirectMusicTrack8 IDirectMusicTrack8_iface;
40 struct dmobject dmobj; /* IPersistStream only */
41 LONG ref;
42 DMUS_IO_BAND_TRACK_HEADER header;
43 struct list bands;
46 static inline struct band_track *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface)
48 return CONTAINING_RECORD(iface, struct band_track, IDirectMusicTrack8_iface);
51 static HRESULT WINAPI band_track_QueryInterface(IDirectMusicTrack8 *iface, REFIID riid,
52 void **ret_iface)
54 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
56 TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface);
58 *ret_iface = NULL;
60 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicTrack) ||
61 IsEqualIID(riid, &IID_IDirectMusicTrack8))
62 *ret_iface = iface;
63 else if (IsEqualIID(riid, &IID_IPersistStream))
64 *ret_iface = &This->dmobj.IPersistStream_iface;
65 else {
66 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface);
67 return E_NOINTERFACE;
70 IUnknown_AddRef((IUnknown*)*ret_iface);
71 return S_OK;
74 static ULONG WINAPI band_track_AddRef(IDirectMusicTrack8 *iface)
76 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
77 LONG ref = InterlockedIncrement(&This->ref);
79 TRACE("(%p) ref=%ld\n", This, ref);
81 return ref;
84 static ULONG WINAPI band_track_Release(IDirectMusicTrack8 *iface)
86 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
87 LONG ref = InterlockedDecrement(&This->ref);
89 TRACE("(%p) ref=%ld\n", This, ref);
91 if (!ref)
93 struct band_entry *entry, *next;
95 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &This->bands, struct band_entry, entry)
97 list_remove(&entry->entry);
98 band_entry_destroy(entry);
101 free(This);
104 return ref;
107 static HRESULT WINAPI band_track_Init(IDirectMusicTrack8 *iface, IDirectMusicSegment *pSegment)
109 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
110 FIXME("(%p, %p): stub\n", This, pSegment);
111 return S_OK;
114 static HRESULT WINAPI band_track_InitPlay(IDirectMusicTrack8 *iface,
115 IDirectMusicSegmentState *segment_state, IDirectMusicPerformance *performance,
116 void **state_data, DWORD virtual_track8id, DWORD flags)
118 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
120 FIXME("(%p, %p, %p, %p, %ld, %lx): stub\n", This, segment_state, performance, state_data, virtual_track8id, flags);
122 return S_OK;
125 static HRESULT WINAPI band_track_EndPlay(IDirectMusicTrack8 *iface, void *pStateData)
127 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
128 FIXME("(%p, %p): stub\n", This, pStateData);
129 return S_OK;
132 static HRESULT WINAPI band_track_Play(IDirectMusicTrack8 *iface, void *state_data,
133 MUSIC_TIME mtStart, MUSIC_TIME mtEnd, MUSIC_TIME mtOffset, DWORD flags,
134 IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state,
135 DWORD virtual_id)
137 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
139 FIXME("(%p, %p, %ld, %ld, %ld, %lx, %p, %p, %ld): semi-stub\n", This, state_data, mtStart, mtEnd, mtOffset, flags, performance, segment_state, virtual_id);
141 /* Sends following pMSG:
142 - DMUS_PATCH_PMSG
143 - DMUS_TRANSPOSE_PMSG
144 - DMUS_CHANNEL_PRIORITY_PMSG
145 - DMUS_MIDI_PMSG
148 return S_OK;
151 static HRESULT WINAPI band_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
152 MUSIC_TIME *next, void *param)
154 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
156 TRACE("(%p, %s, %ld, %p, %p)\n", This, debugstr_dmguid(type), time, next, param);
158 if (!type)
159 return E_POINTER;
160 if (!IsEqualGUID(type, &GUID_BandParam))
161 return DMUS_E_GET_UNSUPPORTED;
163 FIXME("GUID_BandParam not handled yet\n");
165 return S_OK;
168 static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
169 void *param)
171 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
173 TRACE("(%p, %s, %ld, %p)\n", This, debugstr_dmguid(type), time, param);
175 if (!type)
176 return E_POINTER;
177 if (FAILED(IDirectMusicTrack8_IsParamSupported(iface, type)))
178 return DMUS_E_TYPE_UNSUPPORTED;
180 if (IsEqualGUID(type, &GUID_BandParam))
181 FIXME("GUID_BandParam not handled yet\n");
182 else if (IsEqualGUID(type, &GUID_Clear_All_Bands))
183 FIXME("GUID_Clear_All_Bands not handled yet\n");
184 else if (IsEqualGUID(type, &GUID_ConnectToDLSCollection))
186 struct band_entry *entry;
188 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
189 band_connect_to_collection(entry->band, param);
191 else if (IsEqualGUID(type, &GUID_Disable_Auto_Download))
192 FIXME("GUID_Disable_Auto_Download not handled yet\n");
193 else if (IsEqualGUID(type, &GUID_Download))
194 FIXME("GUID_Download not handled yet\n");
195 else if (IsEqualGUID(type, &GUID_DownloadToAudioPath))
196 FIXME("GUID_DownloadToAudioPath not handled yet\n");
197 else if (IsEqualGUID(type, &GUID_Enable_Auto_Download))
198 FIXME("GUID_Enable_Auto_Download not handled yet\n");
199 else if (IsEqualGUID(type, &GUID_IDirectMusicBand))
200 FIXME("GUID_IDirectMusicBand not handled yet\n");
201 else if (IsEqualGUID(type, &GUID_StandardMIDIFile))
202 FIXME("GUID_StandardMIDIFile not handled yet\n");
203 else if (IsEqualGUID(type, &GUID_UnloadFromAudioPath))
205 struct band_entry *entry;
206 HRESULT hr;
208 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
209 if (FAILED(hr = IDirectMusicBand_Unload(entry->band, NULL))) break;
212 return S_OK;
215 static HRESULT WINAPI band_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID rguidType)
217 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
219 TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidType));
221 if (!rguidType)
222 return E_POINTER;
224 if (IsEqualGUID (rguidType, &GUID_BandParam)
225 || IsEqualGUID (rguidType, &GUID_Clear_All_Bands)
226 || IsEqualGUID (rguidType, &GUID_ConnectToDLSCollection)
227 || IsEqualGUID (rguidType, &GUID_Disable_Auto_Download)
228 || IsEqualGUID (rguidType, &GUID_Download)
229 || IsEqualGUID (rguidType, &GUID_DownloadToAudioPath)
230 || IsEqualGUID (rguidType, &GUID_Enable_Auto_Download)
231 || IsEqualGUID (rguidType, &GUID_IDirectMusicBand)
232 || IsEqualGUID (rguidType, &GUID_StandardMIDIFile)
233 || IsEqualGUID (rguidType, &GUID_Unload)
234 || IsEqualGUID (rguidType, &GUID_UnloadFromAudioPath)) {
235 TRACE("param supported\n");
236 return S_OK;
239 TRACE("param unsupported\n");
240 return DMUS_E_TYPE_UNSUPPORTED;
243 static HRESULT WINAPI band_track_AddNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype)
245 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
247 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
248 return E_NOTIMPL;
251 static HRESULT WINAPI band_track_RemoveNotificationType(IDirectMusicTrack8 *iface,
252 REFGUID notiftype)
254 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
256 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
257 return E_NOTIMPL;
260 static HRESULT WINAPI band_track_Clone(IDirectMusicTrack8 *iface, MUSIC_TIME mtStart,
261 MUSIC_TIME mtEnd, IDirectMusicTrack **ppTrack)
263 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
264 FIXME("(%p, %ld, %ld, %p): stub\n", This, mtStart, mtEnd, ppTrack);
265 return S_OK;
268 static HRESULT WINAPI band_track_PlayEx(IDirectMusicTrack8 *iface, void *state_data,
269 REFERENCE_TIME rtStart, REFERENCE_TIME rtEnd, REFERENCE_TIME rtOffset, DWORD flags,
270 IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state,
271 DWORD virtual_id)
273 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
275 FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %lx, %p, %p, %ld): stub\n", This, state_data, wine_dbgstr_longlong(rtStart),
276 wine_dbgstr_longlong(rtEnd), wine_dbgstr_longlong(rtOffset), flags, performance, segment_state, virtual_id);
278 return S_OK;
281 static HRESULT WINAPI band_track_GetParamEx(IDirectMusicTrack8 *iface,
282 REFGUID rguidType, REFERENCE_TIME rtTime, REFERENCE_TIME *rtNext, void *param,
283 void *state_data, DWORD flags)
285 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
287 FIXME("(%p, %s, 0x%s, %p, %p, %p, %lx): stub\n", This, debugstr_dmguid(rguidType),
288 wine_dbgstr_longlong(rtTime), rtNext, param, state_data, flags);
290 return S_OK;
293 static HRESULT WINAPI band_track_SetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType,
294 REFERENCE_TIME rtTime, void *param, void *state_data, DWORD flags)
296 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
298 FIXME("(%p, %s, 0x%s, %p, %p, %lx): stub\n", This, debugstr_dmguid(rguidType),
299 wine_dbgstr_longlong(rtTime), param, state_data, flags);
301 return S_OK;
304 static HRESULT WINAPI band_track_Compose(IDirectMusicTrack8 *iface, IUnknown *context,
305 DWORD trackgroup, IDirectMusicTrack **track)
307 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
309 TRACE("(%p, %p, %ld, %p): method not implemented\n", This, context, trackgroup, track);
310 return E_NOTIMPL;
313 static HRESULT WINAPI band_track_Join(IDirectMusicTrack8 *iface, IDirectMusicTrack *pNewTrack,
314 MUSIC_TIME mtJoin, IUnknown *pContext, DWORD dwTrackGroup,
315 IDirectMusicTrack **ppResultTrack)
317 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
318 FIXME("(%p, %p, %ld, %p, %ld, %p): stub\n", This, pNewTrack, mtJoin, pContext, dwTrackGroup, ppResultTrack);
319 return S_OK;
322 static const IDirectMusicTrack8Vtbl band_track_vtbl =
324 band_track_QueryInterface,
325 band_track_AddRef,
326 band_track_Release,
327 band_track_Init,
328 band_track_InitPlay,
329 band_track_EndPlay,
330 band_track_Play,
331 band_track_GetParam,
332 band_track_SetParam,
333 band_track_IsParamSupported,
334 band_track_AddNotificationType,
335 band_track_RemoveNotificationType,
336 band_track_Clone,
337 band_track_PlayEx,
338 band_track_GetParamEx,
339 band_track_SetParamEx,
340 band_track_Compose,
341 band_track_Join,
344 static HRESULT parse_lbnd_list(struct band_track *This, IStream *stream, struct chunk_entry *parent)
346 struct chunk_entry chunk = {.parent = parent};
347 DMUS_IO_BAND_ITEM_HEADER2 header2;
348 struct band_entry *entry;
349 IDirectMusicBand *band;
350 HRESULT hr;
352 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
354 switch (MAKE_IDTYPE(chunk.id, chunk.type))
356 case DMUS_FOURCC_BANDITEM_CHUNK:
358 DMUS_IO_BAND_ITEM_HEADER header;
360 if (SUCCEEDED(hr = stream_chunk_get_data(stream, &chunk, &header, sizeof(header))))
362 header2.lBandTimeLogical = header.lBandTime;
363 header2.lBandTimePhysical = header.lBandTime;
366 break;
369 case DMUS_FOURCC_BANDITEM_CHUNK2:
370 hr = stream_chunk_get_data(stream, &chunk, &header2, sizeof(header2));
371 break;
373 case MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_BAND_FORM):
375 IPersistStream *persist;
377 if (FAILED(hr = CoCreateInstance(&CLSID_DirectMusicBand, NULL, CLSCTX_INPROC_SERVER,
378 &IID_IDirectMusicBand, (void **)&band)))
379 break;
381 if (SUCCEEDED(hr = IDirectMusicBand_QueryInterface(band, &IID_IPersistStream, (void **)&persist)))
383 if (SUCCEEDED(hr = stream_reset_chunk_start(stream, &chunk)))
384 hr = IPersistStream_Load(persist, stream);
385 IPersistStream_Release(persist);
388 break;
391 default:
392 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
393 break;
396 if (FAILED(hr)) break;
399 if (FAILED(hr)) return hr;
401 if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY;
402 entry->head = header2;
403 entry->band = band;
404 IDirectMusicBand_AddRef(band);
405 list_add_tail(&This->bands, &entry->entry);
407 return S_OK;
410 static HRESULT parse_lbdl_list(struct band_track *This, IStream *stream, struct chunk_entry *parent)
412 struct chunk_entry chunk = {.parent = parent};
413 HRESULT hr;
415 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
417 switch (MAKE_IDTYPE(chunk.id, chunk.type))
419 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_BAND_LIST):
420 hr = parse_lbnd_list(This, stream, &chunk);
421 break;
423 default:
424 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
425 break;
428 if (FAILED(hr)) break;
431 return S_OK;
434 static HRESULT parse_dmbt_chunk(struct band_track *This, IStream *stream, struct chunk_entry *parent)
436 struct chunk_entry chunk = {.parent = parent};
437 HRESULT hr;
439 if (FAILED(hr = dmobj_parsedescriptor(stream, parent, &This->dmobj.desc,
440 DMUS_OBJ_OBJECT|DMUS_OBJ_NAME|DMUS_OBJ_NAME_INAM|DMUS_OBJ_VERSION))
441 || FAILED(hr = stream_reset_chunk_data(stream, parent)))
442 return hr;
444 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
446 switch (MAKE_IDTYPE(chunk.id, chunk.type))
448 case DMUS_FOURCC_GUID_CHUNK:
449 case DMUS_FOURCC_VERSION_CHUNK:
450 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_UNFO_LIST):
451 /* already parsed by dmobj_parsedescriptor */
452 break;
454 case DMUS_FOURCC_BANDTRACK_CHUNK:
455 hr = stream_chunk_get_data(stream, &chunk, &This->header, sizeof(This->header));
456 break;
458 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_BANDS_LIST):
459 hr = parse_lbdl_list(This, stream, &chunk);
460 break;
462 default:
463 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
464 break;
467 if (FAILED(hr)) break;
470 return hr;
473 static inline struct band_track *impl_from_IPersistStream(IPersistStream *iface)
475 return CONTAINING_RECORD(iface, struct band_track, dmobj.IPersistStream_iface);
478 static HRESULT WINAPI band_track_persist_stream_Load(IPersistStream *iface, IStream *stream)
480 struct band_track *This = impl_from_IPersistStream(iface);
481 struct chunk_entry chunk = {0};
482 HRESULT hr;
484 TRACE("(%p, %p)\n", This, stream);
486 if ((hr = stream_get_chunk(stream, &chunk)) == S_OK)
488 switch (MAKE_IDTYPE(chunk.id, chunk.type))
490 case MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_BANDTRACK_FORM):
491 hr = parse_dmbt_chunk(This, stream, &chunk);
492 break;
494 default:
495 WARN("Invalid band track chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
496 hr = DMUS_E_UNSUPPORTED_STREAM;
497 break;
501 if (FAILED(hr)) return hr;
503 if (TRACE_ON(dmband))
505 struct band_entry *entry;
506 int i = 0;
508 TRACE("Loaded DirectMusicBandTrack %p\n", This);
509 dump_DMUS_OBJECTDESC(&This->dmobj.desc);
511 TRACE(" - header:\n");
512 TRACE(" - bAutoDownload: %u\n", This->header.bAutoDownload);
514 TRACE(" - bands:\n");
515 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
517 TRACE(" - band[%u]: %p\n", i++, entry->band);
518 TRACE(" - lBandTimeLogical: %ld\n", entry->head.lBandTimeLogical);
519 TRACE(" - lBandTimePhysical: %ld\n", entry->head.lBandTimePhysical);
523 stream_skip_chunk(stream, &chunk);
524 return S_OK;
527 static const IPersistStreamVtbl band_track_persist_stream_vtbl =
529 dmobj_IPersistStream_QueryInterface,
530 dmobj_IPersistStream_AddRef,
531 dmobj_IPersistStream_Release,
532 dmobj_IPersistStream_GetClassID,
533 unimpl_IPersistStream_IsDirty,
534 band_track_persist_stream_Load,
535 unimpl_IPersistStream_Save,
536 unimpl_IPersistStream_GetSizeMax,
539 /* for ClassFactory */
540 HRESULT create_dmbandtrack(REFIID lpcGUID, void **ppobj)
542 struct band_track *track;
543 HRESULT hr;
545 *ppobj = NULL;
546 if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY;
547 track->IDirectMusicTrack8_iface.lpVtbl = &band_track_vtbl;
548 track->ref = 1;
549 dmobject_init(&track->dmobj, &CLSID_DirectMusicBandTrack, (IUnknown *)&track->IDirectMusicTrack8_iface);
550 track->dmobj.IPersistStream_iface.lpVtbl = &band_track_persist_stream_vtbl;
551 list_init(&track->bands);
553 hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj);
554 IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface);
556 return hr;