include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / dmime / tempotrack.c
blob2e44d8fda5f5f91931013fbefafac4d44b48820f
1 /* IDirectMusicTempoTrack Implementation
3 * Copyright (C) 2003-2004 Rok Mandeljc
4 * Copyright (C) 2004 Raphael Junqueira
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "dmime_private.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(dmime);
24 WINE_DECLARE_DEBUG_CHANNEL(dmfile);
26 /*****************************************************************************
27 * IDirectMusicTempoTrack implementation
30 struct tempo_entry
32 struct list entry;
33 DMUS_IO_TEMPO_ITEM item;
36 typedef struct IDirectMusicTempoTrack {
37 IDirectMusicTrack8 IDirectMusicTrack8_iface;
38 struct dmobject dmobj; /* IPersistStream only */
39 LONG ref;
40 struct list items;
41 } IDirectMusicTempoTrack;
43 /* IDirectMusicTempoTrack IDirectMusicTrack8 part: */
44 static inline IDirectMusicTempoTrack *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface)
46 return CONTAINING_RECORD(iface, IDirectMusicTempoTrack, IDirectMusicTrack8_iface);
49 static HRESULT WINAPI tempo_track_QueryInterface(IDirectMusicTrack8 *iface, REFIID riid,
50 void **ret_iface)
52 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
54 TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface);
56 *ret_iface = NULL;
58 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicTrack) ||
59 IsEqualIID(riid, &IID_IDirectMusicTrack8))
60 *ret_iface = iface;
61 else if (IsEqualIID(riid, &IID_IPersistStream))
62 *ret_iface = &This->dmobj.IPersistStream_iface;
63 else {
64 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface);
65 return E_NOINTERFACE;
68 IUnknown_AddRef((IUnknown*)*ret_iface);
69 return S_OK;
72 static ULONG WINAPI tempo_track_AddRef(IDirectMusicTrack8 *iface)
74 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
75 LONG ref = InterlockedIncrement(&This->ref);
77 TRACE("(%p) ref=%ld\n", This, ref);
79 return ref;
82 static ULONG WINAPI tempo_track_Release(IDirectMusicTrack8 *iface)
84 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
85 LONG ref = InterlockedDecrement(&This->ref);
87 TRACE("(%p) ref=%ld\n", This, ref);
89 if (!ref)
91 struct tempo_entry *item, *next_item;
92 LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &This->items, struct tempo_entry, entry)
94 list_remove(&item->entry);
95 free(item);
97 free(This);
100 return ref;
103 static HRESULT WINAPI tempo_track_Init(IDirectMusicTrack8 *iface, IDirectMusicSegment *pSegment)
105 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
106 TRACE("(%p, %p): nothing to do here\n", This, pSegment);
107 return S_OK;
110 static HRESULT WINAPI tempo_track_InitPlay(IDirectMusicTrack8 *iface,
111 IDirectMusicSegmentState *pSegmentState, IDirectMusicPerformance *pPerformance,
112 void **ppStateData, DWORD dwVirtualTrack8ID, DWORD dwFlags)
114 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
116 LPDMUS_PRIVATE_TEMPO_PLAY_STATE pState = NULL;
118 FIXME("(%p, %p, %p, %p, %ld, %ld): semi-stub\n", This, pSegmentState, pPerformance, ppStateData, dwVirtualTrack8ID, dwFlags);
120 if (!(pState = calloc(1, sizeof(*pState)))) return E_OUTOFMEMORY;
122 /** TODO real fill useful data */
123 pState->dummy = 0;
124 *ppStateData = pState;
125 return S_OK;
128 static HRESULT WINAPI tempo_track_EndPlay(IDirectMusicTrack8 *iface, void *pStateData)
130 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
132 LPDMUS_PRIVATE_TEMPO_PLAY_STATE pState = pStateData;
134 FIXME("(%p, %p): semi-stub\n", This, pStateData);
136 if (NULL == pStateData) {
137 return E_POINTER;
139 /** TODO real clean up */
140 free(pState);
141 return S_OK;
144 static HRESULT WINAPI tempo_track_Play(IDirectMusicTrack8 *iface, void *pStateData,
145 MUSIC_TIME mtStart, MUSIC_TIME mtEnd, MUSIC_TIME mtOffset, DWORD dwFlags,
146 IDirectMusicPerformance *pPerf, IDirectMusicSegmentState *pSegSt, DWORD dwVirtualID)
148 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
149 FIXME("(%p, %p, %ld, %ld, %ld, %ld, %p, %p, %ld): stub\n", This, pStateData, mtStart, mtEnd, mtOffset, dwFlags, pPerf, pSegSt, dwVirtualID);
150 /** should use IDirectMusicPerformance_SendPMsg here */
151 return S_OK;
154 static HRESULT WINAPI tempo_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME music_time,
155 MUSIC_TIME *out_next_time, void *param)
157 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
158 struct tempo_entry *item, *next_item;
159 DMUS_TEMPO_PARAM *tempo = param;
160 MUSIC_TIME next_time = 0;
162 TRACE("(%p, %s, %ld, %p, %p)\n", This, debugstr_dmguid(type), music_time, out_next_time, param);
164 if (!param) return E_POINTER;
165 if (!IsEqualGUID(type, &GUID_TempoParam)) return DMUS_E_GET_UNSUPPORTED;
166 if (list_empty(&This->items)) return DMUS_E_NOT_FOUND;
168 /* if music_time is before the first item, we return the first item. */
169 LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &This->items, struct tempo_entry, entry)
171 tempo->mtTime = item->item.lTime - music_time;
172 tempo->dblTempo = item->item.dblTempo;
174 next_time = tempo->mtTime;
175 if (next_time > 0) break;
176 next_time = 0;
177 if (item->entry.next == &This->items) break;
178 next_time = next_item->item.lTime - music_time;
179 if (next_time > 0) break;
182 if (out_next_time) *out_next_time = next_time;
183 return S_OK;
186 static HRESULT WINAPI tempo_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
187 void *param)
189 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
191 TRACE("(%p, %s, %ld, %p)\n", This, debugstr_dmguid(type), time, param);
193 if (IsEqualGUID(type, &GUID_DisableTempo)) {
194 if (!param)
195 return DMUS_E_TYPE_DISABLED;
196 FIXME("GUID_DisableTempo not handled yet\n");
197 return S_OK;
199 if (IsEqualGUID(type, &GUID_EnableTempo)) {
200 if (!param)
201 return DMUS_E_TYPE_DISABLED;
202 FIXME("GUID_EnableTempo not handled yet\n");
203 return S_OK;
205 if (IsEqualGUID(type, &GUID_TempoParam)) {
206 struct tempo_entry *item, *next_item;
207 DMUS_TEMPO_PARAM *tempo_param = param;
208 struct tempo_entry *entry;
209 if (!param)
210 return E_POINTER;
211 if (!(entry = calloc(1, sizeof(*entry))))
212 return E_OUTOFMEMORY;
213 entry->item.lTime = time;
214 entry->item.dblTempo = tempo_param->dblTempo;
215 if (list_empty(&This->items))
216 list_add_tail(&This->items, &entry->entry);
217 else
219 LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &This->items, struct tempo_entry, entry)
220 if (item->entry.next == &This->items || next_item->item.lTime > time)
222 list_add_after(&item->entry, &entry->entry);
223 break;
226 return S_OK;
229 return DMUS_E_SET_UNSUPPORTED;
232 static HRESULT WINAPI tempo_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID rguidType)
234 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
236 TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidType));
237 if (IsEqualGUID (rguidType, &GUID_DisableTempo)
238 || IsEqualGUID (rguidType, &GUID_EnableTempo)
239 || IsEqualGUID (rguidType, &GUID_TempoParam)) {
240 TRACE("param supported\n");
241 return S_OK;
243 TRACE("param unsupported\n");
244 return DMUS_E_TYPE_UNSUPPORTED;
247 static HRESULT WINAPI tempo_track_AddNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype)
249 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
251 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
252 return E_NOTIMPL;
255 static HRESULT WINAPI tempo_track_RemoveNotificationType(IDirectMusicTrack8 *iface,
256 REFGUID notiftype)
258 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
260 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
261 return E_NOTIMPL;
264 static HRESULT WINAPI tempo_track_Clone(IDirectMusicTrack8 *iface, MUSIC_TIME mtStart,
265 MUSIC_TIME mtEnd, IDirectMusicTrack **ppTrack)
267 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
268 FIXME("(%p, %ld, %ld, %p): stub\n", This, mtStart, mtEnd, ppTrack);
269 return S_OK;
272 static HRESULT WINAPI tempo_track_PlayEx(IDirectMusicTrack8 *iface, void *pStateData,
273 REFERENCE_TIME rtStart, REFERENCE_TIME rtEnd, REFERENCE_TIME rtOffset, DWORD dwFlags,
274 IDirectMusicPerformance *pPerf, IDirectMusicSegmentState *pSegSt, DWORD dwVirtualID)
276 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
277 FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %ld, %p, %p, %ld): stub\n", This, pStateData, wine_dbgstr_longlong(rtStart),
278 wine_dbgstr_longlong(rtEnd), wine_dbgstr_longlong(rtOffset), dwFlags, pPerf, pSegSt, dwVirtualID);
279 return S_OK;
282 static HRESULT WINAPI tempo_track_GetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType,
283 REFERENCE_TIME rtTime, REFERENCE_TIME *prtNext, void *pParam, void *pStateData,
284 DWORD dwFlags)
286 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
287 FIXME("(%p, %s, 0x%s, %p, %p, %p, %ld): stub\n", This, debugstr_dmguid(rguidType),
288 wine_dbgstr_longlong(rtTime), prtNext, pParam, pStateData, dwFlags);
289 return S_OK;
292 static HRESULT WINAPI tempo_track_SetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType,
293 REFERENCE_TIME rtTime, void *pParam, void *pStateData, DWORD dwFlags)
295 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
296 FIXME("(%p, %s, 0x%s, %p, %p, %ld): stub\n", This, debugstr_dmguid(rguidType),
297 wine_dbgstr_longlong(rtTime), pParam, pStateData, dwFlags);
298 return S_OK;
301 static HRESULT WINAPI tempo_track_Compose(IDirectMusicTrack8 *iface, IUnknown *context,
302 DWORD trackgroup, IDirectMusicTrack **track)
304 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
306 TRACE("(%p, %p, %ld, %p): method not implemented\n", This, context, trackgroup, track);
307 return E_NOTIMPL;
310 static HRESULT WINAPI tempo_track_Join(IDirectMusicTrack8 *iface, IDirectMusicTrack *pNewTrack,
311 MUSIC_TIME mtJoin, IUnknown *pContext, DWORD dwTrackGroup,
312 IDirectMusicTrack **ppResultTrack)
314 IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
315 FIXME("(%p, %p, %ld, %p, %ld, %p): stub\n", This, pNewTrack, mtJoin, pContext, dwTrackGroup, ppResultTrack);
316 return S_OK;
319 static const IDirectMusicTrack8Vtbl dmtrack8_vtbl = {
320 tempo_track_QueryInterface,
321 tempo_track_AddRef,
322 tempo_track_Release,
323 tempo_track_Init,
324 tempo_track_InitPlay,
325 tempo_track_EndPlay,
326 tempo_track_Play,
327 tempo_track_GetParam,
328 tempo_track_SetParam,
329 tempo_track_IsParamSupported,
330 tempo_track_AddNotificationType,
331 tempo_track_RemoveNotificationType,
332 tempo_track_Clone,
333 tempo_track_PlayEx,
334 tempo_track_GetParamEx,
335 tempo_track_SetParamEx,
336 tempo_track_Compose,
337 tempo_track_Join
340 static inline IDirectMusicTempoTrack *impl_from_IPersistStream(IPersistStream *iface)
342 return CONTAINING_RECORD(iface, IDirectMusicTempoTrack, dmobj.IPersistStream_iface);
345 static HRESULT WINAPI tempo_IPersistStream_Load(IPersistStream *iface, IStream *stream)
347 IDirectMusicTempoTrack *This = impl_from_IPersistStream(iface);
348 struct chunk_entry chunk = {0};
349 DMUS_IO_TEMPO_ITEM *items;
350 ULONG i = 0;
351 HRESULT hr;
352 UINT count;
354 TRACE("%p, %p\n", This, stream);
356 if (!stream)
357 return E_POINTER;
359 if ((hr = stream_get_chunk(stream, &chunk)) != S_OK)
360 return hr;
361 if (chunk.id != DMUS_FOURCC_TEMPO_TRACK)
362 return DMUS_E_UNSUPPORTED_STREAM;
364 hr = stream_chunk_get_array(stream, &chunk, (void **)&items, &count,
365 sizeof(DMUS_IO_TEMPO_ITEM));
366 if (FAILED(hr))
367 return hr;
369 for (i = 0; i < count; i++)
371 struct tempo_entry *entry = calloc(1, sizeof(*entry));
372 if (!entry)
374 hr = E_OUTOFMEMORY;
375 break;
378 entry->item = items[i];
379 list_add_tail(&This->items, &entry->entry);
381 TRACE_(dmfile)("DMUS_IO_TEMPO_ITEM #%lu\n", i);
382 TRACE_(dmfile)(" - lTime = %lu\n", items[i].lTime);
383 TRACE_(dmfile)(" - dblTempo = %g\n", items[i].dblTempo);
386 free(items);
387 return hr;
390 static const IPersistStreamVtbl persiststream_vtbl = {
391 dmobj_IPersistStream_QueryInterface,
392 dmobj_IPersistStream_AddRef,
393 dmobj_IPersistStream_Release,
394 dmobj_IPersistStream_GetClassID,
395 unimpl_IPersistStream_IsDirty,
396 tempo_IPersistStream_Load,
397 unimpl_IPersistStream_Save,
398 unimpl_IPersistStream_GetSizeMax
401 /* for ClassFactory */
402 HRESULT create_dmtempotrack(REFIID lpcGUID, void **ppobj)
404 IDirectMusicTempoTrack *track;
405 HRESULT hr;
407 *ppobj = NULL;
408 if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY;
409 track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl;
410 track->ref = 1;
411 dmobject_init(&track->dmobj, &CLSID_DirectMusicTempoTrack,
412 (IUnknown *)&track->IDirectMusicTrack8_iface);
413 track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl;
414 list_init(&track->items);
416 hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj);
417 IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface);
419 return hr;