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.

1127 lines
34 KiB

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