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.

490 lines
11 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. // MIDI.cpp
  3. //
  4. #ifdef DMSYNTH_MINIPORT
  5. #include "common.h"
  6. #else
  7. #include "simple.h"
  8. #include <mmsystem.h>
  9. #include "synth.h"
  10. #include "math.h"
  11. #include "debug.h"
  12. #endif
  13. CMIDIDataList CMIDIRecorder::m_sFreeList;
  14. DWORD CMIDIRecorder::m_sUsageCount = 0;
  15. CMIDIData::CMIDIData()
  16. {
  17. m_stTime = 0;
  18. m_lData = 0;
  19. }
  20. CMIDIRecorder::CMIDIRecorder()
  21. {
  22. m_sUsageCount++;
  23. m_lCurrentData = 0;
  24. m_stCurrentTime = 0;
  25. }
  26. CMIDIRecorder::~CMIDIRecorder()
  27. {
  28. ClearMIDI(0x7FFFFFFF);
  29. m_sUsageCount--;
  30. // If there are no instances of CMIDIRecorder left, get rid of the free pool.
  31. if (!m_sUsageCount)
  32. {
  33. CMIDIData *pMD;
  34. while (pMD = m_sFreeList.RemoveHead())
  35. {
  36. delete pMD;
  37. }
  38. }
  39. }
  40. VREL CMIDIRecorder::m_vrMIDIToVREL[128] =
  41. {
  42. -9600, -8415, -7211, -6506, -6006, -5619, -5302, -5034,
  43. -4802, -4598, -4415, -4249, -4098, -3959, -3830, -3710,
  44. -3598, -3493, -3394, -3300, -3211, -3126, -3045, -2968,
  45. -2894, -2823, -2755, -2689, -2626, -2565, -2506, -2449,
  46. -2394, -2341, -2289, -2238, -2190, -2142, -2096, -2050,
  47. -2006, -1964, -1922, -1881, -1841, -1802, -1764, -1726,
  48. -1690, -1654, -1619, -1584, -1551, -1518, -1485, -1453,
  49. -1422, -1391, -1361, -1331, -1302, -1273, -1245, -1217,
  50. -1190, -1163, -1137, -1110, -1085, -1059, -1034, -1010,
  51. -985, -961, -938, -914, -891, -869, -846, -824,
  52. -802, -781, -759, -738, -718, -697, -677, -657,
  53. -637, -617, -598, -579, -560, -541, -522, -504,
  54. -486, -468, -450, -432, -415, -397, -380, -363,
  55. -347, -330, -313, -297, -281, -265, -249, -233,
  56. -218, -202, -187, -172, -157, -142, -127, -113,
  57. -98, -84, -69, -55, -41, -27, -13, 0
  58. };
  59. VREL CMIDIRecorder::m_vrMIDIPercentToVREL[128] =
  60. {
  61. -9600, -4207, -3605, -3253, -3003, -2809, -2651, -2517,
  62. -2401, -2299, -2207, -2124, -2049, -1979, -1915, -1855,
  63. -1799, -1746, -1697, -1650, -1605, -1563, -1522, -1484,
  64. -1447, -1411, -1377, -1344, -1313, -1282, -1253, -1224,
  65. -1197, -1170, -1144, -1119, -1095, -1071, -1048, -1025,
  66. -1003, -982, -961, -940, -920, -901, -882, -863,
  67. -845, -827, -809, -792, -775, -759, -742, -726,
  68. -711, -695, -680, -665, -651, -636, -622, -608,
  69. -595, -581, -568, -555, -542, -529, -517, -505,
  70. -492, -480, -469, -457, -445, -434, -423, -412,
  71. -401, -390, -379, -369, -359, -348, -338, -328,
  72. -318, -308, -299, -289, -280, -270, -261, -252,
  73. -243, -234, -225, -216, -207, -198, -190, -181,
  74. -173, -165, -156, -148, -140, -132, -124, -116,
  75. -109, -101, -93, -86, -78, -71, -63, -56,
  76. -49, -42, -34, -27, -20, -13, -6, 0
  77. };
  78. /*void CMIDIRecorder::Init()
  79. {
  80. int nIndex;
  81. static BOOL fAlreadyDone = FALSE;
  82. if (!fAlreadyDone)
  83. {
  84. m_sFreeList.RemoveAll();
  85. for (nIndex = 0; nIndex < MAX_MIDI_EVENTS; nIndex++)
  86. {
  87. m_sFreeList.AddHead(&m_sEventBuffer[nIndex]);
  88. }
  89. fAlreadyDone = TRUE;*/
  90. /* for (nIndex = 1; nIndex < 128; nIndex++)
  91. {
  92. double flTemp;
  93. flTemp = nIndex;
  94. flTemp /= 127.0;
  95. flTemp = pow(flTemp,4.0);
  96. flTemp = log10(flTemp);
  97. flTemp *= 1000.0;
  98. Trace(0,"%ld, ",(long)flTemp);
  99. if ((nIndex % 8) == 7)
  100. Trace(0,"\n");
  101. m_vrMIDIToVREL[nIndex] = (VREL) flTemp;
  102. }
  103. Trace(0,"\n");
  104. m_vrMIDIToVREL[0] = -9600;
  105. for (nIndex = 1; nIndex < 128; nIndex++)
  106. {
  107. double flTemp;
  108. flTemp = nIndex;
  109. flTemp /= 127;
  110. flTemp *= flTemp;
  111. flTemp = log10(flTemp);
  112. flTemp *= 1000.0;
  113. m_vrMIDIPercentToVREL[nIndex] = (VREL) flTemp;
  114. Trace(0,"%ld, ",(long)flTemp);
  115. if ((nIndex % 8) == 7)
  116. Trace(0,"\n");
  117. }
  118. m_vrMIDIPercentToVREL[0] = -9600;*/
  119. /*}
  120. }*/
  121. BOOL CMIDIRecorder::FlushMIDI(STIME stTime)
  122. {
  123. CMIDIData *pMD;
  124. CMIDIData *pLast = NULL;
  125. for (pMD = m_EventList.GetHead();pMD != NULL;pMD = pMD->GetNext())
  126. {
  127. if (pMD->m_stTime >= stTime)
  128. {
  129. if (pLast == NULL)
  130. {
  131. m_EventList.RemoveAll();
  132. }
  133. else
  134. {
  135. pLast->SetNext(NULL);
  136. }
  137. m_sFreeList.Cat(pMD);
  138. break;
  139. }
  140. pLast = pMD;
  141. }
  142. return m_EventList.IsEmpty();
  143. }
  144. BOOL CMIDIRecorder::ClearMIDI(STIME stTime)
  145. {
  146. CMIDIData *pMD;
  147. for (;pMD = m_EventList.GetHead();)
  148. {
  149. if (pMD->m_stTime < stTime)
  150. {
  151. m_EventList.RemoveHead();
  152. m_stCurrentTime = pMD->m_stTime;
  153. m_lCurrentData = pMD->m_lData;
  154. m_sFreeList.AddHead(pMD);
  155. }
  156. else break;
  157. }
  158. return m_EventList.IsEmpty();
  159. }
  160. VREL CMIDIRecorder::VelocityToVolume(WORD nVelocity)
  161. {
  162. return (m_vrMIDIToVREL[nVelocity]);
  163. }
  164. BOOL CMIDIRecorder::RecordMIDINote(STIME stTime, long lData)
  165. {
  166. CMIDIData *pMD = m_sFreeList.RemoveHead();
  167. if (!pMD)
  168. {
  169. pMD = new CMIDIData;
  170. }
  171. CMIDIData *pScan = m_EventList.GetHead();
  172. CMIDIData *pNext;
  173. if (pMD)
  174. {
  175. pMD->m_stTime = stTime;
  176. pMD->m_lData = lData;
  177. if (pScan == NULL)
  178. {
  179. m_EventList.AddHead(pMD);
  180. }
  181. else
  182. {
  183. if (pScan->m_stTime > stTime)
  184. {
  185. m_EventList.AddHead(pMD);
  186. }
  187. else
  188. {
  189. for (;pScan != NULL; pScan = pNext)
  190. {
  191. pNext = pScan->GetNext();
  192. if (pNext == NULL)
  193. {
  194. pScan->SetNext(pMD);
  195. }
  196. else
  197. {
  198. if (pNext->m_stTime > stTime)
  199. {
  200. pMD->SetNext(pNext);
  201. pScan->SetNext(pMD);
  202. break;
  203. }
  204. }
  205. }
  206. }
  207. }
  208. return (TRUE);
  209. }
  210. return (FALSE);
  211. }
  212. BOOL CMIDIRecorder::RecordMIDI(STIME stTime, long lData)
  213. {
  214. CMIDIData *pMD = m_sFreeList.RemoveHead();
  215. if (!pMD)
  216. {
  217. pMD = new CMIDIData;
  218. }
  219. CMIDIData *pScan = m_EventList.GetHead();
  220. CMIDIData *pNext;
  221. if (pMD)
  222. {
  223. pMD->m_stTime = stTime;
  224. pMD->m_lData = lData;
  225. if (pScan == NULL)
  226. {
  227. m_EventList.AddHead(pMD);
  228. }
  229. else
  230. {
  231. if (pScan->m_stTime > stTime)
  232. {
  233. m_EventList.AddHead(pMD);
  234. }
  235. else
  236. {
  237. for (;pScan != NULL; pScan = pNext)
  238. {
  239. if ((pScan->m_stTime == stTime) &&
  240. (pScan->m_lData == lData))
  241. {
  242. m_sFreeList.AddHead(pMD);
  243. break;
  244. }
  245. pNext = pScan->GetNext();
  246. if (pNext == NULL)
  247. {
  248. pScan->SetNext(pMD);
  249. }
  250. else
  251. {
  252. if (pNext->m_stTime > stTime)
  253. {
  254. pMD->SetNext(pNext);
  255. pScan->SetNext(pMD);
  256. break;
  257. }
  258. }
  259. }
  260. }
  261. }
  262. return (TRUE);
  263. }
  264. /*#ifdef DBG
  265. static gWarnCount = 0;
  266. if (!gWarnCount)
  267. {
  268. Trace(1,"Warning: MIDI Free event pool empty. This can be caused by time stamping problems, too much MIDI data, or too many PChannels.\n");
  269. gWarnCount = 100;
  270. }
  271. gWarnCount--;
  272. #endif*/
  273. return (FALSE);
  274. }
  275. long CMIDIRecorder::GetData(STIME stTime)
  276. {
  277. CMIDIData *pMD = m_EventList.GetHead();
  278. long lData = m_lCurrentData;
  279. for (;pMD;pMD = pMD->GetNext())
  280. {
  281. if (pMD->m_stTime > stTime)
  282. {
  283. break;
  284. }
  285. lData = pMD->m_lData;
  286. }
  287. return (lData);
  288. }
  289. BOOL CNoteIn::RecordNote(STIME stTime, CNote * pNote)
  290. {
  291. long lData = pNote->m_bPart << 16;
  292. lData |= pNote->m_bKey << 8;
  293. lData |= pNote->m_bVelocity;
  294. return (RecordMIDINote(stTime,lData));
  295. }
  296. BOOL CNoteIn::RecordEvent(STIME stTime, DWORD dwPart, DWORD dwCommand, BYTE bData)
  297. {
  298. long lData = dwPart;
  299. lData <<= 8;
  300. lData |= dwCommand;
  301. lData <<= 8;
  302. lData |= bData;
  303. return (RecordMIDINote(stTime,lData));
  304. }
  305. BOOL CNoteIn::GetNote(STIME stTime, CNote * pNote)
  306. {
  307. CMIDIData *pMD = m_EventList.GetHead();
  308. if (pMD != NULL)
  309. {
  310. if (pMD->m_stTime <= stTime)
  311. {
  312. pNote->m_stTime = pMD->m_stTime;
  313. pNote->m_bPart = (BYTE) (pMD->m_lData >> 16);
  314. pNote->m_bKey = (BYTE) (pMD->m_lData >> 8) & 0xFF;
  315. pNote->m_bVelocity = (BYTE) pMD->m_lData & 0xFF;
  316. m_EventList.RemoveHead();
  317. m_sFreeList.AddHead(pMD);
  318. return (TRUE);
  319. }
  320. }
  321. return (FALSE);
  322. }
  323. void CNoteIn::FlushMIDI(STIME stTime)
  324. {
  325. CMIDIData *pMD;
  326. for (pMD = m_EventList.GetHead();pMD != NULL;pMD = pMD->GetNext())
  327. {
  328. if (pMD->m_stTime >= stTime)
  329. {
  330. pMD->m_stTime = stTime; // Play now.
  331. pMD->m_lData &= 0xFFFFFF00; // Clear velocity to make note off.
  332. }
  333. }
  334. }
  335. void CNoteIn::FlushPart(STIME stTime, BYTE bChannel)
  336. {
  337. CMIDIData *pMD;
  338. for (pMD = m_EventList.GetHead();pMD != NULL;pMD = pMD->GetNext())
  339. {
  340. if (pMD->m_stTime >= stTime)
  341. {
  342. if (bChannel == (BYTE) (pMD->m_lData >> 16))
  343. {
  344. pMD->m_stTime = stTime; // Play now.
  345. pMD->m_lData &= 0xFFFFFF00; // Clear velocity to make note off.
  346. }
  347. }
  348. }
  349. }
  350. DWORD CModWheelIn::GetModulation(STIME stTime)
  351. {
  352. DWORD nResult = CMIDIRecorder::GetData(stTime);
  353. return (nResult);
  354. }
  355. CPitchBendIn::CPitchBendIn()
  356. {
  357. m_lCurrentData = 0x2000; // initially at midpoint, no bend
  358. m_prRange = 200; // whole tone range by default.
  359. }
  360. // note (davidmay 8/14/96): we don't keep a time-stamped range.
  361. // if people are changing the pitch bend range often, this won't work right,
  362. // but that didn't seem likely enough to warrant a new list.
  363. PREL CPitchBendIn::GetPitch(STIME stTime)
  364. {
  365. PREL prResult = (PREL) CMIDIRecorder::GetData(stTime);
  366. prResult -= 0x2000; // Subtract MIDI Midpoint.
  367. prResult *= m_prRange; // adjust by current range
  368. prResult >>= 13;
  369. return (prResult);
  370. }
  371. CVolumeIn::CVolumeIn()
  372. {
  373. m_lCurrentData = 100;
  374. }
  375. VREL CVolumeIn::GetVolume(STIME stTime)
  376. {
  377. long lResult = CMIDIRecorder::GetData(stTime);
  378. return (m_vrMIDIToVREL[lResult]);
  379. }
  380. CExpressionIn::CExpressionIn()
  381. {
  382. m_lCurrentData = 127;
  383. }
  384. VREL CExpressionIn::GetVolume(STIME stTime)
  385. {
  386. long lResult = CMIDIRecorder::GetData(stTime);
  387. return (m_vrMIDIToVREL[lResult]);
  388. }
  389. CPanIn::CPanIn()
  390. {
  391. m_lCurrentData = 64;
  392. }
  393. long CPanIn::GetPan(STIME stTime)
  394. {
  395. long lResult = (long) CMIDIRecorder::GetData(stTime);
  396. return (lResult);
  397. }
  398. //////////////////////////////////////////////////////////
  399. // Directx8 Methods
  400. DWORD CPressureIn::GetPressure(STIME stTime)
  401. {
  402. DWORD nResult = CMIDIRecorder::GetData(stTime);
  403. return (nResult);
  404. }
  405. CReverbIn::CReverbIn()
  406. {
  407. m_lCurrentData = 40;
  408. }
  409. DWORD CReverbIn::GetVolume(STIME stTime)
  410. {
  411. return (m_vrMIDIPercentToVREL[CMIDIRecorder::GetData(stTime)]);
  412. }
  413. DWORD CChorusIn::GetVolume(STIME stTime)
  414. {
  415. return (m_vrMIDIPercentToVREL[CMIDIRecorder::GetData(stTime)]);
  416. }
  417. CCutOffFreqIn::CCutOffFreqIn()
  418. {
  419. m_lCurrentData = 64;
  420. }
  421. DWORD CCutOffFreqIn::GetFrequency(STIME stTime)
  422. {
  423. DWORD nResult = CMIDIRecorder::GetData(stTime);
  424. return (nResult);
  425. }