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

1521 lines
45 KiB

  1. //
  2. // bandtrk.cpp
  3. //
  4. // Copyright (c) 1997-2001 Microsoft Corporation
  5. //
  6. #include "debug.h"
  7. #include "dmusicc.h"
  8. #include "dmusici.h"
  9. #include "dmusicf.h"
  10. #include "..\shared\dmstrm.h"
  11. #include "..\shared\validate.h"
  12. #include "bandtrk.h"
  13. extern long g_cComponent;
  14. //////////////////////////////////////////////////////////////////////
  15. // Class CBandTrk
  16. //////////////////////////////////////////////////////////////////////
  17. // CBandTrk::CBandTrk
  18. CBandTrk::CBandTrk() :
  19. m_dwValidate(0),
  20. m_bAutoDownload(false),
  21. m_fLockAutoDownload(false),
  22. m_dwFlags(0),
  23. m_cRef(1),
  24. m_fCSInitialized(FALSE)
  25. {
  26. InterlockedIncrement(&g_cComponent);
  27. InitializeCriticalSection(&m_CriticalSection);
  28. // Note: on pre-Blackcomb OS's, this call can raise an exception; if it
  29. // ever pops in stress, we can add an exception handler and retry loop.
  30. // (Not all calls to 'new CBandTrk' are protected in handlers.)
  31. m_fCSInitialized = TRUE;
  32. }
  33. //////////////////////////////////////////////////////////////////////
  34. // CBandTrk::~CBandTrk
  35. CBandTrk::~CBandTrk()
  36. {
  37. if (m_fCSInitialized)
  38. {
  39. m_MidiModeList.CleanUp();
  40. while(!BandList.IsEmpty())
  41. {
  42. CBand* pBand = BandList.RemoveHead();
  43. pBand->Release();
  44. }
  45. DeleteCriticalSection(&m_CriticalSection);
  46. }
  47. InterlockedDecrement(&g_cComponent);
  48. }
  49. //////////////////////////////////////////////////////////////////////
  50. // IUnknown
  51. //////////////////////////////////////////////////////////////////////
  52. // CBandTrk::QueryInterface
  53. STDMETHODIMP CBandTrk::QueryInterface(const IID &iid, void **ppv)
  54. {
  55. V_INAME(CBandTrk::QueryInterface);
  56. V_PTRPTR_WRITE(ppv);
  57. V_REFGUID(iid);
  58. if(iid == IID_IUnknown || iid == IID_IDirectMusicTrack || iid == IID_IDirectMusicTrack8)
  59. {
  60. *ppv = static_cast<IDirectMusicTrack8*>(this);
  61. }
  62. else if(iid == IID_IDirectMusicBandTrk)
  63. {
  64. *ppv = static_cast<IDirectMusicBandTrk*>(this);
  65. }
  66. else if(iid == IID_IPersistStream)
  67. {
  68. *ppv = static_cast<IPersistStream*>(this);
  69. }
  70. else if(iid == IID_IPersist)
  71. {
  72. *ppv = static_cast<IPersist*>(this);
  73. }
  74. else
  75. {
  76. Trace(4,"Warning: Request to query unknown interface on Band Track object\n");
  77. *ppv = NULL;
  78. return E_NOINTERFACE;
  79. }
  80. reinterpret_cast<IUnknown*>(this)->AddRef();
  81. return S_OK;
  82. }
  83. //////////////////////////////////////////////////////////////////////
  84. // CBandTrk::AddRef
  85. STDMETHODIMP_(ULONG) CBandTrk::AddRef()
  86. {
  87. return InterlockedIncrement(&m_cRef);
  88. }
  89. //////////////////////////////////////////////////////////////////////
  90. // CBandTrk::Release
  91. STDMETHODIMP_(ULONG) CBandTrk::Release()
  92. {
  93. if(!InterlockedDecrement(&m_cRef))
  94. {
  95. delete this;
  96. return 0;
  97. }
  98. return m_cRef;
  99. }
  100. /////////////////////////////////////////////////////////////////////////////
  101. // IPersist
  102. HRESULT CBandTrk::GetClassID( CLSID* pClassID )
  103. {
  104. V_INAME(CBandTrk::GetClassID);
  105. V_PTR_WRITE(pClassID, CLSID);
  106. *pClassID = CLSID_DirectMusicBandTrack;
  107. return S_OK;
  108. }
  109. //////////////////////////////////////////////////////////////////////
  110. // IPersistStream
  111. //////////////////////////////////////////////////////////////////////
  112. // CBandTrk::Load
  113. STDMETHODIMP CBandTrk::Load(IStream* pIStream)
  114. {
  115. V_INAME(CBandTrk::Load);
  116. V_PTR_READ(pIStream, IStream);
  117. HRESULT hrDLS = S_OK;
  118. EnterCriticalSection(&m_CriticalSection);
  119. m_MidiModeList.CleanUp();
  120. // If we have been previously loaded, cleanup bands
  121. if(!BandList.IsEmpty())
  122. {
  123. m_bAutoDownload = true;
  124. while(!BandList.IsEmpty())
  125. {
  126. CBand* pBand = BandList.RemoveHead();
  127. pBand->Release();
  128. }
  129. ++m_dwValidate;
  130. }
  131. CRiffParser Parser(pIStream);
  132. RIFFIO ckMain;
  133. HRESULT hr = S_OK;
  134. Parser.EnterList(&ckMain);
  135. if (Parser.NextChunk(&hr))
  136. {
  137. if ((ckMain.ckid == FOURCC_RIFF) &&
  138. (ckMain.fccType == DMUS_FOURCC_BANDTRACK_FORM))
  139. {
  140. RIFFIO ckNext; // Descends into the children chunks.
  141. Parser.EnterList(&ckNext);
  142. while (Parser.NextChunk(&hr))
  143. {
  144. switch(ckNext.ckid)
  145. {
  146. case DMUS_FOURCC_BANDTRACK_CHUNK:
  147. DMUS_IO_BAND_TRACK_HEADER ioDMBndTrkHdr;
  148. hr = Parser.Read(&ioDMBndTrkHdr, sizeof(DMUS_IO_BAND_TRACK_HEADER));
  149. if(SUCCEEDED(hr))
  150. {
  151. m_bAutoDownload = ioDMBndTrkHdr.bAutoDownload ? true : false;
  152. m_fLockAutoDownload = true;
  153. }
  154. break;
  155. case FOURCC_LIST:
  156. switch(ckNext.fccType)
  157. {
  158. case DMUS_FOURCC_BANDS_LIST:
  159. hr = BuildDirectMusicBandList(&Parser);
  160. if (hr != S_OK)
  161. {
  162. hrDLS = hr;
  163. }
  164. break;
  165. }
  166. }
  167. }
  168. Parser.LeaveList();
  169. }
  170. }
  171. Parser.LeaveList();
  172. LeaveCriticalSection(&m_CriticalSection);
  173. if (hr == S_OK && hrDLS != S_OK)
  174. {
  175. hr = hrDLS;
  176. }
  177. return hr;
  178. }
  179. //////////////////////////////////////////////////////////////////////
  180. // IDirectMusicTrack
  181. //////////////////////////////////////////////////////////////////////
  182. // CBandTrk::Init
  183. STDMETHODIMP CBandTrk::Init(IDirectMusicSegment* pSegment)
  184. {
  185. V_INAME(CBandTrk::Init);
  186. V_INTERFACE(pSegment);
  187. HRESULT hr = S_OK;
  188. DWORD dwNumPChannels = 0;
  189. DWORD *pdwPChannels = NULL;
  190. EnterCriticalSection(&m_CriticalSection);
  191. CBand* pBand = BandList.GetHead();
  192. for(; pBand; pBand = pBand->GetNext())
  193. {
  194. dwNumPChannels += pBand->GetPChannelCount();
  195. }
  196. if(dwNumPChannels > 0)
  197. {
  198. pdwPChannels = new DWORD[dwNumPChannels];
  199. if(pdwPChannels)
  200. {
  201. pBand = BandList.GetHead();
  202. for(DWORD dwPos = 0; pBand; pBand = pBand->GetNext())
  203. {
  204. DWORD dwNumWritten;
  205. pBand->GetPChannels(pdwPChannels + dwPos, &dwNumWritten);
  206. dwPos += dwNumWritten;
  207. }
  208. }
  209. else
  210. {
  211. hr = E_OUTOFMEMORY;
  212. }
  213. if(SUCCEEDED(hr))
  214. {
  215. hr = pSegment->SetPChannelsUsed(dwNumPChannels, pdwPChannels);
  216. }
  217. delete [] pdwPChannels;
  218. }
  219. LeaveCriticalSection(&m_CriticalSection);
  220. return hr;
  221. }
  222. //////////////////////////////////////////////////////////////////////
  223. // CBandTrk::InitPlay
  224. STDMETHODIMP CBandTrk::InitPlay(IDirectMusicSegmentState* pSegmentState,
  225. IDirectMusicPerformance* pPerformance,
  226. void** ppStateData,
  227. DWORD dwVirtualTrackID,
  228. DWORD dwFlags)
  229. {
  230. V_INAME(CBandTrk::InitPlay);
  231. V_INTERFACE(pSegmentState);
  232. V_INTERFACE(pPerformance);
  233. assert(ppStateData);
  234. EnterCriticalSection(&m_CriticalSection);
  235. CBandTrkStateData* pBandTrkStateData = new CBandTrkStateData;
  236. // If we can not allocate the memory we need to set ppStateData to NULL
  237. // and return S_OK since the caller always expects S_OK;
  238. *ppStateData = pBandTrkStateData;
  239. if(pBandTrkStateData == NULL)
  240. {
  241. LeaveCriticalSection(&m_CriticalSection);
  242. return E_OUTOFMEMORY;
  243. }
  244. // Need to save State Data
  245. pBandTrkStateData->m_pSegmentState = pSegmentState;
  246. pBandTrkStateData->m_pPerformance = pPerformance;
  247. pBandTrkStateData->m_dwVirtualTrackID = dwVirtualTrackID; // Determines instance of Band Track
  248. CBand* pBand = BandList.GetHead();
  249. pBandTrkStateData->m_pNextBandToSPE = pBand;
  250. BOOL fGlobal; // if the performance has been set with an autodownload preference,
  251. // use that. otherwise, assume autodownloading is off, unless it has
  252. // been locked (i.e. specified on the band track.)
  253. if( SUCCEEDED( pPerformance->GetGlobalParam( GUID_PerfAutoDownload, &fGlobal, sizeof(BOOL) )))
  254. {
  255. if( !m_fLockAutoDownload )
  256. {
  257. // it might seem like we can just assign m_bAutoDownload = fGlobal,
  258. // but that's bitten me before, so I'm being paranoid today. (markburt)
  259. if( fGlobal )
  260. {
  261. m_bAutoDownload = true;
  262. }
  263. else
  264. {
  265. m_bAutoDownload = false;
  266. }
  267. }
  268. }
  269. else if( !m_fLockAutoDownload )
  270. {
  271. m_bAutoDownload = false;
  272. }
  273. // Call SetParam to download all instruments used by the track's bands
  274. // This is the auto-download feature that can be turned off with a call to SetParam
  275. if(m_bAutoDownload)
  276. {
  277. IDirectMusicAudioPath *pPath = NULL;
  278. IDirectMusicSegmentState8 *pState8;
  279. if (SUCCEEDED(pSegmentState->QueryInterface(IID_IDirectMusicSegmentState8,(void **)&pState8)))
  280. {
  281. pState8->GetObjectInPath(0,DMUS_PATH_AUDIOPATH,0,GUID_NULL,0,
  282. IID_IDirectMusicAudioPath,(void **) &pPath);
  283. pState8->Release();
  284. }
  285. if (pPath)
  286. {
  287. SetParam(GUID_DownloadToAudioPath,0,(void *)pPath);
  288. pPath->Release();
  289. }
  290. else
  291. {
  292. SetParam(GUID_DownloadToAudioPath, 0, (void *)pPerformance);
  293. }
  294. }
  295. LeaveCriticalSection(&m_CriticalSection);
  296. return S_OK;
  297. }
  298. //////////////////////////////////////////////////////////////////////
  299. // CBandTrk::EndPlay
  300. STDMETHODIMP CBandTrk::EndPlay(void* pStateData)
  301. {
  302. assert(pStateData);
  303. EnterCriticalSection(&m_CriticalSection);
  304. // Call SetParam to unload all instruments used by the track's bands
  305. // This is the auto-unload feature that can be turned off with a call to SetParam
  306. if(m_bAutoDownload)
  307. {
  308. IDirectMusicPerformance *pPerformance = ((CBandTrkStateData *)pStateData)->m_pPerformance;
  309. IDirectMusicSegmentState *pSegmentState = ((CBandTrkStateData *)pStateData)->m_pSegmentState;
  310. IDirectMusicAudioPath *pPath = NULL;
  311. IDirectMusicSegmentState8 *pState8;
  312. if (SUCCEEDED(pSegmentState->QueryInterface(IID_IDirectMusicSegmentState8,(void **)&pState8)))
  313. {
  314. pState8->GetObjectInPath(0,DMUS_PATH_AUDIOPATH,0,GUID_NULL,0,
  315. IID_IDirectMusicAudioPath,(void **) &pPath);
  316. pState8->Release();
  317. }
  318. if (pPath)
  319. {
  320. SetParam(GUID_UnloadFromAudioPath,0,(void *)pPath);
  321. pPath->Release();
  322. }
  323. else
  324. {
  325. SetParam(GUID_UnloadFromAudioPath, 0, (void *)pPerformance);
  326. }
  327. }
  328. if(pStateData)
  329. {
  330. delete ((CBandTrkStateData *)pStateData);
  331. }
  332. LeaveCriticalSection(&m_CriticalSection);
  333. return S_OK;
  334. }
  335. //////////////////////////////////////////////////////////////////////
  336. // CBandTrk::PlayEx
  337. STDMETHODIMP CBandTrk::PlayEx(void* pStateData,REFERENCE_TIME rtStart,
  338. REFERENCE_TIME rtEnd,REFERENCE_TIME rtOffset,
  339. DWORD dwFlags,IDirectMusicPerformance* pPerf,
  340. IDirectMusicSegmentState* pSegSt,DWORD dwVirtualID)
  341. {
  342. HRESULT hr;
  343. EnterCriticalSection(&m_CriticalSection);
  344. if (dwFlags & DMUS_TRACKF_CLOCK)
  345. {
  346. // Convert all reference times to millisecond times. Then, just use same MUSIC_TIME
  347. // variables.
  348. hr = PlayMusicOrClock(pStateData,(MUSIC_TIME)(rtStart / REF_PER_MIL),(MUSIC_TIME)(rtEnd / REF_PER_MIL),
  349. (MUSIC_TIME)(rtOffset / REF_PER_MIL),rtOffset,dwFlags,pPerf,pSegSt,dwVirtualID,TRUE);
  350. }
  351. else
  352. {
  353. hr = PlayMusicOrClock(pStateData,(MUSIC_TIME)rtStart,(MUSIC_TIME)rtEnd,
  354. (MUSIC_TIME)rtOffset,0,dwFlags,pPerf,pSegSt,dwVirtualID,FALSE);
  355. }
  356. LeaveCriticalSection(&m_CriticalSection);
  357. return hr;
  358. }
  359. //////////////////////////////////////////////////////////////////////
  360. // CBandTrk::Play
  361. STDMETHODIMP CBandTrk::Play(
  362. void *pStateData,
  363. MUSIC_TIME mtStart,
  364. MUSIC_TIME mtEnd,
  365. MUSIC_TIME mtOffset,
  366. DWORD dwFlags,
  367. IDirectMusicPerformance* pPerf,
  368. IDirectMusicSegmentState* pSegSt,
  369. DWORD dwVirtualID)
  370. {
  371. EnterCriticalSection(&m_CriticalSection);
  372. HRESULT hr = PlayMusicOrClock(pStateData,mtStart,mtEnd,mtOffset,0,dwFlags,pPerf,pSegSt,dwVirtualID,FALSE);
  373. LeaveCriticalSection(&m_CriticalSection);
  374. return hr;
  375. }
  376. HRESULT CBandTrk::PlayMusicOrClock(
  377. void *pStateData,
  378. MUSIC_TIME mtStart,
  379. MUSIC_TIME mtEnd,
  380. MUSIC_TIME mtOffset,
  381. REFERENCE_TIME rtOffset,
  382. DWORD dwFlags,
  383. IDirectMusicPerformance* pPerf,
  384. IDirectMusicSegmentState* pSegSt,
  385. DWORD dwVirtualID,
  386. bool fClockTime)
  387. {
  388. assert(pPerf);
  389. assert(pSegSt);
  390. assert(pStateData);
  391. // Caller expects S_OK or S_END. Since we have no state info we can not do anything
  392. if(pStateData == NULL)
  393. {
  394. return DMUS_S_END;
  395. }
  396. EnterCriticalSection(&m_CriticalSection);
  397. if( dwFlags & (DMUS_TRACKF_SEEK | DMUS_TRACKF_FLUSH | DMUS_TRACKF_DIRTY |
  398. DMUS_TRACKF_LOOP) )
  399. {
  400. // need to reset the PChannel Map in case of any of these flags.
  401. CBand* pBand = BandList.GetHead();
  402. DWORD dwGroupBits = 0xffffffff;
  403. IDirectMusicSegment* pSeg;
  404. if( SUCCEEDED(pSegSt->GetSegment(&pSeg)))
  405. {
  406. pSeg->GetTrackGroup(this, &dwGroupBits);
  407. pSeg->Release();
  408. }
  409. for(; pBand; pBand = pBand->GetNext())
  410. {
  411. pBand->m_PChMap.Reset();
  412. pBand->m_dwGroupBits = dwGroupBits;
  413. }
  414. }
  415. CBandTrkStateData* pBandTrkStateData = (CBandTrkStateData *)pStateData;
  416. // Seek if we're starting, looping, or if we've been reloaded
  417. if ((dwFlags & DMUS_TRACKF_LOOP) || (dwFlags & DMUS_TRACKF_START) || (pBandTrkStateData->dwValidate != m_dwValidate))
  418. {
  419. // When we start playing a segment, we need to catch up with all the band changes
  420. // that happened before the start point. The instruments that sound when we start
  421. // playing in the middle of a segment should sound the same as if we had played the
  422. // segment to that point from the beginning.
  423. pBandTrkStateData->m_fPlayPreviousInSeek = !!(dwFlags & DMUS_TRACKF_START);
  424. Seek(pBandTrkStateData, mtStart, mtOffset, rtOffset, fClockTime);
  425. pBandTrkStateData->dwValidate = m_dwValidate; // if we were reloading, we're now adjusted
  426. }
  427. // Send all Patch changes between mtStart & mtEnd
  428. // If any fail try next one
  429. CBand* pBand = (CBand *)(pBandTrkStateData->m_pNextBandToSPE);
  430. for( ; pBand && pBand->m_lTimeLogical < mtEnd;
  431. pBand = pBand->GetNext())
  432. {
  433. pBand->SendMessages(pBandTrkStateData, mtOffset, rtOffset, fClockTime);
  434. }
  435. // Save position for next time
  436. pBandTrkStateData->m_pNextBandToSPE = pBand;
  437. LeaveCriticalSection(&m_CriticalSection);
  438. return pBand == NULL ? DMUS_S_END : S_OK;
  439. }
  440. //////////////////////////////////////////////////////////////////////
  441. // CBandTrk::GetParam
  442. STDMETHODIMP CBandTrk::GetParam(REFGUID rguidDataType,
  443. MUSIC_TIME mtTime,
  444. MUSIC_TIME* pmtNext,
  445. void* pData)
  446. {
  447. V_INAME(CBandTrk::GetParam);
  448. V_PTR_WRITE_OPT(pmtNext,MUSIC_TIME);
  449. V_PTR_WRITE(pData,1);
  450. V_REFGUID(rguidDataType);
  451. HRESULT hr = S_OK;
  452. EnterCriticalSection( &m_CriticalSection );
  453. if (rguidDataType == GUID_BandParam)
  454. {
  455. CBand* pScan = BandList.GetHead();
  456. if (pScan)
  457. {
  458. CBand* pBand = pScan;
  459. for (pScan = pScan->GetNext(); pScan; pScan = pScan->GetNext())
  460. {
  461. if (mtTime < pScan->m_lTimeLogical) break;
  462. pBand = pScan;
  463. }
  464. // make a copy of the band found
  465. CBand *pNewBand = new CBand;
  466. if (pNewBand)
  467. {
  468. CBandInstrument* pBandInstrument = pBand->m_BandInstrumentList.GetHead();
  469. for(; pBandInstrument && SUCCEEDED(hr); pBandInstrument = pBandInstrument->GetNext())
  470. {
  471. hr = pNewBand->Load(pBandInstrument);
  472. }
  473. if (FAILED(hr))
  474. {
  475. // Don't leak.
  476. delete pNewBand;
  477. }
  478. else
  479. {
  480. pNewBand->m_lTimeLogical = pBand->m_lTimeLogical;
  481. pNewBand->m_lTimePhysical = pBand->m_lTimePhysical;
  482. pNewBand->m_dwFlags |= DMB_LOADED;
  483. pNewBand->m_dwMidiMode = pBand->m_dwMidiMode;
  484. }
  485. }
  486. else
  487. {
  488. hr = E_OUTOFMEMORY;
  489. }
  490. if (SUCCEEDED(hr))
  491. {
  492. IDirectMusicBand* pIDMBand = NULL;
  493. pNewBand->QueryInterface(IID_IDirectMusicBand, (void**)&pIDMBand);
  494. // The constructor initialized the ref countto 1, so release the QI
  495. pNewBand->Release();
  496. DMUS_BAND_PARAM *pBandParam = reinterpret_cast<DMUS_BAND_PARAM *>(pData);
  497. pBandParam->pBand = pIDMBand;
  498. pBandParam->mtTimePhysical = pBand->m_lTimePhysical;
  499. if (pmtNext)
  500. {
  501. *pmtNext = (pScan != NULL) ? pScan->m_lTimeLogical : 0;
  502. }
  503. hr = S_OK;
  504. }
  505. }
  506. else
  507. {
  508. Trace(4,"Warning: Band Track unable to find Band for GetParam call.\n");
  509. hr = DMUS_E_NOT_FOUND;
  510. }
  511. }
  512. else
  513. {
  514. hr = DMUS_E_GET_UNSUPPORTED;
  515. }
  516. LeaveCriticalSection( &m_CriticalSection );
  517. return hr;
  518. }
  519. //////////////////////////////////////////////////////////////////////
  520. // CBandTrk::SetParam
  521. STDMETHODIMP CBandTrk::SetParam(REFGUID rguidDataType,
  522. MUSIC_TIME mtTime,
  523. void* pData)
  524. {
  525. V_INAME(CBandTrk::SetParam);
  526. V_REFGUID(rguidDataType);
  527. HRESULT hr = S_OK;
  528. if((pData == NULL)
  529. && (rguidDataType != GUID_Enable_Auto_Download)
  530. && (rguidDataType != GUID_Disable_Auto_Download)
  531. && (rguidDataType != GUID_Clear_All_Bands)
  532. && (rguidDataType != GUID_IgnoreBankSelectForGM))
  533. {
  534. Trace(1,"Error: Invalid NULL pointer passed to Band Track for SetParam call.\n");
  535. return E_POINTER;
  536. }
  537. EnterCriticalSection(&m_CriticalSection);
  538. if(rguidDataType == GUID_DownloadToAudioPath)
  539. {
  540. IDirectMusicAudioPath* pPath = (IDirectMusicAudioPath*)pData;
  541. V_INTERFACE(pPath);
  542. HRESULT hrFail = S_OK;
  543. DWORD dwSuccess = 0;
  544. CBand* pBand = BandList.GetHead();
  545. for(; pBand; pBand = pBand->GetNext())
  546. {
  547. if (FAILED(hr = pBand->DownloadEx(pPath))) // If not S_OK, download is only partial.
  548. {
  549. hrFail = hr;
  550. }
  551. else
  552. {
  553. dwSuccess++;
  554. }
  555. }
  556. // If we had a failure, return it if we had no successes.
  557. // Else return S_FALSE for partial success.
  558. if (FAILED(hrFail) && dwSuccess)
  559. {
  560. hr = S_FALSE;
  561. }
  562. }
  563. else if(rguidDataType == GUID_UnloadFromAudioPath)
  564. {
  565. IDirectMusicAudioPath* pPath = (IDirectMusicAudioPath*)pData;
  566. V_INTERFACE(pPath);
  567. CBand* pBand = BandList.GetHead();
  568. for(; pBand; pBand = pBand->GetNext())
  569. {
  570. pBand->UnloadEx(pPath);
  571. }
  572. }
  573. else if(rguidDataType == GUID_Download)
  574. {
  575. IDirectMusicPerformance* pPerf = (IDirectMusicPerformance*)pData;
  576. V_INTERFACE(pPerf);
  577. CBand* pBand = BandList.GetHead();
  578. for(; pBand; pBand = pBand->GetNext())
  579. {
  580. if (pBand->DownloadEx(pPerf) != S_OK) // If not S_OK, download is only partial.
  581. {
  582. hr = S_FALSE;
  583. }
  584. }
  585. }
  586. else if(rguidDataType == GUID_Unload)
  587. {
  588. IDirectMusicPerformance* pPerf = (IDirectMusicPerformance*)pData;
  589. V_INTERFACE(pPerf);
  590. CBand* pBand = BandList.GetHead();
  591. for(; pBand; pBand = pBand->GetNext())
  592. {
  593. pBand->UnloadEx(pPerf);
  594. }
  595. }
  596. else if(rguidDataType == GUID_Enable_Auto_Download)
  597. {
  598. m_bAutoDownload = true;
  599. m_fLockAutoDownload = true;
  600. }
  601. else if(rguidDataType == GUID_Disable_Auto_Download)
  602. {
  603. m_bAutoDownload = false;
  604. m_fLockAutoDownload = true;
  605. }
  606. else if(rguidDataType == GUID_Clear_All_Bands)
  607. {
  608. while(!BandList.IsEmpty())
  609. {
  610. CBand* pBand = BandList.RemoveHead();
  611. pBand->Release();
  612. }
  613. }
  614. else if(rguidDataType == GUID_BandParam)
  615. {
  616. DMUS_BAND_PARAM *pBandParam = reinterpret_cast<DMUS_BAND_PARAM *>(pData);
  617. IDirectMusicBand *pBand = pBandParam->pBand;
  618. V_INTERFACE(pBand);
  619. // If you can QI pData for private interface IDirectMusicBandPrivate
  620. // pBand is of type CBand.
  621. IDirectMusicBandPrivate *pBandPrivate = NULL;
  622. hr = pBand->QueryInterface(IID_IDirectMusicBandPrivate, (void **)&pBandPrivate);
  623. if(FAILED(hr))
  624. {
  625. LeaveCriticalSection(&m_CriticalSection);
  626. return hr;
  627. }
  628. pBandPrivate->Release();
  629. CBand *pBandObject = static_cast<CBand *>(pBand);
  630. pBandObject->m_lTimeLogical = mtTime;
  631. pBandObject->m_lTimePhysical = pBandParam->mtTimePhysical;
  632. hr = AddBand(pBand);
  633. }
  634. else if(rguidDataType == GUID_IDirectMusicBand)
  635. {
  636. IDirectMusicBand *pBand = (IDirectMusicBand *)pData;
  637. V_INTERFACE(pBand);
  638. // If you can QI pData for private interface IDirectMusicBandPrivate
  639. // pData is of type CBand.
  640. IDirectMusicBandPrivate *pBandPrivate = NULL;
  641. hr = pBand->QueryInterface(IID_IDirectMusicBandPrivate, (void **)&pBandPrivate);
  642. if(FAILED(hr))
  643. {
  644. LeaveCriticalSection(&m_CriticalSection);
  645. return hr;
  646. }
  647. pBandPrivate->Release();
  648. CBand *pBandObject = static_cast<CBand *>(pBand);
  649. pBandObject->m_lTimeLogical = mtTime;
  650. pBandObject->m_lTimePhysical = pBandObject->m_lTimeLogical;
  651. hr = AddBand(pBand);
  652. }
  653. else if(rguidDataType == GUID_IgnoreBankSelectForGM)
  654. {
  655. CBand* pBand = BandList.GetHead();
  656. for(; pBand; pBand = pBand->GetNext())
  657. {
  658. pBand->MakeGMOnly();
  659. }
  660. }
  661. else if(rguidDataType == GUID_ConnectToDLSCollection)
  662. {
  663. IDirectMusicCollection* pCollect = (IDirectMusicCollection*)pData;
  664. V_INTERFACE(pData);
  665. CBand* pBand = BandList.GetHead();
  666. for(; pBand; pBand = pBand->GetNext())
  667. {
  668. pBand->ConnectToDLSCollection(pCollect);
  669. }
  670. }
  671. else
  672. {
  673. Trace(3,"Warning: Invalid SetParam call on Band Track, GUID is unknown.\n");
  674. hr = DMUS_E_TYPE_UNSUPPORTED;
  675. }
  676. LeaveCriticalSection(&m_CriticalSection);
  677. return hr;
  678. }
  679. //////////////////////////////////////////////////////////////////////
  680. // CBandTrk::GetParamEx
  681. STDMETHODIMP CBandTrk::GetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime,
  682. REFERENCE_TIME* prtNext,void* pParam,void * pStateData, DWORD dwFlags)
  683. {
  684. HRESULT hr;
  685. MUSIC_TIME mtNext;
  686. if (dwFlags & DMUS_TRACK_PARAMF_CLOCK)
  687. {
  688. hr = GetParam(rguidType,(MUSIC_TIME) (rtTime / REF_PER_MIL), &mtNext, pParam);
  689. if (prtNext)
  690. {
  691. *prtNext = mtNext * REF_PER_MIL;
  692. }
  693. }
  694. else
  695. {
  696. hr = GetParam(rguidType,(MUSIC_TIME) rtTime, &mtNext, pParam);
  697. if (prtNext)
  698. {
  699. *prtNext = mtNext;
  700. }
  701. }
  702. return hr;
  703. }
  704. //////////////////////////////////////////////////////////////////////
  705. // CBandTrk::SetParamEx
  706. STDMETHODIMP CBandTrk::SetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime,
  707. void* pParam, void * pStateData, DWORD dwFlags)
  708. {
  709. if (dwFlags & DMUS_TRACK_PARAMF_CLOCK)
  710. {
  711. rtTime /= REF_PER_MIL;
  712. }
  713. return SetParam(rguidType, (MUSIC_TIME) rtTime, pParam);
  714. }
  715. //////////////////////////////////////////////////////////////////////
  716. // CBandTrk::IsParamSupported
  717. STDMETHODIMP CBandTrk::IsParamSupported(REFGUID rguidDataType)
  718. {
  719. V_INAME(CBandTrk::IsParamSupported);
  720. V_REFGUID(rguidDataType);
  721. // Return S_OK if the object supports the GUID and S_FALSE otherwise
  722. if(rguidDataType == GUID_Download ||
  723. rguidDataType == GUID_Unload ||
  724. rguidDataType == GUID_DownloadToAudioPath ||
  725. rguidDataType == GUID_UnloadFromAudioPath ||
  726. rguidDataType == GUID_Enable_Auto_Download ||
  727. rguidDataType == GUID_Disable_Auto_Download ||
  728. rguidDataType == GUID_Clear_All_Bands ||
  729. rguidDataType == GUID_IDirectMusicBand ||
  730. rguidDataType == GUID_BandParam ||
  731. rguidDataType == GUID_IgnoreBankSelectForGM ||
  732. rguidDataType == GUID_ConnectToDLSCollection)
  733. {
  734. return S_OK;
  735. }
  736. else
  737. {
  738. return DMUS_E_TYPE_UNSUPPORTED;
  739. }
  740. }
  741. //////////////////////////////////////////////////////////////////////
  742. // CBandTrk::AddNotificationType
  743. STDMETHODIMP CBandTrk::AddNotificationType(REFGUID rguidNotify)
  744. {
  745. return E_NOTIMPL;
  746. }
  747. //////////////////////////////////////////////////////////////////////
  748. // CBandTrk::RemoveNotificationType
  749. STDMETHODIMP CBandTrk::RemoveNotificationType(REFGUID rguidNotify)
  750. {
  751. return E_NOTIMPL;
  752. }
  753. //////////////////////////////////////////////////////////////////////
  754. // CBandTrk::Clone
  755. STDMETHODIMP CBandTrk::Clone(MUSIC_TIME mtStart,
  756. MUSIC_TIME mtEnd,
  757. IDirectMusicTrack** ppTrack)
  758. {
  759. V_INAME(CBandTrk::Clone);
  760. V_PTRPTR_WRITE(ppTrack);
  761. if ((mtStart < 0 ) || (mtStart > mtEnd))
  762. {
  763. Trace(1,"Error: Invalid range %ld to %ld sent to Band Track Clone command.\n",mtStart,mtEnd);
  764. return E_INVALIDARG;
  765. }
  766. HRESULT hr = E_OUTOFMEMORY;
  767. IDirectMusicBandTrk *pBandTrack = NULL;
  768. CBandTrk *pNew = new CBandTrk;
  769. if (pNew)
  770. {
  771. hr = pNew->QueryInterface(IID_IDirectMusicBandTrk,(void**)&pBandTrack);
  772. if(SUCCEEDED(hr))
  773. {
  774. hr = LoadClone(pBandTrack, mtStart, mtEnd);
  775. if(SUCCEEDED(hr))
  776. {
  777. hr = pBandTrack->QueryInterface(IID_IDirectMusicTrack, (void **)ppTrack);
  778. if (SUCCEEDED(hr))
  779. {
  780. pBandTrack->Release();
  781. }
  782. }
  783. pBandTrack->Release();
  784. }
  785. if (FAILED(hr))
  786. {
  787. delete pNew;
  788. }
  789. }
  790. return hr;
  791. }
  792. //////////////////////////////////////////////////////////////////////
  793. // IDirectMusicCommon
  794. //////////////////////////////////////////////////////////////////////
  795. // CBandTrk::GetName
  796. STDMETHODIMP CBandTrk::GetName(BSTR* pbstrName)
  797. {
  798. return E_NOTIMPL;
  799. }
  800. //////////////////////////////////////////////////////////////////////
  801. // IDirectMusicBandTrk
  802. //////////////////////////////////////////////////////////////////////
  803. // CBandTrk::AddBand
  804. STDMETHODIMP CBandTrk::AddBand(DMUS_IO_PATCH_ITEM* pPatchEvent)
  805. {
  806. if(pPatchEvent == NULL)
  807. {
  808. return E_POINTER;
  809. }
  810. CBand *pNewBand = new CBand;
  811. HRESULT hr;
  812. if(pNewBand == NULL)
  813. {
  814. hr = E_OUTOFMEMORY;
  815. }
  816. else
  817. {
  818. hr = pNewBand->Load(*pPatchEvent);
  819. }
  820. if(SUCCEEDED(hr))
  821. {
  822. hr = InsertBand(pNewBand);
  823. }
  824. if(FAILED(hr) && pNewBand)
  825. {
  826. delete pNewBand;
  827. }
  828. return hr;
  829. }
  830. //////////////////////////////////////////////////////////////////////
  831. // CBandTrk::AddBand
  832. HRESULT CBandTrk::AddBand(IDirectMusicBand* pIDMBand)
  833. {
  834. if(pIDMBand == NULL)
  835. {
  836. return E_POINTER;
  837. }
  838. // If you can QI pIDMBand for private interface IDirectMusicBandPrivate
  839. // pIDMBand is of type CBand.
  840. IDirectMusicBandPrivate* pIDMBandP = NULL;
  841. HRESULT hr = pIDMBand->QueryInterface(IID_IDirectMusicBandPrivate, (void **)&pIDMBandP);
  842. if(SUCCEEDED(hr))
  843. {
  844. pIDMBandP->Release();
  845. CBand *pNewBand = (CBand *) pIDMBand;
  846. pNewBand->AddRef();
  847. hr = InsertBand(pNewBand);
  848. if(FAILED(hr))
  849. {
  850. pNewBand->Release();
  851. }
  852. }
  853. return hr;
  854. }
  855. //////////////////////////////////////////////////////////////////////
  856. // Internal
  857. //////////////////////////////////////////////////////////////////////
  858. // CBandTrk::BuildDirectMusicBandList
  859. // This method loads all of the bands.
  860. HRESULT CBandTrk::BuildDirectMusicBandList(CRiffParser *pParser)
  861. {
  862. RIFFIO ckNext;
  863. HRESULT hrDLS = S_OK;
  864. HRESULT hr = S_OK;
  865. pParser->EnterList(&ckNext);
  866. while (pParser->NextChunk(&hr))
  867. {
  868. switch(ckNext.ckid)
  869. {
  870. case FOURCC_LIST :
  871. switch(ckNext.fccType)
  872. {
  873. case DMUS_FOURCC_BAND_LIST:
  874. hr = ExtractBand(pParser);
  875. if (hr != S_OK)
  876. {
  877. hrDLS = hr;
  878. }
  879. break;
  880. }
  881. break;
  882. }
  883. }
  884. pParser->LeaveList();
  885. if (hr == S_OK && hrDLS != S_OK)
  886. {
  887. hr = hrDLS;
  888. }
  889. return hr;
  890. }
  891. //////////////////////////////////////////////////////////////////////
  892. // CBandTrk::ExtractBand
  893. HRESULT
  894. CBandTrk::ExtractBand(CRiffParser *pParser)
  895. {
  896. HRESULT hrDLS = S_OK;
  897. RIFFIO ckNext;
  898. CBand *pBand = new CBand;
  899. if(pBand == NULL)
  900. {
  901. return E_OUTOFMEMORY;
  902. }
  903. HRESULT hr = S_OK;
  904. bool fFoundChunk2 = false;
  905. pParser->EnterList(&ckNext);
  906. while (pParser->NextChunk(&hr))
  907. {
  908. switch(ckNext.ckid)
  909. {
  910. case DMUS_FOURCC_BANDITEM_CHUNK2:
  911. fFoundChunk2 = true;
  912. DMUS_IO_BAND_ITEM_HEADER2 ioDMBndItemHdr2;
  913. hr = pParser->Read(&ioDMBndItemHdr2, sizeof(DMUS_IO_BAND_ITEM_HEADER2));
  914. if(SUCCEEDED(hr))
  915. {
  916. pBand->m_lTimeLogical = ioDMBndItemHdr2.lBandTimeLogical;
  917. pBand->m_lTimePhysical = ioDMBndItemHdr2.lBandTimePhysical;
  918. }
  919. break;
  920. case DMUS_FOURCC_BANDITEM_CHUNK:
  921. // if there is both a CHUNK and a CHUNK2, use the info from CHUNK2
  922. if (fFoundChunk2)
  923. break;
  924. DMUS_IO_BAND_ITEM_HEADER ioDMBndItemHdr;
  925. hr = pParser->Read(&ioDMBndItemHdr, sizeof(DMUS_IO_BAND_ITEM_HEADER));
  926. if(SUCCEEDED(hr))
  927. {
  928. pBand->m_lTimeLogical = ioDMBndItemHdr.lBandTime;
  929. pBand->m_lTimePhysical = pBand->m_lTimeLogical;
  930. }
  931. break;
  932. case FOURCC_RIFF:
  933. switch(ckNext.fccType)
  934. {
  935. case DMUS_FOURCC_BAND_FORM:
  936. pParser->SeekBack();
  937. hr = LoadBand(pParser->GetStream(), pBand);
  938. pParser->SeekForward();
  939. if (hr != S_OK)
  940. {
  941. hrDLS = hr;
  942. }
  943. break;
  944. }
  945. break;
  946. default:
  947. break;
  948. }
  949. }
  950. pParser->LeaveList();
  951. if(SUCCEEDED(hr))
  952. {
  953. hr = AddBand(pBand);
  954. }
  955. pBand->Release();
  956. if (hr == S_OK && hrDLS != S_OK)
  957. {
  958. hr = hrDLS;
  959. }
  960. return hr;
  961. }
  962. //////////////////////////////////////////////////////////////////////
  963. // CBandTrk::LoadBand
  964. HRESULT CBandTrk::LoadBand(IStream *pIStream, CBand* pBand)
  965. {
  966. assert(pIStream);
  967. assert(pBand);
  968. IPersistStream *pIPersistStream = NULL;
  969. HRESULT hr = pBand->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
  970. if(SUCCEEDED(hr))
  971. {
  972. hr = pIPersistStream->Load(pIStream);
  973. pIPersistStream->Release();
  974. }
  975. return hr;
  976. }
  977. //////////////////////////////////////////////////////////////////////
  978. // CBandTrk::LoadClone
  979. HRESULT CBandTrk::LoadClone(IDirectMusicBandTrk* pBandTrack,
  980. MUSIC_TIME mtStart,
  981. MUSIC_TIME mtEnd)
  982. {
  983. assert(pBandTrack);
  984. assert(mtStart <= mtEnd);
  985. EnterCriticalSection(&m_CriticalSection);
  986. HRESULT hr = S_OK;
  987. if (mtStart > 0)
  988. {
  989. // We will take all the bands before the start time and create a single new band
  990. // at logical time zero, physical time either -1 or one tick before the physical time
  991. // of the first band after the start time, that accumulates all the instrument changes
  992. // from the earlier bands.
  993. TList<SeekEvent> SEList; // Build a list of all the instrument changes for the new band
  994. DWORD dwLastMidiMode = 0; // Keep track of the MIDI mode of the last band we encounter
  995. for( CBand* pBand = BandList.GetHead();
  996. pBand && pBand->m_lTimeLogical < mtStart;
  997. pBand = pBand->GetNext())
  998. {
  999. for(CBandInstrument* pInstrument = (pBand->m_BandInstrumentList).GetHead();
  1000. pInstrument && SUCCEEDED(hr);
  1001. pInstrument = pInstrument->GetNext())
  1002. {
  1003. // replace if we already have an entry on that channel
  1004. hr = FindSEReplaceInstr(SEList,
  1005. pInstrument->m_dwPChannel,
  1006. pInstrument);
  1007. // otherwise add an entry
  1008. if(hr == S_FALSE)
  1009. {
  1010. TListItem<SeekEvent>* pSEListItem = new TListItem<SeekEvent>;
  1011. if(pSEListItem)
  1012. {
  1013. SeekEvent& rSeekEvent = pSEListItem->GetItemValue();
  1014. rSeekEvent.m_dwPChannel = pInstrument->m_dwPChannel;
  1015. rSeekEvent.m_pInstrument = pInstrument;
  1016. rSeekEvent.m_pParentBand = pBand;
  1017. dwLastMidiMode = pBand->m_dwMidiMode;
  1018. SEList.AddHead(pSEListItem);
  1019. }
  1020. else
  1021. {
  1022. hr = E_OUTOFMEMORY;
  1023. }
  1024. }
  1025. }
  1026. }
  1027. // Make sure the physical time of the new band is less than any bands being cloned.
  1028. MUSIC_TIME mtNewPhysicalTime = -1;
  1029. if (pBand && pBand->m_lTimePhysical <= mtStart)
  1030. {
  1031. mtNewPhysicalTime = (pBand->m_lTimePhysical - mtStart) - 1;
  1032. }
  1033. // Create the new band from the instrument list
  1034. TListItem<SeekEvent>* pSEListItem = SEList.GetHead();
  1035. if(SUCCEEDED(hr) && pSEListItem)
  1036. {
  1037. CBand *pNewBand = new CBand;
  1038. if(pNewBand)
  1039. {
  1040. for(; pSEListItem && SUCCEEDED(hr); pSEListItem = pSEListItem->GetNext())
  1041. {
  1042. SeekEvent& rSeekEvent = pSEListItem->GetItemValue();
  1043. hr = pNewBand->Load(rSeekEvent.m_pInstrument);
  1044. }
  1045. pNewBand->m_lTimeLogical = 0;
  1046. pNewBand->m_lTimePhysical = mtNewPhysicalTime;
  1047. pNewBand->m_dwFlags |= DMB_LOADED;
  1048. pNewBand->m_dwMidiMode = dwLastMidiMode;
  1049. if(SUCCEEDED(hr))
  1050. {
  1051. hr = pBandTrack->AddBand(pNewBand);
  1052. }
  1053. pNewBand->Release();
  1054. }
  1055. else
  1056. {
  1057. hr = E_OUTOFMEMORY;
  1058. }
  1059. }
  1060. }
  1061. // Copy all the bands between the start and the end time
  1062. if(SUCCEEDED(hr))
  1063. {
  1064. for(CBand* pBand = BandList.GetHead();
  1065. pBand && SUCCEEDED(hr);
  1066. pBand = pBand->GetNext())
  1067. {
  1068. // If mtStart is 0, accept bands with negative times.
  1069. if ((!mtStart || (pBand->m_lTimeLogical >= mtStart)) && pBand->m_lTimeLogical < mtEnd)
  1070. {
  1071. CBand *pNewBand = new CBand;
  1072. if (pNewBand)
  1073. {
  1074. CBandInstrument* pBandInstrument = pBand->m_BandInstrumentList.GetHead();
  1075. for(; pBandInstrument && SUCCEEDED(hr); pBandInstrument = pBandInstrument->GetNext())
  1076. {
  1077. hr = pNewBand->Load(pBandInstrument);
  1078. }
  1079. pNewBand->m_lTimeLogical = pBand->m_lTimeLogical - mtStart;
  1080. pNewBand->m_lTimePhysical = pBand->m_lTimePhysical - mtStart;
  1081. pNewBand->m_dwFlags |= DMB_LOADED;
  1082. pNewBand->m_dwMidiMode = pBand->m_dwMidiMode;
  1083. if(SUCCEEDED(hr))
  1084. {
  1085. hr = pBandTrack->AddBand(pNewBand);
  1086. }
  1087. pNewBand->Release();
  1088. }
  1089. else
  1090. {
  1091. hr = E_OUTOFMEMORY;
  1092. }
  1093. }
  1094. }
  1095. }
  1096. LeaveCriticalSection(&m_CriticalSection);
  1097. return hr;
  1098. }
  1099. //////////////////////////////////////////////////////////////////////
  1100. // CBandTrk::Seek
  1101. HRESULT CBandTrk::Seek(CBandTrkStateData* pBandTrkStateData,
  1102. MUSIC_TIME mtStart,
  1103. MUSIC_TIME mtOffset,
  1104. REFERENCE_TIME rtOffset,
  1105. bool fClockTime)
  1106. {
  1107. assert(pBandTrkStateData);
  1108. EnterCriticalSection(&m_CriticalSection);
  1109. HRESULT hr = S_OK;
  1110. CBand *pBand;
  1111. int iPrevBandCount = 0; // count how many bands before mtStart
  1112. for (pBand = BandList.GetHead();
  1113. pBand && pBand->m_lTimeLogical < mtStart;
  1114. pBand = pBand->GetNext())
  1115. {
  1116. ++iPrevBandCount;
  1117. }
  1118. // pBand now holds the first band >= mtStart (or NULL if none)
  1119. // This is the next band that will be played.
  1120. assert(!pBand || pBand->m_lTimeLogical >= mtStart);
  1121. if (pBandTrkStateData->m_fPlayPreviousInSeek)
  1122. {
  1123. // When this flag is on not only do we need to find the first band, but we also
  1124. // need to play all the bands before the start point and schedule them to play
  1125. // in the correct order just beforehand.
  1126. // (Note that we're going to order them according to their logical times. If
  1127. // two bands's logical/physical times cross each other we'll play them in
  1128. // incorrect order in terms of physical time. That's OK because giving
  1129. // band A with a logical time before band B, yet giving A a physical time
  1130. // after B is considered an authoring inconsistency. We'll play band A first.)
  1131. // We will line up the bands just before the following time...
  1132. MUSIC_TIME mtPrevBandQueueStart =
  1133. (pBand && pBand->m_lTimePhysical < mtStart)
  1134. ? pBand->m_lTimePhysical // put previous bands before next band to play if (due to anticipation) its physical time precedes the start time we're seeking
  1135. : mtStart; // otherwise put them just before the start time
  1136. for (pBand = BandList.GetHead();
  1137. pBand && pBand->m_lTimeLogical < mtStart;
  1138. pBand = pBand->GetNext())
  1139. {
  1140. CBandInstrument* pInstrument = (pBand->m_BandInstrumentList).GetHead();
  1141. for (; pInstrument && SUCCEEDED(hr); pInstrument = pInstrument->GetNext())
  1142. {
  1143. pBand->SendInstrumentAtTime(pInstrument, pBandTrkStateData, mtPrevBandQueueStart - iPrevBandCount, mtOffset, rtOffset, fClockTime);
  1144. }
  1145. --iPrevBandCount;
  1146. }
  1147. assert(iPrevBandCount == 0);
  1148. }
  1149. if(SUCCEEDED(hr))
  1150. {
  1151. // Set the state data to the next band to play
  1152. assert(!pBand || pBand->m_lTimeLogical >= mtStart);
  1153. pBandTrkStateData->m_pNextBandToSPE = pBand;
  1154. }
  1155. LeaveCriticalSection(&m_CriticalSection);
  1156. return hr;
  1157. }
  1158. //////////////////////////////////////////////////////////////////////
  1159. // CBandTrk::FindSEReplaceInstr
  1160. // If SEList contains an entry on channel dwPChannel, replace the instrument with pInstrument and return S_OK
  1161. // Otherwise return S_FALSE
  1162. HRESULT CBandTrk::FindSEReplaceInstr(TList<SeekEvent>& SEList,
  1163. DWORD dwPChannel,
  1164. CBandInstrument* pInstrument)
  1165. {
  1166. assert(pInstrument);
  1167. EnterCriticalSection(&m_CriticalSection);
  1168. TListItem<SeekEvent>* pSEListItem = SEList.GetHead();
  1169. for( ; pSEListItem; pSEListItem = pSEListItem->GetNext())
  1170. {
  1171. SeekEvent& rSeekEvent = pSEListItem->GetItemValue();
  1172. if(rSeekEvent.m_dwPChannel == dwPChannel)
  1173. {
  1174. rSeekEvent.m_pInstrument = pInstrument;
  1175. LeaveCriticalSection(&m_CriticalSection);
  1176. return S_OK;
  1177. }
  1178. }
  1179. LeaveCriticalSection(&m_CriticalSection);
  1180. return S_FALSE;
  1181. }
  1182. //////////////////////////////////////////////////////////////////////
  1183. // CBandTrk::InsertBand
  1184. HRESULT CBandTrk::InsertBand(CBand* pNewBand)
  1185. {
  1186. if (!pNewBand) return E_POINTER;
  1187. EnterCriticalSection(&m_CriticalSection);
  1188. TListItem<StampedGMGSXG>* pPair = m_MidiModeList.GetHead();
  1189. for ( ; pPair; pPair = pPair->GetNext() )
  1190. {
  1191. StampedGMGSXG& rPair = pPair->GetItemValue();
  1192. if (rPair.mtTime > pNewBand->m_lTimeLogical)
  1193. {
  1194. break;
  1195. }
  1196. pNewBand->SetGMGSXGMode(rPair.dwMidiMode);
  1197. }
  1198. CBand* pBand = BandList.GetHead();
  1199. CBand* pPrevBand = NULL;
  1200. if(pBand == NULL)
  1201. {
  1202. // Handles case where there is no band in the list
  1203. BandList.AddHead(pNewBand);
  1204. }
  1205. else
  1206. {
  1207. while(pBand != NULL && pNewBand->m_lTimeLogical > pBand->m_lTimeLogical)
  1208. {
  1209. pPrevBand = pBand;
  1210. pBand = pBand->GetNext();
  1211. }
  1212. if(pPrevBand)
  1213. {
  1214. // Handles the cases of inserting a band in the middle of list
  1215. // and at the end
  1216. CBand* pTemp = pPrevBand->GetNext();
  1217. pPrevBand->SetNext(pNewBand);
  1218. pNewBand->SetNext(pTemp);
  1219. }
  1220. else
  1221. {
  1222. // Handles case where pNewBand->m_lTimeLogical < all pBand->m_lTimeLogical in list
  1223. BandList.AddHead(pNewBand);
  1224. }
  1225. }
  1226. LeaveCriticalSection(&m_CriticalSection);
  1227. return S_OK;
  1228. }
  1229. STDMETHODIMP CBandTrk::Compose(
  1230. IUnknown* pContext,
  1231. DWORD dwTrackGroup,
  1232. IDirectMusicTrack** ppResultTrack)
  1233. {
  1234. return E_NOTIMPL;
  1235. }
  1236. STDMETHODIMP CBandTrk::Join(
  1237. IDirectMusicTrack* pNewTrack,
  1238. MUSIC_TIME mtJoin,
  1239. IUnknown* pContext,
  1240. DWORD dwTrackGroup,
  1241. IDirectMusicTrack** ppResultTrack)
  1242. {
  1243. V_INAME(IDirectMusicTrack::Join);
  1244. V_INTERFACE(pNewTrack);
  1245. V_INTERFACE_OPT(pContext);
  1246. V_PTRPTR_WRITE_OPT(ppResultTrack);
  1247. HRESULT hr = S_OK;
  1248. EnterCriticalSection(&m_CriticalSection);
  1249. if (ppResultTrack)
  1250. {
  1251. hr = Clone(0, mtJoin, ppResultTrack);
  1252. if (SUCCEEDED(hr))
  1253. {
  1254. hr = ((CBandTrk*)*ppResultTrack)->JoinInternal(pNewTrack, mtJoin, dwTrackGroup);
  1255. }
  1256. }
  1257. else
  1258. {
  1259. hr = JoinInternal(pNewTrack, mtJoin, dwTrackGroup);
  1260. }
  1261. LeaveCriticalSection(&m_CriticalSection);
  1262. return hr;
  1263. }
  1264. HRESULT CBandTrk::JoinInternal(
  1265. IDirectMusicTrack* pNewTrack,
  1266. MUSIC_TIME mtJoin,
  1267. DWORD dwTrackGroup)
  1268. {
  1269. HRESULT hr = S_OK;
  1270. CBandTrk* pOtherTrack = (CBandTrk*)pNewTrack;
  1271. for(CBand* pBand = pOtherTrack->BandList.GetHead();
  1272. pBand && SUCCEEDED(hr);
  1273. pBand = pBand->GetNext())
  1274. {
  1275. CBand *pNewBand = new CBand;
  1276. if (pNewBand)
  1277. {
  1278. CBandInstrument* pBandInstrument = pBand->m_BandInstrumentList.GetHead();
  1279. for(; pBandInstrument && SUCCEEDED(hr); pBandInstrument = pBandInstrument->GetNext())
  1280. {
  1281. hr = pNewBand->Load(pBandInstrument);
  1282. }
  1283. pNewBand->m_lTimeLogical = pBand->m_lTimeLogical + mtJoin;
  1284. pNewBand->m_lTimePhysical = pBand->m_lTimePhysical + mtJoin;
  1285. pNewBand->m_dwFlags |= DMB_LOADED;
  1286. pNewBand->m_dwMidiMode = pBand->m_dwMidiMode;
  1287. if(SUCCEEDED(hr))
  1288. {
  1289. hr = AddBand(pNewBand);
  1290. }
  1291. pNewBand->Release();
  1292. }
  1293. else
  1294. {
  1295. hr = E_OUTOFMEMORY;
  1296. }
  1297. }
  1298. return hr;
  1299. }