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 struct pchannel_block
{
28 DWORD block_num
; /* Block 0 is PChannels 0-15, Block 1 is PChannels 16-31, etc */
30 DWORD channel
; /* MIDI channel */
31 DWORD group
; /* MIDI group */
32 IDirectMusicPort
*port
;
34 struct wine_rb_entry entry
;
39 IDirectMusicPerformance8 IDirectMusicPerformance8_iface
;
40 IDirectMusicGraph IDirectMusicGraph_iface
;
41 IDirectMusicTool IDirectMusicTool_iface
;
45 IDirectMusicGraph
*pToolGraph
;
47 char cMasterGrooveLevel
;
50 /* performance channels */
51 struct wine_rb_tree pchannels
;
53 BOOL audio_paths_enabled
;
54 IDirectMusicAudioPath
*pDefaultPath
;
55 REFERENCE_TIME latency_offset
;
59 HANDLE message_thread
;
60 CRITICAL_SECTION safe
;
61 CONDITION_VARIABLE cond
;
63 IReferenceClock
*master_clock
;
64 REFERENCE_TIME init_time
;
67 struct list notifications
;
68 REFERENCE_TIME notification_timeout
;
69 HANDLE notification_event
;
70 BOOL notification_performance
;
71 BOOL notification_segment
;
80 static inline struct message
*message_from_DMUS_PMSG(DMUS_PMSG
*msg
)
82 return msg
? CONTAINING_RECORD(msg
, struct message
, msg
) : NULL
;
85 static HRESULT
performance_process_message(struct performance
*This
, DMUS_PMSG
*msg
, DWORD
*timeout
)
87 static const DWORD delivery_flags
= DMUS_PMSGF_TOOL_IMMEDIATE
| DMUS_PMSGF_TOOL_QUEUE
| DMUS_PMSGF_TOOL_ATTIME
;
88 IDirectMusicPerformance
*performance
= (IDirectMusicPerformance
*)&This
->IDirectMusicPerformance8_iface
;
93 REFERENCE_TIME latency
, offset
= 0;
94 IDirectMusicTool
*tool
;
96 if (FAILED(hr
= IDirectMusicPerformance_GetLatencyTime(performance
, &latency
))) return hr
;
97 if (!(tool
= msg
->pTool
)) tool
= &This
->IDirectMusicTool_iface
;
99 switch (msg
->dwFlags
& delivery_flags
)
102 WARN("No delivery flag found for message %p\n", msg
);
104 case DMUS_PMSGF_TOOL_IMMEDIATE
:
105 hr
= IDirectMusicTool_ProcessPMsg(tool
, performance
, msg
);
107 case DMUS_PMSGF_TOOL_QUEUE
:
108 offset
= This
->dwBumperLength
* 10000;
110 case DMUS_PMSGF_TOOL_ATTIME
:
111 if (msg
->rtTime
>= offset
&& msg
->rtTime
- offset
>= latency
)
113 if (timeout
) *timeout
= (msg
->rtTime
- offset
- latency
) / 10000;
114 return DMUS_S_REQUEUE
;
117 hr
= IDirectMusicTool_ProcessPMsg(tool
, performance
, msg
);
120 } while (hr
== DMUS_S_REQUEUE
);
122 if (hr
== DMUS_S_FREE
) hr
= IDirectMusicPerformance_FreePMsg(performance
, msg
);
123 if (FAILED(hr
)) WARN("Failed to process message, hr %#lx\n", hr
);
127 static DWORD WINAPI
message_thread_proc(void *args
)
129 struct performance
*This
= args
;
130 struct message
*message
, *next
;
133 TRACE("performance %p message thread\n", This
);
134 SetThreadDescription(GetCurrentThread(), L
"wine_dmime_message");
136 EnterCriticalSection(&This
->safe
);
138 while (This
->message_thread
)
140 DWORD timeout
= INFINITE
;
142 LIST_FOR_EACH_ENTRY_SAFE(message
, next
, &This
->messages
, struct message
, entry
)
144 list_remove(&message
->entry
);
145 list_init(&message
->entry
);
147 hr
= performance_process_message(This
, &message
->msg
, &timeout
);
148 if (hr
== DMUS_S_REQUEUE
) list_add_before(&next
->entry
, &message
->entry
);
149 if (hr
!= S_OK
) break;
152 SleepConditionVariableCS(&This
->cond
, &This
->safe
, timeout
);
155 LeaveCriticalSection(&This
->safe
);
157 TRACE("(%p): Exiting\n", This
);
161 static HRESULT
performance_send_dirty_pmsg(struct performance
*This
, MUSIC_TIME music_time
)
163 IDirectMusicPerformance8
*performance
= &This
->IDirectMusicPerformance8_iface
;
164 IDirectMusicGraph
*graph
= &This
->IDirectMusicGraph_iface
;
168 if (FAILED(hr
= IDirectMusicPerformance8_AllocPMsg(performance
, sizeof(*msg
), &msg
)))
171 msg
->mtTime
= music_time
;
172 msg
->dwFlags
= DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_QUEUE
;
173 msg
->dwType
= DMUS_PMSGT_DIRTY
;
175 if (FAILED(hr
= IDirectMusicGraph_StampPMsg(graph
, msg
))
176 || FAILED(hr
= IDirectMusicPerformance8_SendPMsg(performance
, msg
)))
177 IDirectMusicPerformance8_FreePMsg(performance
, msg
);
182 static HRESULT
performance_send_notification_pmsg(struct performance
*This
, MUSIC_TIME music_time
, BOOL stamp
,
183 GUID type
, DWORD option
, IUnknown
*object
)
185 IDirectMusicPerformance8
*performance
= &This
->IDirectMusicPerformance8_iface
;
186 IDirectMusicGraph
*graph
= &This
->IDirectMusicGraph_iface
;
187 DMUS_NOTIFICATION_PMSG
*msg
;
190 if (FAILED(hr
= IDirectMusicPerformance8_AllocPMsg(performance
, sizeof(*msg
), (DMUS_PMSG
**)&msg
)))
193 msg
->mtTime
= music_time
;
194 msg
->dwFlags
= DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_QUEUE
;
195 msg
->dwType
= DMUS_PMSGT_NOTIFICATION
;
196 if ((msg
->punkUser
= object
)) IUnknown_AddRef(object
);
197 msg
->guidNotificationType
= type
;
198 msg
->dwNotificationOption
= option
;
200 /* only stamp the message if notifications are enabled, otherwise send them directly to the output tool */
201 if ((stamp
&& FAILED(hr
= IDirectMusicGraph_StampPMsg(graph
, (DMUS_PMSG
*)msg
)))
202 || FAILED(hr
= IDirectMusicPerformance8_SendPMsg(performance
, (DMUS_PMSG
*)msg
)))
203 IDirectMusicPerformance8_FreePMsg(performance
, (DMUS_PMSG
*)msg
);
208 static int pchannel_block_compare(const void *key
, const struct wine_rb_entry
*entry
)
210 const struct pchannel_block
*b
= WINE_RB_ENTRY_VALUE(entry
, const struct pchannel_block
, entry
);
212 return *(DWORD
*)key
- b
->block_num
;
215 static void pchannel_block_free(struct wine_rb_entry
*entry
, void *context
)
217 struct pchannel_block
*b
= WINE_RB_ENTRY_VALUE(entry
, struct pchannel_block
, entry
);
222 static struct pchannel_block
*pchannel_block_set(struct wine_rb_tree
*tree
, DWORD block_num
,
223 IDirectMusicPort
*port
, DWORD group
, BOOL only_set_new
)
225 struct pchannel_block
*block
;
226 struct wine_rb_entry
*entry
;
229 entry
= wine_rb_get(tree
, &block_num
);
231 block
= WINE_RB_ENTRY_VALUE(entry
, struct pchannel_block
, entry
);
235 if (!(block
= malloc(sizeof(*block
)))) return NULL
;
236 block
->block_num
= block_num
;
239 for (i
= 0; i
< 16; ++i
) {
240 block
->pchannel
[i
].port
= port
;
241 block
->pchannel
[i
].group
= group
;
242 block
->pchannel
[i
].channel
= i
;
245 wine_rb_put(tree
, &block
->block_num
, &block
->entry
);
250 static inline struct performance
*impl_from_IDirectMusicPerformance8(IDirectMusicPerformance8
*iface
)
252 return CONTAINING_RECORD(iface
, struct performance
, IDirectMusicPerformance8_iface
);
255 /* IDirectMusicPerformance8 IUnknown part: */
256 static HRESULT WINAPI
performance_QueryInterface(IDirectMusicPerformance8
*iface
, REFIID riid
, void **ret_iface
)
258 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
260 TRACE("(%p, %s, %p)\n", iface
, debugstr_dmguid(riid
), ret_iface
);
262 if (IsEqualGUID(riid
, &IID_IUnknown
)
263 || IsEqualGUID(riid
, &IID_IDirectMusicPerformance
)
264 || IsEqualGUID(riid
, &IID_IDirectMusicPerformance2
)
265 || IsEqualGUID(riid
, &IID_IDirectMusicPerformance8
))
268 IUnknown_AddRef(iface
);
272 if (IsEqualGUID(riid
, &IID_IDirectMusicGraph
))
274 *ret_iface
= &This
->IDirectMusicGraph_iface
;
275 IDirectMusicGraph_AddRef(&This
->IDirectMusicGraph_iface
);
279 if (IsEqualGUID(riid
, &IID_IDirectMusicTool
))
281 *ret_iface
= &This
->IDirectMusicTool_iface
;
282 IDirectMusicTool_AddRef(&This
->IDirectMusicTool_iface
);
287 WARN("(%p, %s, %p): not found\n", iface
, debugstr_dmguid(riid
), ret_iface
);
288 return E_NOINTERFACE
;
291 static ULONG WINAPI
performance_AddRef(IDirectMusicPerformance8
*iface
)
293 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
294 ULONG ref
= InterlockedIncrement(&This
->ref
);
296 TRACE("(%p): ref=%ld\n", This
, ref
);
301 static ULONG WINAPI
performance_Release(IDirectMusicPerformance8
*iface
)
303 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
304 ULONG ref
= InterlockedDecrement(&This
->ref
);
306 TRACE("(%p): ref=%ld\n", This
, ref
);
309 wine_rb_destroy(&This
->pchannels
, pchannel_block_free
, NULL
);
310 This
->safe
.DebugInfo
->Spare
[0] = 0;
311 DeleteCriticalSection(&This
->safe
);
318 static HRESULT
performance_init_dsound(struct performance
*This
, HWND hwnd
)
320 IDirectSound
*dsound
;
323 if (FAILED(hr
= DirectSoundCreate(NULL
, &dsound
, NULL
))) return hr
;
325 if (!hwnd
) hwnd
= GetForegroundWindow();
326 hr
= IDirectSound_SetCooperativeLevel(dsound
, hwnd
, DSSCL_PRIORITY
);
328 if (SUCCEEDED(hr
)) This
->dsound
= dsound
;
329 else IDirectSound_Release(dsound
);
334 static HRESULT
performance_init_dmusic(struct performance
*This
, IDirectSound
*dsound
)
336 IDirectMusic
*dmusic
;
339 if (FAILED(hr
= CoCreateInstance(&CLSID_DirectMusic
, NULL
, CLSCTX_INPROC_SERVER
,
340 &IID_IDirectMusic8
, (void **)&dmusic
)))
343 hr
= IDirectMusic_SetDirectSound(dmusic
, dsound
, NULL
);
345 if (SUCCEEDED(hr
)) This
->dmusic
= dmusic
;
346 else IDirectSound_Release(dmusic
);
351 static HRESULT WINAPI
performance_Init(IDirectMusicPerformance8
*iface
, IDirectMusic
**dmusic
,
352 IDirectSound
*dsound
, HWND hwnd
)
354 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
357 TRACE("(%p, %p, %p, %p)\n", iface
, dmusic
, dsound
, hwnd
);
359 if (This
->dmusic
) return DMUS_E_ALREADY_INITED
;
361 if ((This
->dsound
= dsound
)) IDirectMusic8_AddRef(This
->dsound
);
362 else if (FAILED(hr
= performance_init_dsound(This
, hwnd
))) return hr
;
364 if (dmusic
&& (This
->dmusic
= *dmusic
)) IDirectMusic_AddRef(This
->dmusic
);
365 else if (FAILED(hr
= performance_init_dmusic(This
, This
->dsound
)))
367 IDirectMusicPerformance_CloseDown(iface
);
371 if (FAILED(hr
= IDirectMusic_GetMasterClock(This
->dmusic
, NULL
, &This
->master_clock
))
372 || FAILED(hr
= IDirectMusicPerformance8_GetTime(iface
, &This
->init_time
, NULL
)))
374 IDirectMusicPerformance_CloseDown(iface
);
378 if (!(This
->message_thread
= CreateThread(NULL
, 0, message_thread_proc
, This
, 0, NULL
)))
380 ERR("Failed to start performance message thread, error %lu\n", GetLastError());
381 IDirectMusicPerformance_CloseDown(iface
);
382 return HRESULT_FROM_WIN32(GetLastError());
385 if (dmusic
&& !*dmusic
)
387 *dmusic
= This
->dmusic
;
388 IDirectMusic_AddRef(*dmusic
);
393 static HRESULT WINAPI
performance_PlaySegment(IDirectMusicPerformance8
*iface
, IDirectMusicSegment
*segment
,
394 DWORD segment_flags
, INT64 start_time
, IDirectMusicSegmentState
**ret_state
)
396 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
398 TRACE("(%p, %p, %ld, %I64d, %p)\n", This
, segment
, segment_flags
, start_time
, ret_state
);
400 return IDirectMusicPerformance8_PlaySegmentEx(iface
, (IUnknown
*)segment
, NULL
, NULL
,
401 segment_flags
, start_time
, ret_state
, NULL
, NULL
);
404 static HRESULT WINAPI
performance_Stop(IDirectMusicPerformance8
*iface
, IDirectMusicSegment
*pSegment
,
405 IDirectMusicSegmentState
*pSegmentState
, MUSIC_TIME mtTime
, DWORD dwFlags
)
407 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
409 FIXME("(%p, %p, %p, %ld, %ld): stub\n", This
, pSegment
, pSegmentState
, mtTime
, dwFlags
);
413 static HRESULT WINAPI
performance_GetSegmentState(IDirectMusicPerformance8
*iface
,
414 IDirectMusicSegmentState
**ppSegmentState
, MUSIC_TIME mtTime
)
416 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
418 FIXME("(%p,%p, %ld): stub\n", This
, ppSegmentState
, mtTime
);
422 static HRESULT WINAPI
performance_SetPrepareTime(IDirectMusicPerformance8
*iface
, DWORD dwMilliSeconds
)
424 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
426 TRACE("(%p, %ld)\n", This
, dwMilliSeconds
);
427 This
->dwPrepareTime
= dwMilliSeconds
;
431 static HRESULT WINAPI
performance_GetPrepareTime(IDirectMusicPerformance8
*iface
, DWORD
*pdwMilliSeconds
)
433 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
435 TRACE("(%p, %p)\n", This
, pdwMilliSeconds
);
436 if (NULL
== pdwMilliSeconds
) {
439 *pdwMilliSeconds
= This
->dwPrepareTime
;
443 static HRESULT WINAPI
performance_SetBumperLength(IDirectMusicPerformance8
*iface
, DWORD dwMilliSeconds
)
445 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
447 TRACE("(%p, %ld)\n", This
, dwMilliSeconds
);
448 This
->dwBumperLength
= dwMilliSeconds
;
452 static HRESULT WINAPI
performance_GetBumperLength(IDirectMusicPerformance8
*iface
, DWORD
*pdwMilliSeconds
)
454 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
456 TRACE("(%p, %p)\n", This
, pdwMilliSeconds
);
457 if (NULL
== pdwMilliSeconds
) {
460 *pdwMilliSeconds
= This
->dwBumperLength
;
464 static HRESULT WINAPI
performance_SendPMsg(IDirectMusicPerformance8
*iface
, DMUS_PMSG
*msg
)
466 const DWORD delivery_flags
= DMUS_PMSGF_TOOL_IMMEDIATE
| DMUS_PMSGF_TOOL_QUEUE
| DMUS_PMSGF_TOOL_ATTIME
;
467 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
468 struct message
*message
, *next
;
471 TRACE("(%p, %p)\n", This
, msg
);
473 if (!(message
= message_from_DMUS_PMSG(msg
))) return E_POINTER
;
474 if (!This
->dmusic
) return DMUS_E_NO_MASTER_CLOCK
;
475 if (!(msg
->dwFlags
& (DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_REFTIME
))) return E_INVALIDARG
;
477 EnterCriticalSection(&This
->safe
);
479 if (!list_empty(&message
->entry
))
480 hr
= DMUS_E_ALREADY_SENT
;
483 if (!(msg
->dwFlags
& delivery_flags
)) msg
->dwFlags
|= DMUS_PMSGF_TOOL_IMMEDIATE
;
484 if (!(msg
->dwFlags
& DMUS_PMSGF_MUSICTIME
))
486 if (FAILED(hr
= IDirectMusicPerformance8_ReferenceToMusicTime(iface
,
487 msg
->rtTime
, &msg
->mtTime
)))
489 msg
->dwFlags
|= DMUS_PMSGF_MUSICTIME
;
491 if (!(msg
->dwFlags
& DMUS_PMSGF_REFTIME
))
493 if (FAILED(hr
= IDirectMusicPerformance8_MusicToReferenceTime(iface
,
494 msg
->mtTime
== -1 ? 0 : msg
->mtTime
, &msg
->rtTime
)))
496 msg
->dwFlags
|= DMUS_PMSGF_REFTIME
;
499 if (msg
->dwFlags
& DMUS_PMSGF_TOOL_IMMEDIATE
)
501 hr
= performance_process_message(This
, &message
->msg
, NULL
);
502 if (hr
!= DMUS_S_REQUEUE
) goto done
;
505 LIST_FOR_EACH_ENTRY(next
, &This
->messages
, struct message
, entry
)
506 if (next
->msg
.rtTime
> message
->msg
.rtTime
) break;
507 list_add_before(&next
->entry
, &message
->entry
);
513 LeaveCriticalSection(&This
->safe
);
514 if (SUCCEEDED(hr
)) WakeConditionVariable(&This
->cond
);
519 static HRESULT WINAPI
performance_MusicToReferenceTime(IDirectMusicPerformance8
*iface
,
520 MUSIC_TIME music_time
, REFERENCE_TIME
*time
)
523 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
525 if (!once
++) FIXME("(%p, %ld, %p): semi-stub\n", This
, music_time
, time
);
526 else TRACE("(%p, %ld, %p)\n", This
, music_time
, time
);
528 if (!time
) return E_POINTER
;
531 if (!This
->master_clock
) return DMUS_E_NO_MASTER_CLOCK
;
533 /* FIXME: This should be (music_time * 60) / (DMUS_PPQ * tempo)
534 * but it gives innacurate results */
535 *time
= This
->init_time
+ (music_time
* 6510);
540 static HRESULT WINAPI
performance_ReferenceToMusicTime(IDirectMusicPerformance8
*iface
,
541 REFERENCE_TIME time
, MUSIC_TIME
*music_time
)
544 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
546 if (!once
++) FIXME("(%p, %I64d, %p): semi-stub\n", This
, time
, music_time
);
547 else TRACE("(%p, %I64d, %p)\n", This
, time
, music_time
);
549 if (!music_time
) return E_POINTER
;
552 if (!This
->master_clock
) return DMUS_E_NO_MASTER_CLOCK
;
554 /* FIXME: This should be (time * DMUS_PPQ * tempo) / 60
555 * but it gives innacurate results */
556 *music_time
= (time
- This
->init_time
) / 6510;
561 static HRESULT WINAPI
performance_IsPlaying(IDirectMusicPerformance8
*iface
,
562 IDirectMusicSegment
*pSegment
, IDirectMusicSegmentState
*pSegState
)
564 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
566 FIXME("(%p, %p, %p): stub\n", This
, pSegment
, pSegState
);
570 static HRESULT WINAPI
performance_GetTime(IDirectMusicPerformance8
*iface
, REFERENCE_TIME
*time
, MUSIC_TIME
*music_time
)
572 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
576 TRACE("(%p, %p, %p)\n", iface
, time
, music_time
);
578 if (!This
->master_clock
) return DMUS_E_NO_MASTER_CLOCK
;
579 if (FAILED(hr
= IReferenceClock_GetTime(This
->master_clock
, &now
))) return hr
;
581 if (time
) *time
= now
;
582 if (music_time
) hr
= IDirectMusicPerformance8_ReferenceToMusicTime(iface
, now
, music_time
);
587 static HRESULT WINAPI
performance_AllocPMsg(IDirectMusicPerformance8
*iface
, ULONG size
, DMUS_PMSG
**msg
)
589 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
590 struct message
*message
;
592 TRACE("(%p, %ld, %p)\n", This
, size
, msg
);
594 if (!msg
) return E_POINTER
;
595 if (size
< sizeof(DMUS_PMSG
)) return E_INVALIDARG
;
597 if (!(message
= calloc(1, size
- sizeof(DMUS_PMSG
) + sizeof(struct message
)))) return E_OUTOFMEMORY
;
598 message
->msg
.dwSize
= size
;
599 list_init(&message
->entry
);
600 *msg
= &message
->msg
;
605 static HRESULT WINAPI
performance_FreePMsg(IDirectMusicPerformance8
*iface
, DMUS_PMSG
*msg
)
607 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
608 struct message
*message
;
611 TRACE("(%p, %p)\n", This
, msg
);
613 if (!(message
= message_from_DMUS_PMSG(msg
))) return E_POINTER
;
615 EnterCriticalSection(&This
->safe
);
616 hr
= !list_empty(&message
->entry
) ? DMUS_E_CANNOT_FREE
: S_OK
;
617 LeaveCriticalSection(&This
->safe
);
621 if (msg
->pTool
) IDirectMusicTool_Release(msg
->pTool
);
622 if (msg
->pGraph
) IDirectMusicGraph_Release(msg
->pGraph
);
623 if (msg
->punkUser
) IUnknown_Release(msg
->punkUser
);
630 static HRESULT WINAPI
performance_GetGraph(IDirectMusicPerformance8
*iface
, IDirectMusicGraph
**graph
)
632 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
634 TRACE("(%p, %p)\n", This
, graph
);
639 *graph
= This
->pToolGraph
;
640 if (This
->pToolGraph
) {
641 IDirectMusicGraph_AddRef(*graph
);
644 return *graph
? S_OK
: DMUS_E_NOT_FOUND
;
647 static HRESULT WINAPI
performance_SetGraph(IDirectMusicPerformance8
*iface
, IDirectMusicGraph
*pGraph
)
649 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
651 FIXME("(%p, %p): to check\n", This
, pGraph
);
653 if (NULL
!= This
->pToolGraph
) {
654 /* Todo clean buffers and tools before */
655 IDirectMusicGraph_Release(This
->pToolGraph
);
657 This
->pToolGraph
= pGraph
;
658 if (NULL
!= This
->pToolGraph
) {
659 IDirectMusicGraph_AddRef(This
->pToolGraph
);
664 static HRESULT WINAPI
performance_SetNotificationHandle(IDirectMusicPerformance8
*iface
,
665 HANDLE notification_event
, REFERENCE_TIME minimum_time
)
667 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
669 TRACE("(%p, %p, %I64d)\n", This
, notification_event
, minimum_time
);
671 This
->notification_event
= notification_event
;
673 This
->notification_timeout
= minimum_time
;
674 else if (!This
->notification_timeout
)
675 This
->notification_timeout
= 20000000; /* 2 seconds */
680 static HRESULT WINAPI
performance_GetNotificationPMsg(IDirectMusicPerformance8
*iface
,
681 DMUS_NOTIFICATION_PMSG
**ret_msg
)
683 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
686 TRACE("(%p, %p)\n", This
, ret_msg
);
688 if (!ret_msg
) return E_POINTER
;
690 EnterCriticalSection(&This
->safe
);
691 if ((entry
= list_head(&This
->notifications
)))
693 struct message
*message
= LIST_ENTRY(entry
, struct message
, entry
);
694 list_remove(&message
->entry
);
695 list_init(&message
->entry
);
696 *ret_msg
= (DMUS_NOTIFICATION_PMSG
*)&message
->msg
;
698 LeaveCriticalSection(&This
->safe
);
700 return entry
? S_OK
: S_FALSE
;
703 static HRESULT WINAPI
performance_AddNotificationType(IDirectMusicPerformance8
*iface
, REFGUID type
)
705 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
708 FIXME("(%p, %s): stub\n", This
, debugstr_dmguid(type
));
710 if (IsEqualGUID(type
, &GUID_NOTIFICATION_PERFORMANCE
))
712 hr
= This
->notification_performance
? S_FALSE
: S_OK
;
713 This
->notification_performance
= TRUE
;
715 if (IsEqualGUID(type
, &GUID_NOTIFICATION_SEGMENT
))
717 hr
= This
->notification_segment
? S_FALSE
: S_OK
;
718 This
->notification_segment
= TRUE
;
724 static HRESULT WINAPI
performance_RemoveNotificationType(IDirectMusicPerformance8
*iface
, REFGUID type
)
726 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
727 HRESULT hr
= S_FALSE
;
729 FIXME("(%p, %s): stub\n", This
, debugstr_dmguid(type
));
731 if (IsEqualGUID(type
, &GUID_NOTIFICATION_PERFORMANCE
))
733 hr
= This
->notification_performance
? S_OK
: S_FALSE
;
734 This
->notification_performance
= FALSE
;
736 if (IsEqualGUID(type
, &GUID_NOTIFICATION_SEGMENT
))
738 hr
= This
->notification_segment
? S_OK
: S_FALSE
;
739 This
->notification_segment
= FALSE
;
745 static void performance_update_latency_time(struct performance
*This
, IDirectMusicPort
*port
,
746 REFERENCE_TIME
*ret_time
)
748 IDirectMusicPerformance8
*iface
= &This
->IDirectMusicPerformance8_iface
;
749 REFERENCE_TIME latency_time
, current_time
;
750 IReferenceClock
*latency_clock
;
753 if (!ret_time
) ret_time
= &latency_time
;
754 if (SUCCEEDED(hr
= IDirectMusicPort_GetLatencyClock(port
, &latency_clock
)))
756 hr
= IReferenceClock_GetTime(latency_clock
, ret_time
);
757 if (SUCCEEDED(hr
)) hr
= IDirectMusicPerformance8_GetTime(iface
, ¤t_time
, NULL
);
758 if (SUCCEEDED(hr
) && This
->latency_offset
< (*ret_time
- current_time
))
760 TRACE("Updating performance %p latency %I64d -> %I64d\n", This
,
761 This
->latency_offset
, *ret_time
- current_time
);
762 This
->latency_offset
= *ret_time
- current_time
;
764 IReferenceClock_Release(latency_clock
);
767 if (FAILED(hr
)) ERR("Failed to update performance %p latency, hr %#lx\n", This
, hr
);
770 static HRESULT
perf_dmport_create(struct performance
*perf
, DMUS_PORTPARAMS
*params
)
772 IDirectMusicPort
*port
;
777 if (FAILED(hr
= IDirectMusic8_GetDefaultPort(perf
->dmusic
, &guid
)))
780 if (FAILED(hr
= IDirectMusic8_CreatePort(perf
->dmusic
, &guid
, params
, &port
, NULL
)))
783 if (FAILED(hr
= IDirectMusicPort_SetDirectSound(port
, perf
->dsound
, NULL
))
784 || FAILED(hr
= IDirectMusicPort_Activate(port
, TRUE
)))
786 IDirectMusicPort_Release(port
);
790 for (i
= 0; i
< params
->dwChannelGroups
; i
++)
791 pchannel_block_set(&perf
->pchannels
, i
, port
, i
+ 1, FALSE
);
793 performance_update_latency_time(perf
, port
, NULL
);
797 static HRESULT WINAPI
performance_AddPort(IDirectMusicPerformance8
*iface
, IDirectMusicPort
*port
)
799 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
801 FIXME("(%p, %p): semi-stub\n", This
, port
);
803 if (!This
->dmusic
) return DMUS_E_NOT_INIT
;
804 if (This
->audio_paths_enabled
) return DMUS_E_AUDIOPATHS_IN_USE
;
807 DMUS_PORTPARAMS params
= {
808 .dwSize
= sizeof(params
),
809 .dwValidParams
= DMUS_PORTPARAMS_CHANNELGROUPS
,
813 return perf_dmport_create(This
, ¶ms
);
816 IDirectMusicPort_AddRef(port
);
818 * We should remember added Ports (for example using a list)
819 * and control if Port is registered for each api who use ports
822 performance_update_latency_time(This
, port
, NULL
);
826 static HRESULT WINAPI
performance_RemovePort(IDirectMusicPerformance8
*iface
, IDirectMusicPort
*pPort
)
828 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
830 if (This
->audio_paths_enabled
) return DMUS_E_AUDIOPATHS_IN_USE
;
832 FIXME("(%p, %p): stub\n", This
, pPort
);
833 IDirectMusicPort_Release(pPort
);
837 static HRESULT WINAPI
performance_AssignPChannelBlock(IDirectMusicPerformance8
*iface
,
838 DWORD block_num
, IDirectMusicPort
*port
, DWORD group
)
840 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
842 FIXME("(%p, %ld, %p, %ld): semi-stub\n", This
, block_num
, port
, group
);
844 if (!port
) return E_POINTER
;
845 if (block_num
> MAXDWORD
/ 16) return E_INVALIDARG
;
846 if (This
->audio_paths_enabled
) return DMUS_E_AUDIOPATHS_IN_USE
;
848 pchannel_block_set(&This
->pchannels
, block_num
, port
, group
, FALSE
);
853 static HRESULT WINAPI
performance_AssignPChannel(IDirectMusicPerformance8
*iface
, DWORD pchannel
,
854 IDirectMusicPort
*port
, DWORD group
, DWORD channel
)
856 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
857 struct pchannel_block
*block
;
859 FIXME("(%p)->(%ld, %p, %ld, %ld) semi-stub\n", This
, pchannel
, port
, group
, channel
);
861 if (!port
) return E_POINTER
;
862 if (This
->audio_paths_enabled
) return DMUS_E_AUDIOPATHS_IN_USE
;
864 block
= pchannel_block_set(&This
->pchannels
, pchannel
/ 16, port
, 0, TRUE
);
866 block
->pchannel
[pchannel
% 16].group
= group
;
867 block
->pchannel
[pchannel
% 16].channel
= channel
;
873 static HRESULT WINAPI
performance_PChannelInfo(IDirectMusicPerformance8
*iface
, DWORD pchannel
,
874 IDirectMusicPort
**port
, DWORD
*group
, DWORD
*channel
)
876 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
877 struct pchannel_block
*block
;
878 struct wine_rb_entry
*entry
;
879 DWORD block_num
= pchannel
/ 16;
880 unsigned int index
= pchannel
% 16;
882 TRACE("(%p)->(%ld, %p, %p, %p)\n", This
, pchannel
, port
, group
, channel
);
884 entry
= wine_rb_get(&This
->pchannels
, &block_num
);
887 block
= WINE_RB_ENTRY_VALUE(entry
, struct pchannel_block
, entry
);
890 *port
= block
->pchannel
[index
].port
;
891 IDirectMusicPort_AddRef(*port
);
894 *group
= block
->pchannel
[index
].group
;
896 *channel
= block
->pchannel
[index
].channel
;
901 static HRESULT WINAPI
performance_DownloadInstrument(IDirectMusicPerformance8
*iface
,
902 IDirectMusicInstrument
*instrument
, DWORD port_channel
,
903 IDirectMusicDownloadedInstrument
**downloaded
, DMUS_NOTERANGE
*note_ranges
,
904 DWORD note_range_count
, IDirectMusicPort
**port
, DWORD
*group
, DWORD
*music_channel
)
906 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
907 IDirectMusicPort
*tmp_port
= NULL
;
910 TRACE("(%p, %p, %ld, %p, %p, %ld, %p, %p, %p)\n", This
, instrument
, port_channel
, downloaded
,
911 note_ranges
, note_range_count
, port
, group
, music_channel
);
913 if (!port
) port
= &tmp_port
;
914 if (FAILED(hr
= IDirectMusicPerformance_PChannelInfo(iface
, port_channel
, port
, group
, music_channel
)))
917 hr
= IDirectMusicPort_DownloadInstrument(*port
, instrument
, downloaded
, note_ranges
, note_range_count
);
918 if (tmp_port
) IDirectMusicPort_Release(tmp_port
);
922 static HRESULT WINAPI
performance_Invalidate(IDirectMusicPerformance8
*iface
, MUSIC_TIME mtTime
, DWORD dwFlags
)
924 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
926 FIXME("(%p, %ld, %ld): stub\n", This
, mtTime
, dwFlags
);
930 static HRESULT WINAPI
performance_GetParam(IDirectMusicPerformance8
*iface
, REFGUID rguidType
,
931 DWORD dwGroupBits
, DWORD dwIndex
, MUSIC_TIME mtTime
, MUSIC_TIME
*pmtNext
, void *pParam
)
933 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
935 FIXME("(%p, %s, %ld, %ld, %ld, %p, %p): stub\n", This
, debugstr_dmguid(rguidType
), dwGroupBits
, dwIndex
, mtTime
, pmtNext
, pParam
);
939 static HRESULT WINAPI
performance_SetParam(IDirectMusicPerformance8
*iface
, REFGUID rguidType
,
940 DWORD dwGroupBits
, DWORD dwIndex
, MUSIC_TIME mtTime
, void *pParam
)
942 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
944 FIXME("(%p, %s, %ld, %ld, %ld, %p): stub\n", This
, debugstr_dmguid(rguidType
), dwGroupBits
, dwIndex
, mtTime
, pParam
);
948 static HRESULT WINAPI
performance_GetGlobalParam(IDirectMusicPerformance8
*iface
, REFGUID rguidType
,
949 void *pParam
, DWORD dwSize
)
951 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
953 TRACE("(%p, %s, %p, %ld): stub\n", This
, debugstr_dmguid(rguidType
), pParam
, dwSize
);
955 if (IsEqualGUID (rguidType
, &GUID_PerfAutoDownload
))
956 memcpy(pParam
, &This
->fAutoDownload
, sizeof(This
->fAutoDownload
));
957 if (IsEqualGUID (rguidType
, &GUID_PerfMasterGrooveLevel
))
958 memcpy(pParam
, &This
->cMasterGrooveLevel
, sizeof(This
->cMasterGrooveLevel
));
959 if (IsEqualGUID (rguidType
, &GUID_PerfMasterTempo
))
960 memcpy(pParam
, &This
->fMasterTempo
, sizeof(This
->fMasterTempo
));
961 if (IsEqualGUID (rguidType
, &GUID_PerfMasterVolume
))
962 memcpy(pParam
, &This
->lMasterVolume
, sizeof(This
->lMasterVolume
));
967 static HRESULT WINAPI
performance_SetGlobalParam(IDirectMusicPerformance8
*iface
, REFGUID rguidType
,
968 void *pParam
, DWORD dwSize
)
970 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
972 TRACE("(%p, %s, %p, %ld)\n", This
, debugstr_dmguid(rguidType
), pParam
, dwSize
);
974 if (IsEqualGUID (rguidType
, &GUID_PerfAutoDownload
)) {
975 memcpy(&This
->fAutoDownload
, pParam
, dwSize
);
976 TRACE("=> AutoDownload set to %d\n", This
->fAutoDownload
);
978 if (IsEqualGUID (rguidType
, &GUID_PerfMasterGrooveLevel
)) {
979 memcpy(&This
->cMasterGrooveLevel
, pParam
, dwSize
);
980 TRACE("=> MasterGrooveLevel set to %i\n", This
->cMasterGrooveLevel
);
982 if (IsEqualGUID (rguidType
, &GUID_PerfMasterTempo
)) {
983 memcpy(&This
->fMasterTempo
, pParam
, dwSize
);
984 TRACE("=> MasterTempo set to %f\n", This
->fMasterTempo
);
986 if (IsEqualGUID (rguidType
, &GUID_PerfMasterVolume
)) {
987 memcpy(&This
->lMasterVolume
, pParam
, dwSize
);
988 TRACE("=> MasterVolume set to %li\n", This
->lMasterVolume
);
994 static HRESULT WINAPI
performance_GetLatencyTime(IDirectMusicPerformance8
*iface
, REFERENCE_TIME
*ret_time
)
996 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
997 REFERENCE_TIME current_time
;
1000 TRACE("(%p, %p)\n", This
, ret_time
);
1002 if (SUCCEEDED(hr
= IDirectMusicPerformance8_GetTime(iface
, ¤t_time
, NULL
)))
1003 *ret_time
= current_time
+ This
->latency_offset
;
1008 static HRESULT WINAPI
performance_GetQueueTime(IDirectMusicPerformance8
*iface
, REFERENCE_TIME
*prtTime
)
1011 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1013 FIXME("(%p, %p): stub\n", This
, prtTime
);
1017 static HRESULT WINAPI
performance_AdjustTime(IDirectMusicPerformance8
*iface
, REFERENCE_TIME rtAmount
)
1019 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1021 FIXME("(%p, 0x%s): stub\n", This
, wine_dbgstr_longlong(rtAmount
));
1025 static HRESULT WINAPI
performance_CloseDown(IDirectMusicPerformance8
*iface
)
1027 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1028 struct message
*message
, *next
;
1029 HANDLE message_thread
;
1032 FIXME("(%p): semi-stub\n", This
);
1034 if ((message_thread
= This
->message_thread
))
1036 EnterCriticalSection(&This
->safe
);
1037 This
->message_thread
= NULL
;
1038 LeaveCriticalSection(&This
->safe
);
1039 WakeConditionVariable(&This
->cond
);
1041 WaitForSingleObject(message_thread
, INFINITE
);
1042 CloseHandle(message_thread
);
1045 This
->notification_performance
= FALSE
;
1046 This
->notification_segment
= FALSE
;
1048 LIST_FOR_EACH_ENTRY_SAFE(message
, next
, &This
->messages
, struct message
, entry
)
1050 list_remove(&message
->entry
);
1051 list_init(&message
->entry
);
1053 /* process notifications to end any pending segment states */
1054 if (message
->msg
.dwType
== DMUS_PMSGT_NOTIFICATION
)
1055 hr
= IDirectMusicTool_ProcessPMsg(&This
->IDirectMusicTool_iface
,
1056 (IDirectMusicPerformance
*)iface
, &message
->msg
);
1060 if (hr
== DMUS_S_FREE
&& FAILED(hr
= IDirectMusicPerformance8_FreePMsg(iface
, &message
->msg
)))
1061 WARN("Failed to free message %p, hr %#lx\n", message
, hr
);
1064 LIST_FOR_EACH_ENTRY_SAFE(message
, next
, &This
->notifications
, struct message
, entry
)
1066 list_remove(&message
->entry
);
1067 list_init(&message
->entry
);
1069 if (FAILED(hr
= IDirectMusicPerformance8_FreePMsg(iface
, &message
->msg
)))
1070 WARN("Failed to free message %p, hr %#lx\n", message
, hr
);
1073 if (This
->master_clock
)
1075 IReferenceClock_Release(This
->master_clock
);
1076 This
->master_clock
= NULL
;
1079 IDirectSound_Release(This
->dsound
);
1080 This
->dsound
= NULL
;
1083 IDirectMusic8_SetDirectSound(This
->dmusic
, NULL
, NULL
);
1084 IDirectMusic8_Release(This
->dmusic
);
1085 This
->dmusic
= NULL
;
1087 This
->audio_paths_enabled
= FALSE
;
1092 static HRESULT WINAPI
performance_GetResolvedTime(IDirectMusicPerformance8
*iface
,
1093 REFERENCE_TIME rtTime
, REFERENCE_TIME
*prtResolved
, DWORD dwTimeResolveFlags
)
1095 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1097 FIXME("(%p, 0x%s, %p, %ld): stub\n", This
, wine_dbgstr_longlong(rtTime
),
1098 prtResolved
, dwTimeResolveFlags
);
1102 static HRESULT WINAPI
performance_MIDIToMusic(IDirectMusicPerformance8
*iface
, BYTE bMIDIValue
,
1103 DMUS_CHORD_KEY
*pChord
, BYTE bPlayMode
, BYTE bChordLevel
, WORD
*pwMusicValue
)
1105 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1107 FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This
, bMIDIValue
, pChord
, bPlayMode
, bChordLevel
, pwMusicValue
);
1111 static HRESULT WINAPI
performance_MusicToMIDI(IDirectMusicPerformance8
*iface
, WORD wMusicValue
,
1112 DMUS_CHORD_KEY
*pChord
, BYTE bPlayMode
, BYTE bChordLevel
, BYTE
*pbMIDIValue
)
1114 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1116 FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This
, wMusicValue
, pChord
, bPlayMode
, bChordLevel
, pbMIDIValue
);
1120 static HRESULT WINAPI
performance_TimeToRhythm(IDirectMusicPerformance8
*iface
, MUSIC_TIME mtTime
,
1121 DMUS_TIMESIGNATURE
*pTimeSig
, WORD
*pwMeasure
, BYTE
*pbBeat
, BYTE
*pbGrid
, short *pnOffset
)
1123 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1125 FIXME("(%p, %ld, %p, %p, %p, %p, %p): stub\n", This
, mtTime
, pTimeSig
, pwMeasure
, pbBeat
, pbGrid
, pnOffset
);
1129 static HRESULT WINAPI
performance_RhythmToTime(IDirectMusicPerformance8
*iface
, WORD wMeasure
,
1130 BYTE bBeat
, BYTE bGrid
, short nOffset
, DMUS_TIMESIGNATURE
*pTimeSig
, MUSIC_TIME
*pmtTime
)
1132 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1134 FIXME("(%p, %d, %d, %d, %i, %p, %p): stub\n", This
, wMeasure
, bBeat
, bGrid
, nOffset
, pTimeSig
, pmtTime
);
1138 /* IDirectMusicPerformance8 Interface part follow: */
1139 static HRESULT WINAPI
performance_InitAudio(IDirectMusicPerformance8
*iface
, IDirectMusic
**dmusic
,
1140 IDirectSound
**dsound
, HWND hwnd
, DWORD default_path_type
, DWORD num_channels
, DWORD flags
,
1141 DMUS_AUDIOPARAMS
*params
)
1143 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1146 TRACE("(%p, %p, %p, %p, %lx, %lu, %lx, %p)\n", This
, dmusic
, dsound
, hwnd
, default_path_type
,
1147 num_channels
, flags
, params
);
1149 if (flags
) FIXME("flags parameter not used\n");
1150 if (params
) FIXME("params parameter not used\n");
1152 if (FAILED(hr
= IDirectMusicPerformance8_Init(iface
, dmusic
&& *dmusic
? dmusic
: NULL
,
1153 dsound
? *dsound
: NULL
, hwnd
)))
1156 This
->audio_paths_enabled
= TRUE
;
1157 if (default_path_type
)
1159 hr
= IDirectMusicPerformance8_CreateStandardAudioPath(iface
, default_path_type
,
1160 num_channels
, FALSE
, &This
->pDefaultPath
);
1163 IDirectMusicPerformance_CloseDown(iface
);
1168 if (dsound
&& !*dsound
) {
1169 *dsound
= This
->dsound
;
1170 IDirectSound_AddRef(*dsound
);
1172 if (dmusic
&& !*dmusic
) {
1173 *dmusic
= (IDirectMusic
*)This
->dmusic
;
1174 IDirectMusic_AddRef(*dmusic
);
1180 static HRESULT WINAPI
performance_PlaySegmentEx(IDirectMusicPerformance8
*iface
, IUnknown
*source
,
1181 WCHAR
*segment_name
, IUnknown
*transition
, DWORD segment_flags
, INT64 start_time
,
1182 IDirectMusicSegmentState
**segment_state
, IUnknown
*from
, IUnknown
*audio_path
)
1184 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1185 IDirectMusicSegmentState
*state
;
1186 IDirectMusicSegment
*segment
;
1190 FIXME("(%p, %p, %s, %p, %#lx, %I64d, %p, %p, %p): stub\n", This
, source
, debugstr_w(segment_name
),
1191 transition
, segment_flags
, start_time
, segment_state
, from
, audio_path
);
1193 /* NOTE: The time is in music time unless the DMUS_SEGF_REFTIME flag is set. */
1194 if (segment_flags
) FIXME("flags %#lx not implemented\n", segment_flags
);
1195 if (start_time
) FIXME("start_time %I64d not implemented\n", start_time
);
1197 if (FAILED(hr
= IUnknown_QueryInterface(source
, &IID_IDirectMusicSegment
, (void **)&segment
)))
1199 if (FAILED(hr
= segment_state_create(segment
, start_time
, (IDirectMusicPerformance
*)iface
, &state
)))
1201 IDirectMusicSegment_Release(segment
);
1205 hr
= IDirectMusicSegment_GetLength(segment
, &length
);
1207 hr
= performance_send_notification_pmsg(This
, start_time
, This
->notification_performance
,
1208 GUID_NOTIFICATION_PERFORMANCE
, DMUS_NOTIFICATION_MUSICSTARTED
, NULL
);
1210 hr
= performance_send_notification_pmsg(This
, start_time
, This
->notification_segment
,
1211 GUID_NOTIFICATION_SEGMENT
, DMUS_NOTIFICATION_SEGSTART
, (IUnknown
*)state
);
1213 hr
= performance_send_dirty_pmsg(This
, start_time
);
1216 hr
= segment_state_play(state
, (IDirectMusicPerformance
*)iface
);
1219 hr
= performance_send_notification_pmsg(This
, start_time
+ length
, This
->notification_segment
,
1220 GUID_NOTIFICATION_SEGMENT
, DMUS_NOTIFICATION_SEGEND
, (IUnknown
*)state
);
1222 hr
= performance_send_notification_pmsg(This
, start_time
+ length
, This
->notification_segment
,
1223 GUID_NOTIFICATION_SEGMENT
, DMUS_NOTIFICATION_SEGALMOSTEND
, (IUnknown
*)state
);
1225 hr
= performance_send_dirty_pmsg(This
, start_time
+ length
);
1227 hr
= performance_send_notification_pmsg(This
, start_time
+ length
, This
->notification_performance
,
1228 GUID_NOTIFICATION_PERFORMANCE
, DMUS_NOTIFICATION_MUSICSTOPPED
, NULL
);
1230 if (SUCCEEDED(hr
) && segment_state
)
1232 *segment_state
= state
;
1233 IDirectMusicSegmentState_AddRef(state
);
1236 IDirectMusicSegmentState_Release(state
);
1237 IDirectMusicSegment_Release(segment
);
1241 static HRESULT WINAPI
performance_StopEx(IDirectMusicPerformance8
*iface
, IUnknown
*pObjectToStop
,
1242 __int64 i64StopTime
, DWORD dwFlags
)
1244 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1246 FIXME("(%p, %p, 0x%s, %ld): stub\n", This
, pObjectToStop
,
1247 wine_dbgstr_longlong(i64StopTime
), dwFlags
);
1251 static HRESULT WINAPI
performance_ClonePMsg(IDirectMusicPerformance8
*iface
, DMUS_PMSG
*msg
, DMUS_PMSG
**clone
)
1253 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1256 TRACE("(%p, %p, %p)\n", This
, msg
, clone
);
1258 if (!msg
|| !clone
) return E_POINTER
;
1259 if (FAILED(hr
= IDirectMusicPerformance8_AllocPMsg(iface
, msg
->dwSize
, clone
))) return hr
;
1261 memcpy(*clone
, msg
, msg
->dwSize
);
1262 if (msg
->pTool
) IDirectMusicTool_AddRef(msg
->pTool
);
1263 if (msg
->pGraph
) IDirectMusicGraph_AddRef(msg
->pGraph
);
1264 if (msg
->punkUser
) IUnknown_AddRef(msg
->punkUser
);
1269 static HRESULT WINAPI
performance_CreateAudioPath(IDirectMusicPerformance8
*iface
,
1270 IUnknown
*pSourceConfig
, BOOL fActivate
, IDirectMusicAudioPath
**ret_iface
)
1272 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1273 IDirectMusicAudioPath
*pPath
;
1275 FIXME("(%p, %p, %d, %p): stub\n", This
, pSourceConfig
, fActivate
, ret_iface
);
1277 if (!ret_iface
) return E_POINTER
;
1278 if (!This
->audio_paths_enabled
) return DMUS_E_AUDIOPATH_INACTIVE
;
1280 create_dmaudiopath(&IID_IDirectMusicAudioPath
, (void **)&pPath
);
1281 set_audiopath_perf_pointer(pPath
, iface
);
1285 return IDirectMusicAudioPath_Activate(*ret_iface
, fActivate
);
1288 static HRESULT WINAPI
performance_CreateStandardAudioPath(IDirectMusicPerformance8
*iface
,
1289 DWORD dwType
, DWORD pchannel_count
, BOOL fActivate
, IDirectMusicAudioPath
**ret_iface
)
1291 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1292 IDirectMusicAudioPath
*pPath
;
1294 WAVEFORMATEX format
;
1295 DMUS_PORTPARAMS params
= {0};
1296 IDirectSoundBuffer
*buffer
, *primary_buffer
;
1299 FIXME("(%p)->(%ld, %ld, %d, %p): semi-stub\n", This
, dwType
, pchannel_count
, fActivate
, ret_iface
);
1301 if (!ret_iface
) return E_POINTER
;
1302 if (!This
->audio_paths_enabled
) return DMUS_E_AUDIOPATH_INACTIVE
;
1306 /* Secondary buffer description */
1307 memset(&format
, 0, sizeof(format
));
1308 format
.wFormatTag
= WAVE_FORMAT_PCM
;
1309 format
.nChannels
= 1;
1310 format
.nSamplesPerSec
= 44000;
1311 format
.nAvgBytesPerSec
= 44000*2;
1312 format
.nBlockAlign
= 2;
1313 format
.wBitsPerSample
= 16;
1316 memset(&desc
, 0, sizeof(desc
));
1317 desc
.dwSize
= sizeof(desc
);
1318 desc
.dwFlags
= DSBCAPS_CTRLFX
| DSBCAPS_CTRLVOLUME
| DSBCAPS_GLOBALFOCUS
;
1319 desc
.dwBufferBytes
= DSBSIZE_MIN
;
1320 desc
.dwReserved
= 0;
1321 desc
.lpwfxFormat
= &format
;
1322 desc
.guid3DAlgorithm
= GUID_NULL
;
1325 case DMUS_APATH_DYNAMIC_3D
:
1326 desc
.dwFlags
|= DSBCAPS_CTRL3D
| DSBCAPS_CTRLFREQUENCY
| DSBCAPS_MUTE3DATMAXDISTANCE
;
1328 case DMUS_APATH_DYNAMIC_MONO
:
1329 desc
.dwFlags
|= DSBCAPS_CTRLPAN
| DSBCAPS_CTRLFREQUENCY
;
1331 case DMUS_APATH_SHARED_STEREOPLUSREVERB
:
1332 /* normally we have to create 2 buffers (one for music other for reverb)
1333 * in this case. See msdn
1335 case DMUS_APATH_DYNAMIC_STEREO
:
1336 desc
.dwFlags
|= DSBCAPS_CTRLPAN
| DSBCAPS_CTRLFREQUENCY
;
1337 format
.nChannels
= 2;
1338 format
.nBlockAlign
*= 2;
1339 format
.nAvgBytesPerSec
*=2;
1342 return E_INVALIDARG
;
1346 params
.dwSize
= sizeof(params
);
1347 params
.dwValidParams
= DMUS_PORTPARAMS_CHANNELGROUPS
| DMUS_PORTPARAMS_AUDIOCHANNELS
;
1348 params
.dwChannelGroups
= (pchannel_count
+ 15) / 16;
1349 params
.dwAudioChannels
= format
.nChannels
;
1350 if (FAILED(hr
= perf_dmport_create(This
, ¶ms
)))
1353 hr
= IDirectSound_CreateSoundBuffer(This
->dsound
, &desc
, &buffer
, NULL
);
1355 return DSERR_BUFFERLOST
;
1357 /* Update description for creating primary buffer */
1358 desc
.dwFlags
|= DSBCAPS_PRIMARYBUFFER
;
1359 desc
.dwFlags
&= ~DSBCAPS_CTRLFX
;
1360 desc
.dwBufferBytes
= 0;
1361 desc
.lpwfxFormat
= NULL
;
1363 hr
= IDirectSound_CreateSoundBuffer(This
->dsound
, &desc
, &primary_buffer
, NULL
);
1365 IDirectSoundBuffer_Release(buffer
);
1366 return DSERR_BUFFERLOST
;
1369 create_dmaudiopath(&IID_IDirectMusicAudioPath
, (void**)&pPath
);
1370 set_audiopath_perf_pointer(pPath
, iface
);
1371 set_audiopath_dsound_buffer(pPath
, buffer
);
1372 set_audiopath_primary_dsound_buffer(pPath
, primary_buffer
);
1375 TRACE(" returning IDirectMusicAudioPath interface at %p.\n", *ret_iface
);
1376 return IDirectMusicAudioPath_Activate(*ret_iface
, fActivate
);
1379 static HRESULT WINAPI
performance_SetDefaultAudioPath(IDirectMusicPerformance8
*iface
, IDirectMusicAudioPath
*audio_path
)
1381 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1383 FIXME("(%p, %p): semi-stub\n", This
, audio_path
);
1385 if (!This
->audio_paths_enabled
) return DMUS_E_AUDIOPATH_INACTIVE
;
1387 if (This
->pDefaultPath
) IDirectMusicAudioPath_Release(This
->pDefaultPath
);
1388 if ((This
->pDefaultPath
= audio_path
))
1390 IDirectMusicAudioPath_AddRef(This
->pDefaultPath
);
1391 set_audiopath_perf_pointer(This
->pDefaultPath
, iface
);
1397 static HRESULT WINAPI
performance_GetDefaultAudioPath(IDirectMusicPerformance8
*iface
,
1398 IDirectMusicAudioPath
**ret_iface
)
1400 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1402 FIXME("(%p, %p): semi-stub (%p)\n", This
, ret_iface
, This
->pDefaultPath
);
1404 if (!ret_iface
) return E_POINTER
;
1405 if (!This
->audio_paths_enabled
) return DMUS_E_AUDIOPATH_INACTIVE
;
1407 if ((*ret_iface
= This
->pDefaultPath
)) IDirectMusicAudioPath_AddRef(*ret_iface
);
1412 static HRESULT WINAPI
performance_GetParamEx(IDirectMusicPerformance8
*iface
, REFGUID rguidType
, DWORD dwTrackID
,
1413 DWORD dwGroupBits
, DWORD dwIndex
, MUSIC_TIME mtTime
, MUSIC_TIME
*pmtNext
, void *pParam
)
1415 struct performance
*This
= impl_from_IDirectMusicPerformance8(iface
);
1417 FIXME("(%p, %s, %ld, %ld, %ld, %ld, %p, %p): stub\n", This
, debugstr_dmguid(rguidType
), dwTrackID
, dwGroupBits
, dwIndex
, mtTime
, pmtNext
, pParam
);
1422 static const IDirectMusicPerformance8Vtbl performance_vtbl
=
1424 performance_QueryInterface
,
1426 performance_Release
,
1428 performance_PlaySegment
,
1430 performance_GetSegmentState
,
1431 performance_SetPrepareTime
,
1432 performance_GetPrepareTime
,
1433 performance_SetBumperLength
,
1434 performance_GetBumperLength
,
1435 performance_SendPMsg
,
1436 performance_MusicToReferenceTime
,
1437 performance_ReferenceToMusicTime
,
1438 performance_IsPlaying
,
1439 performance_GetTime
,
1440 performance_AllocPMsg
,
1441 performance_FreePMsg
,
1442 performance_GetGraph
,
1443 performance_SetGraph
,
1444 performance_SetNotificationHandle
,
1445 performance_GetNotificationPMsg
,
1446 performance_AddNotificationType
,
1447 performance_RemoveNotificationType
,
1448 performance_AddPort
,
1449 performance_RemovePort
,
1450 performance_AssignPChannelBlock
,
1451 performance_AssignPChannel
,
1452 performance_PChannelInfo
,
1453 performance_DownloadInstrument
,
1454 performance_Invalidate
,
1455 performance_GetParam
,
1456 performance_SetParam
,
1457 performance_GetGlobalParam
,
1458 performance_SetGlobalParam
,
1459 performance_GetLatencyTime
,
1460 performance_GetQueueTime
,
1461 performance_AdjustTime
,
1462 performance_CloseDown
,
1463 performance_GetResolvedTime
,
1464 performance_MIDIToMusic
,
1465 performance_MusicToMIDI
,
1466 performance_TimeToRhythm
,
1467 performance_RhythmToTime
,
1468 performance_InitAudio
,
1469 performance_PlaySegmentEx
,
1471 performance_ClonePMsg
,
1472 performance_CreateAudioPath
,
1473 performance_CreateStandardAudioPath
,
1474 performance_SetDefaultAudioPath
,
1475 performance_GetDefaultAudioPath
,
1476 performance_GetParamEx
,
1479 static inline struct performance
*impl_from_IDirectMusicGraph(IDirectMusicGraph
*iface
)
1481 return CONTAINING_RECORD(iface
, struct performance
, IDirectMusicGraph_iface
);
1484 static HRESULT WINAPI
performance_graph_QueryInterface(IDirectMusicGraph
*iface
, REFIID riid
, void **ret_iface
)
1486 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1487 return IDirectMusicPerformance8_QueryInterface(&This
->IDirectMusicPerformance8_iface
, riid
, ret_iface
);
1490 static ULONG WINAPI
performance_graph_AddRef(IDirectMusicGraph
*iface
)
1492 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1493 return IDirectMusicPerformance8_AddRef(&This
->IDirectMusicPerformance8_iface
);
1496 static ULONG WINAPI
performance_graph_Release(IDirectMusicGraph
*iface
)
1498 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1499 return IDirectMusicPerformance8_Release(&This
->IDirectMusicPerformance8_iface
);
1502 static HRESULT WINAPI
performance_graph_StampPMsg(IDirectMusicGraph
*iface
, DMUS_PMSG
*msg
)
1504 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1507 TRACE("(%p, %p)\n", This
, msg
);
1509 if (!msg
) return E_POINTER
;
1511 /* FIXME: Implement segment and audio path graphs support */
1512 if (!This
->pToolGraph
) hr
= DMUS_S_LAST_TOOL
;
1513 else if (FAILED(hr
= IDirectMusicGraph_StampPMsg(This
->pToolGraph
, msg
))) return hr
;
1517 IDirectMusicTool_Release(msg
->pGraph
);
1521 if (hr
== DMUS_S_LAST_TOOL
)
1523 const DWORD delivery_flags
= DMUS_PMSGF_TOOL_IMMEDIATE
| DMUS_PMSGF_TOOL_QUEUE
| DMUS_PMSGF_TOOL_ATTIME
;
1524 msg
->dwFlags
&= ~delivery_flags
;
1525 msg
->dwFlags
|= DMUS_PMSGF_TOOL_QUEUE
;
1527 if (msg
->pTool
) IDirectMusicTool_Release(msg
->pTool
);
1528 msg
->pTool
= &This
->IDirectMusicTool_iface
;
1529 IDirectMusicTool_AddRef(msg
->pTool
);
1535 msg
->pGraph
= &This
->IDirectMusicGraph_iface
;
1536 IDirectMusicTool_AddRef(msg
->pGraph
);
1542 static HRESULT WINAPI
performance_graph_InsertTool(IDirectMusicGraph
*iface
, IDirectMusicTool
*tool
,
1543 DWORD
*channels
, DWORD channels_count
, LONG index
)
1545 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1546 TRACE("(%p, %p, %p, %lu, %ld)\n", This
, tool
, channels
, channels_count
, index
);
1550 static HRESULT WINAPI
performance_graph_GetTool(IDirectMusicGraph
*iface
, DWORD index
, IDirectMusicTool
**tool
)
1552 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1553 TRACE("(%p, %lu, %p)\n", This
, index
, tool
);
1557 static HRESULT WINAPI
performance_graph_RemoveTool(IDirectMusicGraph
*iface
, IDirectMusicTool
*tool
)
1559 struct performance
*This
= impl_from_IDirectMusicGraph(iface
);
1560 TRACE("(%p, %p)\n", This
, tool
);
1564 static const IDirectMusicGraphVtbl performance_graph_vtbl
=
1566 performance_graph_QueryInterface
,
1567 performance_graph_AddRef
,
1568 performance_graph_Release
,
1569 performance_graph_StampPMsg
,
1570 performance_graph_InsertTool
,
1571 performance_graph_GetTool
,
1572 performance_graph_RemoveTool
,
1575 static inline struct performance
*impl_from_IDirectMusicTool(IDirectMusicTool
*iface
)
1577 return CONTAINING_RECORD(iface
, struct performance
, IDirectMusicTool_iface
);
1580 static HRESULT WINAPI
performance_tool_QueryInterface(IDirectMusicTool
*iface
, REFIID riid
, void **ret_iface
)
1582 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1583 return IDirectMusicPerformance8_QueryInterface(&This
->IDirectMusicPerformance8_iface
, riid
, ret_iface
);
1586 static ULONG WINAPI
performance_tool_AddRef(IDirectMusicTool
*iface
)
1588 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1589 return IDirectMusicPerformance8_AddRef(&This
->IDirectMusicPerformance8_iface
);
1592 static ULONG WINAPI
performance_tool_Release(IDirectMusicTool
*iface
)
1594 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1595 return IDirectMusicPerformance8_Release(&This
->IDirectMusicPerformance8_iface
);
1598 static HRESULT WINAPI
performance_tool_Init(IDirectMusicTool
*iface
, IDirectMusicGraph
*graph
)
1600 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1601 TRACE("(%p, %p)\n", This
, graph
);
1605 static HRESULT WINAPI
performance_tool_GetMsgDeliveryType(IDirectMusicTool
*iface
, DWORD
*type
)
1607 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1608 TRACE("(%p, %p)\n", This
, type
);
1609 *type
= DMUS_PMSGF_TOOL_IMMEDIATE
;
1613 static HRESULT WINAPI
performance_tool_GetMediaTypeArraySize(IDirectMusicTool
*iface
, DWORD
*size
)
1615 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1616 TRACE("(%p, %p)\n", This
, size
);
1621 static HRESULT WINAPI
performance_tool_GetMediaTypes(IDirectMusicTool
*iface
, DWORD
**types
, DWORD size
)
1623 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1624 TRACE("(%p, %p, %lu)\n", This
, types
, size
);
1628 static HRESULT
performance_send_midi_pmsg(struct performance
*This
, DMUS_PMSG
*msg
, UINT flags
,
1629 BYTE status
, BYTE byte1
, BYTE byte2
)
1631 IDirectMusicPerformance8
*performance
= &This
->IDirectMusicPerformance8_iface
;
1632 DMUS_MIDI_PMSG
*midi
;
1635 if (FAILED(hr
= IDirectMusicPerformance8_AllocPMsg(performance
, sizeof(*midi
),
1636 (DMUS_PMSG
**)&midi
)))
1639 if (flags
& DMUS_PMSGF_REFTIME
) midi
->rtTime
= msg
->rtTime
;
1640 if (flags
& DMUS_PMSGF_MUSICTIME
) midi
->mtTime
= msg
->mtTime
;
1641 midi
->dwFlags
= flags
;
1642 midi
->dwPChannel
= msg
->dwPChannel
;
1643 midi
->dwVirtualTrackID
= msg
->dwVirtualTrackID
;
1644 midi
->dwVoiceID
= msg
->dwVoiceID
;
1645 midi
->dwGroupID
= msg
->dwGroupID
;
1646 midi
->dwType
= DMUS_PMSGT_MIDI
;
1647 midi
->bStatus
= status
;
1648 midi
->bByte1
= byte1
;
1649 midi
->bByte2
= byte2
;
1651 if (FAILED(hr
= IDirectMusicPerformance8_SendPMsg(performance
, (DMUS_PMSG
*)midi
)))
1652 IDirectMusicPerformance8_FreePMsg(performance
, (DMUS_PMSG
*)midi
);
1657 static HRESULT WINAPI
performance_tool_ProcessPMsg(IDirectMusicTool
*iface
,
1658 IDirectMusicPerformance
*performance
, DMUS_PMSG
*msg
)
1660 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1661 struct message
*message
= message_from_DMUS_PMSG(msg
);
1664 TRACE("(%p, %p, %p)\n", This
, performance
, msg
);
1666 switch (msg
->dwType
)
1668 case DMUS_PMSGT_MIDI
:
1670 static const UINT event_size
= sizeof(DMUS_EVENTHEADER
) + sizeof(DWORD
);
1671 DMUS_BUFFERDESC desc
= {.dwSize
= sizeof(desc
), .cbBuffer
= 2 * event_size
};
1672 DMUS_MIDI_PMSG
*midi
= (DMUS_MIDI_PMSG
*)msg
;
1673 REFERENCE_TIME latency_time
;
1674 IDirectMusicBuffer
*buffer
;
1675 IDirectMusicPort
*port
;
1676 DWORD group
, channel
;
1679 if (FAILED(hr
= IDirectMusicPerformance_PChannelInfo(performance
, msg
->dwPChannel
,
1680 &port
, &group
, &channel
)))
1682 WARN("Failed to get message port, hr %#lx\n", hr
);
1685 performance_update_latency_time(This
, port
, &latency_time
);
1688 value
|= (UINT
)midi
->bStatus
;
1689 value
|= (UINT
)midi
->bByte1
<< 8;
1690 value
|= (UINT
)midi
->bByte2
<< 16;
1692 if (SUCCEEDED(hr
= IDirectMusic_CreateMusicBuffer(This
->dmusic
, &desc
, &buffer
, NULL
)))
1694 if (msg
->rtTime
== -1) msg
->rtTime
= latency_time
;
1695 hr
= IDirectMusicBuffer_PackStructured(buffer
, msg
->rtTime
, group
, value
);
1696 if (SUCCEEDED(hr
)) hr
= IDirectMusicPort_PlayBuffer(port
, buffer
);
1697 IDirectMusicBuffer_Release(buffer
);
1700 IDirectMusicPort_Release(port
);
1704 case DMUS_PMSGT_NOTE
:
1706 DMUS_NOTE_PMSG
*note
= (DMUS_NOTE_PMSG
*)msg
;
1708 msg
->mtTime
+= note
->nOffset
;
1709 if (FAILED(hr
= performance_send_midi_pmsg(This
, msg
, DMUS_PMSGF_REFTIME
| DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_IMMEDIATE
,
1710 MIDI_NOTE_ON
, note
->bMidiValue
, note
->bVelocity
)))
1711 WARN("Failed to translate message to MIDI, hr %#lx\n", hr
);
1713 msg
->mtTime
+= note
->mtDuration
;
1714 if (FAILED(hr
= performance_send_midi_pmsg(This
, msg
, DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_QUEUE
,
1715 MIDI_NOTE_OFF
, note
->bMidiValue
, 0)))
1716 WARN("Failed to translate message to MIDI, hr %#lx\n", hr
);
1721 case DMUS_PMSGT_CURVE
:
1723 DMUS_CURVE_PMSG
*curve
= (DMUS_CURVE_PMSG
*)msg
;
1725 msg
->mtTime
+= curve
->nOffset
;
1726 switch (curve
->dwType
)
1728 case DMUS_CURVET_CCCURVE
:
1729 if (FAILED(hr
= performance_send_midi_pmsg(This
, msg
, DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_IMMEDIATE
,
1730 MIDI_CONTROL_CHANGE
, curve
->bCCData
, curve
->nStartValue
)))
1731 WARN("Failed to translate message to MIDI, hr %#lx\n", hr
);
1733 case DMUS_CURVET_RPNCURVE
:
1734 case DMUS_CURVET_NRPNCURVE
:
1735 FIXME("Unhandled curve type %#lx\n", curve
->dwType
);
1742 case DMUS_PMSGT_PATCH
:
1744 DMUS_PATCH_PMSG
*patch
= (DMUS_PATCH_PMSG
*)msg
;
1746 if (FAILED(hr
= performance_send_midi_pmsg(This
, msg
, DMUS_PMSGF_REFTIME
| DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_IMMEDIATE
,
1747 MIDI_CONTROL_CHANGE
, MIDI_CC_BANK_MSB
, patch
->byMSB
)))
1748 WARN("Failed to translate message to MIDI, hr %#lx\n", hr
);
1750 if (FAILED(hr
= performance_send_midi_pmsg(This
, msg
, DMUS_PMSGF_REFTIME
| DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_IMMEDIATE
,
1751 MIDI_CONTROL_CHANGE
, MIDI_CC_BANK_LSB
, patch
->byLSB
)))
1752 WARN("Failed to translate message to MIDI, hr %#lx\n", hr
);
1754 if (FAILED(hr
= performance_send_midi_pmsg(This
, msg
, DMUS_PMSGF_REFTIME
| DMUS_PMSGF_MUSICTIME
| DMUS_PMSGF_TOOL_IMMEDIATE
,
1755 MIDI_PROGRAM_CHANGE
, patch
->byInstrument
, 0)))
1756 WARN("Failed to translate message to MIDI, hr %#lx\n", hr
);
1761 case DMUS_PMSGT_NOTIFICATION
:
1763 DMUS_NOTIFICATION_PMSG
*notif
= (DMUS_NOTIFICATION_PMSG
*)msg
;
1764 struct message
*previous
;
1765 BOOL enabled
= FALSE
;
1767 if (IsEqualGUID(¬if
->guidNotificationType
, &GUID_NOTIFICATION_SEGMENT
)
1768 && notif
->dwNotificationOption
== DMUS_NOTIFICATION_SEGEND
)
1770 if (FAILED(hr
= segment_state_end_play((IDirectMusicSegmentState
*)notif
->punkUser
, performance
)))
1771 WARN("Failed to end segment state %p, hr %#lx\n", notif
->punkUser
, hr
);
1774 if (IsEqualGUID(¬if
->guidNotificationType
, &GUID_NOTIFICATION_PERFORMANCE
))
1775 enabled
= This
->notification_performance
;
1776 if (IsEqualGUID(¬if
->guidNotificationType
, &GUID_NOTIFICATION_SEGMENT
))
1777 enabled
= This
->notification_segment
;
1778 if (!enabled
) return DMUS_S_FREE
;
1780 list_add_tail(&This
->notifications
, &message
->entry
);
1782 /* discard old notification messages */
1785 previous
= LIST_ENTRY(list_head(&This
->notifications
), struct message
, entry
);
1786 if (This
->notification_timeout
<= 0) break; /* negative values may be used to keep everything */
1787 if (message
->msg
.rtTime
- previous
->msg
.rtTime
<= This
->notification_timeout
) break;
1788 list_remove(&previous
->entry
);
1789 list_init(&previous
->entry
);
1790 } while (SUCCEEDED(hr
= IDirectMusicPerformance_FreePMsg(performance
, &previous
->msg
)));
1792 SetEvent(This
->notification_event
);
1796 case DMUS_PMSGT_WAVE
:
1797 if (FAILED(hr
= IDirectSoundBuffer_Play((IDirectSoundBuffer
*)msg
->punkUser
, 0, 0, 0)))
1798 WARN("Failed to play wave buffer, hr %#lx\n", hr
);
1802 FIXME("Unhandled message type %#lx\n", msg
->dwType
);
1809 static HRESULT WINAPI
performance_tool_Flush(IDirectMusicTool
*iface
,
1810 IDirectMusicPerformance
*performance
, DMUS_PMSG
*msg
, REFERENCE_TIME time
)
1812 struct performance
*This
= impl_from_IDirectMusicTool(iface
);
1813 FIXME("(%p, %p, %p, %I64d): stub\n", This
, performance
, msg
, time
);
1817 static const IDirectMusicToolVtbl performance_tool_vtbl
=
1819 performance_tool_QueryInterface
,
1820 performance_tool_AddRef
,
1821 performance_tool_Release
,
1822 performance_tool_Init
,
1823 performance_tool_GetMsgDeliveryType
,
1824 performance_tool_GetMediaTypeArraySize
,
1825 performance_tool_GetMediaTypes
,
1826 performance_tool_ProcessPMsg
,
1827 performance_tool_Flush
,
1830 /* for ClassFactory */
1831 HRESULT
create_dmperformance(REFIID iid
, void **ret_iface
)
1833 struct performance
*obj
;
1836 TRACE("(%s, %p)\n", debugstr_guid(iid
), ret_iface
);
1839 if (!(obj
= calloc(1, sizeof(*obj
)))) return E_OUTOFMEMORY
;
1840 obj
->IDirectMusicPerformance8_iface
.lpVtbl
= &performance_vtbl
;
1841 obj
->IDirectMusicGraph_iface
.lpVtbl
= &performance_graph_vtbl
;
1842 obj
->IDirectMusicTool_iface
.lpVtbl
= &performance_tool_vtbl
;
1845 obj
->pDefaultPath
= NULL
;
1846 InitializeCriticalSection(&obj
->safe
);
1847 obj
->safe
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": performance->safe");
1848 wine_rb_init(&obj
->pchannels
, pchannel_block_compare
);
1850 list_init(&obj
->messages
);
1851 list_init(&obj
->notifications
);
1853 obj
->latency_offset
= 50;
1854 obj
->dwBumperLength
= 50; /* 50 ms default */
1855 obj
->dwPrepareTime
= 1000; /* 1000 ms default */
1857 hr
= IDirectMusicPerformance8_QueryInterface(&obj
->IDirectMusicPerformance8_iface
, iid
, ret_iface
);
1858 IDirectMusicPerformance_Release(&obj
->IDirectMusicPerformance8_iface
);
1862 static inline struct performance
*unsafe_impl_from_IDirectMusicPerformance8(IDirectMusicPerformance8
*iface
)
1864 if (iface
->lpVtbl
!= &performance_vtbl
) return NULL
;
1865 return CONTAINING_RECORD(iface
, struct performance
, IDirectMusicPerformance8_iface
);
1868 HRESULT
performance_get_dsound(IDirectMusicPerformance8
*iface
, IDirectSound
**dsound
)
1870 struct performance
*This
= unsafe_impl_from_IDirectMusicPerformance8(iface
);
1871 if (!This
|| !(*dsound
= This
->dsound
)) return E_FAIL
;
1872 IDirectSound_AddRef(*dsound
);