dmime/tests: Add some COM tests for DirectMusicSegment.
[wine] / dlls / dmime / performance.c
1 /* IDirectMusicPerformance Implementation
2  *
3  * Copyright (C) 2003-2004 Rok Mandeljc
4  * Copyright (C) 2003-2004 Raphael Junqueira
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "dmime_private.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(dmime);
24
25 typedef struct IDirectMusicPerformance8Impl {
26     IDirectMusicPerformance8 IDirectMusicPerformance8_iface;
27     LONG ref;
28     /* IDirectMusicPerformanceImpl fields */
29     IDirectMusic8 *pDirectMusic;
30     IDirectSound *pDirectSound;
31     IDirectMusicGraph *pToolGraph;
32     DMUS_AUDIOPARAMS pParams;
33     /* global parameters */
34     BOOL fAutoDownload;
35     char cMasterGrooveLevel;
36     float fMasterTempo;
37     long lMasterVolume;
38     /* performance channels */
39     DMUSIC_PRIVATE_PCHANNEL PChannel[32];
40     /* IDirectMusicPerformance8Impl fields */
41     IDirectMusicAudioPath *pDefaultPath;
42     HANDLE hNotification;
43     REFERENCE_TIME rtMinimum;
44     REFERENCE_TIME rtLatencyTime;
45     DWORD dwBumperLength;
46     DWORD dwPrepareTime;
47     /** Message Processing */
48     HANDLE procThread;
49     DWORD procThreadId;
50     REFERENCE_TIME procThreadStartTime;
51     BOOL procThreadTicStarted;
52     CRITICAL_SECTION safe;
53     struct DMUS_PMSGItem *head;
54     struct DMUS_PMSGItem *imm_head;
55 } IDirectMusicPerformance8Impl;
56
57 typedef struct DMUS_PMSGItem DMUS_PMSGItem;
58 struct DMUS_PMSGItem {
59   DMUS_PMSGItem* next;
60   DMUS_PMSGItem* prev;
61
62   REFERENCE_TIME rtItemTime;
63   BOOL bInUse;
64   DWORD cb;
65   DMUS_PMSG pMsg;
66 };
67
68 #define DMUS_PMSGToItem(pMSG)   ((DMUS_PMSGItem*) (((unsigned char*) pPMSG) -  offsetof(DMUS_PMSGItem, pMsg)))
69 #define DMUS_ItemToPMSG(pItem)  (&(pItem->pMsg))
70 #define DMUS_ItemRemoveFromQueue(This,pItem) \
71 {\
72   if (pItem->prev) pItem->prev->next = pItem->next;\
73   if (pItem->next) pItem->next->prev = pItem->prev;\
74   if (This->head == pItem) This->head = pItem->next;\
75   if (This->imm_head == pItem) This->imm_head = pItem->next;\
76   pItem->bInUse = FALSE;\
77 }
78
79 #define PROCESSMSG_START           (WM_APP + 0)
80 #define PROCESSMSG_EXIT            (WM_APP + 1)
81 #define PROCESSMSG_REMOVE          (WM_APP + 2)
82 #define PROCESSMSG_ADD             (WM_APP + 4)
83
84
85 static DMUS_PMSGItem* ProceedMsg(IDirectMusicPerformance8Impl* This, DMUS_PMSGItem* cur) {
86   if (cur->pMsg.dwType == DMUS_PMSGT_NOTIFICATION) {
87     SetEvent(This->hNotification);
88   }     
89   DMUS_ItemRemoveFromQueue(This, cur);
90   switch (cur->pMsg.dwType) {
91   case DMUS_PMSGT_WAVE:
92   case DMUS_PMSGT_TEMPO:   
93   case DMUS_PMSGT_STOP:
94   default:
95     FIXME("Unhandled PMsg Type: 0x%x\n", cur->pMsg.dwType);
96     break;
97   }
98   return cur;
99 }
100
101 static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) {
102   IDirectMusicPerformance8Impl* This = lpParam;
103   DWORD timeOut = INFINITE;
104   MSG msg;
105   HRESULT hr;
106   REFERENCE_TIME rtCurTime;
107   DMUS_PMSGItem* it = NULL;
108   DMUS_PMSGItem* cur = NULL;
109   DMUS_PMSGItem* it_next = NULL;
110
111   while (TRUE) {
112     DWORD dwDec = This->rtLatencyTime + This->dwBumperLength;
113
114     if (timeOut > 0) MsgWaitForMultipleObjects(0, NULL, FALSE, timeOut, QS_POSTMESSAGE|QS_SENDMESSAGE|QS_TIMER);
115     timeOut = INFINITE;
116
117     EnterCriticalSection(&This->safe);
118     hr = IDirectMusicPerformance8_GetTime(&This->IDirectMusicPerformance8_iface, &rtCurTime, NULL);
119     if (FAILED(hr)) {
120       goto outrefresh;
121     }
122     
123     for (it = This->imm_head; NULL != it; ) {
124       it_next = it->next;
125       cur = ProceedMsg(This, it);  
126       HeapFree(GetProcessHeap(), 0, cur); 
127       it = it_next;
128     }
129
130     for (it = This->head; NULL != it && it->rtItemTime < rtCurTime + dwDec; ) {
131       it_next = it->next;
132       cur = ProceedMsg(This, it);
133       HeapFree(GetProcessHeap(), 0, cur);
134       it = it_next;
135     }
136     if (NULL != it) {
137       timeOut = ( it->rtItemTime - rtCurTime ) + This->rtLatencyTime;
138     }
139
140 outrefresh:
141     LeaveCriticalSection(&This->safe);
142     
143     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
144       /** if hwnd we suppose that is a windows event ... */
145       if  (NULL != msg.hwnd) {
146         TranslateMessage(&msg);
147         DispatchMessageA(&msg);
148       } else {
149         switch (msg.message) {      
150         case WM_QUIT:
151         case PROCESSMSG_EXIT:
152           goto outofthread;
153         case PROCESSMSG_START:
154           break;
155         case PROCESSMSG_ADD:
156           break;
157         case PROCESSMSG_REMOVE:
158           break;
159         default:
160           ERR("Unhandled message %u. Critical Path\n", msg.message);
161           break;
162         }
163       }
164     }
165
166     /** here we should run a little of current AudioPath */
167
168   }
169
170 outofthread:
171   TRACE("(%p): Exiting\n", This);
172   
173   return 0;
174 }
175
176 static BOOL PostMessageToProcessMsgThread(IDirectMusicPerformance8Impl* This, UINT iMsg) {
177   if (FALSE == This->procThreadTicStarted && PROCESSMSG_EXIT != iMsg) {
178     BOOL res;
179     This->procThread = CreateThread(NULL, 0, ProcessMsgThread, This, 0, &This->procThreadId);
180     if (NULL == This->procThread) return FALSE;
181     SetThreadPriority(This->procThread, THREAD_PRIORITY_TIME_CRITICAL);
182     This->procThreadTicStarted = TRUE;
183     while(1) {
184       res = PostThreadMessageA(This->procThreadId, iMsg, 0, 0);
185       /* Let the thread creates its message queue (with MsgWaitForMultipleObjects call) by yielding and retrying */
186       if (!res && (GetLastError() == ERROR_INVALID_THREAD_ID))
187         Sleep(0);
188       else
189         break;
190     }
191     return res;
192   }
193   return PostThreadMessageA(This->procThreadId, iMsg, 0, 0);
194 }
195
196 static inline IDirectMusicPerformance8Impl *impl_from_IDirectMusicPerformance8(IDirectMusicPerformance8 *iface)
197 {
198     return CONTAINING_RECORD(iface, IDirectMusicPerformance8Impl, IDirectMusicPerformance8_iface);
199 }
200
201 /* IDirectMusicPerformance8 IUnknown part: */
202 static HRESULT WINAPI IDirectMusicPerformance8Impl_QueryInterface(IDirectMusicPerformance8 *iface,
203         REFIID riid, void **ppv)
204 {
205   TRACE("(%p, %s,%p)\n", iface, debugstr_dmguid(riid), ppv);
206
207   if (IsEqualIID (riid, &IID_IUnknown) ||
208       IsEqualIID (riid, &IID_IDirectMusicPerformance) ||
209       IsEqualIID (riid, &IID_IDirectMusicPerformance2) ||
210       IsEqualIID (riid, &IID_IDirectMusicPerformance8)) {
211     *ppv = iface;
212     IUnknown_AddRef(iface);
213     return S_OK;
214   }
215
216   WARN("(%p, %s,%p): not found\n", iface, debugstr_dmguid(riid), ppv);
217   return E_NOINTERFACE;
218 }
219
220 static ULONG WINAPI IDirectMusicPerformance8Impl_AddRef(IDirectMusicPerformance8 *iface)
221 {
222   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
223   ULONG ref = InterlockedIncrement(&This->ref);
224
225   TRACE("(%p): AddRef from %d\n", This, ref - 1);
226
227   DMIME_LockModule();
228
229   return ref;
230 }
231
232 static ULONG WINAPI IDirectMusicPerformance8Impl_Release(IDirectMusicPerformance8 *iface)
233 {
234   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
235   ULONG ref = InterlockedDecrement(&This->ref);
236
237   TRACE("(%p): ReleaseRef to %d\n", This, ref);
238   
239   if (ref == 0) {
240     This->safe.DebugInfo->Spare[0] = 0;
241     DeleteCriticalSection(&This->safe);
242     HeapFree(GetProcessHeap(), 0, This);
243   }
244
245   DMIME_UnlockModule();
246
247   return ref;
248 }
249
250 /* IDirectMusicPerformanceImpl IDirectMusicPerformance Interface part: */
251 static HRESULT WINAPI IDirectMusicPerformance8Impl_Init(IDirectMusicPerformance8 *iface,
252         IDirectMusic **ppDirectMusic, IDirectSound *pDirectSound, HWND hWnd)
253 {
254         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
255
256         FIXME("(iface = %p, dmusic = %p, dsound = %p, hwnd = %p)\n", This, ppDirectMusic, pDirectSound, hWnd);
257         if (This->pDirectMusic || This->pDirectSound)
258           return DMUS_E_ALREADY_INITED;
259         
260         if (NULL == hWnd) {
261           hWnd = GetForegroundWindow();
262         }
263
264         if (NULL != pDirectSound) {
265           This->pDirectSound = pDirectSound;
266           IDirectSound_AddRef(This->pDirectSound);
267         } else {
268           DirectSoundCreate8(NULL, (LPDIRECTSOUND8*) &This->pDirectSound, NULL);
269           if (!This->pDirectSound) return DSERR_NODRIVER;
270
271           if (NULL != hWnd) {
272             IDirectSound8_SetCooperativeLevel(This->pDirectSound, hWnd, DSSCL_PRIORITY);
273           } else {
274             /* how to get the ForeGround window handle ? */
275             /*IDirectSound8_SetCooperativeLevel(This->pDirectSound, hWnd, DSSCL_PRIORITY);*/
276           }
277         }
278
279         if (NULL != ppDirectMusic && NULL != *ppDirectMusic) {
280           /* app creates it's own dmusic object and gives it to performance */
281           This->pDirectMusic = (IDirectMusic8*) *ppDirectMusic;
282           IDirectMusic8_AddRef(This->pDirectMusic);
283         } else {
284         HRESULT hr;
285         /* App enables the performance to initialize itself and needs a pointer to object */
286         hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic8, (void**)&This->pDirectMusic);
287         if (FAILED(hr))
288             return hr;
289         if (ppDirectMusic) {
290             *ppDirectMusic = (LPDIRECTMUSIC)This->pDirectMusic;
291             IDirectMusic8_AddRef((LPDIRECTMUSIC8)*ppDirectMusic);
292         }
293     }
294
295     return S_OK;
296 }
297
298 static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegment(IDirectMusicPerformance8 *iface,
299         IDirectMusicSegment *pSegment, DWORD dwFlags, __int64 i64StartTime,
300         IDirectMusicSegmentState **ppSegmentState)
301 {
302         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
303
304         FIXME("(%p, %p, %d, 0x%s, %p): stub\n", This, pSegment, dwFlags,
305             wine_dbgstr_longlong(i64StartTime), ppSegmentState);
306         if (ppSegmentState)
307           return DMUSIC_CreateDirectMusicSegmentStateImpl(&IID_IDirectMusicSegmentState, (LPVOID*)ppSegmentState, NULL);
308         return S_OK;
309 }
310
311 static HRESULT WINAPI IDirectMusicPerformance8Impl_Stop(IDirectMusicPerformance8 *iface,
312         IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegmentState, MUSIC_TIME mtTime,
313         DWORD dwFlags)
314 {
315         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
316
317         FIXME("(%p, %p, %p, %d, %d): stub\n", This, pSegment, pSegmentState, mtTime, dwFlags);
318         return S_OK;
319 }
320
321 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetSegmentState(IDirectMusicPerformance8 *iface,
322         IDirectMusicSegmentState **ppSegmentState, MUSIC_TIME mtTime)
323 {
324         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
325
326         FIXME("(%p,%p, %d): stub\n", This, ppSegmentState, mtTime);
327         return S_OK;
328 }
329
330 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetPrepareTime(IDirectMusicPerformance8 *iface,
331         DWORD dwMilliSeconds)
332 {
333   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
334
335   TRACE("(%p, %d)\n", This, dwMilliSeconds);
336   This->dwPrepareTime = dwMilliSeconds;
337   return S_OK;
338 }
339
340 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetPrepareTime(IDirectMusicPerformance8 *iface,
341         DWORD *pdwMilliSeconds)
342 {
343   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
344
345   TRACE("(%p, %p)\n", This, pdwMilliSeconds);
346   if (NULL == pdwMilliSeconds) {
347     return E_POINTER;
348   }
349   *pdwMilliSeconds = This->dwPrepareTime;
350   return S_OK;
351 }
352
353 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetBumperLength(IDirectMusicPerformance8 *iface,
354         DWORD dwMilliSeconds)
355 {
356   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
357
358   TRACE("(%p, %d)\n", This, dwMilliSeconds);
359   This->dwBumperLength =  dwMilliSeconds;
360   return S_OK;
361 }
362
363 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetBumperLength(IDirectMusicPerformance8 *iface,
364         DWORD *pdwMilliSeconds)
365 {
366   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
367
368   TRACE("(%p, %p)\n", This, pdwMilliSeconds);
369   if (NULL == pdwMilliSeconds) {
370     return E_POINTER;
371   }
372   *pdwMilliSeconds = This->dwBumperLength;
373   return S_OK;
374 }
375
376 static HRESULT WINAPI IDirectMusicPerformance8Impl_SendPMsg(IDirectMusicPerformance8 *iface,
377         DMUS_PMSG *pPMSG)
378 {
379   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
380   DMUS_PMSGItem* pItem = NULL;
381   DMUS_PMSGItem* it = NULL;
382   DMUS_PMSGItem* prev_it = NULL;
383   DMUS_PMSGItem** queue = NULL;
384
385   FIXME("(%p, %p): stub\n", This, pPMSG);
386          
387   if (NULL == pPMSG) {
388     return E_POINTER;
389   }
390   pItem = DMUS_PMSGToItem(pPMSG);
391   if (NULL == pItem) {
392     return E_POINTER;
393   }
394   if (pItem->bInUse) {
395     return DMUS_E_ALREADY_SENT;
396   }
397   
398   /* TODO: Valid Flags */
399   /* TODO: DMUS_PMSGF_MUSICTIME */
400   pItem->rtItemTime = pPMSG->rtTime;
401
402   if (pPMSG->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) {
403     queue = &This->imm_head;
404   } else {
405     queue = &This->head;
406   }
407
408   EnterCriticalSection(&This->safe);
409   for (it = *queue; NULL != it && it->rtItemTime < pItem->rtItemTime; it = it->next) {
410     prev_it = it;
411   }
412   if (NULL == prev_it) {
413     pItem->prev = NULL;
414     if (NULL != *queue) pItem->next = (*queue)->next;
415     /*assert( NULL == pItem->next->prev );*/
416     if (NULL != pItem->next) pItem->next->prev = pItem;
417     *queue = pItem;
418   } else {
419     pItem->prev = prev_it;
420     pItem->next = prev_it->next;
421     prev_it->next = pItem;
422     if (NULL != pItem->next) pItem->next->prev = pItem;
423   } 
424   LeaveCriticalSection(&This->safe);
425
426   /** now in use, prevent from stupid Frees */
427   pItem->bInUse = TRUE;
428   return S_OK;
429 }
430
431 static HRESULT WINAPI IDirectMusicPerformance8Impl_MusicToReferenceTime(IDirectMusicPerformance8 *iface,
432         MUSIC_TIME mtTime, REFERENCE_TIME *prtTime)
433 {
434         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
435
436         FIXME("(%p, %d, %p): stub\n", This, mtTime, prtTime);
437         return S_OK;
438 }
439
440 static HRESULT WINAPI IDirectMusicPerformance8Impl_ReferenceToMusicTime(IDirectMusicPerformance8 *iface,
441         REFERENCE_TIME rtTime, MUSIC_TIME *pmtTime)
442 {
443         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
444
445         FIXME("(%p, 0x%s, %p): stub\n", This, wine_dbgstr_longlong(rtTime), pmtTime);
446         return S_OK;
447 }
448
449 static HRESULT WINAPI IDirectMusicPerformance8Impl_IsPlaying(IDirectMusicPerformance8 *iface,
450         IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegState)
451 {
452         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
453
454         FIXME("(%p, %p, %p): stub\n", This, pSegment, pSegState);
455         return S_FALSE;
456 }
457
458 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetTime(IDirectMusicPerformance8 *iface,
459         REFERENCE_TIME *prtNow, MUSIC_TIME *pmtNow)
460 {
461   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
462   HRESULT hr = S_OK;
463   REFERENCE_TIME rtCur = 0;
464
465   /*TRACE("(%p, %p, %p)\n", This, prtNow, pmtNow); */
466   if (This->procThreadTicStarted) {
467     rtCur = ((REFERENCE_TIME) GetTickCount() * 10000) - This->procThreadStartTime;
468   } else {
469     /*return DMUS_E_NO_MASTER_CLOCK;*/
470   }
471   if (NULL != prtNow) {
472     *prtNow = rtCur;
473   }
474   if (NULL != pmtNow) {
475     hr = IDirectMusicPerformance8_ReferenceToMusicTime(iface, rtCur, pmtNow);
476   }
477   return hr;
478 }
479
480 static HRESULT WINAPI IDirectMusicPerformance8Impl_AllocPMsg(IDirectMusicPerformance8 *iface,
481         ULONG cb, DMUS_PMSG **ppPMSG)
482 {
483   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
484   DMUS_PMSGItem* pItem = NULL;
485   
486   FIXME("(%p, %d, %p): stub\n", This, cb, ppPMSG);
487         
488   if (sizeof(DMUS_PMSG) > cb) {
489     return E_INVALIDARG;
490   }
491   if (NULL == ppPMSG) {
492     return E_POINTER;
493   }
494   pItem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb - sizeof(DMUS_PMSG)  + sizeof(DMUS_PMSGItem));
495   if (NULL == pItem) {
496     return E_OUTOFMEMORY;
497   }
498   pItem->pMsg.dwSize = cb;
499   *ppPMSG = DMUS_ItemToPMSG(pItem);
500   return S_OK;
501 }
502
503 static HRESULT WINAPI IDirectMusicPerformance8Impl_FreePMsg(IDirectMusicPerformance8 *iface,
504         DMUS_PMSG *pPMSG)
505 {
506   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
507   DMUS_PMSGItem* pItem = NULL;
508   
509   FIXME("(%p, %p): stub\n", This, pPMSG);
510   
511   if (NULL == pPMSG) {
512     return E_POINTER;
513   }
514   pItem = DMUS_PMSGToItem(pPMSG);
515   if (NULL == pItem) {
516     return E_POINTER;
517   }
518   if (pItem->bInUse) {
519     /** prevent for freeing PMsg in queue (ie to be processed) */
520     return DMUS_E_CANNOT_FREE;
521   }
522   /** now we can remove it safely */
523   EnterCriticalSection(&This->safe);
524   DMUS_ItemRemoveFromQueue( This, pItem );
525   LeaveCriticalSection(&This->safe);
526
527   /** TODO: see if we should Release the pItem->pMsg->punkUser and others Interfaces */
528   HeapFree(GetProcessHeap(), 0, pItem);  
529   return S_OK;
530 }
531
532 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetGraph(IDirectMusicPerformance8 *iface,
533         IDirectMusicGraph **ppGraph)
534 {
535   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
536
537   FIXME("(%p, %p): to check\n", This, ppGraph);
538   if (NULL != This->pToolGraph) {
539     *ppGraph = This->pToolGraph;
540     IDirectMusicGraph_AddRef(*ppGraph);
541   } else {
542     return E_FAIL;
543   }
544   return S_OK;
545 }
546
547 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetGraph(IDirectMusicPerformance8 *iface,
548         IDirectMusicGraph *pGraph)
549 {
550   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
551
552   FIXME("(%p, %p): to check\n", This, pGraph);
553   
554   if (NULL != This->pToolGraph) {
555     /* Todo clean buffers and tools before */
556     IDirectMusicGraph_Release(This->pToolGraph);
557   }
558   This->pToolGraph = pGraph;
559   if (NULL != This->pToolGraph) {
560     IDirectMusicGraph_AddRef(This->pToolGraph);
561   }
562   return S_OK;
563 }
564
565 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetNotificationHandle(IDirectMusicPerformance8 *iface,
566         HANDLE hNotification, REFERENCE_TIME rtMinimum)
567 {
568   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
569
570   FIXME("(%p, %p, 0x%s): stub\n", This, hNotification, wine_dbgstr_longlong(rtMinimum));
571   This->hNotification = hNotification;
572   if (rtMinimum) This->rtMinimum = rtMinimum;
573   return S_OK;
574 }
575
576 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetNotificationPMsg(IDirectMusicPerformance8 *iface,
577         DMUS_NOTIFICATION_PMSG **ppNotificationPMsg)
578 {
579   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
580
581   FIXME("(%p, %p): stub\n", This, ppNotificationPMsg);
582   if (NULL == ppNotificationPMsg) {
583     return E_POINTER;
584   }
585   
586   
587
588   return S_FALSE;
589   /*return S_OK;*/
590 }
591
592 static HRESULT WINAPI IDirectMusicPerformance8Impl_AddNotificationType(IDirectMusicPerformance8 *iface,
593         REFGUID rguidNotificationType)
594 {
595         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
596
597         FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType));
598         return S_OK;
599 }
600
601 static HRESULT WINAPI IDirectMusicPerformance8Impl_RemoveNotificationType(IDirectMusicPerformance8 *iface,
602         REFGUID rguidNotificationType)
603 {
604         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
605
606         FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType));
607         return S_OK;
608 }
609
610 static HRESULT WINAPI IDirectMusicPerformance8Impl_AddPort(IDirectMusicPerformance8 *iface,
611         IDirectMusicPort *pPort)
612 {
613         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
614         HRESULT hr = E_FAIL;
615
616         FIXME("(%p, %p): stub\n", This, pPort);
617         if (!This->pDirectMusic || !This->pDirectSound) return DMUS_E_NOT_INIT;
618         if (NULL == pPort) {
619           GUID port_guid;
620           IDirectMusicPort* pDefaultPort = NULL;
621           DMUS_PORTPARAMS params;
622           int i, j;
623           hr = IDirectMusic8_GetDefaultPort(This->pDirectMusic, &port_guid);
624           if (FAILED(hr)) return hr;
625           ZeroMemory(&params, sizeof(params)); 
626           params.dwSize = sizeof(params);
627           params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS | DMUS_PORTPARAMS_SHARE;
628           params.dwChannelGroups = 1;
629           params.fShare = TRUE;
630           hr = IDirectMusic8_CreatePort(This->pDirectMusic, &port_guid, &params, &pDefaultPort, NULL);
631           if (FAILED(hr)) return hr;
632           hr = IDirectMusicPort_Activate(pDefaultPort, TRUE);
633           if (FAILED(hr)) { IDirectMusicPort_Release(pDefaultPort); return hr; }
634           j = 0;
635           for (i = 0; i < 16; ++i) {
636             if (NULL == This->PChannel[i].port) {
637               This->PChannel[i].port = pPort; 
638               This->PChannel[i].group = 0; 
639               This->PChannel[i].channel = j; /* FIXME: should this be assigned? */
640               j++;
641             }
642           }
643         } else {
644           IDirectMusicPort_AddRef(pPort);         
645         }
646         /**
647          * We should remember added Ports (for example using a list)
648          * and control if Port is registered for each api who use ports
649          */
650         return S_OK;
651 }
652
653 static HRESULT WINAPI IDirectMusicPerformance8Impl_RemovePort(IDirectMusicPerformance8 *iface,
654         IDirectMusicPort *pPort)
655 {
656         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
657
658         FIXME("(%p, %p): stub\n", This, pPort);
659         IDirectMusicPort_Release (pPort);
660         return S_OK;
661 }
662
663 static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannelBlock(IDirectMusicPerformance8 *iface,
664         DWORD dwBlockNum, IDirectMusicPort *pPort, DWORD dwGroup)
665 {
666         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
667         int i, j, range /* min value in range */;
668
669         FIXME("(%p, %d, %p, %d): semi-stub\n", This, dwBlockNum, pPort, dwGroup-1);
670         if (NULL == pPort) return E_POINTER;
671
672         range = 16 * dwBlockNum;
673         j = 0;
674         for (i = range; i < range+16; i++) {
675                 /*TRACE("Setting PChannel[%i] to port %p, group %ld, MIDI port %i\n", i, pPort, dwGroup-1, j); */
676                 This->PChannel[i].port = pPort; 
677                 This->PChannel[i].group = dwGroup - 1; /* first index is always zero */
678                 This->PChannel[i].channel = j; /* FIXME: should this be assigned? */
679                 j++;
680         }
681         /*if (dwGroup > 2) return S_FALSE;*/
682
683         return S_OK;
684 }
685
686 static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannel(IDirectMusicPerformance8 *iface,
687         DWORD dwPChannel, IDirectMusicPort *pPort, DWORD dwGroup, DWORD dwMChannel)
688 {
689         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
690
691         TRACE("(%p, %d, %p, %d, %d)\n", This, dwPChannel, pPort, dwGroup, dwMChannel);
692         if (NULL == pPort) return E_POINTER;
693         This->PChannel[dwPChannel].port = pPort; 
694         This->PChannel[dwPChannel].group = dwGroup; 
695         This->PChannel[dwPChannel].channel = dwMChannel;
696
697         return S_OK;
698 }
699
700 static HRESULT WINAPI IDirectMusicPerformance8Impl_PChannelInfo(IDirectMusicPerformance8 *iface,
701         DWORD dwPChannel, IDirectMusicPort **ppPort, DWORD *pdwGroup, DWORD *pdwMChannel)
702 {
703         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
704         DMUS_PORTPARAMS8 dmusportparams;
705         GUID def;
706
707         FIXME("(%p, %d, %p, %p, %p): stub\n", This, dwPChannel, ppPort, pdwGroup, pdwMChannel);
708
709         dmusportparams.dwSize = sizeof(DMUS_PORTPARAMS8);
710         dmusportparams.dwValidParams = 0;
711         IDirectMusic8_GetDefaultPort(This->pDirectMusic, &def);
712         IDirectMusic8_CreatePort(This->pDirectMusic, &def, &dmusportparams, ppPort, NULL);
713
714         return S_OK;
715 }
716
717 static HRESULT WINAPI IDirectMusicPerformance8Impl_DownloadInstrument(IDirectMusicPerformance8 *iface,
718         IDirectMusicInstrument *pInst, DWORD dwPChannel,
719         IDirectMusicDownloadedInstrument **ppDownInst, DMUS_NOTERANGE *pNoteRanges,
720         DWORD dwNumNoteRanges, IDirectMusicPort **ppPort, DWORD *pdwGroup, DWORD *pdwMChannel)
721 {
722         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
723
724         FIXME("(%p, %p, %d, %p, %p, %d, %p, %p, %p): stub\n", This, pInst, dwPChannel, ppDownInst, pNoteRanges, dwNumNoteRanges, ppPort, pdwGroup, pdwMChannel);
725         return S_OK;
726 }
727
728 static HRESULT WINAPI IDirectMusicPerformance8Impl_Invalidate(IDirectMusicPerformance8 *iface,
729         MUSIC_TIME mtTime, DWORD dwFlags)
730 {
731         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
732
733         FIXME("(%p, %d, %d): stub\n", This, mtTime, dwFlags);
734         return S_OK;
735 }
736
737 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetParam(IDirectMusicPerformance8 *iface,
738         REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime,
739         MUSIC_TIME *pmtNext, void *pParam)
740 {
741         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
742
743         FIXME("(%p, %s, %d, %d, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pmtNext, pParam);
744         return S_OK;
745 }
746
747 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetParam(IDirectMusicPerformance8 *iface,
748         REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam)
749 {
750         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
751
752         FIXME("(%p, %s, %d, %d, %d, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pParam);
753         return S_OK;
754 }
755
756 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetGlobalParam(IDirectMusicPerformance8 *iface,
757         REFGUID rguidType, void *pParam, DWORD dwSize)
758 {
759         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
760
761         TRACE("(%p, %s, %p, %d): stub\n", This, debugstr_dmguid(rguidType), pParam, dwSize);
762         
763         if (IsEqualGUID (rguidType, &GUID_PerfAutoDownload))
764                 memcpy(pParam, &This->fAutoDownload, sizeof(This->fAutoDownload));
765         if (IsEqualGUID (rguidType, &GUID_PerfMasterGrooveLevel))
766                 memcpy(pParam, &This->cMasterGrooveLevel, sizeof(This->cMasterGrooveLevel));
767         if (IsEqualGUID (rguidType, &GUID_PerfMasterTempo))
768                 memcpy(pParam, &This->fMasterTempo, sizeof(This->fMasterTempo));
769         if (IsEqualGUID (rguidType, &GUID_PerfMasterVolume))
770                 memcpy(pParam, &This->lMasterVolume, sizeof(This->lMasterVolume));
771
772         return S_OK;
773 }
774
775 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetGlobalParam(IDirectMusicPerformance8 *iface,
776         REFGUID rguidType, void *pParam, DWORD dwSize)
777 {
778         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
779
780         TRACE("(%p, %s, %p, %d)\n", This, debugstr_dmguid(rguidType), pParam, dwSize);
781         
782         if (IsEqualGUID (rguidType, &GUID_PerfAutoDownload)) {
783                 memcpy(&This->fAutoDownload, pParam, dwSize);
784                 TRACE("=> AutoDownload set to %d\n", This->fAutoDownload);
785         }
786         if (IsEqualGUID (rguidType, &GUID_PerfMasterGrooveLevel)) {
787                 memcpy(&This->cMasterGrooveLevel, pParam, dwSize);
788                 TRACE("=> MasterGrooveLevel set to %i\n", This->cMasterGrooveLevel);
789         }
790         if (IsEqualGUID (rguidType, &GUID_PerfMasterTempo)) {
791                 memcpy(&This->fMasterTempo, pParam, dwSize);
792                 TRACE("=> MasterTempo set to %f\n", This->fMasterTempo);
793         }
794         if (IsEqualGUID (rguidType, &GUID_PerfMasterVolume)) {
795                 memcpy(&This->lMasterVolume, pParam, dwSize);
796                 TRACE("=> MasterVolume set to %li\n", This->lMasterVolume);
797         }
798
799         return S_OK;
800 }
801
802 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetLatencyTime(IDirectMusicPerformance8 *iface,
803         REFERENCE_TIME *prtTime)
804 {
805         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
806
807         TRACE("(%p, %p): stub\n", This, prtTime);
808         *prtTime = This->rtLatencyTime;
809         return S_OK;
810 }
811
812 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetQueueTime(IDirectMusicPerformance8 *iface,
813         REFERENCE_TIME *prtTime)
814
815 {
816         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
817
818         FIXME("(%p, %p): stub\n", This, prtTime);
819         return S_OK;
820 }
821
822 static HRESULT WINAPI IDirectMusicPerformance8Impl_AdjustTime(IDirectMusicPerformance8 *iface,
823         REFERENCE_TIME rtAmount)
824 {
825         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
826
827         FIXME("(%p, 0x%s): stub\n", This, wine_dbgstr_longlong(rtAmount));
828         return S_OK;
829 }
830
831 static HRESULT WINAPI IDirectMusicPerformance8Impl_CloseDown(IDirectMusicPerformance8 *iface)
832 {
833   IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
834
835   FIXME("(%p): stub\n", This);
836   if (PostMessageToProcessMsgThread(This, PROCESSMSG_EXIT)) {
837     WaitForSingleObject(This->procThread, INFINITE);
838     This->procThreadTicStarted = FALSE;
839     CloseHandle(This->procThread);
840   }
841   if (NULL != This->pDirectSound) {
842     IDirectSound_Release(This->pDirectSound);
843     This->pDirectSound = NULL;
844   }
845   if (NULL != This->pDirectMusic) {
846     IDirectMusic8_Release(This->pDirectMusic);
847     This->pDirectMusic = NULL;
848   }
849   return S_OK;
850 }
851
852 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetResolvedTime(IDirectMusicPerformance8 *iface,
853         REFERENCE_TIME rtTime, REFERENCE_TIME *prtResolved, DWORD dwTimeResolveFlags)
854 {
855         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
856
857         FIXME("(%p, 0x%s, %p, %d): stub\n", This, wine_dbgstr_longlong(rtTime),
858             prtResolved, dwTimeResolveFlags);
859         return S_OK;
860 }
861
862 static HRESULT WINAPI IDirectMusicPerformance8Impl_MIDIToMusic(IDirectMusicPerformance8 *iface,
863         BYTE bMIDIValue, DMUS_CHORD_KEY *pChord, BYTE bPlayMode, BYTE bChordLevel,
864         WORD *pwMusicValue)
865 {
866         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
867
868         FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This, bMIDIValue, pChord, bPlayMode, bChordLevel, pwMusicValue);
869         return S_OK;
870 }
871
872 static HRESULT WINAPI IDirectMusicPerformance8Impl_MusicToMIDI(IDirectMusicPerformance8 *iface,
873         WORD wMusicValue, DMUS_CHORD_KEY *pChord, BYTE bPlayMode, BYTE bChordLevel,
874         BYTE *pbMIDIValue)
875 {
876         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
877
878         FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This, wMusicValue, pChord, bPlayMode, bChordLevel, pbMIDIValue);
879         return S_OK;
880 }
881
882 static HRESULT WINAPI IDirectMusicPerformance8Impl_TimeToRhythm(IDirectMusicPerformance8 *iface,
883         MUSIC_TIME mtTime, DMUS_TIMESIGNATURE *pTimeSig, WORD *pwMeasure, BYTE *pbBeat,
884         BYTE *pbGrid, short *pnOffset)
885 {
886         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
887
888         FIXME("(%p, %d, %p, %p, %p, %p, %p): stub\n", This, mtTime, pTimeSig, pwMeasure, pbBeat, pbGrid, pnOffset);
889         return S_OK;
890 }
891
892 static HRESULT WINAPI IDirectMusicPerformance8Impl_RhythmToTime(IDirectMusicPerformance8 *iface,
893         WORD wMeasure, BYTE bBeat, BYTE bGrid, short nOffset, DMUS_TIMESIGNATURE *pTimeSig,
894         MUSIC_TIME *pmtTime)
895 {
896         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
897
898         FIXME("(%p, %d, %d, %d, %i, %p, %p): stub\n", This, wMeasure, bBeat, bGrid, nOffset, pTimeSig, pmtTime);
899         return S_OK;
900 }
901
902 /* IDirectMusicPerformance8 Interface part follow: */
903 static HRESULT WINAPI IDirectMusicPerformance8Impl_InitAudio(IDirectMusicPerformance8 *iface,
904         IDirectMusic **ppDirectMusic, IDirectSound **ppDirectSound, HWND hWnd,
905         DWORD dwDefaultPathType, DWORD dwPChannelCount, DWORD dwFlags, DMUS_AUDIOPARAMS* pParams)
906 {
907         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
908         IDirectSound* dsound = NULL;
909         HRESULT hr = S_OK;
910
911         FIXME("(%p, %p, %p, %p, %x, %u, %x, %p): to check\n", This, ppDirectMusic, ppDirectSound, hWnd, dwDefaultPathType, dwPChannelCount, dwFlags, pParams);
912
913         if (This->pDirectMusic || This->pDirectSound)
914           return DMUS_E_ALREADY_INITED;
915
916         if (NULL != ppDirectSound && NULL != *ppDirectSound) {
917           dsound = *ppDirectSound;
918         } else {
919           hr = DirectSoundCreate8 (NULL, (LPDIRECTSOUND8*) &dsound, NULL);
920           FIXME("return dsound(%p,%d)\n", dsound, hr);
921           if (FAILED(hr) || !dsound)
922             return DSERR_NODRIVER;
923           if (ppDirectSound)
924             *ppDirectSound = dsound;  
925         }
926         
927         IDirectMusicPerformance8Impl_Init(iface, ppDirectMusic, dsound, hWnd);
928
929         /* Init increases the ref count of the dsound object. Decrement it if the app doesn't want a pointer to the object. */
930         if (NULL == ppDirectSound) {
931           IDirectSound_Release(This->pDirectSound);
932         }
933
934         /* as seen in msdn we need params init before audio path creation */
935         if (NULL != pParams) {
936           This->pParams = *pParams;
937         } else {
938           /* TODO, how can i fill the struct as seen on msdn */
939           memset(&This->pParams, 0, sizeof(DMUS_AUDIOPARAMS));
940           This->pParams.dwSize = sizeof(DMUS_AUDIOPARAMS);
941           This->pParams.fInitNow = FALSE;
942           This->pParams.dwValidData = DMUS_AUDIOPARAMS_FEATURES | DMUS_AUDIOPARAMS_VOICES | DMUS_AUDIOPARAMS_SAMPLERATE | DMUS_AUDIOPARAMS_DEFAULTSYNTH;
943           This->pParams.dwVoices = 64;
944           This->pParams.dwSampleRate = (DWORD) 22.050; 
945           This->pParams.dwFeatures = dwFlags;
946           This->pParams.clsidDefaultSynth = CLSID_DirectMusicSynthSink;
947         }
948         hr = IDirectMusicPerformance8_CreateStandardAudioPath(iface, dwDefaultPathType, dwPChannelCount, FALSE, &This->pDefaultPath);
949
950         PostMessageToProcessMsgThread(This, PROCESSMSG_START);
951
952         return hr;
953 }
954
955 static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegmentEx(IDirectMusicPerformance8 *iface,
956         IUnknown *pSource, WCHAR *pwzSegmentName, IUnknown *pTransition, DWORD dwFlags,
957         __int64 i64StartTime, IDirectMusicSegmentState **ppSegmentState, IUnknown *pFrom,
958         IUnknown *pAudioPath)
959 {
960         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
961
962         FIXME("(%p, %p, %p, %p, %d, 0x%s, %p, %p, %p): stub\n", This, pSource, pwzSegmentName,
963             pTransition, dwFlags, wine_dbgstr_longlong(i64StartTime), ppSegmentState, pFrom, pAudioPath);
964         if (ppSegmentState)
965           return DMUSIC_CreateDirectMusicSegmentStateImpl(&IID_IDirectMusicSegmentState, (LPVOID*)ppSegmentState, NULL);
966         return S_OK;
967 }
968
969 static HRESULT WINAPI IDirectMusicPerformance8Impl_StopEx(IDirectMusicPerformance8 *iface,
970         IUnknown *pObjectToStop, __int64 i64StopTime, DWORD dwFlags)
971 {
972         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
973
974         FIXME("(%p, %p, 0x%s, %d): stub\n", This, pObjectToStop,
975             wine_dbgstr_longlong(i64StopTime), dwFlags);
976         return S_OK;
977 }
978
979 static HRESULT WINAPI IDirectMusicPerformance8Impl_ClonePMsg(IDirectMusicPerformance8 *iface,
980         DMUS_PMSG *pSourcePMSG, DMUS_PMSG **ppCopyPMSG)
981 {
982         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
983
984         FIXME("(%p, %p, %p): stub\n", This, pSourcePMSG, ppCopyPMSG);
985         return S_OK;
986 }
987
988 static HRESULT WINAPI IDirectMusicPerformance8Impl_CreateAudioPath(IDirectMusicPerformance8 *iface,
989         IUnknown *pSourceConfig, BOOL fActivate, IDirectMusicAudioPath **ppNewPath)
990 {
991         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
992         IDirectMusicAudioPathImpl *default_path;
993         IDirectMusicAudioPath *pPath;
994
995         FIXME("(%p, %p, %d, %p): stub\n", This, pSourceConfig, fActivate, ppNewPath);
996
997         if (NULL == ppNewPath) {
998           return E_POINTER;
999         }
1000
1001         DMUSIC_CreateDirectMusicAudioPathImpl (&IID_IDirectMusicAudioPath, (LPVOID*)&pPath, NULL);
1002         default_path = (IDirectMusicAudioPathImpl*)((char*)(pPath) - offsetof(IDirectMusicAudioPathImpl,AudioPathVtbl));
1003         default_path->pPerf = &This->IDirectMusicPerformance8_iface;
1004
1005         /** TODO */
1006         
1007         *ppNewPath = pPath;
1008
1009         return IDirectMusicAudioPath_Activate(*ppNewPath, fActivate);
1010 }
1011
1012 static HRESULT WINAPI IDirectMusicPerformance8Impl_CreateStandardAudioPath(IDirectMusicPerformance8 *iface,
1013         DWORD dwType, DWORD dwPChannelCount, BOOL fActivate, IDirectMusicAudioPath **ppNewPath)
1014 {
1015         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1016         IDirectMusicAudioPathImpl *default_path;
1017         IDirectMusicAudioPath *pPath;
1018         DSBUFFERDESC desc;
1019         WAVEFORMATEX format;
1020         LPDIRECTSOUNDBUFFER buffer;
1021         HRESULT hr = S_OK;
1022
1023         FIXME("(%p)->(%d, %d, %d, %p): semi-stub\n", This, dwType, dwPChannelCount, fActivate, ppNewPath);
1024
1025         if (NULL == ppNewPath) {
1026           return E_POINTER;
1027         }
1028         
1029         DMUSIC_CreateDirectMusicAudioPathImpl (&IID_IDirectMusicAudioPath, (LPVOID*)&pPath, NULL);
1030         default_path = (IDirectMusicAudioPathImpl*)((char*)(pPath) - offsetof(IDirectMusicAudioPathImpl,AudioPathVtbl));
1031         default_path->pPerf = &This->IDirectMusicPerformance8_iface;
1032
1033         /* Secondary buffer description */
1034         memset(&format, 0, sizeof(format));
1035         format.wFormatTag = WAVE_FORMAT_PCM;
1036         format.nChannels = 1;
1037         format.nSamplesPerSec = 44000;
1038         format.nAvgBytesPerSec = 44000*2;
1039         format.nBlockAlign = 2;
1040         format.wBitsPerSample = 16;
1041         format.cbSize = 0;
1042         
1043         memset(&desc, 0, sizeof(desc));
1044         desc.dwSize = sizeof(desc);
1045         desc.dwFlags = DSBCAPS_CTRLFX | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS;
1046         desc.dwBufferBytes = DSBSIZE_MIN;
1047         desc.dwReserved = 0;
1048         desc.lpwfxFormat = &format;
1049         desc.guid3DAlgorithm = GUID_NULL;
1050         
1051         switch(dwType) {
1052         case DMUS_APATH_DYNAMIC_3D:
1053                 desc.dwFlags |= DSBCAPS_CTRL3D | DSBCAPS_CTRLFREQUENCY | DSBCAPS_MUTE3DATMAXDISTANCE;
1054                 break;
1055         case DMUS_APATH_DYNAMIC_MONO:
1056                 desc.dwFlags |= DSBCAPS_CTRLFREQUENCY;
1057                 break;
1058         case DMUS_APATH_SHARED_STEREOPLUSREVERB:
1059                 /* normally we have to create 2 buffers (one for music other for reverb)
1060                  * in this case. See msdn
1061                  */
1062         case DMUS_APATH_DYNAMIC_STEREO:
1063                 desc.dwFlags |= DSBCAPS_CTRLFREQUENCY;
1064                 format.nChannels = 2;
1065                 format.nBlockAlign *= 2;
1066                 format.nAvgBytesPerSec *=2;
1067                 break;
1068         default:
1069                 HeapFree(GetProcessHeap(), 0, default_path); 
1070                 *ppNewPath = NULL;
1071                 return E_INVALIDARG;
1072         }
1073
1074         /* FIXME: Should we create one secondary buffer for each PChannel? */
1075         hr = IDirectSound8_CreateSoundBuffer ((LPDIRECTSOUND8) This->pDirectSound, &desc, &buffer, NULL);
1076         if (FAILED(hr)) {
1077                 HeapFree(GetProcessHeap(), 0, default_path); 
1078                 *ppNewPath = NULL;
1079                 return DSERR_BUFFERLOST;
1080         }
1081         default_path->pDSBuffer = buffer;
1082
1083         /* Update description for creating primary buffer */
1084         desc.dwFlags |= DSBCAPS_PRIMARYBUFFER;
1085         desc.dwBufferBytes = 0;
1086         desc.lpwfxFormat = NULL;
1087
1088         hr = IDirectSound8_CreateSoundBuffer ((LPDIRECTSOUND8) This->pDirectSound, &desc, &buffer, NULL);
1089         if (FAILED(hr)) {
1090                 IDirectSoundBuffer_Release(default_path->pDSBuffer);
1091                 HeapFree(GetProcessHeap(), 0, default_path); 
1092                 *ppNewPath = NULL;
1093                 return DSERR_BUFFERLOST;
1094         }
1095         default_path->pPrimary = buffer;
1096
1097         *ppNewPath = pPath;
1098         
1099         TRACE(" returning IDirectMusicPerformance interface at %p.\n", *ppNewPath);
1100
1101         return IDirectMusicAudioPath_Activate(*ppNewPath, fActivate);
1102 }
1103
1104 static HRESULT WINAPI IDirectMusicPerformance8Impl_SetDefaultAudioPath(IDirectMusicPerformance8 *iface,
1105         IDirectMusicAudioPath *pAudioPath)
1106 {
1107         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1108
1109         FIXME("(%p, %p): semi-stub\n", This, pAudioPath);
1110         if (NULL != This->pDefaultPath) {
1111                 IDirectMusicAudioPath_Release(This->pDefaultPath);
1112                 ((IDirectMusicAudioPathImpl*) This->pDefaultPath)->pPerf = NULL;
1113                 This->pDefaultPath = NULL;
1114         }
1115         This->pDefaultPath = pAudioPath;
1116         if (NULL != This->pDefaultPath) {
1117                 IDirectMusicAudioPath_AddRef(This->pDefaultPath);
1118                 ((IDirectMusicAudioPathImpl*)This->pDefaultPath)->pPerf = &This->IDirectMusicPerformance8_iface;
1119         }
1120
1121         return S_OK;
1122 }
1123
1124 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetDefaultAudioPath(IDirectMusicPerformance8 *iface,
1125         IDirectMusicAudioPath **ppAudioPath)
1126 {
1127         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1128
1129         FIXME("(%p, %p): semi-stub (%p)\n", This, ppAudioPath, This->pDefaultPath);
1130
1131         if (NULL != This->pDefaultPath) {
1132           *ppAudioPath = This->pDefaultPath;
1133           IDirectMusicAudioPath_AddRef(*ppAudioPath);
1134         } else {
1135           *ppAudioPath = NULL;
1136         }
1137         return S_OK;
1138 }
1139
1140 static HRESULT WINAPI IDirectMusicPerformance8Impl_GetParamEx(IDirectMusicPerformance8 *iface,
1141         REFGUID rguidType, DWORD dwTrackID, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime,
1142         MUSIC_TIME *pmtNext, void *pParam)
1143 {
1144         IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1145
1146         FIXME("(%p, %s, %d, %d, %d, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), dwTrackID, dwGroupBits, dwIndex, mtTime, pmtNext, pParam);
1147
1148         return S_OK;
1149 }
1150
1151 static const IDirectMusicPerformance8Vtbl DirectMusicPerformance8_Vtbl = {
1152         IDirectMusicPerformance8Impl_QueryInterface,
1153         IDirectMusicPerformance8Impl_AddRef,
1154         IDirectMusicPerformance8Impl_Release,
1155         IDirectMusicPerformance8Impl_Init,
1156         IDirectMusicPerformance8Impl_PlaySegment,
1157         IDirectMusicPerformance8Impl_Stop,
1158         IDirectMusicPerformance8Impl_GetSegmentState,
1159         IDirectMusicPerformance8Impl_SetPrepareTime,
1160         IDirectMusicPerformance8Impl_GetPrepareTime,
1161         IDirectMusicPerformance8Impl_SetBumperLength,
1162         IDirectMusicPerformance8Impl_GetBumperLength,
1163         IDirectMusicPerformance8Impl_SendPMsg,
1164         IDirectMusicPerformance8Impl_MusicToReferenceTime,
1165         IDirectMusicPerformance8Impl_ReferenceToMusicTime,
1166         IDirectMusicPerformance8Impl_IsPlaying,
1167         IDirectMusicPerformance8Impl_GetTime,
1168         IDirectMusicPerformance8Impl_AllocPMsg,
1169         IDirectMusicPerformance8Impl_FreePMsg,
1170         IDirectMusicPerformance8Impl_GetGraph,
1171         IDirectMusicPerformance8Impl_SetGraph,
1172         IDirectMusicPerformance8Impl_SetNotificationHandle,
1173         IDirectMusicPerformance8Impl_GetNotificationPMsg,
1174         IDirectMusicPerformance8Impl_AddNotificationType,
1175         IDirectMusicPerformance8Impl_RemoveNotificationType,
1176         IDirectMusicPerformance8Impl_AddPort,
1177         IDirectMusicPerformance8Impl_RemovePort,
1178         IDirectMusicPerformance8Impl_AssignPChannelBlock,
1179         IDirectMusicPerformance8Impl_AssignPChannel,
1180         IDirectMusicPerformance8Impl_PChannelInfo,
1181         IDirectMusicPerformance8Impl_DownloadInstrument,
1182         IDirectMusicPerformance8Impl_Invalidate,
1183         IDirectMusicPerformance8Impl_GetParam,
1184         IDirectMusicPerformance8Impl_SetParam,
1185         IDirectMusicPerformance8Impl_GetGlobalParam,
1186         IDirectMusicPerformance8Impl_SetGlobalParam,
1187         IDirectMusicPerformance8Impl_GetLatencyTime,
1188         IDirectMusicPerformance8Impl_GetQueueTime,
1189         IDirectMusicPerformance8Impl_AdjustTime,
1190         IDirectMusicPerformance8Impl_CloseDown,
1191         IDirectMusicPerformance8Impl_GetResolvedTime,
1192         IDirectMusicPerformance8Impl_MIDIToMusic,
1193         IDirectMusicPerformance8Impl_MusicToMIDI,
1194         IDirectMusicPerformance8Impl_TimeToRhythm,
1195         IDirectMusicPerformance8Impl_RhythmToTime,
1196         IDirectMusicPerformance8Impl_InitAudio,
1197         IDirectMusicPerformance8Impl_PlaySegmentEx,
1198         IDirectMusicPerformance8Impl_StopEx,
1199         IDirectMusicPerformance8Impl_ClonePMsg,
1200         IDirectMusicPerformance8Impl_CreateAudioPath,
1201         IDirectMusicPerformance8Impl_CreateStandardAudioPath,
1202         IDirectMusicPerformance8Impl_SetDefaultAudioPath,
1203         IDirectMusicPerformance8Impl_GetDefaultAudioPath,
1204         IDirectMusicPerformance8Impl_GetParamEx
1205 };
1206
1207 /* for ClassFactory */
1208 HRESULT WINAPI DMUSIC_CreateDirectMusicPerformanceImpl (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter) {
1209         IDirectMusicPerformance8Impl *obj;
1210
1211         TRACE("(%p,%p,%p)\n", lpcGUID, ppobj, pUnkOuter);
1212
1213         if (pUnkOuter) {
1214                 *ppobj = NULL;
1215                 return CLASS_E_NOAGGREGATION;
1216         }
1217
1218         obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicPerformance8Impl));
1219         if (NULL == obj) {
1220                 *ppobj = NULL;
1221                 return E_OUTOFMEMORY;
1222         }
1223         obj->IDirectMusicPerformance8_iface.lpVtbl = &DirectMusicPerformance8_Vtbl;
1224         obj->ref = 0;  /* will be inited by QueryInterface */
1225         obj->pDirectMusic = NULL;
1226         obj->pDirectSound = NULL;
1227         obj->pDefaultPath = NULL;
1228         InitializeCriticalSection(&obj->safe);
1229         obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectMusicPerformance8Impl*->safe");
1230
1231         obj->rtLatencyTime  = 100;  /* 100ms TO FIX */
1232         obj->dwBumperLength =   50; /* 50ms default */
1233         obj->dwPrepareTime  = 1000; /* 1000ms default */
1234         return IDirectMusicPerformance8Impl_QueryInterface(&obj->IDirectMusicPerformance8_iface,
1235                                                            lpcGUID, ppobj);
1236 }