Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5051 lines
178 KiB

  1. //
  2. // DMCompos.cpp : Implementation of CDMCompos
  3. //
  4. // Copyright (c) 1997-2001 Microsoft Corporation
  5. //
  6. // @doc EXTERNAL
  7. //
  8. #include <time.h> // to seed random number generator
  9. #include "DMCompos.h"
  10. #include "debug.h"
  11. #include "DMPers.h"
  12. #include "DMTempl.h"
  13. #include "dmusici.h"
  14. #include "dmusicf.h"
  15. #include "..\dmstyle\iostru.h"
  16. #include "..\dmime\dmgraph.h"
  17. #include "..\shared\Validate.h"
  18. #include "debug.h"
  19. // default scale is C Major
  20. const DWORD DEFAULT_SCALE_PATTERN = 0xab5ab5;
  21. // default chord is major 7
  22. const DWORD DEFAULT_CHORD_PATTERN = 0x891;
  23. BOOL Less(TemplateCommand& TC1, TemplateCommand& TC2)
  24. {
  25. return TC1.m_nMeasure < TC2.m_nMeasure;
  26. }
  27. BOOL Less(PlayChord& PC1, PlayChord& PC2)
  28. {
  29. return PC1.m_nMeasure < PC2.m_nMeasure ||
  30. (PC1.m_nMeasure == PC2.m_nMeasure && PC1.m_nBeat < PC2.m_nBeat);
  31. }
  32. static void Free(TListItem<DMExtendedChord*>*& pSubChord)
  33. {
  34. TListItem<DMExtendedChord*> *pScan = pSubChord;
  35. for (; pScan; pScan = pScan->GetNext())
  36. {
  37. pScan->GetItemValue()->Release();
  38. pScan->GetItemValue() = NULL;
  39. }
  40. TListItem<DMExtendedChord*>::Delete(pSubChord);
  41. pSubChord = NULL;
  42. }
  43. TListItem<DMExtendedChord*>* Copy(TListItem<DMExtendedChord*>* pChord)
  44. {
  45. if (!pChord) return NULL;
  46. TListItem<DMExtendedChord*>* pNext = new TListItem<DMExtendedChord*>;
  47. if (pNext)
  48. {
  49. DMExtendedChord* pNew = new DMExtendedChord;
  50. if (pNew)
  51. {
  52. DMExtendedChord*& rChord = pChord->GetItemValue();
  53. DMExtendedChord*& rNext = pNext->GetItemValue();
  54. rNext = pNew;
  55. rNext->m_dwChordPattern = rChord->m_dwChordPattern;
  56. rNext->m_dwScalePattern = rChord->m_dwScalePattern;
  57. rNext->m_dwInvertPattern = rChord->m_dwInvertPattern;
  58. rNext->m_bRoot = rChord->m_bRoot;
  59. rNext->m_bScaleRoot = rChord->m_bScaleRoot;
  60. rNext->m_wCFlags = rChord->m_wCFlags;
  61. rNext->m_dwParts = rChord->m_dwParts;
  62. rNext->m_nRefCount = 1;
  63. pNext->SetNext(Copy(pChord->GetNext()));
  64. }
  65. else
  66. {
  67. delete pNext;
  68. pNext = NULL;
  69. }
  70. }
  71. return pNext;
  72. }
  73. DMChordData::DMChordData(DMChordData& rChordData)
  74. {
  75. m_strName = rChordData.m_strName;
  76. m_pSubChords = Copy(rChordData.m_pSubChords);
  77. }
  78. DMChordData::DMChordData(DMUS_CHORD_PARAM& DMC)
  79. {
  80. m_strName = DMC.wszName;
  81. m_pSubChords = NULL;
  82. for (BYTE n = 0; n < DMC.bSubChordCount; n++)
  83. {
  84. TListItem<DMExtendedChord*>* pSub = new TListItem<DMExtendedChord*>;
  85. if( pSub )
  86. {
  87. DMExtendedChord* pNew = new DMExtendedChord;
  88. if (pNew)
  89. {
  90. memset( pNew, 0, sizeof( *pNew) );
  91. DMExtendedChord*& rSubChord = pSub->GetItemValue();
  92. rSubChord = pNew;
  93. rSubChord->AddRef();
  94. rSubChord->m_dwChordPattern = DMC.SubChordList[n].dwChordPattern;
  95. rSubChord->m_dwScalePattern = DMC.SubChordList[n].dwScalePattern;
  96. rSubChord->m_dwInvertPattern = DMC.SubChordList[n].dwInversionPoints;
  97. rSubChord->m_dwParts = DMC.SubChordList[n].dwLevels;
  98. rSubChord->m_bRoot = DMC.SubChordList[n].bChordRoot;
  99. rSubChord->m_bScaleRoot = DMC.SubChordList[n].bScaleRoot;
  100. m_pSubChords = m_pSubChords->Cat(pSub);
  101. }
  102. else
  103. {
  104. delete pSub;
  105. // no need continuing in the loop if we ran out of memory
  106. break;
  107. }
  108. }
  109. }
  110. }
  111. // At the moment, this assumes that the pattern of the chord is the pattern of the
  112. // first subchord in the chord's subchord list.
  113. DWORD DMChordData::GetChordPattern()
  114. {
  115. if (m_pSubChords)
  116. {
  117. return m_pSubChords->GetItemValue()->m_dwChordPattern;
  118. }
  119. else return 0;
  120. }
  121. // At the moment, this assumes that the root of the chord is the root of the
  122. // first subchord in the chord's subchord list.
  123. char DMChordData::GetRoot()
  124. {
  125. if (m_pSubChords)
  126. {
  127. return m_pSubChords->GetItemValue()->m_bRoot;
  128. }
  129. else return 0;
  130. }
  131. // At the moment, this assumes that the root of the chord is the root of the
  132. // first subchord in the chord's subchord list.
  133. void DMChordData::SetRoot(char chNewRoot)
  134. {
  135. if (m_pSubChords)
  136. {
  137. m_pSubChords->GetItemValue()->m_bRoot = chNewRoot;
  138. }
  139. }
  140. void DMChordData::Release()
  141. {
  142. Free(m_pSubChords);
  143. }
  144. // Two chords are equal if they have the same number of subchords and each
  145. // corresponding subchord is equal
  146. BOOL DMChordData::Equals(DMChordData& rhsChord)
  147. {
  148. TListItem<DMExtendedChord*> *pLeft = m_pSubChords;
  149. TListItem<DMExtendedChord*> *pRight = rhsChord.m_pSubChords;
  150. for(; pLeft; pLeft = pLeft->GetNext(), pRight = pRight->GetNext())
  151. {
  152. if (pRight == NULL || !pLeft->GetItemValue()->Equals(*pRight->GetItemValue()))
  153. return FALSE;
  154. }
  155. return pRight == NULL;
  156. }
  157. BOOL DMExtendedChord::Equals(DMExtendedChord& rhsChord)
  158. {
  159. char a = m_bRoot;
  160. char b = rhsChord.m_bRoot;
  161. while (a > 11) a -= 12;
  162. while (b > 11) b -= 12;
  163. return ((m_dwChordPattern == rhsChord.m_dwChordPattern) && (a == b));
  164. }
  165. BOOL DMChordLink::Walk(SearchInfo *pSearch)
  166. {
  167. BOOL fResult = FALSE;
  168. if (m_pChord)
  169. {
  170. pSearch->m_nMinBeats = (short)( pSearch->m_nMinBeats + m_wMinBeats );
  171. pSearch->m_nMaxBeats = (short)( pSearch->m_nMaxBeats + m_wMaxBeats );
  172. pSearch->m_nChords++;
  173. fResult = m_pChord->GetItemValue().Walk(pSearch);
  174. pSearch->m_nChords--;
  175. pSearch->m_nMinBeats = (short)( pSearch->m_nMinBeats - m_wMinBeats );
  176. pSearch->m_nMaxBeats = (short)( pSearch->m_nMaxBeats - m_wMaxBeats );
  177. }
  178. return(fResult);
  179. }
  180. TListItem<DMChordLink> *DMChordEntry::ChooseNextChord()
  181. {
  182. int total = 0;
  183. int choice;
  184. TListItem<DMChordLink> *pNext = m_Links.GetHead();
  185. for (; pNext; pNext = pNext->GetNext())
  186. {
  187. if (!(pNext->GetItemValue().m_dwFlags & NC_NOPATH))
  188. {
  189. if (pNext->GetItemValue().m_pChord) total += pNext->GetItemValue().m_wWeight;
  190. }
  191. }
  192. if (!total) return(NULL);
  193. choice = rand() % total;
  194. pNext = m_Links.GetHead();
  195. for (; pNext; pNext = pNext->GetNext())
  196. {
  197. if (!(pNext->GetItemValue().m_dwFlags & NC_NOPATH))
  198. {
  199. if (pNext->GetItemValue().m_pChord) choice -= pNext->GetItemValue().m_wWeight;
  200. if (choice < 0) return(pNext);
  201. }
  202. }
  203. return(NULL);
  204. }
  205. BOOL DMChordEntry::Walk(SearchInfo *pSearch)
  206. {
  207. TListItem<DMChordLink> *pNext = m_Links.GetHead();
  208. if (pSearch->m_nChords > pSearch->m_nMaxChords)
  209. {
  210. pSearch->m_Fail.m_nTooManychords++;
  211. return (FALSE);
  212. }
  213. for (; pNext; pNext = pNext->GetNext())
  214. {
  215. pNext->GetItemValue().m_dwFlags &= ~(NC_PATH | NC_NOPATH);
  216. }
  217. if ((m_dwFlags & CE_END) && (m_ChordData.Equals(pSearch->m_End)))
  218. {
  219. if (pSearch->m_nChords >= pSearch->m_nMinChords)
  220. {
  221. if (pSearch->m_nBeats <= pSearch->m_nMaxBeats)
  222. {
  223. if (pSearch->m_nBeats >= pSearch->m_nMinBeats)
  224. {
  225. m_dwFlags |= CE_PATH;
  226. return(TRUE);
  227. }
  228. else pSearch->m_Fail.m_nTooManybeats++;
  229. }
  230. else pSearch->m_Fail.m_nTooFewbeats++;
  231. }
  232. else
  233. {
  234. pSearch->m_Fail.m_nTooFewchords++;
  235. }
  236. }
  237. m_dwFlags &= ~CE_PATH;
  238. if (pSearch->m_pPlayChord)
  239. {
  240. pSearch->m_pPlayChord = pSearch->m_pPlayChord->GetNext();
  241. }
  242. if (pSearch->m_pPlayChord)
  243. {
  244. TListItem<PlayChord> *pPlay = pSearch->m_pPlayChord;
  245. if (pPlay->GetItemValue().m_pChord)
  246. {
  247. pNext = pPlay->GetItemValue().m_pNext;
  248. if (pNext)
  249. {
  250. if (pNext->GetItemValue().Walk(pSearch))
  251. {
  252. pNext->GetItemValue().m_dwFlags |= NC_PATH;
  253. m_dwFlags |= CE_PATH;
  254. return(TRUE);
  255. }
  256. else
  257. {
  258. pNext->GetItemValue().m_dwFlags |= NC_NOPATH;
  259. pSearch->m_pPlayChord = NULL;
  260. }
  261. }
  262. }
  263. }
  264. while( ( pNext = ChooseNextChord() ) != NULL )
  265. {
  266. if (pNext->GetItemValue().Walk(pSearch))
  267. {
  268. pNext->GetItemValue().m_dwFlags |= NC_PATH;
  269. m_dwFlags |= CE_PATH;
  270. return(TRUE);
  271. }
  272. else
  273. {
  274. pNext->GetItemValue().m_dwFlags |= NC_NOPATH;
  275. }
  276. }
  277. return (FALSE);
  278. }
  279. #define MAX_CHORD_NAME 16
  280. HRESULT PlayChord::Save( IAARIFFStream* pRIFF, DMUS_TIMESIGNATURE& rTimeSig )
  281. {
  282. IStream* pStream;
  283. MMCKINFO ck;
  284. DWORD cb;
  285. DMUS_IO_CHORD iChord;
  286. DMUS_IO_SUBCHORD iSubChord;
  287. DWORD dwSize;
  288. HRESULT hr = E_FAIL;
  289. if ( !m_pChord || !m_pChord->m_pSubChords )
  290. {
  291. Trace(1, "ERROR: Attempt to save an empty chord list.\n");
  292. return E_FAIL;
  293. }
  294. pStream = pRIFF->GetStream();
  295. ck.ckid = mmioFOURCC('c','r','d','b');
  296. if( pRIFF->CreateChunk( &ck, 0 ) == 0 )
  297. {
  298. memset( &iChord, 0, sizeof( iChord ) );
  299. if (m_pChord->m_strName)
  300. {
  301. wcsncpy( iChord.wszName, m_pChord->m_strName, MAX_CHORD_NAME );
  302. iChord.wszName[MAX_CHORD_NAME - 1] = 0;
  303. }
  304. iChord.mtTime = ClocksPerBeat(rTimeSig) * m_nBeat + ClocksPerMeasure(rTimeSig) * m_nMeasure;
  305. iChord.wMeasure = m_nMeasure;
  306. iChord.bBeat = (BYTE)m_nBeat;
  307. iChord.bFlags = 0;
  308. if (m_fSilent) iChord.bFlags |= DMUS_CHORDKEYF_SILENT;
  309. dwSize = sizeof( iChord );
  310. hr = pStream->Write( &dwSize, sizeof( dwSize ), &cb );
  311. if( SUCCEEDED(hr) &&
  312. SUCCEEDED( pStream->Write( &iChord, sizeof( iChord), &cb ) ) &&
  313. cb == sizeof( iChord) )
  314. {
  315. {
  316. DWORD dwCount = (WORD) m_pChord->m_pSubChords->GetCount();
  317. hr = pStream->Write( &dwCount, sizeof( dwCount ), &cb );
  318. if( FAILED( hr ) || cb != sizeof( dwSize ) )
  319. {
  320. pStream->Release();
  321. return E_FAIL;
  322. }
  323. dwSize = sizeof( iSubChord );
  324. hr = pStream->Write( &dwSize, sizeof( dwSize ), &cb );
  325. if( FAILED( hr ) || cb != sizeof( dwSize ) )
  326. {
  327. pStream->Release();
  328. return E_FAIL;
  329. }
  330. for (TListItem<DMExtendedChord*>* pSub = m_pChord->m_pSubChords; pSub != NULL; pSub = pSub->GetNext())
  331. {
  332. DMExtendedChord*& rSubChord = pSub->GetItemValue();
  333. memset( &iSubChord, 0, sizeof( iSubChord ) );
  334. iSubChord.dwChordPattern = rSubChord->m_dwChordPattern;
  335. iSubChord.dwScalePattern = rSubChord->m_dwScalePattern;
  336. iSubChord.dwInversionPoints = rSubChord->m_dwInvertPattern;
  337. iSubChord.dwLevels = rSubChord->m_dwParts;
  338. iSubChord.bChordRoot = rSubChord->m_bRoot;
  339. iSubChord.bScaleRoot = rSubChord->m_bScaleRoot;
  340. if( FAILED( pStream->Write( &iSubChord, sizeof( iSubChord ), &cb ) ) ||
  341. cb != sizeof( iSubChord ) )
  342. {
  343. break;
  344. }
  345. }
  346. // ascend from chord body chunk
  347. if( pSub == NULL &&
  348. pRIFF->Ascend( &ck, 0 ) != 0 )
  349. {
  350. hr = S_OK;
  351. }
  352. }
  353. }
  354. }
  355. pStream->Release();
  356. return hr;
  357. }
  358. char PlayChord::GetRoot()
  359. {
  360. if (m_pChord)
  361. {
  362. return m_pChord->GetRoot();
  363. }
  364. else return 0;
  365. }
  366. void PlayChord::SetRoot(char chNewRoot)
  367. {
  368. if (m_pChord)
  369. {
  370. m_pChord->SetRoot(chNewRoot);
  371. }
  372. }
  373. HRESULT LoadChordChunk(LPSTREAM pStream, PlayChord& rChord)
  374. {
  375. DWORD dwChordSize;
  376. DWORD dwSubChordSize;
  377. DWORD dwSubChordCount;
  378. DWORD cb;
  379. HRESULT hr;
  380. DMUS_IO_CHORD iChord;
  381. DMUS_IO_SUBCHORD iSubChord;
  382. memset(&iChord , 0, sizeof(iChord));
  383. memset(&iSubChord , 0, sizeof(iSubChord));
  384. hr = pStream->Read( &dwChordSize, sizeof( dwChordSize ), &cb );
  385. if (FAILED(hr) || cb != sizeof( dwChordSize ) )
  386. {
  387. return E_FAIL;
  388. }
  389. if( dwChordSize <= sizeof( DMUS_IO_CHORD ) )
  390. {
  391. pStream->Read( &iChord, dwChordSize, NULL );
  392. }
  393. else
  394. {
  395. pStream->Read( &iChord, sizeof( DMUS_IO_CHORD ), NULL );
  396. StreamSeek( pStream, dwChordSize - sizeof( DMUS_IO_CHORD ), STREAM_SEEK_CUR );
  397. }
  398. memset( &rChord, 0, sizeof( rChord) );
  399. rChord.m_nMeasure = iChord.wMeasure;
  400. rChord.m_nBeat = iChord.bBeat;
  401. rChord.m_fSilent = (iChord.bFlags & DMUS_CHORDKEYF_SILENT) ? true : false;
  402. rChord.m_pChord = new DMChordData;
  403. if (!rChord.m_pChord) return E_OUTOFMEMORY;
  404. rChord.m_pChord->m_strName = iChord.wszName;
  405. rChord.m_pChord->m_pSubChords = NULL;
  406. hr = pStream->Read( &dwSubChordCount, sizeof( dwSubChordCount ), &cb );
  407. if (FAILED(hr) || cb != sizeof( dwSubChordCount ) )
  408. {
  409. return E_FAIL;
  410. }
  411. hr = pStream->Read( &dwSubChordSize, sizeof( dwSubChordSize ), &cb );
  412. if (FAILED(hr) || cb != sizeof( dwSubChordSize ) )
  413. {
  414. return E_FAIL;
  415. }
  416. for (; dwSubChordCount > 0; dwSubChordCount--)
  417. {
  418. if( dwSubChordSize <= sizeof( DMUS_IO_SUBCHORD ) )
  419. {
  420. pStream->Read( &iSubChord, dwSubChordSize, NULL );
  421. }
  422. else
  423. {
  424. pStream->Read( &iSubChord, sizeof( DMUS_IO_SUBCHORD ), NULL );
  425. StreamSeek( pStream, dwSubChordSize - sizeof( DMUS_IO_SUBCHORD ), STREAM_SEEK_CUR );
  426. }
  427. TListItem<DMExtendedChord*>* pSub = new TListItem<DMExtendedChord*>;
  428. if( pSub )
  429. {
  430. DMExtendedChord* pNew = new DMExtendedChord;
  431. if (pNew)
  432. {
  433. memset( pNew, 0, sizeof( *pNew) );
  434. DMExtendedChord*& rSubChord = pSub->GetItemValue();
  435. rSubChord = pNew;
  436. rSubChord->AddRef();
  437. rSubChord->m_dwChordPattern = iSubChord.dwChordPattern;
  438. rSubChord->m_dwScalePattern = iSubChord.dwScalePattern;
  439. rSubChord->m_dwInvertPattern = iSubChord.dwInversionPoints;
  440. rSubChord->m_dwParts = iSubChord.dwLevels;
  441. rSubChord->m_bRoot = iSubChord.bChordRoot;
  442. rSubChord->m_bScaleRoot = iSubChord.bScaleRoot;
  443. rChord.m_pChord->m_pSubChords = rChord.m_pChord->m_pSubChords->Cat(pSub);
  444. }
  445. else
  446. {
  447. delete pSub;
  448. pSub = NULL;
  449. }
  450. }
  451. if (!pSub)
  452. {
  453. return E_OUTOFMEMORY;
  454. }
  455. }
  456. return S_OK;
  457. }
  458. HRESULT LoadChordList(TList<PlayChord>& ChordList, LPSTREAM pStream,
  459. BYTE &bRoot, DWORD &dwScalePattern)
  460. {
  461. long lFileSize = 0;
  462. DWORD dwChunkSize;
  463. MMCKINFO ckMain;
  464. MMCKINFO ck;
  465. MMCKINFO ckHeader;
  466. IAARIFFStream* pRIFF;
  467. FOURCC id = 0;
  468. HRESULT hr = E_FAIL;
  469. DWORD dwPos;
  470. dwPos = StreamTell( pStream );
  471. StreamSeek( pStream, dwPos, STREAM_SEEK_SET );
  472. if( SUCCEEDED( AllocRIFFStream( pStream, &pRIFF ) ) )
  473. {
  474. ckMain.fccType = DMUS_FOURCC_CHORDTRACK_LIST;
  475. if( pRIFF->Descend( &ckMain, NULL, MMIO_FINDLIST ) == 0)
  476. {
  477. lFileSize = ckMain.cksize - 4; // subtract off the list type
  478. DWORD dwScale;
  479. DWORD cb;
  480. if (pRIFF->Descend(&ckHeader, &ckMain, 0) == 0 &&
  481. ckHeader.ckid == DMUS_FOURCC_CHORDTRACKHEADER_CHUNK )
  482. {
  483. lFileSize -= 8; // chunk id + chunk size: double words
  484. lFileSize -= ckHeader.cksize;
  485. hr = pStream->Read( &dwScale, sizeof( dwScale ), &cb );
  486. if (FAILED(hr) || cb != sizeof( dwScale ) )
  487. {
  488. if (SUCCEEDED(hr)) hr = E_FAIL;
  489. pRIFF->Ascend( &ckHeader, 0 );
  490. pRIFF->Release();
  491. return hr;
  492. }
  493. hr = pRIFF->Ascend( &ckHeader, 0 );
  494. if (FAILED(hr))
  495. {
  496. return hr;
  497. }
  498. }
  499. bRoot = (BYTE) (dwScale >> 24);
  500. dwScalePattern = dwScale & 0xffffff;
  501. while (lFileSize > 0)
  502. {
  503. if (pRIFF->Descend(&ck, &ckMain, 0) == 0 &&
  504. ck.ckid == mmioFOURCC('c','r','d','b') )
  505. {
  506. dwChunkSize = ck.cksize;
  507. TListItem<PlayChord>* pChord = new TListItem<PlayChord>;
  508. if (!pChord) break;
  509. PlayChord& rChord = pChord->GetItemValue();
  510. if (FAILED(LoadChordChunk(pStream, rChord))) break;
  511. ChordList.AddTail(pChord);
  512. if (pRIFF->Ascend( &ck, 0 ) != 0) break;
  513. lFileSize -= 8; // chunk id + chunk size: double words
  514. lFileSize -= dwChunkSize;
  515. }
  516. else break;
  517. }
  518. if (lFileSize == 0 &&
  519. pRIFF->Ascend( &ck, 0 ) == 0)
  520. {
  521. hr = S_OK;
  522. }
  523. }
  524. }
  525. ChordList.MergeSort(Less);
  526. pRIFF->Release();
  527. return hr;
  528. }
  529. /////////////////////////////////////////////////////////////////////////////
  530. // CDMCompos
  531. CDMCompos::CDMCompos( )
  532. : m_cRef(1),
  533. m_dwFlags(0)
  534. {
  535. InterlockedIncrement(&g_cComponent);
  536. // Do this first since it might throw an exception
  537. //
  538. ::InitializeCriticalSection( &m_CriticalSection );
  539. m_fCSInitialized = TRUE;
  540. srand((unsigned int)time(NULL));
  541. m_pChords = NULL;
  542. }
  543. CDMCompos::~CDMCompos()
  544. {
  545. if (m_fCSInitialized)
  546. {
  547. CleanUp();
  548. ::DeleteCriticalSection( &m_CriticalSection );
  549. }
  550. InterlockedDecrement(&g_cComponent);
  551. }
  552. void CDMCompos::CleanUp()
  553. {
  554. TListItem<DMChordData*>* pScan = m_pChords;
  555. for(; pScan; pScan = pScan->GetNext())
  556. {
  557. pScan->GetItemValue()->Release();
  558. delete pScan->GetItemValue();
  559. }
  560. if (m_pChords)
  561. {
  562. TListItem<DMChordData*>::Delete(m_pChords);
  563. m_pChords = NULL;
  564. }
  565. }
  566. void CDMCompos::AddChord(DMChordData* pChord)
  567. {
  568. TListItem<DMChordData*>* pNew = new TListItem<DMChordData*>(pChord);
  569. if (pNew)
  570. {
  571. pNew->SetNext(m_pChords);
  572. m_pChords = pNew;
  573. }
  574. }
  575. void CDMCompos::ChooseSignPosts(TListItem<DMSignPost> *pSignPostHead,
  576. TListItem<CompositionCommand> *pTempCommand, DWORD dwType,
  577. bool fSecondPass)
  578. {
  579. //TempCommand *ptcom = tclist->GetHead();
  580. TListItem<DMSignPost> *pSignPost;
  581. for (;pTempCommand; pTempCommand = pTempCommand->GetNext())
  582. {
  583. CompositionCommand& rTempCommand = pTempCommand->GetItemValue();
  584. short nTotal = 0;
  585. if ((rTempCommand.m_dwChord & dwType) == 0)
  586. {
  587. continue; // Only command, no chord.
  588. }
  589. pSignPost = pSignPostHead;
  590. for (; pSignPost; pSignPost = pSignPost->GetNext())
  591. {
  592. DMSignPost& rSignPost = pSignPost->GetItemValue();
  593. if (rSignPost.m_dwTempFlags & rTempCommand.m_dwChord & dwType)
  594. {
  595. break;
  596. }
  597. else
  598. {
  599. if (rSignPost.m_dwChords & rTempCommand.m_dwChord & dwType)
  600. {
  601. if (!rSignPost.m_dwTempFlags || fSecondPass) nTotal++;
  602. }
  603. }
  604. }
  605. if (!pSignPost)
  606. {
  607. if (nTotal) nTotal = rand() % nTotal;
  608. else nTotal = 0;
  609. nTotal++;
  610. pSignPost = pSignPostHead;
  611. for (; pSignPost; pSignPost = pSignPost->GetNext())
  612. {
  613. DMSignPost& rSignPost = pSignPost->GetItemValue();
  614. if (rSignPost.m_dwChords & rTempCommand.m_dwChord & dwType)
  615. {
  616. if (!rSignPost.m_dwTempFlags || fSecondPass)
  617. {
  618. nTotal--;
  619. if (!nTotal)
  620. {
  621. break;
  622. }
  623. }
  624. }
  625. }
  626. }
  627. if (pSignPost && !rTempCommand.m_pSignPost)
  628. {
  629. pSignPost->GetItemValue().m_dwTempFlags |= rTempCommand.m_dwChord;
  630. rTempCommand.m_pSignPost = pSignPost;
  631. }
  632. }
  633. }
  634. TListItem<CompositionCommand> *CDMCompos::GetNextChord(TListItem<CompositionCommand> *pCommand)
  635. {
  636. if (pCommand) pCommand = pCommand->GetNext();
  637. for (; pCommand; pCommand = pCommand->GetNext())
  638. {
  639. if (pCommand->GetItemValue().m_dwChord == 0) continue; // Only command, no chord.
  640. if (pCommand->GetItemValue().m_pSignPost) break;
  641. }
  642. return(pCommand);
  643. }
  644. void CDMCompos::FindEarlierSignpost(TListItem<CompositionCommand> *pCommand,
  645. TListItem<CompositionCommand> *pThis,
  646. SearchInfo *pSearch)
  647. {
  648. CompositionCommand& rThis = pThis->GetItemValue();
  649. TListItem<CompositionCommand> *pBest = NULL;
  650. pSearch->m_pPlayChord = NULL;
  651. pSearch->m_pFirstChord = NULL;
  652. for (; pCommand; pCommand = pCommand->GetNext())
  653. {
  654. CompositionCommand& rCommand = pCommand->GetItemValue();
  655. if (pCommand == pThis) break;
  656. if (!UsingDX8() || rCommand.m_dwChord == rThis.m_dwChord)
  657. {
  658. if (rCommand.m_pSignPost == rThis.m_pSignPost)
  659. {
  660. if (rCommand.m_SearchInfo.m_End.Equals(
  661. rThis.m_SearchInfo.m_End))
  662. {
  663. pSearch->m_pPlayChord = rCommand.m_PlayList.GetHead();
  664. pSearch->m_pFirstChord = rCommand.m_pFirstChord;
  665. return;
  666. }
  667. pBest = pCommand;
  668. }
  669. }
  670. }
  671. if (pBest)
  672. {
  673. pSearch->m_pPlayChord = pBest->GetItemValue().m_PlayList.GetHead();
  674. pSearch->m_pFirstChord = pBest->GetItemValue().m_pFirstChord;
  675. }
  676. }
  677. static void ClearChordFlags(TList<DMChordEntry>& ChordMap, DWORD dwFlag)
  678. {
  679. TListItem<DMChordEntry> *pChord = ChordMap.GetHead();
  680. for (; pChord; pChord = pChord->GetNext())
  681. {
  682. pChord->GetItemValue().m_dwFlags &= ~dwFlag;
  683. }
  684. }
  685. static void ClearNextFlags(TList<DMChordEntry>& ChordMap, DWORD dwFlag)
  686. {
  687. TListItem<DMChordEntry> *pChord = ChordMap.GetHead();
  688. for (; pChord; pChord = pChord->GetNext())
  689. {
  690. TListItem<DMChordLink> *pScan = pChord->GetItemValue().m_Links.GetHead();
  691. for (; pScan; pScan = pScan->GetNext())
  692. {
  693. pScan->GetItemValue().m_dwFlags &= ~dwFlag;
  694. }
  695. }
  696. }
  697. // rCommand will hold the first chord and playlist
  698. BOOL CDMCompos::Compose(TList<DMChordEntry>& ChordMap, SearchInfo *pSearch, CompositionCommand& rCommand)
  699. {
  700. TListItem<PlayChord> *pDupe;
  701. TListItem<DMChordEntry> *pChord = NULL;
  702. SearchInfo tempSearch;
  703. FailSearch tempFail;
  704. tempSearch = *pSearch;
  705. int i = 0;
  706. // First, if we have a previous instance with the same starting point,
  707. // try to come up with a solution using its path.
  708. if (pSearch->m_pPlayChord && pSearch->m_pFirstChord)
  709. {
  710. pChord = pSearch->m_pFirstChord;
  711. ClearNextFlags(ChordMap, NC_PATH);
  712. ClearChordFlags(ChordMap, CE_PATH);
  713. if (pChord->GetItemValue().Walk(pSearch))
  714. {
  715. }
  716. else
  717. {
  718. pChord = NULL;
  719. }
  720. }
  721. if (!pChord)
  722. {
  723. pChord = ChordMap.GetHead();
  724. for (; pChord; pChord = pChord->GetNext())
  725. {
  726. DMChordEntry& rChord = pChord->GetItemValue();
  727. if (rChord.m_dwFlags & CE_START)
  728. {
  729. if (rChord.m_ChordData.Equals(pSearch->m_Start))
  730. {
  731. ClearNextFlags(ChordMap, NC_PATH);
  732. ClearChordFlags(ChordMap, CE_PATH);
  733. tempFail = pSearch->m_Fail;
  734. *pSearch = tempSearch;
  735. pSearch->m_Fail = tempFail;
  736. if (rChord.Walk(pSearch)) break;
  737. }
  738. }
  739. }
  740. }
  741. if (!pChord)
  742. {
  743. return(FALSE);
  744. }
  745. pDupe = new TListItem<PlayChord>;
  746. if (pDupe)
  747. {
  748. PlayChord& rDupe = pDupe->GetItemValue();
  749. rDupe.m_fSilent = false;
  750. rDupe.m_pChord = &pChord->GetItemValue().m_ChordData;
  751. rDupe.m_nMeasure = (short)i++;
  752. rDupe.m_nMinbeats = rDupe.m_nMaxbeats = 0;
  753. rDupe.m_pNext = NULL;
  754. pDupe->SetNext(NULL);
  755. rCommand.m_pFirstChord = pChord;
  756. rCommand.m_PlayList.AddTail(pDupe);
  757. }
  758. for (; pChord; )
  759. {
  760. TListItem<DMChordLink> *pNext = pChord->GetItemValue().m_Links.GetHead();
  761. for (; pNext; )
  762. {
  763. DMChordLink& rNext = pNext->GetItemValue();
  764. if (rNext.m_dwFlags & NC_PATH)
  765. {
  766. pDupe = new TListItem<PlayChord>;
  767. if (pDupe)
  768. {
  769. PlayChord& rDupe = pDupe->GetItemValue();
  770. rDupe.m_fSilent = false;
  771. rDupe.m_pChord = &rNext.m_pChord->GetItemValue().m_ChordData;
  772. rDupe.m_nMeasure = (short)i++;
  773. rDupe.m_nMinbeats = (short)rNext.m_wMinBeats;
  774. rDupe.m_nMaxbeats = (short)rNext.m_wMaxBeats;
  775. rDupe.m_pNext = pNext;
  776. pDupe->SetNext(NULL);
  777. rCommand.m_PlayList.AddTail(pDupe);
  778. }
  779. break;
  780. }
  781. else
  782. {
  783. pNext = pNext->GetNext();
  784. }
  785. }
  786. if (pNext)
  787. {
  788. pChord = pNext->GetItemValue().m_pChord;
  789. }
  790. else pChord = NULL;
  791. }
  792. return(TRUE);
  793. }
  794. TListItem<PlayChord> *CDMCompos::AddChord(TList<PlayChord>& rList, DMChordData *pChord,
  795. int nMeasure,int nBeat)
  796. {
  797. if (pChord->m_pSubChords)
  798. {
  799. TListItem<PlayChord> *pNext = new TListItem<PlayChord>;
  800. if (pNext)
  801. {
  802. pNext->GetItemValue().m_pChord = new DMChordData(*pChord);
  803. if (pNext->GetItemValue().m_pChord)
  804. {
  805. AddChord(pNext->GetItemValue().m_pChord);
  806. pNext->GetItemValue().m_fSilent = false;
  807. pNext->GetItemValue().m_nMeasure = (short)nMeasure;
  808. pNext->GetItemValue().m_nBeat = (short)nBeat;
  809. pNext->GetItemValue().m_nMinbeats = 1;
  810. pNext->GetItemValue().m_pNext = NULL;
  811. rList.AddTail(pNext);
  812. }
  813. else
  814. {
  815. delete pNext;
  816. pNext = NULL;
  817. }
  818. }
  819. return (pNext);
  820. }
  821. else return NULL;
  822. }
  823. TListItem<PlayChord> *CDMCompos::AddCadence(TList<PlayChord>& rList, DMChordData *pChord, int nMax)
  824. {
  825. TListItem<PlayChord> *pNext = AddChord(rList, pChord, 0, 0);
  826. if (pNext)
  827. {
  828. pNext->GetItemValue().m_nMaxbeats = (short)nMax;
  829. }
  830. return (pNext);
  831. }
  832. void CDMCompos::JostleBack(TList<PlayChord>& rList, TListItem<PlayChord> *pChord, int nBeats)
  833. {
  834. PlayChord& rChord = pChord->GetItemValue();
  835. TListItem<PlayChord> *pLast = rList.GetPrev(pChord);
  836. if (nBeats && pLast)
  837. {
  838. int distance;
  839. rChord.m_nBeat = (short)( rChord.m_nBeat + nBeats );
  840. distance = rChord.m_nBeat - pLast->GetItemValue().m_nBeat;
  841. if (distance > rChord.m_nMaxbeats)
  842. {
  843. JostleBack(rList, pLast, distance - rChord.m_nMaxbeats);
  844. }
  845. else if (distance < rChord.m_nMinbeats)
  846. {
  847. JostleBack(rList, pLast, distance - rChord.m_nMinbeats);
  848. }
  849. }
  850. }
  851. static BOOL inline InRange(TListItem<PlayChord> *pChord,int nLastbeat)
  852. {
  853. PlayChord& rChord = pChord->GetItemValue();
  854. int time = rChord.m_nBeat - nLastbeat;
  855. return ((time >= rChord.m_nMinbeats) && (time <= rChord.m_nMaxbeats));
  856. }
  857. BOOL CDMCompos::AlignChords(TListItem<PlayChord> *pChord,int nLastbeat,int nRes)
  858. {
  859. if (pChord)
  860. {
  861. PlayChord& rChord = pChord->GetItemValue();
  862. if (!(pChord->GetNext()))
  863. {
  864. return (InRange(pChord, nLastbeat));
  865. }
  866. if ((rChord.m_nBeat % nRes) == 0)
  867. {
  868. if (InRange(pChord, nLastbeat))
  869. {
  870. return(AlignChords(pChord->GetNext(), rChord.m_nBeat, nRes));
  871. }
  872. return(FALSE);
  873. }
  874. BOOL tryright = rand() % 2;
  875. int old = rChord.m_nBeat;
  876. rChord.m_nBeat = (short)( ( rChord.m_nBeat / nRes ) * nRes );
  877. if (tryright) rChord.m_nBeat = (short)( rChord.m_nBeat + nRes );
  878. if (InRange(pChord, nLastbeat))
  879. {
  880. if (AlignChords(pChord->GetNext(), rChord.m_nBeat, nRes))
  881. return(TRUE);
  882. }
  883. if (tryright) rChord.m_nBeat = (short)( rChord.m_nBeat - nRes );
  884. else rChord.m_nBeat = (short)( rChord.m_nBeat + nRes );
  885. if (InRange(pChord, nLastbeat))
  886. {
  887. if (AlignChords(pChord->GetNext(), rChord.m_nBeat, nRes))
  888. return(TRUE);
  889. }
  890. if (!tryright) rChord.m_nBeat = (short)( rChord.m_nBeat - nRes );
  891. rChord.m_nBeat = (short)( rChord.m_nBeat + ( ( nRes + 1 ) >> 1 ) );
  892. if (InRange(pChord, nLastbeat))
  893. {
  894. if (AlignChords(pChord->GetNext(), rChord.m_nBeat, nRes))
  895. return(TRUE);
  896. }
  897. rChord.m_nBeat = (short)old;
  898. if (InRange(pChord, nLastbeat))
  899. {
  900. return(AlignChords(pChord->GetNext(), rChord.m_nBeat, nRes));
  901. }
  902. }
  903. return (FALSE);
  904. }
  905. void CDMCompos::ChordConnections(TList<DMChordEntry>& ChordMap,
  906. CompositionCommand& rCommand,
  907. SearchInfo *pSearch,
  908. short nBPM,
  909. DMChordData *pCadence1,
  910. DMChordData *pCadence2)
  911. {
  912. int mint, maxt, top, bottom, total;
  913. short oldbeats = pSearch->m_nBeats;
  914. //, error;
  915. TListItem<PlayChord> *pChord;
  916. SearchInfo tempSearch;
  917. // Compose a chord list.
  918. pSearch->m_nMinBeats = 0;
  919. pSearch->m_nMaxBeats = 0;
  920. pSearch->m_nChords = 0;
  921. pSearch->m_Fail.m_nTooManybeats = 0;
  922. pSearch->m_Fail.m_nTooFewbeats = 0;
  923. pSearch->m_Fail.m_nTooManychords = 0;
  924. pSearch->m_Fail.m_nTooFewchords = 0;
  925. if (pCadence1)
  926. {
  927. pSearch->m_nMinBeats++;
  928. pSearch->m_nMaxBeats = (short)( pSearch->m_nMaxBeats + ((nBPM + 1) >> 1) );
  929. pSearch->m_nChords++;
  930. }
  931. if (pCadence2)
  932. {
  933. pSearch->m_nMinBeats++;
  934. pSearch->m_nMaxBeats = (short)( pSearch->m_nMaxBeats + ((nBPM + 1) >> 1) );
  935. pSearch->m_nChords++;
  936. }
  937. tempSearch = *pSearch;
  938. for (total = 0;total < 4;total++)
  939. {
  940. rCommand.m_PlayList.RemoveAll();
  941. Compose(ChordMap, pSearch, rCommand);
  942. pChord = rCommand.m_PlayList.GetHead();
  943. if (pChord) break;
  944. if (pSearch->m_Fail.m_nTooManybeats > pSearch->m_Fail.m_nTooFewbeats)
  945. {
  946. tempSearch.m_nBeats = (short)( tempSearch.m_nBeats >> 1 );
  947. }
  948. else if (pSearch->m_Fail.m_nTooManybeats < pSearch->m_Fail.m_nTooFewbeats)
  949. {
  950. tempSearch.m_nBeats = (short)( tempSearch.m_nBeats << 1 );
  951. }
  952. else if (pSearch->m_Fail.m_nTooManychords > pSearch->m_Fail.m_nTooFewchords)
  953. {
  954. break; // Can't possibly get better. Use Cadence.
  955. }
  956. else if (pSearch->m_Fail.m_nTooManychords < pSearch->m_Fail.m_nTooFewchords)
  957. {
  958. tempSearch.m_nMinChords = (short)( tempSearch.m_nMinChords >> 1 );
  959. }
  960. else break;
  961. *pSearch = tempSearch;
  962. }
  963. pSearch->m_nBeats = oldbeats;
  964. // Tally the min and max beats.
  965. mint = 0;
  966. maxt = 0;
  967. for (; pChord; pChord = pChord->GetNext())
  968. {
  969. mint += pChord->GetItemValue().m_nMinbeats;
  970. maxt += pChord->GetItemValue().m_nMaxbeats;
  971. }
  972. pChord = rCommand.m_PlayList.GetHead();
  973. // If no chord connection was found, create one.
  974. if (!pChord)
  975. {
  976. int nextDuration = oldbeats;
  977. pChord = AddCadence(rCommand.m_PlayList, &pSearch->m_Start, 0);
  978. if (pChord)
  979. {
  980. pChord->GetItemValue().m_nMinbeats = 0;
  981. }
  982. if (pCadence1)
  983. {
  984. AddCadence(rCommand.m_PlayList, pCadence1, nextDuration);
  985. mint++;
  986. maxt += nextDuration;
  987. nextDuration = nBPM + 1;
  988. }
  989. if (pCadence2)
  990. {
  991. AddCadence(rCommand.m_PlayList, pCadence2, nextDuration);
  992. mint++;
  993. maxt += nextDuration;
  994. nextDuration = nBPM + 1;
  995. }
  996. AddCadence(rCommand.m_PlayList, &pSearch->m_Start, nextDuration);
  997. mint++;
  998. maxt += nextDuration;
  999. }
  1000. else
  1001. {
  1002. int chordCount = (int) rCommand.m_PlayList.GetCount();
  1003. int avMax;
  1004. if (chordCount > 1) chordCount--;
  1005. avMax = maxt / chordCount;
  1006. if (avMax < 1) avMax = 1;
  1007. if (pCadence1)
  1008. {
  1009. if (pCadence2)
  1010. {
  1011. AddCadence(rCommand.m_PlayList, pCadence2, avMax);
  1012. maxt += avMax;
  1013. mint++;
  1014. }
  1015. AddCadence(rCommand.m_PlayList, &pSearch->m_End, avMax);
  1016. maxt += avMax;
  1017. mint++;
  1018. }
  1019. else if (pCadence2)
  1020. {
  1021. AddCadence(rCommand.m_PlayList, &pSearch->m_End, avMax);
  1022. maxt += avMax;
  1023. mint++;
  1024. }
  1025. }
  1026. // Prepare a ratio to apply to each connection.
  1027. top = pSearch->m_nBeats - mint;
  1028. bottom = maxt - mint;
  1029. if (bottom <= 0) bottom = 1;
  1030. // Assign each connection a time based on the ratio.
  1031. total = 0;
  1032. pChord = rCommand.m_PlayList.GetHead();
  1033. for (; pChord; pChord = pChord->GetNext())
  1034. {
  1035. PlayChord& rChord = pChord->GetItemValue();
  1036. int beat = rChord.m_nMaxbeats - rChord.m_nMinbeats;
  1037. beat *= top;
  1038. beat += (bottom >> 1);
  1039. beat /= bottom;
  1040. if (beat < rChord.m_nMinbeats) beat = rChord.m_nMinbeats;
  1041. if (beat > rChord.m_nMaxbeats) beat = rChord.m_nMaxbeats;
  1042. total += beat;
  1043. rChord.m_nBeat = (short)total;
  1044. }
  1045. // It should not be the case that total is 0 after this loop, but it is possible.
  1046. // (particularly if the playlist contains a single chord). If this happens, give
  1047. // total a value of 1 to make the computations in the following loop work correctly.
  1048. if (!total) total = 1;
  1049. // We should now have a close approximation of the correct time.
  1050. // Stretch or shrink the range to fit exactly. Err on the side
  1051. // of too long, since jostleback will scrunch them back in place.
  1052. pChord = rCommand.m_PlayList.GetHead();
  1053. for (; pChord; pChord = pChord->GetNext())
  1054. {
  1055. PlayChord& rChord = pChord->GetItemValue();
  1056. int newbeat = (rChord.m_nBeat * pSearch->m_nBeats) + total - 1;
  1057. newbeat /= total;
  1058. rChord.m_nBeat = (short)newbeat;
  1059. if (!pChord->GetNext()) total = rChord.m_nBeat;
  1060. }
  1061. // Now we should have times close to the real thing.
  1062. pChord = rCommand.m_PlayList.GetItem(rCommand.m_PlayList.GetCount() - 1);
  1063. if (pChord && (int)pSearch->m_nBeats >= total)
  1064. {
  1065. JostleBack(rCommand.m_PlayList, pChord, pSearch->m_nBeats - total);
  1066. }
  1067. // Now, add the starting time offset to each chord.
  1068. // And, remove the straggler last chord.
  1069. AlignChords(rCommand.m_PlayList.GetHead(), 0, nBPM);
  1070. pChord = rCommand.m_PlayList.GetHead();
  1071. for (; pChord; )
  1072. {
  1073. pChord->GetItemValue().m_nMeasure =
  1074. (short)( ( pChord->GetItemValue().m_nBeat / nBPM ) + rCommand.m_nMeasure );
  1075. pChord->GetItemValue().m_nBeat %= nBPM;
  1076. if (pChord->GetNext())
  1077. {
  1078. pChord = pChord->GetNext();
  1079. }
  1080. else
  1081. {
  1082. rCommand.m_PlayList.Remove(pChord);
  1083. delete pChord;
  1084. break;
  1085. }
  1086. }
  1087. }
  1088. static TListItem<PlayChord> *FindChordInMeasure(TList<PlayChord>& PlayList,int nMeasure)
  1089. {
  1090. TListItem<PlayChord> *pChord = PlayList.GetHead();
  1091. for (; pChord; pChord = pChord->GetNext())
  1092. {
  1093. PlayChord& rChord = pChord->GetItemValue();
  1094. if (rChord.m_nMeasure > nMeasure) break;
  1095. if (rChord.m_nMeasure == nMeasure)
  1096. {
  1097. if (rChord.m_nBeat) return(pChord);
  1098. }
  1099. }
  1100. return(NULL);
  1101. }
  1102. void CDMCompos::CleanUpBreaks(TList<PlayChord>& PlayList, TListItem<CompositionCommand> *pCommand)
  1103. {
  1104. for (; pCommand; pCommand = pCommand->GetNext())
  1105. {
  1106. CompositionCommand& rCommand = pCommand->GetItemValue();
  1107. if ((rCommand.m_Command.bCommand == DMUS_COMMANDT_BREAK) ||
  1108. (rCommand.m_Command.bCommand == DMUS_COMMANDT_END) ||
  1109. (rCommand.m_Command.bCommand == DMUS_COMMANDT_INTRO) )
  1110. {
  1111. TListItem<PlayChord> *pChord;
  1112. while( ( pChord = FindChordInMeasure( PlayList, rCommand.m_nMeasure ) ) != NULL )
  1113. {
  1114. PlayList.Remove(pChord);
  1115. delete pChord;
  1116. }
  1117. }
  1118. }
  1119. }
  1120. static void LoadCommandList(TList<TemplateCommand>& CommandList, LPSTREAM pCStream)
  1121. {
  1122. HRESULT hr = E_FAIL;
  1123. IAARIFFStream* pRIFF;
  1124. MMCKINFO ck;
  1125. long lFileSize = 0;
  1126. DWORD dwNodeSize;
  1127. DWORD cb;
  1128. StreamSeek(pCStream, 0, STREAM_SEEK_SET);
  1129. if( SUCCEEDED( AllocRIFFStream( pCStream, &pRIFF ) ) &&
  1130. pRIFF->Descend( &ck, NULL, 0 ) == 0 &&
  1131. ck.ckid == FOURCC_COMMAND)
  1132. {
  1133. DMUS_IO_COMMAND iCommand;
  1134. lFileSize = ck.cksize;
  1135. hr = pCStream->Read( &dwNodeSize, sizeof( dwNodeSize ), &cb );
  1136. if( SUCCEEDED( hr ) && cb == sizeof( dwNodeSize ) )
  1137. {
  1138. lFileSize -= 4; // for the size dword
  1139. TListItem<TemplateCommand>* pCommand;
  1140. if (lFileSize % dwNodeSize)
  1141. {
  1142. hr = E_FAIL;
  1143. }
  1144. else
  1145. {
  1146. while( lFileSize > 0 )
  1147. {
  1148. pCommand = new TListItem<TemplateCommand>;
  1149. if( pCommand )
  1150. {
  1151. TemplateCommand& rCommand = pCommand->GetItemValue();
  1152. if( dwNodeSize <= sizeof( DMUS_IO_COMMAND ) )
  1153. {
  1154. pCStream->Read( &iCommand, dwNodeSize, NULL );
  1155. }
  1156. else
  1157. {
  1158. pCStream->Read( &iCommand, sizeof( DMUS_IO_COMMAND ), NULL );
  1159. StreamSeek( pCStream, lFileSize - sizeof( DMUS_IO_COMMAND ), STREAM_SEEK_CUR );
  1160. }
  1161. memset( &rCommand, 0, sizeof( rCommand ) );
  1162. rCommand.m_nMeasure = iCommand.wMeasure;
  1163. rCommand.m_Command.bCommand = iCommand.bCommand;
  1164. rCommand.m_Command.bGrooveLevel = iCommand.bGrooveLevel;
  1165. rCommand.m_Command.bGrooveRange = iCommand.bGrooveRange;
  1166. rCommand.m_Command.bRepeatMode = iCommand.bRepeatMode;
  1167. rCommand.m_dwChord = 0;
  1168. CommandList.AddTail(pCommand);
  1169. lFileSize -= dwNodeSize;
  1170. }
  1171. else break;
  1172. }
  1173. }
  1174. }
  1175. if( lFileSize == 0 &&
  1176. pRIFF->Ascend( &ck, 0 ) == 0 )
  1177. {
  1178. hr = S_OK;
  1179. }
  1180. }
  1181. pRIFF->Release();
  1182. }
  1183. static void LoadCommandList(TList<TemplateCommand>& CommandList, LPSTREAM pSPStream, LPSTREAM pCStream)
  1184. {
  1185. TList<DMSignPostStruct> SignPostList;
  1186. HRESULT hr = E_FAIL;
  1187. DWORD dwPos;
  1188. IAARIFFStream* pRIFF = NULL;
  1189. dwPos = StreamTell( pSPStream );
  1190. StreamSeek( pSPStream, dwPos, STREAM_SEEK_SET );
  1191. MMCKINFO ck;
  1192. long lFileSize = 0;
  1193. DWORD dwNodeSize;
  1194. DWORD cb;
  1195. DMUS_IO_SIGNPOST iSignPost;
  1196. if( SUCCEEDED( AllocRIFFStream( pSPStream, &pRIFF ) ) &&
  1197. pRIFF->Descend( &ck, NULL, 0 ) == 0 &&
  1198. ck.ckid == DMUS_FOURCC_SIGNPOST_TRACK_CHUNK)
  1199. {
  1200. lFileSize = ck.cksize;
  1201. hr = pSPStream->Read( &dwNodeSize, sizeof( dwNodeSize ), &cb );
  1202. if( SUCCEEDED( hr ) && cb == sizeof( dwNodeSize ) )
  1203. {
  1204. lFileSize -= 4; // for the size dword
  1205. TListItem<DMSignPostStruct>* pSignPost;
  1206. if (lFileSize % dwNodeSize)
  1207. {
  1208. hr = E_FAIL;
  1209. }
  1210. else
  1211. {
  1212. while( lFileSize > 0 )
  1213. {
  1214. pSignPost = new TListItem<DMSignPostStruct>;
  1215. if( pSignPost )
  1216. {
  1217. DMSignPostStruct& rSignPost = pSignPost->GetItemValue();
  1218. if( dwNodeSize <= sizeof( iSignPost ) )
  1219. {
  1220. pSPStream->Read( &iSignPost, dwNodeSize, NULL );
  1221. }
  1222. else
  1223. {
  1224. pSPStream->Read( &iSignPost, sizeof( iSignPost ), NULL );
  1225. StreamSeek( pSPStream, lFileSize - sizeof( iSignPost ), STREAM_SEEK_CUR );
  1226. }
  1227. memset( &rSignPost, 0, sizeof( rSignPost ) );
  1228. rSignPost.m_mtTime = iSignPost.mtTime;
  1229. rSignPost.m_wMeasure = iSignPost.wMeasure;
  1230. rSignPost.m_dwChords = iSignPost.dwChords;
  1231. SignPostList.AddTail(pSignPost);
  1232. lFileSize -= dwNodeSize;
  1233. }
  1234. else break;
  1235. }
  1236. }
  1237. }
  1238. if( lFileSize == 0 &&
  1239. pRIFF->Ascend( &ck, 0 ) == 0 )
  1240. {
  1241. hr = S_OK;
  1242. }
  1243. }
  1244. if (pRIFF)
  1245. {
  1246. pRIFF->Release();
  1247. pRIFF = NULL;
  1248. }
  1249. // If a command stream exists, load the commands into the command list.
  1250. if (pCStream)
  1251. {
  1252. StreamSeek(pCStream, 0, STREAM_SEEK_SET);
  1253. if( SUCCEEDED( AllocRIFFStream( pCStream, &pRIFF ) ) &&
  1254. pRIFF->Descend( &ck, NULL, 0 ) == 0 &&
  1255. ck.ckid == FOURCC_COMMAND)
  1256. {
  1257. DMUS_IO_COMMAND iCommand;
  1258. lFileSize = ck.cksize;
  1259. hr = pCStream->Read( &dwNodeSize, sizeof( dwNodeSize ), &cb );
  1260. if( SUCCEEDED( hr ) && cb == sizeof( dwNodeSize ) )
  1261. {
  1262. lFileSize -= 4; // for the size dword
  1263. TListItem<TemplateCommand>* pCommand;
  1264. if (lFileSize % dwNodeSize)
  1265. {
  1266. hr = E_FAIL;
  1267. }
  1268. else
  1269. {
  1270. while( lFileSize > 0 )
  1271. {
  1272. pCommand = new TListItem<TemplateCommand>;
  1273. if( pCommand )
  1274. {
  1275. TemplateCommand& rCommand = pCommand->GetItemValue();
  1276. if( dwNodeSize <= sizeof( DMUS_IO_COMMAND ) )
  1277. {
  1278. pCStream->Read( &iCommand, dwNodeSize, NULL );
  1279. }
  1280. else
  1281. {
  1282. pCStream->Read( &iCommand, sizeof( DMUS_IO_COMMAND ), NULL );
  1283. StreamSeek( pCStream, lFileSize - sizeof( DMUS_IO_COMMAND ), STREAM_SEEK_CUR );
  1284. }
  1285. memset( &rCommand, 0, sizeof( rCommand ) );
  1286. rCommand.m_nMeasure = iCommand.wMeasure;
  1287. rCommand.m_Command.bCommand = iCommand.bCommand;
  1288. rCommand.m_Command.bGrooveLevel = iCommand.bGrooveLevel;
  1289. rCommand.m_Command.bGrooveRange = iCommand.bGrooveRange;
  1290. rCommand.m_Command.bRepeatMode = iCommand.bRepeatMode;
  1291. CommandList.AddTail(pCommand);
  1292. lFileSize -= dwNodeSize;
  1293. }
  1294. else break;
  1295. }
  1296. }
  1297. }
  1298. if( lFileSize == 0 &&
  1299. pRIFF->Ascend( &ck, 0 ) == 0 )
  1300. {
  1301. hr = S_OK;
  1302. }
  1303. }
  1304. if (pRIFF) pRIFF->Release();
  1305. }
  1306. // Now, go through the signpost list, making sure that every signpost has a corresponding
  1307. // command. If this is not the case for some signpost, insert a groove with the last
  1308. // current groove level into the list (default this to 67). Give each command's m_dwChord
  1309. // the m_dwChords value from the corresponding signpost.
  1310. BYTE bGrooveLevel = 62;
  1311. TListItem<DMSignPostStruct>* pSignPost = SignPostList.GetHead();
  1312. for( ; pSignPost; pSignPost = pSignPost->GetNext())
  1313. {
  1314. bool fFoundInList = false;
  1315. DMSignPostStruct& rSignPost = pSignPost->GetItemValue();
  1316. TListItem<TemplateCommand>* pPrevious = NULL;
  1317. TListItem<TemplateCommand>* pCommand = CommandList.GetHead();
  1318. for ( ; pCommand; pCommand = pCommand->GetNext())
  1319. {
  1320. TemplateCommand& rCommand = pCommand->GetItemValue();
  1321. if (rSignPost.m_wMeasure == rCommand.m_nMeasure)
  1322. {
  1323. rCommand.m_dwChord = rSignPost.m_dwChords;
  1324. fFoundInList = true;
  1325. break;
  1326. }
  1327. else if (rSignPost.m_wMeasure < rCommand.m_nMeasure)
  1328. {
  1329. // We went too far in the command list, so break out
  1330. break;
  1331. }
  1332. if (rCommand.m_Command.bGrooveLevel)
  1333. {
  1334. bGrooveLevel = rCommand.m_Command.bGrooveLevel;
  1335. }
  1336. pPrevious = pCommand;
  1337. }
  1338. if ( !fFoundInList )
  1339. {
  1340. // We need to create a new command and stick it between pPrevious and pCommand
  1341. TListItem<TemplateCommand>* pNew = new TListItem<TemplateCommand>;
  1342. if( pNew )
  1343. {
  1344. TemplateCommand& rNew = pNew->GetItemValue();
  1345. memset( &rNew, 0, sizeof( rNew ) );
  1346. rNew.m_nMeasure = rSignPost.m_wMeasure;
  1347. rNew.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
  1348. rNew.m_Command.bGrooveLevel = bGrooveLevel;
  1349. rNew.m_Command.bGrooveRange = 0;
  1350. rNew.m_Command.bRepeatMode = DMUS_PATTERNT_RANDOM;
  1351. rNew.m_dwChord = rSignPost.m_dwChords;
  1352. if (pPrevious)
  1353. {
  1354. pPrevious->SetNext(pNew);
  1355. pNew->SetNext(pCommand);
  1356. }
  1357. else
  1358. {
  1359. CommandList.AddHead(pNew);
  1360. }
  1361. }
  1362. }
  1363. }
  1364. }
  1365. HRESULT CDMCompos::SaveChordList( IAARIFFStream* pRIFF, TList<PlayChord>& rPlayList,
  1366. BYTE bRoot, DWORD dwScale, DMUS_TIMESIGNATURE& rTimeSig)
  1367. {
  1368. IStream* pStream;
  1369. MMCKINFO ck;
  1370. MMCKINFO ckHeader;
  1371. HRESULT hr;
  1372. TListItem<PlayChord>* pChord;
  1373. DWORD cb;
  1374. pStream = pRIFF->GetStream();
  1375. ck.fccType = DMUS_FOURCC_CHORDTRACK_LIST;
  1376. hr = pRIFF->CreateChunk(&ck,MMIO_CREATELIST);
  1377. if (SUCCEEDED(hr))
  1378. {
  1379. DWORD dwRoot = bRoot;
  1380. dwScale |= (dwRoot << 24);
  1381. ckHeader.ckid = DMUS_FOURCC_CHORDTRACKHEADER_CHUNK;
  1382. hr = pRIFF->CreateChunk(&ckHeader, 0);
  1383. if (SUCCEEDED(hr))
  1384. {
  1385. hr = pStream->Write( &dwScale, sizeof( dwScale ), &cb );
  1386. if (SUCCEEDED(hr))
  1387. {
  1388. hr = pRIFF->Ascend( &ckHeader, 0 );
  1389. if (hr == S_OK)
  1390. {
  1391. pChord = rPlayList.GetHead();
  1392. for( ; pChord != NULL ; pChord = pChord->GetNext() )
  1393. {
  1394. hr = pChord->GetItemValue().Save(pRIFF, rTimeSig);
  1395. if (FAILED(hr))
  1396. {
  1397. pStream->Release();
  1398. return hr;
  1399. }
  1400. }
  1401. if( pChord == NULL &&
  1402. pRIFF->Ascend( &ck, 0 ) == 0 )
  1403. {
  1404. hr = S_OK;
  1405. }
  1406. }
  1407. }
  1408. }
  1409. }
  1410. pStream->Release();
  1411. return hr;
  1412. }
  1413. static HRESULT SaveCommandList( IAARIFFStream* pRIFF, TList<TemplateCommand>& rCommandList,
  1414. DMUS_TIMESIGNATURE& rTimeSig)
  1415. {
  1416. IStream* pStream;
  1417. MMCKINFO ck;
  1418. HRESULT hr;
  1419. DWORD cb;
  1420. DWORD dwSize;
  1421. DMUS_IO_COMMAND iCommand;
  1422. TListItem<TemplateCommand>* pCommand;
  1423. pStream = pRIFF->GetStream();
  1424. hr = E_FAIL;
  1425. ck.ckid = FOURCC_COMMAND;
  1426. if( pRIFF->CreateChunk( &ck, 0 ) == 0 )
  1427. {
  1428. dwSize = sizeof( DMUS_IO_COMMAND );
  1429. hr = pStream->Write( &dwSize, sizeof( dwSize ), &cb );
  1430. if( FAILED( hr ) || cb != sizeof( dwSize ) )
  1431. {
  1432. pStream->Release( );
  1433. return E_FAIL;
  1434. }
  1435. for( pCommand = rCommandList.GetHead(); pCommand != NULL ; pCommand = pCommand->GetNext() )
  1436. {
  1437. TemplateCommand& rCommand = pCommand->GetItemValue();
  1438. memset( &iCommand, 0, sizeof( iCommand ) );
  1439. iCommand.mtTime = ClocksPerMeasure(rTimeSig) * rCommand.m_nMeasure;
  1440. iCommand.wMeasure = rCommand.m_nMeasure;
  1441. iCommand.bBeat = 0;
  1442. iCommand.bCommand = rCommand.m_Command.bCommand;
  1443. iCommand.bGrooveLevel = rCommand.m_Command.bGrooveLevel;
  1444. iCommand.bGrooveRange = rCommand.m_Command.bGrooveRange;
  1445. iCommand.bRepeatMode = rCommand.m_Command.bRepeatMode;
  1446. if( FAILED( pStream->Write( &iCommand, sizeof( iCommand ), &cb ) ) ||
  1447. cb != sizeof( iCommand ) )
  1448. {
  1449. break;
  1450. }
  1451. }
  1452. if( pCommand == NULL &&
  1453. pRIFF->Ascend( &ck, 0 ) == 0 )
  1454. {
  1455. hr = S_OK;
  1456. }
  1457. }
  1458. pStream->Release( );
  1459. return hr;
  1460. }
  1461. static HRESULT SaveStartMarkers( IAARIFFStream* pRIFF, TemplateCommand& rCommand,
  1462. IDMStyle* pStyle)
  1463. {
  1464. IStream* pStream;
  1465. MMCKINFO ckMain;
  1466. MMCKINFO ck;
  1467. HRESULT hr;
  1468. DWORD cb;
  1469. DWORD dwSize;
  1470. DMUS_IO_VALID_START oValidStart;
  1471. bool fWroteOne = false;
  1472. pStream = pRIFF->GetStream();
  1473. hr = E_FAIL;
  1474. ckMain.ckid = FOURCC_LIST;
  1475. ckMain.fccType = DMUS_FOURCC_MARKERTRACK_LIST;
  1476. if( pRIFF->CreateChunk( &ckMain, MMIO_CREATELIST ) == 0 )
  1477. {
  1478. ck.ckid = DMUS_FOURCC_VALIDSTART_CHUNK;
  1479. if( pRIFF->CreateChunk( &ck, 0 ) == 0 )
  1480. {
  1481. dwSize = sizeof( DMUS_IO_VALID_START );
  1482. hr = pStream->Write( &dwSize, sizeof( dwSize ), &cb );
  1483. if( FAILED( hr ) || cb != sizeof( dwSize ) )
  1484. {
  1485. pStream->Release( );
  1486. return E_FAIL;
  1487. }
  1488. DWORD dwIndex = 0;
  1489. MUSIC_TIME mtTime = 0;
  1490. while(S_OK == (hr = pStyle->EnumStartTime(dwIndex, &rCommand.m_Command, &mtTime)))
  1491. {
  1492. memset( &oValidStart, 0, sizeof( oValidStart ) );
  1493. oValidStart.mtTime = mtTime;
  1494. if( FAILED( hr = pStream->Write( &oValidStart, sizeof( oValidStart ), &cb ) ) ||
  1495. cb != sizeof( oValidStart ) )
  1496. {
  1497. if (SUCCEEDED(hr)) hr = E_FAIL;
  1498. break;
  1499. }
  1500. fWroteOne = true;
  1501. dwIndex++;
  1502. }
  1503. if( SUCCEEDED(hr) && pRIFF->Ascend( &ck, 0 ) == 0 )
  1504. {
  1505. hr = S_OK;
  1506. }
  1507. }
  1508. if( SUCCEEDED(hr) && pRIFF->Ascend( &ck, 0 ) == 0 )
  1509. {
  1510. hr = S_OK;
  1511. }
  1512. }
  1513. if (!fWroteOne) hr = E_FAIL;
  1514. pStream->Release( );
  1515. return hr;
  1516. }
  1517. void CDMCompos::ComposePlayList(TList<PlayChord>& PlayList,
  1518. IDirectMusicStyle* pStyle,
  1519. IDirectMusicChordMap* pPersonality,
  1520. TList<TemplateCommand>& rCommandList,
  1521. WORD wActivity)
  1522. {
  1523. // Extract the style's time signature.
  1524. DMUS_TIMESIGNATURE TimeSig;
  1525. pStyle->GetTimeSignature(&TimeSig);
  1526. if (wActivity < 0) wActivity = 0;
  1527. if (wActivity > 3) wActivity = 3;
  1528. short nBPM = TimeSig.bBeatsPerMeasure;
  1529. IDMPers* pDMP;
  1530. pPersonality->QueryInterface(IID_IDMPers, (void**)&pDMP);
  1531. DMPersonalityStruct* pPers;
  1532. pDMP->GetPersonalityStruct((void**)&pPers);
  1533. TList<DMChordEntry> &ChordMap = pPers->m_ChordMap;
  1534. TList<DMSignPost> &SignPostList = pPers->m_SignPostList;
  1535. TListItem<DMSignPost> *pSign = SignPostList.GetHead();
  1536. for (; pSign; pSign = pSign->GetNext())
  1537. {
  1538. pSign->GetItemValue().m_dwTempFlags = 0;
  1539. }
  1540. // Assign specific root sign posts, then letter based sign posts.
  1541. TList<CompositionCommand> CommandList;
  1542. TListItem<TemplateCommand>* pTC = rCommandList.GetHead();
  1543. for(; pTC; pTC = pTC->GetNext())
  1544. {
  1545. TemplateCommand& rTC = pTC->GetItemValue();
  1546. TListItem<CompositionCommand>* pNew = new TListItem<CompositionCommand>;
  1547. if (pNew)
  1548. {
  1549. CompositionCommand& rNew = pNew->GetItemValue();
  1550. rNew.m_nMeasure = rTC.m_nMeasure;
  1551. rNew.m_Command = rTC.m_Command;
  1552. rNew.m_dwChord = rTC.m_dwChord;
  1553. rNew.m_pSignPost = NULL;
  1554. rNew.m_pFirstChord = NULL;
  1555. CommandList.AddTail(pNew);
  1556. }
  1557. }
  1558. ChooseSignPosts(SignPostList.GetHead(), CommandList.GetHead(),DMUS_SIGNPOSTF_ROOT, false);
  1559. ChooseSignPosts(SignPostList.GetHead(), CommandList.GetHead(),DMUS_SIGNPOSTF_LETTER, false);
  1560. ChooseSignPosts(SignPostList.GetHead(), CommandList.GetHead(),DMUS_SIGNPOSTF_ROOT, true);
  1561. ChooseSignPosts(SignPostList.GetHead(), CommandList.GetHead(),DMUS_SIGNPOSTF_LETTER, true);
  1562. // Now, we should have a chord assigned for each node in the template.
  1563. TListItem<CompositionCommand>* pCommand = CommandList.GetHead();
  1564. for (; pCommand; pCommand = pCommand->GetNext())
  1565. {
  1566. CompositionCommand& rCommand = pCommand->GetItemValue();
  1567. if (rCommand.m_dwChord == 0) continue; // Only command, no chord.
  1568. if (rCommand.m_pSignPost)
  1569. {
  1570. TListItem<CompositionCommand>* pNext = GetNextChord(pCommand);
  1571. if (pNext)
  1572. {
  1573. CompositionCommand& rNext = pNext->GetItemValue();
  1574. SearchInfo *pSearch = &rCommand.m_SearchInfo;
  1575. DMChordData *pCadence1 = NULL;
  1576. DMChordData *pCadence2 = NULL;
  1577. pSearch->m_Start = rCommand.m_pSignPost->GetItemValue().m_ChordData;
  1578. if (rNext.m_dwChord & DMUS_SIGNPOSTF_CADENCE)
  1579. {
  1580. TListItem<DMSignPost> *pLocalSign = rNext.m_pSignPost;
  1581. DMSignPost& rSign = pLocalSign->GetItemValue();
  1582. if (rSign.m_dwFlags & DMUS_SPOSTCADENCEF_1)
  1583. {
  1584. pSearch->m_End = rSign.m_aCadence[0];
  1585. pCadence1 = &rSign.m_aCadence[0];
  1586. if (rSign.m_dwFlags & DMUS_SPOSTCADENCEF_2)
  1587. {
  1588. pCadence2 = &rSign.m_aCadence[1];
  1589. }
  1590. }
  1591. else if (rSign.m_dwFlags & DMUS_SPOSTCADENCEF_2)
  1592. {
  1593. pSearch->m_End = rSign.m_aCadence[1];
  1594. pCadence2 = &rSign.m_aCadence[1];
  1595. }
  1596. else
  1597. {
  1598. pSearch->m_End = rSign.m_ChordData;
  1599. }
  1600. }
  1601. else
  1602. {
  1603. pSearch->m_End = rNext.m_pSignPost->GetItemValue().m_ChordData;
  1604. }
  1605. pSearch->m_nActivity = (short) wActivity;
  1606. pSearch->m_nBeats = (short)( (rNext.m_nMeasure - rCommand.m_nMeasure) * nBPM );
  1607. pSearch->m_nMaxChords = (short)( pSearch->m_nBeats >> wActivity );
  1608. pSearch->m_nMinChords = (short)( pSearch->m_nBeats >> (wActivity + 1) );
  1609. FindEarlierSignpost(CommandList.GetHead(), pCommand, pSearch);
  1610. // rCommand holds the playlist and the measure used by ChordConnections
  1611. // (it should be passed by reference since the playlist changes)
  1612. ChordConnections(ChordMap, rCommand, pSearch, nBPM, pCadence1, pCadence2);
  1613. }
  1614. else
  1615. {
  1616. AddChord(rCommand.m_PlayList, &rCommand.m_pSignPost->GetItemValue().m_ChordData,
  1617. rCommand.m_nMeasure,0);
  1618. }
  1619. }
  1620. }
  1621. // Take all the Chord references and fold 'em into one list.
  1622. pCommand = CommandList.GetHead();
  1623. for (; pCommand; pCommand = pCommand->GetNext())
  1624. {
  1625. PlayList.Cat(pCommand->GetItemValue().m_PlayList.GetHead());
  1626. pCommand->GetItemValue().m_PlayList.RemoveAll();
  1627. }
  1628. CleanUpBreaks(PlayList, CommandList.GetHead());
  1629. pDMP->Release();
  1630. }
  1631. HRESULT CDMCompos::ExtractCommandList(TList<TemplateCommand>& CommandList,
  1632. IDirectMusicTrack* pSignPostTrack,
  1633. IDirectMusicTrack* pCommandTrack,
  1634. DWORD dwGroupBits)
  1635. {
  1636. HRESULT hr = S_OK;
  1637. IPersistStream* pPS1 = NULL;
  1638. IPersistStream* pPS2 = NULL;
  1639. IStream* pStream1 = NULL;
  1640. IStream* pStream2 = NULL;
  1641. // First, get the signpost track from the template segment and persist it to a stream
  1642. if (!pSignPostTrack)
  1643. {
  1644. Trace(1, "ERROR: No signpost track to use for chord composition.\n");
  1645. hr = E_POINTER;
  1646. goto ON_END;
  1647. }
  1648. hr = pSignPostTrack->QueryInterface(IID_IPersistStream, (void**)&pPS1);
  1649. if (hr != S_OK) goto ON_END;
  1650. hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream1);
  1651. if (hr != S_OK) goto ON_END;
  1652. hr = pPS1->Save(pStream1, FALSE);
  1653. if (hr != S_OK) goto ON_END;
  1654. StreamSeek(pStream1, 0, STREAM_SEEK_SET);
  1655. // Next, get the command track from the template segment and persist it to a stream.
  1656. // If there is no command track, we'll just use a NULL stream.
  1657. if (pCommandTrack)
  1658. {
  1659. hr = pCommandTrack->QueryInterface(IID_IPersistStream, (void**)&pPS2);
  1660. if (hr != S_OK) goto ON_END;
  1661. hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream2);
  1662. if (hr != S_OK) goto ON_END;
  1663. hr = pPS2->Save(pStream2, FALSE);
  1664. if (hr != S_OK) goto ON_END;
  1665. StreamSeek(pStream2, 0, STREAM_SEEK_SET);
  1666. }
  1667. // Finally, call LoadCommandList, passing in the two streams.
  1668. LoadCommandList(CommandList, pStream1, pStream2);
  1669. ON_END:
  1670. if (pPS1) pPS1->Release();
  1671. if (pPS2) pPS2->Release();
  1672. if (pStream1) pStream1->Release();
  1673. if (pStream2) pStream2->Release();
  1674. return hr;
  1675. }
  1676. // This will modify an existing segment by adding *only* a chord track to it.
  1677. // Any existing chord tracks with conflicting group bits will be removed.
  1678. HRESULT CDMCompos::AddToSegment(IDirectMusicSegment* pTempSeg,
  1679. TList<PlayChord>& PlayList,
  1680. IDirectMusicStyle* pStyle,
  1681. DWORD dwGroupBits,
  1682. BYTE bRoot, DWORD dwScale)
  1683. {
  1684. HRESULT hr = S_OK;
  1685. IDirectMusicTrack* pIChordTrack = NULL;
  1686. IAARIFFStream* pChordRIFF = NULL;
  1687. IStream* pIChordStream = NULL;
  1688. IPersistStream* pIChordTrackStream = NULL;
  1689. /////////////////////////////////////////////////////////////
  1690. // Extract the style's time signature.
  1691. DMUS_TIMESIGNATURE TimeSig;
  1692. pStyle->GetTimeSignature(&TimeSig);
  1693. // Convert PlayList into a Chord Track
  1694. if (PlayList.GetHead())
  1695. {
  1696. // if there exists a chord track with these group bits, reload these chords into that
  1697. // track (use the first track that's found). Otherwise, create a new chord track
  1698. // to load these chords into.
  1699. hr = pTempSeg->GetTrack(CLSID_DirectMusicChordTrack, dwGroupBits, 0, &pIChordTrack);
  1700. if (S_OK != hr)
  1701. {
  1702. // create a new chord track
  1703. hr = ::CoCreateInstance(
  1704. CLSID_DirectMusicChordTrack,
  1705. NULL,
  1706. CLSCTX_INPROC,
  1707. IID_IDirectMusicTrack,
  1708. (void**)&pIChordTrack
  1709. );
  1710. if (!SUCCEEDED(hr)) goto ON_END;
  1711. // insert the new chord track.
  1712. pTempSeg->InsertTrack(pIChordTrack, dwGroupBits);
  1713. }
  1714. hr = CreateStreamOnHGlobal(NULL, TRUE, &pIChordStream);
  1715. if (S_OK != hr) goto ON_END;
  1716. hr = AllocRIFFStream( pIChordStream, &pChordRIFF);
  1717. if (S_OK != hr) goto ON_END;
  1718. SaveChordList(pChordRIFF, PlayList, bRoot, dwScale, TimeSig);
  1719. hr = pIChordTrack->QueryInterface(IID_IPersistStream, (void**)&pIChordTrackStream);
  1720. if (!SUCCEEDED(hr)) goto ON_END;
  1721. StreamSeek(pIChordStream, 0, STREAM_SEEK_SET);
  1722. hr = pIChordTrackStream->Load(pIChordStream);
  1723. if (!SUCCEEDED(hr)) goto ON_END;
  1724. }
  1725. ON_END:
  1726. if (pIChordTrack) pIChordTrack->Release();
  1727. if (pChordRIFF) pChordRIFF->Release();
  1728. if (pIChordStream) pIChordStream->Release();
  1729. if (pIChordTrackStream) pIChordTrackStream->Release();
  1730. return hr;
  1731. }
  1732. HRESULT CDMCompos::CopySegment(IDirectMusicSegment* pTempSeg,
  1733. IDirectMusicSegment** ppSectionSeg,
  1734. TList<PlayChord>& PlayList,
  1735. IDirectMusicStyle* pStyle,
  1736. IDirectMusicChordMap* pChordMap,
  1737. BOOL fStyleFromTrack,
  1738. BOOL fChordMapFromTrack,
  1739. DWORD dwGroupBits,
  1740. BYTE bRoot, DWORD dwScale)
  1741. {
  1742. if (!ppSectionSeg) return E_INVALIDARG;
  1743. HRESULT hr = S_OK;
  1744. IDirectMusicTrack* pIChordTrack = NULL;
  1745. IAARIFFStream* pChordRIFF = NULL;
  1746. IStream* pIChordStream = NULL;
  1747. IPersistStream* pIChordTrackStream = NULL;
  1748. IDirectMusicTrack* pIStyleTrack = NULL;
  1749. IDirectMusicTrack* pIChordMapTrack = NULL;
  1750. IDirectMusicTrack* pDMTrack = NULL;
  1751. IDirectMusicTrack* pBandTrack = NULL;
  1752. IDirectMusicBand* pBand = NULL;
  1753. long nClocks = 0;
  1754. DMUS_BAND_PARAM DMBandParam;
  1755. DWORD dwStyleGroupBits = 1;
  1756. if (UsingDX8(pStyle, pChordMap))
  1757. {
  1758. for (int i = 0; i < 32; i++)
  1759. {
  1760. if (dwGroupBits & (1 << i))
  1761. {
  1762. dwStyleGroupBits = 1 << i;
  1763. break;
  1764. }
  1765. }
  1766. }
  1767. else
  1768. {
  1769. dwGroupBits = 1;
  1770. }
  1771. pTempSeg->GetLength(&nClocks);
  1772. /////////////////////////////////////////////////////////////
  1773. // clone the template segment to get a section segment
  1774. hr = pTempSeg->Clone(0, nClocks, ppSectionSeg);
  1775. if (!SUCCEEDED(hr)) goto ON_END;
  1776. // Extract the style's time signature.
  1777. DMUS_TIMESIGNATURE TimeSig;
  1778. pStyle->GetTimeSignature(&TimeSig);
  1779. // Convert PlayList into a Chord Track
  1780. if (PlayList.GetHead())
  1781. {
  1782. hr = ::CoCreateInstance(
  1783. CLSID_DirectMusicChordTrack,
  1784. NULL,
  1785. CLSCTX_INPROC,
  1786. IID_IDirectMusicTrack,
  1787. (void**)&pIChordTrack
  1788. );
  1789. if (!SUCCEEDED(hr)) goto ON_END;
  1790. hr = CreateStreamOnHGlobal(NULL, TRUE, &pIChordStream);
  1791. if (S_OK != hr) goto ON_END;
  1792. hr = AllocRIFFStream( pIChordStream, &pChordRIFF);
  1793. if (S_OK != hr) goto ON_END;
  1794. SaveChordList(pChordRIFF, PlayList, bRoot, dwScale, TimeSig);
  1795. hr = pIChordTrack->QueryInterface(IID_IPersistStream, (void**)&pIChordTrackStream);
  1796. if (!SUCCEEDED(hr)) goto ON_END;
  1797. StreamSeek(pIChordStream, 0, STREAM_SEEK_SET);
  1798. hr = pIChordTrackStream->Load(pIChordStream);
  1799. if (!SUCCEEDED(hr)) goto ON_END;
  1800. (*ppSectionSeg)->InsertTrack(pIChordTrack, dwGroupBits);
  1801. }
  1802. // If the passed-in Style is not from the template segment,
  1803. // remove all style tracks from the new segment and add a new Style track.
  1804. if (!fStyleFromTrack)
  1805. {
  1806. do
  1807. {
  1808. hr = (*ppSectionSeg)->GetTrack(CLSID_DirectMusicStyleTrack, ALL_TRACK_GROUPS, 0, &pIStyleTrack);
  1809. if (S_OK == hr)
  1810. {
  1811. (*ppSectionSeg)->RemoveTrack(pIStyleTrack);
  1812. pIStyleTrack->Release();
  1813. }
  1814. } while (S_OK == hr);
  1815. hr = ::CoCreateInstance(
  1816. CLSID_DirectMusicStyleTrack,
  1817. NULL,
  1818. CLSCTX_INPROC,
  1819. IID_IDirectMusicTrack,
  1820. (void**)&pIStyleTrack
  1821. );
  1822. if (FAILED(hr)) goto ON_END;
  1823. pIStyleTrack->SetParam(GUID_IDirectMusicStyle, 0, (void*)pStyle);
  1824. (*ppSectionSeg)->InsertTrack(pIStyleTrack, dwStyleGroupBits);
  1825. }
  1826. // If the passed-in ChordMap is not from the template segment,
  1827. // remove all ChordMap tracks from the new segment and add a new ChordMap track.
  1828. if (!fChordMapFromTrack)
  1829. {
  1830. do
  1831. {
  1832. hr = (*ppSectionSeg)->GetTrack(CLSID_DirectMusicChordMapTrack, ALL_TRACK_GROUPS, 0, &pIChordMapTrack);
  1833. if (S_OK == hr)
  1834. {
  1835. (*ppSectionSeg)->RemoveTrack(pIChordMapTrack);
  1836. pIChordMapTrack->Release();
  1837. }
  1838. } while (S_OK == hr);
  1839. hr = ::CoCreateInstance(
  1840. CLSID_DirectMusicChordMapTrack,
  1841. NULL,
  1842. CLSCTX_INPROC,
  1843. IID_IDirectMusicTrack,
  1844. (void**)&pIChordMapTrack
  1845. );
  1846. if (FAILED(hr)) goto ON_END;
  1847. pIChordMapTrack->SetParam(GUID_IDirectMusicChordMap, 0, (void*)pChordMap);
  1848. (*ppSectionSeg)->InsertTrack(pIChordMapTrack, dwGroupBits);
  1849. }
  1850. // if there's no tempo track in the template segment, create one and add it
  1851. if (FAILED(pTempSeg->GetTrack(CLSID_DirectMusicTempoTrack, ALL_TRACK_GROUPS, 0, &pDMTrack)))
  1852. {
  1853. // Create a Tempo Track in which to store the tempo events
  1854. DMUS_TEMPO_PARAM tempo;
  1855. tempo.mtTime = 0; //ConvertTime( dwTime );
  1856. pStyle->GetTempo(&tempo.dblTempo);
  1857. if( SUCCEEDED( CoCreateInstance( CLSID_DirectMusicTempoTrack,
  1858. NULL, CLSCTX_INPROC, IID_IDirectMusicTrack,
  1859. (void**)&pDMTrack )))
  1860. {
  1861. if ( SUCCEEDED(pDMTrack->SetParam(GUID_TempoParam, 0, &tempo)) )
  1862. {
  1863. (*ppSectionSeg)->InsertTrack( pDMTrack, dwGroupBits );
  1864. }
  1865. }
  1866. }
  1867. // if there's no band track in the template segment, create one and add it
  1868. if (FAILED(pTempSeg->GetTrack(CLSID_DirectMusicBandTrack, ALL_TRACK_GROUPS, 0, &pBandTrack)))
  1869. {
  1870. // Create band track
  1871. hr = ::CoCreateInstance(
  1872. CLSID_DirectMusicBandTrack,
  1873. NULL,
  1874. CLSCTX_INPROC,
  1875. IID_IDirectMusicTrack,
  1876. (void**)&pBandTrack
  1877. );
  1878. if(!SUCCEEDED(hr)) goto ON_END;
  1879. // Load default band from style into track
  1880. // If for some reason the style doesn't have a default band (could happend
  1881. // if the style came from a pattern track), don't make a band track.
  1882. if (pStyle->GetDefaultBand(&pBand) == S_OK)
  1883. {
  1884. DMBandParam.mtTimePhysical = -64;
  1885. DMBandParam.pBand = pBand;
  1886. hr = pBandTrack->SetParam(GUID_BandParam, 0, (void*)&DMBandParam);
  1887. if (!SUCCEEDED(hr)) goto ON_END;
  1888. (*ppSectionSeg)->InsertTrack(pBandTrack, dwGroupBits);
  1889. }
  1890. }
  1891. // Initialize the segment
  1892. (*ppSectionSeg)->SetRepeats(0); // still needed for dx7
  1893. TraceI(4, "Segment Length: %d\n", nClocks);
  1894. (*ppSectionSeg)->SetLength(nClocks);
  1895. if (UsingDX8(pStyle, pChordMap))
  1896. {
  1897. DWORD dwLoopRepeats = 0;
  1898. pTempSeg->GetRepeats( &dwLoopRepeats );
  1899. (*ppSectionSeg)->SetRepeats( dwLoopRepeats );
  1900. MUSIC_TIME mtLoopStart = 0, mtLoopEnd = 0;
  1901. pTempSeg->GetLoopPoints( &mtLoopStart, &mtLoopEnd );
  1902. (*ppSectionSeg)->SetLoopPoints( mtLoopStart, mtLoopEnd );
  1903. }
  1904. ON_END:
  1905. if (pIChordTrack) pIChordTrack->Release();
  1906. if (pChordRIFF) pChordRIFF->Release();
  1907. if (pIChordStream) pIChordStream->Release();
  1908. if (pIChordTrackStream) pIChordTrackStream->Release();
  1909. if (pDMTrack)
  1910. {
  1911. // This releases the Addref made either by GetTrack or (if GetTrack failed)
  1912. // by CoCreateInstance
  1913. pDMTrack->Release();
  1914. }
  1915. if (pBandTrack)
  1916. {
  1917. // This releases the Addref made either by GetTrack or (if GetTrack failed)
  1918. // by CoCreateInstance
  1919. pBandTrack->Release();
  1920. }
  1921. if (pIStyleTrack) pIStyleTrack->Release();
  1922. if (pIChordMapTrack) pIChordMapTrack->Release();
  1923. if (pBand) pBand->Release();
  1924. return hr;
  1925. }
  1926. HRESULT CDMCompos::BuildSegment(TList<TemplateCommand>& CommandList,
  1927. TList<PlayChord>& PlayList,
  1928. IDirectMusicStyle* pStyle,
  1929. IDirectMusicChordMap* pChordMap,
  1930. long lMeasures,
  1931. IDirectMusicSegment** ppSectionSeg,
  1932. BYTE bRoot, DWORD dwScale,
  1933. double* pdblTempo,
  1934. IDirectMusicBand* pCurrentBand,
  1935. bool fAlign,
  1936. IDirectMusicGraph* pGraph,
  1937. IUnknown* pPath)
  1938. {
  1939. if (!ppSectionSeg) return E_INVALIDARG;
  1940. HRESULT hr = S_OK;
  1941. IDirectMusicTrack* pIChordTrack = NULL;
  1942. IAARIFFStream* pChordRIFF = NULL;
  1943. IStream* pIChordStream = NULL;
  1944. IPersistStream* pIChordTrackStream = NULL;
  1945. IDirectMusicTrack* pICommandTrack = NULL;
  1946. IAARIFFStream* pCommandRIFF = NULL;
  1947. IStream* pICommandStream = NULL;
  1948. IPersistStream* pICommandTrackStream = NULL;
  1949. IDirectMusicTrack* pIMarkerTrack = NULL;
  1950. IAARIFFStream* pMarkerRIFF = NULL;
  1951. IStream* pIMarkerStream = NULL;
  1952. IPersistStream* pIMarkerTrackStream = NULL;
  1953. IDirectMusicTrack* pIStyleTrack = NULL;
  1954. IDirectMusicTrack* pIChordMapTrack = NULL;
  1955. IDirectMusicTrack* pDMTrack = NULL;
  1956. IDirectMusicTrack* pBandTrack = NULL;
  1957. IDirectMusicBand* pBand = NULL;
  1958. long nClocks = 0;
  1959. DMUS_BAND_PARAM DMBandParam;
  1960. // create a section segment
  1961. hr = ::CoCreateInstance(
  1962. CLSID_DirectMusicSegment,
  1963. NULL,
  1964. CLSCTX_INPROC,
  1965. IID_IDirectMusicSegment,
  1966. (void**)ppSectionSeg
  1967. );
  1968. if (!SUCCEEDED(hr)) goto ON_END;
  1969. // Extract the style's time signature.
  1970. DMUS_TIMESIGNATURE TimeSig;
  1971. pStyle->GetTimeSignature(&TimeSig);
  1972. nClocks = (lMeasures) * TimeSig.bBeatsPerMeasure * (DMUS_PPQ * 4 / TimeSig.bBeat);
  1973. // Convert PlayList into a Chord Track
  1974. if (PlayList.GetHead())
  1975. {
  1976. hr = ::CoCreateInstance(
  1977. CLSID_DirectMusicChordTrack,
  1978. NULL,
  1979. CLSCTX_INPROC,
  1980. IID_IDirectMusicTrack,
  1981. (void**)&pIChordTrack
  1982. );
  1983. if (!SUCCEEDED(hr)) goto ON_END;
  1984. hr = CreateStreamOnHGlobal(NULL, TRUE, &pIChordStream);
  1985. if (S_OK != hr) goto ON_END;
  1986. hr = AllocRIFFStream( pIChordStream, &pChordRIFF);
  1987. if (S_OK != hr) goto ON_END;
  1988. SaveChordList(pChordRIFF, PlayList, bRoot, dwScale, TimeSig);
  1989. hr = pIChordTrack->QueryInterface(IID_IPersistStream, (void**)&pIChordTrackStream);
  1990. if (!SUCCEEDED(hr)) goto ON_END;
  1991. StreamSeek(pIChordStream, 0, STREAM_SEEK_SET);
  1992. hr = pIChordTrackStream->Load(pIChordStream);
  1993. if (!SUCCEEDED(hr)) goto ON_END;
  1994. }
  1995. // Convert CommandList into a Command Track
  1996. hr = ::CoCreateInstance(
  1997. CLSID_DirectMusicCommandTrack,
  1998. NULL,
  1999. CLSCTX_INPROC,
  2000. IID_IDirectMusicTrack,
  2001. (void**)&pICommandTrack
  2002. );
  2003. if (!SUCCEEDED(hr)) goto ON_END;
  2004. hr = CreateStreamOnHGlobal(NULL, TRUE, &pICommandStream);
  2005. if (S_OK != hr) goto ON_END;
  2006. hr = AllocRIFFStream( pICommandStream, &pCommandRIFF);
  2007. if (S_OK != hr) goto ON_END;
  2008. SaveCommandList(pCommandRIFF, CommandList, TimeSig);
  2009. hr = pICommandTrack->QueryInterface(IID_IPersistStream, (void**)&pICommandTrackStream);
  2010. if (!SUCCEEDED(hr)) goto ON_END;
  2011. StreamSeek(pICommandStream, 0, STREAM_SEEK_SET);
  2012. hr = pICommandTrackStream->Load(pICommandStream);
  2013. if (!SUCCEEDED(hr)) goto ON_END;
  2014. // If the align flag's been set, create a marker track
  2015. if (fAlign)
  2016. {
  2017. TListItem<TemplateCommand>* pCommandItem = CommandList.GetHead();
  2018. IDMStyle* pDMStyle = NULL;
  2019. if (pCommandItem &&
  2020. pStyle &&
  2021. SUCCEEDED(pStyle->QueryInterface(IID_IDMStyle, (void**) &pDMStyle)))
  2022. {
  2023. hr = ::CoCreateInstance(
  2024. CLSID_DirectMusicMarkerTrack,
  2025. NULL,
  2026. CLSCTX_INPROC,
  2027. IID_IDirectMusicTrack,
  2028. (void**)&pIMarkerTrack
  2029. );
  2030. if (!SUCCEEDED(hr))
  2031. {
  2032. pDMStyle->Release();
  2033. goto ON_END;
  2034. }
  2035. hr = CreateStreamOnHGlobal(NULL, TRUE, &pIMarkerStream);
  2036. if (S_OK != hr)
  2037. {
  2038. pDMStyle->Release();
  2039. goto ON_END;
  2040. }
  2041. hr = AllocRIFFStream( pIMarkerStream, &pMarkerRIFF);
  2042. if (S_OK != hr)
  2043. {
  2044. pDMStyle->Release();
  2045. goto ON_END;
  2046. }
  2047. hr = SaveStartMarkers(pMarkerRIFF, pCommandItem->GetItemValue(), pDMStyle);
  2048. // If the above fails, it means the style doesn't have any markers, so just
  2049. // continue without creating a marker track.
  2050. if (SUCCEEDED(hr))
  2051. {
  2052. hr = pIMarkerTrack->QueryInterface(IID_IPersistStream, (void**)&pIMarkerTrackStream);
  2053. if (!SUCCEEDED(hr))
  2054. {
  2055. pDMStyle->Release();
  2056. goto ON_END;
  2057. }
  2058. StreamSeek(pIMarkerStream, 0, STREAM_SEEK_SET);
  2059. hr = pIMarkerTrackStream->Load(pIMarkerStream);
  2060. if (!SUCCEEDED(hr))
  2061. {
  2062. pDMStyle->Release();
  2063. goto ON_END;
  2064. }
  2065. }
  2066. pDMStyle->Release();
  2067. }
  2068. }
  2069. // Use the passed-in Style to create a Style Track
  2070. hr = ::CoCreateInstance(
  2071. CLSID_DirectMusicStyleTrack,
  2072. NULL,
  2073. CLSCTX_INPROC,
  2074. IID_IDirectMusicTrack,
  2075. (void**)&pIStyleTrack
  2076. );
  2077. if (FAILED(hr)) goto ON_END;
  2078. pIStyleTrack->SetParam(GUID_IDirectMusicStyle, 0, (void*)pStyle);
  2079. // Use the passed-in ChordMap to create a ChordMap Track
  2080. hr = ::CoCreateInstance(
  2081. CLSID_DirectMusicChordMapTrack,
  2082. NULL,
  2083. CLSCTX_INPROC,
  2084. IID_IDirectMusicTrack,
  2085. (void**)&pIChordMapTrack
  2086. );
  2087. if (FAILED(hr)) goto ON_END;
  2088. pIChordMapTrack->SetParam(GUID_IDirectMusicChordMap, 0, (void*)pChordMap);
  2089. // Create a Tempo Track in which to store the tempo events
  2090. ////////////////////////////////////////////////////////////
  2091. DMUS_TEMPO_PARAM tempo;
  2092. tempo.mtTime = 0; //ConvertTime( dwTime );
  2093. if (!pdblTempo)
  2094. {
  2095. pStyle->GetTempo(&tempo.dblTempo);
  2096. }
  2097. else
  2098. {
  2099. tempo.dblTempo = *pdblTempo;
  2100. }
  2101. ////////////////////////////////////////////////////////////
  2102. if( SUCCEEDED( CoCreateInstance( CLSID_DirectMusicTempoTrack,
  2103. NULL, CLSCTX_INPROC, IID_IDirectMusicTrack,
  2104. (void**)&pDMTrack )))
  2105. {
  2106. if ( SUCCEEDED(pDMTrack->SetParam(GUID_TempoParam, 0, &tempo)) )
  2107. {
  2108. (*ppSectionSeg)->InsertTrack( pDMTrack, 1 );
  2109. }
  2110. }
  2111. // Create a new band track.
  2112. hr = ::CoCreateInstance(
  2113. CLSID_DirectMusicBandTrack,
  2114. NULL,
  2115. CLSCTX_INPROC,
  2116. IID_IDirectMusicTrack,
  2117. (void**)&pBandTrack
  2118. );
  2119. if(!SUCCEEDED(hr)) goto ON_END;
  2120. // Add either the band passed in, or the style's default band.
  2121. if (pCurrentBand)
  2122. {
  2123. pBand = pCurrentBand;
  2124. pBand->AddRef(); // Needed because we release the band before returning
  2125. }
  2126. else
  2127. {
  2128. hr = pStyle->GetDefaultBand(&pBand);
  2129. }
  2130. DMBandParam.mtTimePhysical = -64;
  2131. DMBandParam.pBand = pBand;
  2132. hr = pBandTrack->SetParam(GUID_BandParam, 0, (void*)&DMBandParam);
  2133. if (!SUCCEEDED(hr)) goto ON_END;
  2134. // Initialize the segment and insert the above tracks
  2135. (*ppSectionSeg)->SetRepeats(0);
  2136. (*ppSectionSeg)->SetLength(nClocks);
  2137. (*ppSectionSeg)->InsertTrack(pBandTrack, 1);
  2138. (*ppSectionSeg)->InsertTrack(pIStyleTrack, 1);
  2139. (*ppSectionSeg)->InsertTrack(pIChordMapTrack, 1);
  2140. (*ppSectionSeg)->InsertTrack(pICommandTrack, 1);
  2141. if (pIMarkerTrack)
  2142. {
  2143. (*ppSectionSeg)->InsertTrack(pIMarkerTrack, 1);
  2144. }
  2145. if (pIChordTrack)
  2146. {
  2147. (*ppSectionSeg)->InsertTrack(pIChordTrack, 1);
  2148. }
  2149. // Add the graph
  2150. if (pGraph)
  2151. {
  2152. (*ppSectionSeg)->SetGraph(pGraph);
  2153. }
  2154. // Add the Audio Path
  2155. if (pPath)
  2156. {
  2157. IDirectMusicSegment8P* pSegP = NULL;
  2158. if (SUCCEEDED((*ppSectionSeg)->QueryInterface(IID_IDirectMusicSegment8P, (void**)&pSegP)))
  2159. {
  2160. pSegP->SetAudioPathConfig(pPath);
  2161. pSegP->Release();
  2162. }
  2163. }
  2164. ON_END:
  2165. if (pIChordTrack) pIChordTrack->Release();
  2166. if (pChordRIFF) pChordRIFF->Release();
  2167. if (pIChordStream) pIChordStream->Release();
  2168. if (pIChordTrackStream) pIChordTrackStream->Release();
  2169. if (pICommandTrack) pICommandTrack->Release();
  2170. if (pCommandRIFF) pCommandRIFF->Release();
  2171. if (pICommandStream) pICommandStream->Release();
  2172. if (pICommandTrackStream) pICommandTrackStream->Release();
  2173. if (pDMTrack) pDMTrack->Release();
  2174. if (pBandTrack) pBandTrack->Release();
  2175. if (pIStyleTrack) pIStyleTrack->Release();
  2176. if (pIMarkerTrack) pIMarkerTrack->Release();
  2177. if (pMarkerRIFF) pMarkerRIFF->Release();
  2178. if (pIMarkerStream) pIMarkerStream->Release();
  2179. if (pIMarkerTrackStream) pIMarkerTrackStream->Release();
  2180. if (pIChordMapTrack) pIChordMapTrack->Release();
  2181. if (pBand) pBand->Release();
  2182. return hr;
  2183. }
  2184. void ChangeCommand(DMUS_COMMAND_PARAM& rResult, DMUS_COMMAND_PARAM& rCommand, int nDirection)
  2185. {
  2186. BYTE bGrooveLevel = 0;
  2187. BYTE bRiff = 0;
  2188. if (nDirection > 0)
  2189. {
  2190. while (nDirection > 0)
  2191. {
  2192. switch (rCommand.bGrooveLevel)
  2193. {
  2194. case 12 : bGrooveLevel = 37; break;
  2195. case 37 : bGrooveLevel = 62; break;
  2196. case 62 : bGrooveLevel = 87; break;
  2197. case 87 : bGrooveLevel = 87; break;
  2198. default: bGrooveLevel = rCommand.bGrooveLevel;
  2199. }
  2200. switch (rCommand.bCommand)
  2201. {
  2202. case DMUS_COMMANDT_FILL : bRiff = DMUS_COMMANDT_FILL; break;
  2203. case DMUS_COMMANDT_BREAK : bRiff = DMUS_COMMANDT_FILL; break;
  2204. default: bRiff = rCommand.bCommand;
  2205. }
  2206. rResult.bGrooveLevel = bGrooveLevel;
  2207. rResult.bCommand = bRiff;
  2208. nDirection--;
  2209. }
  2210. }
  2211. else if (nDirection == 0)
  2212. {
  2213. rResult.bGrooveLevel = rCommand.bGrooveLevel;
  2214. rResult.bCommand = rCommand.bCommand;
  2215. }
  2216. else if (nDirection < 0)
  2217. {
  2218. while (nDirection < 0)
  2219. {
  2220. switch (rCommand.bGrooveLevel)
  2221. {
  2222. case 12 : bGrooveLevel = 12; break;
  2223. case 37 : bGrooveLevel = 12; break;
  2224. case 62 : bGrooveLevel = 37; break;
  2225. case 87 : bGrooveLevel = 62; break;
  2226. default: bGrooveLevel = rCommand.bGrooveLevel;
  2227. }
  2228. switch (rCommand.bCommand)
  2229. {
  2230. case DMUS_COMMANDT_FILL : bRiff = DMUS_COMMANDT_BREAK; break;
  2231. case DMUS_COMMANDT_BREAK : bRiff = DMUS_COMMANDT_BREAK; break;
  2232. default: bRiff = rCommand.bCommand;
  2233. }
  2234. rResult.bGrooveLevel = bGrooveLevel;
  2235. rResult.bCommand = bRiff;
  2236. nDirection++;
  2237. }
  2238. }
  2239. }
  2240. static void InsertStuff(int nMeasure,
  2241. TListItem<TemplateCommand> *pCommands,
  2242. TListItem<PlayChord> *pPlayChord,
  2243. TList<TemplateCommand> &rCommandList,
  2244. TList<PlayChord> &rChordList,
  2245. int nDirection)
  2246. {
  2247. for(; pCommands; pCommands = pCommands->GetNext())
  2248. {
  2249. TemplateCommand& rCommand = pCommands->GetItemValue();
  2250. TListItem<TemplateCommand> *pNew = new TListItem<TemplateCommand>;
  2251. if (pNew)
  2252. {
  2253. TemplateCommand& rNew = pNew->GetItemValue();
  2254. rNew.m_nMeasure = rCommand.m_nMeasure + (short)nMeasure;
  2255. ChangeCommand(rNew.m_Command, rCommand.m_Command, nDirection);
  2256. rNew.m_dwChord = rCommand.m_dwChord;
  2257. rCommandList.AddHead(pNew);
  2258. }
  2259. }
  2260. for (; pPlayChord; pPlayChord = pPlayChord->GetNext())
  2261. {
  2262. PlayChord& rChord = pPlayChord->GetItemValue();
  2263. TListItem<PlayChord>* pNew = new TListItem<PlayChord>;
  2264. if (pNew)
  2265. {
  2266. PlayChord& rNew = pNew->GetItemValue();
  2267. rNew.m_fSilent = rChord.m_fSilent;
  2268. rNew.m_pChord = rChord.m_pChord;
  2269. rNew.m_pNext = rChord.m_pNext;
  2270. rNew.m_dwFlags = rChord.m_dwFlags;
  2271. rNew.m_nMeasure = rChord.m_nMeasure + (short)nMeasure;
  2272. rNew.m_nBeat = rChord.m_nBeat;
  2273. rNew.m_nMinbeats = rChord.m_nMinbeats;
  2274. rNew.m_nMaxbeats = rChord.m_nMaxbeats;
  2275. rChordList.AddHead(pNew);
  2276. }
  2277. }
  2278. }
  2279. void InsertCommand(int nMeasure, int nLength, TList<TemplateCommand> &rCommandList, BYTE bCommand)
  2280. {
  2281. // insert nLength bars before nMeasure
  2282. nMeasure -= nLength;
  2283. TListItem<TemplateCommand> *pTarget = NULL;
  2284. TListItem<TemplateCommand> *pCommand = rCommandList.GetHead();
  2285. for (; pCommand; pCommand = pCommand->GetNext())
  2286. {
  2287. TemplateCommand& rCommand = pCommand->GetItemValue();
  2288. if (rCommand.m_nMeasure == nMeasure)
  2289. {
  2290. pTarget = pCommand;
  2291. }
  2292. // return if another command would interupt this one
  2293. else if ( (rCommand.m_Command.bCommand || rCommand.m_Command.bGrooveLevel) &&
  2294. (rCommand.m_nMeasure > nMeasure) &&
  2295. (rCommand.m_nMeasure < nMeasure + nLength) )
  2296. {
  2297. return;
  2298. }
  2299. }
  2300. if (pTarget)
  2301. {
  2302. pTarget->GetItemValue().m_Command.bCommand = bCommand;
  2303. }
  2304. else
  2305. {
  2306. pCommand = new TListItem<TemplateCommand>;
  2307. if (pCommand)
  2308. {
  2309. TemplateCommand& rCommand = pCommand->GetItemValue();
  2310. rCommand.m_nMeasure = (short)nMeasure;
  2311. rCommand.m_Command.bCommand = bCommand;
  2312. rCommandList.AddHead(pCommand);
  2313. }
  2314. }
  2315. }
  2316. int WeightedRand(int nRange);
  2317. HRESULT CDMCompos::ComposePlayListFromShape(
  2318. long lNumMeasures,
  2319. WORD wShape,
  2320. BOOL fComposeIntro,
  2321. BOOL fComposeEnding,
  2322. int nIntroLength,
  2323. int nFillLength,
  2324. int nBreakLength,
  2325. int nEndLength,
  2326. IDirectMusicStyle* pStyle,
  2327. WORD wActivity,
  2328. IDirectMusicChordMap* pPersonality,
  2329. TList<TemplateCommand>& CommandList,
  2330. TList<PlayChord>& PlayList
  2331. )
  2332. {
  2333. HRESULT hr = S_OK;
  2334. TListItem<TemplateCommand>* pCommand = NULL;
  2335. int nOriginalMeasures = 0;
  2336. if (fComposeIntro)
  2337. {
  2338. lNumMeasures -= nIntroLength;
  2339. if (lNumMeasures < 1)
  2340. {
  2341. lNumMeasures = 1;
  2342. }
  2343. }
  2344. if (fComposeEnding)
  2345. {
  2346. int nLength = nEndLength;
  2347. nOriginalMeasures = (int)lNumMeasures;
  2348. lNumMeasures -= (nLength - 1);
  2349. if (lNumMeasures < 1)
  2350. {
  2351. lNumMeasures = 1;
  2352. }
  2353. }
  2354. TemplateStruct Template;
  2355. TemplateStruct* apTempl[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  2356. if ((wShape != DMUS_SHAPET_SONG) || (lNumMeasures <= 24))
  2357. {
  2358. if (wShape == DMUS_SHAPET_LOOPABLE) lNumMeasures++;
  2359. Template.m_nMeasures = (short)lNumMeasures;
  2360. Template.CreateSignPosts();
  2361. Template.CreateEmbellishments(wShape, nFillLength, nBreakLength);
  2362. if (wShape == DMUS_SHAPET_LOOPABLE)
  2363. {
  2364. lNumMeasures--;
  2365. Template.m_nMeasures = (short)lNumMeasures;
  2366. }
  2367. ComposePlayList(PlayList, pStyle, pPersonality, Template.m_CommandList, wActivity);
  2368. }
  2369. else
  2370. {
  2371. short nShortestLength = 12; // initialized to longest value in sanLengths
  2372. TListItem<TemplateCommand> *apCommands[8];
  2373. TList<PlayChord> aPlayList[8];
  2374. TListItem<PlayChord>* apChords[8];
  2375. int anLengths[8];
  2376. int anGrooveLevel[8];
  2377. int anPlayCount[8];
  2378. BYTE abLeadins[8];
  2379. int nTypeCount = 2;
  2380. unsigned int nSize = (unsigned int) lNumMeasures >> 5;
  2381. int nTypeIndex;
  2382. int nMeasure;
  2383. int nChoice, nLastChoice;
  2384. while (nSize)
  2385. {
  2386. nTypeCount++;
  2387. nSize = nSize >> 1;
  2388. if (nTypeCount >= 8) break;
  2389. }
  2390. for (nTypeIndex = 1; nTypeIndex < nTypeCount; nTypeIndex++)
  2391. {
  2392. static WORD awShapes[8] = {
  2393. DMUS_SHAPET_FALLING, DMUS_SHAPET_LEVEL, DMUS_SHAPET_LOUD, DMUS_SHAPET_QUIET,
  2394. DMUS_SHAPET_RANDOM, DMUS_SHAPET_RANDOM, DMUS_SHAPET_RANDOM, DMUS_SHAPET_RANDOM };
  2395. static int anInitGroovels[8] = { 0,-1,0,0,1,-1,2,-2 };
  2396. static BYTE abRiffs[8] = {
  2397. DMUS_COMMANDT_FILL, DMUS_COMMANDT_BREAK, DMUS_COMMANDT_FILL, DMUS_COMMANDT_BREAK,
  2398. DMUS_COMMANDT_FILL, DMUS_COMMANDT_FILL, DMUS_COMMANDT_BREAK, DMUS_COMMANDT_FILL };
  2399. static short sanLengths[10] = { 8,8,8,8,6,12,8,8,10,6 };
  2400. short nLength = sanLengths[rand() % 10];
  2401. apTempl[nTypeIndex] = new TemplateStruct;
  2402. if (!apTempl[nTypeIndex])
  2403. {
  2404. hr = E_OUTOFMEMORY;
  2405. goto ON_END;
  2406. }
  2407. apTempl[nTypeIndex]->m_nMeasures = nLength;
  2408. anLengths[nTypeIndex] = nLength;
  2409. if (nLength)
  2410. {
  2411. if (nShortestLength > nLength) nShortestLength = nLength;
  2412. apTempl[nTypeIndex]->CreateSignPosts();
  2413. apTempl[nTypeIndex]->CreateEmbellishments(awShapes[nTypeIndex], nFillLength, nBreakLength);
  2414. ComposePlayList(
  2415. aPlayList[nTypeIndex], pStyle, pPersonality, apTempl[nTypeIndex]->m_CommandList, wActivity);
  2416. apCommands[nTypeIndex] = apTempl[nTypeIndex]->m_CommandList.GetHead();
  2417. apChords[nTypeIndex] = aPlayList[nTypeIndex].GetHead();
  2418. anPlayCount[nTypeIndex] = 0;
  2419. anGrooveLevel[nTypeIndex] = anInitGroovels[nTypeIndex];
  2420. if (rand() % 4) abLeadins[nTypeIndex] = abRiffs[nTypeIndex];
  2421. else abLeadins[nTypeIndex] = 0;
  2422. }
  2423. else
  2424. {
  2425. apCommands[nTypeIndex] = NULL;
  2426. }
  2427. }
  2428. anPlayCount[0] = 1;
  2429. anGrooveLevel[0] = 0;
  2430. Template.m_nMeasures = (short)lNumMeasures;
  2431. nMeasure = 0;
  2432. nChoice = 1;
  2433. nLastChoice = 0;
  2434. for (; nMeasure < lNumMeasures; )
  2435. {
  2436. int nGroove;
  2437. int nNewChoice;
  2438. if ((lNumMeasures - nMeasure) <= nShortestLength)
  2439. {
  2440. nChoice = 0;
  2441. short nLength = (short) (lNumMeasures - nMeasure);
  2442. apTempl[0] = new TemplateStruct;
  2443. if (!apTempl[0])
  2444. {
  2445. hr = E_OUTOFMEMORY;
  2446. goto ON_END;
  2447. }
  2448. apTempl[0]->m_nMeasures = nLength;
  2449. anLengths[0] = nLength;
  2450. apTempl[0]->CreateSignPosts();
  2451. apTempl[0]->CreateEmbellishments(DMUS_SHAPET_FALLING, nFillLength, nBreakLength);
  2452. ComposePlayList(
  2453. aPlayList[0], pStyle, pPersonality, apTempl[0]->m_CommandList, wActivity);
  2454. apCommands[0] = apTempl[0]->m_CommandList.GetHead();
  2455. apChords[0] = aPlayList[0].GetHead();
  2456. anPlayCount[0] = 0;
  2457. anGrooveLevel[0] = 0;
  2458. if (rand() % 4) abLeadins[0] = DMUS_COMMANDT_FILL;
  2459. else abLeadins[0] = 0;
  2460. }
  2461. nGroove = anGrooveLevel[nChoice];
  2462. InsertStuff(nMeasure, apCommands[nChoice], apChords[nChoice],
  2463. Template.m_CommandList, PlayList, nGroove);
  2464. if ( (abLeadins[nChoice] == DMUS_COMMANDT_FILL && nMeasure >= nFillLength) )
  2465. {
  2466. InsertCommand(nMeasure, nFillLength, Template.m_CommandList, abLeadins[nChoice]);
  2467. }
  2468. else if ( (abLeadins[nChoice] == DMUS_COMMANDT_BREAK && nMeasure >= nBreakLength) )
  2469. {
  2470. InsertCommand(nMeasure, nBreakLength, Template.m_CommandList, abLeadins[nChoice]);
  2471. }
  2472. if (anGrooveLevel[nChoice] < 0) anGrooveLevel[nChoice]++;
  2473. else
  2474. {
  2475. if (rand() % 3)
  2476. {
  2477. if (rand() % 2)
  2478. {
  2479. anGrooveLevel[nChoice]++;
  2480. }
  2481. else
  2482. {
  2483. anGrooveLevel[nChoice]--;
  2484. }
  2485. }
  2486. }
  2487. anPlayCount[nChoice]++;
  2488. nMeasure += anLengths[nChoice];
  2489. nNewChoice = WeightedRand(nTypeCount - 1) + 1;
  2490. if ((nNewChoice == nChoice) && (nNewChoice == nLastChoice))
  2491. {
  2492. nNewChoice = WeightedRand(nTypeCount - 1) + 1;
  2493. }
  2494. if (nNewChoice == nChoice)
  2495. {
  2496. nNewChoice = WeightedRand(nTypeCount - 1) + 1;
  2497. }
  2498. // If there are enough measures for some but not all of the
  2499. // patterns, find a pattern that fits
  2500. if ((lNumMeasures - nMeasure) > nShortestLength)
  2501. {
  2502. while ((lNumMeasures - nMeasure) < anLengths[nNewChoice])
  2503. {
  2504. nNewChoice = WeightedRand(nTypeCount - 1) + 1;
  2505. }
  2506. }
  2507. nLastChoice = nChoice;
  2508. nChoice = nNewChoice;
  2509. }
  2510. Template.m_CommandList.MergeSort(Less);
  2511. PlayList.MergeSort(Less);
  2512. }
  2513. if (fComposeEnding)
  2514. {
  2515. int nLength = nEndLength;
  2516. if (lNumMeasures != nOriginalMeasures)
  2517. {
  2518. Template.m_nMeasures = (short)nOriginalMeasures;
  2519. }
  2520. if (nLength > nOriginalMeasures)
  2521. {
  2522. nLength = nOriginalMeasures;
  2523. }
  2524. Template.AddEnd(nLength);
  2525. }
  2526. if (fComposeIntro)
  2527. {
  2528. Template.AddIntro(PlayList, nIntroLength);
  2529. }
  2530. pCommand = Template.m_CommandList.GetHead();
  2531. for(; pCommand; pCommand = pCommand->GetNext())
  2532. {
  2533. TemplateCommand& rCommand = pCommand->GetItemValue();
  2534. if (rCommand.m_Command.bCommand || rCommand.m_Command.bGrooveLevel)
  2535. {
  2536. TListItem<TemplateCommand>* pNew = new TListItem<TemplateCommand>;
  2537. if (!pNew)
  2538. {
  2539. hr = E_OUTOFMEMORY;
  2540. goto ON_END;
  2541. }
  2542. pNew->GetItemValue().m_nMeasure = rCommand.m_nMeasure;
  2543. pNew->GetItemValue().m_Command = rCommand.m_Command;
  2544. pNew->GetItemValue().m_dwChord = rCommand.m_dwChord;
  2545. CommandList.AddTail(pNew);
  2546. }
  2547. }
  2548. ON_END:
  2549. for (short n = 0; n < 8; n++)
  2550. {
  2551. if (apTempl[n])
  2552. {
  2553. delete apTempl[n];
  2554. }
  2555. }
  2556. return hr;
  2557. }
  2558. static short ChordMisses(DWORD dwScalePattern, DWORD dwChordPattern, char chRoot)
  2559. {
  2560. short nErrors = 0;
  2561. dwScalePattern &= 0xFFF;
  2562. dwScalePattern |= (dwScalePattern << 12);
  2563. while (chRoot < 0) chRoot += 12;
  2564. while (chRoot > 11) chRoot -= 12;
  2565. dwChordPattern = dwChordPattern << chRoot;
  2566. for (short index = 0;index < 24;index++)
  2567. {
  2568. DWORD dwScaleBit = dwScalePattern & 1;
  2569. DWORD dwChordBit = dwChordPattern & 1;
  2570. dwScalePattern = dwScalePattern >> 1;
  2571. dwChordPattern = dwChordPattern >> 1;
  2572. if (dwChordBit && !dwScaleBit) nErrors++;
  2573. }
  2574. return(nErrors);
  2575. }
  2576. static short CompareSPToChord(DMSignPost& rSign,
  2577. DWORD dwLastScale,
  2578. DMChordData& rNextChord,
  2579. char chLastRoot)
  2580. {
  2581. BYTE bLastRoot = chLastRoot % 12;
  2582. short nResult = 50;
  2583. if (rNextChord.Equals(rSign.m_ChordData))
  2584. {
  2585. nResult = 0;
  2586. }
  2587. else if (rSign.m_dwChords & DMUS_SIGNPOSTF_1)
  2588. {
  2589. nResult = 25;
  2590. }
  2591. if (rSign.m_dwFlags & DMUS_SPOSTCADENCEF_1)
  2592. {
  2593. DMChordData& rChord = rSign.m_aCadence[0];
  2594. BYTE bOffset = rChord.GetRoot();
  2595. if (bOffset < bLastRoot) bOffset += 12;
  2596. nResult += ChordMisses(dwLastScale, rChord.GetChordPattern(), (bOffset - bLastRoot) % 12);
  2597. }
  2598. else if (rSign.m_dwFlags & DMUS_SPOSTCADENCEF_2)
  2599. {
  2600. DMChordData& rChord = rSign.m_aCadence[1];
  2601. BYTE bOffset = rChord.GetRoot();
  2602. if (bOffset < bLastRoot) bOffset += 12;
  2603. nResult += ChordMisses(dwLastScale, rChord.GetChordPattern(), (bOffset - bLastRoot) % 12);
  2604. }
  2605. else nResult += 30;
  2606. return (nResult);
  2607. }
  2608. static HRESULT ChordListFromSegment(TList<PlayChord>& ChordList, IDirectMusicSegment* pSeg,
  2609. BYTE &bRoot, DWORD &dwScale)
  2610. {
  2611. HRESULT hr = S_OK;
  2612. IDirectMusicTrack* pChordTrack = NULL;
  2613. IPersistStream* pPS = NULL;
  2614. IStream* pStream = NULL;
  2615. // Get the segment's chord track.
  2616. hr = pSeg->GetTrack(CLSID_DirectMusicChordTrack, ALL_TRACK_GROUPS, 0, &pChordTrack);
  2617. if (S_OK != hr) goto ON_END;
  2618. // Write the track to a stream, and read from the stream into a chord list.
  2619. hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
  2620. if (S_OK != hr) goto ON_END;
  2621. hr = pChordTrack->QueryInterface(IID_IPersistStream, (void**)&pPS);
  2622. if (S_OK != hr) goto ON_END;
  2623. hr = pPS->Save(pStream, FALSE);
  2624. if (S_OK != hr) goto ON_END;
  2625. StreamSeek(pStream, 0, STREAM_SEEK_SET);
  2626. LoadChordList(ChordList, pStream, bRoot, dwScale);
  2627. ON_END:
  2628. if (pStream) pStream->Release();
  2629. if (pChordTrack) pChordTrack->Release();
  2630. if (pPS) pPS->Release();
  2631. return hr;
  2632. }
  2633. static void Clear(TList<PlayChord>& ChordList)
  2634. {
  2635. for (TListItem<PlayChord>* pChord = ChordList.GetHead(); pChord; pChord = pChord->GetNext())
  2636. {
  2637. pChord->GetItemValue().m_pChord->Release();
  2638. delete pChord->GetItemValue().m_pChord;
  2639. }
  2640. }
  2641. static char TwelveToScale(DWORD dwPattern, char chRoot, char *pchOffset)
  2642. {
  2643. char i;
  2644. *pchOffset = 0;
  2645. char chResult = -1;
  2646. while (chRoot < 0) chRoot += 12;
  2647. while (chRoot >= 24) chRoot -= 12;
  2648. for (i=0;i<24;i++)
  2649. {
  2650. if ((dwPattern >> i) & 1)
  2651. {
  2652. chResult++;
  2653. *pchOffset = 0;
  2654. }
  2655. else
  2656. {
  2657. *pchOffset = (char)( *pchOffset + 1 );
  2658. }
  2659. if (i == chRoot)
  2660. {
  2661. return(chResult);
  2662. }
  2663. }
  2664. return(0);
  2665. }
  2666. static char ScaleToTwelve(DWORD dwPattern, char chRoot, char chOffset)
  2667. {
  2668. char i;
  2669. char chResult = 0;
  2670. while (chRoot < 0) chRoot += 7;
  2671. while (chRoot >= 14) chRoot -= 7;
  2672. for (i=0;i<24;i++)
  2673. {
  2674. if ((dwPattern >> i) & 1)
  2675. {
  2676. if (chResult == chRoot) break;
  2677. chResult++;
  2678. }
  2679. }
  2680. i = (char)( i + chOffset );
  2681. while (i >= 24) i -= 12; // RSW: fix for bug 173304
  2682. return(i);
  2683. }
  2684. /*HRESULT CDMCompos::GetStyle(IDirectMusicSegment* pFromSeg, MUSIC_TIME mt, DWORD dwGroupBits, IDirectMusicStyle*& rpStyle, bool fTryPattern)
  2685. {
  2686. HRESULT hr = S_OK;
  2687. // Get the segment's style track.
  2688. IDirectMusicTrack* pStyleTrack;
  2689. hr = pFromSeg->GetTrack(CLSID_DirectMusicStyleTrack, dwGroupBits, 0, &pStyleTrack);
  2690. if (S_OK != hr && fTryPattern)
  2691. {
  2692. hr = pFromSeg->GetTrack(CLSID_DirectMusicPatternTrack, dwGroupBits, 0, &pStyleTrack);
  2693. }
  2694. if (S_OK != hr) return hr;
  2695. // Get the style from the style track
  2696. hr = pStyleTrack->GetParam(GUID_IDirectMusicStyle, mt, NULL, (void*) &rpStyle);
  2697. pStyleTrack->Release();
  2698. return hr;
  2699. }*/
  2700. HRESULT CDMCompos::GetStyle(IDirectMusicSegment* pFromSeg, MUSIC_TIME mt, DWORD dwGroupBits, IDirectMusicStyle*& rpStyle, bool fTryPattern)
  2701. {
  2702. HRESULT hr = pFromSeg->GetParam(GUID_IDirectMusicStyle, dwGroupBits, 0, mt, NULL, &rpStyle);
  2703. if (S_OK != hr && fTryPattern)
  2704. {
  2705. hr = pFromSeg->GetParam(GUID_IDirectMusicPatternStyle, dwGroupBits, 0, mt, NULL, &rpStyle);
  2706. }
  2707. return hr;
  2708. }
  2709. HRESULT CDMCompos::GetPersonality(IDirectMusicSegment* pFromSeg, MUSIC_TIME mt, DWORD dwGroupBits, IDirectMusicChordMap*& rpPers)
  2710. {
  2711. HRESULT hr = S_OK;
  2712. // Get the segment's personality track.
  2713. IDirectMusicTrack* pPersTrack;
  2714. hr = pFromSeg->GetTrack(CLSID_DirectMusicChordMapTrack, dwGroupBits, 0, &pPersTrack);
  2715. if (S_OK != hr) return hr;
  2716. // Get the personality from the personality track
  2717. hr = pPersTrack->GetParam(GUID_IDirectMusicChordMap, mt, NULL, (void*) &rpPers);
  2718. pPersTrack->Release();
  2719. return hr;
  2720. }
  2721. HRESULT GetTempo(IDirectMusicSegment* pFromSeg, MUSIC_TIME mt, double* pdblTempo)
  2722. {
  2723. HRESULT hr = S_OK;
  2724. // Get the segment's tempo track.
  2725. IDirectMusicTrack* pTempoTrack;
  2726. hr = pFromSeg->GetTrack(CLSID_DirectMusicTempoTrack, ALL_TRACK_GROUPS, 0, &pTempoTrack);
  2727. if (S_OK != hr) return hr;
  2728. // Get the tempo from the tempo track
  2729. DMUS_TEMPO_PARAM Tempo;
  2730. hr = pTempoTrack->GetParam(GUID_TempoParam, mt, NULL, (void*) &Tempo);
  2731. pTempoTrack->Release();
  2732. if (SUCCEEDED(hr))
  2733. {
  2734. *pdblTempo = Tempo.dblTempo;
  2735. }
  2736. return hr;
  2737. }
  2738. /////////////////////////////////////////////////////////////////////////////
  2739. // IDirectMusicComposer
  2740. /*
  2741. @method:(EXTERNAL) HRESULT | IDirectMusicComposer | ComposeSegmentFromTemplate | Creates an
  2742. original section segment from a style, ChordMap, and template.
  2743. @rdesc Returns:
  2744. @flag S_OK | Success
  2745. @flag E_POINTER | One or both of <p pTempSeg> and
  2746. <p ppSectionSeg> is an invalid pointer.
  2747. @flag E_INVALIDARG | Either <p pStyle> is NULL and there is no Style track, or <p pChordMap>
  2748. is NULL and there is no ChordMap track.
  2749. @comm If <p pStyle> is non-NULL, it is used in composing the segment; if it is NULL,
  2750. a Style is retrieved from <p pTempSeg>'s Style track.
  2751. Similarly, if <p pChordMap> is non-NULL, it is used in composing the segment; if it is
  2752. NULL, a ChordMap is retrieved from <p pTempSeg>'s ChordMap track.
  2753. The length of the section segment is equal to the length of the template section
  2754. passed in.
  2755. */
  2756. /*
  2757. DX8 changes in track group bits, etc. (activated by dx8 content)
  2758. 0. The signpost track is used to determine dwCompositionGroupBits.
  2759. 1. Composed chords are placed in track groups dwCompositionGroupBits.
  2760. 2. If a style is passed in, all style ref tracks in the composed segment are removed (as before).
  2761. The new style is placed in the track group with the lowest value matching dwCompositionGroupBits.
  2762. If a chord map is passed in, all chord map ref tracks in the composed segment are removed (as
  2763. before). The new chord map is placed in track groups dwCompositionGroupBits.
  2764. 3. If the Style is pulled from a StyleRef track, the StyleRef tracks are copied from the template
  2765. segment. Ditto for chord maps. The StyleRef track used is the first one that matches
  2766. dwCompositionGroupBits. Ditto for chord maps.
  2767. 4. The groove track used is the first one that matches dwCompositionGroupBits.
  2768. 5. The time signature of the style chosen to compose with is the one used to determine chord
  2769. placement.
  2770. 6. If there are no tempo tracks in the template segment, one is created in track groups
  2771. dwCompositionGroupBits and the style's tempo is set to play at time 0.
  2772. 7. If there are no band tracks in the template segment, one is created in track groups
  2773. dwCompositionGroupBits and the style's default band is set to play at physical time -64,
  2774. logical time 0.
  2775. 8. Loops are handled correctly.
  2776. NOTE: Leaving other Composition methods as they are (they put everything in track group 1). It's
  2777. easy enough to change things programmatically, and since these segments are all created from scratch,
  2778. they don't rely on existing behavior in segments.
  2779. */
  2780. HRESULT CDMCompos::ComposeSegmentFromTemplate(
  2781. IDirectMusicStyle* pStyle, // @parm The style from which to create the section segment.
  2782. IDirectMusicSegment* pTempSeg, // @parm The template from which to create the section segment.
  2783. WORD wActivity, // @parm Specifies the rate of harmonic motion; valid values are 0 through 3.
  2784. IDirectMusicChordMap* pChordMap, // @parm The ChordMap from which to create the section segment.
  2785. IDirectMusicSegment** ppSectionSeg // @parm Returns the created section segment.
  2786. )
  2787. {
  2788. return ComposeSegmentFromTemplateEx(
  2789. pStyle,
  2790. pTempSeg,
  2791. (DMUS_COMPOSE_TEMPLATEF_ACTIVITY | DMUS_COMPOSE_TEMPLATEF_CLONE),
  2792. wActivity,
  2793. pChordMap,
  2794. ppSectionSeg
  2795. );
  2796. }
  2797. /////////////////////////////////////////////////////////////////////////////
  2798. // IDirectMusicComposer
  2799. /*
  2800. @method:(EXTERNAL) HRESULT | IDirectMusicComposer | ComposeSegmentFromTemplate | Creates an
  2801. original section segment from a style, ChordMap, and template.
  2802. @rdesc Returns:
  2803. @flag S_OK | Success
  2804. @flag E_POINTER | One or both of <p pTempSeg> and
  2805. <p ppSectionSeg> is an invalid pointer.
  2806. @flag E_INVALIDARG | Either <p pStyle> is NULL and there is no Style track, or <p pChordMap>
  2807. is NULL and there is no ChordMap track.
  2808. @comm If <p pStyle> is non-NULL, it is used in composing the segment; if it is NULL,
  2809. a Style is retrieved from <p pTempSeg>'s Style track.
  2810. Similarly, if <p pChordMap> is non-NULL, it is used in composing the segment; if it is
  2811. NULL, a ChordMap is retrieved from <p pTempSeg>'s ChordMap track.
  2812. The length of the section segment is equal to the length of the template section
  2813. passed in.
  2814. */
  2815. HRESULT CDMCompos::ComposeSegmentFromTemplateEx(
  2816. IDirectMusicStyle* pStyle, // @parm The style from which to create the section segment.
  2817. IDirectMusicSegment* pTempSeg, // @parm The template from which to create the section segment.
  2818. DWORD dwFlags, // @parm Various composition options.
  2819. DWORD dwActivity, // @parm Specifies the rate of harmonic motion; valid values are 0 through 3.
  2820. IDirectMusicChordMap* pChordMap, // @parm The ChordMap from which to create the section segment.
  2821. IDirectMusicSegment** ppSectionSeg // @parm Returns the created section segment.
  2822. )
  2823. {
  2824. V_INAME(IDirectMusicComposer::ComposeSegmentFromTemplateEx)
  2825. V_PTR_WRITE_OPT(pStyle, 1);
  2826. V_PTR_WRITE_OPT(pChordMap, 1);
  2827. V_PTR_WRITE(pTempSeg, 1);
  2828. V_PTRPTR_WRITE_OPT(ppSectionSeg);
  2829. if ((dwFlags & DMUS_COMPOSE_TEMPLATEF_CLONE) && !ppSectionSeg)
  2830. {
  2831. Trace(1, "ERROR (ComposeSegmentFromTemplateEx): CLONE flag set but ppSectionSeg is NULL\n");
  2832. return E_POINTER;
  2833. }
  2834. bool fUseActivity = (dwFlags & DMUS_COMPOSE_TEMPLATEF_ACTIVITY) ? true : false;
  2835. bool fCloneSegment = (dwFlags & DMUS_COMPOSE_TEMPLATEF_CLONE) ? true : false;
  2836. HRESULT hr = S_OK;
  2837. DWORD dwGroupBitsRead = ALL_TRACK_GROUPS; // fallback to dx7 behavior
  2838. DWORD dwGroupBitsWrite = 1; // fallback to dx7 behavior
  2839. IDirectMusicTrack* pSignPostTrack = NULL;
  2840. IDirectMusicTrack* pCommandTrack = NULL;
  2841. IDirectMusicTrack* pChordMapTrack = NULL;
  2842. EnterCriticalSection( &m_CriticalSection );
  2843. // Look for a style and chord map, just to determine DX8 content
  2844. BOOL fStyleFromTrack = FALSE;
  2845. BOOL fPersFromTrack = FALSE;
  2846. if (!pStyle)
  2847. {
  2848. if (FAILED(GetStyle(pTempSeg, 0, ALL_TRACK_GROUPS, pStyle, true)))
  2849. {
  2850. Trace(1, "ERROR (ComposeSegmentFromTemplateEx): Failed to get a style.\n");
  2851. hr = E_INVALIDARG;
  2852. }
  2853. else fStyleFromTrack = TRUE;
  2854. }
  2855. if (SUCCEEDED(hr) && !pChordMap)
  2856. {
  2857. if (FAILED(GetPersonality(pTempSeg, 0, ALL_TRACK_GROUPS, pChordMap)))
  2858. {
  2859. Trace(1, "ERROR (ComposeSegmentFromTemplateEx): Failed to get a chord map.\n");
  2860. hr = E_INVALIDARG;
  2861. }
  2862. else fPersFromTrack = TRUE;
  2863. }
  2864. // Get track group bits from the signpost track
  2865. if (SUCCEEDED(hr))
  2866. {
  2867. HRESULT hrTemp = pTempSeg->GetTrack(CLSID_DirectMusicSignPostTrack, ALL_TRACK_GROUPS, 0, &pSignPostTrack);
  2868. if (hrTemp == S_OK && UsingDX8(pStyle, pChordMap))
  2869. {
  2870. hrTemp = pTempSeg->GetTrackGroup(pSignPostTrack, &dwGroupBitsWrite);
  2871. if (hrTemp != S_OK) dwGroupBitsWrite = ALL_TRACK_GROUPS; // now read, write are both ALL
  2872. else dwGroupBitsRead = dwGroupBitsWrite;
  2873. }
  2874. else if (UsingDX8(pStyle, pChordMap)) // no signpost track, DX8 content
  2875. {
  2876. dwGroupBitsWrite = ALL_TRACK_GROUPS; // now read, write are both ALL
  2877. }
  2878. }
  2879. // Now that we know the group bits, get a style and chord map that match them.
  2880. if (SUCCEEDED(hr) && fStyleFromTrack)
  2881. {
  2882. pStyle->Release();
  2883. pStyle = NULL;
  2884. if (FAILED(GetStyle(pTempSeg, 0, dwGroupBitsRead, pStyle, true)))
  2885. {
  2886. Trace(1, "ERROR (ComposeSegmentFromTemplateEx): Failed to get a style.\n");
  2887. hr = E_INVALIDARG;
  2888. }
  2889. }
  2890. if (SUCCEEDED(hr) && fPersFromTrack)
  2891. {
  2892. pChordMap->Release();
  2893. pChordMap = NULL;
  2894. if (FAILED(pTempSeg->GetTrack(CLSID_DirectMusicChordMapTrack, dwGroupBitsRead, 0, &pChordMapTrack)))
  2895. {
  2896. Trace(1, "ERROR (ComposeSegmentFromTemplateEx): Failed to get a chordmap.\n");
  2897. hr = E_INVALIDARG;
  2898. }
  2899. }
  2900. if (SUCCEEDED(hr))
  2901. {
  2902. if (FAILED(pTempSeg->GetTrack(CLSID_DirectMusicCommandTrack, dwGroupBitsRead, 0, &pCommandTrack)))
  2903. {
  2904. // If there is no command track, use a NULL command track for ExtractCommandList
  2905. pCommandTrack = NULL;
  2906. }
  2907. }
  2908. if (SUCCEEDED(hr))
  2909. {
  2910. MUSIC_TIME mtLength = 0;
  2911. pTempSeg->GetLength(&mtLength);
  2912. TList<PlayChord> PlayList;
  2913. BYTE bRoot = 0;
  2914. DWORD dwScale = 0;
  2915. hr = ComposePlayListFromTemplate(
  2916. pStyle, pChordMap, pChordMapTrack, pSignPostTrack, pCommandTrack, dwGroupBitsRead,
  2917. mtLength, fUseActivity, dwActivity, PlayList, bRoot, dwScale);
  2918. if (SUCCEEDED(hr))
  2919. {
  2920. // Build a section segment from the playlist and command list.
  2921. if (fCloneSegment)
  2922. {
  2923. hr = CopySegment(pTempSeg, ppSectionSeg, PlayList, pStyle, pChordMap, fStyleFromTrack, fPersFromTrack, dwGroupBitsWrite, bRoot, dwScale);
  2924. }
  2925. else
  2926. {
  2927. hr = AddToSegment(pTempSeg, PlayList, pStyle, dwGroupBitsWrite, bRoot, dwScale);
  2928. }
  2929. if (!PlayList.GetHead() && UsingDX8(pStyle, pChordMap))
  2930. {
  2931. hr = S_FALSE;
  2932. }
  2933. }
  2934. }
  2935. CleanUp();
  2936. if (pSignPostTrack) pSignPostTrack->Release();
  2937. if (pCommandTrack) pCommandTrack->Release();
  2938. if (pChordMapTrack) pChordMapTrack->Release();
  2939. if (fStyleFromTrack && pStyle) pStyle->Release();
  2940. if (fPersFromTrack && pChordMap) pChordMap->Release();
  2941. LeaveCriticalSection( &m_CriticalSection );
  2942. return hr;
  2943. }
  2944. HRESULT CDMCompos::ComposePlayListFromTemplate(IDirectMusicStyle* pStyle,
  2945. IDirectMusicChordMap* pChordMap,
  2946. IDirectMusicTrack* pChordMapTrack,
  2947. IDirectMusicTrack* pSignPostTrack,
  2948. IDirectMusicTrack* pCommandTrack,
  2949. DWORD dwGroupBits,
  2950. MUSIC_TIME mtLength,
  2951. bool fUseActivity,
  2952. DWORD dwActivity,
  2953. TList<PlayChord>& rPlayList,
  2954. BYTE& rbRoot,
  2955. DWORD& rdwScale)
  2956. {
  2957. HRESULT hr = S_OK;
  2958. // Note: assumes time signature doesn't change.
  2959. DMUS_TIMESIGNATURE TimeSig;
  2960. pStyle->GetTimeSignature(&TimeSig);
  2961. if (!TimeSig.bBeatsPerMeasure) TimeSig.bBeatsPerMeasure = 4;
  2962. if (!TimeSig.bBeat) TimeSig.bBeat = 4;
  2963. // tics per bar
  2964. MUSIC_TIME mtBar = ( DMUS_PPQ * 4 * TimeSig.bBeatsPerMeasure ) / TimeSig.bBeat;
  2965. // To find the beat to place a second chord in a measure, divide by 2 and round up
  2966. int nSecondBeat = TimeSig.bBeatsPerMeasure / 2;
  2967. if (nSecondBeat * 2 != TimeSig.bBeatsPerMeasure) nSecondBeat++;
  2968. // Get the command list from the template segment.
  2969. TList<TemplateCommand> CommandList;
  2970. ExtractCommandList(CommandList, pSignPostTrack, pCommandTrack, dwGroupBits);
  2971. // For each chordmap in the chordmap track, compose a playlist from only the commands
  2972. // in the range of the chordmap
  2973. MUSIC_TIME mtNow = 0;
  2974. MUSIC_TIME mtNext = 0;
  2975. HRESULT hrChordMap = S_OK;
  2976. IDirectMusicChordMap* pLastChordMap = NULL;
  2977. while (SUCCEEDED(hrChordMap) && SUCCEEDED(hr) && mtNext < mtLength)
  2978. {
  2979. bool fChordMapPassedIn = false;
  2980. if (!pChordMap)
  2981. {
  2982. if (pChordMapTrack)
  2983. {
  2984. hrChordMap = pChordMapTrack->GetParam(GUID_IDirectMusicChordMap, mtNow, &mtNext, (void*) &pChordMap);
  2985. if (!mtNext) mtNext = mtLength;
  2986. else mtNext += mtNow;
  2987. }
  2988. else
  2989. {
  2990. Trace(1, "ERROR: No chord map track to use for chord composition.\n");
  2991. hr = hrChordMap = E_POINTER;
  2992. }
  2993. }
  2994. else // a chordmap got passed in; make sure it's the only one we use
  2995. {
  2996. mtNext = mtLength;
  2997. fChordMapPassedIn = true;
  2998. }
  2999. if (SUCCEEDED(hrChordMap))
  3000. {
  3001. if (!mtNow)
  3002. {
  3003. pChordMap->GetScale(&rdwScale);
  3004. rbRoot = (BYTE) (rdwScale >> 24);
  3005. rdwScale &= 0xffffff;
  3006. }
  3007. // get the commands in the range of this chordmap.
  3008. TList<TemplateCommand> CurrentCommandList;
  3009. TListItem<TemplateCommand>* pScan = CommandList.GetHead();
  3010. for (; pScan; pScan = pScan->GetNext())
  3011. {
  3012. TemplateCommand& rScan = pScan->GetItemValue();
  3013. MUSIC_TIME mtScanBar = rScan.m_nMeasure * mtBar;
  3014. if ( mtScanBar >= mtNow && mtScanBar < mtNext )
  3015. {
  3016. TListItem<TemplateCommand>* pNew = new TListItem<TemplateCommand>;
  3017. if (pNew)
  3018. {
  3019. pNew->GetItemValue() = rScan;
  3020. CurrentCommandList.AddTail(pNew);
  3021. }
  3022. else
  3023. {
  3024. hr = E_OUTOFMEMORY;
  3025. }
  3026. }
  3027. }
  3028. if (SUCCEEDED(hr))
  3029. {
  3030. // Compose a playlist for this chordmap.
  3031. TList<PlayChord> CurrentPlayList; // playlist for this chordmap.
  3032. if (fUseActivity)
  3033. {
  3034. ComposePlayList(CurrentPlayList, pStyle, pChordMap, CurrentCommandList, (WORD)dwActivity);
  3035. }
  3036. else
  3037. {
  3038. ComposePlayList2(CurrentPlayList, pStyle, pChordMap, CurrentCommandList);
  3039. }
  3040. // if we're past the first bar, compose a cadence to the first chord
  3041. // of the current playlist via a call to ChooseSignPost (using the last
  3042. // chordmap) and add it to the current playlist.
  3043. int nCurrentBar = mtNow / mtBar;
  3044. if (rPlayList.GetHead() && nCurrentBar && pLastChordMap)
  3045. {
  3046. DWORD dwScale = 0;
  3047. pLastChordMap->GetScale(&dwScale);
  3048. BYTE bRoot = (BYTE) (dwScale >> 24);
  3049. dwScale &= 0xffffff;
  3050. int nBar = nCurrentBar - 1;
  3051. bool fCadence1 = false;
  3052. bool fCadence2 = false;
  3053. TListItem<DMSignPost> *pSignChoice = NULL;
  3054. if (CurrentPlayList.GetHead())
  3055. {
  3056. DMChordData* pFirstChord = CurrentPlayList.GetHead()->GetItemValue().m_pChord;
  3057. pSignChoice = ChooseSignPost(pChordMap, pFirstChord, false, dwScale, bRoot);
  3058. }
  3059. else
  3060. {
  3061. pSignChoice = ChooseSignPost(pChordMap, NULL, true, dwScale, bRoot);
  3062. }
  3063. if (pSignChoice)
  3064. {
  3065. DMSignPost& rSignChoice = pSignChoice->GetItemValue();
  3066. fCadence1 = (rSignChoice.m_dwFlags & DMUS_SPOSTCADENCEF_1) ? true : false;
  3067. fCadence2 = (rSignChoice.m_dwFlags & DMUS_SPOSTCADENCEF_2) ? true : false;
  3068. if (fCadence1)
  3069. {
  3070. AddChord( CurrentPlayList, &rSignChoice.m_aCadence[0], nBar, 0 );
  3071. }
  3072. if (fCadence2)
  3073. {
  3074. int nBeat = fCadence1 ? nSecondBeat : 0;
  3075. AddChord( CurrentPlayList, &rSignChoice.m_aCadence[1], nBar, nBeat );
  3076. }
  3077. }
  3078. }
  3079. // Add the current playlist to the end of the master playlist.
  3080. rPlayList.AddTail(CurrentPlayList.GetHead());
  3081. CurrentPlayList.RemoveAll();
  3082. }
  3083. // clear out the chord map for the next iteration
  3084. if (pLastChordMap) pLastChordMap->Release();
  3085. pLastChordMap = pChordMap;
  3086. if (pLastChordMap) pLastChordMap->AddRef();
  3087. if (!fChordMapPassedIn) pChordMap->Release();
  3088. pChordMap = NULL;
  3089. }
  3090. mtNow = mtNext;
  3091. }
  3092. if (pLastChordMap) pLastChordMap->Release();
  3093. return hr;
  3094. }
  3095. /*
  3096. @method:(EXTERNAL) HRESULT | IDirectMusicComposer | ComposeSegmentFromShape | Creates
  3097. an original section segment from a style and ChordMap based on a predefined shape.
  3098. @rdesc Returns:
  3099. @flag S_OK | Success
  3100. @flag E_POINTER | One or more of <p pStyle>, <p pChordMap>, and <p ppSectionSeg>
  3101. is an invalid pointer.
  3102. @comm Creates an original section segment from a style and a ChordMap based on a
  3103. predefined shape. Shapes (passed in <p wShape>) represent the way chords and embellishments
  3104. occur over time across the section. There are nine shapes:
  3105. @flag DMUS_SHAPET_FALLING | The section gets quieter over time.
  3106. @flag DMUS_SHAPET_LEVEL | The section remains at the same level.
  3107. @flag DMUS_SHAPET_LOOPABLE | The section is arranged to loop back to its beginning.
  3108. @flag DMUS_SHAPET_LOUD | The section remains loud.
  3109. @flag DMUS_SHAPET_QUIET | The section remains quiet.
  3110. @flag DMUS_SHAPET_PEAKING | The section peaks.
  3111. @flag DMUS_SHAPET_RANDOM | The section is random.
  3112. @flag DMUS_SHAPET_RISING | The section builds over time.
  3113. @flag DMUS_SHAPET_SONG | The section is in a song form.
  3114. */
  3115. HRESULT CDMCompos::ComposeSegmentFromShape(
  3116. IDirectMusicStyle* pStyle, // @parm The style from which to compose the section segment.
  3117. WORD wNumMeasures, // @parm The length, in measures, to compose the section segment.
  3118. WORD wShape, // @parm The shape to compose the section segment.
  3119. WORD wActivity, // @parm Specifies the rate of harmonic motion; valid values are 0 through 3.
  3120. BOOL fComposeIntro, // @parm TRUE if an intro is to be composed for the section segment.
  3121. BOOL fComposeEnding, // @parm TRUE if an ending is to be composed for the section segment.
  3122. IDirectMusicChordMap* pChordMap, // @parm The ChordMap from which to create the section segment.
  3123. IDirectMusicSegment** ppSectionSeg // @parm Returns the created section segment.
  3124. )
  3125. {
  3126. V_INAME(IDirectMusicComposer::ComposeSegmentFromShape)
  3127. V_PTR_WRITE(pStyle, 1);
  3128. V_PTR_WRITE(pChordMap, 1);
  3129. V_PTRPTR_WRITE(ppSectionSeg);
  3130. EnterCriticalSection( &m_CriticalSection );
  3131. int nIntroLength = 1;
  3132. int nFillLength = 1;
  3133. int nBreakLength = 1;
  3134. int nEndLength = 1;
  3135. // Get the maximum ending length from the style.
  3136. DWORD dwMin, dwMax;
  3137. HRESULT hr = pStyle->GetEmbellishmentLength(DMUS_COMMANDT_END, 0, &dwMin, &dwMax);
  3138. if (FAILED(hr)) // remain consistent with old behavior and fail.
  3139. {
  3140. LeaveCriticalSection( &m_CriticalSection );
  3141. return hr;
  3142. }
  3143. if (hr == S_OK) nEndLength = (int) dwMax;
  3144. if ( UsingDX8(pStyle) )
  3145. {
  3146. hr = pStyle->GetEmbellishmentLength(DMUS_COMMANDT_INTRO, 0, &dwMin, &dwMax);
  3147. if (hr == S_OK) nIntroLength = (int) dwMax;
  3148. hr = pStyle->GetEmbellishmentLength(DMUS_COMMANDT_FILL, 0, &dwMin, &dwMax);
  3149. if (hr == S_OK) nFillLength = (int) dwMax;
  3150. hr = pStyle->GetEmbellishmentLength(DMUS_COMMANDT_BREAK, 0, &dwMin, &dwMax);
  3151. if (hr == S_OK) nBreakLength = (int) dwMax;
  3152. }
  3153. if (wNumMeasures & 0x8000 || wNumMeasures == 0) wNumMeasures = 1;
  3154. int nNumMeasures = wNumMeasures;
  3155. if (wShape != DMUS_SHAPET_FALLING &&
  3156. wShape != DMUS_SHAPET_LEVEL &&
  3157. wShape != DMUS_SHAPET_LOOPABLE &&
  3158. wShape != DMUS_SHAPET_LOUD &&
  3159. wShape != DMUS_SHAPET_QUIET &&
  3160. wShape != DMUS_SHAPET_PEAKING &&
  3161. wShape != DMUS_SHAPET_RANDOM &&
  3162. wShape != DMUS_SHAPET_RISING &&
  3163. wShape != DMUS_SHAPET_SONG)
  3164. {
  3165. wShape = DMUS_SHAPET_RANDOM;
  3166. }
  3167. if (fComposeIntro)
  3168. {
  3169. if (nIntroLength <= 0) nIntroLength = 1;
  3170. if ( nIntroLength >= nNumMeasures )
  3171. {
  3172. nNumMeasures = nIntroLength;
  3173. }
  3174. }
  3175. if (fComposeEnding)
  3176. {
  3177. if (nEndLength <= 0) nEndLength = 1;
  3178. if ( nEndLength >= nNumMeasures )
  3179. {
  3180. nNumMeasures = nEndLength;
  3181. if (fComposeIntro) nNumMeasures += nIntroLength;
  3182. }
  3183. }
  3184. // Compose playlists for sections of the segment.
  3185. TList<TemplateCommand> CommandList;
  3186. TList<PlayChord> PlayList;
  3187. hr = ComposePlayListFromShape(
  3188. nNumMeasures, wShape, fComposeIntro, fComposeEnding,
  3189. nIntroLength, nFillLength, nBreakLength, nEndLength, pStyle, wActivity,
  3190. pChordMap, CommandList, PlayList);
  3191. if (SUCCEEDED(hr))
  3192. {
  3193. // Build a segment from the resulting command lists and playlists.
  3194. BYTE bRoot = 0;
  3195. DWORD dwScale;
  3196. pChordMap->GetScale(&dwScale);
  3197. bRoot = (BYTE) (dwScale >> 24);
  3198. dwScale &= 0xffffff;
  3199. hr = BuildSegment(CommandList, PlayList, pStyle, pChordMap, nNumMeasures, ppSectionSeg, bRoot, dwScale);
  3200. CleanUp();
  3201. }
  3202. LeaveCriticalSection( &m_CriticalSection );
  3203. return hr;
  3204. }
  3205. HRESULT GetCommandList(IDirectMusicSegment* pFromSeg, TList<TemplateCommand>& CommandList)
  3206. {
  3207. HRESULT hr = S_OK;
  3208. IDirectMusicTrack* pCommandTrack;
  3209. hr = pFromSeg->GetTrack(CLSID_DirectMusicCommandTrack, ALL_TRACK_GROUPS, 0, &pCommandTrack);
  3210. if (S_OK != hr) return hr;
  3211. // Write the track to a stream, and read from the stream into a command list.
  3212. IPersistStream* pPS;
  3213. IStream *pStream;
  3214. hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
  3215. if (S_OK == hr)
  3216. {
  3217. hr = pCommandTrack->QueryInterface(IID_IPersistStream, (void**)&pPS);
  3218. if (S_OK == hr)
  3219. {
  3220. hr = pPS->Save(pStream, FALSE);
  3221. if (S_OK == hr)
  3222. {
  3223. StreamSeek(pStream, 0, STREAM_SEEK_SET);
  3224. LoadCommandList(CommandList, pStream);
  3225. }
  3226. pPS->Release();
  3227. }
  3228. pStream->Release();
  3229. }
  3230. pCommandTrack->Release();
  3231. return hr;
  3232. }
  3233. // New flags:
  3234. // DMUS_COMPOSEF_ENTIRE_TRANSITION: play the transition pattern in its entirety.
  3235. // DMUS_COMPOSEF_1BAR_TRANSITION: play one bar of the the transition pattern.
  3236. // the following two are ignored unless DMUS_COMPOSEF_LONG is set:
  3237. // DMUS_COMPOSEF_ENTIRE_ADDITION: play the additional pattern in its entirety.
  3238. // DMUS_COMPOSEF_1BAR_ADDITION: play one bar of the additional pattern.
  3239. // Default behavior will be the same as dx7:
  3240. // DMUS_COMPOSEF_1BAR_TRANSITION unless pattern is an ending
  3241. // DMUS_COMPOSEF_1BAR_ADDITION always
  3242. // Used by both ComposeTransition and AutoTransition
  3243. HRESULT CDMCompos::TransitionCommon(
  3244. IDirectMusicStyle* pFromStyle,
  3245. IDirectMusicBand* pCurrentBand,
  3246. double* pdblFromTempo,
  3247. DMUS_COMMAND_PARAM_2& rFromCommand,
  3248. DMUS_CHORD_PARAM& rLastChord,
  3249. DMUS_CHORD_PARAM& rNextChord,
  3250. IDirectMusicSegment* pToSeg,
  3251. WORD wCommand,
  3252. DWORD dwFlags,
  3253. IDirectMusicChordMap* pChordMap,
  3254. IDirectMusicGraph* pFromGraph,
  3255. IDirectMusicGraph* pToGraph,
  3256. IUnknown* pFromPath,
  3257. IUnknown* pToPath,
  3258. IDirectMusicSegment** ppSectionSeg
  3259. )
  3260. {
  3261. IDirectMusicGraph* pGraph = NULL;
  3262. IUnknown* pPath = NULL;
  3263. BYTE bRoot = rLastChord.bKey;
  3264. DWORD dwScale = rLastChord.dwScale;
  3265. DMChordData LastChord = rLastChord;
  3266. DMChordData NextChord = rNextChord;
  3267. HRESULT hr = S_OK;
  3268. bool fLong = (dwFlags & DMUS_COMPOSEF_LONG) ? true : false;
  3269. bool fModulate = (dwFlags & DMUS_COMPOSEF_MODULATE) ? true : false;
  3270. bool fEnding = wCommand == DMUS_COMMANDT_END || wCommand == DMUS_COMMANDT_ENDANDINTRO;
  3271. bool fHasIntro = wCommand == DMUS_COMMANDT_INTRO || wCommand == DMUS_COMMANDT_ENDANDINTRO;
  3272. bool fEntireTransition = false;
  3273. if ((dwFlags & DMUS_COMPOSEF_ENTIRE_TRANSITION) ||
  3274. (fEnding && !(dwFlags & DMUS_COMPOSEF_1BAR_TRANSITION)))
  3275. {
  3276. fEntireTransition = true;
  3277. }
  3278. bool fEntireAddition = (dwFlags & DMUS_COMPOSEF_ENTIRE_ADDITION) ? true : false;
  3279. bool fAlign = (dwFlags & DMUS_COMPOSEF_ALIGN) ? true : false;
  3280. // Get the ending segment's style
  3281. IDirectMusicStyle* pToStyle = NULL;
  3282. if (pToSeg)
  3283. {
  3284. hr = GetStyle(pToSeg, 0, ALL_TRACK_GROUPS, pToStyle, false);
  3285. if (FAILED(hr)) pToStyle = NULL;
  3286. }
  3287. if (!pToStyle && !pFromStyle) // Not much to do...
  3288. {
  3289. *ppSectionSeg = NULL;
  3290. return S_OK;
  3291. }
  3292. // Get tempo from the end segment. This will be passed into BuildSegment.
  3293. double dblFromTempo = 120.0;
  3294. double dblToTempo = 120.0;
  3295. double* pdblToTempo = &dblToTempo;
  3296. if (pdblFromTempo)
  3297. {
  3298. dblFromTempo = *pdblFromTempo;
  3299. }
  3300. // If there is no To tempo, set it to the From tempo (or keep it at the fallback).
  3301. if (!pToSeg || FAILED(GetTempo(pToSeg, 0, &dblToTempo)))
  3302. {
  3303. if (pdblFromTempo) dblToTempo = dblFromTempo; // otherwise use fallback of 120
  3304. }
  3305. // If there is no From tempo, set it to the To tempo.
  3306. if (!pdblFromTempo)
  3307. {
  3308. dblFromTempo = dblToTempo;
  3309. pdblFromTempo = &dblFromTempo;
  3310. }
  3311. EnterCriticalSection( &m_CriticalSection );
  3312. // Extract the starting style's time signature.
  3313. DMUS_TIMESIGNATURE FromTimeSig;
  3314. if (pFromStyle)
  3315. {
  3316. pFromStyle->GetTimeSignature(&FromTimeSig);
  3317. }
  3318. else
  3319. {
  3320. FromTimeSig.bBeat = 4;
  3321. FromTimeSig.bBeatsPerMeasure = 4;
  3322. FromTimeSig.wGridsPerBeat = 4;
  3323. FromTimeSig.mtTime = 0;
  3324. }
  3325. // Extract the ending style's time signature.
  3326. DMUS_TIMESIGNATURE ToTimeSig;
  3327. if (pToStyle)
  3328. {
  3329. pToStyle->GetTimeSignature(&ToTimeSig);
  3330. }
  3331. else
  3332. {
  3333. ToTimeSig.bBeat = 4;
  3334. ToTimeSig.bBeatsPerMeasure = 4;
  3335. ToTimeSig.wGridsPerBeat = 4;
  3336. ToTimeSig.mtTime = 0;
  3337. }
  3338. if (!ToTimeSig.bBeatsPerMeasure) ToTimeSig.bBeatsPerMeasure = 4;
  3339. // To find the beat to place a second chord in a measure, divide by 2 and round up
  3340. int nSecondBeat = ToTimeSig.bBeatsPerMeasure / 2;
  3341. if (nSecondBeat * 2 != ToTimeSig.bBeatsPerMeasure) nSecondBeat++;
  3342. MUSIC_TIME mtIntro = 0;
  3343. TList<PlayChord> PlayList;
  3344. TListItem<TemplateCommand> *pCommand = new TListItem<TemplateCommand>;
  3345. if (!pCommand)
  3346. {
  3347. LeaveCriticalSection( &m_CriticalSection );
  3348. return E_OUTOFMEMORY;
  3349. }
  3350. TListItem<TemplateCommand> *pLast = pCommand;
  3351. // Intros get their chords when adding commands
  3352. if (wCommand != DMUS_COMMANDT_INTRO)
  3353. {
  3354. if ( fModulate )
  3355. {
  3356. bool fCadence1 = false;
  3357. bool fCadence2 = false;
  3358. TListItem<DMSignPost> *pSignChoice = ChooseSignPost(pChordMap, &NextChord, fEnding, dwScale, bRoot);
  3359. if (pSignChoice)
  3360. {
  3361. fCadence1 = (pSignChoice->GetItemValue().m_dwFlags & DMUS_SPOSTCADENCEF_1) ? true : false;
  3362. fCadence2 = (pSignChoice->GetItemValue().m_dwFlags & DMUS_SPOSTCADENCEF_2) ? true : false;
  3363. }
  3364. if (fCadence1 || fCadence2)
  3365. {
  3366. if ( fCadence1 && (fLong || !fEnding || !fCadence2) )
  3367. {
  3368. AddChord( PlayList, &pSignChoice->GetItemValue().m_aCadence[0], 0, 0 );
  3369. }
  3370. else
  3371. {
  3372. AddChord( PlayList, &pSignChoice->GetItemValue().m_aCadence[1], 0, 0 );
  3373. }
  3374. if (fCadence1 && fCadence2)
  3375. {
  3376. if (fLong == fEnding)
  3377. {
  3378. AddChord( PlayList, &pSignChoice->GetItemValue().m_aCadence[1], 0, nSecondBeat );
  3379. }
  3380. if (fLong && !fEnding)
  3381. {
  3382. AddChord( PlayList, &pSignChoice->GetItemValue().m_aCadence[1], 1, 0 );
  3383. }
  3384. }
  3385. if ( fEnding )
  3386. {
  3387. if (fLong)
  3388. {
  3389. AddChord( PlayList, &pSignChoice->GetItemValue().m_ChordData, 1, 0 );
  3390. }
  3391. else
  3392. {
  3393. AddChord( PlayList, &pSignChoice->GetItemValue().m_ChordData, 0, nSecondBeat );
  3394. }
  3395. }
  3396. }
  3397. else
  3398. {
  3399. AddChord( PlayList, &LastChord, 0 , 0 );
  3400. }
  3401. }
  3402. else
  3403. {
  3404. AddChord( PlayList, &LastChord, 0 , 0 );
  3405. }
  3406. }
  3407. int nLength = 0;
  3408. int nPreIntro = 0;
  3409. if (pCommand)
  3410. {
  3411. DWORD dwMax = 1;
  3412. DWORD dwMin;
  3413. TemplateCommand& rCommand = pCommand->GetItemValue();
  3414. rCommand.m_Command.bCommand = rFromCommand.bCommand;
  3415. rCommand.m_Command.bGrooveLevel = rFromCommand.bGrooveLevel;
  3416. rCommand.m_Command.bGrooveRange = rFromCommand.bGrooveRange;
  3417. rCommand.m_Command.bRepeatMode = rFromCommand.bRepeatMode;
  3418. rCommand.m_nMeasure = 0;
  3419. if (pFromStyle)
  3420. {
  3421. if (wCommand != DMUS_COMMANDT_INTRO)
  3422. {
  3423. WORD wTempCommand = wCommand;
  3424. if ( wCommand == DMUS_COMMANDT_END || wCommand == DMUS_COMMANDT_ENDANDINTRO )
  3425. {
  3426. wTempCommand = DMUS_COMMANDT_END;
  3427. }
  3428. if (fEntireTransition)
  3429. {
  3430. HRESULT hrTemp = pFromStyle->GetEmbellishmentLength(wTempCommand, rFromCommand.bGrooveLevel, &dwMin, &dwMax);
  3431. if (hrTemp != S_OK) dwMax = 1;
  3432. nLength = dwMax;
  3433. }
  3434. else
  3435. {
  3436. nLength = 1;
  3437. }
  3438. }
  3439. if ( fLong )
  3440. {
  3441. if (fEntireAddition)
  3442. {
  3443. HRESULT hrTemp = pFromStyle->GetEmbellishmentLength(DMUS_COMMANDT_GROOVE, rFromCommand.bGrooveLevel, &dwMin, &dwMax);
  3444. if (hrTemp != S_OK) dwMax = 1;
  3445. }
  3446. else
  3447. {
  3448. dwMax = 1;
  3449. }
  3450. nLength += dwMax;
  3451. if (wCommand == DMUS_COMMANDT_GROOVE && UsingDX8(pFromStyle)) // Just have one long groove.
  3452. {
  3453. rCommand.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
  3454. }
  3455. else if (wCommand != DMUS_COMMANDT_INTRO)
  3456. {
  3457. TListItem<TemplateCommand> *pSecond = new TListItem<TemplateCommand>;
  3458. if (pSecond)
  3459. {
  3460. TemplateCommand& rSecond = pSecond->GetItemValue();
  3461. rSecond.m_nMeasure = (short) dwMax;
  3462. if (wCommand == DMUS_COMMANDT_ENDANDINTRO)
  3463. {
  3464. rSecond.m_Command.bCommand = DMUS_COMMANDT_END;
  3465. }
  3466. else
  3467. {
  3468. rSecond.m_Command.bCommand = (BYTE)wCommand;
  3469. }
  3470. rSecond.m_Command.bGrooveLevel = 0;
  3471. rSecond.m_Command.bGrooveRange = 0;
  3472. rSecond.m_Command.bRepeatMode = DMUS_PATTERNT_RANDOM;
  3473. pLast->SetNext(pSecond);
  3474. pLast = pSecond;
  3475. }
  3476. }
  3477. }
  3478. else if (wCommand != DMUS_COMMANDT_INTRO)
  3479. {
  3480. if (wCommand == DMUS_COMMANDT_ENDANDINTRO)
  3481. {
  3482. rCommand.m_Command.bCommand = DMUS_COMMANDT_END;
  3483. }
  3484. else
  3485. {
  3486. rCommand.m_Command.bCommand = (BYTE)wCommand;
  3487. }
  3488. }
  3489. }
  3490. if ( pToStyle && fHasIntro)
  3491. {
  3492. nPreIntro = nLength;
  3493. if (fEntireTransition)
  3494. {
  3495. // Check that this is the correct thing to do if pFromStyle is NULL.
  3496. HRESULT hrTemp = pToStyle->GetEmbellishmentLength(DMUS_COMMANDT_INTRO, rFromCommand.bGrooveLevel, &dwMin, &dwMax);
  3497. if (hrTemp != S_OK) dwMax = 1;
  3498. nLength += dwMax;
  3499. }
  3500. else
  3501. {
  3502. nLength++;
  3503. }
  3504. AddChord( PlayList, &NextChord, nPreIntro , 0 );
  3505. if ( nPreIntro > 0 )
  3506. {
  3507. if (wCommand == DMUS_COMMANDT_INTRO) AddChord( PlayList, &LastChord, 0 , 0 );
  3508. TListItem<TemplateCommand> *pSecond = new TListItem<TemplateCommand>;
  3509. if (pSecond)
  3510. {
  3511. TemplateCommand& rSecond = pSecond->GetItemValue();
  3512. rSecond.m_nMeasure = (short)nPreIntro;
  3513. rSecond.m_Command.bCommand = DMUS_COMMANDT_INTRO;
  3514. rSecond.m_Command.bGrooveLevel = 0;
  3515. rSecond.m_Command.bGrooveRange = 0;
  3516. rSecond.m_Command.bRepeatMode = DMUS_PATTERNT_RANDOM;
  3517. pLast->SetNext(pSecond);
  3518. }
  3519. }
  3520. else
  3521. {
  3522. rCommand.m_Command.bCommand = DMUS_COMMANDT_INTRO;
  3523. }
  3524. }
  3525. }
  3526. TList<TemplateCommand> CommandList2;
  3527. CommandList2.Cat(pCommand);
  3528. *ppSectionSeg = NULL;
  3529. if (fHasIntro && !fEnding && UsingDX8(pToStyle))
  3530. {
  3531. pGraph = pToGraph;
  3532. pPath = pToPath;
  3533. }
  3534. else if (UsingDX8(pFromStyle))
  3535. {
  3536. pGraph = pFromGraph;
  3537. pPath = pFromPath;
  3538. }
  3539. if (fHasIntro)
  3540. {
  3541. if (pFromStyle)
  3542. {
  3543. hr = BuildSegment(CommandList2, PlayList, pFromStyle, pChordMap, nLength, ppSectionSeg, bRoot, dwScale, pdblFromTempo, pCurrentBand, fAlign, pGraph, pPath);
  3544. if (SUCCEEDED(hr) && pToStyle)
  3545. {
  3546. mtIntro = ClocksPerMeasure(FromTimeSig) * nPreIntro;
  3547. IDirectMusicTrack* pStyleTrack;
  3548. hr = (*ppSectionSeg)->GetTrack(CLSID_DirectMusicStyleTrack, ALL_TRACK_GROUPS, 0, &pStyleTrack);
  3549. if (SUCCEEDED(hr))
  3550. {
  3551. pStyleTrack->SetParam(GUID_IDirectMusicStyle, mtIntro, (void*) pToStyle);
  3552. pStyleTrack->Release();
  3553. }
  3554. IDirectMusicTrack* pTempoTrack;
  3555. hr = (*ppSectionSeg)->GetTrack(CLSID_DirectMusicTempoTrack, ALL_TRACK_GROUPS, 0, &pTempoTrack);
  3556. if (SUCCEEDED(hr))
  3557. {
  3558. DMUS_TEMPO_PARAM tempo;
  3559. tempo.mtTime = mtIntro;
  3560. tempo.dblTempo = dblToTempo;
  3561. pTempoTrack->SetParam(GUID_TempoParam, mtIntro, (void*) &tempo);
  3562. pTempoTrack->Release();
  3563. }
  3564. // I also need to add a band (from the To segment) to the band track at the appropriate time...
  3565. if ( UsingDX8(pToStyle) )
  3566. {
  3567. if (mtIntro == 0) // Intro is the first thing to play; don't need any other bands
  3568. {
  3569. (*ppSectionSeg)->SetParam(GUID_Clear_All_Bands, ALL_TRACK_GROUPS, 0, 0, NULL);
  3570. }
  3571. DMUS_BAND_PARAM DMBand;
  3572. if (pToSeg && SUCCEEDED(pToSeg->GetParam(GUID_BandParam, ALL_TRACK_GROUPS, DMUS_SEG_ANYTRACK, 0, NULL, (void*)&DMBand)))
  3573. {
  3574. DMBand.mtTimePhysical = mtIntro;
  3575. (*ppSectionSeg)->SetParam(GUID_BandParam, ALL_TRACK_GROUPS, 0, mtIntro, (void*)&DMBand);
  3576. DMBand.pBand->Release();
  3577. }
  3578. }
  3579. // readjust the length to account for differences in the two styles's time signatures
  3580. if ( nLength > nPreIntro && (UsingDX8(pFromStyle) || UsingDX8(pToStyle)) )
  3581. {
  3582. MUSIC_TIME mtNewLength = mtIntro + ((nLength - nPreIntro) * ClocksPerMeasure(ToTimeSig));
  3583. (*ppSectionSeg)->SetLength(mtNewLength);
  3584. }
  3585. }
  3586. }
  3587. else if (pToStyle)
  3588. {
  3589. hr = BuildSegment(CommandList2, PlayList, pToStyle, pChordMap, nLength, ppSectionSeg, bRoot, dwScale, pdblToTempo, pCurrentBand, fAlign, pGraph, pPath);
  3590. }
  3591. }
  3592. else if (pFromStyle)
  3593. {
  3594. hr = BuildSegment(CommandList2, PlayList, pFromStyle, pChordMap, nLength, ppSectionSeg, bRoot, dwScale, pdblFromTempo, pCurrentBand, fAlign, pGraph, pPath);
  3595. }
  3596. else
  3597. {
  3598. hr = S_OK; // don't build anything, but return OK
  3599. }
  3600. CommandList2.RemoveAll();
  3601. TListItem<TemplateCommand>::Delete(pCommand);
  3602. if (pToStyle) pToStyle->Release();
  3603. CleanUp();
  3604. NextChord.Release();
  3605. LastChord.Release();
  3606. LeaveCriticalSection( &m_CriticalSection );
  3607. return hr;
  3608. }
  3609. TListItem<DMSignPost>* CDMCompos::ChooseSignPost(
  3610. IDirectMusicChordMap* pChordMap,
  3611. DMChordData* pNextChord,
  3612. bool fEnding,
  3613. DWORD dwScale,
  3614. BYTE bRoot)
  3615. {
  3616. if (!fEnding && !pNextChord) return NULL;
  3617. DMPersonalityStruct* pPers = NULL;
  3618. if (pChordMap)
  3619. {
  3620. IDMPers* pDMP;
  3621. if (FAILED(pChordMap->QueryInterface(IID_IDMPers, (void**)&pDMP))) return NULL;
  3622. pDMP->GetPersonalityStruct((void**)&pPers);
  3623. pDMP->Release();
  3624. }
  3625. if (!pPers) return NULL;
  3626. TList<DMSignPost> &SignPostList = pPers->m_SignPostList;
  3627. TListItem<DMSignPost> *pSign = SignPostList.GetHead();
  3628. TListItem<DMSignPost> *pSignChoice = pSign;
  3629. int nMin = 100;
  3630. int nHit = 100;
  3631. int nMatches = 0;
  3632. if (fEnding)
  3633. {
  3634. for (;pSign; pSign = pSign->GetNext())
  3635. {
  3636. if ( (pSign->GetItemValue().m_dwChords & DMUS_SIGNPOSTF_1) )
  3637. {
  3638. pSignChoice = pSign;
  3639. nMatches = 0;
  3640. for (; pSign; pSign = pSign->GetNext())
  3641. {
  3642. if (pSign->GetItemValue().m_dwChords & DMUS_SIGNPOSTF_1) nMatches++;
  3643. }
  3644. break;
  3645. }
  3646. }
  3647. }
  3648. else
  3649. {
  3650. DMChordData& rNextChord = *pNextChord;
  3651. for (;pSign; pSign = pSign->GetNext())
  3652. {
  3653. nHit = CompareSPToChord(pSign->GetItemValue(), dwScale, rNextChord, (char) bRoot);
  3654. if (nHit == nMin) nMatches++;
  3655. else if (nHit < nMin)
  3656. {
  3657. nMin = nHit;
  3658. pSignChoice = pSign;
  3659. nMatches = 1;
  3660. }
  3661. }
  3662. }
  3663. // Pick a winning signpost at random
  3664. pSign = pSignChoice;
  3665. if (nMatches) nMatches = rand() % nMatches;
  3666. for (int i = 0; i <= nMatches && pSign; pSign = pSign->GetNext())
  3667. {
  3668. if (fEnding)
  3669. {
  3670. if (pSign->GetItemValue().m_dwChords & DMUS_SIGNPOSTF_1)
  3671. {
  3672. i++;
  3673. pSignChoice = pSign;
  3674. }
  3675. }
  3676. else
  3677. {
  3678. DMChordData& rNextChord = *pNextChord;
  3679. nHit = CompareSPToChord(pSign->GetItemValue(), dwScale, rNextChord, (char) bRoot);
  3680. if (nHit == nMin)
  3681. {
  3682. i++;
  3683. pSignChoice = pSign;
  3684. }
  3685. }
  3686. }
  3687. // If the signpost that was found doesn't match the chord we're going to, discard it
  3688. if (!fEnding &&
  3689. pSignChoice &&
  3690. (!(*pNextChord).Equals(pSignChoice->GetItemValue().m_ChordData)))
  3691. {
  3692. pSignChoice = NULL;
  3693. }
  3694. return pSignChoice;
  3695. }
  3696. IDirectMusicGraph* CDMCompos::CloneSegmentGraph(IDirectMusicSegment* pSegment)
  3697. {
  3698. if (!pSegment)
  3699. {
  3700. return NULL;
  3701. }
  3702. IDirectMusicGraph* pGraph = NULL;
  3703. HRESULT hr = pSegment->GetGraph(&pGraph);
  3704. if (FAILED(hr) || !pGraph)
  3705. {
  3706. return NULL;
  3707. }
  3708. IGraphClone *pGraph8 = NULL;
  3709. hr = pGraph->QueryInterface(IID_IGraphClone, (void**)&pGraph8);
  3710. pGraph->Release();
  3711. if (FAILED(hr) || !pGraph8)
  3712. {
  3713. return NULL;
  3714. }
  3715. hr = pGraph8->Clone(&pGraph);
  3716. pGraph8->Release();
  3717. if (SUCCEEDED(hr))
  3718. {
  3719. return pGraph;
  3720. }
  3721. else
  3722. {
  3723. return NULL;
  3724. }
  3725. }
  3726. IUnknown* CDMCompos::GetSegmentAudioPath(IDirectMusicSegment* pSegment, DWORD dwFlags, DWORD* pdwAudioPath)
  3727. {
  3728. if (!pSegment)
  3729. {
  3730. return NULL;
  3731. }
  3732. if (!(dwFlags & DMUS_COMPOSEF_USE_AUDIOPATH))
  3733. {
  3734. DWORD dwDefault = 0;
  3735. pSegment->GetDefaultResolution(&dwDefault);
  3736. if ( pdwAudioPath && (dwDefault & DMUS_SEGF_USE_AUDIOPATH) )
  3737. {
  3738. *pdwAudioPath = DMUS_SEGF_USE_AUDIOPATH;
  3739. }
  3740. return NULL;
  3741. }
  3742. IUnknown* pPath = NULL;
  3743. IDirectMusicSegment8* pSeg8 = NULL;
  3744. HRESULT hr = pSegment->QueryInterface(IID_IDirectMusicSegment8, (void**)&pSeg8);
  3745. if (FAILED(hr)) return NULL;
  3746. hr = pSeg8->GetAudioPathConfig(&pPath);
  3747. pSeg8->Release();
  3748. if (FAILED(hr) || !pPath)
  3749. {
  3750. return NULL;
  3751. }
  3752. else
  3753. {
  3754. return pPath;
  3755. }
  3756. }
  3757. /*
  3758. @method:(EXTERNAL) HRESULT | IDirectMusicComposer | ComposeTransition | Composes a
  3759. transition from inside one section segment to another segment.
  3760. @rdesc Returns:
  3761. @flag S_OK | Success
  3762. @flag E_POINTER | One or more of <p pFromSeg>, <p pToSeg> and <p ppSectionSeg>
  3763. is not a valid pointer.
  3764. @flag E_INVALIDARG | <p pToSeg> is NULL and
  3765. DMUS_COMPOSEF_MODULATE is set in <p dwFlags>.
  3766. @flag E_OUTOFMEMORY | An attempt to allocate memory failed.
  3767. @comm Allowable values for <p dwFlags> are:
  3768. @flag DMUS_COMPOSEF_LONG | Composes a long transition. If the flag is not included, the length
  3769. of the transition is the combined lengths of valid embellishments specified by <p wCommand>.
  3770. If the flag is included and <p pFromSeg> is non-null, the length of the transition
  3771. increases by 1.
  3772. @flag DMUS_COMPOSEF_MODULATE | Composes a transition that modulates smoothly from
  3773. <p pFromSeg> to <p pToSeg>.
  3774. @flag DMUS_COMPOSEF_ALIGN | Align transition to the time signature of the currently playing
  3775. segment.
  3776. @flag DMUS_COMPOSEF_OVERLAP | Overlap the transition into <p pToSeg>.
  3777. <p pToSeg> may be NULL, as long as
  3778. <p dwFlags> does not include DMUS_COMPOSEF_MODULATE.
  3779. If <p pToSeg> is NULL or doesn't contain a style track, intro embellishments are not valid.
  3780. If <p pFromSeg> is NULL or doesn't contain a style track,
  3781. fill, break, end, and groove embellishments are not valid.
  3782. Note that the above implies that it is possible for both <p pFromSeg> and <p pToSeg> to be
  3783. NULL or to be
  3784. segments that don't contain style tracks. If so, all embellishments are invalid. When all
  3785. embellishments are invalid, a NULL transition segment is returned.
  3786. <p pChordMap> may be NULL. If so, an attempt is made to obtain a ChordMap from a
  3787. ChordMap track, first from <p pToSeg>, and then from <p pFromSeg>. If neither of these
  3788. segments contains a ChordMap track, the chord occuring at <p mtTime> in <p pFromSeg> is
  3789. used as the chord in the transition.
  3790. */
  3791. HRESULT CDMCompos::ComposeTransition(
  3792. IDirectMusicSegment* pFromSeg, // @parm
  3793. // The section from which to compose the transition.
  3794. IDirectMusicSegment* pToSeg, // @parm
  3795. // The section to which the transition should smoothly flow.
  3796. MUSIC_TIME mtTime, // @parm
  3797. // The time in <p pFromSeg> from which to compose the transition.
  3798. WORD wCommand, // @parm
  3799. // The embellishment to use when composing the transition.
  3800. // DMUS_COMMANDT_ENDANDINTRO means compose a segment containing
  3801. // an end to <p pFromSeg> and an intro to <p pToSeg>.
  3802. DWORD dwFlags, // @parm
  3803. // Various composition options.
  3804. IDirectMusicChordMap* pChordMap, // @parm
  3805. // The ChordMap to be used when composing the transition.
  3806. IDirectMusicSegment** ppSectionSeg // @parm
  3807. // Returns the created section segment.
  3808. )
  3809. {
  3810. V_INAME(IDirectMusicComposer::ComposeTransition)
  3811. V_PTR_WRITE_OPT(pToSeg, 1);
  3812. V_PTR_WRITE_OPT(pFromSeg, 1);
  3813. V_PTR_WRITE_OPT(pChordMap, 1);
  3814. V_PTRPTR_WRITE(ppSectionSeg);
  3815. HRESULT hr = S_OK;
  3816. bool fHaveChordMap = pChordMap ? true : false;
  3817. DWORD dwGroupBits = ALL_TRACK_GROUPS;
  3818. DWORD dwIndex = DMUS_SEG_ANYTRACK;
  3819. bool fLong = (dwFlags & DMUS_COMPOSEF_LONG) ? true : false;
  3820. bool fModulate = (dwFlags & DMUS_COMPOSEF_MODULATE) ? true : false;
  3821. bool fEnding = wCommand == DMUS_COMMANDT_END || wCommand == DMUS_COMMANDT_ENDANDINTRO;
  3822. bool fHasIntro = wCommand == DMUS_COMMANDT_INTRO || wCommand == DMUS_COMMANDT_ENDANDINTRO;
  3823. if (!pToSeg && !fEnding && fModulate)
  3824. {
  3825. Trace(1, "ERROR (ComposeTransition): Invalid modulation.\n");
  3826. return E_INVALIDARG;
  3827. }
  3828. // Get Tool graphs from the To and From segments
  3829. IDirectMusicGraph* pFromGraph = CloneSegmentGraph(pFromSeg);
  3830. IDirectMusicGraph* pToGraph = CloneSegmentGraph(pToSeg);
  3831. // Get Audiopaths from the To and From segments
  3832. IUnknown* pFromPath = GetSegmentAudioPath(pFromSeg, dwFlags);
  3833. IUnknown* pToPath = GetSegmentAudioPath(pToSeg, dwFlags);
  3834. // Get the starting segment's style
  3835. IDirectMusicStyle* pFromStyle = NULL;
  3836. if (pFromSeg)
  3837. {
  3838. hr = GetStyle(pFromSeg, mtTime, ALL_TRACK_GROUPS, pFromStyle, false);
  3839. if (FAILED(hr)) pFromStyle = NULL;
  3840. }
  3841. // if no ChordMap is passed in, try to get one from the segments (first the
  3842. // TO segment, then the FROM segment). If these both fail, use the current chord
  3843. // as the chord for the transition. (if we're composing an ending, skip the TO segment)
  3844. hr = S_OK;
  3845. if (!pChordMap)
  3846. {
  3847. if (fEnding || !pToSeg || FAILED(GetPersonality(pToSeg, 0, ALL_TRACK_GROUPS, pChordMap)))
  3848. {
  3849. if (!pFromSeg || FAILED(GetPersonality(pFromSeg, mtTime, ALL_TRACK_GROUPS, pChordMap)))
  3850. pChordMap = NULL;
  3851. }
  3852. }
  3853. // Get a tempo from the From segment.
  3854. double dblFromTempo = 120.0;
  3855. double* pdblFromTempo = NULL;
  3856. if (pFromSeg && SUCCEEDED(GetTempo(pFromSeg, mtTime, &dblFromTempo)))
  3857. {
  3858. pdblFromTempo = &dblFromTempo;
  3859. }
  3860. DMUS_COMMAND_PARAM_2 Command;
  3861. if (!pFromSeg || FAILED(pFromSeg->GetParam(GUID_CommandParam2, dwGroupBits, dwIndex, mtTime, NULL, (void*) &Command)))
  3862. {
  3863. Command.mtTime = 0;
  3864. Command.bCommand = DMUS_COMMANDT_GROOVE;
  3865. Command.bGrooveLevel = 62;
  3866. Command.bGrooveRange = 0;
  3867. Command.bRepeatMode = DMUS_PATTERNT_RANDOM;
  3868. }
  3869. DMUS_CHORD_PARAM NextChord;
  3870. DMUS_CHORD_PARAM LastChord;
  3871. if (!pFromSeg || FAILED(pFromSeg->GetParam(GUID_ChordParam, dwGroupBits, dwIndex, mtTime, NULL, (void*) &LastChord)))
  3872. {
  3873. wcscpy(LastChord.wszName, L"M7");
  3874. LastChord.wMeasure = 0;
  3875. LastChord.bBeat = 0;
  3876. LastChord.bSubChordCount = 1;
  3877. LastChord.bKey = 12;
  3878. LastChord.dwScale = DEFAULT_SCALE_PATTERN;
  3879. LastChord.SubChordList[0].dwChordPattern = DEFAULT_CHORD_PATTERN;
  3880. LastChord.SubChordList[0].dwScalePattern = DEFAULT_SCALE_PATTERN;
  3881. LastChord.SubChordList[0].dwInversionPoints = 0xffffff;
  3882. LastChord.SubChordList[0].dwLevels = 0xffffffff;
  3883. LastChord.SubChordList[0].bChordRoot = 12; // 2C
  3884. LastChord.SubChordList[0].bScaleRoot = 0;
  3885. }
  3886. if ((fModulate || fHasIntro) && pToSeg)
  3887. {
  3888. hr = pToSeg->GetParam(GUID_ChordParam, dwGroupBits, dwIndex, 0, NULL, (void*) &NextChord);
  3889. }
  3890. else if (pFromSeg)
  3891. {
  3892. hr = pFromSeg->GetParam(GUID_ChordParam, dwGroupBits, dwIndex, 0, NULL, (void*) &NextChord);
  3893. }
  3894. else
  3895. {
  3896. hr = E_FAIL;
  3897. }
  3898. if (FAILED(hr))
  3899. {
  3900. wcscpy(NextChord.wszName, L"M7");
  3901. NextChord.wMeasure = 0;
  3902. NextChord.bBeat = 0;
  3903. NextChord.bSubChordCount = 1;
  3904. NextChord.bKey = 12;
  3905. NextChord.dwScale = DEFAULT_SCALE_PATTERN;
  3906. NextChord.SubChordList[0].dwChordPattern = DEFAULT_CHORD_PATTERN;
  3907. NextChord.SubChordList[0].dwScalePattern = DEFAULT_SCALE_PATTERN;
  3908. NextChord.SubChordList[0].dwInversionPoints = 0xffffff;
  3909. NextChord.SubChordList[0].dwLevels = 0xffffffff;
  3910. NextChord.SubChordList[0].bChordRoot = 12; // 2C
  3911. NextChord.SubChordList[0].bScaleRoot = 0;
  3912. }
  3913. hr = TransitionCommon(pFromStyle, NULL, pdblFromTempo, Command, LastChord, NextChord,
  3914. pToSeg, wCommand, dwFlags, pChordMap, pFromGraph, pToGraph, pFromPath, pToPath, ppSectionSeg);
  3915. if (pFromStyle) pFromStyle->Release();
  3916. if (!fHaveChordMap && pChordMap) pChordMap->Release();
  3917. if (pFromGraph) pFromGraph->Release();
  3918. if (pToGraph) pToGraph->Release();
  3919. if (pFromPath) pFromPath->Release();
  3920. if (pToPath) pToPath->Release();
  3921. return hr;
  3922. }
  3923. /*
  3924. @method:(EXTERNAL) HRESULT | IDirectMusicComposer | AutoTransition | Composes a
  3925. transition from inside a performance's primary segment to another segment, and then
  3926. queues the transition and the second segment to play.
  3927. @rdesc Returns:
  3928. @flag S_OK | Success
  3929. @flag E_POINTER | One or more of <p pPerformance>, <p pToSeg>, <p pChordMap>,
  3930. <p ppTransSeg>, <p ppToSegState>, and <p ppTransSegState> is not a valid pointer.
  3931. @comm Allowable values for <p dwFlags> include all values allowed for
  3932. <om IDirectMusicComposer::ComposeTransition>. Additionally, the following values are
  3933. allowed:
  3934. @flag DMUS_COMPOSEF_IMMEDIATE | Start transition on music or reference time boundary.
  3935. @flag DMUS_COMPOSEF_GRID | Start transition on grid boundary.
  3936. @flag DMUS_COMPOSEF_BEAT | Start transition on beat boundary.
  3937. @flag DMUS_COMPOSEF_MEASURE | Start transition on measure boundary.
  3938. @flag DMUS_COMPOSEF_AFTERPREPARETIME | Use the DMUS_SEGF_AFTERPREPARETIME flag when
  3939. queueing the transition.
  3940. <p ppTransSeg may be NULL. In this case, the transition segment is not returned.
  3941. <p pToSeg> may be NULL as long as <p dwFlags> does not include DMUS_COMPOSEF_MODULATE.
  3942. If <p pToSeg> is NULL or doesn't contain a style track, intro embellishments are not valid.
  3943. If the currently playing segment is NULL or doesn't contain a style track,
  3944. fill, break, end, and groove embellishments are not valid.
  3945. Note that the above implies that it is possible for both the currently playing segment and
  3946. <p pToSeg> to be NULL or to be
  3947. segments that don't contain style tracks. If so, all embellishments are invalid. When all
  3948. embellishments are invalid, no transition occurs between the currently playing segment
  3949. and <p pToSeg>.
  3950. <p pChordMap> may be NULL. If so, an attempt is made to obtain a ChordMap from a
  3951. ChordMap track, first from <p pToSeg>, and then from the performance's primary segment.
  3952. If neither of these
  3953. segments contains a ChordMap track, the chord occuring at <p mtTime> in the primary
  3954. segment is
  3955. used as the chord in the transition.
  3956. */
  3957. HRESULT CDMCompos::AutoTransition(
  3958. IDirectMusicPerformance* pPerformance, // @parm
  3959. // The performance in which to do the transition.
  3960. IDirectMusicSegment* pToSeg, // @parm
  3961. // The section to which the transition should smoothly flow.
  3962. WORD wCommand, // @parm
  3963. // The embellishment to use when composing the transition.
  3964. DWORD dwFlags, // @parm
  3965. // Various composition options.
  3966. IDirectMusicChordMap* pChordMap, // @parm
  3967. // The ChordMap to be used when composing the transition.
  3968. IDirectMusicSegment** ppTransSeg, // @parm
  3969. // Returns the created section segment.
  3970. IDirectMusicSegmentState** ppToSegState, // @parm
  3971. // Returns the segment state for the transition segment.
  3972. IDirectMusicSegmentState** ppTransSegState // @parm
  3973. // Returns the segment state for the segment following the transition.
  3974. )
  3975. {
  3976. // ppToSegState and ppTransSegState are checked in Performance::PlaySegment,
  3977. // BUT I need to check them here as well.
  3978. V_INAME(IDirectMusicComposer::AutoTransition)
  3979. V_PTR_WRITE_OPT(pToSeg, 1);
  3980. V_PTR_WRITE_OPT(pChordMap, 1);
  3981. V_PTR_WRITE(pPerformance, 1);
  3982. V_PTR_WRITE_OPT(ppTransSeg, 1);
  3983. V_PTR_WRITE_OPT(ppToSegState, 1);
  3984. V_PTR_WRITE_OPT(ppTransSegState, 1);
  3985. DWORD dwGroupBits = 0xffffffff;
  3986. DWORD dwIndex = DMUS_SEG_ANYTRACK;
  3987. DWORD dwResolution;
  3988. if (dwFlags & DMUS_COMPOSEF_MEASURE) dwResolution = DMUS_SEGF_MEASURE;
  3989. else if (dwFlags & DMUS_COMPOSEF_BEAT) dwResolution = DMUS_SEGF_BEAT;
  3990. else if (dwFlags & DMUS_COMPOSEF_GRID) dwResolution = DMUS_SEGF_GRID;
  3991. else if (dwFlags & DMUS_COMPOSEF_DEFAULT) dwResolution = DMUS_SEGF_DEFAULT;
  3992. else if (dwFlags & DMUS_COMPOSEF_IMMEDIATE) dwResolution = 0;
  3993. else dwResolution = DMUS_SEGF_MEASURE;
  3994. if (dwFlags & DMUS_COMPOSEF_ALIGN) dwResolution |= DMUS_SEGF_ALIGN;
  3995. if (dwFlags & DMUS_COMPOSEF_VALID_START_MEASURE) dwResolution |= DMUS_SEGF_VALID_START_MEASURE;
  3996. if (dwFlags & DMUS_COMPOSEF_VALID_START_BEAT) dwResolution |= DMUS_SEGF_VALID_START_BEAT;
  3997. if (dwFlags & DMUS_COMPOSEF_VALID_START_GRID) dwResolution |= DMUS_SEGF_VALID_START_GRID;
  3998. if (dwFlags & DMUS_COMPOSEF_VALID_START_TICK) dwResolution |= DMUS_SEGF_VALID_START_TICK;
  3999. if (dwFlags & DMUS_COMPOSEF_AFTERPREPARETIME) dwResolution |= DMUS_SEGF_AFTERPREPARETIME;
  4000. if (dwFlags & DMUS_COMPOSEF_NOINVALIDATE) dwResolution |= DMUS_SEGF_NOINVALIDATE;
  4001. if (dwFlags & DMUS_COMPOSEF_INVALIDATE_PRI) dwResolution |= DMUS_SEGF_INVALIDATE_PRI;
  4002. if (dwFlags & DMUS_COMPOSEF_USE_AUDIOPATH) dwResolution |= DMUS_SEGF_USE_AUDIOPATH;
  4003. DWORD dwUseAudioPath = dwResolution & DMUS_SEGF_USE_AUDIOPATH;
  4004. IDirectMusicSegment* pTransSeg = NULL;
  4005. if (!ppTransSeg)
  4006. {
  4007. ppTransSeg = &pTransSeg;
  4008. }
  4009. IDirectMusicChordMap* pFromChordMap = NULL;
  4010. bool bReleaseFromChordMap = false;
  4011. double dblFromTempo = 120.0;
  4012. double* pdblFromTempo = NULL;
  4013. IDirectMusicStyle* pFromStyle = NULL;
  4014. IDirectMusicBand* pBand = NULL;
  4015. IDirectMusicSegmentState* pSegState = NULL;
  4016. IDirectMusicSegment* pFromSegment = NULL;
  4017. bool fModulate = (dwFlags & DMUS_COMPOSEF_MODULATE) ? true : false;
  4018. bool fEnding = wCommand == DMUS_COMMANDT_END || wCommand == DMUS_COMMANDT_ENDANDINTRO;
  4019. bool fHasIntro = wCommand == DMUS_COMMANDT_INTRO || wCommand == DMUS_COMMANDT_ENDANDINTRO;
  4020. if (!pToSeg && !fEnding && fModulate)
  4021. {
  4022. Trace(1, "ERROR (AutoTransition): Invalid modulation.\n");
  4023. return E_INVALIDARG;
  4024. }
  4025. MUSIC_TIME mtTime, mt;
  4026. MUSIC_TIME mtStart;
  4027. REFERENCE_TIME rt, rtResolved;
  4028. HRESULT hr = pPerformance->GetQueueTime(&rt);
  4029. if (SUCCEEDED(hr)) hr = pPerformance->GetResolvedTime(rt, &rtResolved, dwResolution);
  4030. if (SUCCEEDED(hr)) hr = pPerformance->ReferenceToMusicTime(rtResolved, &mtTime);
  4031. if (SUCCEEDED(hr)) hr = pPerformance->ReferenceToMusicTime(rt, &mt);
  4032. if (!SUCCEEDED(hr)) return hr;
  4033. if (rtResolved > rt) mtTime--;
  4034. hr = pPerformance->GetSegmentState(&pSegState, mtTime);
  4035. if (SUCCEEDED(hr))
  4036. {
  4037. hr = pSegState->GetStartTime(&mtStart);
  4038. TraceI(3, "Time: %d Resolved Time: %d\n", mt - mtStart, mtTime - mtStart);
  4039. if (!SUCCEEDED(hr))
  4040. {
  4041. goto ON_END;
  4042. }
  4043. hr = pSegState->GetSegment(&pFromSegment);
  4044. if (!SUCCEEDED(hr))
  4045. {
  4046. goto ON_END;
  4047. }
  4048. if (dwFlags & DMUS_COMPOSEF_SEGMENTEND)
  4049. {
  4050. MUSIC_TIME mtLength;
  4051. if( SUCCEEDED( pFromSegment->GetLength( &mtLength ) ) )
  4052. {
  4053. mtTime = mtLength - 1;
  4054. mtStart = 0;
  4055. }
  4056. }
  4057. }
  4058. else pSegState = NULL;
  4059. // Get the starting segment's style
  4060. if (pPerformance)
  4061. {
  4062. hr = pPerformance->GetParam(GUID_IDirectMusicStyle, dwGroupBits, dwIndex, mtTime, NULL, (void*)&pFromStyle);
  4063. if (FAILED(hr)) pFromStyle = NULL;
  4064. }
  4065. // if no ChordMap is passed in, try to get one (first from the TO segment,
  4066. // then the FROM segment). If these both fail, use the current chord
  4067. // as the chord for the transition. (if we're composing an ending, skip the TO segment)
  4068. hr = S_OK;
  4069. if (!pChordMap)
  4070. {
  4071. if (fEnding || !pToSeg || FAILED(GetPersonality(pToSeg, 0, dwGroupBits, pFromChordMap)))
  4072. {
  4073. if (!pFromSegment || FAILED(GetPersonality(pFromSegment, 0, dwGroupBits, pFromChordMap)))
  4074. {
  4075. pFromChordMap = NULL;
  4076. }
  4077. }
  4078. if(pFromChordMap)
  4079. {
  4080. bReleaseFromChordMap = true;
  4081. }
  4082. }
  4083. else
  4084. {
  4085. pFromChordMap = pChordMap;
  4086. }
  4087. DMUS_COMMAND_PARAM_2 Command;
  4088. if (FAILED(pPerformance->GetParam(GUID_CommandParam2, dwGroupBits, dwIndex, mtTime, NULL, (void*) &Command)))
  4089. {
  4090. Command.mtTime = 0;
  4091. Command.bCommand = DMUS_COMMANDT_GROOVE;
  4092. Command.bGrooveLevel = 62;
  4093. Command.bGrooveRange = 0;
  4094. Command.bRepeatMode = DMUS_PATTERNT_RANDOM;
  4095. }
  4096. DMUS_CHORD_PARAM NextChord;
  4097. DMUS_CHORD_PARAM LastChord;
  4098. if (FAILED(pPerformance->GetParam(GUID_ChordParam, dwGroupBits, dwIndex, mtTime, NULL, (void*) &LastChord)))
  4099. {
  4100. wcscpy(LastChord.wszName, L"M7");
  4101. LastChord.wMeasure = 0;
  4102. LastChord.bBeat = 0;
  4103. LastChord.bSubChordCount = 1;
  4104. LastChord.bKey = 12;
  4105. LastChord.dwScale = DEFAULT_SCALE_PATTERN;
  4106. LastChord.SubChordList[0].dwChordPattern = DEFAULT_CHORD_PATTERN;
  4107. LastChord.SubChordList[0].dwScalePattern = DEFAULT_SCALE_PATTERN;
  4108. LastChord.SubChordList[0].dwInversionPoints = 0xffffff;
  4109. LastChord.SubChordList[0].dwLevels = 0xffffffff;
  4110. LastChord.SubChordList[0].bChordRoot = 12; // 2C
  4111. LastChord.SubChordList[0].bScaleRoot = 0;
  4112. }
  4113. if ((fModulate || fHasIntro) && pToSeg)
  4114. {
  4115. hr = pToSeg->GetParam(GUID_ChordParam, dwGroupBits, dwIndex, 0, NULL, (void*) &NextChord);
  4116. }
  4117. else
  4118. {
  4119. // Check that this is the correct thing to do if pFromSegment is NULL.
  4120. hr = pFromSegment ? pFromSegment->GetParam(GUID_ChordParam, dwGroupBits, dwIndex, 0, NULL, (void*) &NextChord) : E_FAIL;
  4121. }
  4122. if (FAILED(hr))
  4123. {
  4124. wcscpy(NextChord.wszName, L"M7");
  4125. NextChord.wMeasure = 0;
  4126. NextChord.bBeat = 0;
  4127. NextChord.bSubChordCount = 1;
  4128. NextChord.bKey = 12;
  4129. NextChord.dwScale = DEFAULT_SCALE_PATTERN;
  4130. NextChord.SubChordList[0].dwChordPattern = DEFAULT_CHORD_PATTERN;
  4131. NextChord.SubChordList[0].dwScalePattern = DEFAULT_SCALE_PATTERN;
  4132. NextChord.SubChordList[0].dwInversionPoints = 0xffffff;
  4133. NextChord.SubChordList[0].dwLevels = 0xffffffff;
  4134. NextChord.SubChordList[0].bChordRoot = 12; // 2C
  4135. NextChord.SubChordList[0].bScaleRoot = 0;
  4136. }
  4137. // If < DX8 content for From segment (or playing transition from segment end),
  4138. // call ComposeTransition; otherwise, call TransitionCommon
  4139. if (!UsingDX8(pFromStyle, pFromChordMap, pFromSegment, &Command, &LastChord) ||
  4140. (dwFlags & DMUS_COMPOSEF_SEGMENTEND) )
  4141. {
  4142. if (pSegState)
  4143. {
  4144. hr = ComposeTransition(pFromSegment, pToSeg, mtTime - mtStart, wCommand, dwFlags, pChordMap, ppTransSeg);
  4145. }
  4146. else
  4147. {
  4148. hr = ComposeTransition(NULL, pToSeg, 0, wCommand, dwFlags, pChordMap, ppTransSeg);
  4149. }
  4150. }
  4151. else
  4152. {
  4153. // Get Tool graphs from the To and From segments
  4154. IDirectMusicGraph* pFromGraph = CloneSegmentGraph(pFromSegment);
  4155. IDirectMusicGraph* pToGraph = CloneSegmentGraph(pToSeg);
  4156. // Get Audiopaths from the To and From segments
  4157. IUnknown* pFromPath = GetSegmentAudioPath(pFromSegment, dwFlags);
  4158. IUnknown* pToPath = GetSegmentAudioPath(pToSeg, dwFlags, &dwUseAudioPath);
  4159. // Get a tempo from the performance.
  4160. DMUS_TEMPO_PARAM Tempo;
  4161. if (SUCCEEDED(pPerformance->GetParam(GUID_TempoParam, dwGroupBits, dwIndex, mtTime, NULL, (void*)&Tempo)))
  4162. {
  4163. dblFromTempo = Tempo.dblTempo;
  4164. pdblFromTempo = &dblFromTempo;
  4165. }
  4166. // Get the currently playing band
  4167. DMUS_BAND_PARAM DMBand;
  4168. if (SUCCEEDED(pPerformance->GetParam(GUID_BandParam, dwGroupBits, dwIndex, mtTime, NULL, (void*)&DMBand)))
  4169. {
  4170. pBand = DMBand.pBand;
  4171. }
  4172. hr = TransitionCommon(pFromStyle, pBand, pdblFromTempo, Command, LastChord, NextChord,
  4173. pToSeg, wCommand, dwFlags, pFromChordMap, pFromGraph, pToGraph, pFromPath, pToPath, ppTransSeg);
  4174. if (pFromGraph) pFromGraph->Release();
  4175. if (pToGraph) pToGraph->Release();
  4176. if (pFromPath) pFromPath->Release();
  4177. if (pToPath) pToPath->Release();
  4178. }
  4179. if (SUCCEEDED(hr))
  4180. {
  4181. if (*ppTransSeg && pToSeg)
  4182. {
  4183. DMUS_COMMAND_PARAM_2 CommandParam;
  4184. if (SUCCEEDED(pToSeg->GetParam(GUID_CommandParam2, dwGroupBits, dwIndex, 0, NULL, (void*) &CommandParam)))
  4185. {
  4186. (*ppTransSeg)->SetParam(GUID_CommandParamNext, dwGroupBits, 0, 0, (void*) &CommandParam);
  4187. }
  4188. }
  4189. if (dwFlags & DMUS_COMPOSEF_SEGMENTEND) dwResolution |= DMUS_SEGF_SEGMENTEND;
  4190. if (dwFlags & DMUS_COMPOSEF_MARKER) dwResolution |= DMUS_SEGF_MARKER;
  4191. DWORD dwQueueResolution = DMUS_SEGF_QUEUE | dwUseAudioPath;
  4192. hr = S_OK;
  4193. if (*ppTransSeg)
  4194. {
  4195. hr = pPerformance->PlaySegment(*ppTransSeg, dwResolution, 0, ppTransSegState);
  4196. if (SUCCEEDED(hr) && pToSeg)
  4197. {
  4198. hr = pPerformance->PlaySegment(pToSeg, dwQueueResolution, 0, ppToSegState);
  4199. }
  4200. }
  4201. else
  4202. {
  4203. if (!pToSeg)
  4204. {
  4205. if (!(dwFlags & DMUS_COMPOSEF_SEGMENTEND))
  4206. {
  4207. hr = pPerformance->Stop(pFromSegment, NULL, 0, dwResolution);
  4208. }
  4209. }
  4210. else
  4211. {
  4212. hr = pPerformance->PlaySegment(pToSeg, dwResolution, 0, ppToSegState);
  4213. }
  4214. }
  4215. }
  4216. ON_END:
  4217. if (pFromStyle) pFromStyle->Release();
  4218. if (pBand) pBand->Release();
  4219. if (pTransSeg) pTransSeg->Release();
  4220. if (pSegState) pSegState->Release();
  4221. if (pFromSegment) pFromSegment->Release();
  4222. if (bReleaseFromChordMap) pFromChordMap->Release();
  4223. return hr;
  4224. }
  4225. /*
  4226. @method:(EXTERNAL) HRESULT | IDirectMusicComposer | ComposeTemplateFromShape | Creates
  4227. a new template segment based on a predefined shape.
  4228. @rdesc Returns:
  4229. @flag S_OK | Success
  4230. @flag E_POINTER | <p ppTempSeg> is not a valid pointer.
  4231. @flag E_OUTOFMEMORY | An attempt to allocate memory failed.
  4232. @flag E_INVALIDARG | <p wNumMeasures> is 0, or <p fComposeEnding> is TRUE and either
  4233. <p wEndLength> is 0 or <p wEndLength> is greater than the number of non-intro measures.
  4234. @comm Shapes (passed in <p wShape>) represent the way chords and embellishments
  4235. occur over time across the section. There are nine shapes:
  4236. @flag DMUS_SHAPET_FALLING | The section gets quieter over time.
  4237. @flag DMUS_SHAPET_LEVEL | The section remains at the same level.
  4238. @flag DMUS_SHAPET_LOOPABLE | The section is arranged to loop back to its beginning.
  4239. @flag DMUS_SHAPET_LOUD | The section remains loud.
  4240. @flag DMUS_SHAPET_QUIET | The section remains quiet.
  4241. @flag DMUS_SHAPET_PEAKING | The section peaks.
  4242. @flag DMUS_SHAPET_RANDOM | The section is random.
  4243. @flag DMUS_SHAPET_RISING | The section builds over time.
  4244. @flag DMUS_SHAPET_SONG | The section is in a song form.
  4245. */
  4246. HRESULT CDMCompos::ComposeTemplateFromShape(
  4247. WORD wNumMeasures, // @parm The length, in measures, to compose the section segment
  4248. WORD wShape,// @parm The shape to compose the section segment.
  4249. BOOL fComposeIntro,// @parm TRUE if an intro is to be composed for the section segment.
  4250. BOOL fComposeEnding,// @parm TRUE if an ending is to be composed for the section segment.
  4251. WORD wEndLength, // @parm Length in measures of the ending, if one is to be composed.
  4252. IDirectMusicSegment** ppTempSeg // @parm Returns the created template segment.
  4253. )
  4254. {
  4255. V_INAME(IDirectMusicComposer::ComposeTemplateFromShape)
  4256. V_PTRPTR_WRITE(ppTempSeg);
  4257. return ComposeTemplateFromShapeInternal(wNumMeasures, wShape, fComposeIntro, fComposeEnding,
  4258. 1, 1, 1, (int)wEndLength, ppTempSeg);
  4259. }
  4260. HRESULT CDMCompos::ComposeTemplateFromShapeEx(
  4261. WORD wNumMeasures, // Number of measures in template
  4262. WORD wShape, // Shape for composition
  4263. BOOL fIntro, // Compose an intro?
  4264. BOOL fEnd, // Compose an ending?
  4265. IDirectMusicStyle* pStyle, // Style used for embellishment lengths
  4266. IDirectMusicSegment** ppTemplate // Template containing chord and command tracks
  4267. )
  4268. {
  4269. V_INAME(IDirectMusicComposer::ComposeTemplateFromShapeEx)
  4270. V_PTRPTR_WRITE(ppTemplate);
  4271. V_PTR_WRITE_OPT(pStyle, 1);
  4272. HRESULT hr = S_OK;
  4273. int nIntroLength = 1;
  4274. int nFillLength = 1;
  4275. int nBreakLength = 1;
  4276. int nEndLength = 1;
  4277. if (pStyle)
  4278. {
  4279. DWORD dwMin, dwMax;
  4280. hr = pStyle->GetEmbellishmentLength(DMUS_COMMANDT_INTRO, 0, &dwMin, &dwMax);
  4281. if (hr == S_OK) nIntroLength = (int) dwMax;
  4282. hr = pStyle->GetEmbellishmentLength(DMUS_COMMANDT_FILL, 0, &dwMin, &dwMax);
  4283. if (hr == S_OK) nFillLength = (int) dwMax;
  4284. hr = pStyle->GetEmbellishmentLength(DMUS_COMMANDT_BREAK, 0, &dwMin, &dwMax);
  4285. if (hr == S_OK) nBreakLength = (int) dwMax;
  4286. hr = pStyle->GetEmbellishmentLength(DMUS_COMMANDT_END, 0, &dwMin, &dwMax);
  4287. if (hr == S_OK) nEndLength = (int) dwMax;
  4288. }
  4289. return ComposeTemplateFromShapeInternal(wNumMeasures, wShape, fIntro, fEnd,
  4290. nIntroLength, nFillLength, nBreakLength, nEndLength, ppTemplate);
  4291. }
  4292. HRESULT CDMCompos::ComposeTemplateFromShapeInternal(
  4293. WORD wNumMeasures,
  4294. WORD wShape,
  4295. BOOL fComposeIntro,
  4296. BOOL fComposeEnding,
  4297. int nIntroLength,
  4298. int nFillLength,
  4299. int nBreakLength,
  4300. int nEndLength,
  4301. IDirectMusicSegment** ppTempSeg
  4302. )
  4303. {
  4304. HRESULT hr;
  4305. if ( !wNumMeasures ||
  4306. (fComposeEnding && !nEndLength) ||
  4307. (fComposeIntro && !nIntroLength) ||
  4308. (fComposeEnding && fComposeIntro && (nEndLength + nIntroLength) > wNumMeasures) ||
  4309. (fComposeEnding && (nEndLength > wNumMeasures)) ||
  4310. (fComposeIntro && (nIntroLength > wNumMeasures)) )
  4311. {
  4312. Trace(1, "ERROR (ComposeTemplateFromShape): Invalid template length.\n");
  4313. return E_INVALIDARG;
  4314. }
  4315. if (wNumMeasures & 0x8000 || wNumMeasures == 0) wNumMeasures = 1;
  4316. int nNumMeasures = (int)wNumMeasures;
  4317. if (fComposeEnding)
  4318. {
  4319. if (nEndLength <= 0) nEndLength = 1;
  4320. }
  4321. if (wShape != DMUS_SHAPET_FALLING &&
  4322. wShape != DMUS_SHAPET_LEVEL &&
  4323. wShape != DMUS_SHAPET_LOOPABLE &&
  4324. wShape != DMUS_SHAPET_LOUD &&
  4325. wShape != DMUS_SHAPET_QUIET &&
  4326. wShape != DMUS_SHAPET_PEAKING &&
  4327. wShape != DMUS_SHAPET_RANDOM &&
  4328. wShape != DMUS_SHAPET_RISING &&
  4329. wShape != DMUS_SHAPET_SONG)
  4330. {
  4331. wShape = DMUS_SHAPET_RANDOM;
  4332. }
  4333. int nOriginalMeasures = 0;
  4334. bool f1Bar = false;
  4335. if (fComposeIntro)
  4336. {
  4337. nNumMeasures -= nIntroLength;
  4338. if (nNumMeasures < nIntroLength)
  4339. {
  4340. f1Bar = true;
  4341. nNumMeasures = nIntroLength;
  4342. }
  4343. }
  4344. if (fComposeEnding)
  4345. {
  4346. int nLength = nEndLength;
  4347. nOriginalMeasures = nNumMeasures;
  4348. nNumMeasures -= (nLength - 1);
  4349. if (nNumMeasures < 1)
  4350. {
  4351. nNumMeasures = 1;
  4352. }
  4353. }
  4354. TemplateStruct* pTemplate = new TemplateStruct;
  4355. if (!pTemplate) return E_OUTOFMEMORY;
  4356. TemplateStruct* apTempl[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  4357. if ((wShape != DMUS_SHAPET_SONG) || (nNumMeasures <= 24))
  4358. {
  4359. if (wShape == DMUS_SHAPET_LOOPABLE) nNumMeasures++;
  4360. pTemplate->m_nMeasures = (short)nNumMeasures;
  4361. pTemplate->CreateSignPosts();
  4362. pTemplate->CreateEmbellishments(wShape, nFillLength, nBreakLength);
  4363. if (wShape == DMUS_SHAPET_LOOPABLE)
  4364. {
  4365. nNumMeasures--;
  4366. pTemplate->m_nMeasures = (short)nNumMeasures;
  4367. }
  4368. }
  4369. else
  4370. {
  4371. short nShortestLength = 12; // initialized to longest value in sanLengths
  4372. int anLengths[8];
  4373. int anGrooveLevel[8];
  4374. BYTE abLeadins[8];
  4375. int nTypeCount = 2;
  4376. unsigned int nSize = (unsigned int) nNumMeasures >> 5;
  4377. int nTypeIndex;
  4378. int nMeasure;
  4379. int nChoice, nLastChoice;
  4380. while (nSize)
  4381. {
  4382. nTypeCount++;
  4383. nSize = nSize >> 1;
  4384. if (nTypeCount >= 8) break;
  4385. }
  4386. for (nTypeIndex = 1; nTypeIndex < nTypeCount; nTypeIndex++)
  4387. {
  4388. apTempl[nTypeIndex] = new TemplateStruct;
  4389. if (!apTempl[nTypeIndex])
  4390. {
  4391. hr = E_OUTOFMEMORY;
  4392. goto ON_END;
  4393. }
  4394. static WORD awShapes[8] = {
  4395. DMUS_SHAPET_FALLING, DMUS_SHAPET_LEVEL, DMUS_SHAPET_LOUD, DMUS_SHAPET_QUIET,
  4396. DMUS_SHAPET_RANDOM, DMUS_SHAPET_RANDOM, DMUS_SHAPET_RANDOM, DMUS_SHAPET_RANDOM };
  4397. static int anInitGroovels[8] = { 0,-1,0,0,1,-1,2,-2 };
  4398. static BYTE abRiffs[8] = {
  4399. DMUS_COMMANDT_FILL, DMUS_COMMANDT_BREAK, DMUS_COMMANDT_FILL, DMUS_COMMANDT_BREAK,
  4400. DMUS_COMMANDT_FILL, DMUS_COMMANDT_FILL, DMUS_COMMANDT_BREAK, DMUS_COMMANDT_FILL };
  4401. static short sanLengths[10] = { 8,8,8,8,6,12,8,8,10,6 };
  4402. short nLength = sanLengths[rand() % 10];
  4403. apTempl[nTypeIndex]->m_nMeasures = nLength;
  4404. anLengths[nTypeIndex] = nLength;
  4405. if (nLength)
  4406. {
  4407. if (nShortestLength > nLength) nShortestLength = nLength;
  4408. apTempl[nTypeIndex]->CreateSignPosts();
  4409. apTempl[nTypeIndex]->CreateEmbellishments(awShapes[nTypeIndex], nFillLength, nBreakLength);
  4410. anGrooveLevel[nTypeIndex] = anInitGroovels[nTypeIndex];
  4411. if (rand() % 4) abLeadins[nTypeIndex] = abRiffs[nTypeIndex];
  4412. else abLeadins[nTypeIndex] = 0;
  4413. }
  4414. }
  4415. anGrooveLevel[0] = 0;
  4416. pTemplate->m_nMeasures = (short)nNumMeasures;
  4417. nMeasure = 0;
  4418. nChoice = 1;
  4419. nLastChoice = 0;
  4420. for (; nMeasure < nNumMeasures; )
  4421. {
  4422. int nGroove;
  4423. int nNewChoice;
  4424. if ((nNumMeasures - nMeasure) <= nShortestLength)
  4425. {
  4426. nChoice = 0;
  4427. short nLength = nNumMeasures - nMeasure;
  4428. apTempl[0] = new TemplateStruct;
  4429. if (!apTempl[0])
  4430. {
  4431. hr = E_OUTOFMEMORY;
  4432. goto ON_END;
  4433. }
  4434. apTempl[0]->m_nMeasures = nLength;
  4435. anLengths[0] = nLength;
  4436. apTempl[0]->CreateSignPosts();
  4437. apTempl[0]->CreateEmbellishments(DMUS_SHAPET_FALLING, nFillLength, nBreakLength);
  4438. anGrooveLevel[0] = 0;
  4439. if (rand() % 4) abLeadins[0] = DMUS_COMMANDT_FILL;
  4440. else abLeadins[0] = 0;
  4441. }
  4442. nGroove = anGrooveLevel[nChoice];
  4443. pTemplate->IncorporateTemplate((short)nMeasure, apTempl[nChoice], (short)nGroove);
  4444. if ( (abLeadins[nChoice] == DMUS_COMMANDT_FILL && nMeasure >= nFillLength) )
  4445. {
  4446. InsertCommand(nMeasure, nFillLength, pTemplate->m_CommandList, abLeadins[nChoice]);
  4447. }
  4448. else if ( (abLeadins[nChoice] == DMUS_COMMANDT_BREAK && nMeasure >= nBreakLength) )
  4449. {
  4450. InsertCommand(nMeasure, nBreakLength, pTemplate->m_CommandList, abLeadins[nChoice]);
  4451. }
  4452. if (anGrooveLevel[nChoice] < 0) anGrooveLevel[nChoice]++;
  4453. else
  4454. {
  4455. if (rand() % 3)
  4456. {
  4457. if (rand() % 2)
  4458. {
  4459. anGrooveLevel[nChoice]++;
  4460. }
  4461. else
  4462. {
  4463. anGrooveLevel[nChoice]--;
  4464. }
  4465. }
  4466. }
  4467. nMeasure += anLengths[nChoice];
  4468. nNewChoice = WeightedRand(nTypeCount - 1) + 1;
  4469. if ((nNewChoice == nChoice) && (nNewChoice == nLastChoice))
  4470. {
  4471. nNewChoice = WeightedRand(nTypeCount - 1) + 1;
  4472. }
  4473. if (nNewChoice == nChoice)
  4474. {
  4475. nNewChoice = WeightedRand(nTypeCount - 1) + 1;
  4476. }
  4477. // If there are enough measures for some but not all of the
  4478. // patterns, find a pattern that fits
  4479. if ((nNumMeasures - nMeasure) > nShortestLength)
  4480. {
  4481. while ((nNumMeasures - nMeasure) < anLengths[nNewChoice])
  4482. {
  4483. nNewChoice = WeightedRand(nTypeCount - 1) + 1;
  4484. }
  4485. }
  4486. nLastChoice = nChoice;
  4487. nChoice = nNewChoice;
  4488. }
  4489. pTemplate->m_CommandList.MergeSort(Less);
  4490. }
  4491. if (fComposeEnding)
  4492. {
  4493. int nLength = nEndLength;
  4494. if (nNumMeasures != nOriginalMeasures)
  4495. {
  4496. pTemplate->m_nMeasures = (short)nOriginalMeasures;
  4497. }
  4498. if (nLength > nOriginalMeasures)
  4499. {
  4500. nLength = nOriginalMeasures;
  4501. }
  4502. pTemplate->AddEnd(nLength);
  4503. }
  4504. if (fComposeIntro)
  4505. {
  4506. pTemplate->AddIntro(f1Bar, nIntroLength);
  4507. }
  4508. // build the template segment...
  4509. IDMTempl* pITemplate;
  4510. hr = S_OK;
  4511. hr = CoCreateInstance(
  4512. CLSID_DMTempl,
  4513. NULL,
  4514. CLSCTX_INPROC,
  4515. IID_IDMTempl,
  4516. (void**)&pITemplate);
  4517. if (SUCCEEDED(hr))
  4518. {
  4519. pITemplate->Init(pTemplate);
  4520. hr = CoCreateInstance(
  4521. CLSID_DirectMusicSegment,
  4522. NULL,
  4523. CLSCTX_INPROC,
  4524. IID_IDirectMusicSegment,
  4525. (void**)ppTempSeg);
  4526. if (SUCCEEDED(hr))
  4527. {
  4528. pITemplate->CreateSegment(*ppTempSeg);
  4529. }
  4530. pITemplate->Release();
  4531. }
  4532. ON_END:
  4533. for (short n = 0; n < 8; n++)
  4534. {
  4535. if (apTempl[n])
  4536. {
  4537. delete apTempl[n];
  4538. }
  4539. }
  4540. return hr;
  4541. }
  4542. inline char ShiftRoot(DWORD dwScale, BYTE bRoot)
  4543. {
  4544. switch (dwScale & 0xfff)
  4545. {
  4546. case 0x56b: bRoot += 1; break; // C#
  4547. case 0xad6: bRoot += 2; break; // D
  4548. case 0x5ad: bRoot += 3; break; // D#
  4549. case 0xb5a: bRoot += 4; break; // E
  4550. case 0x6b5: bRoot += 5; break; // F
  4551. case 0xd6a: bRoot += 6; break; // F#
  4552. case 0xad5: bRoot += 7; break; // G
  4553. case 0x5ab: bRoot += 8; break; // G#
  4554. case 0xb56: bRoot += 9; break; // A
  4555. case 0x6ad: bRoot += 10; break; // A#
  4556. case 0xd5a: bRoot += 11; break; // B
  4557. }
  4558. return (char) (bRoot %= 12);
  4559. }
  4560. /*
  4561. @method:(EXTERNAL) HRESULT | IDirectMusicComposer | ChangeChordMap | Modifies the chords
  4562. and scale pattern of an existing section segment to reflect the new ChordMap.
  4563. @rdesc Returns:
  4564. @flag S_OK | Success.
  4565. @flag E_POINTER | Either <p pSectionSeg> or <p pChordMap> is not a valid pointer.
  4566. @comm
  4567. */
  4568. HRESULT CDMCompos::ChangeChordMap(
  4569. IDirectMusicSegment* pSectionSeg, // @parm The section to change the ChordMap upon.
  4570. BOOL fTrackScale, // @parm If TRUE, does scale tracking.
  4571. IDirectMusicChordMap* pChordMap // @parm The ChordMap to change the section.
  4572. )
  4573. {
  4574. V_INAME(IDirectMusicComposer::ChangeChordMap)
  4575. V_PTR_WRITE(pSectionSeg, 1);
  4576. V_PTR_WRITE(pChordMap, 1);
  4577. HRESULT hr = S_OK;
  4578. IDMPers* pDMP = NULL;
  4579. IDirectMusicTrack* pChordTrack = NULL;
  4580. IDirectMusicStyle* pStyle = NULL;
  4581. IPersistStream* pPS = NULL;
  4582. IStream* pStream = NULL;
  4583. IAARIFFStream* pChordRIFF = NULL;
  4584. TList<PlayChord> ChordList;
  4585. BYTE bSectionRoot = 0;
  4586. DWORD dwSectionScale = 0;
  4587. TListItem<PlayChord>* pChords = NULL;
  4588. DMPersonalityStruct* pPers = NULL;
  4589. BYTE bNewRoot = 0;
  4590. DWORD dwNewScale = 0;
  4591. char chOffset = 0;
  4592. EnterCriticalSection( &m_CriticalSection );
  4593. pChordMap->QueryInterface(IID_IDMPers, (void**)&pDMP);
  4594. pDMP->GetPersonalityStruct((void**)&pPers);
  4595. if (!pPers)
  4596. {
  4597. Trace(1, "ERROR (ChangeChordMap): Chord map not properly initialized.\n");
  4598. hr = DMUS_E_NOT_INIT;
  4599. goto ON_END;
  4600. }
  4601. // Get the segment's chord track.
  4602. hr = pSectionSeg->GetTrack(CLSID_DirectMusicChordTrack, ALL_TRACK_GROUPS, 0, &pChordTrack);
  4603. if (S_OK != hr) goto ON_END;
  4604. // Write the track to a stream, and read from the stream into a chord list.
  4605. hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
  4606. if (S_OK != hr) goto ON_END;
  4607. hr = pChordTrack->QueryInterface(IID_IPersistStream, (void**)&pPS);
  4608. if (S_OK != hr) goto ON_END;
  4609. hr = pPS->Save(pStream, FALSE);
  4610. if (S_OK != hr) goto ON_END;
  4611. StreamSeek(pStream, 0, STREAM_SEEK_SET);
  4612. LoadChordList(ChordList, pStream, bSectionRoot, dwSectionScale);
  4613. bSectionRoot %= 24;
  4614. pChordMap->GetScale(&dwNewScale);
  4615. bNewRoot = (BYTE) (dwNewScale >> 24);
  4616. dwNewScale &= 0xffffff;
  4617. if (pPers->m_dwChordMapFlags & DMUS_CHORDMAPF_VERSION8)
  4618. {
  4619. BYTE bTempRoot = bSectionRoot % 12;
  4620. if (bNewRoot < bTempRoot) bNewRoot += 12;
  4621. chOffset = (bNewRoot - bTempRoot) % 12;
  4622. }
  4623. else
  4624. {
  4625. chOffset = ShiftRoot(dwNewScale, bNewRoot) - ShiftRoot(dwSectionScale, bSectionRoot);
  4626. }
  4627. // Modify the chords in the chord list to match the new personality's chord palette.
  4628. for (pChords = ChordList.GetHead(); pChords; pChords = pChords->GetNext())
  4629. {
  4630. PlayChord& rChord = pChords->GetItemValue();
  4631. char chRoot = rChord.GetRoot();
  4632. if (fTrackScale)
  4633. {
  4634. chRoot += chOffset;
  4635. }
  4636. TListItem<DMChordData> *pPalette;
  4637. char chNewRoot = chRoot - bSectionRoot;
  4638. while (chNewRoot < 0) chNewRoot += 12;
  4639. while (chNewRoot > 23) chNewRoot -= 12;
  4640. pPalette = pPers->m_aChordPalette[chNewRoot].GetHead();
  4641. if (!pPalette)
  4642. {
  4643. Trace(1, "ERROR (ChangeChordMap): No Chord Pallette for root %d.\n", chNewRoot);
  4644. hr = E_POINTER;
  4645. goto ON_END;
  4646. }
  4647. if (rChord.m_pChord)
  4648. {
  4649. rChord.m_pChord->Release();
  4650. delete rChord.m_pChord;
  4651. }
  4652. rChord.m_pChord = new DMChordData(pPalette->GetItemValue());
  4653. if (!rChord.m_pChord)
  4654. {
  4655. hr = E_OUTOFMEMORY;
  4656. goto ON_END;
  4657. }
  4658. }
  4659. pStream->Release();
  4660. hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
  4661. if (S_OK != hr) goto ON_END;
  4662. hr = AllocRIFFStream( pStream, &pChordRIFF);
  4663. if (S_OK != hr) goto ON_END;
  4664. // Get the segment's first style
  4665. hr = GetStyle(pSectionSeg, 0, ALL_TRACK_GROUPS, pStyle, true);
  4666. if (FAILED(hr)) goto ON_END;
  4667. // Extract the style's time signature.
  4668. DMUS_TIMESIGNATURE TimeSig;
  4669. pStyle->GetTimeSignature(&TimeSig);
  4670. SaveChordList(pChordRIFF, ChordList, bNewRoot, dwNewScale, TimeSig);
  4671. pPS->Release();
  4672. pPS = NULL;
  4673. // Load the modified chord list into the chord track
  4674. hr = pChordTrack->QueryInterface(IID_IPersistStream, (void**)&pPS);
  4675. if (!SUCCEEDED(hr)) goto ON_END;
  4676. StreamSeek(pStream, 0, STREAM_SEEK_SET);
  4677. hr = pPS->Load(pStream);
  4678. ON_END:
  4679. //ChordList.RemoveAll();
  4680. Clear(ChordList);
  4681. if (pPS)
  4682. {
  4683. pPS->Release();
  4684. }
  4685. if (pChordTrack)
  4686. {
  4687. pChordTrack->Release();
  4688. }
  4689. if (pChordRIFF)
  4690. {
  4691. pChordRIFF->Release();
  4692. }
  4693. if (pStyle)
  4694. {
  4695. pStyle->Release();
  4696. }
  4697. if (pStream)
  4698. {
  4699. pStream->Release();
  4700. }
  4701. if (pDMP)
  4702. {
  4703. pDMP->Release();
  4704. }
  4705. CleanUp();
  4706. LeaveCriticalSection( &m_CriticalSection );
  4707. return hr;
  4708. }
  4709. STDMETHODIMP CDMCompos::QueryInterface(
  4710. const IID &iid,
  4711. void **ppv)
  4712. {
  4713. V_INAME(CDMCompos::QueryInterface);
  4714. V_PTRPTR_WRITE(ppv);
  4715. V_REFGUID(iid);
  4716. *ppv = NULL;
  4717. if (iid == IID_IUnknown || iid == IID_IDirectMusicComposer)
  4718. {
  4719. *ppv = static_cast<IDirectMusicComposer*>(this);
  4720. }
  4721. else if (iid == IID_IDirectMusicComposer8)
  4722. {
  4723. *ppv = static_cast<IDirectMusicComposer8*>(this);
  4724. m_dwFlags |= COMPOSEF_USING_DX8;
  4725. }
  4726. else if (iid == IID_IDirectMusicComposer8P)
  4727. {
  4728. *ppv = static_cast<IDirectMusicComposer8P*>(this);
  4729. }
  4730. if (*ppv == NULL)
  4731. return E_NOINTERFACE;
  4732. reinterpret_cast<IUnknown*>(this)->AddRef();
  4733. return S_OK;
  4734. }
  4735. STDMETHODIMP_(ULONG) CDMCompos::AddRef()
  4736. {
  4737. return InterlockedIncrement(&m_cRef);
  4738. }
  4739. STDMETHODIMP_(ULONG) CDMCompos::Release()
  4740. {
  4741. if (!InterlockedDecrement(&m_cRef))
  4742. {
  4743. m_cRef = 100; // artificial reference count to prevent reentrency due to COM aggregation
  4744. delete this;
  4745. return 0;
  4746. }
  4747. return m_cRef;
  4748. }