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 "dmusic_midi.h"
20 #include "dmime_private.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(dmime
);
26 IDirectMusicTrack8 IDirectMusicTrack8_iface
;
27 struct dmobject dmobj
; /* IPersistStream only */
30 DMUS_IO_SEQ_ITEM
*items
;
33 DMUS_IO_CURVE_ITEM
*curve_items
;
34 unsigned int curve_count
;
37 static inline struct sequence_track
*impl_from_IDirectMusicTrack8(IDirectMusicTrack8
*iface
)
39 return CONTAINING_RECORD(iface
, struct sequence_track
, IDirectMusicTrack8_iface
);
42 static HRESULT WINAPI
sequence_track_QueryInterface(IDirectMusicTrack8
*iface
, REFIID riid
,
45 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
47 TRACE("(%p, %s, %p)\n", This
, debugstr_dmguid(riid
), ret_iface
);
51 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDirectMusicTrack
) ||
52 IsEqualIID(riid
, &IID_IDirectMusicTrack8
))
54 else if (IsEqualIID(riid
, &IID_IPersistStream
))
55 *ret_iface
= &This
->dmobj
.IPersistStream_iface
;
57 WARN("(%p, %s, %p): not found\n", This
, debugstr_dmguid(riid
), ret_iface
);
61 IUnknown_AddRef((IUnknown
*)*ret_iface
);
65 static ULONG WINAPI
sequence_track_AddRef(IDirectMusicTrack8
*iface
)
67 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
68 LONG ref
= InterlockedIncrement(&This
->ref
);
70 TRACE("(%p) ref=%ld\n", This
, ref
);
75 static ULONG WINAPI
sequence_track_Release(IDirectMusicTrack8
*iface
)
77 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
78 LONG ref
= InterlockedDecrement(&This
->ref
);
80 TRACE("(%p) ref=%ld\n", This
, ref
);
89 static HRESULT WINAPI
sequence_track_Init(IDirectMusicTrack8
*iface
, IDirectMusicSegment
*pSegment
)
91 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
92 FIXME("(%p, %p): stub\n", This
, pSegment
);
96 static HRESULT WINAPI
sequence_track_InitPlay(IDirectMusicTrack8
*iface
,
97 IDirectMusicSegmentState
*pSegmentState
, IDirectMusicPerformance
*pPerformance
,
98 void **ppStateData
, DWORD dwVirtualTrack8ID
, DWORD dwFlags
)
100 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
101 FIXME("(%p, %p, %p, %p, %ld, %ld): stub\n", This
, pSegmentState
, pPerformance
, ppStateData
, dwVirtualTrack8ID
, dwFlags
);
105 static HRESULT WINAPI
sequence_track_EndPlay(IDirectMusicTrack8
*iface
, void *pStateData
)
107 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
108 FIXME("(%p, %p): stub\n", This
, pStateData
);
112 static HRESULT WINAPI
sequence_track_Play(IDirectMusicTrack8
*iface
, void *state_data
,
113 MUSIC_TIME start_time
, MUSIC_TIME end_time
, MUSIC_TIME time_offset
, DWORD segment_flags
,
114 IDirectMusicPerformance
*performance
, IDirectMusicSegmentState
*segment_state
, DWORD track_id
)
116 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
117 IDirectMusicGraph
*graph
;
121 TRACE("(%p, %p, %ld, %ld, %ld, %#lx, %p, %p, %ld)\n", This
, state_data
, start_time
, end_time
,
122 time_offset
, segment_flags
, performance
, segment_state
, track_id
);
124 if (segment_flags
) FIXME("segment_flags %#lx not implemented\n", segment_flags
);
125 if (segment_state
) FIXME("segment_state %p not implemented\n", segment_state
);
127 if (FAILED(hr
= IDirectMusicPerformance_QueryInterface(performance
,
128 &IID_IDirectMusicGraph
, (void **)&graph
)))
131 for (i
= 0; SUCCEEDED(hr
) &&i
< This
->count
; i
++)
133 DMUS_IO_SEQ_ITEM
*item
= This
->items
+ i
;
136 if (item
->mtTime
< start_time
) continue;
137 if (item
->mtTime
>= end_time
) continue;
139 if (item
->bStatus
== MIDI_NOTE_ON
)
141 DMUS_NOTE_PMSG
*note
;
142 if (FAILED(hr
= IDirectMusicPerformance_AllocPMsg(performance
, sizeof(*note
),
143 (DMUS_PMSG
**)¬e
)))
146 note
->dwType
= DMUS_PMSGT_NOTE
;
147 note
->mtDuration
= item
->mtDuration
;
148 note
->wMusicValue
= item
->bByte1
;
149 note
->nOffset
= item
->nOffset
;
150 note
->bVelocity
= item
->bByte2
;
152 note
->bMidiValue
= item
->bByte1
;
153 msg
= (DMUS_PMSG
*)note
;
157 DMUS_MIDI_PMSG
*midi
;
158 if (FAILED(hr
= IDirectMusicPerformance_AllocPMsg(performance
, sizeof(*midi
),
159 (DMUS_PMSG
**)&midi
)))
162 midi
->dwType
= DMUS_PMSGT_MIDI
;
163 midi
->bStatus
= item
->bStatus
;
164 midi
->bByte1
= item
->bByte1
;
165 midi
->bByte2
= item
->bByte2
;
166 msg
= (DMUS_PMSG
*)midi
;
169 msg
->mtTime
= item
->mtTime
+ time_offset
;
170 msg
->dwFlags
= DMUS_PMSGF_MUSICTIME
;
171 msg
->dwPChannel
= item
->dwPChannel
;
172 msg
->dwVirtualTrackID
= track_id
;
175 if (FAILED(hr
= IDirectMusicGraph_StampPMsg(graph
, (DMUS_PMSG
*)msg
))
176 || FAILED(hr
= IDirectMusicPerformance_SendPMsg(performance
, (DMUS_PMSG
*)msg
)))
178 IDirectMusicPerformance_FreePMsg(performance
, (DMUS_PMSG
*)msg
);
183 for (i
= 0; SUCCEEDED(hr
) &&i
< This
->curve_count
; i
++)
185 DMUS_IO_CURVE_ITEM
*item
= This
->curve_items
+ i
;
186 DMUS_CURVE_PMSG
*msg
;
188 if (item
->mtStart
< start_time
) continue;
189 if (item
->mtStart
>= end_time
) continue;
191 if (FAILED(hr
= IDirectMusicPerformance_AllocPMsg(performance
, sizeof(*msg
),
192 (DMUS_PMSG
**)&msg
)))
195 msg
->mtTime
= item
->mtStart
+ time_offset
;
196 msg
->dwFlags
= DMUS_PMSGF_MUSICTIME
;
197 msg
->dwPChannel
= item
->dwPChannel
;
198 msg
->dwVirtualTrackID
= track_id
;
199 msg
->dwType
= DMUS_PMSGT_CURVE
;
200 msg
->mtDuration
= item
->mtDuration
;
201 msg
->mtOriginalStart
= item
->mtStart
;
202 msg
->mtResetDuration
= item
->mtResetDuration
;
203 msg
->nStartValue
= item
->nStartValue
;
204 msg
->nEndValue
= item
->nEndValue
;
205 msg
->nResetValue
= item
->nResetValue
;
206 msg
->nOffset
= item
->nOffset
;
207 msg
->bType
= item
->bType
;
208 msg
->bCurveShape
= item
->bCurveShape
;
209 msg
->bCCData
= item
->bCCData
;
210 msg
->bFlags
= item
->bFlags
;
211 msg
->wParamType
= item
->wParamType
;
212 msg
->wMergeIndex
= item
->wMergeIndex
;
214 if (FAILED(hr
= IDirectMusicGraph_StampPMsg(graph
, (DMUS_PMSG
*)msg
))
215 || FAILED(hr
= IDirectMusicPerformance_SendPMsg(performance
, (DMUS_PMSG
*)msg
)))
217 IDirectMusicPerformance_FreePMsg(performance
, (DMUS_PMSG
*)msg
);
222 IDirectMusicGraph_Release(graph
);
226 static HRESULT WINAPI
sequence_track_GetParam(IDirectMusicTrack8
*iface
, REFGUID type
,
227 MUSIC_TIME time
, MUSIC_TIME
*next
, void *param
)
229 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
231 TRACE("(%p, %s, %ld, %p, %p): method not implemented\n", This
, debugstr_dmguid(type
), time
,
236 static HRESULT WINAPI
sequence_track_SetParam(IDirectMusicTrack8
*iface
, REFGUID type
,
237 MUSIC_TIME time
, void *param
)
239 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
241 TRACE("(%p, %s, %ld, %p): method not implemented\n", This
, debugstr_dmguid(type
), time
, param
);
245 static HRESULT WINAPI
sequence_track_IsParamSupported(IDirectMusicTrack8
*iface
, REFGUID type
)
247 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
249 TRACE("(%p, %s): method not implemented\n", This
, debugstr_dmguid(type
));
253 static HRESULT WINAPI
sequence_track_AddNotificationType(IDirectMusicTrack8
*iface
,
256 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
258 TRACE("(%p, %s): method not implemented\n", This
, debugstr_dmguid(notiftype
));
262 static HRESULT WINAPI
sequence_track_RemoveNotificationType(IDirectMusicTrack8
*iface
,
265 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
267 TRACE("(%p, %s): method not implemented\n", This
, debugstr_dmguid(notiftype
));
271 static HRESULT WINAPI
sequence_track_Clone(IDirectMusicTrack8
*iface
, MUSIC_TIME mtStart
,
272 MUSIC_TIME mtEnd
, IDirectMusicTrack
**ppTrack
)
274 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
275 FIXME("(%p, %ld, %ld, %p): stub\n", This
, mtStart
, mtEnd
, ppTrack
);
279 static HRESULT WINAPI
sequence_track_PlayEx(IDirectMusicTrack8
*iface
, void *pStateData
,
280 REFERENCE_TIME rtStart
, REFERENCE_TIME rtEnd
, REFERENCE_TIME rtOffset
, DWORD dwFlags
,
281 IDirectMusicPerformance
*pPerf
, IDirectMusicSegmentState
*pSegSt
, DWORD dwVirtualID
)
283 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
284 FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %ld, %p, %p, %ld): stub\n", This
, pStateData
, wine_dbgstr_longlong(rtStart
),
285 wine_dbgstr_longlong(rtEnd
), wine_dbgstr_longlong(rtOffset
), dwFlags
, pPerf
, pSegSt
, dwVirtualID
);
289 static HRESULT WINAPI
sequence_track_GetParamEx(IDirectMusicTrack8
*iface
, REFGUID type
,
290 REFERENCE_TIME time
, REFERENCE_TIME
*next
, void *param
, void *state
, DWORD flags
)
292 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
294 TRACE("(%p, %s, %s, %p, %p, %p, %lx): method not implemented\n", This
, debugstr_dmguid(type
),
295 wine_dbgstr_longlong(time
), next
, param
, state
, flags
);
299 static HRESULT WINAPI
sequence_track_SetParamEx(IDirectMusicTrack8
*iface
, REFGUID type
,
300 REFERENCE_TIME time
, void *param
, void *state
, DWORD flags
)
302 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
304 TRACE("(%p, %s, %s, %p, %p, %lx): method not implemented\n", This
, debugstr_dmguid(type
),
305 wine_dbgstr_longlong(time
), param
, state
, flags
);
309 static HRESULT WINAPI
sequence_track_Compose(IDirectMusicTrack8
*iface
, IUnknown
*context
,
310 DWORD trackgroup
, IDirectMusicTrack
**track
)
312 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
314 TRACE("(%p, %p, %ld, %p): method not implemented\n", This
, context
, trackgroup
, track
);
318 static HRESULT WINAPI
sequence_track_Join(IDirectMusicTrack8
*iface
, IDirectMusicTrack
*newtrack
,
319 MUSIC_TIME join
, IUnknown
*context
, DWORD trackgroup
, IDirectMusicTrack
**resulttrack
)
321 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(iface
);
322 TRACE("(%p, %p, %ld, %p, %ld, %p): method not implemented\n", This
, newtrack
, join
, context
,
323 trackgroup
, resulttrack
);
327 static const IDirectMusicTrack8Vtbl dmtrack8_vtbl
= {
328 sequence_track_QueryInterface
,
329 sequence_track_AddRef
,
330 sequence_track_Release
,
332 sequence_track_InitPlay
,
333 sequence_track_EndPlay
,
335 sequence_track_GetParam
,
336 sequence_track_SetParam
,
337 sequence_track_IsParamSupported
,
338 sequence_track_AddNotificationType
,
339 sequence_track_RemoveNotificationType
,
340 sequence_track_Clone
,
341 sequence_track_PlayEx
,
342 sequence_track_GetParamEx
,
343 sequence_track_SetParamEx
,
344 sequence_track_Compose
,
348 static HRESULT
parse_curl_list(struct sequence_track
*This
, IStream
*stream
, struct chunk_entry
*chunk
)
353 if (FAILED(hr
= stream_chunk_get_array(stream
, chunk
, (void **)&This
->curve_items
,
354 &This
->curve_count
, sizeof(*This
->curve_items
))))
356 /* try again with the older DMUS_IO_CURVE_ITEM size */
357 UINT size
= offsetof(DMUS_IO_CURVE_ITEM
, wParamType
);
360 if (FAILED(hr
= stream_reset_chunk_data(stream
, chunk
))) return hr
;
361 if (FAILED(hr
= stream_chunk_get_array(stream
, chunk
, (void **)&buffer
,
362 &This
->curve_count
, size
)))
365 if (!(This
->curve_items
= calloc(This
->curve_count
, sizeof(*This
->curve_items
)))) return E_OUTOFMEMORY
;
366 for (i
= 0; i
< This
->curve_count
; i
++) memcpy(This
->curve_items
+ i
, buffer
+ size
* i
, size
);
373 static HRESULT
parse_seqt_chunk(struct sequence_track
*This
, IStream
*stream
, struct chunk_entry
*parent
)
375 struct chunk_entry chunk
= {.parent
= parent
};
378 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
380 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
382 case DMUS_FOURCC_SEQ_LIST
:
383 hr
= stream_chunk_get_array(stream
, &chunk
, (void **)&This
->items
,
384 &This
->count
, sizeof(*This
->items
));
387 case DMUS_FOURCC_CURVE_LIST
:
388 hr
= parse_curl_list(This
, stream
, &chunk
);
392 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
396 if (FAILED(hr
)) break;
402 static inline struct sequence_track
*impl_from_IPersistStream(IPersistStream
*iface
)
404 return CONTAINING_RECORD(iface
, struct sequence_track
, dmobj
.IPersistStream_iface
);
407 static HRESULT WINAPI
track_IPersistStream_Load(IPersistStream
*iface
, IStream
*stream
)
409 struct sequence_track
*This
= impl_from_IPersistStream(iface
);
410 struct chunk_entry chunk
= {0};
413 TRACE("(%p, %p)\n", This
, stream
);
415 if ((hr
= stream_get_chunk(stream
, &chunk
)) == S_OK
)
417 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
419 case DMUS_FOURCC_SEQ_TRACK
:
420 hr
= parse_seqt_chunk(This
, stream
, &chunk
);
424 WARN("Invalid seq track chunk %s %s\n", debugstr_fourcc(chunk
.id
), debugstr_fourcc(chunk
.type
));
425 hr
= DMUS_E_UNSUPPORTED_STREAM
;
430 stream_skip_chunk(stream
, &chunk
);
431 if (FAILED(hr
)) return hr
;
437 TRACE("Loaded DirectMusicSeqTrack %p\n", This
);
439 TRACE("- %u items:\n", This
->count
);
440 for (i
= 0; i
< This
->count
; i
++)
442 TRACE(" - DMUS_IO_SEQ_ITEM[%u]\n", i
);
443 TRACE(" - mtTime: %ld\n", This
->items
[i
].mtTime
);
444 TRACE(" - mtDuration: %ld\n", This
->items
[i
].mtDuration
);
445 TRACE(" - dwPChannel: %ld\n", This
->items
[i
].dwPChannel
);
446 TRACE(" - nOffset: %d\n", This
->items
[i
].nOffset
);
447 TRACE(" - bStatus: %d\n", This
->items
[i
].bStatus
);
448 TRACE(" - bByte1: %#x\n", This
->items
[i
].bByte1
);
449 TRACE(" - bByte2: %#x\n", This
->items
[i
].bByte2
);
452 TRACE("- %u curves:\n", This
->curve_count
);
453 for (i
= 0; i
< This
->curve_count
; i
++)
455 TRACE(" - DMUS_IO_CURVE_ITEM[%u]\n", i
);
456 TRACE(" - mtStart: %ld\n", This
->curve_items
[i
].mtStart
);
457 TRACE(" - mtDuration: %ld\n", This
->curve_items
[i
].mtDuration
);
458 TRACE(" - mtResetDuration: %ld\n", This
->curve_items
[i
].mtResetDuration
);
459 TRACE(" - dwPChannel: %ld\n", This
->curve_items
[i
].dwPChannel
);
460 TRACE(" - nOffset: %d\n", This
->curve_items
[i
].nOffset
);
461 TRACE(" - nStartValue: %d\n", This
->curve_items
[i
].nStartValue
);
462 TRACE(" - nEndValue: %d\n", This
->curve_items
[i
].nEndValue
);
463 TRACE(" - nResetValue: %d\n", This
->curve_items
[i
].nResetValue
);
464 TRACE(" - bType: %d\n", This
->curve_items
[i
].bType
);
465 TRACE(" - bCurveShape: %d\n", This
->curve_items
[i
].bCurveShape
);
466 TRACE(" - bCCData: %d\n", This
->curve_items
[i
].bCCData
);
467 TRACE(" - bFlags: %d\n", This
->curve_items
[i
].bFlags
);
468 TRACE(" - wParamType: %d\n", This
->curve_items
[i
].wParamType
);
469 TRACE(" - wMergeIndex: %d\n", This
->curve_items
[i
].wMergeIndex
);
476 static const IPersistStreamVtbl persiststream_vtbl
= {
477 dmobj_IPersistStream_QueryInterface
,
478 dmobj_IPersistStream_AddRef
,
479 dmobj_IPersistStream_Release
,
480 dmobj_IPersistStream_GetClassID
,
481 unimpl_IPersistStream_IsDirty
,
482 track_IPersistStream_Load
,
483 unimpl_IPersistStream_Save
,
484 unimpl_IPersistStream_GetSizeMax
487 /* for ClassFactory */
488 HRESULT
create_dmseqtrack(REFIID lpcGUID
, void **ppobj
)
490 struct sequence_track
*track
;
494 if (!(track
= calloc(1, sizeof(*track
)))) return E_OUTOFMEMORY
;
495 track
->IDirectMusicTrack8_iface
.lpVtbl
= &dmtrack8_vtbl
;
497 dmobject_init(&track
->dmobj
, &CLSID_DirectMusicSeqTrack
,
498 (IUnknown
*)&track
->IDirectMusicTrack8_iface
);
499 track
->dmobj
.IPersistStream_iface
.lpVtbl
= &persiststream_vtbl
;
501 hr
= IDirectMusicTrack8_QueryInterface(&track
->IDirectMusicTrack8_iface
, lpcGUID
, ppobj
);
502 IDirectMusicTrack8_Release(&track
->IDirectMusicTrack8_iface
);
507 void sequence_track_set_items(IDirectMusicTrack8
*track
, DMUS_IO_SEQ_ITEM
*items
, unsigned int count
)
509 struct sequence_track
*This
= impl_from_IDirectMusicTrack8(track
);