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.

986 lines
42 KiB

  1. //
  2. // DMStyle2.cpp : Further Implementation of CDMStyle
  3. //
  4. // Copyright (c) 1999-2001 Microsoft Corporation
  5. //
  6. // @doc EXTERNAL
  7. //
  8. #include "DMStyle.h"
  9. #include "debug.h"
  10. #include "..\shared\Validate.h"
  11. #include "iostru.h"
  12. #include "mgentrk.h"
  13. struct FirstTimePair
  14. {
  15. DWORD dwPart;
  16. MUSIC_TIME mtTime;
  17. };
  18. /////////////////////////////////////////////////////////////////////////////
  19. // IDirectMusicStyle2
  20. /*
  21. @method:(EXTERNAL) HRESULT | IDirectMusicComposer | ComposeMelodyFromTemplate | Creates a sequence segment from a
  22. style and a Melody template (containing a Melody Generation track, a Chord track, and an
  23. optional Style track). Clones the segment and adds a Sequence track containing melodic
  24. information.
  25. @rdesc Returns:
  26. @flag S_OK | Success
  27. @flag E_POINTER | One or both of <p pTempSeg> and <p ppSeqSeg> is an invalid pointer.
  28. @flag E_INVALIDARG | <p pStyle> is NULL and there is no Style track.
  29. @comm If <p pStyle> is non-NULL, it is used in composing the segment; if it is NULL,
  30. a Style is retrieved from <p pTempSeg>'s Style track.
  31. The length of the section segment is equal to the length of the template section
  32. passed in.
  33. */
  34. HRESULT CDMStyle::ComposeMelodyFromTemplate(
  35. IDirectMusicStyle* pStyle, // @parm The style from which to create the sequence segment.
  36. IDirectMusicSegment* pTempSeg, // @parm The template from which to create the sequence segment.
  37. IDirectMusicSegment** ppSeqSeg // @parm Returns the created sequence segment.
  38. )
  39. {
  40. V_INAME(ComposeMelodyFromTemplate)
  41. V_PTR_WRITE_OPT(pStyle, 1);
  42. V_PTR_WRITE(pTempSeg, 1);
  43. V_PTRPTR_WRITE(ppSeqSeg);
  44. DWORD dwTrackGroup = 0xffffffff;
  45. BOOL fStyleFromTrack = FALSE;
  46. HRESULT hr = S_OK;
  47. IDirectMusicTrack* pPatternTrack = NULL;
  48. IDirectMusicTrack* pMelGenTrack = NULL;
  49. MUSIC_TIME mtLength = 0;
  50. hr = pTempSeg->GetLength(&mtLength);
  51. if (FAILED(hr)) goto ON_END;
  52. // get the MelGen track and its track group.
  53. hr = pTempSeg->GetTrack(CLSID_DirectMusicMelodyFormulationTrack, 0xffffffff, 0, &pMelGenTrack);
  54. if (S_OK != hr) goto ON_END;
  55. if (FAILED(pTempSeg->GetTrackGroup(pMelGenTrack, &dwTrackGroup)))
  56. {
  57. dwTrackGroup = 0xffffffff;
  58. }
  59. // Get the style (either use the passed-in style or get one from a style track)
  60. if (!pStyle)
  61. {
  62. if (FAILED(hr = GetStyle(pTempSeg, 0, dwTrackGroup, pStyle)))
  63. {
  64. hr = E_INVALIDARG;
  65. goto ON_END;
  66. }
  67. fStyleFromTrack = TRUE;
  68. }
  69. // Using style, and melgen track, create a pattern track
  70. hr = GenerateTrack(pTempSeg, NULL, dwTrackGroup, pStyle, pMelGenTrack, mtLength, pPatternTrack);
  71. if (SUCCEEDED(hr))
  72. {
  73. if (hr == S_FALSE)
  74. {
  75. if (pPatternTrack) pPatternTrack->Release();
  76. pPatternTrack = NULL;
  77. }
  78. HRESULT hrCopy = CopySegment(pTempSeg, pStyle, pPatternTrack, dwTrackGroup, ppSeqSeg);
  79. if (FAILED(hrCopy)) hr = hrCopy;
  80. }
  81. ON_END:
  82. // release from Addref in GetTrack
  83. if (pMelGenTrack) pMelGenTrack->Release();
  84. // release from CoCreateInstance in CreatePatternTrack
  85. if (pPatternTrack) pPatternTrack->Release();
  86. // Release from Addref in GetStyle
  87. if (fStyleFromTrack) pStyle->Release();
  88. return hr;
  89. }
  90. HRESULT CDMStyle::GetStyle(IDirectMusicSegment* pFromSeg, MUSIC_TIME mt, DWORD dwTrackGroup, IDirectMusicStyle*& rpStyle)
  91. {
  92. HRESULT hr = S_OK;
  93. // Get the segment's style track.
  94. IDirectMusicTrack* pStyleTrack;
  95. hr = pFromSeg->GetTrack(CLSID_DirectMusicStyleTrack, dwTrackGroup, 0, &pStyleTrack);
  96. if (S_OK != hr) return hr;
  97. // Get the style from the style track
  98. hr = pStyleTrack->GetParam(GUID_IDirectMusicStyle, mt, NULL, (void*) &rpStyle);
  99. pStyleTrack->Release();
  100. return hr;
  101. }
  102. HRESULT CDMStyle::CopySegment(IDirectMusicSegment* pTempSeg,
  103. IDirectMusicStyle* pStyle,
  104. IDirectMusicTrack* pPatternTrack,
  105. DWORD dwTrackGroup,
  106. IDirectMusicSegment** ppSectionSeg)
  107. {
  108. if (!ppSectionSeg) return E_INVALIDARG;
  109. HRESULT hr = S_OK;
  110. long nClocks = 0;
  111. IDirectMusicTrack* pIStyleTrack = NULL;
  112. IDirectMusicTrack* pDMTrack = NULL;
  113. IDirectMusicTrack* pBandTrack = NULL;
  114. IDirectMusicBand* pBand = NULL;
  115. DMUS_BAND_PARAM DMBandParam;
  116. pTempSeg->GetLength(&nClocks);
  117. /////////////////////////////////////////////////////////////
  118. // clone the template segment to get a section segment
  119. hr = pTempSeg->Clone(0, nClocks, ppSectionSeg);
  120. if (!SUCCEEDED(hr)) goto ON_END;
  121. // Extract the style's time signature.
  122. DMUS_TIMESIGNATURE TimeSig;
  123. pStyle->GetTimeSignature(&TimeSig);
  124. // Remove all style tracks from the new segment.
  125. do
  126. {
  127. hr = (*ppSectionSeg)->GetTrack(CLSID_DirectMusicStyleTrack, dwTrackGroup, 0, &pIStyleTrack);
  128. if (S_OK == hr)
  129. {
  130. (*ppSectionSeg)->RemoveTrack(pIStyleTrack);
  131. pIStyleTrack->Release();
  132. pIStyleTrack = NULL;
  133. }
  134. } while (S_OK == hr);
  135. // hr is no longer S_OK, so reset it.
  136. hr = S_OK;
  137. // if there's no tempo track in the template segment, create one and add it
  138. if (FAILED(pTempSeg->GetTrack(CLSID_DirectMusicTempoTrack, dwTrackGroup, 0, &pDMTrack)))
  139. {
  140. // Create a Tempo Track in which to store the tempo events
  141. DMUS_TEMPO_PARAM tempo;
  142. tempo.mtTime = 0;
  143. pStyle->GetTempo(&tempo.dblTempo);
  144. if( SUCCEEDED( CoCreateInstance( CLSID_DirectMusicTempoTrack,
  145. NULL, CLSCTX_INPROC, IID_IDirectMusicTrack,
  146. (void**)&pDMTrack )))
  147. {
  148. if ( SUCCEEDED(pDMTrack->SetParam(GUID_TempoParam, 0, &tempo)) )
  149. {
  150. (*ppSectionSeg)->InsertTrack( pDMTrack, dwTrackGroup );
  151. }
  152. }
  153. }
  154. // if there's no band track in the template segment, create one and add it
  155. if (FAILED(pTempSeg->GetTrack(CLSID_DirectMusicBandTrack, dwTrackGroup, 0, &pBandTrack)))
  156. {
  157. // Create band track
  158. hr = ::CoCreateInstance(
  159. CLSID_DirectMusicBandTrack,
  160. NULL,
  161. CLSCTX_INPROC,
  162. IID_IDirectMusicTrack,
  163. (void**)&pBandTrack
  164. );
  165. if(!SUCCEEDED(hr)) goto ON_END;
  166. // Load default band from style into track
  167. hr = pStyle->GetDefaultBand(&pBand);
  168. if (!SUCCEEDED(hr)) goto ON_END;
  169. DMBandParam.mtTimePhysical = -64;
  170. DMBandParam.pBand = pBand;
  171. hr = pBandTrack->SetParam(GUID_BandParam, 0, (void*)&DMBandParam);
  172. if (!SUCCEEDED(hr)) goto ON_END;
  173. (*ppSectionSeg)->InsertTrack(pBandTrack, dwTrackGroup);
  174. }
  175. // Add the pattern track
  176. if (pPatternTrack)
  177. {
  178. (*ppSectionSeg)->InsertTrack(pPatternTrack, dwTrackGroup);
  179. }
  180. // Initialize the segment
  181. (*ppSectionSeg)->SetRepeats(0);
  182. TraceI(4, "Segment Length: %d\n", nClocks);
  183. (*ppSectionSeg)->SetLength(nClocks);
  184. ON_END:
  185. if (pDMTrack)
  186. {
  187. // This releases the Addref made either by GetTrack or (if GetTrack failed)
  188. // by CoCreateInstance
  189. pDMTrack->Release();
  190. }
  191. if (pBandTrack)
  192. {
  193. // This releases the Addref made either by GetTrack or (if GetTrack failed)
  194. // by CoCreateInstance
  195. pBandTrack->Release();
  196. }
  197. if (pIStyleTrack) pIStyleTrack->Release();
  198. if (pBand) pBand->Release();
  199. return hr;
  200. }
  201. HRESULT CDMStyle::GenerateTrack(IDirectMusicSegment* pTempSeg,
  202. IDirectMusicSong* pSong,
  203. DWORD dwTrackGroup,
  204. IDirectMusicStyle* pStyle,
  205. IDirectMusicTrack* pMelGenTrack,
  206. MUSIC_TIME mtLength,
  207. IDirectMusicTrack*& pNewTrack)
  208. {
  209. if (!pStyle || !pMelGenTrack) return E_INVALIDARG;
  210. HRESULT hr = S_OK;
  211. // CoCreate the pattern track
  212. hr = ::CoCreateInstance(
  213. CLSID_DirectMusicPatternTrack,
  214. NULL,
  215. CLSCTX_INPROC,
  216. IID_IDirectMusicTrack,
  217. (void**)&pNewTrack
  218. );
  219. if (FAILED(hr)) return hr;
  220. // Get the Style's info struct
  221. IDMStyle* pDMStyle = NULL;
  222. hr = pStyle->QueryInterface(IID_IDMStyle, (void**) &pDMStyle);
  223. if (FAILED(hr)) return hr;
  224. DMStyleStruct* pStyleStruct = NULL;
  225. pDMStyle->GetStyleInfo((void**)&pStyleStruct);
  226. MUSIC_TIME mtNewFragment = 0;
  227. MUSIC_TIME mtNext = 0;
  228. MUSIC_TIME mtRealNextChord = 0;
  229. MUSIC_TIME mtNextChord = 0;
  230. MUSIC_TIME mtLaterChord = 0;
  231. DMUS_MELODY_FRAGMENT DMUS_Fragment;
  232. memset(&DMUS_Fragment, 0, sizeof(DMUS_Fragment));
  233. DMUS_CHORD_PARAM CurrentChord;
  234. DMUS_CHORD_PARAM RealCurrentChord;
  235. DMUS_CHORD_PARAM NextChord;
  236. CDirectMusicPattern* pPattern;
  237. TList<CompositionFragment> listFragments;
  238. TListItem<CompositionFragment>* pLastFragment = NULL;
  239. CompositionFragment CompRepeat;
  240. FirstTimePair* aFirstTimes = NULL;
  241. BYTE bPlaymode = 0;
  242. pMelGenTrack->GetParam(GUID_MelodyPlaymode, 0, NULL, (void*)&bPlaymode);
  243. if (bPlaymode & DMUS_PLAYMODE_NONE)
  244. {
  245. bPlaymode = DMUS_PLAYMODE_ALWAYSPLAY;
  246. }
  247. // for each melody fragment:
  248. do
  249. {
  250. pLastFragment = listFragments.GetHead();
  251. // get the fragment
  252. HRESULT hrFragment = pMelGenTrack->GetParam(GUID_MelodyFragment, mtNewFragment, &mtNext, (void*)&DMUS_Fragment);
  253. if (FAILED(hrFragment)) break;
  254. MelodyFragment Fragment = DMUS_Fragment;
  255. if (mtNext) mtNewFragment += mtNext;
  256. else mtNewFragment = 0;
  257. // get its repeat
  258. MelodyFragment repeatFragment = Fragment;
  259. hr = pMelGenTrack->GetParam(GUID_MelodyFragmentRepeat, 0, NULL, (void*)&DMUS_Fragment);
  260. if (SUCCEEDED(hr))
  261. {
  262. repeatFragment = DMUS_Fragment;
  263. }
  264. else // failing to get a repeat just means this fragment doesn't repeat; composition can still continue
  265. {
  266. hr = S_OK;
  267. }
  268. // If the fragment repeats an earlier fragment, get the earlier fragment.
  269. // Regardless, get the fragment's pattern.
  270. ZeroMemory( &CompRepeat, sizeof(CompRepeat));
  271. if (SUCCEEDED(hrFragment) && Fragment.UsesRepeat())
  272. {
  273. TListItem<CompositionFragment>* pScan = listFragments.GetHead();
  274. for (; pScan; pScan = pScan->GetNext())
  275. {
  276. if (pScan->GetItemValue().GetID() == repeatFragment.GetID())
  277. {
  278. CompRepeat = pScan->GetItemValue();
  279. }
  280. }
  281. pPattern = CompRepeat.m_pPattern;
  282. }
  283. else
  284. {
  285. Fragment.GetPattern(pStyleStruct, pPattern, pLastFragment);
  286. }
  287. // bail if we couldn't get a pattern
  288. if (!pPattern)
  289. {
  290. hr = DMUS_E_NOT_FOUND;
  291. break;
  292. }
  293. // get the pattern's partrefs
  294. TListItem<DirectMusicPartRef>* pPartRef = pPattern->m_PartRefList.GetHead();
  295. int nParts = pPattern->m_PartRefList.GetCount();
  296. // clear all inversion groups for the fragment
  297. Fragment.ClearInversionGroups();
  298. // get the starting chords for the fragment
  299. Fragment.GetChord(pTempSeg, pSong, dwTrackGroup, mtNextChord, CurrentChord, mtRealNextChord, RealCurrentChord);
  300. Fragment.GetChord(mtNextChord, pTempSeg, pSong, dwTrackGroup, mtLaterChord, NextChord);
  301. // initializations
  302. TListItem<CompositionFragment>* pFragmentItem = new TListItem<CompositionFragment>(Fragment);
  303. if (!pFragmentItem)
  304. {
  305. hr = E_OUTOFMEMORY;
  306. break;
  307. }
  308. CompositionFragment& rFragment = pFragmentItem->GetItemValue();
  309. hr = rFragment.Init(pPattern, pStyleStruct, nParts);
  310. if (FAILED(hr))
  311. {
  312. break;
  313. }
  314. if (aFirstTimes) delete [] aFirstTimes;
  315. aFirstTimes = new FirstTimePair[nParts];
  316. if (!aFirstTimes)
  317. {
  318. hr = E_OUTOFMEMORY;
  319. break;
  320. }
  321. // If we're repeating using transposition intervals:
  322. // go through each part, attempting to fit the repeated part to the constraints.
  323. // If this process fails for any part, abort the process.
  324. // If it succeeds for every part, we can skip everything else that follows.
  325. // (ASSUMPTION 1: constraints are pattern-wide, and so must be satisfied by every part)
  326. // (ASSUMPTION 2: different parts are allowed to transpose by different intervals)
  327. HRESULT hrSkipVariations = S_OK;
  328. if (Fragment.RepeatsWithConstraints()) // if repeating using transposition intervals
  329. {
  330. for (int i = 0; pPartRef != NULL; pPartRef = pPartRef->GetNext(), i++)
  331. {
  332. aFirstTimes[i].dwPart = pPartRef->GetItemValue().m_dwLogicalPartID;
  333. aFirstTimes[i].mtTime = 0;
  334. hrSkipVariations = Fragment.GetRepeatedEvents(CompRepeat,
  335. CurrentChord,
  336. RealCurrentChord,
  337. bPlaymode,
  338. i,
  339. pPartRef->GetItemValue(),
  340. pLastFragment,
  341. aFirstTimes[i].mtTime,
  342. rFragment.EventList(i));
  343. if (FAILED(hrSkipVariations)) break;
  344. }
  345. }
  346. else
  347. {
  348. hrSkipVariations = E_FAIL;
  349. }
  350. if (FAILED(hrSkipVariations))
  351. {
  352. // If we're repeating, make sure the repeat fragment actually has variations,
  353. // and is not itself repeating an earlier fragment.
  354. // (we don't need to get the pattern again; that will be the same for all repeats)
  355. CompositionFragment CompLast = CompRepeat;
  356. while (repeatFragment.UsesRepeat())
  357. {
  358. DWORD dwRepeatID = repeatFragment.GetRepeatID();
  359. ZeroMemory( &CompRepeat, sizeof(CompRepeat));
  360. TListItem<CompositionFragment>* pScan = listFragments.GetHead();
  361. for (; pScan; pScan = pScan->GetNext())
  362. {
  363. if (pScan->GetItemValue().GetID() == dwRepeatID)
  364. {
  365. CompRepeat = pScan->GetItemValue();
  366. repeatFragment = CompRepeat;
  367. if (!CompLast.m_abVariations && CompRepeat.m_abVariations)
  368. {
  369. ZeroMemory( &CompLast, sizeof(CompLast));
  370. CompLast = CompRepeat;
  371. }
  372. }
  373. }
  374. }
  375. // Get variations for the Fragment
  376. Fragment.GetVariations(rFragment, CompRepeat, CompLast, CurrentChord, NextChord, mtNextChord, pLastFragment);
  377. bool fNeedChord = false;
  378. // for each part in the pattern:
  379. for (int i = 0; pPartRef != NULL; pPartRef = pPartRef->GetNext(), i++)
  380. {
  381. // Clean up anything that might have happened with repeats
  382. rFragment.CleanupEvents(i);
  383. if (fNeedChord)
  384. {
  385. Fragment.GetChord(pTempSeg, pSong, dwTrackGroup, mtNextChord, CurrentChord, mtRealNextChord, RealCurrentChord);
  386. Fragment.GetChord(mtNextChord, pTempSeg, pSong, dwTrackGroup, mtLaterChord, NextChord);
  387. fNeedChord = false;
  388. }
  389. DirectMusicPart* pPart = pPartRef->GetItemValue().m_pDMPart;
  390. DirectMusicTimeSig& TimeSig = rFragment.GetTimeSig(pPart);
  391. aFirstTimes[i].dwPart = pPartRef->GetItemValue().m_dwLogicalPartID;
  392. aFirstTimes[i].mtTime = 0;
  393. bool fFoundFirst = false;
  394. // for each note in the variation:
  395. CDirectMusicEventItem* pEvent = pPart->EventList.GetHead();
  396. for (; pEvent; pEvent = pEvent->GetNext())
  397. {
  398. if ( pEvent->m_dwVariation & (1 << rFragment.m_abVariations[i]) )
  399. {
  400. TListItem<EventWrapper>* pEventItem = NULL;
  401. // get the time (offset from the start of the track)
  402. MUSIC_TIME mtNow = Fragment.GetTime() +
  403. TimeSig.GridToClocks(pEvent->m_nGridStart) + pEvent->m_nTimeOffset;
  404. // Make sure this doesn't overlap with the next fragment.
  405. MUSIC_TIME mtDuration = 0;
  406. switch (pEvent->m_dwEventTag)
  407. {
  408. case DMUS_EVENT_NOTE:
  409. mtDuration = ((CDMStyleNote*)pEvent)->m_mtDuration;
  410. break;
  411. case DMUS_EVENT_CURVE:
  412. mtDuration = ((CDMStyleCurve*)pEvent)->m_mtDuration;
  413. break;
  414. }
  415. bool fAddToOverlap = false;
  416. if ( !mtNewFragment || mtNow + mtDuration <= mtNewFragment )
  417. {
  418. if (pEvent->m_dwEventTag == DMUS_EVENT_ANTICIPATION)
  419. {
  420. fAddToOverlap = true;
  421. }
  422. else
  423. {
  424. // use proper chord for non-anticipated notes
  425. if (mtRealNextChord != mtNextChord && mtNow >= mtRealNextChord)
  426. {
  427. mtRealNextChord = mtNextChord;
  428. RealCurrentChord = CurrentChord;
  429. }
  430. // get a new chord if necessary
  431. if (mtNextChord && mtNow >= mtNextChord)
  432. {
  433. Fragment.GetChord(mtNow, pTempSeg, pSong, dwTrackGroup, mtNextChord, CurrentChord);
  434. mtRealNextChord = mtNextChord;
  435. RealCurrentChord = CurrentChord;
  436. fNeedChord = true;
  437. }
  438. // Convert the event to a wrapped event
  439. hr = Fragment.GetEvent(pEvent, CurrentChord, RealCurrentChord, mtNow, pPartRef->GetItemValue(), pEventItem);
  440. // Add the new event to a list of wrapped events.
  441. if (hr == S_OK)
  442. {
  443. rFragment.AddEvent(i, pEventItem);
  444. }
  445. if (!fFoundFirst || mtNow < aFirstTimes[i].mtTime)
  446. {
  447. fFoundFirst = true;
  448. aFirstTimes[i].mtTime = mtNow;
  449. }
  450. }
  451. }
  452. // ignore anticipations that start after the next fragment
  453. else if (pEvent->m_dwEventTag != DMUS_EVENT_ANTICIPATION)
  454. {
  455. fAddToOverlap = true;
  456. }
  457. if (fAddToOverlap)
  458. {
  459. TListItem<EventOverlap>* pOverlap = new TListItem<EventOverlap>;
  460. if (pOverlap)
  461. {
  462. EventOverlap& rOverlap = pOverlap->GetItemValue();
  463. rOverlap.m_PartRef = pPartRef->GetItemValue();
  464. rOverlap.m_pEvent = pEvent;
  465. rOverlap.m_mtTime = mtNow;
  466. rOverlap.m_mtDuration = mtDuration;
  467. rOverlap.m_Chord = CurrentChord;
  468. rOverlap.m_RealChord = RealCurrentChord;
  469. rFragment.AddOverlap(pOverlap);
  470. }
  471. }
  472. }
  473. }
  474. if (!fFoundFirst) aFirstTimes[i].mtTime = mtNewFragment;
  475. // Sort the sequence items in reverse order, so that the last element is easy to find
  476. rFragment.SortEvents(i);
  477. }
  478. // Clear this so the pointers it may reference aren't deleted twice.
  479. ZeroMemory( &CompLast, sizeof(CompLast));
  480. }
  481. listFragments.AddHead(pFragmentItem);
  482. // Go through the list of overlaps for the last fragment, adding any events that don't
  483. // actually overlap (and processing anticipations)
  484. // alg for processing anticipations:
  485. // if the overlap list contains an anticipation for a part:
  486. // find the first event in that part's fragment list
  487. // make the start time of that event be the start time of the anticipation
  488. // add to the duration of the event the difference between the event's start time
  489. // and the anticipation's start time
  490. if (pLastFragment)
  491. {
  492. TListItem<EventWrapper>* pEventItem = NULL;
  493. CompositionFragment& rLastFragment = pLastFragment->GetItemValue();
  494. TListItem<EventOverlap>* pTupleItem;
  495. pTupleItem = rLastFragment.GetOverlapHead();
  496. for (; pTupleItem; pTupleItem = pTupleItem->GetNext() )
  497. {
  498. EventOverlap& rTuple = pTupleItem->GetItemValue();
  499. for (int i = 0; i < nParts; i++)
  500. {
  501. if (rTuple.m_PartRef.m_dwLogicalPartID == aFirstTimes[i].dwPart) break;
  502. }
  503. if (i >= nParts ||
  504. !aFirstTimes[i].mtTime ||
  505. rTuple.m_mtTime < aFirstTimes[i].mtTime)
  506. {
  507. if (rTuple.m_pEvent->m_dwEventTag == DMUS_EVENT_ANTICIPATION)
  508. {
  509. if (i < nParts && aFirstTimes[i].mtTime)
  510. {
  511. TListItem<EventWrapper>* pFirstNote = NULL;
  512. TListItem<EventWrapper>* pScan = rFragment.GetEventHead(i);
  513. // since the list is sorted in reverse order, the first note in
  514. // the fragment will be the last one in the list.
  515. for (; pScan; pScan = pScan->GetNext())
  516. {
  517. if (pScan->GetItemValue().m_pEvent->m_dwEventTag == DMUS_EVENT_NOTE)
  518. {
  519. pFirstNote = pScan;
  520. }
  521. }
  522. if (pFirstNote)
  523. {
  524. EventWrapper& rFirstNote = pFirstNote->GetItemValue();
  525. CDMStyleNote* pNoteEvent = (CDMStyleNote*)rFirstNote.m_pEvent;
  526. pNoteEvent->m_mtDuration += (rFirstNote.m_mtTime - rTuple.m_mtTime);
  527. rFirstNote.m_mtTime = rTuple.m_mtTime;
  528. }
  529. }
  530. }
  531. else
  532. {
  533. hr = rLastFragment.GetEvent(rTuple.m_pEvent, rTuple.m_Chord, rTuple.m_RealChord, rTuple.m_mtTime, rTuple.m_PartRef, pEventItem);
  534. if (i < nParts &&
  535. aFirstTimes[i].mtTime &&
  536. rTuple.m_mtTime + rTuple.m_mtDuration >= aFirstTimes[i].mtTime)
  537. {
  538. int nDiff = rTuple.m_mtTime + rTuple.m_mtDuration - aFirstTimes[i].mtTime;
  539. if (pEventItem && pEventItem->GetItemValue().m_pEvent)
  540. {
  541. switch (pEventItem->GetItemValue().m_pEvent->m_dwEventTag)
  542. {
  543. case DMUS_EVENT_NOTE:
  544. ((CDMStyleNote*)pEventItem->GetItemValue().m_pEvent)->m_mtDuration -= nDiff;
  545. break;
  546. case DMUS_EVENT_CURVE:
  547. ((CDMStyleCurve*)pEventItem->GetItemValue().m_pEvent)->m_mtDuration -= nDiff;
  548. break;
  549. }
  550. }
  551. }
  552. rLastFragment.InsertEvent(i, pEventItem);
  553. }
  554. }
  555. }
  556. }
  557. // NOTE: Need to apply transformations (invert, reverse...) here.
  558. // I should also move the individual sorts out of the overlapped notes code,
  559. // and put it directly preceding the transformations.
  560. } while (mtNext != 0);
  561. // Clear this so the pointers it may reference aren't deleted twice.
  562. ZeroMemory( &CompRepeat, sizeof(CompRepeat));
  563. // Once pattern tracks are introduced, I need to change this to create a pattern track.
  564. // I should allow an option to create one or the other (?).
  565. if (SUCCEEDED(hr))
  566. {
  567. hr = CreatePatternTrack(listFragments,
  568. pStyleStruct->m_TimeSignature,
  569. pStyleStruct->m_dblTempo,
  570. mtLength,
  571. bPlaymode,
  572. pNewTrack);
  573. }
  574. if (aFirstTimes) delete [] aFirstTimes;
  575. pDMStyle->Release();
  576. return hr;
  577. }
  578. TListItem<DMUS_IO_SEQ_ITEM>* ConvertToSequenceEvent(TListItem<EventWrapper>* pEventItem)
  579. {
  580. TListItem<DMUS_IO_SEQ_ITEM>* pResult = new TListItem<DMUS_IO_SEQ_ITEM>;
  581. if (pResult)
  582. {
  583. DMUS_IO_SEQ_ITEM& rSeq = pResult->GetItemValue();
  584. EventWrapper& rEvent = pEventItem->GetItemValue();
  585. rSeq.bStatus = 0x90; // MIDI note on (with channel nibble stripped out)
  586. rSeq.mtTime = rEvent.m_mtTime;
  587. rSeq.bByte1 = rEvent.m_bMIDI;
  588. rSeq.dwPChannel = rEvent.m_dwPChannel;
  589. rSeq.nOffset = rEvent.m_pEvent->m_nTimeOffset;
  590. if (rEvent.m_pEvent)
  591. {
  592. switch (rEvent.m_pEvent->m_dwEventTag)
  593. {
  594. case DMUS_EVENT_NOTE:
  595. rSeq.mtDuration = ((CDMStyleNote*)rEvent.m_pEvent)->m_mtDuration;
  596. rSeq.bByte2 = ((CDMStyleNote*)rEvent.m_pEvent)->m_bVelocity;
  597. break;
  598. case DMUS_EVENT_CURVE:
  599. rSeq.mtDuration = ((CDMStyleCurve*)rEvent.m_pEvent)->m_mtDuration;
  600. rSeq.bByte2 = 0; // Actually, curves shouldn't end up as note events...
  601. break;
  602. }
  603. }
  604. }
  605. return pResult;
  606. }
  607. HRESULT CDMStyle::CreateSequenceTrack(TList<CompositionFragment>& rlistFragments,
  608. IDirectMusicTrack*& pSequenceTrack)
  609. {
  610. HRESULT hr = S_OK;
  611. TList<DMUS_IO_SEQ_ITEM> SeqList;
  612. // fold all the individual event lists into one list
  613. TListItem<CompositionFragment>* pFragmentItem = rlistFragments.GetHead();
  614. for (; pFragmentItem; pFragmentItem = pFragmentItem->GetNext())
  615. {
  616. CompositionFragment& rFragment = pFragmentItem->GetItemValue();
  617. int nParts = rFragment.m_pPattern->m_PartRefList.GetCount();
  618. for (int i = 0; i < nParts; i++)
  619. {
  620. while (!rFragment.IsEmptyEvents(i))
  621. {
  622. TListItem<EventWrapper>* pHead = rFragment.RemoveEventHead(i);
  623. SeqList.AddHead(ConvertToSequenceEvent(pHead));
  624. }
  625. }
  626. }
  627. // Sort the sequence items
  628. SeqList.MergeSort(Less);
  629. // Now, persist the sequence events into the Sequence track
  630. IPersistStream* pIPSTrack = NULL;
  631. if( SUCCEEDED( pSequenceTrack->QueryInterface( IID_IPersistStream, (void**)&pIPSTrack )))
  632. {
  633. // Create a stream in which to place the events so we can
  634. // give it to the SeqTrack.Load.
  635. IStream* pEventStream;
  636. if( S_OK == CreateStreamOnHGlobal( NULL, TRUE, &pEventStream ) )
  637. {
  638. // Save the events into the stream
  639. TListItem<DMUS_IO_SEQ_ITEM>* pSeqItem = NULL;
  640. ULONG cb, cbWritten;
  641. // Save the chunk id
  642. DWORD dwTemp = DMUS_FOURCC_SEQ_TRACK;
  643. pEventStream->Write( &dwTemp, sizeof(DWORD), NULL );
  644. // Save the overall size. Count the number of events to determine.
  645. DWORD dwSize = 0;
  646. for( pSeqItem = SeqList.GetHead(); pSeqItem; pSeqItem = pSeqItem->GetNext() )
  647. {
  648. dwSize++;
  649. }
  650. dwSize *= sizeof(DMUS_IO_SEQ_ITEM);
  651. // add 12 --- 8 for the subchunk header and overall size,
  652. // and 4 for the DMUS_IO_SEQ_ITEM size DWORD in the subchunk
  653. dwSize += 12;
  654. pEventStream->Write( &dwSize, sizeof(DWORD), NULL );
  655. // Save the subchunk id
  656. dwTemp = DMUS_FOURCC_SEQ_LIST;
  657. pEventStream->Write( &dwTemp, sizeof(DWORD), NULL );
  658. // Subtract the previously added 8 (for subchunk header and overall size)
  659. dwSize -= 8;
  660. // Save the size of the subchunk (including the DMUS_IO_SEQ_ITEM size DWORD)
  661. pEventStream->Write( &dwSize, sizeof(DWORD), NULL );
  662. // Save the structure size.
  663. dwTemp = sizeof(DMUS_IO_SEQ_ITEM);
  664. pEventStream->Write( &dwTemp, sizeof(DWORD), NULL );
  665. // Save the events.
  666. cb = sizeof(DMUS_IO_SEQ_ITEM);
  667. for( pSeqItem = SeqList.GetHead(); pSeqItem; pSeqItem = pSeqItem->GetNext() )
  668. {
  669. DMUS_IO_SEQ_ITEM& rSeqItem = pSeqItem->GetItemValue();
  670. pEventStream->Write( &rSeqItem, cb, &cbWritten );
  671. if( cb != cbWritten ) // error!
  672. {
  673. pEventStream->Release();
  674. pEventStream = NULL;
  675. hr = DMUS_E_CANNOTREAD;
  676. break;
  677. }
  678. }
  679. if( pEventStream ) // may be NULL
  680. {
  681. StreamSeek( pEventStream, 0, STREAM_SEEK_SET );
  682. pIPSTrack->Load( pEventStream );
  683. pEventStream->Release();
  684. }
  685. }
  686. pIPSTrack->Release();
  687. }
  688. return hr;
  689. }
  690. CDirectMusicEventItem* ConvertToPatternEvent(TListItem<EventWrapper>* pEventWrapper,
  691. DWORD dwID,
  692. BYTE bPlaymode,
  693. DirectMusicTimeSig& TimeSig)
  694. {
  695. if (!pEventWrapper) return NULL;
  696. BYTE bEventPlaymode = pEventWrapper->GetItemValue().m_bPlaymode;
  697. if (bPlaymode == bEventPlaymode)
  698. {
  699. bEventPlaymode = DMUS_PLAYMODE_NONE;
  700. }
  701. CDirectMusicEventItem* pWrappedEvent = pEventWrapper->GetItemValue().m_pEvent;
  702. if (!pWrappedEvent) return NULL;
  703. MUSIC_TIME mtClocksPerGrid = TimeSig.ClocksPerGrid();
  704. short nGrid = 0;
  705. short nOffset = 0;
  706. if (mtClocksPerGrid)
  707. {
  708. nGrid = (short) (pEventWrapper->GetItemValue().m_mtTime / mtClocksPerGrid);
  709. nOffset = (short) (pWrappedEvent->m_nTimeOffset + pEventWrapper->GetItemValue().m_mtTime % mtClocksPerGrid);
  710. }
  711. DWORD dwVariations = 0xffffffff;
  712. BYTE bFlags = 0;
  713. if (pEventWrapper->GetItemValue().m_pEvent &&
  714. pEventWrapper->GetItemValue().m_pEvent->m_dwEventTag == DMUS_EVENT_NOTE)
  715. {
  716. bFlags = ((CDMStyleNote*)pEventWrapper->GetItemValue().m_pEvent)->m_bFlags;
  717. }
  718. return pWrappedEvent->ReviseEvent(nGrid, nOffset, &dwVariations, &dwID, &pEventWrapper->GetItemValue().m_wMusic, &bEventPlaymode, &bFlags);
  719. }
  720. HRESULT CDMStyle::CreatePatternTrack(TList<CompositionFragment>& rlistFragments,
  721. DirectMusicTimeSig& rTimeSig,
  722. double dblTempo,
  723. MUSIC_TIME mtLength,
  724. BYTE bPlaymode,
  725. IDirectMusicTrack*& pPatternTrack)
  726. {
  727. HRESULT hr = S_OK;
  728. CDirectMusicPattern* pPattern = new CDirectMusicPattern(&rTimeSig);
  729. if (pPattern == NULL) return E_OUTOFMEMORY;
  730. pPattern->m_strName = "<Composed Pattern>";
  731. // fold all the individual event lists into corresponding parts in the pattern
  732. TListItem<CompositionFragment>* pFragmentItem = rlistFragments.GetHead();
  733. for (; pFragmentItem; pFragmentItem = pFragmentItem->GetNext())
  734. {
  735. CompositionFragment& rFragment = pFragmentItem->GetItemValue();
  736. TListItem<DirectMusicPartRef>* pPartRef = rFragment.m_pPattern->m_PartRefList.GetHead();
  737. int nParts = rFragment.m_pPattern->m_PartRefList.GetCount();
  738. for (int i = 0; i < nParts && pPartRef; i++, pPartRef = pPartRef->GetNext() )
  739. {
  740. DirectMusicPartRef& rPartRef = pPartRef->GetItemValue();
  741. TListItem<DirectMusicPartRef>* pNewPartRef = pPattern->CreatePart(rPartRef, bPlaymode);
  742. if (!pNewPartRef)
  743. {
  744. hr = E_OUTOFMEMORY;
  745. break;
  746. }
  747. DirectMusicPart* pPart = pNewPartRef->GetItemValue().m_pDMPart;
  748. if (!pPart)
  749. {
  750. hr = E_FAIL;
  751. break;
  752. }
  753. while (!rFragment.IsEmptyEvents(i))
  754. {
  755. TListItem<EventWrapper>* pHead = rFragment.RemoveEventHead(i);
  756. CDirectMusicEventItem* pNew = ConvertToPatternEvent(pHead, rFragment.GetID(), bPlaymode, rTimeSig);
  757. if (pNew)
  758. {
  759. pPart->EventList.AddHead(pNew);
  760. }
  761. delete pHead;
  762. }
  763. }
  764. if (FAILED(hr)) break;
  765. }
  766. WORD wNumMeasures = 0;
  767. MUSIC_TIME mtClocksPerMeasure = rTimeSig.ClocksPerMeasure();
  768. if (mtClocksPerMeasure)
  769. {
  770. wNumMeasures = (WORD)(mtLength / mtClocksPerMeasure);
  771. if (mtLength % mtClocksPerMeasure)
  772. {
  773. wNumMeasures++;
  774. }
  775. }
  776. pPattern->m_wNumMeasures = wNumMeasures;
  777. pPattern->m_pRhythmMap = new DWORD[wNumMeasures];
  778. if (pPattern->m_pRhythmMap)
  779. {
  780. for (int i = 0; i < wNumMeasures; i++)
  781. {
  782. pPattern->m_pRhythmMap[i] = 0;
  783. }
  784. }
  785. else
  786. {
  787. hr = E_OUTOFMEMORY;
  788. }
  789. if (SUCCEEDED(hr))
  790. {
  791. TListItem<DirectMusicPartRef>* pPartRef = pPattern->m_PartRefList.GetHead();
  792. int nParts = pPattern->m_PartRefList.GetCount();
  793. // Sort the event lists for each part, and set the number of measures.
  794. for (int i = 0; i < nParts && pPartRef; i++, pPartRef = pPartRef->GetNext() )
  795. {
  796. DirectMusicPart* pPart = pPartRef->GetItemValue().m_pDMPart;
  797. if (pPart)
  798. {
  799. pPart->m_wNumMeasures = wNumMeasures;
  800. pPart->EventList.MergeSort(rTimeSig);
  801. // remove notes so close that they might as well be overlapping
  802. CDirectMusicEventItem* pThisEvent = pPart->EventList.GetHead();
  803. CDirectMusicEventItem* pLastEvent = NULL;
  804. for (; pThisEvent; pThisEvent = pThisEvent->GetNext())
  805. {
  806. if (pThisEvent->m_dwEventTag == DMUS_EVENT_NOTE)
  807. {
  808. CDMStyleNote* pThisNote = (CDMStyleNote*)pThisEvent;
  809. CDirectMusicEventItem* pNextEvent = pThisEvent->GetNext();
  810. for (; pNextEvent; pNextEvent = pNextEvent->GetNext())
  811. {
  812. if (pNextEvent->m_dwEventTag == DMUS_EVENT_NOTE) break;
  813. }
  814. if (pNextEvent)
  815. {
  816. CDMStyleNote* pNextNote = (CDMStyleNote*)pNextEvent;
  817. MUSIC_TIME mtThis = rTimeSig.GridToClocks(pThisNote->m_nGridStart) + pThisNote->m_nTimeOffset;
  818. MUSIC_TIME mtNext = rTimeSig.GridToClocks(pNextNote->m_nGridStart) + pNextNote->m_nTimeOffset;
  819. if ( (pNextNote->m_dwFragmentID != pThisNote->m_dwFragmentID) &&
  820. ((mtThis < mtNext && mtThis + OVERLAP_DELTA > mtNext) ||
  821. (mtThis > mtNext && mtThis + OVERLAP_DELTA < mtNext)) ) // could happen with negative offsets...
  822. {
  823. if (pLastEvent)
  824. {
  825. pLastEvent->SetNext(pThisEvent->GetNext());
  826. }
  827. else // the note I want to remove is the first event
  828. {
  829. pPart->EventList.RemoveHead();
  830. }
  831. pThisEvent->SetNext(NULL);
  832. delete pThisEvent;
  833. pThisEvent = pLastEvent;
  834. }
  835. }
  836. }
  837. pLastEvent = pThisEvent;
  838. }
  839. }
  840. }
  841. // Now, save the newly created pattern to a pattern track
  842. IPersistStream* pIPSTrack = NULL;
  843. IAARIFFStream* pIRiffStream;
  844. MMCKINFO ckMain;
  845. if( SUCCEEDED( pPatternTrack->QueryInterface( IID_IPersistStream, (void**)&pIPSTrack )))
  846. {
  847. // Create a stream in which to place the events so we can
  848. // give it to the PatternTrack.Load.
  849. IStream* pEventStream;
  850. if( S_OK == CreateStreamOnHGlobal( NULL, TRUE, &pEventStream ) )
  851. {
  852. if( SUCCEEDED( AllocRIFFStream( pEventStream, &pIRiffStream ) ) )
  853. {
  854. ckMain.fccType = DMUS_FOURCC_PATTERN_FORM;
  855. if( pIRiffStream->CreateChunk( &ckMain, MMIO_CREATERIFF ) == 0 )
  856. {
  857. MMCKINFO ckHeader;
  858. ckHeader.ckid = DMUS_FOURCC_STYLE_CHUNK;
  859. if( pIRiffStream->CreateChunk( &ckHeader, 0 ) != 0 )
  860. {
  861. hr = E_FAIL;
  862. }
  863. if (SUCCEEDED(hr))
  864. {
  865. // Prepare DMUS_IO_STYLE
  866. DMUS_IO_STYLE oDMStyle;
  867. DWORD dwBytesWritten = 0;
  868. memset( &oDMStyle, 0, sizeof(DMUS_IO_STYLE) );
  869. oDMStyle.timeSig.bBeatsPerMeasure = rTimeSig.m_bBeatsPerMeasure;
  870. oDMStyle.timeSig.bBeat = rTimeSig.m_bBeat;
  871. oDMStyle.timeSig.wGridsPerBeat = rTimeSig.m_wGridsPerBeat;
  872. oDMStyle.dblTempo = dblTempo;
  873. // Write chunk data
  874. hr = pEventStream->Write( &oDMStyle, sizeof(DMUS_IO_STYLE), &dwBytesWritten);
  875. if( FAILED( hr ) || dwBytesWritten != sizeof(DMUS_IO_STYLE) )
  876. {
  877. hr = E_FAIL;
  878. }
  879. if( SUCCEEDED(hr) && pIRiffStream->Ascend( &ckHeader, 0 ) != 0 )
  880. {
  881. hr = E_FAIL;
  882. }
  883. }
  884. if ( SUCCEEDED(hr) )
  885. {
  886. hr = pPattern->Save( pEventStream );
  887. pPartRef = pPattern->m_PartRefList.GetHead();
  888. for (; pPartRef; pPartRef = pPartRef->GetNext())
  889. {
  890. if (pPartRef->GetItemValue().m_pDMPart)
  891. {
  892. delete pPartRef->GetItemValue().m_pDMPart;
  893. pPartRef->GetItemValue().m_pDMPart = NULL;
  894. }
  895. }
  896. pPattern->CleanUp();
  897. delete pPattern;
  898. if ( SUCCEEDED( hr ) && pIRiffStream->Ascend( &ckMain, 0 ) != 0 )
  899. {
  900. hr = E_FAIL;
  901. }
  902. }
  903. }
  904. pIRiffStream->Release();
  905. }
  906. if( SUCCEEDED(hr) )
  907. {
  908. StreamSeek( pEventStream, 0, STREAM_SEEK_SET );
  909. pIPSTrack->Load( pEventStream );
  910. }
  911. pEventStream->Release();
  912. }
  913. pIPSTrack->Release();
  914. }
  915. }
  916. if (hr == S_OK && !rlistFragments.GetHead()) hr = S_FALSE;
  917. return hr;
  918. }