include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / dmime / seqtrack.c
blob1b0e99bd77cea7846d7d9c40e00813ca6c833e2c
1 /*
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);
24 struct sequence_track
26 IDirectMusicTrack8 IDirectMusicTrack8_iface;
27 struct dmobject dmobj; /* IPersistStream only */
28 LONG ref;
30 DMUS_IO_SEQ_ITEM *items;
31 unsigned int count;
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,
43 void **ret_iface)
45 struct sequence_track *This = impl_from_IDirectMusicTrack8(iface);
47 TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface);
49 *ret_iface = NULL;
51 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicTrack) ||
52 IsEqualIID(riid, &IID_IDirectMusicTrack8))
53 *ret_iface = iface;
54 else if (IsEqualIID(riid, &IID_IPersistStream))
55 *ret_iface = &This->dmobj.IPersistStream_iface;
56 else {
57 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface);
58 return E_NOINTERFACE;
61 IUnknown_AddRef((IUnknown*)*ret_iface);
62 return S_OK;
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);
72 return 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);
82 if (!ref) {
83 free(This);
86 return 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);
93 return S_OK;
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);
102 return S_OK;
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);
109 return S_OK;
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;
118 HRESULT hr;
119 UINT i;
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)))
129 return hr;
131 for (i = 0; SUCCEEDED(hr) &&i < This->count; i++)
133 DMUS_IO_SEQ_ITEM *item = This->items + i;
134 DMUS_PMSG *msg;
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 **)&note)))
144 break;
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;
151 note->bFlags = 1;
152 note->bMidiValue = item->bByte1;
153 msg = (DMUS_PMSG *)note;
155 else
157 DMUS_MIDI_PMSG *midi;
158 if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*midi),
159 (DMUS_PMSG **)&midi)))
160 break;
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;
173 msg->dwGroupID = 1;
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);
179 break;
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)))
193 break;
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);
218 break;
222 IDirectMusicGraph_Release(graph);
223 return hr;
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,
232 next, param);
233 return E_NOTIMPL;
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);
242 return E_NOTIMPL;
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));
250 return E_NOTIMPL;
253 static HRESULT WINAPI sequence_track_AddNotificationType(IDirectMusicTrack8 *iface,
254 REFGUID notiftype)
256 struct sequence_track *This = impl_from_IDirectMusicTrack8(iface);
258 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
259 return E_NOTIMPL;
262 static HRESULT WINAPI sequence_track_RemoveNotificationType(IDirectMusicTrack8 *iface,
263 REFGUID notiftype)
265 struct sequence_track *This = impl_from_IDirectMusicTrack8(iface);
267 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
268 return E_NOTIMPL;
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);
276 return S_OK;
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);
286 return S_OK;
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);
296 return E_NOTIMPL;
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);
306 return E_NOTIMPL;
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);
315 return E_NOTIMPL;
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);
324 return E_NOTIMPL;
327 static const IDirectMusicTrack8Vtbl dmtrack8_vtbl = {
328 sequence_track_QueryInterface,
329 sequence_track_AddRef,
330 sequence_track_Release,
331 sequence_track_Init,
332 sequence_track_InitPlay,
333 sequence_track_EndPlay,
334 sequence_track_Play,
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,
345 sequence_track_Join
348 static HRESULT parse_curl_list(struct sequence_track *This, IStream *stream, struct chunk_entry *chunk)
350 HRESULT hr;
351 UINT i;
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);
358 BYTE *buffer;
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)))
363 return hr;
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);
367 free(buffer);
370 return S_OK;
373 static HRESULT parse_seqt_chunk(struct sequence_track *This, IStream *stream, struct chunk_entry *parent)
375 struct chunk_entry chunk = {.parent = parent};
376 HRESULT hr;
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));
385 break;
387 case DMUS_FOURCC_CURVE_LIST:
388 hr = parse_curl_list(This, stream, &chunk);
389 break;
391 default:
392 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
393 break;
396 if (FAILED(hr)) break;
399 return hr;
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};
411 HRESULT hr;
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);
421 break;
423 default:
424 WARN("Invalid seq track chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
425 hr = DMUS_E_UNSUPPORTED_STREAM;
426 break;
430 stream_skip_chunk(stream, &chunk);
431 if (FAILED(hr)) return hr;
433 if (TRACE_ON(dmime))
435 UINT i;
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);
473 return S_OK;
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;
491 HRESULT hr;
493 *ppobj = NULL;
494 if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY;
495 track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl;
496 track->ref = 1;
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);
504 return hr;
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);
510 free(This->items);
511 This->items = items;
512 This->count = count;