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.

3230 lines
111 KiB

  1. // Copyright (c) 1998-1999 Microsoft Corporation
  2. // READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
  3. //
  4. // 4530: C++ exception handler used, but unwind semantics are not enabled. Specify -GX
  5. //
  6. // We disable this because we use exceptions and do *not* specify -GX (USE_NATIVE_EH in
  7. // sources).
  8. //
  9. // The one place we use exceptions is around construction of objects that call
  10. // InitializeCriticalSection. We guarantee that it is safe to use in this case with
  11. // the restriction given by not using -GX (automatic objects in the call chain between
  12. // throw and handler are not destructed). Turning on -GX buys us nothing but +10% to code
  13. // size because of the unwind code.
  14. //
  15. // Any other use of exceptions must follow these restrictions or -GX must be turned on.
  16. //
  17. // READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
  18. //
  19. #pragma warning(disable:4530)
  20. // WavTrack.cpp : Implementation of CWavTrack
  21. #include "dmime.h"
  22. #include "dmperf.h"
  23. #include "WavTrack.h"
  24. #include "dmusici.h"
  25. #include "dmusicf.h"
  26. #include "debug.h"
  27. #include "..\shared\Validate.h"
  28. #include "debug.h"
  29. #include "..\dswave\dswave.h"
  30. #include "dmsegobj.h"
  31. #define ASSERT assert
  32. #include <math.h>
  33. // @doc EXTERNAL
  34. TList<TaggedWave> WaveItem::st_WaveList;
  35. CRITICAL_SECTION WaveItem::st_WaveListCritSect;
  36. long CWavTrack::st_RefCount = 0;
  37. BOOL PhysicalLess(WaveItem& WI1, WaveItem& WI2)
  38. {
  39. return WI1.m_rtTimePhysical < WI2.m_rtTimePhysical;
  40. }
  41. BOOL LogicalLess(WaveItem& WI1, WaveItem& WI2)
  42. {
  43. return WI1.m_mtTimeLogical < WI2.m_mtTimeLogical;
  44. }
  45. /////////////////////////////////////////////////////////////////////////////
  46. // CWavTrack
  47. void CWavTrack::FlushWaves()
  48. {
  49. UnloadAllWaves(NULL);
  50. EnterCriticalSection(&WaveItem::st_WaveListCritSect);
  51. while (!WaveItem::st_WaveList.IsEmpty())
  52. {
  53. TListItem<TaggedWave>* pScan = WaveItem::st_WaveList.RemoveHead();
  54. delete pScan;
  55. }
  56. LeaveCriticalSection(&WaveItem::st_WaveListCritSect);
  57. }
  58. HRESULT CWavTrack::UnloadAllWaves(IDirectMusicPerformance* pPerformance)
  59. {
  60. HRESULT hr = S_OK;
  61. EnterCriticalSection(&WaveItem::st_WaveListCritSect);
  62. TListItem<TaggedWave>* pScan = WaveItem::st_WaveList.GetHead();
  63. TListItem<TaggedWave>* pNext = NULL;
  64. for (; pScan; pScan = pNext)
  65. {
  66. pNext = pScan->GetNext();
  67. TaggedWave& rScan = pScan->GetItemValue();
  68. if (!pPerformance || rScan.m_pPerformance == pPerformance)
  69. {
  70. if (rScan.m_pPort)
  71. {
  72. if (rScan.m_pDownloadedWave)
  73. {
  74. Trace(1, "Error: Wave was downloaded but never unloaded.\n");
  75. rScan.m_pPort->UnloadWave(rScan.m_pDownloadedWave);
  76. rScan.m_pDownloadedWave = NULL;
  77. }
  78. rScan.m_pPort->Release();
  79. rScan.m_pPort = NULL;
  80. }
  81. if (rScan.m_pPerformance)
  82. {
  83. rScan.m_pPerformance->Release();
  84. rScan.m_pPerformance = NULL;
  85. }
  86. if (rScan.m_pWave)
  87. {
  88. rScan.m_pWave->Release();
  89. rScan.m_pWave = NULL;
  90. }
  91. WaveItem::st_WaveList.Remove(pScan);
  92. delete pScan;
  93. }
  94. }
  95. LeaveCriticalSection(&WaveItem::st_WaveListCritSect);
  96. return hr;
  97. }
  98. // This SHOULD NOT be called except from a constructor.
  99. void CWavTrack::Construct()
  100. {
  101. InterlockedIncrement(&g_cComponent);
  102. m_fCSInitialized = FALSE;
  103. InitializeCriticalSection(&m_CrSec);
  104. m_fCSInitialized = TRUE;
  105. m_dwPChannelsUsed = 0;
  106. m_aPChannels = NULL;
  107. m_dwTrackFlags = 0;
  108. m_dwValidate = 0;
  109. m_cRef = 1;
  110. m_dwVariation = 0;
  111. m_dwPart = 0;
  112. m_dwIndex = 0;
  113. m_dwLockID = 0;
  114. m_fAudition = FALSE;
  115. m_fAutoDownload = FALSE;
  116. m_fLockAutoDownload = FALSE;
  117. st_RefCount++;
  118. m_pdwVariations = NULL;
  119. m_pdwRemoveVariations = NULL;
  120. m_dwWaveItems = 0;
  121. }
  122. void CWavTrack::CleanUp()
  123. {
  124. m_dwPChannelsUsed = 0;
  125. if (m_aPChannels) delete [] m_aPChannels;
  126. if (m_pdwVariations) delete [] m_pdwVariations;
  127. if (m_pdwRemoveVariations) delete [] m_pdwRemoveVariations;
  128. m_aPChannels = NULL;
  129. m_pdwVariations = NULL;
  130. m_pdwRemoveVariations = NULL;
  131. TListItem<WavePart>* pScan = m_WavePartList.GetHead();
  132. for (; pScan; pScan = pScan->GetNext() )
  133. {
  134. pScan->GetItemValue().CleanUp();
  135. }
  136. m_WavePartList.CleanUp();
  137. RemoveDownloads(NULL);
  138. }
  139. void CWavTrack::CleanUpTempParts()
  140. {
  141. TListItem<WavePart>* pScan = m_TempWavePartList.GetHead();
  142. for (; pScan; pScan = pScan->GetNext() )
  143. {
  144. pScan->GetItemValue().CleanUp();
  145. }
  146. m_TempWavePartList.CleanUp();
  147. }
  148. void CWavTrack::MovePartsToTemp()
  149. {
  150. CleanUpTempParts();
  151. TListItem<WavePart>* pScan = m_WavePartList.RemoveHead();
  152. for (; pScan; pScan = m_WavePartList.RemoveHead() )
  153. {
  154. m_TempWavePartList.AddHead(pScan);
  155. }
  156. }
  157. // NULL for non-streaming waves.
  158. // For streaming waves, return the DownLoadedWave that's associated with the same wave
  159. // with the same start offset (and remove it from the Item list so it's not returned again).
  160. IDirectSoundDownloadedWaveP* CWavTrack::FindDownload(TListItem<WaveItem>* pItem)
  161. {
  162. if (!pItem || !pItem->GetItemValue().m_pWave || !pItem->GetItemValue().m_fIsStreaming)
  163. {
  164. return NULL;
  165. }
  166. WaveItem& rWaveItem = pItem->GetItemValue();
  167. TListItem<WavePart>* pScan = m_TempWavePartList.GetHead();
  168. for (; pScan ; pScan = pScan->GetNext())
  169. {
  170. TListItem<WaveItem>* pItemScan = pScan->GetItemValue().m_WaveItemList.GetHead();
  171. TListItem<WaveItem>* pNext = NULL;
  172. for (; pItemScan; pItemScan = pNext)
  173. {
  174. pNext = pItemScan->GetNext();
  175. WaveItem& rTempItem = pItemScan->GetItemValue();
  176. if (rTempItem.m_fIsStreaming &&
  177. rWaveItem.m_pWave == rTempItem.m_pWave &&
  178. rWaveItem.m_rtStartOffset == rTempItem.m_rtStartOffset)
  179. {
  180. IDirectSoundDownloadedWaveP* pReturn = rTempItem.m_pDownloadedWave;
  181. if (rTempItem.m_pWave)
  182. {
  183. rTempItem.m_pWave->Release();
  184. rTempItem.m_pWave = NULL;
  185. }
  186. rTempItem.m_pDownloadedWave = NULL;
  187. pScan->GetItemValue().m_WaveItemList.Remove(pItemScan);
  188. delete pItemScan;
  189. return pReturn;
  190. }
  191. }
  192. }
  193. return NULL;
  194. }
  195. HRESULT CWavTrack::GetDownload(
  196. IDirectSoundDownloadedWaveP* pWaveDL,
  197. WaveStateData* pStateData,
  198. IDirectMusicPortP* pPortP,
  199. IDirectSoundWave* pWave,
  200. REFERENCE_TIME rtStartOffset,
  201. WaveItem& rItem,
  202. DWORD dwMChannel,
  203. DWORD dwGroup,
  204. IDirectMusicVoiceP **ppVoice)
  205. {
  206. HRESULT hr = S_OK;
  207. TListItem<WaveDLOnPlay>* pNew = NULL;
  208. if (!pWaveDL || !pStateData) return E_POINTER;
  209. IDirectSoundDownloadedWaveP* pNewWaveDL = NULL;
  210. if (rItem.m_fIsStreaming)
  211. {
  212. bool fPair = false;
  213. TListItem<WavePair>* pPair = m_WaveList.GetHead();
  214. for (; pPair; pPair = pPair->GetNext())
  215. {
  216. if (pWaveDL == pPair->GetItemValue().m_pWaveDL)
  217. {
  218. if (!pNewWaveDL)
  219. {
  220. // download a new one (to be returned), and put it in the state data's list.
  221. if (FAILED(hr = pPortP->DownloadWave( pWave, &pNewWaveDL, rtStartOffset )))
  222. {
  223. return hr;
  224. }
  225. pNew = new TListItem<WaveDLOnPlay>;
  226. if (!pNew)
  227. {
  228. pPortP->UnloadWave(pNewWaveDL);
  229. return E_OUTOFMEMORY;
  230. }
  231. pNew->GetItemValue().m_pWaveDL = pNewWaveDL;
  232. pNew->GetItemValue().m_pPort = pPortP;
  233. pPortP->AddRef();
  234. pStateData->m_WaveDLList.AddHead(pNew);
  235. }
  236. if (pStateData == pPair->GetItemValue().m_pStateData)
  237. {
  238. fPair = true;
  239. break;
  240. }
  241. }
  242. }
  243. if (!fPair)
  244. {
  245. // create one and add it to m_WaveList
  246. pPair = new TListItem<WavePair>;
  247. if (!pPair)
  248. {
  249. return E_OUTOFMEMORY;
  250. }
  251. pPair->GetItemValue().m_pStateData = pStateData;
  252. pPair->GetItemValue().m_pWaveDL = pWaveDL;
  253. pWaveDL->AddRef();
  254. m_WaveList.AddHead(pPair);
  255. }
  256. }
  257. if (SUCCEEDED(hr))
  258. {
  259. if (!pNewWaveDL) pNewWaveDL = pWaveDL;
  260. hr = pPortP->AllocVoice(pNewWaveDL,
  261. dwMChannel, dwGroup, rtStartOffset,
  262. rItem.m_dwLoopStart, rItem.m_dwLoopEnd,
  263. ppVoice);
  264. if (SUCCEEDED(hr))
  265. {
  266. if (pNew)
  267. {
  268. pNew->GetItemValue().m_pVoice = *ppVoice;
  269. }
  270. else
  271. {
  272. if (pStateData->m_apVoice[rItem.m_dwVoiceIndex])
  273. {
  274. pStateData->m_apVoice[rItem.m_dwVoiceIndex]->Release();
  275. }
  276. pStateData->m_apVoice[rItem.m_dwVoiceIndex] = *ppVoice;
  277. }
  278. }
  279. }
  280. return hr;
  281. }
  282. void CWavTrack::RemoveDownloads(WaveStateData* pStateData)
  283. {
  284. TListItem<WavePair>* pPair = m_WaveList.GetHead();
  285. TListItem<WavePair>* pNextPair = NULL;
  286. for (; pPair; pPair = pNextPair)
  287. {
  288. pNextPair = pPair->GetNext();
  289. if (!pStateData || pPair->GetItemValue().m_pStateData == pStateData)
  290. {
  291. m_WaveList.Remove(pPair);
  292. delete pPair;
  293. }
  294. }
  295. if (pStateData)
  296. {
  297. TListItem<WaveDLOnPlay>* pWDLOnPlay = NULL;
  298. while (!pStateData->m_WaveDLList.IsEmpty())
  299. {
  300. pWDLOnPlay = pStateData->m_WaveDLList.RemoveHead();
  301. delete pWDLOnPlay;
  302. }
  303. }
  304. }
  305. CWavTrack::CWavTrack()
  306. {
  307. Construct();
  308. }
  309. CWavTrack::CWavTrack(const CWavTrack& rTrack, MUSIC_TIME mtStart, MUSIC_TIME mtEnd)
  310. {
  311. Construct();
  312. CopyParts(rTrack.m_WavePartList, mtStart, mtEnd);
  313. m_lVolume = rTrack.m_lVolume;
  314. m_dwTrackFlags = rTrack.m_dwTrackFlags;
  315. }
  316. HRESULT CWavTrack::InitTrack(DWORD dwPChannels)
  317. {
  318. HRESULT hr = S_OK;
  319. m_dwPChannelsUsed = dwPChannels;
  320. m_dwWaveItems = 0;
  321. if( m_dwPChannelsUsed )
  322. {
  323. m_aPChannels = new DWORD[m_dwPChannelsUsed];
  324. if (!m_aPChannels) hr = E_OUTOFMEMORY;
  325. else if (m_dwTrackFlags & DMUS_WAVETRACKF_PERSIST_CONTROL)
  326. {
  327. m_pdwVariations = new DWORD[m_dwPChannelsUsed];
  328. m_pdwRemoveVariations = new DWORD[m_dwPChannelsUsed];
  329. if (!m_pdwVariations || !m_pdwRemoveVariations) hr = E_OUTOFMEMORY;
  330. }
  331. if (SUCCEEDED(hr))
  332. {
  333. TListItem<WavePart>* pScan = m_WavePartList.GetHead();
  334. for (DWORD dw = 0; pScan && dw < m_dwPChannelsUsed; pScan = pScan->GetNext(), dw++)
  335. {
  336. m_aPChannels[dw] = pScan->GetItemValue().m_dwPChannel;
  337. if (m_pdwVariations) m_pdwVariations[dw] = 0;
  338. if (m_pdwRemoveVariations) m_pdwRemoveVariations[dw] = 0;
  339. TListItem<WaveItem>* pItemScan = pScan->GetItemValue().m_WaveItemList.GetHead();
  340. for (; pItemScan; pItemScan = pItemScan->GetNext())
  341. {
  342. pItemScan->GetItemValue().m_dwVoiceIndex = m_dwWaveItems;
  343. m_dwWaveItems++;
  344. }
  345. }
  346. }
  347. else CleanUp();
  348. }
  349. return hr;
  350. }
  351. CWavTrack::~CWavTrack()
  352. {
  353. if (m_fCSInitialized)
  354. {
  355. CleanUpTempParts();
  356. CleanUp();
  357. st_RefCount--;
  358. if (st_RefCount <= 0)
  359. {
  360. // if there's still something in the wave list, it means there are waves that
  361. // haven't been unloaded; but at this point we've gotten rid of all wave tracks,
  362. // so unload and release everything now.
  363. UnloadAllWaves(NULL);
  364. EnterCriticalSection(&WaveItem::st_WaveListCritSect);
  365. WaveItem::st_WaveList.CleanUp();
  366. LeaveCriticalSection(&WaveItem::st_WaveListCritSect);
  367. }
  368. DeleteCriticalSection(&m_CrSec);
  369. }
  370. InterlockedDecrement(&g_cComponent);
  371. }
  372. // @method:(INTERNAL) HRESULT | IDirectMusicTrack | QueryInterface | Standard QueryInterface implementation for <i IDirectMusicSeqTrack>
  373. //
  374. // @rdesc Returns one of the following:
  375. //
  376. // @flag S_OK | If the interface is supported and was returned
  377. // @flag E_NOINTERFACE | If the object does not support the given interface.
  378. // @flag E_POINTER | <p ppv> is NULL or invalid.
  379. //
  380. STDMETHODIMP CWavTrack::QueryInterface(
  381. const IID &iid, // @parm Interface to query for
  382. void **ppv) // @parm The requested interface will be returned here
  383. {
  384. V_INAME(CWavTrack::QueryInterface);
  385. V_PTRPTR_WRITE(ppv);
  386. V_REFGUID(iid);
  387. if (iid == IID_IUnknown || iid == IID_IDirectMusicTrack || iid == IID_IDirectMusicTrack8)
  388. {
  389. *ppv = static_cast<IDirectMusicTrack*>(this);
  390. }
  391. else if (iid == IID_IPersistStream)
  392. {
  393. *ppv = static_cast<IPersistStream*>(this);
  394. }
  395. else if (iid == IID_IPrivateWaveTrack)
  396. {
  397. *ppv = static_cast<IPrivateWaveTrack*>(this);
  398. }
  399. else
  400. {
  401. *ppv = NULL;
  402. Trace(4,"Warning: Request to query unknown interface on Wave Track\n");
  403. return E_NOINTERFACE;
  404. }
  405. reinterpret_cast<IUnknown*>(this)->AddRef();
  406. return S_OK;
  407. }
  408. // @method:(INTERNAL) HRESULT | IDirectMusicTrack | AddRef | Standard AddRef implementation for <i IDirectMusicSeqTrack>
  409. //
  410. // @rdesc Returns the new reference count for this object.
  411. //
  412. STDMETHODIMP_(ULONG) CWavTrack::AddRef()
  413. {
  414. return InterlockedIncrement(&m_cRef);
  415. }
  416. // @method:(INTERNAL) HRESULT | IDirectMusicTrack | Release | Standard Release implementation for <i IDirectMusicSeqTrack>
  417. //
  418. // @rdesc Returns the new reference count for this object.
  419. //
  420. STDMETHODIMP_(ULONG) CWavTrack::Release()
  421. {
  422. if (!InterlockedDecrement(&m_cRef))
  423. {
  424. delete this;
  425. return 0;
  426. }
  427. return m_cRef;
  428. }
  429. /////////////////////////////////////////////////////////////////////////////
  430. // IPersist
  431. HRESULT CWavTrack::GetClassID( CLSID* pClassID )
  432. {
  433. V_INAME(CSeqTrack::GetClassID);
  434. V_PTR_WRITE(pClassID, CLSID);
  435. *pClassID = CLSID_DirectMusicWaveTrack;
  436. return S_OK;
  437. }
  438. /////////////////////////////////////////////////////////////////////////////
  439. // IPersistStream functions
  440. HRESULT CWavTrack::IsDirty()
  441. {
  442. return S_FALSE;
  443. }
  444. HRESULT CWavTrack::Load( IStream* pIStream )
  445. {
  446. V_INAME(CWavTrack::Load);
  447. V_INTERFACE(pIStream);
  448. DWORD dwSize;
  449. DWORD dwByteCount;
  450. // Verify that the stream pointer is non-null
  451. if( pIStream == NULL )
  452. {
  453. Trace(1,"Error: Null stream passed to wave track.\n");
  454. return E_POINTER;
  455. }
  456. IDMStream* pIRiffStream;
  457. HRESULT hr = E_FAIL;
  458. // Try and allocate a RIFF stream
  459. if( FAILED( hr = AllocDirectMusicStream( pIStream, &pIRiffStream ) ) )
  460. {
  461. return hr;
  462. }
  463. // Variables used when loading the Wave track
  464. MMCKINFO ckTrack;
  465. MMCKINFO ckList;
  466. EnterCriticalSection(&m_CrSec);
  467. m_dwValidate++; // used to validate state data that's out there
  468. MovePartsToTemp();
  469. CleanUp();
  470. // Interate through every chunk in the stream
  471. while( pIRiffStream->Descend( &ckTrack, NULL, 0 ) == S_OK )
  472. {
  473. switch( ckTrack.ckid )
  474. {
  475. case FOURCC_LIST:
  476. switch( ckTrack.fccType )
  477. {
  478. case DMUS_FOURCC_WAVETRACK_LIST:
  479. while( pIRiffStream->Descend( &ckList, &ckTrack, 0 ) == S_OK )
  480. {
  481. switch( ckList.ckid )
  482. {
  483. case DMUS_FOURCC_WAVETRACK_CHUNK:
  484. {
  485. DMUS_IO_WAVE_TRACK_HEADER iTrackHeader;
  486. // Read in the item's header structure
  487. dwSize = min( sizeof( DMUS_IO_WAVE_TRACK_HEADER ), ckList.cksize );
  488. hr = pIStream->Read( &iTrackHeader, dwSize, &dwByteCount );
  489. // Handle any I/O error by returning a failure code
  490. if( FAILED( hr ) || dwByteCount != dwSize )
  491. {
  492. if (SUCCEEDED(hr)) hr = DMUS_E_CANNOTREAD;
  493. goto ON_ERROR;
  494. }
  495. m_lVolume = iTrackHeader.lVolume;
  496. m_dwTrackFlags = iTrackHeader.dwFlags;
  497. break;
  498. }
  499. case FOURCC_LIST:
  500. switch( ckList.fccType )
  501. {
  502. case DMUS_FOURCC_WAVEPART_LIST:
  503. {
  504. TListItem<WavePart>* pNewPart = new TListItem<WavePart>;
  505. if( !pNewPart )
  506. {
  507. hr = E_OUTOFMEMORY;
  508. goto ON_ERROR;
  509. }
  510. hr = pNewPart->GetItemValue().Load( pIRiffStream, &ckList );
  511. if( FAILED ( hr ) )
  512. {
  513. delete pNewPart;
  514. goto ON_ERROR;
  515. }
  516. InsertByAscendingPChannel( pNewPart );
  517. break;
  518. }
  519. }
  520. break;
  521. }
  522. pIRiffStream->Ascend( &ckList, 0 );
  523. }
  524. break;
  525. }
  526. break;
  527. }
  528. pIRiffStream->Ascend( &ckTrack, 0 );
  529. }
  530. hr = InitTrack(m_WavePartList.GetCount());
  531. if (SUCCEEDED(hr))
  532. {
  533. TListItem<WavePart>* pScan = m_WavePartList.GetHead();
  534. for (; pScan ; pScan = pScan->GetNext())
  535. {
  536. TListItem<WaveItem>* pItemScan = pScan->GetItemValue().m_WaveItemList.GetHead();
  537. for (; pItemScan; pItemScan = pItemScan->GetNext())
  538. {
  539. pItemScan->GetItemValue().m_pDownloadedWave = FindDownload(pItemScan);
  540. }
  541. }
  542. }
  543. else CleanUp();
  544. ON_ERROR:
  545. CleanUpTempParts();
  546. LeaveCriticalSection(&m_CrSec);
  547. pIRiffStream->Release();
  548. return hr;
  549. }
  550. HRESULT CWavTrack::CopyParts( const TList<WavePart>& rParts, MUSIC_TIME mtStart, MUSIC_TIME mtEnd )
  551. {
  552. HRESULT hr = S_OK;
  553. CleanUp();
  554. TListItem<WavePart>* pScan = rParts.GetHead();
  555. for (; pScan; pScan = pScan->GetNext() )
  556. {
  557. WavePart& rScan = pScan->GetItemValue();
  558. TListItem<WavePart>* pNew = new TListItem<WavePart>;
  559. if (pNew)
  560. {
  561. WavePart& rNew = pNew->GetItemValue();
  562. rNew.m_dwLockToPart = rScan.m_dwLockToPart;
  563. rNew.m_dwPChannel = rScan.m_dwPChannel;
  564. rNew.m_dwIndex = rScan.m_dwIndex;
  565. rNew.m_dwPChannelFlags = rScan.m_dwPChannelFlags;
  566. rNew.m_lVolume = rScan.m_lVolume;
  567. rNew.m_dwVariations = rScan.m_dwVariations;
  568. if (SUCCEEDED(hr = rNew.CopyItems(rScan.m_WaveItemList, mtStart, mtEnd)))
  569. {
  570. m_WavePartList.AddHead(pNew);
  571. }
  572. else
  573. {
  574. delete pNew;
  575. break;
  576. }
  577. }
  578. else
  579. {
  580. hr = E_OUTOFMEMORY;
  581. break;
  582. }
  583. }
  584. if (SUCCEEDED(hr))
  585. {
  586. m_WavePartList.Reverse();
  587. }
  588. else
  589. {
  590. CleanUp();
  591. }
  592. return hr;
  593. }
  594. void CWavTrack::InsertByAscendingPChannel( TListItem<WavePart>* pPart )
  595. {
  596. if (pPart)
  597. {
  598. DWORD dwPChannel = pPart->GetItemValue().m_dwPChannel;
  599. TListItem<WavePart>* pScan = m_WavePartList.GetHead();
  600. TListItem<WavePart>* pPrevious = NULL;
  601. for (; pScan; pScan = pScan->GetNext())
  602. {
  603. if (dwPChannel < pScan->GetItemValue().m_dwPChannel)
  604. {
  605. break;
  606. }
  607. pPrevious = pScan;
  608. }
  609. if (pPrevious)
  610. {
  611. pPart->SetNext(pScan);
  612. pPrevious->SetNext(pPart);
  613. }
  614. else
  615. {
  616. m_WavePartList.AddHead(pPart);
  617. }
  618. }
  619. }
  620. HRESULT CWavTrack::Save( IStream* pIStream, BOOL fClearDirty )
  621. {
  622. return E_NOTIMPL;
  623. }
  624. HRESULT CWavTrack::GetSizeMax( ULARGE_INTEGER FAR* pcbSize )
  625. {
  626. return E_NOTIMPL;
  627. }
  628. // IDirectMusicTrack
  629. /*
  630. @method HRESULT | IDirectMusicTrack | IsParamSupported |
  631. Check to see if the Track supports data types in <om .GetParam> and <om .SetParam>.
  632. @rvalue S_OK | It does support the type of data.
  633. @rvalue S_FALSE | It does not support the type of data.
  634. @rvalue E_NOTIMPL | (Or any other failure code) It does not support the type of data.
  635. @comm Note that it is valid for a Track to return different results for the same
  636. guid depending on its current state.
  637. */
  638. HRESULT STDMETHODCALLTYPE CWavTrack::IsParamSupported(
  639. REFGUID rguidType) // @parm The guid identifying the type of data to check.
  640. {
  641. if(rguidType == GUID_Download ||
  642. rguidType == GUID_DownloadToAudioPath ||
  643. rguidType == GUID_UnloadFromAudioPath ||
  644. rguidType == GUID_Enable_Auto_Download ||
  645. rguidType == GUID_Disable_Auto_Download ||
  646. rguidType == GUID_Unload )
  647. {
  648. return S_OK;
  649. }
  650. else
  651. {
  652. return DMUS_E_TYPE_UNSUPPORTED;
  653. }
  654. }
  655. //////////////////////////////////////////////////////////////////////
  656. // IDirectMusicTrack::Init
  657. /*
  658. @method HRESULT | IDirectMusicTrack | Init |
  659. When a track is first added to a <i IDirectMusicSegment>, this method is called
  660. by that Segment.
  661. @rvalue S_OK | Success.
  662. @rvalue E_POINTER | <p pSegment> is NULL or invalid.
  663. @comm If the Track plays messages, it should call <om IDirectMusicSegment.SetPChannelsUsed>.
  664. */
  665. HRESULT CWavTrack::Init(
  666. IDirectMusicSegment *pSegment) // @parm Pointer to the Segment to which this Track belongs.
  667. {
  668. EnterCriticalSection(&m_CrSec);
  669. if( m_dwPChannelsUsed && m_aPChannels )
  670. {
  671. pSegment->SetPChannelsUsed( m_dwPChannelsUsed, m_aPChannels );
  672. }
  673. CSegment* pCSegment = NULL;
  674. bool fSortLogical = false;
  675. if (SUCCEEDED(pSegment->QueryInterface(IID_CSegment, (void**)&pCSegment)))
  676. {
  677. DWORD dwGroupBits = 0;
  678. if (FAILED(pSegment->GetTrackGroup( this, &dwGroupBits )))
  679. {
  680. dwGroupBits = 0xffffffff;
  681. }
  682. DWORD dwConfig = 0;
  683. if (SUCCEEDED(pCSegment->GetTrackConfig(CLSID_DirectMusicWaveTrack, dwGroupBits, 0, &dwConfig)))
  684. {
  685. if ( !(dwConfig & DMUS_TRACKCONFIG_PLAY_CLOCKTIME) )
  686. {
  687. fSortLogical = true;
  688. }
  689. }
  690. pCSegment->Release();
  691. }
  692. TListItem<WavePart>* pScan = m_WavePartList.GetHead();
  693. for (; pScan; pScan = pScan->GetNext())
  694. {
  695. if (fSortLogical)
  696. {
  697. pScan->GetItemValue().m_WaveItemList.MergeSort(LogicalLess);
  698. }
  699. else
  700. {
  701. pScan->GetItemValue().m_WaveItemList.MergeSort(PhysicalLess);
  702. }
  703. }
  704. LeaveCriticalSection(&m_CrSec);
  705. return S_OK;
  706. }
  707. /*
  708. @method HRESULT | IDirectMusicTrack | InitPlay |
  709. This method is called when a Segment is ready to start playing. The <p ppStateData> field
  710. may return a pointer to a structure of state data, which is sent into <om .Play> and
  711. <om .EndPlay>, and allows the Track to keep track of variables on a <i SegmentState> by
  712. <i SegmentState> basis.
  713. @rvalue S_OK | Success. This is the only valid return value from this method.
  714. @rvalue E_POINTER | <p pSegmentState>, <p pPerf>, or <p ppStateData> is NULL or
  715. invalid.
  716. @comm Note that it is unneccessary for the Track to store the <p pSegmentState>, <p pPerf>,
  717. or <p dwTrackID> parameters, since they are also sent into <om .Play>.
  718. */
  719. HRESULT CWavTrack::InitPlay(
  720. IDirectMusicSegmentState *pSegmentState, // @parm The calling <i IDirectMusicSegmentState> pointer.
  721. IDirectMusicPerformance *pPerf, // @parm The calling <i IDirectMusicPerformance> pointer.
  722. void **ppStateData, // @parm This method can return state data information here.
  723. DWORD dwTrackID, // @parm The virtual track ID assigned to this Track instance.
  724. DWORD dwFlags) // @parm Same flags that were set with the call
  725. // to PlaySegment. These are passed all the way down to the tracks, who may want to know
  726. // if the track was played as a primary, controlling, or secondary segment.
  727. {
  728. V_INAME(IDirectMusicTrack::InitPlay);
  729. V_PTRPTR_WRITE(ppStateData);
  730. V_INTERFACE(pSegmentState);
  731. V_INTERFACE(pPerf);
  732. HRESULT hr = E_OUTOFMEMORY;
  733. IDirectMusicSegmentState8 *pSegSt8 = NULL;
  734. EnterCriticalSection(&m_CrSec);
  735. WaveStateData* pStateData = new WaveStateData;
  736. if( NULL == pStateData )
  737. {
  738. goto ON_END;
  739. }
  740. // Get the audiopath being used by our segment state and save it in our state data.
  741. hr = pSegmentState->QueryInterface(IID_IDirectMusicSegmentState8, reinterpret_cast<void**>(&pSegSt8));
  742. if (SUCCEEDED(hr))
  743. {
  744. hr = pSegSt8->GetObjectInPath(
  745. 0, // pchannel doesn't apply
  746. DMUS_PATH_AUDIOPATH, // get the audiopath
  747. 0, // buffer index doesn't apply
  748. CLSID_NULL, // clsid doesn't apply
  749. 0, // there should be only one audiopath
  750. IID_IDirectMusicAudioPath,
  751. reinterpret_cast<void**>(&pStateData->m_pAudioPath));
  752. // If this doesn't find an audiopath that's OK. If we're not playing on an audiopath then
  753. // pAudioPath stays NULL and we'll play our triggered segments on the general performance.
  754. if (hr == DMUS_E_NOT_FOUND)
  755. hr = S_OK;
  756. pSegSt8->Release();
  757. }
  758. pStateData->m_pPerformance = pPerf;
  759. {
  760. *ppStateData = pStateData;
  761. StatePair SP(pSegmentState, pStateData);
  762. TListItem<StatePair>* pPair = new TListItem<StatePair>(SP);
  763. if (!pPair)
  764. {
  765. goto ON_END;
  766. }
  767. m_StateList.AddHead(pPair);
  768. }
  769. SetUpStateCurrentPointers(pStateData);
  770. // Set up arrays for variations
  771. if (m_dwPChannelsUsed)
  772. {
  773. pStateData->pdwVariations = new DWORD[m_dwPChannelsUsed];
  774. if (!pStateData->pdwVariations)
  775. {
  776. goto ON_END;
  777. }
  778. pStateData->pdwRemoveVariations = new DWORD[m_dwPChannelsUsed];
  779. if (!pStateData->pdwRemoveVariations)
  780. {
  781. goto ON_END;
  782. }
  783. for (DWORD dw = 0; dw < m_dwPChannelsUsed; dw++)
  784. {
  785. if ( (m_dwTrackFlags & DMUS_WAVETRACKF_PERSIST_CONTROL) &&
  786. m_pdwVariations &&
  787. m_pdwRemoveVariations )
  788. {
  789. pStateData->pdwVariations[dw] = m_pdwVariations[dw];
  790. pStateData->pdwRemoveVariations[dw] = m_pdwRemoveVariations[dw];
  791. }
  792. else
  793. {
  794. pStateData->pdwVariations[dw] = 0;
  795. pStateData->pdwRemoveVariations[dw] = 0;
  796. }
  797. }
  798. }
  799. // need to know the group this track is in, for the mute track GetParam
  800. IDirectMusicSegment* pSegment;
  801. if( SUCCEEDED( pSegmentState->GetSegment(&pSegment)))
  802. {
  803. pSegment->GetTrackGroup( this, &pStateData->dwGroupBits );
  804. pSegment->Release();
  805. }
  806. // for auditioning variations...
  807. pStateData->InitVariationInfo(m_dwVariation, m_dwPart, m_dwIndex, m_dwLockID, m_fAudition);
  808. hr = S_OK;
  809. BOOL fGlobal; // if the performance has been set with an autodownload preference,
  810. // use that. otherwise, assume autodownloading is off, unless it has
  811. // been locked (i.e. specified on the band track.)
  812. if( SUCCEEDED( pPerf->GetGlobalParam( GUID_PerfAutoDownload, &fGlobal, sizeof(BOOL) )))
  813. {
  814. if( !m_fLockAutoDownload )
  815. {
  816. // it might seem like we can just assign m_fAutoDownload = fGlobal,
  817. // but that's bitten markburt before, so I'm being paranoid today.
  818. if( fGlobal )
  819. {
  820. m_fAutoDownload = TRUE;
  821. }
  822. else
  823. {
  824. m_fAutoDownload = FALSE;
  825. }
  826. }
  827. }
  828. else if( !m_fLockAutoDownload )
  829. {
  830. m_fAutoDownload = FALSE;
  831. }
  832. // Call SetParam to download all waves used by the track
  833. // This is the auto-download feature that can be turned off with a call to SetParam
  834. if(m_fAutoDownload)
  835. {
  836. hr = SetParam(GUID_Download, 0, (void *)pPerf);
  837. if (FAILED(hr)) goto ON_END;
  838. }
  839. ///////////////// pre-allocate voices for all waves in the track ////////////////
  840. pStateData->m_dwVoices = m_dwWaveItems;
  841. pStateData->m_apVoice = new IDirectMusicVoiceP*[m_dwWaveItems];
  842. if (!pStateData->m_apVoice)
  843. {
  844. hr = E_OUTOFMEMORY;
  845. }
  846. else
  847. {
  848. for (DWORD dw = 0; dw < m_dwWaveItems; dw++)
  849. {
  850. pStateData->m_apVoice[dw] = NULL;
  851. }
  852. Seek( pSegmentState, pPerf, dwTrackID, pStateData, 0, TRUE, 0, FALSE );
  853. TListItem<WavePart>* pPart = m_WavePartList.GetHead();
  854. DWORD dwPChannel = 0;
  855. for( DWORD dwIndex = 0; dwIndex < m_dwPChannelsUsed; dwIndex++ )
  856. {
  857. long lPartVolume = 0;
  858. if( pPart )
  859. {
  860. WavePart& rPart = pPart->GetItemValue();
  861. dwPChannel = rPart.m_dwPChannel;
  862. lPartVolume = rPart.m_lVolume;
  863. }
  864. if( pStateData->apCurrentWave )
  865. {
  866. for( ; pStateData->apCurrentWave[dwIndex];
  867. pStateData->apCurrentWave[dwIndex] = pStateData->apCurrentWave[dwIndex]->GetNext() )
  868. {
  869. WaveItem& rItem = pStateData->apCurrentWave[dwIndex]->GetItemValue();
  870. DWORD dwGroup = 0;
  871. DWORD dwMChannel = 0;
  872. IDirectMusicPort* pPort = NULL;
  873. hr = rItem.PChannelInfo(pPerf, pStateData->m_pAudioPath, dwPChannel, &pPort, &dwGroup, &dwMChannel);
  874. if (SUCCEEDED(hr) && pPort)
  875. {
  876. IDirectMusicPortP* pPortP = NULL;
  877. if (SUCCEEDED(hr = pPort->QueryInterface(IID_IDirectMusicPortP, (void**) &pPortP)))
  878. {
  879. EnterCriticalSection(&WaveItem::st_WaveListCritSect);
  880. TListItem<TaggedWave>* pDLWave = rItem.st_WaveList.GetHead();
  881. for (; pDLWave; pDLWave = pDLWave->GetNext())
  882. {
  883. TaggedWave& rDLWave = pDLWave->GetItemValue();
  884. if (rDLWave.m_pWave == rItem.m_pWave &&
  885. rDLWave.m_pPerformance == pPerf &&
  886. rDLWave.m_pPort == pPortP &&
  887. ( !rItem.m_fIsStreaming ||
  888. rDLWave.m_pDownloadedWave == rItem.m_pDownloadedWave ) )
  889. {
  890. break;
  891. }
  892. }
  893. if (pDLWave)
  894. {
  895. TaggedWave& rDLWave = pDLWave->GetItemValue();
  896. REFERENCE_TIME rtStartOffset = rItem.m_rtStartOffset;
  897. if (rItem.m_dwVoiceIndex == 0xffffffff)
  898. {
  899. hr = DMUS_E_NOT_INIT;
  900. TraceI(0, "Voice index not initialized!\n");
  901. }
  902. else if(!rItem.m_fIsStreaming || (rItem.m_fIsStreaming && rItem.m_fUseNoPreRoll == FALSE))
  903. {
  904. IDirectMusicVoiceP *pVoice = NULL;
  905. hr = GetDownload(
  906. rDLWave.m_pDownloadedWave,
  907. pStateData,
  908. pPortP,
  909. rDLWave.m_pWave,
  910. rtStartOffset,
  911. rItem,
  912. dwMChannel, dwGroup,
  913. &pVoice);
  914. }
  915. }
  916. else
  917. {
  918. hr = DMUS_E_NOT_INIT;
  919. Trace(1, "Error: Attempt to play wave that has not been downloaded.\n");
  920. }
  921. LeaveCriticalSection(&WaveItem::st_WaveListCritSect);
  922. // Release the private interface
  923. pPortP->Release();
  924. }
  925. pPort->Release();
  926. }
  927. else if (SUCCEEDED(hr) && !pPort)
  928. {
  929. Trace(1, "Error: the performance was unable to find a port for voice allocation.\n");
  930. hr = DMUS_E_NOT_FOUND;
  931. }
  932. }
  933. }
  934. if( pPart )
  935. {
  936. pPart = pPart->GetNext();
  937. }
  938. }
  939. }
  940. ON_END:
  941. if (FAILED(hr) && pStateData)
  942. {
  943. delete pStateData;
  944. pStateData = NULL;
  945. }
  946. LeaveCriticalSection(&m_CrSec);
  947. return hr;
  948. }
  949. /*
  950. @method HRESULT | IDirectMusicTrack | EndPlay |
  951. This method is called when the <i IDirectMusicSegmentState> object that originally called
  952. <om .InitPlay> is destroyed.
  953. @rvalue S_OK | Success.
  954. @rvalue E_POINTER | <p pStateData> is invalid.
  955. @comm The return code isn't used, but S_OK is preferred.
  956. */
  957. HRESULT CWavTrack::EndPlay(
  958. void *pStateData) // @parm The state data returned from <om .InitPlay>.
  959. {
  960. EnterCriticalSection(&m_CrSec);
  961. ASSERT( pStateData );
  962. if( pStateData )
  963. {
  964. V_INAME(IDirectMusicTrack::EndPlay);
  965. V_BUFPTR_WRITE(pStateData, sizeof(WaveStateData));
  966. WaveStateData* pSD = (WaveStateData*)pStateData;
  967. RemoveDownloads(pSD);
  968. if(m_fAutoDownload)
  969. {
  970. SetParam(GUID_Unload, 0, (void *)pSD->m_pPerformance);
  971. }
  972. for (TListItem<StatePair>* pScan = m_StateList.GetHead(); pScan; pScan = pScan->GetNext())
  973. {
  974. StatePair& rPair = pScan->GetItemValue();
  975. if (pSD == rPair.m_pStateData)
  976. {
  977. rPair.m_pSegState = NULL;
  978. rPair.m_pStateData = NULL;
  979. break;
  980. }
  981. }
  982. delete pSD;
  983. }
  984. LeaveCriticalSection(&m_CrSec);
  985. return S_OK;
  986. }
  987. void CWavTrack::SetUpStateCurrentPointers(WaveStateData* pStateData)
  988. {
  989. ASSERT(pStateData);
  990. pStateData->dwPChannelsUsed = m_dwPChannelsUsed;
  991. if( m_dwPChannelsUsed )
  992. {
  993. if( pStateData->apCurrentWave )
  994. {
  995. delete [] pStateData->apCurrentWave;
  996. pStateData->apCurrentWave = NULL;
  997. }
  998. pStateData->apCurrentWave = new TListItem<WaveItem>* [m_dwPChannelsUsed];
  999. if( pStateData->apCurrentWave )
  1000. {
  1001. memset( pStateData->apCurrentWave, 0, sizeof(TListItem<WavePart>*) * m_dwPChannelsUsed );
  1002. }
  1003. }
  1004. pStateData->dwValidate = m_dwValidate;
  1005. }
  1006. REFERENCE_TIME ConvertOffset(REFERENCE_TIME rtOffset, long lPitch)
  1007. {
  1008. if (lPitch)
  1009. {
  1010. double dblPitch = (double) lPitch;
  1011. double dblStart = (double) rtOffset;
  1012. dblStart *= pow(2, (dblPitch / 1200.0));
  1013. rtOffset = (REFERENCE_TIME) dblStart;
  1014. }
  1015. return rtOffset;
  1016. }
  1017. STDMETHODIMP CWavTrack::PlayEx(void* pStateData,REFERENCE_TIME rtStart,
  1018. REFERENCE_TIME rtEnd,REFERENCE_TIME rtOffset,
  1019. DWORD dwFlags,IDirectMusicPerformance* pPerf,
  1020. IDirectMusicSegmentState* pSegSt,DWORD dwVirtualID)
  1021. {
  1022. V_INAME(IDirectMusicTrack::PlayEx);
  1023. V_BUFPTR_WRITE( pStateData, sizeof(WaveStateData));
  1024. V_INTERFACE(pPerf);
  1025. V_INTERFACE(pSegSt);
  1026. HRESULT hr;
  1027. EnterCriticalSection(&m_CrSec);
  1028. BOOL fClock = (dwFlags & DMUS_TRACKF_CLOCK) ? TRUE : FALSE;
  1029. /* if (dwFlags & DMUS_TRACKF_CLOCK)
  1030. {
  1031. hr = Play(pStateData,(MUSIC_TIME)(rtStart / REF_PER_MIL),(MUSIC_TIME)(rtEnd / REF_PER_MIL),
  1032. (MUSIC_TIME)(rtOffset / REF_PER_MIL),rtOffset,dwFlags,pPerf,pSegSt,dwVirtualID,TRUE);
  1033. }
  1034. else*/
  1035. {
  1036. hr = Play(pStateData, rtStart, rtEnd, rtOffset, dwFlags, pPerf, pSegSt, dwVirtualID, fClock);
  1037. }
  1038. LeaveCriticalSection(&m_CrSec);
  1039. return hr;
  1040. }
  1041. /*
  1042. @enum DMUS_TRACKF_FLAGS | Sent in <om IDirectMusicTrack.Play>'s dwFlags parameter.
  1043. @emem DMUS_TRACKF_SEEK | Play was called on account of seeking, meaning that mtStart is
  1044. not necessarily the same as the previous Play call's mtEnd.
  1045. @emem DMUS_TRACKF_LOOP | Play was called on account of a loop, e.g. repeat.
  1046. @emem DMUS_TRACKF_START | This is the first call to Play. DMUS_TRACKF_SEEK may also be set if the
  1047. Track is not playing from the beginning.
  1048. @emem DMUS_TRACKF_FLUSH | The call to Play is on account of a flush or invalidate, that
  1049. requires the Track to replay something it played previously. In this case, DMUS_TRACKF_SEEK
  1050. will be set as well.
  1051. @method HRESULT | IDirectMusicTrack | Play |
  1052. Play method.
  1053. @rvalue DMUS_DMUS_S_END | The Track is done playing.
  1054. @rvalue S_OK | Success.
  1055. @rvalue E_POINTER | <p pStateData>, <p pPerf>, or <p pSegSt> is NULL or invalid.
  1056. */
  1057. STDMETHODIMP CWavTrack::Play(
  1058. void *pStateData, // @parm State data pointer, from <om .InitPlay>.
  1059. MUSIC_TIME mtStart, // @parm The start time to play.
  1060. MUSIC_TIME mtEnd, // @parm The end time to play.
  1061. MUSIC_TIME mtOffset,// @parm The offset to add to all messages sent to
  1062. // <om IDirectMusicPerformance.SendPMsg>.
  1063. DWORD dwFlags, // @parm Flags that indicate the state of this call.
  1064. // See <t DMUS_TRACKF_FLAGS>. If dwFlags == 0, this is a
  1065. // normal Play call continuing playback from the previous
  1066. // Play call.
  1067. IDirectMusicPerformance* pPerf, // @parm The <i IDirectMusicPerformance>, used to
  1068. // call <om IDirectMusicPerformance.AllocPMsg>,
  1069. // <om IDirectMusicPerformance.SendPMsg>, etc.
  1070. IDirectMusicSegmentState* pSegSt, // @parm The <i IDirectMusicSegmentState> this
  1071. // track belongs to. QueryInterface() can be called on this to
  1072. // obtain the SegmentState's <i IDirectMusicGraph> in order to
  1073. // call <om IDirectMusicGraph.StampPMsg>, for instance.
  1074. DWORD dwVirtualID // @parm This track's virtual track id, which must be set
  1075. // on any <t DMUS_PMSG>'s m_dwVirtualTrackID member that
  1076. // will be queued to <om IDirectMusicPerformance.SendPMsg>.
  1077. )
  1078. {
  1079. V_INAME(IDirectMusicTrack::Play);
  1080. V_BUFPTR_WRITE( pStateData, sizeof(WaveStateData));
  1081. V_INTERFACE(pPerf);
  1082. V_INTERFACE(pSegSt);
  1083. EnterCriticalSection(&m_CrSec);
  1084. HRESULT hr = Play(pStateData, mtStart, mtEnd, mtOffset, dwFlags, pPerf, pSegSt, dwVirtualID, FALSE);
  1085. LeaveCriticalSection(&m_CrSec);
  1086. return hr;
  1087. }
  1088. /* The Play method handles both music time and clock time versions, as determined by
  1089. fClockTime. If running in clock time, rtOffset is used to identify the start time
  1090. of the segment. Otherwise, mtOffset. The mtStart and mtEnd parameters are in MUSIC_TIME units
  1091. or milliseconds, depending on which mode.
  1092. */
  1093. // BUGBUG go through all the times and make sure music time/reference time stuff
  1094. // all makes sense
  1095. HRESULT CWavTrack::Play(
  1096. void *pStateData,
  1097. REFERENCE_TIME rtStart,
  1098. REFERENCE_TIME rtEnd,
  1099. //MUSIC_TIME mtOffset,
  1100. REFERENCE_TIME rtOffset,
  1101. DWORD dwFlags,
  1102. IDirectMusicPerformance* pPerf,
  1103. IDirectMusicSegmentState* pSegSt,
  1104. DWORD dwVirtualID,
  1105. BOOL fClockTime)
  1106. {
  1107. if (dwFlags & DMUS_TRACKF_PLAY_OFF)
  1108. {
  1109. return S_OK;
  1110. }
  1111. HRESULT hr = S_OK;
  1112. IDirectMusicGraph* pGraph = NULL;
  1113. WaveStateData* pSD = (WaveStateData*)pStateData;
  1114. if ( dwFlags & DMUS_TRACKF_LOOP )
  1115. {
  1116. REFERENCE_TIME rtPerfStart = rtStart + rtOffset;
  1117. MUSIC_TIME mtPerfStart = 0;
  1118. if (fClockTime)
  1119. {
  1120. pPerf->ReferenceToMusicTime(rtPerfStart, &mtPerfStart);
  1121. }
  1122. else
  1123. {
  1124. mtPerfStart = (MUSIC_TIME)rtPerfStart;
  1125. }
  1126. CPerformance* pCPerf = NULL;
  1127. if (SUCCEEDED(pPerf->QueryInterface(IID_CPerformance, (void**)&pCPerf)))
  1128. {
  1129. pCPerf->FlushVirtualTrack(dwVirtualID, mtPerfStart, FALSE);
  1130. pCPerf->Release();
  1131. }
  1132. pSD->m_fLoop = true;
  1133. }
  1134. BOOL fSeek = (dwFlags & DMUS_TRACKF_SEEK) ? TRUE : FALSE;
  1135. if ( dwFlags & (DMUS_TRACKF_START | DMUS_TRACKF_LOOP) )
  1136. {
  1137. pSD->rtNextVariation = 0;
  1138. }
  1139. // if we're sync'ing variations to the pattern track, get the current variations
  1140. if ( (m_dwTrackFlags & DMUS_WAVETRACKF_SYNC_VAR) &&
  1141. (!pSD->rtNextVariation || (rtStart <= pSD->rtNextVariation && rtEnd > pSD->rtNextVariation)) )
  1142. {
  1143. hr = SyncVariations(pPerf, pSD, rtStart, rtOffset, fClockTime);
  1144. }
  1145. else if (dwFlags & (DMUS_TRACKF_START | DMUS_TRACKF_LOOP))
  1146. {
  1147. hr = ComputeVariations(pSD);
  1148. }
  1149. if( dwFlags & (DMUS_TRACKF_SEEK | DMUS_TRACKF_FLUSH | DMUS_TRACKF_DIRTY |
  1150. DMUS_TRACKF_LOOP) )
  1151. {
  1152. // need to reset the PChannel Map in case of any of these flags.
  1153. m_PChMap.Reset();
  1154. }
  1155. if( pSD->dwValidate != m_dwValidate )
  1156. {
  1157. if (pSD->m_apVoice)
  1158. {
  1159. for (DWORD dw = 0; dw < pSD->m_dwVoices; dw++)
  1160. {
  1161. if (pSD->m_apVoice[dw])
  1162. {
  1163. pSD->m_apVoice[dw]->Release();
  1164. }
  1165. }
  1166. delete [] pSD->m_apVoice;
  1167. }
  1168. pSD->m_apVoice = new IDirectMusicVoiceP*[m_dwWaveItems];
  1169. if (!pSD->m_apVoice)
  1170. {
  1171. return E_OUTOFMEMORY;
  1172. }
  1173. else
  1174. {
  1175. for (DWORD dw = 0; dw < m_dwWaveItems; dw++)
  1176. {
  1177. pSD->m_apVoice[dw] = NULL;
  1178. }
  1179. }
  1180. pSD->m_dwVoices = m_dwWaveItems;
  1181. SetUpStateCurrentPointers(pSD);
  1182. fSeek = TRUE;
  1183. }
  1184. if( fSeek )
  1185. {
  1186. if( dwFlags & (DMUS_TRACKF_START | DMUS_TRACKF_LOOP) )
  1187. {
  1188. Seek( pSegSt, pPerf, dwVirtualID, pSD, rtStart, TRUE, rtOffset, fClockTime );
  1189. }
  1190. else
  1191. {
  1192. Seek( pSegSt, pPerf, dwVirtualID, pSD, rtStart, FALSE, rtOffset, fClockTime );
  1193. }
  1194. }
  1195. if( FAILED( pSegSt->QueryInterface( IID_IDirectMusicGraph,
  1196. (void**)&pGraph )))
  1197. {
  1198. pGraph = NULL;
  1199. }
  1200. DWORD dwIndex;
  1201. DWORD dwPChannel;
  1202. DWORD dwMutePChannel;
  1203. BOOL fMute;
  1204. TListItem<WavePart>* pPart = m_WavePartList.GetHead();
  1205. for( dwIndex = 0; dwIndex < m_dwPChannelsUsed; dwIndex++ )
  1206. {
  1207. long lPartVolume = 0;
  1208. if( pPart )
  1209. {
  1210. WavePart& rPart = pPart->GetItemValue();
  1211. dwPChannel = rPart.m_dwPChannel;
  1212. lPartVolume = rPart.m_lVolume;
  1213. }
  1214. if( pSD->apCurrentWave )
  1215. {
  1216. for( ; pSD->apCurrentWave[dwIndex];
  1217. pSD->apCurrentWave[dwIndex] = pSD->apCurrentWave[dwIndex]->GetNext() )
  1218. {
  1219. DWORD dwItemVariations = 0;
  1220. WaveItem& rItem = pSD->apCurrentWave[dwIndex]->GetItemValue();
  1221. REFERENCE_TIME rtTime = fClockTime ? rItem.m_rtTimePhysical : rItem.m_mtTimeLogical;
  1222. if( rtTime >= rtEnd )
  1223. {
  1224. break;
  1225. }
  1226. if (pPart)
  1227. {
  1228. dwItemVariations = pSD->Variations(pPart->GetItemValue(), dwIndex) & rItem.m_dwVariations;
  1229. }
  1230. MUSIC_TIME mtTime = 0;
  1231. MUSIC_TIME mtOffset = 0;
  1232. if (fClockTime)
  1233. {
  1234. MUSIC_TIME mtPerfTime = 0;
  1235. pPerf->ReferenceToMusicTime(rtOffset, &mtOffset);
  1236. pPerf->ReferenceToMusicTime(rItem.m_rtTimePhysical + rtOffset, &mtPerfTime);
  1237. mtTime = mtPerfTime - mtOffset;
  1238. }
  1239. else
  1240. {
  1241. mtTime = rItem.m_mtTimeLogical;
  1242. mtOffset = (MUSIC_TIME)rtOffset;
  1243. }
  1244. m_PChMap.GetInfo( dwPChannel, mtTime, mtOffset, pSD->dwGroupBits,
  1245. pPerf, &fMute, &dwMutePChannel, FALSE );
  1246. if( !fMute && dwItemVariations )
  1247. {
  1248. DWORD dwGroup = 0;
  1249. DWORD dwMChannel = 0;
  1250. IDirectMusicPort* pPort = NULL;
  1251. hr = rItem.PChannelInfo(pPerf, pSD->m_pAudioPath, dwMutePChannel, &pPort, &dwGroup, &dwMChannel);
  1252. if (SUCCEEDED(hr) && pPort)
  1253. {
  1254. IDirectMusicPortP* pPortP = NULL;
  1255. hr = pPort->QueryInterface(IID_IDirectMusicPortP, (void**) &pPortP);
  1256. if (SUCCEEDED(hr))
  1257. {
  1258. EnterCriticalSection(&WaveItem::st_WaveListCritSect);
  1259. TListItem<TaggedWave>* pDLWave = rItem.st_WaveList.GetHead();
  1260. for (; pDLWave; pDLWave = pDLWave->GetNext())
  1261. {
  1262. TaggedWave& rDLWave = pDLWave->GetItemValue();
  1263. if (rDLWave.m_pWave == rItem.m_pWave &&
  1264. rDLWave.m_pPerformance == pPerf &&
  1265. rDLWave.m_pPort == pPortP &&
  1266. ( !rItem.m_fIsStreaming ||
  1267. rDLWave.m_pDownloadedWave == rItem.m_pDownloadedWave ) )
  1268. {
  1269. break;
  1270. }
  1271. }
  1272. if (pDLWave)
  1273. {
  1274. REFERENCE_TIME rtDurationMs = 0;
  1275. REFERENCE_TIME rtStartOffset = rItem.m_rtStartOffset;
  1276. REFERENCE_TIME rtDuration = rItem.m_rtDuration;
  1277. DMUS_WAVE_PMSG* pWave;
  1278. if( SUCCEEDED( pPerf->AllocPMsg( sizeof(DMUS_WAVE_PMSG),
  1279. (DMUS_PMSG**)&pWave )))
  1280. {
  1281. pWave->dwType = DMUS_PMSGT_WAVE;
  1282. pWave->dwPChannel = dwMutePChannel;
  1283. pWave->dwVirtualTrackID = dwVirtualID;
  1284. pWave->dwGroupID = pSD->dwGroupBits;
  1285. if (fClockTime)
  1286. {
  1287. REFERENCE_TIME rtPlay = rItem.m_rtTimePhysical;
  1288. rtDuration -= ConvertOffset(rtStartOffset, -rItem.m_lPitch);
  1289. if (rtPlay < rtStart)
  1290. {
  1291. REFERENCE_TIME rtPlayOffset = ConvertOffset(rtStart - rtPlay, rItem.m_lPitch);
  1292. rtStartOffset += rtPlayOffset;
  1293. rtDuration -= (rtStart - rtPlay);
  1294. rtPlay = rtStart;
  1295. }
  1296. pWave->rtTime = rtPlay + rtOffset;
  1297. pWave->dwFlags = DMUS_PMSGF_REFTIME | DMUS_PMSGF_LOCKTOREFTIME;
  1298. pWave->lOffset = 0;
  1299. rtDurationMs = rtDuration / REF_PER_MIL;
  1300. }
  1301. else
  1302. {
  1303. REFERENCE_TIME rtPlay = 0;
  1304. MUSIC_TIME mtPlay = (MUSIC_TIME)rItem.m_rtTimePhysical;
  1305. pPerf->MusicToReferenceTime(mtPlay + (MUSIC_TIME)rtOffset, &rtPlay);
  1306. MUSIC_TIME mtRealPlay = 0;
  1307. pPerf->ReferenceToMusicTime(rtPlay + rtStartOffset, &mtRealPlay);
  1308. if (mtRealPlay > rtOffset + mtPlay)
  1309. {
  1310. rtDuration -= ConvertOffset(mtRealPlay - (rtOffset + mtPlay), -rItem.m_lPitch);
  1311. }
  1312. if (mtPlay < (MUSIC_TIME) rtStart)
  1313. {
  1314. // Calculate distance from wave start to segment start, but begin
  1315. // the calculation at segment start to avoid strangeness
  1316. // when attempting to do conversions at times earlier than
  1317. // segment start.
  1318. REFERENCE_TIME rtRefStartPlus = 0;
  1319. REFERENCE_TIME rtRefPlayPlus = 0;
  1320. MUSIC_TIME mtNewDuration = 0;
  1321. pPerf->MusicToReferenceTime((MUSIC_TIME)rtStart + (MUSIC_TIME)rtStart + (MUSIC_TIME)rtOffset, &rtRefStartPlus);
  1322. pPerf->MusicToReferenceTime((MUSIC_TIME)rtStart + mtPlay + (MUSIC_TIME)rtOffset, &rtRefPlayPlus);
  1323. rtStartOffset += ConvertOffset((rtRefStartPlus - rtRefPlayPlus), rItem.m_lPitch);
  1324. mtPlay = (MUSIC_TIME) rtStart;
  1325. REFERENCE_TIME rtRealDuration = 0;
  1326. pPerf->MusicToReferenceTime((MUSIC_TIME)rtStart + (MUSIC_TIME)rItem.m_rtDuration + (MUSIC_TIME)rtOffset, &rtRealDuration);
  1327. pPerf->ReferenceToMusicTime(rtRealDuration - (ConvertOffset(rItem.m_rtStartOffset, -rItem.m_lPitch) + (rtRefStartPlus - rtRefPlayPlus)), &mtNewDuration);
  1328. rtDuration = (REFERENCE_TIME)mtNewDuration - (rtStart + rtOffset);
  1329. }
  1330. pWave->mtTime = mtPlay + (MUSIC_TIME)rtOffset;
  1331. pWave->dwFlags = DMUS_PMSGF_MUSICTIME;
  1332. pWave->lOffset = (MUSIC_TIME)rItem.m_rtTimePhysical - rItem.m_mtTimeLogical;
  1333. REFERENCE_TIME rtZero = 0;
  1334. pPerf->MusicToReferenceTime((MUSIC_TIME)rtOffset + mtPlay, &rtZero);
  1335. pPerf->MusicToReferenceTime((MUSIC_TIME)(rtDuration + rtOffset) + mtPlay, &rtDurationMs);
  1336. rtDurationMs -= rtZero;
  1337. rtDurationMs /= REF_PER_MIL;
  1338. }
  1339. // If we're either past the end of the wave, or we're within
  1340. // 150 ms of the end of a looping wave (and we've just started
  1341. // playback), don't play the wave.
  1342. if ( rtDurationMs <= 0 ||
  1343. (rItem.m_dwLoopEnd && (dwFlags & DMUS_TRACKF_START) && rtDurationMs < 150) )
  1344. {
  1345. pPerf->FreePMsg((DMUS_PMSG*)pWave);
  1346. }
  1347. else
  1348. {
  1349. pWave->rtStartOffset = rtStartOffset;
  1350. pWave->rtDuration = rtDuration;
  1351. pWave->lVolume = rItem.m_lVolume + lPartVolume + m_lVolume;
  1352. pWave->lPitch = rItem.m_lPitch;
  1353. pWave->bFlags = (BYTE)(rItem.m_dwFlags & 0xff);
  1354. IDirectMusicVoiceP *pVoice = NULL;
  1355. if (rItem.m_dwVoiceIndex == 0xffffffff)
  1356. {
  1357. hr = DMUS_E_NOT_INIT;
  1358. TraceI(0, "Voice index not initialized!\n");
  1359. }
  1360. else
  1361. {
  1362. if ( pSD->m_fLoop ||
  1363. !pSD->m_apVoice[rItem.m_dwVoiceIndex] ||
  1364. rtStartOffset != rItem.m_rtStartOffset ||
  1365. dwMutePChannel != dwPChannel)
  1366. {
  1367. hr = GetDownload(
  1368. pDLWave->GetItemValue().m_pDownloadedWave,
  1369. pSD,
  1370. pPortP,
  1371. pDLWave->GetItemValue().m_pWave,
  1372. pWave->rtStartOffset,
  1373. rItem,
  1374. dwMChannel, dwGroup,
  1375. &pVoice);
  1376. }
  1377. else
  1378. {
  1379. pVoice = pSD->m_apVoice[rItem.m_dwVoiceIndex];
  1380. }
  1381. }
  1382. if (SUCCEEDED(hr))
  1383. {
  1384. pWave->punkUser = (IUnknown*)pVoice;
  1385. pVoice->AddRef();
  1386. if( pGraph )
  1387. {
  1388. pGraph->StampPMsg( (DMUS_PMSG*)pWave );
  1389. }
  1390. hr = pPerf->SendPMsg( (DMUS_PMSG*)pWave );
  1391. }
  1392. if(FAILED(hr))
  1393. {
  1394. pPerf->FreePMsg((DMUS_PMSG*)pWave);
  1395. }
  1396. }
  1397. }
  1398. }
  1399. LeaveCriticalSection(&WaveItem::st_WaveListCritSect);
  1400. pPortP->Release();
  1401. }
  1402. pPort->Release();
  1403. }
  1404. else if (SUCCEEDED(hr) && !pPort)
  1405. {
  1406. Trace(1, "Error: the performance was unable to find a port for voice allocation.\n");
  1407. hr = DMUS_E_NOT_FOUND;
  1408. }
  1409. }
  1410. }
  1411. }
  1412. if( pPart )
  1413. {
  1414. pPart = pPart->GetNext();
  1415. }
  1416. }
  1417. if( pGraph )
  1418. {
  1419. pGraph->Release();
  1420. }
  1421. return hr;
  1422. }
  1423. // Seek() - set all pSD's pointers to the correct location. If fGetPrevious is set,
  1424. // it's legal to start in the middle of a wave.
  1425. HRESULT CWavTrack::Seek( IDirectMusicSegmentState* pSegSt,
  1426. IDirectMusicPerformance* pPerf, DWORD dwVirtualID,
  1427. WaveStateData* pSD, REFERENCE_TIME rtTime, BOOL fGetPrevious,
  1428. REFERENCE_TIME rtOffset, BOOL fClockTime)
  1429. {
  1430. DWORD dwIndex;
  1431. TListItem<WavePart>* pPart;
  1432. TListItem<WaveItem>* pWaveItem;
  1433. // in the case of fGetPrevious (which means DMUS_SEGF_START/LOOP was
  1434. // set in Play() ) we want to reset all lists to the beginning regardless of time.
  1435. if( fGetPrevious )//&& ( rtTime == 0 ) )
  1436. {
  1437. pPart = m_WavePartList.GetHead();
  1438. for( dwIndex = 0; dwIndex < m_dwPChannelsUsed; dwIndex++ )
  1439. {
  1440. if( pPart )
  1441. {
  1442. pWaveItem = pPart->GetItemValue().m_WaveItemList.GetHead();
  1443. if( pWaveItem && pSD->apCurrentWave )
  1444. {
  1445. pSD->apCurrentWave[dwIndex] = pWaveItem;
  1446. }
  1447. pPart = pPart->GetNext();
  1448. }
  1449. else
  1450. {
  1451. break;
  1452. }
  1453. }
  1454. return S_OK;
  1455. }
  1456. pPart = m_WavePartList.GetHead();
  1457. for( dwIndex = 0; dwIndex < m_dwPChannelsUsed; dwIndex++ )
  1458. {
  1459. if( pPart )
  1460. {
  1461. // scan the wave event list in this part.
  1462. for( pWaveItem = pPart->GetItemValue().m_WaveItemList.GetHead(); pWaveItem; pWaveItem = pWaveItem->GetNext() )
  1463. {
  1464. WaveItem& rWaveItem = pWaveItem->GetItemValue();
  1465. REFERENCE_TIME rtWaveTime = fClockTime ? rWaveItem.m_rtTimePhysical : rWaveItem.m_mtTimeLogical;
  1466. if( rtWaveTime >= rtTime )
  1467. {
  1468. break;
  1469. }
  1470. if( !fGetPrevious )
  1471. {
  1472. // if we don't care about previous events, just continue
  1473. continue;
  1474. }
  1475. }
  1476. if( pSD->apCurrentWave )
  1477. {
  1478. pSD->apCurrentWave[dwIndex] = pWaveItem;
  1479. }
  1480. pPart = pPart->GetNext();
  1481. }
  1482. }
  1483. return S_OK;
  1484. }
  1485. /*
  1486. @method HRESULT | IDirectMusicTrack | GetParam |
  1487. Retrieves data from a Track.
  1488. @rvalue S_OK | Got the data ok.
  1489. @rvalue E_NOTIMPL | Not implemented.
  1490. */
  1491. STDMETHODIMP CWavTrack::GetParam(
  1492. REFGUID rguidType, // @parm The type of data to obtain.
  1493. MUSIC_TIME mtTime, // @parm The time, in Track time, to obtain the data.
  1494. MUSIC_TIME* pmtNext,// @parm Returns the Track time until which the data is valid. <p pmtNext>
  1495. // may be NULL. If this returns a value of 0, it means that this
  1496. // data will either be always valid, or it is unknown when it will
  1497. // become invalid.
  1498. void *pData) // @parm The struture in which to return the data. Each
  1499. // <p pGuidType> identifies a particular structure of a
  1500. // particular size. It is important that this field contain
  1501. // the correct structure of the correct size. Otherwise,
  1502. // fatal results can occur.
  1503. {
  1504. return E_NOTIMPL;
  1505. }
  1506. /*
  1507. @method HRESULT | IDirectMusicTrack | SetParam |
  1508. Sets data on a Track.
  1509. @rvalue S_OK | Set the data ok.
  1510. @rvalue E_NOTIMPL | Not implemented.
  1511. */
  1512. STDMETHODIMP CWavTrack::SetParam(
  1513. REFGUID rguidType, // @parm The type of data to set.
  1514. MUSIC_TIME mtTime, // @parm The time, in Track time, to set the data.
  1515. void *pData) // @parm The struture containing the data to set. Each
  1516. // <p pGuidType> identifies a particular structure of a
  1517. // particular size. It is important that this field contain
  1518. // the correct structure of the correct size. Otherwise,
  1519. // fatal results can occur.
  1520. {
  1521. return SetParamEx(rguidType, mtTime, pData, NULL, 0);
  1522. }
  1523. STDMETHODIMP CWavTrack::GetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime,
  1524. REFERENCE_TIME* prtNext,void* pParam,void * pStateData, DWORD dwFlags)
  1525. {
  1526. return E_NOTIMPL;
  1527. }
  1528. STDMETHODIMP CWavTrack::SetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime,
  1529. void* pParam, void * pStateData, DWORD dwFlags)
  1530. {
  1531. V_INAME(CBandTrk::SetParamEx);
  1532. V_REFGUID(rguidType);
  1533. HRESULT hr = S_OK;
  1534. if((pParam == NULL) &&
  1535. (rguidType != GUID_Enable_Auto_Download) &&
  1536. (rguidType != GUID_Disable_Auto_Download))
  1537. {
  1538. return E_POINTER;
  1539. }
  1540. EnterCriticalSection(&m_CrSec);
  1541. if(rguidType == GUID_Download)
  1542. {
  1543. IDirectMusicPerformance* pPerf = (IDirectMusicPerformance*)pParam;
  1544. V_INTERFACE(pPerf);
  1545. HRESULT hrFail = S_OK;
  1546. DWORD dwSuccess = 0;
  1547. TListItem<WavePart>* pPart = m_WavePartList.GetHead();
  1548. for(; pPart; pPart = pPart->GetNext())
  1549. {
  1550. if ( FAILED(hr = pPart->GetItemValue().Download(pPerf, NULL, NULL, GUID_NULL)) )
  1551. {
  1552. hrFail = hr;
  1553. }
  1554. else
  1555. {
  1556. dwSuccess++;
  1557. }
  1558. }
  1559. // If we had a failure, return it if we had no successes.
  1560. // Else return S_FALSE for partial success.
  1561. if (FAILED(hrFail) && dwSuccess)
  1562. {
  1563. Trace(1,"Error: Wavetrack download was only partially successful. Some sounds will not play.\n");
  1564. hr = S_FALSE;
  1565. }
  1566. #ifdef DBG
  1567. if (FAILED(hr))
  1568. {
  1569. Trace(1, "Error: Wavetrack failed download.\n");
  1570. }
  1571. #endif
  1572. }
  1573. else if(rguidType == GUID_DownloadToAudioPath)
  1574. {
  1575. IUnknown* pUnknown = (IUnknown*)pParam;
  1576. V_INTERFACE(pUnknown);
  1577. HRESULT hrFail = S_OK;
  1578. DWORD dwSuccess = 0;
  1579. IDirectMusicAudioPath* pPath = NULL;
  1580. IDirectMusicPerformance *pPerf = NULL;
  1581. hr = pUnknown->QueryInterface(IID_IDirectMusicAudioPath,(void **)&pPath);
  1582. if (SUCCEEDED(hr))
  1583. {
  1584. hr = pPath->GetObjectInPath(0,DMUS_PATH_PERFORMANCE,0,CLSID_DirectMusicPerformance,0,IID_IDirectMusicPerformance,(void **)&pPerf);
  1585. }
  1586. else
  1587. {
  1588. hr = pUnknown->QueryInterface(IID_IDirectMusicPerformance,(void **)&pPerf);
  1589. }
  1590. if (SUCCEEDED(hr))
  1591. {
  1592. TListItem<WavePart>* pPart = m_WavePartList.GetHead();
  1593. for(; pPart; pPart = pPart->GetNext())
  1594. {
  1595. if ( FAILED(hr = pPart->GetItemValue().Download(pPerf, pPath, NULL, GUID_NULL)) )
  1596. {
  1597. hrFail = hr;
  1598. }
  1599. else
  1600. {
  1601. dwSuccess++;
  1602. }
  1603. }
  1604. }
  1605. // If we had a failure, return it if we had no successes.
  1606. // Else return S_FALSE for partial success.
  1607. if (FAILED(hrFail) && dwSuccess)
  1608. {
  1609. Trace(1,"Error: Wavetrack download was only partially successful. Some sounds will not play.\n");
  1610. hr = S_FALSE;
  1611. }
  1612. #ifdef DBG
  1613. if (FAILED(hr))
  1614. {
  1615. Trace(1, "Error: Wavetrack failed download.\n");
  1616. }
  1617. #endif
  1618. if (pPath) pPath->Release();
  1619. if (pPerf) pPerf->Release();
  1620. }
  1621. else if(rguidType == GUID_Unload)
  1622. {
  1623. IDirectMusicPerformance* pPerf = (IDirectMusicPerformance*)pParam;
  1624. V_INTERFACE(pPerf);
  1625. TListItem<WavePart>* pPart = m_WavePartList.GetHead();
  1626. for(; pPart; pPart = pPart->GetNext())
  1627. {
  1628. pPart->GetItemValue().Unload(pPerf, NULL, NULL);
  1629. }
  1630. }
  1631. else if(rguidType == GUID_UnloadFromAudioPath)
  1632. {
  1633. IUnknown* pUnknown = (IUnknown*)pParam;
  1634. V_INTERFACE(pUnknown);
  1635. IDirectMusicAudioPath* pPath = NULL;
  1636. IDirectMusicPerformance *pPerf = NULL;
  1637. hr = pUnknown->QueryInterface(IID_IDirectMusicAudioPath,(void **)&pPath);
  1638. if (SUCCEEDED(hr))
  1639. {
  1640. hr = pPath->GetObjectInPath(0,DMUS_PATH_PERFORMANCE,0,CLSID_DirectMusicPerformance,0,IID_IDirectMusicPerformance,(void **)&pPerf);
  1641. }
  1642. else
  1643. {
  1644. hr = pUnknown->QueryInterface(IID_IDirectMusicPerformance,(void **)&pPerf);
  1645. }
  1646. if (SUCCEEDED(hr))
  1647. {
  1648. TListItem<WavePart>* pPart = m_WavePartList.GetHead();
  1649. for(; pPart; pPart = pPart->GetNext())
  1650. {
  1651. pPart->GetItemValue().Unload(pPerf, pPath, NULL);
  1652. }
  1653. }
  1654. if (pPath) pPath->Release();
  1655. if (pPerf) pPerf->Release();
  1656. }
  1657. else if(rguidType == GUID_Enable_Auto_Download)
  1658. {
  1659. m_fAutoDownload = TRUE;
  1660. m_fLockAutoDownload = TRUE;
  1661. }
  1662. else if(rguidType == GUID_Disable_Auto_Download)
  1663. {
  1664. m_fAutoDownload = FALSE;
  1665. m_fLockAutoDownload = TRUE;
  1666. }
  1667. else
  1668. {
  1669. hr = DMUS_E_TYPE_UNSUPPORTED;
  1670. }
  1671. LeaveCriticalSection(&m_CrSec);
  1672. return hr;
  1673. }
  1674. /*
  1675. @method HRESULT | IDirectMusicTrack | AddNotificationType |
  1676. Similar to and called from <om IDirectMusicSegment.AddNotificationType>. This
  1677. gives the track a chance to respond to notifications.
  1678. @rvalue E_NOTIMPL | The track doesn't support notifications.
  1679. @rvalue S_OK | Success.
  1680. @rvalue S_FALSE | The track doesn't support the requested notification type.
  1681. */
  1682. HRESULT STDMETHODCALLTYPE CWavTrack::AddNotificationType(
  1683. REFGUID rguidNotification) // @parm The notification guid to add.
  1684. {
  1685. return E_NOTIMPL;
  1686. }
  1687. /*
  1688. @method HRESULT | IDirectMusicTrack | RemoveNotificationType |
  1689. Similar to and called from <om IDirectMusicSegment.RemoveNotificationType>. This
  1690. gives the track a chance to remove notifications.
  1691. @rvalue E_NOTIMPL | The track doesn't support notifications.
  1692. @rvalue S_OK | Success.
  1693. @rvalue S_FALSE | The track doesn't support the requested notification type.
  1694. */
  1695. HRESULT STDMETHODCALLTYPE CWavTrack::RemoveNotificationType(
  1696. REFGUID rguidNotification) // @parm The notification guid to remove.
  1697. {
  1698. return E_NOTIMPL;
  1699. }
  1700. /*
  1701. @method HRESULT | IDirectMusicTrack | Clone |
  1702. Creates a copy of the Track.
  1703. @rvalue S_OK | Success.
  1704. @rvalue E_OUTOFMEMORY | Out of memory.
  1705. @rvalue E_POINTER | <p ppTrack> is NULL or invalid.
  1706. @xref <om IDirectMusicSegment.Clone>
  1707. */
  1708. HRESULT STDMETHODCALLTYPE CWavTrack::Clone(
  1709. MUSIC_TIME mtStart, // @parm The start of the part to clone. It should be 0 or greater,
  1710. // and less than the length of the Track.
  1711. MUSIC_TIME mtEnd, // @parm The end of the part to clone. It should be greater than
  1712. // <p mtStart> and less than the length of the Track.
  1713. IDirectMusicTrack** ppTrack) // @parm Returns the cloned Track.
  1714. {
  1715. V_INAME(IDirectMusicTrack::Clone);
  1716. V_PTRPTR_WRITE(ppTrack);
  1717. HRESULT hr = S_OK;
  1718. if((mtStart < 0 )||(mtStart > mtEnd))
  1719. {
  1720. Trace(1,"Error: Wave track clone failed because of invalid start or end time.\n");
  1721. return E_INVALIDARG;
  1722. }
  1723. EnterCriticalSection(&m_CrSec);
  1724. CWavTrack *pDM;
  1725. try
  1726. {
  1727. pDM = new CWavTrack(*this, mtStart, mtEnd);
  1728. }
  1729. catch( ... )
  1730. {
  1731. pDM = NULL;
  1732. }
  1733. if (pDM == NULL)
  1734. {
  1735. hr = E_OUTOFMEMORY;
  1736. }
  1737. else
  1738. {
  1739. hr = pDM->InitTrack(m_dwPChannelsUsed);
  1740. if (SUCCEEDED(hr))
  1741. {
  1742. hr = pDM->QueryInterface(IID_IDirectMusicTrack, (void**)ppTrack);
  1743. }
  1744. pDM->Release();
  1745. }
  1746. LeaveCriticalSection(&m_CrSec);
  1747. return hr;
  1748. }
  1749. STDMETHODIMP CWavTrack::Compose(
  1750. IUnknown* pContext,
  1751. DWORD dwTrackGroup,
  1752. IDirectMusicTrack** ppResultTrack)
  1753. {
  1754. return E_NOTIMPL;
  1755. }
  1756. STDMETHODIMP CWavTrack::Join(
  1757. IDirectMusicTrack* pNewTrack,
  1758. MUSIC_TIME mtJoin,
  1759. IUnknown* pContext,
  1760. DWORD dwTrackGroup,
  1761. IDirectMusicTrack** ppResultTrack)
  1762. {
  1763. return E_NOTIMPL;
  1764. }
  1765. HRESULT CWavTrack::ComputeVariations(WaveStateData* pSD)
  1766. {
  1767. if (!pSD)
  1768. {
  1769. Trace(1,"Error: Unable to play wave track - not initialized.\n");
  1770. return DMUS_E_NOT_INIT;
  1771. }
  1772. HRESULT hr = S_OK;
  1773. // First, initialize the array of variation groups.
  1774. for (int i = 0; i < MAX_WAVE_VARIATION_LOCKS; i++)
  1775. {
  1776. pSD->adwVariationGroups[i] = 0;
  1777. }
  1778. // Now, compute the variations for each part.
  1779. TListItem<WavePart>* pScan = m_WavePartList.GetHead();
  1780. for (i = 0; pScan && i < (int)m_dwPChannelsUsed; pScan = pScan->GetNext(), i++)
  1781. {
  1782. hr = ComputeVariation(i, pScan->GetItemValue(), pSD);
  1783. if (FAILED(hr))
  1784. {
  1785. break;
  1786. }
  1787. }
  1788. return hr;
  1789. }
  1790. HRESULT CWavTrack::SyncVariations(IDirectMusicPerformance* pPerf,
  1791. WaveStateData* pSD,
  1792. REFERENCE_TIME rtStart,
  1793. REFERENCE_TIME rtOffset,
  1794. BOOL fClockTime)
  1795. {
  1796. if (!pSD)
  1797. {
  1798. Trace(1,"Error: Unable to play wave track - not initialized.\n");
  1799. return DMUS_E_NOT_INIT;
  1800. }
  1801. HRESULT hr = S_OK;
  1802. // Get the current variations
  1803. DMUS_VARIATIONS_PARAM Variations;
  1804. memset(&Variations, 0, sizeof(Variations));
  1805. // Call GetParam for variations to sync to
  1806. MUSIC_TIME mtNow = 0;
  1807. MUSIC_TIME mtNext = 0;
  1808. REFERENCE_TIME rtNext = 0;
  1809. if (fClockTime)
  1810. {
  1811. pPerf->ReferenceToMusicTime(pSD->rtNextVariation + rtOffset, &mtNow);
  1812. hr = pPerf->GetParam(GUID_Variations, 0xffffffff, DMUS_SEG_ANYTRACK, mtNow, &mtNext, (void*) &Variations);
  1813. if (SUCCEEDED(hr) &&
  1814. SUCCEEDED(pPerf->MusicToReferenceTime(mtNext + mtNow, &rtNext)) )
  1815. {
  1816. pSD->rtNextVariation += rtNext;
  1817. }
  1818. }
  1819. else
  1820. {
  1821. mtNow = (MUSIC_TIME) (pSD->rtNextVariation + rtOffset);
  1822. hr = pPerf->GetParam(GUID_Variations, 0xffffffff, DMUS_SEG_ANYTRACK, mtNow, &mtNext, (void*) &Variations);
  1823. if (SUCCEEDED(hr))
  1824. {
  1825. pSD->rtNextVariation += mtNext;
  1826. }
  1827. }
  1828. if (SUCCEEDED(hr))
  1829. {
  1830. // Initialize the array of variation groups.
  1831. for (int nGroup = 0; nGroup < MAX_WAVE_VARIATION_LOCKS; nGroup++)
  1832. {
  1833. pSD->adwVariationGroups[nGroup] = 0;
  1834. }
  1835. TListItem<WavePart>* pScan = m_WavePartList.GetHead();
  1836. for (DWORD dwPart = 0; pScan && dwPart < m_dwPChannelsUsed; pScan = pScan->GetNext(), dwPart++)
  1837. {
  1838. WavePart& rPart = pScan->GetItemValue();
  1839. for (DWORD dwSyncPart = 0; dwSyncPart < Variations.dwPChannelsUsed; dwSyncPart++)
  1840. {
  1841. if (rPart.m_dwPChannel == Variations.padwPChannels[dwSyncPart])
  1842. {
  1843. pSD->pdwVariations[dwPart] = Variations.padwVariations[dwSyncPart];
  1844. break;
  1845. }
  1846. }
  1847. if (dwSyncPart == Variations.dwPChannelsUsed) // no part to sync to
  1848. {
  1849. hr = ComputeVariation((int)dwPart, rPart, pSD);
  1850. if (FAILED(hr))
  1851. {
  1852. break;
  1853. }
  1854. }
  1855. }
  1856. }
  1857. else
  1858. {
  1859. return ComputeVariations(pSD);
  1860. }
  1861. return hr;
  1862. }
  1863. HRESULT CWavTrack::ComputeVariation(int nPart, WavePart& rWavePart, WaveStateData* pSD)
  1864. {
  1865. BYTE bLockID = (BYTE)rWavePart.m_dwLockToPart;
  1866. if (bLockID && pSD->adwVariationGroups[bLockID - 1] != 0)
  1867. {
  1868. pSD->pdwVariations[nPart] = pSD->adwVariationGroups[bLockID - 1];
  1869. }
  1870. else if (!rWavePart.m_dwVariations)
  1871. {
  1872. // No variations; clear the flags for this part.
  1873. pSD->pdwVariations[nPart] = 0;
  1874. pSD->pdwRemoveVariations[nPart] = 0;
  1875. }
  1876. else
  1877. {
  1878. // First, collect all matches.
  1879. DWORD dwMatches = rWavePart.m_dwVariations;
  1880. int nMatchCount = 0;
  1881. for (int n = 0; n < 32; n++)
  1882. {
  1883. if (dwMatches & (1 << n)) nMatchCount++;
  1884. }
  1885. // Now, select a variation based on the part's variation mode.
  1886. BYTE bMode = (BYTE)(rWavePart.m_dwPChannelFlags & 0xf);
  1887. DWORD dwTemp = dwMatches;
  1888. if ( bMode == DMUS_VARIATIONT_RANDOM_ROW )
  1889. {
  1890. dwTemp &= ~pSD->pdwRemoveVariations[nPart];
  1891. if (!dwTemp)
  1892. {
  1893. // start counting all over, but don't repeat this one
  1894. pSD->pdwRemoveVariations[nPart] = 0;
  1895. dwTemp = dwMatches;
  1896. bMode = DMUS_VARIATIONT_NO_REPEAT;
  1897. }
  1898. }
  1899. if ( bMode == DMUS_VARIATIONT_NO_REPEAT && pSD->pdwVariations[nPart] != 0 )
  1900. {
  1901. dwTemp &= ~pSD->pdwVariations[nPart];
  1902. }
  1903. if (dwTemp != dwMatches)
  1904. {
  1905. if (dwTemp) // otherwise, keep what we had
  1906. {
  1907. for (int i = 0; i < 32; i++)
  1908. {
  1909. if ( ((1 << i) & dwMatches) && !((1 << i) & dwTemp) )
  1910. {
  1911. nMatchCount--;
  1912. }
  1913. }
  1914. dwMatches = dwTemp;
  1915. }
  1916. }
  1917. int nV = 0;
  1918. switch (bMode)
  1919. {
  1920. case DMUS_VARIATIONT_RANDOM_ROW:
  1921. case DMUS_VARIATIONT_NO_REPEAT:
  1922. case DMUS_VARIATIONT_RANDOM:
  1923. {
  1924. short nChoice = (short) (rand() % nMatchCount);
  1925. short nCount = 0;
  1926. for (nV = 0; nV < 32; nV++)
  1927. {
  1928. if ((1 << nV) & dwMatches)
  1929. {
  1930. if (nChoice == nCount)
  1931. break;
  1932. nCount++;
  1933. }
  1934. }
  1935. pSD->pdwVariations[nPart] = 1 << nV;
  1936. if (bMode == DMUS_VARIATIONT_RANDOM_ROW)
  1937. {
  1938. pSD->pdwRemoveVariations[nPart] |= pSD->pdwVariations[nPart];
  1939. }
  1940. TraceI(3, "New variation: %d\n", nV);
  1941. break;
  1942. }
  1943. case DMUS_VARIATIONT_RANDOM_START:
  1944. // Choose an initial value
  1945. if (pSD->pdwVariations[nPart] == 0)
  1946. {
  1947. int nStart = 0;
  1948. nStart = (BYTE) (rand() % nMatchCount);
  1949. int nCount = 0;
  1950. for (nV = 0; nV < 32; nV++)
  1951. {
  1952. if ((1 << nV) & dwMatches)
  1953. {
  1954. if (nStart == nCount)
  1955. break;
  1956. nCount++;
  1957. }
  1958. }
  1959. pSD->pdwVariations[nPart] = 1 << nV;
  1960. }
  1961. // Now, go directly to the sequential case (no break)
  1962. case DMUS_VARIATIONT_SEQUENTIAL:
  1963. {
  1964. if (!pSD->pdwVariations[nPart]) pSD->pdwVariations[nPart] = 1;
  1965. else
  1966. {
  1967. pSD->pdwVariations[nPart] <<= 1;
  1968. if (!pSD->pdwVariations[nPart]) pSD->pdwVariations[nPart] = 1;
  1969. }
  1970. while (!(pSD->pdwVariations[nPart] & dwMatches))
  1971. {
  1972. pSD->pdwVariations[nPart] <<= 1;
  1973. if (!pSD->pdwVariations[nPart]) pSD->pdwVariations[nPart] = 1;
  1974. }
  1975. TraceI(3, "New variation: %d\n", pSD->pdwVariations[nPart]);
  1976. break;
  1977. }
  1978. }
  1979. // If this is a locked variation, it's the first in its group, so record it.
  1980. if (bLockID)
  1981. {
  1982. pSD->adwVariationGroups[bLockID - 1] = pSD->pdwVariations[nPart];
  1983. }
  1984. if ( (m_dwTrackFlags & DMUS_WAVETRACKF_PERSIST_CONTROL) &&
  1985. m_pdwVariations &&
  1986. m_pdwRemoveVariations )
  1987. {
  1988. m_pdwVariations[nPart] = pSD->pdwVariations[nPart];
  1989. m_pdwRemoveVariations[nPart] = pSD->pdwRemoveVariations[nPart];
  1990. }
  1991. }
  1992. return S_OK;
  1993. }
  1994. // Sets the variations to be played for a part. All other parts use the MOAW
  1995. // to determine which variation plays.
  1996. HRESULT CWavTrack::SetVariation(
  1997. IDirectMusicSegmentState* pSegState, DWORD dwVariationFlags, DWORD dwPart, DWORD dwIndex)
  1998. {
  1999. WaveStateData* pState = NULL;
  2000. EnterCriticalSection( &m_CrSec );
  2001. m_dwVariation = dwVariationFlags;
  2002. m_dwPart = dwPart;
  2003. m_dwIndex = dwIndex;
  2004. m_fAudition = TRUE;
  2005. TListItem<WavePart>* pScan = m_WavePartList.GetHead();
  2006. for (; pScan; pScan = pScan->GetNext() )
  2007. {
  2008. WavePart& rScan = pScan->GetItemValue();
  2009. if (rScan.m_dwPChannel == dwPart && rScan.m_dwIndex == dwIndex)
  2010. {
  2011. m_dwLockID = rScan.m_dwLockToPart;
  2012. }
  2013. }
  2014. pState = FindState(pSegState);
  2015. if (pState)
  2016. {
  2017. pState->InitVariationInfo(dwVariationFlags, dwPart, dwIndex, m_dwLockID, m_fAudition);
  2018. }
  2019. LeaveCriticalSection( &m_CrSec );
  2020. return S_OK;
  2021. }
  2022. // Clears the variations to be played for a part, so that all parts use the MOAW.
  2023. HRESULT CWavTrack::ClearVariations(IDirectMusicSegmentState* pSegState)
  2024. {
  2025. WaveStateData* pState = NULL;
  2026. EnterCriticalSection( &m_CrSec );
  2027. m_dwVariation = 0;
  2028. m_dwPart = 0;
  2029. m_dwIndex = 0;
  2030. m_dwLockID = 0;
  2031. m_fAudition = FALSE;
  2032. pState = FindState(pSegState);
  2033. if (pState)
  2034. {
  2035. pState->InitVariationInfo(0, 0, 0, 0, m_fAudition);
  2036. }
  2037. LeaveCriticalSection( &m_CrSec );
  2038. return S_OK;
  2039. }
  2040. WaveStateData* CWavTrack::FindState(IDirectMusicSegmentState* pSegState)
  2041. {
  2042. TListItem<StatePair>* pPair = m_StateList.GetHead();
  2043. for (; pPair; pPair = pPair->GetNext())
  2044. {
  2045. if (pPair->GetItemValue().m_pSegState == pSegState)
  2046. {
  2047. return pPair->GetItemValue().m_pStateData;
  2048. }
  2049. }
  2050. return NULL;
  2051. }
  2052. // Adds a wave at mtTime to part dwIndex on PChannel dwPChannel
  2053. // If there was already a wave there, the two will co-exist
  2054. HRESULT CWavTrack::AddWave(
  2055. IDirectSoundWave* pWave,
  2056. REFERENCE_TIME rtTime,
  2057. DWORD dwPChannel,
  2058. DWORD dwIndex,
  2059. REFERENCE_TIME* prtLength)
  2060. {
  2061. EnterCriticalSection(&m_CrSec);
  2062. HRESULT hr = S_OK;
  2063. m_lVolume = 0;
  2064. m_dwTrackFlags = 0;
  2065. TListItem<WavePart>* pNewPart = new TListItem<WavePart>;
  2066. if( !pNewPart )
  2067. {
  2068. hr = E_OUTOFMEMORY;
  2069. goto ON_ERROR;
  2070. }
  2071. hr = pNewPart->GetItemValue().Add(pWave, rtTime, dwPChannel, dwIndex, prtLength);
  2072. if( FAILED ( hr ) )
  2073. {
  2074. delete pNewPart;
  2075. goto ON_ERROR;
  2076. }
  2077. InsertByAscendingPChannel( pNewPart );
  2078. m_dwWaveItems = 0;
  2079. m_dwPChannelsUsed = m_WavePartList.GetCount();
  2080. if (m_aPChannels)
  2081. {
  2082. delete [] m_aPChannels;
  2083. m_aPChannels = NULL;
  2084. }
  2085. m_aPChannels = new DWORD[m_dwPChannelsUsed];
  2086. if (m_aPChannels)
  2087. {
  2088. TListItem<WavePart>* pScan = m_WavePartList.GetHead();
  2089. for (DWORD dw = 0; pScan && dw < m_dwPChannelsUsed; pScan = pScan->GetNext(), dw++)
  2090. {
  2091. m_aPChannels[dw] = pScan->GetItemValue().m_dwPChannel;
  2092. TListItem<WaveItem>* pItemScan = pScan->GetItemValue().m_WaveItemList.GetHead();
  2093. for (; pItemScan; pItemScan = pItemScan->GetNext())
  2094. {
  2095. pItemScan->GetItemValue().m_dwVoiceIndex = m_dwWaveItems;
  2096. m_dwWaveItems++;
  2097. }
  2098. }
  2099. }
  2100. else
  2101. {
  2102. CleanUp();
  2103. hr = E_OUTOFMEMORY;
  2104. }
  2105. ON_ERROR:
  2106. LeaveCriticalSection(&m_CrSec);
  2107. return hr;
  2108. }
  2109. HRESULT CWavTrack::DownloadWave(
  2110. IDirectSoundWave* pWave,
  2111. IUnknown* pUnk,
  2112. REFGUID rguidVersion)
  2113. {
  2114. V_INAME(CWavTrack::DownloadWave);
  2115. V_INTERFACE_OPT(pWave);
  2116. V_INTERFACE(pUnk);
  2117. V_REFGUID(rguidVersion);
  2118. IDirectMusicAudioPath* pPath = NULL;
  2119. IDirectMusicPerformance *pPerf = NULL;
  2120. HRESULT hr = pUnk->QueryInterface(IID_IDirectMusicAudioPath,(void **)&pPath);
  2121. if (SUCCEEDED(hr))
  2122. {
  2123. hr = pPath->GetObjectInPath(0,DMUS_PATH_PERFORMANCE,0,CLSID_DirectMusicPerformance,0,IID_IDirectMusicPerformance,(void **)&pPerf);
  2124. }
  2125. else
  2126. {
  2127. hr = pUnk->QueryInterface(IID_IDirectMusicPerformance,(void **)&pPerf);
  2128. }
  2129. if (SUCCEEDED(hr))
  2130. {
  2131. EnterCriticalSection(&m_CrSec);
  2132. TListItem<WavePart>* pPart = m_WavePartList.GetHead();
  2133. for(; pPart; pPart = pPart->GetNext())
  2134. {
  2135. // If not S_OK, download is only partial.
  2136. if (pPart->GetItemValue().Download(pPerf, pPath, pWave, rguidVersion) != S_OK)
  2137. {
  2138. Trace(1,"Error: Wave download was only partially successful. Some sounds will not play.\n");
  2139. hr = S_FALSE;
  2140. }
  2141. }
  2142. LeaveCriticalSection(&m_CrSec);
  2143. }
  2144. if (pPath) pPath->Release();
  2145. if (pPerf) pPerf->Release();
  2146. return hr;
  2147. }
  2148. HRESULT CWavTrack::UnloadWave(
  2149. IDirectSoundWave* pWave,
  2150. IUnknown* pUnk)
  2151. {
  2152. V_INAME(CWavTrack::UnloadWave);
  2153. V_INTERFACE_OPT(pWave);
  2154. V_INTERFACE(pUnk);
  2155. IDirectMusicAudioPath* pPath = NULL;
  2156. IDirectMusicPerformance *pPerf = NULL;
  2157. HRESULT hr = pUnk->QueryInterface(IID_IDirectMusicAudioPath,(void **)&pPath);
  2158. if (SUCCEEDED(hr))
  2159. {
  2160. hr = pPath->GetObjectInPath(0,DMUS_PATH_PERFORMANCE,0,CLSID_DirectMusicPerformance,0,IID_IDirectMusicPerformance,(void **)&pPerf);
  2161. }
  2162. else
  2163. {
  2164. hr = pUnk->QueryInterface(IID_IDirectMusicPerformance,(void **)&pPerf);
  2165. }
  2166. if (SUCCEEDED(hr))
  2167. {
  2168. EnterCriticalSection(&m_CrSec);
  2169. TListItem<WavePart>* pPart = m_WavePartList.GetHead();
  2170. for(; pPart; pPart = pPart->GetNext())
  2171. {
  2172. // If not S_OK, unload is only partial.
  2173. if (pPart->GetItemValue().Unload(pPerf, pPath, pWave) != S_OK)
  2174. {
  2175. Trace(1,"Error: Wavetrack unload was only partially successful.\n");
  2176. hr = S_FALSE;
  2177. }
  2178. }
  2179. LeaveCriticalSection(&m_CrSec);
  2180. }
  2181. if (pPath) pPath->Release();
  2182. if (pPerf) pPerf->Release();
  2183. return hr;
  2184. }
  2185. HRESULT CWavTrack::RefreshWave(
  2186. IDirectSoundWave* pWave,
  2187. IUnknown* pUnk,
  2188. DWORD dwPChannel,
  2189. REFGUID rguidVersion)
  2190. {
  2191. V_INAME(CWavTrack::RefreshWave);
  2192. V_INTERFACE_OPT(pWave);
  2193. V_INTERFACE(pUnk);
  2194. IDirectMusicAudioPath* pPath = NULL;
  2195. IDirectMusicPerformance *pPerf = NULL;
  2196. HRESULT hr = pUnk->QueryInterface(IID_IDirectMusicAudioPath,(void **)&pPath);
  2197. if (SUCCEEDED(hr))
  2198. {
  2199. hr = pPath->GetObjectInPath(0,DMUS_PATH_PERFORMANCE,0,CLSID_DirectMusicPerformance,0,IID_IDirectMusicPerformance,(void **)&pPerf);
  2200. }
  2201. else
  2202. {
  2203. hr = pUnk->QueryInterface(IID_IDirectMusicPerformance,(void **)&pPerf);
  2204. }
  2205. if (SUCCEEDED(hr))
  2206. {
  2207. EnterCriticalSection(&m_CrSec);
  2208. TListItem<WavePart>* pPart = m_WavePartList.GetHead();
  2209. for(; pPart; pPart = pPart->GetNext())
  2210. {
  2211. // If not S_OK, refresh is only partial.
  2212. if (pPart->GetItemValue().Refresh(pPerf, pPath, pWave, dwPChannel, rguidVersion) != S_OK)
  2213. {
  2214. Trace(1,"Error: Wavetrack refresh was only partially successful. Some sounds will not play.\n");
  2215. hr = S_FALSE;
  2216. }
  2217. }
  2218. LeaveCriticalSection(&m_CrSec);
  2219. }
  2220. if (pPath) pPath->Release();
  2221. if (pPerf) pPerf->Release();
  2222. return hr;
  2223. }
  2224. HRESULT CWavTrack::FlushAllWaves()
  2225. {
  2226. FlushWaves();
  2227. return S_OK;
  2228. }
  2229. HRESULT CWavTrack::OnVoiceEnd(IDirectMusicVoiceP *pVoice, void *pStateData)
  2230. {
  2231. HRESULT hr = S_OK;
  2232. if( pStateData && pVoice )
  2233. {
  2234. EnterCriticalSection(&m_CrSec);
  2235. WaveStateData* pSD = (WaveStateData*)pStateData;
  2236. TListItem<WaveDLOnPlay>* pWDLOnPlay = pSD->m_WaveDLList.GetHead();
  2237. TListItem<WaveDLOnPlay>* pWDLNext = NULL;
  2238. for (; pWDLOnPlay; pWDLOnPlay = pWDLNext)
  2239. {
  2240. pWDLNext = pWDLOnPlay->GetNext();
  2241. if (pWDLOnPlay->GetItemValue().m_pVoice == pVoice)
  2242. {
  2243. pSD->m_WaveDLList.Remove(pWDLOnPlay);
  2244. delete pWDLOnPlay;
  2245. break;
  2246. }
  2247. }
  2248. LeaveCriticalSection(&m_CrSec);
  2249. }
  2250. else
  2251. {
  2252. hr = E_POINTER;
  2253. }
  2254. return hr;
  2255. }
  2256. ////////////////////////////////////////////////////////////////////
  2257. // WavePart
  2258. HRESULT WavePart::Load( IDMStream* pIRiffStream, MMCKINFO* pckParent )
  2259. {
  2260. MMCKINFO ck;
  2261. MMCKINFO ckList;
  2262. DWORD dwByteCount;
  2263. DWORD dwSize;
  2264. HRESULT hr = E_FAIL;
  2265. // LoadPChannel does not expect to be called twice on the same object!
  2266. if( pIRiffStream == NULL || pckParent == NULL )
  2267. {
  2268. ASSERT( 0 );
  2269. return DMUS_E_CANNOTREAD;
  2270. }
  2271. IStream* pIStream = pIRiffStream->GetStream();
  2272. ASSERT( pIStream != NULL );
  2273. // Load the PChannel
  2274. while( pIRiffStream->Descend( &ck, pckParent, 0 ) == S_OK )
  2275. {
  2276. switch( ck.ckid )
  2277. {
  2278. case DMUS_FOURCC_WAVEPART_CHUNK:
  2279. {
  2280. DMUS_IO_WAVE_PART_HEADER iPartHeader;
  2281. memset(&iPartHeader, 0, sizeof(iPartHeader));
  2282. // Read in the item's header structure
  2283. dwSize = min( sizeof( DMUS_IO_WAVE_PART_HEADER ), ck.cksize );
  2284. hr = pIStream->Read( &iPartHeader, dwSize, &dwByteCount );
  2285. // Handle any I/O error by returning a failure code
  2286. if( FAILED( hr ) || dwByteCount != dwSize )
  2287. {
  2288. Trace(1,"Error: Unable to read wave track - bad file.\n");
  2289. if (SUCCEEDED(hr)) hr = DMUS_E_CANNOTREAD;
  2290. goto ON_ERROR;
  2291. }
  2292. m_dwPChannel = iPartHeader.dwPChannel;
  2293. m_dwIndex = iPartHeader.dwIndex;
  2294. m_lVolume = iPartHeader.lVolume;
  2295. m_dwLockToPart = iPartHeader.dwLockToPart;
  2296. m_dwPChannelFlags = iPartHeader.dwFlags;
  2297. m_dwVariations = iPartHeader.dwVariations;
  2298. break;
  2299. }
  2300. case FOURCC_LIST:
  2301. switch( ck.fccType )
  2302. {
  2303. case DMUS_FOURCC_WAVEITEM_LIST:
  2304. while( pIRiffStream->Descend( &ckList, &ck, 0 ) == S_OK )
  2305. {
  2306. switch( ckList.ckid )
  2307. {
  2308. case FOURCC_LIST:
  2309. switch( ckList.fccType )
  2310. {
  2311. case DMUS_FOURCC_WAVE_LIST:
  2312. {
  2313. TListItem<WaveItem>* pNewItem = new TListItem<WaveItem>;
  2314. if( pNewItem == NULL )
  2315. {
  2316. hr = E_OUTOFMEMORY;
  2317. goto ON_ERROR;
  2318. }
  2319. hr = pNewItem->GetItemValue().Load( pIRiffStream, &ckList );
  2320. if( FAILED ( hr ) )
  2321. {
  2322. delete pNewItem;
  2323. goto ON_ERROR;
  2324. }
  2325. m_WaveItemList.AddHead( pNewItem );
  2326. //InsertByAscendingTime( pNewItem );
  2327. break;
  2328. }
  2329. }
  2330. }
  2331. pIRiffStream->Ascend( &ckList, 0 );
  2332. }
  2333. break;
  2334. }
  2335. break;
  2336. }
  2337. // Ascend out of the chunk
  2338. pIRiffStream->Ascend( &ck, 0 );
  2339. }
  2340. ON_ERROR:
  2341. RELEASE( pIStream );
  2342. return hr;
  2343. }
  2344. void WavePart::CleanUp()
  2345. {
  2346. TListItem<WaveItem>* pScan = m_WaveItemList.GetHead();
  2347. for (; pScan; pScan = pScan->GetNext() )
  2348. {
  2349. pScan->GetItemValue().CleanUp();
  2350. }
  2351. m_WaveItemList.CleanUp();
  2352. }
  2353. HRESULT WavePart::CopyItems( const TList<WaveItem>& rItems, MUSIC_TIME mtStart, MUSIC_TIME mtEnd )
  2354. {
  2355. HRESULT hr = S_OK;
  2356. CleanUp();
  2357. TListItem<WaveItem>* pScan = rItems.GetHead();
  2358. for (; pScan; pScan = pScan->GetNext() )
  2359. {
  2360. WaveItem& rScan = pScan->GetItemValue();
  2361. if (mtStart <= (MUSIC_TIME) rScan.m_rtTimePhysical &&
  2362. (!mtEnd || (MUSIC_TIME) rScan.m_rtTimePhysical < mtEnd) )
  2363. {
  2364. TListItem<WaveItem>* pNew = new TListItem<WaveItem>;
  2365. if (pNew)
  2366. {
  2367. WaveItem& rNew = pNew->GetItemValue();
  2368. rNew.m_rtTimePhysical = rScan.m_rtTimePhysical - mtStart;
  2369. rNew.m_lVolume = rScan.m_lVolume;
  2370. rNew.m_lPitch = rScan.m_lPitch;
  2371. rNew.m_dwVariations = rScan.m_dwVariations;
  2372. rNew.m_rtStartOffset = rScan.m_rtStartOffset;
  2373. rNew.m_rtDuration = rScan.m_rtDuration;
  2374. rNew.m_mtTimeLogical = rScan.m_mtTimeLogical;
  2375. rNew.m_dwFlags = rScan.m_dwFlags;
  2376. rNew.m_pWave = rScan.m_pWave;
  2377. rNew.m_dwLoopStart = rScan.m_dwLoopStart;
  2378. rNew.m_dwLoopEnd = rScan.m_dwLoopEnd;
  2379. rNew.m_fIsStreaming = rScan.m_fIsStreaming;
  2380. if (rNew.m_pWave)
  2381. {
  2382. rNew.m_pWave->AddRef();
  2383. }
  2384. if (SUCCEEDED(hr))
  2385. {
  2386. m_WaveItemList.AddHead(pNew);
  2387. }
  2388. else
  2389. {
  2390. delete pNew;
  2391. }
  2392. }
  2393. else
  2394. {
  2395. hr = E_OUTOFMEMORY;
  2396. break;
  2397. }
  2398. }
  2399. }
  2400. if (SUCCEEDED(hr))
  2401. {
  2402. m_WaveItemList.Reverse();
  2403. }
  2404. else
  2405. {
  2406. CleanUp();
  2407. }
  2408. return hr;
  2409. }
  2410. HRESULT WavePart::Download(IDirectMusicPerformance* pPerformance,
  2411. IDirectMusicAudioPath* pPath,
  2412. IDirectSoundWave* pWave,
  2413. REFGUID rguidVersion)
  2414. {
  2415. HRESULT hr = S_OK;
  2416. TListItem<WaveItem>* pItem = m_WaveItemList.GetHead();
  2417. for(; pItem; pItem = pItem->GetNext())
  2418. {
  2419. HRESULT hrItem = pItem->GetItemValue().Download(pPerformance, pPath, m_dwPChannel, pWave, rguidVersion);
  2420. if (hrItem != S_OK)
  2421. {
  2422. hr = hrItem; // if any attempt failed, return the failure (but keep downloading)
  2423. }
  2424. }
  2425. return hr;
  2426. }
  2427. HRESULT WavePart::Unload(IDirectMusicPerformance* pPerformance, IDirectMusicAudioPath* pPath, IDirectSoundWave* pWave)
  2428. {
  2429. HRESULT hr = S_OK;
  2430. TListItem<WaveItem>* pItem = m_WaveItemList.GetHead();
  2431. for(; pItem; pItem = pItem->GetNext())
  2432. {
  2433. HRESULT hrItem = pItem->GetItemValue().Unload(pPerformance, pPath, m_dwPChannel, pWave);
  2434. if (hrItem != S_OK)
  2435. {
  2436. hr = hrItem; // if any attempt failed, return the failure (but keep unloading)
  2437. }
  2438. }
  2439. return hr;
  2440. }
  2441. HRESULT WavePart::Refresh(IDirectMusicPerformance* pPerformance,
  2442. IDirectMusicAudioPath* pPath,
  2443. IDirectSoundWave* pWave,
  2444. DWORD dwPChannel,
  2445. REFGUID rguidVersion)
  2446. {
  2447. HRESULT hr = S_OK;
  2448. TListItem<WaveItem>* pItem = m_WaveItemList.GetHead();
  2449. for(; pItem; pItem = pItem->GetNext())
  2450. {
  2451. HRESULT hrItem = pItem->GetItemValue().Refresh(pPerformance, pPath, m_dwPChannel, dwPChannel, pWave, rguidVersion);
  2452. if (hrItem != S_OK)
  2453. {
  2454. hr = hrItem; // if any attempt failed, return the failure (but keep refreshing)
  2455. }
  2456. }
  2457. return hr;
  2458. }
  2459. HRESULT WavePart::Add(
  2460. IDirectSoundWave* pWave,
  2461. REFERENCE_TIME rtTime,
  2462. DWORD dwPChannel,
  2463. DWORD dwIndex,
  2464. REFERENCE_TIME* prtLength)
  2465. {
  2466. HRESULT hr = S_OK;
  2467. m_dwPChannel = dwPChannel;
  2468. m_dwIndex = dwIndex;
  2469. m_lVolume = 0;
  2470. m_dwLockToPart = 0;
  2471. m_dwPChannelFlags = 0;
  2472. m_dwVariations = 0xffffffff;
  2473. TListItem<WaveItem>* pNewItem = new TListItem<WaveItem>;
  2474. if( pNewItem == NULL )
  2475. {
  2476. hr = E_OUTOFMEMORY;
  2477. goto ON_ERROR;
  2478. }
  2479. hr = pNewItem->GetItemValue().Add( pWave, rtTime, prtLength );
  2480. if( FAILED ( hr ) )
  2481. {
  2482. delete pNewItem;
  2483. goto ON_ERROR;
  2484. }
  2485. m_WaveItemList.AddHead( pNewItem );
  2486. ON_ERROR:
  2487. return hr;
  2488. }
  2489. ////////////////////////////////////////////////////////////////////
  2490. // WaveItem
  2491. HRESULT WaveItem::Load( IDMStream* pIRiffStream, MMCKINFO* pckParent )
  2492. {
  2493. MMCKINFO ck;
  2494. DWORD dwByteCount;
  2495. DWORD dwSize;
  2496. HRESULT hr = E_FAIL;
  2497. // LoadListItem does not expect to be called twice on the same object
  2498. // Code assumes item consists of initial values
  2499. ASSERT( m_rtTimePhysical == 0 );
  2500. if( pIRiffStream == NULL || pckParent == NULL )
  2501. {
  2502. ASSERT( 0 );
  2503. return DMUS_E_CANNOTREAD;
  2504. }
  2505. IStream* pIStream = pIRiffStream->GetStream();
  2506. ASSERT( pIStream != NULL );
  2507. // Load the track item
  2508. while( pIRiffStream->Descend( &ck, pckParent, 0 ) == S_OK )
  2509. {
  2510. switch( ck.ckid )
  2511. {
  2512. case DMUS_FOURCC_WAVEITEM_CHUNK:
  2513. {
  2514. DMUS_IO_WAVE_ITEM_HEADER iItemHeader;
  2515. // Read in the item's header structure
  2516. dwSize = min( sizeof( DMUS_IO_WAVE_ITEM_HEADER ), ck.cksize );
  2517. hr = pIStream->Read( &iItemHeader, dwSize, &dwByteCount );
  2518. // Handle any I/O error by returning a failure code
  2519. if( FAILED( hr ) || dwByteCount != dwSize )
  2520. {
  2521. Trace(1,"Error: Unable to read wave track - bad file.\n");
  2522. if (SUCCEEDED(hr)) hr = DMUS_E_CANNOTREAD;
  2523. goto ON_ERROR;
  2524. }
  2525. m_lVolume = iItemHeader.lVolume;
  2526. m_lPitch = iItemHeader.lPitch;
  2527. m_dwVariations = iItemHeader.dwVariations;
  2528. m_rtTimePhysical = iItemHeader.rtTime;
  2529. m_rtStartOffset = iItemHeader.rtStartOffset;
  2530. m_rtDuration = iItemHeader.rtDuration;
  2531. m_mtTimeLogical = iItemHeader.mtLogicalTime;
  2532. m_dwFlags = iItemHeader.dwFlags;
  2533. m_dwLoopStart = iItemHeader.dwLoopStart;
  2534. m_dwLoopEnd = iItemHeader.dwLoopEnd;
  2535. if (m_dwLoopEnd) m_dwLoopEnd++; // fix for bug 38505
  2536. break;
  2537. }
  2538. case FOURCC_LIST:
  2539. if( ck.fccType == DMUS_FOURCC_REF_LIST )
  2540. {
  2541. hr = LoadReference( pIStream, pIRiffStream, ck );
  2542. }
  2543. break;
  2544. }
  2545. // Ascend out of the chunk
  2546. pIRiffStream->Ascend( &ck, 0 );
  2547. }
  2548. ON_ERROR:
  2549. RELEASE( pIStream );
  2550. return hr;
  2551. }
  2552. HRESULT WaveItem::LoadReference(IStream *pStream,
  2553. IDMStream *pIRiffStream,
  2554. MMCKINFO& ckParent)
  2555. {
  2556. if (!pStream || !pIRiffStream) return E_INVALIDARG;
  2557. IDirectSoundWave* pWave;
  2558. IDirectMusicLoader* pLoader = NULL;
  2559. IDirectMusicGetLoader *pIGetLoader;
  2560. HRESULT hr = pStream->QueryInterface( IID_IDirectMusicGetLoader,(void **) &pIGetLoader );
  2561. if (FAILED(hr)) return hr;
  2562. hr = pIGetLoader->GetLoader(&pLoader);
  2563. pIGetLoader->Release();
  2564. if (FAILED(hr)) return hr;
  2565. DMUS_OBJECTDESC desc;
  2566. ZeroMemory(&desc, sizeof(desc));
  2567. MMCKINFO ckNext;
  2568. ckNext.ckid = 0;
  2569. ckNext.fccType = 0;
  2570. DWORD dwSize = 0;
  2571. while( pIRiffStream->Descend( &ckNext, &ckParent, 0 ) == S_OK )
  2572. {
  2573. switch(ckNext.ckid)
  2574. {
  2575. case DMUS_FOURCC_REF_CHUNK:
  2576. DMUS_IO_REFERENCE ioDMRef;
  2577. hr = pStream->Read(&ioDMRef, sizeof(DMUS_IO_REFERENCE), NULL);
  2578. if(SUCCEEDED(hr))
  2579. {
  2580. desc.guidClass = ioDMRef.guidClassID;
  2581. desc.dwValidData |= ioDMRef.dwValidData;
  2582. desc.dwValidData |= DMUS_OBJ_CLASS;
  2583. }
  2584. break;
  2585. case DMUS_FOURCC_GUID_CHUNK:
  2586. hr = pStream->Read(&(desc.guidObject), sizeof(GUID), NULL);
  2587. if(SUCCEEDED(hr) )
  2588. {
  2589. desc.dwValidData |= DMUS_OBJ_OBJECT;
  2590. }
  2591. break;
  2592. case DMUS_FOURCC_DATE_CHUNK:
  2593. hr = pStream->Read(&(desc.ftDate), sizeof(FILETIME), NULL);
  2594. if(SUCCEEDED(hr))
  2595. {
  2596. desc.dwValidData |= DMUS_OBJ_DATE;
  2597. }
  2598. break;
  2599. case DMUS_FOURCC_NAME_CHUNK:
  2600. dwSize = min(sizeof(desc.wszName), ckNext.cksize);
  2601. hr = pStream->Read(desc.wszName, dwSize, NULL);
  2602. if(SUCCEEDED(hr) )
  2603. {
  2604. desc.wszName[DMUS_MAX_NAME - 1] = L'\0';
  2605. desc.dwValidData |= DMUS_OBJ_NAME;
  2606. }
  2607. break;
  2608. case DMUS_FOURCC_FILE_CHUNK:
  2609. dwSize = min(sizeof(desc.wszFileName), ckNext.cksize);
  2610. hr = pStream->Read(desc.wszFileName, dwSize, NULL);
  2611. if(SUCCEEDED(hr))
  2612. {
  2613. desc.wszFileName[DMUS_MAX_FILENAME - 1] = L'\0';
  2614. desc.dwValidData |= DMUS_OBJ_FILENAME;
  2615. }
  2616. break;
  2617. case DMUS_FOURCC_CATEGORY_CHUNK:
  2618. dwSize = min(sizeof(desc.wszCategory), ckNext.cksize);
  2619. hr = pStream->Read(desc.wszCategory, dwSize, NULL);
  2620. if(SUCCEEDED(hr) )
  2621. {
  2622. desc.wszCategory[DMUS_MAX_CATEGORY - 1] = L'\0';
  2623. desc.dwValidData |= DMUS_OBJ_CATEGORY;
  2624. }
  2625. break;
  2626. case DMUS_FOURCC_VERSION_CHUNK:
  2627. DMUS_IO_VERSION ioDMObjVer;
  2628. hr = pStream->Read(&ioDMObjVer, sizeof(DMUS_IO_VERSION), NULL);
  2629. if(SUCCEEDED(hr))
  2630. {
  2631. desc.vVersion.dwVersionMS = ioDMObjVer.dwVersionMS;
  2632. desc.vVersion.dwVersionLS = ioDMObjVer.dwVersionLS;
  2633. desc.dwValidData |= DMUS_OBJ_VERSION;
  2634. }
  2635. break;
  2636. default:
  2637. break;
  2638. }
  2639. if(SUCCEEDED(hr) && pIRiffStream->Ascend(&ckNext, 0) == S_OK)
  2640. {
  2641. ckNext.ckid = 0;
  2642. ckNext.fccType = 0;
  2643. }
  2644. else if (SUCCEEDED(hr)) hr = DMUS_E_CANNOTREAD;
  2645. }
  2646. if (!(desc.dwValidData & DMUS_OBJ_NAME) &&
  2647. !(desc.dwValidData & DMUS_OBJ_FILENAME) &&
  2648. !(desc.dwValidData & DMUS_OBJ_OBJECT) )
  2649. {
  2650. Trace(1,"Error: Wave track is unable to reference a wave because it doesn't have any valid reference information.\n");
  2651. hr = DMUS_E_CANNOTREAD;
  2652. }
  2653. if(SUCCEEDED(hr))
  2654. {
  2655. desc.dwSize = sizeof(DMUS_OBJECTDESC);
  2656. hr = pLoader->GetObject(&desc, IID_IDirectSoundWave, (void**)&pWave);
  2657. if (SUCCEEDED(hr))
  2658. {
  2659. if (m_pWave) m_pWave->Release();
  2660. m_pWave = pWave; // no need to AddRef; GetObject did that
  2661. REFERENCE_TIME rtReadAhead = 0;
  2662. DWORD dwFlags = 0;
  2663. m_pWave->GetStreamingParms(&dwFlags, &rtReadAhead);
  2664. m_fIsStreaming = dwFlags & DMUS_WAVEF_STREAMING ? TRUE : FALSE;
  2665. m_fUseNoPreRoll = dwFlags & DMUS_WAVEF_NOPREROLL ? TRUE : FALSE;
  2666. }
  2667. }
  2668. if (pLoader)
  2669. {
  2670. pLoader->Release();
  2671. }
  2672. return hr;
  2673. }
  2674. HRESULT WaveItem::Download(IDirectMusicPerformance* pPerformance,
  2675. IDirectMusicAudioPath* pPath,
  2676. DWORD dwPChannel,
  2677. IDirectSoundWave* pWave,
  2678. REFGUID rguidVersion)
  2679. {
  2680. HRESULT hr = S_OK;
  2681. IDirectMusicPort* pPort = NULL;
  2682. DWORD dwGroup = 0;
  2683. DWORD dwMChannel = 0;
  2684. if (m_pWave && (!pWave || pWave == m_pWave))
  2685. {
  2686. hr = PChannelInfo(pPerformance, pPath, dwPChannel, &pPort, &dwGroup, &dwMChannel);
  2687. if (SUCCEEDED(hr) && pPort)
  2688. {
  2689. IDirectMusicPortP* pPortP = NULL;
  2690. if (SUCCEEDED(hr = pPort->QueryInterface(IID_IDirectMusicPortP, (void**) &pPortP)))
  2691. {
  2692. EnterCriticalSection(&WaveItem::st_WaveListCritSect);
  2693. TListItem<TaggedWave>* pDLWave = st_WaveList.GetHead();
  2694. for (; pDLWave; pDLWave = pDLWave->GetNext())
  2695. {
  2696. TaggedWave& rDLWave = pDLWave->GetItemValue();
  2697. if ( rDLWave.m_pWave == m_pWave &&
  2698. rDLWave.m_pPerformance == pPerformance &&
  2699. rDLWave.m_pPort == pPortP &&
  2700. ( !m_fIsStreaming ||
  2701. rDLWave.m_pDownloadedWave == m_pDownloadedWave ) )
  2702. {
  2703. break;
  2704. }
  2705. }
  2706. // only download the wave if:
  2707. // 1) it hasn't already been downloaded to the port, or
  2708. // 2) its version doesn't match the currently downloaded version.
  2709. if (!pDLWave)
  2710. {
  2711. pDLWave = new TListItem<TaggedWave>;
  2712. if (!pDLWave)
  2713. {
  2714. hr = E_OUTOFMEMORY;
  2715. }
  2716. else
  2717. {
  2718. TaggedWave& rDLWave = pDLWave->GetItemValue();
  2719. hr = pPortP->DownloadWave( m_pWave, &(rDLWave.m_pDownloadedWave), m_rtStartOffset );
  2720. if (SUCCEEDED(hr))
  2721. {
  2722. rDLWave.m_pPort = pPortP;
  2723. rDLWave.m_pPort->AddRef();
  2724. rDLWave.m_pPerformance = pPerformance;
  2725. rDLWave.m_pPerformance->AddRef();
  2726. rDLWave.m_pWave = m_pWave;
  2727. rDLWave.m_pWave->AddRef();
  2728. rDLWave.m_lRefCount = 1;
  2729. rDLWave.m_guidVersion = rguidVersion;
  2730. st_WaveList.AddHead(pDLWave);
  2731. if (m_pDownloadedWave)
  2732. {
  2733. m_pDownloadedWave->Release();
  2734. }
  2735. if(m_fIsStreaming)
  2736. {
  2737. m_pDownloadedWave = rDLWave.m_pDownloadedWave;
  2738. m_pDownloadedWave->AddRef();
  2739. }
  2740. }
  2741. else
  2742. {
  2743. delete pDLWave;
  2744. }
  2745. }
  2746. }
  2747. else if (rguidVersion != pDLWave->GetItemValue().m_guidVersion)
  2748. {
  2749. TaggedWave& rDLWave = pDLWave->GetItemValue();
  2750. if (rDLWave.m_pDownloadedWave)
  2751. {
  2752. pPortP->UnloadWave(rDLWave.m_pDownloadedWave);
  2753. rDLWave.m_pDownloadedWave = NULL;
  2754. }
  2755. if (rDLWave.m_pPort)
  2756. {
  2757. rDLWave.m_pPort->Release();
  2758. rDLWave.m_pPort = NULL;
  2759. }
  2760. if (rDLWave.m_pPerformance)
  2761. {
  2762. rDLWave.m_pPerformance->Release();
  2763. rDLWave.m_pPerformance = NULL;
  2764. }
  2765. hr = pPortP->DownloadWave( m_pWave, &(rDLWave.m_pDownloadedWave), m_rtStartOffset );
  2766. if (SUCCEEDED(hr))
  2767. {
  2768. rDLWave.m_pPort = pPortP;
  2769. rDLWave.m_pPort->AddRef();
  2770. rDLWave.m_pPerformance = pPerformance;
  2771. rDLWave.m_pPerformance->AddRef();
  2772. rDLWave.m_lRefCount = 1;
  2773. rDLWave.m_guidVersion = rguidVersion;
  2774. if (m_pDownloadedWave)
  2775. {
  2776. m_pDownloadedWave->Release();
  2777. }
  2778. if(m_fIsStreaming)
  2779. {
  2780. m_pDownloadedWave = rDLWave.m_pDownloadedWave;
  2781. m_pDownloadedWave->AddRef();
  2782. }
  2783. }
  2784. else
  2785. {
  2786. if (rDLWave.m_pWave)
  2787. {
  2788. rDLWave.m_pWave->Release();
  2789. rDLWave.m_pWave = NULL;
  2790. }
  2791. st_WaveList.Remove(pDLWave);
  2792. delete pDLWave;
  2793. }
  2794. }
  2795. else // keep track of this, but return S_FALSE (indicates wave wasn't downloaded)
  2796. {
  2797. pDLWave->GetItemValue().m_lRefCount++;
  2798. hr = S_FALSE;
  2799. }
  2800. LeaveCriticalSection(&WaveItem::st_WaveListCritSect);
  2801. pPortP->Release();
  2802. }
  2803. pPort->Release();
  2804. }
  2805. else if (SUCCEEDED(hr) && !pPort)
  2806. {
  2807. Trace(1, "Error: the performance was unable to find a port for download.\n");
  2808. hr = DMUS_E_NOT_FOUND;
  2809. }
  2810. }
  2811. else
  2812. {
  2813. Trace(1,"Error: Wavetrack download failed, initialization error.\n");
  2814. hr = DMUS_E_NOT_INIT;
  2815. }
  2816. return hr;
  2817. }
  2818. HRESULT WaveItem::Unload(IDirectMusicPerformance* pPerformance,
  2819. IDirectMusicAudioPath* pPath,
  2820. DWORD dwPChannel,
  2821. IDirectSoundWave* pWave)
  2822. {
  2823. IDirectMusicPort* pPort = NULL;
  2824. DWORD dwGroup = 0;
  2825. DWORD dwMChannel = 0;
  2826. HRESULT hr = S_OK;
  2827. if (m_pWave && (!pWave || pWave == m_pWave))
  2828. {
  2829. hr = PChannelInfo(pPerformance, pPath, dwPChannel, &pPort, &dwGroup, &dwMChannel);
  2830. if (SUCCEEDED(hr) && pPort)
  2831. {
  2832. IDirectMusicPortP* pPortP = NULL;
  2833. if (SUCCEEDED(hr = pPort->QueryInterface(IID_IDirectMusicPortP, (void**) &pPortP)))
  2834. {
  2835. EnterCriticalSection(&WaveItem::st_WaveListCritSect);
  2836. TListItem<TaggedWave>* pDLWave = st_WaveList.GetHead();
  2837. for (; pDLWave; pDLWave = pDLWave->GetNext())
  2838. {
  2839. TaggedWave& rDLWave = pDLWave->GetItemValue();
  2840. if (rDLWave.m_pWave == m_pWave &&
  2841. rDLWave.m_pPerformance == pPerformance &&
  2842. rDLWave.m_pPort == pPortP &&
  2843. ( !m_fIsStreaming ||
  2844. rDLWave.m_pDownloadedWave == m_pDownloadedWave ) )
  2845. {
  2846. rDLWave.m_lRefCount--;
  2847. if (rDLWave.m_lRefCount <= 0)
  2848. {
  2849. if (rDLWave.m_pWave)
  2850. {
  2851. rDLWave.m_pWave->Release();
  2852. rDLWave.m_pWave = NULL;
  2853. }
  2854. if (rDLWave.m_pPort)
  2855. {
  2856. rDLWave.m_pPort->Release();
  2857. rDLWave.m_pPort = NULL;
  2858. }
  2859. if (rDLWave.m_pPerformance)
  2860. {
  2861. rDLWave.m_pPerformance->Release();
  2862. rDLWave.m_pPerformance = NULL;
  2863. }
  2864. if (rDLWave.m_pDownloadedWave)
  2865. {
  2866. pPortP->UnloadWave(rDLWave.m_pDownloadedWave);
  2867. rDLWave.m_pDownloadedWave = NULL;
  2868. }
  2869. if (m_pDownloadedWave)
  2870. {
  2871. m_pDownloadedWave->Release();
  2872. m_pDownloadedWave = NULL;
  2873. }
  2874. st_WaveList.Remove(pDLWave);
  2875. delete pDLWave;
  2876. }
  2877. else
  2878. {
  2879. hr = S_FALSE; // indicates wave wasn't actually unloaded
  2880. }
  2881. break;
  2882. }
  2883. }
  2884. LeaveCriticalSection(&WaveItem::st_WaveListCritSect);
  2885. pPortP->Release();
  2886. }
  2887. pPort->Release();
  2888. }
  2889. else if (SUCCEEDED(hr) && !pPort)
  2890. {
  2891. Trace(1, "Error: the performance was unable to find a port for unload.\n");
  2892. hr = DMUS_E_NOT_FOUND;
  2893. }
  2894. }
  2895. return hr;
  2896. }
  2897. HRESULT WaveItem::Refresh(IDirectMusicPerformance* pPerformance,
  2898. IDirectMusicAudioPath* pPath,
  2899. DWORD dwOldPChannel,
  2900. DWORD dwNewPChannel,
  2901. IDirectSoundWave* pWave,
  2902. REFGUID rguidVersion)
  2903. {
  2904. IDirectMusicPort* pOldPort = NULL;
  2905. IDirectMusicPort* pNewPort = NULL;
  2906. DWORD dwGroup = 0;
  2907. DWORD dwMChannel = 0;
  2908. HRESULT hr = S_OK;
  2909. hr = PChannelInfo(pPerformance, pPath, dwOldPChannel, &pOldPort, &dwGroup, &dwMChannel);
  2910. if (SUCCEEDED(hr))
  2911. {
  2912. hr = PChannelInfo(pPerformance, pPath, dwNewPChannel, &pNewPort, &dwGroup, &dwMChannel);
  2913. }
  2914. if (SUCCEEDED(hr))
  2915. {
  2916. // if the old port and new port are different, unload the wave from the old port
  2917. // and download to the new one.
  2918. if (pOldPort != pNewPort)
  2919. {
  2920. Unload(pPerformance, pPath, dwOldPChannel, pWave);
  2921. hr = Download(pPerformance, pPath, dwNewPChannel, pWave, rguidVersion);
  2922. }
  2923. }
  2924. if (pOldPort) pOldPort->Release();
  2925. if (pNewPort) pNewPort->Release();
  2926. return hr;
  2927. }
  2928. HRESULT WaveItem::PChannelInfo(
  2929. IDirectMusicPerformance* pPerformance,
  2930. IDirectMusicAudioPath* pAudioPath,
  2931. DWORD dwPChannel,
  2932. IDirectMusicPort** ppPort,
  2933. DWORD* pdwGroup,
  2934. DWORD* pdwMChannel)
  2935. {
  2936. HRESULT hr = S_OK;
  2937. DWORD dwConvertedPChannel = dwPChannel;
  2938. if (pAudioPath)
  2939. {
  2940. hr = pAudioPath->ConvertPChannel(dwPChannel, &dwConvertedPChannel);
  2941. }
  2942. if (SUCCEEDED(hr))
  2943. {
  2944. hr = pPerformance->PChannelInfo(dwConvertedPChannel, ppPort, pdwGroup, pdwMChannel);
  2945. }
  2946. return hr;
  2947. }
  2948. void WaveItem::CleanUp()
  2949. {
  2950. if (m_pWave)
  2951. {
  2952. m_pWave->Release();
  2953. m_pWave = NULL;
  2954. }
  2955. if (m_pDownloadedWave)
  2956. {
  2957. m_pDownloadedWave->Release();
  2958. m_pDownloadedWave = NULL;
  2959. }
  2960. }
  2961. HRESULT WaveItem::Add(IDirectSoundWave* pWave, REFERENCE_TIME rtTime,
  2962. REFERENCE_TIME* prtLength)
  2963. {
  2964. HRESULT hr = S_OK;
  2965. IPrivateWave* pPrivWave = NULL;
  2966. *prtLength = 0; // in case GetLength fails...
  2967. REFERENCE_TIME rtLength = 0;
  2968. m_rtDuration = 0;
  2969. if (SUCCEEDED(hr = pWave->QueryInterface(IID_IPrivateWave, (void**)&pPrivWave)))
  2970. {
  2971. if (SUCCEEDED(hr = pPrivWave->GetLength(&rtLength)))
  2972. {
  2973. // Assumes the track is clock time
  2974. m_rtDuration = rtLength * REF_PER_MIL;
  2975. *prtLength = rtLength; // NOTE: length in milliseconds; duration in Ref time
  2976. }
  2977. pPrivWave->Release();
  2978. }
  2979. if (SUCCEEDED(hr))
  2980. {
  2981. m_lVolume = 0;
  2982. m_lPitch = 0;
  2983. m_dwVariations = 0xffffffff;
  2984. m_rtTimePhysical = rtTime;
  2985. m_rtStartOffset = 0;
  2986. m_mtTimeLogical = 0;
  2987. m_dwFlags = 0;
  2988. m_dwLoopStart = 0;
  2989. m_dwLoopEnd = 0;
  2990. if (m_pWave)
  2991. {
  2992. m_pWave->Release();
  2993. m_pWave = NULL;
  2994. }
  2995. m_pWave = pWave;
  2996. if (m_pWave)
  2997. {
  2998. m_pWave->AddRef();
  2999. REFERENCE_TIME rtReadAhead = 0;
  3000. DWORD dwFlags = 0;
  3001. m_pWave->GetStreamingParms(&dwFlags, &rtReadAhead);
  3002. m_fIsStreaming = dwFlags & DMUS_WAVEF_STREAMING ? TRUE : FALSE;
  3003. m_fUseNoPreRoll = dwFlags & DMUS_WAVEF_NOPREROLL ? TRUE : FALSE;
  3004. }
  3005. if (m_pDownloadedWave)
  3006. {
  3007. m_pDownloadedWave->Release();
  3008. }
  3009. m_pDownloadedWave = NULL;
  3010. }
  3011. return hr;
  3012. }