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.

910 lines
26 KiB

  1. /*
  2. *
  3. * Copyright (c) 1992-1995 Microsoft Corporation
  4. *
  5. */
  6. /*
  7. * midi.c
  8. *
  9. * Midi FM Synthesis routines. converts midi messages into calls to
  10. * FM Synthesis functions - currently supports base adlib (in adlib.c)
  11. * and opl3 synthesisers (in opl3.c).
  12. *
  13. * 15 Dec 92 Geraint Davies - based on a combination of the adlib
  14. * and WSS midi drivers.
  15. */
  16. #include <windows.h>
  17. #include <mmsystem.h>
  18. #include "mmddk.h"
  19. #include "driver.h"
  20. #include "adlib.h"
  21. #include "opl3.h"
  22. /***********************************************************
  23. global memory */
  24. PORTALLOC gMidiInClient; // input client information structure
  25. DWORD dwRefTime; // time when midi input was opened
  26. DWORD dwMsgTime; // timestamp (in ms) of current msg
  27. DWORD dwMsg = 0L; // short midi message
  28. BYTE bBytesLeft = 0; // number of bytes needed to complete message
  29. BYTE bBytePos = 0; // position in short message buffer
  30. DWORD dwCurData = 0L; // position in long message buffer
  31. BOOL fSysex = FALSE; // are we in sysex mode?
  32. BYTE status = 0;
  33. BYTE fMidiInStarted = 0; /* has the midi been started */
  34. LPMIDIHDR lpMIQueue = NULL;
  35. BYTE gbMidiInUse = 0; /* if MIDI is in use */
  36. static WORD wMidiOutEntered = 0; // reentrancy check
  37. static PORTALLOC gMidiOutClient; // client information
  38. /* transformation of linear velocity value to
  39. logarithmic attenuation */
  40. BYTE gbVelocityAtten[32] = {
  41. 40, 36, 32, 28, 23, 21, 19, 17,
  42. 15, 14, 13, 12, 11, 10, 9, 8,
  43. 7, 6, 5, 5, 4, 4, 3, 3,
  44. 2, 2, 1, 1, 1, 0, 0, 0 };
  45. BYTE BCODE gbPercMap[53][2] =
  46. {
  47. { 0, 35 },
  48. { 0, 35 },
  49. { 2, 52 },
  50. { 3, 48 },
  51. { 4, 58 },
  52. { 5, 60 },
  53. { 6, 47 },
  54. { 7, 43 },
  55. { 6, 49 },
  56. { 9, 43 },
  57. { 6, 51 },
  58. { 11, 43 },
  59. { 6, 54 },
  60. { 6, 57 },
  61. { 14, 72 },
  62. { 6, 60 },
  63. { 16, 76 },
  64. { 17, 84 },
  65. { 18, 36 },
  66. { 19, 76 },
  67. { 20, 84 },
  68. { 21, 83 },
  69. { 22, 84 },
  70. { 23, 24 },
  71. { 16, 77 },
  72. { 25, 60 },
  73. { 26, 65 },
  74. { 27, 59 },
  75. { 28, 51 },
  76. { 29, 45 },
  77. { 30, 71 },
  78. { 31, 60 },
  79. { 32, 58 },
  80. { 33, 53 },
  81. { 34, 64 },
  82. { 35, 71 },
  83. { 36, 61 },
  84. { 37, 61 },
  85. { 38, 48 },
  86. { 39, 48 },
  87. { 40, 69 },
  88. { 41, 68 },
  89. { 42, 63 },
  90. { 43, 74 },
  91. { 44, 60 },
  92. { 45, 80 },
  93. { 46, 64 },
  94. { 47, 69 },
  95. { 48, 73 },
  96. { 49, 75 },
  97. { 50, 68 },
  98. { 51, 48 },
  99. { 52, 53 }
  100. } ;
  101. short giBend[NUMCHANNELS]; /* bend for each channel */
  102. BYTE gbPatch[NUMCHANNELS]; /* patch number mapped to */
  103. /* --- interface functions ---------------------------------- */
  104. /*
  105. * the functions in this section call out to adlib.c or opl3.c
  106. * depending on which device we have installed.
  107. */
  108. /**************************************************************
  109. MidiAllNotesOff - switch off all active voices.
  110. inputs - none
  111. returns - none
  112. */
  113. VOID MidiAllNotesOff(void)
  114. {
  115. switch (gMidiType) {
  116. case TYPE_OPL3:
  117. Opl3_AllNotesOff();
  118. break;
  119. case TYPE_ADLIB:
  120. Adlib_AllNotesOff();
  121. break;
  122. }
  123. }
  124. /**************************************************************
  125. MidiNewVolume - This should be called if a volume level
  126. has changed. This will adjust the levels of all the playing
  127. voices.
  128. inputs
  129. WORD wLeft - left attenuation (1.5 db units)
  130. WORD wRight - right attenuation (ignore if mono)
  131. returns
  132. none
  133. */
  134. VOID FAR PASCAL MidiNewVolume (WORD wLeft, WORD wRight)
  135. {
  136. switch (gMidiType) {
  137. case TYPE_OPL3:
  138. Opl3_NewVolume(wLeft, wRight);
  139. break;
  140. case TYPE_ADLIB:
  141. Adlib_NewVolume(wLeft, wRight);
  142. break;
  143. }
  144. }
  145. /***************************************************************
  146. MidiChannelVolume - set the volume level for an individual channel.
  147. inputs
  148. BYTE bChannel - channel number to change
  149. WORD wAtten - attenuation in 1.5 db units
  150. returns
  151. none
  152. */
  153. VOID FAR PASCAL MidiChannelVolume(BYTE bChannel, WORD wAtten)
  154. {
  155. switch (gMidiType) {
  156. case TYPE_OPL3:
  157. Opl3_ChannelVolume(bChannel, wAtten);
  158. break;
  159. case TYPE_ADLIB:
  160. Adlib_ChannelVolume(bChannel, wAtten);
  161. break;
  162. }
  163. }
  164. /***************************************************************
  165. MidiSetPan - set the left-right pan position.
  166. inputs
  167. BYTE bChannel - channel number to alter
  168. BYTE bPan - 0 for left, 127 for right or somewhere in the middle.
  169. returns - none
  170. */
  171. VOID FAR PASCAL MidiSetPan(BYTE bChannel, BYTE bPan)
  172. {
  173. switch (gMidiType) {
  174. case TYPE_OPL3:
  175. Opl3_SetPan(bChannel, bPan);
  176. break;
  177. case TYPE_ADLIB:
  178. Adlib_SetPan(bChannel, bPan);
  179. break;
  180. }
  181. }
  182. /***************************************************************
  183. MidiPitchBend - This pitch bends a channel.
  184. inputs
  185. BYTE bChannel - channel
  186. short iBend - Values from -32768 to 32767, being
  187. -2 to +2 half steps
  188. returns
  189. none
  190. */
  191. VOID NEAR PASCAL MidiPitchBend (BYTE bChannel,
  192. short iBend)
  193. {
  194. switch (gMidiType) {
  195. case TYPE_OPL3:
  196. Opl3_PitchBend(bChannel, iBend);
  197. break;
  198. case TYPE_ADLIB:
  199. Adlib_PitchBend(bChannel, iBend);
  200. break;
  201. }
  202. }
  203. /***************************************************************
  204. MidiBoardInit - initialise board and load patches as necessary.
  205. * inputs - none
  206. * returns - 0 for success or the error code
  207. */
  208. WORD MidiBoardInit(void)
  209. {
  210. /*
  211. * load patch tables and reset board
  212. */
  213. switch (gMidiType) {
  214. case TYPE_OPL3:
  215. return( Opl3_BoardInit());
  216. break;
  217. case TYPE_ADLIB:
  218. return (Adlib_BoardInit());
  219. break;
  220. }
  221. return(MMSYSERR_ERROR);
  222. }
  223. /*
  224. * MidiBoardReset - silence the board and set all voices off.
  225. */
  226. VOID MidiBoardReset(void)
  227. {
  228. BYTE i;
  229. /*
  230. * switch off pitch bend (we own this, not the opl3/adlib code)
  231. */
  232. for (i = 0; i < NUMCHANNELS; i++)
  233. giBend[i] = 0;
  234. /*
  235. * set all voices off, set channel atten to default,
  236. * & silence board.
  237. */
  238. switch (gMidiType) {
  239. case TYPE_OPL3:
  240. Opl3_BoardReset();
  241. break;
  242. case TYPE_ADLIB:
  243. Adlib_BoardReset();
  244. break;
  245. }
  246. }
  247. /* --- midi interpretation -------------------------------------*/
  248. /***************************************************************
  249. MidiMessage - This handles a MIDI message. This
  250. does not do running status.
  251. inputs
  252. DWORD dwData - up to 4 bytes of MIDI data
  253. depending upon the message.
  254. returns
  255. none
  256. */
  257. VOID NEAR PASCAL MidiMessage (DWORD dwData)
  258. {
  259. BYTE bChannel, bVelocity, bNote;
  260. WORD wTemp;
  261. // D1("\nMidiMessage");
  262. bChannel = (BYTE) dwData & (BYTE)0x0f;
  263. bVelocity = (BYTE) (dwData >> 16) & (BYTE)0x7f;
  264. bNote = (BYTE) ((WORD) dwData >> 8) & (BYTE)0x7f;
  265. switch ((BYTE)dwData & 0xf0) {
  266. case 0x90:
  267. #ifdef DEBUG
  268. {
  269. char szTemp[4];
  270. szTemp[0] = "0123456789abcdef"[bNote >> 4];
  271. szTemp[1] = "0123456789abcdef"[bNote & 0x0f];
  272. szTemp[2] = ' ';
  273. szTemp[3] = 0;
  274. if ((bChannel == 9) && bVelocity) D1(szTemp);
  275. }
  276. #endif
  277. /* turn key on, or key off if volume == 0 */
  278. if (bVelocity) {
  279. switch(gMidiType) {
  280. case TYPE_OPL3:
  281. if (bChannel == DRUMCHANNEL)
  282. {
  283. if (bNote >= 35 && bNote <= 87)
  284. {
  285. #ifdef DEBUG
  286. char szDebug[ 80 ] ;
  287. wsprintf( szDebug, "bChannel = %d, bNote = %d",
  288. bChannel, bNote ) ;
  289. D1( szDebug ) ;
  290. #endif
  291. Opl3_NoteOn( (BYTE) (gbPercMap[ bNote - 35 ][ 0 ] + 0x80),
  292. gbPercMap[ bNote - 35 ][ 1 ],
  293. bChannel, bVelocity,
  294. (short) giBend[ bChannel ] ) ;
  295. }
  296. }
  297. else
  298. Opl3_NoteOn( (BYTE) gbPatch[ bChannel ], bNote, bChannel,
  299. bVelocity, (short) giBend[ bChannel ] ) ;
  300. break;
  301. case TYPE_ADLIB:
  302. Adlib_NoteOn (
  303. (BYTE) ((bChannel == DRUMCHANNEL) ?
  304. (BYTE) (bNote + 128) : (BYTE) gbPatch[bChannel]),
  305. bNote, bChannel, bVelocity, (short) giBend[bChannel]);
  306. break;
  307. }
  308. break;
  309. }
  310. /* else, continue through and turn key off */
  311. case 0x80:
  312. /* turn key off */
  313. switch (gMidiType) {
  314. case TYPE_OPL3:
  315. if (bChannel == DRUMCHANNEL)
  316. {
  317. if (bNote >= 35 && bNote <= 87)
  318. Opl3_NoteOff( (BYTE) (gbPercMap[ bNote - 35 ][ 0 ] + 0x80),
  319. gbPercMap[ bNote - 35 ][ 1 ], bChannel ) ;
  320. }
  321. else
  322. Opl3_NoteOff( (BYTE) gbPatch[bChannel], bNote, bChannel ) ;
  323. break;
  324. case TYPE_ADLIB:
  325. Adlib_NoteOff (
  326. (BYTE) ((bChannel == DRUMCHANNEL) ?
  327. (BYTE) (bNote + 128) : (BYTE) gbPatch[bChannel]),
  328. bNote, bChannel);
  329. break;
  330. }
  331. break;
  332. case 0xb0:
  333. // D1("\nChangeControl");
  334. /* change control */
  335. switch (bNote) {
  336. case 7:
  337. /* change channel volume */
  338. MidiChannelVolume(
  339. bChannel,
  340. gbVelocityAtten[(bVelocity & 0x7f) >> 2]);
  341. break;
  342. case 8:
  343. case 10:
  344. /* change the pan level */
  345. MidiSetPan(bChannel, bVelocity);
  346. break;
  347. };
  348. break;
  349. case 0xc0:
  350. if (bChannel != DRUMCHANNEL)
  351. {
  352. int i ;
  353. // Turn off all active notes for this channel...
  354. if (gMidiType == TYPE_OPL3) {
  355. Opl3_ChannelNotesOff(bChannel);
  356. }
  357. gbPatch[ bChannel ] = bNote ;
  358. }
  359. break;
  360. case 0xe0:
  361. // D1("\nBend");
  362. /* pitch bend */
  363. wTemp = ((WORD) bVelocity << 9) | ((WORD) bNote << 2);
  364. giBend[bChannel] = (short) (WORD) (wTemp + 0x7FFF);
  365. MidiPitchBend (bChannel, giBend[bChannel]);
  366. break;
  367. };
  368. return;
  369. }
  370. /****************************************************************************
  371. * @doc INTERNAL
  372. *
  373. * @api void | midiSynthCallback | This calls DriverCallback for a midi device.
  374. *
  375. * @parm NPPORTALLOC| pPort | Pointer to the PORTALLOC.
  376. *
  377. * @parm WORD | msg | The message to send.
  378. *
  379. * @parm DWORD | dw1 | Message-dependent parameter.
  380. *
  381. * @parm DWORD | dw2 | Message-dependent parameter.
  382. *
  383. * @rdesc There is no return value.
  384. ***************************************************************************/
  385. void NEAR PASCAL midiSynthCallback(NPPORTALLOC pPort, WORD msg, DWORD_PTR dw1, DWORD_PTR dw2)
  386. {
  387. // invoke the callback function, if it exists. dwFlags contains driver-
  388. // specific flags in the LOWORD and generic driver flags in the HIWORD
  389. if (pPort->dwCallback)
  390. DriverCallback(pPort->dwCallback, // client's callback DWORD
  391. HIWORD(pPort->dwFlags) | DCB_NOSWITCH, // callback flags
  392. (HDRVR)pPort->hMidi, // handle to the wave device
  393. msg, // the message
  394. pPort->dwInstance, // client's instance data
  395. dw1, // first DWORD
  396. dw2); // second DWORD
  397. }
  398. /****************************************************************************
  399. * @doc INTERNAL
  400. *
  401. * @api void | midBufferWrite | This function writes a byte into the long
  402. * message buffer. If the buffer is full or a SYSEX_ERROR or
  403. * end-of-sysex byte is received, the buffer is marked as 'done' and
  404. * it's owner is called back.
  405. *
  406. * @parm BYTE | byte | The byte received.
  407. *
  408. * @rdesc There is no return value
  409. ***************************************************************************/
  410. static void NEAR PASCAL midBufferWrite(BYTE byte)
  411. {
  412. LPMIDIHDR lpmh;
  413. WORD msg;
  414. // if no buffers, nothing happens
  415. if (lpMIQueue == NULL)
  416. return;
  417. lpmh = lpMIQueue;
  418. if (byte == SYSEX_ERROR) {
  419. D2(("sysexerror"));
  420. msg = MIM_LONGERROR;
  421. }
  422. else {
  423. D2(("bufferwrite"));
  424. msg = MIM_LONGDATA;
  425. *((HPSTR)(lpmh->lpData) + dwCurData++) = byte;
  426. }
  427. // if end of sysex, buffer full or error, send them back the buffer
  428. if ((byte == SYSEX_ERROR) || (byte == 0xF7) || (dwCurData >= lpmh->dwBufferLength)) {
  429. D2(("bufferdone"));
  430. lpMIQueue = lpMIQueue->lpNext;
  431. lpmh->dwBytesRecorded = dwCurData;
  432. dwCurData = 0L;
  433. lpmh->dwFlags |= MHDR_DONE;
  434. lpmh->dwFlags &= ~MHDR_INQUEUE;
  435. midiSynthCallback(&gMidiInClient, msg, (DWORD_PTR)lpmh, dwMsgTime);
  436. }
  437. return;
  438. }
  439. /****************************************************************************
  440. This function conforms to the standard MIDI output driver message proc
  441. modMessage, which is documented in mmddk.d.
  442. ***************************************************************************/
  443. DWORD APIENTRY modSynthMessage(UINT id,
  444. UINT msg, DWORD_PTR dwUser, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
  445. {
  446. LPMIDIHDR lpHdr;
  447. LPSTR lpBuf; /* current spot in the long msg buf */
  448. DWORD dwBytesRead; /* how far are we in the buffer */
  449. DWORD dwMsg = 0; /* short midi message sent to synth */
  450. BYTE bBytePos=0; /* shift current byte by dwBytePos*s */
  451. BYTE bBytesLeft = 0; /* how many dat bytes needed */
  452. BYTE curByte; /* current byte in long buffer */
  453. UINT mRc; /* Return code */
  454. // this driver only supports one device
  455. if (id != 0) {
  456. D1(("invalid midi device id"));
  457. return MMSYSERR_BADDEVICEID;
  458. }
  459. switch (msg) {
  460. case MODM_GETNUMDEVS:
  461. D1(("MODM_GETNUMDEVS"));
  462. //
  463. // Check if the kernel driver got loaded OK
  464. //
  465. mRc = sndGetNumDevs(SYNTH_DEVICE);
  466. break;
  467. case MODM_GETDEVCAPS:
  468. D1(("MODM_GETDEVCAPS"));
  469. mRc = midiGetDevCaps(0, SYNTH_DEVICE, (LPBYTE)dwParam1, (WORD)dwParam2);
  470. break;
  471. case MODM_OPEN:
  472. D1(("MODM_OPEN"));
  473. /* open the midi */
  474. if (MidiOpen())
  475. return MMSYSERR_ALLOCATED;
  476. // save client information
  477. gMidiOutClient.dwCallback = ((LPMIDIOPENDESC)dwParam1)->dwCallback;
  478. gMidiOutClient.dwInstance = ((LPMIDIOPENDESC)dwParam1)->dwInstance;
  479. gMidiOutClient.hMidi = (HMIDIOUT)((LPMIDIOPENDESC)dwParam1)->hMidi;
  480. gMidiOutClient.dwFlags = (DWORD)dwParam2;
  481. // notify client
  482. midiSynthCallback(&gMidiOutClient, MOM_OPEN, 0L, 0L);
  483. /* were in use */
  484. gbMidiInUse = TRUE;
  485. mRc = 0L;
  486. break;
  487. case MODM_CLOSE:
  488. D1(("MODM_CLOSE"));
  489. /* shut up the FM synthesizer */
  490. MidiClose();
  491. // notify client
  492. midiSynthCallback(&gMidiOutClient, MOM_CLOSE, 0L, 0L);
  493. /* were not used any more */
  494. gbMidiInUse = FALSE;
  495. mRc = 0L;
  496. break;
  497. case MODM_RESET:
  498. D1(("MODM_RESET"));
  499. //
  500. // turn off FM synthesis
  501. //
  502. // note that we increment our 're-entered' counter so that a
  503. // background interrupt handler doesn't mess up our resetting
  504. // of the synth by calling midiOut[Short|Long]Msg.. just
  505. // practicing safe midi. NOTE: this should never be necessary
  506. // if a midi app is PROPERLY written!
  507. //
  508. wMidiOutEntered++;
  509. {
  510. if (wMidiOutEntered == 1)
  511. {
  512. MidiReset();
  513. dwParam1 = 0L;
  514. }
  515. else
  516. {
  517. D1(("MODM_RESET reentered!"));
  518. dwParam1 = MIDIERR_NOTREADY;
  519. }
  520. }
  521. wMidiOutEntered--;
  522. mRc = (DWORD)dwParam1;
  523. break;
  524. case MODM_DATA: // message is in dwParam1
  525. MidiCheckVolume(); // See if the volume has changed
  526. // make sure we're not being reentered
  527. wMidiOutEntered++;
  528. if (wMidiOutEntered > 1) {
  529. D1(("MODM_DATA reentered!"));
  530. wMidiOutEntered--;
  531. return MIDIERR_NOTREADY;
  532. }
  533. /* if have repeated messages */
  534. if (dwParam1 & 0x00000080) /* status byte */
  535. status = LOBYTE(LOWORD(dwParam1));
  536. else
  537. dwParam1 = (dwParam1 << 8) | ((DWORD) status);
  538. /* if not, have an FM synthesis message */
  539. MidiMessage ((DWORD)dwParam1);
  540. wMidiOutEntered--;
  541. mRc = 0L;
  542. break;
  543. case MODM_LONGDATA: // far pointer to header in dwParam1
  544. MidiCheckVolume(); // See if the volume has changed
  545. // make sure we're not being reentered
  546. wMidiOutEntered++;
  547. if (wMidiOutEntered > 1) {
  548. D1(("MODM_LONGDATA reentered!"));
  549. wMidiOutEntered--;
  550. return MIDIERR_NOTREADY;
  551. }
  552. // check if it's been prepared
  553. lpHdr = (LPMIDIHDR)dwParam1;
  554. if (!(lpHdr->dwFlags & MHDR_PREPARED)) {
  555. wMidiOutEntered--;
  556. return MIDIERR_UNPREPARED;
  557. }
  558. lpBuf = lpHdr->lpData;
  559. dwBytesRead = 0;
  560. curByte = *lpBuf;
  561. while (TRUE) {
  562. /* if its a system realtime message send it and continue
  563. this does not affect the running status */
  564. if (curByte >= 0xf8)
  565. MidiMessage (0x000000ff & curByte);
  566. else if (curByte >= 0xf0) {
  567. status = 0; /* kill running status */
  568. dwMsg = 0L; /* throw away any incomplete data */
  569. bBytePos = 0; /* start at beginning of message */
  570. switch (curByte) {
  571. case 0xf0: /* sysex - ignore */
  572. case 0xf7:
  573. break;
  574. case 0xf4: /* system common, no data */
  575. case 0xf5:
  576. case 0xf6:
  577. MidiMessage (0x000000ff & curByte);
  578. break;
  579. case 0xf1: /* system common, one data byte */
  580. case 0xf3:
  581. dwMsg |= curByte;
  582. bBytesLeft = 1;
  583. bBytePos = 1;
  584. break;
  585. case 0xf2: /* system common, 2 data bytes */
  586. dwMsg |= curByte;
  587. bBytesLeft = 2;
  588. bBytePos = 1;
  589. break;
  590. };
  591. }
  592. /* else its a channel message */
  593. else if (curByte >= 0x80) {
  594. status = curByte;
  595. dwMsg = 0L;
  596. switch (curByte & 0xf0) {
  597. case 0xc0: /* channel message, one data */
  598. case 0xd0:
  599. dwMsg |= curByte;
  600. bBytesLeft = 1;
  601. bBytePos = 1;
  602. break;
  603. case 0x80: /* two bytes */
  604. case 0x90:
  605. case 0xa0:
  606. case 0xb0:
  607. case 0xe0:
  608. dwMsg |= curByte;
  609. bBytesLeft = 2;
  610. bBytePos = 1;
  611. break;
  612. };
  613. }
  614. /* else if its an expected data byte */
  615. else if (bBytePos != 0) {
  616. dwMsg |= ((DWORD)curByte) << (bBytePos++ * 8);
  617. if (--bBytesLeft == 0) {
  618. MidiMessage (dwMsg);
  619. if (status) {
  620. dwMsg = status;
  621. bBytesLeft = bBytePos - (BYTE)1;
  622. bBytePos = 1;
  623. }
  624. else {
  625. dwMsg = 0L;
  626. bBytePos = 0;
  627. };
  628. };
  629. };
  630. /* read the next byte if there is one */
  631. /* remember we have already read and processed one byte that
  632. * we have not yet counted- so we need to pre-inc, not post-inc
  633. */
  634. if (++dwBytesRead >= lpHdr->dwBufferLength) break;
  635. curByte = *++lpBuf;
  636. }; /* while TRUE */
  637. /* return buffer to client */
  638. lpHdr->dwFlags |= MHDR_DONE;
  639. midiSynthCallback (&gMidiOutClient, MOM_DONE, dwParam1, 0L);
  640. wMidiOutEntered--;
  641. mRc = 0L;
  642. break;
  643. case MODM_SETVOLUME:
  644. mRc = MidiSetVolume(LOWORD(dwParam1) << 16, HIWORD(dwParam1) << 16);
  645. break;
  646. case MODM_GETVOLUME:
  647. mRc = MidiGetVolume((LPDWORD)dwParam1);
  648. break;
  649. default:
  650. return MMSYSERR_NOTSUPPORTED;
  651. }
  652. MidiFlush();
  653. return mRc;
  654. // should never get here...
  655. return MMSYSERR_NOTSUPPORTED;
  656. }
  657. /****************************************************************
  658. MidiInit - Initializes the FM synthesis chip and internal
  659. variables. This assumes that HwInit() has been called
  660. and that a card location has been found. This loads in
  661. the patch information.
  662. inputs
  663. none
  664. returns
  665. WORD - 0 if successful, else error
  666. */
  667. WORD FAR PASCAL MidiInit (VOID)
  668. {
  669. // WORD i;
  670. D1 (("\nMidiInit"));
  671. // don't reset the patch map - it will be initialised at loadtime to 0
  672. // (because its static data) and we should not change it after that
  673. // since the mci sequencer will not re-send patch change messages.
  674. //
  675. //
  676. // /* reset all channels to patch 0 */
  677. // for (i = 0; i < NUMCHANNELS; i++) {
  678. // gbPatch[i] = 0;
  679. // }
  680. /* initialise the h/w specific patch tables */
  681. return MidiBoardInit();
  682. }
  683. /*****************************************************************
  684. MidiOpen - This should be called when a midi file is opened.
  685. It initializes some variables and locks the patch global
  686. memories.
  687. inputs
  688. none
  689. returns
  690. UINT - 0 if succedes, else error
  691. */
  692. UINT FAR PASCAL MidiOpen (VOID)
  693. {
  694. MMRESULT mRc;
  695. D1(("MidiOpen"));
  696. //
  697. // For 32-bit we must open our kernel device
  698. //
  699. mRc = MidiOpenDevice(&MidiDeviceHandle, TRUE);
  700. if (mRc != MMSYSERR_NOERROR) {
  701. return mRc;
  702. }
  703. /*
  704. * reset the device (set default channel attenuation etc)
  705. */
  706. MidiBoardReset();
  707. return 0;
  708. }
  709. /***************************************************************
  710. MidiClose - This kills the playing midi voices and closes the kernel driver
  711. inputs
  712. none
  713. returns
  714. none
  715. */
  716. VOID FAR PASCAL MidiClose (VOID)
  717. {
  718. D1(("MidiClose"));
  719. if (MidiDeviceHandle == NULL) {
  720. return;
  721. }
  722. /* make sure all notes turned off */
  723. MidiAllNotesOff();
  724. MidiCloseDevice(MidiDeviceHandle);
  725. MidiDeviceHandle = NULL;
  726. }
  727. /** void FAR PASCAL MidiReset(void)
  728. *
  729. * DESCRIPTION:
  730. *
  731. *
  732. * ARGUMENTS:
  733. * (void)
  734. *
  735. * RETURN (void FAR PASCAL):
  736. *
  737. *
  738. * NOTES:
  739. *
  740. ** cjp */
  741. void FAR PASCAL MidiReset(void)
  742. {
  743. D1(("MidiReset"));
  744. /* make sure all notes turned off */
  745. MidiAllNotesOff();
  746. /* silence the board and reset board-specific variables */
  747. MidiBoardReset();
  748. } /* MidiReset() */
  749.