1 /* IDirectMusicSegment8 Implementation
3 * Copyright (C) 2003-2004 Rok Mandeljc
4 * Copyright (C) 2003-2004 Raphael Junqueira
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 "dmime_private.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(dmime
);
30 IDirectMusicTrack
*pTrack
;
33 static void track_entry_destroy(struct track_entry
*entry
)
37 if (FAILED(hr
= IDirectMusicTrack_Init(entry
->pTrack
, NULL
)))
38 WARN("Failed to de-init track %p, hr %#lx\n", entry
->pTrack
, hr
);
39 IDirectMusicTrack_Release(entry
->pTrack
);
46 IDirectMusicSegment8 IDirectMusicSegment8_iface
;
47 struct dmobject dmobj
;
49 DMUS_IO_SEGMENT_HEADER header
;
50 IDirectMusicGraph
*pGraph
;
53 PCMWAVEFORMAT wave_format
;
58 static struct segment
*segment_create(void);
60 static inline struct segment
*impl_from_IDirectMusicSegment8(IDirectMusicSegment8
*iface
)
62 return CONTAINING_RECORD(iface
, struct segment
, IDirectMusicSegment8_iface
);
65 static HRESULT WINAPI
segment_QueryInterface(IDirectMusicSegment8
*iface
, REFIID riid
, void **ret_iface
)
67 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
69 TRACE("(%p, %s, %p)\n", This
, debugstr_dmguid(riid
), ret_iface
);
73 if (IsEqualIID (riid
, &IID_IUnknown
) || IsEqualIID (riid
, &IID_IDirectMusicSegment
) ||
74 IsEqualIID(riid
, &IID_IDirectMusicSegment2
) ||
75 IsEqualIID (riid
, &IID_IDirectMusicSegment8
))
77 else if (IsEqualIID (riid
, &IID_IDirectMusicObject
))
78 *ret_iface
= &This
->dmobj
.IDirectMusicObject_iface
;
79 else if (IsEqualIID (riid
, &IID_IPersistStream
))
80 *ret_iface
= &This
->dmobj
.IPersistStream_iface
;
82 WARN("(%p, %s, %p): not found\n", This
, debugstr_dmguid(riid
), ret_iface
);
86 IUnknown_AddRef((IUnknown
*)*ret_iface
);
90 static ULONG WINAPI
segment_AddRef(IDirectMusicSegment8
*iface
)
92 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
93 LONG ref
= InterlockedIncrement(&This
->ref
);
95 TRACE("(%p) ref=%ld\n", This
, ref
);
100 static ULONG WINAPI
segment_Release(IDirectMusicSegment8
*iface
)
102 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
103 LONG ref
= InterlockedDecrement(&This
->ref
);
105 TRACE("(%p) ref=%ld\n", This
, ref
);
108 struct track_entry
*entry
, *next
;
110 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &This
->tracks
, struct track_entry
, entry
)
112 list_remove(&entry
->entry
);
113 track_entry_destroy(entry
);
117 free(This
->wave_data
);
125 static HRESULT WINAPI
segment_GetLength(IDirectMusicSegment8
*iface
, MUSIC_TIME
*length
)
127 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
129 TRACE("(%p, %p)\n", This
, length
);
131 if (!length
) return E_POINTER
;
132 *length
= This
->header
.mtLength
;
137 static HRESULT WINAPI
segment_SetLength(IDirectMusicSegment8
*iface
, MUSIC_TIME length
)
139 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
141 TRACE("(%p, %ld)\n", This
, length
);
143 This
->header
.mtLength
= length
;
148 static HRESULT WINAPI
segment_GetRepeats(IDirectMusicSegment8
*iface
, DWORD
*repeats
)
150 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
152 TRACE("(%p, %p)\n", This
, repeats
);
154 if (!repeats
) return E_POINTER
;
155 *repeats
= This
->header
.dwRepeats
;
160 static HRESULT WINAPI
segment_SetRepeats(IDirectMusicSegment8
*iface
, DWORD repeats
)
162 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
164 TRACE("(%p, %ld)\n", This
, repeats
);
165 This
->header
.dwRepeats
= repeats
;
170 static HRESULT WINAPI
segment_GetDefaultResolution(IDirectMusicSegment8
*iface
, DWORD
*resolution
)
172 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
174 TRACE("(%p, %p)\n", This
, resolution
);
176 if (!resolution
) return E_POINTER
;
177 *resolution
= This
->header
.dwResolution
;
182 static HRESULT WINAPI
segment_SetDefaultResolution(IDirectMusicSegment8
*iface
, DWORD resolution
)
184 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
186 TRACE("(%p, %ld)\n", This
, resolution
);
187 This
->header
.dwResolution
= resolution
;
192 static HRESULT WINAPI
segment_GetTrack(IDirectMusicSegment8
*iface
, REFGUID type
, DWORD group
,
193 DWORD index
, IDirectMusicTrack
**ret_track
)
195 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
196 struct track_entry
*entry
;
199 TRACE("(%p, %s, %#lx, %#lx, %p)\n", This
, debugstr_dmguid(type
), group
, index
, ret_track
);
201 if (!ret_track
) return E_POINTER
;
203 LIST_FOR_EACH_ENTRY(entry
, &This
->tracks
, struct track_entry
, entry
)
205 if (group
!= -1 && !(entry
->dwGroupBits
& group
)) continue;
207 if (!IsEqualGUID(&GUID_NULL
, type
))
209 CLSID entry_type
= GUID_NULL
;
210 IPersistStream
*persist
;
212 if (SUCCEEDED(hr
= IDirectMusicTrack_QueryInterface(entry
->pTrack
, &IID_IPersistStream
, (void **)&persist
)))
214 hr
= IPersistStream_GetClassID(persist
, &entry_type
);
215 if (SUCCEEDED(hr
)) TRACE(" - %p -> %s\n", entry
, debugstr_dmguid(&entry_type
));
216 IPersistStream_Release(persist
);
219 if (!IsEqualGUID(&entry_type
, type
)) continue;
224 *ret_track
= entry
->pTrack
;
225 IDirectMusicTrack_AddRef(entry
->pTrack
);
230 return DMUS_E_NOT_FOUND
;
233 static HRESULT WINAPI
segment_GetTrackGroup(IDirectMusicSegment8
*iface
, IDirectMusicTrack
*track
, DWORD
*ret_group
)
235 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
236 struct track_entry
*entry
;
238 TRACE("(%p, %p, %p)\n", This
, track
, ret_group
);
240 if (!ret_group
) return E_POINTER
;
242 LIST_FOR_EACH_ENTRY(entry
, &This
->tracks
, struct track_entry
, entry
)
244 if (entry
->pTrack
== track
)
246 *ret_group
= entry
->dwGroupBits
;
251 return DMUS_E_NOT_FOUND
;
254 static HRESULT
segment_append_track(struct segment
*This
, IDirectMusicTrack
*track
, DWORD group
, DWORD flags
)
256 struct track_entry
*entry
;
259 if (!(entry
= calloc(1, sizeof(*entry
)))) return E_OUTOFMEMORY
;
260 entry
->dwGroupBits
= group
;
261 entry
->flags
= flags
;
262 entry
->pTrack
= track
;
263 IDirectMusicTrack_AddRef(track
);
265 hr
= IDirectMusicTrack_Init(track
, (IDirectMusicSegment
*)&This
->IDirectMusicSegment8_iface
);
266 if (FAILED(hr
)) track_entry_destroy(entry
);
267 else list_add_tail(&This
->tracks
, &entry
->entry
);
272 static HRESULT WINAPI
segment_InsertTrack(IDirectMusicSegment8
*iface
, IDirectMusicTrack
*track
, DWORD group
)
274 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
275 struct track_entry
*entry
;
277 TRACE("(%p, %p, %#lx)\n", This
, track
, group
);
279 if (!group
) return E_INVALIDARG
;
281 LIST_FOR_EACH_ENTRY(entry
, &This
->tracks
, struct track_entry
, entry
)
282 if (entry
->pTrack
== track
) return E_FAIL
;
284 return segment_append_track(This
, track
, group
, 0);
287 static HRESULT WINAPI
segment_RemoveTrack(IDirectMusicSegment8
*iface
, IDirectMusicTrack
*track
)
289 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
290 struct track_entry
*entry
;
292 TRACE("(%p, %p)\n", This
, track
);
294 LIST_FOR_EACH_ENTRY(entry
, &This
->tracks
, struct track_entry
, entry
)
296 if (entry
->pTrack
== track
)
298 list_remove(&entry
->entry
);
299 track_entry_destroy(entry
);
307 static HRESULT WINAPI
segment_InitPlay(IDirectMusicSegment8
*iface
,
308 IDirectMusicSegmentState
**state
, IDirectMusicPerformance
*performance
, DWORD flags
)
310 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
313 FIXME("(%p, %p, %p, %ld): semi-stub\n", This
, state
, performance
, flags
);
315 if (!state
) return E_POINTER
;
316 if (FAILED(hr
= create_dmsegmentstate(&IID_IDirectMusicSegmentState
, (void **)state
))) return hr
;
318 /* TODO: DMUS_SEGF_FLAGS */
322 static HRESULT WINAPI
segment_GetGraph(IDirectMusicSegment8
*iface
, IDirectMusicGraph
**graph
)
324 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
326 FIXME("(%p, %p): semi-stub\n", This
, graph
);
328 if (!graph
) return E_POINTER
;
329 if (!(*graph
= This
->pGraph
)) return DMUS_E_NOT_FOUND
;
330 IDirectMusicGraph_AddRef(This
->pGraph
);
335 static HRESULT WINAPI
segment_SetGraph(IDirectMusicSegment8
*iface
, IDirectMusicGraph
*graph
)
337 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
339 FIXME("(%p, %p): to complete\n", This
, graph
);
341 if (This
->pGraph
) IDirectMusicGraph_Release(This
->pGraph
);
342 if ((This
->pGraph
= graph
)) IDirectMusicGraph_AddRef(This
->pGraph
);
347 static HRESULT WINAPI
segment_AddNotificationType(IDirectMusicSegment8
*iface
, REFGUID rguidNotificationType
)
349 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
350 FIXME("(%p, %s): stub\n", This
, debugstr_dmguid(rguidNotificationType
));
354 static HRESULT WINAPI
segment_RemoveNotificationType(IDirectMusicSegment8
*iface
, REFGUID rguidNotificationType
)
356 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
357 FIXME("(%p, %s): stub\n", This
, debugstr_dmguid(rguidNotificationType
));
361 static HRESULT WINAPI
segment_GetParam(IDirectMusicSegment8
*iface
, REFGUID type
, DWORD group
,
362 DWORD index
, MUSIC_TIME time
, MUSIC_TIME
*next
, void *param
)
364 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
365 IDirectMusicTrack
*track
;
366 unsigned int i
, count
;
367 HRESULT hr
= DMUS_E_TRACK_NOT_FOUND
;
369 TRACE("(%p, %s, %#lx, %lu, %ld, %p, %p)\n", This
, debugstr_dmguid(type
), group
, index
, time
,
375 /* Index is relative to the search pattern: group bits and supported param type */
376 for (i
= 0, count
= 0; i
< DMUS_SEG_ANYTRACK
&& count
<= index
; i
++) {
377 if (FAILED(segment_GetTrack(iface
, &GUID_NULL
, group
, i
, &track
))) break;
378 if (FAILED(IDirectMusicTrack_IsParamSupported(track
, type
)))
380 if (index
== count
|| index
== DMUS_SEG_ANYTRACK
)
381 hr
= IDirectMusicTrack_GetParam(track
, type
, time
, next
, param
);
382 IDirectMusicTrack_Release(track
);
389 TRACE("(%p): not found\n", This
);
394 static HRESULT WINAPI
segment_SetParam(IDirectMusicSegment8
*iface
, REFGUID type
,
395 DWORD group
, DWORD index
, MUSIC_TIME music_time
, void *param
)
397 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
398 struct track_entry
*entry
;
401 TRACE("(%p, %s, %#lx, %ld, %ld, %p)\n", This
, debugstr_dmguid(type
), group
,
402 index
, music_time
, param
);
404 LIST_FOR_EACH_ENTRY(entry
, &This
->tracks
, struct track_entry
, entry
)
408 if (!(group
& entry
->dwGroupBits
)) continue;
409 if (index
!= DMUS_SEG_ALLTRACKS
&& index
--) continue;
412 if (SUCCEEDED(hr
= IDirectMusicTrack_IsParamSupported(entry
->pTrack
, type
))
413 && FAILED(hr
= IDirectMusicTrack_SetParam(entry
->pTrack
, type
, music_time
, param
)))
414 WARN("SetParam for track %p failed, hr %#lx\n", entry
->pTrack
, hr
);
420 static HRESULT WINAPI
segment_Clone(IDirectMusicSegment8
*iface
, MUSIC_TIME start
, MUSIC_TIME end
,
421 IDirectMusicSegment
**segment
)
423 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
424 struct segment
*clone
;
425 IDirectMusicTrack
*track
;
426 struct track_entry
*entry
;
429 TRACE("(%p, %ld, %ld, %p)\n", This
, start
, end
, segment
);
431 if (!segment
) return E_POINTER
;
433 if (!(clone
= segment_create()))
436 return E_OUTOFMEMORY
;
439 clone
->header
= This
->header
;
440 if ((clone
->pGraph
= This
->pGraph
)) IDirectMusicGraph_AddRef(clone
->pGraph
);
442 LIST_FOR_EACH_ENTRY(entry
, &This
->tracks
, struct track_entry
, entry
)
444 if (FAILED(hr
= IDirectMusicTrack_Clone(entry
->pTrack
, start
, end
, &track
))) break;
445 if (FAILED(hr
= segment_append_track(clone
, track
, entry
->dwGroupBits
, entry
->flags
))) break;
448 *segment
= (IDirectMusicSegment
*)&clone
->IDirectMusicSegment8_iface
;
449 return FAILED(hr
) ? S_FALSE
: S_OK
;
452 static HRESULT WINAPI
segment_SetStartPoint(IDirectMusicSegment8
*iface
, MUSIC_TIME start
)
454 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
456 TRACE("(%p, %ld)\n", This
, start
);
458 if (start
>= This
->header
.mtLength
) return DMUS_E_OUT_OF_RANGE
;
459 This
->header
.mtPlayStart
= start
;
464 static HRESULT WINAPI
segment_GetStartPoint(IDirectMusicSegment8
*iface
, MUSIC_TIME
*start
)
466 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
468 TRACE("(%p, %p)\n", This
, start
);
469 if (!start
) return E_POINTER
;
470 *start
= This
->header
.mtPlayStart
;
475 static HRESULT WINAPI
segment_SetLoopPoints(IDirectMusicSegment8
*iface
, MUSIC_TIME start
, MUSIC_TIME end
)
477 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
479 TRACE("(%p, %ld, %ld)\n", This
, start
, end
);
481 if ((end
|| start
) && (start
>= This
->header
.mtLength
|| end
> This
->header
.mtLength
|| start
> end
))
482 return DMUS_E_OUT_OF_RANGE
;
483 This
->header
.mtLoopStart
= start
;
484 This
->header
.mtLoopEnd
= end
;
489 static HRESULT WINAPI
segment_GetLoopPoints(IDirectMusicSegment8
*iface
, MUSIC_TIME
*start
, MUSIC_TIME
*end
)
491 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
493 TRACE("(%p, %p, %p)\n", This
, start
, end
);
495 if (!start
|| !end
) return E_POINTER
;
496 *start
= This
->header
.mtLoopStart
;
497 *end
= This
->header
.mtLoopEnd
;
502 static HRESULT WINAPI
segment_SetPChannelsUsed(IDirectMusicSegment8
*iface
, DWORD dwNumPChannels
, DWORD
*paPChannels
)
504 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
505 FIXME("(%p, %ld, %p): stub\n", This
, dwNumPChannels
, paPChannels
);
509 static HRESULT WINAPI
segment_SetTrackConfig(IDirectMusicSegment8
*iface
, REFGUID rguidTrackClassID
,
510 DWORD dwGroupBits
, DWORD dwIndex
, DWORD dwFlagsOn
, DWORD dwFlagsOff
)
512 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
513 FIXME("(%p, %s, %#lx, %ld, %ld, %ld): stub\n", This
, debugstr_dmguid(rguidTrackClassID
),
514 dwGroupBits
, dwIndex
, dwFlagsOn
, dwFlagsOff
);
518 static HRESULT WINAPI
segment_GetAudioPathConfig(IDirectMusicSegment8
*iface
, IUnknown
**ppAudioPathConfig
)
520 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
521 FIXME("(%p, %p): stub\n", This
, ppAudioPathConfig
);
525 static HRESULT WINAPI
segment_Compose(IDirectMusicSegment8
*iface
, MUSIC_TIME mtTime
,
526 IDirectMusicSegment
*pFromSegment
, IDirectMusicSegment
*pToSegment
, IDirectMusicSegment
**ppComposedSegment
)
528 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
529 FIXME("(%p, %ld, %p, %p, %p): stub\n", This
, mtTime
, pFromSegment
, pToSegment
, ppComposedSegment
);
533 static HRESULT WINAPI
segment_Download(IDirectMusicSegment8
*iface
, IUnknown
*audio_path
)
535 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
536 TRACE("(%p, %p)\n", This
, audio_path
);
537 return IDirectMusicSegment8_SetParam(iface
, &GUID_DownloadToAudioPath
, -1, DMUS_SEG_ALLTRACKS
, 0, audio_path
);
540 static HRESULT WINAPI
segment_Unload(IDirectMusicSegment8
*iface
, IUnknown
*audio_path
)
542 struct segment
*This
= impl_from_IDirectMusicSegment8(iface
);
543 TRACE("(%p, %p)\n", This
, audio_path
);
544 return IDirectMusicSegment8_SetParam(iface
, &GUID_UnloadFromAudioPath
, -1, DMUS_SEG_ALLTRACKS
, 0, audio_path
);
547 static const IDirectMusicSegment8Vtbl segment_vtbl
=
549 segment_QueryInterface
,
556 segment_GetDefaultResolution
,
557 segment_SetDefaultResolution
,
559 segment_GetTrackGroup
,
565 segment_AddNotificationType
,
566 segment_RemoveNotificationType
,
570 segment_SetStartPoint
,
571 segment_GetStartPoint
,
572 segment_SetLoopPoints
,
573 segment_GetLoopPoints
,
574 segment_SetPChannelsUsed
,
575 segment_SetTrackConfig
,
576 segment_GetAudioPathConfig
,
582 static HRESULT WINAPI
segment_object_ParseDescriptor(IDirectMusicObject
*iface
, IStream
*stream
, DMUS_OBJECTDESC
*desc
)
584 struct chunk_entry riff
= {0};
585 DWORD supported
= DMUS_OBJ_OBJECT
| DMUS_OBJ_VERSION
;
588 TRACE("(%p, %p, %p)\n", iface
, stream
, desc
);
590 if (!stream
|| !desc
)
593 if ((hr
= stream_get_chunk(stream
, &riff
)) != S_OK
)
595 if (riff
.id
!= FOURCC_RIFF
|| !(riff
.type
== DMUS_FOURCC_SEGMENT_FORM
||
596 riff
.type
== mmioFOURCC('W','A','V','E'))) {
597 TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff
));
598 stream_skip_chunk(stream
, &riff
);
602 if (riff
.type
== DMUS_FOURCC_SEGMENT_FORM
)
603 supported
|= DMUS_OBJ_NAME
| DMUS_OBJ_CATEGORY
;
605 supported
|= DMUS_OBJ_NAME_INFO
;
606 hr
= dmobj_parsedescriptor(stream
, &riff
, desc
, supported
);
610 desc
->guidClass
= CLSID_DirectMusicSegment
;
611 desc
->dwValidData
|= DMUS_OBJ_CLASS
;
613 dump_DMUS_OBJECTDESC(desc
);
617 static const IDirectMusicObjectVtbl segment_object_vtbl
=
619 dmobj_IDirectMusicObject_QueryInterface
,
620 dmobj_IDirectMusicObject_AddRef
,
621 dmobj_IDirectMusicObject_Release
,
622 dmobj_IDirectMusicObject_GetDescriptor
,
623 dmobj_IDirectMusicObject_SetDescriptor
,
624 segment_object_ParseDescriptor
,
627 static HRESULT
parse_track_form(struct segment
*This
, IStream
*stream
, const struct chunk_entry
*riff
)
629 struct chunk_entry chunk
= {.parent
= riff
};
630 IDirectMusicTrack
*track
= NULL
;
631 IPersistStream
*ps
= NULL
;
633 DMUS_IO_TRACK_HEADER thdr
;
634 DMUS_IO_TRACK_EXTRAS_HEADER txhdr
= {0};
637 TRACE("Parsing track form in %p: %s\n", stream
, debugstr_chunk(riff
));
639 /* First chunk must be the track header */
640 if (FAILED(hr
= stream_get_chunk(stream
, &chunk
)))
642 if (chunk
.id
!= DMUS_FOURCC_TRACK_CHUNK
)
643 return DMUS_E_TRACK_HDR_NOT_FIRST_CK
;
644 if (FAILED(hr
= stream_chunk_get_data(stream
, &chunk
, &thdr
, sizeof(thdr
))))
646 TRACE("Found DMUS_IO_TRACK_HEADER\n");
647 TRACE("\tclass: %s\n", debugstr_guid (&thdr
.guidClassID
));
648 TRACE("\tdwGroup: %#lx\n", thdr
.dwGroup
);
649 TRACE("\tckid: %s\n", debugstr_fourcc (thdr
.ckid
));
650 TRACE("\tfccType: %s\n", debugstr_fourcc (thdr
.fccType
));
652 if (!!thdr
.ckid
== !!thdr
.fccType
) {
653 WARN("One and only one of the ckid (%s) and fccType (%s) need to be set\n",
654 debugstr_fourcc(thdr
.ckid
), debugstr_fourcc(thdr
.fccType
));
655 return DMUS_E_INVALID_TRACK_HDR
;
658 /* Optional chunks */
659 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
) {
660 if ((thdr
.ckid
&& chunk
.id
== thdr
.ckid
) ||
661 (!thdr
.ckid
&& (chunk
.id
== FOURCC_LIST
|| chunk
.id
== FOURCC_RIFF
) &&
662 chunk
.type
== thdr
.fccType
))
665 if (chunk
.id
== DMUS_FOURCC_TRACK_EXTRAS_CHUNK
&&
666 SUCCEEDED(stream_chunk_get_data(stream
, &chunk
, &txhdr
, sizeof(txhdr
)))) {
667 FIXME("DMUS_IO_TRACK_EXTRAS_HEADER chunk not fully handled\n");
668 TRACE("dwFlags: %#lx, dwPriority: %lu\n", txhdr
.dwFlags
, txhdr
.dwPriority
);
672 return hr
== S_FALSE
? DMUS_E_TRACK_NOT_FOUND
: hr
;
674 /* Some DirectMusicTrack implementation expect the stream to start with their data chunk */
675 if (FAILED(hr
= IStream_Clone(stream
, &clone
)))
677 stream_reset_chunk_start(clone
, &chunk
);
680 hr
= CoCreateInstance(&thdr
.guidClassID
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IDirectMusicTrack
,
684 hr
= IDirectMusicTrack_QueryInterface(track
, &IID_IPersistStream
, (void **)&ps
);
687 hr
= IPersistStream_Load(ps
, clone
);
691 hr
= segment_append_track(This
, track
, thdr
.dwGroup
, txhdr
.dwFlags
);
695 IPersistStream_Release(ps
);
697 IDirectMusicTrack_Release(track
);
698 IStream_Release(clone
);
703 static HRESULT
parse_track_list(struct segment
*This
, IStream
*stream
, const struct chunk_entry
*trkl
)
705 struct chunk_entry chunk
= {.parent
= trkl
};
708 TRACE("Parsing track list in %p: %s\n", stream
, debugstr_chunk(trkl
));
710 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
711 if (chunk
.id
== FOURCC_RIFF
&& chunk
.type
== DMUS_FOURCC_TRACK_FORM
)
712 hr
= parse_track_form(This
, stream
, &chunk
);
714 return SUCCEEDED(hr
) ? S_OK
: hr
;
717 static inline void dump_segment_header(DMUS_IO_SEGMENT_HEADER
*h
, DWORD size
)
721 if (size
== offsetof(DMUS_IO_SEGMENT_HEADER
, rtLength
))
723 else if (size
== offsetof(DMUS_IO_SEGMENT_HEADER
, rtLoopStart
))
725 TRACE("Found DirectX%d DMUS_IO_SEGMENT_HEADER\n", dx
);
726 TRACE("\tdwRepeats: %lu\n", h
->dwRepeats
);
727 TRACE("\tmtLength: %lu\n", h
->mtLength
);
728 TRACE("\tmtPlayStart: %lu\n", h
->mtPlayStart
);
729 TRACE("\tmtLoopStart: %lu\n", h
->mtLoopStart
);
730 TRACE("\tmtLoopEnd: %lu\n", h
->mtLoopEnd
);
731 TRACE("\tdwResolution: %lu\n", h
->dwResolution
);
733 TRACE("\trtLength: %s\n", wine_dbgstr_longlong(h
->rtLength
));
734 TRACE("\tdwFlags: %lu\n", h
->dwFlags
);
735 TRACE("\tdwReserved: %lu\n", h
->dwReserved
);
738 TRACE("\trtLoopStart: %s\n", wine_dbgstr_longlong(h
->rtLoopStart
));
739 TRACE("\trtLoopEnd: %s\n", wine_dbgstr_longlong(h
->rtLoopEnd
));
740 if (size
> offsetof(DMUS_IO_SEGMENT_HEADER
, rtPlayStart
))
741 TRACE("\trtPlayStart: %s\n", wine_dbgstr_longlong(h
->rtPlayStart
));
745 static HRESULT
parse_dmsg_chunk(struct segment
*This
, IStream
*stream
, const struct chunk_entry
*riff
)
747 struct chunk_entry chunk
= {.parent
= riff
};
750 TRACE("Parsing segment form in %p: %s\n", stream
, debugstr_chunk(riff
));
752 if (FAILED(hr
= dmobj_parsedescriptor(stream
, riff
, &This
->dmobj
.desc
, DMUS_OBJ_NAME
| DMUS_OBJ_CATEGORY
))
753 || FAILED(hr
= stream_reset_chunk_data(stream
, riff
)))
756 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
) {
758 case DMUS_FOURCC_SEGMENT_CHUNK
:
759 /* DX9 without rtPlayStart field */
760 if (chunk
.size
== offsetof(DMUS_IO_SEGMENT_HEADER
, rtPlayStart
))
761 WARN("Missing rtPlayStart field in %s\n", debugstr_chunk(&chunk
));
762 /* DX7, DX8 and DX9 structure sizes */
763 else if (chunk
.size
!= offsetof(DMUS_IO_SEGMENT_HEADER
, rtLength
) &&
764 chunk
.size
!= offsetof(DMUS_IO_SEGMENT_HEADER
, rtLoopStart
) &&
765 chunk
.size
!= sizeof(DMUS_IO_SEGMENT_HEADER
)) {
766 WARN("Invalid size of %s\n", debugstr_chunk(&chunk
));
769 if (FAILED(hr
= stream_chunk_get_data(stream
, &chunk
, &This
->header
, chunk
.size
))) {
770 WARN("Failed to read data of %s\n", debugstr_chunk(&chunk
));
773 dump_segment_header(&This
->header
, chunk
.size
);
776 if (chunk
.type
== DMUS_FOURCC_TRACK_LIST
)
777 if (FAILED(hr
= parse_track_list(This
, stream
, &chunk
)))
781 FIXME("Loading of embedded RIFF form %s\n", debugstr_fourcc(chunk
.type
));
786 return SUCCEEDED(hr
) ? S_OK
: hr
;
789 static inline struct segment
*impl_from_IPersistStream(IPersistStream
*iface
)
791 return CONTAINING_RECORD(iface
, struct segment
, dmobj
.IPersistStream_iface
);
794 static HRESULT WINAPI
segment_persist_stream_Load(IPersistStream
*iface
, IStream
*stream
)
796 struct segment
*This
= impl_from_IPersistStream(iface
);
797 struct chunk_entry chunk
= {0};
800 TRACE("(%p, %p): Loading\n", This
, stream
);
802 if (!stream
) return E_POINTER
;
804 if ((hr
= stream_get_chunk(stream
, &chunk
)) == S_OK
)
806 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
808 case MAKE_IDTYPE(FOURCC_RIFF
, DMUS_FOURCC_SEGMENT_FORM
):
809 hr
= parse_dmsg_chunk(This
, stream
, &chunk
);
812 case mmioFOURCC('M','T','h','d'):
813 FIXME("MIDI file loading not supported\n");
816 case MAKE_IDTYPE(FOURCC_RIFF
, mmioFOURCC('W','A','V','E')):
818 IDirectMusicTrack8
*track
;
820 TRACE("Loading segment %p from wave file\n", This
);
822 This
->header
.mtLength
= 1;
823 if (FAILED(hr
= wave_track_create_from_chunk(stream
, &chunk
, &track
))) break;
824 hr
= segment_append_track(This
, (IDirectMusicTrack
*)track
, 1, 0);
829 WARN("Invalid segment chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
830 hr
= DMUS_E_UNSUPPORTED_STREAM
;
835 stream_skip_chunk(stream
, &chunk
);
838 WARN("Failed to load segment from stream %p, hr %#lx\n", stream
, hr
);
839 return DMUS_E_UNSUPPORTED_STREAM
;
842 This
->dmobj
.desc
.guidClass
= CLSID_DirectMusicSegment
;
843 This
->dmobj
.desc
.dwValidData
|= DMUS_OBJ_CLASS
;
848 static const IPersistStreamVtbl segment_persist_stream_vtbl
=
850 dmobj_IPersistStream_QueryInterface
,
851 dmobj_IPersistStream_AddRef
,
852 dmobj_IPersistStream_Release
,
853 dmobj_IPersistStream_GetClassID
,
854 unimpl_IPersistStream_IsDirty
,
855 segment_persist_stream_Load
,
856 unimpl_IPersistStream_Save
,
857 unimpl_IPersistStream_GetSizeMax
,
860 static struct segment
*segment_create(void)
864 if (!(obj
= calloc(1, sizeof(*obj
)))) return NULL
;
865 obj
->IDirectMusicSegment8_iface
.lpVtbl
= &segment_vtbl
;
867 dmobject_init(&obj
->dmobj
, &CLSID_DirectMusicSegment
, (IUnknown
*)&obj
->IDirectMusicSegment8_iface
);
868 obj
->dmobj
.IDirectMusicObject_iface
.lpVtbl
= &segment_object_vtbl
;
869 obj
->dmobj
.IPersistStream_iface
.lpVtbl
= &segment_persist_stream_vtbl
;
870 list_init(&obj
->tracks
);
875 /* for ClassFactory */
876 HRESULT
create_dmsegment(REFIID guid
, void **ret_iface
)
881 if (!(obj
= segment_create()))
884 return E_OUTOFMEMORY
;
887 hr
= IDirectMusicSegment8_QueryInterface(&obj
->IDirectMusicSegment8_iface
, guid
, ret_iface
);
888 IDirectMusicSegment8_Release(&obj
->IDirectMusicSegment8_iface
);