1 /* IDirectMusicWaveTrack Implementation
3 * Copyright (C) 2003-2004 Rok Mandeljc
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "dmime_private.h"
22 #include "wine/heap.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(dmime
);
26 /*****************************************************************************
27 * IDirectMusicWaveTrack implementation
31 DMUS_IO_WAVE_ITEM_HEADER header
;
32 IDirectMusicObject
*object
;
37 DMUS_IO_WAVE_PART_HEADER header
;
41 typedef struct IDirectMusicWaveTrack
{
42 IDirectMusicTrack8 IDirectMusicTrack8_iface
;
43 struct dmobject dmobj
; /* IPersistStream only */
45 DMUS_IO_WAVE_TRACK_HEADER header
;
47 } IDirectMusicWaveTrack
;
49 /* IDirectMusicWaveTrack IDirectMusicTrack8 part: */
50 static inline IDirectMusicWaveTrack
*impl_from_IDirectMusicTrack8(IDirectMusicTrack8
*iface
)
52 return CONTAINING_RECORD(iface
, IDirectMusicWaveTrack
, IDirectMusicTrack8_iface
);
55 static inline IDirectMusicWaveTrack
*impl_from_IPersistStream(IPersistStream
*iface
)
57 return CONTAINING_RECORD(iface
, IDirectMusicWaveTrack
, dmobj
.IPersistStream_iface
);
60 static HRESULT WINAPI
wave_track_QueryInterface(IDirectMusicTrack8
*iface
, REFIID riid
,
63 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
65 TRACE("(%p, %s, %p)\n", This
, debugstr_dmguid(riid
), ret_iface
);
69 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDirectMusicTrack
) ||
70 IsEqualIID(riid
, &IID_IDirectMusicTrack8
))
72 else if (IsEqualIID(riid
, &IID_IPersistStream
))
73 *ret_iface
= &This
->dmobj
.IPersistStream_iface
;
75 WARN("(%p, %s, %p): not found\n", This
, debugstr_dmguid(riid
), ret_iface
);
79 IUnknown_AddRef((IUnknown
*)*ret_iface
);
83 static ULONG WINAPI
wave_track_AddRef(IDirectMusicTrack8
*iface
)
85 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
86 LONG ref
= InterlockedIncrement(&This
->ref
);
88 TRACE("(%p) ref=%ld\n", This
, ref
);
93 static ULONG WINAPI
wave_track_Release(IDirectMusicTrack8
*iface
)
95 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
96 LONG ref
= InterlockedDecrement(&This
->ref
);
98 TRACE("(%p) ref=%ld\n", This
, ref
);
101 struct wave_item
*item
, *item2
;
102 struct wave_part
*part
, *part2
;
104 LIST_FOR_EACH_ENTRY_SAFE(part
, part2
, &This
->parts
, struct wave_part
, entry
) {
105 list_remove(&part
->entry
);
106 LIST_FOR_EACH_ENTRY_SAFE(item
, item2
, &part
->items
, struct wave_item
, entry
) {
107 list_remove(&item
->entry
);
109 IDirectMusicObject_Release(item
->object
);
116 DMIME_UnlockModule();
122 static HRESULT WINAPI
wave_track_Init(IDirectMusicTrack8
*iface
, IDirectMusicSegment
*pSegment
)
124 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
125 FIXME("(%p, %p): stub\n", This
, pSegment
);
129 static HRESULT WINAPI
wave_track_InitPlay(IDirectMusicTrack8
*iface
,
130 IDirectMusicSegmentState
*pSegmentState
, IDirectMusicPerformance
*pPerformance
,
131 void **ppStateData
, DWORD dwVirtualTrack8ID
, DWORD dwFlags
)
133 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
134 FIXME("(%p, %p, %p, %p, %ld, %ld): stub\n", This
, pSegmentState
, pPerformance
, ppStateData
, dwVirtualTrack8ID
, dwFlags
);
138 static HRESULT WINAPI
wave_track_EndPlay(IDirectMusicTrack8
*iface
, void *pStateData
)
140 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
141 FIXME("(%p, %p): stub\n", This
, pStateData
);
145 static HRESULT WINAPI
wave_track_Play(IDirectMusicTrack8
*iface
, void *pStateData
,
146 MUSIC_TIME mtStart
, MUSIC_TIME mtEnd
, MUSIC_TIME mtOffset
, DWORD dwFlags
,
147 IDirectMusicPerformance
*pPerf
, IDirectMusicSegmentState
*pSegSt
, DWORD dwVirtualID
)
149 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
150 FIXME("(%p, %p, %ld, %ld, %ld, %ld, %p, %p, %ld): stub\n", This
, pStateData
, mtStart
, mtEnd
, mtOffset
, dwFlags
, pPerf
, pSegSt
, dwVirtualID
);
154 static HRESULT WINAPI
wave_track_GetParam(IDirectMusicTrack8
*iface
, REFGUID type
, MUSIC_TIME time
,
155 MUSIC_TIME
*next
, void *param
)
157 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
159 TRACE("(%p, %s, %ld, %p, %p): not supported\n", This
, debugstr_dmguid(type
), time
, next
, param
);
160 return DMUS_E_GET_UNSUPPORTED
;
163 static HRESULT WINAPI
wave_track_SetParam(IDirectMusicTrack8
*iface
, REFGUID type
, MUSIC_TIME time
,
166 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
168 TRACE("(%p, %s, %ld, %p)\n", This
, debugstr_dmguid(type
), time
, param
);
170 if (IsEqualGUID(type
, &GUID_Disable_Auto_Download
)) {
171 FIXME("GUID_Disable_Auto_Download not handled yet\n");
174 if (IsEqualGUID(type
, &GUID_Download
)) {
175 FIXME("GUID_Download not handled yet\n");
178 if (IsEqualGUID(type
, &GUID_DownloadToAudioPath
)) {
179 FIXME("GUID_DownloadToAudioPath not handled yet\n");
182 if (IsEqualGUID(type
, &GUID_Enable_Auto_Download
)) {
183 FIXME("GUID_Enable_Auto_Download not handled yet\n");
186 if (IsEqualGUID(type
, &GUID_Unload
)) {
187 FIXME("GUID_Unload not handled yet\n");
190 if (IsEqualGUID(type
, &GUID_UnloadFromAudioPath
)) {
191 FIXME("GUID_UnloadFromAudioPath not handled yet\n");
195 return DMUS_E_TYPE_UNSUPPORTED
;
198 static HRESULT WINAPI
wave_track_IsParamSupported(IDirectMusicTrack8
*iface
, REFGUID type
)
200 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
201 static const GUID
*valid
[] = {
202 &GUID_Disable_Auto_Download
,
204 &GUID_DownloadToAudioPath
,
205 &GUID_Enable_Auto_Download
,
207 &GUID_UnloadFromAudioPath
211 TRACE("(%p, %s)\n", This
, debugstr_dmguid(type
));
213 for (i
= 0; i
< ARRAY_SIZE(valid
); i
++)
214 if (IsEqualGUID(type
, valid
[i
]))
217 TRACE("param unsupported\n");
218 return DMUS_E_TYPE_UNSUPPORTED
;
221 static HRESULT WINAPI
wave_track_AddNotificationType(IDirectMusicTrack8
*iface
, REFGUID notiftype
)
223 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
225 TRACE("(%p, %s): method not implemented\n", This
, debugstr_dmguid(notiftype
));
229 static HRESULT WINAPI
wave_track_RemoveNotificationType(IDirectMusicTrack8
*iface
,
232 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
234 TRACE("(%p, %s): method not implemented\n", This
, debugstr_dmguid(notiftype
));
238 static HRESULT WINAPI
wave_track_Clone(IDirectMusicTrack8
*iface
, MUSIC_TIME mtStart
,
239 MUSIC_TIME mtEnd
, IDirectMusicTrack
**ppTrack
)
241 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
242 FIXME("(%p, %ld, %ld, %p): stub\n", This
, mtStart
, mtEnd
, ppTrack
);
246 static HRESULT WINAPI
wave_track_PlayEx(IDirectMusicTrack8
*iface
, void *pStateData
,
247 REFERENCE_TIME rtStart
, REFERENCE_TIME rtEnd
, REFERENCE_TIME rtOffset
, DWORD dwFlags
,
248 IDirectMusicPerformance
*pPerf
, IDirectMusicSegmentState
*pSegSt
, DWORD dwVirtualID
)
250 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
251 FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %ld, %p, %p, %ld): stub\n", This
, pStateData
, wine_dbgstr_longlong(rtStart
),
252 wine_dbgstr_longlong(rtEnd
), wine_dbgstr_longlong(rtOffset
), dwFlags
, pPerf
, pSegSt
, dwVirtualID
);
256 static HRESULT WINAPI
wave_track_GetParamEx(IDirectMusicTrack8
*iface
, REFGUID rguidType
,
257 REFERENCE_TIME rtTime
, REFERENCE_TIME
*prtNext
, void *pParam
, void *pStateData
,
260 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
261 FIXME("(%p, %s, 0x%s, %p, %p, %p, %ld): stub\n", This
, debugstr_dmguid(rguidType
),
262 wine_dbgstr_longlong(rtTime
), prtNext
, pParam
, pStateData
, dwFlags
);
266 static HRESULT WINAPI
wave_track_SetParamEx(IDirectMusicTrack8
*iface
, REFGUID rguidType
,
267 REFERENCE_TIME rtTime
, void *pParam
, void *pStateData
, DWORD dwFlags
)
269 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
270 FIXME("(%p, %s, 0x%s, %p, %p, %ld): stub\n", This
, debugstr_dmguid(rguidType
),
271 wine_dbgstr_longlong(rtTime
), pParam
, pStateData
, dwFlags
);
275 static HRESULT WINAPI
wave_track_Compose(IDirectMusicTrack8
*iface
, IUnknown
*context
,
276 DWORD trackgroup
, IDirectMusicTrack
**track
)
278 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
280 TRACE("(%p, %p, %ld, %p): method not implemented\n", This
, context
, trackgroup
, track
);
284 static HRESULT WINAPI
wave_track_Join(IDirectMusicTrack8
*iface
, IDirectMusicTrack
*newtrack
,
285 MUSIC_TIME join
, IUnknown
*context
, DWORD trackgroup
, IDirectMusicTrack
**resulttrack
)
287 IDirectMusicWaveTrack
*This
= impl_from_IDirectMusicTrack8(iface
);
288 TRACE("(%p, %p, %ld, %p, %ld, %p): method not implemented\n", This
, newtrack
, join
, context
,
289 trackgroup
, resulttrack
);
293 static const IDirectMusicTrack8Vtbl dmtrack8_vtbl
= {
294 wave_track_QueryInterface
,
303 wave_track_IsParamSupported
,
304 wave_track_AddNotificationType
,
305 wave_track_RemoveNotificationType
,
308 wave_track_GetParamEx
,
309 wave_track_SetParamEx
,
314 static HRESULT
parse_wave_item(struct wave_part
*part
, IStream
*stream
, struct chunk_entry
*wavi
)
316 struct chunk_entry wave
= {.parent
= wavi
};
317 struct chunk_entry chunk
= {.parent
= &wave
};
318 struct wave_item
*item
;
321 /* Nested list with two chunks */
322 if (FAILED(hr
= stream_next_chunk(stream
, &wave
)))
324 if (wave
.id
!= FOURCC_LIST
|| wave
.type
!= DMUS_FOURCC_WAVE_LIST
)
325 return DMUS_E_UNSUPPORTED_STREAM
;
327 if (!(item
= heap_alloc_zero(sizeof(*item
))))
328 return E_OUTOFMEMORY
;
330 /* Wave item header chunk */
331 if (FAILED(hr
= stream_next_chunk(stream
, &chunk
)))
333 if (chunk
.id
!= DMUS_FOURCC_WAVEITEM_CHUNK
) {
334 hr
= DMUS_E_UNSUPPORTED_STREAM
;
338 if (FAILED(hr
= stream_chunk_get_data(stream
, &chunk
, &item
->header
, sizeof(item
->header
)))) {
339 WARN("Failed to read data of %s\n", debugstr_chunk(&chunk
));
343 TRACE("Found DMUS_IO_WAVE_ITEM_HEADER\n");
344 TRACE("\tlVolume %ld\n", item
->header
.lVolume
);
345 TRACE("\tdwVariations %ld\n", item
->header
.dwVariations
);
346 TRACE("\trtTime %s\n", wine_dbgstr_longlong(item
->header
.rtTime
));
347 TRACE("\trtStartOffset %s\n", wine_dbgstr_longlong(item
->header
.rtStartOffset
));
348 TRACE("\trtReserved %s\n", wine_dbgstr_longlong(item
->header
.rtReserved
));
349 TRACE("\trtDuration %s\n", wine_dbgstr_longlong(item
->header
.rtDuration
));
350 TRACE("\tdwLoopStart %ld\n", item
->header
.dwLoopStart
);
351 TRACE("\tdwLoopEnd %ld\n", item
->header
.dwLoopEnd
);
352 TRACE("\tdwFlags %#08lx\n", item
->header
.dwFlags
);
353 TRACE("\twVolumeRange %d\n", item
->header
.wVolumeRange
);
354 TRACE("\twPitchRange %d\n", item
->header
.wPitchRange
);
356 /* Second chunk is a reference list */
357 if (stream_next_chunk(stream
, &chunk
) != S_OK
|| chunk
.id
!= FOURCC_LIST
||
358 chunk
.type
!= DMUS_FOURCC_REF_LIST
) {
359 hr
= DMUS_E_UNSUPPORTED_STREAM
;
362 if (FAILED(hr
= dmobj_parsereference(stream
, &chunk
, &item
->object
)))
365 list_add_tail(&part
->items
, &item
->entry
);
374 static HRESULT
parse_wave_part(IDirectMusicWaveTrack
*This
, IStream
*stream
,
375 struct chunk_entry
*wavp
)
377 struct chunk_entry chunk
= {.parent
= wavp
};
378 struct wave_part
*part
;
381 /* Wave part header chunk */
382 if (FAILED(hr
= stream_next_chunk(stream
, &chunk
)))
384 if (chunk
.id
!= DMUS_FOURCC_WAVEPART_CHUNK
)
385 return DMUS_E_UNSUPPORTED_STREAM
;
387 if (!(part
= heap_alloc_zero(sizeof(*part
))))
388 return E_OUTOFMEMORY
;
389 list_init(&part
->items
);
391 if (FAILED(hr
= stream_chunk_get_data(stream
, &chunk
, &part
->header
, sizeof(part
->header
)))) {
392 WARN("Failed to read data of %s\n", debugstr_chunk(&chunk
));
396 TRACE("Found DMUS_IO_WAVE_PART_HEADER\n");
397 TRACE("\tlVolume %ld\n", part
->header
.lVolume
);
398 TRACE("\tdwVariations %ld\n", part
->header
.dwVariations
);
399 TRACE("\tdwPChannel %ld\n", part
->header
.dwPChannel
);
400 TRACE("\tdwLockToPart %ld\n", part
->header
.dwLockToPart
);
401 TRACE("\tdwFlags %#08lx\n", part
->header
.dwFlags
);
402 TRACE("\tdwIndex %ld\n", part
->header
.dwIndex
);
404 /* Array of wave items */
405 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
406 if (chunk
.id
== FOURCC_LIST
&& chunk
.type
== DMUS_FOURCC_WAVEITEM_LIST
)
407 if (FAILED(hr
= parse_wave_item(part
, stream
, &chunk
)))
413 list_add_tail(&This
->parts
, &part
->entry
);
422 static HRESULT WINAPI
wave_IPersistStream_Load(IPersistStream
*iface
, IStream
*stream
)
424 IDirectMusicWaveTrack
*This
= impl_from_IPersistStream(iface
);
425 struct chunk_entry wavt
= {0};
426 struct chunk_entry chunk
= {.parent
= &wavt
};
429 TRACE("%p, %p\n", This
, stream
);
434 if ((hr
= stream_get_chunk(stream
, &wavt
) != S_OK
))
436 if (wavt
.id
!= FOURCC_LIST
|| wavt
.type
!= DMUS_FOURCC_WAVETRACK_LIST
)
437 return DMUS_E_UNSUPPORTED_STREAM
;
439 TRACE("Parsing segment form in %p: %s\n", stream
, debugstr_chunk(&wavt
));
441 /* Track header chunk */
442 if (FAILED(hr
= stream_next_chunk(stream
, &chunk
)))
444 if (chunk
.id
!= DMUS_FOURCC_WAVETRACK_CHUNK
)
445 return DMUS_E_UNSUPPORTED_STREAM
;
446 if (FAILED(hr
= stream_chunk_get_data(stream
, &chunk
, &This
->header
, sizeof(This
->header
))))
449 TRACE("Found DMUS_IO_WAVE_TRACK_HEADER\n");
450 TRACE("\tlVolume %ld\n", This
->header
.lVolume
);
451 TRACE("\tdwFlags %#08lx\n", This
->header
.dwFlags
);
453 /* Array of wave parts */
454 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
455 if (chunk
.id
== FOURCC_LIST
&& chunk
.type
== DMUS_FOURCC_WAVEPART_LIST
)
456 if (FAILED(hr
= parse_wave_part(This
, stream
, &chunk
)))
459 return SUCCEEDED(hr
) ? S_OK
: hr
;
462 static const IPersistStreamVtbl persiststream_vtbl
= {
463 dmobj_IPersistStream_QueryInterface
,
464 dmobj_IPersistStream_AddRef
,
465 dmobj_IPersistStream_Release
,
466 dmobj_IPersistStream_GetClassID
,
467 unimpl_IPersistStream_IsDirty
,
468 wave_IPersistStream_Load
,
469 unimpl_IPersistStream_Save
,
470 unimpl_IPersistStream_GetSizeMax
473 /* for ClassFactory */
474 HRESULT WINAPI
create_dmwavetrack(REFIID lpcGUID
, void **ppobj
)
476 IDirectMusicWaveTrack
*track
;
479 track
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*track
));
482 return E_OUTOFMEMORY
;
484 track
->IDirectMusicTrack8_iface
.lpVtbl
= &dmtrack8_vtbl
;
486 dmobject_init(&track
->dmobj
, &CLSID_DirectMusicWaveTrack
,
487 (IUnknown
*)&track
->IDirectMusicTrack8_iface
);
488 track
->dmobj
.IPersistStream_iface
.lpVtbl
= &persiststream_vtbl
;
489 list_init(&track
->parts
);
492 hr
= IDirectMusicTrack8_QueryInterface(&track
->IDirectMusicTrack8_iface
, lpcGUID
, ppobj
);
493 IDirectMusicTrack8_Release(&track
->IDirectMusicTrack8_iface
);