Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1071 lines
33 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) 1998-1999 Microsoft Corporation
  6. //
  7. // File: cmmdtrk.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
  11. //
  12. // 4530: C++ exception handler used, but unwind semantics are not enabled. Specify -GX
  13. //
  14. // We disable this because we use exceptions and do *not* specify -GX (USE_NATIVE_EH in
  15. // sources).
  16. //
  17. // The one place we use exceptions is around construction of objects that call
  18. // InitializeCriticalSection. We guarantee that it is safe to use in this case with
  19. // the restriction given by not using -GX (automatic objects in the call chain between
  20. // throw and handler are not destructed). Turning on -GX buys us nothing but +10% to code
  21. // size because of the unwind code.
  22. //
  23. // Any other use of exceptions must follow these restrictions or -GX must be turned on.
  24. //
  25. // READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
  26. //
  27. #pragma warning(disable:4530)
  28. // CommandTrack.cpp : Implementation of CCommandTrack
  29. #include <objbase.h>
  30. #include "CmmdTrk.h"
  31. #include "debug.h"
  32. #include "debug.h"
  33. #include "..\shared\Validate.h"
  34. /////////////////////////////////////////////////////////////////////////////
  35. // CCommandTrack
  36. CCommandTrack::CCommandTrack() : m_bRequiresSave(0),
  37. m_cRef(1), m_fNotifyCommand(FALSE), m_fCSInitialized(FALSE), m_pNextCommand(NULL)
  38. {
  39. InterlockedIncrement(&g_cComponent);
  40. ::InitializeCriticalSection( &m_CriticalSection );
  41. m_fCSInitialized = TRUE;
  42. }
  43. // it is assumed that cloning of commands will only happen on measure boundaries
  44. CCommandTrack::CCommandTrack(const CCommandTrack& rTrack, MUSIC_TIME mtStart, MUSIC_TIME mtEnd) :
  45. m_bRequiresSave(0),
  46. m_cRef(1), m_fNotifyCommand(rTrack.m_fNotifyCommand),
  47. m_fCSInitialized(FALSE), m_pNextCommand(NULL)
  48. {
  49. InterlockedIncrement(&g_cComponent);
  50. ::InitializeCriticalSection( &m_CriticalSection );
  51. m_fCSInitialized = TRUE;
  52. WORD wMeasure = 0;
  53. BOOL fStarted = FALSE;
  54. TListItem<DMCommand>* pScan = rTrack.m_CommandList.GetHead();
  55. TListItem<DMCommand>* pPrevious = NULL;
  56. for(; pScan; pScan = pScan->GetNext())
  57. {
  58. DMCommand& rScan = pScan->GetItemValue();
  59. if (rScan.m_mtTime < mtStart)
  60. {
  61. pPrevious = pScan;
  62. }
  63. else if (rScan.m_mtTime < mtEnd)
  64. {
  65. if (!fStarted)
  66. {
  67. fStarted = TRUE;
  68. wMeasure = rScan.m_wMeasure;
  69. }
  70. if (rScan.m_mtTime == mtStart)
  71. {
  72. pPrevious = NULL;
  73. }
  74. TListItem<DMCommand>* pNew = new TListItem<DMCommand>;
  75. if (pNew)
  76. {
  77. DMCommand& rNew = pNew->GetItemValue();
  78. rNew.m_mtTime = rScan.m_mtTime - mtStart;
  79. rNew.m_wMeasure = rScan.m_wMeasure - wMeasure;
  80. rNew.m_bBeat = rScan.m_bBeat;
  81. rNew.m_bCommand = rScan.m_bCommand;
  82. rNew.m_bGrooveLevel = rScan.m_bGrooveLevel;
  83. rNew.m_bGrooveRange = rScan.m_bGrooveRange;
  84. rNew.m_bRepeatMode = rScan.m_bRepeatMode;
  85. m_CommandList.AddTail(pNew);
  86. }
  87. }
  88. else break;
  89. }
  90. if (pPrevious)
  91. {
  92. TListItem<DMCommand>* pNew = new TListItem<DMCommand>;
  93. if (pNew)
  94. {
  95. DMCommand& rNew = pNew->GetItemValue();
  96. rNew.m_mtTime = 0;
  97. rNew.m_wMeasure = 0;
  98. rNew.m_bBeat = 0;
  99. // Since embellishments are only supposed to last for a bar,
  100. // start the new segment with a regular groove.
  101. rNew.m_bCommand = DMUS_COMMANDT_GROOVE;
  102. // Keep the groove level and range of the previous bar.
  103. rNew.m_bGrooveLevel = pPrevious->GetItemValue().m_bGrooveLevel;
  104. rNew.m_bGrooveRange = pPrevious->GetItemValue().m_bGrooveRange;
  105. // Default to random selection of the pattern.
  106. rNew.m_bRepeatMode = DMUS_PATTERNT_RANDOM;
  107. m_CommandList.AddHead(pNew);
  108. }
  109. }
  110. }
  111. CCommandTrack::~CCommandTrack()
  112. {
  113. if (m_fCSInitialized)
  114. {
  115. ::DeleteCriticalSection( &m_CriticalSection );
  116. }
  117. if (m_pNextCommand)
  118. {
  119. delete m_pNextCommand;
  120. }
  121. InterlockedDecrement(&g_cComponent);
  122. }
  123. void CCommandTrack::Clear()
  124. {
  125. m_CommandList.CleanUp();
  126. }
  127. STDMETHODIMP CCommandTrack::QueryInterface(
  128. const IID &iid,
  129. void **ppv)
  130. {
  131. V_INAME(CCommandTrack::QueryInterface);
  132. V_REFGUID(iid);
  133. V_PTRPTR_WRITE(ppv);
  134. if (iid == IID_IUnknown || iid == IID_IDirectMusicTrack || iid == IID_IDirectMusicTrack8)
  135. {
  136. *ppv = static_cast<IDirectMusicTrack*>(this);
  137. }
  138. else if (iid == IID_IPersistStream)
  139. {
  140. *ppv = static_cast<IPersistStream*>(this);
  141. }
  142. else
  143. {
  144. *ppv = NULL;
  145. return E_NOINTERFACE;
  146. }
  147. reinterpret_cast<IUnknown*>(this)->AddRef();
  148. return S_OK;
  149. }
  150. STDMETHODIMP_(ULONG) CCommandTrack::AddRef()
  151. {
  152. return InterlockedIncrement(&m_cRef);
  153. }
  154. STDMETHODIMP_(ULONG) CCommandTrack::Release()
  155. {
  156. if (!InterlockedDecrement(&m_cRef))
  157. {
  158. delete this;
  159. return 0;
  160. }
  161. return m_cRef;
  162. }
  163. // CCommandTrack Methods
  164. HRESULT CCommandTrack::Init(
  165. /*[in]*/ IDirectMusicSegment* pSegment
  166. )
  167. {
  168. V_INAME(CCommandTrack::Init);
  169. V_INTERFACE(pSegment);
  170. return S_OK;
  171. }
  172. HRESULT CCommandTrack::InitPlay(
  173. /*[in]*/ IDirectMusicSegmentState* pSegmentState,
  174. /*[in]*/ IDirectMusicPerformance* pPerformance,
  175. /*[out]*/ void** ppStateData,
  176. /*[in]*/ DWORD dwTrackID,
  177. /*[in]*/ DWORD dwFlags
  178. )
  179. {
  180. HRESULT hr = S_OK;
  181. CommandStateData* pStateData;
  182. EnterCriticalSection( &m_CriticalSection );
  183. pStateData = new CommandStateData;
  184. if( NULL == pStateData )
  185. {
  186. hr = E_OUTOFMEMORY;
  187. }
  188. else
  189. {
  190. *pStateData = 0;
  191. *ppStateData = pStateData;
  192. }
  193. LeaveCriticalSection( &m_CriticalSection );
  194. return hr;
  195. }
  196. HRESULT CCommandTrack::EndPlay(
  197. /*[in]*/ void* pStateData
  198. )
  199. {
  200. if( pStateData )
  201. {
  202. V_INAME(IDirectMusicTrack::EndPlay);
  203. V_BUFPTR_WRITE(pStateData, sizeof(CommandStateData));
  204. CommandStateData* pSD = (CommandStateData*)pStateData;
  205. delete pSD;
  206. }
  207. if (m_pNextCommand) delete m_pNextCommand;
  208. m_pNextCommand = NULL;
  209. return S_OK;
  210. }
  211. HRESULT CCommandTrack::SendNotification(DWORD dwCommand,
  212. MUSIC_TIME mtTime,
  213. IDirectMusicPerformance* pPerf,
  214. IDirectMusicSegmentState* pSegState,
  215. DWORD dwFlags)
  216. {
  217. if (dwFlags & DMUS_TRACKF_NOTIFY_OFF)
  218. {
  219. return S_OK;
  220. }
  221. IDirectMusicSegment* pSegment = NULL;
  222. DWORD dwOption = DMUS_NOTIFICATION_GROOVE;
  223. if (dwCommand != DMUS_COMMANDT_GROOVE)
  224. {
  225. dwOption = DMUS_NOTIFICATION_EMBELLISHMENT;
  226. }
  227. DMUS_NOTIFICATION_PMSG* pEvent = NULL;
  228. HRESULT hr = pPerf->AllocPMsg( sizeof(DMUS_NOTIFICATION_PMSG), (DMUS_PMSG**)&pEvent );
  229. if( SUCCEEDED( hr ))
  230. {
  231. pEvent->dwField1 = 0;
  232. pEvent->dwField2 = 0;
  233. pEvent->dwType = DMUS_PMSGT_NOTIFICATION;
  234. pEvent->mtTime = mtTime;
  235. pEvent->dwFlags = DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_ATTIME;
  236. pSegState->QueryInterface(IID_IUnknown, (void**)&pEvent->punkUser);
  237. pEvent->dwNotificationOption = dwOption;
  238. pEvent->guidNotificationType = GUID_NOTIFICATION_COMMAND;
  239. if( SUCCEEDED( pSegState->GetSegment(&pSegment)))
  240. {
  241. if (FAILED(pSegment->GetTrackGroup(this, &pEvent->dwGroupID)))
  242. {
  243. pEvent->dwGroupID = 0xffffffff;
  244. }
  245. pSegment->Release();
  246. }
  247. IDirectMusicGraph* pGraph;
  248. hr = pSegState->QueryInterface( IID_IDirectMusicGraph, (void**)&pGraph );
  249. if( SUCCEEDED( hr ))
  250. {
  251. pGraph->StampPMsg((DMUS_PMSG*) pEvent );
  252. pGraph->Release();
  253. }
  254. hr = pPerf->SendPMsg((DMUS_PMSG*) pEvent );
  255. if( FAILED(hr) )
  256. {
  257. pPerf->FreePMsg((DMUS_PMSG*) pEvent );
  258. }
  259. }
  260. return hr;
  261. }
  262. HRESULT CCommandTrack::Play(
  263. /*[in]*/ void* pStateData,
  264. /*[in]*/ MUSIC_TIME mtStart,
  265. /*[in]*/ MUSIC_TIME mtEnd,
  266. /*[in]*/ MUSIC_TIME mtOffset,
  267. DWORD dwFlags,
  268. IDirectMusicPerformance* pPerf,
  269. IDirectMusicSegmentState* pSegState,
  270. DWORD dwVirtualID
  271. )
  272. {
  273. bool fNotifyPastCommand = false;
  274. TListItem<DMCommand>* pLastCommand = NULL;
  275. // If we're seeking and not flushing, we need to notify for the command that happens
  276. // before the current start time (if there is one)
  277. if ( (dwFlags & DMUS_TRACKF_SEEK) && !(dwFlags & DMUS_TRACKF_FLUSH) )
  278. {
  279. fNotifyPastCommand = true;
  280. }
  281. HRESULT hr = S_OK;
  282. EnterCriticalSection( &m_CriticalSection );
  283. if (m_fNotifyCommand)
  284. {
  285. TListItem<DMCommand>* pCommand = m_CommandList.GetHead();
  286. for(; pCommand && SUCCEEDED(hr); pCommand = pCommand->GetNext())
  287. {
  288. MUSIC_TIME mtCommandTime = pCommand->GetItemValue().m_mtTime;
  289. if (mtCommandTime < mtStart && fNotifyPastCommand)
  290. {
  291. pLastCommand = pCommand;
  292. }
  293. else if (mtStart <= mtCommandTime && mtCommandTime < mtEnd)
  294. {
  295. if (pLastCommand)
  296. {
  297. hr = SendNotification(pLastCommand->GetItemValue().m_bCommand,
  298. mtStart + mtOffset, pPerf, pSegState, dwFlags);
  299. pLastCommand = NULL;
  300. }
  301. if (SUCCEEDED(hr))
  302. {
  303. hr = SendNotification(pCommand->GetItemValue().m_bCommand,
  304. mtCommandTime + mtOffset, pPerf, pSegState, dwFlags);
  305. }
  306. }
  307. else if (mtCommandTime >= mtEnd)
  308. {
  309. if (pLastCommand)
  310. {
  311. hr = SendNotification(pLastCommand->GetItemValue().m_bCommand,
  312. mtStart + mtOffset, pPerf, pSegState, dwFlags);
  313. }
  314. break;
  315. }
  316. }
  317. }
  318. LeaveCriticalSection( &m_CriticalSection );
  319. return hr;
  320. }
  321. HRESULT CCommandTrack::GetPriority(
  322. /*[out]*/ DWORD* pPriority
  323. )
  324. {
  325. return E_NOTIMPL;
  326. }
  327. // Returns the Command in effect at the measure containing mtTime.
  328. HRESULT CCommandTrack::GetParam(
  329. REFGUID rCommandGuid,
  330. MUSIC_TIME mtTime,
  331. MUSIC_TIME* pmtNext,
  332. void *pData)
  333. {
  334. V_INAME(CCommandTrack::GetParam);
  335. V_PTR_WRITE_OPT(pmtNext,MUSIC_TIME);
  336. V_REFGUID(rCommandGuid);
  337. if (rCommandGuid == GUID_CommandParam2)
  338. {
  339. return GetParam2(mtTime, pmtNext, (DMUS_COMMAND_PARAM_2*) pData);
  340. }
  341. else if (rCommandGuid == GUID_CommandParamNext)
  342. {
  343. return GetParamNext(mtTime, pmtNext, (DMUS_COMMAND_PARAM_2*) pData);
  344. }
  345. else if (rCommandGuid != GUID_CommandParam)
  346. {
  347. return DMUS_E_GET_UNSUPPORTED;
  348. }
  349. HRESULT hr = S_OK;
  350. if (pData) // Something got passed in
  351. {
  352. EnterCriticalSection( &m_CriticalSection );
  353. DMUS_COMMAND_PARAM* pCommandParam = (DMUS_COMMAND_PARAM*) pData;
  354. // Default to the old groove C
  355. BYTE bCommand = DMUS_COMMANDT_GROOVE;
  356. BYTE bGrooveLevel = 62;
  357. BYTE bGrooveRange = 0;
  358. BYTE bRepeatMode = DMUS_PATTERNT_RANDOM;
  359. TListItem<DMCommand>* pNext = m_CommandList.GetHead();
  360. const int epsilon = DMUS_PPQ / 16; // leave a 64th note on either side...
  361. for( ; pNext; pNext = pNext->GetNext())
  362. {
  363. if ( abs(pNext->GetItemValue().m_mtTime - mtTime) < epsilon ) // this is it
  364. {
  365. bCommand = pNext->GetItemValue().m_bCommand;
  366. bGrooveLevel = pNext->GetItemValue().m_bGrooveLevel;
  367. bGrooveRange = pNext->GetItemValue().m_bGrooveRange;
  368. bRepeatMode = pNext->GetItemValue().m_bRepeatMode;
  369. pNext = pNext->GetNext();
  370. break;
  371. }
  372. else if (pNext->GetItemValue().m_mtTime < mtTime) // may be it, but we need a next time
  373. {
  374. bGrooveLevel = pNext->GetItemValue().m_bGrooveLevel;
  375. bGrooveRange = pNext->GetItemValue().m_bGrooveRange;
  376. bRepeatMode = pNext->GetItemValue().m_bRepeatMode;
  377. }
  378. else // passed it
  379. {
  380. break;
  381. }
  382. }
  383. hr = S_OK;
  384. pCommandParam->bCommand = bCommand;
  385. pCommandParam->bGrooveLevel = bGrooveLevel;
  386. pCommandParam->bGrooveRange = bGrooveRange;
  387. pCommandParam->bRepeatMode = bRepeatMode;
  388. if (pmtNext)
  389. {
  390. if (pNext)
  391. {
  392. *pmtNext = pNext->GetItemValue().m_mtTime - mtTime; // RSW: bug 167740
  393. }
  394. else
  395. {
  396. MUSIC_TIME mtLength = 0;
  397. *pmtNext = mtLength;
  398. }
  399. }
  400. LeaveCriticalSection( &m_CriticalSection );
  401. return hr;
  402. }
  403. else
  404. return E_POINTER;
  405. }
  406. HRESULT CCommandTrack::GetParam2(
  407. MUSIC_TIME mtTime,
  408. MUSIC_TIME* pmtNext,
  409. DMUS_COMMAND_PARAM_2* pCommandParam)
  410. {
  411. //TraceI(0, "GetParam time: %d\n", mtTime);
  412. HRESULT hr = S_OK;
  413. if (pCommandParam) // Something got passed in
  414. {
  415. EnterCriticalSection( &m_CriticalSection );
  416. // Default to the old groove C
  417. MUSIC_TIME mtCommandTime = 0;
  418. BYTE bCommand = DMUS_COMMANDT_GROOVE;
  419. BYTE bGrooveLevel = 62;
  420. BYTE bGrooveRange = 0;
  421. BYTE bRepeatMode = DMUS_PATTERNT_RANDOM;
  422. TListItem<DMCommand>* pNext = m_CommandList.GetHead();
  423. for( ; pNext; pNext = pNext->GetNext())
  424. {
  425. if (pNext->GetItemValue().m_mtTime <= mtTime) // may be it, but we need a next time
  426. {
  427. mtCommandTime = pNext->GetItemValue().m_mtTime - mtTime;
  428. bCommand = pNext->GetItemValue().m_bCommand;
  429. bGrooveLevel = pNext->GetItemValue().m_bGrooveLevel;
  430. bGrooveRange = pNext->GetItemValue().m_bGrooveRange;
  431. bRepeatMode = pNext->GetItemValue().m_bRepeatMode;
  432. }
  433. else // passed it
  434. {
  435. break;
  436. }
  437. }
  438. hr = S_OK;
  439. pCommandParam->mtTime = mtCommandTime;
  440. pCommandParam->bCommand = bCommand;
  441. pCommandParam->bGrooveLevel = bGrooveLevel;
  442. pCommandParam->bGrooveRange = bGrooveRange;
  443. pCommandParam->bRepeatMode = bRepeatMode;
  444. if (pmtNext)
  445. {
  446. if (pNext)
  447. {
  448. *pmtNext = pNext->GetItemValue().m_mtTime - mtTime; // RSW: bug 167740
  449. }
  450. else
  451. {
  452. *pmtNext = 0;
  453. }
  454. }
  455. LeaveCriticalSection( &m_CriticalSection );
  456. return hr;
  457. }
  458. else
  459. return E_POINTER;
  460. }
  461. HRESULT CCommandTrack::GetParamNext(
  462. MUSIC_TIME mtTime,
  463. MUSIC_TIME* pmtNext,
  464. DMUS_COMMAND_PARAM_2* pCommandParam)
  465. {
  466. HRESULT hr = S_OK;
  467. if (pCommandParam) // Something got passed in
  468. {
  469. EnterCriticalSection( &m_CriticalSection );
  470. if (m_pNextCommand)
  471. {
  472. *pCommandParam = *m_pNextCommand;
  473. }
  474. else
  475. {
  476. hr = DMUS_E_NOT_FOUND;
  477. /*// Default to the old groove C
  478. pCommandParam->bCommand = DMUS_COMMANDT_GROOVE;
  479. pCommandParam->bGrooveLevel = 62;
  480. pCommandParam->bGrooveRange = 0;*/
  481. }
  482. if (pmtNext)
  483. {
  484. *pmtNext = 0;
  485. }
  486. LeaveCriticalSection( &m_CriticalSection );
  487. return hr;
  488. }
  489. else
  490. return E_POINTER;
  491. }
  492. HRESULT CCommandTrack::SetParam(
  493. REFGUID rCommandGuid,
  494. MUSIC_TIME mtTime,
  495. void __RPC_FAR *pData)
  496. {
  497. V_INAME(CCommandTrack::SetParam);
  498. V_REFGUID(rCommandGuid);
  499. if (rCommandGuid == GUID_CommandParamNext)
  500. {
  501. return SetParamNext(mtTime, (DMUS_COMMAND_PARAM_2*) pData);
  502. }
  503. else if (rCommandGuid != GUID_CommandParam)
  504. {
  505. return DMUS_E_SET_UNSUPPORTED;
  506. }
  507. HRESULT hr = S_OK;
  508. if (pData) // Something got passed in
  509. {
  510. EnterCriticalSection( &m_CriticalSection );
  511. DMUS_COMMAND_PARAM* pCommandParam = (DMUS_COMMAND_PARAM*) pData;
  512. //DirectMusicTimeSig TimeSig = ((CommandData *)(pData))->m_TimeSig;
  513. //WORD wMeasure = ClocksToMeasure(mtTime, TimeSig);
  514. TListItem<DMCommand>* pCommand = m_CommandList.GetHead();
  515. TListItem<DMCommand>* pPrevious = NULL;
  516. TListItem<DMCommand>* pNew = new TListItem<DMCommand>;
  517. if (!pNew)
  518. {
  519. hr = E_OUTOFMEMORY;
  520. }
  521. else
  522. {
  523. DMCommand& rNew = pNew->GetItemValue();
  524. rNew.m_mtTime = mtTime;
  525. rNew.m_bBeat = 0;
  526. rNew.m_bCommand = pCommandParam->bCommand;
  527. rNew.m_bGrooveLevel = pCommandParam->bGrooveLevel;
  528. rNew.m_bGrooveRange = pCommandParam->bGrooveRange;
  529. rNew.m_bRepeatMode = pCommandParam->bRepeatMode;
  530. for (; pCommand != NULL; pCommand = pCommand->GetNext())
  531. {
  532. DMCommand& rCommand = pCommand->GetItemValue();
  533. if (rCommand.m_mtTime >= mtTime) break;
  534. pPrevious = pCommand;
  535. }
  536. if (pPrevious)
  537. {
  538. pPrevious->SetNext(pNew);
  539. pNew->SetNext(pCommand);
  540. }
  541. else // pCommand is current head of list
  542. {
  543. m_CommandList.AddHead(pNew);
  544. }
  545. if (pCommand && pCommand->GetItemValue().m_mtTime == mtTime)
  546. {
  547. // remove it
  548. pNew->SetNext(pCommand->GetNext());
  549. pCommand->SetNext(NULL);
  550. delete pCommand;
  551. }
  552. hr = S_OK;
  553. }
  554. LeaveCriticalSection( &m_CriticalSection );
  555. return hr;
  556. }
  557. else
  558. return E_POINTER;
  559. }
  560. HRESULT CCommandTrack::SetParamNext(
  561. MUSIC_TIME mtTime,
  562. DMUS_COMMAND_PARAM_2* pCommandParam)
  563. {
  564. EnterCriticalSection( &m_CriticalSection );
  565. if (m_pNextCommand)
  566. {
  567. delete m_pNextCommand;
  568. m_pNextCommand = NULL;
  569. }
  570. if (pCommandParam)
  571. {
  572. m_pNextCommand = new DMUS_COMMAND_PARAM_2;
  573. if (!m_pNextCommand)
  574. {
  575. LeaveCriticalSection( &m_CriticalSection );
  576. return E_OUTOFMEMORY;
  577. }
  578. *m_pNextCommand = *pCommandParam;
  579. }
  580. // Otherwise, allow a null pCommandParam to act as a reset.
  581. LeaveCriticalSection( &m_CriticalSection );
  582. return S_OK;
  583. }
  584. // IPersist methods
  585. HRESULT CCommandTrack::GetClassID( LPCLSID pClassID )
  586. {
  587. V_INAME(CCommandTrack::GetClassID);
  588. V_PTR_WRITE(pClassID, CLSID);
  589. *pClassID = CLSID_DirectMusicCommandTrack;
  590. return S_OK;
  591. }
  592. HRESULT CCommandTrack::IsParamSupported(
  593. /*[in]*/ REFGUID rGuid
  594. )
  595. {
  596. V_INAME(CCommandTrack::IsParamSupported);
  597. V_REFGUID(rGuid);
  598. if (rGuid == GUID_CommandParam ||
  599. rGuid == GUID_CommandParam2 ||
  600. rGuid == GUID_CommandParamNext)
  601. {
  602. return S_OK;
  603. }
  604. else
  605. {
  606. return DMUS_E_TYPE_UNSUPPORTED;
  607. }
  608. }
  609. // IPersistStream methods
  610. HRESULT CCommandTrack::IsDirty()
  611. {
  612. return m_bRequiresSave ? S_OK : S_FALSE;
  613. }
  614. HRESULT CCommandTrack::Save( LPSTREAM pStream, BOOL fClearDirty )
  615. {
  616. V_INAME(CCommandTrack::Save);
  617. V_INTERFACE(pStream);
  618. IAARIFFStream* pRIFF ;
  619. MMCKINFO ck;
  620. HRESULT hr;
  621. DWORD cb;
  622. DWORD dwSize;
  623. DMUS_IO_COMMAND iCommand;
  624. TListItem<DMCommand>* pCommand;
  625. EnterCriticalSection( &m_CriticalSection );
  626. hr = AllocRIFFStream( pStream, &pRIFF );
  627. if (!SUCCEEDED(hr))
  628. {
  629. goto ON_END;
  630. }
  631. hr = E_FAIL;
  632. ck.ckid = FOURCC_COMMAND;
  633. if( pRIFF->CreateChunk( &ck, 0 ) == 0 )
  634. {
  635. dwSize = sizeof( DMUS_IO_COMMAND );
  636. hr = pStream->Write( &dwSize, sizeof( dwSize ), &cb );
  637. if( FAILED( hr ) || cb != sizeof( dwSize ) )
  638. {
  639. if (SUCCEEDED(hr)) hr = E_FAIL;
  640. goto ON_END;
  641. }
  642. for( pCommand = m_CommandList.GetHead(); pCommand != NULL ; pCommand = pCommand->GetNext() )
  643. {
  644. DMCommand& rCommand = pCommand->GetItemValue();
  645. memset( &iCommand, 0, sizeof( iCommand ) );
  646. iCommand.mtTime = rCommand.m_mtTime;
  647. iCommand.wMeasure = rCommand.m_wMeasure;
  648. iCommand.bBeat = rCommand.m_bBeat;
  649. iCommand.bCommand = rCommand.m_bCommand;
  650. iCommand.bGrooveLevel = rCommand.m_bGrooveLevel;
  651. iCommand.bGrooveRange = rCommand.m_bGrooveRange;
  652. iCommand.bRepeatMode = rCommand.m_bRepeatMode;
  653. if( FAILED( pStream->Write( &iCommand, sizeof( iCommand ), &cb ) ) ||
  654. cb != sizeof( iCommand ) )
  655. {
  656. break;
  657. }
  658. }
  659. if( pCommand == NULL &&
  660. pRIFF->Ascend( &ck, 0 ) == 0 )
  661. {
  662. hr = S_OK;
  663. }
  664. }
  665. ON_END:
  666. if (pRIFF) pRIFF->Release();
  667. LeaveCriticalSection( &m_CriticalSection );
  668. return hr;
  669. }
  670. HRESULT CCommandTrack::GetSizeMax( ULARGE_INTEGER* /*pcbSize*/ )
  671. {
  672. return E_NOTIMPL;
  673. }
  674. BOOL Greater(DMCommand& Command1, DMCommand& Command2)
  675. { return Command1.m_wMeasure > Command2.m_wMeasure; }
  676. BOOL Less(DMCommand& Command1, DMCommand& Command2)
  677. { return Command1.m_wMeasure < Command2.m_wMeasure; }
  678. HRESULT CCommandTrack::Load(LPSTREAM pStream )
  679. {
  680. V_INAME(CCommandTrack::Load);
  681. V_INTERFACE(pStream);
  682. long lFileSize = 0;
  683. DWORD dwNodeSize;
  684. DWORD cb;
  685. MMCKINFO ck;
  686. IAARIFFStream* pRIFF;
  687. // FOURCC id = 0;
  688. HRESULT hr = E_FAIL;
  689. DMUS_IO_COMMAND iCommand;
  690. DWORD dwPos;
  691. EnterCriticalSection( &m_CriticalSection );
  692. Clear();
  693. dwPos = StreamTell( pStream );
  694. StreamSeek( pStream, dwPos, STREAM_SEEK_SET );
  695. ck.ckid = FOURCC_COMMAND;
  696. if( SUCCEEDED( AllocRIFFStream( pStream, &pRIFF ) ) &&
  697. pRIFF->Descend( &ck, NULL, MMIO_FINDCHUNK ) == 0 )
  698. {
  699. lFileSize = ck.cksize;
  700. hr = pStream->Read( &dwNodeSize, sizeof( dwNodeSize ), &cb );
  701. if( SUCCEEDED( hr ) && cb == sizeof( dwNodeSize ) )
  702. {
  703. lFileSize -= 4; // for the size dword
  704. TListItem<DMCommand>* pCommand;
  705. if (lFileSize % dwNodeSize)
  706. {
  707. hr = E_FAIL;
  708. }
  709. else
  710. {
  711. while( lFileSize > 0 )
  712. {
  713. pCommand = new TListItem<DMCommand>;
  714. if( pCommand )
  715. {
  716. DMCommand& rCommand = pCommand->GetItemValue();
  717. if( dwNodeSize <= sizeof( DMUS_IO_COMMAND ) )
  718. {
  719. pStream->Read( &iCommand, dwNodeSize, NULL );
  720. }
  721. else
  722. {
  723. pStream->Read( &iCommand, sizeof( DMUS_IO_COMMAND ), NULL );
  724. StreamSeek( pStream, lFileSize - sizeof( DMUS_IO_COMMAND ), STREAM_SEEK_CUR );
  725. }
  726. memset( &rCommand, 0, sizeof( rCommand ) );
  727. rCommand.m_mtTime = iCommand.mtTime;
  728. rCommand.m_wMeasure = iCommand.wMeasure;
  729. rCommand.m_bBeat = iCommand.bBeat;
  730. rCommand.m_bCommand = iCommand.bCommand;
  731. rCommand.m_bGrooveLevel = iCommand.bGrooveLevel;
  732. if( iCommand.bGrooveRange > 100 )
  733. {
  734. Trace(0, "Warning: Illegal value %d read for Command's groove range.\n", iCommand.bGrooveRange);
  735. rCommand.m_bGrooveRange = 0;
  736. }
  737. else
  738. {
  739. rCommand.m_bGrooveRange = iCommand.bGrooveRange;
  740. }
  741. if( iCommand.bRepeatMode > DMUS_PATTERNT_RANDOM_ROW )
  742. {
  743. Trace(0, "Warning: Illegal value %d read for Command's repeat mode.\n", iCommand.bRepeatMode);
  744. rCommand.m_bRepeatMode = 0;
  745. }
  746. else
  747. {
  748. rCommand.m_bRepeatMode = iCommand.bRepeatMode;
  749. }
  750. m_CommandList.AddTail(pCommand);
  751. lFileSize -= dwNodeSize;
  752. }
  753. else break;
  754. }
  755. }
  756. }
  757. if( lFileSize == 0 &&
  758. pRIFF->Ascend( &ck, 0 ) == 0 )
  759. {
  760. hr = S_OK;
  761. m_CommandList.MergeSort(Less);
  762. BYTE bLastGrooveLevel = 62;
  763. TListItem<DMCommand>* pCommand = m_CommandList.GetHead();
  764. for(; pCommand != NULL; pCommand = pCommand->GetNext())
  765. {
  766. if (!pCommand->GetItemValue().m_bGrooveLevel)
  767. {
  768. pCommand->GetItemValue().m_bGrooveLevel = bLastGrooveLevel;
  769. }
  770. else
  771. {
  772. bLastGrooveLevel = pCommand->GetItemValue().m_bGrooveLevel;
  773. }
  774. }
  775. }
  776. pRIFF->Release();
  777. }
  778. LeaveCriticalSection( &m_CriticalSection );
  779. return hr;
  780. }
  781. HRESULT STDMETHODCALLTYPE CCommandTrack::AddNotificationType(
  782. /* [in] */ REFGUID rGuidNotify)
  783. {
  784. V_INAME(CCommandTrack::AddNotificationType);
  785. V_REFGUID(rGuidNotify);
  786. if( rGuidNotify == GUID_NOTIFICATION_COMMAND )
  787. {
  788. m_fNotifyCommand = TRUE;
  789. return S_OK;
  790. }
  791. else
  792. {
  793. return S_FALSE;
  794. }
  795. }
  796. HRESULT STDMETHODCALLTYPE CCommandTrack::RemoveNotificationType(
  797. /* [in] */ REFGUID rGuidNotify)
  798. {
  799. V_INAME(CCommandTrack::RemoveNotificationType);
  800. V_REFGUID(rGuidNotify);
  801. if( rGuidNotify == GUID_NOTIFICATION_COMMAND )
  802. {
  803. m_fNotifyCommand = FALSE;
  804. return S_OK;
  805. }
  806. else
  807. {
  808. return S_FALSE;
  809. }
  810. }
  811. HRESULT STDMETHODCALLTYPE CCommandTrack::Clone(
  812. MUSIC_TIME mtStart,
  813. MUSIC_TIME mtEnd,
  814. IDirectMusicTrack** ppTrack)
  815. {
  816. V_INAME(CCommandTrack::Clone);
  817. V_PTRPTR_WRITE(ppTrack);
  818. HRESULT hr = S_OK;
  819. if(mtStart < 0 )
  820. {
  821. return E_INVALIDARG;
  822. }
  823. if(mtStart > mtEnd)
  824. {
  825. return E_INVALIDARG;
  826. }
  827. EnterCriticalSection( &m_CriticalSection );
  828. CCommandTrack *pDM;
  829. try
  830. {
  831. pDM = new CCommandTrack(*this, mtStart, mtEnd);
  832. }
  833. catch( ... )
  834. {
  835. pDM = NULL;
  836. }
  837. if (pDM == NULL) {
  838. LeaveCriticalSection( &m_CriticalSection );
  839. return E_OUTOFMEMORY;
  840. }
  841. hr = pDM->QueryInterface(IID_IDirectMusicTrack, (void**)ppTrack);
  842. pDM->Release();
  843. LeaveCriticalSection( &m_CriticalSection );
  844. return hr;
  845. }
  846. // For consistency with other track types
  847. STDMETHODIMP CCommandTrack::GetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime,
  848. REFERENCE_TIME* prtNext,void* pParam,void * pStateData, DWORD dwFlags)
  849. {
  850. HRESULT hr;
  851. MUSIC_TIME mtNext;
  852. hr = GetParam(rguidType,(MUSIC_TIME) rtTime, &mtNext, pParam);
  853. if (prtNext)
  854. {
  855. *prtNext = mtNext;
  856. }
  857. return hr;
  858. }
  859. // For consistency with other track types
  860. STDMETHODIMP CCommandTrack::SetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime,
  861. void* pParam, void * pStateData, DWORD dwFlags)
  862. {
  863. return SetParam(rguidType, (MUSIC_TIME) rtTime , pParam);
  864. }
  865. // For consistency with other track types
  866. STDMETHODIMP CCommandTrack::PlayEx(void* pStateData,REFERENCE_TIME rtStart,
  867. REFERENCE_TIME rtEnd,REFERENCE_TIME rtOffset,
  868. DWORD dwFlags,IDirectMusicPerformance* pPerf,
  869. IDirectMusicSegmentState* pSegSt,DWORD dwVirtualID)
  870. {
  871. V_INAME(IDirectMusicTrack::PlayEx);
  872. V_INTERFACE(pPerf);
  873. V_INTERFACE(pSegSt);
  874. HRESULT hr;
  875. EnterCriticalSection(&m_CriticalSection);
  876. hr = Play(pStateData, (MUSIC_TIME)rtStart, (MUSIC_TIME)rtEnd,
  877. (MUSIC_TIME)rtOffset, dwFlags, pPerf, pSegSt, dwVirtualID);
  878. LeaveCriticalSection(&m_CriticalSection);
  879. return hr;
  880. }
  881. STDMETHODIMP CCommandTrack::Compose(
  882. IUnknown* pContext,
  883. DWORD dwTrackGroup,
  884. IDirectMusicTrack** ppResultTrack)
  885. {
  886. return E_NOTIMPL;
  887. }
  888. STDMETHODIMP CCommandTrack::Join(
  889. IDirectMusicTrack* pNewTrack,
  890. MUSIC_TIME mtJoin,
  891. IUnknown* pContext,
  892. DWORD dwTrackGroup,
  893. IDirectMusicTrack** ppResultTrack)
  894. {
  895. V_INAME(IDirectMusicTrack::Join);
  896. V_INTERFACE(pNewTrack);
  897. V_INTERFACE(pContext);
  898. V_PTRPTR_WRITE_OPT(ppResultTrack);
  899. HRESULT hr = S_OK;
  900. EnterCriticalSection(&m_CriticalSection);
  901. TList<DMCommand> ResultList;
  902. CCommandTrack* pResultTrack = NULL;
  903. if (ppResultTrack)
  904. {
  905. hr = Clone(0, mtJoin, ppResultTrack);
  906. pResultTrack = (CCommandTrack*)*ppResultTrack;
  907. while(!pResultTrack->m_CommandList.IsEmpty())
  908. {
  909. ResultList.AddHead(pResultTrack->m_CommandList.RemoveHead());
  910. }
  911. }
  912. else
  913. {
  914. pResultTrack = this;
  915. while(!m_CommandList.IsEmpty() &&
  916. m_CommandList.GetHead()->GetItemValue().m_mtTime < mtJoin)
  917. {
  918. ResultList.AddHead(m_CommandList.RemoveHead());
  919. }
  920. m_CommandList.CleanUp();
  921. }
  922. WORD wMeasure = 0;
  923. HRESULT hrTimeSig = S_OK;
  924. MUSIC_TIME mtTimeSig = 0;
  925. MUSIC_TIME mtOver = 0;
  926. IDirectMusicSong* pSong = NULL;
  927. IDirectMusicSegment* pSegment = NULL;
  928. if (FAILED(pContext->QueryInterface(IID_IDirectMusicSegment, (void**)&pSegment)))
  929. {
  930. if (FAILED(pContext->QueryInterface(IID_IDirectMusicSong, (void**)&pSong)))
  931. {
  932. hrTimeSig = E_FAIL;
  933. }
  934. }
  935. while (SUCCEEDED(hrTimeSig) && mtTimeSig < mtJoin)
  936. {
  937. DMUS_TIMESIGNATURE TimeSig;
  938. MUSIC_TIME mtNext = 0;
  939. if (pSegment)
  940. {
  941. hrTimeSig = pSegment->GetParam(GUID_TimeSignature, dwTrackGroup, 0, mtTimeSig, &mtNext, (void*)&TimeSig);
  942. }
  943. else
  944. {
  945. hrTimeSig = pSong->GetParam(GUID_TimeSignature, dwTrackGroup, 0, mtTimeSig, &mtNext, (void*)&TimeSig);
  946. }
  947. if (SUCCEEDED(hrTimeSig))
  948. {
  949. if (!mtNext) mtNext = mtJoin - mtTimeSig; // means no more time sigs
  950. DirectMusicTimeSig DMTimeSig = TimeSig;
  951. WORD wMeasureOffset = (WORD)DMTimeSig.ClocksToMeasure(mtNext + mtOver);
  952. MUSIC_TIME mtMeasureOffset = (MUSIC_TIME) wMeasureOffset;
  953. // The following line crashes on certain builds on certain machines.
  954. // mtOver = mtMeasureOffset ? (mtNext % mtMeasureOffset) : 0;
  955. if (mtMeasureOffset)
  956. {
  957. mtOver = mtNext % mtMeasureOffset;
  958. }
  959. else
  960. {
  961. mtOver = 0;
  962. }
  963. wMeasure += wMeasureOffset;
  964. mtTimeSig += mtNext;
  965. }
  966. }
  967. CCommandTrack* pOtherTrack = (CCommandTrack*)pNewTrack;
  968. TListItem<DMCommand>* pScan = pOtherTrack->m_CommandList.GetHead();
  969. for (; pScan; pScan = pScan->GetNext())
  970. {
  971. TListItem<DMCommand>* pNew = new TListItem<DMCommand>(pScan->GetItemValue());
  972. if (pNew)
  973. {
  974. pNew->GetItemValue().m_mtTime += mtJoin;
  975. pNew->GetItemValue().m_wMeasure += wMeasure;
  976. ResultList.AddHead(pNew);
  977. }
  978. else
  979. {
  980. ResultList.CleanUp();
  981. hr = E_OUTOFMEMORY;
  982. break;
  983. }
  984. }
  985. if (SUCCEEDED(hr))
  986. {
  987. pResultTrack->m_CommandList.CleanUp();
  988. while(!ResultList.IsEmpty() )
  989. {
  990. pResultTrack->m_CommandList.AddHead(ResultList.RemoveHead());
  991. }
  992. }
  993. if (pSong) pSong->Release();
  994. if (pSegment) pSegment->Release();
  995. LeaveCriticalSection(&m_CriticalSection);
  996. return hr;
  997. }