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.

935 lines
29 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) 1998-1999 Microsoft Corporation
  6. //
  7. // File: spsttrk.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. // SPstTrk.cpp : Implementation of CSPstTrk
  29. #include "SPstTrk.h"
  30. #include "debug.h"
  31. #include "..\shared\Validate.h"
  32. /////////////////////////////////////////////////////////////////////////////
  33. // CSPstTrk
  34. CSPstTrk::CSPstTrk() :
  35. m_bRequiresSave(0), m_pPerformance(NULL),
  36. m_pComposer(NULL),
  37. m_fNotifyRecompose(FALSE),
  38. // m_pSegment(NULL),
  39. m_cRef(1),
  40. m_fCSInitialized(FALSE)
  41. {
  42. InterlockedIncrement(&g_cComponent);
  43. // Do this first since it might throw an exception
  44. //
  45. ::InitializeCriticalSection( &m_CriticalSection );
  46. m_fCSInitialized = TRUE;
  47. }
  48. // This assumes cloning on measure boundaries
  49. CSPstTrk::CSPstTrk(const CSPstTrk& rTrack, MUSIC_TIME mtStart, MUSIC_TIME mtEnd) :
  50. m_bRequiresSave(0), m_pPerformance(NULL),
  51. m_pComposer(NULL),
  52. m_fNotifyRecompose(FALSE),
  53. //m_pSegment(NULL),
  54. m_cRef(1),
  55. m_fCSInitialized(FALSE)
  56. {
  57. InterlockedIncrement(&g_cComponent);
  58. // Do this first since it might throw an exception
  59. //
  60. ::InitializeCriticalSection( &m_CriticalSection );
  61. m_fCSInitialized = TRUE;
  62. BOOL fStarted = FALSE;
  63. WORD wMeasure = 0;
  64. TListItem<DMSignPostStruct>* pScan = rTrack.m_SignPostList.GetHead();
  65. TListItem<DMSignPostStruct>* pPrevious = NULL;
  66. for(; pScan; pScan = pScan->GetNext())
  67. {
  68. DMSignPostStruct& rScan = pScan->GetItemValue();
  69. if (rScan.m_mtTime < mtStart)
  70. {
  71. pPrevious = pScan;
  72. }
  73. else if (rScan.m_mtTime < mtEnd)
  74. {
  75. if (rScan.m_mtTime == mtStart)
  76. {
  77. pPrevious = NULL;
  78. }
  79. if (!fStarted)
  80. {
  81. fStarted = TRUE;
  82. wMeasure = rScan.m_wMeasure;
  83. }
  84. TListItem<DMSignPostStruct>* pNew = new TListItem<DMSignPostStruct>;
  85. if (pNew)
  86. {
  87. DMSignPostStruct& rNew = pNew->GetItemValue();
  88. rNew.m_mtTime = rScan.m_mtTime - mtStart;
  89. rNew.m_wMeasure = rScan.m_wMeasure - wMeasure;
  90. rNew.m_dwChords = rScan.m_dwChords;
  91. m_SignPostList.AddTail(pNew);
  92. }
  93. }
  94. else break;
  95. }
  96. if (pPrevious)
  97. {
  98. TListItem<DMSignPostStruct>* pNew = new TListItem<DMSignPostStruct>;
  99. if (pNew)
  100. {
  101. DMSignPostStruct& rNew = pNew->GetItemValue();
  102. rNew.m_mtTime = 0;
  103. rNew.m_wMeasure = 0;
  104. rNew.m_dwChords = pPrevious->GetItemValue().m_dwChords;
  105. m_SignPostList.AddHead(pNew);
  106. }
  107. }
  108. }
  109. CSPstTrk::~CSPstTrk()
  110. {
  111. if (m_pComposer)
  112. {
  113. delete m_pComposer;
  114. }
  115. if (m_fCSInitialized)
  116. {
  117. ::DeleteCriticalSection( &m_CriticalSection );
  118. }
  119. InterlockedDecrement(&g_cComponent);
  120. }
  121. void CSPstTrk::Clear()
  122. {
  123. m_SignPostList.CleanUp();
  124. }
  125. STDMETHODIMP CSPstTrk::QueryInterface(
  126. const IID &iid,
  127. void **ppv)
  128. {
  129. V_INAME(CSPstTrk::QueryInterface);
  130. V_PTRPTR_WRITE(ppv);
  131. V_REFGUID(iid);
  132. if (iid == IID_IUnknown || iid == IID_IDirectMusicTrack || iid == IID_IDirectMusicTrack8)
  133. {
  134. *ppv = static_cast<IDirectMusicTrack*>(this);
  135. }
  136. else if (iid == IID_IPersistStream)
  137. {
  138. *ppv = static_cast<IPersistStream*>(this);
  139. }
  140. else
  141. {
  142. *ppv = NULL;
  143. return E_NOINTERFACE;
  144. }
  145. reinterpret_cast<IUnknown*>(this)->AddRef();
  146. return S_OK;
  147. }
  148. STDMETHODIMP_(ULONG) CSPstTrk::AddRef()
  149. {
  150. return InterlockedIncrement(&m_cRef);
  151. }
  152. STDMETHODIMP_(ULONG) CSPstTrk::Release()
  153. {
  154. if (!InterlockedDecrement(&m_cRef))
  155. {
  156. delete this;
  157. return 0;
  158. }
  159. return m_cRef;
  160. }
  161. HRESULT CSPstTrk::Init(
  162. /*[in]*/ IDirectMusicSegment* pSegment
  163. )
  164. {
  165. return S_OK; // if I return an error, dmime gives me an assertion failure
  166. }
  167. HRESULT CSPstTrk::InitPlay(
  168. /*[in]*/ IDirectMusicSegmentState* pSegmentState,
  169. /*[in]*/ IDirectMusicPerformance* pPerformance,
  170. /*[out]*/ void** ppStateData,
  171. /*[in]*/ DWORD dwTrackID,
  172. /*[in]*/ DWORD dwFlags
  173. )
  174. {
  175. EnterCriticalSection(&m_CriticalSection);
  176. // get rid of any existing composer object
  177. if (m_pComposer)
  178. {
  179. delete m_pComposer;
  180. m_pComposer = NULL;
  181. }
  182. IDirectMusicSegment* pSegment = NULL;
  183. HRESULT hr = pSegmentState->GetSegment(&pSegment);
  184. if (SUCCEEDED(hr))
  185. {
  186. m_pComposer = new CDMCompos;
  187. if(!m_pComposer)
  188. {
  189. hr = E_OUTOFMEMORY;
  190. }
  191. pSegment->Release();
  192. }
  193. else
  194. {
  195. Trace(2, "WARNING: InitPlay (Signpost Track): Segment State does not contain a segment.\n");
  196. hr = S_OK; // Let it succeed anyway. Just means we can't compose on the fly.
  197. }
  198. LeaveCriticalSection(&m_CriticalSection);
  199. return hr;
  200. }
  201. HRESULT CSPstTrk::EndPlay(
  202. /*[in]*/ void* pStateData
  203. )
  204. {
  205. EnterCriticalSection(&m_CriticalSection);
  206. // get rid of any existing composer object
  207. if (m_pComposer)
  208. {
  209. delete m_pComposer;
  210. m_pComposer = NULL;
  211. }
  212. LeaveCriticalSection(&m_CriticalSection);
  213. return S_OK;
  214. }
  215. HRESULT CSPstTrk::Play(
  216. /*[in]*/ void* pStateData,
  217. /*[in]*/ MUSIC_TIME mtStart,
  218. /*[in]*/ MUSIC_TIME mtEnd,
  219. /*[in]*/ MUSIC_TIME mtOffset,
  220. DWORD dwFlags,
  221. IDirectMusicPerformance* pPerf,
  222. IDirectMusicSegmentState* pSegState,
  223. DWORD dwVirtualID
  224. )
  225. {
  226. bool fStart = (dwFlags & DMUS_TRACKF_START) ? true : false;
  227. bool fLoop = (dwFlags & DMUS_TRACKF_LOOP) ? true : false;
  228. bool fCompose = (dwFlags & DMUS_TRACKF_RECOMPOSE) ? true : false;
  229. bool fPlayOff = (dwFlags & DMUS_TRACKF_PLAY_OFF) ? true : false;
  230. EnterCriticalSection(&m_CriticalSection);
  231. if ( fStart || fLoop )
  232. {
  233. if ( fCompose && !fPlayOff )
  234. {
  235. IDirectMusicSegment* pSegment = NULL;
  236. if (SUCCEEDED(pSegState->GetSegment(&pSegment)))
  237. {
  238. // call ComposeSegmentFromTemplateEx on this segment
  239. if (m_pComposer)
  240. {
  241. // Should an activity level be allowed if desired?
  242. // This could be handled via a SetParam.
  243. m_pComposer->ComposeSegmentFromTemplateEx(
  244. NULL,
  245. pSegment,
  246. 0, // ignore activity level, don't clone
  247. 0, // for activity level
  248. NULL,
  249. NULL
  250. );
  251. // if we recomposed, send a recompose notification
  252. SendNotification(mtStart + mtOffset, pPerf, pSegment, pSegState, dwFlags);
  253. }
  254. pSegment->Release();
  255. }
  256. }
  257. }
  258. LeaveCriticalSection(&m_CriticalSection);
  259. return S_OK;
  260. }
  261. HRESULT CSPstTrk::SendNotification(MUSIC_TIME mtTime,
  262. IDirectMusicPerformance* pPerf,
  263. IDirectMusicSegment* pSegment,
  264. IDirectMusicSegmentState* pSegState,
  265. DWORD dwFlags)
  266. {
  267. if (!m_fNotifyRecompose || (dwFlags & DMUS_TRACKF_NOTIFY_OFF))
  268. {
  269. return S_OK;
  270. }
  271. DMUS_NOTIFICATION_PMSG* pEvent = NULL;
  272. HRESULT hr = pPerf->AllocPMsg( sizeof(DMUS_NOTIFICATION_PMSG), (DMUS_PMSG**)&pEvent );
  273. if( SUCCEEDED( hr ))
  274. {
  275. pEvent->dwField1 = 0;
  276. pEvent->dwField2 = 0;
  277. pEvent->dwType = DMUS_PMSGT_NOTIFICATION;
  278. pEvent->mtTime = mtTime;
  279. pEvent->dwFlags = DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_ATTIME;
  280. pSegState->QueryInterface(IID_IUnknown, (void**)&pEvent->punkUser);
  281. pEvent->dwNotificationOption = DMUS_NOTIFICATION_RECOMPOSE;
  282. pEvent->guidNotificationType = GUID_NOTIFICATION_RECOMPOSE;
  283. if (FAILED(pSegment->GetTrackGroup(this, &pEvent->dwGroupID)))
  284. {
  285. pEvent->dwGroupID = 0xffffffff;
  286. }
  287. IDirectMusicGraph* pGraph;
  288. hr = pSegState->QueryInterface( IID_IDirectMusicGraph, (void**)&pGraph );
  289. if( SUCCEEDED( hr ))
  290. {
  291. pGraph->StampPMsg((DMUS_PMSG*) pEvent );
  292. pGraph->Release();
  293. }
  294. hr = pPerf->SendPMsg((DMUS_PMSG*) pEvent );
  295. if( FAILED(hr) )
  296. {
  297. pPerf->FreePMsg((DMUS_PMSG*) pEvent );
  298. }
  299. }
  300. return hr;
  301. }
  302. HRESULT CSPstTrk::GetPriority(
  303. /*[out]*/ DWORD* pPriority
  304. )
  305. {
  306. return E_NOTIMPL;
  307. }
  308. HRESULT CSPstTrk::GetParam(
  309. REFGUID rCommandGuid,
  310. MUSIC_TIME mtTime,
  311. MUSIC_TIME* pmtNext,
  312. void* pData
  313. )
  314. {
  315. return E_NOTIMPL;
  316. }
  317. HRESULT CSPstTrk::SetParam(
  318. REFGUID rCommandGuid,
  319. MUSIC_TIME mtTime,
  320. void __RPC_FAR *pData)
  321. {
  322. return E_NOTIMPL;
  323. }
  324. // IPersist methods
  325. HRESULT CSPstTrk::GetClassID( LPCLSID pClassID )
  326. {
  327. V_INAME(CSPstTrk::GetClassID);
  328. V_PTR_WRITE(pClassID, CLSID);
  329. *pClassID = CLSID_DirectMusicSignPostTrack;
  330. return S_OK;
  331. }
  332. // IDirectMusicCommon Methods
  333. HRESULT CSPstTrk::GetName(
  334. /*[out]*/ BSTR* pbstrName
  335. )
  336. {
  337. return E_NOTIMPL;
  338. }
  339. HRESULT CSPstTrk::IsParamSupported(
  340. /*[in]*/ REFGUID rGuid
  341. )
  342. {
  343. return E_NOTIMPL;
  344. }
  345. // IPersistStream methods
  346. HRESULT CSPstTrk::IsDirty()
  347. {
  348. return m_bRequiresSave ? S_OK : S_FALSE;
  349. }
  350. HRESULT CSPstTrk::Save( LPSTREAM pStream, BOOL fClearDirty )
  351. {
  352. V_INAME(CSPstTrk::Save);
  353. V_INTERFACE(pStream);
  354. IAARIFFStream* pRIFF = NULL;
  355. MMCKINFO ck;
  356. HRESULT hr;
  357. DWORD cb;
  358. DWORD dwSize;
  359. DMUS_IO_SIGNPOST oSignPost;
  360. TListItem<DMSignPostStruct>* pSignPost;
  361. EnterCriticalSection( &m_CriticalSection );
  362. hr = AllocRIFFStream( pStream, &pRIFF );
  363. if ( FAILED( hr ) )
  364. {
  365. goto ON_END;
  366. }
  367. ck.ckid = DMUS_FOURCC_SIGNPOST_TRACK_CHUNK;
  368. if( pRIFF->CreateChunk( &ck, 0 ) == 0 )
  369. {
  370. dwSize = sizeof( oSignPost );
  371. hr = pStream->Write( &dwSize, sizeof( dwSize ), &cb );
  372. if( FAILED( hr ) || cb != sizeof( dwSize ) )
  373. {
  374. if (SUCCEEDED(hr)) hr = E_FAIL;
  375. goto ON_END;
  376. }
  377. for( pSignPost = m_SignPostList.GetHead(); pSignPost != NULL ; pSignPost = pSignPost->GetNext() )
  378. {
  379. DMSignPostStruct& rSignPost = pSignPost->GetItemValue();
  380. memset( &oSignPost, 0, sizeof( oSignPost ) );
  381. oSignPost.mtTime = rSignPost.m_mtTime;
  382. oSignPost.wMeasure = rSignPost.m_wMeasure;
  383. oSignPost.dwChords = rSignPost.m_dwChords;
  384. if( FAILED( pStream->Write( &oSignPost, sizeof( oSignPost ), &cb ) ) ||
  385. cb != sizeof( oSignPost ) )
  386. {
  387. break;
  388. }
  389. }
  390. if( pSignPost == NULL &&
  391. pRIFF->Ascend( &ck, 0 ) == 0 )
  392. {
  393. hr = S_OK;
  394. }
  395. }
  396. ON_END:
  397. if (pRIFF) pRIFF->Release();
  398. LeaveCriticalSection( &m_CriticalSection );
  399. return hr;
  400. }
  401. HRESULT CSPstTrk::GetSizeMax( ULARGE_INTEGER* /*pcbSize*/ )
  402. {
  403. return E_NOTIMPL;
  404. }
  405. BOOL Less(DMSignPostStruct& SP1, DMSignPostStruct& SP2)
  406. { return SP1.m_wMeasure < SP2.m_wMeasure; }
  407. HRESULT CSPstTrk::Load(LPSTREAM pStream )
  408. {
  409. V_INAME(CSPstTrk::Load);
  410. V_INTERFACE(pStream);
  411. HRESULT hr = E_FAIL;
  412. DWORD dwPos;
  413. IAARIFFStream* pRIFF;
  414. EnterCriticalSection( &m_CriticalSection );
  415. Clear();
  416. dwPos = StreamTell( pStream );
  417. StreamSeek( pStream, dwPos, STREAM_SEEK_SET );
  418. MMCKINFO ck;
  419. long lFileSize = 0;
  420. DWORD dwNodeSize;
  421. DWORD cb;
  422. DMUS_IO_SIGNPOST iSignPost;
  423. ck.ckid = DMUS_FOURCC_SIGNPOST_TRACK_CHUNK;
  424. if( SUCCEEDED( AllocRIFFStream( pStream, &pRIFF ) ) &&
  425. pRIFF->Descend( &ck, NULL, MMIO_FINDCHUNK ) == 0 )
  426. {
  427. lFileSize = (long) ck.cksize;
  428. hr = pStream->Read( &dwNodeSize, sizeof( dwNodeSize ), &cb );
  429. if( SUCCEEDED( hr ) && cb == sizeof( dwNodeSize ) )
  430. {
  431. lFileSize -= 4; // for the size dword
  432. TListItem<DMSignPostStruct>* pSignPost;
  433. if (lFileSize % dwNodeSize)
  434. {
  435. hr = E_FAIL;
  436. }
  437. else
  438. {
  439. while( lFileSize > 0 )
  440. {
  441. //TraceI(0, "File size: %d\n", lFileSize);
  442. pSignPost = new TListItem<DMSignPostStruct>;
  443. if( pSignPost )
  444. {
  445. DMSignPostStruct& rSignPost = pSignPost->GetItemValue();
  446. if( dwNodeSize <= sizeof( iSignPost ) )
  447. {
  448. pStream->Read( &iSignPost, dwNodeSize, NULL );
  449. }
  450. else
  451. {
  452. pStream->Read( &iSignPost, sizeof( iSignPost ), NULL );
  453. DWORD dw = (lFileSize >= sizeof( iSignPost ) ) ? lFileSize - sizeof( iSignPost ) : 0;
  454. StreamSeek( pStream, dw, STREAM_SEEK_CUR );
  455. }
  456. memset( &rSignPost, 0, sizeof( rSignPost ) );
  457. rSignPost.m_mtTime = iSignPost.mtTime;
  458. rSignPost.m_wMeasure = iSignPost.wMeasure;
  459. rSignPost.m_dwChords = iSignPost.dwChords;
  460. m_SignPostList.AddTail(pSignPost);
  461. lFileSize -= dwNodeSize;
  462. }
  463. else break;
  464. }
  465. }
  466. }
  467. if( lFileSize == 0 &&
  468. pRIFF->Ascend( &ck, 0 ) == 0 )
  469. {
  470. hr = S_OK;
  471. m_SignPostList.MergeSort(Less);
  472. }
  473. pRIFF->Release();
  474. }
  475. LeaveCriticalSection( &m_CriticalSection );
  476. return hr;
  477. }
  478. HRESULT STDMETHODCALLTYPE CSPstTrk::AddNotificationType(
  479. /* [in] */ REFGUID rGuidNotify)
  480. {
  481. V_INAME(CPersonalityTrack::AddNotificationType);
  482. V_REFGUID(rGuidNotify);
  483. if( rGuidNotify == GUID_NOTIFICATION_RECOMPOSE )
  484. {
  485. m_fNotifyRecompose = TRUE;
  486. return S_OK;
  487. }
  488. else
  489. {
  490. Trace(2, "WARNING: AddNotificationType (signpost track): Notification type not supported.\n");
  491. return S_FALSE;
  492. }
  493. }
  494. HRESULT STDMETHODCALLTYPE CSPstTrk::RemoveNotificationType(
  495. /* [in] */ REFGUID rGuidNotify)
  496. {
  497. V_INAME(CPersonalityTrack::RemoveNotificationType);
  498. V_REFGUID(rGuidNotify);
  499. if( rGuidNotify == GUID_NOTIFICATION_RECOMPOSE )
  500. {
  501. m_fNotifyRecompose = FALSE;
  502. return S_OK;
  503. }
  504. else
  505. {
  506. Trace(2, "WARNING: RemoveNotificationType (signpost track): Notification type not supported.\n");
  507. return S_FALSE;
  508. }
  509. }
  510. HRESULT STDMETHODCALLTYPE CSPstTrk::Clone(
  511. MUSIC_TIME mtStart,
  512. MUSIC_TIME mtEnd,
  513. IDirectMusicTrack** ppTrack)
  514. {
  515. V_INAME(CSPstTrk::Clone);
  516. V_PTRPTR_WRITE(ppTrack);
  517. HRESULT hr = S_OK;
  518. if(mtStart < 0 )
  519. {
  520. Trace(1, "ERROR: Clone (signpost map): Invalid start time.\n");
  521. return E_INVALIDARG;
  522. }
  523. if(mtStart > mtEnd)
  524. {
  525. Trace(1, "ERROR: Clone (signpost map): Invalid end time.\n");
  526. return E_INVALIDARG;
  527. }
  528. EnterCriticalSection( &m_CriticalSection );
  529. CSPstTrk *pDM;
  530. try
  531. {
  532. pDM = new CSPstTrk(*this, mtStart, mtEnd);
  533. }
  534. catch( ... )
  535. {
  536. pDM = NULL;
  537. }
  538. if (pDM == NULL) {
  539. LeaveCriticalSection( &m_CriticalSection );
  540. return E_OUTOFMEMORY;
  541. }
  542. hr = pDM->QueryInterface(IID_IDirectMusicTrack, (void**)ppTrack);
  543. pDM->Release();
  544. LeaveCriticalSection( &m_CriticalSection );
  545. return hr;
  546. }
  547. // IDirectMusicTrack8 Methods
  548. // For consistency with other track types
  549. STDMETHODIMP CSPstTrk::GetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime,
  550. REFERENCE_TIME* prtNext,void* pParam,void * pStateData, DWORD dwFlags)
  551. {
  552. HRESULT hr;
  553. MUSIC_TIME mtNext;
  554. hr = GetParam(rguidType,(MUSIC_TIME) rtTime, &mtNext, pParam);
  555. if (prtNext)
  556. {
  557. *prtNext = mtNext;
  558. }
  559. return hr;
  560. }
  561. // For consistency with other track types
  562. STDMETHODIMP CSPstTrk::SetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime,
  563. void* pParam, void * pStateData, DWORD dwFlags)
  564. {
  565. return SetParam(rguidType, (MUSIC_TIME) rtTime , pParam);
  566. }
  567. // For consistency with other track types
  568. STDMETHODIMP CSPstTrk::PlayEx(void* pStateData,REFERENCE_TIME rtStart,
  569. REFERENCE_TIME rtEnd,REFERENCE_TIME rtOffset,
  570. DWORD dwFlags,IDirectMusicPerformance* pPerf,
  571. IDirectMusicSegmentState* pSegSt,DWORD dwVirtualID)
  572. {
  573. V_INAME(IDirectMusicTrack::PlayEx);
  574. V_INTERFACE(pPerf);
  575. V_INTERFACE(pSegSt);
  576. HRESULT hr;
  577. EnterCriticalSection(&m_CriticalSection);
  578. hr = Play(pStateData, (MUSIC_TIME)rtStart, (MUSIC_TIME)rtEnd,
  579. (MUSIC_TIME)rtOffset, dwFlags, pPerf, pSegSt, dwVirtualID);
  580. LeaveCriticalSection(&m_CriticalSection);
  581. return hr;
  582. }
  583. STDMETHODIMP CSPstTrk::Compose(
  584. IUnknown* pContext,
  585. DWORD dwTrackGroup,
  586. IDirectMusicTrack** ppResultTrack)
  587. {
  588. V_INAME(IDirectMusicTrack::Compose)
  589. V_INTERFACE(pContext);
  590. V_PTRPTR_WRITE(ppResultTrack);
  591. EnterCriticalSection(&m_CriticalSection);
  592. HRESULT hr = S_OK;
  593. IDirectMusicTrack* pChordTrack = NULL;
  594. IDirectMusicTrack8* pCommandTrack = NULL;
  595. IDirectMusicStyle* pStyle = NULL;
  596. IDirectMusicTrack8* pChordMapTrack = NULL;
  597. IAARIFFStream* pChordRIFF = NULL;
  598. IStream* pIChordStream = NULL;
  599. IPersistStream* pIChordTrackStream = NULL;
  600. CDMCompos* pComposer = NULL;
  601. MUSIC_TIME mtLength = 0;
  602. IDirectMusicSegment* pTempSeg = NULL;
  603. IDirectMusicSong* pSong = NULL;
  604. if (FAILED(pContext->QueryInterface(IID_IDirectMusicSegment, (void**)&pTempSeg)))
  605. {
  606. if (FAILED(pContext->QueryInterface(IID_IDirectMusicSong, (void**)&pSong)))
  607. {
  608. Trace(1, "ERROR: Compose (signpost track): Missing segment or song.\n");
  609. hr = E_INVALIDARG;
  610. goto ON_END;
  611. }
  612. }
  613. if (pTempSeg)
  614. {
  615. if (FAILED(hr = pTempSeg->GetParam(GUID_IDirectMusicStyle, dwTrackGroup, 0, 0, NULL, (void*)&pStyle)))
  616. {
  617. if (FAILED(hr = pTempSeg->GetParam(GUID_IDirectMusicPatternStyle, dwTrackGroup, 0, 0, NULL, (void*)&pStyle)))
  618. {
  619. goto ON_END;
  620. }
  621. }
  622. hr = pTempSeg->GetTrack(CLSID_DirectMusicChordMapTrack, dwTrackGroup, 0, (IDirectMusicTrack**)&pChordMapTrack);
  623. if (FAILED(hr)) goto ON_END;
  624. if (FAILED(hr = pTempSeg->GetLength(&mtLength))) goto ON_END;
  625. hr = pTempSeg->GetTrack(CLSID_DirectMusicCommandTrack, dwTrackGroup, 0, (IDirectMusicTrack**)&pCommandTrack);
  626. if (FAILED(hr)) goto ON_END;
  627. }
  628. else if (pSong)
  629. {
  630. MUSIC_TIME mtNow = 0;
  631. MUSIC_TIME mtNext = 0;
  632. while (FAILED(hr = pSong->GetParam(GUID_IDirectMusicStyle, dwTrackGroup, 0, mtNow, &mtNext, (void*)&pStyle)))
  633. {
  634. if (SUCCEEDED(hr = pSong->GetParam(GUID_IDirectMusicPatternStyle, dwTrackGroup, 0, mtNow, NULL, (void*)&pStyle)))
  635. {
  636. break;
  637. }
  638. if (mtNext <= 0) goto ON_END;
  639. mtNow = mtNext;
  640. }
  641. IDirectMusicSegment* pSeg = NULL;
  642. DWORD dwSeg = 0;
  643. while (S_OK == hr)
  644. {
  645. if (FAILED(hr = pSong->EnumSegment(dwSeg, &pSeg))) goto ON_END;
  646. if (hr == S_OK)
  647. {
  648. HRESULT hrCommand = S_OK;
  649. HRESULT hrChordMap = S_OK;
  650. MUSIC_TIME mt = 0;
  651. hr = pSeg->GetLength(&mt);
  652. if (FAILED(hr))
  653. {
  654. pSeg->Release();
  655. goto ON_END;
  656. }
  657. IDirectMusicTrack8* pSegTrack = NULL;
  658. IDirectMusicTrack8* pSegTrack2 = NULL;
  659. hrCommand = pSeg->GetTrack(CLSID_DirectMusicCommandTrack, dwTrackGroup, 0, (IDirectMusicTrack**)&pSegTrack);
  660. hrChordMap = pSeg->GetTrack(CLSID_DirectMusicChordMapTrack, dwTrackGroup, 0, (IDirectMusicTrack**)&pSegTrack2);
  661. pSeg->Release();
  662. pSeg = NULL;
  663. if (SUCCEEDED(hrCommand))
  664. {
  665. if (!pCommandTrack)
  666. {
  667. hr = pSegTrack->Clone(0, 0, (IDirectMusicTrack**)&pCommandTrack);
  668. }
  669. if (SUCCEEDED(hr))
  670. {
  671. hr = pCommandTrack->Join(pSegTrack, mtLength, pSong, dwTrackGroup, NULL);
  672. }
  673. pSegTrack->Release();
  674. }
  675. if (SUCCEEDED(hrChordMap))
  676. {
  677. if (!pChordMapTrack)
  678. {
  679. hr = pSegTrack2->Clone(0, 0, (IDirectMusicTrack**)&pChordMapTrack);
  680. }
  681. if (SUCCEEDED(hr))
  682. {
  683. hr = pChordMapTrack->Join(pSegTrack2, mtLength, pSong, dwTrackGroup, NULL);
  684. }
  685. pSegTrack2->Release();
  686. }
  687. if (FAILED(hr)) goto ON_END;
  688. mtLength += mt;
  689. dwSeg++;
  690. }
  691. }
  692. }
  693. pComposer = new CDMCompos;
  694. if(!pComposer)
  695. {
  696. hr = E_OUTOFMEMORY;
  697. }
  698. if (SUCCEEDED(hr))
  699. {
  700. TList<PlayChord> PlayList;
  701. BYTE bRoot = 0;
  702. DWORD dwScale;
  703. hr = pComposer->ComposePlayListFromTemplate(
  704. pStyle, NULL, pChordMapTrack, (IDirectMusicTrack*)this, pCommandTrack, dwTrackGroup,
  705. mtLength, false, 0, PlayList, bRoot, dwScale);
  706. // create a new chord track
  707. DMUS_TIMESIGNATURE TimeSig;
  708. // Fill in the time sig event with default values (4/4, 16th note resolution)
  709. TimeSig.mtTime = 0;
  710. TimeSig.bBeatsPerMeasure = 4;
  711. TimeSig.bBeat = 4;
  712. TimeSig.wGridsPerBeat = 4;
  713. hr = ::CoCreateInstance(
  714. CLSID_DirectMusicChordTrack,
  715. NULL,
  716. CLSCTX_INPROC,
  717. IID_IDirectMusicTrack,
  718. (void**)&pChordTrack
  719. );
  720. if (!SUCCEEDED(hr)) goto ON_END;
  721. hr = CreateStreamOnHGlobal(NULL, TRUE, &pIChordStream);
  722. if (S_OK != hr) goto ON_END;
  723. hr = AllocRIFFStream( pIChordStream, &pChordRIFF);
  724. if (S_OK != hr) goto ON_END;
  725. pComposer->SaveChordList(pChordRIFF, PlayList, bRoot, dwScale, TimeSig);
  726. hr = pChordTrack->QueryInterface(IID_IPersistStream, (void**)&pIChordTrackStream);
  727. if (!SUCCEEDED(hr)) goto ON_END;
  728. StreamSeek(pIChordStream, 0, STREAM_SEEK_SET);
  729. hr = pIChordTrackStream->Load(pIChordStream);
  730. if (!SUCCEEDED(hr)) goto ON_END;
  731. *ppResultTrack = pChordTrack;
  732. }
  733. ON_END:
  734. if (pComposer) pComposer->CleanUp();
  735. if (pStyle) pStyle->Release();
  736. if (pChordRIFF) pChordRIFF->Release();
  737. if (pIChordStream) pIChordStream->Release();
  738. if (pIChordTrackStream) pIChordTrackStream->Release();
  739. if (pCommandTrack) pCommandTrack->Release();
  740. if (pChordMapTrack) pChordMapTrack->Release();
  741. if (pComposer) delete pComposer;
  742. if (pSong) pSong->Release();
  743. if (pTempSeg) pTempSeg->Release();
  744. LeaveCriticalSection(&m_CriticalSection);
  745. return hr;
  746. }
  747. STDMETHODIMP CSPstTrk::Join(
  748. IDirectMusicTrack* pNewTrack,
  749. MUSIC_TIME mtJoin,
  750. IUnknown* pContext,
  751. DWORD dwTrackGroup,
  752. IDirectMusicTrack** ppResultTrack)
  753. {
  754. V_INAME(IDirectMusicTrack::Join);
  755. V_INTERFACE(pNewTrack);
  756. V_INTERFACE(pContext);
  757. V_PTRPTR_WRITE_OPT(ppResultTrack);
  758. HRESULT hr = S_OK;
  759. EnterCriticalSection(&m_CriticalSection);
  760. TList<DMSignPostStruct> ResultList;
  761. CSPstTrk* pResultTrack = NULL;
  762. if (ppResultTrack)
  763. {
  764. hr = Clone(0, mtJoin, ppResultTrack);
  765. pResultTrack = (CSPstTrk*)*ppResultTrack;
  766. while(!pResultTrack->m_SignPostList.IsEmpty())
  767. {
  768. ResultList.AddHead(pResultTrack->m_SignPostList.RemoveHead());
  769. }
  770. }
  771. else
  772. {
  773. pResultTrack = this;
  774. while(!m_SignPostList.IsEmpty() &&
  775. m_SignPostList.GetHead()->GetItemValue().m_mtTime < mtJoin)
  776. {
  777. ResultList.AddHead(m_SignPostList.RemoveHead());
  778. }
  779. m_SignPostList.CleanUp();
  780. }
  781. WORD wMeasure = 0;
  782. HRESULT hrTimeSig = S_OK;
  783. MUSIC_TIME mtTimeSig = 0;
  784. MUSIC_TIME mtOver = 0;
  785. IDirectMusicSong* pSong = NULL;
  786. IDirectMusicSegment* pSegment = NULL;
  787. if (FAILED(pContext->QueryInterface(IID_IDirectMusicSegment, (void**)&pSegment)))
  788. {
  789. if (FAILED(pContext->QueryInterface(IID_IDirectMusicSong, (void**)&pSong)))
  790. {
  791. hrTimeSig = E_FAIL;
  792. }
  793. }
  794. while (SUCCEEDED(hrTimeSig) && mtTimeSig < mtJoin)
  795. {
  796. DMUS_TIMESIGNATURE TimeSig;
  797. MUSIC_TIME mtNext = 0;
  798. if (pSegment)
  799. {
  800. hrTimeSig = pSegment->GetParam(GUID_TimeSignature, dwTrackGroup, 0, mtTimeSig, &mtNext, (void*)&TimeSig);
  801. }
  802. else
  803. {
  804. hrTimeSig = pSong->GetParam(GUID_TimeSignature, dwTrackGroup, 0, mtTimeSig, &mtNext, (void*)&TimeSig);
  805. }
  806. if (SUCCEEDED(hrTimeSig))
  807. {
  808. if (!mtNext) mtNext = mtJoin - mtTimeSig; // means no more time sigs
  809. WORD wMeasureOffset = ClocksToMeasure(mtNext + mtOver, TimeSig);
  810. MUSIC_TIME mtMeasureOffset = (MUSIC_TIME) wMeasureOffset;
  811. // The following line crashes on certain builds on certain machines.
  812. // mtOver = mtMeasureOffset ? (mtNext % mtMeasureOffset) : 0;
  813. if (mtMeasureOffset)
  814. {
  815. mtOver = mtNext % mtMeasureOffset;
  816. }
  817. else
  818. {
  819. mtOver = 0;
  820. }
  821. wMeasure += wMeasureOffset;
  822. mtTimeSig += mtNext;
  823. }
  824. }
  825. CSPstTrk* pOtherTrack = (CSPstTrk*)pNewTrack;
  826. TListItem<DMSignPostStruct>* pScan = pOtherTrack->m_SignPostList.GetHead();
  827. for (; pScan; pScan = pScan->GetNext())
  828. {
  829. TListItem<DMSignPostStruct>* pNew = new TListItem<DMSignPostStruct>(pScan->GetItemValue());
  830. if (pNew)
  831. {
  832. pNew->GetItemValue().m_mtTime += mtJoin;
  833. pNew->GetItemValue().m_wMeasure += wMeasure;
  834. ResultList.AddHead(pNew);
  835. }
  836. else
  837. {
  838. ResultList.CleanUp();
  839. hr = E_OUTOFMEMORY;
  840. break;
  841. }
  842. }
  843. if (SUCCEEDED(hr))
  844. {
  845. pResultTrack->m_SignPostList.CleanUp();
  846. while(!ResultList.IsEmpty() )
  847. {
  848. pResultTrack->m_SignPostList.AddHead(ResultList.RemoveHead());
  849. }
  850. }
  851. if (pSong) pSong->Release();
  852. if (pSegment) pSegment->Release();
  853. LeaveCriticalSection(&m_CriticalSection);
  854. return hr;
  855. }