dmime: Rename IDirectMusicSegment8Impl method prefix to segment.
[wine.git] / dlls / dmime / segment.c
blobf86e4a2bb5f70c7724c3bfebd596ac5821f16ee8
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"
22 #include "dmobject.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(dmime);
26 /*****************************************************************************
27 * IDirectMusicSegmentImpl implementation
29 typedef struct IDirectMusicSegment8Impl {
30 IDirectMusicSegment8 IDirectMusicSegment8_iface;
31 struct dmobject dmobj;
32 LONG ref;
33 DMUS_IO_SEGMENT_HEADER header;
34 IDirectMusicGraph *pGraph;
35 struct list Tracks;
37 PCMWAVEFORMAT wave_format;
38 void *wave_data;
39 int data_size;
40 } IDirectMusicSegment8Impl;
42 static IDirectMusicSegment8Impl *segment_create(void);
44 static inline IDirectMusicSegment8Impl *impl_from_IDirectMusicSegment8(IDirectMusicSegment8 *iface)
46 return CONTAINING_RECORD(iface, IDirectMusicSegment8Impl, IDirectMusicSegment8_iface);
49 static HRESULT WINAPI segment_QueryInterface(IDirectMusicSegment8 *iface, REFIID riid, void **ret_iface)
51 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
53 TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface);
55 *ret_iface = NULL;
57 if (IsEqualIID (riid, &IID_IUnknown) || IsEqualIID (riid, &IID_IDirectMusicSegment) ||
58 IsEqualIID(riid, &IID_IDirectMusicSegment2) ||
59 IsEqualIID (riid, &IID_IDirectMusicSegment8))
60 *ret_iface = iface;
61 else if (IsEqualIID (riid, &IID_IDirectMusicObject))
62 *ret_iface = &This->dmobj.IDirectMusicObject_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 segment_AddRef(IDirectMusicSegment8 *iface)
76 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
77 LONG ref = InterlockedIncrement(&This->ref);
79 TRACE("(%p) ref=%ld\n", This, ref);
81 return ref;
84 static ULONG WINAPI segment_Release(IDirectMusicSegment8 *iface)
86 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
87 LONG ref = InterlockedDecrement(&This->ref);
89 TRACE("(%p) ref=%ld\n", This, ref);
91 if (!ref) {
92 if (This->wave_data)
93 free(This->wave_data);
95 free(This);
98 return ref;
101 static HRESULT WINAPI segment_GetLength(IDirectMusicSegment8 *iface, MUSIC_TIME *pmtLength)
103 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
105 TRACE("(%p, %p)\n", This, pmtLength);
106 if (NULL == pmtLength) {
107 return E_POINTER;
109 *pmtLength = This->header.mtLength;
110 return S_OK;
113 static HRESULT WINAPI segment_SetLength(IDirectMusicSegment8 *iface, MUSIC_TIME mtLength)
115 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
117 TRACE("(%p, %ld)\n", This, mtLength);
118 This->header.mtLength = mtLength;
119 return S_OK;
122 static HRESULT WINAPI segment_GetRepeats(IDirectMusicSegment8 *iface, DWORD *pdwRepeats)
124 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
126 TRACE("(%p, %p)\n", This, pdwRepeats);
127 if (NULL == pdwRepeats) {
128 return E_POINTER;
130 *pdwRepeats = This->header.dwRepeats;
131 return S_OK;
134 static HRESULT WINAPI segment_SetRepeats(IDirectMusicSegment8 *iface, DWORD dwRepeats)
136 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
138 TRACE("(%p, %ld)\n", This, dwRepeats);
139 This->header.dwRepeats = dwRepeats;
140 return S_OK;
143 static HRESULT WINAPI segment_GetDefaultResolution(IDirectMusicSegment8 *iface, DWORD *pdwResolution)
145 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
147 TRACE("(%p, %p)\n", This, pdwResolution);
148 if (NULL == pdwResolution) {
149 return E_POINTER;
151 *pdwResolution = This->header.dwResolution;
152 return S_OK;
155 static HRESULT WINAPI segment_SetDefaultResolution(IDirectMusicSegment8 *iface, DWORD dwResolution)
157 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
159 TRACE("(%p, %ld)\n", This, dwResolution);
160 This->header.dwResolution = dwResolution;
161 return S_OK;
164 static HRESULT WINAPI segment_GetTrack(IDirectMusicSegment8 *iface, REFGUID rguidType,
165 DWORD dwGroupBits, DWORD dwIndex, IDirectMusicTrack **ppTrack)
167 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
168 CLSID pIt_clsid;
169 struct list* pEntry = NULL;
170 LPDMUS_PRIVATE_SEGMENT_TRACK pIt = NULL;
171 IPersistStream* pCLSIDStream = NULL;
172 HRESULT hr = S_OK;
174 TRACE("(%p, %s, %#lx, %#lx, %p)\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, ppTrack);
176 if (NULL == ppTrack) {
177 return E_POINTER;
180 LIST_FOR_EACH (pEntry, &This->Tracks) {
181 pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_SEGMENT_TRACK, entry);
182 TRACE(" - %p -> %#lx,%p\n", pIt, pIt->dwGroupBits, pIt->pTrack);
183 if (0xFFFFFFFF != dwGroupBits && 0 == (pIt->dwGroupBits & dwGroupBits)) continue ;
184 if (FALSE == IsEqualGUID(&GUID_NULL, rguidType)) {
186 * it rguidType is not null we must check if CLSIDs are equal
187 * and the unique way to get it is using IPersistStream Interface
189 hr = IDirectMusicTrack_QueryInterface(pIt->pTrack, &IID_IPersistStream, (void**) &pCLSIDStream);
190 if (FAILED(hr)) {
191 ERR("(%p): object %p don't implement IPersistStream Interface. Expect a crash (critical problem)\n", This, pIt->pTrack);
192 continue ;
194 hr = IPersistStream_GetClassID(pCLSIDStream, &pIt_clsid);
195 IPersistStream_Release(pCLSIDStream); pCLSIDStream = NULL;
196 if (FAILED(hr)) {
197 ERR("(%p): non-implemented GetClassID for object %p\n", This, pIt->pTrack);
198 continue ;
200 TRACE(" - %p -> %s\n", pIt, debugstr_dmguid(&pIt_clsid));
201 if (FALSE == IsEqualGUID(&pIt_clsid, rguidType)) continue ;
203 if (0 == dwIndex) {
204 *ppTrack = pIt->pTrack;
205 IDirectMusicTrack_AddRef(*ppTrack);
206 return S_OK;
208 --dwIndex;
210 return DMUS_E_NOT_FOUND;
213 static HRESULT WINAPI segment_GetTrackGroup(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack, DWORD *pdwGroupBits)
215 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
216 struct list* pEntry = NULL;
217 LPDMUS_PRIVATE_SEGMENT_TRACK pIt = NULL;
219 TRACE("(%p, %p, %p)\n", This, pTrack, pdwGroupBits);
221 if (NULL == pdwGroupBits) {
222 return E_POINTER;
225 LIST_FOR_EACH (pEntry, &This->Tracks) {
226 pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_SEGMENT_TRACK, entry);
227 TRACE(" - %p -> %#lx, %p\n", pIt, pIt->dwGroupBits, pIt->pTrack);
228 if (NULL != pIt && pIt->pTrack == pTrack) {
229 *pdwGroupBits = pIt->dwGroupBits;
230 return S_OK;
234 return DMUS_E_NOT_FOUND;
237 static HRESULT WINAPI segment_InsertTrack(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack, DWORD group)
239 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
240 DWORD i = 0;
241 struct list* pEntry = NULL;
242 LPDMUS_PRIVATE_SEGMENT_TRACK pIt = NULL;
243 LPDMUS_PRIVATE_SEGMENT_TRACK pNewSegTrack = NULL;
245 TRACE("(%p, %p, %#lx)\n", This, pTrack, group);
247 if (!group)
248 return E_INVALIDARG;
250 LIST_FOR_EACH (pEntry, &This->Tracks) {
251 i++;
252 pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_SEGMENT_TRACK, entry);
253 TRACE(" - #%lu: %p -> %#lx, %p\n", i, pIt, pIt->dwGroupBits, pIt->pTrack);
254 if (NULL != pIt && pIt->pTrack == pTrack) {
255 ERR("(%p, %p): track is already in list\n", This, pTrack);
256 return E_FAIL;
260 if (!(pNewSegTrack = calloc(1, sizeof(*pNewSegTrack)))) return E_OUTOFMEMORY;
262 pNewSegTrack->dwGroupBits = group;
263 pNewSegTrack->pTrack = pTrack;
264 IDirectMusicTrack_Init(pTrack, (IDirectMusicSegment *)iface);
265 IDirectMusicTrack_AddRef(pTrack);
266 list_add_tail (&This->Tracks, &pNewSegTrack->entry);
268 return S_OK;
271 static HRESULT WINAPI segment_RemoveTrack(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack)
273 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
274 struct list* pEntry = NULL;
275 LPDMUS_PRIVATE_SEGMENT_TRACK pIt = NULL;
277 TRACE("(%p, %p)\n", This, pTrack);
279 LIST_FOR_EACH (pEntry, &This->Tracks) {
280 pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_SEGMENT_TRACK, entry);
281 if (pIt->pTrack == pTrack) {
282 TRACE("(%p, %p): track in list\n", This, pTrack);
284 list_remove(&pIt->entry);
285 IDirectMusicTrack_Init(pIt->pTrack, NULL);
286 IDirectMusicTrack_Release(pIt->pTrack);
287 free(pIt);
289 return S_OK;
293 return S_FALSE;
296 static HRESULT WINAPI segment_InitPlay(IDirectMusicSegment8 *iface,
297 IDirectMusicSegmentState **ppSegState, IDirectMusicPerformance *pPerformance, DWORD dwFlags)
299 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
300 HRESULT hr;
302 FIXME("(%p, %p, %p, %ld): semi-stub\n", This, ppSegState, pPerformance, dwFlags);
303 if (NULL == ppSegState) {
304 return E_POINTER;
306 hr = create_dmsegmentstate(&IID_IDirectMusicSegmentState,(void**) ppSegState);
307 if (FAILED(hr)) {
308 return hr;
310 /* TODO: DMUS_SEGF_FLAGS */
311 return S_OK;
314 static HRESULT WINAPI segment_GetGraph(IDirectMusicSegment8 *iface, IDirectMusicGraph **ppGraph)
316 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
318 FIXME("(%p, %p): semi-stub\n", This, ppGraph);
319 if (NULL == ppGraph) {
320 return E_POINTER;
322 if (NULL == This->pGraph) {
323 return DMUS_E_NOT_FOUND;
325 /**
326 * should return This, as seen in msdn
327 * "...The segment object implements IDirectMusicGraph directly..."
329 *ppGraph = This->pGraph;
330 IDirectMusicGraph_AddRef(This->pGraph);
331 return S_OK;
334 static HRESULT WINAPI segment_SetGraph(IDirectMusicSegment8 *iface, IDirectMusicGraph *pGraph)
336 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
338 FIXME("(%p, %p): to complete\n", This, pGraph);
339 if (NULL != This->pGraph) {
340 IDirectMusicGraph_Release(This->pGraph);
342 This->pGraph = pGraph;
343 if (NULL != This->pGraph) {
344 IDirectMusicGraph_AddRef(This->pGraph);
346 return S_OK;
349 static HRESULT WINAPI segment_AddNotificationType(IDirectMusicSegment8 *iface, REFGUID rguidNotificationType)
351 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
352 FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType));
353 return S_OK;
356 static HRESULT WINAPI segment_RemoveNotificationType(IDirectMusicSegment8 *iface, REFGUID rguidNotificationType)
358 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
359 FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType));
360 return S_OK;
363 static HRESULT WINAPI segment_GetParam(IDirectMusicSegment8 *iface, REFGUID type, DWORD group,
364 DWORD index, MUSIC_TIME time, MUSIC_TIME *next, void *param)
366 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
367 IDirectMusicTrack *track;
368 unsigned int i, count;
369 HRESULT hr = DMUS_E_TRACK_NOT_FOUND;
371 TRACE("(%p, %s, %#lx, %lu, %ld, %p, %p)\n", This, debugstr_dmguid(type), group, index, time,
372 next, param);
374 if (!type)
375 return E_POINTER;
377 /* Index is relative to the search pattern: group bits and supported param type */
378 for (i = 0, count = 0; i < DMUS_SEG_ANYTRACK && count <= index; i++) {
379 if (FAILED(segment_GetTrack(iface, &GUID_NULL, group, i, &track))) break;
380 if (FAILED(IDirectMusicTrack_IsParamSupported(track, type)))
381 continue;
382 if (index == count || index == DMUS_SEG_ANYTRACK)
383 hr = IDirectMusicTrack_GetParam(track, type, time, next, param);
384 IDirectMusicTrack_Release(track);
386 if (SUCCEEDED(hr))
387 return hr;
388 count++;
391 TRACE("(%p): not found\n", This);
393 return hr;
396 static HRESULT WINAPI segment_SetParam(IDirectMusicSegment8 *iface, REFGUID rguidType,
397 DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam)
399 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
400 FIXME("(%p, %s, %#lx, %ld, %ld, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pParam);
401 return S_OK;
404 static HRESULT WINAPI segment_Clone(IDirectMusicSegment8 *iface, MUSIC_TIME start, MUSIC_TIME end,
405 IDirectMusicSegment **segment)
407 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
408 IDirectMusicSegment8Impl *clone;
409 IDirectMusicTrack *track;
410 DMUS_PRIVATE_SEGMENT_TRACK *track_item, *cloned_item;
411 HRESULT hr;
412 BOOL track_clone_fail = FALSE;
414 TRACE("(%p, %ld, %ld, %p)\n", This, start, end, segment);
416 if (!segment)
417 return E_POINTER;
419 if (!(clone = segment_create()))
421 *segment = NULL;
422 return E_OUTOFMEMORY;
425 clone->header = This->header;
426 clone->pGraph = This->pGraph;
427 if (clone->pGraph)
428 IDirectMusicGraph_AddRef(clone->pGraph);
430 LIST_FOR_EACH_ENTRY(track_item, &This->Tracks, DMUS_PRIVATE_SEGMENT_TRACK, entry) {
431 if (SUCCEEDED(hr = IDirectMusicTrack_Clone(track_item->pTrack, start, end, &track))) {
432 if ((cloned_item = malloc(sizeof(*cloned_item))))
434 cloned_item->dwGroupBits = track_item->dwGroupBits;
435 cloned_item->flags = track_item->flags;
436 cloned_item->pTrack = track;
437 list_add_tail(&clone->Tracks, &cloned_item->entry);
438 continue;
440 else
442 IDirectMusicTrack_Release(track);
445 WARN("Failed to clone track %p: %#lx\n", track_item->pTrack, hr);
446 track_clone_fail = TRUE;
449 *segment = (IDirectMusicSegment *)&clone->IDirectMusicSegment8_iface;
451 return track_clone_fail ? S_FALSE : S_OK;
454 static HRESULT WINAPI segment_SetStartPoint(IDirectMusicSegment8 *iface, MUSIC_TIME mtStart)
456 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
458 TRACE("(%p, %ld)\n", This, mtStart);
459 if (mtStart >= This->header.mtLength) {
460 return DMUS_E_OUT_OF_RANGE;
462 This->header.mtPlayStart = mtStart;
463 return S_OK;
466 static HRESULT WINAPI segment_GetStartPoint(IDirectMusicSegment8 *iface, MUSIC_TIME *pmtStart)
468 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
470 TRACE("(%p, %p)\n", This, pmtStart);
471 if (NULL == pmtStart) {
472 return E_POINTER;
474 *pmtStart = This->header.mtPlayStart;
475 return S_OK;
478 static HRESULT WINAPI segment_SetLoopPoints(IDirectMusicSegment8 *iface, MUSIC_TIME start, MUSIC_TIME end)
480 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
482 TRACE("(%p, %ld, %ld)\n", This, start, end);
484 if ((end || start) &&
485 (start >= This->header.mtLength || end > This->header.mtLength || start > end))
486 return DMUS_E_OUT_OF_RANGE;
488 This->header.mtLoopStart = start;
489 This->header.mtLoopEnd = end;
491 return S_OK;
494 static HRESULT WINAPI segment_GetLoopPoints(IDirectMusicSegment8 *iface, MUSIC_TIME *pmtStart, MUSIC_TIME *pmtEnd)
496 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
498 TRACE("(%p, %p, %p)\n", This, pmtStart, pmtEnd);
499 if (NULL == pmtStart || NULL == pmtEnd) {
500 return E_POINTER;
502 *pmtStart = This->header.mtLoopStart;
503 *pmtEnd = This->header.mtLoopEnd;
504 return S_OK;
507 static HRESULT WINAPI segment_SetPChannelsUsed(IDirectMusicSegment8 *iface, DWORD dwNumPChannels, DWORD *paPChannels)
509 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
510 FIXME("(%p, %ld, %p): stub\n", This, dwNumPChannels, paPChannels);
511 return S_OK;
514 static HRESULT WINAPI segment_SetTrackConfig(IDirectMusicSegment8 *iface, REFGUID rguidTrackClassID,
515 DWORD dwGroupBits, DWORD dwIndex, DWORD dwFlagsOn, DWORD dwFlagsOff)
517 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
518 FIXME("(%p, %s, %#lx, %ld, %ld, %ld): stub\n", This, debugstr_dmguid(rguidTrackClassID), dwGroupBits, dwIndex, dwFlagsOn, dwFlagsOff);
519 return S_OK;
522 static HRESULT WINAPI segment_GetAudioPathConfig(IDirectMusicSegment8 *iface, IUnknown **ppAudioPathConfig)
524 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
525 FIXME("(%p, %p): stub\n", This, ppAudioPathConfig);
526 return S_OK;
529 static HRESULT WINAPI segment_Compose(IDirectMusicSegment8 *iface, MUSIC_TIME mtTime,
530 IDirectMusicSegment *pFromSegment, IDirectMusicSegment *pToSegment, IDirectMusicSegment **ppComposedSegment)
532 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
533 FIXME("(%p, %ld, %p, %p, %p): stub\n", This, mtTime, pFromSegment, pToSegment, ppComposedSegment);
534 return S_OK;
537 static HRESULT WINAPI segment_Download(IDirectMusicSegment8 *iface, IUnknown *pAudioPath)
539 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
540 FIXME("(%p, %p): stub\n", This, pAudioPath);
541 return S_OK;
544 static HRESULT WINAPI segment_Unload(IDirectMusicSegment8 *iface, IUnknown *pAudioPath)
546 IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface);
547 FIXME("(%p, %p): stub\n", This, pAudioPath);
548 return S_OK;
551 static const IDirectMusicSegment8Vtbl segment_vtbl =
553 segment_QueryInterface,
554 segment_AddRef,
555 segment_Release,
556 segment_GetLength,
557 segment_SetLength,
558 segment_GetRepeats,
559 segment_SetRepeats,
560 segment_GetDefaultResolution,
561 segment_SetDefaultResolution,
562 segment_GetTrack,
563 segment_GetTrackGroup,
564 segment_InsertTrack,
565 segment_RemoveTrack,
566 segment_InitPlay,
567 segment_GetGraph,
568 segment_SetGraph,
569 segment_AddNotificationType,
570 segment_RemoveNotificationType,
571 segment_GetParam,
572 segment_SetParam,
573 segment_Clone,
574 segment_SetStartPoint,
575 segment_GetStartPoint,
576 segment_SetLoopPoints,
577 segment_GetLoopPoints,
578 segment_SetPChannelsUsed,
579 segment_SetTrackConfig,
580 segment_GetAudioPathConfig,
581 segment_Compose,
582 segment_Download,
583 segment_Unload,
586 static HRESULT WINAPI segment_object_ParseDescriptor(IDirectMusicObject *iface, IStream *stream, DMUS_OBJECTDESC *desc)
588 struct chunk_entry riff = {0};
589 DWORD supported = DMUS_OBJ_OBJECT | DMUS_OBJ_VERSION;
590 HRESULT hr;
592 TRACE("(%p, %p, %p)\n", iface, stream, desc);
594 if (!stream || !desc)
595 return E_POINTER;
597 if ((hr = stream_get_chunk(stream, &riff)) != S_OK)
598 return hr;
599 if (riff.id != FOURCC_RIFF || !(riff.type == DMUS_FOURCC_SEGMENT_FORM ||
600 riff.type == mmioFOURCC('W','A','V','E'))) {
601 TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff));
602 stream_skip_chunk(stream, &riff);
603 return E_FAIL;
606 if (riff.type == DMUS_FOURCC_SEGMENT_FORM)
607 supported |= DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY;
608 else
609 supported |= DMUS_OBJ_NAME_INFO;
610 hr = dmobj_parsedescriptor(stream, &riff, desc, supported);
611 if (FAILED(hr))
612 return hr;
614 desc->guidClass = CLSID_DirectMusicSegment;
615 desc->dwValidData |= DMUS_OBJ_CLASS;
617 dump_DMUS_OBJECTDESC(desc);
618 return S_OK;
621 static const IDirectMusicObjectVtbl segment_object_vtbl =
623 dmobj_IDirectMusicObject_QueryInterface,
624 dmobj_IDirectMusicObject_AddRef,
625 dmobj_IDirectMusicObject_Release,
626 dmobj_IDirectMusicObject_GetDescriptor,
627 dmobj_IDirectMusicObject_SetDescriptor,
628 segment_object_ParseDescriptor,
631 static HRESULT parse_track_form(IDirectMusicSegment8Impl *This, IStream *stream,
632 const struct chunk_entry *riff)
634 struct chunk_entry chunk = {.parent = riff};
635 IDirectMusicTrack *track = NULL;
636 IPersistStream *ps = NULL;
637 IStream *clone;
638 DMUS_IO_TRACK_HEADER thdr;
639 DMUS_IO_TRACK_EXTRAS_HEADER txhdr = {0};
640 HRESULT hr;
641 DMUS_PRIVATE_SEGMENT_TRACK *item;
643 TRACE("Parsing track form in %p: %s\n", stream, debugstr_chunk(riff));
645 /* First chunk must be the track header */
646 if (FAILED(hr = stream_get_chunk(stream, &chunk)))
647 return hr;
648 if (chunk.id != DMUS_FOURCC_TRACK_CHUNK)
649 return DMUS_E_TRACK_HDR_NOT_FIRST_CK;
650 if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &thdr, sizeof(thdr))))
651 return hr;
652 TRACE("Found DMUS_IO_TRACK_HEADER\n");
653 TRACE("\tclass: %s\n", debugstr_guid (&thdr.guidClassID));
654 TRACE("\tdwGroup: %#lx\n", thdr.dwGroup);
655 TRACE("\tckid: %s\n", debugstr_fourcc (thdr.ckid));
656 TRACE("\tfccType: %s\n", debugstr_fourcc (thdr.fccType));
658 if (!!thdr.ckid == !!thdr.fccType) {
659 WARN("One and only one of the ckid (%s) and fccType (%s) need to be set\n",
660 debugstr_fourcc(thdr.ckid), debugstr_fourcc(thdr.fccType));
661 return DMUS_E_INVALID_TRACK_HDR;
664 /* Optional chunks */
665 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
666 if ((thdr.ckid && chunk.id == thdr.ckid) ||
667 (!thdr.ckid && (chunk.id == FOURCC_LIST || chunk.id == FOURCC_RIFF) &&
668 chunk.type == thdr.fccType))
669 break;
671 if (chunk.id == DMUS_FOURCC_TRACK_EXTRAS_CHUNK &&
672 SUCCEEDED(stream_chunk_get_data(stream, &chunk, &txhdr, sizeof(txhdr)))) {
673 FIXME("DMUS_IO_TRACK_EXTRAS_HEADER chunk not fully handled\n");
674 TRACE("dwFlags: %#lx, dwPriority: %lu\n", txhdr.dwFlags, txhdr.dwPriority);
677 if (hr != S_OK)
678 return hr == S_FALSE ? DMUS_E_TRACK_NOT_FOUND : hr;
680 /* Some DirectMusicTrack implementation expect the stream to start with their data chunk */
681 if (FAILED(hr = IStream_Clone(stream, &clone)))
682 return hr;
683 stream_reset_chunk_start(clone, &chunk);
685 /* Load the track */
686 hr = CoCreateInstance(&thdr.guidClassID, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicTrack,
687 (void **)&track);
688 if (FAILED(hr))
689 goto done;
690 hr = IDirectMusicTrack_QueryInterface(track, &IID_IPersistStream, (void **)&ps);
691 if (FAILED(hr))
692 goto done;
693 hr = IPersistStream_Load(ps, clone);
694 if (FAILED(hr))
695 goto done;
697 hr = IDirectMusicSegment8_InsertTrack(&This->IDirectMusicSegment8_iface, track, thdr.dwGroup);
698 if (FAILED(hr))
699 goto done;
701 item = LIST_ENTRY(list_tail(&This->Tracks), DMUS_PRIVATE_SEGMENT_TRACK, entry);
702 item->flags = txhdr.dwFlags;
704 done:
705 if (ps)
706 IPersistStream_Release(ps);
707 if (track)
708 IDirectMusicTrack_Release(track);
709 IStream_Release(clone);
711 return hr;
714 static HRESULT parse_track_list(IDirectMusicSegment8Impl *This, IStream *stream,
715 const struct chunk_entry *trkl)
717 struct chunk_entry chunk = {.parent = trkl};
718 HRESULT hr;
720 TRACE("Parsing track list in %p: %s\n", stream, debugstr_chunk(trkl));
722 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
723 if (chunk.id == FOURCC_RIFF && chunk.type == DMUS_FOURCC_TRACK_FORM)
724 hr = parse_track_form(This, stream, &chunk);
726 return SUCCEEDED(hr) ? S_OK : hr;
729 static inline void dump_segment_header(DMUS_IO_SEGMENT_HEADER *h, DWORD size)
731 unsigned int dx = 9;
733 if (size == offsetof(DMUS_IO_SEGMENT_HEADER, rtLength))
734 dx = 7;
735 else if (size == offsetof(DMUS_IO_SEGMENT_HEADER, rtLoopStart))
736 dx = 8;
737 TRACE("Found DirectX%d DMUS_IO_SEGMENT_HEADER\n", dx);
738 TRACE("\tdwRepeats: %lu\n", h->dwRepeats);
739 TRACE("\tmtLength: %lu\n", h->mtLength);
740 TRACE("\tmtPlayStart: %lu\n", h->mtPlayStart);
741 TRACE("\tmtLoopStart: %lu\n", h->mtLoopStart);
742 TRACE("\tmtLoopEnd: %lu\n", h->mtLoopEnd);
743 TRACE("\tdwResolution: %lu\n", h->dwResolution);
744 if (dx >= 8) {
745 TRACE("\trtLength: %s\n", wine_dbgstr_longlong(h->rtLength));
746 TRACE("\tdwFlags: %lu\n", h->dwFlags);
747 TRACE("\tdwReserved: %lu\n", h->dwReserved);
749 if (dx == 9) {
750 TRACE("\trtLoopStart: %s\n", wine_dbgstr_longlong(h->rtLoopStart));
751 TRACE("\trtLoopEnd: %s\n", wine_dbgstr_longlong(h->rtLoopEnd));
752 if (size > offsetof(DMUS_IO_SEGMENT_HEADER, rtPlayStart))
753 TRACE("\trtPlayStart: %s\n", wine_dbgstr_longlong(h->rtPlayStart));
757 static HRESULT parse_segment_form(IDirectMusicSegment8Impl *This, IStream *stream,
758 const struct chunk_entry *riff)
760 struct chunk_entry chunk = {.parent = riff};
761 HRESULT hr;
763 TRACE("Parsing segment form in %p: %s\n", stream, debugstr_chunk(riff));
765 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
766 switch (chunk.id) {
767 case DMUS_FOURCC_SEGMENT_CHUNK:
768 /* DX9 without rtPlayStart field */
769 if (chunk.size == offsetof(DMUS_IO_SEGMENT_HEADER, rtPlayStart))
770 WARN("Missing rtPlayStart field in %s\n", debugstr_chunk(&chunk));
771 /* DX7, DX8 and DX9 structure sizes */
772 else if (chunk.size != offsetof(DMUS_IO_SEGMENT_HEADER, rtLength) &&
773 chunk.size != offsetof(DMUS_IO_SEGMENT_HEADER, rtLoopStart) &&
774 chunk.size != sizeof(DMUS_IO_SEGMENT_HEADER)) {
775 WARN("Invalid size of %s\n", debugstr_chunk(&chunk));
776 break;
778 if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &This->header, chunk.size))) {
779 WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
780 return hr;
782 dump_segment_header(&This->header, chunk.size);
783 break;
784 case FOURCC_LIST:
785 if (chunk.type == DMUS_FOURCC_TRACK_LIST)
786 if (FAILED(hr = parse_track_list(This, stream, &chunk)))
787 return hr;
788 break;
789 case FOURCC_RIFF:
790 FIXME("Loading of embedded RIFF form %s\n", debugstr_fourcc(chunk.type));
791 break;
795 return SUCCEEDED(hr) ? S_OK : hr;
798 static inline IDirectMusicSegment8Impl *impl_from_IPersistStream(IPersistStream *iface)
800 return CONTAINING_RECORD(iface, IDirectMusicSegment8Impl, dmobj.IPersistStream_iface);
803 static HRESULT parse_wave_form(IDirectMusicSegment8Impl *This, IStream *stream, const struct chunk_entry *riff)
805 HRESULT hr;
806 struct chunk_entry chunk = {.parent = riff};
808 TRACE("Parsing segment wave in %p: %s\n", stream, debugstr_chunk(riff));
810 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
811 switch (chunk.id) {
812 case mmioFOURCC('f','m','t',' '): {
813 if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &This->wave_format,
814 sizeof(This->wave_format))) )
815 return hr;
816 TRACE("Wave Format tag %d\n", This->wave_format.wf.wFormatTag);
817 break;
819 case mmioFOURCC('d','a','t','a'): {
820 TRACE("Wave Data size %lu\n", chunk.size);
821 if (This->wave_data)
822 ERR("Multiple data streams detected\n");
823 This->wave_data = malloc(chunk.size);
824 This->data_size = chunk.size;
825 if (!This->wave_data)
826 return E_OUTOFMEMORY;
827 if (FAILED(hr = stream_chunk_get_data(stream, &chunk, This->wave_data, chunk.size)))
828 return hr;
829 break;
831 case FOURCC_LIST: {
832 FIXME("Skipping LIST tag\n");
833 break;
835 case mmioFOURCC('I','S','F','T'): {
836 FIXME("Skipping ISFT tag\n");
837 break;
839 case mmioFOURCC('f','a','c','t'): {
840 FIXME("Skipping fact tag\n");
841 break;
846 return SUCCEEDED(hr) ? S_OK : hr;
849 static HRESULT WINAPI segment_persist_stream_Load(IPersistStream *iface, IStream *stream)
851 IDirectMusicSegment8Impl *This = impl_from_IPersistStream(iface);
852 struct chunk_entry riff = {0};
853 HRESULT hr;
855 TRACE("(%p, %p): Loading\n", This, stream);
857 if (!stream)
858 return E_POINTER;
860 if (stream_get_chunk(stream, &riff) != S_OK ||
861 (riff.id != FOURCC_RIFF && riff.id != mmioFOURCC('M','T','h','d')))
862 return DMUS_E_UNSUPPORTED_STREAM;
863 stream_reset_chunk_start(stream, &riff);
865 if (riff.id == mmioFOURCC('M','T','h','d')) {
866 FIXME("MIDI file loading not supported\n");
867 return S_OK;
870 hr = IDirectMusicObject_ParseDescriptor(&This->dmobj.IDirectMusicObject_iface, stream,
871 &This->dmobj.desc);
872 if (FAILED(hr))
873 return hr;
874 stream_reset_chunk_data(stream, &riff);
876 if (riff.type == DMUS_FOURCC_SEGMENT_FORM)
877 hr = parse_segment_form(This, stream, &riff);
878 else if(riff.type == mmioFOURCC('W','A','V','E'))
879 hr = parse_wave_form(This, stream, &riff);
880 else {
881 FIXME("Unknown type %s\n", debugstr_chunk(&riff));
882 hr = S_OK;
885 return hr;
888 static const IPersistStreamVtbl segment_persist_stream_vtbl =
890 dmobj_IPersistStream_QueryInterface,
891 dmobj_IPersistStream_AddRef,
892 dmobj_IPersistStream_Release,
893 dmobj_IPersistStream_GetClassID,
894 unimpl_IPersistStream_IsDirty,
895 segment_persist_stream_Load,
896 unimpl_IPersistStream_Save,
897 unimpl_IPersistStream_GetSizeMax,
900 IDirectMusicSegment8Impl *segment_create(void)
902 IDirectMusicSegment8Impl *obj;
904 if (!(obj = calloc(1, sizeof(*obj)))) return NULL;
906 obj->IDirectMusicSegment8_iface.lpVtbl = &segment_vtbl;
907 obj->ref = 1;
908 dmobject_init(&obj->dmobj, &CLSID_DirectMusicSegment, (IUnknown *)&obj->IDirectMusicSegment8_iface);
909 obj->dmobj.IDirectMusicObject_iface.lpVtbl = &segment_object_vtbl;
910 obj->dmobj.IPersistStream_iface.lpVtbl = &segment_persist_stream_vtbl;
911 list_init (&obj->Tracks);
913 return obj;
916 /* for ClassFactory */
917 HRESULT create_dmsegment(REFIID guid, void **ret_iface)
919 IDirectMusicSegment8Impl *obj;
920 HRESULT hr;
922 if (!(obj = segment_create()))
924 *ret_iface = NULL;
925 return E_OUTOFMEMORY;
928 hr = IDirectMusicSegment8_QueryInterface(&obj->IDirectMusicSegment8_iface, guid, ret_iface);
929 IDirectMusicSegment8_Release(&obj->IDirectMusicSegment8_iface);
931 return hr;