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.

7376 lines
246 KiB

  1. //
  2. // DMStyle.cpp : Implementation of CDMStyle
  3. //
  4. // Copyright (c) 1997-2001 Microsoft Corporation
  5. //
  6. // @doc EXTERNAL
  7. //
  8. #include "DMStyle.h"
  9. #include "score.h"
  10. #include "..\dmband\dmbandp.h"
  11. #include "..\shared\Validate.h"
  12. #include <mmreg.h>
  13. #include "dmsect.h"
  14. #include "ptrntrk.h"
  15. #include "StyleTrk.h"
  16. #include "..\shared\dmscriptautguids.h"
  17. V_INAME(DMStyle)
  18. #define NBR_VARIATIONS 32
  19. #define DX8_PART_SIZE 160
  20. #define DX8_PARTREF_SIZE 28
  21. DirectMusicTimeSig DefaultTimeSig(4, 4, 4);
  22. static char achMappings[128] = {
  23. 0, //0 },
  24. 35, //1 },
  25. 36, //2 },
  26. 38, //3 },
  27. 40, //4 },
  28. 41, //5 },
  29. 45, //6 },
  30. 48, //7 },
  31. 42, //8 },
  32. 44, //9 },
  33. 46, //10 },
  34. 39, //11 },
  35. 37, //12 },
  36. 51, //13 },
  37. 49, //14 },
  38. 54, //15 },
  39. 56, //16 },
  40. 61, //17 },
  41. 60, //18 },
  42. 64, //19 },
  43. 63, //20 },
  44. 66, //21 },
  45. 65, //22 },
  46. 69, //23 },
  47. 70, //24 },
  48. 71, //25 },
  49. 72, //26 },
  50. 73, //27 },
  51. 75, //28 },
  52. 47, //29 },
  53. 50, //30 },
  54. 53, //31 },
  55. 57, //32 },
  56. 52, //33 },
  57. 74, //34 },
  58. 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
  59. 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
  60. 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
  61. 95, 96, 97, 98,
  62. 87, //99 },
  63. 86, //100 },
  64. 85, //101 },
  65. 84, //102 },
  66. 83, //103 },
  67. 82, //104 },
  68. 81, //105 },
  69. 80, //106 },
  70. 79, //107 },
  71. 78, //108 },
  72. 77, //109 },
  73. 76, //110 },
  74. 68, //111 },
  75. 67, //112 },
  76. 62, //113 },
  77. 59, //114 },
  78. 58, //115 },
  79. 55, //116 },
  80. 43, //117 },
  81. 34, //118 },
  82. 33, //119 },
  83. 32, //120 },
  84. 31, //121 },
  85. 30, //122 },
  86. 29, //123 },
  87. 28, //124 },
  88. 27, //125 },
  89. 26, //126 },
  90. 25, //127 }
  91. };
  92. /////////////////////////////////////////////////////////////////////////////
  93. // ReadMBSfromWCS
  94. HRESULT ReadMBSfromWCS( IStream* pIStream, DWORD dwSize, String& pstrText )
  95. {
  96. HRESULT hr = S_OK;
  97. wchar_t* wstrText = NULL;
  98. DWORD dwBytesRead;
  99. DWORD dwLength = dwSize / sizeof(WCHAR);
  100. if (dwLength * sizeof(WCHAR) != dwSize)
  101. {
  102. // Funky size that will result in a small (less than sizeof(WCHAR)) overrun
  103. // So adjust the length accordingly
  104. dwLength++;
  105. }
  106. pstrText = "";
  107. wstrText = new wchar_t[dwLength + 1]; // make sure we have room for a null terminator
  108. if( wstrText == NULL )
  109. {
  110. hr = E_OUTOFMEMORY;
  111. goto ON_ERR;
  112. }
  113. hr = pIStream->Read( wstrText, dwSize, &dwBytesRead );
  114. wstrText[dwLength] = 0;
  115. if( FAILED( hr ) || dwBytesRead != dwSize )
  116. {
  117. if (SUCCEEDED(hr))
  118. {
  119. hr = E_FAIL;
  120. }
  121. goto ON_ERR;
  122. }
  123. pstrText = wstrText;
  124. ON_ERR:
  125. if( wstrText )
  126. {
  127. delete [] wstrText;
  128. }
  129. return hr;
  130. }
  131. /////////////////////////////////////////////////////////////////////////////
  132. // SaveMBStoWCS
  133. HRESULT SaveMBStoWCS( IStream* pIStream, String* pstrText )
  134. {
  135. HRESULT hr = S_OK;
  136. wchar_t* wstrText = NULL;
  137. DWORD dwLength;
  138. DWORD dwBytesWritten;
  139. if( pstrText == NULL )
  140. {
  141. hr = E_FAIL;
  142. goto ON_ERR;
  143. }
  144. dwLength = pstrText->GetLength() + 1;
  145. wstrText = new wchar_t[dwLength];
  146. if( wstrText == NULL )
  147. {
  148. hr = E_FAIL;
  149. goto ON_ERR;
  150. }
  151. wcscpy(wstrText, *pstrText);
  152. dwLength *= sizeof(wchar_t);
  153. hr = pIStream->Write( wstrText, dwLength, &dwBytesWritten );
  154. if( FAILED( hr )
  155. || dwBytesWritten != dwLength )
  156. {
  157. goto ON_ERR;
  158. }
  159. ON_ERR:
  160. if( wstrText )
  161. delete [] wstrText;
  162. return hr;
  163. }
  164. DirectMusicPart::DirectMusicPart(DirectMusicTimeSig *pTimeSig) :
  165. m_cRef(1),
  166. m_wNumMeasures(1),
  167. m_bPlayModeFlags(DMUS_PLAYMODE_NORMALCHORD),
  168. m_bInvertLower(0),
  169. m_bInvertUpper(127),
  170. m_dwFlags(0)
  171. {
  172. memset(&m_guidPartID, 0, sizeof(GUID));
  173. if (pTimeSig)
  174. {
  175. m_timeSig = *pTimeSig;
  176. }
  177. for( int i = 0 ; i < NBR_VARIATIONS ; i++ )
  178. {
  179. m_dwVariationChoices[i] = 0;
  180. }
  181. }
  182. STDMETHODIMP_(ULONG) DirectMusicPart::AddRef()
  183. {
  184. return InterlockedIncrement(&m_cRef);
  185. }
  186. STDMETHODIMP_(ULONG) DirectMusicPart::Release()
  187. {
  188. if (!InterlockedDecrement(&m_cRef))
  189. {
  190. delete this;
  191. return 0;
  192. }
  193. return m_cRef;
  194. }
  195. /////////////////////////////////////////////////////////////////////////////
  196. // CDirectMusicPart::DM_LoadPart
  197. HRESULT DirectMusicPart::DM_LoadPart(
  198. IAARIFFStream* pIRiffStream, MMCKINFO* pckMain, DMStyleStruct* pStyle )
  199. {
  200. IStream* pIStream;
  201. HRESULT hr;
  202. MMCKINFO ck;
  203. DWORD dwByteCount;
  204. long lSize;
  205. DWORD dwStructSize;
  206. WORD wExtra;
  207. if( pStyle == NULL ) return E_INVALIDARG;
  208. pIStream = pIRiffStream->GetStream();
  209. if( pIStream == NULL ) return E_FAIL;
  210. while( pIRiffStream->Descend( &ck, pckMain, 0 ) == 0 )
  211. {
  212. switch( ck.ckid )
  213. {
  214. case DMUS_FOURCC_PART_CHUNK:
  215. {
  216. DMUS_IO_STYLEPART iDMStylePart;
  217. memset(&iDMStylePart, 0, sizeof(iDMStylePart));
  218. lSize = min( ck.cksize, sizeof( DMUS_IO_STYLEPART ) );
  219. if (ck.cksize >= DX8_PART_SIZE) pStyle->m_dwFlags |= STYLEF_USING_DX8;
  220. hr = pIStream->Read( &iDMStylePart, lSize, &dwByteCount );
  221. if( FAILED( hr ) || (long)dwByteCount != lSize )
  222. {
  223. hr = E_FAIL;
  224. goto ON_ERROR;
  225. }
  226. if( pStyle->FindPartByGUID( iDMStylePart.guidPartID ) )
  227. {
  228. hr = S_FALSE; // Style already contains a Part with this GUID
  229. goto ON_ERROR; // so we must bypass this Part
  230. }
  231. m_timeSig.m_bBeatsPerMeasure = iDMStylePart.timeSig.bBeatsPerMeasure;
  232. m_timeSig.m_bBeat = iDMStylePart.timeSig.bBeat;
  233. m_timeSig.m_wGridsPerBeat = iDMStylePart.timeSig.wGridsPerBeat;
  234. m_wNumMeasures = iDMStylePart.wNbrMeasures;
  235. m_bInvertUpper = iDMStylePart.bInvertUpper;
  236. m_bInvertLower = iDMStylePart.bInvertLower;
  237. m_bPlayModeFlags = iDMStylePart.bPlayModeFlags;
  238. m_dwFlags = iDMStylePart.dwFlags;
  239. memcpy( &m_guidPartID, &iDMStylePart.guidPartID, sizeof(GUID) );
  240. memcpy( &m_dwVariationChoices, &iDMStylePart.dwVariationChoices, sizeof(m_dwVariationChoices) );
  241. for( int i = 0 ; i < NBR_VARIATIONS ; i++ )
  242. {
  243. if( m_dwVariationChoices[i] == 0xFFFFFFFF )
  244. {
  245. m_dwVariationChoices[i] = 0x3FFFFFFF;
  246. }
  247. if (pStyle->UsingDX8() && m_dwVariationChoices[i] == 0x3FFFFFFF)
  248. {
  249. m_dwVariationChoices[i] = 0x7FFFFFFF;
  250. }
  251. }
  252. break;
  253. }
  254. case DMUS_FOURCC_NOTE_CHUNK:
  255. {
  256. CDMStyleNote* pNote;
  257. DMUS_IO_STYLENOTE iDMStyleNote;
  258. memset(&iDMStyleNote, 0, sizeof(DMUS_IO_STYLENOTE));
  259. lSize = ck.cksize;
  260. // Read size of the note structure
  261. hr = pIStream->Read( &dwStructSize, sizeof( dwStructSize ), &dwByteCount );
  262. if( FAILED( hr )
  263. || dwByteCount != sizeof( dwStructSize ) )
  264. {
  265. hr = E_FAIL;
  266. goto ON_ERROR;
  267. }
  268. lSize -= dwByteCount;
  269. if( dwStructSize > sizeof( DMUS_IO_STYLENOTE ) )
  270. {
  271. wExtra = static_cast<WORD>( dwStructSize - sizeof( DMUS_IO_STYLENOTE ) );
  272. dwStructSize = sizeof( DMUS_IO_STYLENOTE );
  273. }
  274. else
  275. {
  276. wExtra = 0;
  277. }
  278. // now read in the notes
  279. while( lSize > 0 )
  280. {
  281. hr = pIStream->Read( &iDMStyleNote, dwStructSize, &dwByteCount );
  282. if( FAILED( hr ) || dwByteCount != dwStructSize )
  283. {
  284. hr = E_FAIL;
  285. goto ON_ERROR;
  286. }
  287. lSize -= dwStructSize;
  288. if( wExtra > 0 )
  289. {
  290. StreamSeek( pIStream, wExtra, STREAM_SEEK_CUR );
  291. lSize -= wExtra;
  292. }
  293. // Create Direct Music Note (if note event is legal)
  294. if (iDMStyleNote.mtGridStart >= 0)
  295. {
  296. pNote = new CDMStyleNote;
  297. if( pNote )
  298. {
  299. pNote->m_nGridStart = (short)iDMStyleNote.mtGridStart;
  300. pNote->m_dwVariation = iDMStyleNote.dwVariation;
  301. pNote->m_mtDuration = iDMStyleNote.mtDuration;
  302. pNote->m_nTimeOffset = iDMStyleNote.nTimeOffset;
  303. pNote->m_wMusicValue = iDMStyleNote.wMusicValue;
  304. pNote->m_bVelocity = iDMStyleNote.bVelocity;
  305. pNote->m_bTimeRange = iDMStyleNote.bTimeRange;
  306. pNote->m_bDurRange = iDMStyleNote.bDurRange;
  307. pNote->m_bVelRange = iDMStyleNote.bVelRange;
  308. pNote->m_bInversionId = iDMStyleNote.bInversionID;
  309. pNote->m_bPlayModeFlags = iDMStyleNote.bPlayModeFlags;
  310. pNote->m_bFlags = iDMStyleNote.bNoteFlags;
  311. // Place note in Part's event list
  312. EventList.AddHead( pNote );
  313. }
  314. }
  315. }
  316. break;
  317. }
  318. case DMUS_FOURCC_CURVE_CHUNK:
  319. {
  320. CDMStyleCurve* pCurve;
  321. DMUS_IO_STYLECURVE iDMStyleCurve;
  322. memset(&iDMStyleCurve, 0, sizeof(DMUS_IO_STYLECURVE));
  323. lSize = ck.cksize;
  324. // Read size of the curve structure
  325. hr = pIStream->Read( &dwStructSize, sizeof( dwStructSize ), &dwByteCount );
  326. if( FAILED( hr ) || dwByteCount != sizeof( dwStructSize ) )
  327. {
  328. hr = E_FAIL;
  329. goto ON_ERROR;
  330. }
  331. lSize -= dwByteCount;
  332. if( dwStructSize > sizeof( DMUS_IO_STYLECURVE ) )
  333. {
  334. wExtra = static_cast<WORD>( dwStructSize - sizeof( DMUS_IO_STYLECURVE ) );
  335. dwStructSize = sizeof( DMUS_IO_STYLECURVE );
  336. }
  337. else
  338. {
  339. wExtra = 0;
  340. }
  341. // now read in the curves
  342. while( lSize > 0 )
  343. {
  344. hr = pIStream->Read( &iDMStyleCurve, dwStructSize, &dwByteCount );
  345. if( FAILED( hr ) || dwByteCount != dwStructSize )
  346. {
  347. hr = E_FAIL;
  348. goto ON_ERROR;
  349. }
  350. lSize -= dwStructSize;
  351. if( wExtra > 0 )
  352. {
  353. StreamSeek( pIStream, wExtra, STREAM_SEEK_CUR );
  354. lSize -= wExtra;
  355. }
  356. // Create Direct Music Curve (if curve event is legal)
  357. if (iDMStyleCurve.mtGridStart >= 0)
  358. {
  359. pCurve = new CDMStyleCurve;
  360. if( pCurve )
  361. {
  362. pCurve->m_nGridStart = (short)iDMStyleCurve.mtGridStart;
  363. pCurve->m_dwVariation = iDMStyleCurve.dwVariation;
  364. pCurve->m_mtDuration = iDMStyleCurve.mtDuration;
  365. pCurve->m_nTimeOffset = iDMStyleCurve.nTimeOffset;
  366. pCurve->m_StartValue = iDMStyleCurve.nStartValue;
  367. pCurve->m_EndValue = iDMStyleCurve.nEndValue;
  368. pCurve->m_bEventType = iDMStyleCurve.bEventType;
  369. pCurve->m_bCurveShape = iDMStyleCurve.bCurveShape;
  370. pCurve->m_bCCData = iDMStyleCurve.bCCData;
  371. pCurve->m_mtResetDuration = iDMStyleCurve.mtResetDuration;
  372. pCurve->m_nResetValue = iDMStyleCurve.nResetValue;
  373. pCurve->m_bFlags = iDMStyleCurve.bFlags;
  374. // dx8 stuff
  375. pCurve->m_wParamType = iDMStyleCurve.wParamType;
  376. pCurve->m_wMergeIndex = iDMStyleCurve.wMergeIndex;
  377. // Place curve in Part's event list
  378. EventList.AddHead( pCurve );
  379. }
  380. }
  381. }
  382. break;
  383. }
  384. case DMUS_FOURCC_MARKER_CHUNK:
  385. {
  386. CDMStyleMarker* pMarker;
  387. DMUS_IO_STYLEMARKER iDMStyleMarker;
  388. memset(&iDMStyleMarker, 0, sizeof(DMUS_IO_STYLEMARKER));
  389. lSize = ck.cksize;
  390. // Read size of the marker structure
  391. hr = pIStream->Read( &dwStructSize, sizeof( dwStructSize ), &dwByteCount );
  392. if( FAILED( hr ) || dwByteCount != sizeof( dwStructSize ) )
  393. {
  394. hr = E_FAIL;
  395. goto ON_ERROR;
  396. }
  397. lSize -= dwByteCount;
  398. if( dwStructSize > sizeof( DMUS_IO_STYLEMARKER ) )
  399. {
  400. wExtra = static_cast<WORD>( dwStructSize - sizeof( DMUS_IO_STYLEMARKER ) );
  401. dwStructSize = sizeof( DMUS_IO_STYLEMARKER );
  402. }
  403. else
  404. {
  405. wExtra = 0;
  406. }
  407. // now read in the markers
  408. while( lSize > 0 )
  409. {
  410. hr = pIStream->Read( &iDMStyleMarker, dwStructSize, &dwByteCount );
  411. if( FAILED( hr ) || dwByteCount != dwStructSize )
  412. {
  413. hr = E_FAIL;
  414. goto ON_ERROR;
  415. }
  416. lSize -= dwStructSize;
  417. if( wExtra > 0 )
  418. {
  419. StreamSeek( pIStream, wExtra, STREAM_SEEK_CUR );
  420. lSize -= wExtra;
  421. }
  422. // Create Direct Music Marker (if marker event is legal)
  423. if (iDMStyleMarker.mtGridStart >= 0)
  424. {
  425. pMarker = new CDMStyleMarker;
  426. if( pMarker )
  427. {
  428. pMarker->m_nGridStart = (short)iDMStyleMarker.mtGridStart;
  429. pMarker->m_dwVariation = iDMStyleMarker.dwVariation;
  430. pMarker->m_nTimeOffset = 0; // ignore offsets
  431. pMarker->m_wFlags = iDMStyleMarker.wMarkerFlags;
  432. // Place marker in Part's event list
  433. EventList.AddHead( pMarker );
  434. }
  435. }
  436. }
  437. break;
  438. }
  439. case DMUS_FOURCC_ANTICIPATION_CHUNK:
  440. {
  441. CDMStyleAnticipation* pAnticipation;
  442. DMUS_IO_STYLE_ANTICIPATION iDMStyleAnticipation;
  443. memset(&iDMStyleAnticipation, 0, sizeof(DMUS_IO_STYLE_ANTICIPATION));
  444. lSize = ck.cksize;
  445. // Read size of the anticipation structure
  446. hr = pIStream->Read( &dwStructSize, sizeof( dwStructSize ), &dwByteCount );
  447. if( FAILED( hr ) || dwByteCount != sizeof( dwStructSize ) )
  448. {
  449. hr = E_FAIL;
  450. goto ON_ERROR;
  451. }
  452. lSize -= dwByteCount;
  453. if( dwStructSize > sizeof( DMUS_IO_STYLE_ANTICIPATION ) )
  454. {
  455. wExtra = static_cast<WORD>( dwStructSize - sizeof( DMUS_IO_STYLE_ANTICIPATION ) );
  456. dwStructSize = sizeof( DMUS_IO_STYLE_ANTICIPATION );
  457. }
  458. else
  459. {
  460. wExtra = 0;
  461. }
  462. // now read in the markers
  463. while( lSize > 0 )
  464. {
  465. hr = pIStream->Read( &iDMStyleAnticipation, dwStructSize, &dwByteCount );
  466. if( FAILED( hr ) || dwByteCount != dwStructSize )
  467. {
  468. hr = E_FAIL;
  469. goto ON_ERROR;
  470. }
  471. lSize -= dwStructSize;
  472. if( wExtra > 0 )
  473. {
  474. StreamSeek( pIStream, wExtra, STREAM_SEEK_CUR );
  475. lSize -= wExtra;
  476. }
  477. // Create Direct Music Anticipation (if anticipation event is legal)
  478. if (iDMStyleAnticipation.mtGridStart >= 0)
  479. {
  480. pAnticipation = new CDMStyleAnticipation;
  481. if( pAnticipation )
  482. {
  483. pAnticipation->m_nGridStart = (short)iDMStyleAnticipation.mtGridStart;
  484. pAnticipation->m_dwVariation = iDMStyleAnticipation.dwVariation;
  485. pAnticipation->m_nTimeOffset = iDMStyleAnticipation.nTimeOffset;
  486. pAnticipation->m_bTimeRange = iDMStyleAnticipation.bTimeRange;
  487. // Place anticipation in Part's event list
  488. EventList.AddHead( pAnticipation );
  489. }
  490. }
  491. }
  492. break;
  493. }
  494. case DMUS_FOURCC_RESOLUTION_CHUNK:
  495. {
  496. TListItem<DMUS_IO_STYLERESOLUTION>* pResolutionItem;
  497. DMUS_IO_STYLERESOLUTION iDMStyleResolution;
  498. memset(&iDMStyleResolution, 0, sizeof(DMUS_IO_STYLERESOLUTION));
  499. lSize = ck.cksize;
  500. // Read size of the resolution structure
  501. hr = pIStream->Read( &dwStructSize, sizeof( dwStructSize ), &dwByteCount );
  502. if( FAILED( hr ) || dwByteCount != sizeof( dwStructSize ) )
  503. {
  504. hr = E_FAIL;
  505. goto ON_ERROR;
  506. }
  507. lSize -= dwByteCount;
  508. if( dwStructSize > sizeof( DMUS_IO_STYLERESOLUTION ) )
  509. {
  510. wExtra = static_cast<WORD>( dwStructSize - sizeof( DMUS_IO_STYLERESOLUTION ) );
  511. dwStructSize = sizeof( DMUS_IO_STYLERESOLUTION );
  512. }
  513. else
  514. {
  515. wExtra = 0;
  516. }
  517. // now read in the resolutions
  518. while( lSize > 0 )
  519. {
  520. hr = pIStream->Read( &iDMStyleResolution, dwStructSize, &dwByteCount );
  521. if( FAILED( hr ) || dwByteCount != dwStructSize )
  522. {
  523. hr = E_FAIL;
  524. goto ON_ERROR;
  525. }
  526. lSize -= dwStructSize;
  527. if( wExtra > 0 )
  528. {
  529. StreamSeek( pIStream, wExtra, STREAM_SEEK_CUR );
  530. lSize -= wExtra;
  531. }
  532. // Create Direct Music resolution
  533. pResolutionItem = new TListItem<DMUS_IO_STYLERESOLUTION>;
  534. if( pResolutionItem )
  535. {
  536. pResolutionItem->GetItemValue() = iDMStyleResolution;
  537. // Place marker in Part's resolution list
  538. m_ResolutionList.AddHead( pResolutionItem );
  539. }
  540. }
  541. break;
  542. }
  543. }
  544. pIRiffStream->Ascend( &ck, 0 );
  545. }
  546. // Sort the Event List
  547. EventList.MergeSort(m_timeSig);
  548. ON_ERROR:
  549. pIStream->Release();
  550. return hr;
  551. }
  552. /////////////////////////////////////////////////////////////////////////////
  553. // CDMStyle
  554. STDMETHODIMP CDMStyle::QueryInterface(
  555. const IID &iid, // Interface to query for
  556. void **ppv) // The requested interface will be returned here
  557. {
  558. V_INAME(CDMStyle::QueryInterface);
  559. V_REFGUID(iid);
  560. V_PTRPTR_WRITE(ppv);
  561. *ppv = NULL;
  562. if (iid == IID_IUnknown || iid == IID_IDirectMusicStyle)
  563. {
  564. *ppv = static_cast<IDirectMusicStyle*>(this);
  565. }
  566. else if (iid == IID_IDirectMusicStyle8)
  567. {
  568. *ppv = static_cast<IDirectMusicStyle8*>(this);
  569. m_StyleInfo.m_dwFlags |= STYLEF_USING_DX8;
  570. }
  571. else if (iid == IID_IDirectMusicStyle8P)
  572. {
  573. *ppv = static_cast<IDirectMusicStyle8P*>(this);
  574. }
  575. else if (iid == IID_IPersistStream)
  576. {
  577. *ppv = static_cast<IPersistStream*>(this);
  578. }
  579. else if (iid == IID_IDirectMusicObject)
  580. {
  581. *ppv = static_cast<IDirectMusicObject*>(this);
  582. }
  583. else if (iid == IID_IDMStyle)
  584. {
  585. *ppv = static_cast<IDMStyle*>(this);
  586. }
  587. if (*ppv == NULL)
  588. return E_NOINTERFACE;
  589. reinterpret_cast<IUnknown*>(this)->AddRef();
  590. return S_OK;
  591. }
  592. STDMETHODIMP_(ULONG) CDMStyle::AddRef()
  593. {
  594. return InterlockedIncrement(&m_cRef);
  595. }
  596. STDMETHODIMP_(ULONG) CDMStyle::Release()
  597. {
  598. if (!InterlockedDecrement(&m_cRef))
  599. {
  600. m_cRef = 100; // artificial reference count to prevent reentrency due to COM aggregation
  601. delete this;
  602. return 0;
  603. }
  604. return m_cRef;
  605. }
  606. HRESULT CDMStyle::GetDescriptor(LPDMUS_OBJECTDESC pDesc)
  607. {
  608. // Argument validation
  609. V_INAME(CDMStyle::GetDescriptor);
  610. V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
  611. ZeroMemory(pDesc, sizeof(DMUS_OBJECTDESC));
  612. pDesc->dwSize = sizeof(DMUS_OBJECTDESC);
  613. pDesc->dwValidData = DMUS_OBJ_CLASS;
  614. pDesc->guidClass = CLSID_DirectMusicStyle;
  615. if (m_StyleInfo.m_fLoaded)
  616. {
  617. pDesc->dwValidData |= DMUS_OBJ_LOADED;
  618. }
  619. if (m_StyleInfo.m_guid.Data1 || m_StyleInfo.m_guid.Data2)
  620. {
  621. pDesc->dwValidData |= DMUS_OBJ_OBJECT;
  622. pDesc->guidObject = m_StyleInfo.m_guid;
  623. }
  624. if (m_StyleInfo.m_strCategory)
  625. {
  626. pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
  627. wcsncpy(pDesc->wszCategory, m_StyleInfo.m_strCategory, DMUS_MAX_CATEGORY);
  628. pDesc->wszCategory[DMUS_MAX_CATEGORY - 1] = 0;
  629. }
  630. if (m_StyleInfo.m_strName)
  631. {
  632. pDesc->dwValidData |= DMUS_OBJ_NAME;
  633. wcsncpy(pDesc->wszName, m_StyleInfo.m_strName, DMUS_MAX_NAME);
  634. pDesc->wszName[DMUS_MAX_NAME - 1] = 0;
  635. }
  636. if (m_StyleInfo.m_dwVersionMS || m_StyleInfo.m_dwVersionLS)
  637. {
  638. pDesc->dwValidData |= DMUS_OBJ_VERSION;
  639. pDesc->vVersion.dwVersionMS = m_StyleInfo.m_dwVersionMS;
  640. pDesc->vVersion.dwVersionLS = m_StyleInfo.m_dwVersionLS;
  641. }
  642. return S_OK;
  643. }
  644. HRESULT CDMStyle::SetDescriptor(LPDMUS_OBJECTDESC pDesc)
  645. {
  646. // Argument validation
  647. V_INAME(CDMStyle::SetDescriptor);
  648. V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
  649. HRESULT hr = E_INVALIDARG;
  650. DWORD dw = 0;
  651. if( pDesc->dwSize >= sizeof(DMUS_OBJECTDESC) )
  652. {
  653. if( pDesc->dwValidData & DMUS_OBJ_OBJECT )
  654. {
  655. m_StyleInfo.m_guid = pDesc->guidObject;
  656. dw |= DMUS_OBJ_OBJECT;
  657. }
  658. if( pDesc->dwValidData & DMUS_OBJ_NAME )
  659. {
  660. WCHAR wszTempName[DMUS_MAX_NAME];
  661. memcpy(wszTempName, pDesc->wszName, sizeof(WCHAR)*DMUS_MAX_NAME);
  662. wszTempName[DMUS_MAX_NAME - 1] = 0;
  663. m_StyleInfo.m_strName = wszTempName;
  664. dw |= DMUS_OBJ_NAME;
  665. }
  666. if( pDesc->dwValidData & DMUS_OBJ_CATEGORY )
  667. {
  668. WCHAR wszTempCategory[DMUS_MAX_CATEGORY];
  669. memcpy(wszTempCategory, pDesc->wszCategory, sizeof(WCHAR)*DMUS_MAX_CATEGORY);
  670. wszTempCategory[DMUS_MAX_CATEGORY - 1] = 0;
  671. m_StyleInfo.m_strCategory = wszTempCategory;
  672. dw |= DMUS_OBJ_CATEGORY;
  673. }
  674. if ( pDesc->dwValidData & DMUS_OBJ_VERSION )
  675. {
  676. m_StyleInfo.m_dwVersionMS = pDesc->vVersion.dwVersionMS;
  677. m_StyleInfo.m_dwVersionLS = pDesc->vVersion.dwVersionLS;
  678. dw |= DMUS_OBJ_VERSION;
  679. }
  680. if( pDesc->dwValidData & (~dw) )
  681. {
  682. hr = S_FALSE; // there were extra fields we didn't parse;
  683. pDesc->dwValidData = dw;
  684. }
  685. else
  686. {
  687. hr = S_OK;
  688. }
  689. }
  690. return hr;
  691. }
  692. HRESULT CDMStyle::ParseDescriptor(LPSTREAM pStream, LPDMUS_OBJECTDESC pDesc)
  693. {
  694. // Argument validation
  695. V_INAME(CDMStyle::ParseDescriptor);
  696. V_INTERFACE(pStream);
  697. V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
  698. IAARIFFStream* pRIFF;
  699. MMCKINFO ckMain;
  700. MMCKINFO ck;
  701. ioStyle iStyle;
  702. DWORD cb;
  703. DWORD cSize;
  704. HRESULT hr = S_OK;
  705. DWORD dwPos;
  706. BOOL fFoundFormat = FALSE;
  707. dwPos = StreamTell( pStream );
  708. // Check for Direct Music format
  709. hr = AllocRIFFStream( pStream, &pRIFF );
  710. if( SUCCEEDED( hr ) )
  711. {
  712. ckMain.fccType = DMUS_FOURCC_STYLE_FORM;
  713. if( pRIFF->Descend( &ckMain, NULL, MMIO_FINDRIFF ) == 0 )
  714. {
  715. hr = DM_ParseDescriptor( pRIFF, &ckMain, pDesc );
  716. fFoundFormat = TRUE;
  717. }
  718. pRIFF->Release();
  719. pRIFF = NULL;
  720. }
  721. else
  722. {
  723. return hr;
  724. }
  725. // Check for IMA 2.5 format
  726. if( fFoundFormat )
  727. {
  728. hr = S_OK;
  729. }
  730. else
  731. {
  732. StreamSeek( pStream, dwPos, STREAM_SEEK_SET );
  733. hr = AllocRIFFStream( pStream, &pRIFF );
  734. if( SUCCEEDED( hr ) )
  735. {
  736. ckMain.fccType = FOURCC_STYLE_FORM;
  737. if( pRIFF->Descend( &ckMain, NULL, MMIO_FINDRIFF ) != 0 )
  738. {
  739. pRIFF->Release();
  740. return DMUS_E_CHUNKNOTFOUND;
  741. }
  742. ck.ckid = FOURCC_STYLE;
  743. if( pRIFF->Descend( &ck, &ckMain, MMIO_FINDCHUNK ) != 0 )
  744. {
  745. pRIFF->Release();
  746. return DMUS_E_CHUNKNOTFOUND;
  747. }
  748. cSize = min( ck.cksize, sizeof( iStyle ) );
  749. hr = pStream->Read( &iStyle, cSize, &cb );
  750. FixBytes( FBT_IOSTYLE, &iStyle );
  751. if( FAILED( hr ) || cb != cSize )
  752. {
  753. pRIFF->Release();
  754. return DMUS_E_CHUNKNOTFOUND;
  755. }
  756. pDesc->dwValidData = DMUS_OBJ_CLASS;
  757. pDesc->guidClass = CLSID_DirectMusicStyle;
  758. wcsncpy(pDesc->wszName, iStyle.wstrName, DMUS_MAX_NAME);
  759. if(pDesc->wszName[0])
  760. {
  761. pDesc->dwValidData |= DMUS_OBJ_NAME;
  762. pDesc->wszName[16] = 0;
  763. }
  764. wcsncpy(pDesc->wszCategory, iStyle.wstrCategory, DMUS_MAX_CATEGORY);
  765. if(pDesc->wszCategory[0])
  766. {
  767. pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
  768. pDesc->wszCategory[16] = 0;
  769. }
  770. if(iStyle.guid.Data1 || iStyle.guid.Data2 || iStyle.guid.Data3)
  771. {
  772. pDesc->guidObject = iStyle.guid;
  773. pDesc->dwValidData |= DMUS_OBJ_OBJECT;
  774. }
  775. pRIFF->Release();
  776. }
  777. else
  778. {
  779. return hr;
  780. }
  781. }
  782. return hr;
  783. }
  784. // Note: this needs to be called from inside a critical section.
  785. HRESULT CDMStyle::CreateMotifSegment(CDirectMusicPattern* pPattern, IUnknown * * ppSegment,
  786. DWORD dwRepeats)
  787. {
  788. HRESULT hr = S_OK;
  789. //1. Create a Motif track.
  790. IDirectMusicTrack* pIMotifTrack = NULL;
  791. hr = ::CoCreateInstance(
  792. CLSID_DirectMusicMotifTrack,
  793. NULL,
  794. CLSCTX_INPROC,
  795. IID_IDirectMusicTrack,
  796. (void**)&pIMotifTrack
  797. );
  798. if (SUCCEEDED(hr))
  799. {
  800. // 2. Set the Track's Motif
  801. DirectMusicTimeSig& TimeSig =
  802. pPattern->m_timeSig.m_bBeat == 0 ? m_StyleInfo.m_TimeSignature : pPattern->m_timeSig;
  803. TListItem<DirectMusicPartRef>* pPartRef = pPattern->m_PartRefList.GetHead();
  804. for(; pPartRef != NULL; pPartRef = pPartRef->GetNext())
  805. {
  806. DirectMusicPart* pPart = pPartRef->GetItemValue().m_pDMPart;
  807. DirectMusicTimeSig& TS =
  808. pPart->m_timeSig.m_bBeat == 0 ? TimeSig : pPart->m_timeSig;
  809. pPart->EventList.MergeSort(TS);
  810. }
  811. IMotifTrack* pIMT;
  812. hr = pIMotifTrack->QueryInterface(IID_IMotifTrack, (void**)&pIMT);
  813. if (SUCCEEDED(hr))
  814. {
  815. IDirectMusicStyle* pIDMS = NULL;
  816. hr = ((IDMStyle*)this)->QueryInterface(IID_IDirectMusicStyle, (void**)&pIDMS);
  817. hr = pIMT->SetTrack(pIDMS, pPattern);
  818. pIDMS->Release();
  819. DWORD dwLength;
  820. dwLength = pPattern->m_wNumMeasures * TimeSig.ClocksPerMeasure();
  821. // 3. Create a secondary segment for the motif.
  822. IDirectMusicSegment *pISegment;
  823. hr = ::CoCreateInstance(
  824. CLSID_DirectMusicSegment,
  825. NULL,
  826. CLSCTX_INPROC,
  827. IID_IDirectMusicSegment,
  828. (void**)&pISegment
  829. );
  830. if (SUCCEEDED(hr) )
  831. {
  832. // 4. Initialize the segment appropriately.
  833. pISegment->SetLength(dwLength);
  834. if (pPattern->m_fSettings)
  835. {
  836. pISegment->SetRepeats(pPattern->m_dwRepeats);
  837. pISegment->SetDefaultResolution(pPattern->m_dwResolution);
  838. pISegment->SetStartPoint(pPattern->m_mtPlayStart);
  839. pISegment->SetLoopPoints(pPattern->m_mtLoopStart, pPattern->m_mtLoopEnd);
  840. }
  841. else
  842. {
  843. pISegment->SetRepeats(dwRepeats);
  844. pISegment->SetDefaultResolution(DMUS_SEGF_BEAT);
  845. }
  846. pISegment->InsertTrack(pIMotifTrack, 1);
  847. // create and insert a band track, if the motif references a band
  848. if (pPattern->m_pMotifBand)
  849. {
  850. IDirectMusicTrack* pBandTrack = NULL;
  851. hr = ::CoCreateInstance(
  852. CLSID_DirectMusicBandTrack,
  853. NULL,
  854. CLSCTX_INPROC,
  855. IID_IDirectMusicTrack,
  856. (void**)&pBandTrack
  857. );
  858. if (SUCCEEDED(hr))
  859. {
  860. DMUS_BAND_PARAM DMBandParam;
  861. DMBandParam.mtTimePhysical = -64;
  862. DMBandParam.pBand = pPattern->m_pMotifBand;
  863. hr = pBandTrack->SetParam(GUID_BandParam, 0, (void*)&DMBandParam);
  864. if (SUCCEEDED(hr))
  865. {
  866. pISegment->InsertTrack(pBandTrack, 1);
  867. }
  868. pBandTrack->Release(); // Release the AddRef from InsertTrack
  869. }
  870. }
  871. // Note: the segment must release the track objects...
  872. if (SUCCEEDED(hr))
  873. {
  874. IUnknown *pUnknown;
  875. hr = pISegment->QueryInterface(IID_IUnknown, (void**)&pUnknown);
  876. if (SUCCEEDED(hr))
  877. {
  878. *ppSegment = pUnknown;
  879. pISegment->Release();
  880. }
  881. }
  882. }
  883. pIMT->Release();
  884. }
  885. pIMotifTrack->Release();
  886. }
  887. return hr;
  888. }
  889. /////////////////////////////////////////////////////////////////////////////
  890. // CDirectMusicPattern::DM_SaveSinglePattern
  891. HRESULT CDirectMusicPattern::DM_SaveSinglePattern( IAARIFFStream* pIRiffStream )
  892. {
  893. TList<DirectMusicPart*> PartList;
  894. TListItem<DirectMusicPartRef>* pPartRefItem;
  895. TListItem<DirectMusicPart*>* pPartItem;
  896. DirectMusicPart* pPart;
  897. HRESULT hr = S_OK;
  898. IStream* pIStream;
  899. pIStream = pIRiffStream->GetStream();
  900. if ( pIStream == NULL ) return E_FAIL;
  901. // Save Pattern chunk
  902. hr = DM_SavePatternChunk( pIRiffStream );
  903. if( FAILED ( hr ) )
  904. {
  905. goto ON_ERROR;
  906. }
  907. // Save Pattern rhythm
  908. hr = DM_SavePatternRhythm( pIRiffStream );
  909. if( FAILED ( hr ) )
  910. {
  911. goto ON_ERROR;
  912. }
  913. /*// Save Pattern switch points
  914. hr = DM_SavePatternSwitchPoints( pIRiffStream );
  915. if( FAILED ( hr ) )
  916. {
  917. goto ON_ERROR;
  918. }*/
  919. // Save Pattern info
  920. hr = DM_SavePatternInfoList( pIRiffStream );
  921. if( FAILED ( hr ) )
  922. {
  923. goto ON_ERROR;
  924. }
  925. // Build list of Parts
  926. pPartRefItem = m_PartRefList.GetHead();
  927. for( ; pPartRefItem; pPartRefItem = pPartRefItem->GetNext() )
  928. {
  929. DirectMusicPartRef& rPartRef = pPartRefItem->GetItemValue();
  930. if( rPartRef.m_pDMPart == NULL )
  931. {
  932. hr = E_FAIL;
  933. goto ON_ERROR;
  934. }
  935. for (pPartItem = PartList.GetHead(); pPartItem; pPartItem = pPartItem->GetNext())
  936. {
  937. if (pPartItem->GetItemValue() == rPartRef.m_pDMPart)
  938. break;
  939. }
  940. if( pPartItem == NULL )
  941. {
  942. pPartItem = new TListItem<DirectMusicPart*>(rPartRef.m_pDMPart);
  943. if (pPartItem)
  944. {
  945. PartList.AddTail( pPartItem );
  946. }
  947. }
  948. }
  949. // Save Parts
  950. pPartItem = PartList.GetHead();
  951. for ( ; pPartItem; pPartItem = pPartItem->GetNext() )
  952. {
  953. pPart = pPartItem->GetItemValue();
  954. hr = pPart->DM_SavePart( pIRiffStream );
  955. if( FAILED ( hr ) )
  956. {
  957. goto ON_ERROR;
  958. }
  959. }
  960. // Save Part References
  961. pPartRefItem = m_PartRefList.GetHead();
  962. for( ; pPartRefItem; pPartRefItem = pPartRefItem->GetNext() )
  963. {
  964. DirectMusicPartRef& rPartRef = pPartRefItem->GetItemValue();
  965. hr = rPartRef.DM_SavePartRef( pIRiffStream );
  966. if( FAILED ( hr ) )
  967. {
  968. goto ON_ERROR;
  969. }
  970. }
  971. ON_ERROR:
  972. pIStream->Release();
  973. return hr;
  974. }
  975. /////////////////////////////////////////////////////////////////////////////
  976. // CDirectMusicPattern::DM_SavePatternRhythm
  977. HRESULT CDirectMusicPattern::DM_SavePatternRhythm( IAARIFFStream* pIRiffStream )
  978. {
  979. IStream* pIStream;
  980. HRESULT hr = S_OK;
  981. MMCKINFO ck;
  982. DWORD dwBytesWritten;
  983. int i;
  984. pIStream = pIRiffStream->GetStream();
  985. if ( pIStream == NULL )
  986. {
  987. hr = E_FAIL;
  988. goto ON_ERROR;
  989. }
  990. // Write Rhythm chunk header
  991. ck.ckid = DMUS_FOURCC_RHYTHM_CHUNK;
  992. if( pIRiffStream->CreateChunk( &ck, 0 ) != 0 )
  993. {
  994. hr = E_FAIL;
  995. goto ON_ERROR;
  996. }
  997. // Now save the RhythmMap for each measure
  998. for( i = 0 ; i < m_wNumMeasures ; i++ )
  999. {
  1000. // Write Rhythm chunk data
  1001. hr = pIStream->Write( &m_pRhythmMap[i], sizeof(DWORD), &dwBytesWritten);
  1002. if( FAILED( hr ) || dwBytesWritten != sizeof(DWORD) )
  1003. {
  1004. hr = E_FAIL;
  1005. goto ON_ERROR;
  1006. }
  1007. }
  1008. if( pIRiffStream->Ascend( &ck, 0 ) != 0 )
  1009. {
  1010. hr = E_FAIL;
  1011. goto ON_ERROR;
  1012. }
  1013. ON_ERROR:
  1014. pIStream->Release();
  1015. return hr;
  1016. }
  1017. /////////////////////////////////////////////////////////////////////////////
  1018. // CDirectMusicPattern::DM_SavePatternSwitchPoints
  1019. /*
  1020. HRESULT CDirectMusicPattern::DM_SavePatternSwitchPoints( IAARIFFStream* pIRiffStream )
  1021. {
  1022. IStream* pIStream;
  1023. HRESULT hr;
  1024. MMCKINFO ck;
  1025. DWORD dwBytesWritten;
  1026. int i;
  1027. pIStream = pIRiffStream->GetStream();
  1028. if ( pIStream == NULL )
  1029. {
  1030. hr = E_FAIL;
  1031. goto ON_ERROR;
  1032. }
  1033. // Write Pattern Switch Point chunk header
  1034. ck.ckid = DMUS_FOURCC_SWITCH_POINT_CHUNK;
  1035. if( pIRiffStream->CreateChunk( &ck, 0 ) != 0 )
  1036. {
  1037. hr = E_FAIL;
  1038. goto ON_ERROR;
  1039. }
  1040. // Now save the Switch Points for each measure
  1041. for( i = 0 ; i < m_wNumMeasures ; i++ )
  1042. {
  1043. // Write Switch Point chunk data
  1044. hr = pIStream->Write( &m_pSwitchPoints[i], sizeof(DWORD), &dwBytesWritten);
  1045. if( FAILED( hr ) || dwBytesWritten != sizeof(DWORD) )
  1046. {
  1047. hr = E_FAIL;
  1048. goto ON_ERROR;
  1049. }
  1050. }
  1051. if( pIRiffStream->Ascend( &ck, 0 ) != 0 )
  1052. {
  1053. hr = E_FAIL;
  1054. goto ON_ERROR;
  1055. }
  1056. ON_ERROR:
  1057. pIStream->Release();
  1058. return hr;
  1059. }
  1060. */
  1061. /////////////////////////////////////////////////////////////////////////////
  1062. // CDirectMusicPattern::DM_SavePatternInfoList
  1063. HRESULT CDirectMusicPattern::DM_SavePatternInfoList( IAARIFFStream* pIRiffStream )
  1064. {
  1065. IStream* pIStream;
  1066. HRESULT hr;
  1067. MMCKINFO ckMain;
  1068. MMCKINFO ck;
  1069. if( m_strName.IsEmpty() )
  1070. {
  1071. return S_OK;
  1072. }
  1073. pIStream = pIRiffStream->GetStream();
  1074. if ( pIStream == NULL )
  1075. {
  1076. hr = E_FAIL;
  1077. goto ON_ERROR;
  1078. }
  1079. // Write UNFO LIST header
  1080. ckMain.fccType = DMUS_FOURCC_UNFO_LIST;
  1081. if( pIRiffStream->CreateChunk(&ckMain, MMIO_CREATELIST) != 0 )
  1082. {
  1083. hr = E_FAIL;
  1084. goto ON_ERROR;
  1085. }
  1086. // Write Pattern name
  1087. if( !m_strName.IsEmpty() )
  1088. {
  1089. ck.ckid = DMUS_FOURCC_UNAM_CHUNK;
  1090. if( pIRiffStream->CreateChunk( &ck, 0 ) != 0 )
  1091. {
  1092. hr = E_FAIL;
  1093. goto ON_ERROR;
  1094. }
  1095. hr = SaveMBStoWCS( pIStream, &m_strName );
  1096. if( FAILED( hr ) )
  1097. {
  1098. goto ON_ERROR;
  1099. }
  1100. if( pIRiffStream->Ascend(&ck, 0) != 0 )
  1101. {
  1102. hr = E_FAIL;
  1103. goto ON_ERROR;
  1104. }
  1105. }
  1106. if( pIRiffStream->Ascend(&ckMain, 0) != 0 )
  1107. {
  1108. hr = E_FAIL;
  1109. goto ON_ERROR;
  1110. }
  1111. ON_ERROR:
  1112. pIStream->Release();
  1113. return hr;
  1114. }
  1115. /////////////////////////////////////////////////////////////////////////////
  1116. // CDirectMusicPattern::DM_SavePatternChunk
  1117. HRESULT CDirectMusicPattern::DM_SavePatternChunk( IAARIFFStream* pIRiffStream )
  1118. {
  1119. IStream* pIStream;
  1120. HRESULT hr;
  1121. MMCKINFO ck;
  1122. DWORD dwBytesWritten;
  1123. DMUS_IO_PATTERN oDMPattern;
  1124. pIStream = pIRiffStream->GetStream();
  1125. if ( pIStream == NULL )
  1126. {
  1127. hr = E_FAIL;
  1128. goto ON_ERROR;
  1129. }
  1130. // Write Pattern chunk header
  1131. ck.ckid = DMUS_FOURCC_PATTERN_CHUNK;
  1132. if( pIRiffStream->CreateChunk( &ck, 0 ) != 0 )
  1133. {
  1134. hr = E_FAIL;
  1135. goto ON_ERROR;
  1136. }
  1137. // Prepare DMUS_IO_PATTERN
  1138. memset( &oDMPattern, 0, sizeof(DMUS_IO_PATTERN) );
  1139. oDMPattern.timeSig.bBeatsPerMeasure = m_timeSig.m_bBeatsPerMeasure;
  1140. oDMPattern.timeSig.bBeat = m_timeSig.m_bBeat;
  1141. oDMPattern.timeSig.wGridsPerBeat = m_timeSig.m_wGridsPerBeat;
  1142. oDMPattern.bGrooveBottom = m_bGrooveBottom;
  1143. oDMPattern.bGrooveTop = m_bGrooveTop;
  1144. oDMPattern.bDestGrooveBottom = m_bDestGrooveBottom;
  1145. oDMPattern.bDestGrooveTop = m_bDestGrooveTop;
  1146. oDMPattern.wEmbellishment = m_wEmbellishment;
  1147. oDMPattern.wNbrMeasures = m_wNumMeasures;
  1148. oDMPattern.dwFlags = m_dwFlags;
  1149. // Write Pattern chunk data
  1150. hr = pIStream->Write( &oDMPattern, sizeof(DMUS_IO_PATTERN), &dwBytesWritten);
  1151. if( FAILED( hr )
  1152. || dwBytesWritten != sizeof(DMUS_IO_PATTERN) )
  1153. {
  1154. hr = E_FAIL;
  1155. goto ON_ERROR;
  1156. }
  1157. if( pIRiffStream->Ascend( &ck, 0 ) != 0 )
  1158. {
  1159. hr = E_FAIL;
  1160. goto ON_ERROR;
  1161. }
  1162. ON_ERROR:
  1163. pIStream->Release();
  1164. return hr;
  1165. }
  1166. HRESULT CDirectMusicPattern::Save( IStream* pIStream )
  1167. {
  1168. if( pIStream == NULL )
  1169. {
  1170. return E_INVALIDARG;
  1171. }
  1172. IAARIFFStream* pIRiffStream;
  1173. MMCKINFO ckMain;
  1174. HRESULT hr = E_FAIL;
  1175. // Single Pattern (Direct Music format)
  1176. if( SUCCEEDED( AllocRIFFStream( pIStream, &pIRiffStream ) ) )
  1177. {
  1178. ckMain.fccType = DMUS_FOURCC_PATTERN_LIST;
  1179. if( pIRiffStream->CreateChunk( &ckMain, MMIO_CREATERIFF ) == 0
  1180. && SUCCEEDED( DM_SaveSinglePattern( pIRiffStream ) )
  1181. && pIRiffStream->Ascend( &ckMain, 0 ) == 0 )
  1182. {
  1183. hr = S_OK;
  1184. }
  1185. pIRiffStream->Release();
  1186. }
  1187. return hr;
  1188. }
  1189. /////////////////////////////////////////////////////////////////////////////
  1190. // DirectMusicPartRef::DM_SavePartRef
  1191. HRESULT DirectMusicPartRef::DM_SavePartRef( IAARIFFStream* pIRiffStream )
  1192. {
  1193. IStream* pIStream = NULL;
  1194. HRESULT hr;
  1195. MMCKINFO ckMain;
  1196. MMCKINFO ck;
  1197. DWORD dwBytesWritten;
  1198. DMUS_IO_PARTREF oDMPartRef;
  1199. if ( m_pDMPart == NULL )
  1200. {
  1201. hr = E_FAIL;
  1202. goto ON_ERROR;
  1203. }
  1204. pIStream = pIRiffStream->GetStream();
  1205. if ( pIStream == NULL )
  1206. {
  1207. hr = E_FAIL;
  1208. goto ON_ERROR;
  1209. }
  1210. // Write PartRef list header
  1211. ckMain.fccType = DMUS_FOURCC_PARTREF_LIST;
  1212. if( pIRiffStream->CreateChunk(&ckMain, MMIO_CREATELIST) != 0 )
  1213. {
  1214. hr = E_FAIL;
  1215. goto ON_ERROR;
  1216. }
  1217. // Write PartRef chunk header
  1218. ck.ckid = DMUS_FOURCC_PARTREF_CHUNK;
  1219. if( pIRiffStream->CreateChunk( &ck, 0 ) != 0 )
  1220. {
  1221. hr = E_FAIL;
  1222. goto ON_ERROR;
  1223. }
  1224. // Prepare DMUS_IO_PARTREF structure
  1225. memset( &oDMPartRef, 0, sizeof(DMUS_IO_PARTREF) );
  1226. oDMPartRef.dwPChannel = m_dwLogicalPartID;
  1227. oDMPartRef.wLogicalPartID = (WORD) m_dwLogicalPartID;
  1228. oDMPartRef.bVariationLockID = m_bVariationLockID;
  1229. oDMPartRef.bSubChordLevel = m_bSubChordLevel;
  1230. oDMPartRef.bPriority = m_bPriority;
  1231. memcpy( &oDMPartRef.guidPartID, &m_pDMPart->m_guidPartID, sizeof(GUID) );
  1232. // Write PartRef chunk data
  1233. hr = pIStream->Write( &oDMPartRef, sizeof(DMUS_IO_PARTREF), &dwBytesWritten);
  1234. if( FAILED( hr ) || dwBytesWritten != sizeof(DMUS_IO_PARTREF) )
  1235. {
  1236. hr = E_FAIL;
  1237. goto ON_ERROR;
  1238. }
  1239. if( pIRiffStream->Ascend(&ck, 0) != 0 )
  1240. {
  1241. hr = E_FAIL;
  1242. goto ON_ERROR;
  1243. }
  1244. if( pIRiffStream->Ascend( &ckMain, 0 ) != 0 )
  1245. {
  1246. hr = E_FAIL;
  1247. goto ON_ERROR;
  1248. }
  1249. ON_ERROR:
  1250. if (pIStream) pIStream->Release();
  1251. return hr;
  1252. }
  1253. /////////////////////////////////////////////////////////////////////////////
  1254. // CDirectMusicPart::DM_SavePart
  1255. HRESULT DirectMusicPart::DM_SavePart( IAARIFFStream* pIRiffStream )
  1256. {
  1257. IStream* pIStream;
  1258. HRESULT hr;
  1259. MMCKINFO ckMain;
  1260. MMCKINFO ck;
  1261. DWORD dwBytesWritten;
  1262. DMUS_IO_STYLEPART oDMStylePart;
  1263. pIStream = pIRiffStream->GetStream();
  1264. if ( pIStream == NULL )
  1265. {
  1266. hr = E_FAIL;
  1267. goto ON_ERROR;
  1268. }
  1269. // Write Part list header
  1270. ckMain.fccType = DMUS_FOURCC_PART_LIST;
  1271. if( pIRiffStream->CreateChunk(&ckMain, MMIO_CREATELIST) != 0 )
  1272. {
  1273. hr = E_FAIL;
  1274. goto ON_ERROR;
  1275. }
  1276. // Write Part chunk header
  1277. ck.ckid = DMUS_FOURCC_PART_CHUNK;
  1278. if( pIRiffStream->CreateChunk( &ck, 0 ) != 0 )
  1279. {
  1280. hr = E_FAIL;
  1281. goto ON_ERROR;
  1282. }
  1283. // Prepare DMUS_IO_STYLEPART structure
  1284. memset( &oDMStylePart, 0, sizeof(DMUS_IO_STYLEPART) );
  1285. oDMStylePart.timeSig.bBeatsPerMeasure = m_timeSig.m_bBeatsPerMeasure;
  1286. oDMStylePart.timeSig.bBeat = m_timeSig.m_bBeat;
  1287. oDMStylePart.timeSig.wGridsPerBeat = m_timeSig.m_wGridsPerBeat;
  1288. oDMStylePart.wNbrMeasures = m_wNumMeasures;
  1289. oDMStylePart.bInvertUpper = m_bInvertUpper;
  1290. oDMStylePart.bInvertLower = m_bInvertLower;
  1291. oDMStylePart.bPlayModeFlags = m_bPlayModeFlags;
  1292. oDMStylePart.dwFlags = m_dwFlags;
  1293. memcpy( &oDMStylePart.guidPartID, &m_guidPartID, sizeof(GUID) );
  1294. memcpy( &oDMStylePart.dwVariationChoices, &m_dwVariationChoices, sizeof(m_dwVariationChoices) );
  1295. // Write Part chunk data
  1296. hr = pIStream->Write( &oDMStylePart, sizeof(DMUS_IO_STYLEPART), &dwBytesWritten);
  1297. if( FAILED( hr ) || dwBytesWritten != sizeof(DMUS_IO_STYLEPART) )
  1298. {
  1299. hr = E_FAIL;
  1300. goto ON_ERROR;
  1301. }
  1302. if( pIRiffStream->Ascend(&ck, 0) != 0 )
  1303. {
  1304. hr = E_FAIL;
  1305. goto ON_ERROR;
  1306. }
  1307. CDirectMusicEventItem* pEvent;
  1308. // Save Part note list (when applicable)
  1309. pEvent = EventList.GetHead();
  1310. while( pEvent )
  1311. {
  1312. if( pEvent->m_dwEventTag == DMUS_EVENT_NOTE )
  1313. {
  1314. hr = DM_SaveNoteList( pIRiffStream );
  1315. if( FAILED( hr ) )
  1316. {
  1317. goto ON_ERROR;
  1318. }
  1319. break;
  1320. }
  1321. pEvent = pEvent->GetNext();
  1322. }
  1323. // Save Part curve list (when applicable)
  1324. pEvent = EventList.GetHead();
  1325. while( pEvent )
  1326. {
  1327. if( pEvent->m_dwEventTag == DMUS_EVENT_CURVE )
  1328. {
  1329. hr = DM_SaveCurveList( pIRiffStream );
  1330. if( FAILED( hr ) )
  1331. {
  1332. goto ON_ERROR;
  1333. }
  1334. break;
  1335. }
  1336. pEvent = pEvent->GetNext();
  1337. }
  1338. // Save Part marker list (when applicable)
  1339. pEvent = EventList.GetHead();
  1340. while( pEvent )
  1341. {
  1342. if( pEvent->m_dwEventTag == DMUS_EVENT_MARKER )
  1343. {
  1344. hr = DM_SaveMarkerList( pIRiffStream );
  1345. if( FAILED( hr ) )
  1346. {
  1347. goto ON_ERROR;
  1348. }
  1349. break;
  1350. }
  1351. pEvent = pEvent->GetNext();
  1352. }
  1353. // Save Part anticipation list (when applicable)
  1354. pEvent = EventList.GetHead();
  1355. while( pEvent )
  1356. {
  1357. if( pEvent->m_dwEventTag == DMUS_EVENT_ANTICIPATION )
  1358. {
  1359. hr = DM_SaveAnticipationList( pIRiffStream );
  1360. if( FAILED( hr ) )
  1361. {
  1362. goto ON_ERROR;
  1363. }
  1364. break;
  1365. }
  1366. pEvent = pEvent->GetNext();
  1367. }
  1368. // save resolution list (when applicable)
  1369. if (m_ResolutionList.GetHead())
  1370. {
  1371. hr = DM_SaveResolutionList(pIRiffStream);
  1372. if( FAILED( hr ) )
  1373. {
  1374. goto ON_ERROR;
  1375. }
  1376. }
  1377. if( pIRiffStream->Ascend( &ckMain, 0 ) != 0 )
  1378. {
  1379. hr = E_FAIL;
  1380. goto ON_ERROR;
  1381. }
  1382. ON_ERROR:
  1383. pIStream->Release();
  1384. return hr;
  1385. }
  1386. /////////////////////////////////////////////////////////////////////////////
  1387. // DirectMusicPart::DM_SaveNoteList
  1388. HRESULT DirectMusicPart::DM_SaveNoteList( IAARIFFStream* pIRiffStream )
  1389. {
  1390. CDirectMusicEventItem* pEvent;
  1391. CDMStyleNote* pNote;
  1392. IStream* pIStream;
  1393. HRESULT hr;
  1394. MMCKINFO ck;
  1395. DWORD dwBytesWritten;
  1396. WORD dwSize;
  1397. DMUS_IO_STYLENOTE oDMStyleNote;
  1398. pIStream = pIRiffStream->GetStream();
  1399. if ( pIStream == NULL )
  1400. {
  1401. hr = E_FAIL;
  1402. goto ON_ERROR;
  1403. }
  1404. // Write Note chunk header
  1405. ck.ckid = DMUS_FOURCC_NOTE_CHUNK;
  1406. if( pIRiffStream->CreateChunk( &ck, 0 ) != 0)
  1407. {
  1408. hr = E_FAIL;
  1409. goto ON_ERROR;
  1410. }
  1411. // Save size of DMUS_IO_STYLENOTE structure
  1412. dwSize = sizeof(DMUS_IO_STYLENOTE);
  1413. hr = pIStream->Write( &dwSize, sizeof(DWORD), &dwBytesWritten );
  1414. if( FAILED( hr )
  1415. || dwBytesWritten != sizeof(DWORD) )
  1416. {
  1417. hr = E_FAIL;
  1418. goto ON_ERROR;
  1419. }
  1420. // Now save all of the notes
  1421. pEvent = EventList.GetHead();
  1422. while( pEvent )
  1423. {
  1424. if( pEvent->m_dwEventTag == DMUS_EVENT_NOTE )
  1425. {
  1426. pNote = (CDMStyleNote*)pEvent;
  1427. // Prepare DMUS_IO_STYLENOTE structure
  1428. memset( &oDMStyleNote, 0, sizeof(DMUS_IO_STYLENOTE) );
  1429. oDMStyleNote.mtGridStart = pNote->m_nGridStart;
  1430. oDMStyleNote.dwVariation = pNote->m_dwVariation;
  1431. oDMStyleNote.nTimeOffset = pNote->m_nTimeOffset;
  1432. oDMStyleNote.mtDuration = pNote->m_mtDuration;
  1433. oDMStyleNote.wMusicValue = pNote->m_wMusicValue;
  1434. oDMStyleNote.bVelocity = pNote->m_bVelocity;
  1435. oDMStyleNote.bTimeRange = pNote->m_bTimeRange;
  1436. oDMStyleNote.bDurRange = pNote->m_bDurRange;
  1437. oDMStyleNote.bVelRange = pNote->m_bVelRange;
  1438. oDMStyleNote.bInversionID = pNote->m_bInversionId;
  1439. oDMStyleNote.bPlayModeFlags = pNote->m_bPlayModeFlags;
  1440. oDMStyleNote.bNoteFlags = pNote->m_bFlags;
  1441. // Write DMUS_IO_STYLENOTE structure
  1442. hr = pIStream->Write( &oDMStyleNote, sizeof(DMUS_IO_STYLENOTE), &dwBytesWritten );
  1443. if( FAILED( hr )
  1444. || dwBytesWritten != sizeof(DMUS_IO_STYLENOTE) )
  1445. {
  1446. hr = E_FAIL;
  1447. goto ON_ERROR;
  1448. }
  1449. }
  1450. pEvent = pEvent->GetNext();
  1451. }
  1452. if( pIRiffStream->Ascend(&ck, 0) != 0 )
  1453. {
  1454. hr = E_FAIL;
  1455. goto ON_ERROR;
  1456. }
  1457. ON_ERROR:
  1458. pIStream->Release();
  1459. return hr;
  1460. }
  1461. /////////////////////////////////////////////////////////////////////////////
  1462. // DirectMusicPart::DM_SaveCurveList
  1463. HRESULT DirectMusicPart::DM_SaveCurveList( IAARIFFStream* pIRiffStream )
  1464. {
  1465. CDirectMusicEventItem* pEvent;
  1466. CDMStyleCurve* pCurve;
  1467. IStream* pIStream;
  1468. HRESULT hr;
  1469. MMCKINFO ck;
  1470. DWORD dwBytesWritten;
  1471. WORD dwSize;
  1472. DMUS_IO_STYLECURVE oDMStyleCurve;
  1473. pIStream = pIRiffStream->GetStream();
  1474. if ( pIStream == NULL )
  1475. {
  1476. hr = E_FAIL;
  1477. goto ON_ERROR;
  1478. }
  1479. ck.ckid = DMUS_FOURCC_CURVE_CHUNK;
  1480. if( pIRiffStream->CreateChunk( &ck, 0 ) != 0)
  1481. {
  1482. hr = E_FAIL;
  1483. goto ON_ERROR;
  1484. }
  1485. // Save size of DMUS_IO_STYLECURVE structure
  1486. dwSize = sizeof(DMUS_IO_STYLECURVE);
  1487. hr = pIStream->Write( &dwSize, sizeof(dwSize), &dwBytesWritten );
  1488. if( FAILED( hr )
  1489. || dwBytesWritten != sizeof(dwSize) )
  1490. {
  1491. hr = E_FAIL;
  1492. goto ON_ERROR;
  1493. }
  1494. // Now save all of the curves
  1495. pEvent = EventList.GetHead();
  1496. while( pEvent )
  1497. {
  1498. if( pEvent->m_dwEventTag == DMUS_EVENT_CURVE )
  1499. {
  1500. pCurve = (CDMStyleCurve*)pEvent;
  1501. // Prepare DMUS_IO_STYLECURVE structure
  1502. memset( &oDMStyleCurve, 0, sizeof(DMUS_IO_STYLECURVE) );
  1503. oDMStyleCurve.mtGridStart = pCurve->m_nGridStart;
  1504. oDMStyleCurve.dwVariation = pCurve->m_dwVariation;
  1505. oDMStyleCurve.nTimeOffset = pCurve->m_nTimeOffset;
  1506. oDMStyleCurve.mtDuration = pCurve->m_mtDuration;
  1507. oDMStyleCurve.nStartValue = pCurve->m_StartValue;
  1508. oDMStyleCurve.nEndValue = pCurve->m_EndValue;
  1509. oDMStyleCurve.bEventType = pCurve->m_bEventType;
  1510. oDMStyleCurve.bCurveShape = pCurve->m_bCurveShape;
  1511. oDMStyleCurve.bCCData = pCurve->m_bCCData;
  1512. oDMStyleCurve.mtResetDuration = pCurve->m_mtResetDuration;
  1513. oDMStyleCurve.nResetValue = pCurve->m_nResetValue;
  1514. oDMStyleCurve.bFlags = pCurve->m_bFlags;
  1515. // dx8 stuff
  1516. oDMStyleCurve.wParamType = pCurve->m_wParamType;
  1517. oDMStyleCurve.wMergeIndex = pCurve->m_wMergeIndex;
  1518. // Write DMUS_IO_STYLECURVE structure
  1519. hr = pIStream->Write( &oDMStyleCurve, sizeof(DMUS_IO_STYLECURVE), &dwBytesWritten );
  1520. if( FAILED( hr )
  1521. || dwBytesWritten != sizeof(DMUS_IO_STYLECURVE) )
  1522. {
  1523. hr = E_FAIL;
  1524. goto ON_ERROR;
  1525. }
  1526. }
  1527. pEvent = pEvent->GetNext();
  1528. }
  1529. if( pIRiffStream->Ascend(&ck, 0) != 0 )
  1530. {
  1531. hr = E_FAIL;
  1532. goto ON_ERROR;
  1533. }
  1534. ON_ERROR:
  1535. pIStream->Release();
  1536. return hr;
  1537. }
  1538. /////////////////////////////////////////////////////////////////////////////
  1539. // DirectMusicPart::DM_SaveMarkerList
  1540. HRESULT DirectMusicPart::DM_SaveMarkerList( IAARIFFStream* pIRiffStream )
  1541. {
  1542. CDirectMusicEventItem* pEvent;
  1543. CDMStyleMarker* pMarker;
  1544. IStream* pIStream;
  1545. HRESULT hr;
  1546. MMCKINFO ck;
  1547. DWORD dwBytesWritten;
  1548. WORD dwSize;
  1549. DMUS_IO_STYLEMARKER oDMStyleMarker;
  1550. pIStream = pIRiffStream->GetStream();
  1551. if ( pIStream == NULL )
  1552. {
  1553. hr = E_FAIL;
  1554. goto ON_ERROR;
  1555. }
  1556. ck.ckid = DMUS_FOURCC_MARKER_CHUNK;
  1557. if( pIRiffStream->CreateChunk( &ck, 0 ) != 0)
  1558. {
  1559. hr = E_FAIL;
  1560. goto ON_ERROR;
  1561. }
  1562. // Save size of DMUS_IO_STYLEMARKER structure
  1563. dwSize = sizeof(DMUS_IO_STYLEMARKER);
  1564. hr = pIStream->Write( &dwSize, sizeof(dwSize), &dwBytesWritten );
  1565. if( FAILED( hr )
  1566. || dwBytesWritten != sizeof(dwSize) )
  1567. {
  1568. hr = E_FAIL;
  1569. goto ON_ERROR;
  1570. }
  1571. // Now save all of the markers
  1572. pEvent = EventList.GetHead();
  1573. while( pEvent )
  1574. {
  1575. if( pEvent->m_dwEventTag == DMUS_EVENT_MARKER )
  1576. {
  1577. pMarker = (CDMStyleMarker*)pEvent;
  1578. // Prepare DMUS_IO_STYLEMARKER structure
  1579. memset( &oDMStyleMarker, 0, sizeof(DMUS_IO_STYLEMARKER) );
  1580. oDMStyleMarker.mtGridStart = pMarker->m_nGridStart;
  1581. oDMStyleMarker.dwVariation = pMarker->m_dwVariation;
  1582. oDMStyleMarker.wMarkerFlags = pMarker->m_wFlags;
  1583. // Write DMUS_IO_STYLEMARKER structure
  1584. hr = pIStream->Write( &oDMStyleMarker, sizeof(DMUS_IO_STYLEMARKER), &dwBytesWritten );
  1585. if( FAILED( hr )
  1586. || dwBytesWritten != sizeof(DMUS_IO_STYLEMARKER) )
  1587. {
  1588. hr = E_FAIL;
  1589. goto ON_ERROR;
  1590. }
  1591. }
  1592. pEvent = pEvent->GetNext();
  1593. }
  1594. if( pIRiffStream->Ascend(&ck, 0) != 0 )
  1595. {
  1596. hr = E_FAIL;
  1597. goto ON_ERROR;
  1598. }
  1599. ON_ERROR:
  1600. pIStream->Release();
  1601. return hr;
  1602. }
  1603. /////////////////////////////////////////////////////////////////////////////
  1604. // DirectMusicPart::DM_SaveAnticipationList
  1605. HRESULT DirectMusicPart::DM_SaveAnticipationList( IAARIFFStream* pIRiffStream )
  1606. {
  1607. CDirectMusicEventItem* pEvent;
  1608. CDMStyleAnticipation* pAnticipation;
  1609. IStream* pIStream;
  1610. HRESULT hr;
  1611. MMCKINFO ck;
  1612. DWORD dwBytesWritten;
  1613. WORD dwSize;
  1614. DMUS_IO_STYLE_ANTICIPATION oDMStyleAnticipation;
  1615. pIStream = pIRiffStream->GetStream();
  1616. if ( pIStream == NULL )
  1617. {
  1618. hr = E_FAIL;
  1619. goto ON_ERROR;
  1620. }
  1621. ck.ckid = DMUS_FOURCC_ANTICIPATION_CHUNK;
  1622. if( pIRiffStream->CreateChunk( &ck, 0 ) != 0)
  1623. {
  1624. hr = E_FAIL;
  1625. goto ON_ERROR;
  1626. }
  1627. // Save size of DMUS_IO_STYLE_ANTICIPATION structure
  1628. dwSize = sizeof(DMUS_IO_STYLE_ANTICIPATION);
  1629. hr = pIStream->Write( &dwSize, sizeof(dwSize), &dwBytesWritten );
  1630. if( FAILED( hr ) || dwBytesWritten != sizeof(dwSize) )
  1631. {
  1632. hr = E_FAIL;
  1633. goto ON_ERROR;
  1634. }
  1635. // Now save all of the anticipations
  1636. pEvent = EventList.GetHead();
  1637. while( pEvent )
  1638. {
  1639. if( pEvent->m_dwEventTag == DMUS_EVENT_ANTICIPATION )
  1640. {
  1641. pAnticipation = (CDMStyleAnticipation*)pEvent;
  1642. // Prepare DMUS_IO_STYLE_ANTICIPATION structure
  1643. memset( &oDMStyleAnticipation, 0, sizeof(DMUS_IO_STYLE_ANTICIPATION) );
  1644. oDMStyleAnticipation.mtGridStart = pAnticipation->m_nGridStart;
  1645. oDMStyleAnticipation.dwVariation = pAnticipation->m_dwVariation;
  1646. oDMStyleAnticipation.nTimeOffset = pAnticipation->m_nTimeOffset;
  1647. oDMStyleAnticipation.bTimeRange = pAnticipation->m_bTimeRange;
  1648. // Write DMUS_IO_STYLE_ANTICIPATION structure
  1649. hr = pIStream->Write( &oDMStyleAnticipation, sizeof(DMUS_IO_STYLE_ANTICIPATION), &dwBytesWritten );
  1650. if( FAILED( hr ) || dwBytesWritten != sizeof(DMUS_IO_STYLE_ANTICIPATION) )
  1651. {
  1652. hr = E_FAIL;
  1653. goto ON_ERROR;
  1654. }
  1655. }
  1656. pEvent = pEvent->GetNext();
  1657. }
  1658. if( pIRiffStream->Ascend(&ck, 0) != 0 )
  1659. {
  1660. hr = E_FAIL;
  1661. goto ON_ERROR;
  1662. }
  1663. ON_ERROR:
  1664. pIStream->Release();
  1665. return hr;
  1666. }
  1667. /////////////////////////////////////////////////////////////////////////////
  1668. // DirectMusicPart::DM_SaveResolutionList
  1669. HRESULT DirectMusicPart::DM_SaveResolutionList( IAARIFFStream* pIRiffStream )
  1670. {
  1671. IStream* pIStream;
  1672. HRESULT hr;
  1673. MMCKINFO ck;
  1674. DWORD dwBytesWritten;
  1675. WORD dwSize;
  1676. DMUS_IO_STYLERESOLUTION oDMStyleResolution;
  1677. TListItem<DMUS_IO_STYLERESOLUTION>* pScan = m_ResolutionList.GetHead();
  1678. pIStream = pIRiffStream->GetStream();
  1679. if ( pIStream == NULL )
  1680. {
  1681. hr = E_FAIL;
  1682. goto ON_ERROR;
  1683. }
  1684. ck.ckid = DMUS_FOURCC_RESOLUTION_CHUNK;
  1685. if( pIRiffStream->CreateChunk( &ck, 0 ) != 0)
  1686. {
  1687. hr = E_FAIL;
  1688. goto ON_ERROR;
  1689. }
  1690. // Save size of DMUS_IO_STYLERESOLUTION structure
  1691. dwSize = sizeof(DMUS_IO_STYLERESOLUTION);
  1692. hr = pIStream->Write( &dwSize, sizeof(dwSize), &dwBytesWritten );
  1693. if( FAILED( hr ) || dwBytesWritten != sizeof(dwSize) )
  1694. {
  1695. hr = E_FAIL;
  1696. goto ON_ERROR;
  1697. }
  1698. // Now save all of the resolutions
  1699. for(; pScan; pScan = pScan->GetNext() )
  1700. {
  1701. // Prepare DMUS_IO_STYLERESOLUTION structure
  1702. oDMStyleResolution = pScan->GetItemValue();
  1703. // Write DMUS_IO_STYLERESOLUTION structure
  1704. hr = pIStream->Write( &oDMStyleResolution, sizeof(DMUS_IO_STYLERESOLUTION), &dwBytesWritten );
  1705. if( FAILED( hr ) || dwBytesWritten != sizeof(DMUS_IO_STYLERESOLUTION) )
  1706. {
  1707. hr = E_FAIL;
  1708. goto ON_ERROR;
  1709. }
  1710. }
  1711. if( pIRiffStream->Ascend(&ck, 0) != 0 )
  1712. {
  1713. hr = E_FAIL;
  1714. goto ON_ERROR;
  1715. }
  1716. ON_ERROR:
  1717. pIStream->Release();
  1718. return hr;
  1719. }
  1720. HRESULT CDMStyle::GetPatternStream(WCHAR* wszName, DWORD dwPatternType, IStream** ppStream)
  1721. {
  1722. V_PTRPTR_WRITE(ppStream);
  1723. TListItem<CDirectMusicPattern*>* pPattern = NULL;
  1724. switch (dwPatternType)
  1725. {
  1726. case DMUS_STYLET_PATTERN:
  1727. pPattern = m_StyleInfo.m_PatternList.GetHead();
  1728. break;
  1729. case DMUS_STYLET_MOTIF:
  1730. pPattern = m_StyleInfo.m_MotifList.GetHead();
  1731. break;
  1732. // case for melody fragments...
  1733. }
  1734. for (; pPattern != NULL; pPattern = pPattern->GetNext())
  1735. {
  1736. if (pPattern->GetItemValue()->m_strName == wszName)
  1737. break;
  1738. }
  1739. if (pPattern != NULL)
  1740. {
  1741. // Create a stream
  1742. IStream *pIPatternStream;
  1743. HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &pIPatternStream);
  1744. if (SUCCEEDED(hr))
  1745. {
  1746. // Persist the pattern to the stream
  1747. pPattern->GetItemValue()->Save(pIPatternStream);
  1748. // Return the stream
  1749. *ppStream = pIPatternStream;
  1750. }
  1751. return hr;
  1752. }
  1753. else
  1754. {
  1755. return S_FALSE;
  1756. }
  1757. }
  1758. /*
  1759. @method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetMotif | Creates a segment containing
  1760. the named motif.
  1761. @rdesc Returns one of the following:
  1762. @flag S_OK | Success.
  1763. @flag S_FALSE | No motif with the given name.
  1764. @flag E_POINTER | <p ppSegment> is not a valid address.
  1765. @comm Searches the Style's list of motifs for one whose name matches <p wszName>. If one
  1766. is found, a segment is created containing a Motif track. The track references the Style as
  1767. its associated style and the motif as its pattern.
  1768. */
  1769. HRESULT STDMETHODCALLTYPE CDMStyle::GetMotif(
  1770. WCHAR* pwszName, // @parm The name of the motif to be retrieved.
  1771. IDirectMusicSegment** ppSegment // @parm A segment containing the named motif.
  1772. )
  1773. {
  1774. V_PTR_READ(pwszName,1);
  1775. V_PTRPTR_WRITE(ppSegment);
  1776. String str = pwszName;
  1777. EnterCriticalSection( &m_CriticalSection );
  1778. TListItem<CDirectMusicPattern*>* pPattern = m_StyleInfo.m_MotifList.GetHead();
  1779. for (; pPattern != NULL; pPattern = pPattern->GetNext())
  1780. {
  1781. if (pPattern->GetItemValue()->m_strName == str)
  1782. break;
  1783. }
  1784. if (pPattern != NULL)
  1785. {
  1786. // AddRef the style
  1787. ((IDirectMusicStyle*)this)->AddRef();
  1788. // create a segment containing a motif track
  1789. IUnknown* pIUSegment;
  1790. // make a motif with the given number of repeats
  1791. CreateMotifSegment(pPattern->GetItemValue(), &pIUSegment, 0);
  1792. HRESULT hr = pIUSegment->QueryInterface(IID_IDirectMusicSegment, (void**)ppSegment);
  1793. pIUSegment->Release();
  1794. LeaveCriticalSection( &m_CriticalSection );
  1795. return hr;
  1796. }
  1797. else
  1798. {
  1799. LeaveCriticalSection( &m_CriticalSection );
  1800. return S_FALSE;
  1801. }
  1802. }
  1803. HRESULT STDMETHODCALLTYPE CDMStyle::EnumPartGuid(
  1804. DWORD dwIndex, WCHAR* wszName, DWORD dwPatternType, GUID& rGuid)
  1805. {
  1806. HRESULT hr = S_OK;
  1807. TListItem<CDirectMusicPattern*>* pPattern = NULL;
  1808. switch (dwPatternType)
  1809. {
  1810. case DMUS_STYLET_PATTERN:
  1811. pPattern = m_StyleInfo.m_PatternList.GetHead();
  1812. break;
  1813. case DMUS_STYLET_MOTIF:
  1814. pPattern = m_StyleInfo.m_MotifList.GetHead();
  1815. break;
  1816. // case for melody fragments...
  1817. }
  1818. for (; pPattern != NULL; pPattern = pPattern->GetNext())
  1819. {
  1820. if (pPattern->GetItemValue()->m_strName == wszName)
  1821. break;
  1822. }
  1823. if (pPattern != NULL)
  1824. {
  1825. TListItem<DirectMusicPartRef>* pPartRef = pPattern->GetItemValue()->m_PartRefList.GetHead();
  1826. for (DWORD dw = 0; dw < dwIndex; dw++)
  1827. {
  1828. if (pPartRef) pPartRef = pPartRef->GetNext();
  1829. }
  1830. if (pPartRef)
  1831. {
  1832. rGuid = pPartRef->GetItemValue().m_pDMPart->m_guidPartID;
  1833. hr = S_OK;
  1834. }
  1835. else
  1836. {
  1837. hr = S_FALSE;
  1838. }
  1839. }
  1840. else
  1841. {
  1842. hr = DMUS_E_NOT_FOUND;
  1843. }
  1844. return hr;
  1845. }
  1846. // NOTE: assumes wszName is preallocated to MAX_PATH
  1847. HRESULT STDMETHODCALLTYPE CDMStyle::EnumPattern(
  1848. DWORD dwIndex,
  1849. DWORD dwPatternType,
  1850. WCHAR *wszName
  1851. )
  1852. {
  1853. HRESULT hr = E_INVALIDARG;
  1854. switch (dwPatternType)
  1855. {
  1856. case DMUS_STYLET_PATTERN:
  1857. hr = EnumRegularPattern(dwIndex, wszName);
  1858. break;
  1859. case DMUS_STYLET_MOTIF:
  1860. hr = EnumMotif(dwIndex, wszName);
  1861. break;
  1862. // case for melody fragments...
  1863. }
  1864. return hr;
  1865. }
  1866. HRESULT STDMETHODCALLTYPE CDMStyle::EnumRegularPattern(
  1867. DWORD dwIndex,
  1868. WCHAR *wszName
  1869. )
  1870. {
  1871. V_PTR_WRITE(wszName, 1);
  1872. TListItem<CDirectMusicPattern*>* pPattern = m_StyleInfo.m_PatternList.GetHead();
  1873. for (DWORD dw = 0; pPattern != NULL; pPattern = pPattern->GetNext(), dw++)
  1874. {
  1875. if (dw == dwIndex)
  1876. break;
  1877. }
  1878. HRESULT hr = S_OK;
  1879. if (pPattern != NULL)
  1880. {
  1881. if (pPattern->GetItemValue()->m_strName.GetLength() < MAX_PATH)
  1882. {
  1883. wcscpy(wszName, pPattern->GetItemValue()->m_strName);
  1884. hr = S_OK;
  1885. }
  1886. else
  1887. {
  1888. for (int i = 0; i < (MAX_PATH - 1); i++)
  1889. {
  1890. wszName[i] = pPattern->GetItemValue()->m_strName[i];
  1891. }
  1892. wszName[MAX_PATH - 1] = L'\0';
  1893. hr = DMUS_S_STRING_TRUNCATED;
  1894. }
  1895. }
  1896. else
  1897. {
  1898. hr = S_FALSE;
  1899. }
  1900. return hr;
  1901. }
  1902. // enum the list of start times common to all patterns referenced by the associated type, level, and range.
  1903. // (i.e. if more than one such pattern, skip start times not comon to all)
  1904. // return S_FALSE when no start times remain.
  1905. HRESULT STDMETHODCALLTYPE CDMStyle::EnumStartTime(DWORD dwIndex, DMUS_COMMAND_PARAM* pCommand, MUSIC_TIME* pmtStartTime)
  1906. {
  1907. int nRange = (int)pCommand->bGrooveRange / 2;
  1908. int nLow = (int)pCommand->bGrooveLevel - nRange;
  1909. if (nLow < 0) nLow = 0;
  1910. int nHigh = (int)pCommand->bGrooveLevel + nRange;
  1911. if (nHigh > 100) nHigh = 100;
  1912. TList<CDirectMusicPattern*> MatchList;
  1913. int nMatchCount = 0;
  1914. TListItem<CDirectMusicPattern*>* pPattern = m_StyleInfo.m_PatternList.GetHead();
  1915. if (!pPattern) return S_FALSE;
  1916. TListItem<MUSIC_TIME>** apStartTimes = NULL;
  1917. HRESULT hr = S_OK;
  1918. for (; pPattern != NULL; pPattern = pPattern->GetNext())
  1919. {
  1920. CDirectMusicPattern*& rpPattern = pPattern->GetItemValue();
  1921. if (rpPattern->m_bGrooveBottom <= (BYTE)nHigh &&
  1922. rpPattern->m_bGrooveTop >= (BYTE)nLow)
  1923. {
  1924. if ( (pCommand->bCommand == DMUS_COMMANDT_FILL &&
  1925. rpPattern->m_wEmbellishment == EMB_FILL) ||
  1926. (pCommand->bCommand == DMUS_COMMANDT_INTRO &&
  1927. rpPattern->m_wEmbellishment == EMB_INTRO) ||
  1928. (pCommand->bCommand == DMUS_COMMANDT_BREAK &&
  1929. rpPattern->m_wEmbellishment == EMB_BREAK) ||
  1930. (pCommand->bCommand == DMUS_COMMANDT_END &&
  1931. rpPattern->m_wEmbellishment == EMB_END) ||
  1932. (pCommand->bCommand == DMUS_COMMANDT_GROOVE &&
  1933. rpPattern->m_wEmbellishment == EMB_NORMAL) ||
  1934. (rpPattern->m_wEmbellishment & EMB_USER_DEFINED &&
  1935. (rpPattern->m_wEmbellishment >> 8) == (WORD)pCommand->bCommand) )
  1936. {
  1937. if (rpPattern && rpPattern->m_StartTimeList.GetHead())
  1938. {
  1939. TListItem<CDirectMusicPattern*>* pNewPattern;
  1940. pNewPattern = new TListItem<CDirectMusicPattern*>(rpPattern);
  1941. if (!pNewPattern)
  1942. {
  1943. hr = E_OUTOFMEMORY;
  1944. break;
  1945. }
  1946. MatchList.AddHead(pNewPattern);
  1947. nMatchCount++;
  1948. }
  1949. }
  1950. }
  1951. }
  1952. if (S_OK == hr)
  1953. {
  1954. if (nMatchCount)
  1955. {
  1956. apStartTimes = new TListItem<MUSIC_TIME>*[nMatchCount];
  1957. if (!apStartTimes) hr = E_OUTOFMEMORY;
  1958. }
  1959. else hr = S_FALSE;
  1960. }
  1961. if (S_OK == hr)
  1962. {
  1963. MUSIC_TIME mtMin = 0, mtMax = 0;
  1964. TListItem<CDirectMusicPattern*>* pMatch = MatchList.GetHead();
  1965. // initialize the array of start time pointers
  1966. for (int i = 0; pMatch; pMatch = pMatch->GetNext(), i++)
  1967. {
  1968. apStartTimes[i] = pMatch->GetItemValue()->m_StartTimeList.GetHead();
  1969. }
  1970. for (DWORD dw = 0; S_OK == hr && dw <= dwIndex; dw++)
  1971. {
  1972. // get the min and max times for the first item in each list
  1973. mtMin = mtMax = apStartTimes[0]->GetItemValue();
  1974. for (int i = 0; i < nMatchCount; i++)
  1975. {
  1976. if (apStartTimes[i]->GetItemValue() < mtMin)
  1977. {
  1978. mtMin = apStartTimes[i]->GetItemValue();
  1979. }
  1980. if (apStartTimes[i]->GetItemValue() > mtMax)
  1981. {
  1982. mtMax = apStartTimes[i]->GetItemValue();
  1983. }
  1984. }
  1985. // sync up all the start times by making sure max == min.
  1986. // set hr to S_FALSE if any lists run out.
  1987. while (S_OK == hr && mtMax != mtMin)
  1988. {
  1989. // We'll only be changing values less than max, so the
  1990. // new min will be not greater than that.
  1991. MUSIC_TIME mtNewMin = mtMax;
  1992. for (i = 0; i < nMatchCount; i++)
  1993. {
  1994. if (apStartTimes[i]->GetItemValue() < mtMax)
  1995. {
  1996. apStartTimes[i] = apStartTimes[i]->GetNext();
  1997. if (!apStartTimes[i])
  1998. {
  1999. hr = S_FALSE;
  2000. break;
  2001. }
  2002. if (apStartTimes[i]->GetItemValue() < mtNewMin)
  2003. {
  2004. mtNewMin = apStartTimes[i]->GetItemValue();
  2005. }
  2006. if (apStartTimes[i]->GetItemValue() > mtMax)
  2007. {
  2008. mtMax = apStartTimes[i]->GetItemValue();
  2009. }
  2010. }
  2011. }
  2012. // mtTempMin is the new min, since every instance of the
  2013. // old min was less than max and therefore changed.
  2014. mtMin = mtNewMin;
  2015. }
  2016. if (S_OK != hr) break;
  2017. // if we're going to loop again, increment all the start time pointers.
  2018. if (dw < dwIndex)
  2019. {
  2020. for (i = 0; i < nMatchCount; i++)
  2021. {
  2022. apStartTimes[i] = apStartTimes[i]->GetNext();
  2023. // set hr to S_FALSE if any lists run out.
  2024. if (!apStartTimes[i])
  2025. {
  2026. hr = S_FALSE;
  2027. break;
  2028. }
  2029. }
  2030. }
  2031. }
  2032. // if hr is S_OK, max should equal min, so return one of them.
  2033. if (S_OK == hr) *pmtStartTime = mtMax;
  2034. delete [] apStartTimes;
  2035. }
  2036. return hr;
  2037. }
  2038. /*
  2039. @method:(EXTERNAL) HRESULT | IDirectMusicStyle | EnumMotif | Retrieves the name of the
  2040. motif indexed by <p dwIndex>.
  2041. @rdesc Returns one of the following
  2042. @flag S_OK | Success
  2043. @flag S_FALSE | No motif at the given location
  2044. @flag DMUS_S_STRING_TRUNCATED | The length of the motif name is not less than MAX_PATH
  2045. @flag E_POINTER | <p pwszName> is not a valid address
  2046. @comm Searches the Style's list of motifs for the one at the location given by <p dwIndex>.
  2047. If there is such a motif, its name is returned in <p pwszName>; if it is not less than MAX_PATH,
  2048. it is truncated. This assumes that <p pwszName>
  2049. has been pre-allocated to have a length of at least MAX_PATH.
  2050. */
  2051. HRESULT STDMETHODCALLTYPE CDMStyle::EnumMotif(
  2052. DWORD dwIndex, // @parm An index into the Style's motif list (0-based).
  2053. WCHAR *pwszName // @parm The motif name to be returned.
  2054. )
  2055. {
  2056. V_BUFPTR_WRITE(pwszName,MAX_PATH);
  2057. TListItem<CDirectMusicPattern*>* pPattern = m_StyleInfo.m_MotifList.GetHead();
  2058. for (DWORD dw = 0; pPattern != NULL; pPattern = pPattern->GetNext(), dw++)
  2059. {
  2060. if (dw == dwIndex)
  2061. break;
  2062. }
  2063. HRESULT hr = S_OK;
  2064. if (pPattern != NULL)
  2065. {
  2066. if (pPattern->GetItemValue()->m_strName.GetLength() < MAX_PATH)
  2067. {
  2068. wcscpy(pwszName, pPattern->GetItemValue()->m_strName);
  2069. hr = S_OK;
  2070. }
  2071. else
  2072. {
  2073. for (int i = 0; i < (MAX_PATH - 1); i++)
  2074. {
  2075. pwszName[i] = pPattern->GetItemValue()->m_strName[i];
  2076. }
  2077. pwszName[MAX_PATH - 1] = L'\0';
  2078. hr = DMUS_S_STRING_TRUNCATED;
  2079. }
  2080. }
  2081. else
  2082. {
  2083. hr = S_FALSE;
  2084. }
  2085. return hr;
  2086. }
  2087. /*
  2088. @method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetChordMap | Retrieves the named ChordMap.
  2089. @rdesc Returns one of the following:
  2090. @flag S_OK | Success.
  2091. @flag S_FALSE | No ChordMap with the given name.
  2092. @flag E_POINTER | ppChordMap not a valid pointer
  2093. @comm Searches the Style's list of personalities for one whose name matches <p wszName>. If one
  2094. is found, it is returned.
  2095. */
  2096. HRESULT STDMETHODCALLTYPE CDMStyle::GetChordMap(
  2097. WCHAR* pwszName, // @parm The name of the ChordMap to be retrieved.
  2098. IDirectMusicChordMap** ppChordMap // @parm The named ChordMap.
  2099. )
  2100. {
  2101. V_PTR_READ(pwszName,1);
  2102. V_PTRPTR_WRITE(ppChordMap);
  2103. String str1 = pwszName;
  2104. TListItem<IDirectMusicChordMap*>* pPersItem = m_StyleInfo.m_PersList.GetHead();
  2105. IDirectMusicChordMap *pPers = NULL;
  2106. for (; pPersItem != NULL; pPersItem = pPersItem->GetNext())
  2107. {
  2108. HRESULT hr = S_OK;
  2109. String str2;
  2110. pPers = pPersItem->GetItemValue();
  2111. IDirectMusicObject *pIObject = NULL;
  2112. DMUS_OBJECTDESC Desc; // Descriptor.
  2113. if (SUCCEEDED(hr = pPers->QueryInterface(IID_IDirectMusicObject,(void **) &pIObject)))
  2114. {
  2115. if (SUCCEEDED(hr = pIObject->GetDescriptor(&Desc)))
  2116. {
  2117. if (Desc.dwValidData & DMUS_OBJ_NAME)
  2118. {
  2119. str2 = Desc.wszName;
  2120. if (str1 == str2)
  2121. {
  2122. pIObject->Release();
  2123. break;
  2124. }
  2125. }
  2126. else hr = E_FAIL;
  2127. }
  2128. pIObject->Release();
  2129. }
  2130. if (!SUCCEEDED(hr))
  2131. {
  2132. return hr;
  2133. }
  2134. }
  2135. if (pPersItem != NULL)
  2136. {
  2137. // AddRef the ChordMap
  2138. pPers->AddRef();
  2139. // Return it.
  2140. *ppChordMap = pPers;
  2141. return S_OK;
  2142. }
  2143. else
  2144. {
  2145. return S_FALSE;
  2146. }
  2147. }
  2148. /*
  2149. @method:(EXTERNAL) HRESULT | IDirectMusicStyle | EnumChordMap | Retrieves the name of the
  2150. ChordMap indexed by <p dwIndex>.
  2151. @rdesc Returns one of the following
  2152. @flag S_OK | Success
  2153. @flag S_FALSE | No ChordMap at the given location
  2154. @flag DMUS_S_STRING_TRUNCATED | The length of the ChordMap name is not less than MAX_PATH
  2155. @flag E_POINTER | <p pwszName> is not a valid address
  2156. @flag DMUS_E_TYPE_UNSUPPORTED | The ChordMap's descriptor doesn't support DMUS_OBJ_NAME
  2157. @comm Searches the Style's list of chord maps for the one at the location given by <p dwIndex>.
  2158. If there is such a ChordMap, its name is returned in <p pwszName>; if it is not less than MAX_PATH,
  2159. it is truncated. This assumes that <p pwszName>
  2160. has been pre-allocated to have a length of at least MAX_PATH.
  2161. */
  2162. HRESULT STDMETHODCALLTYPE CDMStyle::EnumChordMap(
  2163. DWORD dwIndex, // @parm An index into the Style's ChordMap list (0-based).
  2164. WCHAR *pwszName // @parm The ChordMap name to be returned.
  2165. )
  2166. {
  2167. V_BUFPTR_WRITE(pwszName,MAX_PATH);
  2168. TListItem<IDirectMusicChordMap*>* pPers = m_StyleInfo.m_PersList.GetHead();
  2169. for (DWORD dw = 0; pPers != NULL; pPers = pPers->GetNext(), dw++)
  2170. {
  2171. if (dw == dwIndex)
  2172. break;
  2173. }
  2174. if (pPers != NULL)
  2175. {
  2176. HRESULT hr = S_OK;
  2177. IDirectMusicChordMap* pChordMap = pPers->GetItemValue();
  2178. IDirectMusicObject *pIObject = NULL;
  2179. DMUS_OBJECTDESC Desc; // Descriptor.
  2180. if (SUCCEEDED(hr = pChordMap->QueryInterface(IID_IDirectMusicObject,(void **) &pIObject)))
  2181. {
  2182. if (SUCCEEDED(hr = pIObject->GetDescriptor(&Desc)))
  2183. {
  2184. if (Desc.dwValidData & DMUS_OBJ_NAME)
  2185. {
  2186. if (wcslen(Desc.wszName) < MAX_PATH)
  2187. {
  2188. wcscpy(pwszName, Desc.wszName);
  2189. }
  2190. else
  2191. {
  2192. for (int i = 0; i < (MAX_PATH - 1); i++)
  2193. {
  2194. pwszName[i] = Desc.wszName[i];
  2195. }
  2196. pwszName[MAX_PATH - 1] = L'\0';
  2197. hr = DMUS_S_STRING_TRUNCATED;
  2198. }
  2199. }
  2200. else
  2201. {
  2202. hr = DMUS_E_TYPE_UNSUPPORTED;
  2203. }
  2204. }
  2205. pIObject->Release();
  2206. }
  2207. return hr;
  2208. }
  2209. else
  2210. {
  2211. return S_FALSE;
  2212. }
  2213. }
  2214. /*
  2215. @method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetDefaultChordMap | Gets the style's
  2216. default ChordMap.
  2217. @rdesc Returns one of the following
  2218. @flag S_OK | Success.
  2219. @flag E_POINTER | <p ppChordMap> not a valid pointer.
  2220. @flag S_FALSE | Style does not have a default ChordMap.
  2221. @comm Returns the Style's default ChordMap in <p ppChordMap>.
  2222. */
  2223. HRESULT STDMETHODCALLTYPE CDMStyle::GetDefaultChordMap(
  2224. IDirectMusicChordMap **ppChordMap // @parm The ChordMap to be returned.
  2225. )
  2226. {
  2227. V_PTRPTR_WRITE(ppChordMap);
  2228. if(m_StyleInfo.m_pDefaultPers == NULL)
  2229. {
  2230. return S_FALSE;
  2231. }
  2232. *ppChordMap = m_StyleInfo.m_pDefaultPers;
  2233. (*ppChordMap)->AddRef();
  2234. return S_OK;
  2235. }
  2236. /*
  2237. @method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetBand | Retrieves the named band.
  2238. @rdesc Returns one of the following
  2239. @flag S_OK | Success
  2240. @flag E_POINTER | ppBand not a valid pointer
  2241. @flag S_FALSE | No band with the given name
  2242. @comm Searches the Style's list of bands for one whose name matches <p pwszName>. If one
  2243. is found, it is returned in <p ppBand>.
  2244. */
  2245. HRESULT STDMETHODCALLTYPE CDMStyle::GetBand(
  2246. WCHAR *pwszName, // @parm The name of the band to be retrieved.
  2247. IDirectMusicBand **ppBand // @parm The named band.
  2248. )
  2249. {
  2250. V_PTR_READ(pwszName,1);
  2251. V_PTRPTR_WRITE(ppBand);
  2252. String str1 = pwszName;
  2253. TListItem<IDirectMusicBand*>* pBandItem = m_StyleInfo.m_BandList.GetHead();
  2254. IDirectMusicBand *pBand = NULL;
  2255. for (; pBandItem != NULL; pBandItem = pBandItem->GetNext())
  2256. {
  2257. HRESULT hr = S_OK;
  2258. String str2;
  2259. pBand = pBandItem->GetItemValue();
  2260. IDirectMusicObject *pIObject = NULL;
  2261. DMUS_OBJECTDESC Desc; // Descriptor.
  2262. Desc.dwSize = sizeof(Desc);
  2263. if (SUCCEEDED(hr = pBand->QueryInterface(IID_IDirectMusicObject,(void **) &pIObject)))
  2264. {
  2265. if (SUCCEEDED(hr = pIObject->GetDescriptor(&Desc)))
  2266. {
  2267. if (Desc.dwValidData & DMUS_OBJ_NAME)
  2268. {
  2269. str2 = Desc.wszName;
  2270. if (str1 == str2)
  2271. {
  2272. pIObject->Release();
  2273. break;
  2274. }
  2275. }
  2276. else hr = E_FAIL;
  2277. }
  2278. pIObject->Release();
  2279. }
  2280. if (!SUCCEEDED(hr))
  2281. {
  2282. return hr;
  2283. }
  2284. }
  2285. if (pBandItem != NULL)
  2286. {
  2287. // AddRef the band
  2288. pBand->AddRef();
  2289. // Return it.
  2290. *ppBand = pBand;
  2291. return S_OK;
  2292. }
  2293. else
  2294. {
  2295. return S_FALSE;
  2296. }
  2297. }
  2298. /*
  2299. @method:(EXTERNAL) HRESULT | IDirectMusicStyle | EnumBand | Retrieves the name of the
  2300. band indexed by <p dwIndex>.
  2301. @rdesc Returns one of the following
  2302. @flag S_OK | Success
  2303. @flag S_FALSE | No band at the given location
  2304. @flag DMUS_S_STRING_TRUNCATED | The length of the band name is not less than MAX_PATH
  2305. @flag E_POINTER | <p pwszName> is not a valid address
  2306. @flag DMUS_E_TYPE_UNSUPPORTED | The band's descriptor doesn't support DMUS_OBJ_NAME
  2307. @comm Searches the Style's list of bands for the one at the location given by <p dwIndex>.
  2308. If there is such a band, its name is returned in <p pwszName>; if it is not less than MAX_PATH,
  2309. it is truncated. This assumes that <p pwszName>
  2310. has been pre-allocated to have a length of at least MAX_PATH.
  2311. */
  2312. HRESULT STDMETHODCALLTYPE CDMStyle::EnumBand(
  2313. DWORD dwIndex, // @parm An index into the Style's band list (0-based).
  2314. WCHAR *pwszName// @parm The band name to be returned.
  2315. )
  2316. {
  2317. V_BUFPTR_WRITE(pwszName,MAX_PATH);
  2318. TListItem<IDirectMusicBand*>* pBandItem = m_StyleInfo.m_BandList.GetHead();
  2319. for (DWORD dw = 0; pBandItem != NULL; pBandItem = pBandItem->GetNext(), dw++)
  2320. {
  2321. if (dw == dwIndex)
  2322. break;
  2323. }
  2324. if (pBandItem != NULL)
  2325. {
  2326. HRESULT hr = S_OK;
  2327. IDirectMusicBand* pBand = pBandItem->GetItemValue();
  2328. IDirectMusicObject *pIObject = NULL;
  2329. DMUS_OBJECTDESC Desc; // Descriptor.
  2330. Desc.dwSize = sizeof(Desc);
  2331. if (SUCCEEDED(hr = pBand->QueryInterface(IID_IDirectMusicObject,(void **) &pIObject)))
  2332. {
  2333. if (SUCCEEDED(hr = pIObject->GetDescriptor(&Desc)))
  2334. {
  2335. if (Desc.dwValidData & DMUS_OBJ_NAME)
  2336. {
  2337. if (wcslen(Desc.wszName) < MAX_PATH)
  2338. {
  2339. wcscpy(pwszName, Desc.wszName);
  2340. }
  2341. else
  2342. {
  2343. for (int i = 0; i < (MAX_PATH - 1); i++)
  2344. {
  2345. pwszName[i] = Desc.wszName[i];
  2346. }
  2347. pwszName[MAX_PATH - 1] = L'\0';
  2348. hr = DMUS_S_STRING_TRUNCATED;
  2349. }
  2350. }
  2351. else
  2352. {
  2353. hr = DMUS_E_TYPE_UNSUPPORTED;
  2354. }
  2355. }
  2356. pIObject->Release();
  2357. }
  2358. return hr;
  2359. }
  2360. else
  2361. {
  2362. return S_FALSE;
  2363. }
  2364. }
  2365. /*
  2366. @method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetDefaultBand | Gets the style's default band
  2367. @rdesc Returns one of the following
  2368. @flag S_OK | Success
  2369. @flag E_POINTER | ppBand not a valid pointer
  2370. @flag S_FALSE | Style does not have a default band
  2371. @comm Returns the Style's default band in <p ppBand>.
  2372. */
  2373. HRESULT STDMETHODCALLTYPE CDMStyle::GetDefaultBand(
  2374. IDirectMusicBand **ppBand // @parm The band to be returned.
  2375. )
  2376. {
  2377. V_PTRPTR_WRITE(ppBand);
  2378. if(m_StyleInfo.m_pDefaultBand == NULL)
  2379. {
  2380. return S_FALSE;
  2381. }
  2382. *ppBand = m_StyleInfo.m_pDefaultBand;
  2383. (*ppBand)->AddRef();
  2384. return S_OK;
  2385. }
  2386. /*
  2387. @method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetTimeSignature | Retrieves the Style's
  2388. time signature.
  2389. @rdesc Returns one of the following
  2390. @flag S_OK | Success
  2391. @flag E_POINTER | <p pTimeSig> is not a valid address
  2392. @comm Fills in a <t DMUS_TIMESIGNATURE> structure with data from the Style's time signature.
  2393. */
  2394. HRESULT CDMStyle::GetTimeSignature(
  2395. DMUS_TIMESIGNATURE* pTimeSig // @parm A pre-allocated <t DMUS_TIMESIGNATURE> structure.
  2396. )
  2397. {
  2398. V_PTR_WRITE(pTimeSig, sizeof(DMUS_TIMESIGNATURE) );
  2399. pTimeSig->mtTime = 0;
  2400. pTimeSig->wGridsPerBeat = m_StyleInfo.m_TimeSignature.m_wGridsPerBeat;
  2401. pTimeSig->bBeatsPerMeasure = m_StyleInfo.m_TimeSignature.m_bBeatsPerMeasure;
  2402. pTimeSig->bBeat = m_StyleInfo.m_TimeSignature.m_bBeat;
  2403. return S_OK;
  2404. }
  2405. /*
  2406. @method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetEmbellishmentLength | Finds the shortest
  2407. and longest lengths for patterns of the specified embellishment type and groove level.
  2408. @rdesc Returns one of the following
  2409. @flag S_OK | Success
  2410. @flag S_FALSE | There are no patterns of the specified type and groove level
  2411. @flag E_POINTER | Either <p pdwMin> or <p pdwMax> is not a valid address
  2412. @comm Finds all patterns in the Style with embellishment type given by <p bType> and groove
  2413. range that includes <p bLevel>. The length of the longest such pattern is returned in
  2414. <p pdwMax>, and the length of the shortest pattern is returned in <p pdwMin>.
  2415. Note that <p bLevel> is ignored for non-groove embellishments.
  2416. */
  2417. HRESULT CDMStyle::GetEmbellishmentLength(
  2418. DWORD dwType, // @parm An embellishment type.
  2419. DWORD dwLevel, // @parm A groove level (1 - 100).
  2420. DWORD* pdwMin, // @parm Length of the shortest pattern of the specified type
  2421. // and groove level.
  2422. DWORD* pdwMax // @parm Length of the longest pattern of the specified type
  2423. // and groove level.
  2424. )
  2425. {
  2426. V_PTR_WRITE(pdwMin, sizeof(DWORD) );
  2427. V_PTR_WRITE(pdwMax, sizeof(DWORD) );
  2428. TListItem<CDirectMusicPattern*>* pPattern = m_StyleInfo.m_PatternList.GetHead();
  2429. *pdwMin = *pdwMax = 0;
  2430. if (!pPattern) return S_FALSE;
  2431. for (; pPattern != NULL; pPattern = pPattern->GetNext())
  2432. {
  2433. CDirectMusicPattern*& rpPattern = pPattern->GetItemValue();
  2434. switch (dwType)
  2435. {
  2436. // need to use == rather than & for all of these because of user-defined embellishments
  2437. case DMUS_COMMANDT_FILL:
  2438. if (rpPattern->m_wEmbellishment == EMB_FILL)
  2439. {
  2440. if (rpPattern->m_wNumMeasures > *pdwMax)
  2441. *pdwMax = rpPattern->m_wNumMeasures;
  2442. if (rpPattern->m_wNumMeasures < *pdwMin || *pdwMin == 0)
  2443. *pdwMin = rpPattern->m_wNumMeasures;
  2444. }
  2445. break;
  2446. case DMUS_COMMANDT_INTRO:
  2447. if (rpPattern->m_wEmbellishment == EMB_INTRO)
  2448. {
  2449. if (rpPattern->m_wNumMeasures > *pdwMax)
  2450. *pdwMax = rpPattern->m_wNumMeasures;
  2451. if (rpPattern->m_wNumMeasures < *pdwMin || *pdwMin == 0)
  2452. *pdwMin = rpPattern->m_wNumMeasures;
  2453. }
  2454. break;
  2455. case DMUS_COMMANDT_BREAK:
  2456. if (rpPattern->m_wEmbellishment == EMB_BREAK)
  2457. {
  2458. if (rpPattern->m_wNumMeasures > *pdwMax)
  2459. *pdwMax = rpPattern->m_wNumMeasures;
  2460. if (rpPattern->m_wNumMeasures < *pdwMin || *pdwMin == 0)
  2461. *pdwMin = rpPattern->m_wNumMeasures;
  2462. }
  2463. break;
  2464. case DMUS_COMMANDT_END:
  2465. if (rpPattern->m_wEmbellishment == EMB_END)
  2466. {
  2467. if (rpPattern->m_wNumMeasures > *pdwMax)
  2468. *pdwMax = rpPattern->m_wNumMeasures;
  2469. if (rpPattern->m_wNumMeasures < *pdwMin || *pdwMin == 0)
  2470. *pdwMin = rpPattern->m_wNumMeasures;
  2471. }
  2472. break;
  2473. case DMUS_COMMANDT_GROOVE: // need to use == rather than & since EMB_NORMAL == 0
  2474. if ((rpPattern->m_wEmbellishment == EMB_NORMAL) &&
  2475. rpPattern->m_bGrooveBottom <= (BYTE)dwLevel &&
  2476. rpPattern->m_bGrooveTop >= (BYTE)dwLevel)
  2477. {
  2478. if (rpPattern->m_wNumMeasures > *pdwMax)
  2479. *pdwMax = rpPattern->m_wNumMeasures;
  2480. if (rpPattern->m_wNumMeasures < *pdwMin || *pdwMin == 0)
  2481. *pdwMin = rpPattern->m_wNumMeasures;
  2482. }
  2483. break;
  2484. default: // check for user-defined embellishment
  2485. if ( (rpPattern->m_wEmbellishment & EMB_USER_DEFINED) &&
  2486. (rpPattern->m_wEmbellishment >> 8) == (WORD)dwType )
  2487. {
  2488. if (rpPattern->m_wNumMeasures > *pdwMax)
  2489. *pdwMax = rpPattern->m_wNumMeasures;
  2490. if (rpPattern->m_wNumMeasures < *pdwMin || *pdwMin == 0)
  2491. *pdwMin = rpPattern->m_wNumMeasures;
  2492. }
  2493. }
  2494. }
  2495. if (!*pdwMin || !*pdwMax) return S_FALSE;
  2496. return S_OK;
  2497. }
  2498. /*
  2499. @method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetTempo | Retrieves the recommended tempo
  2500. of the style.
  2501. @rdesc Returns one of the following
  2502. @flag S_OK | Success
  2503. @flag E_POINTER | <p pTempo> is not a valid pointer
  2504. */
  2505. HRESULT CDMStyle::GetTempo
  2506. (
  2507. double* pTempo // @parm The recommended tempo of the style.
  2508. )
  2509. {
  2510. V_PTR_WRITE(pTempo, sizeof(double) );
  2511. *pTempo = m_StyleInfo.m_dblTempo;
  2512. return S_OK;
  2513. }
  2514. CDirectMusicEventItem* CDirectMusicEventItem::MergeSort(DirectMusicTimeSig& TimeSig)
  2515. {
  2516. if (m_pNext != NULL)
  2517. {
  2518. CDirectMusicEventItem *pList1, *pList2;
  2519. Divide(pList1, pList2);
  2520. return pList1->MergeSort(TimeSig)->Merge(pList2->MergeSort(TimeSig), TimeSig);
  2521. }
  2522. return this;
  2523. }
  2524. void CDirectMusicEventItem::Divide(CDirectMusicEventItem*& pHead1, CDirectMusicEventItem*& pHead2)
  2525. {
  2526. CDirectMusicEventItem *pCurrent = this, *pTail1 = NULL, *pTail2 = NULL;
  2527. do
  2528. {
  2529. pHead1 = pCurrent;
  2530. pCurrent = (CDirectMusicEventItem *)pCurrent->m_pNext;
  2531. pHead1->m_pNext = pTail1;
  2532. pTail1 = pHead1;
  2533. if (pCurrent != NULL)
  2534. {
  2535. pHead2 = pCurrent;
  2536. pCurrent = (CDirectMusicEventItem *)pCurrent->m_pNext;
  2537. pHead2->m_pNext = pTail2;
  2538. pTail2 = pHead2;
  2539. }
  2540. } while (pCurrent != NULL);
  2541. }
  2542. CDirectMusicEventItem* CDirectMusicEventItem::Merge(CDirectMusicEventItem* pOtherList, DirectMusicTimeSig& TimeSig)
  2543. {
  2544. if (!pOtherList) return this;
  2545. CDirectMusicEventItem
  2546. *pThisList = this, *pResultHead = NULL, *pResultTail = NULL, *pMergeItem = NULL;
  2547. while (pThisList && pOtherList)
  2548. {
  2549. if (pThisList->m_nGridStart < pOtherList->m_nGridStart ||
  2550. // Markers need to precede other events occuring at the same time
  2551. ((pThisList->m_dwEventTag == DMUS_EVENT_MARKER) &&
  2552. (pThisList->m_nGridStart) == (pOtherList->m_nGridStart)) ||
  2553. // Within a grid, sort by time offset
  2554. ((pThisList->m_nGridStart) == (pOtherList->m_nGridStart) &&
  2555. (pThisList->m_nTimeOffset < pOtherList->m_nTimeOffset)) )
  2556. {
  2557. pMergeItem = pThisList;
  2558. pThisList = pThisList->GetNext();
  2559. }
  2560. else
  2561. {
  2562. pMergeItem = pOtherList;
  2563. pOtherList = pOtherList->GetNext();
  2564. }
  2565. pMergeItem->SetNext(NULL);
  2566. if (!pResultTail)
  2567. {
  2568. pResultHead = pResultTail = pMergeItem;
  2569. }
  2570. else
  2571. {
  2572. pResultTail->SetNext(pMergeItem);
  2573. pResultTail = pMergeItem;
  2574. }
  2575. }
  2576. if (pThisList) pResultTail->SetNext(pThisList);
  2577. else pResultTail->SetNext(pOtherList);
  2578. return pResultHead;
  2579. }
  2580. CDirectMusicEventItem* CDirectMusicEventItem::ReviseEvent(short nGrid,
  2581. short nOffset,
  2582. DWORD* pdwVariation,
  2583. DWORD* pdwID,
  2584. WORD* pwMusic,
  2585. BYTE* pbPlaymode,
  2586. BYTE* pbFlags)
  2587. {
  2588. CDirectMusicEventItem* pEvent = NULL;
  2589. switch (m_dwEventTag)
  2590. {
  2591. case DMUS_EVENT_NOTE:
  2592. pEvent = ((CDMStyleNote*)this)->ReviseEvent(nGrid, nOffset, pdwVariation, pdwID, pwMusic, pbPlaymode, pbFlags);
  2593. break;
  2594. case DMUS_EVENT_CURVE:
  2595. pEvent = ((CDMStyleCurve*)this)->ReviseEvent(nGrid, nOffset);
  2596. break;
  2597. case DMUS_EVENT_MARKER:
  2598. pEvent = ((CDMStyleMarker*)this)->ReviseEvent(nGrid);
  2599. break;
  2600. case DMUS_EVENT_ANTICIPATION:
  2601. pEvent = ((CDMStyleAnticipation*)this)->ReviseEvent(nGrid);
  2602. break;
  2603. }
  2604. return pEvent;
  2605. }
  2606. CDirectMusicEventItem* CDMStyleNote::ReviseEvent(short nGrid,
  2607. short nOffset,
  2608. DWORD* pdwVariation,
  2609. DWORD* pdwID,
  2610. WORD* pwMusic,
  2611. BYTE* pbPlaymode,
  2612. BYTE* pbFlags)
  2613. {
  2614. CDMStyleNote* pNoteEvent = new CDMStyleNote;
  2615. if (pNoteEvent)
  2616. {
  2617. pNoteEvent->m_nGridStart = nGrid;
  2618. pNoteEvent->m_nTimeOffset = nOffset;
  2619. pNoteEvent->m_dwVariation = pdwVariation ? *pdwVariation : m_dwVariation;
  2620. pNoteEvent->m_dwEventTag = m_dwEventTag;
  2621. pNoteEvent->m_mtDuration = m_mtDuration;
  2622. pNoteEvent->m_bVelocity = m_bVelocity;
  2623. pNoteEvent->m_bTimeRange = m_bTimeRange;
  2624. pNoteEvent->m_bDurRange = m_bDurRange;
  2625. pNoteEvent->m_bVelRange = m_bVelRange;
  2626. pNoteEvent->m_bInversionId = m_bInversionId;
  2627. pNoteEvent->m_bPlayModeFlags = pbPlaymode ? *pbPlaymode : m_bPlayModeFlags;
  2628. pNoteEvent->m_wMusicValue = pwMusic ? *pwMusic : m_wMusicValue;
  2629. pNoteEvent->m_dwFragmentID = pdwID ? *pdwID : m_dwFragmentID;
  2630. pNoteEvent->m_bFlags = pbFlags ? *pbFlags : 0;
  2631. }
  2632. return pNoteEvent;
  2633. }
  2634. CDirectMusicEventItem* CDMStyleCurve::ReviseEvent(short nGrid, short nOffset)
  2635. {
  2636. CDMStyleCurve* pCurveEvent = new CDMStyleCurve;
  2637. if (pCurveEvent)
  2638. {
  2639. pCurveEvent->m_nGridStart = nGrid;
  2640. pCurveEvent->m_nTimeOffset = nOffset;
  2641. pCurveEvent->m_dwVariation = 0xffffffff;
  2642. pCurveEvent->m_dwEventTag = m_dwEventTag;
  2643. pCurveEvent->m_mtDuration = m_mtDuration;
  2644. pCurveEvent->m_mtResetDuration = m_mtResetDuration;
  2645. pCurveEvent->m_StartValue = m_StartValue;
  2646. pCurveEvent->m_EndValue = m_EndValue;
  2647. pCurveEvent->m_nResetValue = m_nResetValue;
  2648. pCurveEvent->m_bEventType = m_bEventType;
  2649. pCurveEvent->m_bCurveShape = m_bCurveShape;
  2650. pCurveEvent->m_bCCData = m_bCCData;
  2651. pCurveEvent->m_bFlags = m_bFlags;
  2652. pCurveEvent->m_wParamType = m_wParamType;
  2653. pCurveEvent->m_wMergeIndex = m_wMergeIndex;
  2654. }
  2655. return pCurveEvent;
  2656. }
  2657. CDirectMusicEventItem* CDMStyleMarker::ReviseEvent(short nGrid)
  2658. {
  2659. CDMStyleMarker* pMarkerEvent = new CDMStyleMarker;
  2660. if (pMarkerEvent)
  2661. {
  2662. pMarkerEvent->m_nGridStart = nGrid;
  2663. pMarkerEvent->m_nTimeOffset = 0;
  2664. pMarkerEvent->m_dwVariation = 0xffffffff;
  2665. pMarkerEvent->m_dwEventTag = m_dwEventTag;
  2666. pMarkerEvent->m_wFlags = m_wFlags;
  2667. }
  2668. return pMarkerEvent;
  2669. }
  2670. CDirectMusicEventItem* CDMStyleAnticipation::ReviseEvent(short nGrid)
  2671. {
  2672. CDMStyleAnticipation* pAnticipationEvent = new CDMStyleAnticipation;
  2673. if (pAnticipationEvent)
  2674. {
  2675. pAnticipationEvent->m_nGridStart = nGrid;
  2676. pAnticipationEvent->m_nTimeOffset = m_nTimeOffset;
  2677. pAnticipationEvent->m_dwVariation = 0xffffffff;
  2678. pAnticipationEvent->m_dwEventTag = m_dwEventTag;
  2679. pAnticipationEvent->m_bTimeRange = m_bTimeRange;
  2680. }
  2681. return pAnticipationEvent;
  2682. }
  2683. CDirectMusicEventList::~CDirectMusicEventList()
  2684. {
  2685. CDirectMusicEventItem *pEvent;
  2686. while (pEvent = RemoveHead())
  2687. {
  2688. delete pEvent;
  2689. }
  2690. }
  2691. void CDirectMusicEventList::MergeSort(DirectMusicTimeSig& TimeSig)
  2692. {
  2693. if (m_pHead != NULL && m_pHead->GetNext() != NULL)
  2694. m_pHead = ((CDirectMusicEventItem *)m_pHead)->MergeSort(TimeSig);
  2695. }
  2696. /////////////////////////////////////////////////////////////////////////////
  2697. // CDirectMusicPattern constructor
  2698. CDirectMusicPattern::CDirectMusicPattern( DirectMusicTimeSig* pTimeSig, BOOL fMotif ) :
  2699. m_wNumMeasures(1),
  2700. m_cRef(1),
  2701. m_wID(0),
  2702. m_bGrooveBottom(1),
  2703. m_bGrooveTop(100),
  2704. m_bDestGrooveBottom(1),
  2705. m_bDestGrooveTop(100),
  2706. m_pRhythmMap(NULL),
  2707. // m_pSwitchPoints(NULL),
  2708. m_fSettings(FALSE),
  2709. m_dwRepeats(0),
  2710. m_mtPlayStart(0),
  2711. m_mtLoopStart(0),
  2712. m_mtLoopEnd(-1),
  2713. m_dwResolution(0),
  2714. m_pMotifBand(NULL),
  2715. m_dwFlags(0)
  2716. {
  2717. if ( pTimeSig != NULL )
  2718. {
  2719. m_timeSig = *pTimeSig;
  2720. }
  2721. // Set defaults
  2722. if( fMotif )
  2723. {
  2724. m_wEmbellishment = EMB_MOTIF;
  2725. }
  2726. else
  2727. {
  2728. m_wEmbellishment = EMB_NORMAL;
  2729. }
  2730. }
  2731. CDirectMusicPattern* CDirectMusicPattern::Clone(MUSIC_TIME mtStart, MUSIC_TIME mtEnd, BOOL fMotif)
  2732. {
  2733. HRESULT hr = S_OK;
  2734. CDirectMusicPattern* pNewPattern = new CDirectMusicPattern(&m_timeSig, fMotif);
  2735. if (pNewPattern)
  2736. {
  2737. WORD wMeasureStart = (WORD)m_timeSig.ClocksToMeasure(mtStart);
  2738. WORD wMeasureEnd = (WORD)m_timeSig.ClocksToMeasure(mtEnd);
  2739. pNewPattern->m_wNumMeasures = wMeasureEnd - wMeasureStart;
  2740. pNewPattern->m_cRef = m_cRef;
  2741. pNewPattern->m_wID = m_wID;
  2742. pNewPattern->m_bGrooveBottom = m_bGrooveBottom;
  2743. pNewPattern->m_bGrooveTop = m_bGrooveTop;
  2744. pNewPattern->m_bDestGrooveBottom = m_bDestGrooveBottom;
  2745. pNewPattern->m_bDestGrooveTop = m_bDestGrooveTop;
  2746. pNewPattern->m_fSettings = m_fSettings;
  2747. pNewPattern->m_dwRepeats = m_dwRepeats;
  2748. pNewPattern->m_strName = m_strName;
  2749. pNewPattern->m_dwResolution = m_dwResolution;
  2750. pNewPattern->m_dwFlags = m_dwFlags;
  2751. if (m_mtPlayStart <= mtStart)
  2752. {
  2753. pNewPattern->m_mtPlayStart = 0;
  2754. }
  2755. else
  2756. {
  2757. pNewPattern->m_mtPlayStart = m_mtPlayStart - mtStart;
  2758. }
  2759. if (m_mtLoopStart <= mtStart)
  2760. {
  2761. pNewPattern->m_mtLoopStart = 0;
  2762. }
  2763. else
  2764. {
  2765. pNewPattern->m_mtLoopStart = m_mtLoopStart - mtStart;
  2766. }
  2767. if (m_mtLoopEnd >= (mtEnd - mtStart))
  2768. {
  2769. pNewPattern->m_mtLoopEnd = mtEnd - mtStart;
  2770. }
  2771. else if (m_mtLoopEnd < 0)
  2772. {
  2773. pNewPattern->m_mtLoopEnd = -1;
  2774. }
  2775. else
  2776. {
  2777. pNewPattern->m_mtLoopEnd = m_mtLoopEnd - mtStart;
  2778. }
  2779. pNewPattern->m_pRhythmMap = new DWORD[pNewPattern->m_wNumMeasures];
  2780. if (!pNewPattern->m_pRhythmMap)
  2781. {
  2782. hr = E_FAIL;
  2783. goto ON_END;
  2784. }
  2785. for (int i = 0; i < pNewPattern->m_wNumMeasures; i++)
  2786. {
  2787. pNewPattern->m_pRhythmMap[i] = m_pRhythmMap[i + wMeasureStart];
  2788. }
  2789. if (m_pMotifBand)
  2790. {
  2791. pNewPattern->m_pMotifBand = m_pMotifBand;
  2792. pNewPattern->m_pMotifBand->AddRef();
  2793. }
  2794. TListItem<DirectMusicPartRef>* pPartRefItem = m_PartRefList.GetHead();
  2795. int nParts = m_PartRefList.GetCount();
  2796. for (i = 0; pPartRefItem && i < nParts; pPartRefItem = pPartRefItem->GetNext(), i++)
  2797. {
  2798. DirectMusicPartRef& rPartRef = pPartRefItem->GetItemValue();
  2799. DirectMusicPart* pPart = rPartRef.m_pDMPart;
  2800. if (!pPart)
  2801. {
  2802. hr = E_FAIL;
  2803. goto ON_END;
  2804. }
  2805. TListItem<DirectMusicPartRef>* pNew = pNewPattern->CreatePart(rPartRef, pPart->m_bPlayModeFlags, pNewPattern->m_wNumMeasures);
  2806. if (!pNew)
  2807. {
  2808. hr = E_FAIL;
  2809. goto ON_END;
  2810. }
  2811. DirectMusicPartRef& rNew = pNew->GetItemValue();
  2812. // Now that I've got the new part, I need to add events to its event list based
  2813. // on mtStart and mtEnd
  2814. CDirectMusicEventItem* pEvent = pPart->EventList.GetHead();
  2815. MUSIC_TIME mtClocksInGrid = m_timeSig.ClocksPerGrid();
  2816. for (; pEvent; pEvent = pEvent->GetNext())
  2817. {
  2818. MUSIC_TIME mtEvent = m_timeSig.GridToClocks(pEvent->m_nGridStart);
  2819. if (mtEvent >= mtStart && mtEvent < mtEnd)
  2820. {
  2821. short nNewGrid = (short) ((mtEvent - mtStart) / mtClocksInGrid);
  2822. short nNewOffset = (short) (pEvent->m_nTimeOffset + (mtEvent - mtStart) % mtClocksInGrid);
  2823. CDirectMusicEventItem* pNewEvent = pEvent->ReviseEvent(nNewGrid, nNewOffset);
  2824. if (!pNewEvent)
  2825. {
  2826. hr = E_FAIL;
  2827. goto ON_END;
  2828. }
  2829. rNew.m_pDMPart->EventList.AddHead(pNewEvent);
  2830. }
  2831. }
  2832. rNew.m_pDMPart->EventList.MergeSort(m_timeSig);
  2833. }
  2834. }
  2835. ON_END:
  2836. if (FAILED(hr))
  2837. {
  2838. if (pNewPattern)
  2839. {
  2840. delete pNewPattern;
  2841. pNewPattern = NULL;
  2842. }
  2843. }
  2844. return pNewPattern;
  2845. }
  2846. HRESULT CDirectMusicPattern::LoadCurveList( LPSTREAM pStream, LPMMCKINFO pck, short nClickTime)
  2847. {
  2848. HRESULT hr = S_OK;
  2849. DWORD cb;
  2850. WORD wCurveSize;
  2851. WORD wCurveExtra;
  2852. WORD wSubSize;
  2853. WORD wSubExtra;
  2854. long lSize;
  2855. ioSubCurve iSubCurve;
  2856. ioCurve iCurve;
  2857. WORD wCount;
  2858. CDirectMusicEventItem* pCurve = NULL;
  2859. lSize = pck->cksize;
  2860. // read size of the curve structure
  2861. hr = pStream->Read( &wCurveSize, sizeof( wCurveSize ), &cb );
  2862. FixBytes( FBT_SHORT, &wCurveSize );
  2863. if( FAILED( hr ) || cb != sizeof( wCurveSize ) )
  2864. {
  2865. hr = E_FAIL;
  2866. goto ON_ERR;
  2867. }
  2868. lSize -= cb;
  2869. if( wCurveSize > sizeof( ioCurve ) )
  2870. {
  2871. wCurveExtra = static_cast<WORD>( wCurveSize - sizeof( ioCurve ) );
  2872. wCurveSize = sizeof( ioCurve );
  2873. }
  2874. else
  2875. {
  2876. wCurveExtra = 0;
  2877. }
  2878. // read size of the subcurve structure
  2879. hr = pStream->Read( &wSubSize, sizeof( wSubSize ), &cb );
  2880. FixBytes( FBT_SHORT, &wSubSize );
  2881. if( FAILED( hr ) || cb != sizeof( wSubSize ) )
  2882. {
  2883. hr = E_FAIL;
  2884. goto ON_ERR;
  2885. }
  2886. lSize -= cb;
  2887. if( wSubSize > sizeof( ioSubCurve ) )
  2888. {
  2889. wSubExtra = static_cast<WORD>( wSubSize - sizeof( ioSubCurve ) );
  2890. wSubSize = sizeof( ioSubCurve );
  2891. }
  2892. else
  2893. {
  2894. wSubExtra = 0;
  2895. }
  2896. // now read in the curve
  2897. while( lSize > 0 )
  2898. {
  2899. hr = pStream->Read( &iCurve, wCurveSize, &cb );
  2900. FixBytes( FBT_IOCURVE, &iCurve );
  2901. if( FAILED( hr ) || cb != wCurveSize )
  2902. {
  2903. hr = E_FAIL;
  2904. goto ON_ERR;
  2905. }
  2906. lSize -= cb;
  2907. if( wCurveExtra > 0 )
  2908. {
  2909. StreamSeek( pStream, wCurveExtra, STREAM_SEEK_CUR );
  2910. lSize -= wCurveExtra;
  2911. }
  2912. pCurve = new CDMStyleCurve;
  2913. if( pCurve == NULL )
  2914. {
  2915. hr = E_FAIL;
  2916. goto ON_ERR;
  2917. }
  2918. pCurve->m_dwVariation = iCurve.wVariation;
  2919. pCurve->m_nGridStart = nClickTime;
  2920. ((CDMStyleCurve*)pCurve)->m_bEventType = iCurve.bEventType;
  2921. ((CDMStyleCurve*)pCurve)->m_bCCData = iCurve.bCCData;
  2922. DirectMusicPart* pPart = FindPart(iCurve.bVoiceID);
  2923. // read subcurve count
  2924. hr = pStream->Read( &wCount, sizeof( wCount ), &cb );
  2925. FixBytes( FBT_SHORT, &wCount );
  2926. if( FAILED( hr ) || cb != sizeof( wCount ) )
  2927. {
  2928. hr = E_FAIL;
  2929. delete pCurve;
  2930. goto ON_ERR;
  2931. }
  2932. lSize -= cb;
  2933. for( ; wCount > 0 ; --wCount )
  2934. {
  2935. // read subcurves
  2936. hr = pStream->Read( &iSubCurve, wSubSize, &cb );
  2937. FixBytes( FBT_IOSUBCURVE, &iSubCurve );
  2938. if( FAILED( hr ) || cb != wSubSize )
  2939. {
  2940. hr = E_FAIL;
  2941. delete pCurve;
  2942. goto ON_ERR;
  2943. }
  2944. lSize -= wSubSize;
  2945. if( wSubExtra > 0 )
  2946. {
  2947. StreamSeek( pStream, wSubExtra, STREAM_SEEK_CUR );
  2948. lSize -= wSubExtra;
  2949. }
  2950. ((CDMStyleCurve*)pCurve)->m_bCurveShape = iSubCurve.bCurveType; // shape
  2951. if (iSubCurve.nMaxTime < iSubCurve.nMinTime)
  2952. {
  2953. short n = iSubCurve.nMaxTime;
  2954. iSubCurve.nMaxTime = iSubCurve.nMinTime;
  2955. iSubCurve.nMinTime = n;
  2956. }
  2957. if (iSubCurve.nMaxValue < iSubCurve.nMinValue)
  2958. {
  2959. short n = iSubCurve.nMaxValue;
  2960. iSubCurve.nMaxValue = iSubCurve.nMinValue;
  2961. iSubCurve.nMinValue = n;
  2962. iSubCurve.fFlipped ^= CURVE_FLIPVALUE; // toggle fFlipped
  2963. }
  2964. if( iSubCurve.fFlipped & CURVE_FLIPTIME )
  2965. {
  2966. switch( ((CDMStyleCurve*)pCurve)->m_bCurveShape )
  2967. {
  2968. case DMUS_CURVES_LINEAR:
  2969. if( iSubCurve.fFlipped & CURVE_FLIPVALUE )
  2970. {
  2971. iSubCurve.fFlipped = 0;
  2972. }
  2973. else
  2974. {
  2975. iSubCurve.fFlipped = CURVE_FLIPVALUE;
  2976. }
  2977. break;
  2978. case DMUS_CURVES_INSTANT:
  2979. iSubCurve.nMinTime = iSubCurve.nMaxTime;
  2980. iSubCurve.nMaxTime = iSubCurve.nMinTime + 1;
  2981. break;
  2982. case DMUS_CURVES_EXP:
  2983. ((CDMStyleCurve*)pCurve)->m_bCurveShape = DMUS_CURVES_LOG;
  2984. iSubCurve.fFlipped ^= CURVE_FLIPVALUE; // toggle fFlipped
  2985. // log is the horiz flipped version of vertical flipped exp
  2986. break;
  2987. case DMUS_CURVES_LOG:
  2988. ((CDMStyleCurve*)pCurve)->m_bCurveShape = DMUS_CURVES_EXP;
  2989. iSubCurve.fFlipped ^= CURVE_FLIPVALUE; // toggle fFlipped
  2990. // exp is the horiz flipped version of vertical flipped log
  2991. break;
  2992. case DMUS_CURVES_SINE:
  2993. iSubCurve.fFlipped ^= CURVE_FLIPVALUE; // toggle fFlipped
  2994. // because horiz. and vert. flip are the same for sine wave
  2995. break;
  2996. default:
  2997. assert( 0 );
  2998. break;
  2999. }
  3000. }
  3001. if( iSubCurve.fFlipped & CURVE_FLIPVALUE )
  3002. {
  3003. ((CDMStyleCurve*)pCurve)->m_StartValue = iSubCurve.nMaxValue;
  3004. ((CDMStyleCurve*)pCurve)->m_EndValue = iSubCurve.nMinValue;
  3005. }
  3006. else
  3007. {
  3008. ((CDMStyleCurve*)pCurve)->m_StartValue = iSubCurve.nMinValue;
  3009. ((CDMStyleCurve*)pCurve)->m_EndValue = iSubCurve.nMaxValue;
  3010. }
  3011. pCurve->m_nTimeOffset = ConvertTime(iSubCurve.nMinTime);
  3012. ((CDMStyleCurve*)pCurve)->m_mtDuration = iSubCurve.nMaxTime - iSubCurve.nMinTime;
  3013. ((CDMStyleCurve*)pCurve)->m_mtResetDuration = 0;
  3014. ((CDMStyleCurve*)pCurve)->m_nResetValue = 0;
  3015. ((CDMStyleCurve*)pCurve)->m_bFlags = 0;
  3016. if (pPart != NULL)
  3017. {
  3018. pPart->EventList.AddHead(pCurve);
  3019. }
  3020. else
  3021. {
  3022. delete pCurve;
  3023. }
  3024. pCurve = new CDMStyleCurve;
  3025. if( pCurve == NULL )
  3026. {
  3027. hr = E_FAIL;
  3028. goto ON_ERR;
  3029. }
  3030. pCurve->m_dwVariation = iCurve.wVariation;
  3031. pCurve->m_nGridStart = nClickTime;
  3032. ((CDMStyleCurve*)pCurve)->m_bEventType = iCurve.bEventType;
  3033. ((CDMStyleCurve*)pCurve)->m_bCCData = iCurve.bCCData;
  3034. }
  3035. // the loop generates an extra one, and if we don't enter the loop, we never used
  3036. // the first one we generated.
  3037. delete pCurve;
  3038. }
  3039. ON_ERR:
  3040. return hr;
  3041. }
  3042. HRESULT CDirectMusicPattern::LoadNoteList( LPSTREAM pStream, LPMMCKINFO pck, short nClickTime)
  3043. {
  3044. HRESULT hr = S_OK;;
  3045. ioNote iNote;
  3046. DWORD cb;
  3047. WORD wNoteSize;
  3048. WORD wExtra;
  3049. long lSize;
  3050. CDirectMusicEventItem* pNote = NULL;
  3051. lSize = pck->cksize;
  3052. // read size of the note structure
  3053. hr = pStream->Read( &wNoteSize, sizeof( wNoteSize ), &cb );
  3054. FixBytes( FBT_SHORT, &wNoteSize );
  3055. if( FAILED( hr ) || cb != sizeof( wNoteSize ) )
  3056. {
  3057. hr = E_FAIL;
  3058. goto ON_ERR;
  3059. }
  3060. lSize -= cb;
  3061. if( wNoteSize > sizeof( ioNote ) )
  3062. {
  3063. wExtra = static_cast<WORD>( wNoteSize - sizeof( ioNote ) );
  3064. wNoteSize = sizeof( ioNote );
  3065. }
  3066. else
  3067. {
  3068. wExtra = 0;
  3069. }
  3070. // now read in the notes
  3071. while( lSize > 0 )
  3072. {
  3073. iNote.bPlayMode = 0;
  3074. hr = pStream->Read( &iNote, wNoteSize, &cb );
  3075. FixBytes( FBT_IONOTE, &iNote );
  3076. if( FAILED( hr ) || cb != wNoteSize )
  3077. {
  3078. hr = E_FAIL;
  3079. goto ON_ERR;
  3080. }
  3081. lSize -= wNoteSize;
  3082. if( wExtra > 0 )
  3083. {
  3084. StreamSeek( pStream, wExtra, STREAM_SEEK_CUR );
  3085. lSize -= wExtra;
  3086. }
  3087. pNote = new CDMStyleNote;
  3088. if( pNote != NULL )
  3089. {
  3090. pNote->m_nGridStart = nClickTime;
  3091. pNote->m_nTimeOffset = ConvertTime(iNote.nTime);
  3092. pNote->m_dwVariation = iNote.wVariation;
  3093. ((CDMStyleNote*)pNote)->m_bVelocity = iNote.bVelocity;
  3094. ((CDMStyleNote*)pNote)->m_mtDuration = ConvertTime(iNote.nDuration);
  3095. ((CDMStyleNote*)pNote)->m_bTimeRange = iNote.bTimeRange;
  3096. ((CDMStyleNote*)pNote)->m_bDurRange = iNote.bDurRange;
  3097. ((CDMStyleNote*)pNote)->m_bVelRange = iNote.bVelRange;
  3098. ((CDMStyleNote*)pNote)->m_bInversionId = 0; // not in IMA2.5
  3099. ((CDMStyleNote*)pNote)->m_bFlags = 0; // not in IMA2.5
  3100. // Make sure SuperJAM! play mode is valid
  3101. if ( !(iNote.bPlayMode & 0x80) )
  3102. {
  3103. iNote.bPlayMode = CHTYPE_NONE;
  3104. }
  3105. // Strip 0x80 before checking SuperJAM! play mode
  3106. switch (iNote.bPlayMode & 0x0F)
  3107. {
  3108. case CHTYPE_NOTINITIALIZED:
  3109. case CHTYPE_NONE:
  3110. ((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_NONE;
  3111. break;
  3112. case CHTYPE_DRUM:
  3113. case CHTYPE_FIXED:
  3114. ((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_FIXED;
  3115. break;
  3116. case CHTYPE_UPPER:
  3117. case CHTYPE_BASS:
  3118. ((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_NORMALCHORD;
  3119. break;
  3120. case CHTYPE_SCALEONLY:
  3121. ((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_PEDALPOINT;
  3122. break;
  3123. case CHTYPE_BASSMELODIC:
  3124. case CHTYPE_UPPERMELODIC:
  3125. ((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_SCALE_INTERVALS | DMUS_PLAYMODE_CHORD_ROOT;
  3126. break;
  3127. default:
  3128. // should never get here...
  3129. ((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_FIXED;
  3130. }
  3131. //}
  3132. DirectMusicPart* pPart = FindPart(iNote.bVoiceID);
  3133. if (pPart != NULL)
  3134. {
  3135. pPart->EventList.AddHead(pNote);
  3136. }
  3137. else
  3138. {
  3139. assert(0);
  3140. }
  3141. // Determine playmode of note
  3142. BYTE bNotePlayModeFlags;
  3143. if( ((CDMStyleNote*)pNote)->m_bPlayModeFlags == DMUS_PLAYMODE_NONE )
  3144. {
  3145. bNotePlayModeFlags = pPart->m_bPlayModeFlags;
  3146. }
  3147. else
  3148. {
  3149. bNotePlayModeFlags = ((CDMStyleNote*)pNote)->m_bPlayModeFlags;
  3150. }
  3151. // if ScaleValue is non-zero and the note isn't a pedalpoint, it's purpleized.
  3152. if( iNote.bScaleValue != 0
  3153. && bNotePlayModeFlags != DMUS_PLAYMODE_PEDALPOINT )
  3154. {
  3155. ((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_PURPLEIZED;
  3156. }
  3157. // if the note is a drum event, use the (mapped) MIDI value;
  3158. if( iNote.bVoiceID == 5 ) // it's a drum part
  3159. {
  3160. if (iNote.bValue < 128 && achMappings[iNote.bValue] < 128)
  3161. ((CDMStyleNote*)pNote)->m_wMusicValue = achMappings[iNote.bValue];
  3162. else
  3163. {
  3164. ((CDMStyleNote*)pNote)->m_wMusicValue = 0;
  3165. }
  3166. }
  3167. // otherwise, if it's fixed, use the unmapped Midi value
  3168. else if( bNotePlayModeFlags == DMUS_PLAYMODE_FIXED )
  3169. {
  3170. ((CDMStyleNote*)pNote)->m_wMusicValue = iNote.bValue;
  3171. }
  3172. // otherwise, use MusicValue
  3173. else
  3174. {
  3175. ((CDMStyleNote*)pNote)->m_wMusicValue = iNote.nMusicValue;
  3176. }
  3177. }
  3178. }
  3179. ON_ERR:
  3180. return hr;
  3181. }
  3182. HRESULT CDirectMusicPattern::LoadEvents( IAARIFFStream* pRIFF, MMCKINFO* pckMain )
  3183. {
  3184. ioClick iClick;
  3185. HRESULT hr = S_OK;
  3186. LPSTREAM pStream;
  3187. MMCKINFO ck;
  3188. DWORD cSize;
  3189. DWORD cb;
  3190. BOOL fClickLoaded = FALSE;
  3191. pStream = pRIFF->GetStream();
  3192. if ( pStream == NULL ) return E_FAIL;
  3193. short nClickTime = 0;
  3194. while( pRIFF->Descend( &ck, pckMain, 0 ) == 0 )
  3195. {
  3196. switch( ck.ckid )
  3197. {
  3198. case FOURCC_CLICK:
  3199. fClickLoaded = TRUE;
  3200. cSize = min( ck.cksize, sizeof( iClick ) );
  3201. hr = pStream->Read( &iClick, cSize, &cb );
  3202. FixBytes( FBT_IOCLICK, &iClick );
  3203. if( FAILED( hr ) || cb != cSize )
  3204. {
  3205. hr = E_FAIL;
  3206. goto ON_ERR;
  3207. }
  3208. nClickTime = iClick.lTime;
  3209. break;
  3210. case FOURCC_NOTE:
  3211. if (fClickLoaded)
  3212. LoadNoteList( pStream, &ck, nClickTime);
  3213. else
  3214. {
  3215. hr = E_FAIL;
  3216. goto ON_ERR;
  3217. }
  3218. break;
  3219. case FOURCC_CURVE:
  3220. if (fClickLoaded)
  3221. LoadCurveList( pStream, &ck, nClickTime);
  3222. else
  3223. {
  3224. hr = E_FAIL;
  3225. goto ON_ERR;
  3226. }
  3227. break;
  3228. }
  3229. pRIFF->Ascend( &ck, 0 );
  3230. }
  3231. ON_ERR:
  3232. pStream->Release();
  3233. return hr;
  3234. }
  3235. void CDirectMusicPattern::CleanUp()
  3236. {
  3237. if (m_pRhythmMap != NULL)
  3238. {
  3239. delete [] m_pRhythmMap;
  3240. m_pRhythmMap = NULL;
  3241. }
  3242. /* if (m_pSwitchPoints != NULL)
  3243. {
  3244. delete [] m_pSwitchPoints;
  3245. m_pSwitchPoints = NULL;
  3246. }*/
  3247. if (m_pMotifBand)
  3248. {
  3249. m_pMotifBand->Release();
  3250. m_pMotifBand = NULL;
  3251. }
  3252. m_PartRefList.CleanUp();
  3253. }
  3254. STDMETHODIMP_(ULONG) CDirectMusicPattern::AddRef()
  3255. {
  3256. return InterlockedIncrement(&m_cRef);
  3257. }
  3258. STDMETHODIMP_(ULONG) CDirectMusicPattern::Release()
  3259. {
  3260. if (!InterlockedDecrement(&m_cRef))
  3261. {
  3262. delete this;
  3263. return 0;
  3264. }
  3265. return m_cRef;
  3266. }
  3267. DirectMusicPart* CDirectMusicPattern::FindPart(BYTE bVoiceID)
  3268. {
  3269. TListItem<DirectMusicPartRef> *li;
  3270. for(li = m_PartRefList.GetHead(); li != NULL; li = li->GetNext())
  3271. {
  3272. if (VOICEID_TO_CHANNEL(bVoiceID + 1) == li->GetItemValue().m_dwLogicalPartID)
  3273. return li->GetItemValue().m_pDMPart;
  3274. }
  3275. return NULL;
  3276. }
  3277. TListItem<DirectMusicPartRef>* CDirectMusicPattern::FindPartRefByPChannel(DWORD dwPChannel)
  3278. {
  3279. TListItem<DirectMusicPartRef> *li;
  3280. for(li = m_PartRefList.GetHead(); li != NULL; li = li->GetNext())
  3281. {
  3282. if (dwPChannel == li->GetItemValue().m_dwLogicalPartID)
  3283. return li;
  3284. }
  3285. return NULL;
  3286. }
  3287. TListItem<DirectMusicPartRef>* CDirectMusicPattern::CreatePart( DirectMusicPartRef& rPartRef, BYTE bPlaymode, WORD wMeasures )
  3288. {
  3289. TListItem<DirectMusicPartRef>* pNewPartRef = FindPartRefByPChannel(rPartRef.m_dwLogicalPartID);
  3290. if (pNewPartRef)
  3291. {
  3292. DirectMusicPartRef& rNewPartRef = pNewPartRef->GetItemValue();
  3293. DirectMusicPart* pFoundPart = rNewPartRef.m_pDMPart;
  3294. DirectMusicPart* pOtherPart = rPartRef.m_pDMPart;
  3295. if (pFoundPart && pOtherPart)
  3296. {
  3297. if (pOtherPart->m_bInvertUpper > pFoundPart->m_bInvertUpper)
  3298. {
  3299. pFoundPart->m_bInvertUpper = pOtherPart->m_bInvertUpper;
  3300. }
  3301. if (pOtherPart->m_bInvertLower < pFoundPart->m_bInvertLower)
  3302. {
  3303. pFoundPart->m_bInvertLower = pOtherPart->m_bInvertLower;
  3304. }
  3305. pFoundPart->m_dwFlags |= pOtherPart->m_dwFlags;
  3306. }
  3307. }
  3308. else
  3309. {
  3310. pNewPartRef = new TListItem<DirectMusicPartRef>;
  3311. if( pNewPartRef )
  3312. {
  3313. DirectMusicPart* pPart = new DirectMusicPart;
  3314. if( !pPart )
  3315. {
  3316. delete pNewPartRef;
  3317. pNewPartRef = NULL;
  3318. }
  3319. else
  3320. {
  3321. DirectMusicPartRef& rNewPartRef = pNewPartRef->GetItemValue();
  3322. // initialize the new part...
  3323. DirectMusicPart* pOtherPart = rPartRef.m_pDMPart;
  3324. if (pPart && pOtherPart)
  3325. {
  3326. pPart->m_guidPartID = pOtherPart->m_guidPartID;
  3327. pPart->m_timeSig = m_timeSig;
  3328. for (int i = 0; i < 32; i++) // activate all variations
  3329. {
  3330. pPart->m_dwVariationChoices[i] = 0x7fffffff;
  3331. }
  3332. pPart->m_bPlayModeFlags = bPlaymode;
  3333. pPart->m_bInvertUpper = pOtherPart->m_bInvertUpper;
  3334. pPart->m_bInvertLower = pOtherPart->m_bInvertLower;
  3335. pPart->m_dwFlags = pOtherPart->m_dwFlags;
  3336. pPart->m_wNumMeasures = wMeasures;
  3337. }
  3338. // initialize the new part ref...
  3339. rNewPartRef.m_pDMPart = pPart;
  3340. rNewPartRef.m_dwLogicalPartID = rPartRef.m_dwLogicalPartID;
  3341. rNewPartRef.m_bVariationLockID = rPartRef.m_bVariationLockID;
  3342. rNewPartRef.m_bSubChordLevel = rPartRef.m_bSubChordLevel;
  3343. rNewPartRef.m_bPriority = rPartRef.m_bPriority;
  3344. rNewPartRef.m_bRandomVariation = rPartRef.m_bRandomVariation;
  3345. m_PartRefList.AddTail(pNewPartRef);
  3346. }
  3347. }
  3348. }
  3349. return pNewPartRef;
  3350. }
  3351. /////////////////////////////////////////////////////////////////////////////
  3352. // CDirectMusicPattern::DM_LoadPattern
  3353. HRESULT CDirectMusicPattern::DM_LoadPattern(
  3354. IAARIFFStream* pIRiffStream, MMCKINFO* pckMain, DMStyleStruct* pStyle )
  3355. {
  3356. TListItem<DirectMusicPartRef>* pPartRefItem = NULL;
  3357. DirectMusicPart* pPart;
  3358. IStream* pIStream;
  3359. HRESULT hr = S_OK;
  3360. DWORD dwByteCount;
  3361. DWORD dwSize;
  3362. MMCKINFO ck;
  3363. MMCKINFO ckList;
  3364. int i;
  3365. if ( pStyle == NULL ) return E_INVALIDARG;
  3366. if ( pIRiffStream == NULL ) return E_INVALIDARG;
  3367. if ( pckMain == NULL ) return E_INVALIDARG;
  3368. pIStream = pIRiffStream->GetStream();
  3369. if ( pIStream == NULL ) return E_FAIL;
  3370. // Load the Pattern
  3371. while( pIRiffStream->Descend( &ck, pckMain, 0 ) == 0 )
  3372. {
  3373. switch( ck.ckid )
  3374. {
  3375. case DMUS_FOURCC_PATTERN_CHUNK:
  3376. {
  3377. DMUS_IO_PATTERN iDMPattern;
  3378. memset(&iDMPattern, 0, sizeof(iDMPattern));
  3379. dwSize = min( ck.cksize, sizeof( DMUS_IO_PATTERN ) );
  3380. hr = pIStream->Read( &iDMPattern, dwSize, &dwByteCount );
  3381. if( FAILED( hr ) || dwByteCount != dwSize )
  3382. {
  3383. hr = E_FAIL;
  3384. goto ON_ERROR;
  3385. }
  3386. m_bGrooveBottom = iDMPattern.bGrooveBottom;
  3387. m_bGrooveTop = iDMPattern.bGrooveTop;
  3388. m_wEmbellishment = iDMPattern.wEmbellishment;
  3389. m_bDestGrooveBottom = iDMPattern.bDestGrooveBottom;
  3390. m_bDestGrooveTop = iDMPattern.bDestGrooveTop;
  3391. m_dwFlags = iDMPattern.dwFlags;
  3392. m_timeSig.m_bBeatsPerMeasure = iDMPattern.timeSig.bBeatsPerMeasure;
  3393. m_timeSig.m_bBeat = iDMPattern.timeSig.bBeat;
  3394. m_timeSig.m_wGridsPerBeat = iDMPattern.timeSig.wGridsPerBeat;
  3395. m_wNumMeasures = iDMPattern.wNbrMeasures;
  3396. break;
  3397. }
  3398. case DMUS_FOURCC_RHYTHM_CHUNK:
  3399. if( m_pRhythmMap )
  3400. {
  3401. delete [] m_pRhythmMap;
  3402. m_pRhythmMap = NULL;
  3403. }
  3404. m_pRhythmMap = new DWORD[m_wNumMeasures];
  3405. if( m_pRhythmMap == NULL )
  3406. {
  3407. hr = E_OUTOFMEMORY;
  3408. goto ON_ERROR;
  3409. }
  3410. for( i = 0 ; i < m_wNumMeasures ; i++ )
  3411. {
  3412. hr = pIStream->Read( &m_pRhythmMap[i], sizeof(DWORD), &dwByteCount );
  3413. if( FAILED( hr ) || dwByteCount != sizeof(DWORD) )
  3414. {
  3415. hr = E_FAIL;
  3416. goto ON_ERROR;
  3417. }
  3418. }
  3419. break;
  3420. /* case DMUS_FOURCC_SWITCH_POINT_CHUNK:
  3421. if( m_pSwitchPoints )
  3422. {
  3423. delete [] m_pSwitchPoints;
  3424. m_pSwitchPoints = NULL;
  3425. }
  3426. m_pSwitchPoints = new DWORD[m_wNumMeasures];
  3427. if( m_pSwitchPoints == NULL )
  3428. {
  3429. hr = E_OUTOFMEMORY;
  3430. goto ON_ERROR;
  3431. }
  3432. for( i = 0 ; i < m_wNumMeasures ; i++ )
  3433. {
  3434. hr = pIStream->Read( &m_pSwitchPoints[i], sizeof(DWORD), &dwByteCount );
  3435. if( FAILED( hr ) || dwByteCount != sizeof(DWORD) )
  3436. {
  3437. hr = E_FAIL;
  3438. goto ON_ERROR;
  3439. }
  3440. }
  3441. break;
  3442. */
  3443. case DMUS_FOURCC_MOTIFSETTINGS_CHUNK:
  3444. {
  3445. DMUS_IO_MOTIFSETTINGS ioMotifSettings;
  3446. hr = pIStream->Read( &ioMotifSettings, sizeof(DMUS_IO_MOTIFSETTINGS), &dwByteCount );
  3447. if( FAILED( hr ) || dwByteCount != sizeof(DMUS_IO_MOTIFSETTINGS) )
  3448. {
  3449. hr = E_FAIL;
  3450. goto ON_ERROR;
  3451. }
  3452. m_fSettings = TRUE;
  3453. m_dwRepeats = ioMotifSettings.dwRepeats;
  3454. m_mtPlayStart = ioMotifSettings.mtPlayStart;
  3455. m_mtLoopStart = ioMotifSettings.mtLoopStart;
  3456. m_mtLoopEnd = ioMotifSettings.mtLoopEnd;
  3457. m_dwResolution = ioMotifSettings.dwResolution;
  3458. break;
  3459. }
  3460. case FOURCC_RIFF:
  3461. switch( ck.fccType )
  3462. {
  3463. case DMUS_FOURCC_BAND_FORM:
  3464. {
  3465. // load band associated with the motif
  3466. if (m_pMotifBand)
  3467. {
  3468. m_pMotifBand->Release();
  3469. m_pMotifBand = NULL;
  3470. }
  3471. // Create a band
  3472. hr = CoCreateInstance(CLSID_DirectMusicBand,
  3473. NULL,
  3474. CLSCTX_INPROC,
  3475. IID_IDirectMusicBand,
  3476. (void**)&m_pMotifBand);
  3477. if(SUCCEEDED(hr))
  3478. {
  3479. // Seek back to begining of Riff chunk
  3480. // This is the amount read by Descend when descending into a FOURCC_RIFF chunk
  3481. // Get current position
  3482. LARGE_INTEGER li;
  3483. ULARGE_INTEGER ul;
  3484. li.HighPart = 0;
  3485. li.LowPart = 0;
  3486. hr = pIStream->Seek(li,
  3487. STREAM_SEEK_CUR,
  3488. &ul);
  3489. if(SUCCEEDED(hr))
  3490. {
  3491. li.HighPart = 0;
  3492. // This is always a valid operation
  3493. li.LowPart = ul.LowPart - (2 * sizeof(FOURCC) + sizeof(DWORD));
  3494. hr = pIStream->Seek(li,
  3495. STREAM_SEEK_SET,
  3496. &ul);
  3497. }
  3498. }
  3499. if(SUCCEEDED(hr))
  3500. {
  3501. // Load band
  3502. IPersistStream* pIPersistStream;
  3503. hr = m_pMotifBand->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
  3504. if(SUCCEEDED(hr))
  3505. {
  3506. hr = pIPersistStream->Load(pIStream);
  3507. pIPersistStream->Release();
  3508. }
  3509. }
  3510. if(FAILED(hr))
  3511. {
  3512. if (m_pMotifBand)
  3513. {
  3514. m_pMotifBand->Release();
  3515. m_pMotifBand = NULL;
  3516. }
  3517. goto ON_ERROR;
  3518. }
  3519. break;
  3520. }
  3521. }
  3522. break;
  3523. case FOURCC_LIST:
  3524. switch( ck.fccType )
  3525. {
  3526. case DMUS_FOURCC_UNFO_LIST:
  3527. while( pIRiffStream->Descend( &ckList, &ck, 0 ) == 0 )
  3528. {
  3529. switch( ckList.ckid )
  3530. {
  3531. case RIFFINFO_INAM:
  3532. case DMUS_FOURCC_UNAM_CHUNK:
  3533. {
  3534. DWORD dwLength = min(ckList.cksize, (DWORD)(sizeof(WCHAR)*(DMUS_MAX_NAME - 1)));
  3535. hr = ReadMBSfromWCS( pIStream, dwLength, m_strName );
  3536. if (FAILED(hr))
  3537. {
  3538. goto ON_ERROR;
  3539. }
  3540. break;
  3541. }
  3542. }
  3543. pIRiffStream->Ascend( &ckList, 0 );
  3544. }
  3545. break;
  3546. case DMUS_FOURCC_PART_LIST: // only in GUID_SinglePattern format
  3547. pPart = pStyle->AllocPart();
  3548. if( pPart == NULL )
  3549. {
  3550. hr = E_OUTOFMEMORY ;
  3551. goto ON_ERROR;
  3552. }
  3553. hr = pPart->DM_LoadPart( pIRiffStream, &ck, pStyle );
  3554. if( FAILED( hr ) )
  3555. {
  3556. pStyle->DeletePart( pPart );
  3557. goto ON_ERROR;
  3558. }
  3559. if( hr == S_FALSE )
  3560. {
  3561. // Bypass this Part because Style already contains a Part
  3562. // whose GUID matches pPart->m_guidPartID
  3563. pStyle->DeletePart( pPart );
  3564. }
  3565. else // merge the part's marker events
  3566. {
  3567. pPart->MergeMarkerEvents(pStyle, this);
  3568. }
  3569. break;
  3570. case DMUS_FOURCC_PARTREF_LIST:
  3571. hr = AllocPartRef(pPartRefItem);
  3572. if ( FAILED(hr) )
  3573. {
  3574. goto ON_ERROR;
  3575. }
  3576. hr = pPartRefItem->GetItemValue().DM_LoadPartRef( pIRiffStream, &ck, pStyle );
  3577. if ( FAILED( hr ) )
  3578. {
  3579. DeletePartRef( pPartRefItem );
  3580. goto ON_ERROR;
  3581. }
  3582. break;
  3583. }
  3584. break;
  3585. }
  3586. pIRiffStream->Ascend( &ck, 0 );
  3587. }
  3588. ON_ERROR:
  3589. pIStream->Release();
  3590. return hr;
  3591. }
  3592. /////////////////////////////////////////////////////////////////////////////
  3593. // CDirectMusicPattern additional functions
  3594. /////////////////////////////////////////////////////////////////////////////
  3595. // CDirectMusicPattern::AllocPartRef
  3596. HRESULT CDirectMusicPattern::AllocPartRef(TListItem<DirectMusicPartRef>*& rpPartRefItem)
  3597. {
  3598. rpPartRefItem = new TListItem<DirectMusicPartRef>;
  3599. if (rpPartRefItem)
  3600. {
  3601. // Add PartRef to Pattern's list of Parts
  3602. m_PartRefList.AddTail( rpPartRefItem );
  3603. return S_OK;
  3604. }
  3605. return E_OUTOFMEMORY;
  3606. }
  3607. /////////////////////////////////////////////////////////////////////////////
  3608. // CDirectMusicPattern::DeletePartRef
  3609. void CDirectMusicPattern::DeletePartRef(TListItem<DirectMusicPartRef>* pPartRefItem)
  3610. {
  3611. // add stuff later...
  3612. }
  3613. HRESULT CDirectMusicPattern::LoadPattern(IAARIFFStream* pRIFF,
  3614. MMCKINFO* pckMain,
  3615. TList<DirectMusicPart*> &partList,
  3616. DMStyleStruct& rStyleStruct
  3617. )
  3618. {
  3619. int i;
  3620. int j;
  3621. ioPattern iPattern;
  3622. LPSTREAM pStream;
  3623. HRESULT hr = S_OK;
  3624. MMCKINFO ck;
  3625. DWORD cb;
  3626. DWORD cSize;
  3627. WORD wKludge;
  3628. DWORD dwRhythm = 1; // make it a whole note pattern by default
  3629. pStream = pRIFF->GetStream();
  3630. if ( pStream == NULL ) return E_FAIL;
  3631. while( pRIFF->Descend( &ck, pckMain, 0 ) == 0 )
  3632. {
  3633. switch( ck.ckid )
  3634. {
  3635. case FOURCC_PATTERN:
  3636. cSize = min( ck.cksize, sizeof( iPattern ) );
  3637. hr = pStream->Read( &iPattern, cSize, &cb );
  3638. FixBytes( FBT_IOPATTERN, &iPattern );
  3639. if( FAILED( hr ) || cb != cSize )
  3640. {
  3641. hr = E_FAIL;
  3642. goto ON_ERR;
  3643. }
  3644. m_strName = iPattern.wstrName;
  3645. m_timeSig.m_bBeatsPerMeasure = static_cast<BYTE>( iPattern.dwLength / static_cast<long>( iPattern.wClocksPerBeat ) / iPattern.wMeasures );
  3646. m_timeSig.m_bBeat = static_cast<BYTE>(iPattern.wBeat);
  3647. m_timeSig.m_wGridsPerBeat = iPattern.wClocksPerBeat / iPattern.wClocksPerClick;
  3648. m_wNumMeasures = iPattern.wMeasures;
  3649. // Bottom of groove range is 1 if either level A or no levels were specified;
  3650. // 26 if level B is the lowest level specified, etc.
  3651. if ( iPattern.fFlags & PF_A || !(iPattern.fFlags & (PF_A | PF_B | PF_C | PF_D)) )
  3652. m_bGrooveBottom = 1;
  3653. else if (iPattern.fFlags & PF_B) m_bGrooveBottom = 26;
  3654. else if (iPattern.fFlags & PF_C) m_bGrooveBottom = 51;
  3655. else m_bGrooveBottom = 76;
  3656. // Top of groove range is 100 if either level D or no levels were specified;
  3657. // 75 if level C is the highest level specified, etc.
  3658. if ( iPattern.fFlags & PF_D || !(iPattern.fFlags & (PF_A | PF_B | PF_C | PF_D)) )
  3659. m_bGrooveTop = 100;
  3660. else if (iPattern.fFlags & PF_C) m_bGrooveTop = 75;
  3661. else if (iPattern.fFlags & PF_B) m_bGrooveTop = 50;
  3662. else m_bGrooveTop = 25;
  3663. m_wEmbellishment = EMB_NORMAL;
  3664. if (iPattern.fFlags & PF_FILL) m_wEmbellishment |= EMB_FILL;
  3665. if (iPattern.fFlags & PF_INTRO) m_wEmbellishment |= EMB_INTRO;
  3666. if (iPattern.fFlags & PF_END) m_wEmbellishment |= EMB_END;
  3667. if (iPattern.fFlags & PF_BREAK) m_wEmbellishment |= EMB_BREAK;
  3668. if (iPattern.fFlags & PF_MOTIF) m_wEmbellishment |= EMB_MOTIF;
  3669. m_pRhythmMap = new DWORD[iPattern.wMeasures];
  3670. if( m_pRhythmMap == NULL )
  3671. {
  3672. hr = E_OUTOFMEMORY;
  3673. goto ON_ERR;
  3674. }
  3675. if (iPattern.fFlags & PF_WHOLE) dwRhythm = 1; // bit 1 set
  3676. if (iPattern.fFlags & PF_HALF) dwRhythm = 5; // bits 1 and 3
  3677. if (iPattern.fFlags & PF_QUARTER) dwRhythm = 15; // bits 1-4
  3678. for (i = 0; i < iPattern.wMeasures; ++i)
  3679. {
  3680. m_pRhythmMap[i] = dwRhythm;
  3681. }
  3682. for( i = 0 ; i < 16 ; ++i ) // loop over Parts
  3683. {
  3684. TListItem<DirectMusicPart*> *pPartItem = new TListItem<DirectMusicPart*>;
  3685. if( pPartItem == NULL )
  3686. {
  3687. hr = E_OUTOFMEMORY;
  3688. goto ON_ERR;
  3689. }
  3690. DirectMusicPart*& pPart = pPartItem->GetItemValue();
  3691. pPart = new DirectMusicPart;
  3692. if( pPart == NULL )
  3693. {
  3694. hr = E_OUTOFMEMORY;
  3695. goto ON_ERR;
  3696. }
  3697. pPart->m_wNumMeasures = m_wNumMeasures;
  3698. TListItem<DirectMusicPartRef> *pPartRefItem = new TListItem<DirectMusicPartRef>;
  3699. if( pPartRefItem == NULL )
  3700. {
  3701. hr = E_OUTOFMEMORY;
  3702. goto ON_ERR;
  3703. }
  3704. DirectMusicPartRef& rPartRef = pPartRefItem->GetItemValue();
  3705. rPartRef.m_pDMPart = pPart;
  3706. rPartRef.m_pDMPart->AddRef();
  3707. rPartRef.m_dwLogicalPartID = VOICEID_TO_CHANNEL(i + 1);
  3708. AdjoinPChannel(rStyleStruct.m_PChannelList, rPartRef.m_dwLogicalPartID);
  3709. rPartRef.m_bVariationLockID = 0; // 0 means no locking between parts...
  3710. rPartRef.m_bRandomVariation = DMUS_VARIATIONT_RANDOM; // (default in 2.5)
  3711. if( iPattern.wInvert & (1 << i) )
  3712. {
  3713. pPart->m_bInvertLower = iPattern.abInvertLower[i];
  3714. pPart->m_bInvertUpper = iPattern.abInvertUpper[i];
  3715. }
  3716. else
  3717. {
  3718. pPart->m_bInvertLower = 0;
  3719. pPart->m_bInvertUpper = 127;
  3720. }
  3721. if (iPattern.achChordChoice[i] == CHTYPE_UPPER ||
  3722. iPattern.achChordChoice[i] == CHTYPE_UPPERMELODIC)
  3723. {
  3724. rPartRef.m_bSubChordLevel = SUBCHORD_STANDARD_CHORD;
  3725. }
  3726. else
  3727. {
  3728. rPartRef.m_bSubChordLevel = SUBCHORD_BASS;
  3729. }
  3730. switch (iPattern.achChordChoice[i])
  3731. {
  3732. case CHTYPE_DRUM:
  3733. case CHTYPE_FIXED:
  3734. pPart->m_bPlayModeFlags = DMUS_PLAYMODE_FIXED;
  3735. break;
  3736. case CHTYPE_UPPER:
  3737. case CHTYPE_BASS:
  3738. pPart->m_bPlayModeFlags = DMUS_PLAYMODE_NORMALCHORD;
  3739. break;
  3740. case CHTYPE_SCALEONLY:
  3741. pPart->m_bPlayModeFlags = DMUS_PLAYMODE_PEDALPOINT;
  3742. break;
  3743. case CHTYPE_BASSMELODIC:
  3744. case CHTYPE_UPPERMELODIC:
  3745. pPart->m_bPlayModeFlags = DMUS_PLAYMODE_SCALE_INTERVALS | DMUS_PLAYMODE_CHORD_ROOT;
  3746. break;
  3747. default:
  3748. // should never get here...
  3749. pPart->m_bPlayModeFlags = DMUS_PLAYMODE_FIXED;
  3750. }
  3751. // if none of the variations have the ->I or ->V flag set, set it in all variations
  3752. wKludge = VF_TO1 | VF_TO5;
  3753. for (j = 16; j < 32; j++) pPart->m_dwVariationChoices[j] = 0;
  3754. for( j = 0 ; j < 16 ; ++j )
  3755. {
  3756. pPart->m_dwVariationChoices[j] = iPattern.awVarFlags[i][j];
  3757. if( ( pPart->m_dwVariationChoices[j] & VF_TO1 ) != 0 )
  3758. {
  3759. wKludge &= ~VF_TO1;
  3760. }
  3761. if( ( pPart->m_dwVariationChoices[j] & VF_TO5 ) != 0 )
  3762. {
  3763. wKludge &= ~VF_TO5;
  3764. }
  3765. }
  3766. if( wKludge != 0 )
  3767. {
  3768. for( j = 0 ; j < 16 ; ++j )
  3769. {
  3770. pPart->m_dwVariationChoices[j] |= wKludge;
  3771. }
  3772. }
  3773. partList.AddTail(pPartItem);
  3774. m_PartRefList.AddTail(pPartRefItem);
  3775. }
  3776. break;
  3777. case FOURCC_LIST:
  3778. switch( ck.fccType )
  3779. {
  3780. case FOURCC_CLICK_LIST:
  3781. LoadEvents(pRIFF, &ck);
  3782. break;
  3783. }
  3784. break;
  3785. }
  3786. pRIFF->Ascend( &ck, 0 );
  3787. }
  3788. ON_ERR:
  3789. pStream->Release();
  3790. return hr;
  3791. }
  3792. /////////////////////////////////////////////////////////////////////////////
  3793. // CDirectMusicPartRef::DM_LoadPartRef
  3794. HRESULT DirectMusicPartRef::DM_LoadPartRef(
  3795. IAARIFFStream* pIRiffStream, MMCKINFO* pckMain, DMStyleStruct* pStyle )
  3796. {
  3797. DirectMusicPart* pPart;
  3798. IStream* pIStream;
  3799. HRESULT hr;
  3800. MMCKINFO ck;
  3801. DWORD dwByteCount;
  3802. DWORD dwSize;
  3803. if ( pStyle == NULL ) return E_INVALIDARG;
  3804. pIStream = pIRiffStream->GetStream();
  3805. if ( pIStream == NULL ) return E_FAIL;
  3806. while( pIRiffStream->Descend( &ck, pckMain, 0 ) == 0 )
  3807. {
  3808. switch( ck.ckid )
  3809. {
  3810. case DMUS_FOURCC_PARTREF_CHUNK:
  3811. {
  3812. DMUS_IO_PARTREF iDMPartRef;
  3813. dwSize = min( ck.cksize, sizeof( DMUS_IO_PARTREF ) );
  3814. hr = pIStream->Read( &iDMPartRef, dwSize, &dwByteCount );
  3815. if( FAILED( hr ) || dwByteCount != dwSize )
  3816. {
  3817. hr = E_FAIL;
  3818. goto ON_ERROR;
  3819. }
  3820. m_bRandomVariation = iDMPartRef.bRandomVariation;
  3821. if (dwSize < DX8_PARTREF_SIZE)
  3822. {
  3823. m_dwLogicalPartID = iDMPartRef.wLogicalPartID;
  3824. }
  3825. else
  3826. {
  3827. m_dwLogicalPartID = iDMPartRef.dwPChannel;
  3828. }
  3829. AdjoinPChannel(pStyle->m_PChannelList, m_dwLogicalPartID);
  3830. m_bVariationLockID = iDMPartRef.bVariationLockID;
  3831. m_bSubChordLevel = iDMPartRef.bSubChordLevel;
  3832. m_bPriority = iDMPartRef.bPriority;
  3833. pPart = pStyle->FindPartByGUID( iDMPartRef.guidPartID );
  3834. if( pPart == NULL )
  3835. {
  3836. hr = E_FAIL;
  3837. goto ON_ERROR;
  3838. }
  3839. SetPart( pPart );
  3840. break;
  3841. }
  3842. }
  3843. pIRiffStream->Ascend( &ck, 0 );
  3844. }
  3845. ON_ERROR:
  3846. pIStream->Release();
  3847. return hr;
  3848. }
  3849. /////////////////////////////////////////////////////////////////////////////
  3850. // DirectMusicPartRef::SetPart
  3851. void DirectMusicPartRef::SetPart( DirectMusicPart* pPart )
  3852. {
  3853. if( m_pDMPart == pPart )
  3854. {
  3855. return;
  3856. }
  3857. if( m_pDMPart )
  3858. {
  3859. m_pDMPart->Release();
  3860. }
  3861. if( pPart )
  3862. {
  3863. m_pDMPart = pPart;
  3864. m_pDMPart->AddRef();
  3865. }
  3866. }
  3867. CDMStyle::CDMStyle() : m_cRef(1), m_fCSInitialized(FALSE)
  3868. {
  3869. InterlockedIncrement(&g_cComponent);
  3870. ::InitializeCriticalSection( &m_CriticalSection );
  3871. m_fCSInitialized = TRUE;
  3872. m_StyleInfo.m_fLoaded = false;
  3873. m_StyleInfo.m_dwFlags = 0;
  3874. m_StyleInfo.m_pDefaultBand = NULL;
  3875. m_StyleInfo.m_pDefaultPers = NULL;
  3876. }
  3877. CDMStyle::~CDMStyle()
  3878. {
  3879. if (m_fCSInitialized)
  3880. {
  3881. // Don't need to clean up if critical section failed.
  3882. // DON'T MOVE THIS - it will fault in low memory conditions
  3883. //
  3884. CleanUp();
  3885. ::DeleteCriticalSection( &m_CriticalSection );
  3886. }
  3887. InterlockedDecrement(&g_cComponent);
  3888. }
  3889. HRESULT CDMStyle::GetStyleInfo(void **pData)
  3890. {
  3891. *pData = (void *) &m_StyleInfo;
  3892. return S_OK;
  3893. }
  3894. HRESULT CDMStyle::IsDX8()
  3895. {
  3896. return m_StyleInfo.UsingDX8() ? S_OK : S_FALSE;
  3897. }
  3898. HRESULT CDMStyle::CritSec(bool fEnter)
  3899. {
  3900. HRESULT hr = S_OK;
  3901. if (m_fCSInitialized)
  3902. {
  3903. if (fEnter)
  3904. {
  3905. EnterCriticalSection(&m_CriticalSection);
  3906. }
  3907. else
  3908. {
  3909. LeaveCriticalSection(&m_CriticalSection);
  3910. }
  3911. }
  3912. else
  3913. {
  3914. hr = E_FAIL;
  3915. }
  3916. return hr;
  3917. }
  3918. /* IPersist methods */
  3919. HRESULT CDMStyle::GetClassID( LPCLSID pclsid )
  3920. {
  3921. //assert ( pclsid != NULL );
  3922. *pclsid = CLSID_DirectMusicStyle;
  3923. return S_OK;
  3924. }
  3925. HRESULT CDMStyle::IsDirty()
  3926. {
  3927. return ( m_fDirty ) ? S_OK : S_FALSE;
  3928. }
  3929. HRESULT CDMStyle::Save( LPSTREAM pStream, BOOL /*fClearDirty*/ )
  3930. {
  3931. return E_NOTIMPL;
  3932. }
  3933. HRESULT CDMStyle::GetSizeMax( ULARGE_INTEGER* /*pcbSize*/ )
  3934. {
  3935. return E_NOTIMPL;
  3936. }
  3937. HRESULT CDMStyle::Load( LPSTREAM pIStream )
  3938. {
  3939. DWORD dwPos;
  3940. IAARIFFStream* pIRiffStream;
  3941. MMCKINFO ckMain;
  3942. HRESULT hr = E_FAIL;
  3943. if( pIStream == NULL )
  3944. {
  3945. return E_INVALIDARG;
  3946. }
  3947. EnterCriticalSection( &m_CriticalSection );
  3948. CleanUp();
  3949. dwPos = StreamTell( pIStream );
  3950. BOOL fFoundFormat = FALSE;
  3951. // Check for Direct Music format
  3952. if( SUCCEEDED( AllocRIFFStream( pIStream, &pIRiffStream ) ) )
  3953. {
  3954. ckMain.fccType = DMUS_FOURCC_STYLE_FORM;
  3955. if( pIRiffStream->Descend( &ckMain, NULL, MMIO_FINDRIFF ) == 0 )
  3956. {
  3957. hr = DM_LoadStyle( pIRiffStream, &ckMain );
  3958. fFoundFormat = TRUE;
  3959. }
  3960. pIRiffStream->Release();
  3961. pIRiffStream = NULL;
  3962. }
  3963. // Check for IMA 2.5 format
  3964. if( !fFoundFormat )
  3965. {
  3966. StreamSeek( pIStream, dwPos, STREAM_SEEK_SET );
  3967. if( SUCCEEDED( AllocRIFFStream( pIStream, &pIRiffStream ) ) )
  3968. {
  3969. ckMain.fccType = FOURCC_STYLE_FORM;
  3970. if( pIRiffStream->Descend( &ckMain, NULL, MMIO_FINDRIFF ) == 0 )
  3971. {
  3972. hr = IMA25_LoadStyle( pIRiffStream, &ckMain );
  3973. fFoundFormat = TRUE;
  3974. }
  3975. pIRiffStream->Release();
  3976. }
  3977. }
  3978. if (SUCCEEDED(hr)) m_StyleInfo.m_fLoaded = true;
  3979. LeaveCriticalSection( &m_CriticalSection );
  3980. return hr;
  3981. }
  3982. void CDMStyle::CleanUp()
  3983. {
  3984. EnterCriticalSection(&m_CriticalSection);
  3985. m_StyleInfo.m_fLoaded = false;
  3986. TListItem<IDirectMusicBand*>* pBandListItem = (m_StyleInfo.m_BandList).GetHead();
  3987. for (; pBandListItem; pBandListItem = pBandListItem->GetNext())
  3988. {
  3989. IDirectMusicBand* pBand = pBandListItem->GetItemValue();
  3990. if(pBand)
  3991. {
  3992. pBand->Release();
  3993. }
  3994. }
  3995. m_StyleInfo.m_BandList.CleanUp();
  3996. TListItem<IDirectMusicChordMap*>* pPersListItem = (m_StyleInfo.m_PersList).GetHead();
  3997. for (; pPersListItem; pPersListItem = pPersListItem->GetNext())
  3998. {
  3999. IDirectMusicChordMap* pPers = pPersListItem->GetItemValue();
  4000. if(pPers)
  4001. {
  4002. pPers->Release();
  4003. }
  4004. }
  4005. m_StyleInfo.m_PersList.CleanUp();
  4006. TListItem<DirectMusicPart*>* pPartListItem = (m_StyleInfo.m_PartList).GetHead();
  4007. for (int count = 0; pPartListItem; pPartListItem = pPartListItem->GetNext(),count++)
  4008. {
  4009. DirectMusicPart* pPart = pPartListItem->GetItemValue();
  4010. if(pPart)
  4011. {
  4012. if (pPart->Release() == 0)
  4013. {
  4014. pPartListItem->GetItemValue() = NULL;
  4015. }
  4016. }
  4017. }
  4018. m_StyleInfo.m_PartList.CleanUp();
  4019. TListItem<CDirectMusicPattern*>* pPatternListItem = (m_StyleInfo.m_PatternList).GetHead();
  4020. for (; pPatternListItem; pPatternListItem = pPatternListItem->GetNext())
  4021. {
  4022. CDirectMusicPattern* pPattern = pPatternListItem->GetItemValue();
  4023. if(pPattern)
  4024. {
  4025. if (pPattern->Release() == 0)
  4026. {
  4027. pPatternListItem->GetItemValue() = NULL;
  4028. }
  4029. }
  4030. }
  4031. m_StyleInfo.m_PatternList.CleanUp();
  4032. pPatternListItem = (m_StyleInfo.m_MotifList).GetHead();
  4033. for (; pPatternListItem; pPatternListItem = pPatternListItem->GetNext())
  4034. {
  4035. CDirectMusicPattern* pPattern = pPatternListItem->GetItemValue();
  4036. if(pPattern)
  4037. {
  4038. pPattern->Release();
  4039. }
  4040. }
  4041. m_StyleInfo.m_MotifList.CleanUp();
  4042. m_StyleInfo.m_PChannelList.CleanUp();
  4043. LeaveCriticalSection(&m_CriticalSection);
  4044. }
  4045. HRESULT CDMStyle::IMA25_LoadPersonalityReference( IStream* pStream, MMCKINFO* pck )
  4046. {
  4047. ioPersonalityRef ref;
  4048. DWORD dwSize;
  4049. WORD wStructSize;
  4050. String strFileName;
  4051. HRESULT hr = S_OK;
  4052. HRESULT hrChordMap = E_FAIL;
  4053. if ( pStream == NULL ) return E_POINTER;
  4054. dwSize = pck->cksize;
  4055. pStream->Read( &wStructSize, sizeof( wStructSize ), NULL );
  4056. FixBytes( FBT_SHORT, &wStructSize );
  4057. dwSize -= sizeof( wStructSize );
  4058. if( wStructSize > sizeof(ref) )
  4059. {
  4060. hr = pStream->Read( &ref, sizeof(ref), NULL );
  4061. FixBytes( FBT_IOPERSONALITYREF, &ref );
  4062. StreamSeek( pStream, wStructSize - sizeof(ref), STREAM_SEEK_CUR );
  4063. }
  4064. else
  4065. {
  4066. hr = pStream->Read( &ref, wStructSize, NULL );
  4067. FixBytes( FBT_IOPERSONALITYREF, &ref );
  4068. }
  4069. if (!SUCCEEDED(hr)) return hr;
  4070. dwSize -= wStructSize;
  4071. // loader stuff here...
  4072. DMUS_OBJECTDESC ObjectDescript;
  4073. ZeroMemory(&ObjectDescript, sizeof(DMUS_OBJECTDESC));
  4074. ObjectDescript.dwSize = sizeof(DMUS_OBJECTDESC);
  4075. ObjectDescript.guidClass = CLSID_DirectMusicChordMap;
  4076. wcscpy(ObjectDescript.wszName, ref.wstrName);
  4077. ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_NAME;
  4078. IDirectMusicLoader* pLoader;
  4079. IDirectMusicGetLoader *pIGetLoader;
  4080. hr = pStream->QueryInterface( IID_IDirectMusicGetLoader,(void **) &pIGetLoader );
  4081. if (!SUCCEEDED(hr)) return hr;
  4082. hr = pIGetLoader->GetLoader(&pLoader);
  4083. pIGetLoader->Release();
  4084. if (!SUCCEEDED(hr)) return hr;
  4085. IDirectMusicObject* pObject = NULL;
  4086. // Ignore this result (except for purposes of incorporating it into the style):
  4087. // success or failure of loading individual ChordMap references should have no
  4088. // bearing on the success or failure of loading the style.
  4089. hrChordMap = pLoader->GetObject(&ObjectDescript, IID_IDirectMusicObject, (void**)&pObject);
  4090. if (!SUCCEEDED(hrChordMap))
  4091. {
  4092. hr = strFileName.ReadWCS( pStream, dwSize );
  4093. if (SUCCEEDED(hr))
  4094. {
  4095. strFileName += ".per";
  4096. wcscpy(ObjectDescript.wszFileName, strFileName);
  4097. ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;
  4098. hrChordMap = pLoader->GetObject(&ObjectDescript, IID_IDirectMusicObject, (void**)&pObject);
  4099. }
  4100. }
  4101. pLoader->Release();
  4102. if (SUCCEEDED(hrChordMap))
  4103. {
  4104. IDirectMusicChordMap* pPers;
  4105. hr = pObject->QueryInterface(IID_IDirectMusicChordMap, (void**)&pPers);
  4106. pObject->Release();
  4107. if (SUCCEEDED(hr))
  4108. {
  4109. hr = IncorporatePersonality(pPers, ref.wstrName, ref.fDefault);
  4110. }
  4111. }
  4112. return hr;
  4113. }
  4114. HRESULT CDMStyle::IncorporatePersonality( IDirectMusicChordMap* pPers, String strName, BOOL fDefault )
  4115. {
  4116. EnterCriticalSection( &m_CriticalSection );
  4117. TListItem<IDirectMusicChordMap*>* pScan = m_StyleInfo.m_PersList.GetHead();
  4118. for( ; pScan != NULL ; pScan = pScan->GetNext() )
  4119. {
  4120. HRESULT hr = S_OK;
  4121. String str2;
  4122. IDirectMusicObject *pIObject = NULL;
  4123. DMUS_OBJECTDESC Desc; // Descriptor.
  4124. if (SUCCEEDED(hr = pScan->GetItemValue()->QueryInterface(IID_IDirectMusicObject,(void **) &pIObject)))
  4125. {
  4126. if (SUCCEEDED(hr = pIObject->GetDescriptor(&Desc)))
  4127. {
  4128. if (Desc.dwValidData & DMUS_OBJ_NAME)
  4129. {
  4130. str2 = Desc.wszName;
  4131. if (strName == str2)
  4132. {
  4133. pPers->Release();
  4134. break;
  4135. }
  4136. }
  4137. else hr = E_FAIL;
  4138. }
  4139. pIObject->Release();
  4140. }
  4141. if (!SUCCEEDED(hr))
  4142. {
  4143. LeaveCriticalSection( &m_CriticalSection );
  4144. return hr;
  4145. }
  4146. }
  4147. if( pScan == NULL )
  4148. {
  4149. TListItem<IDirectMusicChordMap*>* pNew = NULL;
  4150. pNew = new TListItem<IDirectMusicChordMap*>(pPers);
  4151. if (pNew)
  4152. {
  4153. m_StyleInfo.m_PersList.AddHead(pNew);
  4154. if (fDefault)
  4155. {
  4156. if (m_StyleInfo.m_pDefaultPers) m_StyleInfo.m_pDefaultPers->Release();
  4157. m_StyleInfo.m_pDefaultPers = pPers;
  4158. }
  4159. }
  4160. }
  4161. LeaveCriticalSection( &m_CriticalSection );
  4162. return S_OK;
  4163. }
  4164. /////////////////////////////////////////////////////////////////////////////
  4165. // CDMStyle::DM_ParseDescriptor
  4166. HRESULT CDMStyle::DM_ParseDescriptor( IAARIFFStream* pIRiffStream, MMCKINFO* pckMain, LPDMUS_OBJECTDESC pDesc )
  4167. {
  4168. IStream* pIStream;
  4169. MMCKINFO ck;
  4170. MMCKINFO ckList;
  4171. DWORD dwByteCount;
  4172. DWORD dwSize;
  4173. DWORD dwPos;
  4174. HRESULT hr = S_OK;
  4175. String str;
  4176. pIStream = pIRiffStream->GetStream();
  4177. if ( pIStream == NULL ) return E_FAIL;
  4178. dwPos = StreamTell( pIStream );
  4179. pDesc->dwValidData = DMUS_OBJ_CLASS;
  4180. pDesc->guidClass = CLSID_DirectMusicStyle;
  4181. while( pIRiffStream->Descend( &ck, pckMain, 0 ) == 0 )
  4182. {
  4183. switch( ck.ckid )
  4184. {
  4185. case DMUS_FOURCC_GUID_CHUNK:
  4186. dwSize = min( ck.cksize, sizeof( GUID ) );
  4187. hr = pIStream->Read( &pDesc->guidObject, dwSize, &dwByteCount );
  4188. if( FAILED( hr ) || dwByteCount != dwSize )
  4189. {
  4190. hr = DMUS_E_CHUNKNOTFOUND;
  4191. goto ON_ERROR;
  4192. }
  4193. else
  4194. {
  4195. pDesc->dwValidData |= DMUS_OBJ_OBJECT;
  4196. }
  4197. break;
  4198. case DMUS_FOURCC_VERSION_CHUNK:
  4199. {
  4200. dwSize = min( ck.cksize, sizeof( DMUS_IO_VERSION ) );
  4201. hr = pIStream->Read( &pDesc->vVersion, dwSize, &dwByteCount );
  4202. if( FAILED( hr )|| dwByteCount != dwSize )
  4203. {
  4204. hr = DMUS_E_CHUNKNOTFOUND;
  4205. goto ON_ERROR;
  4206. }
  4207. else
  4208. {
  4209. pDesc->dwValidData |= DMUS_OBJ_VERSION;
  4210. }
  4211. break;
  4212. }
  4213. case FOURCC_LIST:
  4214. switch( ck.fccType )
  4215. {
  4216. case DMUS_FOURCC_UNFO_LIST:
  4217. while( pIRiffStream->Descend( &ckList, &ck, 0 ) == 0 )
  4218. {
  4219. switch( ckList.ckid )
  4220. {
  4221. case RIFFINFO_INAM:
  4222. case DMUS_FOURCC_UNAM_CHUNK:
  4223. {
  4224. DWORD dwLength = min(ckList.cksize, (DWORD)(sizeof(WCHAR)*(DMUS_MAX_NAME - 1)));
  4225. hr = ReadMBSfromWCS( pIStream, dwLength, str );
  4226. if (FAILED(hr))
  4227. {
  4228. goto ON_ERROR;
  4229. }
  4230. wcscpy(pDesc->wszName, str);
  4231. if(pDesc->wszName[0])
  4232. {
  4233. pDesc->dwValidData |= DMUS_OBJ_NAME;
  4234. pDesc->wszName[16] = 0;
  4235. }
  4236. break;
  4237. }
  4238. case DMUS_FOURCC_CATEGORY_CHUNK:
  4239. {
  4240. DWORD dwLength = min(ckList.cksize, (DWORD)(sizeof(WCHAR)*(DMUS_MAX_CATEGORY - 1)));
  4241. hr = ReadMBSfromWCS( pIStream, dwLength, str );
  4242. if (FAILED(hr))
  4243. {
  4244. goto ON_ERROR;
  4245. }
  4246. wcscpy(pDesc->wszCategory, str);
  4247. if(pDesc->wszCategory[0])
  4248. {
  4249. pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
  4250. pDesc->wszCategory[16] = 0;
  4251. }
  4252. break;
  4253. }
  4254. }
  4255. pIRiffStream->Ascend( &ckList, 0 );
  4256. }
  4257. break;
  4258. }
  4259. break;
  4260. }
  4261. pIRiffStream->Ascend( &ck, 0 );
  4262. dwPos = StreamTell( pIStream );
  4263. }
  4264. ON_ERROR:
  4265. pIStream->Release();
  4266. return hr;
  4267. }
  4268. /////////////////////////////////////////////////////////////////////////////
  4269. // CDMStyle::DM_LoadStyle
  4270. HRESULT CDMStyle::DM_LoadStyle( IAARIFFStream* pIRiffStream, MMCKINFO* pckMain )
  4271. {
  4272. DirectMusicPart* pPart;
  4273. IStream* pIStream;
  4274. MMCKINFO ck;
  4275. MMCKINFO ckList;
  4276. DWORD dwByteCount;
  4277. DWORD dwSize;
  4278. DWORD dwPos;
  4279. HRESULT hr = S_OK;
  4280. HRESULT hrBand = S_OK;
  4281. BOOL fFoundDefault = FALSE;
  4282. pIStream = pIRiffStream->GetStream();
  4283. if ( pIStream == NULL ) return E_FAIL;
  4284. dwPos = StreamTell( pIStream );
  4285. while( pIRiffStream->Descend( &ck, pckMain, 0 ) == 0 )
  4286. {
  4287. switch( ck.ckid )
  4288. {
  4289. case DMUS_FOURCC_STYLE_CHUNK:
  4290. {
  4291. DMUS_IO_STYLE iDMStyle;
  4292. dwSize = min( ck.cksize, sizeof( DMUS_IO_STYLE ) );
  4293. hr = pIStream->Read( &iDMStyle, dwSize, &dwByteCount );
  4294. if( FAILED( hr )
  4295. || dwByteCount != dwSize )
  4296. {
  4297. hr = E_FAIL;
  4298. goto ON_ERROR;
  4299. }
  4300. m_StyleInfo.m_TimeSignature.m_bBeatsPerMeasure = iDMStyle.timeSig.bBeatsPerMeasure;
  4301. m_StyleInfo.m_TimeSignature.m_bBeat = iDMStyle.timeSig.bBeat;
  4302. m_StyleInfo.m_TimeSignature.m_wGridsPerBeat = iDMStyle.timeSig.wGridsPerBeat;
  4303. m_StyleInfo.m_dblTempo = iDMStyle.dblTempo;
  4304. break;
  4305. }
  4306. case DMUS_FOURCC_GUID_CHUNK:
  4307. dwSize = min( ck.cksize, sizeof( GUID ) );
  4308. hr = pIStream->Read( &m_StyleInfo.m_guid, dwSize, &dwByteCount );
  4309. if( FAILED( hr )
  4310. || dwByteCount != dwSize )
  4311. {
  4312. hr = E_FAIL;
  4313. goto ON_ERROR;
  4314. }
  4315. break;
  4316. case DMUS_FOURCC_VERSION_CHUNK:
  4317. {
  4318. DMUS_IO_VERSION iDMStyleVersion;
  4319. dwSize = min( ck.cksize, sizeof( DMUS_IO_VERSION ) );
  4320. hr = pIStream->Read( &iDMStyleVersion, dwSize, &dwByteCount );
  4321. if( FAILED( hr )
  4322. || dwByteCount != dwSize )
  4323. {
  4324. hr = E_FAIL;
  4325. goto ON_ERROR;
  4326. }
  4327. m_StyleInfo.m_dwVersionMS = iDMStyleVersion.dwVersionMS;
  4328. m_StyleInfo.m_dwVersionLS = iDMStyleVersion.dwVersionLS;
  4329. break;
  4330. }
  4331. case FOURCC_LIST:
  4332. switch( ck.fccType )
  4333. {
  4334. case DMUS_FOURCC_STYLE_PERS_REF_LIST:
  4335. {
  4336. hr = DM_LoadPersonalityReference( pIRiffStream, &ck );
  4337. if( FAILED( hr ) )
  4338. {
  4339. goto ON_ERROR;
  4340. }
  4341. break;
  4342. }
  4343. case DMUS_FOURCC_UNFO_LIST:
  4344. while( pIRiffStream->Descend( &ckList, &ck, 0 ) == 0 )
  4345. {
  4346. switch( ckList.ckid )
  4347. {
  4348. case RIFFINFO_INAM:
  4349. case DMUS_FOURCC_UNAM_CHUNK:
  4350. {
  4351. DWORD dwLength = min(ckList.cksize, (DWORD)(sizeof(WCHAR)*(DMUS_MAX_NAME - 1)));
  4352. hr = ReadMBSfromWCS( pIStream, dwLength, m_StyleInfo.m_strName );
  4353. if (FAILED(hr))
  4354. {
  4355. goto ON_ERROR;
  4356. }
  4357. break;
  4358. }
  4359. case DMUS_FOURCC_CATEGORY_CHUNK:
  4360. {
  4361. DWORD dwLength = min(ckList.cksize, (DWORD)(sizeof(WCHAR)*(DMUS_MAX_CATEGORY - 1)));
  4362. hr = ReadMBSfromWCS( pIStream, dwLength, m_StyleInfo.m_strCategory );
  4363. if (FAILED(hr))
  4364. {
  4365. goto ON_ERROR;
  4366. }
  4367. break;
  4368. }
  4369. }
  4370. pIRiffStream->Ascend( &ckList, 0 );
  4371. }
  4372. break;
  4373. case DMUS_FOURCC_PART_LIST:
  4374. pPart = m_StyleInfo.AllocPart();
  4375. if( pPart == NULL )
  4376. {
  4377. hr = E_OUTOFMEMORY ;
  4378. goto ON_ERROR;
  4379. }
  4380. hr = pPart->DM_LoadPart( pIRiffStream, &ck, &m_StyleInfo );
  4381. if( FAILED( hr ) )
  4382. {
  4383. m_StyleInfo.DeletePart( pPart );
  4384. goto ON_ERROR;
  4385. }
  4386. if( hr == S_FALSE )
  4387. {
  4388. // This should not happen when loading a Style!
  4389. Trace(0, "LOAD CONFLICT: Two parts with the same Guid.\n");
  4390. assert( 0 );
  4391. // Bypass this Part because Style already contains a Part
  4392. // whose GUID matches pPart->m_guidPartID
  4393. m_StyleInfo.DeletePart( pPart );
  4394. }
  4395. break;
  4396. case DMUS_FOURCC_PATTERN_LIST:
  4397. StreamSeek( pIStream, dwPos, STREAM_SEEK_SET );
  4398. CDirectMusicPattern* pPattern =
  4399. new CDirectMusicPattern( &m_StyleInfo.m_TimeSignature, FALSE );
  4400. if( pPattern == NULL )
  4401. {
  4402. hr = E_OUTOFMEMORY ;
  4403. goto ON_ERROR;
  4404. }
  4405. ckList.fccType = DMUS_FOURCC_PATTERN_LIST;
  4406. if( pIRiffStream->Descend( &ckList, NULL, MMIO_FINDLIST ) != 0 )
  4407. {
  4408. hr = E_FAIL;
  4409. pPattern->Release();
  4410. goto ON_ERROR;
  4411. }
  4412. hr = pPattern->DM_LoadPattern( pIRiffStream, &ckList, &m_StyleInfo );
  4413. pIRiffStream->Ascend( &ckList, 0 );
  4414. if( FAILED( hr ) )
  4415. {
  4416. pPattern->Release();
  4417. goto ON_ERROR;
  4418. }
  4419. TListItem<CDirectMusicPattern*>* pPatternItem =
  4420. new TListItem<CDirectMusicPattern*>(pPattern);
  4421. if( pPatternItem == NULL )
  4422. {
  4423. hr = E_OUTOFMEMORY ;
  4424. goto ON_ERROR;
  4425. }
  4426. if( pPattern->m_wEmbellishment & EMB_MOTIF )
  4427. {
  4428. m_StyleInfo.m_MotifList.AddTail( pPatternItem );
  4429. }
  4430. else
  4431. {
  4432. m_StyleInfo.m_PatternList.AddTail( pPatternItem );
  4433. }
  4434. break;
  4435. }
  4436. break;
  4437. case FOURCC_RIFF:
  4438. switch( ck.fccType )
  4439. {
  4440. case FOURCC_BAND_FORM:
  4441. case DMUS_FOURCC_BAND_FORM:
  4442. {
  4443. TListItem<IDirectMusicBand*>* pBandListItem = new TListItem<IDirectMusicBand*>;
  4444. if(pBandListItem)
  4445. {
  4446. pBandListItem->GetItemValue() = NULL;
  4447. // Create a band
  4448. hr = CoCreateInstance(CLSID_DirectMusicBand,
  4449. NULL,
  4450. CLSCTX_INPROC,
  4451. IID_IDirectMusicBand,
  4452. (void**)&(pBandListItem->GetItemValue()));
  4453. }
  4454. else
  4455. {
  4456. hr = E_OUTOFMEMORY;
  4457. }
  4458. if(SUCCEEDED(hr))
  4459. {
  4460. // Seek back to begining of Riff chunk
  4461. // This is the amount read by Descend when descending into a FOURCC_RIFF chunk
  4462. // Get current position
  4463. LARGE_INTEGER li;
  4464. ULARGE_INTEGER ul;
  4465. li.HighPart = 0;
  4466. li.LowPart = 0;
  4467. hr = pIStream->Seek(li,
  4468. STREAM_SEEK_CUR,
  4469. &ul);
  4470. if(SUCCEEDED(hr))
  4471. {
  4472. li.HighPart = 0;
  4473. // This is always a valid operation
  4474. li.LowPart = ul.LowPart - (2 * sizeof(FOURCC) + sizeof(DWORD));
  4475. hr = pIStream->Seek(li,
  4476. STREAM_SEEK_SET,
  4477. &ul);
  4478. }
  4479. }
  4480. if(SUCCEEDED(hr))
  4481. {
  4482. // Load band
  4483. IPersistStream* pIPersistStream;
  4484. hr = (pBandListItem->GetItemValue())->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
  4485. if (hr != S_OK)
  4486. {
  4487. hrBand = hr;
  4488. }
  4489. if(SUCCEEDED(hr))
  4490. {
  4491. hr = pIPersistStream->Load(pIStream);
  4492. pIPersistStream->Release();
  4493. DWORD dwFlags = 0;
  4494. if(SUCCEEDED(hr))
  4495. {
  4496. IDirectMusicBandPrivate *pIDMBandP = NULL;
  4497. hr = (pBandListItem->GetItemValue())->QueryInterface(IID_IDirectMusicBandPrivate, (void **)&pIDMBandP);
  4498. if(SUCCEEDED(hr))
  4499. {
  4500. hr = pIDMBandP->GetFlags(&dwFlags);
  4501. if(SUCCEEDED(hr))
  4502. {
  4503. if( (ck.fccType == FOURCC_BAND_FORM && (dwFlags & DMUSB_DEFAULT)) ||
  4504. (ck.fccType == DMUS_FOURCC_BAND_FORM && !fFoundDefault) )
  4505. {
  4506. // We have a default band
  4507. m_StyleInfo.m_pDefaultBand = pBandListItem->GetItemValue();
  4508. fFoundDefault = TRUE;
  4509. }
  4510. }
  4511. pIDMBandP->Release();
  4512. }
  4513. }
  4514. }
  4515. }
  4516. if(FAILED(hr))
  4517. {
  4518. if(pBandListItem)
  4519. {
  4520. IDirectMusicBand* pBand = pBandListItem->GetItemValue();
  4521. if(pBand)
  4522. {
  4523. pBand->Release();
  4524. }
  4525. delete pBandListItem;
  4526. }
  4527. goto ON_ERROR;
  4528. }
  4529. EnterCriticalSection(&m_CriticalSection);
  4530. (m_StyleInfo.m_BandList).AddHead(pBandListItem);
  4531. LeaveCriticalSection(&m_CriticalSection);
  4532. }
  4533. break;
  4534. }
  4535. break;
  4536. }
  4537. pIRiffStream->Ascend( &ck, 0 );
  4538. dwPos = StreamTell( pIStream );
  4539. }
  4540. ON_ERROR:
  4541. // Merge the marker event start times in each of the patterns
  4542. TListItem<CDirectMusicPattern*>* pPattern;
  4543. pPattern = m_StyleInfo.m_PatternList.GetHead();
  4544. for (; pPattern != NULL; pPattern = pPattern->GetNext())
  4545. {
  4546. pPattern->GetItemValue()->MergeMarkerEvents(&m_StyleInfo);
  4547. }
  4548. pPattern = m_StyleInfo.m_MotifList.GetHead();
  4549. for (; pPattern != NULL; pPattern = pPattern->GetNext())
  4550. {
  4551. pPattern->GetItemValue()->MergeMarkerEvents(&m_StyleInfo);
  4552. }
  4553. pIStream->Release();
  4554. if (hr == S_OK && hrBand != S_OK)
  4555. {
  4556. hr = hrBand;
  4557. }
  4558. return hr;
  4559. }
  4560. HRESULT CDMStyle::DM_LoadPersonalityReference( IAARIFFStream* pIRiffStream, MMCKINFO* pckParent)
  4561. {
  4562. BOOL fDefaultPers = TRUE;
  4563. HRESULT hr = S_OK;
  4564. if (!pIRiffStream || !pckParent) return E_INVALIDARG;
  4565. MMCKINFO ck;
  4566. IStream* pIStream = pIRiffStream->GetStream();
  4567. if(!pIStream) return E_FAIL;
  4568. while (pIRiffStream->Descend( &ck, pckParent, 0 ) == 0)
  4569. {
  4570. switch (ck.ckid)
  4571. {
  4572. case FOURCC_LIST:
  4573. if (ck.fccType == DMUS_FOURCC_REF_LIST)
  4574. {
  4575. // Ignore this result: success or failure of loading individual
  4576. // ChordMap references should have no bearing on the success or
  4577. // failure of loading the style.
  4578. //hr = LoadReference(pIStream, pIRiffStream, ck, fDefaultPers);
  4579. LoadReference(pIStream, pIRiffStream, ck, fDefaultPers);
  4580. fDefaultPers = FALSE;
  4581. }
  4582. break;
  4583. }
  4584. pIRiffStream->Ascend( &ck, 0 );
  4585. }
  4586. pIStream->Release();
  4587. return hr;
  4588. }
  4589. //////////////////////////////////////////////////////////////////////
  4590. // CDMStyle::LoadReference
  4591. HRESULT CDMStyle::LoadReference(IStream *pStream,
  4592. IAARIFFStream *pIRiffStream,
  4593. MMCKINFO& ckParent,
  4594. BOOL fDefault)
  4595. {
  4596. if (!pStream || !pIRiffStream) return E_INVALIDARG;
  4597. IDirectMusicChordMap* pChordMap;
  4598. IDirectMusicLoader* pLoader = NULL;
  4599. IDirectMusicGetLoader *pIGetLoader;
  4600. HRESULT hr = pStream->QueryInterface( IID_IDirectMusicGetLoader,(void **) &pIGetLoader );
  4601. if (FAILED(hr)) return hr;
  4602. hr = pIGetLoader->GetLoader(&pLoader);
  4603. pIGetLoader->Release();
  4604. if (FAILED(hr)) return hr;
  4605. DMUS_OBJECTDESC desc;
  4606. ZeroMemory(&desc, sizeof(desc));
  4607. DWORD cbRead;
  4608. MMCKINFO ckNext;
  4609. ckNext.ckid = 0;
  4610. ckNext.fccType = 0;
  4611. DWORD dwSize = 0;
  4612. while( pIRiffStream->Descend( &ckNext, &ckParent, 0 ) == 0 )
  4613. {
  4614. switch(ckNext.ckid)
  4615. {
  4616. case DMUS_FOURCC_REF_CHUNK:
  4617. DMUS_IO_REFERENCE ioDMRef;
  4618. hr = pStream->Read(&ioDMRef, sizeof(DMUS_IO_REFERENCE), &cbRead);
  4619. if(SUCCEEDED(hr) && cbRead == sizeof(DMUS_IO_REFERENCE))
  4620. {
  4621. desc.guidClass = ioDMRef.guidClassID;
  4622. desc.dwValidData |= ioDMRef.dwValidData;
  4623. desc.dwValidData |= DMUS_OBJ_CLASS;
  4624. }
  4625. else if(SUCCEEDED(hr))
  4626. {
  4627. hr = E_FAIL;
  4628. }
  4629. break;
  4630. case DMUS_FOURCC_GUID_CHUNK:
  4631. hr = pStream->Read(&(desc.guidObject), sizeof(GUID), &cbRead);
  4632. if(SUCCEEDED(hr) && cbRead == sizeof(GUID))
  4633. {
  4634. desc.dwValidData |= DMUS_OBJ_OBJECT;
  4635. }
  4636. else if(SUCCEEDED(hr))
  4637. {
  4638. hr = E_FAIL;
  4639. }
  4640. break;
  4641. case DMUS_FOURCC_DATE_CHUNK:
  4642. hr = pStream->Read(&(desc.ftDate), sizeof(FILETIME), &cbRead);
  4643. if(SUCCEEDED(hr) && cbRead == sizeof(FILETIME))
  4644. {
  4645. desc.dwValidData |= DMUS_OBJ_DATE;
  4646. }
  4647. else if(SUCCEEDED(hr))
  4648. {
  4649. hr = E_FAIL;
  4650. }
  4651. break;
  4652. case DMUS_FOURCC_NAME_CHUNK:
  4653. dwSize = min(sizeof(desc.wszName), ckNext.cksize);
  4654. hr = pStream->Read(desc.wszName, dwSize, &cbRead);
  4655. if(SUCCEEDED(hr) && cbRead == dwSize)
  4656. {
  4657. desc.wszName[DMUS_MAX_NAME - 1] = L'\0';
  4658. desc.dwValidData |= DMUS_OBJ_NAME;
  4659. }
  4660. else if(SUCCEEDED(hr))
  4661. {
  4662. hr = E_FAIL;
  4663. }
  4664. break;
  4665. case DMUS_FOURCC_FILE_CHUNK:
  4666. dwSize = min(sizeof(desc.wszFileName), ckNext.cksize);
  4667. hr = pStream->Read(desc.wszFileName, dwSize, &cbRead);
  4668. if(SUCCEEDED(hr) && cbRead == dwSize)
  4669. {
  4670. desc.wszFileName[DMUS_MAX_FILENAME - 1] = L'\0';
  4671. desc.dwValidData |= DMUS_OBJ_FILENAME;
  4672. }
  4673. else if(SUCCEEDED(hr))
  4674. {
  4675. hr = E_FAIL;
  4676. }
  4677. break;
  4678. case DMUS_FOURCC_CATEGORY_CHUNK:
  4679. dwSize = min(sizeof(desc.wszCategory), ckNext.cksize);
  4680. hr = pStream->Read(desc.wszCategory, dwSize, &cbRead);
  4681. if(SUCCEEDED(hr) && cbRead == dwSize)
  4682. {
  4683. desc.wszCategory[DMUS_MAX_CATEGORY - 1] = L'\0';
  4684. desc.dwValidData |= DMUS_OBJ_CATEGORY;
  4685. }
  4686. else if(SUCCEEDED(hr))
  4687. {
  4688. hr = E_FAIL;
  4689. }
  4690. break;
  4691. case DMUS_FOURCC_VERSION_CHUNK:
  4692. DMUS_IO_VERSION ioDMObjVer;
  4693. hr = pStream->Read(&ioDMObjVer, sizeof(DMUS_IO_VERSION), &cbRead);
  4694. if(SUCCEEDED(hr) && cbRead == sizeof(DMUS_IO_VERSION))
  4695. {
  4696. desc.vVersion.dwVersionMS = ioDMObjVer.dwVersionMS;
  4697. desc.vVersion.dwVersionLS = ioDMObjVer.dwVersionLS;
  4698. desc.dwValidData |= DMUS_OBJ_VERSION;
  4699. }
  4700. else if(SUCCEEDED(hr))
  4701. {
  4702. hr = E_FAIL;
  4703. }
  4704. break;
  4705. default:
  4706. break;
  4707. }
  4708. if(SUCCEEDED(hr) && pIRiffStream->Ascend(&ckNext, 0) == 0)
  4709. {
  4710. ckNext.ckid = 0;
  4711. ckNext.fccType = 0;
  4712. }
  4713. else if (SUCCEEDED(hr)) hr = E_FAIL;
  4714. }
  4715. if (!(desc.dwValidData & DMUS_OBJ_NAME) )
  4716. {
  4717. hr = E_FAIL;
  4718. }
  4719. if(SUCCEEDED(hr))
  4720. {
  4721. desc.dwSize = sizeof(DMUS_OBJECTDESC);
  4722. hr = pLoader->GetObject(&desc,IID_IDirectMusicChordMap, (void**)&pChordMap);
  4723. if (SUCCEEDED(hr))
  4724. {
  4725. hr = IncorporatePersonality(pChordMap, desc.wszName, fDefault);
  4726. }
  4727. }
  4728. if (pLoader)
  4729. {
  4730. pLoader->Release();
  4731. }
  4732. return hr;
  4733. }
  4734. HRESULT CDMStyle::IMA25_LoadStyle( IAARIFFStream* pRIFF, MMCKINFO* pckMain )
  4735. {
  4736. HRESULT hr = S_OK;
  4737. HRESULT hrBand = S_OK;
  4738. MMCKINFO ck;
  4739. DWORD cb;
  4740. DWORD cSize;
  4741. LPSTREAM pStream;
  4742. ioStyle iStyle; // in iostructs.h
  4743. BOOL fReadStyle = FALSE;
  4744. pStream = pRIFF->GetStream();
  4745. while( pRIFF->Descend( &ck, pckMain, 0 ) == 0 )
  4746. {
  4747. switch( ck.ckid )
  4748. {
  4749. case FOURCC_STYLE:
  4750. fReadStyle = TRUE;
  4751. cSize = min( ck.cksize, sizeof( iStyle ) );
  4752. hr = pStream->Read( &iStyle, cSize, &cb );
  4753. FixBytes( FBT_IOSTYLE, &iStyle );
  4754. if( FAILED( hr ) || cb != cSize )
  4755. {
  4756. hr = E_FAIL;
  4757. goto ON_ERR;
  4758. }
  4759. m_StyleInfo.m_dwVersionMS = m_StyleInfo.m_dwVersionLS = 0; // no version info in IMA 2.5
  4760. m_StyleInfo.m_strName = iStyle.wstrName;
  4761. m_StyleInfo.m_TimeSignature.m_bBeatsPerMeasure = (BYTE) iStyle.wBPM;
  4762. m_StyleInfo.m_TimeSignature.m_bBeat = (BYTE) iStyle.wBeat;
  4763. m_StyleInfo.m_TimeSignature.m_wGridsPerBeat = iStyle.wClocksPerBeat / iStyle.wClocksPerClick;
  4764. m_StyleInfo.m_dblTempo = iStyle.wTempo;
  4765. m_StyleInfo.m_strCategory = iStyle.wstrCategory;
  4766. memcpy( &m_StyleInfo.m_guid, &iStyle.guid, sizeof( m_StyleInfo.m_guid ) );
  4767. break;
  4768. // find ChordMap reference
  4769. case FOURCC_PERSONALITYREF:
  4770. hr = IMA25_LoadPersonalityReference( pStream, &ck );
  4771. if( FAILED( hr ) )
  4772. {
  4773. goto ON_ERR;
  4774. }
  4775. break;
  4776. case FOURCC_RIFF:
  4777. switch( ck.fccType )
  4778. {
  4779. case FOURCC_BAND_FORM:
  4780. {
  4781. TListItem<IDirectMusicBand*>* pBandListItem = new TListItem<IDirectMusicBand*>;
  4782. if(pBandListItem)
  4783. {
  4784. pBandListItem->GetItemValue() = NULL;
  4785. // Create a band
  4786. hr = CoCreateInstance(CLSID_DirectMusicBand,
  4787. NULL,
  4788. CLSCTX_INPROC,
  4789. IID_IDirectMusicBand,
  4790. (void**)&(pBandListItem->GetItemValue()));
  4791. }
  4792. else
  4793. {
  4794. hr = E_OUTOFMEMORY;
  4795. }
  4796. if(SUCCEEDED(hr))
  4797. {
  4798. // Seek back to begining of Riff chunk
  4799. // This is the amount read by Descend when descending into a FOURCC_RIFF chunk
  4800. // Get current position
  4801. LARGE_INTEGER li;
  4802. ULARGE_INTEGER ul;
  4803. li.HighPart = 0;
  4804. li.LowPart = 0;
  4805. hr = pStream->Seek(li,
  4806. STREAM_SEEK_CUR,
  4807. &ul);
  4808. if(SUCCEEDED(hr))
  4809. {
  4810. li.HighPart = 0;
  4811. // This is always a valid operation
  4812. li.LowPart = ul.LowPart - (2 * sizeof(FOURCC) + sizeof(DWORD));
  4813. hr = pStream->Seek(li,
  4814. STREAM_SEEK_SET,
  4815. &ul);
  4816. }
  4817. }
  4818. if(SUCCEEDED(hr))
  4819. {
  4820. // Load band
  4821. IPersistStream* pIPersistStream;
  4822. hr = (pBandListItem->GetItemValue())->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
  4823. if(SUCCEEDED(hr))
  4824. {
  4825. hr = pIPersistStream->Load(pStream);
  4826. if (hr != S_OK)
  4827. {
  4828. hrBand = hr;
  4829. }
  4830. pIPersistStream->Release();
  4831. DWORD dwFlags = 0;
  4832. IDirectMusicBandPrivate *pIDMBandP = NULL;
  4833. hr = (pBandListItem->GetItemValue())->QueryInterface(IID_IDirectMusicBandPrivate, (void **)&pIDMBandP);
  4834. if(SUCCEEDED(hr))
  4835. {
  4836. hr = pIDMBandP->GetFlags(&dwFlags);
  4837. if(SUCCEEDED(hr))
  4838. {
  4839. if(dwFlags & DMUSB_DEFAULT)
  4840. {
  4841. // We have a default band
  4842. m_StyleInfo.m_pDefaultBand = pBandListItem->GetItemValue();
  4843. }
  4844. }
  4845. pIDMBandP->Release();
  4846. }
  4847. }
  4848. }
  4849. if(FAILED(hr))
  4850. {
  4851. if(pBandListItem)
  4852. {
  4853. IDirectMusicBand* pBand = pBandListItem->GetItemValue();
  4854. if(pBand)
  4855. {
  4856. pBand->Release();
  4857. }
  4858. delete pBandListItem;
  4859. }
  4860. goto ON_ERR;
  4861. }
  4862. EnterCriticalSection(&m_CriticalSection);
  4863. (m_StyleInfo.m_BandList).AddHead(pBandListItem);
  4864. LeaveCriticalSection(&m_CriticalSection);
  4865. }
  4866. break;
  4867. // find first pattern
  4868. case FOURCC_PATTERN_FORM:
  4869. if( fReadStyle )
  4870. {
  4871. TListItem<CDirectMusicPattern*>* pOldPattern = new TListItem<CDirectMusicPattern*>;
  4872. if( pOldPattern == NULL )
  4873. {
  4874. hr = E_OUTOFMEMORY;
  4875. goto ON_ERR;
  4876. }
  4877. CDirectMusicPattern*& rpOldPattern = pOldPattern->GetItemValue();
  4878. rpOldPattern = new CDirectMusicPattern;
  4879. if( rpOldPattern == NULL )
  4880. {
  4881. hr = E_OUTOFMEMORY;
  4882. goto ON_ERR;
  4883. }
  4884. hr = rpOldPattern->LoadPattern( pRIFF, &ck, m_StyleInfo.m_PartList, m_StyleInfo);
  4885. if( FAILED( hr ) )
  4886. {
  4887. hr = E_FAIL;
  4888. goto ON_ERR;
  4889. }
  4890. if( ( rpOldPattern->m_wEmbellishment & EMB_MOTIF ) != 0 )
  4891. {
  4892. EnterCriticalSection( &m_CriticalSection );
  4893. m_StyleInfo.m_MotifList.AddTail(pOldPattern);
  4894. LeaveCriticalSection( &m_CriticalSection );
  4895. }
  4896. else
  4897. {
  4898. EnterCriticalSection( &m_CriticalSection );
  4899. m_StyleInfo.m_PatternList.AddTail(pOldPattern);
  4900. LeaveCriticalSection( &m_CriticalSection );
  4901. }
  4902. }
  4903. break;
  4904. }
  4905. break;
  4906. }
  4907. pRIFF->Ascend( &ck, 0 );
  4908. }
  4909. ON_ERR:
  4910. pStream->Release();
  4911. // sort here
  4912. TListItem<DirectMusicPart*>* pPartItem = m_StyleInfo.m_PartList.GetHead();
  4913. for ( ; pPartItem; pPartItem = pPartItem->GetNext() )
  4914. {
  4915. pPartItem->GetItemValue()->EventList.MergeSort(m_StyleInfo.m_TimeSignature);
  4916. }
  4917. if (hr == S_OK && hrBand != S_OK)
  4918. {
  4919. hr = hrBand;
  4920. }
  4921. return hr;
  4922. }
  4923. /////////////////////////////////////////////////////////////////////////////
  4924. // DMStyleStruct::FindPartByGUID
  4925. DirectMusicPart* DMStyleStruct::FindPartByGUID( GUID guidPartID )
  4926. {
  4927. DirectMusicPart* pThePart = NULL;
  4928. DirectMusicPart* pPart;
  4929. TListItem<DirectMusicPart*>* pScan = m_PartList.GetHead();
  4930. for (; pScan; pScan = pScan->GetNext() )
  4931. {
  4932. pPart = pScan->GetItemValue();
  4933. if( ::IsEqualGUID( pPart->m_guidPartID, guidPartID ) )
  4934. {
  4935. pThePart = pPart;
  4936. break;
  4937. }
  4938. }
  4939. return pThePart;
  4940. }
  4941. /////////////////////////////////////////////////////////////////////////////
  4942. // DMStyleStruct::AllocPart
  4943. DirectMusicPart* DMStyleStruct::AllocPart( )
  4944. {
  4945. DirectMusicPart* pPart = new DirectMusicPart(&m_TimeSignature);
  4946. if (pPart)
  4947. {
  4948. TListItem<DirectMusicPart*>* pPartItem = new TListItem<DirectMusicPart*>(pPart);
  4949. if( pPartItem)
  4950. {
  4951. // Add Part to Style's list of Parts
  4952. m_PartList.AddTail( pPartItem );
  4953. }
  4954. else
  4955. {
  4956. delete pPart;
  4957. pPart = NULL;
  4958. }
  4959. }
  4960. return pPart;
  4961. }
  4962. /////////////////////////////////////////////////////////////////////////////
  4963. // DMStyleStruct::DeletePart
  4964. void DMStyleStruct::DeletePart( DirectMusicPart* pPart )
  4965. {
  4966. TListItem<DirectMusicPart*>* pPartItem = m_PartList.GetHead();
  4967. TListItem<DirectMusicPart*>* pPrevious = NULL;
  4968. for ( ; pPartItem; pPartItem = pPartItem->GetNext() )
  4969. {
  4970. DirectMusicPart* pScan = pPartItem->GetItemValue();
  4971. if (pPart == pScan)
  4972. {
  4973. pScan->Release();
  4974. if (pPrevious)
  4975. {
  4976. pPrevious->SetNext(pPartItem->GetNext());
  4977. }
  4978. else
  4979. {
  4980. m_PartList.RemoveHead();
  4981. }
  4982. pPartItem->SetNext(NULL);
  4983. delete pPartItem;
  4984. break;
  4985. }
  4986. pPrevious = pPartItem;
  4987. }
  4988. }
  4989. HRESULT DMStyleStruct::GetCommand(
  4990. MUSIC_TIME mtTime,
  4991. MUSIC_TIME mtOffset,
  4992. IDirectMusicPerformance* pPerformance,
  4993. IDirectMusicSegment* pSegment,
  4994. DWORD dwGroupID,
  4995. DMUS_COMMAND_PARAM_2* pCommand,
  4996. BYTE& rbActualCommand)
  4997. {
  4998. HRESULT hr = S_OK;
  4999. if (!pPerformance && !pSegment) return E_INVALIDARG;
  5000. if (pPerformance)
  5001. {
  5002. hr = pPerformance->GetParam(GUID_CommandParam2, dwGroupID, DMUS_SEG_ANYTRACK, mtTime + mtOffset,
  5003. NULL, ((void*) pCommand));
  5004. }
  5005. else
  5006. {
  5007. hr = pSegment->GetParam(GUID_CommandParam2, dwGroupID, DMUS_SEG_ANYTRACK, mtTime,
  5008. NULL, ((void*) pCommand));
  5009. }
  5010. if (FAILED(hr)) return hr;
  5011. // Look at the command's mtTime to see how far in the past it occurred. If a measure
  5012. // or more, keep the groove level but make the command a regular groove.
  5013. MUSIC_TIME mtMeasureTime = (MUSIC_TIME) m_TimeSignature.ClocksPerMeasure();
  5014. //TraceI(0, "Now: %d Offset: %d Command: %x, Groove Level: %d, Command time: %d Measure time: %d\n",
  5015. // mtTime, mtOffset, pCommand->bCommand, pCommand->bGrooveLevel, pCommand->mtTime, mtMeasureTime);
  5016. rbActualCommand = pCommand->bCommand;
  5017. if (pCommand->mtTime + mtMeasureTime <= 0 ||
  5018. (pCommand->mtTime + mtMeasureTime < mtMeasureTime &&
  5019. (mtMeasureTime + pCommand->mtTime) % mtMeasureTime) )
  5020. {
  5021. pCommand->bCommand = DMUS_COMMANDT_GROOVE;
  5022. }
  5023. return hr;
  5024. }
  5025. struct TaggedCommands
  5026. {
  5027. TaggedCommands()
  5028. {
  5029. m_pCommands = NULL;
  5030. m_pRhythms = NULL;
  5031. m_mtTag = 0;
  5032. }
  5033. HRESULT Init(MUSIC_TIME mtTag, int nSize, int nGlobalGroove)
  5034. {
  5035. HRESULT hr = S_OK;
  5036. m_mtTag = mtTag;
  5037. m_pCommands = new DMUS_COMMAND_PARAM_2 [nSize];
  5038. m_pRhythms = new DWORD [nSize];
  5039. if (!m_pCommands || !m_pRhythms)
  5040. {
  5041. Cleanup();
  5042. hr = E_OUTOFMEMORY;
  5043. }
  5044. else
  5045. {
  5046. int nGroove = 62 + nGlobalGroove;
  5047. if (nGroove > 100) nGroove = 100;
  5048. if (nGroove < 1) nGroove = 1;
  5049. m_pCommands[0].bGrooveLevel = (BYTE)nGroove;
  5050. m_pCommands[0].bGrooveLevel = 62;
  5051. m_pCommands[0].bGrooveRange = 0;
  5052. m_pCommands[0].bCommand = DMUS_COMMANDT_GROOVE;
  5053. m_pCommands[0].bRepeatMode = DMUS_PATTERNT_RANDOM;
  5054. m_pRhythms[0] = 0;
  5055. }
  5056. return hr;
  5057. }
  5058. void Cleanup()
  5059. {
  5060. if (m_pCommands) delete [] m_pCommands;
  5061. if (m_pRhythms) delete [] m_pRhythms;
  5062. }
  5063. ~TaggedCommands()
  5064. {
  5065. Cleanup();
  5066. }
  5067. MUSIC_TIME m_mtTag;
  5068. DMUS_COMMAND_PARAM_2* m_pCommands;
  5069. DWORD* m_pRhythms;
  5070. };
  5071. TListItem<TaggedCommands>* FindTaggedCommands(MUSIC_TIME mtTag, TList<TaggedCommands>& rCommands)
  5072. {
  5073. TListItem<TaggedCommands>* pScan = rCommands.GetHead();
  5074. for(; pScan; pScan = pScan->GetNext())
  5075. {
  5076. if (pScan->GetItemValue().m_mtTag == mtTag) return pScan;
  5077. }
  5078. return NULL;
  5079. }
  5080. CDirectMusicPattern* DMStyleStruct::SelectPattern(bool fNewMode,
  5081. DMUS_COMMAND_PARAM_2* pCommands,
  5082. StyleTrackState* StyleTrackState,
  5083. PatternDispatcher& rDispatcher)
  5084. {
  5085. if (rDispatcher.IsEmpty()) return NULL;
  5086. if (!UsingDX8() || !StyleTrackState)
  5087. {
  5088. return rDispatcher.RandomSelect();
  5089. }
  5090. CDirectMusicPattern* pResult = NULL;
  5091. TListItem<CDirectMusicPattern*>* pNew = NULL;
  5092. TListItem<CDirectMusicPattern*>* pScan = NULL;
  5093. int nIndex = 0;
  5094. if (pCommands)
  5095. {
  5096. switch (pCommands[0].bRepeatMode)
  5097. {
  5098. case DMUS_PATTERNT_RANDOM:
  5099. pResult = rDispatcher.RandomSelect();
  5100. break;
  5101. case DMUS_PATTERNT_REPEAT:
  5102. pResult = (!fNewMode && S_OK == rDispatcher.FindPattern(StyleTrackState->m_pPattern, nIndex))
  5103. ? StyleTrackState->m_pPattern : rDispatcher.RandomSelect();
  5104. break;
  5105. case DMUS_PATTERNT_SEQUENTIAL:
  5106. case DMUS_PATTERNT_RANDOM_START:
  5107. if (fNewMode)
  5108. {
  5109. if (pCommands[0].bRepeatMode == DMUS_PATTERNT_SEQUENTIAL)
  5110. {
  5111. pResult = rDispatcher.GetItem(0);
  5112. }
  5113. else
  5114. {
  5115. pResult = rDispatcher.RandomSelect();
  5116. }
  5117. }
  5118. else
  5119. {
  5120. HRESULT hr = rDispatcher.FindPattern(StyleTrackState->m_pPattern, nIndex);
  5121. if (hr == S_OK && rDispatcher.GetItem(nIndex + 1))
  5122. {
  5123. pResult = rDispatcher.GetItem(nIndex + 1);
  5124. }
  5125. else
  5126. {
  5127. pResult = rDispatcher.GetItem(0);
  5128. }
  5129. }
  5130. break;
  5131. case DMUS_PATTERNT_NO_REPEAT:
  5132. if (!fNewMode)
  5133. {
  5134. HRESULT hr = rDispatcher.FindPattern(StyleTrackState->m_pPattern, nIndex);
  5135. if (hr == S_OK)
  5136. {
  5137. rDispatcher.SetTag(nIndex, REMOVED);
  5138. }
  5139. }
  5140. pResult = rDispatcher.RandomSelect();
  5141. break;
  5142. case DMUS_PATTERNT_RANDOM_ROW:
  5143. if (fNewMode)
  5144. {
  5145. StyleTrackState->m_PlayedPatterns.CleanUp();
  5146. }
  5147. pScan = StyleTrackState->m_PlayedPatterns.GetHead();
  5148. for (; pScan; pScan = pScan->GetNext())
  5149. {
  5150. HRESULT hr = rDispatcher.FindPattern(pScan->GetItemValue(), nIndex);
  5151. if (hr == S_OK)
  5152. {
  5153. rDispatcher.SetTag(nIndex, RANDOM_ROW);
  5154. }
  5155. }
  5156. if (rDispatcher.IsEmpty()) // start over, but avoid the one just played
  5157. {
  5158. rDispatcher.RestorePatterns(RANDOM_ROW);
  5159. pScan = StyleTrackState->m_PlayedPatterns.GetHead();
  5160. if (pScan)
  5161. {
  5162. HRESULT hr = rDispatcher.FindPattern(pScan->GetItemValue(), nIndex);
  5163. if (hr == S_OK)
  5164. {
  5165. rDispatcher.SetTag(nIndex, RANDOM_ROW);
  5166. }
  5167. }
  5168. StyleTrackState->m_PlayedPatterns.CleanUp();
  5169. }
  5170. pResult = rDispatcher.RandomSelect();
  5171. if (pResult)
  5172. {
  5173. pNew = new TListItem<CDirectMusicPattern*>(pResult);
  5174. if (pNew)
  5175. {
  5176. StyleTrackState->m_PlayedPatterns.AddHead(pNew);
  5177. }
  5178. }
  5179. break;
  5180. default:
  5181. pResult = rDispatcher.RandomSelect();
  5182. break;
  5183. }
  5184. }
  5185. return pResult;
  5186. }
  5187. HRESULT DMStyleStruct::GetPattern(
  5188. bool fNewMode,
  5189. MUSIC_TIME mtNow,
  5190. MUSIC_TIME mtOffset,
  5191. StyleTrackState* pStyleTrackState,
  5192. IDirectMusicPerformance* pPerformance,
  5193. IDirectMusicSegment* pSegment,
  5194. CDirectMusicPattern*& rpTargetPattern,
  5195. MUSIC_TIME& rmtMeasureTime,
  5196. MUSIC_TIME& rmtNextCommand)
  5197. {
  5198. if (!pSegment && !pPerformance) return E_INVALIDARG;
  5199. static aMatchType[5] =
  5200. {MATCH_COMMAND_AND_RHYTHM, MATCH_COMMAND_FULL, MATCH_COMMAND_PARTIAL, MATCH_EMBELLISHMENT, MATCH_GROOVE_LEVEL};
  5201. HRESULT hr = S_OK;
  5202. MUSIC_TIME mtNextStyleTime = pStyleTrackState ? pStyleTrackState->m_mtNextStyleTime : 0;
  5203. DMUS_RHYTHM_PARAM ChordRhythm;
  5204. TList<TaggedCommands> Commands;
  5205. int nLongestPattern = 0;
  5206. int nPatternLength = 1;
  5207. DWORD dwGroupID = pStyleTrackState ? pStyleTrackState->m_dwGroupID : 0xffffffff;
  5208. TListItem<CDirectMusicPattern*> *pPatternItem = m_PatternList.GetHead();
  5209. for (; pPatternItem != NULL; pPatternItem = pPatternItem->GetNext())
  5210. {
  5211. CDirectMusicPattern*& rpPattern = pPatternItem->GetItemValue();
  5212. if (rpPattern->m_wNumMeasures > nLongestPattern)
  5213. nLongestPattern = rpPattern->m_wNumMeasures;
  5214. }
  5215. if (nLongestPattern <= 0) return E_POINTER;
  5216. char chGroove;
  5217. if (!pPerformance ||
  5218. !SUCCEEDED(pPerformance->GetGlobalParam((GUID)GUID_PerfMasterGrooveLevel, &chGroove, 1)))
  5219. {
  5220. chGroove = 0;
  5221. }
  5222. DMUS_COMMAND_PARAM_2 CommandParam;
  5223. // this call to GetParam is for rmtNextCommand only (?)
  5224. HRESULT hrCommand = E_FAIL;
  5225. if (pPerformance)
  5226. {
  5227. hrCommand = pPerformance->GetParam(GUID_CommandParam2, dwGroupID, DMUS_SEG_ANYTRACK, mtNow + mtOffset,
  5228. &rmtNextCommand, ((void*) &CommandParam));
  5229. }
  5230. else
  5231. {
  5232. hrCommand = pSegment->GetParam(GUID_CommandParam2, dwGroupID, DMUS_SEG_ANYTRACK, mtNow,
  5233. &rmtNextCommand, ((void*) &CommandParam));
  5234. }
  5235. if (DMUS_E_TRACK_NOT_FOUND == hrCommand || rmtNextCommand <= 0) // Happens if the performance can't find a segment with a command track
  5236. {
  5237. if (mtNextStyleTime) rmtNextCommand = mtNextStyleTime;
  5238. else if (pStyleTrackState && pStyleTrackState->m_pSegState)
  5239. {
  5240. MUSIC_TIME mtLength = 0;
  5241. IDirectMusicSegment* pTmpSegment = NULL;
  5242. if (SUCCEEDED(pStyleTrackState->m_pSegState->GetSegment(&pTmpSegment)))
  5243. {
  5244. hr = pTmpSegment->GetLength(&mtLength);
  5245. pTmpSegment->Release();
  5246. // GetLength may return DMUS_S_GARBAGE_COLLECTED which FAILED will not catch
  5247. if(hr != S_OK)
  5248. {
  5249. mtLength = 0x7FFFFFFF;
  5250. }
  5251. }
  5252. rmtNextCommand = mtLength - mtNow;
  5253. }
  5254. else rmtNextCommand = 0;
  5255. }
  5256. MUSIC_TIME mtStyleDifference = mtNextStyleTime ? mtNextStyleTime - mtNow : 0;
  5257. if ( mtStyleDifference > 0 && (!rmtNextCommand || mtStyleDifference < rmtNextCommand) )
  5258. {
  5259. rmtNextCommand = mtStyleDifference;
  5260. }
  5261. if (pStyleTrackState)
  5262. {
  5263. if (FAILED(hrCommand) || pStyleTrackState->m_CommandData.bRepeatMode != CommandParam.bRepeatMode)
  5264. {
  5265. fNewMode = true;
  5266. }
  5267. pStyleTrackState->m_CommandData = CommandParam;
  5268. pStyleTrackState->m_CommandData.bGrooveLevel += chGroove;
  5269. }
  5270. TListItem<TaggedCommands>* pTaggedCommands = NULL;
  5271. PatternDispatcher Dispatcher(m_PatternList, rmtNextCommand, mtNow, mtOffset, pStyleTrackState, pPerformance, this);
  5272. // find a pattern matching the chord rhythm and command
  5273. for (int nMatch = 0; nMatch < 5; nMatch++, Dispatcher.RestoreAllPatterns())
  5274. {
  5275. if (nMatch > 2 && !UsingDX8()) break; // only do these for dx8
  5276. // while more pattern lengths:
  5277. do
  5278. {
  5279. // divide current list into those with the longest patterns and eveything else
  5280. Dispatcher.ResetMeasures();
  5281. Dispatcher.Scan(FIND_LONGEST_PATTERN);
  5282. Dispatcher.Filter(COLLECT_LONGEST_PATTERN);
  5283. // while more time signatures:
  5284. do
  5285. {
  5286. int nLength = 0;
  5287. DirectMusicTimeSig TimeSig;
  5288. // divide list into those with "longest" time sigs and everything else
  5289. Dispatcher.ResetTimeSig();
  5290. Dispatcher.Scan(FIND_LONGEST_TIMESIG);
  5291. Dispatcher.Filter(COLLECT_LONGEST_TIMESIG);
  5292. // fill up pCommands and pRhythms (also get mtMeasureTime, based on time sig)
  5293. CDirectMusicPattern* pFirstPattern = Dispatcher.GetItem(0);
  5294. MUSIC_TIME mtMeasureTime = 0;
  5295. if (pFirstPattern)
  5296. {
  5297. TimeSig = pFirstPattern->TimeSignature(this);
  5298. nLength = pFirstPattern->m_wNumMeasures;
  5299. }
  5300. else
  5301. {
  5302. TimeSig = m_TimeSignature;
  5303. }
  5304. mtMeasureTime = TimeSig.ClocksPerMeasure();
  5305. Dispatcher.SetMeasureTime(mtMeasureTime);
  5306. IDirectMusicStyle* pThisStyle = NULL;
  5307. MUSIC_TIME mtNextStyle = 0;
  5308. if (SUCCEEDED(pPerformance->GetParam(GUID_IDirectMusicStyle, dwGroupID, DMUS_SEG_ANYTRACK, mtNow + mtOffset,
  5309. &mtNextStyle, (void*) &pThisStyle)))
  5310. {
  5311. if (mtNextStyle && mtMeasureTime)
  5312. {
  5313. nPatternLength = (mtNextStyle / mtMeasureTime);
  5314. if (!nPatternLength) nPatternLength = 1;
  5315. }
  5316. if (nPatternLength > nLongestPattern) nPatternLength = nLongestPattern;
  5317. pThisStyle->Release();
  5318. }
  5319. Dispatcher.SetPatternLength(nPatternLength);
  5320. pTaggedCommands = FindTaggedCommands(mtMeasureTime, Commands);
  5321. if (!pTaggedCommands)
  5322. {
  5323. pTaggedCommands = new TListItem<TaggedCommands>;
  5324. if (!pTaggedCommands) return E_OUTOFMEMORY;
  5325. TaggedCommands& rCommands = pTaggedCommands->GetItemValue();
  5326. hr = rCommands.Init(mtMeasureTime, nPatternLength, chGroove);
  5327. if (FAILED(hr)) return hr;
  5328. Commands.AddHead(pTaggedCommands);
  5329. if (SUCCEEDED(hrCommand))
  5330. {
  5331. HRESULT hrChord = S_OK;
  5332. // get chord rhythm for next measure(s)
  5333. // get command for next measure(s)
  5334. ChordRhythm.TimeSig = TimeSig;
  5335. for (short i = 0; i < nPatternLength; i++)
  5336. {
  5337. BYTE bActualCommand;
  5338. if (S_OK != GetCommand(mtNow + (i * mtMeasureTime),
  5339. mtOffset, pPerformance, pSegment, dwGroupID, &CommandParam,
  5340. bActualCommand))
  5341. {
  5342. break;
  5343. }
  5344. rCommands.m_pCommands[i] = CommandParam;
  5345. short nGroove = CommandParam.bGrooveLevel + chGroove;
  5346. if (nGroove > 100) nGroove = 100;
  5347. if (nGroove < 1) nGroove = 1;
  5348. rCommands.m_pCommands[i].bGrooveLevel = (BYTE)nGroove;
  5349. if (pPerformance)
  5350. {
  5351. hrChord = pPerformance->GetParam(GUID_RhythmParam, dwGroupID, DMUS_SEG_ANYTRACK, (mtNow + (i * mtMeasureTime) + mtOffset),
  5352. NULL, (void*) &ChordRhythm);
  5353. }
  5354. else
  5355. {
  5356. hrChord = pSegment->GetParam(GUID_RhythmParam, dwGroupID, DMUS_SEG_ANYTRACK, (mtNow + (i * mtMeasureTime)),
  5357. NULL, (void*) &ChordRhythm);
  5358. }
  5359. if (SUCCEEDED(hrChord))
  5360. {
  5361. rCommands.m_pRhythms[i] = ChordRhythm.dwRhythmPattern;
  5362. }
  5363. else
  5364. {
  5365. rCommands.m_pRhythms[i] = 0;
  5366. }
  5367. TraceI(3, "NOW: %d, i: %d, Groove level: %d, command: %d, rhythm: %x\n",
  5368. mtNow + (i * mtMeasureTime), i, rCommands.m_pCommands[i].bGrooveLevel,
  5369. rCommands.m_pCommands[i].bCommand, rCommands.m_pRhythms[i]);
  5370. }
  5371. }
  5372. }
  5373. TaggedCommands& rCommands = pTaggedCommands->GetItemValue();
  5374. Dispatcher.SetCommands(rCommands.m_pCommands, rCommands.m_pRhythms);
  5375. // filter best matches, using aMatchType[nMatch]
  5376. // (MATCH_COMMAND_AND_RHYTHM also needs to filter with MATCH_RHYTHM_BITS)
  5377. // break on match
  5378. if (aMatchType[nMatch] == MATCH_COMMAND_AND_RHYTHM)
  5379. {
  5380. Dispatcher.ResetRhythms();
  5381. }
  5382. Dispatcher.Filter(aMatchType[nMatch]);
  5383. if (!Dispatcher.IsEmpty())
  5384. {
  5385. if (aMatchType[nMatch] == MATCH_COMMAND_AND_RHYTHM)
  5386. {
  5387. Dispatcher.Filter(MATCH_RHYTHM_BITS);
  5388. if (!Dispatcher.IsEmpty()) break;
  5389. Dispatcher.RestorePatterns(MATCH_RHYTHM_BITS);
  5390. }
  5391. else break;
  5392. }
  5393. Dispatcher.ReplacePatterns(COLLECT_LONGEST_TIMESIG, REMOVED);
  5394. TraceI(2, "Failed Match: %d (%d, %d/%d)\n",
  5395. nMatch, nLength, TimeSig.m_bBeatsPerMeasure, TimeSig.m_bBeat);
  5396. } while (!Dispatcher.IsEmpty());
  5397. if (!Dispatcher.IsEmpty()) break;
  5398. Dispatcher.ReplacePatterns(COLLECT_LONGEST_PATTERN, REMOVED);
  5399. } while (!Dispatcher.IsEmpty());
  5400. if (!Dispatcher.IsEmpty()) break;
  5401. }
  5402. if (!Dispatcher.IsEmpty())
  5403. {
  5404. //TraceI(2, "Filtering Destinations...\n");
  5405. Dispatcher.Filter(MATCH_NEXT_COMMAND);
  5406. if (Dispatcher.IsEmpty())
  5407. {
  5408. Dispatcher.RestorePatterns(MATCH_NEXT_COMMAND);
  5409. }
  5410. rpTargetPattern = SelectPattern(fNewMode, pTaggedCommands->GetItemValue().m_pCommands, pStyleTrackState, Dispatcher);
  5411. }
  5412. // if all searches failed, select the first pattern
  5413. if (!rpTargetPattern)
  5414. {
  5415. TraceI(1, "ALL SEARCHES FAILED\n");
  5416. TListItem<CDirectMusicPattern*> *pPattern = m_PatternList.GetHead();
  5417. if (pPattern) // if this is NULL, something's wrong
  5418. {
  5419. rpTargetPattern = pPattern->GetItemValue();
  5420. }
  5421. }
  5422. if (rpTargetPattern) // if pTargetPattern is NULL, something's really wrong
  5423. {
  5424. rmtMeasureTime = rpTargetPattern->TimeSignature(this).ClocksPerMeasure();
  5425. if (pStyleTrackState)
  5426. {
  5427. hr = pStyleTrackState->InitPattern(rpTargetPattern, mtNow);
  5428. }
  5429. TraceI(2, "Pattern: %S (%d, %d/%d) [%d]\n",
  5430. //TraceI(0, "Pattern: %S (%d, %d/%d) [%d]\n",
  5431. (const WCHAR *)rpTargetPattern->m_strName, rpTargetPattern->m_wNumMeasures,
  5432. rpTargetPattern->TimeSignature(this).m_bBeatsPerMeasure,
  5433. rpTargetPattern->TimeSignature(this).m_bBeat, mtNow);
  5434. }
  5435. else hr = E_POINTER;
  5436. return hr;
  5437. }
  5438. /////////////////////////////////////////////////////////////////////////////
  5439. // AdjoinPChannel
  5440. HRESULT AdjoinPChannel(TList<DWORD>& rPChannelList, DWORD dwPChannel)
  5441. {
  5442. TListItem<DWORD>* pScan = rPChannelList.GetHead();
  5443. for (; pScan; pScan = pScan->GetNext() )
  5444. {
  5445. DWORD rdwPChannel = pScan->GetItemValue();
  5446. if( dwPChannel == rdwPChannel )
  5447. {
  5448. return S_OK;
  5449. }
  5450. }
  5451. TListItem<DWORD>* pNew = new TListItem<DWORD>(dwPChannel);
  5452. if (!pNew) return E_OUTOFMEMORY;
  5453. rPChannelList.AddHead(pNew);
  5454. return S_OK;
  5455. }
  5456. static inline BOOL InversionPoint(char chNote, DWORD dwInvertPattern)
  5457. {
  5458. if (chNote < 0 || chNote >= 24) return FALSE;
  5459. return (dwInvertPattern >> chNote) & 1;
  5460. }
  5461. static BYTE NotePosition(char chMidiValue, BYTE bRoot)
  5462. {
  5463. chMidiValue -= bRoot;
  5464. while (chMidiValue < 0) chMidiValue += 12;
  5465. while (chMidiValue > 23) chMidiValue -= 12;
  5466. return (BYTE)chMidiValue;
  5467. }
  5468. static char InversionAmountLow(
  5469. BYTE bMidiValue,
  5470. BYTE bLower,
  5471. DWORD dwInvertPattern,
  5472. BYTE bRoot)
  5473. {
  5474. char chResult = 0;
  5475. TraceI(3, "InversionAmountLow: MidiValue: %d, Lower: %d, Pattern: %X, Root: %d\n",
  5476. bMidiValue, bLower, dwInvertPattern, bRoot);
  5477. char chDifference = (char) (bLower - bMidiValue);
  5478. char chPosition = NotePosition(bMidiValue, bRoot);
  5479. while (chDifference > 23) chDifference -= 24;
  5480. TraceI(3, "Position: %d Difference: %d\n", chPosition, chDifference);
  5481. // Right now I'm checking both endpoints. Is this what I want?
  5482. for (char i = chPosition; chDifference >= 0; (i = (i < 23) ? i + 1 : 0), chDifference--)
  5483. {
  5484. if (InversionPoint(i, dwInvertPattern)) break;
  5485. }
  5486. if (chDifference >= 0)
  5487. {
  5488. while (bLower > bMidiValue + chResult)
  5489. {
  5490. chResult += 12;
  5491. }
  5492. }
  5493. TraceI(3, "Result: %d\n", chResult);
  5494. return chResult;
  5495. }
  5496. static char InversionAmountHigh(
  5497. BYTE bMidiValue,
  5498. BYTE bUpper,
  5499. DWORD dwInvertPattern,
  5500. BYTE bRoot)
  5501. {
  5502. char chResult = 0;
  5503. TraceI(3, "InversionAmountHigh: MidiValue: %d, Upper: %d, Pattern: %X, Root: %d\n",
  5504. bMidiValue, bUpper, dwInvertPattern, bRoot);
  5505. char chDifference = (char) (bMidiValue - bUpper);
  5506. char chPosition = NotePosition(bMidiValue, bRoot);
  5507. while (chDifference > 23) chDifference -= 24;
  5508. TraceI(3, "Position: %d Difference: %d\n", chPosition, chDifference);
  5509. // Right now I'm checking both endpoints. Is this what I want?
  5510. for (char i = chPosition; chDifference >= 0; (i = (i > 0) ? i - 1 : 23), chDifference--)
  5511. {
  5512. if (InversionPoint(i, dwInvertPattern)) break;
  5513. }
  5514. if (chDifference >= 0)
  5515. {
  5516. while ((char)bMidiValue + chResult > (char)bUpper)
  5517. {
  5518. chResult -= 12;
  5519. }
  5520. }
  5521. TraceI(3, "Result: %d\n", chResult);
  5522. return chResult;
  5523. }
  5524. static char InversionAmount(
  5525. BYTE bMidiValue,
  5526. BYTE bLower,
  5527. BYTE bUpper,
  5528. DWORD dwInvertPattern,
  5529. BYTE bRoot)
  5530. {
  5531. char chResult = 0;
  5532. if (bMidiValue <= 0 || bMidiValue > 127) return 0;
  5533. if (dwInvertPattern & 0xff000000)
  5534. {
  5535. while (bMidiValue + chResult < bLower) chResult += 12;
  5536. while (bMidiValue + chResult > bUpper) chResult -= 12;
  5537. return chResult;
  5538. }
  5539. TraceI(4, "InversionAmount: MidiValue: %d, Lower: %d, Upper: %d, Pattern: %X, Root: %d\n",
  5540. bMidiValue, bLower, bUpper, dwInvertPattern, bRoot);
  5541. if (bLower <= bMidiValue && bMidiValue <= bUpper) return 0;
  5542. if (bMidiValue < bLower)
  5543. {
  5544. chResult = InversionAmountLow(bMidiValue, bLower, dwInvertPattern, bRoot);
  5545. }
  5546. else
  5547. {
  5548. chResult = InversionAmountHigh(bMidiValue, bUpper, dwInvertPattern, bRoot);
  5549. }
  5550. return chResult;
  5551. }
  5552. HRESULT DirectMusicPartRef::ConvertMusicValue(CDMStyleNote* pNoteEvent,
  5553. DMUS_CHORD_PARAM& rCurrentChord,
  5554. BYTE bPlayModeFlags,
  5555. BOOL fPlayAsIs,
  5556. InversionGroup aInversionGroups[],
  5557. IDirectMusicPerformance* pPerformance,
  5558. BYTE& rbMidiValue,
  5559. short& rnMidiOffset)
  5560. {
  5561. bool fReleasePerformance = false;
  5562. if (!pPerformance)
  5563. {
  5564. fReleasePerformance = true;
  5565. if( FAILED( CoCreateInstance( CLSID_DirectMusicPerformance,
  5566. NULL, CLSCTX_INPROC, IID_IDirectMusicPerformance,
  5567. (void**)&pPerformance )))
  5568. {
  5569. return E_FAIL;
  5570. }
  5571. }
  5572. // music value is computed using the current chord info and the playmode flags
  5573. // musicvalue is a MIDI note value (0-127)
  5574. WORD wMV = pNoteEvent->m_wMusicValue;
  5575. short nMidiOffset = 0;
  5576. if (bPlayModeFlags != DMUS_PLAYMODE_FIXED)
  5577. {
  5578. DMSubChord rSubChord;
  5579. DWORD dwLevel = 1 << m_bSubChordLevel;
  5580. DWORD dwIndex;
  5581. for (dwIndex = 0; dwIndex < rCurrentChord.bSubChordCount; dwIndex++)
  5582. {
  5583. if (dwLevel & rCurrentChord.SubChordList[dwIndex].dwLevels)
  5584. {
  5585. rSubChord = rCurrentChord.SubChordList[dwIndex];
  5586. break;
  5587. }
  5588. }
  5589. if (dwIndex == rCurrentChord.bSubChordCount)
  5590. {
  5591. rSubChord = rCurrentChord.SubChordList[0];
  5592. dwIndex = 0;
  5593. }
  5594. DMUS_CHORD_KEY ChordAndKey;
  5595. ZeroMemory(&ChordAndKey, sizeof(DMUS_CHORD_KEY));
  5596. ChordAndKey.dwScale = rCurrentChord.dwScale;
  5597. ChordAndKey.bSubChordCount = rCurrentChord.bSubChordCount;
  5598. ChordAndKey.bKey = rCurrentChord.bKey;
  5599. ChordAndKey.bFlags = 0;
  5600. ChordAndKey.SubChordList[dwIndex].bChordRoot = rSubChord.m_bChordRoot;
  5601. ChordAndKey.SubChordList[dwIndex].bScaleRoot = rSubChord.m_bScaleRoot;
  5602. ChordAndKey.SubChordList[dwIndex].dwChordPattern = rSubChord.m_dwChordPattern;
  5603. ChordAndKey.SubChordList[dwIndex].dwLevels = rSubChord.m_dwLevels;
  5604. ChordAndKey.SubChordList[dwIndex].dwScalePattern = rSubChord.m_dwScalePattern;
  5605. BYTE bChordRoot = 0;
  5606. HRESULT hrChordRoot = pPerformance->MusicToMIDI(
  5607. (pNoteEvent->m_wMusicValue & 0xf000),
  5608. &ChordAndKey,
  5609. bPlayModeFlags,
  5610. m_bSubChordLevel,
  5611. &bChordRoot);
  5612. if (bPlayModeFlags == DMUS_PLAYMODE_CHORD_ROOT) // fixed to chord
  5613. {
  5614. wMV += (rSubChord.m_bChordRoot % 24);
  5615. }
  5616. else if (bPlayModeFlags == DMUS_PLAYMODE_SCALE_ROOT) // fixed to scale
  5617. {
  5618. wMV += rCurrentChord.bKey;
  5619. }
  5620. else
  5621. {
  5622. BYTE bMIDIVal;
  5623. HRESULT hrTest = pPerformance->MusicToMIDI(
  5624. pNoteEvent->m_wMusicValue,
  5625. &ChordAndKey,
  5626. bPlayModeFlags,
  5627. m_bSubChordLevel,
  5628. &bMIDIVal);
  5629. if (hrTest == S_OK)
  5630. {
  5631. wMV = bMIDIVal;
  5632. }
  5633. else
  5634. {
  5635. wMV = 0;
  5636. }
  5637. }
  5638. if (wMV && !fPlayAsIs )
  5639. {
  5640. if (pNoteEvent->m_bInversionId == 0)
  5641. {
  5642. nMidiOffset = InversionAmount((BYTE)wMV,
  5643. m_pDMPart->m_bInvertLower,
  5644. m_pDMPart->m_bInvertUpper,
  5645. rSubChord.m_dwInversionPoints,
  5646. bChordRoot);
  5647. }
  5648. else // handle inversion groups
  5649. {
  5650. short nIndex = FindGroup(aInversionGroups, pNoteEvent->m_bInversionId);
  5651. if (nIndex >= 0) // invert according to the existing group
  5652. {
  5653. nMidiOffset = aInversionGroups[nIndex].m_nOffset;
  5654. aInversionGroups[nIndex].m_wCount--;
  5655. if (aInversionGroups[nIndex].m_wCount == 0)
  5656. aInversionGroups[nIndex].m_wGroupID = 0;
  5657. }
  5658. else // create a new inversion group
  5659. {
  5660. // 1. find out how many events have this group id for a count
  5661. WORD wCount = 1; // for this event...
  5662. CDirectMusicEventItem* pScan = pNoteEvent->GetNext();
  5663. for (; pScan; pScan = pScan->GetNext())
  5664. {
  5665. if (pScan->m_dwEventTag == DMUS_EVENT_NOTE)
  5666. {
  5667. CDMStyleNote* pScanEvent = (CDMStyleNote*)pScan;
  5668. if (pScanEvent->m_bInversionId == pNoteEvent->m_bInversionId)
  5669. wCount++;
  5670. }
  5671. }
  5672. // 2. call InversionAmount for an offset
  5673. short nOffset = InversionAmount((BYTE)wMV,
  5674. m_pDMPart->m_bInvertLower,
  5675. m_pDMPart->m_bInvertUpper,
  5676. rSubChord.m_dwInversionPoints,
  5677. bChordRoot);
  5678. // 3. call AddGroup with the id, count, and offset
  5679. short nIndex2 = AddGroup(aInversionGroups, pNoteEvent->m_bInversionId, wCount, nOffset);
  5680. // 4. If the add was successful, do the inversion.
  5681. if (nIndex2 >= 0)
  5682. {
  5683. nMidiOffset = aInversionGroups[nIndex2].m_nOffset;
  5684. aInversionGroups[nIndex2].m_wCount--;
  5685. if (aInversionGroups[nIndex2].m_wCount == 0)
  5686. aInversionGroups[nIndex2].m_wGroupID = 0;
  5687. }
  5688. }
  5689. }
  5690. }
  5691. }
  5692. wMV += nMidiOffset;
  5693. while (wMV < 0) wMV += 12;
  5694. while (wMV > 127) wMV -= 12;
  5695. // NOT IMPLEMENTED: Don't play notes with low priority when the device
  5696. // runs out of notes
  5697. rbMidiValue = (BYTE) wMV;
  5698. rnMidiOffset = nMidiOffset;
  5699. if (fReleasePerformance) pPerformance->Release();
  5700. return S_OK;
  5701. }
  5702. HRESULT DirectMusicPartRef::ConvertMIDIValue(BYTE bMIDI,
  5703. DMUS_CHORD_PARAM& rCurrentChord,
  5704. BYTE bPlayModeFlags,
  5705. IDirectMusicPerformance* pPerformance,
  5706. WORD& rwMusicValue)
  5707. {
  5708. HRESULT hr = S_OK;
  5709. bool fReleasePerformance = false;
  5710. if (!pPerformance)
  5711. {
  5712. fReleasePerformance = true;
  5713. if( FAILED( CoCreateInstance( CLSID_DirectMusicPerformance,
  5714. NULL, CLSCTX_INPROC, IID_IDirectMusicPerformance,
  5715. (void**)&pPerformance )))
  5716. {
  5717. return E_FAIL;
  5718. }
  5719. }
  5720. if (bPlayModeFlags != DMUS_PLAYMODE_FIXED)
  5721. {
  5722. DMSubChord rSubChord;
  5723. DWORD dwLevel = 1 << m_bSubChordLevel;
  5724. DWORD dwIndex;
  5725. for (dwIndex = 0; dwIndex < rCurrentChord.bSubChordCount; dwIndex++)
  5726. {
  5727. if (dwLevel & rCurrentChord.SubChordList[dwIndex].dwLevels)
  5728. {
  5729. rSubChord = rCurrentChord.SubChordList[dwIndex];
  5730. break;
  5731. }
  5732. }
  5733. if (dwIndex == rCurrentChord.bSubChordCount)
  5734. {
  5735. rSubChord = rCurrentChord.SubChordList[0];
  5736. dwIndex = 0;
  5737. }
  5738. DMUS_CHORD_KEY ChordAndKey;
  5739. ZeroMemory(&ChordAndKey, sizeof(DMUS_CHORD_KEY));
  5740. ChordAndKey.dwScale = rCurrentChord.dwScale;
  5741. ChordAndKey.bSubChordCount = rCurrentChord.bSubChordCount;
  5742. ChordAndKey.bKey = rCurrentChord.bKey;
  5743. ChordAndKey.bFlags = 0;
  5744. ChordAndKey.SubChordList[dwIndex].bChordRoot = rSubChord.m_bChordRoot;
  5745. ChordAndKey.SubChordList[dwIndex].bScaleRoot = rSubChord.m_bScaleRoot;
  5746. ChordAndKey.SubChordList[dwIndex].dwChordPattern = rSubChord.m_dwChordPattern;
  5747. ChordAndKey.SubChordList[dwIndex].dwLevels = rSubChord.m_dwLevels;
  5748. ChordAndKey.SubChordList[dwIndex].dwScalePattern = rSubChord.m_dwScalePattern;
  5749. hr = pPerformance->MIDIToMusic(
  5750. bMIDI,
  5751. &ChordAndKey,
  5752. bPlayModeFlags,
  5753. m_bSubChordLevel,
  5754. &rwMusicValue);
  5755. }
  5756. if (fReleasePerformance) pPerformance->Release();
  5757. return hr;
  5758. }
  5759. short FindGroup(InversionGroup aGroup[], WORD wID)
  5760. {
  5761. for (short n = 0; n < INVERSIONGROUPLIMIT; n++)
  5762. if (wID == aGroup[n].m_wGroupID)
  5763. return n;
  5764. return -1;
  5765. }
  5766. short AddGroup(InversionGroup aGroup[], WORD wID, WORD wCount, short nOffset)
  5767. {
  5768. for (short n = 0; n < INVERSIONGROUPLIMIT; n++)
  5769. {
  5770. if (aGroup[n].m_wGroupID == 0)
  5771. {
  5772. aGroup[n].m_wGroupID = wID;
  5773. aGroup[n].m_wCount = wCount;
  5774. aGroup[n].m_nOffset = nOffset;
  5775. return n;
  5776. }
  5777. }
  5778. return -1;
  5779. }
  5780. inline DWORD CleanupScale(DWORD dwPattern)
  5781. // Force scale to be exactly two octaves
  5782. {
  5783. dwPattern &= 0x0FFF; // Clear upper octave.
  5784. dwPattern |= (dwPattern << 12); // Copy lower octave to top.
  5785. return dwPattern;
  5786. }
  5787. inline BYTE RelativeRoot(char chChordRoot, char chScaleRoot)
  5788. {
  5789. // is there any reason this should be > 12?
  5790. while (chScaleRoot > chChordRoot) chChordRoot += 12;
  5791. BYTE bResult = chChordRoot - chScaleRoot;
  5792. return bResult % 12;
  5793. }
  5794. // returns 1 - 7 for scale positions I - VII and 0 if chord isn't in scale
  5795. BYTE ScalePosition(DMSubChord& rSubChord, BYTE bKey, DWORD dwScale)
  5796. {
  5797. DWORD dwScalePattern = dwScale ? CleanupScale(dwScale) : DEFAULT_SCALE_PATTERN;
  5798. DWORD dwRootBit = (DWORD) (1 << RelativeRoot(rSubChord.m_bChordRoot, bKey));
  5799. if (dwRootBit & dwScalePattern)
  5800. {
  5801. BYTE bResult = 0;
  5802. while (dwRootBit > 0)
  5803. {
  5804. if (dwRootBit & dwScalePattern)
  5805. bResult++;
  5806. dwRootBit >>= 1;
  5807. }
  5808. return bResult;
  5809. }
  5810. else return 0;
  5811. }
  5812. // returns 1 - 7 for scale positions #I - #VII, 0 if not a sharp position
  5813. BYTE ScalePositionSharp(DMSubChord& rSubChord, BYTE bKey, DWORD dwScale)
  5814. {
  5815. DWORD dwScalePattern = dwScale ? CleanupScale(dwScale) : DEFAULT_SCALE_PATTERN;
  5816. DWORD dwRootBit = (DWORD) (1 << RelativeRoot(rSubChord.m_bChordRoot, bKey));
  5817. // now shift to see if this is sharp from the next position down
  5818. if (dwRootBit == 1) dwRootBit <<= 11;
  5819. else dwRootBit >>= 1;
  5820. if (dwRootBit & dwScalePattern)
  5821. {
  5822. BYTE bResult = 0;
  5823. while (dwRootBit > 0)
  5824. {
  5825. if (dwRootBit & dwScalePattern)
  5826. bResult++;
  5827. dwRootBit >>= 1;
  5828. }
  5829. return bResult;
  5830. }
  5831. else return 0;
  5832. }
  5833. // returns 1 - 7 for scale positions bI - bVII, 0 if not a flat position
  5834. BYTE ScalePositionFlat(DMSubChord& rSubChord, BYTE bKey, DWORD dwScale)
  5835. {
  5836. DWORD dwScalePattern = dwScale ? CleanupScale(dwScale) : DEFAULT_SCALE_PATTERN;
  5837. DWORD dwRootBit = (DWORD) (1 << RelativeRoot(rSubChord.m_bChordRoot, bKey));
  5838. // now shift to see if this is flat from the next position up
  5839. if (dwRootBit == (1 << 11)) dwRootBit = 1;
  5840. else dwRootBit <<= 1;
  5841. if (dwRootBit & dwScalePattern)
  5842. {
  5843. BYTE bResult = 0;
  5844. while (dwRootBit > 0)
  5845. {
  5846. if (dwRootBit & dwScalePattern)
  5847. bResult++;
  5848. dwRootBit >>= 1;
  5849. }
  5850. return bResult;
  5851. }
  5852. else return 0;
  5853. }
  5854. bool IsSimple(DMUS_CHORD_PARAM& Chord)
  5855. {
  5856. if (Chord.bSubChordCount <= 1)
  5857. {
  5858. return true;
  5859. }
  5860. else
  5861. {
  5862. bool fResult = true;
  5863. for (int n = 1; n < Chord.bSubChordCount; n++)
  5864. {
  5865. if ( (Chord.SubChordList[n].dwChordPattern != Chord.SubChordList[0].dwChordPattern) ||
  5866. (Chord.SubChordList[n].dwScalePattern != Chord.SubChordList[0].dwScalePattern) ||
  5867. (Chord.SubChordList[n].bChordRoot != Chord.SubChordList[0].bChordRoot) ||
  5868. (Chord.SubChordList[n].bScaleRoot != Chord.SubChordList[0].bScaleRoot) )
  5869. {
  5870. fResult = false;
  5871. break;
  5872. }
  5873. }
  5874. return fResult;
  5875. }
  5876. }
  5877. bool IsSimple(DMUS_CHORD_PARAM& Chord, int& rCount, int& rSixSeven)
  5878. {
  5879. // Combine all the notes from all chord patterns into one pattern
  5880. DWORD dwMOAPatterns = 0;
  5881. int nBaseRoot = Chord.SubChordList[0].bChordRoot;
  5882. for (int n = 0; n < Chord.bSubChordCount; n++)
  5883. {
  5884. int nShift = (int)Chord.SubChordList[n].bChordRoot - nBaseRoot;
  5885. while (nShift < 0) nShift += 12;
  5886. dwMOAPatterns |= (Chord.SubChordList[n].dwChordPattern << nShift);
  5887. }
  5888. // Fold both octaves of the pattern together
  5889. DWORD dwHighOctave = (dwMOAPatterns & 0xfff000) >> 12;
  5890. dwMOAPatterns = (dwMOAPatterns & 0xfff) | dwHighOctave;
  5891. // count the total notes
  5892. rCount = 0;
  5893. rSixSeven = 0;
  5894. for (n = 0; n < 12; n++)
  5895. {
  5896. if (dwMOAPatterns & (1 << n))
  5897. {
  5898. rCount++;
  5899. if (n > 7) rSixSeven++;
  5900. }
  5901. }
  5902. return rCount <= 4;
  5903. }
  5904. DWORD CDirectMusicPattern::IMA25MoawFlags(MUSIC_TIME mtTime,
  5905. MUSIC_TIME mtNextChord,
  5906. DMUS_CHORD_PARAM& rCurrentChord,
  5907. DMUS_CHORD_PARAM& rNextChord)
  5908. {
  5909. DWORD dwMoawFlags = 0;
  5910. DMSubChord rSubChord = rCurrentChord.SubChordList[0];
  5911. // set one of bits 0-7 based on chord root and scale root of current chord
  5912. DWORD dwPosition = ScalePosition(rSubChord, rCurrentChord.bKey, rCurrentChord.dwScale);
  5913. if (dwPosition)
  5914. dwMoawFlags |= 1 << (dwPosition - 1); // bit 0 for scale position I, etc.
  5915. else
  5916. dwMoawFlags |= VF_ACCIDENTAL;
  5917. // set bits based on tonality of 1st subchord of current chord
  5918. if ((rSubChord.m_dwChordPattern & MAJOR_PATTERN) == MAJOR_PATTERN)
  5919. dwMoawFlags |= VF_MAJOR;
  5920. else if ((rSubChord.m_dwChordPattern & MINOR_PATTERN) == MINOR_PATTERN)
  5921. dwMoawFlags |= VF_MINOR;
  5922. else
  5923. dwMoawFlags |= VF_ALL;
  5924. // set bits if the root of the next chord is I or V
  5925. MUSIC_TIME mtPatternLength = 0;
  5926. mtPatternLength = m_timeSig.ClocksPerMeasure() * m_wNumMeasures;
  5927. if (rNextChord.bSubChordCount > 0)
  5928. {
  5929. DMSubChord SC = rNextChord.SubChordList[0];
  5930. int nNextRoot = ScalePosition(SC, rCurrentChord.bKey, rCurrentChord.dwScale);
  5931. int nThisRoot = ScalePosition(rSubChord, rCurrentChord.bKey, rCurrentChord.dwScale);
  5932. if (mtPatternLength + mtTime < mtNextChord)
  5933. {
  5934. nNextRoot = nThisRoot;
  5935. }
  5936. switch (nNextRoot)
  5937. {
  5938. case 1: // Next chord is a I
  5939. dwMoawFlags |= VF_TO1;
  5940. break;
  5941. case 5: // Next chord is a 5
  5942. dwMoawFlags |= VF_TO5;
  5943. break;
  5944. }
  5945. }
  5946. // Set bits for simple and complex chords
  5947. if ( IsSimple(rCurrentChord) )
  5948. dwMoawFlags |= VF_SIMPLE;
  5949. else
  5950. dwMoawFlags |= VF_COMPLEX;
  5951. return dwMoawFlags;
  5952. }
  5953. void CDirectMusicPattern::DMusMoawFlags(MUSIC_TIME mtTime,
  5954. MUSIC_TIME mtNextChord,
  5955. DMUS_CHORD_PARAM& rCurrentChord,
  5956. DMUS_CHORD_PARAM& rNextChord,
  5957. bool fIsDX8,
  5958. DWORD& dwNaturals,
  5959. DWORD& dwSharps,
  5960. DWORD& dwFlats)
  5961. {
  5962. dwNaturals = dwSharps = dwFlats = 0;
  5963. DMSubChord rSubChord = rCurrentChord.SubChordList[0];
  5964. // dwScalePosition holds the scale position of the chord.
  5965. DWORD dwScalePosition = ScalePosition(rSubChord, rCurrentChord.bKey, rCurrentChord.dwScale);
  5966. // dwSharpPosition holds the sharped scale position of the chord.
  5967. DWORD dwSharpPosition = ScalePositionSharp(rSubChord, rCurrentChord.bKey, rCurrentChord.dwScale);
  5968. // dwFlatPosition holds the flatted scale position of the chord.
  5969. DWORD dwFlatPosition = ScalePositionFlat(rSubChord, rCurrentChord.bKey, rCurrentChord.dwScale);
  5970. // set bits for scale tone, sharp, and flat
  5971. if (dwScalePosition)
  5972. {
  5973. dwNaturals |= DMUS_VARIATIONF_ROOT_SCALE;
  5974. // shift bits based on tonality of 1st subchord of current chord
  5975. if ( (rSubChord.m_dwChordPattern & MAJOR_PATTERN) == MAJOR_PATTERN )
  5976. {
  5977. dwNaturals |= 1 << (dwScalePosition - 1);
  5978. }
  5979. else if ( (rSubChord.m_dwChordPattern & MINOR_PATTERN) == MINOR_PATTERN)
  5980. {
  5981. dwNaturals |= 1 << (dwScalePosition + 6);
  5982. }
  5983. else
  5984. {
  5985. dwNaturals |= 1 << (dwScalePosition + 13);
  5986. }
  5987. dwSharps = dwFlats = dwNaturals;
  5988. dwSharpPosition = dwFlatPosition = dwScalePosition;
  5989. }
  5990. else
  5991. {
  5992. if (dwSharpPosition)
  5993. {
  5994. dwSharps |= DMUS_VARIATIONF_ROOT_SHARP;
  5995. // shift bits based on tonality of 1st subchord of current chord
  5996. if ( (rSubChord.m_dwChordPattern & MAJOR_PATTERN) == MAJOR_PATTERN )
  5997. {
  5998. dwSharps |= 1 << (dwSharpPosition - 1);
  5999. }
  6000. else if ( (rSubChord.m_dwChordPattern & MINOR_PATTERN) == MINOR_PATTERN)
  6001. {
  6002. dwSharps |= 1 << (dwSharpPosition + 6);
  6003. }
  6004. else
  6005. {
  6006. dwSharps |= 1 << (dwSharpPosition + 13);
  6007. }
  6008. }
  6009. if (dwFlatPosition)
  6010. {
  6011. dwFlats |= DMUS_VARIATIONF_ROOT_FLAT;
  6012. // shift bits based on tonality of 1st subchord of current chord
  6013. if ( (rSubChord.m_dwChordPattern & MAJOR_PATTERN) == MAJOR_PATTERN )
  6014. {
  6015. dwFlats |= 1 << (dwFlatPosition - 1);
  6016. }
  6017. else if ( (rSubChord.m_dwChordPattern & MINOR_PATTERN) == MINOR_PATTERN)
  6018. {
  6019. dwFlats |= 1 << (dwFlatPosition + 6);
  6020. }
  6021. else
  6022. {
  6023. dwFlats |= 1 << (dwFlatPosition + 13);
  6024. }
  6025. }
  6026. }
  6027. // set bits if the root of the next chord is I or V (and it's different from the current chord)
  6028. MUSIC_TIME mtPatternLength = 0;
  6029. mtPatternLength = m_timeSig.ClocksPerMeasure() * m_wNumMeasures;
  6030. if (rNextChord.bSubChordCount > 0)
  6031. {
  6032. DMSubChord SC = rNextChord.SubChordList[0];
  6033. int nNextRoot = ScalePosition(SC, rCurrentChord.bKey, rCurrentChord.dwScale);
  6034. int nThisRoot = ScalePosition(rSubChord, rCurrentChord.bKey, rCurrentChord.dwScale);
  6035. if (mtPatternLength + mtTime < mtNextChord)
  6036. {
  6037. nNextRoot = nThisRoot;
  6038. }
  6039. /* This is easy enough to add if it's desired --- but not having it allows a bit more control
  6040. //Don't require anything but the ->Other flag to be set when staying on the same chord
  6041. if (fIsDX8 && nNextRoot == nThisRoot)
  6042. {
  6043. if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_DEST_OTHER;
  6044. if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_DEST_OTHER;
  6045. if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_DEST_OTHER;
  6046. }
  6047. */
  6048. switch (nNextRoot)
  6049. {
  6050. case 1: // Next chord is a I
  6051. if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_DEST_TO1;
  6052. if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_DEST_TO1;
  6053. if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_DEST_TO1;
  6054. break;
  6055. case 5: // Next chord is a V
  6056. if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_DEST_TO5;
  6057. if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_DEST_TO5;
  6058. if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_DEST_TO5;
  6059. break;
  6060. default: // Next chord is neither I nor V
  6061. if (fIsDX8)
  6062. {
  6063. if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_DEST_OTHER;
  6064. if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_DEST_OTHER;
  6065. if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_DEST_OTHER;
  6066. }
  6067. break;
  6068. }
  6069. }
  6070. // Set bits for simple and complex chords
  6071. int nCount = 0;
  6072. int nSixSeven = 0;
  6073. if ( IsSimple(rCurrentChord, nCount, nSixSeven) )
  6074. {
  6075. if (nCount <= 3)
  6076. {
  6077. if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_TYPE_TRIAD;
  6078. if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_TYPE_TRIAD;
  6079. if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_TYPE_TRIAD;
  6080. }
  6081. else if (nCount == 4)
  6082. {
  6083. if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_TYPE_6AND7;
  6084. if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_TYPE_6AND7;
  6085. if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_TYPE_6AND7;
  6086. }
  6087. else
  6088. {
  6089. if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_TYPE_COMPLEX;
  6090. if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_TYPE_COMPLEX;
  6091. if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_TYPE_COMPLEX;
  6092. }
  6093. }
  6094. else
  6095. {
  6096. if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_TYPE_COMPLEX;
  6097. if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_TYPE_COMPLEX;
  6098. if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_TYPE_COMPLEX;
  6099. }
  6100. }
  6101. HRESULT CDirectMusicPattern::ComputeVariations(DWORD dwFlags,
  6102. DMUS_CHORD_PARAM& rCurrentChord,
  6103. DMUS_CHORD_PARAM& rNextChord,
  6104. BYTE abVariationGroups[],
  6105. DWORD adwVariationMask[],
  6106. DWORD adwRemoveVariations[],
  6107. BYTE abVariation[],
  6108. MUSIC_TIME mtTime,
  6109. MUSIC_TIME mtNextChord,
  6110. PatternTrackState* pState)
  6111. {
  6112. HRESULT hr = S_OK;
  6113. // First, initialize the array of variation groups.
  6114. for (short i = 0; i < MAX_VARIATION_LOCKS; i++)
  6115. {
  6116. abVariationGroups[i] = 0xFF;
  6117. }
  6118. // Now, compute the variations for each part.
  6119. TListItem<DirectMusicPartRef>* pPartRef = m_PartRefList.GetHead();
  6120. for (i = 0; pPartRef != NULL; pPartRef = pPartRef->GetNext(), i++)
  6121. {
  6122. hr = ComputeVariation(
  6123. pPartRef->GetItemValue(),
  6124. i,
  6125. dwFlags,
  6126. rCurrentChord,
  6127. rNextChord,
  6128. abVariationGroups,
  6129. adwVariationMask,
  6130. adwRemoveVariations,
  6131. abVariation,
  6132. mtTime,
  6133. mtNextChord,
  6134. pState);
  6135. if (FAILED(hr))
  6136. {
  6137. break;
  6138. }
  6139. }
  6140. return hr;
  6141. }
  6142. HRESULT CDirectMusicPattern::ComputeVariationGroup(DirectMusicPartRef& rPartRef,
  6143. int nPartIndex,
  6144. DWORD dwFlags,
  6145. DMUS_CHORD_PARAM& rCurrentChord,
  6146. DMUS_CHORD_PARAM& rNextChord,
  6147. BYTE abVariationGroups[],
  6148. DWORD adwVariationMask[],
  6149. DWORD adwRemoveVariations[],
  6150. BYTE abVariation[],
  6151. MUSIC_TIME mtTime,
  6152. MUSIC_TIME mtNextChord,
  6153. PatternTrackState* pState)
  6154. {
  6155. HRESULT hr = S_OK;
  6156. BYTE bLockID = rPartRef.m_bVariationLockID;
  6157. bool fChangedVariation = (dwFlags & COMPUTE_VARIATIONSF_CHANGED) ? true : false;
  6158. // If this part is locked, get a new variation for all parts locked to it;
  6159. // otherwise, just get a new variation for this part.
  6160. if (bLockID)
  6161. {
  6162. if (!fChangedVariation)
  6163. {
  6164. // First, initialize the variation group for this variation.
  6165. abVariationGroups[bLockID - 1] = 0xFF;
  6166. // Now, compute the variations for each part locked to this one.
  6167. TListItem<DirectMusicPartRef>* pPartRef = m_PartRefList.GetHead();
  6168. for (int i = 0; pPartRef != NULL; pPartRef = pPartRef->GetNext(), i++)
  6169. {
  6170. DirectMusicPartRef& rPartRefScan = pPartRef->GetItemValue();
  6171. if ( (bLockID == rPartRefScan.m_bVariationLockID) )
  6172. {
  6173. hr = ComputeVariation(
  6174. rPartRefScan,
  6175. i,
  6176. dwFlags,
  6177. rCurrentChord,
  6178. rNextChord,
  6179. abVariationGroups,
  6180. adwVariationMask,
  6181. adwRemoveVariations,
  6182. abVariation,
  6183. mtTime,
  6184. mtNextChord,
  6185. pState);
  6186. if (FAILED(hr))
  6187. {
  6188. break;
  6189. }
  6190. }
  6191. }
  6192. }
  6193. }
  6194. else
  6195. {
  6196. hr = ComputeVariation(
  6197. rPartRef,
  6198. nPartIndex,
  6199. dwFlags,
  6200. rCurrentChord,
  6201. rNextChord,
  6202. abVariationGroups,
  6203. adwVariationMask,
  6204. adwRemoveVariations,
  6205. abVariation,
  6206. mtTime,
  6207. mtNextChord,
  6208. pState);
  6209. }
  6210. return hr;
  6211. }
  6212. HRESULT CDirectMusicPattern::ComputeVariation(DirectMusicPartRef& rPartRef,
  6213. int nPartIndex,
  6214. DWORD dwFlags,
  6215. DMUS_CHORD_PARAM& rCurrentChord,
  6216. DMUS_CHORD_PARAM& rNextChord,
  6217. BYTE abVariationGroups[],
  6218. DWORD adwVariationMask[],
  6219. DWORD adwRemoveVariations[],
  6220. BYTE abVariation[],
  6221. MUSIC_TIME mtTime,
  6222. MUSIC_TIME mtNextChord,
  6223. PatternTrackState* pState)
  6224. {
  6225. int i = nPartIndex;
  6226. bool fUseMask = (dwFlags & COMPUTE_VARIATIONSF_USE_MASK) ? true : false;
  6227. bool fNewPattern = (dwFlags & COMPUTE_VARIATIONSF_NEW_PATTERN) ? true : false;
  6228. bool fChordAlign = (dwFlags & COMPUTE_VARIATIONSF_CHORD_ALIGN) ? true : false;
  6229. bool fMarker = (dwFlags & COMPUTE_VARIATIONSF_MARKER) ? true : false;
  6230. bool fStart = (dwFlags & COMPUTE_VARIATIONSF_START) ? true : false;
  6231. bool fIsDX8 = (dwFlags & COMPUTE_VARIATIONSF_DX8) ? true : false;
  6232. bool fChord = false;
  6233. if (pState && (mtTime == pState->m_mtCurrentChordTime || mtTime == pState->m_mtNextChordTime))
  6234. {
  6235. fChord = true;
  6236. }
  6237. DWORD dwMarkerFlags = DMUS_MARKERF_START;
  6238. DWORD dwDMusNaturals, dwDMusSharps, dwDMusFlats;
  6239. DMusMoawFlags(mtTime, mtNextChord, rCurrentChord, rNextChord, fIsDX8, dwDMusNaturals, dwDMusSharps, dwDMusFlats);
  6240. DWORD dwIMA25MoawFlags = IMA25MoawFlags(mtTime, mtNextChord, rCurrentChord, rNextChord);
  6241. TListItem<DirectMusicPartRef>* pPartRef = m_PartRefList.GetHead();
  6242. DWORD dwNaturalFlags, dwSharpFlags, dwFlatFlags;
  6243. /*// First, initialize the array of variation groups
  6244. for (short i = 0; i < MAX_VARIATION_LOCKS; i++)
  6245. {
  6246. abVariationGroups[i] = 0xFF;
  6247. }*/
  6248. //for (i = 0; pPartRef != NULL; pPartRef = pPartRef->GetNext(), i++)
  6249. {
  6250. // if (pguidPart &&
  6251. // pPartRef->GetItemValue().m_pDMPart &&
  6252. // *pguidPart != pPartRef->GetItemValue().m_pDMPart->m_guidPartID)
  6253. // {
  6254. // continue; // the way this was, it wiped out variation locking
  6255. // }
  6256. DWORD dwVariationChoices = 0xffffffff;
  6257. if (fUseMask)
  6258. {
  6259. dwVariationChoices = adwVariationMask[i];
  6260. }
  6261. // DirectMusicPartRef& rPartRef = pPartRef->GetItemValue();
  6262. BYTE bLockID = rPartRef.m_bVariationLockID;
  6263. DirectMusicPart* pPart = rPartRef.m_pDMPart;
  6264. MUSIC_TIME mtPartOffset = (pState) ? pState->PartOffset(i) : 0;
  6265. MUSIC_TIME mtNowRelative = (mtTime >= mtPartOffset) ? mtTime - mtPartOffset : 0;
  6266. MUSIC_TIME mtClosestTime = 0;
  6267. // Find a variation whose moaw field matches dwMoawFlags.
  6268. // Variation locking: If a part ref has a variation lock id that has already been
  6269. // recorded, use the recorded variation. Otherwise, find a variation and, if the
  6270. // part ref has a variation lock id, record the variation.
  6271. if (bLockID && abVariationGroups[bLockID - 1] != 0xFF)
  6272. {
  6273. abVariation[i] = abVariationGroups[bLockID - 1];
  6274. adwVariationMask[i] = abVariationGroups[bLockID - 1];
  6275. }
  6276. else
  6277. {
  6278. // First, collect all matches.
  6279. // Also, find the time of the matching variation closest to but not preceding mtTime.
  6280. BYTE bMode = 0;
  6281. DWORD dwMatches = 0;
  6282. DWORD dwCompleteMatches = 0;
  6283. short nMatchCount = 0;
  6284. DWORD dwEnabled = 0;
  6285. short nEnabledCount = 0;
  6286. bool fGotClosest = false;
  6287. for (short nV = 0; nV < 32; nV++)
  6288. {
  6289. DWORD dwVariation = 1 << nV;
  6290. if (dwVariation & dwVariationChoices)
  6291. {
  6292. if ( (pPart->m_dwVariationChoices[nV] & 0x5FFFFFFF) != 0) // enabled
  6293. {
  6294. nEnabledCount++;
  6295. dwEnabled |= dwVariation;
  6296. }
  6297. if (pPart->m_dwVariationChoices[nV] & DMUS_VARIATIONF_DMUS_MODE)
  6298. {
  6299. dwNaturalFlags = dwDMusNaturals;
  6300. dwSharpFlags = dwDMusSharps;
  6301. dwFlatFlags = dwDMusFlats;
  6302. }
  6303. else
  6304. {
  6305. dwNaturalFlags = dwSharpFlags = dwFlatFlags = dwIMA25MoawFlags;
  6306. }
  6307. if ( (dwNaturalFlags && (pPart->m_dwVariationChoices[nV] & dwNaturalFlags) == dwNaturalFlags) ||
  6308. (dwSharpFlags && (pPart->m_dwVariationChoices[nV] & dwSharpFlags) == dwSharpFlags) ||
  6309. (dwFlatFlags && (pPart->m_dwVariationChoices[nV] & dwFlatFlags) == dwFlatFlags) )
  6310. {
  6311. nMatchCount++;
  6312. dwMatches |= dwVariation;
  6313. if ((fStart || fMarker) && pPart && (pPart->m_dwFlags & DMUS_PARTF_USE_MARKERS))
  6314. {
  6315. MUSIC_TIME mtTemp = 0;
  6316. if (SUCCEEDED(pPart->GetClosestTime(nV, mtNowRelative, dwMarkerFlags, fChord, mtTemp)))
  6317. {
  6318. if (!fGotClosest || mtTemp < mtClosestTime)
  6319. {
  6320. mtClosestTime = mtTemp;
  6321. fGotClosest = true;
  6322. }
  6323. }
  6324. }
  6325. }
  6326. }
  6327. }
  6328. dwCompleteMatches = dwMatches;
  6329. DWORD dwTemp = dwMatches;
  6330. bMode = rPartRef.m_bRandomVariation;
  6331. if ( bMode == DMUS_VARIATIONT_RANDOM_ROW )
  6332. {
  6333. dwTemp &= ~adwRemoveVariations[i];
  6334. if (!dwTemp)
  6335. {
  6336. // start counting all over, but don't repeat this one
  6337. adwRemoveVariations[i] = 0;
  6338. dwTemp = dwMatches;
  6339. bMode = DMUS_VARIATIONT_NO_REPEAT;
  6340. }
  6341. }
  6342. if ( bMode == DMUS_VARIATIONT_NO_REPEAT && abVariation[i] != 0xff )
  6343. {
  6344. dwTemp &= ~(1 << abVariation[i]);
  6345. }
  6346. if (dwTemp != dwMatches)
  6347. {
  6348. if (dwTemp) // otherwise, keep what we had
  6349. {
  6350. for (int j = 0; j < 32; j++)
  6351. {
  6352. if ( ((1 << j) & dwMatches) && !((1 << j) & dwTemp) )
  6353. {
  6354. nMatchCount--;
  6355. }
  6356. }
  6357. dwMatches = dwTemp;
  6358. }
  6359. }
  6360. if (nMatchCount == 0)
  6361. {
  6362. if (nEnabledCount)
  6363. {
  6364. // if there are any enabled variations, choose from among them
  6365. nMatchCount = nEnabledCount;
  6366. dwMatches = dwEnabled;
  6367. }
  6368. else
  6369. {
  6370. // otherwise, choose any variation from among the first 16
  6371. // (for compatability with SuperJam)
  6372. nMatchCount = 16;
  6373. dwMatches = 0xffffffff;
  6374. }
  6375. }
  6376. adwVariationMask[i] = dwMatches;
  6377. // If we're starting at or past a marker, or we're at a marker,
  6378. // and the part is using markers, filter out all
  6379. // variations except those with start markers closest to but not preceding mtNow.
  6380. if ( ((fStart && mtTime >= mtClosestTime) || fMarker) &&
  6381. pPart && (pPart->m_dwFlags & DMUS_PARTF_USE_MARKERS) )
  6382. {
  6383. DWORD dwMatchTemp = dwMatches;
  6384. short nCountTemp = nMatchCount;
  6385. for (nV = 0; nV < 32; nV++)
  6386. {
  6387. if (dwMatches & (1 << nV))
  6388. {
  6389. if ( !pPart->IsMarkerAtTime(nV, mtClosestTime, dwMarkerFlags, fChord) )
  6390. {
  6391. dwMatches &= ~(1 << nV);
  6392. nMatchCount--;
  6393. }
  6394. }
  6395. }
  6396. // Fall back to the original matches
  6397. if (!dwMatches)
  6398. {
  6399. dwMatches = dwMatchTemp;
  6400. nMatchCount = nCountTemp;
  6401. }
  6402. }
  6403. // Next, select a match.
  6404. // Only select a match if either we're just starting a new pattern,
  6405. // we're at a chord-aligned marker,
  6406. // or the current variation isn't a match.
  6407. // If this part aligns variations to chords, only get a new variation
  6408. // if we're just starting a new pattern,
  6409. // or we're at a chord-aligned marker AND the current variation isn't a match.
  6410. TraceI(3, "Matches: %x\n", dwMatches);
  6411. bool fAlignPartToChord = (pPart->m_dwFlags & DMUS_PARTF_ALIGN_CHORDS) ? true : false;
  6412. bool fMatch = ((1 << abVariation[i]) & dwCompleteMatches) ? true : false;
  6413. bool fFirstRandomInOrder = false;
  6414. if ( fNewPattern ||
  6415. (!fAlignPartToChord && (fChordAlign || !fMatch)) ||
  6416. (fAlignPartToChord && fChordAlign && !fMatch) )
  6417. {
  6418. //TraceI(0, "Time: %d, New Pattern: %d Chord Align: %d Variation: %d Matches: %x\n",
  6419. // mtTime, fNewPattern, fChordAlign, abVariation[i], dwCompleteMatches);
  6420. switch (rPartRef.m_bRandomVariation)
  6421. {
  6422. case DMUS_VARIATIONT_RANDOM_ROW:
  6423. case DMUS_VARIATIONT_NO_REPEAT:
  6424. case DMUS_VARIATIONT_RANDOM:
  6425. {
  6426. short nChoice = 0;
  6427. if (pState)
  6428. {
  6429. nChoice = (short)pState->RandomVariation(mtTime, nMatchCount);
  6430. }
  6431. else
  6432. {
  6433. nChoice = (short) (rand() % nMatchCount);
  6434. }
  6435. short nCount = 0;
  6436. for (nV = 0; nV < 32; nV++)
  6437. {
  6438. if ((1 << nV) & dwMatches)
  6439. {
  6440. if (nChoice == nCount)
  6441. break;
  6442. nCount++;
  6443. }
  6444. }
  6445. abVariation[i] = (BYTE) nV;
  6446. if (rPartRef.m_bRandomVariation == DMUS_VARIATIONT_RANDOM_ROW)
  6447. {
  6448. adwRemoveVariations[i] |= (1 << abVariation[i]);
  6449. }
  6450. TraceI(3, "New variation: %d at time %d\n", nV, mtTime);
  6451. break;
  6452. }
  6453. case DMUS_VARIATIONT_RANDOM_START:
  6454. // Choose an initial value
  6455. if (abVariation[i] == 0xff)
  6456. {
  6457. fFirstRandomInOrder = true;
  6458. int nStart = 0;
  6459. if (pState)
  6460. {
  6461. nStart = (BYTE)pState->RandomVariation(mtTime, nMatchCount);
  6462. }
  6463. else
  6464. {
  6465. nStart = (BYTE) (rand() % nMatchCount);
  6466. }
  6467. int nCount = 0;
  6468. for (nV = 0; nV < 32; nV++)
  6469. {
  6470. if ((1 << nV) & dwMatches)
  6471. {
  6472. if (nStart == nCount)
  6473. break;
  6474. nCount++;
  6475. }
  6476. }
  6477. abVariation[i] = (BYTE) nV;
  6478. }
  6479. // Now, go directly to the sequential case (no break)
  6480. case DMUS_VARIATIONT_SEQUENTIAL:
  6481. {
  6482. if (!fFirstRandomInOrder)
  6483. {
  6484. do
  6485. {
  6486. abVariation[i]++;
  6487. }
  6488. while (!((1 << ((nV + abVariation[i]) % 32)) & dwMatches));
  6489. abVariation[i] %= 32;
  6490. }
  6491. TraceI(3, "New variation: %d at time %d\n", abVariation[i], mtTime);
  6492. break;
  6493. }
  6494. }
  6495. // If this is a locked variation, it's the first in its group, so record it.
  6496. if (bLockID)
  6497. {
  6498. abVariationGroups[bLockID - 1] = abVariation[i];
  6499. }
  6500. }
  6501. }
  6502. }
  6503. return S_OK;
  6504. }
  6505. // Returns:
  6506. // Total number of bits in the pattern if all bits in the rhythm match the pattern.
  6507. // 0 otherwise.
  6508. void CDirectMusicPattern::MatchRhythm(DWORD pRhythms[], short nPatternLength,
  6509. short& nBits)
  6510. {
  6511. nBits = 0;
  6512. for (int i = 0; i < nPatternLength; i++)
  6513. {
  6514. if (i >= m_wNumMeasures)
  6515. {
  6516. return;
  6517. }
  6518. if ((pRhythms[i] & m_pRhythmMap[i]) == pRhythms[i])
  6519. {
  6520. for (int n = 0; n < 32; n++)
  6521. {
  6522. nBits += (short) (m_pRhythmMap[i] >> n) & 1;
  6523. }
  6524. }
  6525. else
  6526. {
  6527. nBits = 0;
  6528. return;
  6529. }
  6530. }
  6531. }
  6532. BOOL CDirectMusicPattern::MatchCommand(DMUS_COMMAND_PARAM_2 pCommands[], short nLength)
  6533. {
  6534. short nPatternLength = (m_wNumMeasures < nLength) ? m_wNumMeasures : nLength;
  6535. if ((m_wEmbellishment & EMB_MOTIF) == EMB_MOTIF) return FALSE; // discard all motifs
  6536. for (int i = 0; i < nPatternLength; i++)
  6537. {
  6538. if ( (i > 0) &&
  6539. (pCommands[i].bCommand == DMUS_COMMANDT_GROOVE) &&
  6540. (pCommands[i].bGrooveLevel == pCommands[0].bGrooveLevel) )
  6541. {
  6542. continue;
  6543. }
  6544. if (!MatchEmbellishment(pCommands[i])) return FALSE;
  6545. if (!MatchGrooveLevel(pCommands[i])) return FALSE;
  6546. }
  6547. return TRUE;
  6548. }
  6549. BOOL CDirectMusicPattern::MatchGrooveLevel(DMUS_COMMAND_PARAM_2& rCommand)
  6550. {
  6551. if ((m_wEmbellishment & EMB_MOTIF) == EMB_MOTIF) return FALSE; // discard all motifs
  6552. // Lower the upper range and raise the lower range by half of the total range each
  6553. BYTE bMiddle = rCommand.bGrooveRange / 2;
  6554. BYTE bUpper = (rCommand.bGrooveLevel < bMiddle) ? 1 : rCommand.bGrooveLevel - bMiddle;
  6555. BYTE bLower = (rCommand.bGrooveLevel + bMiddle > 100) ? 100 : rCommand.bGrooveLevel + bMiddle;
  6556. TraceI(3, "Range: %d Upper: %d Lower: %d\n", bMiddle, bUpper, bLower);
  6557. return (bLower >= m_bGrooveBottom && bUpper <= m_bGrooveTop);
  6558. }
  6559. BOOL CDirectMusicPattern::MatchEmbellishment(DMUS_COMMAND_PARAM_2& rCommand)
  6560. {
  6561. if ((m_wEmbellishment & EMB_MOTIF) == EMB_MOTIF) return FALSE; // discard all motifs
  6562. if ((m_wEmbellishment & EMB_USER_DEFINED)) // handle user-defined embellishments
  6563. {
  6564. if ((BYTE)(m_wEmbellishment >> 8) != rCommand.bCommand) return FALSE;
  6565. }
  6566. else
  6567. {
  6568. switch (rCommand.bCommand)
  6569. {
  6570. case DMUS_COMMANDT_GROOVE:
  6571. if ((m_wEmbellishment & EMB_NORMAL) != m_wEmbellishment) return FALSE;
  6572. break;
  6573. case DMUS_COMMANDT_FILL:
  6574. if (!(m_wEmbellishment & EMB_FILL)) return FALSE;
  6575. break;
  6576. case DMUS_COMMANDT_INTRO:
  6577. if (!(m_wEmbellishment & EMB_INTRO)) return FALSE;
  6578. break;
  6579. case DMUS_COMMANDT_BREAK:
  6580. if (!(m_wEmbellishment & EMB_BREAK)) return FALSE;
  6581. break;
  6582. case DMUS_COMMANDT_END:
  6583. if (!(m_wEmbellishment & EMB_END)) return FALSE;
  6584. break;
  6585. default: return FALSE;
  6586. }
  6587. }
  6588. return TRUE;
  6589. }
  6590. BOOL CDirectMusicPattern::MatchNextCommand(DMUS_COMMAND_PARAM_2& rNextCommand)
  6591. {
  6592. TraceI(3, "Next Command: %x (%d) Embellishment: %x [%d %d] <%d %d>\n", rNextCommand.bCommand, rNextCommand.bGrooveLevel,
  6593. m_wEmbellishment, m_bGrooveBottom, m_bGrooveTop, m_bDestGrooveBottom, m_bDestGrooveTop);
  6594. if ((m_wEmbellishment & EMB_MOTIF) == EMB_MOTIF) return FALSE; // discard all motifs
  6595. if (!m_bDestGrooveBottom || !m_bDestGrooveTop) // handle legacy
  6596. {
  6597. return TRUE;
  6598. }
  6599. // Lower the upper range and raise the lower range by half of the total range each
  6600. BYTE bMiddle = rNextCommand.bGrooveRange / 2;
  6601. BYTE bUpper = (rNextCommand.bGrooveLevel < bMiddle) ? 1 : rNextCommand.bGrooveLevel - bMiddle;
  6602. BYTE bLower = (rNextCommand.bGrooveLevel + bMiddle > 100) ? 100 : rNextCommand.bGrooveLevel + bMiddle;
  6603. TraceI(3, "Range: %d Upper: %d Lower: %d\n", bMiddle, bUpper, bLower);
  6604. return (bLower >= m_bDestGrooveBottom && bUpper <= m_bDestGrooveTop);
  6605. }
  6606. HRESULT CDirectMusicPattern::MergeMarkerEvents( DMStyleStruct* pStyle )
  6607. {
  6608. TListItem<DirectMusicPartRef>* pPartRef = m_PartRefList.GetHead();
  6609. for (; pPartRef; pPartRef = pPartRef->GetNext())
  6610. {
  6611. pPartRef->GetItemValue().m_pDMPart->MergeMarkerEvents(pStyle, this);
  6612. }
  6613. return S_OK;
  6614. }
  6615. bool Greater(MUSIC_TIME& mt1, MUSIC_TIME& mt2)
  6616. {
  6617. return mt1 > mt2;
  6618. }
  6619. bool Greater(Marker& m1, Marker& m2)
  6620. {
  6621. return m1.mtTime > m2.mtTime;
  6622. }
  6623. template <class T>
  6624. HRESULT InsertInOrder(TList<T>& List, T tValue)
  6625. {
  6626. TListItem<T>* pNew = new TListItem<T>(tValue);
  6627. if (!pNew) return E_OUTOFMEMORY;
  6628. TListItem<T>* pScan = List.GetHead();
  6629. TListItem<T>* pPrevious = NULL;
  6630. for (; pScan; pScan = pScan->GetNext())
  6631. {
  6632. if (Greater(pScan->GetItemValue(), tValue))
  6633. {
  6634. break;
  6635. }
  6636. pPrevious = pScan;
  6637. }
  6638. if (!pPrevious)
  6639. {
  6640. List.AddHead(pNew);
  6641. }
  6642. else
  6643. {
  6644. pPrevious->SetNext(pNew);
  6645. pNew->SetNext(pScan);
  6646. }
  6647. return S_OK;
  6648. }
  6649. HRESULT DirectMusicPart::MergeMarkerEvents( DMStyleStruct* pStyle, CDirectMusicPattern* pPattern )
  6650. {
  6651. DirectMusicTimeSig& TimeSig = TimeSignature(pStyle, pPattern);
  6652. CDirectMusicEventItem* pEvent;
  6653. for (pEvent = EventList.GetHead(); pEvent; pEvent = pEvent->GetNext())
  6654. {
  6655. if (pEvent->m_dwEventTag == DMUS_EVENT_MARKER)
  6656. {
  6657. CDMStyleMarker* pMarker = (CDMStyleMarker*)pEvent;
  6658. if (pMarker->m_wFlags & DMUS_MARKERF_START)
  6659. {
  6660. MUSIC_TIME mtTime =
  6661. (MUSIC_TIME)(TimeSig.GridToClocks(pMarker->m_nGridStart) + pMarker->m_nTimeOffset);
  6662. // Put this in all the appropriate variation lists
  6663. for (int i = 0; i < 32; i++)
  6664. {
  6665. if (pMarker->m_dwVariation & (1 << i))
  6666. {
  6667. Marker M;
  6668. M.mtTime = mtTime;
  6669. M.wFlags = pMarker->m_wFlags;
  6670. InsertInOrder(m_StartTimes[i], M);
  6671. }
  6672. }
  6673. InsertInOrder(pPattern->m_StartTimeList, mtTime);
  6674. }
  6675. }
  6676. }
  6677. return S_OK;
  6678. }
  6679. HRESULT DirectMusicPart::GetClosestTime(int nVariation, MUSIC_TIME mtTime, DWORD dwFlags, bool fChord, MUSIC_TIME& rmtResult)
  6680. {
  6681. HRESULT hr = E_FAIL;
  6682. rmtResult = 0;
  6683. if (nVariation < 32 && nVariation >= 0)
  6684. {
  6685. TListItem<Marker>* pMarker = m_StartTimes[nVariation].GetHead();
  6686. for (; pMarker; pMarker = pMarker->GetNext())
  6687. {
  6688. if ( pMarker->GetItemValue().mtTime >= mtTime &&
  6689. (pMarker->GetItemValue().wFlags & dwFlags) == dwFlags &&
  6690. (fChord || !(pMarker->GetItemValue().wFlags & DMUS_MARKERF_CHORD_ALIGN)) )
  6691. {
  6692. rmtResult = pMarker->GetItemValue().mtTime;
  6693. hr = S_OK;
  6694. break;
  6695. }
  6696. }
  6697. }
  6698. return hr;
  6699. }
  6700. bool DirectMusicPart::IsMarkerAtTime(int nVariation, MUSIC_TIME mtTime, DWORD dwFlags, bool fChord)
  6701. {
  6702. bool fResult = false;
  6703. if (nVariation < 32 && nVariation >= 0)
  6704. {
  6705. TListItem<Marker>* pMarker = m_StartTimes[nVariation].GetHead();
  6706. for (; pMarker; pMarker = pMarker->GetNext())
  6707. {
  6708. if ( pMarker->GetItemValue().mtTime == mtTime &&
  6709. (pMarker->GetItemValue().wFlags & dwFlags) == dwFlags &&
  6710. (fChord || !(pMarker->GetItemValue().wFlags & DMUS_MARKERF_CHORD_ALIGN)) )
  6711. {
  6712. fResult = true;
  6713. break;
  6714. }
  6715. }
  6716. }
  6717. return fResult;
  6718. }
  6719. DirectMusicTimeSig& CDirectMusicPattern::TimeSignature( DMStyleStruct* pStyle )
  6720. {
  6721. if (m_timeSig.m_bBeat != 0)
  6722. {
  6723. return m_timeSig;
  6724. }
  6725. else if (pStyle)
  6726. {
  6727. return pStyle->TimeSignature();
  6728. }
  6729. else
  6730. {
  6731. return ::DefaultTimeSig;
  6732. }
  6733. }
  6734. DirectMusicTimeSig& DirectMusicPart::TimeSignature( DMStyleStruct* pStyle, CDirectMusicPattern* pPattern )
  6735. {
  6736. if (m_timeSig.m_bBeat != 0)
  6737. {
  6738. return m_timeSig;
  6739. }
  6740. else if (pPattern)
  6741. {
  6742. return pPattern->TimeSignature(pStyle);
  6743. }
  6744. else
  6745. {
  6746. return ::DefaultTimeSig;
  6747. }
  6748. }