Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2284 lines
73 KiB

  1. //
  2. // dmband.cpp
  3. //
  4. // Copyright (c) 1997-1999 Microsoft Corporation
  5. //
  6. #define INITGUID
  7. #include <objbase.h>
  8. #include "debug.h"
  9. #include "dmksctrl.h"
  10. #include "dmusicc.h"
  11. #include "dmusici.h"
  12. #include "..\shared\dmstrm.h"
  13. #include "dmbandp.h"
  14. #include "bandtrk.h"
  15. #include "debug.h"
  16. #define MAX_LEGACY_BAND_NAME 20
  17. #define MAX_LEGACY_COLLECTION_NAME 32
  18. extern long g_cComponent;
  19. static GUID nullGUID = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  20. //////////////////////////////////////////////////////////////////////
  21. // Class CBand
  22. //////////////////////////////////////////////////////////////////////
  23. // CBand::CBand
  24. CBand::CBand()
  25. {
  26. m_lTimeLogical = 0;
  27. m_lTimePhysical = 0;
  28. m_dwFlags = 0;
  29. m_dwGroupBits = 0xffffffff;
  30. m_dwMidiMode = 0;
  31. m_cRef = 1;
  32. m_fCSInitialized = FALSE;
  33. InterlockedIncrement(&g_cComponent);
  34. // Do this first since it can throw an exception
  35. //
  36. InitializeCriticalSection(&m_CriticalSection);
  37. m_fCSInitialized = TRUE;
  38. m_dwValidData = 0;
  39. }
  40. //////////////////////////////////////////////////////////////////////
  41. // CBand::~CBand
  42. CBand::~CBand()
  43. {
  44. if (m_fCSInitialized)
  45. {
  46. m_BandInstrumentList.Clear();
  47. DeleteCriticalSection(&m_CriticalSection);
  48. }
  49. InterlockedDecrement(&g_cComponent);
  50. }
  51. void CBandInstrumentList::Clear()
  52. {
  53. CBandInstrument* pBandInstrument;
  54. while(pBandInstrument = RemoveHead())
  55. {
  56. delete pBandInstrument;
  57. }
  58. }
  59. //////////////////////////////////////////////////////////////////////
  60. // IUnknown
  61. //////////////////////////////////////////////////////////////////////
  62. // CBand::QueryInterface
  63. STDMETHODIMP
  64. CBand::QueryInterface(const IID &iid, void **ppv)
  65. {
  66. V_INAME(CBand::QueryInterface);
  67. V_PTRPTR_WRITE(ppv);
  68. V_REFGUID(iid);
  69. *ppv = NULL;
  70. if(iid == IID_IUnknown || iid == IID_IDirectMusicBand)
  71. {
  72. *ppv = static_cast<IDirectMusicBand*>(this);
  73. }
  74. else if(iid == IID_IDirectMusicBandP)
  75. {
  76. *ppv = static_cast<IDirectMusicBandP*>(this);
  77. }
  78. else if(iid == IID_IDirectMusicBandPrivate)
  79. {
  80. *ppv = static_cast<IDirectMusicBandPrivate*>(this);
  81. }
  82. else if(iid == IID_IDirectMusicObject)
  83. {
  84. *ppv = static_cast<IDirectMusicObject*>(this);
  85. }
  86. else if(iid == IID_IPersistStream)
  87. {
  88. *ppv = static_cast<IPersistStream*>(this);
  89. }
  90. else if(iid == IID_IPersist)
  91. {
  92. *ppv = static_cast<IPersist*>(this);
  93. }
  94. if (*ppv == NULL)
  95. return E_NOINTERFACE;
  96. reinterpret_cast<IUnknown*>(this)->AddRef();
  97. return S_OK;
  98. }
  99. //////////////////////////////////////////////////////////////////////
  100. // CBand::AddRef
  101. STDMETHODIMP_(ULONG)
  102. CBand::AddRef()
  103. {
  104. return InterlockedIncrement(&m_cRef);
  105. }
  106. //////////////////////////////////////////////////////////////////////
  107. // CBand::Release
  108. STDMETHODIMP_(ULONG)
  109. CBand::Release()
  110. {
  111. if (!InterlockedDecrement(&m_cRef))
  112. {
  113. m_cRef = 100; // artificial reference count to prevent reentrency due to COM aggregation
  114. delete this;
  115. return 0;
  116. }
  117. return m_cRef;
  118. }
  119. //////////////////////////////////////////////////////////////////////
  120. // IPersistStream
  121. //////////////////////////////////////////////////////////////////////
  122. // CBand::Load
  123. STDMETHODIMP CBand::Load(IStream* pStream)
  124. {
  125. V_INAME(CBand::Load);
  126. V_PTR_READ(pStream, IStream);
  127. // Get the loader from stream if it has one
  128. // so we can open required collections
  129. IDirectMusicLoader* pIDMLoader = NULL;
  130. IDirectMusicGetLoader *pIDMGetLoader = NULL;
  131. if (SUCCEEDED(pStream->QueryInterface(IID_IDirectMusicGetLoader,(void **)&pIDMGetLoader)))
  132. {
  133. pIDMGetLoader->GetLoader(&pIDMLoader);
  134. pIDMGetLoader->Release();
  135. }
  136. else
  137. {
  138. Trace(1,"Error: Band unable to reference DLS Collections because IStream does not support Loader.\n");
  139. return DMUS_E_UNSUPPORTED_STREAM;
  140. }
  141. EnterCriticalSection(&m_CriticalSection);
  142. // If we have been previously loaded, clean up instruments
  143. if(m_dwFlags & DMB_LOADED)
  144. {
  145. m_dwValidData = 0;
  146. m_BandInstrumentList.Clear();
  147. m_lTimeLogical = 0;
  148. m_lTimePhysical = 0;
  149. m_dwFlags = 0;
  150. }
  151. RIFFIO ckMain;
  152. HRESULT hr = S_OK;
  153. CRiffParser Parser(pStream);
  154. Parser.EnterList(&ckMain);
  155. if (Parser.NextChunk(&hr))
  156. {
  157. if (ckMain.fccType == FOURCC_BAND_FORM)
  158. {
  159. hr = LoadLegacyBand(&Parser, pIDMLoader);
  160. }
  161. else if(ckMain.fccType == DMUS_FOURCC_BAND_FORM)
  162. {
  163. hr = LoadDirectMusicBand(&Parser, pIDMLoader);
  164. }
  165. else
  166. {
  167. Trace(1,"Error: Failure Parsing Band - invalid chunk ID.\n");
  168. hr = DMUS_E_INVALID_BAND;
  169. }
  170. }
  171. if(FAILED(hr))
  172. {
  173. m_BandInstrumentList.Clear();
  174. }
  175. if(pIDMLoader)
  176. {
  177. pIDMLoader->Release();
  178. }
  179. LeaveCriticalSection(&m_CriticalSection);
  180. return hr;
  181. }
  182. //////////////////////////////////////////////////////////////////////
  183. // IDirectMusicBand
  184. //////////////////////////////////////////////////////////////////////
  185. // CBand::CreateSegment
  186. STDMETHODIMP CBand::CreateSegment(IDirectMusicSegment** ppSegment)
  187. {
  188. V_INAME(IDirectMusicBand::CreateSegment);
  189. V_PTRPTR_WRITE(ppSegment);
  190. HRESULT hr = CoCreateInstance(CLSID_DirectMusicSegment,
  191. NULL,
  192. CLSCTX_INPROC,
  193. IID_IDirectMusicSegment,
  194. (void**)ppSegment);
  195. if(SUCCEEDED(hr))
  196. {
  197. IDirectMusicTrack* pDMTrack = NULL;
  198. CBandTrk *pBandTrack;
  199. // Create Band track
  200. pBandTrack = new CBandTrk;
  201. if (pBandTrack)
  202. {
  203. pBandTrack->QueryInterface(IID_IDirectMusicTrack,(void**)&pDMTrack);
  204. // Add band to track
  205. m_lTimePhysical--; // Subtract one from the time when creating the segment. This is somewhat arbitrary. (See NT5 bug 226848.)
  206. hr = pBandTrack->AddBand(static_cast<IDirectMusicBand*>(this));
  207. m_lTimePhysical++; // add the one back in
  208. // Set Auto-download to off
  209. pBandTrack->m_bAutoDownload = false;
  210. pBandTrack->m_fLockAutoDownload = true;
  211. // Insert track into segment
  212. hr = (*ppSegment)->InsertTrack(pDMTrack, 1);
  213. pDMTrack->Release();
  214. pBandTrack->Release(); // We don't need the original count created by the constructor.
  215. }
  216. else
  217. {
  218. hr = E_OUTOFMEMORY;
  219. }
  220. }
  221. if(FAILED(hr))
  222. {
  223. if(*ppSegment)
  224. {
  225. (*ppSegment)->Release();
  226. *ppSegment = NULL;
  227. }
  228. }
  229. return hr;
  230. }
  231. HRESULT CBandInstrument::Download(IDirectMusicPerformanceP *pPerformance,
  232. IDirectMusicAudioPath *pPath,
  233. DWORD dwMidiMode)
  234. {
  235. DWORD dwPChannel;
  236. HRESULT hr = S_OK;
  237. // First, if there is an audiopath, convert the band's pchannel to performance pchannel.
  238. if (pPath)
  239. {
  240. hr = pPath->ConvertPChannel(m_dwPChannel,&dwPChannel);
  241. if (FAILED(hr))
  242. {
  243. Trace(1,"Error: Couldn't download to Audiopath because pchannel %ld is out of bounds\n",m_dwPChannel);
  244. // Not a valid pchannel on this audiopath.
  245. return hr;
  246. }
  247. }
  248. else
  249. {
  250. dwPChannel = m_dwPChannel;
  251. }
  252. // We need to get the port we will be downloading to.
  253. IDirectMusicPort *pPort = NULL;
  254. DWORD dwGMFlags;
  255. BOOL fDownload = TRUE;
  256. hr = pPerformance->GetPortAndFlags(dwPChannel,&pPort,&dwGMFlags);
  257. // Once we know the port, we can find out whether a download has
  258. // already occured. And, if not, we'll use that to do the download.
  259. if (SUCCEEDED(hr))
  260. {
  261. CDownloadedInstrument* pDLInstrument = m_DownloadList.GetHead();
  262. for(; pDLInstrument; pDLInstrument = pDLInstrument->GetNext())
  263. {
  264. if (pDLInstrument->m_pPort == pPort)
  265. {
  266. // Increment reference counter and leave.
  267. pDLInstrument->m_cRef++;
  268. pPort->Release();
  269. return S_OK;
  270. }
  271. }
  272. // Okay, didn't find it, so we need to create a download record and download it.
  273. if(m_fNotInFile && !m_fGMOnly)
  274. {
  275. // Unless we've set the GMOnly flag, don't download an instrument
  276. // that was automatically generated from the midi
  277. // parsing to give a patchless channel an instrument.
  278. fDownload = FALSE;
  279. }
  280. else if (m_pIDMCollection == NULL)
  281. {
  282. // Can not download this instrument but still want to add a record and continue with others.
  283. // If instrument is a GM and GS instrument it may still play if GM or GS is supported in hardware.
  284. fDownload = FALSE;
  285. Trace(2,"Warning: No collection, unable to download instrument %lx on PChannel %ld\n",m_dwPatch,m_dwPChannel);
  286. }
  287. if (m_dwFlags & DMUS_IO_INST_GS)
  288. {
  289. // If this is a GS instrument, determine whether it needs to be downloaded.
  290. if ((dwGMFlags & DM_PORTFLAGS_GM) && (m_dwFlags & DMUS_IO_INST_GM))
  291. {
  292. // The synth has a GM set in ROM, and this is a GM instrument,
  293. // and the instrument does not specifically requests that it use the
  294. // DLS version in gm.dls.
  295. if (!(m_dwFlags & DMUS_IO_INST_USE_DEFAULT_GM_SET) )
  296. {
  297. fDownload = FALSE;
  298. }
  299. }
  300. else if (dwGMFlags & DM_PORTFLAGS_GS)
  301. {
  302. // If the synth has a GS set, the problem is simpler, since it is going to be very similar to our
  303. // gm.dls set, so it is okay to use it.
  304. fDownload = FALSE;
  305. }
  306. }
  307. if( dwMidiMode ) // if this is anything, it indicates we were loaded from a midi file
  308. {
  309. // if we're not an XG file, make sure channel 9 is drums
  310. if( (dwMidiMode != DMUS_MIDIMODEF_XG) &&
  311. (m_dwPChannel == 9) )
  312. {
  313. m_dwPatch |= 0x80000000;
  314. }
  315. }
  316. // Okay, ready to download...
  317. if (fDownload)
  318. {
  319. hr = DownloadAddRecord(pPort);
  320. // Use fallbacks for XG mode
  321. if( FAILED(hr) && dwMidiMode == DMUS_MIDIMODEF_XG )
  322. {
  323. DWORD dwOldPatch = m_dwPatch;
  324. DWORD dwOldFlags = m_dwFlags;
  325. DWORD dwOldAssignPatch = m_dwAssignPatch;
  326. // If this band failed, try clearing the MSB. If it was an XG or GS instrument,
  327. // and the collection doesn't have the instrument, clearing the MSB is a
  328. // good fallback. If that doesn't work, try clearing the LSB.
  329. // Also, if this band is XG see if it is on the drum channel. If so,
  330. // try setting the drum bit.
  331. if( (m_dwPatch & 0x00ff0000) == 0x007f0000 )
  332. {
  333. // XG drums. Try GM drums instead, but keep program change
  334. m_dwPatch &= 0xff0000ff; // clear MSB and LSB
  335. m_dwPatch |= 0x80000000; // set drum bit
  336. m_dwFlags |= DMUS_IO_INST_ASSIGN_PATCH;
  337. m_dwAssignPatch = dwOldPatch & 0x00ffffff;
  338. hr = DownloadAddRecord(pPort);
  339. if( FAILED(hr) )
  340. {
  341. // If that didn't work, try unsetting the program change
  342. m_dwPatch = 0x80000000;
  343. hr = DownloadAddRecord(pPort);
  344. }
  345. }
  346. else
  347. {
  348. if( (m_dwPatch & 0x00ff0000) != 0x007e0000 )
  349. {
  350. m_dwPatch &= 0xffff00ff; // clear LSB
  351. hr = DownloadAddRecord(pPort);
  352. if( FAILED(hr) )
  353. {
  354. if( m_dwPatch & 0x0000ff00 )
  355. {
  356. m_dwPatch &= 0xff0000ff; // clear MSB & LSB
  357. hr = DownloadAddRecord(pPort);
  358. }
  359. }
  360. }
  361. }
  362. if (FAILED(hr))
  363. {
  364. // Revert back to original values
  365. m_dwPatch = dwOldPatch;
  366. m_dwFlags = dwOldFlags;
  367. m_dwAssignPatch = dwOldAssignPatch;
  368. }
  369. }
  370. }
  371. pPort->Release();
  372. }
  373. else
  374. {
  375. Trace(1,"Error: Unable to download to Performance because pchannel %ld is not initialized on the performance.\n",m_dwPChannel);
  376. }
  377. return hr;
  378. }
  379. //////////////////////////////////////////////////////////////////////
  380. // CBand::DownloadEx
  381. STDMETHODIMP
  382. CBand::DownloadEx(IUnknown *pAudioPath)
  383. {
  384. V_INAME(CBand::DownloadEx);
  385. V_PTR_READ(pAudioPath, IUnknown);
  386. BOOL fGotOneDown = FALSE;
  387. BOOL fNoInit = FALSE;
  388. IDirectMusicPerformance *pPerformance = NULL;
  389. IDirectMusicAudioPath *pPath = NULL;
  390. // If the band doesn't have any instruments, return immediately with S_FALSE.
  391. if (m_BandInstrumentList.IsEmpty())
  392. {
  393. Trace(2,"Warning: Trying to download an empty band\n");
  394. return S_FALSE;
  395. }
  396. HRESULT hr = pAudioPath->QueryInterface(IID_IDirectMusicAudioPath,(void **)&pPath);
  397. if (SUCCEEDED(hr))
  398. {
  399. hr = pPath->GetObjectInPath(0,DMUS_PATH_PERFORMANCE,0,CLSID_DirectMusicPerformance,0,IID_IDirectMusicPerformance,(void **)&pPerformance);
  400. }
  401. else
  402. {
  403. hr = pAudioPath->QueryInterface(IID_IDirectMusicPerformance,(void **)&pPerformance);
  404. }
  405. if (SUCCEEDED(hr))
  406. {
  407. EnterCriticalSection(&m_CriticalSection);
  408. IDirectMusicPerformanceP *pPerfp;
  409. hr = pPerformance->QueryInterface(IID_IDirectMusicPerformanceP, (void **)&pPerfp);
  410. if (SUCCEEDED(hr))
  411. {
  412. DWORD dwSuccess = 0;
  413. HRESULT hrTemp = S_OK;
  414. CBandInstrument* pBandInstrument = m_BandInstrumentList.GetHead();
  415. for( ; SUCCEEDED(hr) && pBandInstrument != NULL; pBandInstrument = pBandInstrument->GetNext())
  416. {
  417. hr = pBandInstrument->Download(pPerfp,pPath,m_dwMidiMode);
  418. if (FAILED(hr))
  419. {
  420. if (hr == DMUS_E_NOT_INIT)
  421. {
  422. Trace(1,"Error: Performance is not initialized - Band download terminated.\n");
  423. // Performance is not initialized. Leave now.
  424. break;
  425. }
  426. hrTemp = hr;
  427. hr = S_FALSE;
  428. }
  429. else
  430. {
  431. // At least one succeeded.
  432. dwSuccess++;
  433. }
  434. }
  435. // If we had a failure but it was not performance not initialized and we did have at least one
  436. // successful download, return a partial download success code.
  437. if (FAILED(hrTemp))
  438. {
  439. // Was this a partial download?
  440. if ((hr != DMUS_E_NOT_INIT) && dwSuccess)
  441. {
  442. hr = DMUS_S_PARTIALDOWNLOAD;
  443. }
  444. // Otherwise, make sure we don't return S_FALSE for hr!
  445. else
  446. {
  447. hr = hrTemp;
  448. }
  449. }
  450. pPerfp->Release();
  451. }
  452. LeaveCriticalSection(&m_CriticalSection);
  453. }
  454. if (pPath) pPath->Release();
  455. if (pPerformance) pPerformance->Release();
  456. return hr;
  457. }
  458. STDMETHODIMP
  459. CBand::Download(
  460. IDirectMusicPerformance* pPerformance) // @parm Performance to download instruments
  461. // to. The performance manages the mapping
  462. // of PChannels to DirectMusic ports.
  463. {
  464. V_INAME(CBand::Download);
  465. V_PTR_READ(pPerformance, IDirectMusicPerformance);
  466. return DownloadEx(pPerformance);
  467. }
  468. HRESULT CBandInstrument::Unload(IDirectMusicPerformanceP *pPerformance, IDirectMusicAudioPath *pPath)
  469. {
  470. DWORD dwPChannel;
  471. HRESULT hr = S_OK;
  472. // First, if there is an audiopath, convert the band's pchannel to performance pchannel.
  473. if (pPath)
  474. {
  475. hr = pPath->ConvertPChannel(m_dwPChannel,&dwPChannel);
  476. if (FAILED(hr))
  477. {
  478. Trace(1,"Error: Couldn't download to Audiopath because pchannel %ld is out of bounds\n",m_dwPChannel);
  479. // Not a valid pchannel on this audiopath.
  480. return hr;
  481. }
  482. }
  483. else
  484. {
  485. dwPChannel = m_dwPChannel;
  486. }
  487. // We need to get the port we will be unloading from.
  488. IDirectMusicPort *pPort = NULL;
  489. DWORD dwGMFlags;
  490. hr = pPerformance->GetPortAndFlags(dwPChannel,&pPort,&dwGMFlags);
  491. if (SUCCEEDED(hr))
  492. {
  493. hr = S_FALSE; // Just in case we don't find the download record.
  494. CDownloadedInstrument* pDLInstrument = m_DownloadList.GetHead();
  495. for(; pDLInstrument; pDLInstrument = pDLInstrument->GetNext())
  496. {
  497. if (pDLInstrument->m_pPort == pPort)
  498. {
  499. pDLInstrument->m_cRef--;
  500. if(!pDLInstrument->m_cRef)
  501. {
  502. m_DownloadList.Remove(pDLInstrument);
  503. if (FAILED(pPort->UnloadInstrument(pDLInstrument->m_pDLInstrument)))
  504. {
  505. Trace(1, "Error: UnloadInstrument %ld failed\n",m_dwPatch);
  506. }
  507. pDLInstrument->m_pDLInstrument->Release();
  508. pDLInstrument->m_pDLInstrument = NULL;
  509. delete pDLInstrument;
  510. }
  511. hr = S_OK;
  512. break;
  513. }
  514. }
  515. pPort->Release();
  516. }
  517. else if (!pPath && m_DownloadList.GetCount() == 1)
  518. {
  519. CDownloadedInstrument* pDLInstrument = m_DownloadList.GetHead();
  520. pDLInstrument->m_cRef--;
  521. if (!pDLInstrument->m_cRef)
  522. {
  523. m_DownloadList.Remove(pDLInstrument);
  524. if (FAILED(pDLInstrument->m_pPort->UnloadInstrument(pDLInstrument->m_pDLInstrument)))
  525. {
  526. Trace(1, "Error: UnloadInstrument %ld failed\n",m_dwPatch);
  527. }
  528. pDLInstrument->m_pDLInstrument->Release();
  529. pDLInstrument->m_pDLInstrument = NULL;
  530. delete pDLInstrument;
  531. }
  532. hr = S_OK;
  533. }
  534. return hr;
  535. }
  536. //////////////////////////////////////////////////////////////////////
  537. // CBand::UnloadEx
  538. STDMETHODIMP
  539. CBand::UnloadEx(IUnknown *pAudioPath)
  540. {
  541. V_INAME(CBand::UnloadEx);
  542. V_PTR_READ(pAudioPath, IUnknown);
  543. IDirectMusicPerformance *pPerformance = NULL;
  544. IDirectMusicAudioPath *pPath = NULL;
  545. HRESULT hr = pAudioPath->QueryInterface(IID_IDirectMusicAudioPath,(void **)&pPath);
  546. if (SUCCEEDED(hr))
  547. {
  548. hr = pPath->GetObjectInPath(0,DMUS_PATH_PERFORMANCE,0,CLSID_DirectMusicPerformance,0,IID_IDirectMusicPerformance,(void **)&pPerformance);
  549. }
  550. else
  551. {
  552. hr = pAudioPath->QueryInterface(IID_IDirectMusicPerformance,(void **)&pPerformance);
  553. }
  554. if (SUCCEEDED(hr))
  555. {
  556. hr = S_FALSE; // Returns this for empty band.
  557. EnterCriticalSection(&m_CriticalSection);
  558. IDirectMusicPerformanceP *pPerfp;
  559. hr = pPerformance->QueryInterface(IID_IDirectMusicPerformanceP, (void **)&pPerfp);
  560. if (SUCCEEDED(hr))
  561. {
  562. CBandInstrument* pBandInstrument = m_BandInstrumentList.GetHead();
  563. for( ; pBandInstrument != NULL; pBandInstrument = pBandInstrument->GetNext())
  564. {
  565. hr = pBandInstrument->Unload(pPerfp,pPath);
  566. }
  567. pPerfp->Release();
  568. }
  569. LeaveCriticalSection(&m_CriticalSection);
  570. }
  571. if (pPath) pPath->Release();
  572. if (pPerformance) pPerformance->Release();
  573. return hr;
  574. }
  575. STDMETHODIMP
  576. CBand::Unload(
  577. IDirectMusicPerformance* pPerformance) // @parm Performance to unload instruments
  578. // from. The performance manages the mapping
  579. // of PChannels to DirectMusic ports.
  580. {
  581. V_INAME(CBand::Unload);
  582. V_PTR_READ(pPerformance, IDirectMusicPerformance);
  583. return UnloadEx(pPerformance);
  584. }
  585. //////////////////////////////////////////////////////////////////////
  586. // IDirectMusicObject
  587. //////////////////////////////////////////////////////////////////////
  588. // CBand::GetDescriptor
  589. STDMETHODIMP CBand::GetDescriptor(LPDMUS_OBJECTDESC pDesc)
  590. {
  591. V_INAME(CBand::GetDescriptor);
  592. V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
  593. if (pDesc->dwSize)
  594. {
  595. V_STRUCTPTR_WRITE(pDesc, DMUS_OBJECTDESC);
  596. }
  597. else
  598. {
  599. pDesc->dwSize = sizeof(DMUS_OBJECTDESC);
  600. }
  601. pDesc->guidClass = CLSID_DirectMusicBand;
  602. pDesc->guidObject = m_guidObject;
  603. pDesc->ftDate = m_ftDate;
  604. pDesc->vVersion = m_vVersion;
  605. memcpy( pDesc->wszName, m_wszName, sizeof(m_wszName) );
  606. memcpy( pDesc->wszCategory, m_wszCategory, sizeof(m_wszCategory) );
  607. memcpy( pDesc->wszFileName, m_wszFileName, sizeof(m_wszFileName) );
  608. pDesc->dwValidData = ( m_dwValidData | DMUS_OBJ_CLASS );
  609. return S_OK;
  610. }
  611. //////////////////////////////////////////////////////////////////////
  612. // CBand::SetDescriptor
  613. STDMETHODIMP CBand::SetDescriptor(LPDMUS_OBJECTDESC pDesc)
  614. {
  615. // Argument validation
  616. V_INAME(CBand::SetDescriptor);
  617. V_PTR_READ(pDesc, DMUS_OBJECTDESC);
  618. if (pDesc->dwSize)
  619. {
  620. V_STRUCTPTR_READ(pDesc, DMUS_OBJECTDESC);
  621. }
  622. HRESULT hr = E_INVALIDARG;
  623. DWORD dw = 0;
  624. if( pDesc->dwValidData & DMUS_OBJ_OBJECT )
  625. {
  626. m_guidObject = pDesc->guidObject;
  627. dw |= DMUS_OBJ_OBJECT;
  628. }
  629. if( pDesc->dwValidData & DMUS_OBJ_NAME )
  630. {
  631. memcpy( m_wszName, pDesc->wszName, sizeof(WCHAR)*DMUS_MAX_NAME );
  632. dw |= DMUS_OBJ_NAME;
  633. }
  634. if( pDesc->dwValidData & DMUS_OBJ_CATEGORY )
  635. {
  636. memcpy( m_wszCategory, pDesc->wszCategory, sizeof(WCHAR)*DMUS_MAX_CATEGORY );
  637. dw |= DMUS_OBJ_CATEGORY;
  638. }
  639. if( ( pDesc->dwValidData & DMUS_OBJ_FILENAME ) ||
  640. ( pDesc->dwValidData & DMUS_OBJ_FULLPATH ) )
  641. {
  642. memcpy( m_wszFileName, pDesc->wszFileName, sizeof(WCHAR)*DMUS_MAX_FILENAME );
  643. dw |= (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH));
  644. }
  645. if( pDesc->dwValidData & DMUS_OBJ_VERSION )
  646. {
  647. m_vVersion = pDesc->vVersion;
  648. dw |= DMUS_OBJ_VERSION;
  649. }
  650. if( pDesc->dwValidData & DMUS_OBJ_DATE )
  651. {
  652. m_ftDate = pDesc->ftDate;
  653. dw |= DMUS_OBJ_DATE;
  654. }
  655. m_dwValidData |= dw;
  656. if( pDesc->dwValidData & (~dw) )
  657. {
  658. hr = S_FALSE; // there were extra fields we didn't parse;
  659. pDesc->dwValidData = dw;
  660. }
  661. else
  662. {
  663. hr = S_OK;
  664. }
  665. return hr;
  666. }
  667. //////////////////////////////////////////////////////////////////////
  668. // CBand::ParseDescriptor
  669. STDMETHODIMP CBand::ParseDescriptor(LPSTREAM pStream, LPDMUS_OBJECTDESC pDesc)
  670. {
  671. V_INAME(CBand::ParseDescriptor);
  672. V_PTR_READ(pStream, IStream);
  673. V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
  674. if (pDesc->dwSize)
  675. {
  676. V_STRUCTPTR_WRITE(pDesc, DMUS_OBJECTDESC);
  677. }
  678. else
  679. {
  680. pDesc->dwSize = sizeof(DMUS_OBJECTDESC);
  681. }
  682. RIFFIO ckMain;
  683. HRESULT hr = S_OK;
  684. CRiffParser Parser(pStream);
  685. Parser.EnterList(&ckMain);
  686. if (Parser.NextChunk(&hr))
  687. {
  688. pDesc->guidClass = CLSID_DirectMusicBand;
  689. pDesc->dwValidData |= DMUS_OBJ_CLASS;
  690. if (ckMain.fccType == FOURCC_BAND_FORM)
  691. {
  692. hr = ParseLegacyDescriptor(&Parser, pDesc);
  693. }
  694. else if(ckMain.fccType == DMUS_FOURCC_BAND_FORM)
  695. {
  696. hr = ParseDirectMusicDescriptor(&Parser, pDesc);
  697. }
  698. else
  699. {
  700. Trace(2,"Warning: ParseDescriptor failed because this is not a Band file.\n");
  701. hr = DMUS_E_INVALID_BAND;
  702. }
  703. }
  704. return hr;
  705. }
  706. //////////////////////////////////////////////////////////////////////
  707. // Internal
  708. //////////////////////////////////////////////////////////////////////
  709. // CBand::ParseLegacyDescriptor
  710. HRESULT CBand::ParseLegacyDescriptor(CRiffParser *pParser, LPDMUS_OBJECTDESC pDesc)
  711. {
  712. RIFFIO ckNext;
  713. HRESULT hr = S_OK;
  714. pParser->EnterList(&ckNext);
  715. while(pParser->NextChunk(&hr))
  716. {
  717. if (ckNext.ckid == FOURCC_BAND)
  718. {
  719. ioBandLegacy Band;
  720. hr = pParser->Read( &Band, sizeof(Band) );
  721. if( SUCCEEDED(hr) )
  722. {
  723. pDesc->dwValidData |= DMUS_OBJ_NAME;
  724. wcsncpy(pDesc->wszName, Band.wstrName, MAX_LEGACY_BAND_NAME);
  725. pDesc->wszName[MAX_LEGACY_BAND_NAME - 1] = 0;
  726. }
  727. }
  728. }
  729. return hr;
  730. }
  731. //////////////////////////////////////////////////////////////////////
  732. // CBand::ParseDirectMusicDescriptor
  733. HRESULT CBand::ParseDirectMusicDescriptor(CRiffParser *pParser, LPDMUS_OBJECTDESC pDesc)
  734. {
  735. RIFFIO ckNext;
  736. RIFFIO ckUNFO;
  737. HRESULT hr = S_OK;
  738. DWORD dwValidData = pDesc->dwValidData;
  739. pParser->EnterList(&ckNext);
  740. while(pParser->NextChunk(&hr))
  741. {
  742. switch(ckNext.ckid)
  743. {
  744. case DMUS_FOURCC_GUID_CHUNK:
  745. hr = pParser->Read( &pDesc->guidObject, sizeof(GUID) );
  746. dwValidData |= DMUS_OBJ_OBJECT;
  747. break;
  748. case DMUS_FOURCC_VERSION_CHUNK:
  749. hr = pParser->Read( &pDesc->vVersion, sizeof(DMUS_VERSION) );
  750. dwValidData |= DMUS_OBJ_VERSION;
  751. break;
  752. case DMUS_FOURCC_CATEGORY_CHUNK:
  753. hr = pParser->Read( &pDesc->wszCategory, sizeof(pDesc->wszCategory) );
  754. pDesc->wszCategory[DMUS_MAX_CATEGORY - 1] = 0;
  755. dwValidData |= DMUS_OBJ_CATEGORY;
  756. case DMUS_FOURCC_DATE_CHUNK:
  757. hr = pParser->Read( &pDesc->ftDate, sizeof(FILETIME) );
  758. dwValidData |= DMUS_OBJ_DATE;
  759. break;
  760. case FOURCC_LIST:
  761. switch(ckNext.fccType)
  762. {
  763. case DMUS_FOURCC_UNFO_LIST:
  764. pParser->EnterList(&ckUNFO);
  765. while (pParser->NextChunk(&hr))
  766. {
  767. if (( ckUNFO.ckid == DMUS_FOURCC_UNAM_CHUNK ) ||
  768. (ckUNFO.ckid == mmioFOURCC('I','N','A','M')))
  769. {
  770. hr = pParser->Read(&pDesc->wszName, sizeof(pDesc->wszName));
  771. pDesc->wszName[DMUS_MAX_NAME - 1] = 0;
  772. dwValidData |= DMUS_OBJ_NAME;
  773. }
  774. }
  775. pParser->LeaveList();
  776. break;
  777. }
  778. break;
  779. }
  780. }
  781. if (SUCCEEDED(hr))
  782. {
  783. pDesc->dwValidData = dwValidData;
  784. }
  785. return hr;
  786. }
  787. //////////////////////////////////////////////////////////////////////
  788. // CBand::LoadLegacyBand
  789. HRESULT CBand::LoadLegacyBand(CRiffParser *pParser, IDirectMusicLoader* pIDMLoader)
  790. {
  791. RIFFIO ckNext;
  792. HRESULT hr = S_OK;
  793. pParser->EnterList(&ckNext);
  794. while(pParser->NextChunk(&hr))
  795. {
  796. if (ckNext.ckid == FOURCC_BAND)
  797. {
  798. ioBandLegacy Band;
  799. hr = pParser->Read( &Band, sizeof(Band) );
  800. if( SUCCEEDED(hr) )
  801. {
  802. wcsncpy(m_wszName, Band.wstrName, MAX_LEGACY_BAND_NAME);
  803. m_wszName[MAX_LEGACY_BAND_NAME - 1] = 0;
  804. m_dwValidData |= DMUS_OBJ_NAME;
  805. hr = BuildLegacyInstrumentList(Band, pIDMLoader);
  806. if (SUCCEEDED(hr))
  807. {
  808. m_dwFlags |= DMB_LOADED;
  809. if(Band.fDefault)
  810. {
  811. m_dwFlags |= DMB_DEFAULT;
  812. }
  813. }
  814. }
  815. }
  816. }
  817. return hr;
  818. }
  819. //////////////////////////////////////////////////////////////////////
  820. // CBand::LoadDirectMusicBand
  821. HRESULT CBand::LoadDirectMusicBand(CRiffParser *pParser, IDirectMusicLoader *pIDMLoader)
  822. {
  823. HRESULT hrDLS = S_OK;
  824. RIFFIO ckNext;
  825. RIFFIO ckChild;
  826. HRESULT hr = S_OK;
  827. pParser->EnterList(&ckNext);
  828. while(pParser->NextChunk(&hr))
  829. {
  830. switch(ckNext.ckid)
  831. {
  832. case DMUS_FOURCC_GUID_CHUNK:
  833. hr = pParser->Read( &m_guidObject, sizeof(GUID) );
  834. m_dwValidData |= DMUS_OBJ_OBJECT;
  835. break;
  836. case DMUS_FOURCC_VERSION_CHUNK:
  837. hr = pParser->Read( &m_vVersion, sizeof(DMUS_VERSION) );
  838. m_dwValidData |= DMUS_OBJ_VERSION;
  839. break;
  840. case DMUS_FOURCC_CATEGORY_CHUNK:
  841. hr = pParser->Read( &m_wszCategory, sizeof(WCHAR)*DMUS_MAX_CATEGORY );
  842. m_wszCategory[DMUS_MAX_CATEGORY - 1] = 0;
  843. m_dwValidData |= DMUS_OBJ_CATEGORY;
  844. break;
  845. case DMUS_FOURCC_DATE_CHUNK:
  846. hr = pParser->Read( &m_ftDate, sizeof(FILETIME) );
  847. m_dwValidData |= DMUS_OBJ_DATE;
  848. break;
  849. case FOURCC_LIST:
  850. switch(ckNext.fccType)
  851. {
  852. case DMUS_FOURCC_UNFO_LIST:
  853. pParser->EnterList(&ckChild);
  854. while (pParser->NextChunk(&hr))
  855. {
  856. if (( ckChild.ckid == DMUS_FOURCC_UNAM_CHUNK ) ||
  857. (ckChild.ckid == mmioFOURCC('I','N','A','M')))
  858. {
  859. hr = pParser->Read(&m_wszName, sizeof(m_wszName));
  860. m_wszName[DMUS_MAX_NAME - 1] = 0;
  861. m_dwValidData |= DMUS_OBJ_NAME;
  862. }
  863. }
  864. pParser->LeaveList();
  865. break;
  866. case DMUS_FOURCC_INSTRUMENTS_LIST:
  867. pParser->EnterList(&ckChild);
  868. while (pParser->NextChunk(&hr))
  869. {
  870. if ((ckChild.ckid == FOURCC_LIST) &&
  871. (ckChild.fccType == DMUS_FOURCC_INSTRUMENT_LIST))
  872. {
  873. hr = ExtractBandInstrument(pParser, pIDMLoader);
  874. if (hr != S_OK)
  875. {
  876. hrDLS = hr;
  877. }
  878. }
  879. }
  880. pParser->LeaveList();
  881. break;
  882. }
  883. }
  884. }
  885. pParser->LeaveList();
  886. if (hr == S_OK && hrDLS != S_OK)
  887. {
  888. hr = hrDLS;
  889. }
  890. return hr;
  891. }
  892. //////////////////////////////////////////////////////////////////////
  893. // CBand::BuildLegacyInstrumentList
  894. HRESULT CBand::BuildLegacyInstrumentList(const ioBandLegacy& iob,
  895. IDirectMusicLoader* pIDMLoader)
  896. {
  897. // Legacy band channel to pchannel translation table
  898. static char sj_translation_table[] = { -1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3 };
  899. HRESULT hrGM = S_OK;
  900. HRESULT hr = S_OK;
  901. EnterCriticalSection(&m_CriticalSection);
  902. char szCollection[DM_LEGACY_BAND_COLLECTION_NAME_LEN];
  903. for(DWORD i = 0; SUCCEEDED(hr) && i < DMBAND_NUM_LEGACY_INSTRUMENTS; i++)
  904. {
  905. CBandInstrument* pBandInstrument = new CBandInstrument();
  906. if(pBandInstrument)
  907. {
  908. if(iob.awDLSBank[i] & 0x8000)
  909. {
  910. // We have a plain old GM collection where MSB & LSB are both zero
  911. pBandInstrument->m_dwPatch = 0;
  912. pBandInstrument->m_dwPatch |= (iob.abPatch[i] & 0x7F);
  913. pBandInstrument->m_dwFlags |= (DMUS_IO_INST_GM | DMUS_IO_INST_GS);
  914. }
  915. else
  916. {
  917. if(iob.awDLSBank[i] & 0x4000)
  918. {
  919. // We has a GS collection with valid MSB and LSB numbers
  920. pBandInstrument->m_dwPatch = 0;
  921. pBandInstrument->m_dwPatch |= (iob.abDLSPatch[i] & 0x7F);
  922. pBandInstrument->m_dwPatch |= (iob.awDLSBank[i] & 0x7F) << 8; // Set LSB
  923. pBandInstrument->m_dwPatch |= ((iob.awDLSBank[i] >> 7) & 0x7F) << 16; // Set MSB
  924. pBandInstrument->m_dwFlags |= (DMUS_IO_INST_BANKSELECT | DMUS_IO_INST_GS | DMUS_IO_INST_GM);
  925. }
  926. else
  927. {
  928. if(iob.szCollection[0] == '\0')
  929. {
  930. // We have no unique DLS file so we will assume GM
  931. pBandInstrument->m_dwPatch = 0;
  932. pBandInstrument->m_dwPatch |= (iob.abPatch[i] & 0x7F);
  933. pBandInstrument->m_dwFlags |= (DMUS_IO_INST_GM | DMUS_IO_INST_GS);
  934. }
  935. else
  936. {
  937. // We have a unique DLS file
  938. pBandInstrument->m_dwPatch = 0;
  939. pBandInstrument->m_dwPatch |= (iob.abDLSPatch[i] & 0x7F);
  940. pBandInstrument->m_dwPatch |= (iob.awDLSBank[i] & 0x7F) << 8; // Set LSB
  941. pBandInstrument->m_dwPatch |= ((iob.awDLSBank[i] >> 7) & 0x7F) << 16; // Set MSB
  942. pBandInstrument->m_dwFlags |= (DMUS_IO_INST_BANKSELECT);
  943. lstrcpyn(szCollection, iob.szCollection, MAX_LEGACY_COLLECTION_NAME);
  944. szCollection[MAX_LEGACY_COLLECTION_NAME - 1] = '\0';
  945. }
  946. }
  947. }
  948. pBandInstrument->m_dwFlags |= (DMUS_IO_INST_TRANSPOSE | DMUS_IO_INST_PAN | DMUS_IO_INST_VOLUME | DMUS_IO_INST_PATCH);
  949. pBandInstrument->m_bPan = iob.abPan[i];
  950. pBandInstrument->m_bVolume = iob.abVolume[i];
  951. pBandInstrument->m_dwPChannel = sj_translation_table[i + 1];
  952. // Set drum-kit bit if a drum-kit
  953. if(pBandInstrument->m_dwPChannel % 16 == 9)
  954. {
  955. pBandInstrument->m_dwPatch |= 0x80000000;
  956. }
  957. pBandInstrument->m_nTranspose = iob.achOctave[i];
  958. pBandInstrument->m_pIDMCollection = NULL;
  959. // We will try to load the collection but if we can not we will continure
  960. // and use the default GM on the card
  961. if(pIDMLoader && (pBandInstrument->m_dwFlags & DMUS_IO_INST_GM || pBandInstrument->m_dwFlags & DMUS_IO_INST_GS))
  962. {
  963. HRESULT hrTemp = LoadCollection(&(pBandInstrument->m_pIDMCollection),
  964. NULL,
  965. pIDMLoader);
  966. if (FAILED(hrTemp))
  967. {
  968. hrGM = hrTemp;
  969. }
  970. }
  971. else if(pIDMLoader)
  972. {
  973. HRESULT hrTemp = LoadCollection(&(pBandInstrument->m_pIDMCollection),
  974. szCollection,
  975. pIDMLoader);
  976. if (FAILED(hrTemp))
  977. {
  978. hrGM = hrTemp;
  979. }
  980. }
  981. m_BandInstrumentList.AddHead(pBandInstrument);
  982. }
  983. else
  984. {
  985. hr = E_OUTOFMEMORY;
  986. }
  987. }
  988. LeaveCriticalSection(&m_CriticalSection);
  989. // This function expects the caller to cleanup m_BandInstrumentList on any errors
  990. if (SUCCEEDED(hrGM) || hr != S_OK)
  991. {
  992. return hr;
  993. }
  994. else
  995. {
  996. return DMUS_S_PARTIALLOAD;
  997. }
  998. }
  999. //////////////////////////////////////////////////////////////////////
  1000. // CBand::ExtractBandInstrument
  1001. HRESULT CBand::ExtractBandInstrument(CRiffParser *pParser,
  1002. IDirectMusicLoader* pIDMLoader)
  1003. {
  1004. CBandInstrument* pBandInstrument = new CBandInstrument();
  1005. if(pBandInstrument == NULL)
  1006. {
  1007. return E_OUTOFMEMORY;
  1008. }
  1009. RIFFIO ckNext;
  1010. HRESULT hrGM = S_OK;
  1011. HRESULT hr = S_OK;
  1012. pParser->EnterList(&ckNext);
  1013. while (pParser->NextChunk(&hr))
  1014. {
  1015. switch(ckNext.ckid)
  1016. {
  1017. case DMUS_FOURCC_INSTRUMENT_CHUNK:
  1018. {
  1019. DMUS_IO_INSTRUMENT ioDMInst;
  1020. ZeroMemory( &ioDMInst, sizeof(DMUS_IO_INSTRUMENT) );
  1021. hr = pParser->Read(&ioDMInst, sizeof(DMUS_IO_INSTRUMENT));
  1022. if(SUCCEEDED(hr))
  1023. {
  1024. pBandInstrument->m_dwPatch = ioDMInst.dwPatch;
  1025. pBandInstrument->m_dwAssignPatch = ioDMInst.dwAssignPatch;
  1026. pBandInstrument->m_bPan = ioDMInst.bPan;
  1027. pBandInstrument->m_bVolume = ioDMInst.bVolume;
  1028. pBandInstrument->m_dwPChannel = ioDMInst.dwPChannel;
  1029. pBandInstrument->m_nTranspose = ioDMInst.nTranspose;
  1030. pBandInstrument->m_dwFlags = ioDMInst.dwFlags;
  1031. pBandInstrument->m_dwChannelPriority = ioDMInst.dwChannelPriority;
  1032. pBandInstrument->m_nPitchBendRange = ioDMInst.nPitchBendRange;
  1033. CopyMemory(&(pBandInstrument->m_dwNoteRanges[0]),
  1034. &(ioDMInst.dwNoteRanges[0]),
  1035. (sizeof(DWORD) * 4));
  1036. pBandInstrument->m_pIDMCollection = NULL;
  1037. }
  1038. }
  1039. break;
  1040. case FOURCC_LIST :
  1041. switch(ckNext.fccType)
  1042. {
  1043. case DMUS_FOURCC_REF_LIST:
  1044. // We can only load if we have a valid loader
  1045. if(pIDMLoader)
  1046. {
  1047. HRESULT hrTemp = GetCollectionRefAndLoad(pParser,pIDMLoader,pBandInstrument);
  1048. if (FAILED(hrTemp))
  1049. {
  1050. hrGM = hrTemp;
  1051. }
  1052. }
  1053. break;
  1054. }
  1055. break;
  1056. }
  1057. }
  1058. pParser->LeaveList();
  1059. if(SUCCEEDED(hr))
  1060. {
  1061. if(pIDMLoader &&
  1062. pBandInstrument->m_pIDMCollection == NULL &&
  1063. (pBandInstrument->m_dwFlags & (DMUS_IO_INST_GM | DMUS_IO_INST_GS | DMUS_IO_INST_XG)) )
  1064. {
  1065. HRESULT hrTemp = LoadCollection(&(pBandInstrument->m_pIDMCollection),
  1066. NULL,
  1067. pIDMLoader);
  1068. if (FAILED(hrTemp))
  1069. {
  1070. hrGM = hrTemp;
  1071. }
  1072. }
  1073. m_BandInstrumentList.AddHead(pBandInstrument);
  1074. }
  1075. else
  1076. {
  1077. delete pBandInstrument;
  1078. }
  1079. if (SUCCEEDED(hrGM) || hr != S_OK)
  1080. {
  1081. return hr;
  1082. }
  1083. else
  1084. {
  1085. return DMUS_S_PARTIALLOAD;
  1086. }
  1087. }
  1088. //////////////////////////////////////////////////////////////////////
  1089. // CBand::GetCollectionRefAndLoad
  1090. HRESULT CBand::GetCollectionRefAndLoad(CRiffParser *pParser,
  1091. IDirectMusicLoader *pIDMLoader,
  1092. CBandInstrument *pBandInstrument)
  1093. {
  1094. DMUS_OBJECTDESC desc;
  1095. desc.dwValidData = 0;
  1096. desc.dwSize = sizeof(desc);
  1097. RIFFIO ckNext;
  1098. HRESULT hr = S_OK;
  1099. pParser->EnterList(&ckNext);
  1100. while (pParser->NextChunk(&hr))
  1101. {
  1102. switch(ckNext.ckid)
  1103. {
  1104. case DMUS_FOURCC_REF_CHUNK:
  1105. DMUS_IO_REFERENCE ioDMRef;
  1106. hr = pParser->Read(&ioDMRef, sizeof(DMUS_IO_REFERENCE));
  1107. desc.guidClass = ioDMRef.guidClassID;
  1108. desc.dwValidData |= ioDMRef.dwValidData;
  1109. desc.dwValidData |= DMUS_OBJ_CLASS;
  1110. break;
  1111. case DMUS_FOURCC_GUID_CHUNK:
  1112. hr = pParser->Read(&(desc.guidObject), sizeof(GUID));
  1113. desc.dwValidData |= DMUS_OBJ_OBJECT;
  1114. break;
  1115. case DMUS_FOURCC_DATE_CHUNK:
  1116. hr = pParser->Read(&(desc.ftDate), sizeof(FILETIME));
  1117. desc.dwValidData |= DMUS_OBJ_DATE;
  1118. break;
  1119. case DMUS_FOURCC_NAME_CHUNK:
  1120. hr = pParser->Read(desc.wszName, sizeof(desc.wszName));
  1121. desc.wszName[DMUS_MAX_NAME - 1] = 0;
  1122. desc.dwValidData |= DMUS_OBJ_NAME;
  1123. break;
  1124. case DMUS_FOURCC_FILE_CHUNK:
  1125. hr = pParser->Read(desc.wszFileName, sizeof(desc.wszFileName));
  1126. desc.wszFileName[DMUS_MAX_FILENAME - 1] = 0;
  1127. desc.dwValidData |= DMUS_OBJ_FILENAME;
  1128. break;
  1129. case DMUS_FOURCC_CATEGORY_CHUNK:
  1130. hr = pParser->Read(desc.wszCategory, sizeof(desc.wszCategory));
  1131. desc.wszCategory[DMUS_MAX_CATEGORY - 1] = 0;
  1132. desc.dwValidData |= DMUS_OBJ_CATEGORY;
  1133. break;
  1134. case DMUS_FOURCC_VERSION_CHUNK:
  1135. DMUS_IO_VERSION dmioVer;
  1136. hr = pParser->Read(&dmioVer, sizeof(DMUS_IO_VERSION));
  1137. desc.vVersion.dwVersionMS = dmioVer.dwVersionMS;
  1138. desc.vVersion.dwVersionLS = dmioVer.dwVersionLS;
  1139. desc.dwValidData |= DMUS_OBJ_VERSION;
  1140. break;
  1141. }
  1142. }
  1143. pParser->LeaveList();
  1144. if(SUCCEEDED(hr))
  1145. {
  1146. hr = pIDMLoader->GetObject(&desc,IID_IDirectMusicCollection, (void**)&(pBandInstrument->m_pIDMCollection));
  1147. }
  1148. #ifdef DBG
  1149. if (FAILED(hr))
  1150. {
  1151. if (desc.dwValidData & DMUS_OBJ_FILENAME)
  1152. {
  1153. Trace(1,"Error: Unable to load DLS Collection from file %ls for instrument %lx\n",
  1154. desc.wszFileName, pBandInstrument->m_dwPatch);
  1155. }
  1156. else if (desc.dwValidData & DMUS_OBJ_NAME)
  1157. {
  1158. Trace(1,"Error: Unable to load DLS Collection %ls for instrument %lx\n",
  1159. desc.wszName, pBandInstrument->m_dwPatch);
  1160. }
  1161. else
  1162. {
  1163. Trace(1,"Error: Unable to load DLS Collection for instrument %lx\n",
  1164. pBandInstrument->m_dwPatch);
  1165. }
  1166. }
  1167. #endif
  1168. return hr;
  1169. }
  1170. //////////////////////////////////////////////////////////////////////
  1171. // CBand::Load
  1172. HRESULT CBand::Load(DMUS_IO_PATCH_ITEM& rPatchEvent)
  1173. {
  1174. // This method is used to load PatchEvents generated by the parsing of a MIDI file.
  1175. // Each PatchEvent represents a program change and possibly a bank select. Using
  1176. // this information this method will generate a band with one instrument.
  1177. HRESULT hr = S_OK;
  1178. EnterCriticalSection(&m_CriticalSection);
  1179. CBandInstrument* pBandInstrument = NULL;
  1180. pBandInstrument = new CBandInstrument();
  1181. if(pBandInstrument)
  1182. {
  1183. pBandInstrument->m_dwFlags |= rPatchEvent.dwFlags;
  1184. if(pBandInstrument->m_dwFlags & DMUS_IO_INST_PATCH)
  1185. {
  1186. pBandInstrument->m_dwPatch |= (rPatchEvent.byPChange & 0x7F); // Program change
  1187. }
  1188. if(pBandInstrument->m_dwFlags & DMUS_IO_INST_BANKSELECT)
  1189. {
  1190. pBandInstrument->m_dwPatch |= (rPatchEvent.byLSB & 0x7F) << 8; // Set LSB
  1191. pBandInstrument->m_dwPatch |= (rPatchEvent.byMSB & 0x7F) << 16; // Set MSB
  1192. }
  1193. if(IsGS(rPatchEvent))
  1194. {
  1195. pBandInstrument->m_dwFlags |= DMUS_IO_INST_GS;
  1196. if( (rPatchEvent.byLSB == 0) && (rPatchEvent.byMSB == 0) )
  1197. {
  1198. pBandInstrument->m_dwFlags |= DMUS_IO_INST_GM;
  1199. }
  1200. }
  1201. pBandInstrument->m_dwPChannel = (rPatchEvent.byStatus & 0xF);
  1202. pBandInstrument->m_pIDMCollection = rPatchEvent.pIDMCollection;
  1203. pBandInstrument->m_fNotInFile = rPatchEvent.fNotInFile;
  1204. if(pBandInstrument->m_pIDMCollection)
  1205. {
  1206. (pBandInstrument->m_pIDMCollection)->AddRef();
  1207. }
  1208. // Set the time for the band. Since this band will have only one instrument in
  1209. // it we use the time for PatchEvent as the time for the band
  1210. m_lTimeLogical = rPatchEvent.lTime;
  1211. m_lTimePhysical = m_lTimeLogical;
  1212. m_BandInstrumentList.AddHead(pBandInstrument);
  1213. }
  1214. else
  1215. {
  1216. hr = E_OUTOFMEMORY;
  1217. }
  1218. if(SUCCEEDED(hr))
  1219. {
  1220. m_dwFlags |= DMB_LOADED;
  1221. }
  1222. else
  1223. {
  1224. if(pBandInstrument)
  1225. {
  1226. delete pBandInstrument;
  1227. }
  1228. }
  1229. LeaveCriticalSection(&m_CriticalSection);
  1230. return hr;
  1231. }
  1232. //////////////////////////////////////////////////////////////////////
  1233. // CBand::Load
  1234. HRESULT CBand::Load(CBandInstrument* pInstrument)
  1235. {
  1236. HRESULT hr = S_OK;
  1237. EnterCriticalSection(&m_CriticalSection);
  1238. CBandInstrument* pBandInstrument = NULL;
  1239. pBandInstrument = new CBandInstrument();
  1240. if(pBandInstrument)
  1241. {
  1242. pBandInstrument->m_dwPatch = pInstrument->m_dwPatch;
  1243. pBandInstrument->m_dwAssignPatch = pInstrument->m_dwAssignPatch;
  1244. pBandInstrument->m_dwPChannel = pInstrument->m_dwPChannel;
  1245. pBandInstrument->m_dwFlags = pInstrument->m_dwFlags;
  1246. pBandInstrument->m_bPan = pInstrument->m_bPan;
  1247. pBandInstrument->m_bVolume = pInstrument->m_bVolume;
  1248. pBandInstrument->m_nTranspose = pInstrument->m_nTranspose;
  1249. pBandInstrument->m_pIDMCollection = pInstrument->m_pIDMCollection;
  1250. CopyMemory(pBandInstrument->m_dwNoteRanges, pInstrument->m_dwNoteRanges, sizeof(pInstrument->m_dwNoteRanges));
  1251. if(pBandInstrument->m_pIDMCollection)
  1252. {
  1253. (pBandInstrument->m_pIDMCollection)->AddRef();
  1254. }
  1255. m_BandInstrumentList.AddHead(pBandInstrument);
  1256. }
  1257. else
  1258. {
  1259. hr = E_OUTOFMEMORY;
  1260. }
  1261. if(SUCCEEDED(hr))
  1262. {
  1263. m_dwFlags |= DMB_LOADED;
  1264. }
  1265. else
  1266. {
  1267. if(pBandInstrument)
  1268. {
  1269. delete pBandInstrument;
  1270. }
  1271. }
  1272. LeaveCriticalSection(&m_CriticalSection);
  1273. return hr;
  1274. }
  1275. //////////////////////////////////////////////////////////////////////
  1276. // CBand::SendMessages
  1277. HRESULT CBand::SendMessages(CBandTrkStateData* pBTStateData,
  1278. MUSIC_TIME mtOffset,
  1279. REFERENCE_TIME rtOffset,
  1280. bool fClockTime)
  1281. {
  1282. if(pBTStateData == NULL)
  1283. {
  1284. return E_POINTER;
  1285. }
  1286. HRESULT hr = S_OK;
  1287. EnterCriticalSection(&m_CriticalSection);
  1288. CBandInstrument* pInstrument = m_BandInstrumentList.GetHead();
  1289. for( ; pInstrument && SUCCEEDED(hr); pInstrument = pInstrument->GetNext())
  1290. {
  1291. if( pInstrument->m_fNotInFile && !pInstrument->m_fGMOnly )
  1292. {
  1293. // don't send program changes for instruments that were automatically
  1294. // generated by midi file parsing, unless we've set GMOnly.
  1295. continue;
  1296. }
  1297. hr = SendInstrumentAtTime(pInstrument, pBTStateData, m_lTimePhysical, mtOffset, rtOffset, fClockTime);
  1298. }
  1299. LeaveCriticalSection(&m_CriticalSection);
  1300. return hr;
  1301. }
  1302. HRESULT CBand::AllocPMsgFromGenericTemplate(
  1303. DWORD dwType,
  1304. IDirectMusicPerformance *pPerformance,
  1305. DMUS_PMSG **ppMsg,
  1306. ULONG cb,
  1307. DMUS_PMSG *pMsgGenericFields)
  1308. {
  1309. HRESULT hr = pPerformance->AllocPMsg(cb, ppMsg);
  1310. if (SUCCEEDED(hr))
  1311. {
  1312. DWORD dwSize = (*ppMsg)->dwSize; // Remember the size.
  1313. assert(dwSize == cb);
  1314. ZeroMemory(*ppMsg, cb); // Clear it - ensures we zero the non-DMUS_PMSG_PART fields.
  1315. CopyMemory(*ppMsg, pMsgGenericFields, sizeof(*pMsgGenericFields)); // Copy the DMUS_PMSG_PART fields.
  1316. // Fill in the correct size and type
  1317. (*ppMsg)->dwSize = dwSize;
  1318. (*ppMsg)->dwType = dwType;
  1319. }
  1320. return hr;
  1321. }
  1322. HRESULT CBand::StampSendFreePMsg(
  1323. IDirectMusicPerformance *pPerformance,
  1324. IDirectMusicGraph *pGraph,
  1325. DMUS_PMSG *pMsg)
  1326. {
  1327. // Let the graph set the delivery parameters.
  1328. HRESULT hr = pGraph->StampPMsg(pMsg);
  1329. if (SUCCEEDED(hr))
  1330. hr = pPerformance->SendPMsg(pMsg);
  1331. if (FAILED(hr))
  1332. hr = pPerformance->FreePMsg(pMsg);
  1333. return hr;
  1334. }
  1335. HRESULT CBand::SendInstrumentAtTime(CBandInstrument* pInstrument,
  1336. CBandTrkStateData* pBTStateData,
  1337. MUSIC_TIME mtTimeToPlay,
  1338. MUSIC_TIME mtOffset,
  1339. REFERENCE_TIME rtOffset,
  1340. bool fClockTime)
  1341. {
  1342. if(pInstrument == NULL || pBTStateData == NULL)
  1343. {
  1344. return E_POINTER;
  1345. }
  1346. IDirectMusicGraph *pGraph = NULL;
  1347. IDirectMusicPerformance *pPerformance = pBTStateData->m_pPerformance;
  1348. DWORD dwVirtualTrackID = pBTStateData->m_dwVirtualTrackID;
  1349. DWORD dwPatch = 0;
  1350. BOOL fMute;
  1351. DWORD dwPChannel;
  1352. // Get the mute/pchannel reassignment.
  1353. MUSIC_TIME mtParam = ( m_lTimeLogical < 0 ) ? 0 : m_lTimeLogical;
  1354. m_PChMap.GetInfo( pInstrument->m_dwPChannel, mtParam, mtOffset, m_dwGroupBits,
  1355. pPerformance, &fMute, &dwPChannel, fClockTime );
  1356. if( fMute )
  1357. return S_OK;
  1358. HRESULT hr = pBTStateData->m_pSegmentState->QueryInterface(IID_IDirectMusicGraph,
  1359. reinterpret_cast<void**>(&pGraph));
  1360. if(FAILED(hr))
  1361. return hr;
  1362. EnterCriticalSection(&m_CriticalSection);
  1363. DMUS_PMSG pmsgGeneric; // template for stamping out the common fields in the various specific kinds of messages
  1364. ZeroMemory(&pmsgGeneric, sizeof(pmsgGeneric));
  1365. if (fClockTime)
  1366. {
  1367. pmsgGeneric.rtTime = mtTimeToPlay * REF_PER_MIL + rtOffset;
  1368. pmsgGeneric.dwFlags |= DMUS_PMSGF_REFTIME | DMUS_PMSGF_LOCKTOREFTIME;
  1369. }
  1370. else
  1371. {
  1372. pmsgGeneric.mtTime = mtTimeToPlay + mtOffset;
  1373. pmsgGeneric.dwFlags |= DMUS_PMSGF_MUSICTIME;
  1374. }
  1375. pmsgGeneric.dwPChannel = dwPChannel;
  1376. pmsgGeneric.dwVirtualTrackID = dwVirtualTrackID;
  1377. pmsgGeneric.dwGroupID = m_dwGroupBits;
  1378. if(pInstrument->m_dwFlags & DMUS_IO_INST_PATCH)
  1379. {
  1380. if(pInstrument->m_dwFlags & DMUS_IO_INST_BANKSELECT)
  1381. {
  1382. if(pInstrument->m_dwFlags & DMUS_IO_INST_ASSIGN_PATCH)
  1383. {
  1384. dwPatch = pInstrument->m_dwAssignPatch & 0x007F7F00;
  1385. }
  1386. else
  1387. {
  1388. dwPatch = pInstrument->m_dwPatch & 0x007F7F00;
  1389. // if the m_fGMOnly flag is set, and either we're GS or we're XG and
  1390. // the instument's port supports XG, use the full patch
  1391. if (pInstrument->m_fGMOnly || (pInstrument->m_dwFlags & DMUS_IO_INST_XG))
  1392. {
  1393. bool fXG = XGInHardware(pPerformance,pBTStateData->m_pSegmentState,pInstrument->m_dwPChannel);
  1394. if(pInstrument->m_fGMOnly)
  1395. {
  1396. if ( m_dwMidiMode & DMUS_MIDIMODEF_GS )
  1397. {
  1398. dwPatch = pInstrument->m_dwFullPatch & 0x007F7F00;
  1399. }
  1400. if ( (m_dwMidiMode & DMUS_MIDIMODEF_XG) && fXG )
  1401. {
  1402. dwPatch = pInstrument->m_dwFullPatch & 0x007F7F00;
  1403. }
  1404. }
  1405. // If the instrument is an XG instrument and the hardware doesn't support
  1406. // XG, strip off the bank selects.
  1407. if ( (pInstrument->m_dwFlags & DMUS_IO_INST_XG) && !fXG)
  1408. {
  1409. dwPatch = 0;
  1410. }
  1411. }
  1412. }
  1413. }
  1414. // Now, get the program change.
  1415. if(pInstrument->m_dwFlags & DMUS_IO_INST_ASSIGN_PATCH)
  1416. {
  1417. dwPatch |= pInstrument->m_dwAssignPatch & 0x7f;
  1418. }
  1419. else
  1420. {
  1421. dwPatch |= pInstrument->m_dwPatch & 0x7f;
  1422. }
  1423. DMUS_PATCH_PMSG *pMsg = NULL;
  1424. hr = AllocPMsgFromGenericTemplate(DMUS_PMSGT_PATCH, pPerformance, reinterpret_cast<DMUS_PMSG**>(&pMsg), sizeof(*pMsg), &pmsgGeneric);
  1425. if(SUCCEEDED(hr))
  1426. {
  1427. // DMUS_PATCH_PMSG members that need to be initialized
  1428. pMsg->byInstrument = (BYTE) dwPatch & 0x7F;
  1429. pMsg->byMSB = (BYTE) ((dwPatch >> 16) & 0x7F);
  1430. pMsg->byLSB = (BYTE) ((dwPatch >> 8) & 0x7F);
  1431. hr = StampSendFreePMsg(pPerformance, pGraph, reinterpret_cast<DMUS_PMSG*>(pMsg));
  1432. }
  1433. }
  1434. if(pInstrument->m_dwFlags & DMUS_IO_INST_TRANSPOSE)
  1435. {
  1436. DMUS_TRANSPOSE_PMSG *pMsg = NULL;
  1437. hr = AllocPMsgFromGenericTemplate(DMUS_PMSGT_TRANSPOSE, pPerformance, reinterpret_cast<DMUS_PMSG**>(&pMsg), sizeof(*pMsg), &pmsgGeneric);
  1438. if(SUCCEEDED(hr))
  1439. {
  1440. // DMUS_TRANSPOSE_PMSG members that need to be initialized
  1441. pMsg->nTranspose = pInstrument->m_nTranspose;
  1442. hr = StampSendFreePMsg(pPerformance, pGraph, reinterpret_cast<DMUS_PMSG*>(pMsg));
  1443. }
  1444. }
  1445. if(pInstrument->m_dwFlags & DMUS_IO_INST_VOLUME)
  1446. {
  1447. // Set Volume
  1448. DMUS_MIDI_PMSG* pMsg = NULL;
  1449. hr = AllocPMsgFromGenericTemplate(DMUS_PMSGT_MIDI, pPerformance, reinterpret_cast<DMUS_PMSG**>(&pMsg), sizeof(*pMsg), &pmsgGeneric);
  1450. if(SUCCEEDED(hr))
  1451. {
  1452. // DMUS_MIDI_PMSG members that need to be initialized
  1453. pMsg->bStatus = MIDI_CONTROL_CHANGE;
  1454. pMsg->bByte1 = MIDI_CC_VOLUME;
  1455. pMsg->bByte2 = pInstrument->m_bVolume;
  1456. hr = StampSendFreePMsg(pPerformance, pGraph, reinterpret_cast<DMUS_PMSG*>(pMsg));
  1457. }
  1458. }
  1459. if(pInstrument->m_dwFlags & DMUS_IO_INST_PAN)
  1460. {
  1461. // Set Pan
  1462. DMUS_MIDI_PMSG* pMsg = NULL;
  1463. hr = AllocPMsgFromGenericTemplate(DMUS_PMSGT_MIDI, pPerformance, reinterpret_cast<DMUS_PMSG**>(&pMsg), sizeof(*pMsg), &pmsgGeneric);
  1464. if(SUCCEEDED(hr))
  1465. {
  1466. // DMUS_MIDI_PMSG members that need to be initialized
  1467. pMsg->bStatus = MIDI_CONTROL_CHANGE;
  1468. pMsg->bByte1 = MIDI_CC_PAN;
  1469. pMsg->bByte2 = pInstrument->m_bPan;
  1470. hr = StampSendFreePMsg(pPerformance, pGraph, reinterpret_cast<DMUS_PMSG*>(pMsg));
  1471. }
  1472. }
  1473. if(pInstrument->m_dwFlags & DMUS_IO_INST_CHANNEL_PRIORITY)
  1474. {
  1475. DMUS_CHANNEL_PRIORITY_PMSG *pMsg = NULL;
  1476. hr = AllocPMsgFromGenericTemplate(DMUS_PMSGT_CHANNEL_PRIORITY, pPerformance, reinterpret_cast<DMUS_PMSG**>(&pMsg), sizeof(*pMsg), &pmsgGeneric);
  1477. if(SUCCEEDED(hr))
  1478. {
  1479. // DMUS_CHANNEL_PRIORITY_PMSG members that need to be initialized
  1480. pMsg->dwChannelPriority = pInstrument->m_dwChannelPriority;
  1481. hr = StampSendFreePMsg(pPerformance, pGraph, reinterpret_cast<DMUS_PMSG*>(pMsg));
  1482. }
  1483. }
  1484. if(pInstrument->m_dwFlags & DMUS_IO_INST_PITCHBENDRANGE)
  1485. {
  1486. DMUS_CURVE_PMSG *pMsg = NULL;
  1487. hr = AllocPMsgFromGenericTemplate(DMUS_PMSGT_CURVE, pPerformance, reinterpret_cast<DMUS_PMSG**>(&pMsg), sizeof(*pMsg), &pmsgGeneric);
  1488. if(SUCCEEDED(hr))
  1489. {
  1490. pMsg->dwFlags |= DMUS_PMSGF_DX8; // pitch band is a DX8-only flag
  1491. // DMUS_CURVE_PMSG members that need to be initialized
  1492. pMsg->nEndValue = pInstrument->m_nPitchBendRange << 7;
  1493. pMsg->nOffset = static_cast<short>(m_lTimePhysical - m_lTimeLogical);
  1494. pMsg->bType = DMUS_CURVET_RPNCURVE;
  1495. pMsg->bCurveShape = DMUS_CURVES_INSTANT;
  1496. pMsg->wParamType = RPN_PITCHBEND;
  1497. // Leave as zero: mtDuration, mtOriginalStart, mtResetDuration, nStartValue, nResetValue,
  1498. // wMeasure, bBeat, bGrid, wMergeIndex
  1499. hr = StampSendFreePMsg(pPerformance, pGraph, reinterpret_cast<DMUS_PMSG*>(pMsg));
  1500. }
  1501. }
  1502. pGraph->Release();
  1503. LeaveCriticalSection(&m_CriticalSection);
  1504. return hr;
  1505. }
  1506. //////////////////////////////////////////////////////////////////////
  1507. // CBand::LoadCollection
  1508. HRESULT CBand::LoadCollection(IDirectMusicCollection** ppIDMCollection,
  1509. char* pszCollection,
  1510. IDirectMusicLoader* pIDMLoader)
  1511. {
  1512. // Any changes made to this function should also be made to LoadCollection
  1513. // in dmime.dll
  1514. assert(ppIDMCollection);
  1515. assert(pIDMLoader);
  1516. DMUS_OBJECTDESC desc;
  1517. ZeroMemory(&desc, sizeof(desc));
  1518. desc.dwSize = sizeof(desc);
  1519. desc.guidClass = CLSID_DirectMusicCollection;
  1520. if(pszCollection == NULL)
  1521. {
  1522. desc.guidObject = GUID_DefaultGMCollection;
  1523. desc.dwValidData |= (DMUS_OBJ_CLASS | DMUS_OBJ_OBJECT);
  1524. }
  1525. else
  1526. {
  1527. MultiByteToWideChar(CP_ACP, 0, pszCollection, -1, desc.wszName, DMUS_MAX_NAME);
  1528. desc.dwValidData |= (DMUS_OBJ_CLASS | DMUS_OBJ_NAME);
  1529. }
  1530. HRESULT hr = pIDMLoader->GetObject(&desc,IID_IDirectMusicCollection, (void**)ppIDMCollection);
  1531. return hr;
  1532. }
  1533. //////////////////////////////////////////////////////////////////////
  1534. // CBand::GetPChannelCount
  1535. DWORD CBand::GetPChannelCount()
  1536. {
  1537. EnterCriticalSection(&m_CriticalSection);
  1538. DWORD dwCount = 0;
  1539. CBandInstrument* pInstrument = m_BandInstrumentList.GetHead();
  1540. for( ; pInstrument; pInstrument = pInstrument->GetNext())
  1541. {
  1542. dwCount++;
  1543. }
  1544. LeaveCriticalSection(&m_CriticalSection);
  1545. return dwCount;
  1546. }
  1547. //////////////////////////////////////////////////////////////////////
  1548. // CBand::GetPChannels
  1549. HRESULT CBand::GetPChannels(DWORD *pdwPChannels, DWORD *pdwNumWritten)
  1550. {
  1551. assert(pdwPChannels);
  1552. assert(pdwNumWritten);
  1553. EnterCriticalSection(&m_CriticalSection);
  1554. *pdwNumWritten = 0;
  1555. CBandInstrument* pInstrument = m_BandInstrumentList.GetHead();
  1556. for(; pInstrument; pInstrument = pInstrument->GetNext())
  1557. {
  1558. *pdwPChannels++ = pInstrument->m_dwPChannel;
  1559. (*pdwNumWritten)++;
  1560. }
  1561. LeaveCriticalSection(&m_CriticalSection);
  1562. return S_OK;
  1563. }
  1564. HRESULT CBandInstrument::BuildNoteRangeArray(DWORD *pNoteRangeMap, DMUS_NOTERANGE **ppNoteRanges, DWORD *pdwNumNoteRanges)
  1565. {
  1566. const int c_iIn = 0;
  1567. const int c_iOut = 1;
  1568. HRESULT hr = S_OK;
  1569. // Count the number of DMUS_NOTERANGE structures we need to allocate
  1570. DWORD dwNRNum = 0;
  1571. int nState = c_iOut;
  1572. for(int i = 0; i < 4; i++)
  1573. {
  1574. DWORD dwTemp = pNoteRangeMap[i];
  1575. DWORD dwBitPos = 0;
  1576. while(dwBitPos < 32)
  1577. {
  1578. if(dwTemp & 0x1ul)
  1579. {
  1580. if(nState == c_iOut)
  1581. {
  1582. nState = c_iIn;
  1583. dwNRNum++;
  1584. }
  1585. }
  1586. else
  1587. {
  1588. nState = c_iOut;
  1589. }
  1590. dwTemp = dwTemp >> 1;
  1591. dwBitPos++;
  1592. }
  1593. }
  1594. // If the NoteRangeMap is empty or full we do nothing
  1595. // since this will cause NULL to be returned which means we
  1596. // want to download the complete instrument
  1597. if(dwNRNum && dwNRNum < 128)
  1598. {
  1599. *ppNoteRanges = new DMUS_NOTERANGE[dwNRNum];
  1600. if(*ppNoteRanges)
  1601. {
  1602. DWORD dwNRIdx = 0;
  1603. for(dwNRIdx = 0; dwNRIdx < dwNRNum; dwNRIdx++)
  1604. {
  1605. (*ppNoteRanges)[dwNRIdx].dwLowNote = 0;
  1606. (*ppNoteRanges)[dwNRIdx].dwHighNote = 127;
  1607. }
  1608. dwNRIdx = 0;
  1609. nState = c_iOut;
  1610. for(int i = 0; i < 4; i++)
  1611. {
  1612. DWORD dwTemp = pNoteRangeMap[i];
  1613. DWORD dwBitPos = 0;
  1614. while(dwBitPos < 32)
  1615. {
  1616. if(dwTemp & 0x1ul)
  1617. {
  1618. if(nState == c_iOut)
  1619. {
  1620. nState = c_iIn;
  1621. (*ppNoteRanges)[dwNRIdx].dwLowNote = dwBitPos + (i * 32);
  1622. }
  1623. }
  1624. else if(nState == c_iIn)
  1625. {
  1626. (*ppNoteRanges)[dwNRIdx].dwHighNote = dwBitPos + (i * 32) - 1;
  1627. nState = c_iOut;
  1628. dwNRIdx++;
  1629. }
  1630. dwTemp = dwTemp >> 1;
  1631. dwBitPos++;
  1632. }
  1633. }
  1634. assert(nState == c_iIn ? dwNRIdx == dwNRNum - 1 : dwNRIdx == dwNRNum);
  1635. *pdwNumNoteRanges = dwNRNum;
  1636. }
  1637. else
  1638. {
  1639. hr = E_OUTOFMEMORY;
  1640. }
  1641. }
  1642. else
  1643. {
  1644. *ppNoteRanges = NULL;
  1645. *pdwNumNoteRanges = 0;
  1646. }
  1647. return hr;
  1648. }
  1649. //////////////////////////////////////////////////////////////////////
  1650. // CBand::IsGS
  1651. bool CBand::IsGS(DMUS_IO_PATCH_ITEM& rPatchEvent)
  1652. {
  1653. BYTE bMSB = 0;
  1654. BYTE bPatch = 0;
  1655. if( rPatchEvent.dwFlags & DMUS_IO_INST_BANKSELECT )
  1656. {
  1657. if( rPatchEvent.byLSB != 0 ) return FALSE; // LSB must be 0 for GS
  1658. bMSB = rPatchEvent.byMSB;
  1659. }
  1660. if( rPatchEvent.dwFlags & DMUS_IO_INST_PATCH )
  1661. {
  1662. bPatch = rPatchEvent.byPChange & 0x7F;
  1663. }
  1664. if( bMSB == 0)
  1665. {
  1666. // If this is a drum kit (on MIDI channel 10)
  1667. if( (rPatchEvent.byStatus & 0xF) == 10 )
  1668. {
  1669. if ((bPatch == 0x0) ||
  1670. (bPatch == 0x08) ||
  1671. (bPatch == 0x10) ||
  1672. (bPatch == 0x18) ||
  1673. (bPatch == 0x19) ||
  1674. (bPatch == 0x20) ||
  1675. (bPatch == 0x28) ||
  1676. (bPatch == 0x30) ||
  1677. (bPatch == 0x38) )
  1678. {
  1679. return true;
  1680. }
  1681. else
  1682. return false;
  1683. }
  1684. else return true;//is GM
  1685. }
  1686. // check for GS
  1687. switch (bMSB)
  1688. {
  1689. case 6:
  1690. case 7:
  1691. if (bPatch == 0x7D) return true;
  1692. break;
  1693. case 24:
  1694. if ((bPatch == 0x04) || (bPatch == 0x06)) return true;
  1695. break;
  1696. case 9:
  1697. if ((bPatch == 0x0E) || (bPatch == 0x76) || (bPatch == 0x7D)) return true;
  1698. break;
  1699. case 2:
  1700. if ( (bPatch == 0x66) || (bPatch == 0x78) || ((bPatch > 0x79)&&(bPatch < 0x80) )) return true;
  1701. break;
  1702. case 3:
  1703. if ((bPatch > 0x79) && (bPatch < 0x80)) return true;
  1704. break;
  1705. case 4:
  1706. case 5:
  1707. if ( (bPatch == 0x7A) || ((bPatch > 0x7B)&&(bPatch < 0x7F) )) return true;
  1708. break;
  1709. case 32:
  1710. if ((bPatch == 0x10) ||
  1711. (bPatch == 0x11) ||
  1712. (bPatch == 0x18) ||
  1713. (bPatch == 0x34) ) return true;
  1714. break;
  1715. case 1:
  1716. if ((bPatch == 0x26) ||
  1717. (bPatch == 0x39) ||
  1718. (bPatch == 0x3C) ||
  1719. (bPatch == 0x50) ||
  1720. (bPatch == 0x51) ||
  1721. (bPatch == 0x62) ||
  1722. (bPatch == 0x66) ||
  1723. (bPatch == 0x68) ||
  1724. ((bPatch > 0x77) && (bPatch < 0x80))) return true;
  1725. break;
  1726. case 16:
  1727. switch (bPatch)
  1728. {
  1729. case 0x00:
  1730. return true;
  1731. break;
  1732. case 0x04:
  1733. return true;
  1734. break;
  1735. case 0x05:
  1736. return true;
  1737. break;
  1738. case 0x06:
  1739. return true;
  1740. break;
  1741. case 0x10:
  1742. return true;
  1743. break;
  1744. case 0x13:
  1745. return true;
  1746. break;
  1747. case 0x18:
  1748. return true;
  1749. break;
  1750. case 0x19:
  1751. return true;
  1752. break;
  1753. case 0x1C:
  1754. return true;
  1755. break;
  1756. case 0x27:
  1757. return true;
  1758. break;
  1759. case 0x3E:
  1760. return true;
  1761. break;
  1762. case 0x3F:
  1763. return true;
  1764. break;
  1765. default:
  1766. return false;
  1767. }
  1768. break;
  1769. case 8:
  1770. if ((bPatch < 0x07) || ((bPatch == 0x7D)))
  1771. {
  1772. return true;
  1773. }
  1774. else if ((bPatch > 0x3F) && (bPatch < 0x50))
  1775. {
  1776. return false;
  1777. }
  1778. else if ((bPatch > 0x4F) && (bPatch < 0x72) )
  1779. {
  1780. if ((bPatch == 0x50) ||
  1781. (bPatch == 0x51) ||
  1782. (bPatch == 0x6B))
  1783. {
  1784. return true;
  1785. }
  1786. return false;
  1787. }
  1788. else if ((bPatch > 0x1F) && (bPatch < 0x40))
  1789. {
  1790. if ((bPatch > 0x25) && (bPatch < 0x29) ||
  1791. (bPatch > 0x3C) ||
  1792. (bPatch == 0x30) ||
  1793. (bPatch == 0x32) )
  1794. {
  1795. return true;
  1796. }
  1797. return false;
  1798. }
  1799. else if ((bPatch > 0x0A) && (bPatch < 0x12) &&
  1800. (bPatch != 0x0D) && (bPatch != 0x0F))
  1801. {
  1802. return true;
  1803. }
  1804. else if ((bPatch > 0x0F) && (bPatch < 0x20))
  1805. {
  1806. if (bPatch > 0x17)
  1807. {
  1808. return true;
  1809. }
  1810. else if ( (bPatch == 0x13) || (bPatch == 0x15) )
  1811. return true;
  1812. else
  1813. return false;
  1814. }
  1815. break;
  1816. default:
  1817. return false;
  1818. }
  1819. return false;
  1820. }
  1821. HRESULT CBandInstrument::DownloadAddRecord(IDirectMusicPort *pPort)
  1822. {
  1823. IDirectMusicInstrument* pInstrument = NULL;
  1824. HRESULT hr = m_pIDMCollection->GetInstrument(m_dwPatch, &pInstrument);
  1825. if (FAILED(hr) && (m_dwFlags & (DMUS_IO_INST_GM | DMUS_IO_INST_GS | DMUS_IO_INST_XG)))
  1826. {
  1827. // If drums, set to standard drums.
  1828. if (m_dwPatch & 0x80000000)
  1829. {
  1830. m_dwPatch = 0;
  1831. }
  1832. // Else make this a GM melodic instrument.
  1833. else
  1834. {
  1835. m_dwPatch &= 0x7F;
  1836. }
  1837. hr = m_pIDMCollection->GetInstrument(m_dwPatch, &pInstrument);
  1838. }
  1839. if(SUCCEEDED(hr) && m_dwFlags & DMUS_IO_INST_ASSIGN_PATCH)
  1840. {
  1841. hr = pInstrument->SetPatch(m_dwAssignPatch);
  1842. }
  1843. if(SUCCEEDED(hr))
  1844. {
  1845. CDownloadedInstrument* pDLInstrument = new CDownloadedInstrument;
  1846. if(pDLInstrument)
  1847. {
  1848. pDLInstrument->m_pPort = pPort;
  1849. pPort->AddRef();
  1850. pDLInstrument->m_cRef = 1;
  1851. DMUS_NOTERANGE *pNoteRanges = NULL;
  1852. DWORD dwNumNoteRanges = 0;
  1853. if(m_dwFlags & DMUS_IO_INST_NOTERANGES)
  1854. {
  1855. BuildNoteRangeArray(m_dwNoteRanges, &pNoteRanges, &dwNumNoteRanges);
  1856. }
  1857. hr = pPort->DownloadInstrument( pInstrument,
  1858. &pDLInstrument->m_pDLInstrument,
  1859. pNoteRanges,
  1860. dwNumNoteRanges );
  1861. if (pNoteRanges)
  1862. {
  1863. delete [] pNoteRanges;
  1864. }
  1865. if(SUCCEEDED(hr))
  1866. {
  1867. m_DownloadList.AddHead(pDLInstrument);
  1868. }
  1869. else
  1870. {
  1871. delete pDLInstrument;
  1872. #ifdef DBG
  1873. if (hr == DMUS_E_NOT_INIT)
  1874. {
  1875. Trace(0,"Error: Download failed because performance not initialized\n");
  1876. }
  1877. else
  1878. {
  1879. Trace(1,"Error: Unable to download instrument %lx to PChannel %ld\n",
  1880. m_dwPatch,m_dwPChannel);
  1881. }
  1882. #endif
  1883. }
  1884. }
  1885. else
  1886. {
  1887. hr = E_OUTOFMEMORY;
  1888. Trace(0,"Error: Memory allocation failure - Unable to download instrument\n");
  1889. }
  1890. }
  1891. else
  1892. {
  1893. Trace(1,"Error: Unable to download instrument %lx; not in dls collection\n",m_dwPatch);
  1894. }
  1895. if (pInstrument)
  1896. {
  1897. pInstrument->Release();
  1898. }
  1899. return hr;
  1900. }
  1901. //////////////////////////////////////////////////////////////////////
  1902. // CBand::XGInHardware
  1903. bool CBand::XGInHardware(
  1904. IDirectMusicPerformance *pPerformance,
  1905. IDirectMusicSegmentState *pSegState,
  1906. DWORD dwPChannel)
  1907. {
  1908. DWORD dwGMFlags = 0;
  1909. // If this is playing via an audiopath, we need to access the audiopath to
  1910. // convert the pchannels so we can use them to access the right port.
  1911. IDirectMusicSegmentState8 *pState8;
  1912. if (SUCCEEDED(pSegState->QueryInterface(IID_IDirectMusicSegmentState8,(void **) &pState8)))
  1913. {
  1914. IDirectMusicAudioPath *pAudioPath;
  1915. if (SUCCEEDED(pState8->GetObjectInPath(DMUS_PCHANNEL_ALL,DMUS_PATH_AUDIOPATH,0,
  1916. GUID_All_Objects,0,IID_IDirectMusicAudioPath,(void **) &pAudioPath)))
  1917. {
  1918. pAudioPath->ConvertPChannel(dwPChannel, &dwPChannel);
  1919. pAudioPath->Release();
  1920. }
  1921. pState8->Release();
  1922. }
  1923. // Now, use the PChannel and the performance to read the flags.
  1924. IDirectMusicPort *pPort = NULL;
  1925. IDirectMusicPerformanceP *pPerfp;
  1926. if (SUCCEEDED(pPerformance->QueryInterface(IID_IDirectMusicPerformanceP, (void **)&pPerfp)))
  1927. {
  1928. if (SUCCEEDED(pPerfp->GetPortAndFlags(dwPChannel,&pPort,&dwGMFlags)))
  1929. {
  1930. pPort->Release();
  1931. }
  1932. pPerfp->Release();
  1933. }
  1934. return ((dwGMFlags & DM_PORTFLAGS_XG) && TRUE);
  1935. }
  1936. //////////////////////////////////////////////////////////////////////
  1937. // CBand::MakeGMOnly
  1938. HRESULT CBand::MakeGMOnly()
  1939. {
  1940. EnterCriticalSection(&m_CriticalSection);
  1941. CBandInstrument* pBandInstrument = m_BandInstrumentList.GetHead();
  1942. for( ; pBandInstrument != NULL; pBandInstrument = pBandInstrument->GetNext())
  1943. {
  1944. pBandInstrument->m_fGMOnly = true;
  1945. pBandInstrument->m_dwFullPatch = pBandInstrument->m_dwPatch;
  1946. DWORD dwTemp = pBandInstrument->m_dwPatch;
  1947. pBandInstrument->m_dwPatch = (dwTemp & 0x7F);
  1948. // If a drum kit set drum kit flag
  1949. if( m_dwMidiMode == DMUS_MIDIMODEF_XG )
  1950. {
  1951. if( (dwTemp & 0x00ff0000) == 0x007f0000 )
  1952. {
  1953. // XG drums. Keep this msb, as it is taken care of in the :Download function.
  1954. pBandInstrument->m_dwPatch |= 0x007f0000;
  1955. }
  1956. }
  1957. if(dwTemp & 0x80000000)
  1958. {
  1959. pBandInstrument->m_dwPatch |= 0x80000000;
  1960. }
  1961. }
  1962. LeaveCriticalSection(&m_CriticalSection);
  1963. return S_OK;
  1964. }
  1965. //////////////////////////////////////////////////////////////////////
  1966. // CBand::ConnectToDLSCollection
  1967. HRESULT CBand::ConnectToDLSCollection(IDirectMusicCollection *pCollection)
  1968. {
  1969. assert(pCollection);
  1970. EnterCriticalSection(&m_CriticalSection);
  1971. CBandInstrument* pBandInstrument = m_BandInstrumentList.GetHead();
  1972. for( ; pBandInstrument != NULL; pBandInstrument = pBandInstrument->GetNext())
  1973. {
  1974. if(pBandInstrument->m_pIDMCollection == NULL)
  1975. {
  1976. pCollection->AddRef();
  1977. pBandInstrument->m_pIDMCollection = pCollection;
  1978. }
  1979. else
  1980. {
  1981. if( m_dwMidiMode ) // if this is anything, it indicates we were loaded from a midi file
  1982. {
  1983. // if we're not an XG file, make sure channel 9 is drums
  1984. if( (m_dwMidiMode != DMUS_MIDIMODEF_XG) &&
  1985. (pBandInstrument->m_dwPChannel == 9) )
  1986. {
  1987. pBandInstrument->m_dwPatch |= 0x80000000;
  1988. }
  1989. }
  1990. // if we get an instrument from this collection, set the band's collection
  1991. // pointer to it instead.
  1992. IDirectMusicInstrument* pInstrument = NULL;
  1993. if( SUCCEEDED( pCollection->GetInstrument(pBandInstrument->m_dwPatch, &pInstrument)))
  1994. {
  1995. pBandInstrument->m_pIDMCollection->Release();
  1996. pBandInstrument->m_pIDMCollection = pCollection;
  1997. pCollection->AddRef();
  1998. pInstrument->Release();
  1999. }
  2000. }
  2001. }
  2002. LeaveCriticalSection(&m_CriticalSection);
  2003. return S_OK;
  2004. }