dmband: Download / unload bands when initializing / ending band track.
[wine.git] / dlls / dmband / bandtrack.c
blob6233d39b9c023bc43bdf13bb271f4009f17decc5
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 *segment)
109 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
111 FIXME("(%p, %p): stub\n", This, segment);
113 if (!segment) return E_POINTER;
114 return S_OK;
117 static HRESULT WINAPI band_track_InitPlay(IDirectMusicTrack8 *iface,
118 IDirectMusicSegmentState *segment_state, IDirectMusicPerformance *performance,
119 void **state_data, DWORD virtual_track8id, DWORD flags)
121 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
122 struct band_entry *entry;
123 HRESULT hr;
125 FIXME("(%p, %p, %p, %p, %ld, %lx): semi-stub\n", This, segment_state, performance, state_data, virtual_track8id, flags);
127 if (!performance) return E_POINTER;
129 if (This->header.bAutoDownload)
131 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
133 if (FAILED(hr = IDirectMusicBand_Download(entry->band, performance)))
134 return hr;
138 return S_OK;
141 static HRESULT WINAPI band_track_EndPlay(IDirectMusicTrack8 *iface, void *state_data)
143 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
144 struct band_entry *entry;
145 HRESULT hr;
147 FIXME("(%p, %p): semi-stub\n", This, state_data);
149 if (This->header.bAutoDownload)
151 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
153 if (FAILED(hr = IDirectMusicBand_Unload(entry->band, NULL)))
154 return hr;
158 return S_OK;
161 static HRESULT WINAPI band_track_Play(IDirectMusicTrack8 *iface, void *state_data,
162 MUSIC_TIME mtStart, MUSIC_TIME mtEnd, MUSIC_TIME mtOffset, DWORD flags,
163 IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state,
164 DWORD virtual_id)
166 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
168 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);
170 /* Sends following pMSG:
171 - DMUS_PATCH_PMSG
172 - DMUS_TRANSPOSE_PMSG
173 - DMUS_CHANNEL_PRIORITY_PMSG
174 - DMUS_MIDI_PMSG
177 return S_OK;
180 static HRESULT WINAPI band_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
181 MUSIC_TIME *next, void *param)
183 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
185 TRACE("(%p, %s, %ld, %p, %p)\n", This, debugstr_dmguid(type), time, next, param);
187 if (!type)
188 return E_POINTER;
189 if (!IsEqualGUID(type, &GUID_BandParam))
190 return DMUS_E_GET_UNSUPPORTED;
192 FIXME("GUID_BandParam not handled yet\n");
194 return S_OK;
197 static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
198 void *param)
200 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
202 TRACE("(%p, %s, %ld, %p)\n", This, debugstr_dmguid(type), time, param);
204 if (!type)
205 return E_POINTER;
206 if (FAILED(IDirectMusicTrack8_IsParamSupported(iface, type)))
207 return DMUS_E_TYPE_UNSUPPORTED;
209 if (IsEqualGUID(type, &GUID_BandParam))
210 FIXME("GUID_BandParam not handled yet\n");
211 else if (IsEqualGUID(type, &GUID_Clear_All_Bands))
212 FIXME("GUID_Clear_All_Bands not handled yet\n");
213 else if (IsEqualGUID(type, &GUID_ConnectToDLSCollection))
215 struct band_entry *entry;
217 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
218 band_connect_to_collection(entry->band, param);
220 else if (IsEqualGUID(type, &GUID_Disable_Auto_Download))
221 FIXME("GUID_Disable_Auto_Download not handled yet\n");
222 else if (IsEqualGUID(type, &GUID_Download))
223 FIXME("GUID_Download not handled yet\n");
224 else if (IsEqualGUID(type, &GUID_DownloadToAudioPath))
226 IDirectMusicPerformance *performance;
227 IDirectMusicAudioPath *audio_path;
228 IUnknown *object = param;
229 struct band_entry *entry;
230 HRESULT hr;
232 if (FAILED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicPerformance8, (void **)&performance))
233 && SUCCEEDED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicAudioPath, (void **)&audio_path)))
235 hr = IDirectMusicAudioPath_GetObjectInPath(audio_path, DMUS_PCHANNEL_ALL, DMUS_PATH_PERFORMANCE, 0,
236 &GUID_All_Objects, 0, &IID_IDirectMusicPerformance8, (void **)&performance);
237 IDirectMusicAudioPath_Release(audio_path);
240 if (FAILED(hr))
242 WARN("Failed to get IDirectMusicPerformance from param %p\n", param);
243 return hr;
246 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
247 if (FAILED(hr = IDirectMusicBand_Download(entry->band, performance))) break;
249 IDirectMusicPerformance_Release(performance);
251 else if (IsEqualGUID(type, &GUID_Enable_Auto_Download))
252 FIXME("GUID_Enable_Auto_Download not handled yet\n");
253 else if (IsEqualGUID(type, &GUID_IDirectMusicBand))
254 FIXME("GUID_IDirectMusicBand not handled yet\n");
255 else if (IsEqualGUID(type, &GUID_StandardMIDIFile))
256 FIXME("GUID_StandardMIDIFile not handled yet\n");
257 else if (IsEqualGUID(type, &GUID_UnloadFromAudioPath))
259 struct band_entry *entry;
260 HRESULT hr;
262 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
263 if (FAILED(hr = IDirectMusicBand_Unload(entry->band, NULL))) break;
266 return S_OK;
269 static HRESULT WINAPI band_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID rguidType)
271 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
273 TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidType));
275 if (!rguidType)
276 return E_POINTER;
278 if (IsEqualGUID (rguidType, &GUID_BandParam)
279 || IsEqualGUID (rguidType, &GUID_Clear_All_Bands)
280 || IsEqualGUID (rguidType, &GUID_ConnectToDLSCollection)
281 || IsEqualGUID (rguidType, &GUID_Disable_Auto_Download)
282 || IsEqualGUID (rguidType, &GUID_Download)
283 || IsEqualGUID (rguidType, &GUID_DownloadToAudioPath)
284 || IsEqualGUID (rguidType, &GUID_Enable_Auto_Download)
285 || IsEqualGUID (rguidType, &GUID_IDirectMusicBand)
286 || IsEqualGUID (rguidType, &GUID_StandardMIDIFile)
287 || IsEqualGUID (rguidType, &GUID_Unload)
288 || IsEqualGUID (rguidType, &GUID_UnloadFromAudioPath)) {
289 TRACE("param supported\n");
290 return S_OK;
293 TRACE("param unsupported\n");
294 return DMUS_E_TYPE_UNSUPPORTED;
297 static HRESULT WINAPI band_track_AddNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype)
299 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
301 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
302 return E_NOTIMPL;
305 static HRESULT WINAPI band_track_RemoveNotificationType(IDirectMusicTrack8 *iface,
306 REFGUID notiftype)
308 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
310 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
311 return E_NOTIMPL;
314 static HRESULT WINAPI band_track_Clone(IDirectMusicTrack8 *iface, MUSIC_TIME mtStart,
315 MUSIC_TIME mtEnd, IDirectMusicTrack **ppTrack)
317 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
318 FIXME("(%p, %ld, %ld, %p): stub\n", This, mtStart, mtEnd, ppTrack);
319 return S_OK;
322 static HRESULT WINAPI band_track_PlayEx(IDirectMusicTrack8 *iface, void *state_data,
323 REFERENCE_TIME rtStart, REFERENCE_TIME rtEnd, REFERENCE_TIME rtOffset, DWORD flags,
324 IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state,
325 DWORD virtual_id)
327 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
329 FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %lx, %p, %p, %ld): stub\n", This, state_data, wine_dbgstr_longlong(rtStart),
330 wine_dbgstr_longlong(rtEnd), wine_dbgstr_longlong(rtOffset), flags, performance, segment_state, virtual_id);
332 return S_OK;
335 static HRESULT WINAPI band_track_GetParamEx(IDirectMusicTrack8 *iface,
336 REFGUID rguidType, REFERENCE_TIME rtTime, REFERENCE_TIME *rtNext, void *param,
337 void *state_data, DWORD flags)
339 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
341 FIXME("(%p, %s, 0x%s, %p, %p, %p, %lx): stub\n", This, debugstr_dmguid(rguidType),
342 wine_dbgstr_longlong(rtTime), rtNext, param, state_data, flags);
344 return S_OK;
347 static HRESULT WINAPI band_track_SetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType,
348 REFERENCE_TIME rtTime, void *param, void *state_data, DWORD flags)
350 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
352 FIXME("(%p, %s, 0x%s, %p, %p, %lx): stub\n", This, debugstr_dmguid(rguidType),
353 wine_dbgstr_longlong(rtTime), param, state_data, flags);
355 return S_OK;
358 static HRESULT WINAPI band_track_Compose(IDirectMusicTrack8 *iface, IUnknown *context,
359 DWORD trackgroup, IDirectMusicTrack **track)
361 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
363 TRACE("(%p, %p, %ld, %p): method not implemented\n", This, context, trackgroup, track);
364 return E_NOTIMPL;
367 static HRESULT WINAPI band_track_Join(IDirectMusicTrack8 *iface, IDirectMusicTrack *pNewTrack,
368 MUSIC_TIME mtJoin, IUnknown *pContext, DWORD dwTrackGroup,
369 IDirectMusicTrack **ppResultTrack)
371 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
372 FIXME("(%p, %p, %ld, %p, %ld, %p): stub\n", This, pNewTrack, mtJoin, pContext, dwTrackGroup, ppResultTrack);
373 return S_OK;
376 static const IDirectMusicTrack8Vtbl band_track_vtbl =
378 band_track_QueryInterface,
379 band_track_AddRef,
380 band_track_Release,
381 band_track_Init,
382 band_track_InitPlay,
383 band_track_EndPlay,
384 band_track_Play,
385 band_track_GetParam,
386 band_track_SetParam,
387 band_track_IsParamSupported,
388 band_track_AddNotificationType,
389 band_track_RemoveNotificationType,
390 band_track_Clone,
391 band_track_PlayEx,
392 band_track_GetParamEx,
393 band_track_SetParamEx,
394 band_track_Compose,
395 band_track_Join,
398 static HRESULT parse_lbnd_list(struct band_track *This, IStream *stream, struct chunk_entry *parent)
400 struct chunk_entry chunk = {.parent = parent};
401 DMUS_IO_BAND_ITEM_HEADER2 header2;
402 struct band_entry *entry;
403 IDirectMusicBand *band;
404 HRESULT hr;
406 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
408 switch (MAKE_IDTYPE(chunk.id, chunk.type))
410 case DMUS_FOURCC_BANDITEM_CHUNK:
412 DMUS_IO_BAND_ITEM_HEADER header;
414 if (SUCCEEDED(hr = stream_chunk_get_data(stream, &chunk, &header, sizeof(header))))
416 header2.lBandTimeLogical = header.lBandTime;
417 header2.lBandTimePhysical = header.lBandTime;
420 break;
423 case DMUS_FOURCC_BANDITEM_CHUNK2:
424 hr = stream_chunk_get_data(stream, &chunk, &header2, sizeof(header2));
425 break;
427 case MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_BAND_FORM):
429 IPersistStream *persist;
431 if (FAILED(hr = CoCreateInstance(&CLSID_DirectMusicBand, NULL, CLSCTX_INPROC_SERVER,
432 &IID_IDirectMusicBand, (void **)&band)))
433 break;
435 if (SUCCEEDED(hr = IDirectMusicBand_QueryInterface(band, &IID_IPersistStream, (void **)&persist)))
437 if (SUCCEEDED(hr = stream_reset_chunk_start(stream, &chunk)))
438 hr = IPersistStream_Load(persist, stream);
439 IPersistStream_Release(persist);
442 break;
445 default:
446 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
447 break;
450 if (FAILED(hr)) break;
453 if (FAILED(hr)) return hr;
455 if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY;
456 entry->head = header2;
457 entry->band = band;
458 IDirectMusicBand_AddRef(band);
459 list_add_tail(&This->bands, &entry->entry);
461 return S_OK;
464 static HRESULT parse_lbdl_list(struct band_track *This, IStream *stream, struct chunk_entry *parent)
466 struct chunk_entry chunk = {.parent = parent};
467 HRESULT hr;
469 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
471 switch (MAKE_IDTYPE(chunk.id, chunk.type))
473 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_BAND_LIST):
474 hr = parse_lbnd_list(This, stream, &chunk);
475 break;
477 default:
478 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
479 break;
482 if (FAILED(hr)) break;
485 return S_OK;
488 static HRESULT parse_dmbt_chunk(struct band_track *This, IStream *stream, struct chunk_entry *parent)
490 struct chunk_entry chunk = {.parent = parent};
491 HRESULT hr;
493 if (FAILED(hr = dmobj_parsedescriptor(stream, parent, &This->dmobj.desc,
494 DMUS_OBJ_OBJECT|DMUS_OBJ_NAME|DMUS_OBJ_NAME_INAM|DMUS_OBJ_VERSION))
495 || FAILED(hr = stream_reset_chunk_data(stream, parent)))
496 return hr;
498 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
500 switch (MAKE_IDTYPE(chunk.id, chunk.type))
502 case DMUS_FOURCC_GUID_CHUNK:
503 case DMUS_FOURCC_VERSION_CHUNK:
504 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_UNFO_LIST):
505 /* already parsed by dmobj_parsedescriptor */
506 break;
508 case DMUS_FOURCC_BANDTRACK_CHUNK:
509 hr = stream_chunk_get_data(stream, &chunk, &This->header, sizeof(This->header));
510 break;
512 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_BANDS_LIST):
513 hr = parse_lbdl_list(This, stream, &chunk);
514 break;
516 default:
517 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
518 break;
521 if (FAILED(hr)) break;
524 return hr;
527 static inline struct band_track *impl_from_IPersistStream(IPersistStream *iface)
529 return CONTAINING_RECORD(iface, struct band_track, dmobj.IPersistStream_iface);
532 static HRESULT WINAPI band_track_persist_stream_Load(IPersistStream *iface, IStream *stream)
534 struct band_track *This = impl_from_IPersistStream(iface);
535 struct chunk_entry chunk = {0};
536 HRESULT hr;
538 TRACE("(%p, %p)\n", This, stream);
540 if ((hr = stream_get_chunk(stream, &chunk)) == S_OK)
542 switch (MAKE_IDTYPE(chunk.id, chunk.type))
544 case MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_BANDTRACK_FORM):
545 hr = parse_dmbt_chunk(This, stream, &chunk);
546 break;
548 default:
549 WARN("Invalid band track chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
550 hr = DMUS_E_UNSUPPORTED_STREAM;
551 break;
555 if (FAILED(hr)) return hr;
557 if (TRACE_ON(dmband))
559 struct band_entry *entry;
560 int i = 0;
562 TRACE("Loaded DirectMusicBandTrack %p\n", This);
563 dump_DMUS_OBJECTDESC(&This->dmobj.desc);
565 TRACE(" - header:\n");
566 TRACE(" - bAutoDownload: %u\n", This->header.bAutoDownload);
568 TRACE(" - bands:\n");
569 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
571 TRACE(" - band[%u]: %p\n", i++, entry->band);
572 TRACE(" - lBandTimeLogical: %ld\n", entry->head.lBandTimeLogical);
573 TRACE(" - lBandTimePhysical: %ld\n", entry->head.lBandTimePhysical);
577 stream_skip_chunk(stream, &chunk);
578 return S_OK;
581 static const IPersistStreamVtbl band_track_persist_stream_vtbl =
583 dmobj_IPersistStream_QueryInterface,
584 dmobj_IPersistStream_AddRef,
585 dmobj_IPersistStream_Release,
586 dmobj_IPersistStream_GetClassID,
587 unimpl_IPersistStream_IsDirty,
588 band_track_persist_stream_Load,
589 unimpl_IPersistStream_Save,
590 unimpl_IPersistStream_GetSizeMax,
593 /* for ClassFactory */
594 HRESULT create_dmbandtrack(REFIID lpcGUID, void **ppobj)
596 struct band_track *track;
597 HRESULT hr;
599 *ppobj = NULL;
600 if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY;
601 track->IDirectMusicTrack8_iface.lpVtbl = &band_track_vtbl;
602 track->ref = 1;
603 dmobject_init(&track->dmobj, &CLSID_DirectMusicBandTrack, (IUnknown *)&track->IDirectMusicTrack8_iface);
604 track->dmobj.IPersistStream_iface.lpVtbl = &band_track_persist_stream_vtbl;
605 list_init(&track->bands);
607 hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj);
608 IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface);
610 return hr;