dmime: Return hr from wave track SetParam GUID_DownloadToAudioPath.
[wine.git] / dlls / dmime / wavetrack.c
blobfcf57c1148d86871b13d4117cbb3a79ed4dd3a8d
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 "dmime_private.h"
20 #include "dmusic_wave.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(dmime);
24 struct wave_item {
25 struct list entry;
26 DMUS_IO_WAVE_ITEM_HEADER header;
27 IUnknown *object;
28 IDirectSoundBuffer *buffer;
31 struct wave_part {
32 struct list entry;
33 DMUS_IO_WAVE_PART_HEADER header;
34 struct list items;
37 struct wave_track
39 IDirectMusicTrack8 IDirectMusicTrack8_iface;
40 struct dmobject dmobj; /* IPersistStream only */
41 LONG ref;
42 DMUS_IO_WAVE_TRACK_HEADER header;
43 struct list parts;
46 /* struct wave_track IDirectMusicTrack8 part: */
47 static inline struct wave_track *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface)
49 return CONTAINING_RECORD(iface, struct wave_track, IDirectMusicTrack8_iface);
52 static inline struct wave_track *impl_from_IPersistStream(IPersistStream *iface)
54 return CONTAINING_RECORD(iface, struct wave_track, dmobj.IPersistStream_iface);
57 static HRESULT WINAPI wave_track_QueryInterface(IDirectMusicTrack8 *iface, REFIID riid,
58 void **ret_iface)
60 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
62 TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface);
64 *ret_iface = NULL;
66 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicTrack) ||
67 IsEqualIID(riid, &IID_IDirectMusicTrack8))
68 *ret_iface = iface;
69 else if (IsEqualIID(riid, &IID_IPersistStream))
70 *ret_iface = &This->dmobj.IPersistStream_iface;
71 else {
72 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface);
73 return E_NOINTERFACE;
76 IUnknown_AddRef((IUnknown*)*ret_iface);
77 return S_OK;
80 static ULONG WINAPI wave_track_AddRef(IDirectMusicTrack8 *iface)
82 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
83 LONG ref = InterlockedIncrement(&This->ref);
85 TRACE("(%p) ref=%ld\n", This, ref);
87 return ref;
90 static ULONG WINAPI wave_track_Release(IDirectMusicTrack8 *iface)
92 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
93 LONG ref = InterlockedDecrement(&This->ref);
95 TRACE("(%p) ref=%ld\n", This, ref);
97 if (!ref) {
98 struct wave_item *item, *item2;
99 struct wave_part *part, *part2;
101 LIST_FOR_EACH_ENTRY_SAFE(part, part2, &This->parts, struct wave_part, entry)
103 list_remove(&part->entry);
105 LIST_FOR_EACH_ENTRY_SAFE(item, item2, &part->items, struct wave_item, entry)
107 list_remove(&item->entry);
108 if (item->buffer) IDirectSoundBuffer_Release(item->buffer);
109 if (item->object) IUnknown_Release(item->object);
110 free(item);
113 free(part);
116 free(This);
119 return ref;
122 static HRESULT WINAPI wave_track_Init(IDirectMusicTrack8 *iface, IDirectMusicSegment *pSegment)
124 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
125 FIXME("(%p, %p): stub\n", This, pSegment);
126 return S_OK;
129 static HRESULT WINAPI wave_track_InitPlay(IDirectMusicTrack8 *iface,
130 IDirectMusicSegmentState *pSegmentState, IDirectMusicPerformance *pPerformance,
131 void **ppStateData, DWORD dwVirtualTrack8ID, DWORD dwFlags)
133 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
134 FIXME("(%p, %p, %p, %p, %ld, %ld): stub\n", This, pSegmentState, pPerformance, ppStateData,
135 dwVirtualTrack8ID, dwFlags);
136 return S_OK;
139 static HRESULT WINAPI wave_track_EndPlay(IDirectMusicTrack8 *iface, void *pStateData)
141 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
142 FIXME("(%p, %p): stub\n", This, pStateData);
143 return S_OK;
146 static HRESULT WINAPI wave_track_Play(IDirectMusicTrack8 *iface, void *state_data,
147 MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD segment_flags,
148 IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD track_id)
150 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
151 LONG volume = This->header.lVolume;
152 IDirectMusicGraph *graph;
153 struct wave_part *part;
154 struct wave_item *item;
155 HRESULT hr;
157 TRACE("(%p, %p, %ld, %ld, %ld, %#lx, %p, %p, %ld)\n", This, state_data, start_time, end_time,
158 time_offset, segment_flags, performance, segment_state, track_id);
160 if (start_time != 0) FIXME("start_time %ld not implemented\n", start_time);
161 if (end_time != -1) FIXME("end_time %ld not implemented\n", end_time);
162 if (time_offset != 0) FIXME("time_offset %ld not implemented\n", time_offset);
163 if (segment_flags) FIXME("segment_flags %#lx not implemented\n", segment_flags);
164 if (segment_state) FIXME("segment_state %p not implemented\n", segment_state);
166 if (FAILED(hr = IDirectMusicPerformance_QueryInterface(performance,
167 &IID_IDirectMusicGraph, (void **)&graph)))
168 return hr;
170 LIST_FOR_EACH_ENTRY(part, &This->parts, struct wave_part, entry)
172 volume += part->header.lVolume;
174 LIST_FOR_EACH_ENTRY(item, &part->items, struct wave_item, entry)
176 DMUS_WAVE_PMSG *msg;
178 if (!item->buffer) continue;
180 if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*msg),
181 (DMUS_PMSG **)&msg)))
182 break;
184 msg->mtTime = item->header.rtTime;
185 msg->dwFlags = DMUS_PMSGF_MUSICTIME;
186 msg->dwPChannel = part->header.dwPChannel;
187 msg->dwVirtualTrackID = track_id;
188 msg->dwType = DMUS_PMSGT_WAVE;
189 msg->punkUser = (IUnknown *)item->buffer;
190 IDirectSoundBuffer_AddRef(item->buffer);
192 msg->rtStartOffset = item->header.rtStartOffset;
193 msg->rtDuration = item->header.rtDuration;
194 msg->lVolume = volume + item->header.lVolume;
195 msg->lPitch = item->header.lPitch;
197 if (FAILED(hr = IDirectMusicGraph_StampPMsg(graph, (DMUS_PMSG *)msg))
198 || FAILED(hr = IDirectMusicPerformance_SendPMsg(performance, (DMUS_PMSG *)msg)))
200 IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)msg);
201 break;
205 volume -= part->header.lVolume;
208 IDirectMusicGraph_Release(graph);
209 return hr;
212 static HRESULT WINAPI wave_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
213 MUSIC_TIME *next, void *param)
215 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
217 TRACE("(%p, %s, %ld, %p, %p): not supported\n", This, debugstr_dmguid(type), time, next, param);
218 return DMUS_E_GET_UNSUPPORTED;
221 static HRESULT WINAPI wave_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
222 void *param)
224 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
226 TRACE("(%p, %s, %ld, %p)\n", This, debugstr_dmguid(type), time, param);
228 if (IsEqualGUID(type, &GUID_Disable_Auto_Download)) {
229 FIXME("GUID_Disable_Auto_Download not handled yet\n");
230 return S_OK;
232 if (IsEqualGUID(type, &GUID_Download)) {
233 FIXME("GUID_Download not handled yet\n");
234 return S_OK;
236 if (IsEqualGUID(type, &GUID_DownloadToAudioPath))
238 IDirectMusicPerformance8 *performance;
239 IDirectMusicAudioPath *audio_path;
240 IUnknown *object = param;
241 struct wave_part *part;
242 struct wave_item *item;
243 IDirectSound *dsound;
244 HRESULT hr;
246 if (FAILED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicPerformance8, (void **)&performance))
247 && SUCCEEDED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicAudioPath, (void **)&audio_path)))
249 hr = IDirectMusicAudioPath_GetObjectInPath(audio_path, DMUS_PCHANNEL_ALL, DMUS_PATH_PERFORMANCE, 0,
250 &GUID_All_Objects, 0, &IID_IDirectMusicPerformance8, (void **)&performance);
251 IDirectMusicAudioPath_Release(audio_path);
254 if (SUCCEEDED(hr))
255 hr = performance_get_dsound(performance, &dsound);
256 IDirectMusicPerformance_Release(performance);
258 if (FAILED(hr))
260 WARN("Failed to get direct sound from param %p, hr %#lx\n", param, hr);
261 return hr;
264 LIST_FOR_EACH_ENTRY(part, &This->parts, struct wave_part, entry)
266 LIST_FOR_EACH_ENTRY(item, &part->items, struct wave_item, entry)
268 if (item->buffer) continue;
269 if (FAILED(hr = wave_download_to_dsound(item->object, dsound, &item->buffer)))
271 WARN("Failed to download wave %p to direct sound, hr %#lx\n", item->object, hr);
272 return hr;
277 return hr;
279 if (IsEqualGUID(type, &GUID_Enable_Auto_Download)) {
280 FIXME("GUID_Enable_Auto_Download not handled yet\n");
281 return S_OK;
283 if (IsEqualGUID(type, &GUID_Unload)) {
284 FIXME("GUID_Unload not handled yet\n");
285 return S_OK;
287 if (IsEqualGUID(type, &GUID_UnloadFromAudioPath))
289 struct wave_part *part;
290 struct wave_item *item;
292 LIST_FOR_EACH_ENTRY(part, &This->parts, struct wave_part, entry)
294 LIST_FOR_EACH_ENTRY(item, &part->items, struct wave_item, entry)
296 if (!item->buffer) continue;
297 IDirectSoundBuffer_Release(item->buffer);
298 item->buffer = NULL;
302 return S_OK;
305 return DMUS_E_TYPE_UNSUPPORTED;
308 static HRESULT WINAPI wave_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID type)
310 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
311 static const GUID *valid[] = {
312 &GUID_Disable_Auto_Download,
313 &GUID_Download,
314 &GUID_DownloadToAudioPath,
315 &GUID_Enable_Auto_Download,
316 &GUID_Unload,
317 &GUID_UnloadFromAudioPath
319 unsigned int i;
321 TRACE("(%p, %s)\n", This, debugstr_dmguid(type));
323 for (i = 0; i < ARRAY_SIZE(valid); i++)
324 if (IsEqualGUID(type, valid[i]))
325 return S_OK;
327 TRACE("param unsupported\n");
328 return DMUS_E_TYPE_UNSUPPORTED;
331 static HRESULT WINAPI wave_track_AddNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype)
333 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
335 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
336 return E_NOTIMPL;
339 static HRESULT WINAPI wave_track_RemoveNotificationType(IDirectMusicTrack8 *iface,
340 REFGUID notiftype)
342 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
344 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
345 return E_NOTIMPL;
348 static HRESULT WINAPI wave_track_Clone(IDirectMusicTrack8 *iface, MUSIC_TIME mtStart,
349 MUSIC_TIME mtEnd, IDirectMusicTrack **ppTrack)
351 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
352 FIXME("(%p, %ld, %ld, %p): stub\n", This, mtStart, mtEnd, ppTrack);
353 return S_OK;
356 static HRESULT WINAPI wave_track_PlayEx(IDirectMusicTrack8 *iface, void *pStateData,
357 REFERENCE_TIME rtStart, REFERENCE_TIME rtEnd, REFERENCE_TIME rtOffset, DWORD dwFlags,
358 IDirectMusicPerformance *pPerf, IDirectMusicSegmentState *pSegSt, DWORD dwVirtualID)
360 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
361 FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %ld, %p, %p, %ld): stub\n", This, pStateData,
362 wine_dbgstr_longlong(rtStart), wine_dbgstr_longlong(rtEnd),
363 wine_dbgstr_longlong(rtOffset), dwFlags, pPerf, pSegSt, dwVirtualID);
364 return S_OK;
367 static HRESULT WINAPI wave_track_GetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType,
368 REFERENCE_TIME rtTime, REFERENCE_TIME *prtNext, void *pParam, void *pStateData,
369 DWORD dwFlags)
371 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
372 FIXME("(%p, %s, 0x%s, %p, %p, %p, %ld): stub\n", This, debugstr_dmguid(rguidType),
373 wine_dbgstr_longlong(rtTime), prtNext, pParam, pStateData, dwFlags);
374 return S_OK;
377 static HRESULT WINAPI wave_track_SetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType,
378 REFERENCE_TIME rtTime, void *pParam, void *pStateData, DWORD dwFlags)
380 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
381 FIXME("(%p, %s, 0x%s, %p, %p, %ld): stub\n", This, debugstr_dmguid(rguidType),
382 wine_dbgstr_longlong(rtTime), pParam, pStateData, dwFlags);
383 return S_OK;
386 static HRESULT WINAPI wave_track_Compose(IDirectMusicTrack8 *iface, IUnknown *context,
387 DWORD trackgroup, IDirectMusicTrack **track)
389 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
391 TRACE("(%p, %p, %ld, %p): method not implemented\n", This, context, trackgroup, track);
392 return E_NOTIMPL;
395 static HRESULT WINAPI wave_track_Join(IDirectMusicTrack8 *iface, IDirectMusicTrack *newtrack,
396 MUSIC_TIME join, IUnknown *context, DWORD trackgroup, IDirectMusicTrack **resulttrack)
398 struct wave_track *This = impl_from_IDirectMusicTrack8(iface);
399 TRACE("(%p, %p, %ld, %p, %ld, %p): method not implemented\n", This, newtrack, join, context,
400 trackgroup, resulttrack);
401 return E_NOTIMPL;
404 static const IDirectMusicTrack8Vtbl dmtrack8_vtbl = {
405 wave_track_QueryInterface,
406 wave_track_AddRef,
407 wave_track_Release,
408 wave_track_Init,
409 wave_track_InitPlay,
410 wave_track_EndPlay,
411 wave_track_Play,
412 wave_track_GetParam,
413 wave_track_SetParam,
414 wave_track_IsParamSupported,
415 wave_track_AddNotificationType,
416 wave_track_RemoveNotificationType,
417 wave_track_Clone,
418 wave_track_PlayEx,
419 wave_track_GetParamEx,
420 wave_track_SetParamEx,
421 wave_track_Compose,
422 wave_track_Join
425 static HRESULT parse_wave_item(struct wave_part *part, IStream *stream, struct chunk_entry *wavi)
427 struct chunk_entry wave = {.parent = wavi};
428 struct chunk_entry chunk = {.parent = &wave};
429 struct wave_item *item;
430 HRESULT hr;
432 /* Nested list with two chunks */
433 if (FAILED(hr = stream_next_chunk(stream, &wave)))
434 return hr;
435 if (wave.id != FOURCC_LIST || wave.type != DMUS_FOURCC_WAVE_LIST)
436 return DMUS_E_UNSUPPORTED_STREAM;
438 if (!(item = calloc(1, sizeof(*item)))) return E_OUTOFMEMORY;
440 /* Wave item header chunk */
441 if (FAILED(hr = stream_next_chunk(stream, &chunk)))
442 goto error;
443 if (chunk.id != DMUS_FOURCC_WAVEITEM_CHUNK) {
444 hr = DMUS_E_UNSUPPORTED_STREAM;
445 goto error;
448 if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &item->header, sizeof(item->header)))) {
449 WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
450 goto error;
453 TRACE("Found DMUS_IO_WAVE_ITEM_HEADER\n");
454 TRACE("\tlVolume %ld\n", item->header.lVolume);
455 TRACE("\tdwVariations %ld\n", item->header.dwVariations);
456 TRACE("\trtTime %s\n", wine_dbgstr_longlong(item->header.rtTime));
457 TRACE("\trtStartOffset %s\n", wine_dbgstr_longlong(item->header.rtStartOffset));
458 TRACE("\trtReserved %s\n", wine_dbgstr_longlong(item->header.rtReserved));
459 TRACE("\trtDuration %s\n", wine_dbgstr_longlong(item->header.rtDuration));
460 TRACE("\tdwLoopStart %ld\n", item->header.dwLoopStart);
461 TRACE("\tdwLoopEnd %ld\n", item->header.dwLoopEnd);
462 TRACE("\tdwFlags %#08lx\n", item->header.dwFlags);
463 TRACE("\twVolumeRange %d\n", item->header.wVolumeRange);
464 TRACE("\twPitchRange %d\n", item->header.wPitchRange);
466 /* Second chunk is a reference list */
467 if (stream_next_chunk(stream, &chunk) != S_OK || chunk.id != FOURCC_LIST ||
468 chunk.type != DMUS_FOURCC_REF_LIST) {
469 hr = DMUS_E_UNSUPPORTED_STREAM;
470 goto error;
472 if (FAILED(hr = dmobj_parsereference(stream, &chunk, (IDirectMusicObject **)&item->object)))
473 goto error;
475 list_add_tail(&part->items, &item->entry);
477 return S_OK;
479 error:
480 free(item);
481 return hr;
484 static HRESULT parse_wave_part(struct wave_track *This, IStream *stream, struct chunk_entry *wavp)
486 struct chunk_entry chunk = {.parent = wavp};
487 struct wave_part *part;
488 HRESULT hr;
490 /* Wave part header chunk */
491 if (FAILED(hr = stream_next_chunk(stream, &chunk)))
492 return hr;
493 if (chunk.id != DMUS_FOURCC_WAVEPART_CHUNK)
494 return DMUS_E_UNSUPPORTED_STREAM;
496 if (!(part = calloc(1, sizeof(*part)))) return E_OUTOFMEMORY;
497 list_init(&part->items);
499 if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &part->header, sizeof(part->header)))) {
500 WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
501 goto error;
504 TRACE("Found DMUS_IO_WAVE_PART_HEADER\n");
505 TRACE("\tlVolume %ld\n", part->header.lVolume);
506 TRACE("\tdwVariations %ld\n", part->header.dwVariations);
507 TRACE("\tdwPChannel %ld\n", part->header.dwPChannel);
508 TRACE("\tdwLockToPart %ld\n", part->header.dwLockToPart);
509 TRACE("\tdwFlags %#08lx\n", part->header.dwFlags);
510 TRACE("\tdwIndex %ld\n", part->header.dwIndex);
512 /* Array of wave items */
513 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
514 if (chunk.id == FOURCC_LIST && chunk.type == DMUS_FOURCC_WAVEITEM_LIST)
515 if (FAILED(hr = parse_wave_item(part, stream, &chunk)))
516 break;
518 if (FAILED(hr))
519 goto error;
521 list_add_tail(&This->parts, &part->entry);
523 return S_OK;
525 error:
526 free(part);
527 return hr;
530 static HRESULT WINAPI wave_IPersistStream_Load(IPersistStream *iface, IStream *stream)
532 struct wave_track *This = impl_from_IPersistStream(iface);
533 struct chunk_entry wavt = {0};
534 struct chunk_entry chunk = {.parent = &wavt};
535 HRESULT hr;
537 TRACE("%p, %p\n", This, stream);
539 if (!stream)
540 return E_POINTER;
542 if ((hr = stream_get_chunk(stream, &wavt) != S_OK))
543 return hr;
544 if (wavt.id != FOURCC_LIST || wavt.type != DMUS_FOURCC_WAVETRACK_LIST)
545 return DMUS_E_UNSUPPORTED_STREAM;
547 TRACE("Parsing segment form in %p: %s\n", stream, debugstr_chunk(&wavt));
549 /* Track header chunk */
550 if (FAILED(hr = stream_next_chunk(stream, &chunk)))
551 return hr;
552 if (chunk.id != DMUS_FOURCC_WAVETRACK_CHUNK)
553 return DMUS_E_UNSUPPORTED_STREAM;
554 if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &This->header, sizeof(This->header))))
555 return hr;
557 TRACE("Found DMUS_IO_WAVE_TRACK_HEADER\n");
558 TRACE("\tlVolume %ld\n", This->header.lVolume);
559 TRACE("\tdwFlags %#08lx\n", This->header.dwFlags);
561 /* Array of wave parts */
562 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
563 if (chunk.id == FOURCC_LIST && chunk.type == DMUS_FOURCC_WAVEPART_LIST)
564 if (FAILED(hr = parse_wave_part(This, stream, &chunk)))
565 break;
567 return SUCCEEDED(hr) ? S_OK : hr;
570 static const IPersistStreamVtbl persiststream_vtbl = {
571 dmobj_IPersistStream_QueryInterface,
572 dmobj_IPersistStream_AddRef,
573 dmobj_IPersistStream_Release,
574 dmobj_IPersistStream_GetClassID,
575 unimpl_IPersistStream_IsDirty,
576 wave_IPersistStream_Load,
577 unimpl_IPersistStream_Save,
578 unimpl_IPersistStream_GetSizeMax
581 /* for ClassFactory */
582 HRESULT create_dmwavetrack(REFIID lpcGUID, void **ppobj)
584 struct wave_track *track;
585 HRESULT hr;
587 *ppobj = NULL;
588 if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY;
589 track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl;
590 track->ref = 1;
591 dmobject_init(&track->dmobj, &CLSID_DirectMusicWaveTrack,
592 (IUnknown *)&track->IDirectMusicTrack8_iface);
593 track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl;
594 list_init(&track->parts);
596 hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj);
597 IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface);
599 return hr;
602 HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent,
603 IDirectMusicTrack8 **ret_iface)
605 IDirectMusicTrack8 *iface;
606 struct wave_track *This;
607 struct wave_item *item;
608 struct wave_part *part;
609 HRESULT hr;
611 if (FAILED(hr = create_dmwavetrack(&IID_IDirectMusicTrack8, (void **)&iface))) return hr;
612 This = impl_from_IDirectMusicTrack8(iface);
614 if (!(part = calloc(1, sizeof(*part))))
616 IDirectMusicTrack8_Release(iface);
617 return E_OUTOFMEMORY;
619 list_init(&part->items);
620 list_add_tail(&This->parts, &part->entry);
622 if (!(item = calloc(1, sizeof(*item)))
623 || FAILED(hr = wave_create_from_chunk(stream, parent, &item->object)))
625 IDirectMusicTrack8_Release(iface);
626 free(item);
627 return hr;
629 if (FAILED(hr = wave_get_duration(item->object, &item->header.rtDuration)))
630 WARN("Failed to get wave duration, hr %#lx\n", hr);
631 list_add_tail(&part->items, &item->entry);
633 *ret_iface = iface;
634 return S_OK;