performance.c 40.5 KB
Newer Older
1 2
/* IDirectMusicPerformance Implementation
 *
3
 * Copyright (C) 2003-2004 Rok Mandeljc
4
 * Copyright (C) 2003-2004 Raphael Junqueira
5
 *
6 7 8 9
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
10 11 12
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
15
 *
16 17 18
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * 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 26 27
typedef struct IDirectMusicPerformance8Impl {
    IDirectMusicPerformance8 IDirectMusicPerformance8_iface;
    LONG ref;
28
    IDirectMusic8 *dmusic;
29
    IDirectSound *dsound;
30
    IDirectMusicGraph *pToolGraph;
31
    DMUS_AUDIOPARAMS params;
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
    BOOL fAutoDownload;
    char cMasterGrooveLevel;
    float fMasterTempo;
    long lMasterVolume;
    /* performance channels */
    DMUSIC_PRIVATE_PCHANNEL PChannel[32];
    /* IDirectMusicPerformance8Impl fields */
    IDirectMusicAudioPath *pDefaultPath;
    HANDLE hNotification;
    REFERENCE_TIME rtMinimum;
    REFERENCE_TIME rtLatencyTime;
    DWORD dwBumperLength;
    DWORD dwPrepareTime;
    /** Message Processing */
    HANDLE procThread;
    DWORD procThreadId;
    REFERENCE_TIME procThreadStartTime;
    BOOL procThreadTicStarted;
    CRITICAL_SECTION safe;
    struct DMUS_PMSGItem *head;
    struct DMUS_PMSGItem *imm_head;
} IDirectMusicPerformance8Impl;

55 56 57 58 59 60 61 62 63 64
typedef struct DMUS_PMSGItem DMUS_PMSGItem;
struct DMUS_PMSGItem {
  DMUS_PMSGItem* next;
  DMUS_PMSGItem* prev;

  REFERENCE_TIME rtItemTime;
  BOOL bInUse;
  DWORD cb;
  DMUS_PMSG pMsg;
};
65

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
#define DMUS_PMSGToItem(pMSG)   ((DMUS_PMSGItem*) (((unsigned char*) pPMSG) -  offsetof(DMUS_PMSGItem, pMsg)))
#define DMUS_ItemToPMSG(pItem)  (&(pItem->pMsg))
#define DMUS_ItemRemoveFromQueue(This,pItem) \
{\
  if (pItem->prev) pItem->prev->next = pItem->next;\
  if (pItem->next) pItem->next->prev = pItem->prev;\
  if (This->head == pItem) This->head = pItem->next;\
  if (This->imm_head == pItem) This->imm_head = pItem->next;\
  pItem->bInUse = FALSE;\
}

#define PROCESSMSG_START           (WM_APP + 0)
#define PROCESSMSG_EXIT            (WM_APP + 1)
#define PROCESSMSG_REMOVE          (WM_APP + 2)
#define PROCESSMSG_ADD             (WM_APP + 4)


83
static DMUS_PMSGItem* ProceedMsg(IDirectMusicPerformance8Impl* This, DMUS_PMSGItem* cur) {
84 85 86 87 88
  if (cur->pMsg.dwType == DMUS_PMSGT_NOTIFICATION) {
    SetEvent(This->hNotification);
  }	
  DMUS_ItemRemoveFromQueue(This, cur);
  switch (cur->pMsg.dwType) {
89 90
  case DMUS_PMSGT_WAVE:
  case DMUS_PMSGT_TEMPO:   
91 92
  case DMUS_PMSGT_STOP:
  default:
93
    FIXME("Unhandled PMsg Type: 0x%x\n", cur->pMsg.dwType);
94 95
    break;
  }
96
  return cur;
97 98 99
}

static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) {
100
  IDirectMusicPerformance8Impl* This = lpParam;
101
  DWORD timeOut = INFINITE;
102 103 104 105
  MSG msg;
  HRESULT hr;
  REFERENCE_TIME rtCurTime;
  DMUS_PMSGItem* it = NULL;
106
  DMUS_PMSGItem* cur = NULL;
107 108 109 110 111
  DMUS_PMSGItem* it_next = NULL;

  while (TRUE) {
    DWORD dwDec = This->rtLatencyTime + This->dwBumperLength;

112 113 114
    if (timeOut > 0) MsgWaitForMultipleObjects(0, NULL, FALSE, timeOut, QS_POSTMESSAGE|QS_SENDMESSAGE|QS_TIMER);
    timeOut = INFINITE;

115
    EnterCriticalSection(&This->safe);
116
    hr = IDirectMusicPerformance8_GetTime(&This->IDirectMusicPerformance8_iface, &rtCurTime, NULL);
117 118 119 120 121 122
    if (FAILED(hr)) {
      goto outrefresh;
    }
    
    for (it = This->imm_head; NULL != it; ) {
      it_next = it->next;
123
      cur = ProceedMsg(This, it);  
124
      HeapFree(GetProcessHeap(), 0, cur); 
125 126 127 128 129
      it = it_next;
    }

    for (it = This->head; NULL != it && it->rtItemTime < rtCurTime + dwDec; ) {
      it_next = it->next;
130
      cur = ProceedMsg(This, it);
131
      HeapFree(GetProcessHeap(), 0, cur);
132 133
      it = it_next;
    }
134 135 136
    if (NULL != it) {
      timeOut = ( it->rtItemTime - rtCurTime ) + This->rtLatencyTime;
    }
137 138 139 140

outrefresh:
    LeaveCriticalSection(&This->safe);
    
141
    while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
      /** if hwnd we suppose that is a windows event ... */
      if  (NULL != msg.hwnd) {
	TranslateMessage(&msg);
	DispatchMessageA(&msg);
      } else {
	switch (msg.message) {	    
	case WM_QUIT:
	case PROCESSMSG_EXIT:
	  goto outofthread;
	case PROCESSMSG_START:
	  break;
	case PROCESSMSG_ADD:
	  break;
	case PROCESSMSG_REMOVE:
	  break;
	default:
	  ERR("Unhandled message %u. Critical Path\n", msg.message);
	  break;
160
	}
161 162
      }
    }
163 164 165

    /** here we should run a little of current AudioPath */

166 167 168 169 170 171 172 173 174 175
  }

outofthread:
  TRACE("(%p): Exiting\n", This);
  
  return 0;
}

static BOOL PostMessageToProcessMsgThread(IDirectMusicPerformance8Impl* This, UINT iMsg) {
  if (FALSE == This->procThreadTicStarted && PROCESSMSG_EXIT != iMsg) {
176
    BOOL res;
177 178 179 180
    This->procThread = CreateThread(NULL, 0, ProcessMsgThread, This, 0, &This->procThreadId);
    if (NULL == This->procThread) return FALSE;
    SetThreadPriority(This->procThread, THREAD_PRIORITY_TIME_CRITICAL);
    This->procThreadTicStarted = TRUE;
181 182 183 184 185 186 187 188 189
    while(1) {
      res = PostThreadMessageA(This->procThreadId, iMsg, 0, 0);
      /* Let the thread creates its message queue (with MsgWaitForMultipleObjects call) by yielding and retrying */
      if (!res && (GetLastError() == ERROR_INVALID_THREAD_ID))
	Sleep(0);
      else
	break;
    }
    return res;
190 191 192 193
  }
  return PostThreadMessageA(This->procThreadId, iMsg, 0, 0);
}

194 195 196 197 198
static inline IDirectMusicPerformance8Impl *impl_from_IDirectMusicPerformance8(IDirectMusicPerformance8 *iface)
{
    return CONTAINING_RECORD(iface, IDirectMusicPerformance8Impl, IDirectMusicPerformance8_iface);
}

199
/* IDirectMusicPerformance8 IUnknown part: */
200 201 202 203
static HRESULT WINAPI IDirectMusicPerformance8Impl_QueryInterface(IDirectMusicPerformance8 *iface,
        REFIID riid, void **ppv)
{
  TRACE("(%p, %s,%p)\n", iface, debugstr_dmguid(riid), ppv);
204

205
  if (IsEqualIID (riid, &IID_IUnknown) ||
206
      IsEqualIID (riid, &IID_IDirectMusicPerformance) ||
207
      IsEqualIID (riid, &IID_IDirectMusicPerformance2) ||
208
      IsEqualIID (riid, &IID_IDirectMusicPerformance8)) {
209
    *ppv = iface;
210
    IUnknown_AddRef(iface);
211 212
    return S_OK;
  }
213 214

  WARN("(%p, %s,%p): not found\n", iface, debugstr_dmguid(riid), ppv);
215
  return E_NOINTERFACE;
216 217
}

218 219 220
static ULONG WINAPI IDirectMusicPerformance8Impl_AddRef(IDirectMusicPerformance8 *iface)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
221 222
  ULONG ref = InterlockedIncrement(&This->ref);

223
  TRACE("(%p): AddRef from %d\n", This, ref - 1);
224

225 226
  DMIME_LockModule();

227
  return ref;
228 229
}

230 231 232
static ULONG WINAPI IDirectMusicPerformance8Impl_Release(IDirectMusicPerformance8 *iface)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
233
  ULONG ref = InterlockedDecrement(&This->ref);
234

235
  TRACE("(%p): ReleaseRef to %d\n", This, ref);
236
  
237
  if (ref == 0) {
238
    This->safe.DebugInfo->Spare[0] = 0;
239 240 241
    DeleteCriticalSection(&This->safe);
    HeapFree(GetProcessHeap(), 0, This);
  }
242 243 244

  DMIME_UnlockModule();

245
  return ref;
246 247
}

248
/* IDirectMusicPerformanceImpl IDirectMusicPerformance Interface part: */
249
static HRESULT WINAPI IDirectMusicPerformance8Impl_Init(IDirectMusicPerformance8 *iface,
250
        IDirectMusic **dmusic, IDirectSound *dsound, HWND hwnd)
251
{
252
    TRACE("(%p, %p, %p, %p)\n", iface, dmusic, dsound, hwnd);
253

254 255
    return IDirectMusicPerformance8_InitAudio(iface, dmusic, dsound ? &dsound : NULL, hwnd, 0, 0,
            0, NULL);
256 257
}

258 259 260 261 262 263
static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegment(IDirectMusicPerformance8 *iface,
        IDirectMusicSegment *pSegment, DWORD dwFlags, __int64 i64StartTime,
        IDirectMusicSegmentState **ppSegmentState)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

264
	FIXME("(%p, %p, %d, 0x%s, %p): stub\n", This, pSegment, dwFlags,
265
	    wine_dbgstr_longlong(i64StartTime), ppSegmentState);
266
	if (ppSegmentState)
267
          return create_dmsegmentstate(&IID_IDirectMusicSegmentState,(void**)ppSegmentState);
Rok Mandeljc's avatar
Rok Mandeljc committed
268
	return S_OK;
269 270
}

271 272 273 274 275 276
static HRESULT WINAPI IDirectMusicPerformance8Impl_Stop(IDirectMusicPerformance8 *iface,
        IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegmentState, MUSIC_TIME mtTime,
        DWORD dwFlags)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

277
	FIXME("(%p, %p, %p, %d, %d): stub\n", This, pSegment, pSegmentState, mtTime, dwFlags);
Rok Mandeljc's avatar
Rok Mandeljc committed
278
	return S_OK;
279 280
}

281 282 283 284 285
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetSegmentState(IDirectMusicPerformance8 *iface,
        IDirectMusicSegmentState **ppSegmentState, MUSIC_TIME mtTime)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

286
	FIXME("(%p,%p, %d): stub\n", This, ppSegmentState, mtTime);
Rok Mandeljc's avatar
Rok Mandeljc committed
287
	return S_OK;
288 289
}

290 291 292 293 294
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetPrepareTime(IDirectMusicPerformance8 *iface,
        DWORD dwMilliSeconds)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

295
  TRACE("(%p, %d)\n", This, dwMilliSeconds);
296 297
  This->dwPrepareTime = dwMilliSeconds;
  return S_OK;
298 299
}

300 301 302 303 304
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetPrepareTime(IDirectMusicPerformance8 *iface,
        DWORD *pdwMilliSeconds)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

305 306 307 308 309 310
  TRACE("(%p, %p)\n", This, pdwMilliSeconds);
  if (NULL == pdwMilliSeconds) {
    return E_POINTER;
  }
  *pdwMilliSeconds = This->dwPrepareTime;
  return S_OK;
311 312
}

313 314 315 316 317
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetBumperLength(IDirectMusicPerformance8 *iface,
        DWORD dwMilliSeconds)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

318
  TRACE("(%p, %d)\n", This, dwMilliSeconds);
319 320
  This->dwBumperLength =  dwMilliSeconds;
  return S_OK;
321 322
}

323 324 325 326 327
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetBumperLength(IDirectMusicPerformance8 *iface,
        DWORD *pdwMilliSeconds)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

328 329 330 331 332 333
  TRACE("(%p, %p)\n", This, pdwMilliSeconds);
  if (NULL == pdwMilliSeconds) {
    return E_POINTER;
  }
  *pdwMilliSeconds = This->dwBumperLength;
  return S_OK;
334 335
}

336 337 338 339
static HRESULT WINAPI IDirectMusicPerformance8Impl_SendPMsg(IDirectMusicPerformance8 *iface,
        DMUS_PMSG *pPMSG)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
340 341 342 343 344 345 346 347 348 349 350
  DMUS_PMSGItem* pItem = NULL;
  DMUS_PMSGItem* it = NULL;
  DMUS_PMSGItem* prev_it = NULL;
  DMUS_PMSGItem** queue = NULL;

  FIXME("(%p, %p): stub\n", This, pPMSG);
	 
  if (NULL == pPMSG) {
    return E_POINTER;
  }
  pItem = DMUS_PMSGToItem(pPMSG);
351
  if (pItem->bInUse) {
352 353 354 355 356 357 358 359 360 361 362 363 364
    return DMUS_E_ALREADY_SENT;
  }
  
  /* TODO: Valid Flags */
  /* TODO: DMUS_PMSGF_MUSICTIME */
  pItem->rtItemTime = pPMSG->rtTime;

  if (pPMSG->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) {
    queue = &This->imm_head;
  } else {
    queue = &This->head;
  }

365
  EnterCriticalSection(&This->safe);
366 367 368 369 370
  for (it = *queue; NULL != it && it->rtItemTime < pItem->rtItemTime; it = it->next) {
    prev_it = it;
  }
  if (NULL == prev_it) {
    pItem->prev = NULL;
371
    if (NULL != *queue) pItem->next = (*queue)->next;
372 373 374 375 376 377 378 379
    /*assert( NULL == pItem->next->prev );*/
    if (NULL != pItem->next) pItem->next->prev = pItem;
    *queue = pItem;
  } else {
    pItem->prev = prev_it;
    pItem->next = prev_it->next;
    prev_it->next = pItem;
    if (NULL != pItem->next) pItem->next->prev = pItem;
380 381 382
  } 
  LeaveCriticalSection(&This->safe);

383 384 385
  /** now in use, prevent from stupid Frees */
  pItem->bInUse = TRUE;
  return S_OK;
386 387
}

388 389 390 391 392
static HRESULT WINAPI IDirectMusicPerformance8Impl_MusicToReferenceTime(IDirectMusicPerformance8 *iface,
        MUSIC_TIME mtTime, REFERENCE_TIME *prtTime)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

393
	FIXME("(%p, %d, %p): stub\n", This, mtTime, prtTime);
Rok Mandeljc's avatar
Rok Mandeljc committed
394
	return S_OK;
395 396
}

397 398 399 400 401
static HRESULT WINAPI IDirectMusicPerformance8Impl_ReferenceToMusicTime(IDirectMusicPerformance8 *iface,
        REFERENCE_TIME rtTime, MUSIC_TIME *pmtTime)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

402
	FIXME("(%p, 0x%s, %p): stub\n", This, wine_dbgstr_longlong(rtTime), pmtTime);
Rok Mandeljc's avatar
Rok Mandeljc committed
403
	return S_OK;
404 405
}

406 407 408 409 410
static HRESULT WINAPI IDirectMusicPerformance8Impl_IsPlaying(IDirectMusicPerformance8 *iface,
        IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegState)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

Rok Mandeljc's avatar
Rok Mandeljc committed
411
	FIXME("(%p, %p, %p): stub\n", This, pSegment, pSegState);
412
	return S_FALSE;
413 414
}

415 416 417 418
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetTime(IDirectMusicPerformance8 *iface,
        REFERENCE_TIME *prtNow, MUSIC_TIME *pmtNow)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
419 420 421 422
  HRESULT hr = S_OK;
  REFERENCE_TIME rtCur = 0;

  /*TRACE("(%p, %p, %p)\n", This, prtNow, pmtNow); */
423
  if (This->procThreadTicStarted) {
424 425 426 427 428 429 430 431 432 433 434
    rtCur = ((REFERENCE_TIME) GetTickCount() * 10000) - This->procThreadStartTime;
  } else {
    /*return DMUS_E_NO_MASTER_CLOCK;*/
  }
  if (NULL != prtNow) {
    *prtNow = rtCur;
  }
  if (NULL != pmtNow) {
    hr = IDirectMusicPerformance8_ReferenceToMusicTime(iface, rtCur, pmtNow);
  }
  return hr;
435 436
}

437 438 439 440
static HRESULT WINAPI IDirectMusicPerformance8Impl_AllocPMsg(IDirectMusicPerformance8 *iface,
        ULONG cb, DMUS_PMSG **ppPMSG)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
441 442
  DMUS_PMSGItem* pItem = NULL;
  
443
  FIXME("(%p, %d, %p): stub\n", This, cb, ppPMSG);
444 445 446 447 448 449 450 451 452 453 454 455
	
  if (sizeof(DMUS_PMSG) > cb) {
    return E_INVALIDARG;
  }
  if (NULL == ppPMSG) {
    return E_POINTER;
  }
  pItem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb - sizeof(DMUS_PMSG)  + sizeof(DMUS_PMSGItem));
  if (NULL == pItem) {
    return E_OUTOFMEMORY;
  }
  pItem->pMsg.dwSize = cb;
456
  *ppPMSG = DMUS_ItemToPMSG(pItem);
457
  return S_OK;
458 459
}

460 461 462 463
static HRESULT WINAPI IDirectMusicPerformance8Impl_FreePMsg(IDirectMusicPerformance8 *iface,
        DMUS_PMSG *pPMSG)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
464 465 466 467 468 469 470
  DMUS_PMSGItem* pItem = NULL;
  
  FIXME("(%p, %p): stub\n", This, pPMSG);
  
  if (NULL == pPMSG) {
    return E_POINTER;
  }
471
  pItem = DMUS_PMSGToItem(pPMSG);
472
  if (pItem->bInUse) {
473
    /** prevent for freeing PMsg in queue (ie to be processed) */
474
    return DMUS_E_CANNOT_FREE;
475 476
  }
  /** now we can remove it safely */
477
  EnterCriticalSection(&This->safe);
478
  DMUS_ItemRemoveFromQueue( This, pItem );
479 480
  LeaveCriticalSection(&This->safe);

481
  /** TODO: see if we should Release the pItem->pMsg->punkUser and others Interfaces */
482 483
  HeapFree(GetProcessHeap(), 0, pItem);  
  return S_OK;
484 485
}

486 487 488 489 490
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetGraph(IDirectMusicPerformance8 *iface,
        IDirectMusicGraph **ppGraph)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

491 492
  FIXME("(%p, %p): to check\n", This, ppGraph);
  if (NULL != This->pToolGraph) {
493 494
    *ppGraph = This->pToolGraph;
    IDirectMusicGraph_AddRef(*ppGraph);
495 496
  } else {
    return E_FAIL;
497 498
  }
  return S_OK;
499 500
}

501 502 503 504 505
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetGraph(IDirectMusicPerformance8 *iface,
        IDirectMusicGraph *pGraph)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

506 507 508 509
  FIXME("(%p, %p): to check\n", This, pGraph);
  
  if (NULL != This->pToolGraph) {
    /* Todo clean buffers and tools before */
510
    IDirectMusicGraph_Release(This->pToolGraph);
511 512 513
  }
  This->pToolGraph = pGraph;
  if (NULL != This->pToolGraph) {
514
    IDirectMusicGraph_AddRef(This->pToolGraph);
515 516
  }
  return S_OK;
517 518
}

519 520 521 522 523
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetNotificationHandle(IDirectMusicPerformance8 *iface,
        HANDLE hNotification, REFERENCE_TIME rtMinimum)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

524
  FIXME("(%p, %p, 0x%s): stub\n", This, hNotification, wine_dbgstr_longlong(rtMinimum));
525 526 527
  This->hNotification = hNotification;
  if (rtMinimum) This->rtMinimum = rtMinimum;
  return S_OK;
528 529
}

530 531 532 533 534
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetNotificationPMsg(IDirectMusicPerformance8 *iface,
        DMUS_NOTIFICATION_PMSG **ppNotificationPMsg)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

535 536 537 538
  FIXME("(%p, %p): stub\n", This, ppNotificationPMsg);
  if (NULL == ppNotificationPMsg) {
    return E_POINTER;
  }
539 540 541
  
  

542 543
  return S_FALSE;
  /*return S_OK;*/
544 545
}

546 547 548 549 550
static HRESULT WINAPI IDirectMusicPerformance8Impl_AddNotificationType(IDirectMusicPerformance8 *iface,
        REFGUID rguidNotificationType)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

551
	FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType));
Rok Mandeljc's avatar
Rok Mandeljc committed
552
	return S_OK;
553 554
}

555 556 557 558 559
static HRESULT WINAPI IDirectMusicPerformance8Impl_RemoveNotificationType(IDirectMusicPerformance8 *iface,
        REFGUID rguidNotificationType)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

560
	FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType));
Rok Mandeljc's avatar
Rok Mandeljc committed
561
	return S_OK;
562 563
}

564 565 566 567
static HRESULT WINAPI IDirectMusicPerformance8Impl_AddPort(IDirectMusicPerformance8 *iface,
        IDirectMusicPort *pPort)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
568
	HRESULT hr = E_FAIL;
569

Rok Mandeljc's avatar
Rok Mandeljc committed
570
	FIXME("(%p, %p): stub\n", This, pPort);
571 572
        if (!This->dmusic)
          return DMUS_E_NOT_INIT;
573 574 575 576 577
	if (NULL == pPort) {
	  GUID port_guid;
	  IDirectMusicPort* pDefaultPort = NULL;
	  DMUS_PORTPARAMS params;
	  int i, j;
578
          hr = IDirectMusic8_GetDefaultPort(This->dmusic, &port_guid);
579 580 581 582 583 584
	  if (FAILED(hr)) return hr;
	  ZeroMemory(&params, sizeof(params)); 
	  params.dwSize = sizeof(params);
	  params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS | DMUS_PORTPARAMS_SHARE;
	  params.dwChannelGroups = 1;
	  params.fShare = TRUE;
585
          hr = IDirectMusic8_CreatePort(This->dmusic, &port_guid, &params, &pDefaultPort, NULL);
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
	  if (FAILED(hr)) return hr;
	  hr = IDirectMusicPort_Activate(pDefaultPort, TRUE);
	  if (FAILED(hr)) { IDirectMusicPort_Release(pDefaultPort); return hr; }
	  j = 0;
	  for (i = 0; i < 16; ++i) {
	    if (NULL == This->PChannel[i].port) {
	      This->PChannel[i].port = pPort; 
	      This->PChannel[i].group = 0; 
	      This->PChannel[i].channel = j; /* FIXME: should this be assigned? */
	      j++;
	    }
	  }
	} else {
	  IDirectMusicPort_AddRef(pPort);	  
	}
	/**
	 * We should remember added Ports (for example using a list)
	 * and control if Port is registered for each api who use ports
	 */
Rok Mandeljc's avatar
Rok Mandeljc committed
605
	return S_OK;
606 607
}

608 609 610 611 612
static HRESULT WINAPI IDirectMusicPerformance8Impl_RemovePort(IDirectMusicPerformance8 *iface,
        IDirectMusicPort *pPort)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

Rok Mandeljc's avatar
Rok Mandeljc committed
613
	FIXME("(%p, %p): stub\n", This, pPort);
614
	IDirectMusicPort_Release (pPort);
Rok Mandeljc's avatar
Rok Mandeljc committed
615
	return S_OK;
616 617
}

618 619 620 621
static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannelBlock(IDirectMusicPerformance8 *iface,
        DWORD dwBlockNum, IDirectMusicPort *pPort, DWORD dwGroup)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
622
	int i, j, range /* min value in range */;
Rok Mandeljc's avatar
Rok Mandeljc committed
623

624
	FIXME("(%p, %d, %p, %d): semi-stub\n", This, dwBlockNum, pPort, dwGroup-1);
625 626
	if (NULL == pPort) return E_POINTER;

627 628 629 630 631 632 633 634 635
	range = 16 * dwBlockNum;
	j = 0;
	for (i = range; i < range+16; i++) {
		/*TRACE("Setting PChannel[%i] to port %p, group %ld, MIDI port %i\n", i, pPort, dwGroup-1, j); */
		This->PChannel[i].port = pPort; 
		This->PChannel[i].group = dwGroup - 1; /* first index is always zero */
		This->PChannel[i].channel = j; /* FIXME: should this be assigned? */
		j++;
	}
636
	/*if (dwGroup > 2) return S_FALSE;*/
637 638

	return S_OK;
639 640
}

641
static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannel(IDirectMusicPerformance8 *iface,
642
        DWORD PChannel, IDirectMusicPort *port, DWORD group, DWORD MChannel)
643
{
644
    IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
645

646
    TRACE("(%p)->(%d, %p, %d, %d)\n", This, PChannel, port, group, MChannel);
Rok Mandeljc's avatar
Rok Mandeljc committed
647

648 649 650 651 652 653 654 655
    if (!port)
        return E_POINTER;

    This->PChannel[PChannel].port = port;
    This->PChannel[PChannel].group = group;
    This->PChannel[PChannel].channel = MChannel;

    return S_OK;
656 657
}

658
static HRESULT WINAPI IDirectMusicPerformance8Impl_PChannelInfo(IDirectMusicPerformance8 *iface,
659
        DWORD PChannel, IDirectMusicPort **port, DWORD *group, DWORD *MChannel)
660
{
661 662 663
    IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
    DMUS_PORTPARAMS8 port_params;
    GUID default_port;
664

665
    FIXME("(%p)->(%d, %p, %p, %p): stub\n", This, PChannel, port, group, MChannel);
666

667 668
    port_params.dwSize = sizeof(DMUS_PORTPARAMS8);
    port_params.dwValidParams = 0;
669 670
    IDirectMusic8_GetDefaultPort(This->dmusic, &default_port);
    IDirectMusic8_CreatePort(This->dmusic, &default_port, &port_params, port, NULL);
671

672
    return S_OK;
673 674
}

675 676 677 678 679 680 681
static HRESULT WINAPI IDirectMusicPerformance8Impl_DownloadInstrument(IDirectMusicPerformance8 *iface,
        IDirectMusicInstrument *pInst, DWORD dwPChannel,
        IDirectMusicDownloadedInstrument **ppDownInst, DMUS_NOTERANGE *pNoteRanges,
        DWORD dwNumNoteRanges, IDirectMusicPort **ppPort, DWORD *pdwGroup, DWORD *pdwMChannel)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

682
	FIXME("(%p, %p, %d, %p, %p, %d, %p, %p, %p): stub\n", This, pInst, dwPChannel, ppDownInst, pNoteRanges, dwNumNoteRanges, ppPort, pdwGroup, pdwMChannel);
Rok Mandeljc's avatar
Rok Mandeljc committed
683
	return S_OK;
684 685
}

686 687 688 689 690
static HRESULT WINAPI IDirectMusicPerformance8Impl_Invalidate(IDirectMusicPerformance8 *iface,
        MUSIC_TIME mtTime, DWORD dwFlags)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

691
	FIXME("(%p, %d, %d): stub\n", This, mtTime, dwFlags);
Rok Mandeljc's avatar
Rok Mandeljc committed
692
	return S_OK;
693 694
}

695 696 697 698 699 700
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetParam(IDirectMusicPerformance8 *iface,
        REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime,
        MUSIC_TIME *pmtNext, void *pParam)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

701
	FIXME("(%p, %s, %d, %d, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pmtNext, pParam);
Rok Mandeljc's avatar
Rok Mandeljc committed
702
	return S_OK;
703 704
}

705 706 707 708 709
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetParam(IDirectMusicPerformance8 *iface,
        REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

710
	FIXME("(%p, %s, %d, %d, %d, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pParam);
Rok Mandeljc's avatar
Rok Mandeljc committed
711
	return S_OK;
712 713
}

714 715 716 717
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetGlobalParam(IDirectMusicPerformance8 *iface,
        REFGUID rguidType, void *pParam, DWORD dwSize)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
718

719
	TRACE("(%p, %s, %p, %d): stub\n", This, debugstr_dmguid(rguidType), pParam, dwSize);
720
	
721
	if (IsEqualGUID (rguidType, &GUID_PerfAutoDownload))
722
		memcpy(pParam, &This->fAutoDownload, sizeof(This->fAutoDownload));
723
	if (IsEqualGUID (rguidType, &GUID_PerfMasterGrooveLevel))
724
		memcpy(pParam, &This->cMasterGrooveLevel, sizeof(This->cMasterGrooveLevel));
725
	if (IsEqualGUID (rguidType, &GUID_PerfMasterTempo))
726
		memcpy(pParam, &This->fMasterTempo, sizeof(This->fMasterTempo));
727
	if (IsEqualGUID (rguidType, &GUID_PerfMasterVolume))
728
		memcpy(pParam, &This->lMasterVolume, sizeof(This->lMasterVolume));
Rok Mandeljc's avatar
Rok Mandeljc committed
729 730

	return S_OK;
731 732
}

733 734 735 736
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetGlobalParam(IDirectMusicPerformance8 *iface,
        REFGUID rguidType, void *pParam, DWORD dwSize)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
737

738
	TRACE("(%p, %s, %p, %d)\n", This, debugstr_dmguid(rguidType), pParam, dwSize);
739
	
740
	if (IsEqualGUID (rguidType, &GUID_PerfAutoDownload)) {
741 742
		memcpy(&This->fAutoDownload, pParam, dwSize);
		TRACE("=> AutoDownload set to %d\n", This->fAutoDownload);
743
	}
744
	if (IsEqualGUID (rguidType, &GUID_PerfMasterGrooveLevel)) {
745 746
		memcpy(&This->cMasterGrooveLevel, pParam, dwSize);
		TRACE("=> MasterGrooveLevel set to %i\n", This->cMasterGrooveLevel);
747
	}
748
	if (IsEqualGUID (rguidType, &GUID_PerfMasterTempo)) {
749 750
		memcpy(&This->fMasterTempo, pParam, dwSize);
		TRACE("=> MasterTempo set to %f\n", This->fMasterTempo);
751
	}
752
	if (IsEqualGUID (rguidType, &GUID_PerfMasterVolume)) {
753 754
		memcpy(&This->lMasterVolume, pParam, dwSize);
		TRACE("=> MasterVolume set to %li\n", This->lMasterVolume);
755
	}
Rok Mandeljc's avatar
Rok Mandeljc committed
756 757

	return S_OK;
758 759
}

760 761 762 763 764
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetLatencyTime(IDirectMusicPerformance8 *iface,
        REFERENCE_TIME *prtTime)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

765 766
	TRACE("(%p, %p): stub\n", This, prtTime);
	*prtTime = This->rtLatencyTime;
Rok Mandeljc's avatar
Rok Mandeljc committed
767
	return S_OK;
768 769
}

770 771 772 773 774 775
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetQueueTime(IDirectMusicPerformance8 *iface,
        REFERENCE_TIME *prtTime)

{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

Rok Mandeljc's avatar
Rok Mandeljc committed
776 777
	FIXME("(%p, %p): stub\n", This, prtTime);
	return S_OK;
778 779
}

780 781 782 783 784
static HRESULT WINAPI IDirectMusicPerformance8Impl_AdjustTime(IDirectMusicPerformance8 *iface,
        REFERENCE_TIME rtAmount)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

785
	FIXME("(%p, 0x%s): stub\n", This, wine_dbgstr_longlong(rtAmount));
Rok Mandeljc's avatar
Rok Mandeljc committed
786
	return S_OK;
787 788
}

789 790
static HRESULT WINAPI IDirectMusicPerformance8Impl_CloseDown(IDirectMusicPerformance8 *iface)
{
791
    IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
792

793 794 795 796 797 798 799
    FIXME("(%p): semi-stub\n", This);

    if (PostMessageToProcessMsgThread(This, PROCESSMSG_EXIT)) {
        WaitForSingleObject(This->procThread, INFINITE);
        This->procThreadTicStarted = FALSE;
        CloseHandle(This->procThread);
    }
800 801 802 803
    if (This->dsound) {
        IDirectSound_Release(This->dsound);
        This->dsound = NULL;
    }
804
    if (This->dmusic) {
805
        IDirectMusic_SetDirectSound(This->dmusic, NULL, NULL);
806 807 808 809
        IDirectMusic8_Release(This->dmusic);
        This->dmusic = NULL;
    }
    return S_OK;
810 811
}

812 813 814 815 816
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetResolvedTime(IDirectMusicPerformance8 *iface,
        REFERENCE_TIME rtTime, REFERENCE_TIME *prtResolved, DWORD dwTimeResolveFlags)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

817
	FIXME("(%p, 0x%s, %p, %d): stub\n", This, wine_dbgstr_longlong(rtTime),
818
	    prtResolved, dwTimeResolveFlags);
Rok Mandeljc's avatar
Rok Mandeljc committed
819
	return S_OK;
820 821
}

822 823 824 825 826 827
static HRESULT WINAPI IDirectMusicPerformance8Impl_MIDIToMusic(IDirectMusicPerformance8 *iface,
        BYTE bMIDIValue, DMUS_CHORD_KEY *pChord, BYTE bPlayMode, BYTE bChordLevel,
        WORD *pwMusicValue)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

Rok Mandeljc's avatar
Rok Mandeljc committed
828 829
	FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This, bMIDIValue, pChord, bPlayMode, bChordLevel, pwMusicValue);
	return S_OK;
830 831
}

832 833 834 835 836 837
static HRESULT WINAPI IDirectMusicPerformance8Impl_MusicToMIDI(IDirectMusicPerformance8 *iface,
        WORD wMusicValue, DMUS_CHORD_KEY *pChord, BYTE bPlayMode, BYTE bChordLevel,
        BYTE *pbMIDIValue)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

Rok Mandeljc's avatar
Rok Mandeljc committed
838 839
	FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This, wMusicValue, pChord, bPlayMode, bChordLevel, pbMIDIValue);
	return S_OK;
840 841
}

842 843 844 845 846 847
static HRESULT WINAPI IDirectMusicPerformance8Impl_TimeToRhythm(IDirectMusicPerformance8 *iface,
        MUSIC_TIME mtTime, DMUS_TIMESIGNATURE *pTimeSig, WORD *pwMeasure, BYTE *pbBeat,
        BYTE *pbGrid, short *pnOffset)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

848
	FIXME("(%p, %d, %p, %p, %p, %p, %p): stub\n", This, mtTime, pTimeSig, pwMeasure, pbBeat, pbGrid, pnOffset);
Rok Mandeljc's avatar
Rok Mandeljc committed
849
	return S_OK;
850 851
}

852 853 854 855 856 857
static HRESULT WINAPI IDirectMusicPerformance8Impl_RhythmToTime(IDirectMusicPerformance8 *iface,
        WORD wMeasure, BYTE bBeat, BYTE bGrid, short nOffset, DMUS_TIMESIGNATURE *pTimeSig,
        MUSIC_TIME *pmtTime)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

Rok Mandeljc's avatar
Rok Mandeljc committed
858 859
	FIXME("(%p, %d, %d, %d, %i, %p, %p): stub\n", This, wMeasure, bBeat, bGrid, nOffset, pTimeSig, pmtTime);
	return S_OK;
860 861 862
}

/* IDirectMusicPerformance8 Interface part follow: */
863
static HRESULT WINAPI IDirectMusicPerformance8Impl_InitAudio(IDirectMusicPerformance8 *iface,
864 865
        IDirectMusic **dmusic, IDirectSound **dsound, HWND hwnd, DWORD default_path_type,
        DWORD num_channels, DWORD flags, DMUS_AUDIOPARAMS *params)
866
{
867 868
    IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
    HRESULT hr = S_OK;
869

870 871
    TRACE("(%p, %p, %p, %p, %x, %u, %x, %p)\n", This, dmusic, dsound, hwnd, default_path_type,
            num_channels, flags, params);
872

873 874
    if (This->dmusic)
        return DMUS_E_ALREADY_INITED;
875

876 877 878 879 880
    if (!dmusic || !*dmusic) {
        hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic8,
                (void **)&This->dmusic);
        if (FAILED(hr))
            return hr;
881
    } else {
882 883
        This->dmusic = (IDirectMusic8 *)*dmusic;
        IDirectMusic8_AddRef(This->dmusic);
884
    }
885

886 887 888
    if (!dsound || !*dsound) {
        hr = DirectSoundCreate8(NULL, (IDirectSound8 **)&This->dsound, NULL);
        if (FAILED(hr))
889 890
            goto error;
        hr = IDirectSound_SetCooperativeLevel(This->dsound, hwnd ? hwnd : GetForegroundWindow(),
891
                DSSCL_PRIORITY);
892 893 894
        if (FAILED(hr))
            goto error;
    } else {
895
        This->dsound = *dsound;
896
        IDirectSound_AddRef(This->dsound);
897
    }
898

899 900 901 902
    hr = IDirectMusic8_SetDirectSound(This->dmusic, This->dsound, NULL);
    if (FAILED(hr))
        goto error;

903 904 905 906 907 908 909 910 911 912 913 914
    if (!params) {
        This->params.dwSize = sizeof(DMUS_AUDIOPARAMS);
        This->params.fInitNow = FALSE;
        This->params.dwValidData = DMUS_AUDIOPARAMS_FEATURES | DMUS_AUDIOPARAMS_VOICES |
                DMUS_AUDIOPARAMS_SAMPLERATE | DMUS_AUDIOPARAMS_DEFAULTSYNTH;
        This->params.dwVoices = 64;
        This->params.dwSampleRate = 22050;
        This->params.dwFeatures = flags;
        This->params.clsidDefaultSynth = CLSID_DirectMusicSynthSink;
    } else
        This->params = *params;

915
    if (default_path_type) {
916 917
        hr = IDirectMusicPerformance8_CreateStandardAudioPath(iface, default_path_type,
                num_channels, FALSE, &This->pDefaultPath);
918 919
        if (FAILED(hr)) {
            IDirectMusic8_SetDirectSound(This->dmusic, NULL, NULL);
920
            goto error;
921
        }
922
    }
Rok Mandeljc's avatar
Rok Mandeljc committed
923

924 925 926 927 928 929 930 931
    if (dsound && !*dsound) {
        *dsound = This->dsound;
        IDirectSound_AddRef(*dsound);
    }
    if (dmusic && !*dmusic) {
        *dmusic = (IDirectMusic *)This->dmusic;
        IDirectMusic_AddRef(*dmusic);
    }
932
    PostMessageToProcessMsgThread(This, PROCESSMSG_START);
933

934 935 936 937 938 939 940 941 942 943 944
    return S_OK;

error:
    if (This->dsound) {
        IDirectSound_Release(This->dsound);
        This->dsound = NULL;
    }
    if (This->dmusic) {
        IDirectMusic8_Release(This->dmusic);
        This->dmusic = NULL;
    }
945
    return hr;
946 947
}

948 949 950 951 952 953 954
static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegmentEx(IDirectMusicPerformance8 *iface,
        IUnknown *pSource, WCHAR *pwzSegmentName, IUnknown *pTransition, DWORD dwFlags,
        __int64 i64StartTime, IDirectMusicSegmentState **ppSegmentState, IUnknown *pFrom,
        IUnknown *pAudioPath)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

955
	FIXME("(%p, %p, %p, %p, %d, 0x%s, %p, %p, %p): stub\n", This, pSource, pwzSegmentName,
956
	    pTransition, dwFlags, wine_dbgstr_longlong(i64StartTime), ppSegmentState, pFrom, pAudioPath);
957
	if (ppSegmentState)
958
          return create_dmsegmentstate(&IID_IDirectMusicSegmentState,(void**)ppSegmentState);
959
	return S_OK;
960 961
}

962 963 964 965 966
static HRESULT WINAPI IDirectMusicPerformance8Impl_StopEx(IDirectMusicPerformance8 *iface,
        IUnknown *pObjectToStop, __int64 i64StopTime, DWORD dwFlags)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

967
	FIXME("(%p, %p, 0x%s, %d): stub\n", This, pObjectToStop,
968
	    wine_dbgstr_longlong(i64StopTime), dwFlags);
Rok Mandeljc's avatar
Rok Mandeljc committed
969
	return S_OK;
970 971
}

972 973 974 975 976
static HRESULT WINAPI IDirectMusicPerformance8Impl_ClonePMsg(IDirectMusicPerformance8 *iface,
        DMUS_PMSG *pSourcePMSG, DMUS_PMSG **ppCopyPMSG)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

Rok Mandeljc's avatar
Rok Mandeljc committed
977 978
	FIXME("(%p, %p, %p): stub\n", This, pSourcePMSG, ppCopyPMSG);
	return S_OK;
979 980
}

981 982 983 984
static HRESULT WINAPI IDirectMusicPerformance8Impl_CreateAudioPath(IDirectMusicPerformance8 *iface,
        IUnknown *pSourceConfig, BOOL fActivate, IDirectMusicAudioPath **ppNewPath)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
985 986
	IDirectMusicAudioPath *pPath;

Rok Mandeljc's avatar
Rok Mandeljc committed
987
	FIXME("(%p, %p, %d, %p): stub\n", This, pSourceConfig, fActivate, ppNewPath);
988 989 990 991 992

	if (NULL == ppNewPath) {
	  return E_POINTER;
	}

993
        create_dmaudiopath(&IID_IDirectMusicAudioPath, (void**)&pPath);
994
        set_audiopath_perf_pointer(pPath, iface);
995 996 997

	/** TODO */
	
998
	*ppNewPath = pPath;
999

1000
	return IDirectMusicAudioPath_Activate(*ppNewPath, fActivate);
1001 1002
}

1003 1004 1005 1006
static HRESULT WINAPI IDirectMusicPerformance8Impl_CreateStandardAudioPath(IDirectMusicPerformance8 *iface,
        DWORD dwType, DWORD dwPChannelCount, BOOL fActivate, IDirectMusicAudioPath **ppNewPath)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1007
	IDirectMusicAudioPath *pPath;
1008 1009
	DSBUFFERDESC desc;
	WAVEFORMATEX format;
1010
	IDirectSoundBuffer *buffer, *primary_buffer;
1011
	HRESULT hr = S_OK;
Rok Mandeljc's avatar
Rok Mandeljc committed
1012

1013
	FIXME("(%p)->(%d, %d, %d, %p): semi-stub\n", This, dwType, dwPChannelCount, fActivate, ppNewPath);
Rok Mandeljc's avatar
Rok Mandeljc committed
1014

1015 1016 1017
	if (NULL == ppNewPath) {
	  return E_POINTER;
	}
1018

1019
        *ppNewPath = NULL;
1020

1021
	/* Secondary buffer description */
1022
	memset(&format, 0, sizeof(format));
1023 1024 1025 1026 1027 1028 1029 1030
	format.wFormatTag = WAVE_FORMAT_PCM;
	format.nChannels = 1;
	format.nSamplesPerSec = 44000;
	format.nAvgBytesPerSec = 44000*2;
	format.nBlockAlign = 2;
	format.wBitsPerSample = 16;
	format.cbSize = 0;
	
1031
	memset(&desc, 0, sizeof(desc));
1032
	desc.dwSize = sizeof(desc);
1033
        desc.dwFlags = DSBCAPS_CTRLFX | DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS;
1034 1035 1036 1037 1038 1039
	desc.dwBufferBytes = DSBSIZE_MIN;
	desc.dwReserved = 0;
	desc.lpwfxFormat = &format;
	desc.guid3DAlgorithm = GUID_NULL;
	
	switch(dwType) {
1040
	case DMUS_APATH_DYNAMIC_3D:
1041
                desc.dwFlags |= DSBCAPS_CTRL3D | DSBCAPS_CTRLFREQUENCY | DSBCAPS_MUTE3DATMAXDISTANCE;
1042
		break;
1043
	case DMUS_APATH_DYNAMIC_MONO:
1044
                desc.dwFlags |= DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY;
1045
		break;
1046
	case DMUS_APATH_SHARED_STEREOPLUSREVERB:
Austin English's avatar
Austin English committed
1047
	        /* normally we have to create 2 buffers (one for music other for reverb)
1048 1049
		 * in this case. See msdn
                 */
1050
	case DMUS_APATH_DYNAMIC_STEREO:
1051
                desc.dwFlags |= DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY;
1052 1053 1054 1055
		format.nChannels = 2;
		format.nBlockAlign *= 2;
		format.nAvgBytesPerSec *=2;
		break;
1056
	default:
1057
	        return E_INVALIDARG;
1058
	}
1059

1060
	/* FIXME: Should we create one secondary buffer for each PChannel? */
1061
        hr = IDirectSound_CreateSoundBuffer(This->dsound, &desc, &buffer, NULL);
1062
	if (FAILED(hr))
1063
	        return DSERR_BUFFERLOST;
1064

1065 1066 1067 1068 1069
	/* Update description for creating primary buffer */
	desc.dwFlags |= DSBCAPS_PRIMARYBUFFER;
	desc.dwBufferBytes = 0;
	desc.lpwfxFormat = NULL;

1070
        hr = IDirectSound_CreateSoundBuffer(This->dsound, &desc, &primary_buffer, NULL);
1071
	if (FAILED(hr)) {
1072
                IDirectSoundBuffer_Release(buffer);
1073 1074
	        return DSERR_BUFFERLOST;
	}
1075 1076 1077 1078

	create_dmaudiopath(&IID_IDirectMusicAudioPath, (void**)&pPath);
	set_audiopath_perf_pointer(pPath, iface);
	set_audiopath_dsound_buffer(pPath, buffer);
1079
	set_audiopath_primary_dsound_buffer(pPath, primary_buffer);
1080

1081
	*ppNewPath = pPath;
1082
	
1083
	TRACE(" returning IDirectMusicAudioPath interface at %p.\n", *ppNewPath);
1084

1085
	return IDirectMusicAudioPath_Activate(*ppNewPath, fActivate);
1086 1087
}

1088 1089 1090 1091
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetDefaultAudioPath(IDirectMusicPerformance8 *iface,
        IDirectMusicAudioPath *pAudioPath)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
1092

1093
	FIXME("(%p, %p): semi-stub\n", This, pAudioPath);
1094 1095

	if (This->pDefaultPath) {
1096
		IDirectMusicAudioPath_Release(This->pDefaultPath);
1097 1098 1099
		This->pDefaultPath = NULL;
	}
	This->pDefaultPath = pAudioPath;
1100
	if (This->pDefaultPath) {
1101
		IDirectMusicAudioPath_AddRef(This->pDefaultPath);
1102
		set_audiopath_perf_pointer(This->pDefaultPath, iface);
1103
	}
1104

1105
	return S_OK;
1106 1107
}

1108 1109 1110 1111
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetDefaultAudioPath(IDirectMusicPerformance8 *iface,
        IDirectMusicAudioPath **ppAudioPath)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
1112

1113
	FIXME("(%p, %p): semi-stub (%p)\n", This, ppAudioPath, This->pDefaultPath);
Rok Mandeljc's avatar
Rok Mandeljc committed
1114

1115
	if (NULL != This->pDefaultPath) {
1116
	  *ppAudioPath = This->pDefaultPath;
1117
          IDirectMusicAudioPath_AddRef(*ppAudioPath);
1118 1119 1120
        } else {
	  *ppAudioPath = NULL;
        }
1121
	return S_OK;
1122 1123
}

1124 1125 1126 1127 1128
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetParamEx(IDirectMusicPerformance8 *iface,
        REFGUID rguidType, DWORD dwTrackID, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime,
        MUSIC_TIME *pmtNext, void *pParam)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
1129

1130
	FIXME("(%p, %s, %d, %d, %d, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), dwTrackID, dwGroupBits, dwIndex, mtTime, pmtNext, pParam);
Rok Mandeljc's avatar
Rok Mandeljc committed
1131 1132

	return S_OK;
1133 1134
}

1135
static const IDirectMusicPerformance8Vtbl DirectMusicPerformance8_Vtbl = {
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
	IDirectMusicPerformance8Impl_QueryInterface,
	IDirectMusicPerformance8Impl_AddRef,
	IDirectMusicPerformance8Impl_Release,
	IDirectMusicPerformance8Impl_Init,
	IDirectMusicPerformance8Impl_PlaySegment,
	IDirectMusicPerformance8Impl_Stop,
	IDirectMusicPerformance8Impl_GetSegmentState,
	IDirectMusicPerformance8Impl_SetPrepareTime,
	IDirectMusicPerformance8Impl_GetPrepareTime,
	IDirectMusicPerformance8Impl_SetBumperLength,
	IDirectMusicPerformance8Impl_GetBumperLength,
	IDirectMusicPerformance8Impl_SendPMsg,
	IDirectMusicPerformance8Impl_MusicToReferenceTime,
	IDirectMusicPerformance8Impl_ReferenceToMusicTime,
	IDirectMusicPerformance8Impl_IsPlaying,
	IDirectMusicPerformance8Impl_GetTime,
	IDirectMusicPerformance8Impl_AllocPMsg,
	IDirectMusicPerformance8Impl_FreePMsg,
	IDirectMusicPerformance8Impl_GetGraph,
	IDirectMusicPerformance8Impl_SetGraph,
	IDirectMusicPerformance8Impl_SetNotificationHandle,
	IDirectMusicPerformance8Impl_GetNotificationPMsg,
	IDirectMusicPerformance8Impl_AddNotificationType,
	IDirectMusicPerformance8Impl_RemoveNotificationType,
	IDirectMusicPerformance8Impl_AddPort,
	IDirectMusicPerformance8Impl_RemovePort,
	IDirectMusicPerformance8Impl_AssignPChannelBlock,
	IDirectMusicPerformance8Impl_AssignPChannel,
	IDirectMusicPerformance8Impl_PChannelInfo,
	IDirectMusicPerformance8Impl_DownloadInstrument,
	IDirectMusicPerformance8Impl_Invalidate,
	IDirectMusicPerformance8Impl_GetParam,
	IDirectMusicPerformance8Impl_SetParam,
	IDirectMusicPerformance8Impl_GetGlobalParam,
	IDirectMusicPerformance8Impl_SetGlobalParam,
	IDirectMusicPerformance8Impl_GetLatencyTime,
	IDirectMusicPerformance8Impl_GetQueueTime,
	IDirectMusicPerformance8Impl_AdjustTime,
	IDirectMusicPerformance8Impl_CloseDown,
	IDirectMusicPerformance8Impl_GetResolvedTime,
	IDirectMusicPerformance8Impl_MIDIToMusic,
	IDirectMusicPerformance8Impl_MusicToMIDI,
	IDirectMusicPerformance8Impl_TimeToRhythm,
	IDirectMusicPerformance8Impl_RhythmToTime,
1180 1181 1182 1183 1184 1185 1186 1187 1188
	IDirectMusicPerformance8Impl_InitAudio,
	IDirectMusicPerformance8Impl_PlaySegmentEx,
	IDirectMusicPerformance8Impl_StopEx,
	IDirectMusicPerformance8Impl_ClonePMsg,
	IDirectMusicPerformance8Impl_CreateAudioPath,
	IDirectMusicPerformance8Impl_CreateStandardAudioPath,
	IDirectMusicPerformance8Impl_SetDefaultAudioPath,
	IDirectMusicPerformance8Impl_GetDefaultAudioPath,
	IDirectMusicPerformance8Impl_GetParamEx
1189
};
1190 1191

/* for ClassFactory */
1192 1193
HRESULT WINAPI create_dmperformance(REFIID lpcGUID, void **ppobj)
{
1194 1195
	IDirectMusicPerformance8Impl *obj;

1196
        TRACE("(%s, %p)\n", debugstr_guid(lpcGUID), ppobj);
1197

1198
	obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicPerformance8Impl));
1199
        if (NULL == obj) {
1200
		*ppobj = NULL;
1201
		return E_OUTOFMEMORY;
1202
	}
1203
        obj->IDirectMusicPerformance8_iface.lpVtbl = &DirectMusicPerformance8_Vtbl;
1204
	obj->ref = 0;  /* will be inited by QueryInterface */
1205
	obj->pDefaultPath = NULL;
1206
	InitializeCriticalSection(&obj->safe);
1207
	obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectMusicPerformance8Impl*->safe");
1208

1209 1210 1211
        obj->rtLatencyTime  = 100;  /* 100 ms TO FIX */
        obj->dwBumperLength =   50; /* 50 ms default */
        obj->dwPrepareTime  = 1000; /* 1000 ms default */
1212 1213
        return IDirectMusicPerformance8Impl_QueryInterface(&obj->IDirectMusicPerformance8_iface,
                                                           lpcGUID, ppobj);
1214
}