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.

1294 lines
42 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. // CControlLogic.cpp
  3. //
  4. #ifdef DMSYNTH_MINIPORT
  5. #include "common.h"
  6. #else
  7. #include "simple.h"
  8. #include <mmsystem.h>
  9. #include <dmusicc.h>
  10. #include <dmusics.h>
  11. #include "synth.h"
  12. #include "misc.h"
  13. #include "csynth.h"
  14. #include "debug.h"
  15. #endif
  16. //////////////////////////////////////////////////////////////////////////////
  17. //
  18. // Manage the global critical section. #pragma's disable the warning about
  19. // not compiling with -GX when using exception handling, which we don't
  20. // care about.
  21. //
  22. //
  23. // The critical section must be global because it protects global
  24. // data in the CMIDIRecorder class. These functions are called from
  25. // DllMain().
  26. //
  27. CRITICAL_SECTION CControlLogic::s_CriticalSection;
  28. BOOL CControlLogic::s_fCSInitialized = FALSE;
  29. #pragma warning(push)
  30. #pragma warning(disable:4530)
  31. /* static */ BOOL CControlLogic::InitCriticalSection()
  32. {
  33. s_fCSInitialized = FALSE;
  34. try
  35. {
  36. ::InitializeCriticalSection(&s_CriticalSection);
  37. } catch(...)
  38. {
  39. return FALSE;
  40. }
  41. s_fCSInitialized = TRUE;
  42. return TRUE;
  43. }
  44. #pragma warning(pop)
  45. /* static */ void CControlLogic::KillCriticalSection()
  46. {
  47. if (s_fCSInitialized)
  48. {
  49. ::DeleteCriticalSection(&s_CriticalSection);
  50. s_fCSInitialized = FALSE;
  51. }
  52. }
  53. CControlLogic::CControlLogic()
  54. {
  55. m_pSynth = NULL;
  56. m_pInstruments = NULL;
  57. DWORD nIndex;
  58. GMReset();
  59. m_fGSActive = FALSE;
  60. m_fXGActive = FALSE;
  61. for (nIndex = 0;nIndex < 16;nIndex++)
  62. {
  63. m_fSustain[nIndex] = FALSE;
  64. m_dwProgram[nIndex] = 0;
  65. }
  66. m_fEmpty = TRUE;
  67. }
  68. CControlLogic::~CControlLogic()
  69. {
  70. }
  71. void CControlLogic::GMReset()
  72. {
  73. static int nPartToChannel[16] = {
  74. 9,0,1,2,3,4,5,6,7,8,10,11,12,13,14,15
  75. };
  76. int nX;
  77. for (nX = 0; nX < 16; nX++)
  78. {
  79. int nY;
  80. m_nData[nX] = 0;
  81. m_prFineTune[nX] = 0;
  82. m_bDrums[nX] = 0;
  83. for (nY = 0; nY < 12; nY++)
  84. {
  85. m_prScaleTune[nX][nY] = 0;
  86. }
  87. m_nCurrentRPN[nX] = (short) 0x3FFF;
  88. m_prCoarseTune[nX] = 0;
  89. m_bPartToChannel[nX] = (BYTE)nPartToChannel[nX];
  90. m_fMono[nX] = FALSE;
  91. m_dwPriority[nX] = DAUD_STANDARD_VOICE_PRIORITY +
  92. ((16 - nX) * DAUD_CHAN15_VOICE_PRIORITY_OFFSET);
  93. m_bBankH[nX] = 0;
  94. m_bBankL[nX] = 0;
  95. }
  96. m_bDrums[0] = 1;
  97. m_vrMasterVolume = 0;
  98. m_fGSActive = FALSE;
  99. m_fXGActive = FALSE;
  100. }
  101. HRESULT CControlLogic::Init(CInstManager *pInstruments, CSynth *pSynth)
  102. {
  103. m_pSynth = pSynth;
  104. m_pInstruments = pInstruments;
  105. m_vrGainAdjust = 0;
  106. CVoice::Init();
  107. return S_OK;
  108. }
  109. void CControlLogic::ClearAll()
  110. {
  111. int nIndex;
  112. ::EnterCriticalSection(&s_CriticalSection);
  113. m_Notes.ClearMIDI(0x7FFFFFFF);
  114. for (nIndex = 0; nIndex < 16; nIndex++) {
  115. m_ModWheel[nIndex].ClearMIDI(0x7FFFFFFF);
  116. m_Volume[nIndex].ClearMIDI(0x7FFFFFFF);
  117. m_Pan[nIndex].ClearMIDI(0x7FFFFFFF);
  118. m_Expression[nIndex].ClearMIDI(0x7FFFFFFF);
  119. m_PitchBend[nIndex].ClearMIDI(0x7FFFFFFF);
  120. m_Pressure[nIndex].ClearMIDI(0x7FFFFFFF);
  121. m_ReverbSends[nIndex].ClearMIDI(0x7FFFFFFF);
  122. m_ChorusSends[nIndex].ClearMIDI(0x7FFFFFFF);
  123. m_CutOffFreqCC[nIndex].ClearMIDI(0x7FFFFFFF);
  124. }
  125. for (nIndex = 0; nIndex < 16; nIndex++) {
  126. m_ModWheel[nIndex].RecordMIDI(0, 0);
  127. m_Volume[nIndex].RecordMIDI(0, 100);
  128. m_Pan[nIndex].RecordMIDI(0, 64);
  129. m_Expression[nIndex].RecordMIDI(0, 127);
  130. m_PitchBend[nIndex].RecordMIDI(0, 0x2000);
  131. m_Pressure[nIndex].RecordMIDI(0, 0);
  132. m_ReverbSends[nIndex].RecordMIDI(0, 40);
  133. m_ChorusSends[nIndex].RecordMIDI(0, 0);
  134. m_CutOffFreqCC[nIndex].RecordMIDI(0, 64);
  135. m_Notes.RecordEvent(0, nIndex, NOTE_SUSTAIN, 0);
  136. }
  137. m_fEmpty = TRUE;
  138. ::LeaveCriticalSection(&s_CriticalSection);
  139. }
  140. void CControlLogic::ClearMIDI(STIME stEndTime)
  141. {
  142. DWORD dwIndex;
  143. ::EnterCriticalSection(&s_CriticalSection);
  144. if (!m_fEmpty)
  145. {
  146. m_fEmpty = TRUE;
  147. for (dwIndex = 0;dwIndex < 16; dwIndex++)
  148. {
  149. m_fEmpty = m_ModWheel[dwIndex].ClearMIDI(stEndTime) && m_fEmpty;
  150. m_fEmpty = m_PitchBend[dwIndex].ClearMIDI(stEndTime) && m_fEmpty;
  151. m_fEmpty = m_Volume[dwIndex].ClearMIDI(stEndTime) && m_fEmpty;
  152. m_fEmpty = m_Expression[dwIndex].ClearMIDI(stEndTime) && m_fEmpty;
  153. m_fEmpty = m_Pan[dwIndex].ClearMIDI(stEndTime) && m_fEmpty;
  154. m_fEmpty = m_Pressure[dwIndex].ClearMIDI(stEndTime) && m_fEmpty;
  155. m_fEmpty = m_ReverbSends[dwIndex].ClearMIDI(stEndTime) && m_fEmpty;
  156. m_fEmpty = m_ChorusSends[dwIndex].ClearMIDI(stEndTime) && m_fEmpty;
  157. m_fEmpty = m_CutOffFreqCC[dwIndex].ClearMIDI(stEndTime) && m_fEmpty;
  158. }
  159. }
  160. ::LeaveCriticalSection(&s_CriticalSection);
  161. }
  162. void CControlLogic::SetGainAdjust(VREL vrGainAdjust)
  163. {
  164. m_vrGainAdjust = vrGainAdjust;
  165. }
  166. void CControlLogic::QueueNotes(STIME stStartTime, STIME stEndTime)
  167. {
  168. CNote note;
  169. ::EnterCriticalSection(&s_CriticalSection);
  170. while (m_Notes.GetNote(stEndTime,&note))
  171. {
  172. if (note.m_stTime < stStartTime)
  173. {
  174. TraceI(2, "Note started %d samples late!\n", (long)(stStartTime - note.m_stTime));
  175. note.m_stTime = stStartTime;
  176. }
  177. if (note.m_bKey > 0x7F) // Special command events.
  178. {
  179. long lTemp;
  180. DWORD dwPart = note.m_bPart;
  181. DWORD dwCommand = note.m_bKey;
  182. BYTE bData = note.m_bVelocity;
  183. switch (dwCommand)
  184. {
  185. case NOTE_PROGRAMCHANGE:
  186. m_dwProgram[dwPart] = bData |
  187. (m_bBankH[dwPart] << 16) |
  188. (m_bBankL[dwPart] << 8);
  189. break;
  190. case NOTE_CC_BANKSELECTH:
  191. m_bBankH[dwPart] = bData;
  192. break;
  193. case NOTE_CC_BANKSELECTL:
  194. m_bBankL[dwPart] = bData;
  195. break;
  196. case NOTE_CC_POLYMODE:
  197. m_fMono[dwPart] = FALSE;
  198. break;
  199. case NOTE_CC_MONOMODE:
  200. m_fMono[dwPart] = TRUE;
  201. break;
  202. case NOTE_CC_RPN_MSB:
  203. m_nCurrentRPN[dwPart] = (m_nCurrentRPN[dwPart] & 0x7f) + (bData << 7);
  204. break;
  205. case NOTE_CC_RPN_LSB:
  206. m_nCurrentRPN[dwPart] = (m_nCurrentRPN[dwPart] & 0x3f80) + bData;
  207. break;
  208. case NOTE_CC_NRPN:
  209. m_nCurrentRPN[dwPart] = 0x3FFF;
  210. break;
  211. case NOTE_CC_DATAENTRYLSB:
  212. m_nData[dwPart] &= ~0x7F;
  213. m_nData[dwPart] |= bData;
  214. switch (m_nCurrentRPN[dwPart])
  215. {
  216. case RPN_PITCHBEND: // Don't do anything, Roland ignores lsb
  217. break;
  218. case RPN_FINETUNE:
  219. lTemp = m_nData[dwPart];
  220. lTemp -= 8192;
  221. lTemp *= 100;
  222. lTemp /= 8192;
  223. m_prFineTune[dwPart] = lTemp;
  224. break;
  225. case RPN_COARSETUNE: // Ignore lsb
  226. break;
  227. }
  228. break;
  229. case NOTE_CC_DATAENTRYMSB:
  230. m_nData[dwPart] &= ~(0x7F << 7);
  231. m_nData[dwPart] |= bData << 7;
  232. switch (m_nCurrentRPN[dwPart])
  233. {
  234. case RPN_PITCHBEND:
  235. m_PitchBend[dwPart].m_prRange = bData * 100;
  236. break;
  237. case RPN_FINETUNE:
  238. lTemp = m_nData[dwPart];
  239. lTemp -= 8192;
  240. lTemp *= 100;
  241. lTemp /= 8192;
  242. m_prFineTune[dwPart] = lTemp;
  243. break;
  244. case RPN_COARSETUNE:
  245. m_prCoarseTune[dwPart] = 100 * (bData - 64);
  246. break;
  247. }
  248. break;
  249. case NOTE_SUSTAIN: // special sustain marker
  250. m_fSustain[dwPart] = (BOOL) bData;
  251. if (bData == FALSE)
  252. {
  253. CVoice * pVoice = m_pSynth->m_VoicesInUse.GetHead();
  254. for (;pVoice != NULL;pVoice = pVoice->GetNext())
  255. {
  256. if (pVoice->m_fSustainOn &&
  257. (pVoice->m_nPart == dwPart) &&
  258. (pVoice->m_pControl == this))
  259. {
  260. pVoice->StopVoice(note.m_stTime);
  261. }
  262. }
  263. }
  264. break;
  265. case NOTE_ALLOFF:
  266. {
  267. CVoice *pVoice = m_pSynth->m_VoicesInUse.GetHead();
  268. for (;pVoice != NULL; pVoice = pVoice->GetNext())
  269. {
  270. if (pVoice->m_fNoteOn && !pVoice->m_fSustainOn &&
  271. (pVoice->m_nPart == dwPart) &&
  272. (pVoice->m_pControl == this))
  273. {
  274. if (m_fSustain[dwPart])
  275. {
  276. pVoice->m_fSustainOn = TRUE;
  277. }
  278. else
  279. {
  280. pVoice->StopVoice(note.m_stTime);
  281. }
  282. }
  283. }
  284. }
  285. break;
  286. case NOTE_SOUNDSOFF:
  287. {
  288. CVoice *pVoice = m_pSynth->m_VoicesInUse.GetHead();
  289. for (;pVoice != NULL; pVoice = pVoice->GetNext())
  290. {
  291. if ((pVoice->m_nPart == dwPart) &&
  292. (pVoice->m_pControl == this))
  293. {
  294. pVoice->QuickStopVoice(note.m_stTime);
  295. }
  296. }
  297. }
  298. break;
  299. case NOTE_ASSIGNRECEIVE:
  300. m_bPartToChannel[dwPart] = (BYTE) bData;
  301. break;
  302. case NOTE_MASTERVOLUME:
  303. m_vrMasterVolume = CMIDIRecorder::VelocityToVolume(bData);
  304. break;
  305. }
  306. }
  307. else if (note.m_bVelocity == 0) // Note Off.
  308. {
  309. CVoice * pVoice = m_pSynth->m_VoicesInUse.GetHead();
  310. WORD nPart = note.m_bPart;
  311. DWORD dwNoteID = 0; // Use to track multiple voices on one note.
  312. for (;pVoice != NULL;pVoice = pVoice->GetNext())
  313. {
  314. if (pVoice->m_fNoteOn && !pVoice->m_fSustainOn &&
  315. (pVoice->m_nKey == (WORD) note.m_bKey) &&
  316. (pVoice->m_nPart == nPart) &&
  317. (pVoice->m_pControl == this))
  318. {
  319. if (!dwNoteID || (dwNoteID == pVoice->m_dwNoteID))
  320. {
  321. dwNoteID = pVoice->m_dwNoteID;
  322. if (m_fSustain[nPart])
  323. {
  324. pVoice->m_fSustainOn = TRUE;
  325. }
  326. else
  327. {
  328. pVoice->StopVoice(note.m_stTime);
  329. }
  330. }
  331. }
  332. }
  333. }
  334. else // Note On.
  335. {
  336. DWORD dwProgram = m_dwProgram[note.m_bPart];
  337. if (m_bDrums[note.m_bPart])
  338. {
  339. dwProgram |= F_INSTRUMENT_DRUMS;
  340. }
  341. if (m_fMono[note.m_bPart])
  342. {
  343. CVoice * pVoice = m_pSynth->m_VoicesInUse.GetHead();
  344. WORD nPart = note.m_bPart;
  345. for (;pVoice != NULL;pVoice = pVoice->GetNext())
  346. {
  347. if (pVoice->m_fNoteOn && (pVoice->m_nPart == nPart) &&
  348. (pVoice->m_pControl == this))
  349. {
  350. pVoice->StopVoice(note.m_stTime);
  351. }
  352. }
  353. }
  354. // While we are working with the instrument, including copying
  355. // the data over from the region, we have to make sure it
  356. // can not be removed from the instrument list.
  357. EnterCriticalSection(&m_pInstruments->m_CriticalSection);
  358. CInstrument * pInstrument =
  359. m_pInstruments->GetInstrument(dwProgram,note.m_bKey,note.m_bVelocity);
  360. if (!pInstrument)
  361. {
  362. if (dwProgram & F_INSTRUMENT_DRUMS)
  363. {
  364. dwProgram = F_INSTRUMENT_DRUMS;
  365. pInstrument =
  366. m_pInstruments->GetInstrument(dwProgram,note.m_bKey,note.m_bVelocity);
  367. }
  368. else if (m_fXGActive)
  369. {
  370. if ((dwProgram & 0x7F0000) == 0x7F0000) // Drum?
  371. {
  372. dwProgram &= 0x7F007F; // Enforce 0 LSB
  373. pInstrument =
  374. m_pInstruments->GetInstrument(dwProgram,note.m_bKey,note.m_bVelocity);
  375. if (!pInstrument)
  376. {
  377. dwProgram = 0x7F0000;
  378. pInstrument =
  379. m_pInstruments->GetInstrument(dwProgram,note.m_bKey,note.m_bVelocity);
  380. }
  381. }
  382. else
  383. {
  384. dwProgram &= 0x7F; // Fall back to GM set.
  385. pInstrument =
  386. m_pInstruments->GetInstrument(dwProgram,note.m_bKey,note.m_bVelocity);
  387. }
  388. }
  389. }
  390. if (pInstrument != NULL)
  391. {
  392. DWORD dwNotesLost = 1; // Assume note will be lost, will be decremented if played
  393. CSourceRegion * pRegion = NULL;
  394. static DWORD sdwNoteID = 0; // Generate a unique id that will be placed in all voices that play this note.
  395. sdwNoteID++; // This will be used to keep the voices associated so we can stop them all at once later.
  396. while ( pRegion = pInstrument->ScanForRegion(note.m_bKey, note.m_bVelocity, pRegion) )
  397. {
  398. WORD nPart = note.m_bPart;
  399. CVoice * pVoice = m_pSynth->m_VoicesInUse.GetHead();
  400. if (!pRegion->m_bAllowOverlap)
  401. {
  402. for (;pVoice != NULL; pVoice = pVoice->GetNext())
  403. {
  404. if ((pVoice->m_nPart == nPart) &&
  405. (pVoice->m_nKey == note.m_bKey) &&
  406. (pVoice->m_pControl == this) &&
  407. (pVoice->m_pRegion == pRegion))
  408. {
  409. pVoice->QuickStopVoice(note.m_stTime);
  410. }
  411. }
  412. }
  413. if (pRegion->m_bGroup != 0)
  414. {
  415. pVoice = m_pSynth->m_VoicesInUse.GetHead();
  416. for (;pVoice != NULL;pVoice = pVoice->GetNext())
  417. {
  418. if ((pVoice->m_dwGroup == pRegion->m_bGroup) &&
  419. (pVoice->m_nPart == nPart) &&
  420. (pVoice->m_dwProgram == dwProgram) &&
  421. (pVoice->m_pControl == this))
  422. {
  423. pVoice->QuickStopVoice(note.m_stTime);
  424. }
  425. }
  426. }
  427. pVoice = m_pSynth->m_VoicesFree.RemoveHead();
  428. if (pVoice == NULL)
  429. {
  430. pVoice = m_pSynth->m_VoicesExtra.RemoveHead();
  431. }
  432. if (pVoice == NULL)
  433. {
  434. pVoice = m_pSynth->StealVoice(m_dwPriority[nPart]);
  435. // The voice IDs are used by the VoiceServiceThread in DMusic
  436. // to refill the streaming wave buffers....
  437. // Since the voice is stolen this voice could really belong to
  438. // a streaming wave in which case preserving the voice ID will
  439. // break the refill code. (NOTE!! This is different from stealing
  440. // voices for waves. Waves will ultimately preserve the voice ID as
  441. // they pass it to StartWave where it gets assigned to the voice's
  442. // m_dwVoiceId member).
  443. if(pVoice)
  444. {
  445. // Set the voice ID to something unacceptable
  446. pVoice->m_dwVoiceId = 0xffffffff;
  447. }
  448. }
  449. if (pVoice != NULL)
  450. {
  451. PREL prPitch = m_prFineTune[nPart] + m_prScaleTune[nPart][note.m_bKey % 12];
  452. if (!m_bDrums[nPart])
  453. {
  454. if (m_fXGActive)
  455. {
  456. if ((dwProgram & 0x7F0000) != 0x7F0000)
  457. {
  458. prPitch += m_prCoarseTune[nPart];
  459. }
  460. }
  461. else
  462. {
  463. prPitch += m_prCoarseTune[nPart];
  464. }
  465. }
  466. pVoice->m_nKey = note.m_bKey;
  467. pVoice->m_nPart = nPart;
  468. pVoice->m_dwProgram = dwProgram;
  469. pVoice->m_dwPriority = m_dwPriority[nPart];
  470. pVoice->m_pControl = this;
  471. pVoice->m_pRegion = pRegion;
  472. pVoice->m_dwNoteID = sdwNoteID;
  473. if (pVoice->StartVoice(m_pSynth,
  474. pRegion, note.m_stTime,
  475. &m_ModWheel[nPart],
  476. &m_PitchBend[nPart],
  477. &m_Expression[nPart],
  478. &m_Volume[nPart],
  479. &m_Pan[nPart],
  480. &m_Pressure[nPart],
  481. &m_ReverbSends[nPart],
  482. &m_ChorusSends[nPart],
  483. &m_CutOffFreqCC[nPart],
  484. &m_BusIds[nPart],
  485. (WORD)note.m_bKey,
  486. (WORD)note.m_bVelocity,
  487. m_vrMasterVolume,
  488. prPitch))
  489. {
  490. pVoice->m_fInUse = TRUE;
  491. m_pSynth->QueueVoice(pVoice);
  492. dwNotesLost = 0; // Note played remove notelost assumpstion
  493. }
  494. else
  495. {
  496. m_pSynth->m_VoicesFree.AddHead(pVoice);
  497. }
  498. }
  499. }
  500. m_pSynth->m_BuildStats.dwNotesLost += dwNotesLost;
  501. }
  502. else
  503. {
  504. Trace(1,"Error: No instrument/region was found for patch # %lx, note %ld\n",
  505. dwProgram, (long) note.m_bKey);
  506. }
  507. LeaveCriticalSection(&m_pInstruments->m_CriticalSection);
  508. }
  509. }
  510. ::LeaveCriticalSection(&s_CriticalSection);
  511. }
  512. void CControlLogic::Flush(STIME stTime)
  513. {
  514. DWORD dwIndex;
  515. ::EnterCriticalSection(&s_CriticalSection);
  516. if (!m_fEmpty)
  517. {
  518. m_fEmpty = TRUE;
  519. for (dwIndex = 0;dwIndex < 16; dwIndex++)
  520. {
  521. m_fEmpty = m_ModWheel[dwIndex].FlushMIDI(stTime) && m_fEmpty;
  522. m_fEmpty = m_PitchBend[dwIndex].FlushMIDI(stTime) && m_fEmpty;
  523. m_fEmpty = m_Volume[dwIndex].FlushMIDI(stTime) && m_fEmpty;
  524. m_fEmpty = m_Expression[dwIndex].FlushMIDI(stTime) && m_fEmpty;
  525. m_fEmpty = m_Pan[dwIndex].FlushMIDI(stTime) && m_fEmpty;
  526. m_fEmpty = m_Pressure[dwIndex].FlushMIDI(stTime) && m_fEmpty;
  527. m_fEmpty = m_ReverbSends[dwIndex].FlushMIDI(stTime) && m_fEmpty;
  528. m_fEmpty = m_ChorusSends[dwIndex].FlushMIDI(stTime) && m_fEmpty;
  529. m_fEmpty = m_CutOffFreqCC[dwIndex].FlushMIDI(stTime) && m_fEmpty;
  530. }
  531. m_Notes.FlushMIDI(stTime);
  532. }
  533. ::LeaveCriticalSection(&s_CriticalSection);
  534. }
  535. BOOL CControlLogic::RecordMIDI(STIME stTime,BYTE bStatus, BYTE bData1, BYTE bData2)
  536. {
  537. WORD nPreChannel = bStatus & 0xF;
  538. CNote note;
  539. bStatus = bStatus & 0xF0;
  540. BOOL bReturn = TRUE;
  541. WORD nPart;
  542. ::EnterCriticalSection(&s_CriticalSection);
  543. for (nPart = 0;nPart < 16; nPart++)
  544. {
  545. if (nPreChannel == m_bPartToChannel[nPart])
  546. {
  547. switch (bStatus)
  548. {
  549. case MIDI_NOTEOFF :
  550. bData2 = 0;
  551. case MIDI_NOTEON :
  552. note.m_bPart = (BYTE) nPart;
  553. note.m_bKey = bData1;
  554. note.m_bVelocity = bData2;
  555. bReturn = m_Notes.RecordNote(stTime,&note);
  556. break;
  557. case MIDI_CCHANGE :
  558. switch (bData1)
  559. {
  560. case CC_BANKSELECTH :
  561. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_BANKSELECTH, bData2);
  562. break;
  563. case CC_MODWHEEL :
  564. m_fEmpty = FALSE;
  565. bReturn = m_ModWheel[nPart].RecordMIDI(stTime,(long) bData2);
  566. break;
  567. case CC_VOLUME :
  568. m_fEmpty = FALSE;
  569. bReturn = m_Volume[nPart].RecordMIDI(stTime,(long) bData2);
  570. break;
  571. case CC_PAN :
  572. m_fEmpty = FALSE;
  573. bReturn = m_Pan[nPart].RecordMIDI(stTime,(long) bData2);
  574. break;
  575. case CC_EXPRESSION :
  576. m_fEmpty = FALSE;
  577. bReturn = m_Expression[nPart].RecordMIDI(stTime,(long)bData2);
  578. break;
  579. case CC_BANKSELECTL :
  580. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_BANKSELECTL, bData2);
  581. break;
  582. case CC_RESETALL:
  583. m_fEmpty = FALSE;
  584. if (bData2)
  585. {
  586. bReturn = bReturn && m_Volume[nPart].RecordMIDI(stTime, 100);
  587. bReturn = bReturn && m_Pan[nPart].RecordMIDI(stTime, 64);
  588. }
  589. bReturn = bReturn && m_Expression[nPart].RecordMIDI(stTime, 127);
  590. bReturn = bReturn && m_PitchBend[nPart].RecordMIDI(stTime, 0x2000);
  591. bReturn = bReturn && m_ModWheel[nPart].RecordMIDI(stTime, 0);
  592. bReturn = bReturn && m_Pressure[nPart].RecordMIDI(stTime, 0);
  593. bReturn = bReturn && m_ReverbSends[nPart].RecordMIDI(stTime, 40);
  594. bReturn = bReturn && m_ChorusSends[nPart].RecordMIDI(stTime, 0);
  595. bReturn = bReturn && m_CutOffFreqCC[nPart].RecordMIDI(stTime, 64);
  596. bData2 = 0;
  597. // fall through into Sustain Off case....
  598. case CC_SUSTAIN :
  599. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_SUSTAIN, bData2);
  600. break;
  601. case CC_ALLSOUNDSOFF:
  602. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_SOUNDSOFF, 0);
  603. break;
  604. case CC_ALLNOTESOFF:
  605. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_ALLOFF, 0);
  606. break;
  607. case CC_DATAENTRYMSB:
  608. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_DATAENTRYMSB, bData2);
  609. break;
  610. case CC_DATAENTRYLSB:
  611. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_DATAENTRYLSB, bData2);
  612. break;
  613. case CC_NRPN_LSB :
  614. case CC_NRPN_MSB :
  615. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_NRPN, bData2);
  616. break;
  617. case CC_RPN_LSB:
  618. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_RPN_LSB, bData2);
  619. break;
  620. case CC_RPN_MSB:
  621. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_RPN_MSB, bData2);
  622. break;
  623. case CC_MONOMODE :
  624. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_MONOMODE, bData2);
  625. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_SOUNDSOFF, 0);
  626. break;
  627. case CC_POLYMODE :
  628. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_POLYMODE, bData2);
  629. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_SOUNDSOFF, 0);
  630. break;
  631. case CC_REVERB :
  632. m_fEmpty = FALSE;
  633. bReturn = m_ReverbSends[nPart].RecordMIDI(stTime,(long)bData2);
  634. break;
  635. case CC_CHORUS :
  636. m_fEmpty = FALSE;
  637. bReturn = m_ChorusSends[nPart].RecordMIDI(stTime,(long)bData2);
  638. break;
  639. case CC_CUTOFFFREQ:
  640. m_fEmpty = FALSE;
  641. bReturn = m_CutOffFreqCC[nPart].RecordMIDI(stTime,(long)bData2);
  642. break;
  643. default:
  644. break;
  645. }
  646. break;
  647. case MIDI_PCHANGE :
  648. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_PROGRAMCHANGE, bData1);
  649. break;
  650. case MIDI_PBEND :
  651. m_fEmpty = FALSE;
  652. {
  653. WORD nBend;
  654. nBend = bData2 << 7;
  655. nBend |= bData1;
  656. bReturn = m_PitchBend[nPart].RecordMIDI(stTime,(long)nBend);
  657. }
  658. break;
  659. case MIDI_MTOUCH:
  660. m_fEmpty = FALSE;
  661. bReturn = m_Pressure[nPart].RecordMIDI(stTime,(long)bData1);
  662. break;
  663. }
  664. }
  665. }
  666. ::LeaveCriticalSection(&s_CriticalSection);
  667. return bReturn;
  668. }
  669. HRESULT CControlLogic::RecordSysEx(DWORD dwSysExLength,BYTE *pSysExData, STIME stTime)
  670. {
  671. HRESULT hSuccess = S_OK;
  672. int nPart;
  673. int nTune;
  674. DWORD dwAddress;
  675. BOOL fClearAll = FALSE;
  676. BOOL fResetPatches = FALSE;
  677. if (dwSysExLength < 6)
  678. {
  679. Trace(4,"Warning: Unknown sysex message sent to synth.\n");
  680. return E_FAIL;
  681. }
  682. EnterCriticalSection(&s_CriticalSection);
  683. switch (pSysExData[1]) // ID number
  684. {
  685. case 0x7E : // General purpose ID
  686. if (pSysExData[3] == 0x09)
  687. {
  688. GMReset();
  689. fClearAll = TRUE;
  690. fResetPatches = TRUE;
  691. }
  692. break;
  693. case 0x7F : // Real time ID
  694. if (pSysExData[3] == 0x04)
  695. {
  696. if (pSysExData[4] == 1) // Master Volume
  697. {
  698. m_Notes.RecordEvent(stTime, 0, NOTE_MASTERVOLUME, pSysExData[6]);
  699. }
  700. }
  701. break;
  702. case 0x41 : // Roland
  703. if (dwSysExLength < 11)
  704. {
  705. Trace(4,"Warning: Unknown sysex message sent to synth.\n");
  706. LeaveCriticalSection(&s_CriticalSection);
  707. return E_FAIL;
  708. }
  709. if (pSysExData[3] != 0x42) break;
  710. if (pSysExData[4] != 0x12) break;
  711. nPart = pSysExData[6] & 0xF;
  712. dwAddress = (pSysExData[5] << 16) |
  713. ((pSysExData[6] & 0xF0) << 8) | pSysExData[7];
  714. switch (dwAddress)
  715. {
  716. case 0x40007F : // GS Reset.
  717. GMReset();
  718. m_fXGActive = FALSE;
  719. fClearAll = TRUE;
  720. m_fGSActive = TRUE;
  721. fResetPatches = TRUE;
  722. break;
  723. case 0x401002 : // Set Receive Channel.
  724. if (m_fGSActive)
  725. {
  726. if (pSysExData[8])
  727. {
  728. m_Notes.RecordEvent(stTime, nPart, NOTE_ASSIGNRECEIVE, pSysExData[8] - 1);
  729. }
  730. }
  731. break;
  732. case 0x401015 : // Use for Rhythm.
  733. if (m_fGSActive)
  734. {
  735. m_bDrums[nPart] = pSysExData[8];
  736. fClearAll = TRUE;
  737. }
  738. break;
  739. case 0x401040 : // Scale Tuning.
  740. if (m_fGSActive)
  741. {
  742. for (nTune = 0;nTune < 12; nTune++)
  743. {
  744. if (pSysExData[9 + nTune] & 0x80) break;
  745. m_prScaleTune[nPart][nTune] =
  746. (PREL) pSysExData[8 + nTune] - (PREL) 64;
  747. }
  748. }
  749. break;
  750. }
  751. break;
  752. case 0x43 : // Yamaha
  753. if ((pSysExData[3] == 0x4C) &&
  754. (pSysExData[4] == 0) &&
  755. (pSysExData[5] == 0) &&
  756. (pSysExData[6] == 0x7E) &&
  757. (pSysExData[7] == 0))
  758. { // XG System On
  759. m_fXGActive = TRUE;
  760. m_fGSActive = FALSE;
  761. GMReset();
  762. m_fXGActive = TRUE;
  763. m_bDrums[0] = 0;
  764. m_bBankH[0] = 127;
  765. fClearAll = TRUE;
  766. fResetPatches = TRUE;
  767. }
  768. break;
  769. }
  770. if (fClearAll)
  771. {
  772. Flush(0);
  773. for (nPart = 0;nPart < 16;nPart++)
  774. {
  775. m_Notes.RecordEvent(stTime, nPart, NOTE_SOUNDSOFF, 0);
  776. m_Notes.RecordEvent(stTime, nPart, NOTE_SUSTAIN, 0);
  777. m_Volume[nPart].RecordMIDI(stTime, 100);
  778. m_Pan[nPart].RecordMIDI(stTime, 64);
  779. m_Expression[nPart].RecordMIDI(stTime, 127);
  780. m_PitchBend[nPart].RecordMIDI(stTime, 0x2000);
  781. m_ModWheel[nPart].RecordMIDI(stTime, 0);
  782. m_Pressure[nPart].RecordMIDI(stTime, 0);
  783. m_ReverbSends[nPart].RecordMIDI(stTime, 40);
  784. m_ChorusSends[nPart].RecordMIDI(stTime, 0);
  785. m_CutOffFreqCC[nPart].RecordMIDI(stTime, 64);
  786. }
  787. }
  788. if (fResetPatches)
  789. {
  790. for (nPart = 0;nPart < 16;nPart++)
  791. {
  792. if ((nPart == 0) && (m_fXGActive))
  793. {
  794. m_Notes.RecordEvent(stTime-1, nPart, NOTE_CC_BANKSELECTH, 127);
  795. }
  796. else
  797. {
  798. m_Notes.RecordEvent(stTime-1, nPart, NOTE_CC_BANKSELECTH, 0);
  799. }
  800. m_Notes.RecordEvent(stTime-1, nPart, NOTE_CC_BANKSELECTL, 0);
  801. m_Notes.RecordEvent(stTime, nPart, NOTE_PROGRAMCHANGE, 0);
  802. }
  803. }
  804. LeaveCriticalSection(&s_CriticalSection);
  805. return hSuccess;
  806. }
  807. HRESULT CControlLogic::SetChannelPriority(DWORD dwChannel,DWORD dwPriority)
  808. {
  809. DWORD dwPart;
  810. for (dwPart = 0;dwPart < 16; dwPart++)
  811. {
  812. if (m_bPartToChannel[dwPart] == dwChannel)
  813. {
  814. m_dwPriority[dwPart] = dwPriority;
  815. }
  816. }
  817. return S_OK;
  818. }
  819. HRESULT CControlLogic::GetChannelPriority(DWORD dwChannel,LPDWORD pdwPriority)
  820. {
  821. DWORD dwPart;
  822. for (dwPart = 0;dwPart < 16; dwPart++)
  823. {
  824. if (m_bPartToChannel[dwPart] == dwChannel)
  825. {
  826. *pdwPriority = m_dwPriority[dwPart];
  827. break;
  828. }
  829. }
  830. return S_OK;
  831. }
  832. //////////////////////////////////////////////////////////
  833. // Directx8 Methods
  834. BOOL CControlLogic::RecordWaveEvent(
  835. STIME stTime, BYTE bChannel, DWORD dwVoiceId, VREL vrVolume, PREL prPitch,
  836. SAMPLE_TIME stVoiceStart, SAMPLE_TIME stLoopStart, SAMPLE_TIME stLoopEnd,
  837. CWaveArt* pWaveArt)
  838. {
  839. WORD nPreChannel = bChannel;
  840. CWaveEvent wave;
  841. BOOL bReturn = TRUE;
  842. WORD nPart;
  843. ::EnterCriticalSection(&s_CriticalSection);
  844. for (nPart = 0;nPart < 16; nPart++)
  845. {
  846. if (nPreChannel == m_bPartToChannel[nPart])
  847. {
  848. wave.m_bPart = (BYTE)nPart;
  849. wave.m_dwVoiceId = dwVoiceId;
  850. wave.m_vrVolume = vrVolume;
  851. wave.m_prPitch = prPitch;
  852. wave.m_pWaveArt = pWaveArt;
  853. wave.m_stVoiceStart = stVoiceStart;
  854. wave.m_stLoopStart = stLoopStart;
  855. wave.m_stLoopEnd = stLoopEnd;
  856. wave.m_pWaveArt->AddRef();
  857. bReturn = m_Waves.RecordWave(stTime,&wave);
  858. }
  859. }
  860. ::LeaveCriticalSection(&s_CriticalSection);
  861. return bReturn;
  862. }
  863. void CControlLogic::QueueWaves(STIME stEndTime)
  864. {
  865. CWaveEvent wave;
  866. BOOL fGotAWave = TRUE;
  867. while (fGotAWave)
  868. {
  869. EnterCriticalSection(&m_pInstruments->m_CriticalSection);
  870. fGotAWave = m_Waves.GetWave(stEndTime,&wave);
  871. if (!fGotAWave)
  872. {
  873. LeaveCriticalSection(&m_pInstruments->m_CriticalSection);
  874. break;
  875. }
  876. WORD nPart = wave.m_bPart;
  877. CVoice * pVoice = m_pSynth->m_VoicesFree.RemoveHead();
  878. if (pVoice == NULL)
  879. {
  880. pVoice = m_pSynth->m_VoicesExtra.RemoveHead();
  881. }
  882. if (pVoice == NULL)
  883. {
  884. pVoice = m_pSynth->StealVoice(m_dwPriority[nPart]);
  885. }
  886. if (pVoice != NULL)
  887. {
  888. PREL prPitch = wave.m_prPitch;
  889. prPitch += m_prFineTune[nPart];
  890. prPitch += m_prCoarseTune[nPart];
  891. pVoice->m_nKey = 0xffff; // set to unused values
  892. pVoice->m_dwProgram = 0xffffffff; // set to unused values
  893. pVoice->m_nPart = nPart;
  894. pVoice->m_dwPriority = m_dwPriority[nPart];
  895. pVoice->m_pControl = this;
  896. pVoice->m_pRegion = NULL;
  897. if (pVoice->StartWave(m_pSynth,
  898. wave.m_pWaveArt,
  899. wave.m_dwVoiceId,
  900. wave.m_stTime,
  901. &m_PitchBend[nPart],
  902. &m_Expression[nPart],
  903. &m_Volume[nPart],
  904. &m_Pan[nPart],
  905. &m_ReverbSends[nPart],
  906. &m_ChorusSends[nPart],
  907. &m_CutOffFreqCC[nPart],
  908. &m_BusIds[nPart],
  909. wave.m_vrVolume,
  910. prPitch,
  911. wave.m_stVoiceStart,
  912. wave.m_stLoopStart,
  913. wave.m_stLoopEnd
  914. ))
  915. {
  916. pVoice->m_fInUse = TRUE;
  917. m_pSynth->QueueVoice(pVoice);
  918. }
  919. else
  920. {
  921. m_pSynth->m_VoicesFree.AddHead(pVoice);
  922. }
  923. }
  924. else
  925. {
  926. Trace(1,"Error: No voice avaible for voice id #%lx\n", wave.m_dwVoiceId);
  927. }
  928. if (wave.m_pWaveArt) wave.m_pWaveArt->Release(); // no longer need to hold this ref count
  929. LeaveCriticalSection(&m_pInstruments->m_CriticalSection);
  930. }
  931. }
  932. void CControlLogic::FlushWaveByStopTime(DWORD dwID, STIME stStopTime)
  933. {
  934. EnterCriticalSection(&m_pInstruments->m_CriticalSection);
  935. m_Waves.RemoveWaveByStopTime(dwID, stStopTime);
  936. LeaveCriticalSection(&m_pInstruments->m_CriticalSection);
  937. }
  938. HRESULT CControlLogic::AssignChannelToBuses(DWORD dwChannel, LPDWORD pdwBusIds, DWORD dwBusCount)
  939. {
  940. HRESULT hr = S_OK;
  941. DWORD dwPart;
  942. for (dwPart = 0;dwPart < 16; dwPart++)
  943. {
  944. if (m_bPartToChannel[dwPart] == dwChannel)
  945. {
  946. //
  947. // Assign new bus ids to this channel
  948. //
  949. if ( pdwBusIds && dwBusCount > 0 )
  950. {
  951. hr = m_BusIds[dwPart].AssignBuses(pdwBusIds, dwBusCount);
  952. }
  953. }
  954. }
  955. return hr;
  956. }
  957. /////////////////////////////////////////////////////////////////
  958. CWaveDataList CWaveIn::m_sFreeList;
  959. DWORD CWaveIn::m_sUsageCount = 0;
  960. CWaveData::CWaveData()
  961. {
  962. m_stTime = 0;
  963. }
  964. CWaveIn::CWaveIn()
  965. {
  966. m_sUsageCount++;
  967. m_stCurrentTime = 0;
  968. }
  969. CWaveIn::~CWaveIn()
  970. {
  971. ClearWave(0x7FFFFFFF);
  972. m_sUsageCount--;
  973. // If there are no instances of CMIDIRecorder left, get rid of the free pool.
  974. if (!m_sUsageCount)
  975. {
  976. CWaveData *pWD;
  977. while (pWD = m_sFreeList.RemoveHead())
  978. {
  979. delete pWD;
  980. }
  981. }
  982. }
  983. /*void CWaveIn::Init()
  984. {
  985. int nIndex;
  986. static BOOL fAlreadyDone = FALSE;
  987. if (!fAlreadyDone)
  988. {
  989. m_sFreeList.RemoveAll();
  990. for (nIndex = 0; nIndex < MAX_MIDI_EVENTS; nIndex++)
  991. {
  992. m_sFreeList.AddHead(&m_sEventBuffer[nIndex]);
  993. }
  994. fAlreadyDone = TRUE;
  995. }
  996. }*/
  997. /*
  998. BOOL CWaveIn::FlushWave(STIME stTime)
  999. {
  1000. CWaveData *pWD;
  1001. CWaveData *pLast = NULL;
  1002. for (pWD = m_EventList.GetHead();pWD != NULL;pWD = pWD->GetNext())
  1003. {
  1004. if (pWD->m_stTime >= stTime)
  1005. {
  1006. if (pLast == NULL)
  1007. {
  1008. m_EventList.RemoveAll();
  1009. }
  1010. else
  1011. {
  1012. pLast->SetNext(NULL);
  1013. }
  1014. m_sFreeList.Cat(pWD);
  1015. break;
  1016. }
  1017. pLast = pWD;
  1018. }
  1019. return m_EventList.IsEmpty();
  1020. }
  1021. */
  1022. BOOL CWaveIn::ClearWave(STIME stTime)
  1023. {
  1024. CWaveData *pWD;
  1025. for (;pWD = m_EventList.GetHead();)
  1026. {
  1027. if (pWD->m_stTime < stTime)
  1028. {
  1029. m_EventList.RemoveHead();
  1030. m_stCurrentTime = pWD->m_stTime;
  1031. m_lCurrentData = pWD->m_WaveEventData;
  1032. if (pWD->m_WaveEventData.m_pWaveArt)
  1033. {
  1034. pWD->m_WaveEventData.m_pWaveArt->Release();
  1035. pWD->m_WaveEventData.m_pWaveArt = NULL;
  1036. }
  1037. m_sFreeList.AddHead(pWD);
  1038. }
  1039. else break;
  1040. }
  1041. return m_EventList.IsEmpty();
  1042. }
  1043. BOOL CWaveIn::RemoveWave(DWORD dwID)
  1044. {
  1045. CWaveData *pWD = m_EventList.GetHead();
  1046. CWaveData *pWDNext = NULL;
  1047. for (; pWD; pWD = pWDNext)
  1048. {
  1049. pWDNext = pWD->GetNext();
  1050. if (pWD->m_WaveEventData.m_dwVoiceId == dwID)
  1051. {
  1052. m_EventList.Remove(pWD);
  1053. if (pWD->m_WaveEventData.m_pWaveArt)
  1054. {
  1055. pWD->m_WaveEventData.m_pWaveArt->Release();
  1056. pWD->m_WaveEventData.m_pWaveArt = NULL;
  1057. }
  1058. m_sFreeList.AddHead(pWD);
  1059. }
  1060. }
  1061. return m_EventList.IsEmpty();
  1062. }
  1063. BOOL CWaveIn::RemoveWaveByStopTime(DWORD dwID, STIME stStopTime)
  1064. {
  1065. CWaveData *pWD = m_EventList.GetHead();
  1066. CWaveData *pWDNext = NULL;
  1067. for (; pWD; pWD = pWDNext)
  1068. {
  1069. pWDNext = pWD->GetNext();
  1070. if (pWD->m_WaveEventData.m_dwVoiceId == dwID && pWD->m_stTime >= stStopTime)
  1071. {
  1072. m_EventList.Remove(pWD);
  1073. if (pWD->m_WaveEventData.m_pWaveArt)
  1074. {
  1075. pWD->m_WaveEventData.m_pWaveArt->Release();
  1076. pWD->m_WaveEventData.m_pWaveArt = NULL;
  1077. }
  1078. m_sFreeList.AddHead(pWD);
  1079. }
  1080. }
  1081. return m_EventList.IsEmpty();
  1082. }
  1083. BOOL CWaveIn::RecordWave(STIME stTime, CWaveEvent* pWave)
  1084. {
  1085. CWaveData *pWD = m_sFreeList.RemoveHead();
  1086. if (!pWD)
  1087. {
  1088. pWD = new CWaveData;
  1089. }
  1090. CWaveData *pScan = m_EventList.GetHead();
  1091. CWaveData *pNext;
  1092. if (pWD)
  1093. {
  1094. pWD->m_stTime = stTime;
  1095. pWD->m_WaveEventData = *pWave;
  1096. pWD->m_WaveEventData.m_stTime = stTime;
  1097. if (pScan == NULL)
  1098. {
  1099. m_EventList.AddHead(pWD);
  1100. }
  1101. else
  1102. {
  1103. if (pScan->m_stTime > stTime)
  1104. {
  1105. m_EventList.AddHead(pWD);
  1106. }
  1107. else
  1108. {
  1109. for (;pScan != NULL; pScan = pNext)
  1110. {
  1111. pNext = pScan->GetNext();
  1112. if (pNext == NULL)
  1113. {
  1114. pScan->SetNext(pWD);
  1115. }
  1116. else
  1117. {
  1118. if (pNext->m_stTime > stTime)
  1119. {
  1120. pWD->SetNext(pNext);
  1121. pScan->SetNext(pWD);
  1122. break;
  1123. }
  1124. }
  1125. }
  1126. }
  1127. }
  1128. return (TRUE);
  1129. }
  1130. Trace(1,"Error: Wave Event pool empty.\n");
  1131. return (FALSE);
  1132. }
  1133. BOOL CWaveIn::GetWave(STIME stTime, CWaveEvent *pWave)
  1134. {
  1135. CWaveData *pWD = m_EventList.GetHead();
  1136. if (pWD != NULL)
  1137. {
  1138. if (pWD->m_stTime <= stTime)
  1139. {
  1140. *pWave = pWD->m_WaveEventData;
  1141. m_EventList.RemoveHead();
  1142. m_sFreeList.AddHead(pWD);
  1143. return (TRUE);
  1144. }
  1145. }
  1146. return (FALSE);
  1147. }
  1148. /////////////////////////////////////////////////////////////////
  1149. CBusIds::CBusIds()
  1150. {
  1151. m_dwBusIds[0] = DSBUSID_LEFT;
  1152. m_dwBusIds[1] = DSBUSID_RIGHT;
  1153. m_dwBusIds[2] = DSBUSID_REVERB_SEND;
  1154. m_dwBusIds[3] = DSBUSID_CHORUS_SEND;
  1155. m_dwBusCount = NUM_DEFAULT_BUSES;
  1156. }
  1157. CBusIds::~CBusIds()
  1158. {
  1159. }
  1160. HRESULT CBusIds::Initialize()
  1161. {
  1162. HRESULT hr = S_OK;
  1163. m_dwBusIds[0] = DSBUSID_LEFT;
  1164. m_dwBusIds[1] = DSBUSID_RIGHT;
  1165. m_dwBusIds[2] = DSBUSID_REVERB_SEND;
  1166. m_dwBusIds[3] = DSBUSID_CHORUS_SEND;
  1167. m_dwBusCount = NUM_DEFAULT_BUSES;
  1168. return hr;
  1169. }
  1170. HRESULT CBusIds::AssignBuses(LPDWORD pdwBusIds, DWORD dwBusCount)
  1171. {
  1172. HRESULT hr = S_OK;
  1173. if ( pdwBusIds && dwBusCount > 0 )
  1174. {
  1175. if ( dwBusCount > MAX_DAUD_CHAN )
  1176. dwBusCount = MAX_DAUD_CHAN;
  1177. memcpy(m_dwBusIds,pdwBusIds,sizeof(DWORD)*dwBusCount);
  1178. m_dwBusCount = dwBusCount;
  1179. }
  1180. return hr;
  1181. }