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"
24 WINE_DEFAULT_DEBUG_CHANNEL(dmime
);
26 /*****************************************************************************
27 * IDirectMusicSegmentImpl implementation
29 typedef struct IDirectMusicSegment8Impl
{
30 IDirectMusicSegment8 IDirectMusicSegment8_iface
;
31 struct dmobject dmobj
;
33 DMUS_IO_SEGMENT_HEADER header
;
34 IDirectMusicGraph
*pGraph
;
37 PCMWAVEFORMAT wave_format
;
40 } IDirectMusicSegment8Impl
;
42 IDirectMusicSegment8Impl
*create_segment(void);
44 static inline IDirectMusicSegment8Impl
*impl_from_IDirectMusicSegment8(IDirectMusicSegment8
*iface
)
46 return CONTAINING_RECORD(iface
, IDirectMusicSegment8Impl
, IDirectMusicSegment8_iface
);
49 static HRESULT WINAPI
IDirectMusicSegment8Impl_QueryInterface(IDirectMusicSegment8
*iface
,
50 REFIID riid
, void **ret_iface
)
52 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
54 TRACE("(%p, %s, %p)\n", This
, debugstr_dmguid(riid
), ret_iface
);
58 if (IsEqualIID (riid
, &IID_IUnknown
) || IsEqualIID (riid
, &IID_IDirectMusicSegment
) ||
59 IsEqualIID(riid
, &IID_IDirectMusicSegment2
) ||
60 IsEqualIID (riid
, &IID_IDirectMusicSegment8
))
62 else if (IsEqualIID (riid
, &IID_IDirectMusicObject
))
63 *ret_iface
= &This
->dmobj
.IDirectMusicObject_iface
;
64 else if (IsEqualIID (riid
, &IID_IPersistStream
))
65 *ret_iface
= &This
->dmobj
.IPersistStream_iface
;
67 WARN("(%p, %s, %p): not found\n", This
, debugstr_dmguid(riid
), ret_iface
);
71 IUnknown_AddRef((IUnknown
*)*ret_iface
);
75 static ULONG WINAPI
IDirectMusicSegment8Impl_AddRef(IDirectMusicSegment8
*iface
)
77 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
78 LONG ref
= InterlockedIncrement(&This
->ref
);
80 TRACE("(%p) ref=%ld\n", This
, ref
);
85 static ULONG WINAPI
IDirectMusicSegment8Impl_Release(IDirectMusicSegment8
*iface
)
87 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
88 LONG ref
= InterlockedDecrement(&This
->ref
);
90 TRACE("(%p) ref=%ld\n", This
, ref
);
94 free(This
->wave_data
);
96 HeapFree(GetProcessHeap(), 0, This
);
103 static HRESULT WINAPI
IDirectMusicSegment8Impl_GetLength(IDirectMusicSegment8
*iface
,
104 MUSIC_TIME
*pmtLength
)
106 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
108 TRACE("(%p, %p)\n", This
, pmtLength
);
109 if (NULL
== pmtLength
) {
112 *pmtLength
= This
->header
.mtLength
;
116 static HRESULT WINAPI
IDirectMusicSegment8Impl_SetLength(IDirectMusicSegment8
*iface
,
119 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
121 TRACE("(%p, %ld)\n", This
, mtLength
);
122 This
->header
.mtLength
= mtLength
;
126 static HRESULT WINAPI
IDirectMusicSegment8Impl_GetRepeats(IDirectMusicSegment8
*iface
,
129 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
131 TRACE("(%p, %p)\n", This
, pdwRepeats
);
132 if (NULL
== pdwRepeats
) {
135 *pdwRepeats
= This
->header
.dwRepeats
;
139 static HRESULT WINAPI
IDirectMusicSegment8Impl_SetRepeats(IDirectMusicSegment8
*iface
,
142 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
144 TRACE("(%p, %ld)\n", This
, dwRepeats
);
145 This
->header
.dwRepeats
= dwRepeats
;
149 static HRESULT WINAPI
IDirectMusicSegment8Impl_GetDefaultResolution(IDirectMusicSegment8
*iface
,
150 DWORD
*pdwResolution
)
152 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
154 TRACE("(%p, %p)\n", This
, pdwResolution
);
155 if (NULL
== pdwResolution
) {
158 *pdwResolution
= This
->header
.dwResolution
;
162 static HRESULT WINAPI
IDirectMusicSegment8Impl_SetDefaultResolution(IDirectMusicSegment8
*iface
,
165 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
167 TRACE("(%p, %ld)\n", This
, dwResolution
);
168 This
->header
.dwResolution
= dwResolution
;
172 static HRESULT WINAPI
IDirectMusicSegment8Impl_GetTrack(IDirectMusicSegment8
*iface
,
173 REFGUID rguidType
, DWORD dwGroupBits
, DWORD dwIndex
, IDirectMusicTrack
**ppTrack
)
175 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
177 struct list
* pEntry
= NULL
;
178 LPDMUS_PRIVATE_SEGMENT_TRACK pIt
= NULL
;
179 IPersistStream
* pCLSIDStream
= NULL
;
182 TRACE("(%p, %s, %#lx, %#lx, %p)\n", This
, debugstr_dmguid(rguidType
), dwGroupBits
, dwIndex
, ppTrack
);
184 if (NULL
== ppTrack
) {
188 LIST_FOR_EACH (pEntry
, &This
->Tracks
) {
189 pIt
= LIST_ENTRY(pEntry
, DMUS_PRIVATE_SEGMENT_TRACK
, entry
);
190 TRACE(" - %p -> %#lx,%p\n", pIt
, pIt
->dwGroupBits
, pIt
->pTrack
);
191 if (0xFFFFFFFF != dwGroupBits
&& 0 == (pIt
->dwGroupBits
& dwGroupBits
)) continue ;
192 if (FALSE
== IsEqualGUID(&GUID_NULL
, rguidType
)) {
194 * it rguidType is not null we must check if CLSIDs are equal
195 * and the unique way to get it is using IPersistStream Interface
197 hr
= IDirectMusicTrack_QueryInterface(pIt
->pTrack
, &IID_IPersistStream
, (void**) &pCLSIDStream
);
199 ERR("(%p): object %p don't implement IPersistStream Interface. Expect a crash (critical problem)\n", This
, pIt
->pTrack
);
202 hr
= IPersistStream_GetClassID(pCLSIDStream
, &pIt_clsid
);
203 IPersistStream_Release(pCLSIDStream
); pCLSIDStream
= NULL
;
205 ERR("(%p): non-implemented GetClassID for object %p\n", This
, pIt
->pTrack
);
208 TRACE(" - %p -> %s\n", pIt
, debugstr_dmguid(&pIt_clsid
));
209 if (FALSE
== IsEqualGUID(&pIt_clsid
, rguidType
)) continue ;
212 *ppTrack
= pIt
->pTrack
;
213 IDirectMusicTrack_AddRef(*ppTrack
);
218 return DMUS_E_NOT_FOUND
;
221 static HRESULT WINAPI
IDirectMusicSegment8Impl_GetTrackGroup(IDirectMusicSegment8
*iface
,
222 IDirectMusicTrack
*pTrack
, DWORD
*pdwGroupBits
)
224 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
225 struct list
* pEntry
= NULL
;
226 LPDMUS_PRIVATE_SEGMENT_TRACK pIt
= NULL
;
228 TRACE("(%p, %p, %p)\n", This
, pTrack
, pdwGroupBits
);
230 if (NULL
== pdwGroupBits
) {
234 LIST_FOR_EACH (pEntry
, &This
->Tracks
) {
235 pIt
= LIST_ENTRY(pEntry
, DMUS_PRIVATE_SEGMENT_TRACK
, entry
);
236 TRACE(" - %p -> %#lx, %p\n", pIt
, pIt
->dwGroupBits
, pIt
->pTrack
);
237 if (NULL
!= pIt
&& pIt
->pTrack
== pTrack
) {
238 *pdwGroupBits
= pIt
->dwGroupBits
;
243 return DMUS_E_NOT_FOUND
;
246 static HRESULT WINAPI
IDirectMusicSegment8Impl_InsertTrack(IDirectMusicSegment8
*iface
,
247 IDirectMusicTrack
*pTrack
, DWORD group
)
249 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
251 struct list
* pEntry
= NULL
;
252 LPDMUS_PRIVATE_SEGMENT_TRACK pIt
= NULL
;
253 LPDMUS_PRIVATE_SEGMENT_TRACK pNewSegTrack
= NULL
;
255 TRACE("(%p, %p, %#lx)\n", This
, pTrack
, group
);
260 LIST_FOR_EACH (pEntry
, &This
->Tracks
) {
262 pIt
= LIST_ENTRY(pEntry
, DMUS_PRIVATE_SEGMENT_TRACK
, entry
);
263 TRACE(" - #%lu: %p -> %#lx, %p\n", i
, pIt
, pIt
->dwGroupBits
, pIt
->pTrack
);
264 if (NULL
!= pIt
&& pIt
->pTrack
== pTrack
) {
265 ERR("(%p, %p): track is already in list\n", This
, pTrack
);
270 pNewSegTrack
= HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY
, sizeof(DMUS_PRIVATE_SEGMENT_TRACK
));
271 if (NULL
== pNewSegTrack
)
272 return E_OUTOFMEMORY
;
274 pNewSegTrack
->dwGroupBits
= group
;
275 pNewSegTrack
->pTrack
= pTrack
;
276 IDirectMusicTrack_Init(pTrack
, (IDirectMusicSegment
*)iface
);
277 IDirectMusicTrack_AddRef(pTrack
);
278 list_add_tail (&This
->Tracks
, &pNewSegTrack
->entry
);
283 static HRESULT WINAPI
IDirectMusicSegment8Impl_RemoveTrack(IDirectMusicSegment8
*iface
,
284 IDirectMusicTrack
*pTrack
)
286 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
287 struct list
* pEntry
= NULL
;
288 LPDMUS_PRIVATE_SEGMENT_TRACK pIt
= NULL
;
290 TRACE("(%p, %p)\n", This
, pTrack
);
292 LIST_FOR_EACH (pEntry
, &This
->Tracks
) {
293 pIt
= LIST_ENTRY(pEntry
, DMUS_PRIVATE_SEGMENT_TRACK
, entry
);
294 if (pIt
->pTrack
== pTrack
) {
295 TRACE("(%p, %p): track in list\n", This
, pTrack
);
297 list_remove(&pIt
->entry
);
298 IDirectMusicTrack_Init(pIt
->pTrack
, NULL
);
299 IDirectMusicTrack_Release(pIt
->pTrack
);
300 HeapFree(GetProcessHeap(), 0, pIt
);
309 static HRESULT WINAPI
IDirectMusicSegment8Impl_InitPlay(IDirectMusicSegment8
*iface
,
310 IDirectMusicSegmentState
**ppSegState
, IDirectMusicPerformance
*pPerformance
, DWORD dwFlags
)
312 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
315 FIXME("(%p, %p, %p, %ld): semi-stub\n", This
, ppSegState
, pPerformance
, dwFlags
);
316 if (NULL
== ppSegState
) {
319 hr
= create_dmsegmentstate(&IID_IDirectMusicSegmentState
,(void**) ppSegState
);
323 /* TODO: DMUS_SEGF_FLAGS */
327 static HRESULT WINAPI
IDirectMusicSegment8Impl_GetGraph(IDirectMusicSegment8
*iface
,
328 IDirectMusicGraph
**ppGraph
)
330 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
332 FIXME("(%p, %p): semi-stub\n", This
, ppGraph
);
333 if (NULL
== ppGraph
) {
336 if (NULL
== This
->pGraph
) {
337 return DMUS_E_NOT_FOUND
;
340 * should return This, as seen in msdn
341 * "...The segment object implements IDirectMusicGraph directly..."
343 *ppGraph
= This
->pGraph
;
344 IDirectMusicGraph_AddRef(This
->pGraph
);
348 static HRESULT WINAPI
IDirectMusicSegment8Impl_SetGraph(IDirectMusicSegment8
*iface
,
349 IDirectMusicGraph
*pGraph
)
351 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
353 FIXME("(%p, %p): to complete\n", This
, pGraph
);
354 if (NULL
!= This
->pGraph
) {
355 IDirectMusicGraph_Release(This
->pGraph
);
357 This
->pGraph
= pGraph
;
358 if (NULL
!= This
->pGraph
) {
359 IDirectMusicGraph_AddRef(This
->pGraph
);
364 static HRESULT WINAPI
IDirectMusicSegment8Impl_AddNotificationType(IDirectMusicSegment8
*iface
,
365 REFGUID rguidNotificationType
)
367 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
368 FIXME("(%p, %s): stub\n", This
, debugstr_dmguid(rguidNotificationType
));
372 static HRESULT WINAPI
IDirectMusicSegment8Impl_RemoveNotificationType(IDirectMusicSegment8
*iface
,
373 REFGUID rguidNotificationType
)
375 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
376 FIXME("(%p, %s): stub\n", This
, debugstr_dmguid(rguidNotificationType
));
380 static HRESULT WINAPI
IDirectMusicSegment8Impl_GetParam(IDirectMusicSegment8
*iface
, REFGUID type
,
381 DWORD group
, DWORD index
, MUSIC_TIME time
, MUSIC_TIME
*next
, void *param
)
383 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
384 IDirectMusicTrack
*track
;
385 unsigned int i
, count
;
386 HRESULT hr
= DMUS_E_TRACK_NOT_FOUND
;
388 TRACE("(%p, %s, %#lx, %lu, %ld, %p, %p)\n", This
, debugstr_dmguid(type
), group
, index
, time
,
394 /* Index is relative to the search pattern: group bits and supported param type */
395 for (i
= 0, count
= 0; i
< DMUS_SEG_ANYTRACK
&& count
<= index
; i
++) {
396 if (FAILED(IDirectMusicSegment8Impl_GetTrack(iface
, &GUID_NULL
, group
, i
, &track
)))
398 if (FAILED(IDirectMusicTrack_IsParamSupported(track
, type
)))
400 if (index
== count
|| index
== DMUS_SEG_ANYTRACK
)
401 hr
= IDirectMusicTrack_GetParam(track
, type
, time
, next
, param
);
402 IDirectMusicTrack_Release(track
);
409 TRACE("(%p): not found\n", This
);
414 static HRESULT WINAPI
IDirectMusicSegment8Impl_SetParam(IDirectMusicSegment8
*iface
,
415 REFGUID rguidType
, DWORD dwGroupBits
, DWORD dwIndex
, MUSIC_TIME mtTime
, void *pParam
)
417 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
418 FIXME("(%p, %s, %#lx, %ld, %ld, %p): stub\n", This
, debugstr_dmguid(rguidType
), dwGroupBits
, dwIndex
, mtTime
, pParam
);
422 static HRESULT WINAPI
IDirectMusicSegment8Impl_Clone(IDirectMusicSegment8
*iface
, MUSIC_TIME start
, MUSIC_TIME end
,
423 IDirectMusicSegment
**segment
)
425 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
426 IDirectMusicSegment8Impl
*clone
;
427 IDirectMusicTrack
*track
;
428 DMUS_PRIVATE_SEGMENT_TRACK
*track_item
, *cloned_item
;
430 BOOL track_clone_fail
= FALSE
;
432 TRACE("(%p, %ld, %ld, %p)\n", This
, start
, end
, segment
);
437 if (!(clone
= create_segment())) {
439 return E_OUTOFMEMORY
;
442 clone
->header
= This
->header
;
443 clone
->pGraph
= This
->pGraph
;
445 IDirectMusicGraph_AddRef(clone
->pGraph
);
447 LIST_FOR_EACH_ENTRY(track_item
, &This
->Tracks
, DMUS_PRIVATE_SEGMENT_TRACK
, entry
) {
448 if (SUCCEEDED(hr
= IDirectMusicTrack_Clone(track_item
->pTrack
, start
, end
, &track
))) {
449 if ((cloned_item
= HeapAlloc(GetProcessHeap(), 0, sizeof(*cloned_item
)))) {
450 cloned_item
->dwGroupBits
= track_item
->dwGroupBits
;
451 cloned_item
->flags
= track_item
->flags
;
452 cloned_item
->pTrack
= track
;
453 list_add_tail(&clone
->Tracks
, &cloned_item
->entry
);
456 IDirectMusicTrack_Release(track
);
459 WARN("Failed to clone track %p: %#lx\n", track_item
->pTrack
, hr
);
460 track_clone_fail
= TRUE
;
463 *segment
= (IDirectMusicSegment
*)&clone
->IDirectMusicSegment8_iface
;
465 return track_clone_fail
? S_FALSE
: S_OK
;
468 static HRESULT WINAPI
IDirectMusicSegment8Impl_SetStartPoint(IDirectMusicSegment8
*iface
,
471 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
473 TRACE("(%p, %ld)\n", This
, mtStart
);
474 if (mtStart
>= This
->header
.mtLength
) {
475 return DMUS_E_OUT_OF_RANGE
;
477 This
->header
.mtPlayStart
= mtStart
;
481 static HRESULT WINAPI
IDirectMusicSegment8Impl_GetStartPoint(IDirectMusicSegment8
*iface
,
482 MUSIC_TIME
*pmtStart
)
484 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
486 TRACE("(%p, %p)\n", This
, pmtStart
);
487 if (NULL
== pmtStart
) {
490 *pmtStart
= This
->header
.mtPlayStart
;
494 static HRESULT WINAPI
IDirectMusicSegment8Impl_SetLoopPoints(IDirectMusicSegment8
*iface
,
495 MUSIC_TIME start
, MUSIC_TIME end
)
497 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
499 TRACE("(%p, %ld, %ld)\n", This
, start
, end
);
501 if ((end
|| start
) &&
502 (start
>= This
->header
.mtLength
|| end
> This
->header
.mtLength
|| start
> end
))
503 return DMUS_E_OUT_OF_RANGE
;
505 This
->header
.mtLoopStart
= start
;
506 This
->header
.mtLoopEnd
= end
;
511 static HRESULT WINAPI
IDirectMusicSegment8Impl_GetLoopPoints(IDirectMusicSegment8
*iface
,
512 MUSIC_TIME
*pmtStart
, MUSIC_TIME
*pmtEnd
)
514 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
516 TRACE("(%p, %p, %p)\n", This
, pmtStart
, pmtEnd
);
517 if (NULL
== pmtStart
|| NULL
== pmtEnd
) {
520 *pmtStart
= This
->header
.mtLoopStart
;
521 *pmtEnd
= This
->header
.mtLoopEnd
;
525 static HRESULT WINAPI
IDirectMusicSegment8Impl_SetPChannelsUsed(IDirectMusicSegment8
*iface
,
526 DWORD dwNumPChannels
, DWORD
*paPChannels
)
528 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
529 FIXME("(%p, %ld, %p): stub\n", This
, dwNumPChannels
, paPChannels
);
533 static HRESULT WINAPI
IDirectMusicSegment8Impl_SetTrackConfig(IDirectMusicSegment8
*iface
,
534 REFGUID rguidTrackClassID
, DWORD dwGroupBits
, DWORD dwIndex
, DWORD dwFlagsOn
,
537 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
538 FIXME("(%p, %s, %#lx, %ld, %ld, %ld): stub\n", This
, debugstr_dmguid(rguidTrackClassID
), dwGroupBits
, dwIndex
, dwFlagsOn
, dwFlagsOff
);
542 static HRESULT WINAPI
IDirectMusicSegment8Impl_GetAudioPathConfig(IDirectMusicSegment8
*iface
,
543 IUnknown
**ppAudioPathConfig
)
545 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
546 FIXME("(%p, %p): stub\n", This
, ppAudioPathConfig
);
550 static HRESULT WINAPI
IDirectMusicSegment8Impl_Compose(IDirectMusicSegment8
*iface
,
551 MUSIC_TIME mtTime
, IDirectMusicSegment
*pFromSegment
, IDirectMusicSegment
*pToSegment
,
552 IDirectMusicSegment
**ppComposedSegment
)
554 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
555 FIXME("(%p, %ld, %p, %p, %p): stub\n", This
, mtTime
, pFromSegment
, pToSegment
, ppComposedSegment
);
559 static HRESULT WINAPI
IDirectMusicSegment8Impl_Download(IDirectMusicSegment8
*iface
,
560 IUnknown
*pAudioPath
)
562 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
563 FIXME("(%p, %p): stub\n", This
, pAudioPath
);
567 static HRESULT WINAPI
IDirectMusicSegment8Impl_Unload(IDirectMusicSegment8
*iface
,
568 IUnknown
*pAudioPath
)
570 IDirectMusicSegment8Impl
*This
= impl_from_IDirectMusicSegment8(iface
);
571 FIXME("(%p, %p): stub\n", This
, pAudioPath
);
575 static const IDirectMusicSegment8Vtbl dmsegment8_vtbl
= {
576 IDirectMusicSegment8Impl_QueryInterface
,
577 IDirectMusicSegment8Impl_AddRef
,
578 IDirectMusicSegment8Impl_Release
,
579 IDirectMusicSegment8Impl_GetLength
,
580 IDirectMusicSegment8Impl_SetLength
,
581 IDirectMusicSegment8Impl_GetRepeats
,
582 IDirectMusicSegment8Impl_SetRepeats
,
583 IDirectMusicSegment8Impl_GetDefaultResolution
,
584 IDirectMusicSegment8Impl_SetDefaultResolution
,
585 IDirectMusicSegment8Impl_GetTrack
,
586 IDirectMusicSegment8Impl_GetTrackGroup
,
587 IDirectMusicSegment8Impl_InsertTrack
,
588 IDirectMusicSegment8Impl_RemoveTrack
,
589 IDirectMusicSegment8Impl_InitPlay
,
590 IDirectMusicSegment8Impl_GetGraph
,
591 IDirectMusicSegment8Impl_SetGraph
,
592 IDirectMusicSegment8Impl_AddNotificationType
,
593 IDirectMusicSegment8Impl_RemoveNotificationType
,
594 IDirectMusicSegment8Impl_GetParam
,
595 IDirectMusicSegment8Impl_SetParam
,
596 IDirectMusicSegment8Impl_Clone
,
597 IDirectMusicSegment8Impl_SetStartPoint
,
598 IDirectMusicSegment8Impl_GetStartPoint
,
599 IDirectMusicSegment8Impl_SetLoopPoints
,
600 IDirectMusicSegment8Impl_GetLoopPoints
,
601 IDirectMusicSegment8Impl_SetPChannelsUsed
,
602 IDirectMusicSegment8Impl_SetTrackConfig
,
603 IDirectMusicSegment8Impl_GetAudioPathConfig
,
604 IDirectMusicSegment8Impl_Compose
,
605 IDirectMusicSegment8Impl_Download
,
606 IDirectMusicSegment8Impl_Unload
609 /* IDirectMusicSegment8Impl IDirectMusicObject part: */
610 static HRESULT WINAPI
seg_IDirectMusicObject_ParseDescriptor(IDirectMusicObject
*iface
,
611 IStream
*stream
, DMUS_OBJECTDESC
*desc
)
613 struct chunk_entry riff
= {0};
614 DWORD supported
= DMUS_OBJ_OBJECT
| DMUS_OBJ_VERSION
;
617 TRACE("(%p, %p, %p)\n", iface
, stream
, desc
);
619 if (!stream
|| !desc
)
622 if ((hr
= stream_get_chunk(stream
, &riff
)) != S_OK
)
624 if (riff
.id
!= FOURCC_RIFF
|| !(riff
.type
== DMUS_FOURCC_SEGMENT_FORM
||
625 riff
.type
== mmioFOURCC('W','A','V','E'))) {
626 TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff
));
627 stream_skip_chunk(stream
, &riff
);
631 if (riff
.type
== DMUS_FOURCC_SEGMENT_FORM
)
632 supported
|= DMUS_OBJ_NAME
| DMUS_OBJ_CATEGORY
;
634 supported
|= DMUS_OBJ_NAME_INFO
;
635 hr
= dmobj_parsedescriptor(stream
, &riff
, desc
, supported
);
639 desc
->guidClass
= CLSID_DirectMusicSegment
;
640 desc
->dwValidData
|= DMUS_OBJ_CLASS
;
642 dump_DMUS_OBJECTDESC(desc
);
646 static const IDirectMusicObjectVtbl dmobject_vtbl
= {
647 dmobj_IDirectMusicObject_QueryInterface
,
648 dmobj_IDirectMusicObject_AddRef
,
649 dmobj_IDirectMusicObject_Release
,
650 dmobj_IDirectMusicObject_GetDescriptor
,
651 dmobj_IDirectMusicObject_SetDescriptor
,
652 seg_IDirectMusicObject_ParseDescriptor
655 /* IDirectMusicSegment8Impl IPersistStream part: */
656 static HRESULT
parse_track_form(IDirectMusicSegment8Impl
*This
, IStream
*stream
,
657 const struct chunk_entry
*riff
)
659 struct chunk_entry chunk
= {.parent
= riff
};
660 IDirectMusicTrack
*track
= NULL
;
661 IPersistStream
*ps
= NULL
;
663 DMUS_IO_TRACK_HEADER thdr
;
664 DMUS_IO_TRACK_EXTRAS_HEADER txhdr
= {0};
666 DMUS_PRIVATE_SEGMENT_TRACK
*item
;
668 TRACE("Parsing track form in %p: %s\n", stream
, debugstr_chunk(riff
));
670 /* First chunk must be the track header */
671 if (FAILED(hr
= stream_get_chunk(stream
, &chunk
)))
673 if (chunk
.id
!= DMUS_FOURCC_TRACK_CHUNK
)
674 return DMUS_E_TRACK_HDR_NOT_FIRST_CK
;
675 if (FAILED(hr
= stream_chunk_get_data(stream
, &chunk
, &thdr
, sizeof(thdr
))))
677 TRACE("Found DMUS_IO_TRACK_HEADER\n");
678 TRACE("\tclass: %s\n", debugstr_guid (&thdr
.guidClassID
));
679 TRACE("\tdwGroup: %#lx\n", thdr
.dwGroup
);
680 TRACE("\tckid: %s\n", debugstr_fourcc (thdr
.ckid
));
681 TRACE("\tfccType: %s\n", debugstr_fourcc (thdr
.fccType
));
683 if (!!thdr
.ckid
== !!thdr
.fccType
) {
684 WARN("One and only one of the ckid (%s) and fccType (%s) need to be set\n",
685 debugstr_fourcc(thdr
.ckid
), debugstr_fourcc(thdr
.fccType
));
686 return DMUS_E_INVALID_TRACK_HDR
;
689 /* Optional chunks */
690 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
) {
691 if ((thdr
.ckid
&& chunk
.id
== thdr
.ckid
) ||
692 (!thdr
.ckid
&& (chunk
.id
== FOURCC_LIST
|| chunk
.id
== FOURCC_RIFF
) &&
693 chunk
.type
== thdr
.fccType
))
696 if (chunk
.id
== DMUS_FOURCC_TRACK_EXTRAS_CHUNK
&&
697 SUCCEEDED(stream_chunk_get_data(stream
, &chunk
, &txhdr
, sizeof(txhdr
)))) {
698 FIXME("DMUS_IO_TRACK_EXTRAS_HEADER chunk not fully handled\n");
699 TRACE("dwFlags: %#lx, dwPriority: %lu\n", txhdr
.dwFlags
, txhdr
.dwPriority
);
703 return hr
== S_FALSE
? DMUS_E_TRACK_NOT_FOUND
: hr
;
705 /* Some DirectMusicTrack implementation expect the stream to start with their data chunk */
706 if (FAILED(hr
= IStream_Clone(stream
, &clone
)))
708 stream_reset_chunk_start(clone
, &chunk
);
711 hr
= CoCreateInstance(&thdr
.guidClassID
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IDirectMusicTrack
,
715 hr
= IDirectMusicTrack_QueryInterface(track
, &IID_IPersistStream
, (void **)&ps
);
718 hr
= IPersistStream_Load(ps
, clone
);
722 hr
= IDirectMusicSegment8_InsertTrack(&This
->IDirectMusicSegment8_iface
, track
, thdr
.dwGroup
);
726 item
= LIST_ENTRY(list_tail(&This
->Tracks
), DMUS_PRIVATE_SEGMENT_TRACK
, entry
);
727 item
->flags
= txhdr
.dwFlags
;
731 IPersistStream_Release(ps
);
733 IDirectMusicTrack_Release(track
);
734 IStream_Release(clone
);
739 static HRESULT
parse_track_list(IDirectMusicSegment8Impl
*This
, IStream
*stream
,
740 const struct chunk_entry
*trkl
)
742 struct chunk_entry chunk
= {.parent
= trkl
};
745 TRACE("Parsing track list in %p: %s\n", stream
, debugstr_chunk(trkl
));
747 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
748 if (chunk
.id
== FOURCC_RIFF
&& chunk
.type
== DMUS_FOURCC_TRACK_FORM
)
749 hr
= parse_track_form(This
, stream
, &chunk
);
751 return SUCCEEDED(hr
) ? S_OK
: hr
;
754 static inline void dump_segment_header(DMUS_IO_SEGMENT_HEADER
*h
, DWORD size
)
758 if (size
== offsetof(DMUS_IO_SEGMENT_HEADER
, rtLength
))
760 else if (size
== offsetof(DMUS_IO_SEGMENT_HEADER
, rtLoopStart
))
762 TRACE("Found DirectX%d DMUS_IO_SEGMENT_HEADER\n", dx
);
763 TRACE("\tdwRepeats: %lu\n", h
->dwRepeats
);
764 TRACE("\tmtLength: %lu\n", h
->mtLength
);
765 TRACE("\tmtPlayStart: %lu\n", h
->mtPlayStart
);
766 TRACE("\tmtLoopStart: %lu\n", h
->mtLoopStart
);
767 TRACE("\tmtLoopEnd: %lu\n", h
->mtLoopEnd
);
768 TRACE("\tdwResolution: %lu\n", h
->dwResolution
);
770 TRACE("\trtLength: %s\n", wine_dbgstr_longlong(h
->rtLength
));
771 TRACE("\tdwFlags: %lu\n", h
->dwFlags
);
772 TRACE("\tdwReserved: %lu\n", h
->dwReserved
);
775 TRACE("\trtLoopStart: %s\n", wine_dbgstr_longlong(h
->rtLoopStart
));
776 TRACE("\trtLoopEnd: %s\n", wine_dbgstr_longlong(h
->rtLoopEnd
));
777 if (size
> offsetof(DMUS_IO_SEGMENT_HEADER
, rtPlayStart
))
778 TRACE("\trtPlayStart: %s\n", wine_dbgstr_longlong(h
->rtPlayStart
));
782 static HRESULT
parse_segment_form(IDirectMusicSegment8Impl
*This
, IStream
*stream
,
783 const struct chunk_entry
*riff
)
785 struct chunk_entry chunk
= {.parent
= riff
};
788 TRACE("Parsing segment form in %p: %s\n", stream
, debugstr_chunk(riff
));
790 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
) {
792 case DMUS_FOURCC_SEGMENT_CHUNK
:
793 /* DX9 without rtPlayStart field */
794 if (chunk
.size
== offsetof(DMUS_IO_SEGMENT_HEADER
, rtPlayStart
))
795 WARN("Missing rtPlayStart field in %s\n", debugstr_chunk(&chunk
));
796 /* DX7, DX8 and DX9 structure sizes */
797 else if (chunk
.size
!= offsetof(DMUS_IO_SEGMENT_HEADER
, rtLength
) &&
798 chunk
.size
!= offsetof(DMUS_IO_SEGMENT_HEADER
, rtLoopStart
) &&
799 chunk
.size
!= sizeof(DMUS_IO_SEGMENT_HEADER
)) {
800 WARN("Invalid size of %s\n", debugstr_chunk(&chunk
));
803 if (FAILED(hr
= stream_chunk_get_data(stream
, &chunk
, &This
->header
, chunk
.size
))) {
804 WARN("Failed to read data of %s\n", debugstr_chunk(&chunk
));
807 dump_segment_header(&This
->header
, chunk
.size
);
810 if (chunk
.type
== DMUS_FOURCC_TRACK_LIST
)
811 if (FAILED(hr
= parse_track_list(This
, stream
, &chunk
)))
815 FIXME("Loading of embedded RIFF form %s\n", debugstr_fourcc(chunk
.type
));
820 return SUCCEEDED(hr
) ? S_OK
: hr
;
823 static inline IDirectMusicSegment8Impl
*impl_from_IPersistStream(IPersistStream
*iface
)
825 return CONTAINING_RECORD(iface
, IDirectMusicSegment8Impl
, dmobj
.IPersistStream_iface
);
828 static HRESULT
parse_wave_form(IDirectMusicSegment8Impl
*This
, IStream
*stream
, const struct chunk_entry
*riff
)
831 struct chunk_entry chunk
= {.parent
= riff
};
833 TRACE("Parsing segment wave in %p: %s\n", stream
, debugstr_chunk(riff
));
835 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
) {
837 case mmioFOURCC('f','m','t',' '): {
838 if (FAILED(hr
= stream_chunk_get_data(stream
, &chunk
, &This
->wave_format
,
839 sizeof(This
->wave_format
))) )
841 TRACE("Wave Format tag %d\n", This
->wave_format
.wf
.wFormatTag
);
844 case mmioFOURCC('d','a','t','a'): {
845 TRACE("Wave Data size %lu\n", chunk
.size
);
847 ERR("Multiple data streams detected\n");
848 This
->wave_data
= malloc(chunk
.size
);
849 This
->data_size
= chunk
.size
;
850 if (!This
->wave_data
)
851 return E_OUTOFMEMORY
;
852 if (FAILED(hr
= stream_chunk_get_data(stream
, &chunk
, This
->wave_data
, chunk
.size
)))
857 FIXME("Skipping LIST tag\n");
860 case mmioFOURCC('I','S','F','T'): {
861 FIXME("Skipping ISFT tag\n");
864 case mmioFOURCC('f','a','c','t'): {
865 FIXME("Skipping fact tag\n");
871 return SUCCEEDED(hr
) ? S_OK
: hr
;
874 static HRESULT WINAPI
seg_IPersistStream_Load(IPersistStream
*iface
, IStream
*stream
)
876 IDirectMusicSegment8Impl
*This
= impl_from_IPersistStream(iface
);
877 struct chunk_entry riff
= {0};
880 TRACE("(%p, %p): Loading\n", This
, stream
);
885 if (stream_get_chunk(stream
, &riff
) != S_OK
||
886 (riff
.id
!= FOURCC_RIFF
&& riff
.id
!= mmioFOURCC('M','T','h','d')))
887 return DMUS_E_UNSUPPORTED_STREAM
;
888 stream_reset_chunk_start(stream
, &riff
);
890 if (riff
.id
== mmioFOURCC('M','T','h','d')) {
891 FIXME("MIDI file loading not supported\n");
895 hr
= IDirectMusicObject_ParseDescriptor(&This
->dmobj
.IDirectMusicObject_iface
, stream
,
899 stream_reset_chunk_data(stream
, &riff
);
901 if (riff
.type
== DMUS_FOURCC_SEGMENT_FORM
)
902 hr
= parse_segment_form(This
, stream
, &riff
);
903 else if(riff
.type
== mmioFOURCC('W','A','V','E'))
904 hr
= parse_wave_form(This
, stream
, &riff
);
906 FIXME("Unknown type %s\n", debugstr_chunk(&riff
));
913 static const IPersistStreamVtbl persiststream_vtbl
= {
914 dmobj_IPersistStream_QueryInterface
,
915 dmobj_IPersistStream_AddRef
,
916 dmobj_IPersistStream_Release
,
917 dmobj_IPersistStream_GetClassID
,
918 unimpl_IPersistStream_IsDirty
,
919 seg_IPersistStream_Load
,
920 unimpl_IPersistStream_Save
,
921 unimpl_IPersistStream_GetSizeMax
924 IDirectMusicSegment8Impl
*create_segment(void)
926 IDirectMusicSegment8Impl
*obj
;
928 if (!(obj
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*obj
))))
931 obj
->IDirectMusicSegment8_iface
.lpVtbl
= &dmsegment8_vtbl
;
933 dmobject_init(&obj
->dmobj
, &CLSID_DirectMusicSegment
, (IUnknown
*)&obj
->IDirectMusicSegment8_iface
);
934 obj
->dmobj
.IDirectMusicObject_iface
.lpVtbl
= &dmobject_vtbl
;
935 obj
->dmobj
.IPersistStream_iface
.lpVtbl
= &persiststream_vtbl
;
936 list_init (&obj
->Tracks
);
943 /* for ClassFactory */
944 HRESULT
create_dmsegment(REFIID guid
, void **ret_iface
)
946 IDirectMusicSegment8Impl
*obj
;
949 if (!(obj
= create_segment())) {
951 return E_OUTOFMEMORY
;
954 hr
= IDirectMusicSegment8_QueryInterface(&obj
->IDirectMusicSegment8_iface
, guid
, ret_iface
);
955 IDirectMusicSegment8_Release(&obj
->IDirectMusicSegment8_iface
);