Windows NT 4.0 source code leak
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.

1009 lines
23 KiB

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