explorer: Call user driver through a new CreateDesktop callback.
[wine.git] / dlls / dmime / wavetrack.c
blobd87d16fcdab104fbba84de8383d657d36b9c84a4
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"
21 #include "dmobject.h"
22 #include "wine/heap.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(dmime);
26 /*****************************************************************************
27 * IDirectMusicWaveTrack implementation
29 struct wave_item {
30 struct list entry;
31 DMUS_IO_WAVE_ITEM_HEADER header;
32 IDirectMusicObject *object;
35 struct wave_part {
36 struct list entry;
37 DMUS_IO_WAVE_PART_HEADER header;
38 struct list items;
41 typedef struct IDirectMusicWaveTrack {
42 IDirectMusicTrack8 IDirectMusicTrack8_iface;
43 struct dmobject dmobj; /* IPersistStream only */
44 LONG ref;
45 DMUS_IO_WAVE_TRACK_HEADER header;
46 struct list parts;
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,
61 void **ret_iface)
63 IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface);
65 TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface);
67 *ret_iface = NULL;
69 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicTrack) ||
70 IsEqualIID(riid, &IID_IDirectMusicTrack8))
71 *ret_iface = iface;
72 else if (IsEqualIID(riid, &IID_IPersistStream))
73 *ret_iface = &This->dmobj.IPersistStream_iface;
74 else {
75 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface);
76 return E_NOINTERFACE;
79 IUnknown_AddRef((IUnknown*)*ret_iface);
80 return S_OK;
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);
90 return 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);
100 if (!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);
108 if (item->object)
109 IDirectMusicObject_Release(item->object);
110 heap_free(item);
112 heap_free(part);
115 heap_free(This);
116 DMIME_UnlockModule();
119 return ref;
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);
126 return S_OK;
129 static HRESULT WINAPI wave_track_InitPlay(IDirectMusicTrack8 *iface,
130 IDirectMusicSegmentState *pSegmentState, IDirectMusicPerformance *pPerformance,
131 void **ppStateData, DWORD dwVirtualTrack8ID, DWORD dwFlags)
133 IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface);
134 FIXME("(%p, %p, %p, %p, %ld, %ld): stub\n", This, pSegmentState, pPerformance, ppStateData, dwVirtualTrack8ID, dwFlags);
135 return S_OK;
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);
142 return S_OK;
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);
151 return S_OK;
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,
164 void *param)
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");
172 return S_OK;
174 if (IsEqualGUID(type, &GUID_Download)) {
175 FIXME("GUID_Download not handled yet\n");
176 return S_OK;
178 if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) {
179 FIXME("GUID_DownloadToAudioPath not handled yet\n");
180 return S_OK;
182 if (IsEqualGUID(type, &GUID_Enable_Auto_Download)) {
183 FIXME("GUID_Enable_Auto_Download not handled yet\n");
184 return S_OK;
186 if (IsEqualGUID(type, &GUID_Unload)) {
187 FIXME("GUID_Unload not handled yet\n");
188 return S_OK;
190 if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) {
191 FIXME("GUID_UnloadFromAudioPath not handled yet\n");
192 return S_OK;
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,
203 &GUID_Download,
204 &GUID_DownloadToAudioPath,
205 &GUID_Enable_Auto_Download,
206 &GUID_Unload,
207 &GUID_UnloadFromAudioPath
209 unsigned int i;
211 TRACE("(%p, %s)\n", This, debugstr_dmguid(type));
213 for (i = 0; i < ARRAY_SIZE(valid); i++)
214 if (IsEqualGUID(type, valid[i]))
215 return S_OK;
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));
226 return E_NOTIMPL;
229 static HRESULT WINAPI wave_track_RemoveNotificationType(IDirectMusicTrack8 *iface,
230 REFGUID notiftype)
232 IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface);
234 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
235 return E_NOTIMPL;
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);
243 return S_OK;
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);
253 return S_OK;
256 static HRESULT WINAPI wave_track_GetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType,
257 REFERENCE_TIME rtTime, REFERENCE_TIME *prtNext, void *pParam, void *pStateData,
258 DWORD dwFlags)
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);
263 return S_OK;
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);
272 return S_OK;
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);
281 return E_NOTIMPL;
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);
290 return E_NOTIMPL;
293 static const IDirectMusicTrack8Vtbl dmtrack8_vtbl = {
294 wave_track_QueryInterface,
295 wave_track_AddRef,
296 wave_track_Release,
297 wave_track_Init,
298 wave_track_InitPlay,
299 wave_track_EndPlay,
300 wave_track_Play,
301 wave_track_GetParam,
302 wave_track_SetParam,
303 wave_track_IsParamSupported,
304 wave_track_AddNotificationType,
305 wave_track_RemoveNotificationType,
306 wave_track_Clone,
307 wave_track_PlayEx,
308 wave_track_GetParamEx,
309 wave_track_SetParamEx,
310 wave_track_Compose,
311 wave_track_Join
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;
319 HRESULT hr;
321 /* Nested list with two chunks */
322 if (FAILED(hr = stream_next_chunk(stream, &wave)))
323 return hr;
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)))
332 goto error;
333 if (chunk.id != DMUS_FOURCC_WAVEITEM_CHUNK) {
334 hr = DMUS_E_UNSUPPORTED_STREAM;
335 goto error;
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));
340 goto error;
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;
360 goto error;
362 if (FAILED(hr = dmobj_parsereference(stream, &chunk, &item->object)))
363 goto error;
365 list_add_tail(&part->items, &item->entry);
367 return S_OK;
369 error:
370 heap_free(item);
371 return hr;
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;
379 HRESULT hr;
381 /* Wave part header chunk */
382 if (FAILED(hr = stream_next_chunk(stream, &chunk)))
383 return hr;
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));
393 goto error;
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)))
408 break;
410 if (FAILED(hr))
411 goto error;
413 list_add_tail(&This->parts, &part->entry);
415 return S_OK;
417 error:
418 heap_free(part);
419 return hr;
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};
427 HRESULT hr;
429 TRACE("%p, %p\n", This, stream);
431 if (!stream)
432 return E_POINTER;
434 if ((hr = stream_get_chunk(stream, &wavt) != S_OK))
435 return hr;
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)))
443 return hr;
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))))
447 return hr;
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)))
457 break;
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 create_dmwavetrack(REFIID lpcGUID, void **ppobj)
476 IDirectMusicWaveTrack *track;
477 HRESULT hr;
479 track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track));
480 if (!track) {
481 *ppobj = NULL;
482 return E_OUTOFMEMORY;
484 track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl;
485 track->ref = 1;
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);
491 DMIME_LockModule();
492 hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj);
493 IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface);
495 return hr;