performance.c 42.3 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
typedef struct IDirectMusicPerformance8Impl {
    IDirectMusicPerformance8 IDirectMusicPerformance8_iface;
    LONG ref;
    /* IDirectMusicPerformanceImpl fields */
    IDirectMusic8 *pDirectMusic;
    IDirectSound *pDirectSound;
    IDirectMusicGraph *pToolGraph;
    DMUS_AUDIOPARAMS pParams;
    /* global parameters */
    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;

57 58 59 60 61 62 63 64 65 66
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;
};
67

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
#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)


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

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

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

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

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

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

outrefresh:
    LeaveCriticalSection(&This->safe);
    
143
    while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
      /** 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;
162
	}
163 164
      }
    }
165 166 167

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

168 169 170 171 172 173 174 175 176 177
  }

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

static BOOL PostMessageToProcessMsgThread(IDirectMusicPerformance8Impl* This, UINT iMsg) {
  if (FALSE == This->procThreadTicStarted && PROCESSMSG_EXIT != iMsg) {
178
    BOOL res;
179 180 181 182
    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;
183 184 185 186 187 188 189 190 191
    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;
192 193 194 195
  }
  return PostThreadMessageA(This->procThreadId, iMsg, 0, 0);
}

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

201
/* IDirectMusicPerformance8 IUnknown part: */
202 203 204 205
static HRESULT WINAPI IDirectMusicPerformance8Impl_QueryInterface(IDirectMusicPerformance8 *iface,
        REFIID riid, void **ppv)
{
  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 214
    return S_OK;
  }
215 216

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

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

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

227 228
  DMIME_LockModule();

229
  return ref;
230 231
}

232 233 234
static ULONG WINAPI IDirectMusicPerformance8Impl_Release(IDirectMusicPerformance8 *iface)
{
  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 242 243
    DeleteCriticalSection(&This->safe);
    HeapFree(GetProcessHeap(), 0, This);
  }
244 245 246

  DMIME_UnlockModule();

247
  return ref;
248 249
}

250
/* IDirectMusicPerformanceImpl IDirectMusicPerformance Interface part: */
251 252 253 254
static HRESULT WINAPI IDirectMusicPerformance8Impl_Init(IDirectMusicPerformance8 *iface,
        IDirectMusic **ppDirectMusic, IDirectSound *pDirectSound, HWND hWnd)
{
        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 259
	  return DMUS_E_ALREADY_INITED;
	
260 261 262 263
	if (NULL == hWnd) {
	  hWnd = GetForegroundWindow();
	}

264
	if (NULL != pDirectSound) {
265 266
	  This->pDirectSound = pDirectSound;
	  IDirectSound_AddRef(This->pDirectSound);
267
	} else {
268
	  DirectSoundCreate8(NULL, (LPDIRECTSOUND8*) &This->pDirectSound, NULL);
269
	  if (!This->pDirectSound) return DSERR_NODRIVER;
270

271 272 273 274 275 276
	  if (NULL != hWnd) {
	    IDirectSound8_SetCooperativeLevel(This->pDirectSound, hWnd, DSSCL_PRIORITY);
	  } else {
	    /* how to get the ForeGround window handle ? */
            /*IDirectSound8_SetCooperativeLevel(This->pDirectSound, hWnd, DSSCL_PRIORITY);*/
	  }
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 285 286 287 288 289 290 291 292 293 294 295
        HRESULT hr;
        /* App enables the performance to initialize itself and needs a pointer to object */
        hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic8, (void**)&This->pDirectMusic);
        if (FAILED(hr))
            return hr;
        if (ppDirectMusic) {
            *ppDirectMusic = (LPDIRECTMUSIC)This->pDirectMusic;
            IDirectMusic8_AddRef((LPDIRECTMUSIC8)*ppDirectMusic);
        }
    }

    return S_OK;
296 297
}

298 299 300 301 302 303
static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegment(IDirectMusicPerformance8 *iface,
        IDirectMusicSegment *pSegment, DWORD dwFlags, __int64 i64StartTime,
        IDirectMusicSegmentState **ppSegmentState)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

304
	FIXME("(%p, %p, %d, 0x%s, %p): stub\n", This, pSegment, dwFlags,
305
	    wine_dbgstr_longlong(i64StartTime), ppSegmentState);
306 307
	if (ppSegmentState)
	  return DMUSIC_CreateDirectMusicSegmentStateImpl(&IID_IDirectMusicSegmentState, (LPVOID*)ppSegmentState, NULL);
Rok Mandeljc's avatar
Rok Mandeljc committed
308
	return S_OK;
309 310
}

311 312 313 314 315 316
static HRESULT WINAPI IDirectMusicPerformance8Impl_Stop(IDirectMusicPerformance8 *iface,
        IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegmentState, MUSIC_TIME mtTime,
        DWORD dwFlags)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

317
	FIXME("(%p, %p, %p, %d, %d): stub\n", This, pSegment, pSegmentState, mtTime, dwFlags);
Rok Mandeljc's avatar
Rok Mandeljc committed
318
	return S_OK;
319 320
}

321 322 323 324 325
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetSegmentState(IDirectMusicPerformance8 *iface,
        IDirectMusicSegmentState **ppSegmentState, MUSIC_TIME mtTime)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

326
	FIXME("(%p,%p, %d): stub\n", This, ppSegmentState, mtTime);
Rok Mandeljc's avatar
Rok Mandeljc committed
327
	return S_OK;
328 329
}

330 331 332 333 334
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetPrepareTime(IDirectMusicPerformance8 *iface,
        DWORD dwMilliSeconds)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

335
  TRACE("(%p, %d)\n", This, dwMilliSeconds);
336 337
  This->dwPrepareTime = dwMilliSeconds;
  return S_OK;
338 339
}

340 341 342 343 344
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetPrepareTime(IDirectMusicPerformance8 *iface,
        DWORD *pdwMilliSeconds)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

345 346 347 348 349 350
  TRACE("(%p, %p)\n", This, pdwMilliSeconds);
  if (NULL == pdwMilliSeconds) {
    return E_POINTER;
  }
  *pdwMilliSeconds = This->dwPrepareTime;
  return S_OK;
351 352
}

353 354 355 356 357
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetBumperLength(IDirectMusicPerformance8 *iface,
        DWORD dwMilliSeconds)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

358
  TRACE("(%p, %d)\n", This, dwMilliSeconds);
359 360
  This->dwBumperLength =  dwMilliSeconds;
  return S_OK;
361 362
}

363 364 365 366 367
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetBumperLength(IDirectMusicPerformance8 *iface,
        DWORD *pdwMilliSeconds)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

368 369 370 371 372 373
  TRACE("(%p, %p)\n", This, pdwMilliSeconds);
  if (NULL == pdwMilliSeconds) {
    return E_POINTER;
  }
  *pdwMilliSeconds = This->dwBumperLength;
  return S_OK;
374 375
}

376 377 378 379
static HRESULT WINAPI IDirectMusicPerformance8Impl_SendPMsg(IDirectMusicPerformance8 *iface,
        DMUS_PMSG *pPMSG)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
380 381 382 383 384 385 386 387 388 389 390 391 392 393
  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);
  if (NULL == pItem) {
    return E_POINTER;
  }
394
  if (pItem->bInUse) {
395 396 397 398 399 400 401 402 403 404 405 406 407
    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;
  }

408
  EnterCriticalSection(&This->safe);
409 410 411 412 413
  for (it = *queue; NULL != it && it->rtItemTime < pItem->rtItemTime; it = it->next) {
    prev_it = it;
  }
  if (NULL == prev_it) {
    pItem->prev = NULL;
414
    if (NULL != *queue) pItem->next = (*queue)->next;
415 416 417 418 419 420 421 422
    /*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;
423 424 425
  } 
  LeaveCriticalSection(&This->safe);

426 427 428
  /** now in use, prevent from stupid Frees */
  pItem->bInUse = TRUE;
  return S_OK;
429 430
}

431 432 433 434 435
static HRESULT WINAPI IDirectMusicPerformance8Impl_MusicToReferenceTime(IDirectMusicPerformance8 *iface,
        MUSIC_TIME mtTime, REFERENCE_TIME *prtTime)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

436
	FIXME("(%p, %d, %p): stub\n", This, mtTime, prtTime);
Rok Mandeljc's avatar
Rok Mandeljc committed
437
	return S_OK;
438 439
}

440 441 442 443 444
static HRESULT WINAPI IDirectMusicPerformance8Impl_ReferenceToMusicTime(IDirectMusicPerformance8 *iface,
        REFERENCE_TIME rtTime, MUSIC_TIME *pmtTime)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

445
	FIXME("(%p, 0x%s, %p): stub\n", This, wine_dbgstr_longlong(rtTime), pmtTime);
Rok Mandeljc's avatar
Rok Mandeljc committed
446
	return S_OK;
447 448
}

449 450 451 452 453
static HRESULT WINAPI IDirectMusicPerformance8Impl_IsPlaying(IDirectMusicPerformance8 *iface,
        IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegState)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

Rok Mandeljc's avatar
Rok Mandeljc committed
454
	FIXME("(%p, %p, %p): stub\n", This, pSegment, pSegState);
455
	return S_FALSE;
456 457
}

458 459 460 461
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetTime(IDirectMusicPerformance8 *iface,
        REFERENCE_TIME *prtNow, MUSIC_TIME *pmtNow)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
462 463 464 465
  HRESULT hr = S_OK;
  REFERENCE_TIME rtCur = 0;

  /*TRACE("(%p, %p, %p)\n", This, prtNow, pmtNow); */
466
  if (This->procThreadTicStarted) {
467 468 469 470 471 472 473 474 475 476 477
    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;
478 479
}

480 481 482 483
static HRESULT WINAPI IDirectMusicPerformance8Impl_AllocPMsg(IDirectMusicPerformance8 *iface,
        ULONG cb, DMUS_PMSG **ppPMSG)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
484 485
  DMUS_PMSGItem* pItem = NULL;
  
486
  FIXME("(%p, %d, %p): stub\n", This, cb, ppPMSG);
487 488 489 490 491 492 493 494 495 496 497 498
	
  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;
499
  *ppPMSG = DMUS_ItemToPMSG(pItem);
500
  return S_OK;
501 502
}

503 504 505 506
static HRESULT WINAPI IDirectMusicPerformance8Impl_FreePMsg(IDirectMusicPerformance8 *iface,
        DMUS_PMSG *pPMSG)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
507 508 509 510 511 512 513
  DMUS_PMSGItem* pItem = NULL;
  
  FIXME("(%p, %p): stub\n", This, pPMSG);
  
  if (NULL == pPMSG) {
    return E_POINTER;
  }
514
  pItem = DMUS_PMSGToItem(pPMSG);
515 516 517
  if (NULL == pItem) {
    return E_POINTER;
  }
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 526
  LeaveCriticalSection(&This->safe);

527
  /** TODO: see if we should Release the pItem->pMsg->punkUser and others Interfaces */
528 529
  HeapFree(GetProcessHeap(), 0, pItem);  
  return S_OK;
530 531
}

532 533 534 535 536
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetGraph(IDirectMusicPerformance8 *iface,
        IDirectMusicGraph **ppGraph)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

537 538
  FIXME("(%p, %p): to check\n", This, ppGraph);
  if (NULL != This->pToolGraph) {
539 540
    *ppGraph = This->pToolGraph;
    IDirectMusicGraph_AddRef(*ppGraph);
541 542
  } else {
    return E_FAIL;
543 544
  }
  return S_OK;
545 546
}

547 548 549 550 551
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetGraph(IDirectMusicPerformance8 *iface,
        IDirectMusicGraph *pGraph)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

552 553 554 555
  FIXME("(%p, %p): to check\n", This, pGraph);
  
  if (NULL != This->pToolGraph) {
    /* Todo clean buffers and tools before */
556
    IDirectMusicGraph_Release(This->pToolGraph);
557 558 559
  }
  This->pToolGraph = pGraph;
  if (NULL != This->pToolGraph) {
560
    IDirectMusicGraph_AddRef(This->pToolGraph);
561 562
  }
  return S_OK;
563 564
}

565 566 567 568 569
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetNotificationHandle(IDirectMusicPerformance8 *iface,
        HANDLE hNotification, REFERENCE_TIME rtMinimum)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

570
  FIXME("(%p, %p, 0x%s): stub\n", This, hNotification, wine_dbgstr_longlong(rtMinimum));
571 572 573
  This->hNotification = hNotification;
  if (rtMinimum) This->rtMinimum = rtMinimum;
  return S_OK;
574 575
}

576 577 578 579 580
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetNotificationPMsg(IDirectMusicPerformance8 *iface,
        DMUS_NOTIFICATION_PMSG **ppNotificationPMsg)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

581 582 583 584
  FIXME("(%p, %p): stub\n", This, ppNotificationPMsg);
  if (NULL == ppNotificationPMsg) {
    return E_POINTER;
  }
585 586 587
  
  

588 589
  return S_FALSE;
  /*return S_OK;*/
590 591
}

592 593 594 595 596
static HRESULT WINAPI IDirectMusicPerformance8Impl_AddNotificationType(IDirectMusicPerformance8 *iface,
        REFGUID rguidNotificationType)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

597
	FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType));
Rok Mandeljc's avatar
Rok Mandeljc committed
598
	return S_OK;
599 600
}

601 602 603 604 605
static HRESULT WINAPI IDirectMusicPerformance8Impl_RemoveNotificationType(IDirectMusicPerformance8 *iface,
        REFGUID rguidNotificationType)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

606
	FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType));
Rok Mandeljc's avatar
Rok Mandeljc committed
607
	return S_OK;
608 609
}

610 611 612 613
static HRESULT WINAPI IDirectMusicPerformance8Impl_AddPort(IDirectMusicPerformance8 *iface,
        IDirectMusicPort *pPort)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
614
	HRESULT hr = E_FAIL;
615

Rok Mandeljc's avatar
Rok Mandeljc committed
616
	FIXME("(%p, %p): stub\n", This, pPort);
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
	if (!This->pDirectMusic || !This->pDirectSound) return DMUS_E_NOT_INIT;
	if (NULL == pPort) {
	  GUID port_guid;
	  IDirectMusicPort* pDefaultPort = NULL;
	  DMUS_PORTPARAMS params;
	  int i, j;
	  hr = IDirectMusic8_GetDefaultPort(This->pDirectMusic, &port_guid);
	  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;
	  hr = IDirectMusic8_CreatePort(This->pDirectMusic, &port_guid, &params, &pDefaultPort, NULL);
	  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
650
	return S_OK;
651 652
}

653 654 655 656 657
static HRESULT WINAPI IDirectMusicPerformance8Impl_RemovePort(IDirectMusicPerformance8 *iface,
        IDirectMusicPort *pPort)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

Rok Mandeljc's avatar
Rok Mandeljc committed
658
	FIXME("(%p, %p): stub\n", This, pPort);
659
	IDirectMusicPort_Release (pPort);
Rok Mandeljc's avatar
Rok Mandeljc committed
660
	return S_OK;
661 662
}

663 664 665 666
static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannelBlock(IDirectMusicPerformance8 *iface,
        DWORD dwBlockNum, IDirectMusicPort *pPort, DWORD dwGroup)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
667
	int i, j, range /* min value in range */;
Rok Mandeljc's avatar
Rok Mandeljc committed
668

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

672 673 674 675 676 677 678 679 680
	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++;
	}
681
	/*if (dwGroup > 2) return S_FALSE;*/
682 683

	return S_OK;
684 685
}

686 687 688 689
static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannel(IDirectMusicPerformance8 *iface,
        DWORD dwPChannel, IDirectMusicPort *pPort, DWORD dwGroup, DWORD dwMChannel)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
690

691
	TRACE("(%p, %d, %p, %d, %d)\n", This, dwPChannel, pPort, dwGroup, dwMChannel);
692
	if (NULL == pPort) return E_POINTER;
693 694 695
	This->PChannel[dwPChannel].port = pPort; 
	This->PChannel[dwPChannel].group = dwGroup; 
	This->PChannel[dwPChannel].channel = dwMChannel;
Rok Mandeljc's avatar
Rok Mandeljc committed
696 697

	return S_OK;
698 699
}

700 701 702 703
static HRESULT WINAPI IDirectMusicPerformance8Impl_PChannelInfo(IDirectMusicPerformance8 *iface,
        DWORD dwPChannel, IDirectMusicPort **ppPort, DWORD *pdwGroup, DWORD *pdwMChannel)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
704 705 706
	DMUS_PORTPARAMS8 dmusportparams;
	GUID def;

707
	FIXME("(%p, %d, %p, %p, %p): stub\n", This, dwPChannel, ppPort, pdwGroup, pdwMChannel);
708 709 710 711 712 713

	dmusportparams.dwSize = sizeof(DMUS_PORTPARAMS8);
	dmusportparams.dwValidParams = 0;
	IDirectMusic8_GetDefaultPort(This->pDirectMusic, &def);
	IDirectMusic8_CreatePort(This->pDirectMusic, &def, &dmusportparams, ppPort, NULL);

Rok Mandeljc's avatar
Rok Mandeljc committed
714
	return S_OK;
715 716
}

717 718 719 720 721 722 723
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);

724
	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
725
	return S_OK;
726 727
}

728 729 730 731 732
static HRESULT WINAPI IDirectMusicPerformance8Impl_Invalidate(IDirectMusicPerformance8 *iface,
        MUSIC_TIME mtTime, DWORD dwFlags)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

733
	FIXME("(%p, %d, %d): stub\n", This, mtTime, dwFlags);
Rok Mandeljc's avatar
Rok Mandeljc committed
734
	return S_OK;
735 736
}

737 738 739 740 741 742
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);

743
	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
744
	return S_OK;
745 746
}

747 748 749 750 751
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetParam(IDirectMusicPerformance8 *iface,
        REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

752
	FIXME("(%p, %s, %d, %d, %d, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pParam);
Rok Mandeljc's avatar
Rok Mandeljc committed
753
	return S_OK;
754 755
}

756 757 758 759
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
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));
Rok Mandeljc's avatar
Rok Mandeljc committed
771 772

	return S_OK;
773 774
}

775 776 777 778
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
779

780
	TRACE("(%p, %s, %p, %d)\n", This, debugstr_dmguid(rguidType), pParam, dwSize);
781
	
782
	if (IsEqualGUID (rguidType, &GUID_PerfAutoDownload)) {
783 784
		memcpy(&This->fAutoDownload, pParam, dwSize);
		TRACE("=> AutoDownload set to %d\n", This->fAutoDownload);
785
	}
786
	if (IsEqualGUID (rguidType, &GUID_PerfMasterGrooveLevel)) {
787 788
		memcpy(&This->cMasterGrooveLevel, pParam, dwSize);
		TRACE("=> MasterGrooveLevel set to %i\n", This->cMasterGrooveLevel);
789
	}
790
	if (IsEqualGUID (rguidType, &GUID_PerfMasterTempo)) {
791 792
		memcpy(&This->fMasterTempo, pParam, dwSize);
		TRACE("=> MasterTempo set to %f\n", This->fMasterTempo);
793
	}
794
	if (IsEqualGUID (rguidType, &GUID_PerfMasterVolume)) {
795 796
		memcpy(&This->lMasterVolume, pParam, dwSize);
		TRACE("=> MasterVolume set to %li\n", This->lMasterVolume);
797
	}
Rok Mandeljc's avatar
Rok Mandeljc committed
798 799

	return S_OK;
800 801
}

802 803 804 805 806
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetLatencyTime(IDirectMusicPerformance8 *iface,
        REFERENCE_TIME *prtTime)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

807 808
	TRACE("(%p, %p): stub\n", This, prtTime);
	*prtTime = This->rtLatencyTime;
Rok Mandeljc's avatar
Rok Mandeljc committed
809
	return S_OK;
810 811
}

812 813 814 815 816 817
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetQueueTime(IDirectMusicPerformance8 *iface,
        REFERENCE_TIME *prtTime)

{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

Rok Mandeljc's avatar
Rok Mandeljc committed
818 819
	FIXME("(%p, %p): stub\n", This, prtTime);
	return S_OK;
820 821
}

822 823 824 825 826
static HRESULT WINAPI IDirectMusicPerformance8Impl_AdjustTime(IDirectMusicPerformance8 *iface,
        REFERENCE_TIME rtAmount)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

827
	FIXME("(%p, 0x%s): stub\n", This, wine_dbgstr_longlong(rtAmount));
Rok Mandeljc's avatar
Rok Mandeljc committed
828
	return S_OK;
829 830
}

831 832 833 834
static HRESULT WINAPI IDirectMusicPerformance8Impl_CloseDown(IDirectMusicPerformance8 *iface)
{
  IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

835 836 837 838 839 840 841
  FIXME("(%p): stub\n", This);
  if (PostMessageToProcessMsgThread(This, PROCESSMSG_EXIT)) {
    WaitForSingleObject(This->procThread, INFINITE);
    This->procThreadTicStarted = FALSE;
    CloseHandle(This->procThread);
  }
  if (NULL != This->pDirectSound) {
842
    IDirectSound_Release(This->pDirectSound);
843 844 845
    This->pDirectSound = NULL;
  }
  if (NULL != This->pDirectMusic) {
846
    IDirectMusic8_Release(This->pDirectMusic);
847 848 849
    This->pDirectMusic = NULL;
  }
  return S_OK;
850 851
}

852 853 854 855 856
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetResolvedTime(IDirectMusicPerformance8 *iface,
        REFERENCE_TIME rtTime, REFERENCE_TIME *prtResolved, DWORD dwTimeResolveFlags)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

857
	FIXME("(%p, 0x%s, %p, %d): stub\n", This, wine_dbgstr_longlong(rtTime),
858
	    prtResolved, dwTimeResolveFlags);
Rok Mandeljc's avatar
Rok Mandeljc committed
859
	return S_OK;
860 861
}

862 863 864 865 866 867
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
868 869
	FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This, bMIDIValue, pChord, bPlayMode, bChordLevel, pwMusicValue);
	return S_OK;
870 871
}

872 873 874 875 876 877
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
878 879
	FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This, wMusicValue, pChord, bPlayMode, bChordLevel, pbMIDIValue);
	return S_OK;
880 881
}

882 883 884 885 886 887
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);

888
	FIXME("(%p, %d, %p, %p, %p, %p, %p): stub\n", This, mtTime, pTimeSig, pwMeasure, pbBeat, pbGrid, pnOffset);
Rok Mandeljc's avatar
Rok Mandeljc committed
889
	return S_OK;
890 891
}

892 893 894 895 896 897
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
898 899
	FIXME("(%p, %d, %d, %d, %i, %p, %p): stub\n", This, wMeasure, bBeat, bGrid, nOffset, pTimeSig, pmtTime);
	return S_OK;
900 901 902
}

/* IDirectMusicPerformance8 Interface part follow: */
903 904 905 906 907
static HRESULT WINAPI IDirectMusicPerformance8Impl_InitAudio(IDirectMusicPerformance8 *iface,
        IDirectMusic **ppDirectMusic, IDirectSound **ppDirectSound, HWND hWnd,
        DWORD dwDefaultPathType, DWORD dwPChannelCount, DWORD dwFlags, DMUS_AUDIOPARAMS* pParams)
{
        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 915
	  return DMUS_E_ALREADY_INITED;

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

Austin English's avatar
Austin English committed
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 935
	/* as seen in msdn we need params init before audio path creation */
	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 941 942 943 944 945 946
	  This->pParams.dwSize = sizeof(DMUS_AUDIOPARAMS);
	  This->pParams.fInitNow = FALSE;
	  This->pParams.dwValidData = DMUS_AUDIOPARAMS_FEATURES | DMUS_AUDIOPARAMS_VOICES | DMUS_AUDIOPARAMS_SAMPLERATE | DMUS_AUDIOPARAMS_DEFAULTSYNTH;
	  This->pParams.dwVoices = 64;
	  This->pParams.dwSampleRate = (DWORD) 22.050; 
	  This->pParams.dwFeatures = dwFlags;
	  This->pParams.clsidDefaultSynth = CLSID_DirectMusicSynthSink;
947
	}
948
	hr = IDirectMusicPerformance8_CreateStandardAudioPath(iface, dwDefaultPathType, dwPChannelCount, FALSE, &This->pDefaultPath);
Rok Mandeljc's avatar
Rok Mandeljc committed
949

950 951
	PostMessageToProcessMsgThread(This, PROCESSMSG_START);

952
	return hr;
953 954
}

955 956 957 958 959 960 961
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);

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 965 966
	if (ppSegmentState)
	  return DMUSIC_CreateDirectMusicSegmentStateImpl(&IID_IDirectMusicSegmentState, (LPVOID*)ppSegmentState, NULL);
	return S_OK;
967 968
}

969 970 971 972 973
static HRESULT WINAPI IDirectMusicPerformance8Impl_StopEx(IDirectMusicPerformance8 *iface,
        IUnknown *pObjectToStop, __int64 i64StopTime, DWORD dwFlags)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);

974
	FIXME("(%p, %p, 0x%s, %d): stub\n", This, pObjectToStop,
975
	    wine_dbgstr_longlong(i64StopTime), dwFlags);
Rok Mandeljc's avatar
Rok Mandeljc committed
976
	return S_OK;
977 978
}

979 980 981 982 983
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
984 985
	FIXME("(%p, %p, %p): stub\n", This, pSourcePMSG, ppCopyPMSG);
	return S_OK;
986 987
}

988 989 990 991
static HRESULT WINAPI IDirectMusicPerformance8Impl_CreateAudioPath(IDirectMusicPerformance8 *iface,
        IUnknown *pSourceConfig, BOOL fActivate, IDirectMusicAudioPath **ppNewPath)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
992 993 994
	IDirectMusicAudioPathImpl *default_path;
	IDirectMusicAudioPath *pPath;

Rok Mandeljc's avatar
Rok Mandeljc committed
995
	FIXME("(%p, %p, %d, %p): stub\n", This, pSourceConfig, fActivate, ppNewPath);
996 997 998 999 1000 1001 1002

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

	DMUSIC_CreateDirectMusicAudioPathImpl (&IID_IDirectMusicAudioPath, (LPVOID*)&pPath, NULL);
	default_path = (IDirectMusicAudioPathImpl*)((char*)(pPath) - offsetof(IDirectMusicAudioPathImpl,AudioPathVtbl));
1003
        default_path->pPerf = &This->IDirectMusicPerformance8_iface;
1004 1005 1006

	/** TODO */
	
1007
	*ppNewPath = pPath;
1008

1009
	return IDirectMusicAudioPath_Activate(*ppNewPath, fActivate);
1010 1011
}

1012 1013 1014 1015
static HRESULT WINAPI IDirectMusicPerformance8Impl_CreateStandardAudioPath(IDirectMusicPerformance8 *iface,
        DWORD dwType, DWORD dwPChannelCount, BOOL fActivate, IDirectMusicAudioPath **ppNewPath)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
1016
	IDirectMusicAudioPathImpl *default_path;
1017
	IDirectMusicAudioPath *pPath;
1018 1019
	DSBUFFERDESC desc;
	WAVEFORMATEX format;
Alexandre Julliard's avatar
Alexandre Julliard committed
1020
	LPDIRECTSOUNDBUFFER buffer;
1021
	HRESULT hr = S_OK;
Rok Mandeljc's avatar
Rok Mandeljc committed
1022

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

1025 1026 1027
	if (NULL == ppNewPath) {
	  return E_POINTER;
	}
1028
	
1029 1030
	DMUSIC_CreateDirectMusicAudioPathImpl (&IID_IDirectMusicAudioPath, (LPVOID*)&pPath, NULL);
	default_path = (IDirectMusicAudioPathImpl*)((char*)(pPath) - offsetof(IDirectMusicAudioPathImpl,AudioPathVtbl));
1031 1032
        default_path->pPerf = &This->IDirectMusicPerformance8_iface;

1033
	/* Secondary buffer description */
1034
	memset(&format, 0, sizeof(format));
1035 1036 1037 1038 1039 1040 1041 1042
	format.wFormatTag = WAVE_FORMAT_PCM;
	format.nChannels = 1;
	format.nSamplesPerSec = 44000;
	format.nAvgBytesPerSec = 44000*2;
	format.nBlockAlign = 2;
	format.wBitsPerSample = 16;
	format.cbSize = 0;
	
1043
	memset(&desc, 0, sizeof(desc));
1044
	desc.dwSize = sizeof(desc);
1045
	desc.dwFlags = DSBCAPS_CTRLFX | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS;
1046 1047 1048 1049 1050 1051
	desc.dwBufferBytes = DSBSIZE_MIN;
	desc.dwReserved = 0;
	desc.lpwfxFormat = &format;
	desc.guid3DAlgorithm = GUID_NULL;
	
	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:
Austin English's avatar
Austin English committed
1059
	        /* normally we have to create 2 buffers (one for music other for reverb)
1060 1061
		 * in this case. See msdn
                 */
1062
	case DMUS_APATH_DYNAMIC_STEREO:
1063
		desc.dwFlags |= DSBCAPS_CTRLFREQUENCY;
1064 1065 1066 1067
		format.nChannels = 2;
		format.nBlockAlign *= 2;
		format.nAvgBytesPerSec *=2;
		break;
1068
	default:
1069 1070 1071
	        HeapFree(GetProcessHeap(), 0, default_path); 
	        *ppNewPath = NULL;
	        return E_INVALIDARG;
1072
	}
1073

1074
	/* FIXME: Should we create one secondary buffer for each PChannel? */
1075 1076 1077 1078 1079 1080
	hr = IDirectSound8_CreateSoundBuffer ((LPDIRECTSOUND8) This->pDirectSound, &desc, &buffer, NULL);
	if (FAILED(hr)) {
	        HeapFree(GetProcessHeap(), 0, default_path); 
	        *ppNewPath = NULL;
	        return DSERR_BUFFERLOST;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1081
	default_path->pDSBuffer = buffer;
1082

1083 1084 1085 1086 1087
	/* Update description for creating primary buffer */
	desc.dwFlags |= DSBCAPS_PRIMARYBUFFER;
	desc.dwBufferBytes = 0;
	desc.lpwfxFormat = NULL;

1088 1089 1090 1091 1092 1093 1094
	hr = IDirectSound8_CreateSoundBuffer ((LPDIRECTSOUND8) This->pDirectSound, &desc, &buffer, NULL);
	if (FAILED(hr)) {
                IDirectSoundBuffer_Release(default_path->pDSBuffer);
	        HeapFree(GetProcessHeap(), 0, default_path); 
	        *ppNewPath = NULL;
	        return DSERR_BUFFERLOST;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
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 1105 1106 1107
static HRESULT WINAPI IDirectMusicPerformance8Impl_SetDefaultAudioPath(IDirectMusicPerformance8 *iface,
        IDirectMusicAudioPath *pAudioPath)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
1108

1109 1110
	FIXME("(%p, %p): semi-stub\n", This, pAudioPath);
	if (NULL != This->pDefaultPath) {
1111
		IDirectMusicAudioPath_Release(This->pDefaultPath);
1112 1113 1114 1115 1116
		((IDirectMusicAudioPathImpl*) This->pDefaultPath)->pPerf = NULL;
		This->pDefaultPath = NULL;
	}
	This->pDefaultPath = pAudioPath;
	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 1125 1126 1127
static HRESULT WINAPI IDirectMusicPerformance8Impl_GetDefaultAudioPath(IDirectMusicPerformance8 *iface,
        IDirectMusicAudioPath **ppAudioPath)
{
        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
1128

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

1131
	if (NULL != This->pDefaultPath) {
1132
	  *ppAudioPath = This->pDefaultPath;
1133
          IDirectMusicAudioPath_AddRef(*ppAudioPath);
1134 1135 1136
        } else {
	  *ppAudioPath = NULL;
        }
1137
	return S_OK;
1138 1139
}

1140 1141 1142 1143 1144
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
1145

1146
	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
1147 1148

	return S_OK;
1149 1150
}

1151
static const IDirectMusicPerformance8Vtbl DirectMusicPerformance8_Vtbl = {
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 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
	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,
1196 1197 1198 1199 1200 1201 1202 1203 1204
	IDirectMusicPerformance8Impl_InitAudio,
	IDirectMusicPerformance8Impl_PlaySegmentEx,
	IDirectMusicPerformance8Impl_StopEx,
	IDirectMusicPerformance8Impl_ClonePMsg,
	IDirectMusicPerformance8Impl_CreateAudioPath,
	IDirectMusicPerformance8Impl_CreateStandardAudioPath,
	IDirectMusicPerformance8Impl_SetDefaultAudioPath,
	IDirectMusicPerformance8Impl_GetDefaultAudioPath,
	IDirectMusicPerformance8Impl_GetParamEx
1205
};
1206 1207

/* for ClassFactory */
1208 1209 1210 1211 1212
HRESULT WINAPI DMUSIC_CreateDirectMusicPerformanceImpl (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter) {
	IDirectMusicPerformance8Impl *obj;

	TRACE("(%p,%p,%p)\n", lpcGUID, ppobj, pUnkOuter);

1213 1214 1215 1216 1217
        if (pUnkOuter) {
                *ppobj = NULL;
                return CLASS_E_NOAGGREGATION;
        }

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 1226 1227
	obj->pDirectMusic = NULL;
	obj->pDirectSound = NULL;
	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 1233
	obj->dwBumperLength =   50; /* 50ms default */
	obj->dwPrepareTime  = 1000; /* 1000ms default */
1234 1235
        return IDirectMusicPerformance8Impl_QueryInterface(&obj->IDirectMusicPerformance8_iface,
                                                           lpcGUID, ppobj);
1236
}