1 /* IDirectMusicPerformance Implementation
3 * Copyright (C) 2003-2004 Rok Mandeljc
4 * Copyright (C) 2003-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"
22 #include "dmusic_midi.h"
23 #include "wine/rbtree.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(dmime
);
27 enum dmus_internal_message_type
29 DMUS_PMSGT_INTERNAL_FIRST
= 0x10,
30 DMUS_PMSGT_INTERNAL_SEGMENT_END
= DMUS_PMSGT_INTERNAL_FIRST
,
31 DMUS_PMSGT_INTERNAL_SEGMENT_TICK
,
34 struct pchannel_block
{
35 DWORD block_num
; /* Block 0 is PChannels 0-15, Block 1 is PChannels 16-31, etc */
37 DWORD channel
; /* MIDI channel */
38 DWORD group
; /* MIDI group */
39 IDirectMusicPort
*port
;
41 struct wine_rb_entry entry
;
46 IDirectMusicPerformance8 IDirectMusicPerformance8_iface
;
47 IDirectMusicGraph IDirectMusicGraph_iface
;
48 IDirectMusicTool IDirectMusicTool_iface
;
52 IDirectMusicGraph
*pToolGraph
;
54 char cMasterGrooveLevel
;
57 /* performance channels */
58 struct wine_rb_tree pchannels
;
60 BOOL audio_paths_enabled
;
61 IDirectMusicAudioPath
*pDefaultPath
;
62 REFERENCE_TIME latency_offset
;
66 HANDLE message_thread
;
67 CRITICAL_SECTION safe
;
68 CONDITION_VARIABLE cond
;
70 IReferenceClock
*master_clock
;
71 REFERENCE_TIME init_time
;
74 struct list notifications
;
75 REFERENCE_TIME notification_timeout
;
76 HANDLE notification_event
;
77 BOOL notification_performance
;
78 BOOL notification_segment
;
80 IDirectMusicSegment
*primary_segment
;
89 static inline struct message
*message_from_DMUS_PMSG(DMUS_PMSG
*msg
)
91 return msg
? CONTAINING_RECORD(msg
, struct message
, msg
) : NULL
;
94 static void performance_queue_message(struct performance
*This
, struct message
*message
, struct list
*hint
)
98 LIST_FOR_EACH_ENTRY_REV(prev
, hint
? hint
: &This
->messages
, struct message
, entry
)
100 if (&prev
->entry
== &This
->messages
) break;
101 if (prev
->msg
.rtTime
<= message
->msg
.rtTime
) break;
104 list_add_after(&prev
->entry
, &message
->entry
);
107 static HRESULT
performance_process_message(struct performance
*This
, DMUS_PMSG
*msg
, DWORD
*timeout
)
109 static const DWORD delivery_flags
= DMUS_PMSGF_TOOL_IMMEDIATE
| DMUS_PMSGF_TOOL_QUEUE
| DMUS_PMSGF_TOOL_ATTIME
;
110 IDirectMusicPerformance
*performance
= (IDirectMusicPerformance
*)&This
->IDirectMusicPerformance8_iface
;
115 REFERENCE_TIME latency
, offset
= 0;
116 IDirectMusicTool
*tool
;
118 if (FAILED(hr
= IDirectMusicPerformance_GetLatencyTime(performance
, &latency
))) return hr
;
119 if (!(tool
= msg
->pTool
)) tool
= &This
->IDirectMusicTool_iface
;
121 switch (msg
->dwFlags
& delivery_flags
)
124 WARN("No delivery flag found for message %p\n", msg
);
126 case DMUS_PMSGF_TOOL_IMMEDIATE
:
127 hr
= IDirectMusicTool_ProcessPMsg(tool
, performance
, msg
);
129 case DMUS_PMSGF_TOOL_QUEUE
:
130 offset
= This
->dwBumperLength
* 10000;
132 case DMUS_PMSGF_TOOL_ATTIME
:
133 if (msg
->rtTime
>= offset
&& msg
->rtTime
- offset
>= latency
)
135 if (timeout
) *timeout
= (msg
->rtTime
- offset
- latency
) / 10000;
136 return DMUS_S_REQUEUE
;
139 hr
= IDirectMusicTool_ProcessPMsg(tool
, performance
, msg
);
142 } while (hr
== DMUS_S_REQUEUE
);
144 if (hr
== DMUS_S_FREE
) hr
= IDirectMusicPerformance_FreePMsg(performance
, msg
);
145 if (FAILED(hr
)) WARN("Failed to process message, hr %#lx\n", hr
);
149 static DWORD WINAPI
message_thread_proc(void *args
)
151 struct performance
*This
= args
;
152 HRESULT hr
= DMUS_S_REQUEUE
;
155 TRACE("performance %p message thread\n", This
);
156 SetThreadDescription(GetCurrentThread(), L
"wine_dmime_message");
158 EnterCriticalSection(&This
->safe
);
160 while (This
->message_thread
)
162 DWORD timeout
= INFINITE
;
164 while ((ptr
= list_head(&This
->messages
)))
166 struct message
*message
= LIST_ENTRY(ptr
, struct message
, entry
);
167 struct list
*next
= ptr
->next
;
168 list_remove(&message
->entry
);
169 list_init(&message
->entry
);
171 hr
= performance_process_message(This
, &message
->msg
, &timeout
);
172 if (hr
== DMUS_S_REQUEUE
) performance_queue_message(This
, message
, next
);
173 if (hr
!= S_OK
) break;
176 SleepConditionVariableCS(&This
->cond
, &This
->safe
, timeout
);
179 LeaveCriticalSection(&This
->safe
);
181 TRACE("(%p): Exiting\n", This
);
185 static HRESULT
performance_send_pmsg(struct performance
*This
, MUSIC_TIME music_time
, DWORD flags
,
186 DWORD type
, IUnknown
*object
)
188 IDirectMusicPerformance8
*performance
= &This
->IDirectMusicPerformance8_iface
;
189 IDirectMusicGraph
*graph
= &This
->IDirectMusicGraph_iface
;
193 if (FAILED(hr
= IDirectMusicPerformance8_AllocPMsg(performance
, sizeof(*msg
), &msg
)))
196 msg
->mtTime
= music_time
;
197 msg
->dwFlags
= DMUS_PMSGF_MUSICTIME
| flags
;
199 if ((msg
->punkUser
= object
)) IUnknown_AddRef(object
);
201 if ((type
< DMUS_PMSGT_INTERNAL_FIRST
&& FAILED(hr
= IDirectMusicGraph_StampPMsg(graph
, msg
)))
202 || FAILED(hr
= IDirectMusicPerformance8_SendPMsg(performance
, msg
)))
203 IDirectMusicPerformance8_FreePMsg(performance
, msg
);
208 static HRESULT
performance_send_notification_pmsg(struct performance
*This
, MUSIC_TIME music_time
, BOOL stamp
,
209 GUID type
, DWORD option
, IUnknown
*object
)
211 IDirectMusicPerformance8
*performance
= &This
->IDirectMusicPerformance8_iface
;
212 IDirectMusicGraph
*graph
= &This
->IDirectMusicGraph_iface
;
213 DMUS_NOTIFICATION_PMSG
*msg
;
216 if (FAILED(hr
= IDirectMusicPerformance8_AllocPMsg(performance
, sizeof(*msg
), (DMUS_PMSG
**)&msg
)))
219 msg
->mtTime
= music_time
;
220 msg
->dwFlags
= DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_IMMEDIATE
;
221 msg
->dwType
= DMUS_PMSGT_NOTIFICATION
;
222 if ((msg
->punkUser
= object
)) IUnknown_AddRef(object
);
223 msg
->guidNotificationType
= type
;
224 msg
->dwNotificationOption
= option
;
226 /* only stamp the message if notifications are enabled, otherwise send them directly to the output tool */
227 if ((stamp
&& FAILED(hr
= IDirectMusicGraph_StampPMsg(graph
, (DMUS_PMSG
*)msg
)))
228 || FAILED(hr
= IDirectMusicPerformance8_SendPMsg(performance
, (DMUS_PMSG
*)msg
)))
229 IDirectMusicPerformance8_FreePMsg(performance
, (DMUS_PMSG
*)msg
);
234 static int pchannel_block_compare(const void *key
, const struct wine_rb_entry
*entry
)
236 const struct pchannel_block
*b
= WINE_RB_ENTRY_VALUE(entry
, const struct pchannel_block
, entry
);
238 return *(DWORD
*)key
- b
->block_num
;
241 static void pchannel_block_free(struct wine_rb_entry
*entry
, void *context
)
243 struct pchannel_block
*b
= WINE_RB_ENTRY_VALUE(entry
, struct pchannel_block
, entry
);
248 static struct pchannel_block
*pchannel_block_set(struct wine_rb_tree
*tree
, DWORD block_num
,
249 IDirectMusicPort
*port
, DWORD group
, BOOL only_set_new
)
251 struct pchannel_block
*block
;
252 struct wine_rb_entry
*entry
;
255 entry
= wine_rb_get(tree
, &block_num
);
257 block
= WINE_RB_ENTRY_VALUE(entry
, struct pchannel_block
, entry
);
261 if (!(block
= malloc(sizeof(*block
)))) return NULL
;
262 block
->block_num
= block_num
;
265 for (i
= 0; i
< 16; ++i
) {
266 block
->pchannel
[i
].port
= port
;
267 block
->pchannel
[i
].group
= group
;
268 block
->pchannel
[i
].channel
= i
;
271 wine_rb_put(tree
, &block
->block_num
, &block
->entry
);
276 static inline struct performance
*impl_from_IDirectMusicPerformance8(IDirectMusicPerformance8
*iface
)
278 return CONTAINING_RECORD(iface
, struct performance
, IDirectMusicPerformance8_iface
);
281 HRESULT
performance_send_segment_start(IDirectMusicPerformance8
*iface
, MUSIC_TIME music_time
,
282 IDirectMusicSegmentState
*state
)
284 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
287 if (FAILED(hr
= performance_send_notification_pmsg(This
, music_time
, This
->notification_performance
,
288 GUID_NOTIFICATION_PERFORMANCE
, DMUS_NOTIFICATION_MUSICSTARTED
, NULL
)))
290 if (FAILED(hr
= performance_send_notification_pmsg(This
, music_time
, This
->notification_segment
,
291 GUID_NOTIFICATION_SEGMENT
, DMUS_NOTIFICATION_SEGSTART
, (IUnknown
*)state
)))
293 if (FAILED(hr
= performance_send_pmsg(This
, music_time
, DMUS_PMSGF_TOOL_IMMEDIATE
,
294 DMUS_PMSGT_DIRTY
, NULL
)))
300 HRESULT
performance_send_segment_tick(IDirectMusicPerformance8
*iface
, MUSIC_TIME music_time
,
301 IDirectMusicSegmentState
*state
)
303 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
307 if (FAILED(hr
= IDirectMusicPerformance8_MusicToReferenceTime(iface
, music_time
, &time
)))
309 if (FAILED(hr
= IDirectMusicPerformance8_ReferenceToMusicTime(iface
, time
+ 2000000, &music_time
)))
311 if (FAILED(hr
= performance_send_pmsg(This
, music_time
, DMUS_PMSGF_TOOL_QUEUE
,
312 DMUS_PMSGT_INTERNAL_SEGMENT_TICK
, (IUnknown
*)state
)))
318 HRESULT
performance_send_segment_end(IDirectMusicPerformance8
*iface
, MUSIC_TIME music_time
,
319 IDirectMusicSegmentState
*state
)
321 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
324 if (FAILED(hr
= performance_send_notification_pmsg(This
, music_time
- 1450, This
->notification_segment
,
325 GUID_NOTIFICATION_SEGMENT
, DMUS_NOTIFICATION_SEGALMOSTEND
, (IUnknown
*)state
)))
327 if (FAILED(hr
= performance_send_notification_pmsg(This
, music_time
, This
->notification_segment
,
328 GUID_NOTIFICATION_SEGMENT
, DMUS_NOTIFICATION_SEGEND
, (IUnknown
*)state
)))
330 if (FAILED(hr
= performance_send_pmsg(This
, music_time
, DMUS_PMSGF_TOOL_IMMEDIATE
,
331 DMUS_PMSGT_DIRTY
, NULL
)))
333 if (FAILED(hr
= performance_send_notification_pmsg(This
, music_time
, This
->notification_performance
,
334 GUID_NOTIFICATION_PERFORMANCE
, DMUS_NOTIFICATION_MUSICSTOPPED
, NULL
)))
336 if (FAILED(hr
= performance_send_pmsg(This
, music_time
, DMUS_PMSGF_TOOL_ATTIME
,
337 DMUS_PMSGT_INTERNAL_SEGMENT_END
, (IUnknown
*)state
)))
343 static void performance_set_primary_segment(struct performance
*This
, IDirectMusicSegment
*segment
)
345 if (This
->primary_segment
) IDirectMusicSegment_Release(This
->primary_segment
);
346 if ((This
->primary_segment
= segment
)) IDirectMusicSegment_AddRef(This
->primary_segment
);
349 /* IDirectMusicPerformance8 IUnknown part: */
350 static HRESULT WINAPI
performance_QueryInterface(IDirectMusicPerformance8
*iface
, REFIID riid
, void **ret_iface
)
352 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
354 TRACE("(%p, %s, %p)\n", iface
, debugstr_dmguid(riid
), ret_iface
);
356 if (IsEqualGUID(riid
, &IID_IUnknown
)
357 || IsEqualGUID(riid
, &IID_IDirectMusicPerformance
)
358 || IsEqualGUID(riid
, &IID_IDirectMusicPerformance2
)
359 || IsEqualGUID(riid
, &IID_IDirectMusicPerformance8
))
362 IUnknown_AddRef(iface
);
366 if (IsEqualGUID(riid
, &IID_IDirectMusicGraph
))
368 *ret_iface
= &This
->IDirectMusicGraph_iface
;
369 IDirectMusicGraph_AddRef(&This
->IDirectMusicGraph_iface
);
373 if (IsEqualGUID(riid
, &IID_IDirectMusicTool
))
375 *ret_iface
= &This
->IDirectMusicTool_iface
;
376 IDirectMusicTool_AddRef(&This
->IDirectMusicTool_iface
);
381 WARN("(%p, %s, %p): not found\n", iface
, debugstr_dmguid(riid
), ret_iface
);
382 return E_NOINTERFACE
;
385 static ULONG WINAPI
performance_AddRef(IDirectMusicPerformance8
*iface
)
387 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
388 ULONG ref
= InterlockedIncrement(&This
->ref
);
390 TRACE("(%p): ref=%ld\n", This
, ref
);
395 static ULONG WINAPI
performance_Release(IDirectMusicPerformance8
*iface
)
397 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
398 ULONG ref
= InterlockedDecrement(&This
->ref
);
400 TRACE("(%p): ref=%ld\n", This
, ref
);
403 wine_rb_destroy(&This
->pchannels
, pchannel_block_free
, NULL
);
404 This
->safe
.DebugInfo
->Spare
[0] = 0;
405 DeleteCriticalSection(&This
->safe
);
412 static HRESULT
performance_init_dsound(struct performance
*This
, HWND hwnd
)
414 IDirectSound
*dsound
;
417 if (FAILED(hr
= DirectSoundCreate(NULL
, &dsound
, NULL
))) return hr
;
419 if (!hwnd
) hwnd
= GetForegroundWindow();
420 hr
= IDirectSound_SetCooperativeLevel(dsound
, hwnd
, DSSCL_PRIORITY
);
422 if (SUCCEEDED(hr
)) This
->dsound
= dsound
;
423 else IDirectSound_Release(dsound
);
428 static HRESULT
performance_init_dmusic(struct performance
*This
, IDirectSound
*dsound
)
430 IDirectMusic
*dmusic
;
433 if (FAILED(hr
= CoCreateInstance(&CLSID_DirectMusic
, NULL
, CLSCTX_INPROC_SERVER
,
434 &IID_IDirectMusic8
, (void **)&dmusic
)))
437 hr
= IDirectMusic_SetDirectSound(dmusic
, dsound
, NULL
);
439 if (SUCCEEDED(hr
)) This
->dmusic
= dmusic
;
440 else IDirectSound_Release(dmusic
);
445 static HRESULT WINAPI
performance_Init(IDirectMusicPerformance8
*iface
, IDirectMusic
**dmusic
,
446 IDirectSound
*dsound
, HWND hwnd
)
448 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
451 TRACE("(%p, %p, %p, %p)\n", iface
, dmusic
, dsound
, hwnd
);
453 if (This
->dmusic
) return DMUS_E_ALREADY_INITED
;
455 if ((This
->dsound
= dsound
)) IDirectMusic8_AddRef(This
->dsound
);
456 else if (FAILED(hr
= performance_init_dsound(This
, hwnd
))) return hr
;
458 if (dmusic
&& (This
->dmusic
= *dmusic
)) IDirectMusic_AddRef(This
->dmusic
);
459 else if (FAILED(hr
= performance_init_dmusic(This
, This
->dsound
)))
461 IDirectMusicPerformance_CloseDown(iface
);
465 if (FAILED(hr
= IDirectMusic_GetMasterClock(This
->dmusic
, NULL
, &This
->master_clock
))
466 || FAILED(hr
= IDirectMusicPerformance8_GetTime(iface
, &This
->init_time
, NULL
)))
468 IDirectMusicPerformance_CloseDown(iface
);
472 if (!(This
->message_thread
= CreateThread(NULL
, 0, message_thread_proc
, This
, 0, NULL
)))
474 ERR("Failed to start performance message thread, error %lu\n", GetLastError());
475 IDirectMusicPerformance_CloseDown(iface
);
476 return HRESULT_FROM_WIN32(GetLastError());
479 if (dmusic
&& !*dmusic
)
481 *dmusic
= This
->dmusic
;
482 IDirectMusic_AddRef(*dmusic
);
487 static HRESULT WINAPI
performance_PlaySegment(IDirectMusicPerformance8
*iface
, IDirectMusicSegment
*segment
,
488 DWORD segment_flags
, INT64 start_time
, IDirectMusicSegmentState
**ret_state
)
490 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
492 TRACE("(%p, %p, %ld, %I64d, %p)\n", This
, segment
, segment_flags
, start_time
, ret_state
);
494 return IDirectMusicPerformance8_PlaySegmentEx(iface
, (IUnknown
*)segment
, NULL
, NULL
,
495 segment_flags
, start_time
, ret_state
, NULL
, NULL
);
501 IDirectMusicSegmentState
*state
;
504 static void state_entry_destroy(struct state_entry
*entry
)
506 list_remove(&entry
->entry
);
507 IDirectMusicSegmentState_Release(entry
->state
);
511 static void enum_segment_states(struct performance
*This
, IDirectMusicSegment
*segment
, struct list
*list
)
513 struct state_entry
*entry
;
514 struct message
*message
;
516 LIST_FOR_EACH_ENTRY(message
, &This
->messages
, struct message
, entry
)
518 IDirectMusicSegmentState
*message_state
;
520 if (message
->msg
.dwType
!= DMUS_PMSGT_INTERNAL_SEGMENT_TICK
521 && message
->msg
.dwType
!= DMUS_PMSGT_INTERNAL_SEGMENT_END
)
524 message_state
= (IDirectMusicSegmentState
*)message
->msg
.punkUser
;
525 if (segment
&& !segment_state_has_segment(message_state
, segment
)) continue;
527 if (!(entry
= malloc(sizeof(*entry
)))) return;
528 entry
->state
= message_state
;
529 IDirectMusicSegmentState_AddRef(entry
->state
);
530 list_add_tail(list
, &entry
->entry
);
534 static HRESULT WINAPI
performance_Stop(IDirectMusicPerformance8
*iface
, IDirectMusicSegment
*pSegment
,
535 IDirectMusicSegmentState
*pSegmentState
, MUSIC_TIME mtTime
, DWORD dwFlags
)
537 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
539 FIXME("(%p, %p, %p, %ld, %ld): stub\n", This
, pSegment
, pSegmentState
, mtTime
, dwFlags
);
543 static HRESULT WINAPI
performance_GetSegmentState(IDirectMusicPerformance8
*iface
,
544 IDirectMusicSegmentState
**state
, MUSIC_TIME time
)
546 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
547 struct list
*ptr
, states
= LIST_INIT(states
);
548 struct state_entry
*entry
, *next
;
551 TRACE("(%p, %p, %ld)\n", This
, state
, time
);
553 if (!state
) return E_POINTER
;
555 EnterCriticalSection(&This
->safe
);
557 enum_segment_states(This
, This
->primary_segment
, &states
);
559 if (!(ptr
= list_head(&states
))) hr
= DMUS_E_NOT_FOUND
;
562 entry
= LIST_ENTRY(ptr
, struct state_entry
, entry
);
564 *state
= entry
->state
;
565 IDirectMusicSegmentState_AddRef(entry
->state
);
567 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &states
, struct state_entry
, entry
)
568 state_entry_destroy(entry
);
571 LeaveCriticalSection(&This
->safe
);
576 static HRESULT WINAPI
performance_SetPrepareTime(IDirectMusicPerformance8
*iface
, DWORD dwMilliSeconds
)
578 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
580 TRACE("(%p, %ld)\n", This
, dwMilliSeconds
);
581 This
->dwPrepareTime
= dwMilliSeconds
;
585 static HRESULT WINAPI
performance_GetPrepareTime(IDirectMusicPerformance8
*iface
, DWORD
*pdwMilliSeconds
)
587 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
589 TRACE("(%p, %p)\n", This
, pdwMilliSeconds
);
590 if (NULL
== pdwMilliSeconds
) {
593 *pdwMilliSeconds
= This
->dwPrepareTime
;
597 static HRESULT WINAPI
performance_SetBumperLength(IDirectMusicPerformance8
*iface
, DWORD dwMilliSeconds
)
599 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
601 TRACE("(%p, %ld)\n", This
, dwMilliSeconds
);
602 This
->dwBumperLength
= dwMilliSeconds
;
606 static HRESULT WINAPI
performance_GetBumperLength(IDirectMusicPerformance8
*iface
, DWORD
*pdwMilliSeconds
)
608 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
610 TRACE("(%p, %p)\n", This
, pdwMilliSeconds
);
611 if (NULL
== pdwMilliSeconds
) {
614 *pdwMilliSeconds
= This
->dwBumperLength
;
618 static HRESULT WINAPI
performance_SendPMsg(IDirectMusicPerformance8
*iface
, DMUS_PMSG
*msg
)
620 const DWORD delivery_flags
= DMUS_PMSGF_TOOL_IMMEDIATE
| DMUS_PMSGF_TOOL_QUEUE
| DMUS_PMSGF_TOOL_ATTIME
;
621 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
622 struct message
*message
;
625 TRACE("(%p, %p)\n", This
, msg
);
627 if (!(message
= message_from_DMUS_PMSG(msg
))) return E_POINTER
;
628 if (!This
->dmusic
) return DMUS_E_NO_MASTER_CLOCK
;
629 if (!(msg
->dwFlags
& (DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_REFTIME
))) return E_INVALIDARG
;
631 EnterCriticalSection(&This
->safe
);
633 if (!list_empty(&message
->entry
))
634 hr
= DMUS_E_ALREADY_SENT
;
637 if (!(msg
->dwFlags
& delivery_flags
)) msg
->dwFlags
|= DMUS_PMSGF_TOOL_IMMEDIATE
;
638 if (!(msg
->dwFlags
& DMUS_PMSGF_MUSICTIME
))
640 if (FAILED(hr
= IDirectMusicPerformance8_ReferenceToMusicTime(iface
,
641 msg
->rtTime
, &msg
->mtTime
)))
643 msg
->dwFlags
|= DMUS_PMSGF_MUSICTIME
;
645 if (!(msg
->dwFlags
& DMUS_PMSGF_REFTIME
))
647 if (FAILED(hr
= IDirectMusicPerformance8_MusicToReferenceTime(iface
,
648 msg
->mtTime
== -1 ? 0 : msg
->mtTime
, &msg
->rtTime
)))
650 msg
->dwFlags
|= DMUS_PMSGF_REFTIME
;
653 if (msg
->dwFlags
& DMUS_PMSGF_TOOL_IMMEDIATE
)
655 hr
= performance_process_message(This
, &message
->msg
, NULL
);
656 if (hr
!= DMUS_S_REQUEUE
) goto done
;
659 performance_queue_message(This
, message
, NULL
);
664 LeaveCriticalSection(&This
->safe
);
665 if (SUCCEEDED(hr
)) WakeConditionVariable(&This
->cond
);
670 static HRESULT WINAPI
performance_MusicToReferenceTime(IDirectMusicPerformance8
*iface
,
671 MUSIC_TIME music_time
, REFERENCE_TIME
*time
)
674 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
676 if (!once
++) FIXME("(%p, %ld, %p): semi-stub\n", This
, music_time
, time
);
677 else TRACE("(%p, %ld, %p)\n", This
, music_time
, time
);
679 if (!time
) return E_POINTER
;
682 if (!This
->master_clock
) return DMUS_E_NO_MASTER_CLOCK
;
684 /* FIXME: This should be (music_time * 60) / (DMUS_PPQ * tempo)
685 * but it gives innacurate results */
686 *time
= This
->init_time
+ (music_time
* 6510);
691 static HRESULT WINAPI
performance_ReferenceToMusicTime(IDirectMusicPerformance8
*iface
,
692 REFERENCE_TIME time
, MUSIC_TIME
*music_time
)
695 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
697 if (!once
++) FIXME("(%p, %I64d, %p): semi-stub\n", This
, time
, music_time
);
698 else TRACE("(%p, %I64d, %p)\n", This
, time
, music_time
);
700 if (!music_time
) return E_POINTER
;
703 if (!This
->master_clock
) return DMUS_E_NO_MASTER_CLOCK
;
705 /* FIXME: This should be (time * DMUS_PPQ * tempo) / 60
706 * but it gives innacurate results */
707 *music_time
= (time
- This
->init_time
) / 6510;
712 static HRESULT WINAPI
performance_IsPlaying(IDirectMusicPerformance8
*iface
,
713 IDirectMusicSegment
*pSegment
, IDirectMusicSegmentState
*pSegState
)
715 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
717 FIXME("(%p, %p, %p): stub\n", This
, pSegment
, pSegState
);
721 static HRESULT WINAPI
performance_GetTime(IDirectMusicPerformance8
*iface
, REFERENCE_TIME
*time
, MUSIC_TIME
*music_time
)
723 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
727 TRACE("(%p, %p, %p)\n", iface
, time
, music_time
);
729 if (!This
->master_clock
) return DMUS_E_NO_MASTER_CLOCK
;
730 if (FAILED(hr
= IReferenceClock_GetTime(This
->master_clock
, &now
))) return hr
;
732 if (time
) *time
= now
;
733 if (music_time
) hr
= IDirectMusicPerformance8_ReferenceToMusicTime(iface
, now
, music_time
);
738 static HRESULT WINAPI
performance_AllocPMsg(IDirectMusicPerformance8
*iface
, ULONG size
, DMUS_PMSG
**msg
)
740 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
741 struct message
*message
;
743 TRACE("(%p, %ld, %p)\n", This
, size
, msg
);
745 if (!msg
) return E_POINTER
;
746 if (size
< sizeof(DMUS_PMSG
)) return E_INVALIDARG
;
748 if (!(message
= calloc(1, size
- sizeof(DMUS_PMSG
) + sizeof(struct message
)))) return E_OUTOFMEMORY
;
749 message
->msg
.dwSize
= size
;
750 list_init(&message
->entry
);
751 *msg
= &message
->msg
;
756 static HRESULT WINAPI
performance_FreePMsg(IDirectMusicPerformance8
*iface
, DMUS_PMSG
*msg
)
758 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
759 struct message
*message
;
762 TRACE("(%p, %p)\n", This
, msg
);
764 if (!(message
= message_from_DMUS_PMSG(msg
))) return E_POINTER
;
766 EnterCriticalSection(&This
->safe
);
767 hr
= !list_empty(&message
->entry
) ? DMUS_E_CANNOT_FREE
: S_OK
;
768 LeaveCriticalSection(&This
->safe
);
772 if (msg
->pTool
) IDirectMusicTool_Release(msg
->pTool
);
773 if (msg
->pGraph
) IDirectMusicGraph_Release(msg
->pGraph
);
774 if (msg
->punkUser
) IUnknown_Release(msg
->punkUser
);
781 static HRESULT WINAPI
performance_GetGraph(IDirectMusicPerformance8
*iface
, IDirectMusicGraph
**graph
)
783 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
785 TRACE("(%p, %p)\n", This
, graph
);
790 *graph
= This
->pToolGraph
;
791 if (This
->pToolGraph
) {
792 IDirectMusicGraph_AddRef(*graph
);
795 return *graph
? S_OK
: DMUS_E_NOT_FOUND
;
798 static HRESULT WINAPI
performance_SetGraph(IDirectMusicPerformance8
*iface
, IDirectMusicGraph
*pGraph
)
800 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
802 FIXME("(%p, %p): to check\n", This
, pGraph
);
804 if (NULL
!= This
->pToolGraph
) {
805 /* Todo clean buffers and tools before */
806 IDirectMusicGraph_Release(This
->pToolGraph
);
808 This
->pToolGraph
= pGraph
;
809 if (NULL
!= This
->pToolGraph
) {
810 IDirectMusicGraph_AddRef(This
->pToolGraph
);
815 static HRESULT WINAPI
performance_SetNotificationHandle(IDirectMusicPerformance8
*iface
,
816 HANDLE notification_event
, REFERENCE_TIME minimum_time
)
818 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
820 TRACE("(%p, %p, %I64d)\n", This
, notification_event
, minimum_time
);
822 This
->notification_event
= notification_event
;
824 This
->notification_timeout
= minimum_time
;
825 else if (!This
->notification_timeout
)
826 This
->notification_timeout
= 20000000; /* 2 seconds */
831 static HRESULT WINAPI
performance_GetNotificationPMsg(IDirectMusicPerformance8
*iface
,
832 DMUS_NOTIFICATION_PMSG
**ret_msg
)
834 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
837 TRACE("(%p, %p)\n", This
, ret_msg
);
839 if (!ret_msg
) return E_POINTER
;
841 EnterCriticalSection(&This
->safe
);
842 if ((entry
= list_head(&This
->notifications
)))
844 struct message
*message
= LIST_ENTRY(entry
, struct message
, entry
);
845 list_remove(&message
->entry
);
846 list_init(&message
->entry
);
847 *ret_msg
= (DMUS_NOTIFICATION_PMSG
*)&message
->msg
;
849 LeaveCriticalSection(&This
->safe
);
851 return entry
? S_OK
: S_FALSE
;
854 static HRESULT WINAPI
performance_AddNotificationType(IDirectMusicPerformance8
*iface
, REFGUID type
)
856 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
859 FIXME("(%p, %s): stub\n", This
, debugstr_dmguid(type
));
861 if (IsEqualGUID(type
, &GUID_NOTIFICATION_PERFORMANCE
))
863 hr
= This
->notification_performance
? S_FALSE
: S_OK
;
864 This
->notification_performance
= TRUE
;
866 if (IsEqualGUID(type
, &GUID_NOTIFICATION_SEGMENT
))
868 hr
= This
->notification_segment
? S_FALSE
: S_OK
;
869 This
->notification_segment
= TRUE
;
875 static HRESULT WINAPI
performance_RemoveNotificationType(IDirectMusicPerformance8
*iface
, REFGUID type
)
877 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
878 HRESULT hr
= S_FALSE
;
880 FIXME("(%p, %s): stub\n", This
, debugstr_dmguid(type
));
882 if (IsEqualGUID(type
, &GUID_NOTIFICATION_PERFORMANCE
))
884 hr
= This
->notification_performance
? S_OK
: S_FALSE
;
885 This
->notification_performance
= FALSE
;
887 if (IsEqualGUID(type
, &GUID_NOTIFICATION_SEGMENT
))
889 hr
= This
->notification_segment
? S_OK
: S_FALSE
;
890 This
->notification_segment
= FALSE
;
896 static void performance_update_latency_time(struct performance
*This
, IDirectMusicPort
*port
,
897 REFERENCE_TIME
*ret_time
)
899 IDirectMusicPerformance8
*iface
= &This
->IDirectMusicPerformance8_iface
;
900 REFERENCE_TIME latency_time
, current_time
;
901 IReferenceClock
*latency_clock
;
904 if (!ret_time
) ret_time
= &latency_time
;
905 if (SUCCEEDED(hr
= IDirectMusicPort_GetLatencyClock(port
, &latency_clock
)))
907 hr
= IReferenceClock_GetTime(latency_clock
, ret_time
);
908 if (SUCCEEDED(hr
)) hr
= IDirectMusicPerformance8_GetTime(iface
, ¤t_time
, NULL
);
909 if (SUCCEEDED(hr
) && This
->latency_offset
< (*ret_time
- current_time
))
911 TRACE("Updating performance %p latency %I64d -> %I64d\n", This
,
912 This
->latency_offset
, *ret_time
- current_time
);
913 This
->latency_offset
= *ret_time
- current_time
;
915 IReferenceClock_Release(latency_clock
);
918 if (FAILED(hr
)) ERR("Failed to update performance %p latency, hr %#lx\n", This
, hr
);
921 static HRESULT
perf_dmport_create(struct performance
*perf
, DMUS_PORTPARAMS
*params
)
923 IDirectMusicPort
*port
;
928 if (FAILED(hr
= IDirectMusic8_GetDefaultPort(perf
->dmusic
, &guid
)))
931 if (FAILED(hr
= IDirectMusic8_CreatePort(perf
->dmusic
, &guid
, params
, &port
, NULL
)))
934 if (FAILED(hr
= IDirectMusicPort_SetDirectSound(port
, perf
->dsound
, NULL
))
935 || FAILED(hr
= IDirectMusicPort_Activate(port
, TRUE
)))
937 IDirectMusicPort_Release(port
);
941 for (i
= 0; i
< params
->dwChannelGroups
; i
++)
942 pchannel_block_set(&perf
->pchannels
, i
, port
, i
+ 1, FALSE
);
944 performance_update_latency_time(perf
, port
, NULL
);
948 static HRESULT WINAPI
performance_AddPort(IDirectMusicPerformance8
*iface
, IDirectMusicPort
*port
)
950 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
952 FIXME("(%p, %p): semi-stub\n", This
, port
);
954 if (!This
->dmusic
) return DMUS_E_NOT_INIT
;
955 if (This
->audio_paths_enabled
) return DMUS_E_AUDIOPATHS_IN_USE
;
958 DMUS_PORTPARAMS params
= {
959 .dwSize
= sizeof(params
),
960 .dwValidParams
= DMUS_PORTPARAMS_CHANNELGROUPS
,
964 return perf_dmport_create(This
, ¶ms
);
967 IDirectMusicPort_AddRef(port
);
969 * We should remember added Ports (for example using a list)
970 * and control if Port is registered for each api who use ports
973 performance_update_latency_time(This
, port
, NULL
);
977 static HRESULT WINAPI
performance_RemovePort(IDirectMusicPerformance8
*iface
, IDirectMusicPort
*pPort
)
979 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
981 if (This
->audio_paths_enabled
) return DMUS_E_AUDIOPATHS_IN_USE
;
983 FIXME("(%p, %p): stub\n", This
, pPort
);
984 IDirectMusicPort_Release(pPort
);
988 static HRESULT WINAPI
performance_AssignPChannelBlock(IDirectMusicPerformance8
*iface
,
989 DWORD block_num
, IDirectMusicPort
*port
, DWORD group
)
991 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
993 FIXME("(%p, %ld, %p, %ld): semi-stub\n", This
, block_num
, port
, group
);
995 if (!port
) return E_POINTER
;
996 if (block_num
> MAXDWORD
/ 16) return E_INVALIDARG
;
997 if (This
->audio_paths_enabled
) return DMUS_E_AUDIOPATHS_IN_USE
;
999 pchannel_block_set(&This
->pchannels
, block_num
, port
, group
, FALSE
);
1004 static HRESULT WINAPI
performance_AssignPChannel(IDirectMusicPerformance8
*iface
, DWORD pchannel
,
1005 IDirectMusicPort
*port
, DWORD group
, DWORD channel
)
1007 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1008 struct pchannel_block
*block
;
1010 FIXME("(%p)->(%ld, %p, %ld, %ld) semi-stub\n", This
, pchannel
, port
, group
, channel
);
1012 if (!port
) return E_POINTER
;
1013 if (This
->audio_paths_enabled
) return DMUS_E_AUDIOPATHS_IN_USE
;
1015 block
= pchannel_block_set(&This
->pchannels
, pchannel
/ 16, port
, 0, TRUE
);
1017 block
->pchannel
[pchannel
% 16].group
= group
;
1018 block
->pchannel
[pchannel
% 16].channel
= channel
;
1024 static HRESULT WINAPI
performance_PChannelInfo(IDirectMusicPerformance8
*iface
, DWORD pchannel
,
1025 IDirectMusicPort
**port
, DWORD
*group
, DWORD
*channel
)
1027 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1028 struct pchannel_block
*block
;
1029 struct wine_rb_entry
*entry
;
1030 DWORD block_num
= pchannel
/ 16;
1031 unsigned int index
= pchannel
% 16;
1033 TRACE("(%p)->(%ld, %p, %p, %p)\n", This
, pchannel
, port
, group
, channel
);
1035 entry
= wine_rb_get(&This
->pchannels
, &block_num
);
1037 return E_INVALIDARG
;
1038 block
= WINE_RB_ENTRY_VALUE(entry
, struct pchannel_block
, entry
);
1041 *port
= block
->pchannel
[index
].port
;
1042 IDirectMusicPort_AddRef(*port
);
1045 *group
= block
->pchannel
[index
].group
;
1047 *channel
= block
->pchannel
[index
].channel
;
1052 static HRESULT WINAPI
performance_DownloadInstrument(IDirectMusicPerformance8
*iface
,
1053 IDirectMusicInstrument
*instrument
, DWORD port_channel
,
1054 IDirectMusicDownloadedInstrument
**downloaded
, DMUS_NOTERANGE
*note_ranges
,
1055 DWORD note_range_count
, IDirectMusicPort
**port
, DWORD
*group
, DWORD
*music_channel
)
1057 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1058 IDirectMusicPort
*tmp_port
= NULL
;
1061 TRACE("(%p, %p, %ld, %p, %p, %ld, %p, %p, %p)\n", This
, instrument
, port_channel
, downloaded
,
1062 note_ranges
, note_range_count
, port
, group
, music_channel
);
1064 if (!port
) port
= &tmp_port
;
1065 if (FAILED(hr
= IDirectMusicPerformance_PChannelInfo(iface
, port_channel
, port
, group
, music_channel
)))
1068 hr
= IDirectMusicPort_DownloadInstrument(*port
, instrument
, downloaded
, note_ranges
, note_range_count
);
1069 if (tmp_port
) IDirectMusicPort_Release(tmp_port
);
1073 static HRESULT WINAPI
performance_Invalidate(IDirectMusicPerformance8
*iface
, MUSIC_TIME mtTime
, DWORD dwFlags
)
1075 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1077 FIXME("(%p, %ld, %ld): stub\n", This
, mtTime
, dwFlags
);
1081 static HRESULT WINAPI
performance_GetParam(IDirectMusicPerformance8
*iface
, REFGUID rguidType
,
1082 DWORD dwGroupBits
, DWORD dwIndex
, MUSIC_TIME mtTime
, MUSIC_TIME
*pmtNext
, void *pParam
)
1084 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1086 FIXME("(%p, %s, %ld, %ld, %ld, %p, %p): stub\n", This
, debugstr_dmguid(rguidType
), dwGroupBits
, dwIndex
, mtTime
, pmtNext
, pParam
);
1090 static HRESULT WINAPI
performance_SetParam(IDirectMusicPerformance8
*iface
, REFGUID rguidType
,
1091 DWORD dwGroupBits
, DWORD dwIndex
, MUSIC_TIME mtTime
, void *pParam
)
1093 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1095 FIXME("(%p, %s, %ld, %ld, %ld, %p): stub\n", This
, debugstr_dmguid(rguidType
), dwGroupBits
, dwIndex
, mtTime
, pParam
);
1099 static HRESULT WINAPI
performance_GetGlobalParam(IDirectMusicPerformance8
*iface
, REFGUID rguidType
,
1100 void *pParam
, DWORD dwSize
)
1102 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1104 TRACE("(%p, %s, %p, %ld): stub\n", This
, debugstr_dmguid(rguidType
), pParam
, dwSize
);
1106 if (IsEqualGUID (rguidType
, &GUID_PerfAutoDownload
))
1107 memcpy(pParam
, &This
->fAutoDownload
, sizeof(This
->fAutoDownload
));
1108 if (IsEqualGUID (rguidType
, &GUID_PerfMasterGrooveLevel
))
1109 memcpy(pParam
, &This
->cMasterGrooveLevel
, sizeof(This
->cMasterGrooveLevel
));
1110 if (IsEqualGUID (rguidType
, &GUID_PerfMasterTempo
))
1111 memcpy(pParam
, &This
->fMasterTempo
, sizeof(This
->fMasterTempo
));
1112 if (IsEqualGUID (rguidType
, &GUID_PerfMasterVolume
))
1113 memcpy(pParam
, &This
->lMasterVolume
, sizeof(This
->lMasterVolume
));
1118 static HRESULT WINAPI
performance_SetGlobalParam(IDirectMusicPerformance8
*iface
, REFGUID rguidType
,
1119 void *pParam
, DWORD dwSize
)
1121 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1123 TRACE("(%p, %s, %p, %ld)\n", This
, debugstr_dmguid(rguidType
), pParam
, dwSize
);
1125 if (IsEqualGUID (rguidType
, &GUID_PerfAutoDownload
)) {
1126 memcpy(&This
->fAutoDownload
, pParam
, dwSize
);
1127 TRACE("=> AutoDownload set to %d\n", This
->fAutoDownload
);
1129 if (IsEqualGUID (rguidType
, &GUID_PerfMasterGrooveLevel
)) {
1130 memcpy(&This
->cMasterGrooveLevel
, pParam
, dwSize
);
1131 TRACE("=> MasterGrooveLevel set to %i\n", This
->cMasterGrooveLevel
);
1133 if (IsEqualGUID (rguidType
, &GUID_PerfMasterTempo
)) {
1134 memcpy(&This
->fMasterTempo
, pParam
, dwSize
);
1135 TRACE("=> MasterTempo set to %f\n", This
->fMasterTempo
);
1137 if (IsEqualGUID (rguidType
, &GUID_PerfMasterVolume
)) {
1138 memcpy(&This
->lMasterVolume
, pParam
, dwSize
);
1139 TRACE("=> MasterVolume set to %li\n", This
->lMasterVolume
);
1145 static HRESULT WINAPI
performance_GetLatencyTime(IDirectMusicPerformance8
*iface
, REFERENCE_TIME
*ret_time
)
1147 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1148 REFERENCE_TIME current_time
;
1151 TRACE("(%p, %p)\n", This
, ret_time
);
1153 if (SUCCEEDED(hr
= IDirectMusicPerformance8_GetTime(iface
, ¤t_time
, NULL
)))
1154 *ret_time
= current_time
+ This
->latency_offset
;
1159 static HRESULT WINAPI
performance_GetQueueTime(IDirectMusicPerformance8
*iface
, REFERENCE_TIME
*prtTime
)
1162 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1164 FIXME("(%p, %p): stub\n", This
, prtTime
);
1168 static HRESULT WINAPI
performance_AdjustTime(IDirectMusicPerformance8
*iface
, REFERENCE_TIME rtAmount
)
1170 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1172 FIXME("(%p, 0x%s): stub\n", This
, wine_dbgstr_longlong(rtAmount
));
1176 static HRESULT WINAPI
performance_CloseDown(IDirectMusicPerformance8
*iface
)
1178 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1179 struct message
*message
, *next
;
1180 HANDLE message_thread
;
1183 FIXME("(%p): semi-stub\n", This
);
1185 if ((message_thread
= This
->message_thread
))
1187 EnterCriticalSection(&This
->safe
);
1188 This
->message_thread
= NULL
;
1189 LeaveCriticalSection(&This
->safe
);
1190 WakeConditionVariable(&This
->cond
);
1192 WaitForSingleObject(message_thread
, INFINITE
);
1193 CloseHandle(message_thread
);
1196 This
->notification_performance
= FALSE
;
1197 This
->notification_segment
= FALSE
;
1199 LIST_FOR_EACH_ENTRY_SAFE(message
, next
, &This
->messages
, struct message
, entry
)
1201 list_remove(&message
->entry
);
1202 list_init(&message
->entry
);
1204 if (message
->msg
.dwType
== DMUS_PMSGT_INTERNAL_SEGMENT_END
)
1205 hr
= IDirectMusicTool_ProcessPMsg(&This
->IDirectMusicTool_iface
,
1206 (IDirectMusicPerformance
*)iface
, &message
->msg
);
1210 if (hr
== DMUS_S_FREE
&& FAILED(hr
= IDirectMusicPerformance8_FreePMsg(iface
, &message
->msg
)))
1211 WARN("Failed to free message %p, hr %#lx\n", message
, hr
);
1214 LIST_FOR_EACH_ENTRY_SAFE(message
, next
, &This
->notifications
, struct message
, entry
)
1216 list_remove(&message
->entry
);
1217 list_init(&message
->entry
);
1219 if (FAILED(hr
= IDirectMusicPerformance8_FreePMsg(iface
, &message
->msg
)))
1220 WARN("Failed to free message %p, hr %#lx\n", message
, hr
);
1223 performance_set_primary_segment(This
, NULL
);
1225 if (This
->master_clock
)
1227 IReferenceClock_Release(This
->master_clock
);
1228 This
->master_clock
= NULL
;
1231 IDirectSound_Release(This
->dsound
);
1232 This
->dsound
= NULL
;
1235 IDirectMusic8_SetDirectSound(This
->dmusic
, NULL
, NULL
);
1236 IDirectMusic8_Release(This
->dmusic
);
1237 This
->dmusic
= NULL
;
1239 This
->audio_paths_enabled
= FALSE
;
1244 static HRESULT WINAPI
performance_GetResolvedTime(IDirectMusicPerformance8
*iface
,
1245 REFERENCE_TIME rtTime
, REFERENCE_TIME
*prtResolved
, DWORD dwTimeResolveFlags
)
1247 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1249 FIXME("(%p, 0x%s, %p, %ld): stub\n", This
, wine_dbgstr_longlong(rtTime
),
1250 prtResolved
, dwTimeResolveFlags
);
1254 static HRESULT WINAPI
performance_MIDIToMusic(IDirectMusicPerformance8
*iface
, BYTE bMIDIValue
,
1255 DMUS_CHORD_KEY
*pChord
, BYTE bPlayMode
, BYTE bChordLevel
, WORD
*pwMusicValue
)
1257 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1259 FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This
, bMIDIValue
, pChord
, bPlayMode
, bChordLevel
, pwMusicValue
);
1263 static HRESULT WINAPI
performance_MusicToMIDI(IDirectMusicPerformance8
*iface
, WORD wMusicValue
,
1264 DMUS_CHORD_KEY
*pChord
, BYTE bPlayMode
, BYTE bChordLevel
, BYTE
*pbMIDIValue
)
1266 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1268 FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This
, wMusicValue
, pChord
, bPlayMode
, bChordLevel
, pbMIDIValue
);
1272 static HRESULT WINAPI
performance_TimeToRhythm(IDirectMusicPerformance8
*iface
, MUSIC_TIME mtTime
,
1273 DMUS_TIMESIGNATURE
*pTimeSig
, WORD
*pwMeasure
, BYTE
*pbBeat
, BYTE
*pbGrid
, short *pnOffset
)
1275 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1277 FIXME("(%p, %ld, %p, %p, %p, %p, %p): stub\n", This
, mtTime
, pTimeSig
, pwMeasure
, pbBeat
, pbGrid
, pnOffset
);
1281 static HRESULT WINAPI
performance_RhythmToTime(IDirectMusicPerformance8
*iface
, WORD wMeasure
,
1282 BYTE bBeat
, BYTE bGrid
, short nOffset
, DMUS_TIMESIGNATURE
*pTimeSig
, MUSIC_TIME
*pmtTime
)
1284 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1286 FIXME("(%p, %d, %d, %d, %i, %p, %p): stub\n", This
, wMeasure
, bBeat
, bGrid
, nOffset
, pTimeSig
, pmtTime
);
1290 /* IDirectMusicPerformance8 Interface part follow: */
1291 static HRESULT WINAPI
performance_InitAudio(IDirectMusicPerformance8
*iface
, IDirectMusic
**dmusic
,
1292 IDirectSound
**dsound
, HWND hwnd
, DWORD default_path_type
, DWORD num_channels
, DWORD flags
,
1293 DMUS_AUDIOPARAMS
*params
)
1295 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1298 TRACE("(%p, %p, %p, %p, %lx, %lu, %lx, %p)\n", This
, dmusic
, dsound
, hwnd
, default_path_type
,
1299 num_channels
, flags
, params
);
1301 if (flags
) FIXME("flags parameter not used\n");
1302 if (params
) FIXME("params parameter not used\n");
1304 if (FAILED(hr
= IDirectMusicPerformance8_Init(iface
, dmusic
&& *dmusic
? dmusic
: NULL
,
1305 dsound
? *dsound
: NULL
, hwnd
)))
1308 This
->audio_paths_enabled
= TRUE
;
1309 if (default_path_type
)
1311 hr
= IDirectMusicPerformance8_CreateStandardAudioPath(iface
, default_path_type
,
1312 num_channels
, FALSE
, &This
->pDefaultPath
);
1315 IDirectMusicPerformance_CloseDown(iface
);
1320 if (dsound
&& !*dsound
) {
1321 *dsound
= This
->dsound
;
1322 IDirectSound_AddRef(*dsound
);
1324 if (dmusic
&& !*dmusic
) {
1325 *dmusic
= (IDirectMusic
*)This
->dmusic
;
1326 IDirectMusic_AddRef(*dmusic
);
1332 static HRESULT WINAPI
performance_PlaySegmentEx(IDirectMusicPerformance8
*iface
, IUnknown
*source
,
1333 WCHAR
*segment_name
, IUnknown
*transition
, DWORD segment_flags
, INT64 start_time
,
1334 IDirectMusicSegmentState
**segment_state
, IUnknown
*from
, IUnknown
*audio_path
)
1336 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1337 IDirectMusicSegmentState
*state
;
1338 IDirectMusicSegment
*segment
;
1339 MUSIC_TIME music_time
;
1342 FIXME("(%p, %p, %s, %p, %#lx, %I64d, %p, %p, %p): stub\n", This
, source
, debugstr_w(segment_name
),
1343 transition
, segment_flags
, start_time
, segment_state
, from
, audio_path
);
1345 /* NOTE: The time is in music time unless the DMUS_SEGF_REFTIME flag is set. */
1346 if (segment_flags
) FIXME("flags %#lx not implemented\n", segment_flags
);
1347 if (start_time
) FIXME("start_time %I64d not implemented\n", start_time
);
1349 if (FAILED(hr
= IUnknown_QueryInterface(source
, &IID_IDirectMusicSegment
, (void **)&segment
)))
1352 EnterCriticalSection(&This
->safe
);
1354 performance_set_primary_segment(This
, segment
);
1356 if ((!(music_time
= start_time
) && FAILED(hr
= IDirectMusicPerformance8_GetTime(iface
, NULL
, &music_time
)))
1357 || FAILED(hr
= segment_state_create(segment
, music_time
, iface
, &state
)))
1359 performance_set_primary_segment(This
, NULL
);
1360 LeaveCriticalSection(&This
->safe
);
1362 IDirectMusicSegment_Release(segment
);
1366 if (FAILED(hr
= segment_state_play(state
, iface
)))
1368 ERR("Failed to play segment state, hr %#lx\n", hr
);
1369 performance_set_primary_segment(This
, NULL
);
1371 else if (segment_state
)
1373 *segment_state
= state
;
1374 IDirectMusicSegmentState_AddRef(state
);
1377 LeaveCriticalSection(&This
->safe
);
1379 IDirectMusicSegmentState_Release(state
);
1380 IDirectMusicSegment_Release(segment
);
1384 static HRESULT WINAPI
performance_StopEx(IDirectMusicPerformance8
*iface
, IUnknown
*pObjectToStop
,
1385 __int64 i64StopTime
, DWORD dwFlags
)
1387 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1389 FIXME("(%p, %p, 0x%s, %ld): stub\n", This
, pObjectToStop
,
1390 wine_dbgstr_longlong(i64StopTime
), dwFlags
);
1394 static HRESULT WINAPI
performance_ClonePMsg(IDirectMusicPerformance8
*iface
, DMUS_PMSG
*msg
, DMUS_PMSG
**clone
)
1396 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1399 TRACE("(%p, %p, %p)\n", This
, msg
, clone
);
1401 if (!msg
|| !clone
) return E_POINTER
;
1402 if (FAILED(hr
= IDirectMusicPerformance8_AllocPMsg(iface
, msg
->dwSize
, clone
))) return hr
;
1404 memcpy(*clone
, msg
, msg
->dwSize
);
1405 if (msg
->pTool
) IDirectMusicTool_AddRef(msg
->pTool
);
1406 if (msg
->pGraph
) IDirectMusicGraph_AddRef(msg
->pGraph
);
1407 if (msg
->punkUser
) IUnknown_AddRef(msg
->punkUser
);
1412 static HRESULT WINAPI
performance_CreateAudioPath(IDirectMusicPerformance8
*iface
,
1413 IUnknown
*pSourceConfig
, BOOL fActivate
, IDirectMusicAudioPath
**ret_iface
)
1415 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1416 IDirectMusicAudioPath
*pPath
;
1418 FIXME("(%p, %p, %d, %p): stub\n", This
, pSourceConfig
, fActivate
, ret_iface
);
1420 if (!ret_iface
) return E_POINTER
;
1421 if (!This
->audio_paths_enabled
) return DMUS_E_AUDIOPATH_INACTIVE
;
1423 create_dmaudiopath(&IID_IDirectMusicAudioPath
, (void **)&pPath
);
1424 set_audiopath_perf_pointer(pPath
, iface
);
1428 return IDirectMusicAudioPath_Activate(*ret_iface
, fActivate
);
1431 static HRESULT WINAPI
performance_CreateStandardAudioPath(IDirectMusicPerformance8
*iface
,
1432 DWORD dwType
, DWORD pchannel_count
, BOOL fActivate
, IDirectMusicAudioPath
**ret_iface
)
1434 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1435 IDirectMusicAudioPath
*pPath
;
1437 WAVEFORMATEX format
;
1438 DMUS_PORTPARAMS params
= {0};
1439 IDirectSoundBuffer
*buffer
, *primary_buffer
;
1442 FIXME("(%p)->(%ld, %ld, %d, %p): semi-stub\n", This
, dwType
, pchannel_count
, fActivate
, ret_iface
);
1444 if (!ret_iface
) return E_POINTER
;
1445 if (!This
->audio_paths_enabled
) return DMUS_E_AUDIOPATH_INACTIVE
;
1449 /* Secondary buffer description */
1450 memset(&format
, 0, sizeof(format
));
1451 format
.wFormatTag
= WAVE_FORMAT_PCM
;
1452 format
.nChannels
= 1;
1453 format
.nSamplesPerSec
= 44000;
1454 format
.nAvgBytesPerSec
= 44000*2;
1455 format
.nBlockAlign
= 2;
1456 format
.wBitsPerSample
= 16;
1459 memset(&desc
, 0, sizeof(desc
));
1460 desc
.dwSize
= sizeof(desc
);
1461 desc
.dwFlags
= DSBCAPS_CTRLFX
| DSBCAPS_CTRLVOLUME
| DSBCAPS_GLOBALFOCUS
;
1462 desc
.dwBufferBytes
= DSBSIZE_MIN
;
1463 desc
.dwReserved
= 0;
1464 desc
.lpwfxFormat
= &format
;
1465 desc
.guid3DAlgorithm
= GUID_NULL
;
1468 case DMUS_APATH_DYNAMIC_3D
:
1469 desc
.dwFlags
|= DSBCAPS_CTRL3D
| DSBCAPS_CTRLFREQUENCY
| DSBCAPS_MUTE3DATMAXDISTANCE
;
1471 case DMUS_APATH_DYNAMIC_MONO
:
1472 desc
.dwFlags
|= DSBCAPS_CTRLPAN
| DSBCAPS_CTRLFREQUENCY
;
1474 case DMUS_APATH_SHARED_STEREOPLUSREVERB
:
1475 /* normally we have to create 2 buffers (one for music other for reverb)
1476 * in this case. See msdn
1478 case DMUS_APATH_DYNAMIC_STEREO
:
1479 desc
.dwFlags
|= DSBCAPS_CTRLPAN
| DSBCAPS_CTRLFREQUENCY
;
1480 format
.nChannels
= 2;
1481 format
.nBlockAlign
*= 2;
1482 format
.nAvgBytesPerSec
*=2;
1485 return E_INVALIDARG
;
1489 params
.dwSize
= sizeof(params
);
1490 params
.dwValidParams
= DMUS_PORTPARAMS_CHANNELGROUPS
| DMUS_PORTPARAMS_AUDIOCHANNELS
;
1491 params
.dwChannelGroups
= (pchannel_count
+ 15) / 16;
1492 params
.dwAudioChannels
= format
.nChannels
;
1493 if (FAILED(hr
= perf_dmport_create(This
, ¶ms
)))
1496 hr
= IDirectSound_CreateSoundBuffer(This
->dsound
, &desc
, &buffer
, NULL
);
1498 return DSERR_BUFFERLOST
;
1500 /* Update description for creating primary buffer */
1501 desc
.dwFlags
|= DSBCAPS_PRIMARYBUFFER
;
1502 desc
.dwFlags
&= ~DSBCAPS_CTRLFX
;
1503 desc
.dwBufferBytes
= 0;
1504 desc
.lpwfxFormat
= NULL
;
1506 hr
= IDirectSound_CreateSoundBuffer(This
->dsound
, &desc
, &primary_buffer
, NULL
);
1508 IDirectSoundBuffer_Release(buffer
);
1509 return DSERR_BUFFERLOST
;
1512 create_dmaudiopath(&IID_IDirectMusicAudioPath
, (void**)&pPath
);
1513 set_audiopath_perf_pointer(pPath
, iface
);
1514 set_audiopath_dsound_buffer(pPath
, buffer
);
1515 set_audiopath_primary_dsound_buffer(pPath
, primary_buffer
);
1518 TRACE(" returning IDirectMusicAudioPath interface at %p.\n", *ret_iface
);
1519 return IDirectMusicAudioPath_Activate(*ret_iface
, fActivate
);
1522 static HRESULT WINAPI
performance_SetDefaultAudioPath(IDirectMusicPerformance8
*iface
, IDirectMusicAudioPath
*audio_path
)
1524 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1526 FIXME("(%p, %p): semi-stub\n", This
, audio_path
);
1528 if (!This
->audio_paths_enabled
) return DMUS_E_AUDIOPATH_INACTIVE
;
1530 if (This
->pDefaultPath
) IDirectMusicAudioPath_Release(This
->pDefaultPath
);
1531 if ((This
->pDefaultPath
= audio_path
))
1533 IDirectMusicAudioPath_AddRef(This
->pDefaultPath
);
1534 set_audiopath_perf_pointer(This
->pDefaultPath
, iface
);
1540 static HRESULT WINAPI
performance_GetDefaultAudioPath(IDirectMusicPerformance8
*iface
,
1541 IDirectMusicAudioPath
**ret_iface
)
1543 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1545 FIXME("(%p, %p): semi-stub (%p)\n", This
, ret_iface
, This
->pDefaultPath
);
1547 if (!ret_iface
) return E_POINTER
;
1548 if (!This
->audio_paths_enabled
) return DMUS_E_AUDIOPATH_INACTIVE
;
1550 if ((*ret_iface
= This
->pDefaultPath
)) IDirectMusicAudioPath_AddRef(*ret_iface
);
1555 static HRESULT WINAPI
performance_GetParamEx(IDirectMusicPerformance8
*iface
, REFGUID rguidType
, DWORD dwTrackID
,
1556 DWORD dwGroupBits
, DWORD dwIndex
, MUSIC_TIME mtTime
, MUSIC_TIME
*pmtNext
, void *pParam
)
1558 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1560 FIXME("(%p, %s, %ld, %ld, %ld, %ld, %p, %p): stub\n", This
, debugstr_dmguid(rguidType
), dwTrackID
, dwGroupBits
, dwIndex
, mtTime
, pmtNext
, pParam
);
1565 static const IDirectMusicPerformance8Vtbl performance_vtbl
=
1567 performance_QueryInterface
,
1569 performance_Release
,
1571 performance_PlaySegment
,
1573 performance_GetSegmentState
,
1574 performance_SetPrepareTime
,
1575 performance_GetPrepareTime
,
1576 performance_SetBumperLength
,
1577 performance_GetBumperLength
,
1578 performance_SendPMsg
,
1579 performance_MusicToReferenceTime
,
1580 performance_ReferenceToMusicTime
,
1581 performance_IsPlaying
,
1582 performance_GetTime
,
1583 performance_AllocPMsg
,
1584 performance_FreePMsg
,
1585 performance_GetGraph
,
1586 performance_SetGraph
,
1587 performance_SetNotificationHandle
,
1588 performance_GetNotificationPMsg
,
1589 performance_AddNotificationType
,
1590 performance_RemoveNotificationType
,
1591 performance_AddPort
,
1592 performance_RemovePort
,
1593 performance_AssignPChannelBlock
,
1594 performance_AssignPChannel
,
1595 performance_PChannelInfo
,
1596 performance_DownloadInstrument
,
1597 performance_Invalidate
,
1598 performance_GetParam
,
1599 performance_SetParam
,
1600 performance_GetGlobalParam
,
1601 performance_SetGlobalParam
,
1602 performance_GetLatencyTime
,
1603 performance_GetQueueTime
,
1604 performance_AdjustTime
,
1605 performance_CloseDown
,
1606 performance_GetResolvedTime
,
1607 performance_MIDIToMusic
,
1608 performance_MusicToMIDI
,
1609 performance_TimeToRhythm
,
1610 performance_RhythmToTime
,
1611 performance_InitAudio
,
1612 performance_PlaySegmentEx
,
1614 performance_ClonePMsg
,
1615 performance_CreateAudioPath
,
1616 performance_CreateStandardAudioPath
,
1617 performance_SetDefaultAudioPath
,
1618 performance_GetDefaultAudioPath
,
1619 performance_GetParamEx
,
1622 static inline struct performance
*impl_from_IDirectMusicGraph(IDirectMusicGraph
*iface
)
1624 return CONTAINING_RECORD(iface
, struct performance
, IDirectMusicGraph_iface
);
1627 static HRESULT WINAPI
performance_graph_QueryInterface(IDirectMusicGraph
*iface
, REFIID riid
, void **ret_iface
)
1629 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1630 return IDirectMusicPerformance8_QueryInterface(&This
->IDirectMusicPerformance8_iface
, riid
, ret_iface
);
1633 static ULONG WINAPI
performance_graph_AddRef(IDirectMusicGraph
*iface
)
1635 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1636 return IDirectMusicPerformance8_AddRef(&This
->IDirectMusicPerformance8_iface
);
1639 static ULONG WINAPI
performance_graph_Release(IDirectMusicGraph
*iface
)
1641 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1642 return IDirectMusicPerformance8_Release(&This
->IDirectMusicPerformance8_iface
);
1645 static HRESULT WINAPI
performance_graph_StampPMsg(IDirectMusicGraph
*iface
, DMUS_PMSG
*msg
)
1647 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1650 TRACE("(%p, %p)\n", This
, msg
);
1652 if (!msg
) return E_POINTER
;
1654 /* FIXME: Implement segment and audio path graphs support */
1655 if (!This
->pToolGraph
) hr
= DMUS_S_LAST_TOOL
;
1656 else if (FAILED(hr
= IDirectMusicGraph_StampPMsg(This
->pToolGraph
, msg
))) return hr
;
1660 IDirectMusicTool_Release(msg
->pGraph
);
1664 if (hr
== DMUS_S_LAST_TOOL
)
1666 const DWORD delivery_flags
= DMUS_PMSGF_TOOL_IMMEDIATE
| DMUS_PMSGF_TOOL_QUEUE
| DMUS_PMSGF_TOOL_ATTIME
;
1667 msg
->dwFlags
&= ~delivery_flags
;
1668 msg
->dwFlags
|= DMUS_PMSGF_TOOL_QUEUE
;
1670 if (msg
->pTool
) IDirectMusicTool_Release(msg
->pTool
);
1671 msg
->pTool
= &This
->IDirectMusicTool_iface
;
1672 IDirectMusicTool_AddRef(msg
->pTool
);
1678 msg
->pGraph
= &This
->IDirectMusicGraph_iface
;
1679 IDirectMusicTool_AddRef(msg
->pGraph
);
1685 static HRESULT WINAPI
performance_graph_InsertTool(IDirectMusicGraph
*iface
, IDirectMusicTool
*tool
,
1686 DWORD
*channels
, DWORD channels_count
, LONG index
)
1688 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1689 TRACE("(%p, %p, %p, %lu, %ld)\n", This
, tool
, channels
, channels_count
, index
);
1693 static HRESULT WINAPI
performance_graph_GetTool(IDirectMusicGraph
*iface
, DWORD index
, IDirectMusicTool
**tool
)
1695 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1696 TRACE("(%p, %lu, %p)\n", This
, index
, tool
);
1700 static HRESULT WINAPI
performance_graph_RemoveTool(IDirectMusicGraph
*iface
, IDirectMusicTool
*tool
)
1702 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1703 TRACE("(%p, %p)\n", This
, tool
);
1707 static const IDirectMusicGraphVtbl performance_graph_vtbl
=
1709 performance_graph_QueryInterface
,
1710 performance_graph_AddRef
,
1711 performance_graph_Release
,
1712 performance_graph_StampPMsg
,
1713 performance_graph_InsertTool
,
1714 performance_graph_GetTool
,
1715 performance_graph_RemoveTool
,
1718 static inline struct performance
*impl_from_IDirectMusicTool(IDirectMusicTool
*iface
)
1720 return CONTAINING_RECORD(iface
, struct performance
, IDirectMusicTool_iface
);
1723 static HRESULT WINAPI
performance_tool_QueryInterface(IDirectMusicTool
*iface
, REFIID riid
, void **ret_iface
)
1725 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1726 return IDirectMusicPerformance8_QueryInterface(&This
->IDirectMusicPerformance8_iface
, riid
, ret_iface
);
1729 static ULONG WINAPI
performance_tool_AddRef(IDirectMusicTool
*iface
)
1731 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1732 return IDirectMusicPerformance8_AddRef(&This
->IDirectMusicPerformance8_iface
);
1735 static ULONG WINAPI
performance_tool_Release(IDirectMusicTool
*iface
)
1737 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1738 return IDirectMusicPerformance8_Release(&This
->IDirectMusicPerformance8_iface
);
1741 static HRESULT WINAPI
performance_tool_Init(IDirectMusicTool
*iface
, IDirectMusicGraph
*graph
)
1743 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1744 TRACE("(%p, %p)\n", This
, graph
);
1748 static HRESULT WINAPI
performance_tool_GetMsgDeliveryType(IDirectMusicTool
*iface
, DWORD
*type
)
1750 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1751 TRACE("(%p, %p)\n", This
, type
);
1752 *type
= DMUS_PMSGF_TOOL_IMMEDIATE
;
1756 static HRESULT WINAPI
performance_tool_GetMediaTypeArraySize(IDirectMusicTool
*iface
, DWORD
*size
)
1758 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1759 TRACE("(%p, %p)\n", This
, size
);
1764 static HRESULT WINAPI
performance_tool_GetMediaTypes(IDirectMusicTool
*iface
, DWORD
**types
, DWORD size
)
1766 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1767 TRACE("(%p, %p, %lu)\n", This
, types
, size
);
1771 static HRESULT
performance_send_midi_pmsg(struct performance
*This
, DMUS_PMSG
*msg
, UINT flags
,
1772 BYTE status
, BYTE byte1
, BYTE byte2
)
1774 IDirectMusicPerformance8
*performance
= &This
->IDirectMusicPerformance8_iface
;
1775 DMUS_MIDI_PMSG
*midi
;
1778 if (FAILED(hr
= IDirectMusicPerformance8_AllocPMsg(performance
, sizeof(*midi
),
1779 (DMUS_PMSG
**)&midi
)))
1782 if (flags
& DMUS_PMSGF_REFTIME
) midi
->rtTime
= msg
->rtTime
;
1783 if (flags
& DMUS_PMSGF_MUSICTIME
) midi
->mtTime
= msg
->mtTime
;
1784 midi
->dwFlags
= flags
;
1785 midi
->dwPChannel
= msg
->dwPChannel
;
1786 midi
->dwVirtualTrackID
= msg
->dwVirtualTrackID
;
1787 midi
->dwVoiceID
= msg
->dwVoiceID
;
1788 midi
->dwGroupID
= msg
->dwGroupID
;
1789 midi
->dwType
= DMUS_PMSGT_MIDI
;
1790 midi
->bStatus
= status
;
1791 midi
->bByte1
= byte1
;
1792 midi
->bByte2
= byte2
;
1794 if (FAILED(hr
= IDirectMusicPerformance8_SendPMsg(performance
, (DMUS_PMSG
*)midi
)))
1795 IDirectMusicPerformance8_FreePMsg(performance
, (DMUS_PMSG
*)midi
);
1800 static HRESULT WINAPI
performance_tool_ProcessPMsg(IDirectMusicTool
*iface
,
1801 IDirectMusicPerformance
*performance
, DMUS_PMSG
*msg
)
1803 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1804 struct message
*message
= message_from_DMUS_PMSG(msg
);
1807 TRACE("(%p, %p, %p)\n", This
, performance
, msg
);
1809 switch (msg
->dwType
)
1811 case DMUS_PMSGT_MIDI
:
1813 static const UINT event_size
= sizeof(DMUS_EVENTHEADER
) + sizeof(DWORD
);
1814 DMUS_BUFFERDESC desc
= {.dwSize
= sizeof(desc
), .cbBuffer
= 2 * event_size
};
1815 DMUS_MIDI_PMSG
*midi
= (DMUS_MIDI_PMSG
*)msg
;
1816 REFERENCE_TIME latency_time
;
1817 IDirectMusicBuffer
*buffer
;
1818 IDirectMusicPort
*port
;
1819 DWORD group
, channel
;
1822 if (FAILED(hr
= IDirectMusicPerformance_PChannelInfo(performance
, msg
->dwPChannel
,
1823 &port
, &group
, &channel
)))
1825 WARN("Failed to get message port, hr %#lx\n", hr
);
1828 performance_update_latency_time(This
, port
, &latency_time
);
1831 value
|= (UINT
)midi
->bStatus
;
1832 value
|= (UINT
)midi
->bByte1
<< 8;
1833 value
|= (UINT
)midi
->bByte2
<< 16;
1835 if (SUCCEEDED(hr
= IDirectMusic_CreateMusicBuffer(This
->dmusic
, &desc
, &buffer
, NULL
)))
1837 if (msg
->rtTime
== -1) msg
->rtTime
= latency_time
;
1838 hr
= IDirectMusicBuffer_PackStructured(buffer
, msg
->rtTime
, group
, value
);
1839 if (SUCCEEDED(hr
)) hr
= IDirectMusicPort_PlayBuffer(port
, buffer
);
1840 IDirectMusicBuffer_Release(buffer
);
1843 IDirectMusicPort_Release(port
);
1847 case DMUS_PMSGT_NOTE
:
1849 DMUS_NOTE_PMSG
*note
= (DMUS_NOTE_PMSG
*)msg
;
1851 msg
->mtTime
+= note
->nOffset
;
1852 if (FAILED(hr
= performance_send_midi_pmsg(This
, msg
, DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_IMMEDIATE
,
1853 MIDI_NOTE_ON
, note
->bMidiValue
, note
->bVelocity
)))
1854 WARN("Failed to translate message to MIDI, hr %#lx\n", hr
);
1856 msg
->mtTime
+= note
->mtDuration
;
1857 if (FAILED(hr
= performance_send_midi_pmsg(This
, msg
, DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_QUEUE
,
1858 MIDI_NOTE_OFF
, note
->bMidiValue
, 0)))
1859 WARN("Failed to translate message to MIDI, hr %#lx\n", hr
);
1864 case DMUS_PMSGT_CURVE
:
1866 DMUS_CURVE_PMSG
*curve
= (DMUS_CURVE_PMSG
*)msg
;
1868 msg
->mtTime
+= curve
->nOffset
;
1869 switch (curve
->dwType
)
1871 case DMUS_CURVET_CCCURVE
:
1872 if (FAILED(hr
= performance_send_midi_pmsg(This
, msg
, DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_IMMEDIATE
,
1873 MIDI_CONTROL_CHANGE
, curve
->bCCData
, curve
->nStartValue
)))
1874 WARN("Failed to translate message to MIDI, hr %#lx\n", hr
);
1876 case DMUS_CURVET_RPNCURVE
:
1877 case DMUS_CURVET_NRPNCURVE
:
1878 FIXME("Unhandled curve type %#lx\n", curve
->dwType
);
1885 case DMUS_PMSGT_PATCH
:
1887 DMUS_PATCH_PMSG
*patch
= (DMUS_PATCH_PMSG
*)msg
;
1889 if (FAILED(hr
= performance_send_midi_pmsg(This
, msg
, DMUS_PMSGF_REFTIME
| DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_IMMEDIATE
,
1890 MIDI_CONTROL_CHANGE
, MIDI_CC_BANK_MSB
, patch
->byMSB
)))
1891 WARN("Failed to translate message to MIDI, hr %#lx\n", hr
);
1893 if (FAILED(hr
= performance_send_midi_pmsg(This
, msg
, DMUS_PMSGF_REFTIME
| DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_IMMEDIATE
,
1894 MIDI_CONTROL_CHANGE
, MIDI_CC_BANK_LSB
, patch
->byLSB
)))
1895 WARN("Failed to translate message to MIDI, hr %#lx\n", hr
);
1897 if (FAILED(hr
= performance_send_midi_pmsg(This
, msg
, DMUS_PMSGF_REFTIME
| DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_IMMEDIATE
,
1898 MIDI_PROGRAM_CHANGE
, patch
->byInstrument
, 0)))
1899 WARN("Failed to translate message to MIDI, hr %#lx\n", hr
);
1904 case DMUS_PMSGT_NOTIFICATION
:
1906 DMUS_NOTIFICATION_PMSG
*notif
= (DMUS_NOTIFICATION_PMSG
*)msg
;
1907 struct message
*previous
;
1908 BOOL enabled
= FALSE
;
1910 if (IsEqualGUID(¬if
->guidNotificationType
, &GUID_NOTIFICATION_PERFORMANCE
))
1911 enabled
= This
->notification_performance
;
1912 if (IsEqualGUID(¬if
->guidNotificationType
, &GUID_NOTIFICATION_SEGMENT
))
1913 enabled
= This
->notification_segment
;
1914 if (!enabled
) return DMUS_S_FREE
;
1916 if (msg
->dwFlags
& DMUS_PMSGF_TOOL_IMMEDIATE
)
1918 /* re-send the message for queueing at the expected time */
1919 msg
->dwFlags
&= ~DMUS_PMSGF_TOOL_IMMEDIATE
;
1920 msg
->dwFlags
|= DMUS_PMSGF_TOOL_ATTIME
;
1922 if (FAILED(hr
= IDirectMusicPerformance8_SendPMsg(performance
, (DMUS_PMSG
*)msg
)))
1924 ERR("Failed to send notification message, hr %#lx\n", hr
);
1931 list_add_tail(&This
->notifications
, &message
->entry
);
1933 /* discard old notification messages */
1936 previous
= LIST_ENTRY(list_head(&This
->notifications
), struct message
, entry
);
1937 if (This
->notification_timeout
<= 0) break; /* negative values may be used to keep everything */
1938 if (message
->msg
.rtTime
- previous
->msg
.rtTime
<= This
->notification_timeout
) break;
1939 list_remove(&previous
->entry
);
1940 list_init(&previous
->entry
);
1941 } while (SUCCEEDED(hr
= IDirectMusicPerformance_FreePMsg(performance
, &previous
->msg
)));
1943 SetEvent(This
->notification_event
);
1947 case DMUS_PMSGT_WAVE
:
1948 if (FAILED(hr
= IDirectSoundBuffer_Play((IDirectSoundBuffer
*)msg
->punkUser
, 0, 0, 0)))
1949 WARN("Failed to play wave buffer, hr %#lx\n", hr
);
1952 case DMUS_PMSGT_INTERNAL_SEGMENT_TICK
:
1953 msg
->rtTime
+= 10000000;
1954 msg
->dwFlags
&= ~DMUS_PMSGF_MUSICTIME
;
1956 /* re-send the tick message until segment_state_tick returns S_FALSE */
1957 if (FAILED(hr
= segment_state_tick((IDirectMusicSegmentState
*)msg
->punkUser
,
1958 (IDirectMusicPerformance8
*)performance
)))
1959 ERR("Failed to tick segment state %p, hr %#lx\n", msg
->punkUser
, hr
);
1960 else if (hr
== S_FALSE
)
1961 return DMUS_S_FREE
; /* done ticking */
1962 else if (FAILED(hr
= IDirectMusicPerformance_SendPMsg(performance
, msg
)))
1963 ERR("Failed to queue tick for segment state %p, hr %#lx\n", msg
->punkUser
, hr
);
1967 case DMUS_PMSGT_INTERNAL_SEGMENT_END
:
1968 if (FAILED(hr
= segment_state_end_play((IDirectMusicSegmentState
*)msg
->punkUser
,
1969 (IDirectMusicPerformance8
*)performance
)))
1970 WARN("Failed to end segment state %p, hr %#lx\n", msg
->punkUser
, hr
);
1974 FIXME("Unhandled message type %#lx\n", msg
->dwType
);
1981 static HRESULT WINAPI
performance_tool_Flush(IDirectMusicTool
*iface
,
1982 IDirectMusicPerformance
*performance
, DMUS_PMSG
*msg
, REFERENCE_TIME time
)
1984 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1985 FIXME("(%p, %p, %p, %I64d): stub\n", This
, performance
, msg
, time
);
1989 static const IDirectMusicToolVtbl performance_tool_vtbl
=
1991 performance_tool_QueryInterface
,
1992 performance_tool_AddRef
,
1993 performance_tool_Release
,
1994 performance_tool_Init
,
1995 performance_tool_GetMsgDeliveryType
,
1996 performance_tool_GetMediaTypeArraySize
,
1997 performance_tool_GetMediaTypes
,
1998 performance_tool_ProcessPMsg
,
1999 performance_tool_Flush
,
2002 /* for ClassFactory */
2003 HRESULT
create_dmperformance(REFIID iid
, void **ret_iface
)
2005 struct performance
*obj
;
2008 TRACE("(%s, %p)\n", debugstr_guid(iid
), ret_iface
);
2011 if (!(obj
= calloc(1, sizeof(*obj
)))) return E_OUTOFMEMORY
;
2012 obj
->IDirectMusicPerformance8_iface
.lpVtbl
= &performance_vtbl
;
2013 obj
->IDirectMusicGraph_iface
.lpVtbl
= &performance_graph_vtbl
;
2014 obj
->IDirectMusicTool_iface
.lpVtbl
= &performance_tool_vtbl
;
2017 obj
->pDefaultPath
= NULL
;
2018 InitializeCriticalSection(&obj
->safe
);
2019 obj
->safe
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": performance->safe");
2020 wine_rb_init(&obj
->pchannels
, pchannel_block_compare
);
2022 list_init(&obj
->messages
);
2023 list_init(&obj
->notifications
);
2025 obj
->latency_offset
= 50;
2026 obj
->dwBumperLength
= 50; /* 50 ms default */
2027 obj
->dwPrepareTime
= 1000; /* 1000 ms default */
2029 hr
= IDirectMusicPerformance8_QueryInterface(&obj
->IDirectMusicPerformance8_iface
, iid
, ret_iface
);
2030 IDirectMusicPerformance_Release(&obj
->IDirectMusicPerformance8_iface
);
2034 static inline struct performance
*unsafe_impl_from_IDirectMusicPerformance8(IDirectMusicPerformance8
*iface
)
2036 if (iface
->lpVtbl
!= &performance_vtbl
) return NULL
;
2037 return CONTAINING_RECORD(iface
, struct performance
, IDirectMusicPerformance8_iface
);
2040 HRESULT
performance_get_dsound(IDirectMusicPerformance8
*iface
, IDirectSound
**dsound
)
2042 struct performance
*This
= unsafe_impl_from_IDirectMusicPerformance8(iface
);
2043 if (!This
|| !(*dsound
= This
->dsound
)) return E_FAIL
;
2044 IDirectSound_AddRef(*dsound
);