dmime: The soft synth doesn't supports sharing the channel groups.
[wine.git] / dlls / dmime / performance.c
blob58d16de234da8697a7939d770e50bb54f2f3a59d
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 "wine/heap.h"
23 #include "wine/rbtree.h"
24 #include "dmobject.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dmime);
28 struct pchannel_block {
29 DWORD block_num; /* Block 0 is PChannels 0-15, Block 1 is PChannels 16-31, etc */
30 struct {
31 DWORD channel; /* MIDI channel */
32 DWORD group; /* MIDI group */
33 IDirectMusicPort *port;
34 } pchannel[16];
35 struct wine_rb_entry entry;
38 typedef struct IDirectMusicPerformance8Impl {
39 IDirectMusicPerformance8 IDirectMusicPerformance8_iface;
40 LONG ref;
41 IDirectMusic8 *dmusic;
42 IDirectSound *dsound;
43 IDirectMusicGraph *pToolGraph;
44 DMUS_AUDIOPARAMS params;
45 BOOL fAutoDownload;
46 char cMasterGrooveLevel;
47 float fMasterTempo;
48 long lMasterVolume;
49 /* performance channels */
50 struct wine_rb_tree pchannels;
51 /* IDirectMusicPerformance8Impl fields */
52 IDirectMusicAudioPath *pDefaultPath;
53 HANDLE hNotification;
54 REFERENCE_TIME rtMinimum;
55 REFERENCE_TIME rtLatencyTime;
56 DWORD dwBumperLength;
57 DWORD dwPrepareTime;
58 /** Message Processing */
59 HANDLE procThread;
60 DWORD procThreadId;
61 REFERENCE_TIME procThreadStartTime;
62 BOOL procThreadTicStarted;
63 CRITICAL_SECTION safe;
64 struct DMUS_PMSGItem *head;
65 struct DMUS_PMSGItem *imm_head;
66 } IDirectMusicPerformance8Impl;
68 typedef struct DMUS_PMSGItem DMUS_PMSGItem;
69 struct DMUS_PMSGItem {
70 DMUS_PMSGItem* next;
71 DMUS_PMSGItem* prev;
73 REFERENCE_TIME rtItemTime;
74 BOOL bInUse;
75 DWORD cb;
76 DMUS_PMSG pMsg;
79 #define DMUS_PMSGToItem(pMSG) ((DMUS_PMSGItem*) (((unsigned char*) pPMSG) - offsetof(DMUS_PMSGItem, pMsg)))
80 #define DMUS_ItemToPMSG(pItem) (&(pItem->pMsg))
81 #define DMUS_ItemRemoveFromQueue(This,pItem) \
83 if (pItem->prev) pItem->prev->next = pItem->next;\
84 if (pItem->next) pItem->next->prev = pItem->prev;\
85 if (This->head == pItem) This->head = pItem->next;\
86 if (This->imm_head == pItem) This->imm_head = pItem->next;\
87 pItem->bInUse = FALSE;\
90 #define PROCESSMSG_START (WM_APP + 0)
91 #define PROCESSMSG_EXIT (WM_APP + 1)
92 #define PROCESSMSG_REMOVE (WM_APP + 2)
93 #define PROCESSMSG_ADD (WM_APP + 4)
96 static DMUS_PMSGItem* ProceedMsg(IDirectMusicPerformance8Impl* This, DMUS_PMSGItem* cur) {
97 if (cur->pMsg.dwType == DMUS_PMSGT_NOTIFICATION) {
98 SetEvent(This->hNotification);
100 DMUS_ItemRemoveFromQueue(This, cur);
101 switch (cur->pMsg.dwType) {
102 case DMUS_PMSGT_WAVE:
103 case DMUS_PMSGT_TEMPO:
104 case DMUS_PMSGT_STOP:
105 default:
106 FIXME("Unhandled PMsg Type: 0x%x\n", cur->pMsg.dwType);
107 break;
109 return cur;
112 static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) {
113 IDirectMusicPerformance8Impl* This = lpParam;
114 DWORD timeOut = INFINITE;
115 MSG msg;
116 HRESULT hr;
117 REFERENCE_TIME rtCurTime;
118 DMUS_PMSGItem* it = NULL;
119 DMUS_PMSGItem* cur = NULL;
120 DMUS_PMSGItem* it_next = NULL;
122 while (TRUE) {
123 DWORD dwDec = This->rtLatencyTime + This->dwBumperLength;
125 if (timeOut > 0) MsgWaitForMultipleObjects(0, NULL, FALSE, timeOut, QS_POSTMESSAGE|QS_SENDMESSAGE|QS_TIMER);
126 timeOut = INFINITE;
128 EnterCriticalSection(&This->safe);
129 hr = IDirectMusicPerformance8_GetTime(&This->IDirectMusicPerformance8_iface, &rtCurTime, NULL);
130 if (FAILED(hr)) {
131 goto outrefresh;
134 for (it = This->imm_head; NULL != it; ) {
135 it_next = it->next;
136 cur = ProceedMsg(This, it);
137 HeapFree(GetProcessHeap(), 0, cur);
138 it = it_next;
141 for (it = This->head; NULL != it && it->rtItemTime < rtCurTime + dwDec; ) {
142 it_next = it->next;
143 cur = ProceedMsg(This, it);
144 HeapFree(GetProcessHeap(), 0, cur);
145 it = it_next;
147 if (NULL != it) {
148 timeOut = ( it->rtItemTime - rtCurTime ) + This->rtLatencyTime;
151 outrefresh:
152 LeaveCriticalSection(&This->safe);
154 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
155 /** if hwnd we suppose that is a windows event ... */
156 if (NULL != msg.hwnd) {
157 TranslateMessage(&msg);
158 DispatchMessageA(&msg);
159 } else {
160 switch (msg.message) {
161 case WM_QUIT:
162 case PROCESSMSG_EXIT:
163 goto outofthread;
164 case PROCESSMSG_START:
165 break;
166 case PROCESSMSG_ADD:
167 break;
168 case PROCESSMSG_REMOVE:
169 break;
170 default:
171 ERR("Unhandled message %u. Critical Path\n", msg.message);
172 break;
177 /** here we should run a little of current AudioPath */
181 outofthread:
182 TRACE("(%p): Exiting\n", This);
184 return 0;
187 static BOOL PostMessageToProcessMsgThread(IDirectMusicPerformance8Impl* This, UINT iMsg) {
188 if (FALSE == This->procThreadTicStarted && PROCESSMSG_EXIT != iMsg) {
189 BOOL res;
190 This->procThread = CreateThread(NULL, 0, ProcessMsgThread, This, 0, &This->procThreadId);
191 if (NULL == This->procThread) return FALSE;
192 SetThreadPriority(This->procThread, THREAD_PRIORITY_TIME_CRITICAL);
193 This->procThreadTicStarted = TRUE;
194 while(1) {
195 res = PostThreadMessageA(This->procThreadId, iMsg, 0, 0);
196 /* Let the thread creates its message queue (with MsgWaitForMultipleObjects call) by yielding and retrying */
197 if (!res && (GetLastError() == ERROR_INVALID_THREAD_ID))
198 Sleep(0);
199 else
200 break;
202 return res;
204 return PostThreadMessageA(This->procThreadId, iMsg, 0, 0);
207 static int pchannel_block_compare(const void *key, const struct wine_rb_entry *entry)
209 const struct pchannel_block *b = WINE_RB_ENTRY_VALUE(entry, const struct pchannel_block, entry);
211 return *(DWORD *)key - b->block_num;
214 static void pchannel_block_free(struct wine_rb_entry *entry, void *context)
216 struct pchannel_block *b = WINE_RB_ENTRY_VALUE(entry, struct pchannel_block, entry);
218 heap_free(b);
221 static struct pchannel_block *pchannel_block_set(struct wine_rb_tree *tree, DWORD block_num,
222 IDirectMusicPort *port, DWORD group, BOOL only_set_new)
224 struct pchannel_block *block;
225 struct wine_rb_entry *entry;
226 unsigned int i;
228 entry = wine_rb_get(tree, &block_num);
229 if (entry) {
230 block = WINE_RB_ENTRY_VALUE(entry, struct pchannel_block, entry);
231 if (only_set_new)
232 return block;
233 } else {
234 if (!(block = heap_alloc(sizeof(*block))))
235 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;
244 if (!entry)
245 wine_rb_put(tree, &block->block_num, &block->entry);
247 return block;
250 static inline IDirectMusicPerformance8Impl *impl_from_IDirectMusicPerformance8(IDirectMusicPerformance8 *iface)
252 return CONTAINING_RECORD(iface, IDirectMusicPerformance8Impl, IDirectMusicPerformance8_iface);
255 /* IDirectMusicPerformance8 IUnknown part: */
256 static HRESULT WINAPI IDirectMusicPerformance8Impl_QueryInterface(IDirectMusicPerformance8 *iface,
257 REFIID riid, void **ppv)
259 TRACE("(%p, %s,%p)\n", iface, debugstr_dmguid(riid), ppv);
261 if (IsEqualIID (riid, &IID_IUnknown) ||
262 IsEqualIID (riid, &IID_IDirectMusicPerformance) ||
263 IsEqualIID (riid, &IID_IDirectMusicPerformance2) ||
264 IsEqualIID (riid, &IID_IDirectMusicPerformance8)) {
265 *ppv = iface;
266 IUnknown_AddRef(iface);
267 return S_OK;
270 WARN("(%p, %s,%p): not found\n", iface, debugstr_dmguid(riid), ppv);
271 return E_NOINTERFACE;
274 static ULONG WINAPI IDirectMusicPerformance8Impl_AddRef(IDirectMusicPerformance8 *iface)
276 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
277 ULONG ref = InterlockedIncrement(&This->ref);
279 TRACE("(%p): AddRef from %d\n", This, ref - 1);
281 DMIME_LockModule();
283 return ref;
286 static ULONG WINAPI IDirectMusicPerformance8Impl_Release(IDirectMusicPerformance8 *iface)
288 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
289 ULONG ref = InterlockedDecrement(&This->ref);
291 TRACE("(%p): ReleaseRef to %d\n", This, ref);
293 if (ref == 0) {
294 wine_rb_destroy(&This->pchannels, pchannel_block_free, NULL);
295 This->safe.DebugInfo->Spare[0] = 0;
296 DeleteCriticalSection(&This->safe);
297 HeapFree(GetProcessHeap(), 0, This);
300 DMIME_UnlockModule();
302 return ref;
305 /* IDirectMusicPerformanceImpl IDirectMusicPerformance Interface part: */
306 static HRESULT WINAPI IDirectMusicPerformance8Impl_Init(IDirectMusicPerformance8 *iface,
307 IDirectMusic **dmusic, IDirectSound *dsound, HWND hwnd)
309 TRACE("(%p, %p, %p, %p)\n", iface, dmusic, dsound, hwnd);
311 return IDirectMusicPerformance8_InitAudio(iface, dmusic, dsound ? &dsound : NULL, hwnd, 0, 0,
312 0, NULL);
315 static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegment(IDirectMusicPerformance8 *iface,
316 IDirectMusicSegment *pSegment, DWORD dwFlags, __int64 i64StartTime,
317 IDirectMusicSegmentState **ppSegmentState)
319 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
321 FIXME("(%p, %p, %d, 0x%s, %p): stub\n", This, pSegment, dwFlags,
322 wine_dbgstr_longlong(i64StartTime), ppSegmentState);
323 if (ppSegmentState)
324 return create_dmsegmentstate(&IID_IDirectMusicSegmentState,(void**)ppSegmentState);
325 return S_OK;
328 static HRESULT WINAPI IDirectMusicPerformance8Impl_Stop(IDirectMusicPerformance8 *iface,
329 IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegmentState, MUSIC_TIME mtTime,
330 DWORD dwFlags)
332 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
334 FIXME("(%p, %p, %p, %d, %d): stub\n", This, pSegment, pSegmentState, mtTime, dwFlags);
335 return S_OK;
338 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetSegmentState(IDirectMusicPerformance8 *iface,
339 IDirectMusicSegmentState **ppSegmentState, MUSIC_TIME mtTime)
341 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
343 FIXME("(%p,%p, %d): stub\n", This, ppSegmentState, mtTime);
344 return S_OK;
347 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetPrepareTime(IDirectMusicPerformance8 *iface,
348 DWORD dwMilliSeconds)
350 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
352 TRACE("(%p, %d)\n", This, dwMilliSeconds);
353 This->dwPrepareTime = dwMilliSeconds;
354 return S_OK;
357 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetPrepareTime(IDirectMusicPerformance8 *iface,
358 DWORD *pdwMilliSeconds)
360 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
362 TRACE("(%p, %p)\n", This, pdwMilliSeconds);
363 if (NULL == pdwMilliSeconds) {
364 return E_POINTER;
366 *pdwMilliSeconds = This->dwPrepareTime;
367 return S_OK;
370 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetBumperLength(IDirectMusicPerformance8 *iface,
371 DWORD dwMilliSeconds)
373 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
375 TRACE("(%p, %d)\n", This, dwMilliSeconds);
376 This->dwBumperLength = dwMilliSeconds;
377 return S_OK;
380 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetBumperLength(IDirectMusicPerformance8 *iface,
381 DWORD *pdwMilliSeconds)
383 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
385 TRACE("(%p, %p)\n", This, pdwMilliSeconds);
386 if (NULL == pdwMilliSeconds) {
387 return E_POINTER;
389 *pdwMilliSeconds = This->dwBumperLength;
390 return S_OK;
393 static HRESULT WINAPI IDirectMusicPerformance8Impl_SendPMsg(IDirectMusicPerformance8 *iface,
394 DMUS_PMSG *pPMSG)
396 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
397 DMUS_PMSGItem* pItem = NULL;
398 DMUS_PMSGItem* it = NULL;
399 DMUS_PMSGItem* prev_it = NULL;
400 DMUS_PMSGItem** queue = NULL;
402 FIXME("(%p, %p): stub\n", This, pPMSG);
404 if (NULL == pPMSG) {
405 return E_POINTER;
407 pItem = DMUS_PMSGToItem(pPMSG);
408 if (pItem->bInUse) {
409 return DMUS_E_ALREADY_SENT;
412 /* TODO: Valid Flags */
413 /* TODO: DMUS_PMSGF_MUSICTIME */
414 pItem->rtItemTime = pPMSG->rtTime;
416 if (pPMSG->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) {
417 queue = &This->imm_head;
418 } else {
419 queue = &This->head;
422 EnterCriticalSection(&This->safe);
423 for (it = *queue; NULL != it && it->rtItemTime < pItem->rtItemTime; it = it->next) {
424 prev_it = it;
426 if (NULL == prev_it) {
427 pItem->prev = NULL;
428 if (NULL != *queue) pItem->next = (*queue)->next;
429 /*assert( NULL == pItem->next->prev );*/
430 if (NULL != pItem->next) pItem->next->prev = pItem;
431 *queue = pItem;
432 } else {
433 pItem->prev = prev_it;
434 pItem->next = prev_it->next;
435 prev_it->next = pItem;
436 if (NULL != pItem->next) pItem->next->prev = pItem;
438 LeaveCriticalSection(&This->safe);
440 /** now in use, prevent from stupid Frees */
441 pItem->bInUse = TRUE;
442 return S_OK;
445 static HRESULT WINAPI IDirectMusicPerformance8Impl_MusicToReferenceTime(IDirectMusicPerformance8 *iface,
446 MUSIC_TIME mtTime, REFERENCE_TIME *prtTime)
448 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
450 FIXME("(%p, %d, %p): stub\n", This, mtTime, prtTime);
451 return S_OK;
454 static HRESULT WINAPI IDirectMusicPerformance8Impl_ReferenceToMusicTime(IDirectMusicPerformance8 *iface,
455 REFERENCE_TIME rtTime, MUSIC_TIME *pmtTime)
457 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
459 FIXME("(%p, 0x%s, %p): stub\n", This, wine_dbgstr_longlong(rtTime), pmtTime);
460 return S_OK;
463 static HRESULT WINAPI IDirectMusicPerformance8Impl_IsPlaying(IDirectMusicPerformance8 *iface,
464 IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegState)
466 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
468 FIXME("(%p, %p, %p): stub\n", This, pSegment, pSegState);
469 return S_FALSE;
472 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetTime(IDirectMusicPerformance8 *iface,
473 REFERENCE_TIME *prtNow, MUSIC_TIME *pmtNow)
475 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
476 HRESULT hr = S_OK;
477 REFERENCE_TIME rtCur = 0;
479 /*TRACE("(%p, %p, %p)\n", This, prtNow, pmtNow); */
480 if (This->procThreadTicStarted) {
481 rtCur = ((REFERENCE_TIME) GetTickCount() * 10000) - This->procThreadStartTime;
482 } else {
483 /*return DMUS_E_NO_MASTER_CLOCK;*/
485 if (NULL != prtNow) {
486 *prtNow = rtCur;
488 if (NULL != pmtNow) {
489 hr = IDirectMusicPerformance8_ReferenceToMusicTime(iface, rtCur, pmtNow);
491 return hr;
494 static HRESULT WINAPI IDirectMusicPerformance8Impl_AllocPMsg(IDirectMusicPerformance8 *iface,
495 ULONG cb, DMUS_PMSG **ppPMSG)
497 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
498 DMUS_PMSGItem* pItem = NULL;
500 FIXME("(%p, %d, %p): stub\n", This, cb, ppPMSG);
502 if (sizeof(DMUS_PMSG) > cb) {
503 return E_INVALIDARG;
505 if (NULL == ppPMSG) {
506 return E_POINTER;
508 pItem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb - sizeof(DMUS_PMSG) + sizeof(DMUS_PMSGItem));
509 if (NULL == pItem) {
510 return E_OUTOFMEMORY;
512 pItem->pMsg.dwSize = cb;
513 *ppPMSG = DMUS_ItemToPMSG(pItem);
514 return S_OK;
517 static HRESULT WINAPI IDirectMusicPerformance8Impl_FreePMsg(IDirectMusicPerformance8 *iface,
518 DMUS_PMSG *pPMSG)
520 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
521 DMUS_PMSGItem* pItem = NULL;
523 FIXME("(%p, %p): stub\n", This, pPMSG);
525 if (NULL == pPMSG) {
526 return E_POINTER;
528 pItem = DMUS_PMSGToItem(pPMSG);
529 if (pItem->bInUse) {
530 /** prevent for freeing PMsg in queue (ie to be processed) */
531 return DMUS_E_CANNOT_FREE;
533 /** now we can remove it safely */
534 EnterCriticalSection(&This->safe);
535 DMUS_ItemRemoveFromQueue( This, pItem );
536 LeaveCriticalSection(&This->safe);
538 if (pPMSG->pTool)
539 IDirectMusicTool_Release(pPMSG->pTool);
541 if (pPMSG->pGraph)
542 IDirectMusicGraph_Release(pPMSG->pGraph);
544 if (pPMSG->punkUser)
545 IUnknown_Release(pPMSG->punkUser);
547 HeapFree(GetProcessHeap(), 0, pItem);
548 return S_OK;
551 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetGraph(IDirectMusicPerformance8 *iface,
552 IDirectMusicGraph **graph)
554 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
556 TRACE("(%p, %p)\n", This, graph);
558 if (!graph)
559 return E_POINTER;
561 *graph = This->pToolGraph;
562 if (This->pToolGraph) {
563 IDirectMusicGraph_AddRef(*graph);
566 return *graph ? S_OK : DMUS_E_NOT_FOUND;
569 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetGraph(IDirectMusicPerformance8 *iface,
570 IDirectMusicGraph *pGraph)
572 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
574 FIXME("(%p, %p): to check\n", This, pGraph);
576 if (NULL != This->pToolGraph) {
577 /* Todo clean buffers and tools before */
578 IDirectMusicGraph_Release(This->pToolGraph);
580 This->pToolGraph = pGraph;
581 if (NULL != This->pToolGraph) {
582 IDirectMusicGraph_AddRef(This->pToolGraph);
584 return S_OK;
587 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetNotificationHandle(IDirectMusicPerformance8 *iface,
588 HANDLE hNotification, REFERENCE_TIME rtMinimum)
590 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
592 TRACE("(%p, %p, 0x%s)\n", This, hNotification, wine_dbgstr_longlong(rtMinimum));
594 This->hNotification = hNotification;
595 if (rtMinimum)
596 This->rtMinimum = rtMinimum;
597 else if (!This->rtMinimum)
598 This->rtMinimum = 20000000; /* 2 seconds */
599 return S_OK;
602 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetNotificationPMsg(IDirectMusicPerformance8 *iface,
603 DMUS_NOTIFICATION_PMSG **ppNotificationPMsg)
605 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
607 FIXME("(%p, %p): stub\n", This, ppNotificationPMsg);
608 if (NULL == ppNotificationPMsg) {
609 return E_POINTER;
614 return S_FALSE;
615 /*return S_OK;*/
618 static HRESULT WINAPI IDirectMusicPerformance8Impl_AddNotificationType(IDirectMusicPerformance8 *iface,
619 REFGUID rguidNotificationType)
621 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
623 FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType));
624 return S_OK;
627 static HRESULT WINAPI IDirectMusicPerformance8Impl_RemoveNotificationType(IDirectMusicPerformance8 *iface,
628 REFGUID rguidNotificationType)
630 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
632 FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType));
633 return S_OK;
636 static HRESULT perf_dmport_create(IDirectMusicPerformance8Impl *perf, DMUS_PORTPARAMS *params)
638 IDirectMusicPort *port;
639 GUID guid;
640 unsigned int i;
641 HRESULT hr;
643 if (FAILED(hr = IDirectMusic8_GetDefaultPort(perf->dmusic, &guid)))
644 return hr;
646 if (FAILED(hr = IDirectMusic8_CreatePort(perf->dmusic, &guid, params, &port, NULL)))
647 return hr;
648 if (FAILED(hr = IDirectMusicPort_Activate(port, TRUE))) {
649 IDirectMusicPort_Release(port);
650 return hr;
652 for (i = 0; i < params->dwChannelGroups; i++)
653 pchannel_block_set(&perf->pchannels, i, port, i + 1, FALSE);
655 return S_OK;
658 static HRESULT WINAPI IDirectMusicPerformance8Impl_AddPort(IDirectMusicPerformance8 *iface,
659 IDirectMusicPort *port)
661 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
663 FIXME("(%p, %p): semi-stub\n", This, port);
665 if (!This->dmusic)
666 return DMUS_E_NOT_INIT;
668 if (!port) {
669 DMUS_PORTPARAMS params = {
670 .dwSize = sizeof(params),
671 .dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS,
672 .dwChannelGroups = 1
675 return perf_dmport_create(This, &params);
678 IDirectMusicPort_AddRef(port);
680 * We should remember added Ports (for example using a list)
681 * and control if Port is registered for each api who use ports
683 return S_OK;
686 static HRESULT WINAPI IDirectMusicPerformance8Impl_RemovePort(IDirectMusicPerformance8 *iface,
687 IDirectMusicPort *pPort)
689 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
691 FIXME("(%p, %p): stub\n", This, pPort);
692 IDirectMusicPort_Release (pPort);
693 return S_OK;
696 static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannelBlock(IDirectMusicPerformance8 *iface,
697 DWORD block_num, IDirectMusicPort *port, DWORD group)
699 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
701 FIXME("(%p, %d, %p, %d): semi-stub\n", This, block_num, port, group);
703 if (!port)
704 return E_POINTER;
705 if (block_num > MAXDWORD / 16)
706 return E_INVALIDARG;
708 pchannel_block_set(&This->pchannels, block_num, port, group, FALSE);
710 return S_OK;
713 static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannel(IDirectMusicPerformance8 *iface,
714 DWORD pchannel, IDirectMusicPort *port, DWORD group, DWORD channel)
716 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
717 struct pchannel_block *block;
719 FIXME("(%p)->(%d, %p, %d, %d) semi-stub\n", This, pchannel, port, group, channel);
721 if (!port)
722 return E_POINTER;
724 block = pchannel_block_set(&This->pchannels, pchannel / 16, port, 0, TRUE);
725 if (block) {
726 block->pchannel[pchannel % 16].group = group;
727 block->pchannel[pchannel % 16].channel = channel;
730 return S_OK;
733 static HRESULT WINAPI IDirectMusicPerformance8Impl_PChannelInfo(IDirectMusicPerformance8 *iface,
734 DWORD pchannel, IDirectMusicPort **port, DWORD *group, DWORD *channel)
736 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
737 struct pchannel_block *block;
738 struct wine_rb_entry *entry;
739 DWORD block_num = pchannel / 16;
740 unsigned int index = pchannel % 16;
742 TRACE("(%p)->(%d, %p, %p, %p)\n", This, pchannel, port, group, channel);
744 entry = wine_rb_get(&This->pchannels, &block_num);
745 if (!entry)
746 return E_INVALIDARG;
747 block = WINE_RB_ENTRY_VALUE(entry, struct pchannel_block, entry);
749 if (port) {
750 *port = block->pchannel[index].port;
751 IDirectMusicPort_AddRef(*port);
753 if (group)
754 *group = block->pchannel[index].group;
755 if (channel)
756 *channel = block->pchannel[index].channel;
758 return S_OK;
761 static HRESULT WINAPI IDirectMusicPerformance8Impl_DownloadInstrument(IDirectMusicPerformance8 *iface,
762 IDirectMusicInstrument *pInst, DWORD dwPChannel,
763 IDirectMusicDownloadedInstrument **ppDownInst, DMUS_NOTERANGE *pNoteRanges,
764 DWORD dwNumNoteRanges, IDirectMusicPort **ppPort, DWORD *pdwGroup, DWORD *pdwMChannel)
766 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
768 FIXME("(%p, %p, %d, %p, %p, %d, %p, %p, %p): stub\n", This, pInst, dwPChannel, ppDownInst, pNoteRanges, dwNumNoteRanges, ppPort, pdwGroup, pdwMChannel);
769 return S_OK;
772 static HRESULT WINAPI IDirectMusicPerformance8Impl_Invalidate(IDirectMusicPerformance8 *iface,
773 MUSIC_TIME mtTime, DWORD dwFlags)
775 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
777 FIXME("(%p, %d, %d): stub\n", This, mtTime, dwFlags);
778 return S_OK;
781 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetParam(IDirectMusicPerformance8 *iface,
782 REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime,
783 MUSIC_TIME *pmtNext, void *pParam)
785 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
787 FIXME("(%p, %s, %d, %d, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pmtNext, pParam);
788 return S_OK;
791 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetParam(IDirectMusicPerformance8 *iface,
792 REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam)
794 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
796 FIXME("(%p, %s, %d, %d, %d, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pParam);
797 return S_OK;
800 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetGlobalParam(IDirectMusicPerformance8 *iface,
801 REFGUID rguidType, void *pParam, DWORD dwSize)
803 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
805 TRACE("(%p, %s, %p, %d): stub\n", This, debugstr_dmguid(rguidType), pParam, dwSize);
807 if (IsEqualGUID (rguidType, &GUID_PerfAutoDownload))
808 memcpy(pParam, &This->fAutoDownload, sizeof(This->fAutoDownload));
809 if (IsEqualGUID (rguidType, &GUID_PerfMasterGrooveLevel))
810 memcpy(pParam, &This->cMasterGrooveLevel, sizeof(This->cMasterGrooveLevel));
811 if (IsEqualGUID (rguidType, &GUID_PerfMasterTempo))
812 memcpy(pParam, &This->fMasterTempo, sizeof(This->fMasterTempo));
813 if (IsEqualGUID (rguidType, &GUID_PerfMasterVolume))
814 memcpy(pParam, &This->lMasterVolume, sizeof(This->lMasterVolume));
816 return S_OK;
819 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetGlobalParam(IDirectMusicPerformance8 *iface,
820 REFGUID rguidType, void *pParam, DWORD dwSize)
822 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
824 TRACE("(%p, %s, %p, %d)\n", This, debugstr_dmguid(rguidType), pParam, dwSize);
826 if (IsEqualGUID (rguidType, &GUID_PerfAutoDownload)) {
827 memcpy(&This->fAutoDownload, pParam, dwSize);
828 TRACE("=> AutoDownload set to %d\n", This->fAutoDownload);
830 if (IsEqualGUID (rguidType, &GUID_PerfMasterGrooveLevel)) {
831 memcpy(&This->cMasterGrooveLevel, pParam, dwSize);
832 TRACE("=> MasterGrooveLevel set to %i\n", This->cMasterGrooveLevel);
834 if (IsEqualGUID (rguidType, &GUID_PerfMasterTempo)) {
835 memcpy(&This->fMasterTempo, pParam, dwSize);
836 TRACE("=> MasterTempo set to %f\n", This->fMasterTempo);
838 if (IsEqualGUID (rguidType, &GUID_PerfMasterVolume)) {
839 memcpy(&This->lMasterVolume, pParam, dwSize);
840 TRACE("=> MasterVolume set to %li\n", This->lMasterVolume);
843 return S_OK;
846 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetLatencyTime(IDirectMusicPerformance8 *iface,
847 REFERENCE_TIME *prtTime)
849 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
851 TRACE("(%p, %p): stub\n", This, prtTime);
852 *prtTime = This->rtLatencyTime;
853 return S_OK;
856 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetQueueTime(IDirectMusicPerformance8 *iface,
857 REFERENCE_TIME *prtTime)
860 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
862 FIXME("(%p, %p): stub\n", This, prtTime);
863 return S_OK;
866 static HRESULT WINAPI IDirectMusicPerformance8Impl_AdjustTime(IDirectMusicPerformance8 *iface,
867 REFERENCE_TIME rtAmount)
869 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
871 FIXME("(%p, 0x%s): stub\n", This, wine_dbgstr_longlong(rtAmount));
872 return S_OK;
875 static HRESULT WINAPI IDirectMusicPerformance8Impl_CloseDown(IDirectMusicPerformance8 *iface)
877 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
879 FIXME("(%p): semi-stub\n", This);
881 if (PostMessageToProcessMsgThread(This, PROCESSMSG_EXIT)) {
882 WaitForSingleObject(This->procThread, INFINITE);
883 This->procThreadTicStarted = FALSE;
884 CloseHandle(This->procThread);
886 if (This->dsound) {
887 IDirectSound_Release(This->dsound);
888 This->dsound = NULL;
890 if (This->dmusic) {
891 IDirectMusic_SetDirectSound(This->dmusic, NULL, NULL);
892 IDirectMusic8_Release(This->dmusic);
893 This->dmusic = NULL;
895 return S_OK;
898 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetResolvedTime(IDirectMusicPerformance8 *iface,
899 REFERENCE_TIME rtTime, REFERENCE_TIME *prtResolved, DWORD dwTimeResolveFlags)
901 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
903 FIXME("(%p, 0x%s, %p, %d): stub\n", This, wine_dbgstr_longlong(rtTime),
904 prtResolved, dwTimeResolveFlags);
905 return S_OK;
908 static HRESULT WINAPI IDirectMusicPerformance8Impl_MIDIToMusic(IDirectMusicPerformance8 *iface,
909 BYTE bMIDIValue, DMUS_CHORD_KEY *pChord, BYTE bPlayMode, BYTE bChordLevel,
910 WORD *pwMusicValue)
912 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
914 FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This, bMIDIValue, pChord, bPlayMode, bChordLevel, pwMusicValue);
915 return S_OK;
918 static HRESULT WINAPI IDirectMusicPerformance8Impl_MusicToMIDI(IDirectMusicPerformance8 *iface,
919 WORD wMusicValue, DMUS_CHORD_KEY *pChord, BYTE bPlayMode, BYTE bChordLevel,
920 BYTE *pbMIDIValue)
922 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
924 FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This, wMusicValue, pChord, bPlayMode, bChordLevel, pbMIDIValue);
925 return S_OK;
928 static HRESULT WINAPI IDirectMusicPerformance8Impl_TimeToRhythm(IDirectMusicPerformance8 *iface,
929 MUSIC_TIME mtTime, DMUS_TIMESIGNATURE *pTimeSig, WORD *pwMeasure, BYTE *pbBeat,
930 BYTE *pbGrid, short *pnOffset)
932 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
934 FIXME("(%p, %d, %p, %p, %p, %p, %p): stub\n", This, mtTime, pTimeSig, pwMeasure, pbBeat, pbGrid, pnOffset);
935 return S_OK;
938 static HRESULT WINAPI IDirectMusicPerformance8Impl_RhythmToTime(IDirectMusicPerformance8 *iface,
939 WORD wMeasure, BYTE bBeat, BYTE bGrid, short nOffset, DMUS_TIMESIGNATURE *pTimeSig,
940 MUSIC_TIME *pmtTime)
942 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
944 FIXME("(%p, %d, %d, %d, %i, %p, %p): stub\n", This, wMeasure, bBeat, bGrid, nOffset, pTimeSig, pmtTime);
945 return S_OK;
948 /* IDirectMusicPerformance8 Interface part follow: */
949 static HRESULT WINAPI IDirectMusicPerformance8Impl_InitAudio(IDirectMusicPerformance8 *iface,
950 IDirectMusic **dmusic, IDirectSound **dsound, HWND hwnd, DWORD default_path_type,
951 DWORD num_channels, DWORD flags, DMUS_AUDIOPARAMS *params)
953 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
954 HRESULT hr = S_OK;
956 TRACE("(%p, %p, %p, %p, %x, %u, %x, %p)\n", This, dmusic, dsound, hwnd, default_path_type,
957 num_channels, flags, params);
959 if (This->dmusic)
960 return DMUS_E_ALREADY_INITED;
962 if (!dmusic || !*dmusic) {
963 hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic8,
964 (void **)&This->dmusic);
965 if (FAILED(hr))
966 return hr;
967 } else {
968 This->dmusic = (IDirectMusic8 *)*dmusic;
969 IDirectMusic8_AddRef(This->dmusic);
972 if (!dsound || !*dsound) {
973 hr = DirectSoundCreate8(NULL, (IDirectSound8 **)&This->dsound, NULL);
974 if (FAILED(hr))
975 goto error;
976 hr = IDirectSound_SetCooperativeLevel(This->dsound, hwnd ? hwnd : GetForegroundWindow(),
977 DSSCL_PRIORITY);
978 if (FAILED(hr))
979 goto error;
980 } else {
981 This->dsound = *dsound;
982 IDirectSound_AddRef(This->dsound);
985 hr = IDirectMusic8_SetDirectSound(This->dmusic, This->dsound, NULL);
986 if (FAILED(hr))
987 goto error;
989 if (!params) {
990 This->params.dwSize = sizeof(DMUS_AUDIOPARAMS);
991 This->params.fInitNow = FALSE;
992 This->params.dwValidData = DMUS_AUDIOPARAMS_FEATURES | DMUS_AUDIOPARAMS_VOICES |
993 DMUS_AUDIOPARAMS_SAMPLERATE | DMUS_AUDIOPARAMS_DEFAULTSYNTH;
994 This->params.dwVoices = 64;
995 This->params.dwSampleRate = 22050;
996 This->params.dwFeatures = flags;
997 This->params.clsidDefaultSynth = CLSID_DirectMusicSynthSink;
998 } else
999 This->params = *params;
1001 if (default_path_type) {
1002 hr = IDirectMusicPerformance8_CreateStandardAudioPath(iface, default_path_type,
1003 num_channels, FALSE, &This->pDefaultPath);
1004 if (FAILED(hr)) {
1005 IDirectMusic8_SetDirectSound(This->dmusic, NULL, NULL);
1006 goto error;
1010 if (dsound && !*dsound) {
1011 *dsound = This->dsound;
1012 IDirectSound_AddRef(*dsound);
1014 if (dmusic && !*dmusic) {
1015 *dmusic = (IDirectMusic *)This->dmusic;
1016 IDirectMusic_AddRef(*dmusic);
1018 PostMessageToProcessMsgThread(This, PROCESSMSG_START);
1020 return S_OK;
1022 error:
1023 if (This->dsound) {
1024 IDirectSound_Release(This->dsound);
1025 This->dsound = NULL;
1027 if (This->dmusic) {
1028 IDirectMusic8_Release(This->dmusic);
1029 This->dmusic = NULL;
1031 return hr;
1034 static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegmentEx(IDirectMusicPerformance8 *iface,
1035 IUnknown *pSource, WCHAR *pwzSegmentName, IUnknown *pTransition, DWORD dwFlags,
1036 __int64 i64StartTime, IDirectMusicSegmentState **ppSegmentState, IUnknown *pFrom,
1037 IUnknown *pAudioPath)
1039 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1041 FIXME("(%p, %p, %p, %p, %d, 0x%s, %p, %p, %p): stub\n", This, pSource, pwzSegmentName,
1042 pTransition, dwFlags, wine_dbgstr_longlong(i64StartTime), ppSegmentState, pFrom, pAudioPath);
1043 if (ppSegmentState)
1044 return create_dmsegmentstate(&IID_IDirectMusicSegmentState,(void**)ppSegmentState);
1045 return S_OK;
1048 static HRESULT WINAPI IDirectMusicPerformance8Impl_StopEx(IDirectMusicPerformance8 *iface,
1049 IUnknown *pObjectToStop, __int64 i64StopTime, DWORD dwFlags)
1051 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1053 FIXME("(%p, %p, 0x%s, %d): stub\n", This, pObjectToStop,
1054 wine_dbgstr_longlong(i64StopTime), dwFlags);
1055 return S_OK;
1058 static HRESULT WINAPI IDirectMusicPerformance8Impl_ClonePMsg(IDirectMusicPerformance8 *iface,
1059 DMUS_PMSG *pSourcePMSG, DMUS_PMSG **ppCopyPMSG)
1061 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1063 FIXME("(%p, %p, %p): stub\n", This, pSourcePMSG, ppCopyPMSG);
1064 return S_OK;
1067 static HRESULT WINAPI IDirectMusicPerformance8Impl_CreateAudioPath(IDirectMusicPerformance8 *iface,
1068 IUnknown *pSourceConfig, BOOL fActivate, IDirectMusicAudioPath **ppNewPath)
1070 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1071 IDirectMusicAudioPath *pPath;
1073 FIXME("(%p, %p, %d, %p): stub\n", This, pSourceConfig, fActivate, ppNewPath);
1075 if (NULL == ppNewPath) {
1076 return E_POINTER;
1079 create_dmaudiopath(&IID_IDirectMusicAudioPath, (void**)&pPath);
1080 set_audiopath_perf_pointer(pPath, iface);
1082 /** TODO */
1084 *ppNewPath = pPath;
1086 return IDirectMusicAudioPath_Activate(*ppNewPath, fActivate);
1089 static HRESULT WINAPI IDirectMusicPerformance8Impl_CreateStandardAudioPath(IDirectMusicPerformance8 *iface,
1090 DWORD dwType, DWORD pchannel_count, BOOL fActivate, IDirectMusicAudioPath **ppNewPath)
1092 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1093 IDirectMusicAudioPath *pPath;
1094 DSBUFFERDESC desc;
1095 WAVEFORMATEX format;
1096 DMUS_PORTPARAMS params = {0};
1097 IDirectSoundBuffer *buffer, *primary_buffer;
1098 HRESULT hr = S_OK;
1100 FIXME("(%p)->(%d, %d, %d, %p): semi-stub\n", This, dwType, pchannel_count, fActivate, ppNewPath);
1102 if (NULL == ppNewPath) {
1103 return E_POINTER;
1106 *ppNewPath = NULL;
1108 /* Secondary buffer description */
1109 memset(&format, 0, sizeof(format));
1110 format.wFormatTag = WAVE_FORMAT_PCM;
1111 format.nChannels = 1;
1112 format.nSamplesPerSec = 44000;
1113 format.nAvgBytesPerSec = 44000*2;
1114 format.nBlockAlign = 2;
1115 format.wBitsPerSample = 16;
1116 format.cbSize = 0;
1118 memset(&desc, 0, sizeof(desc));
1119 desc.dwSize = sizeof(desc);
1120 desc.dwFlags = DSBCAPS_CTRLFX | DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS;
1121 desc.dwBufferBytes = DSBSIZE_MIN;
1122 desc.dwReserved = 0;
1123 desc.lpwfxFormat = &format;
1124 desc.guid3DAlgorithm = GUID_NULL;
1126 switch(dwType) {
1127 case DMUS_APATH_DYNAMIC_3D:
1128 desc.dwFlags |= DSBCAPS_CTRL3D | DSBCAPS_CTRLFREQUENCY | DSBCAPS_MUTE3DATMAXDISTANCE;
1129 break;
1130 case DMUS_APATH_DYNAMIC_MONO:
1131 desc.dwFlags |= DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY;
1132 break;
1133 case DMUS_APATH_SHARED_STEREOPLUSREVERB:
1134 /* normally we have to create 2 buffers (one for music other for reverb)
1135 * in this case. See msdn
1137 case DMUS_APATH_DYNAMIC_STEREO:
1138 desc.dwFlags |= DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY;
1139 format.nChannels = 2;
1140 format.nBlockAlign *= 2;
1141 format.nAvgBytesPerSec *=2;
1142 break;
1143 default:
1144 return E_INVALIDARG;
1147 /* Create a port */
1148 params.dwSize = sizeof(params);
1149 params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS | DMUS_PORTPARAMS_AUDIOCHANNELS;
1150 params.dwChannelGroups = (pchannel_count + 15) / 16;
1151 params.dwAudioChannels = format.nChannels;
1152 if (FAILED(hr = perf_dmport_create(This, &params)))
1153 return hr;
1155 hr = IDirectSound_CreateSoundBuffer(This->dsound, &desc, &buffer, NULL);
1156 if (FAILED(hr))
1157 return DSERR_BUFFERLOST;
1159 /* Update description for creating primary buffer */
1160 desc.dwFlags |= DSBCAPS_PRIMARYBUFFER;
1161 desc.dwFlags &= ~DSBCAPS_CTRLFX;
1162 desc.dwBufferBytes = 0;
1163 desc.lpwfxFormat = NULL;
1165 hr = IDirectSound_CreateSoundBuffer(This->dsound, &desc, &primary_buffer, NULL);
1166 if (FAILED(hr)) {
1167 IDirectSoundBuffer_Release(buffer);
1168 return DSERR_BUFFERLOST;
1171 create_dmaudiopath(&IID_IDirectMusicAudioPath, (void**)&pPath);
1172 set_audiopath_perf_pointer(pPath, iface);
1173 set_audiopath_dsound_buffer(pPath, buffer);
1174 set_audiopath_primary_dsound_buffer(pPath, primary_buffer);
1176 *ppNewPath = pPath;
1178 TRACE(" returning IDirectMusicAudioPath interface at %p.\n", *ppNewPath);
1180 return IDirectMusicAudioPath_Activate(*ppNewPath, fActivate);
1183 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetDefaultAudioPath(IDirectMusicPerformance8 *iface,
1184 IDirectMusicAudioPath *pAudioPath)
1186 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1188 FIXME("(%p, %p): semi-stub\n", This, pAudioPath);
1190 if (This->pDefaultPath) {
1191 IDirectMusicAudioPath_Release(This->pDefaultPath);
1192 This->pDefaultPath = NULL;
1194 This->pDefaultPath = pAudioPath;
1195 if (This->pDefaultPath) {
1196 IDirectMusicAudioPath_AddRef(This->pDefaultPath);
1197 set_audiopath_perf_pointer(This->pDefaultPath, iface);
1200 return S_OK;
1203 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetDefaultAudioPath(IDirectMusicPerformance8 *iface,
1204 IDirectMusicAudioPath **ppAudioPath)
1206 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1208 FIXME("(%p, %p): semi-stub (%p)\n", This, ppAudioPath, This->pDefaultPath);
1210 if (NULL != This->pDefaultPath) {
1211 *ppAudioPath = This->pDefaultPath;
1212 IDirectMusicAudioPath_AddRef(*ppAudioPath);
1213 } else {
1214 *ppAudioPath = NULL;
1216 return S_OK;
1219 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetParamEx(IDirectMusicPerformance8 *iface,
1220 REFGUID rguidType, DWORD dwTrackID, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime,
1221 MUSIC_TIME *pmtNext, void *pParam)
1223 IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1225 FIXME("(%p, %s, %d, %d, %d, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), dwTrackID, dwGroupBits, dwIndex, mtTime, pmtNext, pParam);
1227 return S_OK;
1230 static const IDirectMusicPerformance8Vtbl DirectMusicPerformance8_Vtbl = {
1231 IDirectMusicPerformance8Impl_QueryInterface,
1232 IDirectMusicPerformance8Impl_AddRef,
1233 IDirectMusicPerformance8Impl_Release,
1234 IDirectMusicPerformance8Impl_Init,
1235 IDirectMusicPerformance8Impl_PlaySegment,
1236 IDirectMusicPerformance8Impl_Stop,
1237 IDirectMusicPerformance8Impl_GetSegmentState,
1238 IDirectMusicPerformance8Impl_SetPrepareTime,
1239 IDirectMusicPerformance8Impl_GetPrepareTime,
1240 IDirectMusicPerformance8Impl_SetBumperLength,
1241 IDirectMusicPerformance8Impl_GetBumperLength,
1242 IDirectMusicPerformance8Impl_SendPMsg,
1243 IDirectMusicPerformance8Impl_MusicToReferenceTime,
1244 IDirectMusicPerformance8Impl_ReferenceToMusicTime,
1245 IDirectMusicPerformance8Impl_IsPlaying,
1246 IDirectMusicPerformance8Impl_GetTime,
1247 IDirectMusicPerformance8Impl_AllocPMsg,
1248 IDirectMusicPerformance8Impl_FreePMsg,
1249 IDirectMusicPerformance8Impl_GetGraph,
1250 IDirectMusicPerformance8Impl_SetGraph,
1251 IDirectMusicPerformance8Impl_SetNotificationHandle,
1252 IDirectMusicPerformance8Impl_GetNotificationPMsg,
1253 IDirectMusicPerformance8Impl_AddNotificationType,
1254 IDirectMusicPerformance8Impl_RemoveNotificationType,
1255 IDirectMusicPerformance8Impl_AddPort,
1256 IDirectMusicPerformance8Impl_RemovePort,
1257 IDirectMusicPerformance8Impl_AssignPChannelBlock,
1258 IDirectMusicPerformance8Impl_AssignPChannel,
1259 IDirectMusicPerformance8Impl_PChannelInfo,
1260 IDirectMusicPerformance8Impl_DownloadInstrument,
1261 IDirectMusicPerformance8Impl_Invalidate,
1262 IDirectMusicPerformance8Impl_GetParam,
1263 IDirectMusicPerformance8Impl_SetParam,
1264 IDirectMusicPerformance8Impl_GetGlobalParam,
1265 IDirectMusicPerformance8Impl_SetGlobalParam,
1266 IDirectMusicPerformance8Impl_GetLatencyTime,
1267 IDirectMusicPerformance8Impl_GetQueueTime,
1268 IDirectMusicPerformance8Impl_AdjustTime,
1269 IDirectMusicPerformance8Impl_CloseDown,
1270 IDirectMusicPerformance8Impl_GetResolvedTime,
1271 IDirectMusicPerformance8Impl_MIDIToMusic,
1272 IDirectMusicPerformance8Impl_MusicToMIDI,
1273 IDirectMusicPerformance8Impl_TimeToRhythm,
1274 IDirectMusicPerformance8Impl_RhythmToTime,
1275 IDirectMusicPerformance8Impl_InitAudio,
1276 IDirectMusicPerformance8Impl_PlaySegmentEx,
1277 IDirectMusicPerformance8Impl_StopEx,
1278 IDirectMusicPerformance8Impl_ClonePMsg,
1279 IDirectMusicPerformance8Impl_CreateAudioPath,
1280 IDirectMusicPerformance8Impl_CreateStandardAudioPath,
1281 IDirectMusicPerformance8Impl_SetDefaultAudioPath,
1282 IDirectMusicPerformance8Impl_GetDefaultAudioPath,
1283 IDirectMusicPerformance8Impl_GetParamEx
1286 /* for ClassFactory */
1287 HRESULT WINAPI create_dmperformance(REFIID lpcGUID, void **ppobj)
1289 IDirectMusicPerformance8Impl *obj;
1291 TRACE("(%s, %p)\n", debugstr_guid(lpcGUID), ppobj);
1293 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicPerformance8Impl));
1294 if (NULL == obj) {
1295 *ppobj = NULL;
1296 return E_OUTOFMEMORY;
1298 obj->IDirectMusicPerformance8_iface.lpVtbl = &DirectMusicPerformance8_Vtbl;
1299 obj->ref = 0; /* will be inited by QueryInterface */
1300 obj->pDefaultPath = NULL;
1301 InitializeCriticalSection(&obj->safe);
1302 obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectMusicPerformance8Impl*->safe");
1303 wine_rb_init(&obj->pchannels, pchannel_block_compare);
1305 obj->rtLatencyTime = 100; /* 100 ms TO FIX */
1306 obj->dwBumperLength = 50; /* 50 ms default */
1307 obj->dwPrepareTime = 1000; /* 1000 ms default */
1308 return IDirectMusicPerformance8Impl_QueryInterface(&obj->IDirectMusicPerformance8_iface,
1309 lpcGUID, ppobj);