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.

1157 lines
31 KiB

  1. /*
  2. * Copyright (c) 1992-1994 Microsoft Corporation
  3. */
  4. /*
  5. * Interface functions for the OPL3 midi device type.
  6. *
  7. * These functions are called from midi.c when the kernel driver
  8. * has decreed that this is an opl3-compatible device.
  9. *
  10. * Geraint Davies, Dec 92
  11. */
  12. #include <windows.h>
  13. #include <mmsystem.h>
  14. #include <mmddk.h>
  15. #include "driver.h"
  16. #include "opl3.h"
  17. #pragma pack(1)
  18. /* --- typedefs ----------------------------------------------- */
  19. /* typedefs for MIDI patches */
  20. #define NUMOPS (4)
  21. #define PATCH_1_4OP (0) /* use 4-operator patch */
  22. #define PATCH_2_2OP (1) /* use two 2-operator patches */
  23. #define PATCH_1_2OP (2) /* use one 2-operator patch */
  24. #define RIFF_PATCH (mmioFOURCC('P','t','c','h'))
  25. #define RIFF_FM4 (mmioFOURCC('f','m','4',' '))
  26. #define NUM2VOICES (18) /* # 2operator voices */
  27. typedef struct _operStruct {
  28. BYTE bAt20; /* flags which are send to 0x20 on fm */
  29. BYTE bAt40; /* flags seet to 0x40 */
  30. /* the note velocity & midi velocity affect total level */
  31. BYTE bAt60; /* flags sent to 0x60 */
  32. BYTE bAt80; /* flags sent to 0x80 */
  33. BYTE bAtE0; /* flags send to 0xe0 */
  34. } operStruct;
  35. typedef struct _noteStruct {
  36. operStruct op[NUMOPS]; /* operators */
  37. BYTE bAtA0[2]; /* send to 0xA0, A3 */
  38. BYTE bAtB0[2]; /* send to 0xB0, B3 */
  39. /* use in a patch, the block should be 4 to indicate
  40. normal pitch, 3 => octave below, etc. */
  41. BYTE bAtC0[2]; /* sent to 0xc0, C3 */
  42. BYTE bOp; /* see PATCH_??? */
  43. BYTE bDummy; /* place holder */
  44. } noteStruct;
  45. typedef struct _patchStruct {
  46. noteStruct note; /* note. This is all in the structure at the moment */
  47. } patchStruct;
  48. #pragma pack()
  49. /* MIDI */
  50. typedef struct _voiceStruct {
  51. BYTE bNote; /* note played */
  52. BYTE bChannel; /* channel played on */
  53. BYTE bPatch; /* what patch is the note,
  54. drums patch = drum note + 128 */
  55. BYTE bOn; /* TRUE if note is on, FALSE if off */
  56. BYTE bVelocity; /* velocity */
  57. BYTE bJunk; /* filler */
  58. DWORD dwTime; /* time that was turned on/off;
  59. 0 time indicates that its not in use */
  60. DWORD dwOrigPitch[2]; /* original pitch, for pitch bend */
  61. BYTE bBlock[2]; /* value sent to the block */
  62. } voiceStruct;
  63. /* --- module data -------------------------------------------- */
  64. /* a bit of tuning information */
  65. #define FSAMP (50000.0) /* sampling frequency */
  66. #define PITCH(x) ((DWORD)((x) * (double) (1L << 19) / FSAMP))
  67. /* x is the desired frequency,
  68. == FNUM at b=1 */
  69. #define EQUAL (1.059463094359)
  70. #ifdef EUROPE
  71. # define A (442.0)
  72. #else
  73. # define A (440.0)
  74. #endif
  75. #define ASHARP (A * EQUAL)
  76. #define B (ASHARP * EQUAL)
  77. #define C (B * EQUAL / 2.0)
  78. #define CSHARP (C * EQUAL)
  79. #define D (CSHARP * EQUAL)
  80. #define DSHARP (D * EQUAL)
  81. #define E (DSHARP * EQUAL)
  82. #define F (E * EQUAL)
  83. #define FSHARP (F * EQUAL)
  84. #define G (FSHARP * EQUAL)
  85. #define GSHARP (G * EQUAL)
  86. /* volume */
  87. WORD wSynthAttenL = 0; /* in 1.5dB steps */
  88. WORD wSynthAttenR = 0; /* in 1.5dB steps */
  89. /* patch library */
  90. patchStruct FAR * glpPatch = NULL; /* points to the patches */
  91. /* voices being played */
  92. voiceStruct gVoice[NUM2VOICES]; /* info on what voice is where */
  93. static DWORD gdwCurTime = 1; /* for note on/off */
  94. BYTE gbCur4opReg = 0; /* current value to 4-operator connection */
  95. /* channel volumes */
  96. BYTE gbChanAtten[NUMCHANNELS]; /* attenuation of each channel, in .75 db steps */
  97. BYTE gbStereoMask[NUMCHANNELS]; /* mask for left/right for stereo midi files */
  98. extern short giBend[ NUMCHANNELS ] ; // bend for each channel
  99. /* operator offset location */
  100. static WORD BCODE gw2OpOffset[ NUM2VOICES ][ 2 ] =
  101. {
  102. { 0x000,0x003 },
  103. { 0x001,0x004 },
  104. { 0x002,0x005 },
  105. { 0x008,0x00b },
  106. { 0x009,0x00c },
  107. { 0x00a,0x00d },
  108. { 0x010,0x013 },
  109. { 0x011,0x014 },
  110. { 0x012,0x015 },
  111. { 0x100,0x103 },
  112. { 0x101,0x104 },
  113. { 0x102,0x105 },
  114. { 0x108,0x10b },
  115. { 0x109,0x10c },
  116. { 0x10a,0x10d },
  117. { 0x110,0x113 },
  118. { 0x111,0x114 },
  119. { 0x112,0x115 },
  120. } ;
  121. /* pitch values, from middle c, to octave above it */
  122. static DWORD BCODE gdwPitch[12] = {
  123. PITCH(C), PITCH(CSHARP), PITCH(D), PITCH(DSHARP),
  124. PITCH(E), PITCH(F), PITCH(FSHARP), PITCH(G),
  125. PITCH(GSHARP), PITCH(A), PITCH(ASHARP), PITCH(B)};
  126. /* --- internal functions -------------------------------------- */
  127. //------------------------------------------------------------------------
  128. // VOID MidiFMNote
  129. //
  130. // Description:
  131. // Turns on an FM-synthesizer note.
  132. //
  133. // Parameters:
  134. // WORD wNote
  135. // the note number from 0 to NUMVOICES
  136. //
  137. // noteStruct FAR *lpSN
  138. // structure containing information about what
  139. // is to be played.
  140. //
  141. // Return Value:
  142. // Nothing.
  143. //
  144. //
  145. //------------------------------------------------------------------------
  146. VOID NEAR PASCAL Opl3_FMNote
  147. (
  148. WORD wNote,
  149. noteStruct FAR * lpSN
  150. )
  151. {
  152. WORD i ;
  153. WORD wOffset ;
  154. operStruct FAR *lpOS ;
  155. // D1( "\nMidiFMNote" ) ;
  156. // write out a note off, just to make sure...
  157. wOffset =
  158. (wNote < (NUM2VOICES / 2)) ? wNote : (wNote + 0x100 - 9) ;
  159. MidiSendFM( AD_BLOCK + wOffset, 0 ) ;
  160. // writing the operator information
  161. // for (i = 0; i < (WORD)((wNote < NUM4VOICES) ? NUMOPS : 2); i++)
  162. for (i = 0; i < 2; i++)
  163. {
  164. lpOS = &lpSN -> op[ i ] ;
  165. wOffset = gw2OpOffset[ wNote ][ i ] ;
  166. MidiSendFM( 0x20 + wOffset, lpOS -> bAt20) ;
  167. MidiSendFM( 0x40 + wOffset, lpOS -> bAt40) ;
  168. MidiSendFM( 0x60 + wOffset, lpOS -> bAt60) ;
  169. MidiSendFM( 0x80 + wOffset, lpOS -> bAt80) ;
  170. MidiSendFM( 0xE0 + wOffset, lpOS -> bAtE0) ;
  171. #ifdef DEBUG
  172. {
  173. char szDebug[ 80 ] ;
  174. wsprintf( szDebug, "20=%02x 40=%02x 60=%02x 80=%02x E0=%02x",
  175. lpOS -> bAt20, lpOS -> bAt40, lpOS -> bAt60,
  176. lpOS -> bAt80, lpOS -> bAtE0 ) ;
  177. D1( szDebug ) ;
  178. }
  179. #endif
  180. }
  181. // write out the voice information
  182. wOffset = (wNote < 9) ? wNote : (wNote + 0x100 - 9) ;
  183. MidiSendFM( 0xa0 + wOffset, lpSN -> bAtA0[ 0 ] ) ;
  184. MidiSendFM( 0xc0 + wOffset, lpSN -> bAtC0[ 0 ] ) ;
  185. // Note on...
  186. MidiSendFM( 0xb0 + wOffset,
  187. (BYTE)(lpSN -> bAtB0[ 0 ] | 0x20) ) ;
  188. #ifdef NOT_USED
  189. {
  190. char szDebug[ 80 ] ;
  191. wsprintf( szDebug, "A0=%02x B0=%02x C0=%02x", lpSN -> bAtA0[ 0 ],
  192. lpSN -> bAtB0[ 0 ], lpSN -> bAtC0[ 0 ] ) ;
  193. D1( szDebug ) ;
  194. }
  195. #endif
  196. } // end of MidiFMNote()
  197. //------------------------------------------------------------------------
  198. // WORD MidiFindEmptySlot
  199. //
  200. // Description:
  201. // This finds an empty note-slot for a MIDI voice.
  202. // If there are no empty slots then this looks for the oldest
  203. // off note. If this doesn't work then it looks for the oldest
  204. // on-note of the same patch. If all notes are still on then
  205. // this finds the oldests turned-on-note.
  206. //
  207. // Parameters:
  208. // BYTE bPatch
  209. // MIDI patch that will replace it.
  210. //
  211. // Return Value:
  212. // WORD
  213. // note slot #
  214. //
  215. //
  216. //------------------------------------------------------------------------
  217. WORD NEAR PASCAL Opl3_FindEmptySlot
  218. (
  219. BYTE bPatch
  220. )
  221. {
  222. WORD i, found ;
  223. DWORD dwOldest ;
  224. // D1( "\nMidiFindEmptySlot" ) ;
  225. // First, look for a slot with a time == 0
  226. for (i = 0; i < NUM2VOICES; i++)
  227. if (!gVoice[ i ].dwTime)
  228. return ( i ) ;
  229. // Now, look for a slot of the oldest off-note
  230. dwOldest = 0xffffffff ;
  231. found = 0xffff ;
  232. for (i = 0; i < NUM2VOICES; i++)
  233. if (!gVoice[ i ].bOn && (gVoice[ i ].dwTime < dwOldest))
  234. {
  235. dwOldest = gVoice[ i ].dwTime ;
  236. found = i ;
  237. }
  238. if (found != 0xffff)
  239. return ( found ) ;
  240. // Now, look for a slot of the oldest note with
  241. // the same patch
  242. dwOldest = 0xffffffff ;
  243. found = 0xffff ;
  244. for (i = 0; i < NUM2VOICES; i++)
  245. if ((gVoice[ i ].bPatch == bPatch) && (gVoice[ i ].dwTime < dwOldest))
  246. {
  247. dwOldest = gVoice[ i ].dwTime ;
  248. found = i ;
  249. }
  250. if (found != 0xffff)
  251. return ( found ) ;
  252. // Now, just look for the oldest voice
  253. found = 0 ;
  254. dwOldest = gVoice[ found ].dwTime ;
  255. for (i = (found + 1); i < NUM2VOICES; i++)
  256. if (gVoice[ i ].dwTime < dwOldest)
  257. {
  258. dwOldest = gVoice[ i ].dwTime ;
  259. found = i ;
  260. }
  261. return ( found ) ;
  262. } // end of MidiFindEmptySlot()
  263. //------------------------------------------------------------------------
  264. // WORD MidiFindFullSlot
  265. //
  266. // Description:
  267. // This finds a slot with a specific note, and channel.
  268. // If it is not found then 0xFFFF is returned.
  269. //
  270. // Parameters:
  271. // BYTE bNote
  272. // MIDI note number
  273. //
  274. // BYTE bChannel
  275. // MIDI channel #
  276. //
  277. // Return Value:
  278. // WORD
  279. // note slot #, or 0xFFFF if can't find it
  280. //
  281. //
  282. //------------------------------------------------------------------------
  283. WORD NEAR PASCAL Opl3_FindFullSlot
  284. (
  285. BYTE bNote,
  286. BYTE bChannel
  287. )
  288. {
  289. WORD i ;
  290. // D1( "\nMidiFindFullSlot" ) ;
  291. for (i = 0; i < NUM2VOICES; i++)
  292. if ((bChannel == gVoice[ i ].bChannel) &&
  293. (bNote == gVoice[ i ].bNote) && (gVoice[ i ].bOn))
  294. return ( i ) ;
  295. // couldn't find it
  296. return ( 0xFFFF ) ;
  297. } // end of MidiFindFullSlot()
  298. /**************************************************************
  299. Opl3_CalcBend - This calculates the effects of pitch bend
  300. on an original value.
  301. inputs
  302. DWORD dwOrig - original frequency
  303. short iBend - from -32768 to 32768, -2 half steps to +2
  304. returns
  305. DWORD - new frequency
  306. */
  307. DWORD NEAR PASCAL Opl3_CalcBend (DWORD dwOrig, short iBend)
  308. {
  309. DWORD dw;
  310. // D1 (("Opl3_CalcBend"));
  311. /* do different things depending upon positive or
  312. negative bend */
  313. if (iBend > 0)
  314. {
  315. dw = (DWORD)((iBend * (LONG)(256.0 * (EQUAL * EQUAL - 1.0))) >> 8);
  316. dwOrig += (DWORD)(AsULMUL(dw, dwOrig) >> 15);
  317. }
  318. else if (iBend < 0)
  319. {
  320. dw = (DWORD)(((-iBend) * (LONG)(256.0 * (1.0 - 1.0 / EQUAL / EQUAL))) >> 8);
  321. dwOrig -= (DWORD)(AsULMUL(dw, dwOrig) >> 15);
  322. }
  323. return dwOrig;
  324. }
  325. /*****************************************************************
  326. Opl3_CalcFAndB - Calculates the FNumber and Block given
  327. a frequency.
  328. inputs
  329. DWORD dwPitch - pitch
  330. returns
  331. WORD - High byte contains the 0xb0 section of the
  332. block and fNum, and the low byte contains the
  333. 0xa0 section of the fNumber
  334. */
  335. WORD NEAR PASCAL Opl3_CalcFAndB (DWORD dwPitch)
  336. {
  337. BYTE bBlock;
  338. // D1(("Opl3_CalcFAndB"));
  339. /* bBlock is like an exponential to dwPitch (or FNumber) */
  340. for (bBlock = 1; dwPitch >= 0x400; dwPitch >>= 1, bBlock++)
  341. ;
  342. if (bBlock > 0x07)
  343. bBlock = 0x07; /* we cant do anything about this */
  344. /* put in high two bits of F-num into bBlock */
  345. return ((WORD) bBlock << 10) | (WORD) dwPitch;
  346. }
  347. /**************************************************************
  348. Opl3_CalcVolume - This calculates the attenuation for an operator.
  349. inputs
  350. BYTE bOrigAtten - original attenuation in 0.75 dB units
  351. BYTE bChannel - MIDI channel
  352. BYTE bVelocity - velocity of the note
  353. BYTE bOper - operator number (from 0 to 3)
  354. BYTE bMode - voice mode (from 0 through 7 for
  355. modulator/carrier selection)
  356. returns
  357. BYTE - new attenuation in 0.75 dB units, maxing out at 0x3f.
  358. */
  359. BYTE NEAR PASCAL Opl3_CalcVolume (BYTE bOrigAtten, BYTE bChannel,
  360. BYTE bVelocity, BYTE bOper, BYTE bMode)
  361. {
  362. BYTE bVolume;
  363. WORD wTemp;
  364. WORD wMin;
  365. switch (bMode) {
  366. case 0:
  367. bVolume = (BYTE)(bOper == 3);
  368. break;
  369. case 1:
  370. bVolume = (BYTE)((bOper == 1) || (bOper == 3));
  371. break;
  372. case 2:
  373. bVolume = (BYTE)((bOper == 0) || (bOper == 3));
  374. break;
  375. case 3:
  376. bVolume = (BYTE)(bOper != 1);
  377. break;
  378. case 4:
  379. bVolume = (BYTE)((bOper == 1) || (bOper == 3));
  380. break;
  381. case 5:
  382. bVolume = (BYTE)(bOper >= 1);
  383. break;
  384. case 6:
  385. bVolume = (BYTE)(bOper <= 2);
  386. break;
  387. case 7:
  388. bVolume = TRUE;
  389. break;
  390. };
  391. if (!bVolume)
  392. return bOrigAtten; /* this is a modulator wave */
  393. wMin =(wSynthAttenL < wSynthAttenR) ? wSynthAttenL : wSynthAttenR;
  394. wTemp = bOrigAtten + ((wMin << 1) +
  395. gbChanAtten[bChannel] + gbVelocityAtten[bVelocity >> 2]);
  396. return (wTemp > 0x3f) ? (BYTE) 0x3f : (BYTE) wTemp;
  397. }
  398. /**************************************************************
  399. Opl3_CalcStereoMask - This calculates the stereo mask.
  400. inputs
  401. BYTE bChannel - MIDI channel
  402. returns
  403. BYTE - mask (for register 0xc0-c8) for eliminating the
  404. left/right/both channels
  405. */
  406. BYTE NEAR PASCAL Opl3_CalcStereoMask (BYTE bChannel)
  407. {
  408. WORD wLeft, wRight;
  409. /* figure out the basic levels of the 2 channels */
  410. wLeft = (wSynthAttenL << 1) + gbChanAtten[bChannel];
  411. wRight = (wSynthAttenR << 1) + gbChanAtten[bChannel];
  412. /* if both are too quiet then mask to nothing */
  413. if ((wLeft > 0x3f) && (wRight > 0x3f))
  414. return 0xcf;
  415. /* if one channel is significantly quieter than the other than
  416. eliminate it */
  417. if ((wLeft + 8) < wRight)
  418. return (BYTE)(0xef & gbStereoMask[bChannel]); /* right is too quiet so eliminate */
  419. else if ((wRight + 8) < wLeft)
  420. return (BYTE)(0xdf & gbStereoMask[bChannel]); /* left too quiet so eliminate */
  421. else
  422. return (BYTE)(gbStereoMask[bChannel]); /* use both channels */
  423. }
  424. //------------------------------------------------------------------------
  425. // VOID MidiNewVolume
  426. //
  427. // Description:
  428. // This should be called if a volume level has changed.
  429. // This will adjust the levels of all the playing voices.
  430. //
  431. // Parameters:
  432. // BYTE bChannel
  433. // channel # of 0xFF for all channels
  434. //
  435. // Return Value:
  436. // Nothing.
  437. //
  438. //
  439. //------------------------------------------------------------------------
  440. VOID FAR PASCAL Opl3_setvolume
  441. (
  442. BYTE bChannel
  443. )
  444. {
  445. WORD i, j, wTemp, wOffset ;
  446. noteStruct FAR *lpPS ;
  447. BYTE bMode, bStereo ;
  448. // Make sure that we are actually open...
  449. if (!glpPatch)
  450. return ;
  451. // Loop through all the notes looking for the right
  452. // channel. Anything with the right channel gets
  453. // its pitch bent.
  454. for (i = 0; i < NUM2VOICES; i++)
  455. if ((gVoice[ i ].bChannel == bChannel) || (bChannel == 0xff))
  456. {
  457. // Get a pointer to the patch
  458. lpPS = &(glpPatch + gVoice[ i ].bPatch) -> note ;
  459. // Modify level for each operator, but only if they
  460. // are carrier waves...
  461. bMode = (BYTE) ( (lpPS->bAtC0[0] & 0x01) * 2 + 4);
  462. for (j = 0; j < 2; j++)
  463. {
  464. wTemp =
  465. (BYTE) Opl3_CalcVolume( (BYTE)(lpPS -> op[ j ].bAt40 & (BYTE) 0x3f),
  466. gVoice[ i ].bChannel,
  467. gVoice[i].bVelocity, (BYTE) j, bMode ) ;
  468. // Write the new value out.
  469. wOffset = gw2OpOffset[ i ][ j ] ;
  470. MidiSendFM( 0x40 + wOffset,
  471. (BYTE) ((lpPS -> op[ j ].bAt40 & (BYTE)0xc0) |
  472. (BYTE) wTemp) ) ;
  473. }
  474. // Do stereo panning, but cutting off a left or right
  475. // channel if necessary.
  476. bStereo = Opl3_CalcStereoMask( gVoice[ i ].bChannel ) ;
  477. wOffset = (i < (NUM2VOICES / 2)) ? i : (i + 0x100 - 9) ;
  478. MidiSendFM( 0xc0 + wOffset, (BYTE)(lpPS -> bAtC0[ 0 ] & bStereo) ) ;
  479. }
  480. } // end of MidiNewVolume()
  481. //------------------------------------------------------------------------
  482. // WORD MidiNoteOn
  483. //
  484. // Description:
  485. // This turns on a note, including drums with a patch # of the
  486. // drum note + 0x80.
  487. //
  488. // Parameters:
  489. // BYTE bPatch
  490. // MIDI patch
  491. //
  492. // BYTE bNote
  493. // MIDI note
  494. //
  495. // BYTE bChannel
  496. // MIDI channel
  497. //
  498. // BYTE bVelocity
  499. // velocity value
  500. //
  501. // short iBend
  502. // current pitch bend from -32768 to 32767
  503. //
  504. // Return Value:
  505. // WORD
  506. // note slot #, or 0xFFFF if it is inaudible
  507. //
  508. //
  509. //------------------------------------------------------------------------
  510. VOID NEAR PASCAL Opl3_NoteOn
  511. (
  512. BYTE bPatch,
  513. BYTE bNote,
  514. BYTE bChannel,
  515. BYTE bVelocity,
  516. short iBend
  517. )
  518. {
  519. WORD wTemp, i, j ;
  520. BYTE b4Op, bTemp, bMode, bStereo ;
  521. patchStruct FAR *lpPS ;
  522. DWORD dwBasicPitch, dwPitch[ 2 ] ;
  523. noteStruct NS ;
  524. // D1( "\nMidiNoteOn" ) ;
  525. // Get a pointer to the patch
  526. lpPS = glpPatch + bPatch ;
  527. #ifdef DEBUG
  528. {
  529. char szDebug[ 80 ] ;
  530. wsprintf( szDebug, "bPatch = %d, bNote = %d", bPatch, bNote ) ;
  531. D1( szDebug ) ;
  532. }
  533. #endif
  534. // Find out the basic pitch according to our
  535. // note value. This may be adjusted because of
  536. // pitch bends or special qualities for the note.
  537. dwBasicPitch = gdwPitch[ bNote % 12 ] ;
  538. bTemp = bNote / (BYTE) 12 ;
  539. if (bTemp > (BYTE) (60 / 12))
  540. dwBasicPitch = AsLSHL( dwBasicPitch, (BYTE)(bTemp - (BYTE)(60/12)) ) ;
  541. else if (bTemp < (BYTE) (60/12))
  542. dwBasicPitch = AsULSHR( dwBasicPitch, (BYTE)((BYTE) (60/12) - bTemp) ) ;
  543. // Copy the note information over and modify
  544. // the total level and pitch according to
  545. // the velocity, midi volume, and tuning.
  546. AsMemCopy( (LPSTR) &NS, (LPSTR) &lpPS -> note, sizeof( noteStruct ) ) ;
  547. b4Op = (BYTE)(NS.bOp != PATCH_1_2OP) ;
  548. // for (j = 0; j < (WORD)(b4Op ? 2 : 1); j++)
  549. for (j = 0; j < 2; j++)
  550. {
  551. // modify pitch
  552. dwPitch[ j ] = dwBasicPitch ;
  553. bTemp = (BYTE)((NS.bAtB0[ j ] >> 2) & 0x07) ;
  554. if (bTemp > 4)
  555. dwPitch[ j ] = AsLSHL( dwPitch[ j ], (BYTE)(bTemp - (BYTE)4) ) ;
  556. else if (bTemp < 4)
  557. dwPitch[ j ] = AsULSHR( dwPitch[ j ], (BYTE)((BYTE)4 - bTemp) ) ;
  558. wTemp = Opl3_CalcFAndB( Opl3_CalcBend( dwPitch[ j ], iBend ) ) ;
  559. NS.bAtA0[ j ] = (BYTE) wTemp ;
  560. NS.bAtB0[ j ] = (BYTE) 0x20 | (BYTE) (wTemp >> 8) ;
  561. }
  562. // Modify level for each operator, but only
  563. // if they are carrier waves
  564. // if (b4Op)
  565. // {
  566. // bMode = (BYTE)((NS.bAtC0[ 0 ] & 0x01) * 2 | (NS.bAtC0[ 1 ] & 0x01)) ;
  567. // if (NS.bOp == PATCH_2_2OP)
  568. // bMode += 4 ;
  569. // }
  570. // else
  571. bMode = (BYTE) ((NS.bAtC0[ 0 ] & 0x01) * 2 + 4) ;
  572. // for (i = 0; i < (WORD)(b4Op ? NUMOPS : 2); i++)
  573. for (i = 0; i < 2; i++)
  574. {
  575. wTemp =
  576. (BYTE) Opl3_CalcVolume ( (BYTE)(NS.op[ i ].bAt40 & (BYTE) 0x3f),
  577. bChannel, bVelocity, (BYTE) i, bMode ) ;
  578. NS.op[ i ].bAt40 = (NS.op[ i ].bAt40 & (BYTE)0xc0) | (BYTE) wTemp ;
  579. }
  580. // Do stereo panning, but cutting off a left or
  581. // right channel if necessary...
  582. bStereo = Opl3_CalcStereoMask( bChannel ) ;
  583. NS.bAtC0[ 0 ] &= bStereo ;
  584. // if (b4Op)
  585. // NS.bAtC0[ 1 ] &= bStereo ;
  586. // Find an empty slot, and use it...
  587. // wTemp = Opl3_FindEmptySlot( bPatch, b4Op ) ;
  588. wTemp = Opl3_FindEmptySlot( bPatch ) ;
  589. #ifdef DEBUG
  590. {
  591. char szDebug[ 80 ] ;
  592. wsprintf( szDebug, "Found empty slot: %d", wTemp ) ;
  593. D1( szDebug ) ;
  594. }
  595. #endif
  596. Opl3_FMNote( wTemp, &NS ) ;
  597. gVoice[ wTemp ].bNote = bNote ;
  598. gVoice[ wTemp ].bChannel = bChannel ;
  599. gVoice[ wTemp ].bPatch = bPatch ;
  600. gVoice[ wTemp ].bVelocity = bVelocity ;
  601. gVoice[ wTemp ].bOn = TRUE ;
  602. gVoice[ wTemp ].dwTime = gdwCurTime++ ;
  603. gVoice[ wTemp ].dwOrigPitch[0] = dwPitch[ 0 ] ; // not including bend
  604. gVoice[ wTemp ].dwOrigPitch[1] = dwPitch[ 1 ] ; // not including bend
  605. gVoice[ wTemp ].bBlock[0] = NS.bAtB0[ 0 ] ;
  606. gVoice[ wTemp ].bBlock[1] = NS.bAtB0[ 1 ] ;
  607. } // end of Opl3_NoteOn()
  608. //------------------------------------------------------------------------
  609. // VOID Opl3_NoteOff
  610. //
  611. // Description:
  612. // This turns off a note, including drums with a patch
  613. // # of the drum note + 128.
  614. //
  615. // Parameters:
  616. // BYTE bPatch
  617. // MIDI patch
  618. //
  619. // BYTE bNote
  620. // MIDI note
  621. //
  622. // BYTE bChannel
  623. // MIDI channel
  624. //
  625. // Return Value:
  626. // Nothing.
  627. //
  628. //
  629. //------------------------------------------------------------------------
  630. VOID FAR PASCAL Opl3_NoteOff
  631. (
  632. BYTE bPatch,
  633. BYTE bNote,
  634. BYTE bChannel
  635. )
  636. {
  637. patchStruct FAR *lpPS ;
  638. WORD wOffset, wTemp ;
  639. // D1( "\nMidiNoteOff" ) ;
  640. // Find the note slot
  641. wTemp = Opl3_FindFullSlot( bNote, bChannel ) ;
  642. if (wTemp != 0xffff)
  643. {
  644. // get a pointer to the patch
  645. lpPS = glpPatch + (BYTE) gVoice[ wTemp ].bPatch ;
  646. // shut off the note portion
  647. // we have the note slot, turn it off.
  648. // if (wTemp < NUM4VOICES)
  649. // {
  650. // MidiSendFM( AD_BLOCK + gw4VoiceOffset[ wTemp ],
  651. // (BYTE)(gVoice[ wTemp ].bBlock[ 0 ] & 0x1f) ) ;
  652. // MidiSendFM( AD_BLOCK + gw4VoiceOffset[ wTemp ] + 3,
  653. // (BYTE)(gVoice[ wTemp ].bBlock[ 1 ] & 0x1f) ) ;
  654. // }
  655. // else
  656. wOffset = (wTemp < (NUM2VOICES / 2)) ? wTemp : (wTemp + 0x100 - 9) ;
  657. MidiSendFM( AD_BLOCK + wOffset,
  658. (BYTE)(gVoice[ wTemp ].bBlock[ 0 ] & 0x1f) ) ;
  659. // Note this...
  660. gVoice[ wTemp ].bOn = FALSE ;
  661. gVoice[ wTemp ].bBlock[ 0 ] &= 0x1f ;
  662. gVoice[ wTemp ].bBlock[ 1 ] &= 0x1f ;
  663. gVoice[ wTemp ].dwTime = gdwCurTime ;
  664. }
  665. } // end of Opl3_NoteOff()
  666. /*
  667. * Opl3_ChannelNotesOff - turn off all notes on a channel
  668. */
  669. VOID Opl3_ChannelNotesOff(BYTE bChannel)
  670. {
  671. int i;
  672. for (i = 0; i < NUM2VOICES; i++) {
  673. if ((gVoice[ i ].bOn) && (gVoice[ i ].bChannel == bChannel)) {
  674. Opl3_NoteOff( gVoice[i].bPatch, gVoice[i].bNote,
  675. gVoice[i].bChannel ) ;
  676. }
  677. }
  678. }
  679. /*
  680. * Opl3_AllNotesOff - turn off all notes
  681. *
  682. */
  683. VOID Opl3_AllNotesOff(void)
  684. {
  685. BYTE i;
  686. for (i = 0; i < NUM2VOICES; i++) {
  687. Opl3_NoteOff (gVoice[i].bPatch, gVoice[i].bNote, gVoice[i].bChannel);
  688. }
  689. }
  690. /* Opl3_NewVolume - This should be called if a volume level
  691. * has changed. This will adjust the levels of all the playing
  692. * voices.
  693. *
  694. * inputs
  695. * WORD wLeft - left attenuation (1.5 db units)
  696. * WORD wRight - right attenuation (ignore if mono)
  697. * returns
  698. * none
  699. */
  700. VOID FAR PASCAL Opl3_NewVolume (WORD wLeft, WORD wRight)
  701. {
  702. /* make sure that we are actually open */
  703. if (!glpPatch)
  704. return;
  705. wSynthAttenL = wLeft;
  706. wSynthAttenR = wRight;
  707. Opl3_setvolume(0xff);
  708. }
  709. /* Opl3_ChannelVolume - set the volume level for an individual channel.
  710. *
  711. * inputs
  712. * BYTE bChannel - channel number to change
  713. * WORD wAtten - attenuation in 1.5 db units
  714. *
  715. * returns
  716. * none
  717. */
  718. VOID FAR PASCAL Opl3_ChannelVolume(BYTE bChannel, WORD wAtten)
  719. {
  720. gbChanAtten[bChannel] = (BYTE)wAtten;
  721. Opl3_setvolume(bChannel);
  722. }
  723. /* Opl3_SetPan - set the left-right pan position.
  724. *
  725. * inputs
  726. * BYTE bChannel - channel number to alter
  727. * BYTE bPan - 0 for left, 127 for right or somewhere in the middle.
  728. *
  729. * returns - none
  730. */
  731. VOID FAR PASCAL Opl3_SetPan(BYTE bChannel, BYTE bPan)
  732. {
  733. /* change the pan level */
  734. if (bPan > (64 + 16))
  735. gbStereoMask[bChannel] = 0xef; /* let only right channel through */
  736. else if (bPan < (64 - 16))
  737. gbStereoMask[bChannel] = 0xdf; /* let only left channel through */
  738. else
  739. gbStereoMask[bChannel] = 0xff; /* let both channels */
  740. /* change any curently playing patches */
  741. Opl3_setvolume(bChannel);
  742. }
  743. //------------------------------------------------------------------------
  744. // VOID MidiPitchBend
  745. //
  746. // Description:
  747. // This pitch bends a channel.
  748. //
  749. // Parameters:
  750. // BYTE bChannel
  751. // channel
  752. //
  753. // short iBend
  754. // values from -32768 to 32767, being -2 to +2 half steps
  755. //
  756. // Return Value:
  757. // Nothing.
  758. //
  759. //
  760. //------------------------------------------------------------------------
  761. VOID NEAR PASCAL Opl3_PitchBend
  762. (
  763. BYTE bChannel,
  764. short iBend
  765. )
  766. {
  767. WORD i, wTemp[ 2 ], wOffset, j ;
  768. DWORD dwNew ;
  769. // D1( "\nMidiPitchBend" ) ;
  770. // Remember the current bend..
  771. giBend[ bChannel ] = iBend ;
  772. // Loop through all the notes looking for the right
  773. // channel. Anything with the right channel gets its
  774. // pitch bent...
  775. for (i = 0; i < NUM2VOICES; i++)
  776. if (gVoice[ i ].bChannel == bChannel)
  777. {
  778. j = 0 ;
  779. dwNew = Opl3_CalcBend( gVoice[ i ].dwOrigPitch[ j ], iBend ) ;
  780. wTemp[ j ] = Opl3_CalcFAndB( dwNew ) ;
  781. gVoice[ i ].bBlock[ j ] =
  782. (gVoice[ i ].bBlock[ j ] & (BYTE) 0xe0) |
  783. (BYTE) (wTemp[ j ] >> 8) ;
  784. wOffset = (i < (NUM2VOICES / 2)) ? i : (i + 0x100 - 9) ;
  785. MidiSendFM( AD_BLOCK + wOffset, gVoice[ i ].bBlock[ 0 ] ) ;
  786. MidiSendFM( AD_FNUMBER + wOffset, (BYTE) wTemp[ 0 ] ) ;
  787. }
  788. } // end of MidiPitchBend()
  789. #ifdef LOAD_PATCHES
  790. static TCHAR BCODE gszDefPatchLib[] = TEXT("SYNTH.PAT");
  791. static TCHAR BCODE gszIniKeyPatchLib[] = INI_STR_PATCHLIB;
  792. static TCHAR BCODE gszIniDrvSection[] = INI_DRIVER;
  793. static TCHAR BCODE gszIniDrvFile[] = INI_SOUND;
  794. static TCHAR BCODE gszSysIniSection[] = TEXT("synth.dll");
  795. static TCHAR BCODE gszSysIniFile[] = TEXT("System.Ini");
  796. /** static DWORD NEAR PASCAL DrvGetProfileString(LPSTR szKeyName, LPSTR szDef, LPSTR szBuf, UINT wBufLen)
  797. *
  798. * DESCRIPTION:
  799. *
  800. *
  801. * ARGUMENTS:
  802. * (LPSTR szKeyName, LPSTR szDef, LPSTR szBuf, WORD wBufLen)
  803. * HINT wSystem - if TRUE write/read to system.ini
  804. *
  805. * RETURN (static DWORD NEAR PASCAL):
  806. *
  807. *
  808. * NOTES:
  809. *
  810. ** cjp */
  811. static DWORD NEAR PASCAL DrvGetProfileString(LPTSTR szKeyName, LPTSTR szDef, LPTSTR szBuf, UINT wBufLen,
  812. UINT wSystem)
  813. {
  814. return GetPrivateProfileString(wSystem ? gszSysIniSection : gszIniDrvSection, szKeyName, szDef,
  815. szBuf, wBufLen, wSystem ? gszSysIniFile : gszIniDrvFile);
  816. } /* DrvGetProfileString() */
  817. #endif // LOAD_PATCHES
  818. /* Opl3_BoardInit - initialise board and load patches as necessary.
  819. *
  820. * inputs - none
  821. * returns - 0 for success or the error code
  822. */
  823. WORD Opl3_BoardInit(void)
  824. {
  825. HMMIO hmmio;
  826. MMCKINFO mmckinfo, mm2;
  827. TCHAR szPatchLib[STRINGLEN]; /* patch libarary */
  828. D1 (("Opl3_Init"));
  829. /* Check we haven't already initialized */
  830. if (glpPatch != NULL) {
  831. return 0;
  832. }
  833. /* allocate the memory, and fill it up from the patch
  834. * library.
  835. */
  836. glpPatch = (patchStruct FAR *)GlobalLock(GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE|GMEM_ZEROINIT, sizeof(patchStruct) * NUMPATCHES));
  837. if (!glpPatch) {
  838. D1 (("Opl3_Init: could not allocate patch container memory!"));
  839. return ERROR_OUTOFMEMORY;
  840. }
  841. #ifdef LOAD_PATCHES
  842. /* should the load patches be moved to the init section? */
  843. DrvGetProfileString(gszIniKeyPatchLib, TEXT(""),
  844. szPatchLib, sizeof(szPatchLib), FALSE);
  845. if (lstrcmpi( (LPTSTR) szPatchLib, TEXT("") ) == 0)
  846. #endif // LOAD_PATCHES
  847. {
  848. HRSRC hrsrcPatches ;
  849. HGLOBAL hPatches ;
  850. LPTSTR lpPatches ;
  851. hrsrcPatches =
  852. FindResource( ghModule, MAKEINTRESOURCE( DATA_FMPATCHES ),
  853. RT_BINARY ) ;
  854. if (NULL != hrsrcPatches)
  855. {
  856. hPatches = LoadResource( ghModule, hrsrcPatches ) ;
  857. lpPatches = LockResource( hPatches ) ;
  858. AsMemCopy( glpPatch, lpPatches,
  859. sizeof( patchStruct ) * NUMPATCHES ) ;
  860. UnlockResource( hPatches ) ;
  861. FreeResource( hPatches ) ;
  862. }
  863. else
  864. {
  865. TCHAR szAlert[ 50 ] ;
  866. TCHAR szErrorBuffer[ 255 ] ;
  867. LoadString( ghModule, SR_ALERT, szAlert, sizeof( szAlert ) / sizeof(TCHAR)) ;
  868. LoadString( ghModule, SR_ALERT_NORESOURCE, szErrorBuffer,
  869. sizeof( szErrorBuffer ) / sizeof(TCHAR) ) ;
  870. MessageBox( NULL, szErrorBuffer, szAlert, MB_OK|MB_ICONHAND ) ;
  871. }
  872. }
  873. #ifdef LOAD_PATCHES
  874. else
  875. {
  876. hmmio = mmioOpen (szPatchLib, NULL, MMIO_READ);
  877. if (hmmio) {
  878. mmioDescend (hmmio, &mmckinfo, NULL, 0);
  879. if ((mmckinfo.ckid == FOURCC_RIFF) &&
  880. (mmckinfo.fccType == RIFF_PATCH)) {
  881. mm2.ckid = RIFF_FM4;
  882. if (!mmioDescend (hmmio, &mm2, &mmckinfo, MMIO_FINDCHUNK)) {
  883. /* we have found the synthesis chunk */
  884. if (mm2.cksize > (sizeof(patchStruct)*NUMPATCHES))
  885. mm2.cksize = sizeof(patchStruct)*NUMPATCHES;
  886. mmioRead (hmmio, (LPSTR) glpPatch, mm2.cksize);
  887. } else {
  888. D1(("Bad mmioDescend2"));
  889. }
  890. } else {
  891. D1(("Bad mmioDescend1"));
  892. }
  893. mmioClose (hmmio, 0);
  894. } else {
  895. TCHAR szAlert[50];
  896. TCHAR szErrorBuffer[255];
  897. LoadString(ghModule, SR_ALERT, szAlert, sizeof(szAlert));
  898. LoadString(ghModule, SR_ALERT_NOPATCH, szErrorBuffer, sizeof(szErrorBuffer));
  899. MessageBox(NULL, szErrorBuffer, szAlert, MB_OK|MB_ICONHAND);
  900. D1 (("Bad mmioOpen"));
  901. }
  902. }
  903. #endif // LOAD_PATCHES
  904. return 0; /* done */
  905. }
  906. /*
  907. * Opl3_BoardReset - silence the board and set all voices off.
  908. */
  909. VOID Opl3_BoardReset(void)
  910. {
  911. BYTE i;
  912. /* make sure all notes turned off */
  913. Opl3_AllNotesOff();
  914. /* ---- silence the chip -------- */
  915. /* tell the FM chip to use 4-operator mode, and
  916. fill in any other random variables */
  917. MidiSendFM (AD_NEW, 0x01);
  918. MidiSendFM (AD_MASK, 0x60);
  919. MidiSendFM (AD_CONNECTION, 0x00);
  920. MidiSendFM (AD_NTS, 0x00);
  921. /* turn off the drums, and use high vibrato/modulation */
  922. MidiSendFM (AD_DRUM, 0xc0);
  923. /* turn off all the oscillators */
  924. for (i = 0; i < 0x15; i++) {
  925. MidiSendFM (AD_LEVEL + i, 0x3f);
  926. MidiSendFM (AD_LEVEL2 + i, 0x3f);
  927. };
  928. /* turn off all the voices */
  929. for (i = 0; i < 0x08; i++) {
  930. MidiSendFM (AD_BLOCK + i, 0x00);
  931. MidiSendFM (AD_BLOCK2 + i, 0x00);
  932. };
  933. /* clear all of the voice slots to empty */
  934. for (i = 0; i < NUM2VOICES; i++)
  935. gVoice[i].dwTime = 0;
  936. /* start attenuations at -3 dB, which is 90 MIDI level */
  937. for (i = 0; i < NUMCHANNELS; i++) {
  938. gbChanAtten[i] = 4;
  939. gbStereoMask[i] = 0xff;
  940. };
  941. /* turn off the pitch bend */
  942. for (i = 0; i < NUMCHANNELS; i++)
  943. giBend[i] = 0;
  944. }