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.

1947 lines
67 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) 1999-1999 Microsoft Corporation
  6. //
  7. // File: mgentrk.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
  11. //
  12. // 4530: C++ exception handler used, but unwind semantics are not enabled. Specify -GX
  13. //
  14. // We disable this because we use exceptions and do *not* specify -GX (USE_NATIVE_EH in
  15. // sources).
  16. //
  17. // The one place we use exceptions is around construction of objects that call
  18. // InitializeCriticalSection. We guarantee that it is safe to use in this case with
  19. // the restriction given by not using -GX (automatic objects in the call chain between
  20. // throw and handler are not destructed). Turning on -GX buys us nothing but +10% to code
  21. // size because of the unwind code.
  22. //
  23. // Any other use of exceptions must follow these restrictions or -GX must be turned on.
  24. //
  25. // READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
  26. //
  27. #pragma warning(disable:4530)
  28. // MGenTrk.cpp : Implementation of CMelodyFormulationTrack
  29. #include "MGenTrk.h"
  30. #include "dmstyle.h"
  31. #include "debug.h"
  32. #include "..\shared\Validate.h"
  33. DirectMusicTimeSig CompositionFragment::m_staticTimeSig(4, 4, 4);
  34. const BYTE g_bDefaultPlaymode = DMUS_PLAYMODE_ALWAYSPLAY;
  35. // Since one of these is typedef'd to the other, we only need a single
  36. // implementation that does a structure-wide copy (but keep the other 3 implementations
  37. // around, in case we separate the types out later)
  38. HRESULT CopyMelodyFragment(DMUS_MELODY_FRAGMENT& rTo, const DMUS_MELODY_FRAGMENT& rFrom)
  39. {
  40. rTo = rFrom;
  41. rTo.dwPlayModeFlags = DMUS_PLAYMODE_NONE; // only flag supported for dx8
  42. return S_OK;
  43. }
  44. BOOL Less(DMUS_IO_SEQ_ITEM& SeqItem1, DMUS_IO_SEQ_ITEM& SeqItem2)
  45. { return SeqItem1.mtTime + SeqItem1.nOffset < SeqItem2.mtTime + SeqItem2.nOffset; }
  46. BOOL Greater(DMUS_IO_SEQ_ITEM& SeqItem1, DMUS_IO_SEQ_ITEM& SeqItem2)
  47. { return SeqItem1.mtTime + SeqItem1.nOffset > SeqItem2.mtTime + SeqItem2.nOffset; }
  48. BOOL Less(EventWrapper& SeqItem1, EventWrapper& SeqItem2)
  49. {
  50. MUSIC_TIME mtOffset1 = SeqItem1.m_pEvent ? SeqItem1.m_pEvent->m_nTimeOffset : 0;
  51. MUSIC_TIME mtOffset2 = SeqItem2.m_pEvent ? SeqItem2.m_pEvent->m_nTimeOffset : 0;
  52. return SeqItem1.m_mtTime + mtOffset1 < SeqItem2.m_mtTime + mtOffset2;
  53. }
  54. BOOL Greater(EventWrapper& SeqItem1, EventWrapper& SeqItem2)
  55. {
  56. MUSIC_TIME mtOffset1 = SeqItem1.m_pEvent ? SeqItem1.m_pEvent->m_nTimeOffset : 0;
  57. MUSIC_TIME mtOffset2 = SeqItem2.m_pEvent ? SeqItem2.m_pEvent->m_nTimeOffset : 0;
  58. return SeqItem1.m_mtTime + mtOffset1 > SeqItem2.m_mtTime + mtOffset2;
  59. }
  60. /*
  61. HRESULT CopyMelodyFragment(DMUS_MELODY_FRAGMENT& rTo, const DMUS_IO_MELODY_FRAGMENT& rFrom)
  62. {
  63. rTo = rFrom;
  64. return S_OK;
  65. }
  66. HRESULT CopyMelodyFragment(DMUS_IO_MELODY_FRAGMENT& rTo, const DMUS_MELODY_FRAGMENT& rFrom)
  67. {
  68. rTo = rFrom;
  69. return S_OK;
  70. }
  71. HRESULT CopyMelodyFragment(DMUS_IO_MELODY_FRAGMENT& rTo, const DMUS_IO_MELODY_FRAGMENT& rFrom)
  72. {
  73. rTo = rFrom;
  74. return S_OK;
  75. }
  76. */
  77. /////////////////////////////////////////////////////////////////////////////
  78. // CMelodyFormulationTrack
  79. CMelodyFormulationTrack::CMelodyFormulationTrack() :
  80. m_bRequiresSave(0), m_dwLastId(0), m_bPlaymode(g_bDefaultPlaymode),
  81. m_cRef(1), m_fNotifyRecompose(FALSE)
  82. {
  83. // Do this first since it might throw an exception
  84. //
  85. ::InitializeCriticalSection( &m_CriticalSection );
  86. InterlockedIncrement(&g_cComponent);
  87. }
  88. CMelodyFormulationTrack::CMelodyFormulationTrack(const CMelodyFormulationTrack& rTrack, MUSIC_TIME mtStart, MUSIC_TIME mtEnd) :
  89. m_bRequiresSave(0), m_dwLastId(rTrack.m_dwLastId), m_bPlaymode(rTrack.m_bPlaymode),
  90. m_cRef(1), m_fNotifyRecompose(FALSE)
  91. {
  92. // Do this first since it might throw an exception
  93. //
  94. ::InitializeCriticalSection( &m_CriticalSection );
  95. InterlockedIncrement(&g_cComponent);
  96. m_bPlaymode = rTrack.m_bPlaymode;
  97. BOOL fStarted = FALSE;
  98. TListItem<DMUS_MELODY_FRAGMENT>* pScan = rTrack.m_FragmentList.GetHead();
  99. TListItem<DMUS_MELODY_FRAGMENT>* pPrevious = NULL;
  100. for(; pScan; pScan = pScan->GetNext())
  101. {
  102. DMUS_MELODY_FRAGMENT& rScan = pScan->GetItemValue();
  103. if (rScan.mtTime < mtStart)
  104. {
  105. pPrevious = pScan;
  106. }
  107. else if (rScan.mtTime < mtEnd)
  108. {
  109. if (rScan.mtTime == mtStart)
  110. {
  111. pPrevious = NULL;
  112. }
  113. if (!fStarted)
  114. {
  115. fStarted = TRUE;
  116. }
  117. TListItem<DMUS_MELODY_FRAGMENT>* pNew = new TListItem<DMUS_MELODY_FRAGMENT>;
  118. if (pNew)
  119. {
  120. DMUS_MELODY_FRAGMENT& rNew = pNew->GetItemValue();
  121. CopyMelodyFragment(rNew, rScan);
  122. rNew.mtTime = rScan.mtTime - mtStart;
  123. m_FragmentList.AddTail(pNew);
  124. }
  125. }
  126. else break;
  127. }
  128. if (pPrevious)
  129. {
  130. DMUS_MELODY_FRAGMENT& rPrevious = pPrevious->GetItemValue();
  131. TListItem<DMUS_MELODY_FRAGMENT>* pNew = new TListItem<DMUS_MELODY_FRAGMENT>;
  132. if (pNew)
  133. {
  134. DMUS_MELODY_FRAGMENT& rNew = pNew->GetItemValue();
  135. CopyMelodyFragment(rNew, rPrevious);
  136. rNew.mtTime = 0;
  137. m_FragmentList.AddHead(pNew);
  138. }
  139. }
  140. }
  141. CMelodyFormulationTrack::~CMelodyFormulationTrack()
  142. {
  143. ::DeleteCriticalSection( &m_CriticalSection );
  144. InterlockedDecrement(&g_cComponent);
  145. }
  146. void CMelodyFormulationTrack::Clear()
  147. {
  148. m_FragmentList.CleanUp();
  149. m_dwLastId = 0;
  150. }
  151. HRESULT CMelodyFormulationTrack::SetID(DWORD& rdwID)
  152. {
  153. m_dwLastId++;
  154. rdwID = m_dwLastId;
  155. return S_OK;
  156. }
  157. HRESULT CMelodyFormulationTrack::GetID(DWORD& rdwID)
  158. {
  159. rdwID = m_dwLastId;
  160. return S_OK;
  161. }
  162. STDMETHODIMP CMelodyFormulationTrack::QueryInterface(
  163. const IID &iid,
  164. void **ppv)
  165. {
  166. V_INAME(CMelodyFormulationTrack::QueryInterface);
  167. V_PTRPTR_WRITE(ppv);
  168. V_REFGUID(iid);
  169. if (iid == IID_IUnknown || iid == IID_IDirectMusicTrack || iid == IID_IDirectMusicTrack8)
  170. {
  171. *ppv = static_cast<IDirectMusicTrack*>(this);
  172. }
  173. else if (iid == IID_IPersistStream)
  174. {
  175. *ppv = static_cast<IPersistStream*>(this);
  176. }
  177. else
  178. {
  179. *ppv = NULL;
  180. return E_NOINTERFACE;
  181. }
  182. reinterpret_cast<IUnknown*>(this)->AddRef();
  183. return S_OK;
  184. }
  185. STDMETHODIMP_(ULONG) CMelodyFormulationTrack::AddRef()
  186. {
  187. return InterlockedIncrement(&m_cRef);
  188. }
  189. STDMETHODIMP_(ULONG) CMelodyFormulationTrack::Release()
  190. {
  191. if (!InterlockedDecrement(&m_cRef))
  192. {
  193. delete this;
  194. return 0;
  195. }
  196. return m_cRef;
  197. }
  198. HRESULT CMelodyFormulationTrack::Init(
  199. /*[in]*/ IDirectMusicSegment* pSegment
  200. )
  201. {
  202. return S_OK; // if I return an error, dmime gives me an assertion failure
  203. }
  204. HRESULT CMelodyFormulationTrack::InitPlay(
  205. /*[in]*/ IDirectMusicSegmentState* pSegmentState,
  206. /*[in]*/ IDirectMusicPerformance* pPerformance,
  207. /*[out]*/ void** ppStateData,
  208. /*[in]*/ DWORD dwTrackID,
  209. /*[in]*/ DWORD dwFlags
  210. )
  211. {
  212. return S_OK;
  213. }
  214. HRESULT CMelodyFormulationTrack::EndPlay(
  215. /*[in]*/ void* pStateData
  216. )
  217. {
  218. return S_OK;
  219. }
  220. HRESULT CMelodyFormulationTrack::Play(
  221. /*[in]*/ void* pStateData,
  222. /*[in]*/ MUSIC_TIME mtStart,
  223. /*[in]*/ MUSIC_TIME mtEnd,
  224. /*[in]*/ MUSIC_TIME mtOffset,
  225. DWORD dwFlags,
  226. IDirectMusicPerformance* pPerf,
  227. IDirectMusicSegmentState* pSegState,
  228. DWORD dwVirtualID
  229. )
  230. {
  231. bool fStart = (dwFlags & DMUS_TRACKF_START) ? true : false;
  232. bool fLoop = (dwFlags & DMUS_TRACKF_LOOP) ? true : false;
  233. bool fCompose = (dwFlags & DMUS_TRACKF_RECOMPOSE) ? true : false;
  234. bool fPlayOff = (dwFlags & DMUS_TRACKF_PLAY_OFF) ? true : false;
  235. HRESULT hr = S_OK;
  236. EnterCriticalSection(&m_CriticalSection);
  237. DWORD dwTrackGroup = 1;
  238. if ( fStart || fLoop )
  239. {
  240. if ( fCompose && !fPlayOff )
  241. {
  242. IDirectMusicSegment* pSegment = NULL;
  243. if (SUCCEEDED(hr = pSegState->GetSegment(&pSegment)))
  244. {
  245. IDirectMusicTrack* pTrack = NULL;
  246. if (SUCCEEDED(hr = QueryInterface(IID_IDirectMusicTrack, (void**)&pTrack)))
  247. {
  248. pSegment->GetTrackGroup(pTrack, &dwTrackGroup);
  249. pTrack->Release();
  250. // call Track::Compose on this track
  251. if (SUCCEEDED(hr = Compose(pSegment, dwTrackGroup, &pTrack)))
  252. {
  253. if (SUCCEEDED(AddToSegment(pSegment, pTrack, dwTrackGroup)))
  254. {
  255. // if we recomposed, send a recompose notification
  256. SendNotification(mtStart + mtOffset, pPerf, pSegment, pSegState, dwFlags);
  257. }
  258. pTrack->Release();
  259. }
  260. }
  261. }
  262. pSegment->Release();
  263. }
  264. }
  265. LeaveCriticalSection(&m_CriticalSection);
  266. return hr;
  267. }
  268. // This will modify an existing segment by adding *only* a pattern track to it.
  269. // Any existing pattern tracks with conflicting group bits will be modifed.
  270. HRESULT CMelodyFormulationTrack::AddToSegment(IDirectMusicSegment* pTempSeg,
  271. IDirectMusicTrack* pNewPatternTrack,
  272. DWORD dwGroupBits)
  273. {
  274. HRESULT hr = S_OK;
  275. IDirectMusicTrack* pCurrentPatternTrack = NULL;
  276. IStream* pNewPatternStream = NULL;
  277. IPersistStream* pNewPatternTrackStream = NULL;
  278. IPersistStream* pCurrentPatternTrackStream = NULL;
  279. // if there exists a pattern track with these group bits, reload this pattern into that
  280. // track (use the first track that's found). Otherwise, insert this track into the segment.
  281. hr = pTempSeg->GetTrack(CLSID_DirectMusicPatternTrack, dwGroupBits, 0, &pCurrentPatternTrack);
  282. if (S_OK != hr)
  283. {
  284. // insert the passed-in track
  285. hr = pTempSeg->InsertTrack(pNewPatternTrack, dwGroupBits);
  286. }
  287. else
  288. {
  289. // load the new track into the one that already exists
  290. hr = CreateStreamOnHGlobal(NULL, TRUE, &pNewPatternStream);
  291. if (S_OK != hr) goto ON_END;
  292. hr = pNewPatternTrack->QueryInterface( IID_IPersistStream, (void**)&pNewPatternTrackStream);
  293. if (S_OK != hr) goto ON_END;
  294. pNewPatternTrackStream->Save(pNewPatternStream, FALSE);
  295. hr = pCurrentPatternTrack->QueryInterface(IID_IPersistStream, (void**)&pCurrentPatternTrackStream);
  296. if (!SUCCEEDED(hr)) goto ON_END;
  297. StreamSeek(pNewPatternStream, 0, STREAM_SEEK_SET);
  298. hr = pCurrentPatternTrackStream->Load(pNewPatternStream);
  299. if (!SUCCEEDED(hr)) goto ON_END;
  300. }
  301. ON_END:
  302. if (pCurrentPatternTrack) pCurrentPatternTrack->Release();
  303. if (pCurrentPatternTrackStream) pCurrentPatternTrackStream->Release();
  304. if (pNewPatternStream) pNewPatternStream->Release();
  305. if (pNewPatternTrackStream) pNewPatternTrackStream->Release();
  306. return hr;
  307. }
  308. HRESULT CMelodyFormulationTrack::SendNotification(MUSIC_TIME mtTime,
  309. IDirectMusicPerformance* pPerf,
  310. IDirectMusicSegment* pSegment,
  311. IDirectMusicSegmentState* pSegState,
  312. DWORD dwFlags)
  313. {
  314. if (!m_fNotifyRecompose || (dwFlags & DMUS_TRACKF_NOTIFY_OFF))
  315. {
  316. return S_OK;
  317. }
  318. DMUS_NOTIFICATION_PMSG* pEvent = NULL;
  319. HRESULT hr = pPerf->AllocPMsg( sizeof(DMUS_NOTIFICATION_PMSG), (DMUS_PMSG**)&pEvent );
  320. if( SUCCEEDED( hr ))
  321. {
  322. pEvent->dwField1 = 0;
  323. pEvent->dwField2 = 0;
  324. pEvent->dwType = DMUS_PMSGT_NOTIFICATION;
  325. pEvent->mtTime = mtTime;
  326. pEvent->dwFlags = DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_ATTIME;
  327. pSegState->QueryInterface(IID_IUnknown, (void**)&pEvent->punkUser);
  328. pEvent->dwNotificationOption = DMUS_NOTIFICATION_RECOMPOSE;
  329. pEvent->guidNotificationType = GUID_NOTIFICATION_RECOMPOSE;
  330. if (FAILED(pSegment->GetTrackGroup(this, &pEvent->dwGroupID)))
  331. {
  332. pEvent->dwGroupID = 0xffffffff;
  333. }
  334. IDirectMusicGraph* pGraph;
  335. hr = pSegState->QueryInterface( IID_IDirectMusicGraph, (void**)&pGraph );
  336. if( SUCCEEDED( hr ))
  337. {
  338. pGraph->StampPMsg((DMUS_PMSG*) pEvent );
  339. pGraph->Release();
  340. }
  341. hr = pPerf->SendPMsg((DMUS_PMSG*) pEvent );
  342. if( FAILED(hr) )
  343. {
  344. pPerf->FreePMsg((DMUS_PMSG*) pEvent );
  345. }
  346. }
  347. return hr;
  348. }
  349. HRESULT CMelodyFormulationTrack::GetParam(
  350. REFGUID rParamGuid,
  351. MUSIC_TIME mtTime,
  352. MUSIC_TIME* pmtNext,
  353. void* pData
  354. )
  355. {
  356. V_INAME(CMelodyFormulationTrack::GetParam);
  357. V_PTR_WRITE_OPT(pmtNext,MUSIC_TIME);
  358. V_PTR_WRITE(pData, 1);
  359. V_REFGUID(rParamGuid);
  360. HRESULT hr = S_OK;
  361. EnterCriticalSection(&m_CriticalSection);
  362. if (rParamGuid == GUID_MelodyFragment)
  363. {
  364. TListItem<DMUS_MELODY_FRAGMENT>* pMelGen = m_FragmentList.GetHead();
  365. if (pMelGen)
  366. {
  367. TListItem<DMUS_MELODY_FRAGMENT>* pNext = pMelGen->GetNext();
  368. for(; pNext; pNext = pNext->GetNext())
  369. {
  370. if (pNext->GetItemValue().mtTime <= mtTime) // may be it, but we need a next time
  371. {
  372. pMelGen = pNext;
  373. }
  374. else // passed it
  375. {
  376. break;
  377. }
  378. }
  379. *(DMUS_MELODY_FRAGMENT*)pData = pMelGen->GetItemValue();
  380. if (pmtNext)
  381. {
  382. if (pNext)
  383. {
  384. *pmtNext = pNext->GetItemValue().mtTime - mtTime;
  385. }
  386. else
  387. {
  388. *pmtNext = 0;
  389. }
  390. }
  391. hr = S_OK;
  392. }
  393. else hr = DMUS_E_NOT_FOUND;
  394. }
  395. else if (rParamGuid == GUID_MelodyFragmentRepeat)
  396. {
  397. // replace the passed-in fragment with the one its repeat field refers to
  398. DMUS_MELODY_FRAGMENT* pFragment = (DMUS_MELODY_FRAGMENT*)pData;
  399. if (!(pFragment->dwFragmentFlags & DMUS_FRAGMENTF_USE_REPEAT))
  400. {
  401. hr = DMUS_E_NOT_FOUND;
  402. }
  403. else
  404. {
  405. TListItem<DMUS_MELODY_FRAGMENT>* pMelGen = m_FragmentList.GetHead();
  406. for(; pMelGen; pMelGen = pMelGen->GetNext())
  407. {
  408. if (pMelGen->GetItemValue().dwID == pFragment->dwRepeatFragmentID)
  409. {
  410. break;
  411. }
  412. }
  413. if (pMelGen)
  414. {
  415. *(DMUS_MELODY_FRAGMENT*)pData = pMelGen->GetItemValue();
  416. if (pmtNext)
  417. {
  418. TListItem<DMUS_MELODY_FRAGMENT>* pNext = pMelGen->GetNext();
  419. if (pNext)
  420. {
  421. *pmtNext = pNext->GetItemValue().mtTime - mtTime;
  422. }
  423. else
  424. {
  425. *pmtNext = 0;
  426. }
  427. }
  428. hr = S_OK;
  429. }
  430. else hr = DMUS_E_NOT_FOUND;
  431. }
  432. }
  433. else if (rParamGuid == GUID_MelodyPlaymode)
  434. {
  435. *(BYTE*)pData = m_bPlaymode;
  436. if (pmtNext)
  437. {
  438. *pmtNext = 0;
  439. }
  440. }
  441. else
  442. {
  443. hr = DMUS_E_GET_UNSUPPORTED;
  444. }
  445. LeaveCriticalSection(&m_CriticalSection);
  446. return hr;
  447. }
  448. HRESULT CMelodyFormulationTrack::SetParam(
  449. REFGUID rParamGuid,
  450. MUSIC_TIME mtTime,
  451. void __RPC_FAR *pData)
  452. {
  453. V_INAME(CMelodyFormulationTrack::SetParam);
  454. V_PTR_WRITE(pData, 1);
  455. V_REFGUID(rParamGuid);
  456. HRESULT hr;
  457. EnterCriticalSection( &m_CriticalSection );
  458. if (rParamGuid == GUID_Clear_All_MelodyFragments)
  459. {
  460. Clear();
  461. hr = S_OK;
  462. }
  463. else if (rParamGuid == GUID_MelodyFragment)
  464. {
  465. DMUS_MELODY_FRAGMENT* pFragment = (DMUS_MELODY_FRAGMENT*)pData;
  466. TListItem<DMUS_MELODY_FRAGMENT>* pFragmentItem = m_FragmentList.GetHead();
  467. TListItem<DMUS_MELODY_FRAGMENT>* pPrevious = NULL;
  468. TListItem<DMUS_MELODY_FRAGMENT>* pNew = new TListItem<DMUS_MELODY_FRAGMENT>;
  469. if (!pNew)
  470. {
  471. hr = E_OUTOFMEMORY;
  472. }
  473. else
  474. {
  475. pNew->GetItemValue() = *pFragment;
  476. // overide time in struct with time passed in
  477. pNew->GetItemValue().mtTime = mtTime;
  478. for(; pFragmentItem != NULL; pFragmentItem = pFragmentItem->GetNext())
  479. {
  480. if (pFragmentItem->GetItemValue().mtTime >= mtTime) break;
  481. pPrevious = pFragmentItem;
  482. }
  483. if (pPrevious)
  484. {
  485. pPrevious->SetNext(pNew);
  486. pNew->SetNext(pFragmentItem);
  487. }
  488. else // pFragmentItem is current head of list
  489. {
  490. m_FragmentList.AddHead(pNew);
  491. }
  492. if (pFragmentItem && pFragmentItem->GetItemValue().mtTime == mtTime)
  493. {
  494. // remove it
  495. pNew->GetItemValue().dwID = pFragmentItem->GetItemValue().dwID;
  496. pNew->SetNext(pFragmentItem->GetNext());
  497. pFragmentItem->SetNext(NULL);
  498. delete pFragmentItem;
  499. }
  500. else
  501. {
  502. // give the struct a brand new ID
  503. SetID(pNew->GetItemValue().dwID);
  504. }
  505. hr = S_OK;
  506. }
  507. }
  508. else
  509. {
  510. hr = DMUS_E_SET_UNSUPPORTED;
  511. }
  512. LeaveCriticalSection( &m_CriticalSection );
  513. return hr;
  514. }
  515. // IPersist methods
  516. HRESULT CMelodyFormulationTrack::GetClassID( LPCLSID pClassID )
  517. {
  518. V_INAME(CMelodyFormulationTrack::GetClassID);
  519. V_PTR_WRITE(pClassID, CLSID);
  520. *pClassID = CLSID_DirectMusicMelodyFormulationTrack;
  521. return S_OK;
  522. }
  523. HRESULT CMelodyFormulationTrack::IsParamSupported(
  524. /*[in]*/ REFGUID rGuid
  525. )
  526. {
  527. V_INAME(CMelodyFormulationTrack::IsParamSupported);
  528. V_REFGUID(rGuid);
  529. if (rGuid == GUID_MelodyFragment ||
  530. rGuid == GUID_MelodyPlaymode ||
  531. rGuid == GUID_Clear_All_MelodyFragments)
  532. return S_OK;
  533. else
  534. return DMUS_E_TYPE_UNSUPPORTED;
  535. }
  536. // IPersistStream methods
  537. HRESULT CMelodyFormulationTrack::IsDirty()
  538. {
  539. return m_bRequiresSave ? S_OK : S_FALSE;
  540. }
  541. HRESULT CMelodyFormulationTrack::Save( LPSTREAM pStream, BOOL fClearDirty )
  542. {
  543. V_INAME(CMelodyFormulationTrack::Save);
  544. V_INTERFACE(pStream);
  545. HRESULT hr = S_OK;
  546. IAARIFFStream* pRIFF = NULL;
  547. MMCKINFO ckMain, ckHeader, ckBody;
  548. DWORD cb;
  549. DWORD dwSize;
  550. DMUS_IO_MELODY_FRAGMENT oMelGen;
  551. TListItem<DMUS_MELODY_FRAGMENT>* pMelGen;
  552. EnterCriticalSection( &m_CriticalSection );
  553. hr = AllocRIFFStream( pStream, &pRIFF );
  554. if ( FAILED( hr ) )
  555. {
  556. goto ON_END;
  557. }
  558. // Create a chunk to store the MelGen data
  559. ckMain.fccType = DMUS_FOURCC_MELODYFORM_TRACK_LIST;
  560. if( pRIFF->CreateChunk( &ckMain, MMIO_CREATELIST ) != 0 )
  561. {
  562. hr = E_FAIL;
  563. goto ON_END;
  564. }
  565. // Write MelForm chunk header
  566. ckHeader.ckid = DMUS_FOURCC_MELODYFORM_HEADER_CHUNK;
  567. if( pRIFF->CreateChunk( &ckHeader, 0 ) != 0 )
  568. {
  569. hr = E_FAIL;
  570. goto ON_END;
  571. }
  572. // Prepare DMUS_IO_MELFORM
  573. DMUS_IO_MELFORM oMelForm;
  574. memset( &oMelForm, 0, sizeof(DMUS_IO_MELFORM) );
  575. oMelForm.dwPlaymode = m_bPlaymode;
  576. // Write MelForm chunk data
  577. hr = pStream->Write( &oMelForm, sizeof(DMUS_IO_MELFORM), &cb);
  578. if( FAILED( hr ) || cb != sizeof(DMUS_IO_MELFORM) )
  579. {
  580. hr = E_FAIL;
  581. goto ON_END;
  582. }
  583. if( pRIFF->Ascend( &ckHeader, 0 ) != 0 )
  584. {
  585. hr = E_FAIL;
  586. goto ON_END;
  587. }
  588. // Write MelForm chunk body
  589. ckBody.ckid = DMUS_FOURCC_MELODYFORM_BODY_CHUNK;
  590. if( pRIFF->CreateChunk( &ckBody, 0 ) == 0 )
  591. {
  592. dwSize = sizeof( oMelGen );
  593. hr = pStream->Write( &dwSize, sizeof( dwSize ), &cb );
  594. if( FAILED( hr ) || cb != sizeof( dwSize ) )
  595. {
  596. if (SUCCEEDED(hr)) hr = E_FAIL;
  597. goto ON_END;
  598. }
  599. for( pMelGen = m_FragmentList.GetHead(); pMelGen != NULL ; pMelGen = pMelGen->GetNext() )
  600. {
  601. DMUS_MELODY_FRAGMENT& rMelGen = pMelGen->GetItemValue();
  602. memset( &oMelGen, 0, sizeof( oMelGen ) );
  603. CopyMelodyFragment(oMelGen, rMelGen);
  604. if( FAILED( pStream->Write( &oMelGen, sizeof( oMelGen ), &cb ) ) ||
  605. cb != sizeof( oMelGen ) )
  606. {
  607. break;
  608. }
  609. }
  610. if( pMelGen == NULL )
  611. {
  612. hr = S_OK;
  613. }
  614. // Ascend out of the MelForm Body chunk
  615. if( pRIFF->Ascend( &ckBody, 0 ) != 0 )
  616. {
  617. hr = E_FAIL;
  618. goto ON_END;
  619. }
  620. }
  621. // Ascend out of the MelGen chunk.
  622. pRIFF->Ascend( &ckMain, 0 );
  623. ON_END:
  624. if (pRIFF) pRIFF->Release();
  625. LeaveCriticalSection( &m_CriticalSection );
  626. return hr;
  627. }
  628. HRESULT CMelodyFormulationTrack::GetSizeMax( ULARGE_INTEGER* /*pcbSize*/ )
  629. {
  630. return E_NOTIMPL;
  631. }
  632. BOOL Less(DMUS_MELODY_FRAGMENT& MF1, DMUS_MELODY_FRAGMENT& MF2)
  633. { return MF1.mtTime < MF2.mtTime; }
  634. HRESULT CMelodyFormulationTrack::Load(LPSTREAM pStream )
  635. {
  636. V_INAME(CMelodyFormulationTrack::Load);
  637. V_INTERFACE(pStream);
  638. // Melody formulation temporarily turned off for DX8.
  639. return E_NOTIMPL;
  640. /*
  641. HRESULT hr = DMUS_E_CHUNKNOTFOUND;
  642. DWORD dwPos;
  643. IAARIFFStream* pRIFF;
  644. EnterCriticalSection( &m_CriticalSection );
  645. Clear();
  646. m_dwLastId = 0;
  647. dwPos = StreamTell( pStream );
  648. StreamSeek( pStream, dwPos, STREAM_SEEK_SET );
  649. MMCKINFO ck;
  650. MMCKINFO ckMain;
  651. MMCKINFO ckHeader;
  652. bool fFoundTrack = false;
  653. if( SUCCEEDED( AllocRIFFStream( pStream, &pRIFF ) ) )
  654. {
  655. ckMain.fccType = DMUS_FOURCC_MELODYFORM_TRACK_LIST;
  656. if( pRIFF->Descend( &ckMain, NULL, MMIO_FINDLIST ) == 0)
  657. {
  658. // New melform track
  659. long lFileSize = ckMain.cksize - 4; // subtract off the list type
  660. DMUS_IO_MELFORM iMelform;
  661. DWORD cb;
  662. if (pRIFF->Descend(&ckHeader, &ckMain, 0) == 0)
  663. {
  664. if (ckHeader.ckid == DMUS_FOURCC_MELODYFORM_HEADER_CHUNK )
  665. {
  666. lFileSize -= 8; // chunk id + chunk size: double words
  667. lFileSize -= ckHeader.cksize;
  668. hr = pStream->Read( &iMelform, sizeof( iMelform ), &cb );
  669. if (FAILED(hr) || cb != sizeof( iMelform ) )
  670. {
  671. if (SUCCEEDED(hr)) hr = DMUS_E_CHUNKNOTFOUND;
  672. }
  673. else
  674. {
  675. //m_bPlaymode = (BYTE) iMelform.dwPlaymode;
  676. m_bPlaymode = DMUS_PLAYMODE_NONE; // only flag supported for dx8
  677. }
  678. }
  679. pRIFF->Ascend( &ckHeader, 0 );
  680. }
  681. if (SUCCEEDED(hr))
  682. {
  683. hr = DMUS_E_CHUNKNOTFOUND;
  684. if (pRIFF->Descend(&ck, &ckMain, 0) == 0)
  685. {
  686. if (ck.ckid == DMUS_FOURCC_MELODYFORM_BODY_CHUNK )
  687. {
  688. if( SUCCEEDED(LoadFragments(pStream, (long) ck.cksize)) )
  689. {
  690. hr = S_OK;
  691. m_FragmentList.MergeSort(Less);
  692. }
  693. }
  694. pRIFF->Ascend( &ck, 0 );
  695. }
  696. }
  697. fFoundTrack = true;
  698. }
  699. pRIFF->Release();
  700. pRIFF = NULL;
  701. }
  702. if (!fFoundTrack)
  703. {
  704. StreamSeek( pStream, dwPos, STREAM_SEEK_SET );
  705. // old (obsolete) melform track
  706. if( SUCCEEDED( AllocRIFFStream( pStream, &pRIFF ) ) )
  707. {
  708. ck.ckid = DMUS_FOURCC_MELODYGEN_TRACK_CHUNK;
  709. if ( pRIFF->Descend( &ck, NULL, MMIO_FINDCHUNK ) == 0 )
  710. {
  711. if( SUCCEEDED(LoadFragments(pStream, (long) ck.cksize)) &&
  712. pRIFF->Ascend( &ck, 0 ) == 0 )
  713. {
  714. hr = S_OK;
  715. m_FragmentList.MergeSort(Less);
  716. }
  717. }
  718. pRIFF->Release();
  719. }
  720. }
  721. LeaveCriticalSection( &m_CriticalSection );
  722. return hr;*/
  723. }
  724. HRESULT CMelodyFormulationTrack::LoadFragments(LPSTREAM pStream, long lFileSize )
  725. {
  726. DWORD dwNodeSize;
  727. DWORD cb;
  728. HRESULT hr = pStream->Read( &dwNodeSize, sizeof( dwNodeSize ), &cb );
  729. DMUS_IO_MELODY_FRAGMENT iMelGen;
  730. if( SUCCEEDED( hr ) && cb == sizeof( dwNodeSize ) )
  731. {
  732. lFileSize -= 4; // for the size dword
  733. TListItem<DMUS_MELODY_FRAGMENT>* pMelGen;
  734. if (lFileSize % dwNodeSize)
  735. {
  736. hr = E_FAIL;
  737. }
  738. else
  739. {
  740. while( lFileSize > 0 )
  741. {
  742. pMelGen = new TListItem<DMUS_MELODY_FRAGMENT>;
  743. if( pMelGen )
  744. {
  745. DMUS_MELODY_FRAGMENT& rMelGen = pMelGen->GetItemValue();
  746. if( dwNodeSize <= sizeof( iMelGen ) )
  747. {
  748. pStream->Read( &iMelGen, dwNodeSize, NULL );
  749. }
  750. else
  751. {
  752. pStream->Read( &iMelGen, sizeof( iMelGen ), NULL );
  753. DWORD dw = (lFileSize >= sizeof( iMelGen ) ) ? lFileSize - sizeof( iMelGen ) : 0;
  754. StreamSeek( pStream, dw, STREAM_SEEK_CUR );
  755. }
  756. memset( &rMelGen, 0, sizeof( rMelGen ) );
  757. CopyMelodyFragment(rMelGen, iMelGen);
  758. m_FragmentList.AddHead(pMelGen);
  759. lFileSize -= dwNodeSize;
  760. }
  761. else break;
  762. }
  763. }
  764. }
  765. if (SUCCEEDED(hr))
  766. {
  767. if (lFileSize != 0)
  768. {
  769. hr = E_FAIL;
  770. }
  771. }
  772. return hr;
  773. }
  774. HRESULT STDMETHODCALLTYPE CMelodyFormulationTrack::AddNotificationType(
  775. /* [in] */ REFGUID rGuidNotify)
  776. {
  777. V_INAME(CPersonalityTrack::AddNotificationType);
  778. V_REFGUID(rGuidNotify);
  779. if( rGuidNotify == GUID_NOTIFICATION_RECOMPOSE )
  780. {
  781. m_fNotifyRecompose = TRUE;
  782. return S_OK;
  783. }
  784. else
  785. {
  786. return S_FALSE;
  787. }
  788. }
  789. HRESULT STDMETHODCALLTYPE CMelodyFormulationTrack::RemoveNotificationType(
  790. /* [in] */ REFGUID rGuidNotify)
  791. {
  792. V_INAME(CPersonalityTrack::RemoveNotificationType);
  793. V_REFGUID(rGuidNotify);
  794. if( rGuidNotify == GUID_NOTIFICATION_RECOMPOSE )
  795. {
  796. m_fNotifyRecompose = FALSE;
  797. return S_OK;
  798. }
  799. else
  800. {
  801. return S_FALSE;
  802. }
  803. }
  804. HRESULT STDMETHODCALLTYPE CMelodyFormulationTrack::Clone(
  805. MUSIC_TIME mtStart,
  806. MUSIC_TIME mtEnd,
  807. IDirectMusicTrack** ppTrack)
  808. {
  809. V_INAME(CSPstTrk::Clone);
  810. V_PTRPTR_WRITE(ppTrack);
  811. HRESULT hr = S_OK;
  812. if(mtStart < 0 )
  813. {
  814. return E_INVALIDARG;
  815. }
  816. if(mtStart > mtEnd)
  817. {
  818. return E_INVALIDARG;
  819. }
  820. EnterCriticalSection( &m_CriticalSection );
  821. CMelodyFormulationTrack *pDM;
  822. try
  823. {
  824. pDM = new CMelodyFormulationTrack(*this, mtStart, mtEnd);
  825. }
  826. catch( ... )
  827. {
  828. pDM = NULL;
  829. }
  830. if (pDM == NULL) {
  831. LeaveCriticalSection( &m_CriticalSection );
  832. return E_OUTOFMEMORY;
  833. }
  834. hr = pDM->QueryInterface(IID_IDirectMusicTrack, (void**)ppTrack);
  835. pDM->Release();
  836. LeaveCriticalSection( &m_CriticalSection );
  837. return hr;
  838. }
  839. HRESULT MelodyFragment::GetChord(IDirectMusicSegment* pTempSeg,
  840. IDirectMusicSong* pSong,
  841. DWORD dwTrackGroup,
  842. MUSIC_TIME& rmtNext,
  843. DMUS_CHORD_PARAM& rCurrentChord,
  844. MUSIC_TIME& rmtCurrent,
  845. DMUS_CHORD_PARAM& rRealCurrentChord)
  846. {
  847. HRESULT hr = S_OK;
  848. hr = GetChord(m_mtTime, pTempSeg, pSong, dwTrackGroup, rmtNext, rRealCurrentChord);
  849. if ( SUCCEEDED(hr) )
  850. {
  851. rmtCurrent = rmtNext;
  852. if (m_dwFragmentFlags & DMUS_FRAGMENTF_ANTICIPATE)
  853. {
  854. hr = GetChord(rmtCurrent, pTempSeg, pSong, dwTrackGroup, rmtNext, rCurrentChord);
  855. }
  856. else
  857. {
  858. rCurrentChord = rRealCurrentChord;
  859. }
  860. }
  861. return hr;
  862. }
  863. HRESULT MelodyFragment::GetChord(MUSIC_TIME mtTime,
  864. IDirectMusicSegment* pTempSeg,
  865. IDirectMusicSong* pSong,
  866. DWORD dwTrackGroup,
  867. MUSIC_TIME& rmtNext,
  868. DMUS_CHORD_PARAM& rCurrentChord)
  869. {
  870. HRESULT hr = E_FAIL;
  871. DMUS_CHORD_PARAM DefaultChord;
  872. wcscpy(DefaultChord.wszName, L"M7");
  873. DefaultChord.wMeasure = 0;
  874. DefaultChord.bBeat = 0;
  875. DefaultChord.bSubChordCount = 1;
  876. DefaultChord.dwScale = 0xab5ab5; // default: major scale
  877. DefaultChord.bKey = 12; // default: C2
  878. DefaultChord.SubChordList[0].dwChordPattern = 0x91; // default: major chord
  879. DefaultChord.SubChordList[0].dwScalePattern = 0xab5ab5; // default: major scale
  880. DefaultChord.SubChordList[0].dwInversionPoints = 0xffffff; // default: inversions everywhere
  881. DefaultChord.SubChordList[0].dwLevels = 0xffffff; // let this work with anything...
  882. DefaultChord.SubChordList[0].bChordRoot = 12; // default: C2
  883. DefaultChord.SubChordList[0].bScaleRoot = 0;
  884. if (pTempSeg)
  885. {
  886. hr = pTempSeg->GetParam(GUID_ChordParam, dwTrackGroup, 0, mtTime, &rmtNext, (void*)&rCurrentChord);
  887. }
  888. else if (pSong)
  889. {
  890. hr = pSong->GetParam(GUID_ChordParam, dwTrackGroup, 0, mtTime, &rmtNext, (void*)&rCurrentChord);
  891. }
  892. if (SUCCEEDED(hr))
  893. {
  894. rmtNext += mtTime;
  895. hr = S_OK;
  896. }
  897. else
  898. {
  899. rCurrentChord = DefaultChord;
  900. rmtNext = 0;
  901. hr = S_FALSE;
  902. }
  903. return hr;
  904. }
  905. HRESULT MelodyFragment::GetPattern(DMStyleStruct* pStyleStruct,
  906. CDirectMusicPattern*& rpPattern,
  907. TListItem<CompositionFragment>* pLastFragment)
  908. {
  909. HRESULT hr = S_OK;
  910. DMUS_COMMAND_PARAM_2 Command[1];
  911. Command[0].mtTime = 0;
  912. if (m_Command.bGrooveLevel == 0 && pLastFragment)
  913. {
  914. m_Command = pLastFragment->GetItemValue().GetCommand();
  915. }
  916. Command[0].bCommand = m_Command.bCommand;
  917. Command[0].bGrooveLevel = m_Command.bGrooveLevel;
  918. Command[0].bGrooveRange = m_Command.bGrooveRange;
  919. TListItem<CDirectMusicPattern*>* pPatItem = pStyleStruct->m_PatternList.GetHead();
  920. if (pPatItem)
  921. {
  922. // choose the first matching pattern
  923. for ( ; pPatItem; pPatItem = pPatItem->GetNext())
  924. {
  925. CDirectMusicPattern* pPattern = pPatItem->GetItemValue();
  926. if (pPattern && pPattern->MatchCommand(Command, 1) )
  927. {
  928. rpPattern = pPattern;
  929. hr = S_OK;
  930. break;
  931. }
  932. }
  933. if (!pPatItem) // problem; fallback to first pattern
  934. {
  935. pPatItem = pStyleStruct->m_PatternList.GetHead();
  936. rpPattern = pPatItem->GetItemValue();
  937. hr = S_OK;
  938. }
  939. }
  940. else
  941. {
  942. hr = DMUS_E_NOT_FOUND;
  943. }
  944. return hr;
  945. }
  946. // GetTransitionNotes: given the time of a note, and a fragment, return the appropriate
  947. // transition note tuple (last and overlap; ghost tested separately)
  948. HRESULT GetTransitionNotes(MUSIC_TIME mtTime,
  949. DWORD dwPart,
  950. TListItem<CompositionFragment>* pCompFragment,
  951. TransitionConstraint& rTransition)
  952. {
  953. rTransition.dwFlags &= ~DMUS_TRANSITIONF_OVERLAP_FOUND;
  954. rTransition.dwFlags &= ~DMUS_TRANSITIONF_LAST_FOUND;
  955. // Check pCompFragment overlaps for the last note to start before mtTime,
  956. // and the first note to start on or after mtTime.
  957. if (pCompFragment)
  958. {
  959. CompositionFragment& rFragment = pCompFragment->GetItemValue();
  960. TListItem<EventOverlap>* pOverlap = rFragment.GetOverlapHead();
  961. MUSIC_TIME nMinOverlap = 0;
  962. MUSIC_TIME nMaxPlayed = 0;
  963. for (; pOverlap; pOverlap = pOverlap->GetNext() )
  964. {
  965. EventOverlap& rOverlap = pOverlap->GetItemValue();
  966. if ( rOverlap.m_PartRef.m_dwLogicalPartID == dwPart &&
  967. (rOverlap.m_pEvent->m_dwEventTag & DMUS_EVENT_NOTE) )
  968. {
  969. if (rOverlap.m_mtTime >= mtTime) // this note overlaps
  970. {
  971. if ( !(rTransition.dwFlags & DMUS_TRANSITIONF_OVERLAP_FOUND) ||
  972. rOverlap.m_mtTime < nMinOverlap )
  973. {
  974. HRESULT hr = rFragment.GetNote(rOverlap.m_pEvent, rOverlap.m_Chord, rOverlap.m_PartRef, rTransition.bOverlap);
  975. if (SUCCEEDED(hr))
  976. {
  977. nMinOverlap = rOverlap.m_mtTime;
  978. rTransition.dwFlags |= DMUS_TRANSITIONF_OVERLAP_FOUND;
  979. }
  980. }
  981. }
  982. if (rOverlap.m_mtTime < mtTime) // this note will be played
  983. {
  984. if ( !(rTransition.dwFlags & DMUS_TRANSITIONF_LAST_FOUND) ||
  985. rOverlap.m_mtTime >= nMaxPlayed )
  986. {
  987. HRESULT hr = rFragment.GetNote(rOverlap.m_pEvent, rOverlap.m_Chord, rOverlap.m_PartRef, rTransition.bLastPlayed);
  988. if (SUCCEEDED(hr))
  989. {
  990. nMaxPlayed = rOverlap.m_mtTime;
  991. rTransition.dwFlags |= DMUS_TRANSITIONF_LAST_FOUND;
  992. }
  993. }
  994. }
  995. }
  996. }
  997. // If we couldn't find a last note, use the last note in the event list of pCompFragment
  998. TListItem<CompositionFragment>* pfragmentScan = pCompFragment;
  999. while (pfragmentScan && !(rTransition.dwFlags & DMUS_TRANSITIONF_LAST_FOUND))
  1000. {
  1001. CompositionFragment& rfragmentScan = pfragmentScan->GetItemValue();
  1002. TListItem<DirectMusicPartRef>* pPartRef = rfragmentScan.m_pPattern->m_PartRefList.GetHead();
  1003. int nParts = rfragmentScan.m_pPattern->m_PartRefList.GetCount();
  1004. for (int i = 0; pPartRef != NULL; pPartRef = pPartRef->GetNext(), i++)
  1005. {
  1006. if (pPartRef->GetItemValue().m_dwLogicalPartID == dwPart) break;
  1007. }
  1008. if (i < nParts)
  1009. {
  1010. TListItem<EventWrapper>* pEventItem = rfragmentScan.GetEventHead(i);
  1011. if (pEventItem)
  1012. {
  1013. // The list is sorted in reverse order, so the head is the last element
  1014. rTransition.bLastPlayed = pEventItem->GetItemValue().m_bMIDI;
  1015. rTransition.dwFlags |= DMUS_TRANSITIONF_LAST_FOUND;
  1016. }
  1017. }
  1018. pfragmentScan = pfragmentScan->GetNext(); // goes backwards to first fragment
  1019. }
  1020. }
  1021. return S_OK;
  1022. }
  1023. HRESULT MelodyFragment::TestTransition(BYTE bMIDI,
  1024. MUSIC_TIME mtNote,
  1025. DMUS_CHORD_PARAM& rCurrentChord,
  1026. int nPartIndex,
  1027. DirectMusicPartRef& rPartRef,
  1028. TListItem<CompositionFragment>* pLastFragment)
  1029. {
  1030. bool fGhost = false;
  1031. bool fOverlap = false;
  1032. bool fGoodInterval = false;
  1033. if (pLastFragment)
  1034. {
  1035. // if this variation doesn't meet the constraints, return S_FALSE; otherwise return S_OK
  1036. DMUS_CONNECTION_RULE Connection = pLastFragment->GetItemValue().GetConnectionArc();
  1037. DWORD dwPart = rPartRef.m_dwLogicalPartID;
  1038. TransitionConstraint Transition;
  1039. ZeroMemory(&Transition , sizeof(Transition));
  1040. GetTransitionNotes(mtNote, dwPart, pLastFragment, Transition);
  1041. // Test ghost notes
  1042. if ( (Connection.dwFlags & DMUS_CONNECTIONF_GHOST) )
  1043. {
  1044. BYTE bGhost = 0;
  1045. CDMStyleNote* pNoteEvent = new CDMStyleNote;
  1046. if (pNoteEvent)
  1047. {
  1048. pNoteEvent->m_bDurRange = 0;
  1049. pNoteEvent->m_bFlags = 0;
  1050. pNoteEvent->m_bTimeRange = 0;
  1051. pNoteEvent->m_bVelocity = 0;
  1052. pNoteEvent->m_dwFragmentID = 0;
  1053. pNoteEvent->m_mtDuration = 0;
  1054. pNoteEvent->m_nGridStart = 0;
  1055. pNoteEvent->m_nTimeOffset = 0;
  1056. TListItem<DMUS_IO_STYLERESOLUTION>* pScan = rPartRef.m_pDMPart->m_ResolutionList.GetHead();
  1057. for(; pScan; pScan = pScan->GetNext() )
  1058. {
  1059. DMUS_IO_STYLERESOLUTION& rResolution = pScan->GetItemValue();
  1060. pNoteEvent->m_bInversionId = rResolution.bInversionID;
  1061. pNoteEvent->m_bPlayModeFlags = rResolution.bPlayModeFlags;
  1062. pNoteEvent->m_dwVariation = rResolution.dwVariation;
  1063. pNoteEvent->m_wMusicValue = rResolution.wMusicValue;
  1064. if ((1 << pLastFragment->GetItemValue().m_abVariations[nPartIndex]) & pNoteEvent->m_dwVariation &&
  1065. SUCCEEDED(GetNote(pNoteEvent, rCurrentChord, rPartRef, bGhost)))
  1066. {
  1067. if (bGhost == bMIDI)
  1068. {
  1069. fGhost = true;
  1070. break;
  1071. }
  1072. }
  1073. }
  1074. delete pNoteEvent;
  1075. }
  1076. }
  1077. // Test overlap notes
  1078. if ( (Connection.dwFlags & DMUS_CONNECTIONF_OVERLAP) &&
  1079. (Transition.dwFlags & DMUS_TRANSITIONF_OVERLAP_FOUND) )
  1080. {
  1081. if (Transition.bOverlap == bMIDI) fOverlap = true;
  1082. }
  1083. // Test last played notes
  1084. // Assumptions:
  1085. // 1. intervals go in either direction (up or down)
  1086. // 2. intervals are in absolute semitones.
  1087. if ( (Connection.dwFlags & DMUS_CONNECTIONF_INTERVALS) &&
  1088. (Transition.dwFlags & DMUS_TRANSITIONF_LAST_FOUND) )
  1089. {
  1090. DWORD dwIntervals = Connection.dwIntervals;
  1091. for (int nTranspose = 0; nTranspose <= 12; nTranspose++)
  1092. {
  1093. if ( dwIntervals & (1 << nTranspose) )
  1094. {
  1095. if (Transition.bLastPlayed + nTranspose == bMIDI ||
  1096. Transition.bLastPlayed - nTranspose == bMIDI)
  1097. {
  1098. fGoodInterval = true;
  1099. }
  1100. }
  1101. }
  1102. }
  1103. }
  1104. return (fGhost || fOverlap || fGoodInterval) ? S_OK : S_FALSE;
  1105. }
  1106. // Currently assuming diatonic intervals spanning an octave
  1107. #define MAX_INTERVAL 8
  1108. // Currently only transposes up...
  1109. BYTE TransposeNote(BYTE bMIDI, int nInterval, DMUS_CHORD_PARAM& rChord)
  1110. {
  1111. if (!bMIDI) return bMIDI;
  1112. nInterval++; // To correspond to scale intervals
  1113. for (int nSemitone = 0; nSemitone < 24; nSemitone++)
  1114. {
  1115. if (rChord.dwScale & (1 << nSemitone))
  1116. {
  1117. nInterval--;
  1118. if (!nInterval) break;
  1119. }
  1120. }
  1121. if (nSemitone < 24)
  1122. {
  1123. bMIDI = (BYTE) (bMIDI + nSemitone);
  1124. }
  1125. return bMIDI;
  1126. }
  1127. DWORD ShiftScale(DWORD dwScale, char chRoot)
  1128. {
  1129. while (chRoot < 0) chRoot += 12;
  1130. while (chRoot > 11) chRoot -= 12;
  1131. dwScale &= 0xfff;
  1132. dwScale <<= chRoot;
  1133. dwScale |= (dwScale >> 12);
  1134. return dwScale & 0xfff;
  1135. }
  1136. void ScaleMisses(BYTE bTone, DWORD dwScale, BYTE& rFlats, BYTE& rSharps)
  1137. {
  1138. // make sure the flats don't underflow the scale
  1139. bool fUnderflow = true;
  1140. for (int i = 0; i <= bTone; i++)
  1141. {
  1142. if (dwScale & (1 << i))
  1143. {
  1144. fUnderflow = false;
  1145. break;
  1146. }
  1147. }
  1148. if (fUnderflow)
  1149. {
  1150. bTone += 12;
  1151. }
  1152. // make sure the sharps don't overflow the scale
  1153. bool fOverflow = true;
  1154. for (i = bTone; i < 24; i++)
  1155. {
  1156. if (dwScale & (1 << i))
  1157. {
  1158. fOverflow = false;
  1159. break;
  1160. }
  1161. }
  1162. if (fOverflow)
  1163. {
  1164. dwScale |= ((dwScale << 12) & 0xfff000);
  1165. }
  1166. rFlats = rSharps = 0;
  1167. // If this note is in the scale, no need to do any other processing
  1168. if ( !(dwScale & (1 << bTone)) )
  1169. {
  1170. for (i = 0; i <= bTone; i++)
  1171. {
  1172. if (dwScale & (1 << i))
  1173. {
  1174. rFlats = 0;
  1175. }
  1176. else
  1177. {
  1178. rFlats++;
  1179. }
  1180. }
  1181. for (i = bTone; i < 24; i++)
  1182. {
  1183. if (dwScale & (1 << i))
  1184. {
  1185. return;
  1186. }
  1187. else
  1188. {
  1189. rSharps++;
  1190. }
  1191. }
  1192. }
  1193. }
  1194. // Transpose all events in the repeat fragment diatonically, according to the underlying scale given
  1195. // in the chord, adjusting all times relative to the the current fragment.
  1196. // Return the time of the first note in the transposed fragment.
  1197. HRESULT MelodyFragment::TransposeEventList(int nInterval,
  1198. CompositionFragment& rfragmentRepeat,
  1199. DMUS_CHORD_PARAM& rCurrentChord,
  1200. DMUS_CHORD_PARAM& rRealCurrentChord,
  1201. BYTE bPlaymode,
  1202. DirectMusicPartRef& rPartRef,
  1203. TListItem<EventWrapper>*& rpOldEventHead,
  1204. TList<EventWrapper>& rNewEventList,
  1205. BYTE& rbFirstMIDI,
  1206. MUSIC_TIME& rmtFirstTime)
  1207. {
  1208. DWORD dwScale = ShiftScale(rCurrentChord.dwScale, rCurrentChord.bKey);
  1209. DWORD dwChord = ShiftScale(rCurrentChord.SubChordList[0].dwChordPattern, rCurrentChord.SubChordList[0].bChordRoot);
  1210. rbFirstMIDI = 0;
  1211. rmtFirstTime = 0;
  1212. bool fFirstEvent = true;
  1213. HRESULT hr = S_OK;
  1214. MUSIC_TIME mtElapsed = m_mtTime - rfragmentRepeat.GetTime();
  1215. //if (!mtElapsed) mtElapsed = 0; // clamp mtElapsed to non-negative (??)
  1216. if (m_dwTransposeIntervals & (1 << nInterval))
  1217. {
  1218. rNewEventList.CleanUp();
  1219. // Find the corresponding part in the repeat fragment
  1220. TListItem<DirectMusicPartRef>* pPartRef = rfragmentRepeat.m_pPattern->m_PartRefList.GetHead();
  1221. int nParts = rfragmentRepeat.m_pPattern->m_PartRefList.GetCount();
  1222. for (int i = 0; pPartRef != NULL; pPartRef = pPartRef->GetNext(), i++)
  1223. {
  1224. if (pPartRef->GetItemValue().m_dwLogicalPartID == rPartRef.m_dwLogicalPartID) break;
  1225. }
  1226. if (i < nParts)
  1227. {
  1228. TListItem<EventWrapper>* pScan = rfragmentRepeat.GetEventHead(i);
  1229. rpOldEventHead = pScan;
  1230. for (; pScan && SUCCEEDED(hr); pScan = pScan->GetNext())
  1231. {
  1232. EventWrapper ScanEvent = pScan->GetItemValue();
  1233. TListItem<EventWrapper>* pEventItem = new TListItem<EventWrapper>;
  1234. if (!pEventItem) hr = E_OUTOFMEMORY;
  1235. else
  1236. {
  1237. EventWrapper& rEvent = pEventItem->GetItemValue();
  1238. rEvent.m_mtTime = ScanEvent.m_mtTime + mtElapsed;
  1239. rEvent.m_bMIDI = TransposeNote(ScanEvent.m_bMIDI, nInterval, rCurrentChord);
  1240. BYTE bTone = (BYTE) (rEvent.m_bMIDI % 12);
  1241. ScaleMisses(bTone, dwScale, rEvent.m_bScaleFlat, rEvent.m_bScaleSharp);
  1242. ScaleMisses(bTone, dwChord, rEvent.m_bChordFlat, rEvent.m_bChordSharp);
  1243. hr = rPartRef.ConvertMIDIValue(rEvent.m_bMIDI,
  1244. rRealCurrentChord,
  1245. bPlaymode,
  1246. NULL,
  1247. rEvent.m_wMusic);
  1248. if (FAILED(rEvent.m_wMusic))
  1249. {
  1250. rEvent.m_wMusic = 0;
  1251. }
  1252. rEvent.m_bPlaymode = bPlaymode;
  1253. rEvent.m_pEvent = ScanEvent.m_pEvent;
  1254. rEvent.m_dwPChannel = ScanEvent.m_dwPChannel;
  1255. rNewEventList.AddHead(pEventItem);
  1256. if (fFirstEvent || rEvent.m_mtTime < rmtFirstTime)
  1257. {
  1258. rmtFirstTime = rEvent.m_mtTime;
  1259. rbFirstMIDI = rEvent.m_bMIDI;
  1260. fFirstEvent = false;
  1261. }
  1262. }
  1263. }
  1264. if (SUCCEEDED(hr))
  1265. {
  1266. rNewEventList.MergeSort(Greater);
  1267. }
  1268. }
  1269. else hr = E_FAIL;
  1270. }
  1271. else hr = E_FAIL;
  1272. return hr;
  1273. }
  1274. HRESULT MelodyFragment::TestHarmonicConstraints(TListItem<EventWrapper>* pOldEventHead,
  1275. TList<EventWrapper>& rNewEventList)
  1276. {
  1277. HRESULT hr = S_OK;
  1278. TListItem<EventWrapper>* pOldScan = pOldEventHead;
  1279. TListItem<EventWrapper>* pNewScan = rNewEventList.GetHead();
  1280. for (; pOldScan && pNewScan && SUCCEEDED(hr); pOldScan = pOldScan->GetNext(), pNewScan = pNewScan->GetNext())
  1281. {
  1282. EventWrapper& rOldEvent = pOldScan->GetItemValue();
  1283. EventWrapper& rNewEvent = pNewScan->GetItemValue();
  1284. BYTE bOldFlats, bOldSharps, bNewFlats, bNewSharps;
  1285. if (m_dwFragmentFlags & DMUS_FRAGMENTF_CHORD)
  1286. {
  1287. bOldFlats = rOldEvent.m_bChordFlat;
  1288. bOldSharps = rOldEvent.m_bChordSharp;
  1289. bNewFlats = rNewEvent.m_bChordFlat;
  1290. bNewSharps = rNewEvent.m_bChordSharp;
  1291. }
  1292. else if (m_dwFragmentFlags & DMUS_FRAGMENTF_SCALE)
  1293. {
  1294. bOldFlats = rOldEvent.m_bScaleFlat;
  1295. bOldSharps = rOldEvent.m_bScaleSharp;
  1296. bNewFlats = rNewEvent.m_bScaleFlat;
  1297. bNewSharps = rNewEvent.m_bScaleSharp;
  1298. }
  1299. else // something's wrong
  1300. {
  1301. hr = E_FAIL;
  1302. break;
  1303. }
  1304. if (bOldFlats != bNewFlats && bOldSharps != bNewSharps)
  1305. {
  1306. hr = E_FAIL;
  1307. break;
  1308. }
  1309. }
  1310. return hr;
  1311. }
  1312. HRESULT MelodyFragment::GetRepeatedEvents(CompositionFragment& rfragmentRepeat,
  1313. DMUS_CHORD_PARAM& rCurrentChord,
  1314. DMUS_CHORD_PARAM& rRealCurrentChord,
  1315. BYTE bPlaymode,
  1316. int nPartIndex,
  1317. DirectMusicPartRef& rPartRef,
  1318. TListItem<CompositionFragment>* pLastFragment,
  1319. MUSIC_TIME& rmtFirstNote,
  1320. TList<EventWrapper>& rEventList)
  1321. {
  1322. HRESULT hr = E_FAIL;
  1323. BYTE bMIDI = 0;
  1324. TListItem<EventWrapper>* pOldEventHead;
  1325. // For each transposition interval (unison is always the first interval tested):
  1326. for (int i = 0; i < MAX_INTERVAL; i++)
  1327. {
  1328. if (SUCCEEDED(TransposeEventList(i, rfragmentRepeat, rCurrentChord, rRealCurrentChord, bPlaymode, rPartRef, pOldEventHead, rEventList, bMIDI, rmtFirstNote)))
  1329. {
  1330. // Test transposed notes against harmonic constraints
  1331. if (SUCCEEDED(TestHarmonicConstraints(pOldEventHead, rEventList)))
  1332. {
  1333. // Test transposed notes against transition constraints (assuming there are any)
  1334. // (note: eventually this test may be allowed to add transition notes as appropriate)
  1335. // If there are no transition constraints, don't bother to test them.
  1336. if (!pLastFragment ||
  1337. !pLastFragment->GetItemValue().UsesTransitionRules())
  1338. {
  1339. hr = S_OK;
  1340. break;
  1341. }
  1342. if (S_OK == TestTransition(bMIDI, rmtFirstNote, rCurrentChord, nPartIndex, rPartRef, pLastFragment))
  1343. {
  1344. hr = S_OK;
  1345. break;
  1346. }
  1347. }
  1348. }
  1349. }
  1350. // If no interval satisfies both constraints, fail.
  1351. if (FAILED(hr)) rEventList.CleanUp();
  1352. return hr;
  1353. }
  1354. // this should ensure, if possible, that the selected variations
  1355. // work for all chords from the current one to mtNext
  1356. HRESULT MelodyFragment::GetVariations(CompositionFragment& rCompFragment,
  1357. CompositionFragment& rfragmentRepeat,
  1358. CompositionFragment& rfragmentLast,
  1359. DMUS_CHORD_PARAM& rCurrentChord,
  1360. DMUS_CHORD_PARAM& rNextChord,
  1361. MUSIC_TIME mtNextChord,
  1362. TListItem<CompositionFragment>* pLastFragment)
  1363. {
  1364. DWORD* adwVariationMask = NULL;
  1365. DWORD* adwRemoveVariations = NULL;
  1366. static BYTE abVariationGroups[MAX_VARIATION_LOCKS];
  1367. DWORD dwVariationFlags = 0;
  1368. CDirectMusicPattern* pPattern = NULL;
  1369. if (m_dwFragmentFlags & DMUS_FRAGMENTF_USE_REPEAT)
  1370. {
  1371. dwVariationFlags = rfragmentRepeat.GetVariationFlags();
  1372. pPattern = rfragmentRepeat.m_pPattern;
  1373. int nParts = rfragmentRepeat.m_pPattern->m_PartRefList.GetCount();
  1374. adwVariationMask = new DWORD[nParts];
  1375. adwRemoveVariations = new DWORD[nParts];
  1376. if (!adwVariationMask || !adwRemoveVariations)
  1377. {
  1378. return E_OUTOFMEMORY;
  1379. }
  1380. for (int i = 0; i < nParts; i++)
  1381. {
  1382. adwRemoveVariations[i] = 0;
  1383. }
  1384. if (m_dwFragmentFlags & DMUS_FRAGMENTF_REJECT_REPEAT)
  1385. {
  1386. // any variation but the one previously selected (for all parts)
  1387. for (int i = 0; i < nParts; i++)
  1388. {
  1389. adwVariationMask[i] = dwVariationFlags ^ (1 << rfragmentLast.m_abVariations[i]);
  1390. }
  1391. }
  1392. else
  1393. {
  1394. // only the variation previously selected (for all parts)
  1395. for (int i = 0; i < nParts; i++)
  1396. {
  1397. adwVariationMask[i] = dwVariationFlags & (1 << rfragmentLast.m_abVariations[i]);
  1398. }
  1399. }
  1400. }
  1401. else
  1402. {
  1403. pPattern = rCompFragment.m_pPattern;
  1404. int nParts = rCompFragment.m_pPattern->m_PartRefList.GetCount();
  1405. adwVariationMask = new DWORD[nParts];
  1406. if (!adwVariationMask)
  1407. {
  1408. return E_OUTOFMEMORY;
  1409. }
  1410. adwRemoveVariations = new DWORD[nParts];
  1411. if (!adwRemoveVariations)
  1412. {
  1413. delete [] adwVariationMask;
  1414. return E_OUTOFMEMORY;
  1415. }
  1416. for (int i = 0; i < nParts; i++)
  1417. {
  1418. adwRemoveVariations[i] = 0;
  1419. }
  1420. if (m_dwFragmentFlags & DMUS_FRAGMENTF_USE_LABEL)
  1421. {
  1422. delete [] adwVariationMask;
  1423. delete [] adwRemoveVariations;
  1424. return E_NOTIMPL;
  1425. }
  1426. else
  1427. {
  1428. for (int i = 0; i < nParts; i++)
  1429. {
  1430. adwVariationMask[i] = rCompFragment.GetVariationFlags();
  1431. }
  1432. }
  1433. }
  1434. // filter variations according to transition constraints
  1435. if (pLastFragment && pLastFragment->GetItemValue().UsesTransitionRules())
  1436. {
  1437. TListItem<DirectMusicPartRef>* pPartRef = rCompFragment.m_pPattern->m_PartRefList.GetHead();
  1438. for (int i = 0; pPartRef != NULL; pPartRef = pPartRef->GetNext(), i++)
  1439. {
  1440. DWORD dwOriginalMask = adwVariationMask[i];
  1441. //int nPart = pPartRef->GetItemValue().m_wLogicalPartID;
  1442. for (int nVar = 0; nVar < 32; nVar++)
  1443. {
  1444. if ( adwVariationMask[i] & (1 << nVar) )
  1445. {
  1446. // get the first note of the variation
  1447. BYTE bMIDI = 0;
  1448. MUSIC_TIME mtNote = 0;
  1449. HRESULT hrFirst = GetFirstNote(nVar, rCurrentChord, rCompFragment, pPartRef->GetItemValue(), bMIDI, mtNote);
  1450. // if this variation doesn't meet the constraints, remove it from the mask
  1451. if ( SUCCEEDED(hrFirst) &&
  1452. S_OK != TestTransition(bMIDI, mtNote, rCurrentChord, i, pPartRef->GetItemValue(), pLastFragment) )
  1453. {
  1454. adwVariationMask[i] &= ~(1 << nVar);
  1455. }
  1456. }
  1457. }
  1458. // If none of the variations meet all the constraints, fall back to the original mask
  1459. if (!adwVariationMask[i]) adwVariationMask[i] = dwOriginalMask;
  1460. }
  1461. }
  1462. DWORD dwFlags = (COMPUTE_VARIATIONSF_USE_MASK | COMPUTE_VARIATIONSF_NEW_PATTERN | COMPUTE_VARIATIONSF_DX8);
  1463. HRESULT hr = pPattern->ComputeVariations(dwFlags,
  1464. rCurrentChord,
  1465. rNextChord,
  1466. abVariationGroups,
  1467. adwVariationMask,
  1468. adwRemoveVariations,
  1469. rCompFragment.m_abVariations,
  1470. m_mtTime,
  1471. mtNextChord);
  1472. if (adwVariationMask) delete [] adwVariationMask;
  1473. if (adwRemoveVariations) delete [] adwRemoveVariations;
  1474. return hr;
  1475. }
  1476. HRESULT MelodyFragment::GetFirstNote(int nVariation,
  1477. DMUS_CHORD_PARAM& rCurrentChord,
  1478. CompositionFragment& rCompFragment,
  1479. DirectMusicPartRef& rPartRef,
  1480. BYTE& rbMidi,
  1481. MUSIC_TIME& rmtNote)
  1482. {
  1483. HRESULT hr = S_OK;
  1484. DirectMusicPart* pPart = rPartRef.m_pDMPart;
  1485. DirectMusicTimeSig& TimeSig = rCompFragment.GetTimeSig(pPart);
  1486. CDirectMusicEventItem* pEvent = pPart->EventList.GetHead();
  1487. bool fFoundNote = false;
  1488. for (; pEvent; pEvent = pEvent->GetNext())
  1489. {
  1490. if ( pEvent->m_dwVariation & (1 << nVariation) )
  1491. {
  1492. if (pEvent->m_dwEventTag == DMUS_EVENT_NOTE)
  1493. {
  1494. MUSIC_TIME mtNow = GetTime() +
  1495. TimeSig.GridToClocks(pEvent->m_nGridStart) + pEvent->m_nTimeOffset;
  1496. if (!fFoundNote || mtNow < rmtNote)
  1497. {
  1498. hr = GetNote(pEvent, rCurrentChord, rPartRef, rbMidi);
  1499. if (SUCCEEDED(hr))
  1500. {
  1501. fFoundNote = true;
  1502. rmtNote = mtNow;
  1503. }
  1504. }
  1505. }
  1506. }
  1507. }
  1508. if (!fFoundNote) hr = S_FALSE;
  1509. return hr;
  1510. }
  1511. HRESULT MelodyFragment::GetNote(CDirectMusicEventItem* pEvent,
  1512. DMUS_CHORD_PARAM& rCurrentChord,
  1513. DirectMusicPartRef& rPartRef,
  1514. BYTE& rbMidi)
  1515. {
  1516. HRESULT hr = S_OK;
  1517. // only process note events
  1518. CDMStyleNote* pNoteEvent = NULL;
  1519. if (pEvent->m_dwEventTag == DMUS_EVENT_NOTE) // we have a note event
  1520. {
  1521. pNoteEvent = (CDMStyleNote*)pEvent;
  1522. // get a playmode (either from the note or from the melody fragment)
  1523. BYTE bPlaymode = (BYTE) m_dwPlayModeFlags;
  1524. short nMidiOffset = 0;
  1525. if (bPlaymode == DMUS_PLAYMODE_NONE)
  1526. {
  1527. bPlaymode =
  1528. (pNoteEvent->m_bPlayModeFlags & DMUS_PLAYMODE_NONE) ?
  1529. rPartRef.m_pDMPart->m_bPlayModeFlags :
  1530. pNoteEvent->m_bPlayModeFlags;
  1531. }
  1532. // generate a MIDI value from the melody note, fragment, chord, and playmode
  1533. HRESULT hrTest = rPartRef.ConvertMusicValue(pNoteEvent,
  1534. rCurrentChord,
  1535. bPlaymode,
  1536. FALSE,
  1537. m_aInversionGroups,
  1538. NULL,
  1539. rbMidi,
  1540. nMidiOffset);
  1541. }
  1542. else
  1543. {
  1544. hr = S_FALSE;
  1545. }
  1546. return hr;
  1547. }
  1548. HRESULT MelodyFragment::GetEvent(CDirectMusicEventItem* pEvent,
  1549. DMUS_CHORD_PARAM& rCurrentChord,
  1550. DMUS_CHORD_PARAM& rRealCurrentChord,
  1551. MUSIC_TIME mtNow,
  1552. DirectMusicPartRef& rPartRef,
  1553. TListItem<EventWrapper>*& rpEventItem)
  1554. {
  1555. DWORD dwScale = ShiftScale(rCurrentChord.dwScale, rCurrentChord.bKey);
  1556. DWORD dwChord = ShiftScale(rCurrentChord.SubChordList[0].dwChordPattern, rCurrentChord.SubChordList[0].bChordRoot);
  1557. HRESULT hr = S_OK;
  1558. // only process note events
  1559. CDMStyleNote* pNoteEvent = NULL;
  1560. if (pEvent->m_dwEventTag == DMUS_EVENT_NOTE) // we have a note event
  1561. {
  1562. pNoteEvent = (CDMStyleNote*)pEvent;
  1563. // get a playmode (either from the note or from the melody fragment)
  1564. BYTE bPlaymode = (BYTE) m_dwPlayModeFlags;
  1565. BYTE bMIDI = 0;
  1566. WORD wMusic = 0;
  1567. short nMidiOffset = 0;
  1568. if (bPlaymode == DMUS_PLAYMODE_NONE)
  1569. {
  1570. bPlaymode =
  1571. (pNoteEvent->m_bPlayModeFlags & DMUS_PLAYMODE_NONE) ?
  1572. rPartRef.m_pDMPart->m_bPlayModeFlags :
  1573. pNoteEvent->m_bPlayModeFlags;
  1574. }
  1575. // generate a MIDI value from the melody note, fragment, chord, and playmode
  1576. HRESULT hrTest = rPartRef.ConvertMusicValue(pNoteEvent,
  1577. rCurrentChord,
  1578. bPlaymode,
  1579. FALSE,
  1580. m_aInversionGroups,
  1581. NULL,
  1582. bMIDI,
  1583. nMidiOffset);
  1584. if (SUCCEEDED(hrTest))
  1585. {
  1586. hrTest = rPartRef.ConvertMIDIValue(bMIDI,
  1587. rRealCurrentChord,
  1588. bPlaymode,
  1589. NULL,
  1590. wMusic);
  1591. }
  1592. if (FAILED(hrTest)) hr = hrTest;
  1593. else
  1594. {
  1595. rpEventItem = new TListItem<EventWrapper>;
  1596. if (!rpEventItem) hr = E_OUTOFMEMORY;
  1597. else
  1598. {
  1599. EventWrapper& rEvent = rpEventItem->GetItemValue();
  1600. rEvent.m_mtTime = mtNow - pNoteEvent->m_nTimeOffset; // remove the offset (it's in m_nTimeOffset)
  1601. rEvent.m_bMIDI = bMIDI;
  1602. BYTE bTone = (BYTE) (bMIDI % 12);
  1603. ScaleMisses(bTone, dwScale, rEvent.m_bScaleFlat, rEvent.m_bScaleSharp);
  1604. ScaleMisses(bTone, dwChord, rEvent.m_bChordFlat, rEvent.m_bChordSharp);
  1605. rEvent.m_wMusic = wMusic;
  1606. rEvent.m_pEvent = pNoteEvent;
  1607. rEvent.m_dwPChannel = rPartRef.m_dwLogicalPartID;
  1608. rEvent.m_bPlaymode = bPlaymode;
  1609. }
  1610. }
  1611. }
  1612. else
  1613. {
  1614. hr = S_FALSE;
  1615. }
  1616. return hr;
  1617. }
  1618. // IDirectMusicTrack8 Methods
  1619. // For consistency with other track types
  1620. STDMETHODIMP CMelodyFormulationTrack::GetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime,
  1621. REFERENCE_TIME* prtNext,void* pParam,void * pStateData, DWORD dwFlags)
  1622. {
  1623. HRESULT hr;
  1624. MUSIC_TIME mtNext;
  1625. hr = GetParam(rguidType,(MUSIC_TIME) rtTime, &mtNext, pParam);
  1626. if (prtNext)
  1627. {
  1628. *prtNext = mtNext;
  1629. }
  1630. return hr;
  1631. }
  1632. // For consistency with other track types
  1633. STDMETHODIMP CMelodyFormulationTrack::SetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime,
  1634. void* pParam, void * pStateData, DWORD dwFlags)
  1635. {
  1636. return SetParam(rguidType, (MUSIC_TIME) rtTime , pParam);
  1637. }
  1638. // For consistency with other track types
  1639. STDMETHODIMP CMelodyFormulationTrack::PlayEx(void* pStateData,REFERENCE_TIME rtStart,
  1640. REFERENCE_TIME rtEnd,REFERENCE_TIME rtOffset,
  1641. DWORD dwFlags,IDirectMusicPerformance* pPerf,
  1642. IDirectMusicSegmentState* pSegSt,DWORD dwVirtualID)
  1643. {
  1644. V_INAME(IDirectMusicTrack::PlayEx);
  1645. V_INTERFACE(pPerf);
  1646. V_INTERFACE(pSegSt);
  1647. HRESULT hr;
  1648. EnterCriticalSection(&m_CriticalSection);
  1649. hr = Play(pStateData, (MUSIC_TIME)rtStart, (MUSIC_TIME)rtEnd,
  1650. (MUSIC_TIME)rtOffset, dwFlags, pPerf, pSegSt, dwVirtualID);
  1651. LeaveCriticalSection(&m_CriticalSection);
  1652. return hr;
  1653. }
  1654. STDMETHODIMP CMelodyFormulationTrack::Compose(
  1655. IUnknown* pContext,
  1656. DWORD dwTrackGroup,
  1657. IDirectMusicTrack** ppResultTrack)
  1658. {
  1659. V_INAME(Compose)
  1660. V_INTERFACE(pContext);
  1661. V_PTRPTR_WRITE(ppResultTrack);
  1662. EnterCriticalSection(&m_CriticalSection);
  1663. HRESULT hr = S_OK;
  1664. IDirectMusicTrack* pPatternTrack = NULL;
  1665. IDirectMusicStyle* pStyle = NULL;
  1666. IDMStyle* pDMStyle = NULL;
  1667. MUSIC_TIME mtLength = 0;
  1668. IDirectMusicSegment* pTempSeg = NULL;
  1669. IDirectMusicSong* pSong = NULL;
  1670. if (FAILED(pContext->QueryInterface(IID_IDirectMusicSegment, (void**)&pTempSeg)))
  1671. {
  1672. if (FAILED(pContext->QueryInterface(IID_IDirectMusicSong, (void**)&pSong)))
  1673. {
  1674. hr = E_INVALIDARG;
  1675. goto ON_END;
  1676. }
  1677. }
  1678. if (pTempSeg)
  1679. {
  1680. if (FAILED(hr = pTempSeg->GetParam(GUID_IDirectMusicStyle, dwTrackGroup, 0, 0, NULL, (void*)&pStyle))) goto ON_END;
  1681. if (FAILED(hr = pTempSeg->GetLength(&mtLength))) goto ON_END;
  1682. }
  1683. else if (pSong)
  1684. {
  1685. MUSIC_TIME mtNow = 0;
  1686. MUSIC_TIME mtNext = 0;
  1687. while (FAILED(hr = pSong->GetParam(GUID_IDirectMusicStyle, dwTrackGroup, 0, mtNow, &mtNext, (void*)&pStyle)))
  1688. {
  1689. if (mtNext <= 0) goto ON_END;
  1690. mtNow = mtNext;
  1691. }
  1692. //if (FAILED(hr = pSong->GetParam(GUID_IDirectMusicStyle, dwTrackGroup, 0, 0, NULL, (void*)&pStyle))) goto ON_END;
  1693. IDirectMusicSegment* pSeg = NULL;
  1694. DWORD dwSeg = 0;
  1695. while (S_OK == hr)
  1696. {
  1697. if (FAILED(hr = pSong->EnumSegment(dwSeg, &pSeg))) goto ON_END;
  1698. if (hr == S_OK)
  1699. {
  1700. MUSIC_TIME mt = 0;
  1701. hr = pSeg->GetLength(&mt);
  1702. if (FAILED(hr)) goto ON_END;
  1703. mtLength += mt;
  1704. pSeg->Release();
  1705. pSeg = NULL;
  1706. dwSeg++;
  1707. }
  1708. }
  1709. }
  1710. // Using chord track, style, and melgen track, create a pattern track
  1711. hr = pStyle->QueryInterface(IID_IDMStyle, (void**)&pDMStyle);
  1712. if (SUCCEEDED(hr))
  1713. {
  1714. hr = pDMStyle->GenerateTrack(pTempSeg, pSong, dwTrackGroup, pStyle, this, mtLength, pPatternTrack);
  1715. if (SUCCEEDED(hr))
  1716. {
  1717. *ppResultTrack = pPatternTrack;
  1718. }
  1719. pDMStyle->Release();
  1720. }
  1721. ON_END:
  1722. // Release from Addref in GetStyle
  1723. if (pStyle) pStyle->Release();
  1724. if (pSong) pSong->Release();
  1725. if (pTempSeg) pTempSeg->Release();
  1726. LeaveCriticalSection(&m_CriticalSection);
  1727. return hr;
  1728. }
  1729. // if ppResultTrack is NULL, add pNewTrack to the end of the current track;
  1730. // otherwise, create a copy of the current track and add pNewTrack to the end of the copy.
  1731. // The new track starts at mtJoin, so get rid of everything before that in the current
  1732. // track (or its clone). If cloning, simply clone to mtJoin.
  1733. STDMETHODIMP CMelodyFormulationTrack::Join(
  1734. IDirectMusicTrack* pNewTrack,
  1735. MUSIC_TIME mtJoin,
  1736. IUnknown* pContext,
  1737. DWORD dwTrackGroup,
  1738. IDirectMusicTrack** ppResultTrack)
  1739. {
  1740. V_INAME(IDirectMusicTrack::Join);
  1741. V_INTERFACE(pNewTrack);
  1742. V_PTRPTR_WRITE_OPT(ppResultTrack);
  1743. HRESULT hr = S_OK;
  1744. EnterCriticalSection(&m_CriticalSection);
  1745. TList<DMUS_MELODY_FRAGMENT> ResultList;
  1746. CMelodyFormulationTrack* pResultTrack = NULL;
  1747. DWORD dwMaxID = 0;
  1748. if (ppResultTrack)
  1749. {
  1750. hr = Clone(0, mtJoin, ppResultTrack);
  1751. pResultTrack = (CMelodyFormulationTrack*)*ppResultTrack;
  1752. while(!pResultTrack->m_FragmentList.IsEmpty())
  1753. {
  1754. ResultList.AddHead(pResultTrack->m_FragmentList.RemoveHead());
  1755. DWORD dwThis = ResultList.GetHead()->GetItemValue().dwID;
  1756. if (dwThis > dwMaxID) dwMaxID = dwThis;
  1757. }
  1758. }
  1759. else
  1760. {
  1761. pResultTrack = this;
  1762. while(!m_FragmentList.IsEmpty() &&
  1763. m_FragmentList.GetHead()->GetItemValue().mtTime < mtJoin)
  1764. {
  1765. ResultList.AddHead(m_FragmentList.RemoveHead());
  1766. DWORD dwThis = ResultList.GetHead()->GetItemValue().dwID;
  1767. if (dwThis > dwMaxID) dwMaxID = dwThis;
  1768. }
  1769. m_FragmentList.CleanUp();
  1770. }
  1771. CMelodyFormulationTrack* pOtherTrack = (CMelodyFormulationTrack*)pNewTrack;
  1772. TListItem<DMUS_MELODY_FRAGMENT>* pScan = pOtherTrack->m_FragmentList.GetHead();
  1773. for (; pScan; pScan = pScan->GetNext())
  1774. {
  1775. TListItem<DMUS_MELODY_FRAGMENT>* pNew = new TListItem<DMUS_MELODY_FRAGMENT>(pScan->GetItemValue());
  1776. if (pNew)
  1777. {
  1778. DMUS_MELODY_FRAGMENT& rNew = pNew->GetItemValue();
  1779. rNew.mtTime += mtJoin;
  1780. rNew.dwID += dwMaxID;
  1781. if (rNew.dwRepeatFragmentID &&
  1782. (rNew.dwFragmentFlags & (DMUS_FRAGMENTF_USE_REPEAT | DMUS_FRAGMENTF_REJECT_REPEAT)) )
  1783. {
  1784. rNew.dwRepeatFragmentID += dwMaxID;
  1785. }
  1786. ResultList.AddHead(pNew);
  1787. }
  1788. else
  1789. {
  1790. ResultList.CleanUp();
  1791. hr = E_OUTOFMEMORY;
  1792. break;
  1793. }
  1794. }
  1795. if (SUCCEEDED(hr))
  1796. {
  1797. pResultTrack->m_FragmentList.CleanUp();
  1798. while(!ResultList.IsEmpty() )
  1799. {
  1800. pResultTrack->m_FragmentList.AddHead(ResultList.RemoveHead());
  1801. }
  1802. }
  1803. LeaveCriticalSection(&m_CriticalSection);
  1804. return hr;
  1805. }