Source code of Windows XP (NT5)
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.

3368 lines
111 KiB

  1. // Copyright (c) 1998-2001 Microsoft Corporation
  2. // dmsegobj.cpp : Implementation of CSegment
  3. #include "dmime.h"
  4. #include "DMSegObj.h"
  5. #include "DMSStObj.h"
  6. #include "DMGraph.h"
  7. #include "dmusici.h"
  8. #include "tlist.h"
  9. #include "midifile.h"
  10. #include "dmusicc.h"
  11. #include "dmusicf.h"
  12. #include "dmperf.h"
  13. #include "wavtrack.h"
  14. #include "..\shared\validp.h"
  15. #include "..\shared\dmstrm.h"
  16. #include "..\shared\Validate.h"
  17. #include "..\dmstyle\dmstyle.h"
  18. #include "..\dmcompos\dmcompp.h"
  19. #include "debug.h"
  20. #include "dmscriptautguids.h"
  21. #include "tempotrk.h"
  22. #include <strsafe.h>
  23. #define ASSERT assert
  24. // @doc EXTERNAL
  25. long g_lNewTrackID = 0; // shared by all instances of Segments, this keeps track of the
  26. // next available TrackID when creating new Track states.
  27. /////////////////////////////////////////////////////////////////////////////
  28. // CSegment
  29. void CSegment::Init()
  30. {
  31. InitializeCriticalSection(&m_CriticalSection);
  32. m_pSong = NULL;
  33. m_dwNextPlayFlags = 0;
  34. m_dwNextPlayID = 0xFFFFFFFF;
  35. m_dwPlayID = 0;
  36. // m_fPartialLoad = FALSE;
  37. m_mtLength = 1;
  38. m_mtStart = 0;
  39. m_mtLoopStart = 0;
  40. m_mtLoopEnd = 0;
  41. m_rtLength = 0;
  42. m_dwRepeats = 0;
  43. m_dwResolution = 0;
  44. m_dwNumPChannels = 0;
  45. m_paPChannels = NULL;
  46. m_pGraph = NULL;
  47. m_pAudioPathConfig = NULL;
  48. m_pUnkDispatch = NULL;
  49. m_dwSegFlags = 0;
  50. m_cRef = 0;
  51. m_dwVersion = 0; // Init to 6.1 behavior.
  52. m_dwValidData = DMUS_OBJ_CLASS; // upon creation, only this data is valid
  53. memset(&m_guidObject,0,sizeof(m_guidObject));
  54. memset(&m_ftDate, 0,sizeof(m_ftDate));
  55. memset(&m_vVersion, 0,sizeof(m_vVersion));
  56. m_fZombie = false;
  57. InterlockedIncrement(&g_cComponent);
  58. TraceI(2, "Segment %lx created\n", this );
  59. }
  60. CSegment::CSegment()
  61. {
  62. Init();
  63. }
  64. CSegment::CSegment(DMUS_IO_SEGMENT_HEADER *pHeader, CSegment *pSource)
  65. {
  66. Init();
  67. AddRef(); // so that this doesn't get deleted in Track::Init...
  68. // Force the version to at least 8 so audiopath functionality will be turned on.
  69. m_dwVersion = 8;
  70. m_dwResolution = pHeader->dwResolution;
  71. m_mtLength = pHeader->mtLength;
  72. m_mtStart = pHeader->mtPlayStart;
  73. m_mtLoopStart = pHeader->mtLoopStart;
  74. m_mtLoopEnd = pHeader->mtLoopEnd;
  75. m_dwRepeats = pHeader->dwRepeats;
  76. m_dwSegFlags = pHeader->dwFlags;
  77. if (m_dwSegFlags & DMUS_SEGIOF_REFLENGTH)
  78. {
  79. m_rtLength = pHeader->rtLength;
  80. }
  81. else
  82. {
  83. m_rtLength = 0;
  84. }
  85. if (pSource)
  86. {
  87. pSource->m_TrackList.CreateCopyWithBlankState(&m_TrackList);
  88. CTrack *pTrack = m_TrackList.GetHead();
  89. for (;pTrack;pTrack = pTrack->GetNext())
  90. {
  91. pTrack->m_pTrack->Init( this );
  92. }
  93. }
  94. }
  95. CSegment::~CSegment()
  96. {
  97. if (m_pUnkDispatch)
  98. m_pUnkDispatch->Release(); // free IDispatch implementation we may have borrowed
  99. Clear(false);
  100. DeleteCriticalSection(&m_CriticalSection);
  101. InterlockedDecrement(&g_cComponent);
  102. TraceI(2, "Segment %lx destroyed\n", this );
  103. }
  104. void CSegment::Clear(bool fZombie)
  105. {
  106. m_TrackList.Clear();
  107. if (m_pAudioPathConfig)
  108. {
  109. m_pAudioPathConfig->Release();
  110. m_pAudioPathConfig = NULL;
  111. }
  112. SetGraph(NULL); // shut down the graph and release it
  113. // We need the following stuff to hang around if the segment is being zombied.
  114. if (!fZombie)
  115. {
  116. // remove all notifies
  117. CNotificationItem* pItem = m_NotificationList.GetHead();
  118. while( pItem )
  119. {
  120. CNotificationItem* pNext = pItem->GetNext();
  121. m_NotificationList.Remove( pItem );
  122. delete pItem;
  123. pItem = pNext;
  124. }
  125. if( m_paPChannels )
  126. {
  127. delete [] m_paPChannels;
  128. m_paPChannels = NULL;
  129. }
  130. m_dwNumPChannels = 0;
  131. }
  132. }
  133. STDMETHODIMP_(void) CSegment::Zombie()
  134. {
  135. Clear(true);
  136. m_fZombie = true;
  137. }
  138. STDMETHODIMP CSegment::QueryInterface(
  139. const IID &iid, // @parm Interface to query for
  140. void **ppv) // @parm The requested interface will be returned here
  141. {
  142. V_INAME(CSegment::QueryInterface);
  143. V_PTRPTR_WRITE(ppv);
  144. V_REFGUID(iid);
  145. *ppv = NULL;
  146. if (iid == IID_IUnknown || iid == IID_IDirectMusicSegment)
  147. {
  148. *ppv = static_cast<IDirectMusicSegment*>(this);
  149. }
  150. else if (iid == IID_CSegment)
  151. {
  152. *ppv = static_cast<CSegment*>(this);
  153. }
  154. else if (iid == IID_IDirectMusicSegment8)
  155. {
  156. m_dwVersion = 8;
  157. *ppv = static_cast<IDirectMusicSegment*>(this);
  158. }
  159. else if (iid == IID_IDirectMusicSegment8P)
  160. {
  161. *ppv = static_cast<IDirectMusicSegment8P*>(this);
  162. }
  163. else if (iid == IID_IDirectMusicSegment2)
  164. {
  165. m_dwVersion = 2;
  166. *ppv = static_cast<IDirectMusicSegment*>(this);
  167. }
  168. else if (iid == IID_IPersistStream)
  169. {
  170. *ppv = static_cast<IPersistStream*>(this);
  171. }
  172. else if(iid == IID_IDirectMusicObject)
  173. {
  174. *ppv = static_cast<IDirectMusicObject*>(this);
  175. }
  176. else if (iid == IID_IDirectMusicObjectP)
  177. {
  178. *ppv = static_cast<IDirectMusicObjectP*>(this);
  179. }
  180. else if (iid == IID_IDispatch)
  181. {
  182. // A helper scripting object implements IDispatch, which we expose from the
  183. // Performance object via COM aggregation.
  184. if (!m_pUnkDispatch)
  185. {
  186. // Create the helper object
  187. ::CoCreateInstance(
  188. CLSID_AutDirectMusicSegment,
  189. static_cast<IDirectMusicSegment*>(this),
  190. CLSCTX_INPROC_SERVER,
  191. IID_IUnknown,
  192. reinterpret_cast<void**>(&m_pUnkDispatch));
  193. }
  194. if (m_pUnkDispatch)
  195. {
  196. return m_pUnkDispatch->QueryInterface(IID_IDispatch, ppv);
  197. }
  198. }
  199. if (*ppv == NULL)
  200. {
  201. Trace(4,"Warning: Segment queried for unknown interface.\n");
  202. return E_NOINTERFACE;
  203. }
  204. reinterpret_cast<IUnknown*>(this)->AddRef();
  205. return S_OK;
  206. }
  207. STDMETHODIMP_(ULONG) CSegment::AddRef()
  208. {
  209. return InterlockedIncrement(&m_cRef);
  210. }
  211. STDMETHODIMP_(ULONG) CSegment::Release()
  212. {
  213. if (!InterlockedDecrement(&m_cRef))
  214. {
  215. m_cRef = 100; // artificial reference count to prevent reentrency due to COM aggregation
  216. delete this;
  217. return 0;
  218. }
  219. return m_cRef;
  220. }
  221. STDMETHODIMP CSegment::GetLength(
  222. MUSIC_TIME *pmtLength) // @parm Returns the Segment's length.
  223. {
  224. V_INAME(IDirectMusicSegment::GetLength);
  225. V_PTR_WRITE(pmtLength, MUSIC_TIME);
  226. if (m_fZombie)
  227. {
  228. Trace(2, "Warning: Call of IDirectMusicSegment::GetLength after the segment has been garbage collected.\n");
  229. return DMUS_S_GARBAGE_COLLECTED;
  230. }
  231. *pmtLength = m_mtLength;
  232. return S_OK;
  233. }
  234. STDMETHODIMP CSegment::SetLength(
  235. MUSIC_TIME mtLength) // @parm The desired length.
  236. {
  237. if( mtLength <=0 )
  238. {
  239. Trace(1,"Error: Can not set segment length to a negative number (%ld.)\n",mtLength);
  240. return E_INVALIDARG;
  241. }
  242. if(( mtLength <= m_mtStart ) || ( mtLength < m_mtLoopEnd ))
  243. {
  244. Trace(1,"Error: Can not set segment length to %ld, which is either less that the start time %ld or the loop end %ld\n",
  245. mtLength,m_mtStart,m_mtLoopEnd);
  246. return DMUS_E_OUT_OF_RANGE;
  247. }
  248. if (m_fZombie)
  249. {
  250. Trace(2, "Warning: Call of IDirectMusicSegment::SetLength after the segment has been garbage collected.\n");
  251. return DMUS_S_GARBAGE_COLLECTED;
  252. }
  253. m_mtLength = mtLength;
  254. return S_OK;
  255. }
  256. STDMETHODIMP CSegment::GetRepeats(
  257. DWORD *pdwRepeats) // @parm Returns the number of repeats.
  258. {
  259. V_INAME(IDirectMusicSegment::GetRepeats);
  260. V_PTR_WRITE(pdwRepeats, DWORD);
  261. if (m_fZombie)
  262. {
  263. Trace(2, "Warning: Call of IDirectMusicSegment::GetRepeats after the segment has been garbage collected.\n");
  264. return DMUS_S_GARBAGE_COLLECTED;
  265. }
  266. *pdwRepeats = m_dwRepeats;
  267. return S_OK;
  268. }
  269. STDMETHODIMP CSegment::SetRepeats(
  270. DWORD dwRepeats) // @parm The desired number of repeats.
  271. {
  272. if (m_fZombie)
  273. {
  274. Trace(2, "Warning: Call of IDirectMusicSegment::SetRepeats after the segment has been garbage collected.\n");
  275. return DMUS_S_GARBAGE_COLLECTED;
  276. }
  277. m_dwRepeats = dwRepeats;
  278. return S_OK;
  279. }
  280. STDMETHODIMP CSegment::GetDefaultResolution(
  281. DWORD *pdwResolution) // @parm Returns the default resolution. (See <t DMPLAYSEGFLAGS>.)
  282. {
  283. V_INAME(IDirectMusicSegment::GetDefaultResolution);
  284. V_PTR_WRITE(pdwResolution, DWORD);
  285. if (m_fZombie)
  286. {
  287. Trace(2, "Warning: Call of IDirectMusicSegment::GetDefaultResolution after the segment has been garbage collected.\n");
  288. return DMUS_S_GARBAGE_COLLECTED;
  289. }
  290. *pdwResolution = m_dwResolution;
  291. return S_OK;
  292. }
  293. #define LEGAL_RES_FLAGS (DMUS_SEGF_SECONDARY | \
  294. DMUS_SEGF_QUEUE | \
  295. DMUS_SEGF_CONTROL | \
  296. DMUS_SEGF_AFTERPREPARETIME | \
  297. DMUS_SEGF_GRID | \
  298. DMUS_SEGF_BEAT | \
  299. DMUS_SEGF_MEASURE | \
  300. DMUS_SEGF_NOINVALIDATE | \
  301. DMUS_SEGF_ALIGN | \
  302. DMUS_SEGF_VALID_START_BEAT | \
  303. DMUS_SEGF_VALID_START_GRID | \
  304. DMUS_SEGF_VALID_START_TICK | \
  305. DMUS_SEGF_AFTERQUEUETIME | \
  306. DMUS_SEGF_AFTERLATENCYTIME | \
  307. DMUS_SEGF_SEGMENTEND | \
  308. DMUS_SEGF_MARKER | \
  309. DMUS_SEGF_TIMESIG_ALWAYS | \
  310. DMUS_SEGF_USE_AUDIOPATH | \
  311. DMUS_SEGF_VALID_START_MEASURE)
  312. STDMETHODIMP CSegment::SetDefaultResolution(
  313. DWORD dwResolution) // @parm The desired default resolution. (See <t DMPLAYSEGFLAGS>.)
  314. {
  315. if (m_fZombie)
  316. {
  317. Trace(2, "Warning: Call of IDirectMusicSegment::SetDefaultResolution after the segment has been garbage collected.\n");
  318. return DMUS_S_GARBAGE_COLLECTED;
  319. }
  320. #ifdef DBG
  321. if ((dwResolution & LEGAL_RES_FLAGS) != dwResolution)
  322. {
  323. Trace(1,"Warning: Attempt to set resolution includes inappropriate or non-existant flag: %lx\n",
  324. dwResolution & ~LEGAL_RES_FLAGS);
  325. }
  326. #endif
  327. m_dwResolution = dwResolution;
  328. return S_OK;
  329. }
  330. STDMETHODIMP CSegment::GetHeaderChunk(
  331. DWORD *pdwSize, /* Size of passed header chunk. Also, returns size written. */
  332. DMUS_IO_SEGMENT_HEADER *pHeader)
  333. {
  334. if (m_fZombie)
  335. {
  336. Trace(2, "Warning: Call of IDirectMusicSegment::GetHeaderChunk after the segment has been garbage collected.\n");
  337. return DMUS_S_GARBAGE_COLLECTED;
  338. }
  339. DMUS_IO_SEGMENT_HEADER Header;
  340. Header.dwFlags = m_dwSegFlags;
  341. Header.dwRepeats = m_dwRepeats;
  342. Header.dwResolution = m_dwResolution;
  343. Header.mtLength = m_mtLength;
  344. Header.mtLoopEnd = m_mtLoopEnd;
  345. Header.mtLoopStart = m_mtLoopStart;
  346. Header.mtPlayStart = m_mtStart;
  347. Header.dwReserved = 0;
  348. Header.rtLength = m_rtLength;
  349. if (pdwSize && pHeader)
  350. {
  351. *pdwSize = min(sizeof(Header),*pdwSize);
  352. memcpy(pHeader,&Header,*pdwSize);
  353. return S_OK;
  354. }
  355. Trace(1,"Error: GetHeaderChunk() was passed a NULL for either pdwSize or pHeader.\n");
  356. return E_POINTER;
  357. }
  358. STDMETHODIMP CSegment::SetHeaderChunk(
  359. DWORD dwSize, /* Size of passed header chunk. */
  360. DMUS_IO_SEGMENT_HEADER *pHeader)
  361. {
  362. if (m_fZombie)
  363. {
  364. Trace(2, "Warning: Call of IDirectMusicSegment::SetHeaderChunk after the segment has been garbage collected.\n");
  365. return DMUS_S_GARBAGE_COLLECTED;
  366. }
  367. if (pHeader)
  368. {
  369. DMUS_IO_SEGMENT_HEADER Header;
  370. dwSize = min(sizeof(Header),dwSize);
  371. // Initialize all fields so we don't have to worry about the passed size.
  372. Header.dwFlags = m_dwSegFlags;
  373. Header.dwRepeats = m_dwRepeats;
  374. Header.dwResolution = m_dwResolution;
  375. Header.mtLength = m_mtLength;
  376. Header.mtLoopEnd = m_mtLoopEnd;
  377. Header.mtLoopStart = m_mtLoopStart;
  378. Header.mtPlayStart = m_mtStart;
  379. Header.dwReserved = 0;
  380. Header.rtLength = m_rtLength;
  381. memcpy(&Header,pHeader,dwSize);
  382. m_dwSegFlags = Header.dwFlags;
  383. m_dwRepeats = Header.dwRepeats;
  384. m_dwResolution = Header.dwResolution;
  385. m_mtLength = Header.mtLength;
  386. m_mtLoopEnd = Header.mtLoopEnd;
  387. m_mtLoopStart = Header.mtLoopStart;
  388. m_mtStart = Header.mtPlayStart;
  389. m_rtLength = Header.rtLength;
  390. return S_OK;
  391. }
  392. Trace(1,"Error: SetHeaderChunk() was passed a NULL for pHeader.\n");
  393. return E_POINTER;
  394. }
  395. STDMETHODIMP CSegment::SetTrackPriority(
  396. REFGUID rguidTrackClassID, /* ClassID of Track. */
  397. DWORD dwGroupBits, /* Group bits. */
  398. DWORD dwIndex, /* Nth track. */
  399. DWORD dwPriority) /* Priority to set. */
  400. {
  401. if (m_fZombie)
  402. {
  403. Trace(2, "Warning: Call of IDirectMusicSegment::SetTrackPriority after the segment has been garbage collected.\n");
  404. return DMUS_S_GARBAGE_COLLECTED;
  405. }
  406. HRESULT hr = DMUS_E_TRACK_NOT_FOUND;
  407. CTrack* pCTrack;
  408. DWORD dwCounter = dwIndex;
  409. DWORD dwMax = dwIndex;
  410. if (dwIndex == DMUS_SEG_ALLTRACKS)
  411. {
  412. dwCounter = 0;
  413. dwMax = DMUS_SEG_ALLTRACKS;
  414. }
  415. EnterCriticalSection(&m_CriticalSection);
  416. while (pCTrack = GetTrack(rguidTrackClassID,dwGroupBits,dwCounter))
  417. {
  418. pCTrack->m_dwPriority = dwPriority;
  419. hr = S_OK;
  420. dwCounter++;
  421. if (dwCounter > dwMax) break;
  422. }
  423. LeaveCriticalSection(&m_CriticalSection);
  424. return hr;
  425. }
  426. STDMETHODIMP CSegment::SetAudioPathConfig(
  427. IUnknown *pAudioPathConfig)
  428. {
  429. if (m_fZombie)
  430. {
  431. Trace(2, "Warning: Call of IDirectMusicSegment::SetAudioPathConfig after the segment has been garbage collected.\n");
  432. return DMUS_S_GARBAGE_COLLECTED;
  433. }
  434. if (m_dwVersion < 8) m_dwVersion = 8;
  435. if (m_pAudioPathConfig)
  436. {
  437. m_pAudioPathConfig->Release();
  438. m_pAudioPathConfig = NULL;
  439. }
  440. if (pAudioPathConfig)
  441. {
  442. return pAudioPathConfig->QueryInterface(IID_CAudioPathConfig,(void **) &m_pAudioPathConfig);
  443. }
  444. return S_OK;
  445. }
  446. STDMETHODIMP CSegment::GetTrack(
  447. REFCLSID rType,
  448. DWORD dwGroupBits,
  449. DWORD dwIndex,
  450. IDirectMusicTrack **ppTrack)
  451. {
  452. V_INAME(IDirectMusicSegment::GetTrack);
  453. V_PTRPTR_WRITE(ppTrack);
  454. if (m_fZombie)
  455. {
  456. Trace(2, "Warning: Call of IDirectMusicSegment::GetTrack after the segment has been garbage collected.\n");
  457. return DMUS_S_GARBAGE_COLLECTED;
  458. }
  459. CTrack* pCTrack;
  460. HRESULT hr;
  461. EnterCriticalSection(&m_CriticalSection);
  462. pCTrack = GetTrack(rType,dwGroupBits,dwIndex);
  463. if (pCTrack)
  464. {
  465. *ppTrack = pCTrack->m_pTrack;
  466. pCTrack->m_pTrack->AddRef();
  467. hr = S_OK;
  468. }
  469. else
  470. {
  471. Trace(1,"Error: GetTrack could not find the requested track at index %ld.\n",dwIndex);
  472. hr = DMUS_E_NOT_FOUND;
  473. }
  474. LeaveCriticalSection(&m_CriticalSection);
  475. return hr;
  476. }
  477. CTrack *CSegment::GetTrack(
  478. REFCLSID rType,
  479. DWORD dwGroupBits,
  480. DWORD dwIndex)
  481. {
  482. CTrack* pCTrack;
  483. pCTrack = m_TrackList.GetHead();
  484. while( pCTrack )
  485. {
  486. ASSERT(pCTrack->m_pTrack);
  487. if( pCTrack->m_dwGroupBits & dwGroupBits )
  488. {
  489. if( (GUID_NULL == rType) || (pCTrack->m_guidClassID == rType))
  490. {
  491. if( 0 == dwIndex )
  492. {
  493. break;
  494. }
  495. dwIndex--;
  496. }
  497. }
  498. pCTrack = pCTrack->GetNext();
  499. }
  500. return pCTrack;
  501. }
  502. BOOL CSegment::IsTempoSource()
  503. {
  504. EnterCriticalSection(&m_CriticalSection);
  505. BOOL fHasTempo = (NULL != GetTrackByParam(NULL, GUID_TempoParam,-1,0, FALSE));
  506. LeaveCriticalSection(&m_CriticalSection);
  507. return fHasTempo;
  508. }
  509. STDMETHODIMP CSegment::GetTrackGroup(
  510. IDirectMusicTrack* pTrack, // @parm The Track to find the group bits.
  511. DWORD* pdwGroupBits)// @parm Returns the group(s) to which a Track belongs.
  512. // Each bit in <p pdwGroupBits> corresponds to a Track
  513. // group.
  514. {
  515. V_INAME(IDirectMusicSegment::GetTrackGroup);
  516. V_INTERFACE(pTrack);
  517. V_PTR_WRITE(pdwGroupBits,DWORD);
  518. if (m_fZombie)
  519. {
  520. Trace(2, "Warning: Call of IDirectMusicSegment::GetTrackGroup after the segment has been garbage collected.\n");
  521. return DMUS_S_GARBAGE_COLLECTED;
  522. }
  523. CTrack* pCTrack;
  524. HRESULT hr = DMUS_E_NOT_FOUND;
  525. EnterCriticalSection(&m_CriticalSection);
  526. pCTrack = m_TrackList.GetHead();
  527. while( pCTrack )
  528. {
  529. ASSERT(pCTrack->m_pTrack);
  530. if( pCTrack->m_pTrack == pTrack )
  531. {
  532. *pdwGroupBits = pCTrack->m_dwGroupBits;
  533. hr = S_OK;
  534. break;
  535. }
  536. pCTrack = pCTrack->GetNext();
  537. }
  538. #ifdef DBG
  539. if (hr == DMUS_E_NOT_FOUND)
  540. {
  541. Trace(1,"Error: GetTrackGroup could not find the requested track.\n");
  542. }
  543. #endif
  544. LeaveCriticalSection(&m_CriticalSection);
  545. return hr;
  546. }
  547. CTrack * CSegment::GetTrackByParam( CTrack * pCTrack,
  548. REFGUID rguidType,DWORD dwGroupBits,DWORD dwIndex, BOOL fDontCheck)
  549. {
  550. // If the caller was already part way through the list, it passes the current
  551. // track. Otherwise, NULL to indicate start at the top.
  552. if (pCTrack)
  553. {
  554. pCTrack = pCTrack->GetNext();
  555. }
  556. else
  557. {
  558. pCTrack = m_TrackList.GetHead();
  559. }
  560. while( pCTrack )
  561. {
  562. ASSERT(pCTrack->m_pTrack);
  563. if( (pCTrack->m_dwGroupBits & dwGroupBits ) && (fDontCheck ||
  564. (pCTrack->m_dwFlags & DMUS_TRACKCONFIG_CONTROL_ENABLED)))
  565. {
  566. if( (GUID_NULL == rguidType) ||
  567. (pCTrack->m_pTrack->IsParamSupported( rguidType ) == S_OK ))
  568. {
  569. if( 0 == dwIndex )
  570. {
  571. return pCTrack;
  572. }
  573. dwIndex--;
  574. }
  575. }
  576. pCTrack = pCTrack->GetNext();
  577. }
  578. return NULL;
  579. }
  580. HRESULT CSegment::GetTrackByParam(
  581. REFGUID rguidType, // The command type of the Track to find. A value of GUID_NULL
  582. // will get any track.
  583. DWORD dwGroupBits, // Which track groups to scan for the track in. A value of 0
  584. // is invalid. Each bit in <p dwGroupBits> corresponds to a Track
  585. // group. To scan all tracks regardless of groups, set all bits in
  586. // this parameter (0xffffffff).
  587. DWORD dwIndex, // The index into the list of tracks of type <p rguidType>
  588. // and in group <p dwGroupBits> to return. 0 means the first
  589. // one found, 1 would be the second, etc. If multiple groups are
  590. // selected in <p dwGroupBits>, this index will indicate the nth
  591. // track of type <p pCommandGuid> encountered in the union
  592. // of the groups selected.
  593. IDirectMusicTrack **ppTrack) // Returns the Track (AddRef'd), or NULL if the
  594. // Track isn't found.
  595. {
  596. HRESULT hr;
  597. CTrack* pCTrack;
  598. EnterCriticalSection(&m_CriticalSection);
  599. pCTrack = GetTrackByParam(NULL,rguidType,dwGroupBits,dwIndex,TRUE);
  600. if (pCTrack)
  601. {
  602. *ppTrack = pCTrack->m_pTrack;
  603. pCTrack->m_pTrack->AddRef();
  604. hr = S_OK;
  605. }
  606. else
  607. {
  608. hr = DMUS_E_NOT_FOUND;
  609. // Don't think we need an error message here since SetParam also does one...
  610. // Trace(1,"Error: Could not find the requested track for SetParam.\n");
  611. }
  612. LeaveCriticalSection(&m_CriticalSection);
  613. return hr;
  614. }
  615. STDMETHODIMP CSegment::InsertTrack(
  616. IDirectMusicTrack *pTrack, // @parm The Track to add to the Segment.
  617. DWORD dwGroupBits ) // @parm Identifies the group(s) this should be inserted into.
  618. // May not be 0.
  619. {
  620. V_INAME(IDirectMusicSegment::InsertTrack);
  621. V_INTERFACE(pTrack);
  622. if (m_fZombie)
  623. {
  624. Trace(2, "Warning: Call of IDirectMusicSegment::InsertTrack after the segment has been garbage collected.\n");
  625. return DMUS_S_GARBAGE_COLLECTED;
  626. }
  627. return InsertTrack(pTrack,dwGroupBits,DMUS_TRACKCONFIG_DEFAULT,0, 0);
  628. }
  629. HRESULT CSegment::InsertTrack(
  630. IDirectMusicTrack *pTrack,
  631. DWORD dwGroupBits,
  632. DWORD dwFlags,
  633. DWORD dwPriority,
  634. DWORD dwPosition)
  635. {
  636. CTrack* pCTrack;
  637. if( 0 == dwGroupBits )
  638. {
  639. Trace(1,"Error: InsertTrack called with dwGroupBits set to 0.\n");
  640. return E_INVALIDARG;
  641. }
  642. if( FAILED( pTrack->Init( this ) ))
  643. {
  644. TraceI(1,"Error: Track failed to initialize\n");
  645. return DMUS_E_NOT_INIT;
  646. }
  647. pCTrack = new CTrack;
  648. if( NULL == pCTrack )
  649. {
  650. return E_OUTOFMEMORY;
  651. }
  652. pCTrack->m_pTrack = pTrack;
  653. pTrack->QueryInterface(IID_IDirectMusicTrack8,(void **) &pCTrack->m_pTrack8);
  654. IPersist *pPersist;
  655. if (S_OK == pTrack->QueryInterface(IID_IPersistStream,(void **) &pPersist))
  656. {
  657. pPersist->GetClassID( &pCTrack->m_guidClassID );
  658. pPersist->Release();
  659. }
  660. pCTrack->m_dwGroupBits = dwGroupBits;
  661. pCTrack->m_dwFlags = dwFlags;
  662. pCTrack->m_dwPriority = dwPriority;
  663. pCTrack->m_dwPosition = dwPosition;
  664. pTrack->AddRef();
  665. EnterCriticalSection(&m_CriticalSection);
  666. // Add the track based on position.
  667. CTrack* pScan = m_TrackList.GetHead();
  668. CTrack* pPrevTrack = NULL;
  669. for (; pScan; pScan = pScan->GetNext())
  670. {
  671. if (pCTrack->Less(pScan))
  672. {
  673. break;
  674. }
  675. pPrevTrack = pScan;
  676. }
  677. if (pPrevTrack)
  678. {
  679. pPrevTrack->SetNext(pCTrack);
  680. pCTrack->SetNext(pScan);
  681. }
  682. else
  683. {
  684. m_TrackList.AddHead( pCTrack );
  685. }
  686. // send notifications to track
  687. CNotificationItem* pItem = m_NotificationList.GetHead();
  688. while( pItem )
  689. {
  690. pTrack->AddNotificationType( pItem->guidNotificationType );
  691. pItem = pItem->GetNext();
  692. }
  693. LeaveCriticalSection(&m_CriticalSection);
  694. return S_OK;
  695. }
  696. STDMETHODIMP CSegment::RemoveTrack(
  697. IDirectMusicTrack *pTrack) // @parm The Track to remove from the Segment's Track list.
  698. {
  699. V_INAME(IDirectMusicSegment::RemoveTrack);
  700. V_INTERFACE(pTrack);
  701. if (m_fZombie)
  702. {
  703. Trace(2, "Warning: Call of IDirectMusicSegment::RemoveTrack after the segment has been garbage collected.\n");
  704. return DMUS_S_GARBAGE_COLLECTED;
  705. }
  706. HRESULT hr = S_FALSE;
  707. EnterCriticalSection(&m_CriticalSection);
  708. CTrack* pCTrackTemp;
  709. pCTrackTemp = m_TrackList.GetHead();
  710. while( pCTrackTemp )
  711. {
  712. if( pTrack == pCTrackTemp->m_pTrack )
  713. {
  714. hr = S_OK;
  715. m_TrackList.Remove( pCTrackTemp );
  716. delete pCTrackTemp;
  717. break;
  718. }
  719. pCTrackTemp = pCTrackTemp->GetNext();
  720. }
  721. LeaveCriticalSection(&m_CriticalSection);
  722. #ifdef DBG
  723. if (hr == S_FALSE)
  724. {
  725. Trace(1,"Warning: RemoveTrack failed because the requested track is not in the segment.\n");
  726. }
  727. #endif
  728. return hr;
  729. }
  730. HRESULT CSegment::CreateSegmentState(
  731. CSegState **ppSegState,
  732. CPerformance *pPerformance,
  733. IDirectMusicAudioPath *pAudioPath,
  734. DWORD dwFlags)
  735. {
  736. IDirectMusicSegmentState* pSegmentState;
  737. CSegState *pState = new CSegState;
  738. if (pState)
  739. {
  740. pState->QueryInterface( IID_IDirectMusicSegmentState,
  741. (void**)&pSegmentState);
  742. pState->m_dwVersion = m_dwVersion;
  743. pState->Release();
  744. }
  745. else
  746. {
  747. return E_OUTOFMEMORY;
  748. }
  749. EnterCriticalSection(&m_CriticalSection);
  750. if( FAILED( m_TrackList.CreateCopyWithBlankState(&pState->m_TrackList)))
  751. {
  752. LeaveCriticalSection(&m_CriticalSection);
  753. pState->Release();
  754. return E_OUTOFMEMORY;
  755. }
  756. // set the segstate's parent and performance
  757. pState->PrivateInit( this, pPerformance );
  758. if (m_pGraph)
  759. {
  760. m_pGraph->Clone((IDirectMusicGraph **) &pState->m_pGraph);
  761. }
  762. pState->InitRoute(pAudioPath);
  763. CTrack* pCTrack = pState->m_TrackList.GetHead();
  764. while( pCTrack )
  765. {
  766. DWORD dwTempID;
  767. InterlockedIncrement(&g_lNewTrackID);
  768. dwTempID = g_lNewTrackID;
  769. if (!pState->m_dwFirstTrackID)
  770. pState->m_dwFirstTrackID = dwTempID;
  771. pState->m_dwLastTrackID = dwTempID;
  772. ASSERT(pCTrack->m_pTrack);
  773. if( FAILED(pCTrack->m_pTrack->InitPlay(
  774. pSegmentState, (IDirectMusicPerformance *) pPerformance,
  775. &pCTrack->m_pTrackState, dwTempID, dwFlags )))
  776. {
  777. pCTrack->m_pTrackState = NULL;
  778. }
  779. pCTrack->m_dwVirtualID = dwTempID;
  780. pCTrack = pCTrack->GetNext();
  781. }
  782. *ppSegState = pState;
  783. LeaveCriticalSection(&m_CriticalSection);
  784. return S_OK;
  785. }
  786. /* The following function is kept around only for DX6.1 compatibility just
  787. in case some mindless bureaucrat actually uses this somehow.
  788. For internal use, we've switched to the function above.
  789. */
  790. STDMETHODIMP CSegment::InitPlay(
  791. IDirectMusicSegmentState **ppSegState, // @parm Returns the SegmentState created
  792. // by this method call. It is returned with a reference count of 1, thus a
  793. // call to its Release will fully release it.
  794. IDirectMusicPerformance *pPerformance, // @parm The IDirectMusicPerformance pointer.
  795. // This is needed by the Segment and SegmentState in order to call methods on
  796. // the Performance object. This pointer is not AddRef'd. It is a weak reference
  797. // because it is assumed that the Performance will outlive the Segment.
  798. DWORD dwFlags) // @parm Same flags that were set with the call
  799. // to PlaySegment. These are passed to the tracks, who may want to know
  800. // if the track was played as a primary, controlling, or secondary segment.
  801. {
  802. V_INAME(IDirectMusicSegment::InitPlay);
  803. V_INTERFACE(pPerformance);
  804. V_PTRPTR_WRITE(ppSegState);
  805. if (m_dwVersion)
  806. {
  807. return E_NOTIMPL;
  808. }
  809. IDirectMusicSegmentState* pSegmentState;
  810. CSegState *pState = new CSegState;
  811. if (pState)
  812. {
  813. pState->QueryInterface( IID_IDirectMusicSegmentState,
  814. (void**)&pSegmentState);
  815. pState->m_dwVersion = m_dwVersion;
  816. pState->Release();
  817. if (pPerformance)
  818. {
  819. // QI addref's the performance but we want only a weak refrenece with the segment state
  820. HRESULT hr = pPerformance->QueryInterface(IID_CPerformance,(void **) &pState->m_pPerformance);
  821. if(FAILED(hr))
  822. {
  823. return E_FAIL;
  824. }
  825. pPerformance->Release();
  826. }
  827. }
  828. else
  829. {
  830. return E_OUTOFMEMORY;
  831. }
  832. *ppSegState = pSegmentState;
  833. return S_OK;
  834. }
  835. STDMETHODIMP CSegment::GetGraph(
  836. IDirectMusicGraph** ppGraph // @parm Returns the Tool Graph pointer.
  837. )
  838. {
  839. V_INAME(IDirectMusicSegment::GetGraph);
  840. V_PTRPTR_WRITE(ppGraph);
  841. if (m_fZombie)
  842. {
  843. Trace(2, "Warning: Call of IDirectMusicSegment::GetGraph after the segment has been garbage collected.\n");
  844. return DMUS_S_GARBAGE_COLLECTED;
  845. }
  846. if( NULL == m_pGraph )
  847. {
  848. Trace(1,"Error: GetGraph failed because segment does not have a tool graph.\n");
  849. return DMUS_E_NOT_FOUND;
  850. }
  851. EnterCriticalSection(&m_CriticalSection);
  852. *ppGraph = m_pGraph;
  853. m_pGraph->AddRef();
  854. LeaveCriticalSection(&m_CriticalSection);
  855. return S_OK;
  856. }
  857. STDMETHODIMP CSegment::SetGraph(
  858. IDirectMusicGraph* pGraph // @parm The Tool Graph pointer. May be NULL to
  859. // clear out the Segment graph.
  860. )
  861. {
  862. V_INAME(IDirectMusicSegment::SetGraph);
  863. V_INTERFACE_OPT(pGraph);
  864. if (m_fZombie)
  865. {
  866. Trace(2, "Warning: Call of IDirectMusicSegment::SetGraph after the segment has been garbage collected.\n");
  867. return DMUS_S_GARBAGE_COLLECTED;
  868. }
  869. EnterCriticalSection(&m_CriticalSection);
  870. if( m_pGraph )
  871. {
  872. m_pGraph->Release();
  873. }
  874. m_pGraph = (CGraph *) pGraph;
  875. if( pGraph )
  876. {
  877. pGraph->AddRef();
  878. }
  879. LeaveCriticalSection(&m_CriticalSection);
  880. return S_OK;
  881. }
  882. HRESULT CSegment::SetClockTimeDuration(REFERENCE_TIME rtDuration)
  883. {
  884. m_rtLength = rtDuration;
  885. return S_OK;
  886. }
  887. HRESULT CSegment::SetFlags(DWORD dwFlags)
  888. {
  889. m_dwSegFlags = dwFlags;
  890. return S_OK;
  891. }
  892. /*
  893. Check to see if this notification is already being tracked.
  894. */
  895. CNotificationItem* CSegment::FindNotification( REFGUID rguidNotification )
  896. {
  897. CNotificationItem* pItem;
  898. pItem = m_NotificationList.GetHead();
  899. while(pItem)
  900. {
  901. if( rguidNotification == pItem->guidNotificationType )
  902. {
  903. break;
  904. }
  905. pItem = pItem->GetNext();
  906. }
  907. return pItem;
  908. }
  909. void CSegment::AddNotificationTypeToAllTracks( REFGUID rguidNotification )
  910. {
  911. CTrack* pTrack;
  912. // add the notify to the tracks
  913. pTrack = m_TrackList.GetHead();
  914. while( pTrack )
  915. {
  916. pTrack->m_pTrack->AddNotificationType( rguidNotification );
  917. pTrack = pTrack->GetNext();
  918. }
  919. }
  920. void CSegment::RemoveNotificationTypeFromAllTracks( REFGUID rguidNotification )
  921. {
  922. CTrack* pTrack;
  923. // add the notify to the tracks
  924. pTrack = m_TrackList.GetHead();
  925. while( pTrack )
  926. {
  927. pTrack->m_pTrack->RemoveNotificationType( rguidNotification );
  928. pTrack = pTrack->GetNext();
  929. }
  930. }
  931. HRESULT CSegment::AddNotificationType(
  932. REFGUID rguidNotification, BOOL fFromPerformance)
  933. {
  934. CNotificationItem* pItem;
  935. HRESULT hr = S_OK;
  936. EnterCriticalSection(&m_CriticalSection);
  937. pItem = FindNotification( rguidNotification );
  938. if (pItem)
  939. {
  940. // If the item was installed previously, but by
  941. // a difference source (performance vs. app)
  942. // then treat this as a normal addition.
  943. // Otherwise, indicate that the same operation
  944. // was done twice.
  945. if (pItem->fFromPerformance == fFromPerformance)
  946. {
  947. hr = S_FALSE;
  948. }
  949. else
  950. {
  951. // Clear the fFromPerformance flag since this has
  952. // now been added by the app and the performance.
  953. pItem->fFromPerformance = FALSE;
  954. }
  955. }
  956. else
  957. {
  958. pItem = new CNotificationItem;
  959. if( NULL == pItem )
  960. {
  961. hr = E_OUTOFMEMORY;
  962. }
  963. else
  964. {
  965. pItem->fFromPerformance = fFromPerformance;
  966. pItem->guidNotificationType = rguidNotification;
  967. m_NotificationList.Cat( pItem );
  968. AddNotificationTypeToAllTracks( rguidNotification );
  969. }
  970. }
  971. LeaveCriticalSection(&m_CriticalSection);
  972. return hr;
  973. }
  974. STDMETHODIMP CSegment::AddNotificationType(
  975. REFGUID rguidNotification) // @parm The notification guid to add.
  976. {
  977. V_INAME(IDirectMusicSegment::AddNotificationType);
  978. V_REFGUID(rguidNotification);
  979. if (m_fZombie)
  980. {
  981. Trace(2, "Warning: Call of IDirectMusicSegment::AddNotificationType after the segment has been garbage collected.\n");
  982. return DMUS_S_GARBAGE_COLLECTED;
  983. }
  984. return AddNotificationType(rguidNotification,FALSE);
  985. }
  986. HRESULT CSegment::RemoveNotificationType(
  987. REFGUID rguidNotification,BOOL fFromPerformance)
  988. {
  989. CNotificationItem* pItem;
  990. HRESULT hr = S_OK;
  991. EnterCriticalSection(&m_CriticalSection);
  992. if( GUID_NULL == rguidNotification )
  993. {
  994. CNotificationList TempList;
  995. while( pItem = m_NotificationList.RemoveHead() )
  996. {
  997. // If this is being called on an item that was installed by the
  998. // performance OR we are calling this directly from the app,
  999. // go ahead and remove. However, do not remove in the specific
  1000. // case where the app installed the notification and the performance
  1001. // is clearing notifications.
  1002. if (pItem->fFromPerformance || !fFromPerformance)
  1003. {
  1004. RemoveNotificationTypeFromAllTracks( pItem->guidNotificationType );
  1005. delete pItem;
  1006. }
  1007. else
  1008. {
  1009. TempList.AddHead(pItem);
  1010. }
  1011. }
  1012. // Now, put the saved notifications back.
  1013. while (pItem = TempList.RemoveHead())
  1014. {
  1015. m_NotificationList.AddHead(pItem);
  1016. }
  1017. }
  1018. else if( pItem = FindNotification( rguidNotification ))
  1019. {
  1020. m_NotificationList.Remove( pItem );
  1021. delete pItem;
  1022. RemoveNotificationTypeFromAllTracks( rguidNotification );
  1023. }
  1024. else
  1025. {
  1026. Trace(2,"Warning: Unable to remove requested notification from segment, it was not currently installed.\n");
  1027. hr = S_FALSE;
  1028. }
  1029. LeaveCriticalSection(&m_CriticalSection);
  1030. return hr;
  1031. }
  1032. STDMETHODIMP CSegment::RemoveNotificationType(
  1033. REFGUID rguidNotification) // @parm The notification guid to remove. GUID_NULL to remove all notifies.
  1034. {
  1035. V_INAME(IDirectMusicSegment::RemoveNotificationType);
  1036. V_REFGUID(rguidNotification);
  1037. if (m_fZombie)
  1038. {
  1039. Trace(2, "Warning: Call of IDirectMusicSegment::RemoveNotificationType after the segment has been garbage collected.\n");
  1040. return DMUS_S_GARBAGE_COLLECTED;
  1041. }
  1042. return RemoveNotificationType(rguidNotification,FALSE);
  1043. }
  1044. STDMETHODIMP CSegment::GetParam(
  1045. REFGUID rguidType, // @parm The type of data to obtain.
  1046. DWORD dwGroupBits, // @parm The group the desired track is in. Use 0xffffffff
  1047. // for all groups.
  1048. DWORD dwIndex, // @parm Identifies which track, by index, in the group
  1049. // identified by <p dwGroupBits> to obtain the data from.
  1050. MUSIC_TIME mtTime, // @parm The segment time from which to obtain the data.
  1051. MUSIC_TIME* pmtNext, // @parm Returns the segment time until which the data is valid. <p pmtNext>
  1052. // may be NULL. If this returns a value of 0, it means that this
  1053. // data will either be always valid, or it is unknown when it will
  1054. // become invalid.
  1055. void* pParam) // @parm The struture in which to return the data. Each
  1056. // <p rguidType> identifies a particular structure of a
  1057. // particular size. It is important that this field contain
  1058. // the correct structure of the correct size. Otherwise,
  1059. // fatal results can occur.
  1060. {
  1061. V_INAME(IDirectMusicSegment::GetParam);
  1062. V_REFGUID(rguidType);
  1063. if (m_fZombie)
  1064. {
  1065. Trace(2, "Warning: Call of IDirectMusicSegment::GetParam after the segment has been garbage collected.\n");
  1066. return DMUS_S_GARBAGE_COLLECTED;
  1067. }
  1068. HRESULT hr = DMUS_E_TRACK_NOT_FOUND;
  1069. BOOL fMultipleTry = FALSE;
  1070. if (dwIndex == DMUS_SEG_ANYTRACK)
  1071. {
  1072. dwIndex = 0;
  1073. // App must be using IDirectMusicSegment8 interface for this to be enabled...
  1074. // Nah, nobody would ever have a use for an index that high, so this is safe.
  1075. fMultipleTry = TRUE; // (m_dwVersion > 2);
  1076. }
  1077. CTrack* pCTrack;
  1078. EnterCriticalSection(&m_CriticalSection);
  1079. pCTrack = GetTrackByParam(NULL,rguidType,dwGroupBits,dwIndex,FALSE);
  1080. while (pCTrack)
  1081. {
  1082. if (pCTrack->m_pTrack8)
  1083. {
  1084. REFERENCE_TIME rtNext, *prtNext;
  1085. // We need to store the next time in a 64 bit pointer. But, don't
  1086. // make 'em fill it in unless the caller requested it.
  1087. if (pmtNext)
  1088. {
  1089. prtNext = &rtNext;
  1090. }
  1091. else
  1092. {
  1093. prtNext = NULL;
  1094. }
  1095. hr = pCTrack->m_pTrack8->GetParamEx( rguidType, mtTime, prtNext, pParam, NULL, 0 );
  1096. if (pmtNext)
  1097. {
  1098. *pmtNext = (MUSIC_TIME) rtNext;
  1099. }
  1100. }
  1101. else
  1102. {
  1103. hr = pCTrack->m_pTrack->GetParam( rguidType, mtTime, pmtNext, pParam );
  1104. if( pmtNext && (( *pmtNext == 0 ) || (*pmtNext > (m_mtLength - mtTime))))
  1105. {
  1106. *pmtNext = m_mtLength - mtTime;
  1107. }
  1108. }
  1109. // If nothing was found and dwIndex was DMUS_SEG_ANYTRACK, try again...
  1110. if (fMultipleTry && (hr == DMUS_E_NOT_FOUND))
  1111. {
  1112. pCTrack = GetTrackByParam( pCTrack, rguidType, dwGroupBits, 0, FALSE);
  1113. }
  1114. else
  1115. {
  1116. pCTrack = NULL;
  1117. }
  1118. }
  1119. LeaveCriticalSection(&m_CriticalSection);
  1120. #ifdef DBG
  1121. if (hr == DMUS_E_TRACK_NOT_FOUND)
  1122. {
  1123. Trace(2,"Warning: Segment GetParam failed to find a track.\n");
  1124. }
  1125. #endif
  1126. return hr;
  1127. }
  1128. STDMETHODIMP CSegment::SetParam(
  1129. REFGUID rguidType, // @parm The type of data to set.
  1130. DWORD dwGroupBits, // @parm The group the desired track is in. Use 0xffffffff
  1131. // for all groups.
  1132. DWORD dwIndex, // @parm Identifies which track, by index, in the group
  1133. // identified by <p dwGroupBits> to set the data.
  1134. MUSIC_TIME mtTime, // @parm The time at which to set the data.
  1135. void* pParam) // @parm The struture containing the data to set. Each
  1136. // <p rguidType> identifies a particular structure of a
  1137. // particular size. It is important that this field contain
  1138. // the correct structure of the correct size. Otherwise,
  1139. // fatal results can occur.
  1140. {
  1141. V_INAME(IDirectMusicSegment::SetParam);
  1142. V_REFGUID(rguidType);
  1143. if (m_fZombie)
  1144. {
  1145. Trace(2, "Warning: Call of IDirectMusicSegment::SetParam after the segment has been garbage collected.\n");
  1146. return DMUS_S_GARBAGE_COLLECTED;
  1147. }
  1148. HRESULT hr = DMUS_E_TRACK_NOT_FOUND;
  1149. IDirectMusicTrack* pTrack;
  1150. DWORD dwCounter = dwIndex;
  1151. DWORD dwMax = dwIndex;
  1152. if (dwIndex == DMUS_SEG_ALLTRACKS)
  1153. {
  1154. dwCounter = 0;
  1155. dwMax = DMUS_SEG_ALLTRACKS;
  1156. }
  1157. while (SUCCEEDED( GetTrackByParam( rguidType, dwGroupBits, dwCounter, &pTrack )))
  1158. {
  1159. hr = pTrack->SetParam( rguidType, mtTime, pParam );
  1160. pTrack->Release();
  1161. dwCounter++;
  1162. if (dwCounter > dwMax) break;
  1163. }
  1164. #ifdef DBG
  1165. if (hr == DMUS_E_TRACK_NOT_FOUND)
  1166. {
  1167. Trace(2,"Warning: Segment SetParam failed to find the requested track.\n");
  1168. }
  1169. #endif
  1170. return hr;
  1171. }
  1172. STDMETHODIMP CSegment::Download(IUnknown *pAudioPath)
  1173. {
  1174. V_INAME(IDirectMusicSegment::Download);
  1175. V_INTERFACE(pAudioPath);
  1176. HRESULT hr = S_OK;
  1177. if (m_fZombie)
  1178. {
  1179. Trace(2, "Warning: Call of IDirectMusicSegment::Download after the segment has been garbage collected.\n");
  1180. return DMUS_S_GARBAGE_COLLECTED;
  1181. }
  1182. // Validate that pAudioPath is either a performance or an audio path
  1183. IDirectMusicPerformance* pPerf = NULL;
  1184. if ( FAILED(hr = pAudioPath->QueryInterface(IID_IDirectMusicPerformance, (void**)&pPerf)) )
  1185. {
  1186. IDirectMusicAudioPath* pAP = NULL;
  1187. if ( FAILED(hr = pAudioPath->QueryInterface(IID_IDirectMusicAudioPath, (void**)&pAP)) )
  1188. {
  1189. return hr; // nothing to release, since all the QI's failed.
  1190. }
  1191. else
  1192. {
  1193. pAP->Release();
  1194. }
  1195. }
  1196. else
  1197. {
  1198. pPerf->Release();
  1199. }
  1200. hr = SetParam(GUID_DownloadToAudioPath,-1,DMUS_SEG_ALLTRACKS,0,pAudioPath);
  1201. if (hr == DMUS_E_TRACK_NOT_FOUND)
  1202. {
  1203. Trace(2,"Attempted download to a segment that has no tracks that support downloading (wave and band tracks.)\n");
  1204. hr = S_OK;
  1205. }
  1206. return hr;
  1207. }
  1208. STDMETHODIMP CSegment::Unload(IUnknown *pAudioPath)
  1209. {
  1210. V_INAME(IDirectMusicSegment::Unload);
  1211. V_INTERFACE(pAudioPath);
  1212. if (m_fZombie)
  1213. {
  1214. Trace(2, "Warning: Call of IDirectMusicSegment::Unload after the segment has been garbage collected.\n");
  1215. return DMUS_S_GARBAGE_COLLECTED;
  1216. }
  1217. HRESULT hr = SetParam(GUID_UnloadFromAudioPath,-1,DMUS_SEG_ALLTRACKS,0,pAudioPath);
  1218. if (hr == DMUS_E_TRACK_NOT_FOUND)
  1219. {
  1220. Trace(2,"Attempted unload from a segment that has no tracks that support downloading (wave and band tracks.)\n");
  1221. hr = S_OK;
  1222. }
  1223. return hr;
  1224. }
  1225. STDMETHODIMP CSegment::SetTrackConfig(REFGUID rguidTrackClassID,
  1226. DWORD dwGroup, DWORD dwIndex,
  1227. DWORD dwFlagsOn, DWORD dwFlagsOff)
  1228. {
  1229. V_INAME(IDirectMusicSegment::SetTrackConfig);
  1230. V_REFGUID(rguidTrackClassID);
  1231. if (rguidTrackClassID == GUID_NULL)
  1232. {
  1233. return E_INVALIDARG;
  1234. }
  1235. if (m_fZombie)
  1236. {
  1237. Trace(2, "Warning: Call of IDirectMusicSegment::SetTrackConfig after the segment has been garbage collected.\n");
  1238. return DMUS_S_GARBAGE_COLLECTED;
  1239. }
  1240. HRESULT hr = DMUS_E_TRACK_NOT_FOUND;
  1241. CTrack* pCTrack;
  1242. DWORD dwCounter = dwIndex;
  1243. DWORD dwMax = dwIndex;
  1244. if (dwIndex == DMUS_SEG_ALLTRACKS)
  1245. {
  1246. dwCounter = 0;
  1247. dwMax = DMUS_SEG_ALLTRACKS;
  1248. }
  1249. EnterCriticalSection(&m_CriticalSection);
  1250. while (pCTrack = GetTrack(rguidTrackClassID,dwGroup,dwCounter))
  1251. {
  1252. pCTrack->m_dwFlags &= ~dwFlagsOff;
  1253. pCTrack->m_dwFlags |= dwFlagsOn;
  1254. hr = S_OK;
  1255. dwCounter++;
  1256. if (dwCounter > dwMax) break;
  1257. }
  1258. LeaveCriticalSection(&m_CriticalSection);
  1259. #ifdef DBG
  1260. if (hr == DMUS_E_TRACK_NOT_FOUND)
  1261. {
  1262. Trace(1,"Error: Segment SetTrackConfig failed to find the requested track.\n");
  1263. }
  1264. #endif
  1265. return hr;
  1266. }
  1267. HRESULT CSegment::GetTrackConfig(REFGUID rguidTrackClassID,
  1268. DWORD dwGroup, DWORD dwIndex, DWORD *pdwFlags)
  1269. {
  1270. HRESULT hr = DMUS_E_TRACK_NOT_FOUND;
  1271. CTrack* pCTrack;
  1272. EnterCriticalSection(&m_CriticalSection);
  1273. pCTrack = GetTrack(rguidTrackClassID,dwGroup,dwIndex);
  1274. if (pCTrack)
  1275. {
  1276. *pdwFlags = pCTrack->m_dwFlags;
  1277. hr = S_OK;
  1278. }
  1279. LeaveCriticalSection(&m_CriticalSection);
  1280. return hr;
  1281. }
  1282. STDMETHODIMP CSegment::Clone(
  1283. MUSIC_TIME mtStart, // @parm The start of the part to clone. If less than 0,
  1284. // or greater than the length of the Segment, 0 will be used.
  1285. MUSIC_TIME mtEnd, // @parm The end of the part to clone. If past the end of the
  1286. // Segment, it will clone to the end. Also, a value of 0 or
  1287. // anything less than <p mtStart> will also clone to the end.
  1288. IDirectMusicSegment** ppSegment // @parm Returns the created Segment, if successful.
  1289. // It is caller's responsibility to call Release() when finished
  1290. // with it.
  1291. )
  1292. {
  1293. V_INAME(IDirectMusicSegment::Clone);
  1294. V_PTRPTR_WRITE(ppSegment);
  1295. if (m_fZombie)
  1296. {
  1297. Trace(2, "Warning: Call of IDirectMusicSegment::Clone after the segment has been garbage collected.\n");
  1298. return DMUS_S_GARBAGE_COLLECTED;
  1299. }
  1300. CSegment* pCSegment;
  1301. HRESULT hr = S_OK;
  1302. if( (mtEnd < mtStart) || (mtEnd > m_mtLength) )
  1303. {
  1304. mtEnd = m_mtLength;
  1305. }
  1306. if( ( mtEnd == 0 ) && ( mtStart == 0 ))
  1307. {
  1308. mtEnd = m_mtLength;
  1309. }
  1310. if( (mtStart < 0) || (mtStart > m_mtLength) )
  1311. {
  1312. mtStart = 0;
  1313. }
  1314. pCSegment = new CSegment;
  1315. if (pCSegment == NULL) {
  1316. return E_OUTOFMEMORY;
  1317. }
  1318. // Addref to 1 and assign to ppSegment.
  1319. pCSegment->AddRef();
  1320. (*ppSegment) = (IDirectMusicSegment *) pCSegment;
  1321. if( m_pGraph )
  1322. {
  1323. pCSegment->m_pGraph = m_pGraph;
  1324. m_pGraph->AddRef();
  1325. }
  1326. if (m_pAudioPathConfig)
  1327. {
  1328. pCSegment->m_pAudioPathConfig = m_pAudioPathConfig;
  1329. m_pAudioPathConfig->AddRef();
  1330. }
  1331. pCSegment->m_dwRepeats = m_dwRepeats;
  1332. pCSegment->m_dwResolution = m_dwResolution;
  1333. pCSegment->m_dwSegFlags = m_dwSegFlags;
  1334. pCSegment->m_mtLength = mtEnd - mtStart;
  1335. pCSegment->m_rtLength = m_rtLength;
  1336. pCSegment->m_mtStart = m_mtStart;
  1337. pCSegment->m_mtLoopStart = m_mtLoopStart;
  1338. pCSegment->m_mtLoopEnd = m_mtLoopEnd;
  1339. pCSegment->m_dwValidData = m_dwValidData;
  1340. pCSegment->m_guidObject = m_guidObject;
  1341. pCSegment->m_ftDate = m_ftDate;
  1342. pCSegment->m_vVersion = m_vVersion;
  1343. StringCchCopyW(pCSegment->m_wszName, DMUS_MAX_NAME, m_wszName);
  1344. StringCchCopyW(pCSegment->m_wszCategory, DMUS_MAX_CATEGORY, m_wszCategory);
  1345. StringCchCopyW(pCSegment->m_wszFileName, DMUS_MAX_FILENAME, m_wszFileName);
  1346. pCSegment->m_dwVersion = m_dwVersion;
  1347. pCSegment->m_dwLoadID = m_dwLoadID;
  1348. pCSegment->m_dwPlayID = m_dwPlayID;
  1349. pCSegment->m_dwNextPlayID = m_dwNextPlayID;
  1350. pCSegment->m_dwNextPlayFlags = m_dwNextPlayFlags;
  1351. CTrack* pCTrack;
  1352. IDirectMusicTrack* pTrack;
  1353. EnterCriticalSection(&m_CriticalSection);
  1354. pCTrack = m_TrackList.GetHead();
  1355. while( pCTrack )
  1356. {
  1357. if( SUCCEEDED( pCTrack->m_pTrack->Clone( mtStart, mtEnd, &pTrack )))
  1358. {
  1359. if( FAILED( pCSegment->InsertTrack( pTrack, pCTrack->m_dwGroupBits, pCTrack->m_dwFlags, pCTrack->m_dwPriority, pCTrack->m_dwPosition )))
  1360. {
  1361. Trace(1,"Warning: Insertion of cloned track failed, cloned segment is incomplete.\n");
  1362. hr = S_FALSE;
  1363. }
  1364. pTrack->Release();
  1365. }
  1366. else
  1367. {
  1368. Trace(1,"Warning: Track clone failed, cloned segment is incomplete.\n");
  1369. hr = S_FALSE;
  1370. }
  1371. pCTrack = pCTrack->GetNext();
  1372. }
  1373. LeaveCriticalSection(&m_CriticalSection);
  1374. return hr;
  1375. }
  1376. STDMETHODIMP CSegment::GetAudioPathConfig(IUnknown ** ppAudioPathConfig)
  1377. {
  1378. V_INAME(IDirectMusicSegment::GetAudioPathConfig);
  1379. V_PTRPTR_WRITE(ppAudioPathConfig);
  1380. if (m_fZombie)
  1381. {
  1382. Trace(2, "Warning: Call of IDirectMusicSegment::GetAudioPathConfig after the segment has been garbage collected.\n");
  1383. return DMUS_S_GARBAGE_COLLECTED;
  1384. }
  1385. HRESULT hr;
  1386. EnterCriticalSection(&m_CriticalSection);
  1387. if (m_pAudioPathConfig)
  1388. {
  1389. hr = m_pAudioPathConfig->QueryInterface(IID_IUnknown,(void **)ppAudioPathConfig);
  1390. }
  1391. else
  1392. {
  1393. Trace(2,"Warning: No embedded audiopath configuration in the segment.\n");
  1394. hr = DMUS_E_NO_AUDIOPATH_CONFIG;
  1395. }
  1396. LeaveCriticalSection(&m_CriticalSection);
  1397. return hr;
  1398. }
  1399. STDMETHODIMP CSegment::GetObjectInPath(DWORD dwPChannel, /* PChannel to search. */
  1400. DWORD dwStage, /* Which stage in the path. */
  1401. DWORD dwBuffer,
  1402. REFGUID guidObject, /* ClassID of object. */
  1403. DWORD dwIndex, /* Which object of that class. */
  1404. REFGUID iidInterface,/* Requested COM interface. */
  1405. void ** ppObject)
  1406. {
  1407. V_INAME(IDirectMusicSegment::GetObjectInPath);
  1408. V_PTRPTR_WRITE(ppObject);
  1409. if (m_fZombie)
  1410. {
  1411. Trace(2, "Warning: Call of IDirectMusicSegment::GetObjectInPath after the segment has been garbage collected.\n");
  1412. return DMUS_S_GARBAGE_COLLECTED;
  1413. }
  1414. HRESULT hr = DMUS_E_NOT_FOUND;
  1415. EnterCriticalSection(&m_CriticalSection);
  1416. if (dwStage == DMUS_PATH_SEGMENT_TRACK)
  1417. {
  1418. CTrack * pCTrack = GetTrack(guidObject,-1,dwIndex);
  1419. if (pCTrack)
  1420. {
  1421. if (pCTrack->m_pTrack)
  1422. {
  1423. hr = pCTrack->m_pTrack->QueryInterface(iidInterface,ppObject);
  1424. }
  1425. }
  1426. }
  1427. else if (dwStage == DMUS_PATH_SEGMENT_GRAPH)
  1428. {
  1429. if (dwIndex == 0)
  1430. {
  1431. if (!m_pGraph)
  1432. {
  1433. m_pGraph = new CGraph;
  1434. }
  1435. if (m_pGraph)
  1436. {
  1437. hr = m_pGraph->QueryInterface(iidInterface,ppObject);
  1438. }
  1439. else
  1440. {
  1441. hr = E_OUTOFMEMORY;
  1442. }
  1443. }
  1444. }
  1445. else if (dwStage == DMUS_PATH_SEGMENT_TOOL)
  1446. {
  1447. if (!m_pGraph)
  1448. {
  1449. m_pGraph = new CGraph;
  1450. }
  1451. if (m_pGraph)
  1452. {
  1453. hr = m_pGraph->GetObjectInPath(dwPChannel,guidObject,dwIndex,iidInterface,ppObject);
  1454. }
  1455. else
  1456. {
  1457. hr = E_OUTOFMEMORY;
  1458. }
  1459. }
  1460. else if (dwStage >= DMUS_PATH_BUFFER)
  1461. {
  1462. // Nothing here now. But, in DX9, we may add support for addressing the buffer configuration
  1463. // and DMOS in it.
  1464. }
  1465. LeaveCriticalSection(&m_CriticalSection);
  1466. return hr;
  1467. }
  1468. STDMETHODIMP CSegment::Compose(MUSIC_TIME mtTime,
  1469. IDirectMusicSegment* pFromSegment,
  1470. IDirectMusicSegment* pToSegment,
  1471. IDirectMusicSegment** ppComposedSegment)
  1472. {
  1473. V_INAME(IDirectMusicSegment::Compose);
  1474. V_INTERFACE_OPT(pFromSegment);
  1475. V_INTERFACE_OPT(pToSegment);
  1476. V_PTRPTR_WRITE_OPT(ppComposedSegment);
  1477. #ifdef DBG
  1478. if (pFromSegment)
  1479. {
  1480. MUSIC_TIME mtLength, mtLoopEnd, mtLoopStart;
  1481. DWORD dwRepeats;
  1482. // To calculate the full length, we need to access the loop parameters.
  1483. pFromSegment->GetLoopPoints(&mtLoopStart,&mtLoopEnd);
  1484. pFromSegment->GetRepeats(&dwRepeats);
  1485. pFromSegment->GetLength(&mtLength);
  1486. // If repeats is set to infinite, the total length will be greater than 32 bits.
  1487. LONGLONG llTotalLength = dwRepeats * (mtLoopEnd - mtLoopStart) + mtLength;
  1488. if (mtTime >= (llTotalLength & 0x7FFFFFFF))
  1489. {
  1490. Trace(2,"Warning: A time value of %ld was passed to Compose for a segment of length %ld.\n",
  1491. mtTime, (long) llTotalLength);
  1492. }
  1493. }
  1494. #endif
  1495. if (m_fZombie)
  1496. {
  1497. Trace(2, "Warning: Call of IDirectMusicSegment::Compose after the segment has been garbage collected.\n");
  1498. return DMUS_S_GARBAGE_COLLECTED;
  1499. }
  1500. HRESULT hr = S_OK;
  1501. EnterCriticalSection(&m_CriticalSection);
  1502. if (ppComposedSegment)
  1503. {
  1504. hr = Clone(0, m_mtLength, ppComposedSegment);
  1505. if (SUCCEEDED(hr))
  1506. {
  1507. hr = ((CSegment*)*ppComposedSegment)->ComposeTransition(mtTime, pFromSegment, pToSegment);
  1508. }
  1509. }
  1510. else
  1511. {
  1512. hr = ComposeTransition(mtTime, pFromSegment, pToSegment);
  1513. }
  1514. LeaveCriticalSection(&m_CriticalSection);
  1515. return hr;
  1516. }
  1517. HRESULT CSegment::ComposeTransition(MUSIC_TIME mtTime,
  1518. IDirectMusicSegment* pFromSegment,
  1519. IDirectMusicSegment* pToSegment)
  1520. {
  1521. HRESULT hr = S_OK;
  1522. bool fTrackPadded = false;
  1523. // Compute amount of time to pad any tracks that need padding.
  1524. DMUS_TIMESIGNATURE TimeSig;
  1525. if (!pFromSegment ||
  1526. FAILED(pFromSegment->GetParam(GUID_TimeSignature, 0xffffffff, 0, mtTime, NULL, (void*) &TimeSig)))
  1527. {
  1528. TimeSig.mtTime = 0;
  1529. TimeSig.bBeatsPerMeasure = 4;
  1530. TimeSig.bBeat = 4;
  1531. TimeSig.wGridsPerBeat = 4;
  1532. }
  1533. else // avoid divide-by-zero
  1534. {
  1535. if (!TimeSig.bBeat) TimeSig.bBeat = 4;
  1536. }
  1537. MUSIC_TIME mtBar = ( DMUS_PPQ * 4 * TimeSig.bBeatsPerMeasure ) / TimeSig.bBeat;
  1538. MUSIC_TIME mtStartPad = min(mtBar, mtTime);
  1539. if (!pFromSegment) mtStartPad = 0;
  1540. MUSIC_TIME mtToLength = 0;
  1541. if (pToSegment) pToSegment->GetLength(&mtToLength);
  1542. MUSIC_TIME mtEndPad = min(mtBar, mtToLength);
  1543. // Instantiate tracks
  1544. CTrack* pTrack = m_TrackList.GetHead();
  1545. for (; pTrack; pTrack = pTrack->GetNext())
  1546. {
  1547. pTrack->m_dwInternalFlags &= ~(TRACKINTERNAL_START_PADDED | TRACKINTERNAL_END_PADDED);
  1548. IDirectMusicTrack* pTransTrack1 = NULL;
  1549. IDirectMusicTrack* pTransTrack2 = NULL;
  1550. GUID guidClassID;
  1551. memset(&guidClassID, 0, sizeof(guidClassID));
  1552. IPersist* pPersist = NULL;
  1553. if (SUCCEEDED(pTrack->m_pTrack->QueryInterface(IID_IPersistStream, (void**)&pPersist)))
  1554. {
  1555. pPersist->GetClassID(&guidClassID);
  1556. pPersist->Release();
  1557. }
  1558. DWORD dwTrackGroup = 0;
  1559. GetTrackGroup(pTrack->m_pTrack, &dwTrackGroup);
  1560. // Get track info
  1561. if (pTrack->m_dwFlags & COMPOSE_TRANSITION1)
  1562. {
  1563. // Clone the appropriate track, with length m_mtLength
  1564. MUSIC_TIME mtStart = 0;
  1565. if (pTrack->m_dwFlags & DMUS_TRACKCONFIG_TRANS1_FROMSEGCURRENT)
  1566. {
  1567. mtStart = mtTime;
  1568. }
  1569. MUSIC_TIME mtEnd = mtStart + m_mtLength;
  1570. IDirectMusicTrack* pSourceTrack = NULL;
  1571. if ( (pTrack->m_dwFlags & DMUS_TRACKCONFIG_TRANS1_FROMSEGSTART) ||
  1572. (pTrack->m_dwFlags & DMUS_TRACKCONFIG_TRANS1_FROMSEGCURRENT) )
  1573. {
  1574. if (pFromSegment)
  1575. {
  1576. hr = pFromSegment->GetTrack(guidClassID, dwTrackGroup, 0, &pSourceTrack);
  1577. }
  1578. }
  1579. else if (pTrack->m_dwFlags & DMUS_TRACKCONFIG_TRANS1_TOSEGSTART)
  1580. {
  1581. if (pToSegment)
  1582. {
  1583. hr = pToSegment->GetTrack(guidClassID, dwTrackGroup, 0, &pSourceTrack);
  1584. }
  1585. }
  1586. if (pSourceTrack)
  1587. {
  1588. hr = pSourceTrack->Clone(mtStart, mtEnd, &pTransTrack1);
  1589. pSourceTrack->Release();
  1590. pSourceTrack = NULL;
  1591. }
  1592. }
  1593. if (!pTransTrack1)
  1594. {
  1595. pTransTrack1 = pTrack->m_pTrack;
  1596. pTransTrack1->AddRef();
  1597. }
  1598. if (pTransTrack1)
  1599. {
  1600. // Pad the track with an extra bar of header and trailer, by cloning header and trailer
  1601. // tracks (from From and To segments, respectively --- *not* using transition flags) and
  1602. // joining them onto the transition segment track.
  1603. IDirectMusicTrack* pStartPadTrack = NULL;
  1604. IDirectMusicTrack* pEndPadTrack = NULL;
  1605. IDirectMusicTrack* pSourceTrack = NULL;
  1606. if (pFromSegment && mtStartPad)
  1607. {
  1608. hr = pFromSegment->GetTrack(guidClassID, dwTrackGroup, 0, &pSourceTrack);
  1609. if (SUCCEEDED(hr))
  1610. {
  1611. pSourceTrack->Clone(mtTime - mtStartPad, mtTime, &pStartPadTrack);
  1612. pSourceTrack->Release();
  1613. pSourceTrack = NULL;
  1614. }
  1615. }
  1616. if (pToSegment && mtEndPad)
  1617. {
  1618. hr = pToSegment->GetTrack(guidClassID, dwTrackGroup, 0, &pSourceTrack);
  1619. if (SUCCEEDED(hr))
  1620. {
  1621. pSourceTrack->Clone(0, mtEndPad, &pEndPadTrack);
  1622. pSourceTrack->Release();
  1623. pSourceTrack = NULL;
  1624. }
  1625. }
  1626. IDirectMusicTrack8* pTrack8 = NULL;
  1627. if (pEndPadTrack)
  1628. {
  1629. if (SUCCEEDED(pTransTrack1->QueryInterface(IID_IDirectMusicTrack8, (void**)&pTrack8)))
  1630. {
  1631. if (SUCCEEDED(pTrack8->Join(pEndPadTrack, m_mtLength, (IDirectMusicSegment*)this, dwTrackGroup, NULL)))
  1632. {
  1633. fTrackPadded = true;
  1634. pTrack->m_dwInternalFlags |= TRACKINTERNAL_END_PADDED;
  1635. }
  1636. pTrack8->Release();
  1637. }
  1638. pEndPadTrack->Release();
  1639. }
  1640. if (SUCCEEDED(hr) && pStartPadTrack)
  1641. {
  1642. if (SUCCEEDED(hr = pStartPadTrack->QueryInterface(IID_IDirectMusicTrack8, (void**)&pTrack8)))
  1643. {
  1644. if (SUCCEEDED(pTrack8->Join(pTransTrack1, mtStartPad, (IDirectMusicSegment*)this, dwTrackGroup, NULL)))
  1645. {
  1646. fTrackPadded = true;
  1647. pTrack->m_dwInternalFlags |= TRACKINTERNAL_START_PADDED;
  1648. pTransTrack1->Release();
  1649. pTransTrack1 = pStartPadTrack;
  1650. }
  1651. else
  1652. {
  1653. pStartPadTrack->Release();
  1654. }
  1655. pTrack8->Release();
  1656. }
  1657. else
  1658. {
  1659. pStartPadTrack->Release();
  1660. }
  1661. }
  1662. else if(pStartPadTrack)
  1663. {
  1664. pStartPadTrack->Release();
  1665. }
  1666. // Replace the current track with the instantiated one
  1667. IDirectMusicTrack8* pTempTrack8 = NULL;
  1668. pTransTrack1->QueryInterface(IID_IDirectMusicTrack8, (void**)&pTempTrack8);
  1669. if (pTrack->m_pTrack) pTrack->m_pTrack->Release();
  1670. pTrack->m_pTrack = pTransTrack1;
  1671. pTrack->m_pTrack->Init( this );
  1672. if (pTrack->m_pTrack8) pTrack->m_pTrack8->Release();
  1673. pTrack->m_pTrack8 = pTempTrack8;
  1674. }
  1675. if (FAILED(hr)) break;
  1676. }
  1677. MUSIC_TIME mtOldLength = m_mtLength;
  1678. if (fTrackPadded) // any tracks got joined with header/trailer info
  1679. {
  1680. // pad the length of the segment, to account for the header/trailer
  1681. m_mtLength += mtStartPad + mtEndPad;
  1682. }
  1683. // Compose
  1684. if (SUCCEEDED(hr))
  1685. {
  1686. hr = ComposeInternal();
  1687. }
  1688. // Back end
  1689. if (fTrackPadded) // any tracks got joined with header/trailer info
  1690. {
  1691. // Trim header and trailer from each track that was joined, using Clone.
  1692. pTrack = m_TrackList.GetHead();
  1693. for (; pTrack; pTrack = pTrack->GetNext())
  1694. {
  1695. if ( (pTrack->m_pTrack) && (pTrack->m_dwInternalFlags & TRACKINTERNAL_START_PADDED) )
  1696. {
  1697. IDirectMusicTrack* pTempTrack = NULL;
  1698. IDirectMusicTrack8* pTempTrack8 = NULL;
  1699. pTrack->m_pTrack->Clone(mtStartPad, mtOldLength + mtStartPad, &pTempTrack);
  1700. pTempTrack->QueryInterface(IID_IDirectMusicTrack8, (void**)&pTempTrack8);
  1701. pTrack->m_pTrack->Release();
  1702. pTrack->m_pTrack = pTempTrack;
  1703. pTrack->m_pTrack->Init( this );
  1704. if (pTrack->m_pTrack8) pTrack->m_pTrack8->Release();
  1705. pTrack->m_pTrack8 = pTempTrack8;
  1706. }
  1707. else if ( (pTrack->m_pTrack) && (pTrack->m_dwInternalFlags & TRACKINTERNAL_END_PADDED) )
  1708. {
  1709. IDirectMusicTrack* pTempTrack = NULL;
  1710. IDirectMusicTrack8* pTempTrack8 = NULL;
  1711. pTrack->m_pTrack->Clone(0, mtOldLength, &pTempTrack);
  1712. pTempTrack->QueryInterface(IID_IDirectMusicTrack8, (void**)&pTempTrack8);
  1713. pTrack->m_pTrack->Release();
  1714. pTrack->m_pTrack = pTempTrack;
  1715. pTrack->m_pTrack->Init( this );
  1716. if (pTrack->m_pTrack8) pTrack->m_pTrack8->Release();
  1717. pTrack->m_pTrack8 = pTempTrack8;
  1718. }
  1719. pTrack->m_dwInternalFlags &= ~(TRACKINTERNAL_START_PADDED | TRACKINTERNAL_END_PADDED);
  1720. }
  1721. // Return the length of the segment to its original value.
  1722. m_mtLength = mtOldLength;
  1723. }
  1724. return hr;
  1725. }
  1726. HRESULT CSegment::ComposeInternal()
  1727. {
  1728. HRESULT hr = S_OK;
  1729. TList<CTrack*> TrackList;
  1730. // Find the composing tracks and put them in priority order
  1731. CTrack* pTrack = m_TrackList.GetHead();
  1732. for (; pTrack; pTrack = pTrack->GetNext())
  1733. {
  1734. if (pTrack->m_dwFlags & DMUS_TRACKCONFIG_COMPOSING)
  1735. {
  1736. TListItem<CTrack*>* pTrackItem = new TListItem<CTrack*>(pTrack);
  1737. if (!pTrackItem)
  1738. {
  1739. hr = E_OUTOFMEMORY;
  1740. }
  1741. else
  1742. {
  1743. TListItem<CTrack*>* pMaster = TrackList.GetHead();
  1744. TListItem<CTrack*>* pPrevious = NULL;
  1745. for (; pMaster; pMaster = pMaster->GetNext())
  1746. {
  1747. CTrack*& rpMaster = pMaster->GetItemValue();
  1748. if (pTrack->m_dwPriority > rpMaster->m_dwPriority) break;
  1749. pPrevious = pMaster;
  1750. }
  1751. if (!pPrevious) // this has higher priority than anything in the list
  1752. {
  1753. TrackList.AddHead(pTrackItem);
  1754. }
  1755. else // lower priority than pPrevious, higher than pMaster
  1756. {
  1757. pTrackItem->SetNext(pMaster);
  1758. pPrevious->SetNext(pTrackItem);
  1759. }
  1760. }
  1761. }
  1762. if (FAILED(hr)) break;
  1763. }
  1764. // Compose a new track from each from each composing track; put the results
  1765. // in the segment (remove any existing composed tracks)
  1766. if (SUCCEEDED(hr))
  1767. {
  1768. TListItem<CTrack*>* pTrackItem = TrackList.GetHead();
  1769. for (; pTrackItem; pTrackItem = pTrackItem->GetNext())
  1770. {
  1771. CTrack*& rpTrack = pTrackItem->GetItemValue();
  1772. IDirectMusicTrack8* pComposedTrack = NULL;
  1773. hr = rpTrack->m_pTrack8->Compose((IDirectMusicSegment*)this, rpTrack->m_dwGroupBits, (IDirectMusicTrack**)&pComposedTrack);
  1774. if (SUCCEEDED(hr))
  1775. {
  1776. // Remove any tracks of this type (in the same group) from the segment.
  1777. IDirectMusicTrack* pOldTrack = NULL;
  1778. GUID guidClassId;
  1779. memset(&guidClassId, 0, sizeof(guidClassId));
  1780. IPersistStream* pPersist = NULL;
  1781. if (SUCCEEDED(pComposedTrack->QueryInterface(IID_IPersistStream, (void**)&pPersist)) )
  1782. {
  1783. if (SUCCEEDED(pPersist->GetClassID(&guidClassId)) &&
  1784. SUCCEEDED( GetTrack( guidClassId, rpTrack->m_dwGroupBits, 0, &pOldTrack ) ) )
  1785. {
  1786. RemoveTrack( pOldTrack );
  1787. pOldTrack->Release();
  1788. }
  1789. pPersist->Release();
  1790. }
  1791. hr = InsertTrack(pComposedTrack, rpTrack->m_dwGroupBits);
  1792. pComposedTrack->Release();
  1793. }
  1794. if (FAILED(hr)) break;
  1795. }
  1796. }
  1797. return hr;
  1798. }
  1799. STDMETHODIMP CSegment::GetStartPoint(
  1800. MUSIC_TIME* pmtStart // @parm Returns the Segment's start point.
  1801. )
  1802. {
  1803. V_INAME(IDirectMusicSegment::GetStartPoint);
  1804. if (m_fZombie)
  1805. {
  1806. Trace(2, "Warning: Call of IDirectMusicSegment::GetStartPoint after the segment has been garbage collected.\n");
  1807. return DMUS_S_GARBAGE_COLLECTED;
  1808. }
  1809. *pmtStart = m_mtStart;
  1810. return S_OK;
  1811. }
  1812. STDMETHODIMP CSegment::SetStartPoint(
  1813. MUSIC_TIME mtStart // @parm The start point at which to begin playing the
  1814. // Segment. If it is less than zero or greater than the
  1815. // length of the Segment, the start point will be set
  1816. // to zero.
  1817. )
  1818. {
  1819. if( (mtStart < 0) || (mtStart >= m_mtLength) )
  1820. {
  1821. Trace(1,"Error: Unable to set start point %ld because not within the range of the segment, which is %ld.\n",
  1822. mtStart,m_mtLength);
  1823. return DMUS_E_OUT_OF_RANGE;
  1824. }
  1825. if (m_fZombie)
  1826. {
  1827. Trace(2, "Warning: Call of IDirectMusicSegment::SetStartPoint after the segment has been garbage collected.\n");
  1828. return DMUS_S_GARBAGE_COLLECTED;
  1829. }
  1830. m_mtStart = mtStart;
  1831. return S_OK;
  1832. }
  1833. STDMETHODIMP CSegment::GetLoopPoints(
  1834. MUSIC_TIME* pmtStart, // @parm Returns the start point of the loop.
  1835. MUSIC_TIME* pmtEnd // @parm Returns the end point of the loop. A value of
  1836. // 0 indicates that the entire Segment will loop.
  1837. )
  1838. {
  1839. V_INAME(IDirectMusicSegment::GetLoopPoints);
  1840. V_PTR_WRITE(pmtStart, MUSIC_TIME);
  1841. V_PTR_WRITE(pmtEnd, MUSIC_TIME);
  1842. if (m_fZombie)
  1843. {
  1844. Trace(2, "Warning: Call of IDirectMusicSegment::GetLoopPoints after the segment has been garbage collected.\n");
  1845. return DMUS_S_GARBAGE_COLLECTED;
  1846. }
  1847. *pmtStart = m_mtLoopStart;
  1848. *pmtEnd = m_mtLoopEnd;
  1849. return S_OK;
  1850. }
  1851. STDMETHODIMP CSegment::SetLoopPoints(
  1852. MUSIC_TIME mtStart, // @parm The start point at which to begin the loop.
  1853. MUSIC_TIME mtEnd // @parm The end point at which to begin the loop. Set
  1854. // <p mtStart> and <p mtEnd> to 0
  1855. // to loop the entire Segment.
  1856. )
  1857. {
  1858. if( (mtStart < 0) || (mtEnd > m_mtLength) || (mtStart > mtEnd) )
  1859. {
  1860. Trace(1,"Error: Unable to set loop points %ld, %ld because they are not within the range of the segment, which is %ld.\n",
  1861. mtStart,mtStart,mtEnd,m_mtLength);
  1862. return DMUS_E_OUT_OF_RANGE;
  1863. }
  1864. if (m_fZombie)
  1865. {
  1866. Trace(2, "Warning: Call of IDirectMusicSegment::SetLoopPoints after the segment has been garbage collected.\n");
  1867. return DMUS_S_GARBAGE_COLLECTED;
  1868. }
  1869. m_mtLoopStart = mtStart;
  1870. m_mtLoopEnd = mtEnd;
  1871. return S_OK;
  1872. }
  1873. STDMETHODIMP CSegment::SetPChannelsUsed(
  1874. DWORD dwNumPChannels, // @parm The number of PChannels to set. This must be equal
  1875. // to the number of members in the array pointed to by
  1876. // <p paPChannels>.
  1877. DWORD* paPChannels // @parm Points to an array of PChannels. The array should
  1878. // have the same number of elements as specified by <p dwNumPChannels>.
  1879. )
  1880. {
  1881. V_INAME(IDirectMusicSegment::SetPChannelsUsed);
  1882. if (m_fZombie)
  1883. {
  1884. Trace(2, "Warning: Call of IDirectMusicSegment::SetPChannelsUsed after the segment has been garbage collected.\n");
  1885. return DMUS_S_GARBAGE_COLLECTED;
  1886. }
  1887. if( dwNumPChannels )
  1888. {
  1889. if( NULL == paPChannels )
  1890. {
  1891. Trace(1,"Error: Bad call to SetPChannelsUsed, pointer to PChannel array is NULL.\n");
  1892. return E_INVALIDARG;
  1893. }
  1894. V_BUFPTR_READ(paPChannels, sizeof(DWORD)*dwNumPChannels);
  1895. DWORD* padwTemp = new DWORD[dwNumPChannels]; // temp array
  1896. DWORD dwTotalNum = 0;
  1897. if( NULL == padwTemp )
  1898. {
  1899. return E_OUTOFMEMORY;
  1900. }
  1901. // count the number of unique PChannels are in the array. That is, the ones
  1902. // that we don't already have stored.
  1903. DWORD dwCount;
  1904. for( dwCount = 0; dwCount < dwNumPChannels; dwCount++ )
  1905. {
  1906. DWORD dwCurrent;
  1907. for( dwCurrent = 0; dwCurrent < m_dwNumPChannels; dwCurrent++ )
  1908. {
  1909. if( m_paPChannels[dwCurrent] == paPChannels[dwCount] )
  1910. {
  1911. // we already track this one
  1912. break;
  1913. }
  1914. }
  1915. if( dwCurrent >= m_dwNumPChannels )
  1916. {
  1917. // we're not already tracking this one
  1918. padwTemp[dwTotalNum] = paPChannels[dwCount];
  1919. dwTotalNum++;
  1920. }
  1921. }
  1922. // dwTotalNum equals the total number of new PChannels, and they are indexed
  1923. // inside adwTemp.
  1924. DWORD* paNewPChannels = new DWORD[m_dwNumPChannels + dwTotalNum];
  1925. if( NULL == paNewPChannels )
  1926. {
  1927. delete [] padwTemp;
  1928. return E_OUTOFMEMORY;
  1929. }
  1930. if( m_paPChannels )
  1931. {
  1932. memcpy( paNewPChannels, m_paPChannels, sizeof(DWORD) * m_dwNumPChannels );
  1933. delete [] m_paPChannels;
  1934. }
  1935. memcpy( &paNewPChannels[m_dwNumPChannels], padwTemp, sizeof(DWORD) * dwTotalNum );
  1936. delete [] padwTemp;
  1937. m_dwNumPChannels += dwTotalNum;
  1938. m_paPChannels = paNewPChannels;
  1939. }
  1940. return S_OK;
  1941. }
  1942. /////////////////////////////////////////////////////////////////////////////
  1943. // IDirectMusicSegmentObject (private)
  1944. HRESULT CSegment::GetPChannels(
  1945. DWORD* pdwNumPChannels, // returns the number of pchannels
  1946. DWORD** ppaPChannels) // returns a pointer to the array of pchannels. Don't free this
  1947. // memory or keep it, as it is owned by the Segment.
  1948. {
  1949. ASSERT(pdwNumPChannels && ppaPChannels);
  1950. *pdwNumPChannels = m_dwNumPChannels;
  1951. *ppaPChannels = m_paPChannels;
  1952. return S_OK;
  1953. }
  1954. // return S_OK if the notification is active, S_FALSE if not.
  1955. HRESULT CSegment::CheckNotification( REFGUID rguid )
  1956. {
  1957. if( NULL == FindNotification( rguid ) )
  1958. {
  1959. return S_FALSE;
  1960. }
  1961. return S_OK;
  1962. }
  1963. /////////////////////////////////////////////////////////////////////////////
  1964. // IPersist
  1965. HRESULT CSegment::GetClassID( CLSID* pClassID )
  1966. {
  1967. V_INAME(CSegment::GetClassID);
  1968. V_PTR_WRITE(pClassID, CLSID);
  1969. if (m_fZombie)
  1970. {
  1971. Trace(2, "Warning: Call of IDirectMusicSegment::GetClassID after the segment has been garbage collected.\n");
  1972. return DMUS_S_GARBAGE_COLLECTED;
  1973. }
  1974. *pClassID = CLSID_DirectMusicSegment;
  1975. return S_OK;
  1976. }
  1977. /////////////////////////////////////////////////////////////////////////////
  1978. // IPersistStream functions
  1979. HRESULT CSegment::IsDirty()
  1980. {
  1981. if (m_fZombie)
  1982. {
  1983. Trace(2, "Warning: Call of IDirectMusicSegment::IsDirty after the segment has been garbage collected.\n");
  1984. return DMUS_S_GARBAGE_COLLECTED;
  1985. }
  1986. return S_FALSE;
  1987. }
  1988. #define DMUS_FOURCC_RMID_FORM mmioFOURCC('R','M','I','D')
  1989. #define DMUS_FOURCC_data_FORM mmioFOURCC('d','a','t','a')
  1990. #define DMUS_FOURCC_DLS_FORM mmioFOURCC('D','L','S',' ')
  1991. #define FOURCC_SECTION_FORM mmioFOURCC('A','A','S','E')
  1992. HRESULT CSegment::Load( IStream* pIStream )
  1993. {
  1994. V_INAME(CSegment::Load);
  1995. V_INTERFACE(pIStream);
  1996. if (m_fZombie)
  1997. {
  1998. Trace(2, "Warning: Call of IDirectMusicSegment::Load after the segment has been garbage collected.\n");
  1999. return DMUS_S_GARBAGE_COLLECTED;
  2000. }
  2001. // Save stream's current position
  2002. LARGE_INTEGER li;
  2003. ULARGE_INTEGER ul;
  2004. li.HighPart = 0;
  2005. li.LowPart = 0;
  2006. HRESULT hr = pIStream->Seek(li, STREAM_SEEK_CUR, &ul);
  2007. if(FAILED(hr))
  2008. {
  2009. return hr;
  2010. }
  2011. EnterCriticalSection(&m_CriticalSection);
  2012. Clear(false);
  2013. DWORD dwSavedPos = ul.LowPart;
  2014. // Read first 4 bytes to determine what type of stream we
  2015. // have been passed
  2016. FOURCC type;
  2017. DWORD dwRead;
  2018. hr = pIStream->Read(&type, sizeof(FOURCC), &dwRead);
  2019. if(SUCCEEDED(hr) && dwRead == sizeof(FOURCC))
  2020. {
  2021. // Check for a RIFF file
  2022. if(type == mmioFOURCC( 'R', 'I', 'F', 'F' ))
  2023. {
  2024. long lFileLength = 0;
  2025. pIStream->Read(&lFileLength, sizeof(long), &dwRead);
  2026. // Check to see if what type of RIFF file we have
  2027. hr = pIStream->Read(&type, sizeof(FOURCC), &dwRead);
  2028. if(SUCCEEDED(hr) && dwRead == sizeof(FOURCC))
  2029. {
  2030. if(type == DMUS_FOURCC_SEGMENT_FORM) // We have a DirectMusic segment
  2031. {
  2032. // Since we now know what type of stream we need to
  2033. // seek back to saved position
  2034. li.HighPart = 0;
  2035. li.LowPart = dwSavedPos;
  2036. hr = pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  2037. hr = LoadDirectMusicSegment(pIStream);
  2038. }
  2039. else if(type == FOURCC_SECTION_FORM) // We have section
  2040. {
  2041. // Since we now know what type of stream we need to seek back to saved position
  2042. li.HighPart = 0;
  2043. li.LowPart = dwSavedPos;
  2044. hr = pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  2045. // Create Section
  2046. IDMSection* pSection;
  2047. if(SUCCEEDED(hr))
  2048. {
  2049. hr = ::CoCreateInstance(CLSID_DMSection,
  2050. NULL,
  2051. CLSCTX_INPROC,
  2052. IID_IDMSection,
  2053. (void**)&pSection);
  2054. }
  2055. if(SUCCEEDED(hr))
  2056. {
  2057. // Load Section
  2058. IPersistStream* pIPersistStream;
  2059. hr = pSection->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
  2060. if(SUCCEEDED(hr))
  2061. {
  2062. hr = pIPersistStream->Load(pIStream);
  2063. pIPersistStream->Release();
  2064. }
  2065. if(SUCCEEDED(hr))
  2066. {
  2067. HRESULT hrTemp = pSection->CreateSegment(static_cast<IDirectMusicSegment*>(this));
  2068. if (hrTemp != S_OK)
  2069. {
  2070. hr = hrTemp;
  2071. }
  2072. }
  2073. pSection->Release();
  2074. }
  2075. }
  2076. else if(type == DMUS_FOURCC_RMID_FORM) // We have an RMID MIDI file
  2077. {
  2078. IDirectMusicCollection *pCollection = NULL;
  2079. BOOL fLoadedMIDI = FALSE;
  2080. // Since it's a RIFF file, it could have more than one top level chunk.
  2081. while (SUCCEEDED(hr) && (lFileLength > 8))
  2082. {
  2083. FOURCC dwType = 0;
  2084. DWORD dwLength;
  2085. pIStream->Read(&dwType, sizeof(FOURCC), &dwRead);
  2086. hr = pIStream->Read(&dwLength, sizeof(DWORD), &dwRead);
  2087. lFileLength -= 8;
  2088. if (FAILED(hr))
  2089. {
  2090. break;
  2091. }
  2092. ULARGE_INTEGER ulPosition; // Memorize start of chunk.
  2093. LARGE_INTEGER liStart;
  2094. liStart.QuadPart = 0;
  2095. hr = pIStream->Seek(liStart, STREAM_SEEK_CUR, &ulPosition);
  2096. liStart.QuadPart = ulPosition.QuadPart;
  2097. if (dwType == DMUS_FOURCC_data_FORM)
  2098. { // Get MIDI file header.
  2099. hr = pIStream->Read(&dwType, sizeof(FOURCC), &dwRead);
  2100. if(SUCCEEDED(hr) && (dwType == mmioFOURCC( 'M', 'T', 'h', 'd' )))
  2101. {
  2102. // Since we now know what type of stream we need to seek back to saved position
  2103. hr = pIStream->Seek(liStart, STREAM_SEEK_SET, NULL);
  2104. if(SUCCEEDED(hr))
  2105. {
  2106. hr = CreateSegmentFromMIDIStream(pIStream,
  2107. static_cast<IDirectMusicSegment*>(this));
  2108. }
  2109. if (SUCCEEDED(hr)) fLoadedMIDI = TRUE;
  2110. }
  2111. }
  2112. else if ((dwType == mmioFOURCC( 'R', 'I', 'F', 'F' ) ||
  2113. (dwType == mmioFOURCC( 'L', 'I', 'S', 'T' ))))
  2114. {
  2115. pIStream->Read(&dwType, sizeof(FOURCC), &dwRead);
  2116. if (dwType == DMUS_FOURCC_DLS_FORM)
  2117. {
  2118. hr = CoCreateInstance(CLSID_DirectMusicCollection,
  2119. NULL,
  2120. CLSCTX_INPROC_SERVER,
  2121. IID_IDirectMusicCollection,
  2122. (void**)&pCollection);
  2123. if (SUCCEEDED(hr))
  2124. {
  2125. IPersistStream* pIPS;
  2126. hr = pCollection->QueryInterface( IID_IPersistStream, (void**)&pIPS );
  2127. if (SUCCEEDED(hr))
  2128. {
  2129. // We need to seek back to start of chunk
  2130. liStart.QuadPart -= 8;
  2131. pIStream->Seek(liStart, STREAM_SEEK_SET, NULL);
  2132. hr = pIPS->Load( pIStream );
  2133. pIPS->Release();
  2134. }
  2135. if (FAILED(hr))
  2136. {
  2137. pCollection->Release();
  2138. pCollection = NULL;
  2139. }
  2140. }
  2141. }
  2142. }
  2143. if (SUCCEEDED(hr))
  2144. {
  2145. if (dwLength & 1) ++dwLength;
  2146. ulPosition.QuadPart += dwLength; // Point to start of next chunk.
  2147. liStart.QuadPart = ulPosition.QuadPart;
  2148. hr = pIStream->Seek(liStart, STREAM_SEEK_SET, NULL);
  2149. lFileLength -= dwLength; // Decrement amount left in file.
  2150. }
  2151. }
  2152. if (pCollection)
  2153. {
  2154. if (fLoadedMIDI)
  2155. {
  2156. SetParam(GUID_ConnectToDLSCollection,-1,0,0,(void *) pCollection);
  2157. }
  2158. pCollection->Release();
  2159. }
  2160. }
  2161. else if (type == mmioFOURCC('W','A','V','E')) // we have a wave file
  2162. {
  2163. IDirectSoundWave* pWave = NULL;
  2164. // Seek back to saved position
  2165. li.HighPart = 0;
  2166. li.LowPart = dwSavedPos;
  2167. hr = pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  2168. // Check to see if this wave is embedded
  2169. if (dwSavedPos == 0)
  2170. {
  2171. // CoCreate the wave and load it from the stream
  2172. if (SUCCEEDED(hr))
  2173. {
  2174. hr = CoCreateInstance(CLSID_DirectSoundWave,
  2175. NULL,
  2176. CLSCTX_INPROC_SERVER,
  2177. IID_IDirectSoundWave,
  2178. (void**)&pWave);
  2179. if (SUCCEEDED(hr))
  2180. {
  2181. IPersistStream* pIPS = NULL;
  2182. hr = pWave->QueryInterface(IID_IPersistStream, (void**)&pIPS);
  2183. if (SUCCEEDED(hr))
  2184. {
  2185. hr = pIPS->Load( pIStream );
  2186. pIPS->Release();
  2187. }
  2188. if (FAILED(hr))
  2189. {
  2190. pWave->Release();
  2191. pWave = NULL;
  2192. }
  2193. }
  2194. }
  2195. }
  2196. else
  2197. {
  2198. // Have the loader load the wave object from the stream
  2199. DMUS_OBJECTDESC descWave;
  2200. ZeroMemory(&descWave, sizeof(descWave));
  2201. descWave.dwSize = sizeof(descWave);
  2202. descWave.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_STREAM;
  2203. descWave.guidClass = CLSID_DirectSoundWave;
  2204. descWave.pStream = pIStream;
  2205. IDirectMusicLoader *pLoader = NULL;
  2206. IDirectMusicGetLoader *pGetLoader = NULL;
  2207. hr = pIStream->QueryInterface(IID_IDirectMusicGetLoader,(void **)&pGetLoader);
  2208. if (SUCCEEDED(hr))
  2209. {
  2210. if (SUCCEEDED(pGetLoader->GetLoader(&pLoader)))
  2211. {
  2212. hr = pLoader->GetObject(&descWave, IID_IDirectSoundWave, (void **)&pWave);
  2213. descWave.pStream = NULL;
  2214. descWave.dwValidData &= ~DMUS_OBJ_STREAM;
  2215. if (SUCCEEDED(hr))
  2216. {
  2217. IDirectMusicObject* pObject = NULL;
  2218. hr = pWave->QueryInterface(IID_IDirectMusicObject, (void **)&pObject);
  2219. if (SUCCEEDED(hr))
  2220. {
  2221. // set this object to be a segment with the same GUID
  2222. pObject->GetDescriptor(&descWave);
  2223. descWave.guidClass = CLSID_DirectMusicSegment;
  2224. SetDescriptor(&descWave);
  2225. pObject->Release();
  2226. }
  2227. }
  2228. pLoader->Release();
  2229. }
  2230. pGetLoader->Release();
  2231. }
  2232. }
  2233. if(pWave)
  2234. {
  2235. // CoCreate a wave track
  2236. IDirectMusicTrack* pWaveTrack = NULL;
  2237. if (SUCCEEDED(hr))
  2238. {
  2239. hr = ::CoCreateInstance(CLSID_DirectMusicWaveTrack,
  2240. NULL,
  2241. CLSCTX_INPROC,
  2242. IID_IDirectMusicTrack,
  2243. (void**)&pWaveTrack);
  2244. }
  2245. // Add the wave object to the wave track, and insert the track in the segment.
  2246. if (SUCCEEDED(hr))
  2247. {
  2248. IPrivateWaveTrack* pPrivateWave = NULL;
  2249. hr = pWaveTrack->QueryInterface(IID_IPrivateWaveTrack, (void**)&pPrivateWave);
  2250. if (SUCCEEDED(hr))
  2251. {
  2252. REFERENCE_TIME rt = 0;
  2253. hr = pPrivateWave->AddWave(pWave, 0, 0, 0, &rt);
  2254. if (SUCCEEDED(hr))
  2255. {
  2256. SetClockTimeDuration(rt * REF_PER_MIL);
  2257. SetFlags(DMUS_SEGIOF_REFLENGTH);
  2258. }
  2259. InsertTrack(pWaveTrack, 1);
  2260. SetTrackConfig(CLSID_DirectMusicWaveTrack, 1, 0, DMUS_TRACKCONFIG_DEFAULT | DMUS_TRACKCONFIG_PLAY_CLOCKTIME,0);
  2261. pPrivateWave->Release();
  2262. }
  2263. }
  2264. // Clean up anything that's still hanging around
  2265. if (pWaveTrack) pWaveTrack->Release();
  2266. if (pWave) pWave->Release();
  2267. }
  2268. }
  2269. }
  2270. else
  2271. {
  2272. hr = DMUS_E_CANNOTREAD;
  2273. }
  2274. }
  2275. // Check for a template file
  2276. else if(type == mmioFOURCC('L', 'P', 'T', 's'))
  2277. {
  2278. // Since we now know what type of stream we need to seek back to saved position
  2279. li.HighPart = 0;
  2280. li.LowPart = dwSavedPos;
  2281. hr = pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  2282. // Create Template
  2283. IDMTempl* pTemplate;
  2284. if(SUCCEEDED(hr))
  2285. {
  2286. hr = ::CoCreateInstance(CLSID_DMTempl,
  2287. NULL,
  2288. CLSCTX_INPROC,
  2289. IID_IDMTempl,
  2290. (void**)&pTemplate);
  2291. }
  2292. if(SUCCEEDED(hr))
  2293. {
  2294. // Load Template
  2295. IPersistStream* pIPersistStream;
  2296. hr = pTemplate->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
  2297. if(SUCCEEDED(hr))
  2298. {
  2299. hr = pIPersistStream->Load(pIStream);
  2300. pIPersistStream->Release();
  2301. }
  2302. if(SUCCEEDED(hr))
  2303. {
  2304. hr = pTemplate->CreateSegment(static_cast<IDirectMusicSegment*>(this));
  2305. }
  2306. pTemplate->Release();
  2307. }
  2308. }
  2309. // Check for normal MIDI file
  2310. else if(type == mmioFOURCC('M', 'T', 'h', 'd'))
  2311. {
  2312. // Since we now know what type of stream we need to seek back to saved position
  2313. li.HighPart = 0;
  2314. li.LowPart = dwSavedPos;
  2315. hr = pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  2316. if(SUCCEEDED(hr))
  2317. {
  2318. hr = CreateSegmentFromMIDIStream(pIStream,
  2319. static_cast<IDirectMusicSegment*>(this));
  2320. }
  2321. }
  2322. else
  2323. {
  2324. // Not a DirectMusic Segment file, MIDI file or section or
  2325. // template; unsupported
  2326. Trace(1,"Error: Segment unable to parse file. Must be segment, midi, wave, or rmi file format.\n");
  2327. hr = DMUS_E_UNSUPPORTED_STREAM;
  2328. }
  2329. }
  2330. else
  2331. {
  2332. hr = DMUS_E_CANNOTREAD;
  2333. }
  2334. if( SUCCEEDED(hr) )
  2335. {
  2336. m_dwValidData |= DMUS_OBJ_LOADED;
  2337. }
  2338. LeaveCriticalSection(&m_CriticalSection);
  2339. return hr;
  2340. }
  2341. HRESULT CSegment::Save( IStream* pIStream, BOOL fClearDirty )
  2342. {
  2343. return E_NOTIMPL;
  2344. }
  2345. HRESULT CSegment::GetSizeMax( ULARGE_INTEGER FAR* pcbSize )
  2346. {
  2347. return E_NOTIMPL;
  2348. }
  2349. HRESULT CSegment::LoadDirectMusicSegment(IStream* pIStream)
  2350. {
  2351. // Argument validation
  2352. assert(pIStream);
  2353. CRiffParser Parser(pIStream);
  2354. RIFFIO ckMain;
  2355. HRESULT hr = S_OK;
  2356. Parser.EnterList(&ckMain);
  2357. if (Parser.NextChunk(&hr))
  2358. {
  2359. if (ckMain.fccType == DMUS_FOURCC_SEGMENT_FORM)
  2360. {
  2361. RIFFIO ckNext; // Descends into the next chunk.
  2362. RIFFIO ckChild; // For scanning through children lists.
  2363. IDirectMusicContainer *pContainer = NULL; // For handling embedded container with linked objects.
  2364. Parser.EnterList(&ckNext);
  2365. while(Parser.NextChunk(&hr))
  2366. {
  2367. switch(ckNext.ckid)
  2368. {
  2369. case DMUS_FOURCC_SEGMENT_CHUNK:
  2370. DMUS_IO_SEGMENT_HEADER ioSegHdr;
  2371. ioSegHdr.rtLength = 0;
  2372. ioSegHdr.dwFlags = 0;
  2373. hr = Parser.Read(&ioSegHdr, sizeof(DMUS_IO_SEGMENT_HEADER));
  2374. if(SUCCEEDED(hr))
  2375. {
  2376. m_dwResolution = ioSegHdr.dwResolution;
  2377. m_mtLength = ioSegHdr.mtLength;
  2378. m_mtStart = ioSegHdr.mtPlayStart;
  2379. m_mtLoopStart = ioSegHdr.mtLoopStart;
  2380. m_mtLoopEnd = ioSegHdr.mtLoopEnd;
  2381. m_dwRepeats = ioSegHdr.dwRepeats;
  2382. m_dwSegFlags = ioSegHdr.dwFlags;
  2383. if (m_dwSegFlags & DMUS_SEGIOF_REFLENGTH)
  2384. {
  2385. m_rtLength = ioSegHdr.rtLength;
  2386. }
  2387. else
  2388. {
  2389. m_rtLength = 0;
  2390. }
  2391. }
  2392. break;
  2393. case DMUS_FOURCC_GUID_CHUNK:
  2394. if( ckNext.cksize == sizeof(GUID) )
  2395. {
  2396. hr = Parser.Read(&m_guidObject, sizeof(GUID));
  2397. if( SUCCEEDED(hr) )
  2398. {
  2399. m_dwValidData |= DMUS_OBJ_OBJECT;
  2400. }
  2401. }
  2402. break;
  2403. case DMUS_FOURCC_VERSION_CHUNK:
  2404. hr = Parser.Read(&m_vVersion, sizeof(DMUS_VERSION) );
  2405. if( SUCCEEDED(hr) )
  2406. {
  2407. m_dwValidData |= DMUS_OBJ_VERSION;
  2408. }
  2409. break;
  2410. case DMUS_FOURCC_CATEGORY_CHUNK:
  2411. hr = Parser.Read( m_wszCategory, sizeof(WCHAR)*DMUS_MAX_CATEGORY );
  2412. m_wszCategory[DMUS_MAX_CATEGORY-1] = '\0';
  2413. if( SUCCEEDED(hr) )
  2414. {
  2415. m_dwValidData |= DMUS_OBJ_CATEGORY;
  2416. }
  2417. break;
  2418. case DMUS_FOURCC_DATE_CHUNK:
  2419. if( sizeof(FILETIME) == ckNext.cksize )
  2420. {
  2421. hr = Parser.Read( &m_ftDate, sizeof(FILETIME));
  2422. if( SUCCEEDED(hr) )
  2423. {
  2424. m_dwValidData |= DMUS_OBJ_DATE;
  2425. }
  2426. }
  2427. break;
  2428. case FOURCC_LIST:
  2429. case FOURCC_RIFF:
  2430. switch(ckNext.fccType)
  2431. {
  2432. case DMUS_FOURCC_UNFO_LIST:
  2433. Parser.EnterList(&ckChild);
  2434. while (Parser.NextChunk(&hr))
  2435. {
  2436. switch( ckChild.ckid )
  2437. {
  2438. case DMUS_FOURCC_UNAM_CHUNK:
  2439. {
  2440. hr = Parser.Read(&m_wszName, sizeof(m_wszName));
  2441. m_wszName[DMUS_MAX_NAME-1] = '\0';
  2442. if(SUCCEEDED(hr) )
  2443. {
  2444. m_dwValidData |= DMUS_OBJ_NAME;
  2445. }
  2446. break;
  2447. }
  2448. default:
  2449. break;
  2450. }
  2451. }
  2452. Parser.LeaveList();
  2453. break;
  2454. case DMUS_FOURCC_CONTAINER_FORM:
  2455. // An embedded container RIFF chunk which includes a bunch
  2456. // of objects referenced by the segment. This should precede the
  2457. // tracks and gets loaded prior to the tracks. Loading this
  2458. // causes all of its objects to get SetObject'd in the loader,
  2459. // so they later get pulled in as requested by the tracks.
  2460. // After the tracks are loaded, the loader references are
  2461. // released by a call to release the IDirectMusicContainer.
  2462. {
  2463. DMUS_OBJECTDESC Desc;
  2464. IDirectMusicLoader *pLoader;
  2465. IDirectMusicGetLoader *pGetLoader;
  2466. HRESULT hrTemp = pIStream->QueryInterface(IID_IDirectMusicGetLoader,(void **) &pGetLoader);
  2467. if (SUCCEEDED(hrTemp))
  2468. {
  2469. if (SUCCEEDED(pGetLoader->GetLoader(&pLoader)))
  2470. {
  2471. // Move back stream's current position
  2472. Parser.SeekBack();
  2473. Desc.dwSize = sizeof(Desc);
  2474. Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_STREAM;
  2475. Desc.guidClass = CLSID_DirectMusicContainer;
  2476. Desc.pStream = pIStream;
  2477. pLoader->GetObject(&Desc,IID_IDirectMusicContainer,(void **) &pContainer);
  2478. if (pContainer)
  2479. {
  2480. // Don't cache the container object! We want it and the
  2481. // objects it references to go away when the segment is done loading.
  2482. IDirectMusicObject *pObject = NULL;
  2483. pContainer->QueryInterface(IID_IDirectMusicObject,(void **)&pObject);
  2484. if (pObject)
  2485. {
  2486. pLoader->ReleaseObject(pObject);
  2487. pObject->Release();
  2488. }
  2489. }
  2490. // Now, seek to the end of this chunk.
  2491. Parser.SeekForward();
  2492. pLoader->Release();
  2493. }
  2494. pGetLoader->Release();
  2495. }
  2496. }
  2497. break;
  2498. case DMUS_FOURCC_TRACK_LIST:
  2499. Parser.EnterList(&ckChild);
  2500. while(Parser.NextChunk(&hr))
  2501. {
  2502. if ((ckChild.ckid == FOURCC_RIFF) && (ckChild.fccType == DMUS_FOURCC_TRACK_FORM))
  2503. {
  2504. hr = LoadTrack(&Parser);
  2505. }
  2506. }
  2507. Parser.LeaveList();
  2508. break;
  2509. case DMUS_FOURCC_TOOLGRAPH_FORM:
  2510. hr = LoadGraph(&Parser,&m_pGraph);
  2511. break;
  2512. case DMUS_FOURCC_AUDIOPATH_FORM:
  2513. // Move back to start of this chunk.
  2514. Parser.SeekBack();
  2515. hr = LoadAudioPath(pIStream);
  2516. // Now, seek to the end of this chunk.
  2517. Parser.SeekForward();
  2518. break;
  2519. }
  2520. break;
  2521. }
  2522. }
  2523. Parser.LeaveList();
  2524. if (pContainer)
  2525. {
  2526. pContainer->Release();
  2527. }
  2528. }
  2529. else
  2530. {
  2531. Trace(1,"Error: Unknown file format.\n");
  2532. hr = DMUS_E_DESCEND_CHUNK_FAIL;
  2533. }
  2534. }
  2535. Parser.LeaveList();
  2536. if (SUCCEEDED(hr) && Parser.ComponentFailed())
  2537. {
  2538. Trace(1,"Warning: Segment successfully loaded but one or more tracks within it did not.\n");
  2539. hr = DMUS_S_PARTIALLOAD;
  2540. }
  2541. return hr;
  2542. }
  2543. HRESULT CSegment::LoadTrack(CRiffParser *pParser)
  2544. {
  2545. BOOL fHeaderRead = FALSE;
  2546. DMUS_IO_TRACK_HEADER ioTrackHdr;
  2547. DMUS_IO_TRACK_EXTRAS_HEADER ioTrackExtrasHdr;
  2548. ioTrackExtrasHdr.dwPriority = 0;
  2549. ioTrackExtrasHdr.dwFlags = DMUS_TRACKCONFIG_DEFAULT;
  2550. ioTrackHdr.ckid = 0;
  2551. ioTrackHdr.fccType = 0;
  2552. ioTrackHdr.dwPosition = 0;
  2553. RIFFIO ckNext;
  2554. HRESULT hr = S_OK;
  2555. pParser->EnterList(&ckNext);
  2556. while(pParser->NextChunk(&hr))
  2557. {
  2558. if (ckNext.ckid == DMUS_FOURCC_TRACK_CHUNK)
  2559. {
  2560. fHeaderRead = TRUE;
  2561. hr = pParser->Read(&ioTrackHdr, sizeof(DMUS_IO_TRACK_HEADER));
  2562. if(ioTrackHdr.ckid == 0 && ioTrackHdr.fccType == NULL)
  2563. {
  2564. Trace(1,"Error: Invalid track header in Segment.\n");
  2565. hr = DMUS_E_INVALID_TRACK_HDR;
  2566. }
  2567. }
  2568. else if (ckNext.ckid == DMUS_FOURCC_TRACK_EXTRAS_CHUNK)
  2569. {
  2570. hr = pParser->Read(&ioTrackExtrasHdr, sizeof(DMUS_IO_TRACK_EXTRAS_HEADER));
  2571. }
  2572. else if((((ckNext.ckid == FOURCC_LIST) || (ckNext.ckid == FOURCC_RIFF))
  2573. && ckNext.fccType == ioTrackHdr.fccType) ||
  2574. (ckNext.ckid == ioTrackHdr.ckid))
  2575. {
  2576. if (fHeaderRead)
  2577. {
  2578. // Okay, this is the chunk we are looking for.
  2579. // Seek back to start of chunk.
  2580. pParser->SeekBack();
  2581. // Let the parser know it's okay to fail this.
  2582. pParser->EnteringComponent();
  2583. hr = CreateTrack(ioTrackHdr, ioTrackExtrasHdr.dwFlags, ioTrackExtrasHdr.dwPriority, pParser->GetStream());
  2584. // Now, make sure we are at the end of the chunk.
  2585. pParser->SeekForward();
  2586. }
  2587. else
  2588. {
  2589. Trace(1,"Error: Invalid track in Segment - track header is not before track data.\n");
  2590. hr = DMUS_E_TRACK_HDR_NOT_FIRST_CK;
  2591. }
  2592. }
  2593. }
  2594. pParser->LeaveList();
  2595. return hr;
  2596. }
  2597. HRESULT CSegment::CreateTrack(DMUS_IO_TRACK_HEADER& ioTrackHdr, DWORD dwFlags, DWORD dwPriority, IStream *pStream)
  2598. {
  2599. assert(pStream);
  2600. IDirectMusicTrack* pDMTrack = NULL;
  2601. HRESULT hrTrack = S_OK;
  2602. HRESULT hr = CoCreateInstance(ioTrackHdr.guidClassID,
  2603. NULL,
  2604. CLSCTX_INPROC,
  2605. IID_IDirectMusicTrack,
  2606. (void**)&pDMTrack);
  2607. IPersistStream *pIPersistStream = NULL;
  2608. if(SUCCEEDED(hr))
  2609. {
  2610. hr = pDMTrack->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
  2611. }
  2612. if(SUCCEEDED(hr))
  2613. {
  2614. hr = hrTrack = pIPersistStream->Load(pStream);
  2615. }
  2616. if(SUCCEEDED(hr))
  2617. {
  2618. hr = InsertTrack(pDMTrack, ioTrackHdr.dwGroup, dwFlags, dwPriority, ioTrackHdr.dwPosition);
  2619. }
  2620. if(pIPersistStream)
  2621. {
  2622. pIPersistStream->Release();
  2623. }
  2624. if(pDMTrack)
  2625. {
  2626. pDMTrack->Release();
  2627. }
  2628. if (hr == S_OK && hrTrack != S_OK)
  2629. {
  2630. hr = hrTrack;
  2631. }
  2632. return hr;
  2633. }
  2634. HRESULT CSegment::LoadGraph(CRiffParser *pParser,CGraph **ppGraph)
  2635. {
  2636. CGraph *pGraph = new CGraph;
  2637. if (pGraph == NULL) {
  2638. return E_OUTOFMEMORY;
  2639. }
  2640. HRESULT hr = pGraph->Load(pParser);
  2641. EnterCriticalSection(&m_CriticalSection);
  2642. if(*ppGraph)
  2643. {
  2644. (*ppGraph)->Release();
  2645. }
  2646. *ppGraph = pGraph;
  2647. LeaveCriticalSection(&m_CriticalSection);
  2648. return hr;
  2649. }
  2650. HRESULT CSegment::LoadAudioPath(IStream *pStream)
  2651. {
  2652. assert(pStream);
  2653. CAudioPathConfig *pPath = new CAudioPathConfig;
  2654. if (pPath == NULL) {
  2655. return E_OUTOFMEMORY;
  2656. }
  2657. HRESULT hr = pPath->Load(pStream);
  2658. if (FAILED(hr))
  2659. {
  2660. Trace(1,"Segment failed loading embedded AudioPath Configuration\n");
  2661. }
  2662. EnterCriticalSection(&m_CriticalSection);
  2663. if(m_pAudioPathConfig)
  2664. {
  2665. m_pAudioPathConfig->Release();
  2666. }
  2667. m_pAudioPathConfig = pPath;
  2668. if (m_dwVersion < 8) m_dwVersion = 8;
  2669. LeaveCriticalSection(&m_CriticalSection);
  2670. return hr;
  2671. }
  2672. /////////////////////////////////////////////////////////////////////////////
  2673. // IDirectMusicObject
  2674. STDMETHODIMP CSegment::GetDescriptor(LPDMUS_OBJECTDESC pDesc)
  2675. {
  2676. // Argument validation
  2677. V_INAME(CSegment::GetDescriptor);
  2678. V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
  2679. if (m_fZombie)
  2680. {
  2681. Trace(2, "Warning: Call of IDirectMusicSegment::GetDescriptor after the segment has been garbage collected.\n");
  2682. return DMUS_S_GARBAGE_COLLECTED;
  2683. }
  2684. if (pDesc->dwSize)
  2685. {
  2686. V_STRUCTPTR_WRITE(pDesc, DMUS_OBJECTDESC);
  2687. }
  2688. else
  2689. {
  2690. pDesc->dwSize = sizeof(DMUS_OBJECTDESC);
  2691. }
  2692. pDesc->guidClass = CLSID_DirectMusicSegment;
  2693. pDesc->guidObject = m_guidObject;
  2694. pDesc->ftDate = m_ftDate;
  2695. pDesc->vVersion = m_vVersion;
  2696. StringCchCopyW( pDesc->wszName, DMUS_MAX_NAME, m_wszName);
  2697. StringCchCopyW( pDesc->wszCategory, DMUS_MAX_CATEGORY, m_wszCategory);
  2698. StringCchCopyW( pDesc->wszFileName, DMUS_MAX_FILENAME, m_wszFileName);
  2699. pDesc->dwValidData = ( m_dwValidData | DMUS_OBJ_CLASS );
  2700. return S_OK;
  2701. }
  2702. STDMETHODIMP CSegment::SetDescriptor(LPDMUS_OBJECTDESC pDesc)
  2703. {
  2704. // Argument validation
  2705. V_INAME(CSegment::SetDescriptor);
  2706. V_PTR_READ(pDesc, DMUS_OBJECTDESC);
  2707. if (m_fZombie)
  2708. {
  2709. Trace(2, "Warning: Call of IDirectMusicSegment::SetDescriptor after the segment has been garbage collected.\n");
  2710. return DMUS_S_GARBAGE_COLLECTED;
  2711. }
  2712. if (pDesc->dwSize)
  2713. {
  2714. V_STRUCTPTR_READ(pDesc, DMUS_OBJECTDESC);
  2715. }
  2716. HRESULT hr = E_INVALIDARG;
  2717. DWORD dw = 0;
  2718. if( pDesc->dwSize >= sizeof(DMUS_OBJECTDESC) )
  2719. {
  2720. if(pDesc->dwValidData & DMUS_OBJ_CLASS)
  2721. {
  2722. dw |= DMUS_OBJ_CLASS;
  2723. }
  2724. if(pDesc->dwValidData & DMUS_OBJ_LOADED)
  2725. {
  2726. dw |= DMUS_OBJ_LOADED;
  2727. }
  2728. if( pDesc->dwValidData & DMUS_OBJ_OBJECT )
  2729. {
  2730. m_guidObject = pDesc->guidObject;
  2731. dw |= DMUS_OBJ_OBJECT;
  2732. }
  2733. if( pDesc->dwValidData & DMUS_OBJ_NAME )
  2734. {
  2735. StringCchCopyW( m_wszName, DMUS_MAX_NAME, pDesc->wszName);
  2736. dw |= DMUS_OBJ_NAME;
  2737. }
  2738. if( pDesc->dwValidData & DMUS_OBJ_CATEGORY )
  2739. {
  2740. StringCchCopyW( m_wszCategory, DMUS_MAX_CATEGORY, pDesc->wszCategory);
  2741. dw |= DMUS_OBJ_CATEGORY;
  2742. }
  2743. if( ( pDesc->dwValidData & DMUS_OBJ_FILENAME ) ||
  2744. ( pDesc->dwValidData & DMUS_OBJ_FULLPATH ) )
  2745. {
  2746. StringCchCopyW( m_wszFileName, DMUS_MAX_FILENAME, pDesc->wszFileName);
  2747. dw |= (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH));
  2748. }
  2749. if( pDesc->dwValidData & DMUS_OBJ_VERSION )
  2750. {
  2751. m_vVersion = pDesc->vVersion;
  2752. dw |= DMUS_OBJ_VERSION;
  2753. }
  2754. if( pDesc->dwValidData & DMUS_OBJ_DATE )
  2755. {
  2756. m_ftDate = pDesc->ftDate;
  2757. dw |= DMUS_OBJ_DATE;
  2758. }
  2759. m_dwValidData |= dw;
  2760. if( pDesc->dwValidData & (~dw) )
  2761. {
  2762. Trace(2,"Warning: Segment::SetDescriptor was not able to handle all passed fields, dwValidData bits %lx.\n",pDesc->dwValidData & (~dw));
  2763. hr = S_FALSE; // there were extra fields we didn't parse;
  2764. pDesc->dwValidData = dw;
  2765. }
  2766. else
  2767. {
  2768. hr = S_OK;
  2769. }
  2770. }
  2771. else
  2772. {
  2773. Trace(1,"Error: Unable to set segment descriptor, size field is too small.\n");
  2774. }
  2775. return hr;
  2776. }
  2777. STDMETHODIMP CSegment::ParseDescriptor(LPSTREAM pStream, LPDMUS_OBJECTDESC pDesc)
  2778. {
  2779. V_INAME(CSegment::ParseDescriptor);
  2780. V_INTERFACE(pStream);
  2781. V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
  2782. if (pDesc->dwSize)
  2783. {
  2784. V_STRUCTPTR_WRITE(pDesc, DMUS_OBJECTDESC);
  2785. }
  2786. else
  2787. {
  2788. pDesc->dwSize = sizeof(DMUS_OBJECTDESC);
  2789. }
  2790. if (m_fZombie)
  2791. {
  2792. Trace(2, "Warning: Call of IDirectMusicSegment::ParseDescriptor after the segment has been garbage collected.\n");
  2793. return DMUS_S_GARBAGE_COLLECTED;
  2794. }
  2795. HRESULT hret = E_FAIL;
  2796. // Save stream's current position
  2797. LARGE_INTEGER li;
  2798. ULARGE_INTEGER ul;
  2799. li.HighPart = 0;
  2800. li.LowPart = 0;
  2801. HRESULT hr = pStream->Seek(li, STREAM_SEEK_CUR, &ul);
  2802. if(FAILED(hr))
  2803. {
  2804. return hr;
  2805. }
  2806. pDesc->dwValidData = 0;
  2807. DWORD dwSavedPos = ul.LowPart;
  2808. // Read first 4 bytes to determine what type of stream we
  2809. // have been passed
  2810. FOURCC type;
  2811. DWORD dwRead;
  2812. hr = pStream->Read(&type, sizeof(FOURCC), &dwRead);
  2813. if(SUCCEEDED(hr) && dwRead == sizeof(FOURCC))
  2814. {
  2815. // Check for a RIFF file
  2816. if(type == mmioFOURCC( 'R', 'I', 'F', 'F' ))
  2817. {
  2818. // Check to see if what type of RIFF file we have
  2819. li.HighPart = 0;
  2820. li.LowPart = dwSavedPos + 8; // Length needed to seek to form type of RIFF chunk
  2821. hr = pStream->Seek(li, STREAM_SEEK_SET, NULL);
  2822. if(SUCCEEDED(hr))
  2823. {
  2824. hr = pStream->Read(&type, sizeof(FOURCC), &dwRead);
  2825. }
  2826. if(SUCCEEDED(hr) && dwRead == sizeof(FOURCC))
  2827. {
  2828. if(type == DMUS_FOURCC_SEGMENT_FORM) // We have a DirectMusic segment
  2829. {
  2830. // Since we now know what type of stream we need to
  2831. // seek back to saved position
  2832. li.HighPart = 0;
  2833. li.LowPart = dwSavedPos;
  2834. hr = pStream->Seek(li, STREAM_SEEK_SET, NULL);
  2835. if( SUCCEEDED(hr) ) // should always succeed.
  2836. {
  2837. hret = ParseSegment(pStream, pDesc);
  2838. }
  2839. }
  2840. else if(type == FOURCC_SECTION_FORM) // We have section
  2841. {
  2842. long lTemp;
  2843. hr = pStream->Read(&lTemp, sizeof(long), &dwRead);
  2844. if( lTemp == mmioFOURCC('s','e','c','n') )
  2845. {
  2846. hr = pStream->Read(&lTemp, sizeof(long), &dwRead); // length
  2847. hr = pStream->Read(&lTemp, sizeof(long), &dwRead); // time
  2848. if( SUCCEEDED(hr) && (dwRead == sizeof(long) ))
  2849. {
  2850. hr = pStream->Read(&pDesc->wszName, sizeof(WCHAR)*16, &dwRead);
  2851. pDesc->wszName[16-1] = '\0';
  2852. if(SUCCEEDED(hr) && (dwRead == sizeof(WCHAR)*16))
  2853. {
  2854. pDesc->dwValidData |= DMUS_OBJ_NAME;
  2855. }
  2856. }
  2857. hret = S_OK;
  2858. }
  2859. }
  2860. else if (type == mmioFOURCC('W','A','V','E')) // we have a wave file
  2861. {
  2862. // Create a wave object and have it parse the file.
  2863. IDirectMusicObject *pObject;
  2864. hret = CoCreateInstance(CLSID_DirectSoundWave,NULL,CLSCTX_INPROC_SERVER,
  2865. IID_IDirectMusicObject,(void **) &pObject);
  2866. if(SUCCEEDED(hret))
  2867. {
  2868. // seek back to saved position
  2869. li.HighPart = 0;
  2870. li.LowPart = dwSavedPos;
  2871. hret = pStream->Seek(li, STREAM_SEEK_SET, NULL);
  2872. if (SUCCEEDED(hret))
  2873. {
  2874. hret = pObject->ParseDescriptor(pStream,pDesc);
  2875. }
  2876. pObject->Release();
  2877. }
  2878. }
  2879. // Check to see if we have a MIDI file
  2880. else
  2881. {
  2882. li.HighPart = 0;
  2883. li.LowPart = dwSavedPos + 20; // Length needed to seek to start of normal MIDI file
  2884. // contained within the Riff chunk
  2885. hr = pStream->Seek(li, STREAM_SEEK_SET, NULL);
  2886. if(SUCCEEDED(hr))
  2887. {
  2888. hr = pStream->Read(&type, sizeof(FOURCC), &dwRead);
  2889. }
  2890. if(SUCCEEDED(hr) && dwRead == sizeof(FOURCC))
  2891. {
  2892. if(type == mmioFOURCC( 'M', 'T', 'h', 'd' ))
  2893. {
  2894. hret = S_OK;
  2895. }
  2896. }
  2897. }
  2898. }
  2899. }
  2900. // Check for a template file
  2901. else if(type == mmioFOURCC('L', 'P', 'T', 's'))
  2902. {
  2903. hret = S_OK;
  2904. }
  2905. // Check for normal MIDI file
  2906. else if(type == mmioFOURCC('M', 'T', 'h', 'd'))
  2907. {
  2908. hret = S_OK;
  2909. }
  2910. }
  2911. if (SUCCEEDED(hret))
  2912. {
  2913. pDesc->dwValidData |= DMUS_OBJ_CLASS;
  2914. pDesc->guidClass = CLSID_DirectMusicSegment;
  2915. }
  2916. #ifdef DBG
  2917. if (hret == E_FAIL)
  2918. {
  2919. Trace(1,"Error: Segment unable to parse file - unknown format.\n");
  2920. }
  2921. #endif
  2922. return hret;
  2923. }
  2924. HRESULT CSegment::ParseSegment(IStream* pIStream, LPDMUS_OBJECTDESC pDesc)
  2925. {
  2926. CRiffParser Parser(pIStream);
  2927. RIFFIO ckMain;
  2928. RIFFIO ckNext;
  2929. RIFFIO ckUNFO;
  2930. HRESULT hr = S_OK;
  2931. Parser.EnterList(&ckMain);
  2932. if (Parser.NextChunk(&hr) && (ckMain.fccType == DMUS_FOURCC_SEGMENT_FORM))
  2933. {
  2934. Parser.EnterList(&ckNext);
  2935. while(Parser.NextChunk(&hr))
  2936. {
  2937. switch(ckNext.ckid)
  2938. {
  2939. case DMUS_FOURCC_GUID_CHUNK:
  2940. hr = Parser.Read( &pDesc->guidObject, sizeof(GUID) );
  2941. if( SUCCEEDED(hr) )
  2942. {
  2943. pDesc->dwValidData |= DMUS_OBJ_OBJECT;
  2944. }
  2945. break;
  2946. case DMUS_FOURCC_VERSION_CHUNK:
  2947. hr = Parser.Read( &pDesc->vVersion, sizeof(DMUS_VERSION) );
  2948. if( SUCCEEDED(hr) )
  2949. {
  2950. pDesc->dwValidData |= DMUS_OBJ_VERSION;
  2951. }
  2952. break;
  2953. case DMUS_FOURCC_CATEGORY_CHUNK:
  2954. hr = Parser.Read( &pDesc->wszCategory, sizeof(pDesc->wszCategory) );
  2955. pDesc->wszCategory[DMUS_MAX_CATEGORY-1] = '\0';
  2956. if( SUCCEEDED(hr) )
  2957. {
  2958. pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
  2959. }
  2960. break;
  2961. case DMUS_FOURCC_DATE_CHUNK:
  2962. hr = Parser.Read( &pDesc->ftDate, sizeof(FILETIME) );
  2963. if( SUCCEEDED(hr))
  2964. {
  2965. pDesc->dwValidData |= DMUS_OBJ_DATE;
  2966. }
  2967. break;
  2968. case FOURCC_LIST:
  2969. switch(ckNext.fccType)
  2970. {
  2971. case DMUS_FOURCC_UNFO_LIST:
  2972. Parser.EnterList(&ckUNFO);
  2973. while (Parser.NextChunk(&hr))
  2974. {
  2975. switch( ckUNFO.ckid )
  2976. {
  2977. case DMUS_FOURCC_UNAM_CHUNK:
  2978. {
  2979. hr = Parser.Read(&pDesc->wszName, sizeof(pDesc->wszName));
  2980. pDesc->wszName[DMUS_MAX_NAME-1] = '\0';
  2981. if(SUCCEEDED(hr) )
  2982. {
  2983. pDesc->dwValidData |= DMUS_OBJ_NAME;
  2984. }
  2985. break;
  2986. }
  2987. default:
  2988. break;
  2989. }
  2990. }
  2991. Parser.LeaveList();
  2992. break;
  2993. }
  2994. break;
  2995. default:
  2996. break;
  2997. }
  2998. }
  2999. Parser.LeaveList();
  3000. }
  3001. return hr;
  3002. }
  3003. void CSegmentList::Clear()
  3004. {
  3005. CSegment *pSeg;
  3006. while (pSeg = RemoveHead())
  3007. {
  3008. pSeg->SetNext(NULL);
  3009. pSeg->m_pSong = NULL;
  3010. pSeg->Release();
  3011. }
  3012. }
  3013. inline REFERENCE_TIME ConvertToReference(MUSIC_TIME mtSpan, double dblTempo)
  3014. {
  3015. REFERENCE_TIME rtTemp = mtSpan;
  3016. rtTemp *= 600000000;
  3017. rtTemp += (DMUS_PPQ / 2);
  3018. rtTemp /= DMUS_PPQ;
  3019. rtTemp = (REFERENCE_TIME)(rtTemp / dblTempo);
  3020. return rtTemp;
  3021. }
  3022. inline MUSIC_TIME ConvertToMusic(REFERENCE_TIME rtSpan, double dblTempo)
  3023. {
  3024. rtSpan *= DMUS_PPQ;
  3025. rtSpan = (REFERENCE_TIME)(rtSpan * dblTempo);
  3026. rtSpan += 300000000;
  3027. rtSpan /= 600000000;
  3028. #ifdef DBG
  3029. if ( rtSpan & 0xFFFFFFFF00000000 )
  3030. {
  3031. Trace(1,"Error: Invalid Reference to Music time conversion resulted in overflow.\n");
  3032. }
  3033. #endif
  3034. return (MUSIC_TIME) (rtSpan & 0xFFFFFFFF);
  3035. }
  3036. HRESULT CSegment::MusicToReferenceTime(MUSIC_TIME mtTime, REFERENCE_TIME *prtTime)
  3037. {
  3038. double dbl = 120;
  3039. MUSIC_TIME mtTempo = 0;
  3040. REFERENCE_TIME rtTempo = 0;
  3041. MUSIC_TIME mtNext = 0;
  3042. PrivateTempo Tempo;
  3043. HRESULT hr;
  3044. do
  3045. {
  3046. hr = GetParam(GUID_PrivateTempoParam, -1, 0, mtTempo, &mtNext,(void *)&Tempo );
  3047. if (hr == S_OK)
  3048. {
  3049. dbl = Tempo.dblTempo;
  3050. if (Tempo.fLast || mtTempo + mtNext >= mtTime) break;
  3051. rtTempo += ConvertToReference(mtNext, dbl);
  3052. mtTempo += mtNext;
  3053. }
  3054. } while (hr == S_OK);
  3055. *prtTime = rtTempo + ConvertToReference(mtTime - mtTempo, dbl);
  3056. return S_OK;
  3057. }
  3058. HRESULT CSegment::ReferenceToMusicTime(REFERENCE_TIME rtTime, MUSIC_TIME *pmtTime)
  3059. {
  3060. double dbl = 120;
  3061. MUSIC_TIME mtTempo = 0;
  3062. REFERENCE_TIME rtTempo = 0;
  3063. MUSIC_TIME mtNext = 0;
  3064. PrivateTempo Tempo;
  3065. HRESULT hr;
  3066. do
  3067. {
  3068. hr = GetParam(GUID_PrivateTempoParam, -1, 0, mtTempo, &mtNext,(void *)&Tempo );
  3069. if (hr == S_OK)
  3070. {
  3071. REFERENCE_TIME rtNext = rtTempo + ConvertToReference(mtNext, dbl);
  3072. dbl = Tempo.dblTempo;
  3073. if (Tempo.fLast || rtNext >= rtTime) break;
  3074. rtTempo = rtNext;
  3075. mtTempo += mtNext;
  3076. }
  3077. } while (hr == S_OK);
  3078. *pmtTime = mtTempo + ConvertToMusic(rtTime - rtTempo, dbl);
  3079. return S_OK;
  3080. }