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

822 lines
24 KiB

  1. //
  2. // Copyright (c) 1996-2000 Microsoft Corporation. All rights reserved.
  3. // CControlLogic.cpp
  4. //
  5. #define STR_MODULENAME "DDKSynth.sys:Control: "
  6. #include "common.h"
  7. #pragma code_seg()
  8. /*****************************************************************************
  9. * CControlLogic::CControlLogic()
  10. *****************************************************************************
  11. * Constructor for CControlLogic object.
  12. */
  13. CControlLogic::CControlLogic()
  14. {
  15. m_fCSInitialized = FALSE;
  16. InitializeCriticalSection(&m_CriticalSection);
  17. m_fCSInitialized = TRUE;
  18. m_pSynth = NULL;
  19. m_pInstruments = NULL;
  20. DWORD nIndex;
  21. GMReset();
  22. m_fGSActive = FALSE;
  23. m_fXGActive = FALSE;
  24. for (nIndex = 0;nIndex < 16;nIndex++)
  25. {
  26. m_fSustain[nIndex] = FALSE;
  27. m_dwProgram[nIndex] = 0;
  28. }
  29. m_fEmpty = TRUE;
  30. }
  31. /*****************************************************************************
  32. * CControlLogic::~CControlLogic()
  33. *****************************************************************************
  34. * Destructor for CControlLogic object.
  35. */
  36. CControlLogic::~CControlLogic()
  37. {
  38. if (m_fCSInitialized)
  39. {
  40. DeleteCriticalSection(&m_CriticalSection);
  41. }
  42. }
  43. /*****************************************************************************
  44. * CControlLogic::GMReset()
  45. *****************************************************************************
  46. * Performs a General MIDI reset, including resetting all the voice priorities,
  47. * GS, XG, master volume, etc.
  48. */
  49. void CControlLogic::GMReset()
  50. {
  51. static const int nPartToChannel[16] = {
  52. 9,0,1,2,3,4,5,6,7,8,10,11,12,13,14,15
  53. };
  54. int nX;
  55. for (nX = 0; nX < 16; nX++)
  56. {
  57. int nY;
  58. m_nData[nX] = 0;
  59. m_prFineTune[nX] = 0;
  60. m_bDrums[nX] = 0;
  61. for (nY = 0; nY < 12; nY++)
  62. {
  63. m_prScaleTune[nX][nY] = 0;
  64. }
  65. m_nCurrentRPN[nX] = (short) 0x3FFF;
  66. m_prCoarseTune[nX] = 0;
  67. m_bPartToChannel[nX] = (BYTE)nPartToChannel[nX];
  68. m_fMono[nX] = FALSE;
  69. m_dwPriority[nX] = DAUD_STANDARD_VOICE_PRIORITY +
  70. ((16 - nX) * DAUD_CHAN15_VOICE_PRIORITY_OFFSET);
  71. m_bBankH[nX] = 0;
  72. m_bBankL[nX] = 0;
  73. }
  74. m_bDrums[0] = 1;
  75. m_vrMasterVolume = 0;
  76. m_fGSActive = FALSE;
  77. m_fXGActive = FALSE;
  78. }
  79. /*****************************************************************************
  80. * CControlLogic::Init()
  81. *****************************************************************************
  82. * Initialize the CControlLogic object, and initialize all the child objects --
  83. * Note recorders, ModWheels, Volumes, Pan, Expression, PitchBend.
  84. */
  85. HRESULT CControlLogic::Init(CInstManager *pInstruments, CSynth *pSynth)
  86. {
  87. m_pSynth = pSynth;
  88. m_pInstruments = pInstruments;
  89. m_vrGainAdjust = 0;
  90. m_Notes.Init();
  91. int iRecIdx;
  92. for (iRecIdx = 0; iRecIdx < sizeof(m_ModWheel) / sizeof(*m_ModWheel); iRecIdx++)
  93. {
  94. m_ModWheel[iRecIdx].Init();
  95. }
  96. for (iRecIdx = 0; iRecIdx < sizeof(m_PitchBend) / sizeof(*m_PitchBend); iRecIdx++)
  97. {
  98. m_PitchBend[iRecIdx].Init();
  99. }
  100. for (iRecIdx = 0; iRecIdx < sizeof(m_Volume) / sizeof(*m_Volume); iRecIdx++)
  101. {
  102. m_Volume[iRecIdx].Init();
  103. }
  104. for (iRecIdx = 0; iRecIdx < sizeof(m_Expression) / sizeof(*m_Expression); iRecIdx++)
  105. {
  106. m_Expression[iRecIdx].Init();
  107. }
  108. for (iRecIdx = 0; iRecIdx < sizeof(m_Pan) / sizeof(*m_Pan); iRecIdx++)
  109. {
  110. m_Pan[iRecIdx].Init();
  111. }
  112. return S_OK;
  113. }
  114. /*****************************************************************************
  115. * CControlLogic::ClearMIDI()
  116. *****************************************************************************
  117. * Clears MIDI up to a certain time, and updates m_fEmpty.
  118. */
  119. void CControlLogic::ClearMIDI(STIME stEndTime)
  120. {
  121. DWORD dwIndex;
  122. ::EnterCriticalSection(&m_CriticalSection);
  123. if (!m_fEmpty)
  124. {
  125. m_fEmpty = TRUE;
  126. for (dwIndex = 0;dwIndex < 16; dwIndex++)
  127. {
  128. m_fEmpty = m_ModWheel[dwIndex].ClearMIDI(stEndTime)
  129. && m_PitchBend[dwIndex].ClearMIDI(stEndTime)
  130. && m_Volume[dwIndex].ClearMIDI(stEndTime)
  131. && m_Expression[dwIndex].ClearMIDI(stEndTime)
  132. && m_Pan[dwIndex].ClearMIDI(stEndTime);
  133. }
  134. }
  135. ::LeaveCriticalSection(&m_CriticalSection);
  136. }
  137. /*****************************************************************************
  138. * CControlLogic::SetGainAdjust()
  139. *****************************************************************************
  140. * Sets the overall gain for this CControlLogic.
  141. */
  142. void CControlLogic::SetGainAdjust(VREL vrGainAdjust)
  143. {
  144. m_vrGainAdjust = vrGainAdjust;
  145. }
  146. /*****************************************************************************
  147. * CControlLogic::QueueNotes()
  148. *****************************************************************************
  149. * Retrieves notes from the note recorders, and dispatches them appropriately.
  150. * Called during the Mix.
  151. */
  152. void CControlLogic::QueueNotes(STIME stEndTime)
  153. {
  154. CNote note;
  155. while (m_Notes.GetNote(stEndTime,&note))
  156. {
  157. if (note.m_bKey > 0x7F) // Special command events.
  158. {
  159. long lTemp;
  160. DWORD dwPart = note.m_bPart;
  161. DWORD dwCommand = note.m_bKey;
  162. BYTE bData = note.m_bVelocity;
  163. switch (dwCommand)
  164. {
  165. case NOTE_PROGRAMCHANGE:
  166. m_dwProgram[dwPart] = bData |
  167. (m_bBankH[dwPart] << 16) |
  168. (m_bBankL[dwPart] << 8);
  169. break;
  170. case NOTE_CC_BANKSELECTH:
  171. m_bBankH[dwPart] = bData;
  172. break;
  173. case NOTE_CC_BANKSELECTL:
  174. m_bBankL[dwPart] = bData;
  175. break;
  176. case NOTE_CC_POLYMODE:
  177. m_fMono[dwPart] = FALSE;
  178. break;
  179. case NOTE_CC_MONOMODE:
  180. m_fMono[dwPart] = TRUE;
  181. break;
  182. case NOTE_CC_RPN_MSB:
  183. m_nCurrentRPN[dwPart] = (m_nCurrentRPN[dwPart] & 0x7f) + (bData << 7);
  184. break;
  185. case NOTE_CC_RPN_LSB:
  186. m_nCurrentRPN[dwPart] = (m_nCurrentRPN[dwPart] & 0x3f80) + bData;
  187. break;
  188. case NOTE_CC_NRPN:
  189. m_nCurrentRPN[dwPart] = 0x3FFF;
  190. break;
  191. case NOTE_CC_DATAENTRYLSB:
  192. m_nData[dwPart] &= ~0x7F;
  193. m_nData[dwPart] |= bData;
  194. switch (m_nCurrentRPN[dwPart])
  195. {
  196. case RPN_PITCHBEND: // Don't do anything, Roland ignores lsb
  197. break;
  198. case RPN_FINETUNE:
  199. lTemp = m_nData[dwPart];
  200. lTemp -= 8192;
  201. lTemp *= 100;
  202. lTemp /= 8192;
  203. m_prFineTune[dwPart] = lTemp;
  204. break;
  205. case RPN_COARSETUNE: // Ignore lsb
  206. break;
  207. }
  208. break;
  209. case NOTE_CC_DATAENTRYMSB:
  210. m_nData[dwPart] &= ~(0x7F << 7);
  211. m_nData[dwPart] |= bData << 7;
  212. switch (m_nCurrentRPN[dwPart])
  213. {
  214. case RPN_PITCHBEND:
  215. m_PitchBend[dwPart].m_prRange = bData * 100;
  216. break;
  217. case RPN_FINETUNE:
  218. lTemp = m_nData[dwPart];
  219. lTemp -= 8192;
  220. lTemp *= 100;
  221. lTemp /= 8192;
  222. m_prFineTune[dwPart] = lTemp;
  223. break;
  224. case RPN_COARSETUNE:
  225. m_prCoarseTune[dwPart] = 100 * (bData - 64);
  226. break;
  227. }
  228. break;
  229. case NOTE_SUSTAIN: // special sustain marker
  230. m_fSustain[dwPart] = (BOOL) bData;
  231. if (bData == FALSE)
  232. {
  233. CVoice * pVoice = m_pSynth->m_VoicesInUse.GetHead();
  234. for (;pVoice != NULL;pVoice = pVoice->GetNext())
  235. {
  236. if (pVoice->m_fSustainOn &&
  237. (pVoice->m_nPart == dwPart) &&
  238. (pVoice->m_pControl == this))
  239. {
  240. pVoice->StopVoice(note.m_stTime);
  241. }
  242. }
  243. }
  244. break;
  245. case NOTE_ALLOFF:
  246. {
  247. CVoice *pVoice = m_pSynth->m_VoicesInUse.GetHead();
  248. for (;pVoice != NULL; pVoice = pVoice->GetNext())
  249. {
  250. if (pVoice->m_fNoteOn && !pVoice->m_fSustainOn &&
  251. (pVoice->m_nPart == dwPart) &&
  252. (pVoice->m_pControl == this))
  253. {
  254. if (m_fSustain[dwPart])
  255. {
  256. pVoice->m_fSustainOn = TRUE;
  257. }
  258. else
  259. {
  260. pVoice->StopVoice(note.m_stTime);
  261. }
  262. }
  263. }
  264. }
  265. break;
  266. case NOTE_SOUNDSOFF:
  267. {
  268. CVoice *pVoice = m_pSynth->m_VoicesInUse.GetHead();
  269. for (;pVoice != NULL; pVoice = pVoice->GetNext())
  270. {
  271. if (pVoice->m_fNoteOn &&
  272. (pVoice->m_nPart == dwPart) &&
  273. (pVoice->m_pControl == this))
  274. {
  275. pVoice->StopVoice(note.m_stTime);
  276. }
  277. }
  278. }
  279. break;
  280. case NOTE_ASSIGNRECEIVE:
  281. m_bPartToChannel[dwPart] = (BYTE) bData;
  282. break;
  283. case NOTE_MASTERVOLUME:
  284. m_vrMasterVolume = CMIDIRecorder::VelocityToVolume(bData);
  285. break;
  286. }
  287. }
  288. else if (note.m_bVelocity == 0) // Note Off.
  289. {
  290. CVoice * pVoice = m_pSynth->m_VoicesInUse.GetHead();
  291. WORD nPart = note.m_bPart;
  292. for (;pVoice != NULL;pVoice = pVoice->GetNext())
  293. {
  294. if (pVoice->m_fNoteOn && !pVoice->m_fSustainOn &&
  295. (pVoice->m_nKey == (WORD) note.m_bKey) &&
  296. (pVoice->m_nPart == nPart) &&
  297. (pVoice->m_pControl == this))
  298. {
  299. if (m_fSustain[nPart])
  300. {
  301. pVoice->m_fSustainOn = TRUE;
  302. }
  303. else
  304. {
  305. pVoice->StopVoice(note.m_stTime);
  306. }
  307. break;
  308. }
  309. }
  310. }
  311. else // Note On.
  312. {
  313. DWORD dwProgram = m_dwProgram[note.m_bPart];
  314. if (m_bDrums[note.m_bPart])
  315. {
  316. dwProgram |= F_INSTRUMENT_DRUMS;
  317. }
  318. if (m_fMono[note.m_bPart])
  319. {
  320. CVoice * pVoice = m_pSynth->m_VoicesInUse.GetHead();
  321. WORD nPart = note.m_bPart;
  322. for (;pVoice != NULL;pVoice = pVoice->GetNext())
  323. {
  324. if (pVoice->m_fNoteOn && (pVoice->m_nPart == nPart) &&
  325. (pVoice->m_pControl == this))
  326. {
  327. pVoice->StopVoice(note.m_stTime);
  328. }
  329. }
  330. }
  331. // While we are working with the instrument, including copying
  332. // the data over from the region, we have to make sure it
  333. // can not be removed from the instrument list.
  334. EnterCriticalSection(&m_pInstruments->m_CriticalSection);
  335. CInstrument * pInstrument =
  336. m_pInstruments->GetInstrument(dwProgram,note.m_bKey);
  337. if (!pInstrument)
  338. {
  339. if (dwProgram & F_INSTRUMENT_DRUMS)
  340. {
  341. dwProgram = F_INSTRUMENT_DRUMS;
  342. pInstrument =
  343. m_pInstruments->GetInstrument(dwProgram,note.m_bKey);
  344. }
  345. else if (m_fXGActive)
  346. {
  347. if ((dwProgram & 0x7F0000) == 0x7F0000) // Drum?
  348. {
  349. dwProgram &= 0x7F007F; // Enforce 0 LSB
  350. pInstrument =
  351. m_pInstruments->GetInstrument(dwProgram,note.m_bKey);
  352. if (!pInstrument)
  353. {
  354. dwProgram = 0x7F0000;
  355. pInstrument =
  356. m_pInstruments->GetInstrument(dwProgram,note.m_bKey);
  357. }
  358. }
  359. else
  360. {
  361. dwProgram &= 0x7F; // Fall back to GM set.
  362. pInstrument =
  363. m_pInstruments->GetInstrument(dwProgram,note.m_bKey);
  364. }
  365. }
  366. }
  367. if (pInstrument != NULL)
  368. {
  369. CSourceRegion * pRegion =
  370. pInstrument->ScanForRegion(note.m_bKey);
  371. if (pRegion != NULL)
  372. {
  373. WORD nPart = note.m_bPart;
  374. CVoice * pVoice = m_pSynth->m_VoicesInUse.GetHead();
  375. if (!pRegion->m_bAllowOverlap)
  376. {
  377. for (;pVoice != NULL; pVoice = pVoice->GetNext())
  378. {
  379. if ((pVoice->m_nPart == nPart) &&
  380. (pVoice->m_nKey == note.m_bKey) &&
  381. (pVoice->m_pControl == this))
  382. {
  383. pVoice->QuickStopVoice(note.m_stTime);
  384. }
  385. }
  386. }
  387. if (pRegion->m_bGroup != 0)
  388. {
  389. pVoice = m_pSynth->m_VoicesInUse.GetHead();
  390. for (;pVoice != NULL;pVoice = pVoice->GetNext())
  391. {
  392. if ((pVoice->m_dwGroup == pRegion->m_bGroup) &&
  393. (pVoice->m_nPart == nPart) &&
  394. (pVoice->m_dwProgram == dwProgram) &&
  395. (pVoice->m_pControl == this))
  396. {
  397. pVoice->QuickStopVoice(note.m_stTime);
  398. }
  399. }
  400. }
  401. pVoice = m_pSynth->m_VoicesFree.RemoveHead();
  402. if (pVoice == NULL)
  403. {
  404. pVoice = m_pSynth->m_VoicesExtra.RemoveHead();
  405. }
  406. if (pVoice == NULL)
  407. {
  408. pVoice = m_pSynth->StealVoice(m_dwPriority[nPart]);
  409. }
  410. if (pVoice != NULL)
  411. {
  412. PREL prPitch = m_prFineTune[nPart] + m_prScaleTune[nPart][note.m_bKey % 12];
  413. if (!m_bDrums[nPart])
  414. {
  415. if (m_fXGActive)
  416. {
  417. if ((dwProgram & 0x7F0000) != 0x7F0000)
  418. {
  419. prPitch += m_prCoarseTune[nPart];
  420. }
  421. }
  422. else
  423. {
  424. prPitch += m_prCoarseTune[nPart];
  425. }
  426. }
  427. pVoice->m_nKey = note.m_bKey;
  428. pVoice->m_nPart = nPart;
  429. pVoice->m_dwProgram = dwProgram;
  430. pVoice->m_dwPriority = m_dwPriority[nPart];
  431. pVoice->m_pControl = this;
  432. if (pVoice->StartVoice( m_pSynth,
  433. pRegion, note.m_stTime,
  434. &m_ModWheel[nPart],
  435. &m_PitchBend[nPart],
  436. &m_Expression[nPart],
  437. &m_Volume[nPart],
  438. &m_Pan[nPart],
  439. (WORD)note.m_bKey,
  440. (WORD)note.m_bVelocity,
  441. m_vrMasterVolume,
  442. prPitch))
  443. {
  444. pVoice->m_fInUse = TRUE;
  445. m_pSynth->QueueVoice(pVoice);
  446. }
  447. else
  448. {
  449. m_pSynth->m_VoicesFree.AddHead(pVoice);
  450. }
  451. }
  452. else
  453. {
  454. m_pSynth->m_BuildStats.dwNotesLost++;
  455. }
  456. }
  457. else
  458. {
  459. m_pSynth->m_BuildStats.dwNotesLost++;
  460. }
  461. }
  462. else
  463. {
  464. Trace(1, "No instrument/region was found for patch # %lx, note %ld\n",
  465. dwProgram, (long) note.m_bKey);
  466. }
  467. LeaveCriticalSection(&m_pInstruments->m_CriticalSection);
  468. }
  469. }
  470. }
  471. /*****************************************************************************
  472. * CControlLogic::Flush()
  473. *****************************************************************************
  474. * Clears events and notes up to a given time.
  475. */
  476. void CControlLogic::Flush(STIME stTime)
  477. {
  478. DWORD dwIndex;
  479. ::EnterCriticalSection(&m_CriticalSection);
  480. if (!m_fEmpty)
  481. {
  482. m_fEmpty = TRUE;
  483. for (dwIndex = 0;dwIndex < 16; dwIndex++)
  484. {
  485. m_fEmpty = m_ModWheel[dwIndex].FlushMIDI(stTime)
  486. && m_PitchBend[dwIndex].FlushMIDI(stTime)
  487. && m_Volume[dwIndex].FlushMIDI(stTime)
  488. && m_Expression[dwIndex].FlushMIDI(stTime)
  489. && m_Pan[dwIndex].FlushMIDI(stTime);
  490. }
  491. m_Notes.FlushMIDI(stTime);
  492. }
  493. ::LeaveCriticalSection(&m_CriticalSection);
  494. }
  495. /*****************************************************************************
  496. * CControlLogic::RecordMIDI()
  497. *****************************************************************************
  498. * Record a MIDI short message into this channel group.
  499. * This dispatches the different MIDI
  500. * messages to the different receptor objects.
  501. */
  502. BOOL CControlLogic::RecordMIDI(STIME stTime,BYTE bStatus, BYTE bData1, BYTE bData2)
  503. {
  504. WORD nPreChannel = bStatus & 0xF;
  505. CNote note;
  506. bStatus = bStatus & 0xF0;
  507. BOOL bReturn = TRUE;
  508. WORD nPart;
  509. ::EnterCriticalSection(&m_CriticalSection);
  510. for (nPart = 0;nPart < 16; nPart++)
  511. {
  512. if (nPreChannel == m_bPartToChannel[nPart])
  513. {
  514. switch (bStatus)
  515. {
  516. case MIDI_NOTEOFF :
  517. bData2 = 0;
  518. case MIDI_NOTEON :
  519. note.m_bPart = (BYTE) nPart;
  520. note.m_bKey = bData1;
  521. note.m_bVelocity = bData2;
  522. bReturn = m_Notes.RecordNote(stTime,&note);
  523. break;
  524. case MIDI_CCHANGE :
  525. switch (bData1)
  526. {
  527. case CC_BANKSELECTH :
  528. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_BANKSELECTH, bData2);
  529. break;
  530. case CC_MODWHEEL :
  531. m_fEmpty = FALSE;
  532. bReturn = m_ModWheel[nPart].RecordMIDI(stTime,(long) bData2);
  533. break;
  534. case CC_VOLUME :
  535. m_fEmpty = FALSE;
  536. bReturn = m_Volume[nPart].RecordMIDI(stTime,(long) bData2);
  537. break;
  538. case CC_PAN :
  539. m_fEmpty = FALSE;
  540. bReturn = m_Pan[nPart].RecordMIDI(stTime,(long) bData2);
  541. break;
  542. case CC_EXPRESSION :
  543. m_fEmpty = FALSE;
  544. bReturn = m_Expression[nPart].RecordMIDI(stTime,(long)bData2);
  545. break;
  546. case CC_BANKSELECTL :
  547. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_BANKSELECTL, bData2);
  548. break;
  549. case CC_RESETALL:
  550. m_fEmpty = FALSE;
  551. if (bData2)
  552. {
  553. bReturn = bReturn && m_Volume[nPart].RecordMIDI(stTime, 100);
  554. bReturn = bReturn && m_Pan[nPart].RecordMIDI(stTime, 64);
  555. }
  556. bReturn = bReturn && m_Expression[nPart].RecordMIDI(stTime, 127);
  557. bReturn = bReturn && m_PitchBend[nPart].RecordMIDI(stTime, 0x2000);
  558. bReturn = m_ModWheel[nPart].RecordMIDI(stTime, 0);
  559. bData2 = 0;
  560. // fall through into Sustain Off case....
  561. case CC_SUSTAIN :
  562. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_SUSTAIN, bData2);
  563. break;
  564. case CC_ALLSOUNDSOFF:
  565. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_SOUNDSOFF, 0);
  566. break;
  567. case CC_ALLNOTESOFF:
  568. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_ALLOFF, 0);
  569. break;
  570. case CC_DATAENTRYMSB:
  571. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_DATAENTRYMSB, bData2);
  572. break;
  573. case CC_DATAENTRYLSB:
  574. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_DATAENTRYLSB, bData2);
  575. break;
  576. case CC_NRPN_LSB :
  577. case CC_NRPN_MSB :
  578. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_NRPN, bData2);
  579. break;
  580. case CC_RPN_LSB:
  581. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_RPN_LSB, bData2);
  582. break;
  583. case CC_RPN_MSB:
  584. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_RPN_MSB, bData2);
  585. break;
  586. case CC_MONOMODE :
  587. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_MONOMODE, bData2);
  588. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_SOUNDSOFF, 0);
  589. break;
  590. case CC_POLYMODE :
  591. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_POLYMODE, bData2);
  592. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_SOUNDSOFF, 0);
  593. break;
  594. default:
  595. break;
  596. }
  597. break;
  598. case MIDI_PCHANGE :
  599. bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_PROGRAMCHANGE, bData1);
  600. break;
  601. case MIDI_PBEND :
  602. m_fEmpty = FALSE;
  603. {
  604. WORD nBend;
  605. nBend = bData2 << 7;
  606. nBend |= bData1;
  607. bReturn = m_PitchBend[nPart].RecordMIDI(stTime,(long)nBend);
  608. }
  609. break;
  610. }
  611. }
  612. }
  613. ::LeaveCriticalSection(&m_CriticalSection);
  614. return bReturn;
  615. }
  616. /*****************************************************************************
  617. * CControlLogic::RecordSysEx()
  618. *****************************************************************************
  619. * Record a MIDI SysEx message into this channel group.
  620. * This dispatches the different MIDI
  621. * messages to the different receptor objects.
  622. */
  623. HRESULT CControlLogic::RecordSysEx(DWORD dwSysExLength,BYTE *pSysExData, STIME stTime)
  624. {
  625. HRESULT hSuccess = S_OK;
  626. int nPart;
  627. int nTune;
  628. DWORD dwAddress;
  629. BOOL fClearAll = FALSE;
  630. BOOL fResetPatches = FALSE;
  631. if (dwSysExLength < 6)
  632. {
  633. return E_FAIL;
  634. }
  635. switch (pSysExData[1]) // ID number
  636. {
  637. case 0x7E : // General purpose ID
  638. if (pSysExData[3] == 0x09)
  639. {
  640. GMReset();
  641. fClearAll = TRUE;
  642. fResetPatches = TRUE;
  643. }
  644. break;
  645. case 0x7F : // Real time ID
  646. if (pSysExData[3] == 0x04)
  647. {
  648. if (pSysExData[4] == 1) // Master Volume
  649. {
  650. m_Notes.RecordEvent(stTime, 0, NOTE_MASTERVOLUME, pSysExData[6]);
  651. }
  652. }
  653. break;
  654. case 0x41 : // Roland
  655. if (dwSysExLength < 11)
  656. {
  657. return E_FAIL;
  658. }
  659. if (pSysExData[3] != 0x42) break;
  660. if (pSysExData[4] != 0x12) break;
  661. nPart = pSysExData[6] & 0xF;
  662. dwAddress = (pSysExData[5] << 16) |
  663. ((pSysExData[6] & 0xF0) << 8) | pSysExData[7];
  664. switch (dwAddress)
  665. {
  666. case 0x40007F : // GS Reset.
  667. GMReset();
  668. m_fXGActive = FALSE;
  669. fClearAll = TRUE;
  670. m_fGSActive = TRUE;
  671. fResetPatches = TRUE;
  672. break;
  673. case 0x401002 : // Set Receive Channel.
  674. if (m_fGSActive)
  675. {
  676. if (pSysExData[8])
  677. {
  678. m_Notes.RecordEvent(stTime, nPart, NOTE_ASSIGNRECEIVE, pSysExData[8] - 1);
  679. }
  680. }
  681. break;
  682. case 0x401015 : // Use for Rhythm.
  683. if (m_fGSActive)
  684. {
  685. m_bDrums[nPart] = pSysExData[8];
  686. fClearAll = TRUE;
  687. }
  688. break;
  689. case 0x401040 : // Scale Tuning.
  690. if (m_fGSActive)
  691. {
  692. for (nTune = 0;nTune < 12; nTune++)
  693. {
  694. if (pSysExData[9 + nTune] & 0x80) break;
  695. m_prScaleTune[nPart][nTune] =
  696. (PREL) pSysExData[8 + nTune] - (PREL) 64;
  697. }
  698. }
  699. break;
  700. }
  701. break;
  702. case 0x43 : // Yamaha
  703. if ((pSysExData[3] == 0x4C) &&
  704. (pSysExData[4] == 0) &&
  705. (pSysExData[5] == 0) &&
  706. (pSysExData[6] == 0x7E) &&
  707. (pSysExData[7] == 0))
  708. { // XG System On
  709. m_fXGActive = TRUE;
  710. m_fGSActive = FALSE;
  711. GMReset();
  712. m_fXGActive = TRUE;
  713. m_bDrums[0] = 0;
  714. m_bBankH[0] = 127;
  715. fClearAll = TRUE;
  716. fResetPatches = TRUE;
  717. }
  718. break;
  719. }
  720. if (fClearAll)
  721. {
  722. m_pSynth->AllNotesOff();
  723. Flush(0);
  724. for (nPart = 0;nPart < 16;nPart++)
  725. {
  726. m_Notes.RecordEvent(stTime, nPart, NOTE_SUSTAIN, 0);
  727. m_Volume[nPart].RecordMIDI(stTime, 100);
  728. m_Pan[nPart].RecordMIDI(stTime, 64);
  729. m_Expression[nPart].RecordMIDI(stTime, 127);
  730. m_PitchBend[nPart].RecordMIDI(stTime, 0x2000);
  731. m_ModWheel[nPart].RecordMIDI(stTime, 0);
  732. }
  733. }
  734. if (fResetPatches)
  735. {
  736. for (nPart = 0;nPart < 16;nPart++)
  737. {
  738. if ((nPart == 0) && (m_fXGActive))
  739. {
  740. m_Notes.RecordEvent(stTime-1, nPart, NOTE_CC_BANKSELECTH, 127);
  741. }
  742. else
  743. {
  744. m_Notes.RecordEvent(stTime-1, nPart, NOTE_CC_BANKSELECTH, 0);
  745. }
  746. m_Notes.RecordEvent(stTime-1, nPart, NOTE_CC_BANKSELECTL, 0);
  747. m_Notes.RecordEvent(stTime, nPart, NOTE_PROGRAMCHANGE, 0);
  748. }
  749. }
  750. return hSuccess;
  751. }
  752. /*****************************************************************************
  753. * CControlLogic::SetChannelPriority()
  754. *****************************************************************************
  755. * Set the priority for a given channel, within this channel group.
  756. */
  757. HRESULT CControlLogic::SetChannelPriority(DWORD dwChannel,DWORD dwPriority)
  758. {
  759. DWORD dwPart;
  760. for (dwPart = 0;dwPart < 16; dwPart++)
  761. {
  762. if (m_bPartToChannel[dwPart] == dwChannel)
  763. {
  764. m_dwPriority[dwPart] = dwPriority;
  765. }
  766. }
  767. return S_OK;
  768. }
  769. /*****************************************************************************
  770. * CControlLogic::GetChannelPriority()
  771. *****************************************************************************
  772. * Retrieve the priority for a given channel, within this channel group.
  773. */
  774. HRESULT CControlLogic::GetChannelPriority(DWORD dwChannel,LPDWORD pdwPriority)
  775. {
  776. DWORD dwPart;
  777. for (dwPart = 0;dwPart < 16; dwPart++)
  778. {
  779. if (m_bPartToChannel[dwPart] == dwChannel)
  780. {
  781. *pdwPriority = m_dwPriority[dwPart];
  782. break;
  783. }
  784. }
  785. return S_OK;
  786. }