2 * Copyright (C) 2003-2004 Rok Mandeljc
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "dmime_private.h"
21 WINE_DEFAULT_DEBUG_CHANNEL(dmime
);
25 IDirectMusicTrack8 IDirectMusicTrack8_iface
;
26 struct dmobject dmobj
; /* IPersistStream only */
29 DMUS_IO_SEQ_ITEM
*items
;
32 DMUS_IO_CURVE_ITEM
*curve_items
;
33 unsigned int curve_count
;
36 static inline struct sequence_track
*impl_from_IDirectMusicTrack8(IDirectMusicTrack8
*iface
)
38 return CONTAINING_RECORD(iface
, struct sequence_track
, IDirectMusicTrack8_iface
);
41 static HRESULT WINAPI
sequence_track_QueryInterface(IDirectMusicTrack8
*iface
, REFIID riid
,
44 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
46 TRACE("(%p, %s, %p)\n", This
, debugstr_dmguid(riid
), ret_iface
);
50 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDirectMusicTrack
) ||
51 IsEqualIID(riid
, &IID_IDirectMusicTrack8
))
53 else if (IsEqualIID(riid
, &IID_IPersistStream
))
54 *ret_iface
= &This
->dmobj
.IPersistStream_iface
;
56 WARN("(%p, %s, %p): not found\n", This
, debugstr_dmguid(riid
), ret_iface
);
60 IUnknown_AddRef((IUnknown
*)*ret_iface
);
64 static ULONG WINAPI
sequence_track_AddRef(IDirectMusicTrack8
*iface
)
66 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
67 LONG ref
= InterlockedIncrement(&This
->ref
);
69 TRACE("(%p) ref=%ld\n", This
, ref
);
74 static ULONG WINAPI
sequence_track_Release(IDirectMusicTrack8
*iface
)
76 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
77 LONG ref
= InterlockedDecrement(&This
->ref
);
79 TRACE("(%p) ref=%ld\n", This
, ref
);
88 static HRESULT WINAPI
sequence_track_Init(IDirectMusicTrack8
*iface
, IDirectMusicSegment
*pSegment
)
90 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
91 FIXME("(%p, %p): stub\n", This
, pSegment
);
95 static HRESULT WINAPI
sequence_track_InitPlay(IDirectMusicTrack8
*iface
,
96 IDirectMusicSegmentState
*pSegmentState
, IDirectMusicPerformance
*pPerformance
,
97 void **ppStateData
, DWORD dwVirtualTrack8ID
, DWORD dwFlags
)
99 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
100 FIXME("(%p, %p, %p, %p, %ld, %ld): stub\n", This
, pSegmentState
, pPerformance
, ppStateData
, dwVirtualTrack8ID
, dwFlags
);
104 static HRESULT WINAPI
sequence_track_EndPlay(IDirectMusicTrack8
*iface
, void *pStateData
)
106 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
107 FIXME("(%p, %p): stub\n", This
, pStateData
);
111 static HRESULT WINAPI
sequence_track_Play(IDirectMusicTrack8
*iface
, void *state_data
,
112 MUSIC_TIME start_time
, MUSIC_TIME end_time
, MUSIC_TIME time_offset
, DWORD segment_flags
,
113 IDirectMusicPerformance
*performance
, IDirectMusicSegmentState
*segment_state
, DWORD track_id
)
115 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
116 IDirectMusicGraph
*graph
;
120 TRACE("(%p, %p, %ld, %ld, %ld, %#lx, %p, %p, %ld)\n", This
, state_data
, start_time
, end_time
,
121 time_offset
, segment_flags
, performance
, segment_state
, track_id
);
123 if (segment_flags
) FIXME("segment_flags %#lx not implemented\n", segment_flags
);
124 if (segment_state
) FIXME("segment_state %p not implemented\n", segment_state
);
126 if (FAILED(hr
= IDirectMusicPerformance_QueryInterface(performance
,
127 &IID_IDirectMusicGraph
, (void **)&graph
)))
130 for (i
= 0; SUCCEEDED(hr
) &&i
< This
->count
; i
++)
132 DMUS_IO_SEQ_ITEM
*item
= This
->items
+ i
;
135 if (item
->mtTime
< start_time
) continue;
136 if (item
->mtTime
>= end_time
) continue;
138 if (FAILED(hr
= IDirectMusicPerformance_AllocPMsg(performance
, sizeof(*msg
),
139 (DMUS_PMSG
**)&msg
)))
142 msg
->mtTime
= item
->mtTime
+ time_offset
;
143 msg
->dwFlags
= DMUS_PMSGF_MUSICTIME
;
144 msg
->dwPChannel
= item
->dwPChannel
;
145 msg
->dwVirtualTrackID
= track_id
;
146 msg
->dwType
= DMUS_PMSGT_NOTE
;
148 msg
->mtDuration
= item
->mtDuration
;
149 msg
->wMusicValue
= item
->bByte1
;
150 msg
->nOffset
= item
->nOffset
;
151 msg
->bVelocity
= item
->bByte2
;
153 msg
->bMidiValue
= item
->bByte1
;
155 if (FAILED(hr
= IDirectMusicGraph_StampPMsg(graph
, (DMUS_PMSG
*)msg
))
156 || FAILED(hr
= IDirectMusicPerformance_SendPMsg(performance
, (DMUS_PMSG
*)msg
)))
158 IDirectMusicPerformance_FreePMsg(performance
, (DMUS_PMSG
*)msg
);
163 for (i
= 0; SUCCEEDED(hr
) &&i
< This
->curve_count
; i
++)
165 DMUS_IO_CURVE_ITEM
*item
= This
->curve_items
+ i
;
166 DMUS_CURVE_PMSG
*msg
;
168 if (item
->mtStart
< start_time
) continue;
169 if (item
->mtStart
>= end_time
) continue;
171 if (FAILED(hr
= IDirectMusicPerformance_AllocPMsg(performance
, sizeof(*msg
),
172 (DMUS_PMSG
**)&msg
)))
175 msg
->mtTime
= item
->mtStart
+ time_offset
;
176 msg
->dwFlags
= DMUS_PMSGF_MUSICTIME
;
177 msg
->dwPChannel
= item
->dwPChannel
;
178 msg
->dwVirtualTrackID
= track_id
;
179 msg
->dwType
= DMUS_PMSGT_CURVE
;
180 msg
->mtDuration
= item
->mtDuration
;
181 msg
->mtOriginalStart
= item
->mtStart
;
182 msg
->mtResetDuration
= item
->mtResetDuration
;
183 msg
->nStartValue
= item
->nStartValue
;
184 msg
->nEndValue
= item
->nEndValue
;
185 msg
->nResetValue
= item
->nResetValue
;
186 msg
->nOffset
= item
->nOffset
;
187 msg
->bType
= item
->bType
;
188 msg
->bCurveShape
= item
->bCurveShape
;
189 msg
->bCCData
= item
->bCCData
;
190 msg
->bFlags
= item
->bFlags
;
191 msg
->wParamType
= item
->wParamType
;
192 msg
->wMergeIndex
= item
->wMergeIndex
;
194 if (FAILED(hr
= IDirectMusicGraph_StampPMsg(graph
, (DMUS_PMSG
*)msg
))
195 || FAILED(hr
= IDirectMusicPerformance_SendPMsg(performance
, (DMUS_PMSG
*)msg
)))
197 IDirectMusicPerformance_FreePMsg(performance
, (DMUS_PMSG
*)msg
);
202 IDirectMusicGraph_Release(graph
);
206 static HRESULT WINAPI
sequence_track_GetParam(IDirectMusicTrack8
*iface
, REFGUID type
,
207 MUSIC_TIME time
, MUSIC_TIME
*next
, void *param
)
209 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
211 TRACE("(%p, %s, %ld, %p, %p): method not implemented\n", This
, debugstr_dmguid(type
), time
,
216 static HRESULT WINAPI
sequence_track_SetParam(IDirectMusicTrack8
*iface
, REFGUID type
,
217 MUSIC_TIME time
, void *param
)
219 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
221 TRACE("(%p, %s, %ld, %p): method not implemented\n", This
, debugstr_dmguid(type
), time
, param
);
225 static HRESULT WINAPI
sequence_track_IsParamSupported(IDirectMusicTrack8
*iface
, REFGUID type
)
227 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
229 TRACE("(%p, %s): method not implemented\n", This
, debugstr_dmguid(type
));
233 static HRESULT WINAPI
sequence_track_AddNotificationType(IDirectMusicTrack8
*iface
,
236 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
238 TRACE("(%p, %s): method not implemented\n", This
, debugstr_dmguid(notiftype
));
242 static HRESULT WINAPI
sequence_track_RemoveNotificationType(IDirectMusicTrack8
*iface
,
245 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
247 TRACE("(%p, %s): method not implemented\n", This
, debugstr_dmguid(notiftype
));
251 static HRESULT WINAPI
sequence_track_Clone(IDirectMusicTrack8
*iface
, MUSIC_TIME mtStart
,
252 MUSIC_TIME mtEnd
, IDirectMusicTrack
**ppTrack
)
254 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
255 FIXME("(%p, %ld, %ld, %p): stub\n", This
, mtStart
, mtEnd
, ppTrack
);
259 static HRESULT WINAPI
sequence_track_PlayEx(IDirectMusicTrack8
*iface
, void *pStateData
,
260 REFERENCE_TIME rtStart
, REFERENCE_TIME rtEnd
, REFERENCE_TIME rtOffset
, DWORD dwFlags
,
261 IDirectMusicPerformance
*pPerf
, IDirectMusicSegmentState
*pSegSt
, DWORD dwVirtualID
)
263 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
264 FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %ld, %p, %p, %ld): stub\n", This
, pStateData
, wine_dbgstr_longlong(rtStart
),
265 wine_dbgstr_longlong(rtEnd
), wine_dbgstr_longlong(rtOffset
), dwFlags
, pPerf
, pSegSt
, dwVirtualID
);
269 static HRESULT WINAPI
sequence_track_GetParamEx(IDirectMusicTrack8
*iface
, REFGUID type
,
270 REFERENCE_TIME time
, REFERENCE_TIME
*next
, void *param
, void *state
, DWORD flags
)
272 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
274 TRACE("(%p, %s, %s, %p, %p, %p, %lx): method not implemented\n", This
, debugstr_dmguid(type
),
275 wine_dbgstr_longlong(time
), next
, param
, state
, flags
);
279 static HRESULT WINAPI
sequence_track_SetParamEx(IDirectMusicTrack8
*iface
, REFGUID type
,
280 REFERENCE_TIME time
, void *param
, void *state
, DWORD flags
)
282 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
284 TRACE("(%p, %s, %s, %p, %p, %lx): method not implemented\n", This
, debugstr_dmguid(type
),
285 wine_dbgstr_longlong(time
), param
, state
, flags
);
289 static HRESULT WINAPI
sequence_track_Compose(IDirectMusicTrack8
*iface
, IUnknown
*context
,
290 DWORD trackgroup
, IDirectMusicTrack
**track
)
292 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
294 TRACE("(%p, %p, %ld, %p): method not implemented\n", This
, context
, trackgroup
, track
);
298 static HRESULT WINAPI
sequence_track_Join(IDirectMusicTrack8
*iface
, IDirectMusicTrack
*newtrack
,
299 MUSIC_TIME join
, IUnknown
*context
, DWORD trackgroup
, IDirectMusicTrack
**resulttrack
)
301 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
302 TRACE("(%p, %p, %ld, %p, %ld, %p): method not implemented\n", This
, newtrack
, join
, context
,
303 trackgroup
, resulttrack
);
307 static const IDirectMusicTrack8Vtbl dmtrack8_vtbl
= {
308 sequence_track_QueryInterface
,
309 sequence_track_AddRef
,
310 sequence_track_Release
,
312 sequence_track_InitPlay
,
313 sequence_track_EndPlay
,
315 sequence_track_GetParam
,
316 sequence_track_SetParam
,
317 sequence_track_IsParamSupported
,
318 sequence_track_AddNotificationType
,
319 sequence_track_RemoveNotificationType
,
320 sequence_track_Clone
,
321 sequence_track_PlayEx
,
322 sequence_track_GetParamEx
,
323 sequence_track_SetParamEx
,
324 sequence_track_Compose
,
328 static HRESULT
parse_curl_list(struct sequence_track
*This
, IStream
*stream
, struct chunk_entry
*chunk
)
333 if (FAILED(hr
= stream_chunk_get_array(stream
, chunk
, (void **)&This
->curve_items
,
334 &This
->curve_count
, sizeof(*This
->curve_items
))))
336 /* try again with the older DMUS_IO_CURVE_ITEM size */
337 UINT size
= offsetof(DMUS_IO_CURVE_ITEM
, wParamType
);
340 if (FAILED(hr
= stream_reset_chunk_data(stream
, chunk
))) return hr
;
341 if (FAILED(hr
= stream_chunk_get_array(stream
, chunk
, (void **)&buffer
,
342 &This
->curve_count
, size
)))
345 if (!(This
->curve_items
= calloc(This
->curve_count
, sizeof(*This
->curve_items
)))) return E_OUTOFMEMORY
;
346 for (i
= 0; i
< This
->curve_count
; i
++) memcpy(This
->curve_items
+ i
, buffer
+ size
* i
, size
);
353 static HRESULT
parse_seqt_chunk(struct sequence_track
*This
, IStream
*stream
, struct chunk_entry
*parent
)
355 struct chunk_entry chunk
= {.parent
= parent
};
358 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
360 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
362 case DMUS_FOURCC_SEQ_LIST
:
363 hr
= stream_chunk_get_array(stream
, &chunk
, (void **)&This
->items
,
364 &This
->count
, sizeof(*This
->items
));
367 case DMUS_FOURCC_CURVE_LIST
:
368 hr
= parse_curl_list(This
, stream
, &chunk
);
372 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
376 if (FAILED(hr
)) break;
382 static inline struct sequence_track
*impl_from_IPersistStream(IPersistStream
*iface
)
384 return CONTAINING_RECORD(iface
, struct sequence_track
, dmobj
.IPersistStream_iface
);
387 static HRESULT WINAPI
track_IPersistStream_Load(IPersistStream
*iface
, IStream
*stream
)
389 struct sequence_track
*This
= impl_from_IPersistStream(iface
);
390 struct chunk_entry chunk
= {0};
393 TRACE("(%p, %p)\n", This
, stream
);
395 if ((hr
= stream_get_chunk(stream
, &chunk
)) == S_OK
)
397 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
399 case DMUS_FOURCC_SEQ_TRACK
:
400 hr
= parse_seqt_chunk(This
, stream
, &chunk
);
404 WARN("Invalid seq track chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
405 hr
= DMUS_E_UNSUPPORTED_STREAM
;
410 stream_skip_chunk(stream
, &chunk
);
411 if (FAILED(hr
)) return hr
;
417 TRACE("Loaded DirectMusicSeqTrack %p\n", This
);
419 TRACE("- %u items:\n", This
->count
);
420 for (i
= 0; i
< This
->count
; i
++)
422 TRACE(" - DMUS_IO_SEQ_ITEM[%u]\n", i
);
423 TRACE(" - mtTime: %ld\n", This
->items
[i
].mtTime
);
424 TRACE(" - mtDuration: %ld\n", This
->items
[i
].mtDuration
);
425 TRACE(" - dwPChannel: %ld\n", This
->items
[i
].dwPChannel
);
426 TRACE(" - nOffset: %d\n", This
->items
[i
].nOffset
);
427 TRACE(" - bStatus: %d\n", This
->items
[i
].bStatus
);
428 TRACE(" - bByte1: %#x\n", This
->items
[i
].bByte1
);
429 TRACE(" - bByte2: %#x\n", This
->items
[i
].bByte2
);
432 TRACE("- %u curves:\n", This
->curve_count
);
433 for (i
= 0; i
< This
->curve_count
; i
++)
435 TRACE(" - DMUS_IO_CURVE_ITEM[%u]\n", i
);
436 TRACE(" - mtStart: %ld\n", This
->curve_items
[i
].mtStart
);
437 TRACE(" - mtDuration: %ld\n", This
->curve_items
[i
].mtDuration
);
438 TRACE(" - mtResetDuration: %ld\n", This
->curve_items
[i
].mtResetDuration
);
439 TRACE(" - dwPChannel: %ld\n", This
->curve_items
[i
].dwPChannel
);
440 TRACE(" - nOffset: %d\n", This
->curve_items
[i
].nOffset
);
441 TRACE(" - nStartValue: %d\n", This
->curve_items
[i
].nStartValue
);
442 TRACE(" - nEndValue: %d\n", This
->curve_items
[i
].nEndValue
);
443 TRACE(" - nResetValue: %d\n", This
->curve_items
[i
].nResetValue
);
444 TRACE(" - bType: %d\n", This
->curve_items
[i
].bType
);
445 TRACE(" - bCurveShape: %d\n", This
->curve_items
[i
].bCurveShape
);
446 TRACE(" - bCCData: %d\n", This
->curve_items
[i
].bCCData
);
447 TRACE(" - bFlags: %d\n", This
->curve_items
[i
].bFlags
);
448 TRACE(" - wParamType: %d\n", This
->curve_items
[i
].wParamType
);
449 TRACE(" - wMergeIndex: %d\n", This
->curve_items
[i
].wMergeIndex
);
456 static const IPersistStreamVtbl persiststream_vtbl
= {
457 dmobj_IPersistStream_QueryInterface
,
458 dmobj_IPersistStream_AddRef
,
459 dmobj_IPersistStream_Release
,
460 dmobj_IPersistStream_GetClassID
,
461 unimpl_IPersistStream_IsDirty
,
462 track_IPersistStream_Load
,
463 unimpl_IPersistStream_Save
,
464 unimpl_IPersistStream_GetSizeMax
467 /* for ClassFactory */
468 HRESULT
create_dmseqtrack(REFIID lpcGUID
, void **ppobj
)
470 struct sequence_track
*track
;
474 if (!(track
= calloc(1, sizeof(*track
)))) return E_OUTOFMEMORY
;
475 track
->IDirectMusicTrack8_iface
.lpVtbl
= &dmtrack8_vtbl
;
477 dmobject_init(&track
->dmobj
, &CLSID_DirectMusicSeqTrack
,
478 (IUnknown
*)&track
->IDirectMusicTrack8_iface
);
479 track
->dmobj
.IPersistStream_iface
.lpVtbl
= &persiststream_vtbl
;
481 hr
= IDirectMusicTrack8_QueryInterface(&track
->IDirectMusicTrack8_iface
, lpcGUID
, ppobj
);
482 IDirectMusicTrack8_Release(&track
->IDirectMusicTrack8_iface
);