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.

1558 lines
43 KiB

4 years ago
  1. /*
  2. * Copyright (c) 1992 Microsoft Corporation
  3. */
  4. /*
  5. * definition of interface functions to the adlib midi device type.
  6. *
  7. * These functions are called from midi.c when the kernel driver
  8. * has decreed that this is an adlib-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 "adlib.h"
  17. /*
  18. * overview
  19. *
  20. * The FM synthesis chip consists of 18 operator cells or 'slots'. Each slot
  21. * can produce a sine wave modified by a number of parameters such
  22. * as frequency, output level and envelope shape (attack/decay/sustain
  23. * release). Slots are arranged in pairs, with one slot modulating
  24. * the sine wave of another to produce the harmonics desired for
  25. * a given instrument sound. Thus one pair of slots is a 'voice' and can
  26. * play one note at a time.
  27. *
  28. * In percussive mode (which we always use), there are 6 melodic voices
  29. * available, and one voice for the base drum. The remaining four slots
  30. * are used singly rather than in pairs to produce four further percussive
  31. * voices. The 6 melodic voices will be changed to any given timbre
  32. * as needed. The five percussive voices are fixed to particular instrument
  33. * timbres: bass drum, snare, tom-tom, hi-hat and cymbal.
  34. *
  35. * To play a note, we first find a free voice of the appropriate type. If
  36. * there are none free, we use the oldest busy one. We then set the
  37. * parameters for both operator slots from the patch table - this table gives
  38. * parameter settings for the different instrument timbres available.
  39. * We adjust the output level and frequency depending on the
  40. * note played and the velocity it was played with, and then switch on the
  41. * note.
  42. */
  43. /* --- typedefs ------------------------------------------------- */
  44. #define NUMVOICES (11) // number of voices we have
  45. #define NUMMELODIC (6) // number of melodic voices
  46. #define NUMPERCUSSIVE (5) // number of percussive voices
  47. #define MAXPATCH 180 // nr of patches (including drums)
  48. #define MAXVOLUME 0x7f
  49. #define NUMLOCPARAM 14 // number of loc params per slot
  50. #define FIRSTDRUMNOTE 35
  51. #define LASTDRUMNOTE 81
  52. #define NUMDRUMNOTES (LASTDRUMNOTE - FIRSTDRUMNOTE + 1)
  53. #define MAX_PITCH 0x3fff // maximum pitch bend value
  54. #define MID_PITCH 0x2000 // mid pitch bend value (no shift)
  55. #define PITCHRANGE 2 // total bend range +- 2 semitones
  56. #define NR_STEP_PITCH 25 // steps per half-tone for pitch bend
  57. #define MID_C 60 // MIDI standard mid C
  58. #define CHIP_MID_C 48 // sound chip mid C
  59. /*
  60. * to write to the device, we write a SYNTH_DATA port,data pair
  61. * to the kernel driver.
  62. */
  63. #define SndOutput(p,d) MidiSendFM(p, d)
  64. /****************************************************************************
  65. *
  66. * definitions of sound chip parameters
  67. */
  68. // parameters of each voice
  69. #define prmKsl 0 // key scale level (KSL) - level controller
  70. #define prmMulti 1 // frequency multiplier (MULTI) - oscillator
  71. #define prmFeedBack 2 // modulation feedback (FB) - oscillator
  72. #define prmAttack 3 // attack rate (AR) - envelope generator
  73. #define prmSustain 4 // sustain level (SL) - envelope generator
  74. #define prmStaining 5 // sustaining sound (SS) - envelope generator
  75. #define prmDecay 6 // decay rate (DR) - envelope generator
  76. #define prmRelease 7 // release rate (RR) - envelope generator
  77. #define prmLevel 8 // output level (OL) - level controller
  78. #define prmAm 9 // amplitude vibrato (AM) - level controller
  79. #define prmVib 10 // frequency vibrator (VIB) - oscillator
  80. #define prmKsr 11 // envelope scaling (KSR) - envelope generator
  81. #define prmFm 12 // fm=0, additive=1 (FM) (operator 0 only)
  82. #define prmWaveSel 13 // wave select
  83. // global parameters
  84. #define prmAmDepth 14
  85. #define prmVibDepth 15
  86. #define prmNoteSel 16
  87. #define prmPercussion 17
  88. // percussive voice numbers (0-5 are melodic voices, 2 op):
  89. #define BD 6 // bass drum (2 op)
  90. #define SD 7 // snare drum (1 op)
  91. #define TOM 8 // tom-tom (1 op)
  92. #define CYMB 9 // cymbal (1 op)
  93. #define HIHAT 10 // hi-hat (1 op)
  94. // In percussive mode, the last 4 voices (SD TOM HH CYMB) are created
  95. // using melodic voices 7 & 8. A noise generator uses channels 7 & 8
  96. // frequency information for creating rhythm instruments. Best results
  97. // are obtained by setting TOM two octaves below mid C and SD 7 half-tones
  98. // above TOM. In this implementation, only the TOM pitch may vary, with the
  99. // SD always set 7 half-tones above.
  100. #define TOM_PITCH 24 // best frequency, in range of 0 to 95
  101. #define TOM_TO_SD 7 // 7 half-tones between voice 7 & 8
  102. #define SD_PITCH (TOM_PITCH + TOM_TO_SD)
  103. /****************************************************************************
  104. *
  105. * bank file support
  106. *
  107. ***************************************************************************/
  108. #define BANK_SIG_LEN 6
  109. #define BANK_FILLER_SIZE 8
  110. typedef BYTE *HPBYTE;
  111. typedef BYTE NEAR * NPBYTE;
  112. typedef WORD NEAR * NPWORD;
  113. // instrument bank file header
  114. typedef struct {
  115. char majorVersion;
  116. char minorVersion;
  117. char sig[BANK_SIG_LEN]; // signature: "ADLIB-"
  118. WORD nrDefined; // number of list entries used
  119. WORD nrEntry; // number of total entries in list
  120. long offsetIndex; // offset of start of list of names
  121. long offsetTimbre; // offset of start of data
  122. char filler[BANK_FILLER_SIZE]; // must be zero
  123. } BANKHDR, NEAR *NPBANKHDR, FAR *LPBANKHDR;
  124. // all the parameters for one slot
  125. typedef struct {
  126. BYTE ksl; // KSL
  127. BYTE freqMult; // MULTI
  128. BYTE feedBack; // FB
  129. BYTE attack; // AR
  130. BYTE sustLevel; // SL
  131. BYTE sustain; // SS
  132. BYTE decay; // DR
  133. BYTE release; // RR
  134. BYTE output; // OL
  135. BYTE am; // AM
  136. BYTE vib; // VIB
  137. BYTE ksr; // KSR
  138. BYTE fm; // FM
  139. } OPERATOR, NEAR *NPOPERATOR, FAR *LPOPERATOR;
  140. // definition of a particular instrument sound or timbre -
  141. // one of these per patch
  142. typedef struct {
  143. BYTE mode; // 0 = melodic, 1 = percussive
  144. BYTE percVoice; // if mode == 1, voice number to be used
  145. OPERATOR op0; // params for slot 0
  146. OPERATOR op1; // params for slot 1
  147. BYTE wave0; // waveform for operator 0
  148. BYTE wave1; // waveform for operator 1
  149. } TIMBRE, NEAR *NPTIMBRE, FAR *LPTIMBRE;
  150. typedef struct drumpatch_tag {
  151. BYTE patch; // the patch to use
  152. BYTE note; // the note to play
  153. } DRUMPATCH;
  154. // format of drumkit.dat file
  155. typedef struct drumfilepatch_tag {
  156. BYTE key; // the key to map
  157. BYTE patch; // the patch to use
  158. BYTE note; // the note to play
  159. } DRUMFILEPATCH, *PDRUMFILEPATCH;
  160. typedef struct _VOICE {
  161. BYTE alloc; // is voice allocated?
  162. BYTE note; // note that is currently being played
  163. BYTE channel; // channel that it is being played on
  164. BYTE volume; // current volume setting of voice
  165. DWORD dwTimeStamp; // time voice was allocated
  166. } VOICE;
  167. #define GetLocPrm(slot_num, prm) ((WORD)paramSlot[slot_num][prm])
  168. /* --- module data ---------------------------------------------- */
  169. // this table gives the offset of each slot within the chip.
  170. BYTE offsetSlot[] = {
  171. 0, 1, 2, 3, 4, 5,
  172. 8, 9, 10, 11, 12, 13,
  173. 16, 17, 18, 19, 20, 21
  174. };
  175. static BYTE percMasks[] = {
  176. 0x10, 0x08, 0x04, 0x02, 0x01 };
  177. // voice number associated with each slot (melodic mode only)
  178. static BYTE voiceSlot[] = {
  179. 0, 1, 2,
  180. 0, 1, 2,
  181. 3, 4, 5,
  182. 3, 4, 5,
  183. 6, 7, 8,
  184. 6, 7, 8,
  185. };
  186. // slot numbers for percussive voices (0 indicates that there is only one slot)
  187. static BYTE slotPerc[][2] = {
  188. {12, 15}, // Bass Drum
  189. {16, 0}, // SD
  190. {14, 0}, // TOM
  191. {17, 0}, // TOP-CYM
  192. {13, 0} // HH
  193. };
  194. // slot numbers as a function of the voice and the operator (melodic only)
  195. static BYTE slotVoice[][2] = {
  196. {0, 3}, // voice 0
  197. {1, 4}, // 1
  198. {2, 5}, // 2
  199. {6, 9}, // 3
  200. {7, 10}, // 4
  201. {8, 11}, // 5
  202. {12, 15}, // 6
  203. {13, 16}, // 7
  204. {14, 17} // 8
  205. };
  206. // this table indicates if the slot is a modulator (0) or a carrier (1).
  207. BYTE operSlot[] = {
  208. 0, 0, 0, // 1 2 3
  209. 1, 1, 1, // 4 5 6
  210. 0, 0, 0, // 7 8 9
  211. 1, 1, 1, // 10 11 12
  212. 0, 0, 0, // 13 14 15
  213. 1, 1, 1, // 16 17 18
  214. };
  215. // this array adjusts the octave of a note for certain patches.
  216. static char patchKeyOffset[] = {
  217. 0, -12, 12, 0, 0, 12, -12, 0, 0, -24, // 0 - 9
  218. 0, 0, 0, 0, 0, 0, 0, 0, -12, 0, // 10 - 19
  219. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 - 29
  220. 0, 0, 12, 12, 12, 0, 0, 12, 12, 0, // 30 - 39
  221. -12, -12, 0, 12, -12, -12, 0, 12, 0, 0, // 40 - 49
  222. -12, 0, 0, 0, 12, 12, 0, 0, 12, 0, // 50 - 59
  223. 0, 0, 12, 0, 0, 0, 12, 12, 0, 12, // 60 - 69
  224. 0, 0, -12, 0, -12, -12, 0, 0, -12, -12, // 70 - 79
  225. 0, 0, 0, 0, 0, -12, -19, 0, 0, -12, // 80 - 89
  226. 0, 0, 0, 0, 0, 0, -31, -12, 0, 12, // 90 - 99
  227. 12, 12, 12, 0, 12, 0, 12, 0, 0, 0, // 100 - 109
  228. 0, 12, 0, 0, 0, 0, 12, 12, 12, 0, // 110 - 119
  229. 0, 0, 0, 0, -24, -36, 0, 0}; // 120 - 127
  230. static BYTE loudervol[128] = {
  231. 0, 0, 65, 65, 66, 66, 67, 67, // 0 - 7
  232. 68, 68, 69, 69, 70, 70, 71, 71, // 8 - 15
  233. 72, 72, 73, 73, 74, 74, 75, 75, // 16 - 23
  234. 76, 76, 77, 77, 78, 78, 79, 79, // 24 - 31
  235. 80, 80, 81, 81, 82, 82, 83, 83, // 32 - 39
  236. 84, 84, 85, 85, 86, 86, 87, 87, // 40 - 47
  237. 88, 88, 89, 89, 90, 90, 91, 91, // 48 - 55
  238. 92, 92, 93, 93, 94, 94, 95, 95, // 56 - 63
  239. 96, 96, 97, 97, 98, 98, 99, 99, // 64 - 71
  240. 100, 100, 101, 101, 102, 102, 103, 103, // 72 - 79
  241. 104, 104, 105, 105, 106, 106, 107, 107, // 80 - 87
  242. 108, 108, 109, 109, 110, 110, 111, 111, // 88 - 95
  243. 112, 112, 113, 113, 114, 114, 115, 115, // 96 - 103
  244. 116, 116, 117, 117, 118, 118, 119, 119, // 104 - 111
  245. 120, 120, 121, 121, 122, 122, 123, 123, // 112 - 119
  246. 124, 124, 125, 125, 126, 126, 127, 127}; // 120 - 127
  247. /*
  248. * attenuation setting for each slot - combination
  249. * of the channel attenuation for this channel, and the
  250. * velocity (converted to attenuation). Combine with
  251. * global attenuation and timbre output attenuation before
  252. * writing to device.
  253. */
  254. WORD slotAtten[18]; // vol-control attenuation of slots
  255. WORD wSynthAtten; // overall volume setting
  256. BYTE gbChanAtten[NUMCHANNELS]; // attenuation for each channel
  257. VOICE voices[11]; // 9 voices if melodic mode or 11 if percussive
  258. BYTE voiceKeyOn[11]; // keyOn bit for each voice (implicit 0 init)
  259. BYTE paramSlot[18][NUMLOCPARAM]; // all the parameters of slots...
  260. BYTE percBits; // control bits of percussive voices
  261. WORD fNumNotes[NR_STEP_PITCH][12];
  262. PWORD fNumFreqPtr[11]; // lines of fNumNotes table (one per voice)
  263. int halfToneOffset[11]; // one per voice
  264. BYTE notePitch[11]; // pitch value for each voice (implicit 0 init)
  265. // patches - parameters for different instrument timbres
  266. TIMBRE patches[MAXPATCH]; // patch data
  267. DRUMPATCH drumpatch[NUMDRUMNOTES]; // drum kit data
  268. DWORD dwAge = 0; // voice relative age
  269. /* --- internal functions --------------------------------------- */
  270. /* -- initialisation --- */
  271. /****************************************************************************
  272. * @doc INTERNAL
  273. *
  274. * @api int | LoadPatches | Reads the patch set from the BANK resource and
  275. * builds the <p patches> array.
  276. *
  277. * @rdesc Returns the number of patches loaded, or 0 if an error occurs.
  278. ***************************************************************************/
  279. static BYTE PatchRes[] = {
  280. #include "adlib.dat"
  281. };
  282. int LoadPatches(void)
  283. {
  284. #ifdef WIN16
  285. HANDLE hResInfo;
  286. HANDLE hResData;
  287. #endif
  288. LPSTR lpRes;
  289. int iPatches;
  290. DWORD dwOffset;
  291. DWORD dwResSize;
  292. LPTIMBRE lpBankTimbre;
  293. LPTIMBRE lpPatchTimbre;
  294. LPBANKHDR lpBankHdr;
  295. // find resource and get its size
  296. #ifdef WIN16
  297. hResInfo = FindResource(ghInstance, MAKEINTRESOURCE(DEFAULTBANK), MAKEINTRESOURCE(RT_BANK));
  298. if (!hResInfo) {
  299. D1("Default bank resource not found");
  300. return 0;
  301. }
  302. dwResSize = (DWORD)SizeofResource(ghInstance, hResInfo);
  303. // load and lock resource
  304. hResData = LoadResource(ghInstance, hResInfo);
  305. if (!hResData) {
  306. D1("Bank resource not loaded");
  307. return 0;
  308. }
  309. lpRes = LockResource(hResData);
  310. if (!lpRes) {
  311. D1("Bank resource not locked");
  312. return 0;
  313. }
  314. #else
  315. lpRes = PatchRes;
  316. dwResSize = sizeof(PatchRes);
  317. #endif
  318. // read the bank resource, loading patches as we find them
  319. D2("loading patches");
  320. lpBankHdr = (LPBANKHDR)lpRes;
  321. dwOffset = lpBankHdr->offsetTimbre; // point to first one
  322. for (iPatches = 0; iPatches < MAXPATCH; iPatches++) {
  323. lpBankTimbre = (LPTIMBRE)(lpRes + dwOffset);
  324. lpPatchTimbre = &patches[iPatches];
  325. *lpPatchTimbre = *lpBankTimbre;
  326. dwOffset += sizeof(TIMBRE);
  327. if (dwOffset + sizeof(TIMBRE) > dwResSize) {
  328. D1("Attempt to read past end of bank resource");
  329. break;
  330. }
  331. }
  332. #ifdef WIN16
  333. UnlockResource(hResData);
  334. FreeResource(hResData);
  335. #endif
  336. return iPatches;
  337. }
  338. /****************************************************************************
  339. * @doc INTERNAL
  340. *
  341. * @api int | LoadDrumPatches | Reads the drum kit patch set from the
  342. * DRUMKIT resource and builds the <p drumpatch> array.
  343. *
  344. * @comm Each entry of the <t drumpatch> array (representing a key number
  345. * from the "drum patch") consists of a patch number and note number
  346. * from some other patch.
  347. *
  348. * @rdesc Returns the number of patches loaded, or 0 if an error occurs.
  349. ***************************************************************************/
  350. static BYTE DrumRes[] = {
  351. #include "drumkit.dat"
  352. };
  353. int LoadDrumPatches(void)
  354. {
  355. #ifdef WIN16
  356. HANDLE hResInfo;
  357. HANDLE hResData;
  358. #endif
  359. LPSTR lpRes;
  360. int iPatches;
  361. int key;
  362. DWORD dwOffset;
  363. DWORD dwResSize;
  364. PDRUMFILEPATCH lpResPatch;
  365. #ifdef WIN16
  366. // find resource and get its size
  367. hResInfo = FindResource(ghInstance, MAKEINTRESOURCE(DEFAULTDRUMKIT), MAKEINTRESOURCE(RT_DRUMKIT));
  368. if (!hResInfo) {
  369. D1("Default drum resource not found");
  370. return 0;
  371. }
  372. dwResSize = (DWORD)SizeofResource(ghInstance, hResInfo);
  373. // load and lock resource
  374. hResData = LoadResource(ghInstance, hResInfo);
  375. if (!hResData) {
  376. D1("Drum resource not loaded");
  377. return 0;
  378. }
  379. lpRes = LockResource(hResData);
  380. if (!lpRes) {
  381. D1("Drum resource not locked");
  382. return 0;
  383. }
  384. #else
  385. lpRes = DrumRes;
  386. dwResSize = sizeof(DrumRes);
  387. #endif
  388. // read the drum resource, loading patches as we find them
  389. D2("reading drum data");
  390. dwOffset = 0;
  391. for (iPatches = 0; iPatches < NUMDRUMNOTES; iPatches++) {
  392. lpResPatch = (PDRUMFILEPATCH)(lpRes + dwOffset);
  393. key = lpResPatch->key;
  394. if ((key >= FIRSTDRUMNOTE) && (key <= LASTDRUMNOTE)) {
  395. drumpatch[key - FIRSTDRUMNOTE].patch = lpResPatch->patch;
  396. drumpatch[key - FIRSTDRUMNOTE].note = lpResPatch->note;
  397. }
  398. else {
  399. D1("Drum patch key out of range");
  400. }
  401. dwOffset += sizeof(DRUMFILEPATCH);
  402. if (dwOffset > dwResSize) {
  403. D1("Attempt to read past end of drum resource");
  404. break;
  405. }
  406. }
  407. #ifdef WIN16
  408. UnlockResource(hResData);
  409. FreeResource(hResData);
  410. #endif
  411. return iPatches;
  412. }
  413. /****************************************************************************
  414. * @doc INTERNAL
  415. *
  416. * @api long | CalcPremFNum | Calculates some magic number that is used in
  417. * setting the values in the <p fNumNotes> table.
  418. *
  419. * @parm int | numDeltaDemiTon | Numerator (-100 to +100).
  420. *
  421. * @parm int | denDeltaDemiTon | Denominator (1 to 100).
  422. *
  423. * @comm If the numerator (numDeltaDemiTon) is positive, the frequency is
  424. * increased; if negative, it is decreased. The function calculates:
  425. * f8 = Fb(1 + 0.06 num /den) (where Fb = 26044 * 2 / 25)
  426. * fNum8 = f8 * 65536 * 72 / 3.58e6
  427. *
  428. * @rdesc Returns fNum8, which is the binary value of the frequency 260.44 (C)
  429. * shifted by +/- <p numdeltaDemiTon> / <p denDeltaDemiTon> * 8.
  430. ***************************************************************************/
  431. long NEAR CalcPremFNum(int numDeltaDemiTon, int denDeltaDemiTon)
  432. {
  433. long f8;
  434. long fNum8;
  435. long d100;
  436. d100 = denDeltaDemiTon * 100;
  437. f8 = (d100 + 6 * numDeltaDemiTon) * (26044L * 2L);
  438. f8 /= d100 * 25;
  439. fNum8 = f8 * 16384;
  440. fNum8 *= 9L;
  441. fNum8 /= 179L * 625L;
  442. return fNum8;
  443. }
  444. /****************************************************************************
  445. * @doc INTERNAL
  446. *
  447. * @api void | SetFNum | Initializes a line in the frequency table with
  448. * shifted frequency values. The values are shifted a fraction (num/den)
  449. * of a half-tone.
  450. *
  451. * @parm NPWORD | fNumVec | The line from the frequency table.
  452. *
  453. * @parm int | num | Numerator.
  454. *
  455. * @parm int | den | Denominator.
  456. *
  457. * @xref CalcPremFNum
  458. *
  459. * @rdesc There is no return value.
  460. ***************************************************************************/
  461. void NEAR SetFNum(NPWORD fNumVec, int num, int den)
  462. {
  463. int i;
  464. long val;
  465. *fNumVec++ = (WORD)((4 + (val = CalcPremFNum(num, den))) >> 3);
  466. for (i = 1; i < 12; i++) {
  467. val *= 106;
  468. *fNumVec++ = (WORD)((4 + (val /= 100)) >> 3);
  469. }
  470. }
  471. /****************************************************************************
  472. * @doc INTERNAL
  473. *
  474. * @api void | InitFNums | Initializes all lines of the frequency table
  475. * (the <p fNumNotes> array). Each line represents 12 half-tones shifted
  476. * by (n / NR_STEP_PITCH), where 'n' is the line number and ranges from
  477. * 1 to NR_STEP_PITCH.
  478. *
  479. * @rdesc There is no return value.
  480. ***************************************************************************/
  481. void NEAR InitFNums(void)
  482. {
  483. WORD i;
  484. WORD num; // numerator
  485. WORD numStep; // step value for numerator
  486. WORD row; // row in the frequency table
  487. // calculate each row in the fNumNotes table
  488. numStep = 100 / NR_STEP_PITCH;
  489. for (num = row = 0; row < NR_STEP_PITCH; row++, num += numStep)
  490. SetFNum(fNumNotes[row], num, 100);
  491. // fNumFreqPtr has an element for each voice, pointing to the
  492. // appropriate row in the fNumNotes table. They're all initialized
  493. // to the first row, which represents no pitch shift.
  494. for (i = 0; i < 11; i++) {
  495. fNumFreqPtr[i] = fNumNotes[0];
  496. halfToneOffset[i] = 0;
  497. }
  498. }
  499. /****************************************************************************
  500. * @doc INTERNAL
  501. *
  502. * @api void | SoundChut | Sets the frequency of voice <p voice> to 0 Hz.
  503. *
  504. * @parm BYTE | voice | Specifies which voice to set.
  505. *
  506. * @rdesc There is no return value.
  507. ***************************************************************************/
  508. void NEAR SoundChut(BYTE voice)
  509. {
  510. SndOutput((BYTE)(0xA0 | voice), 0);
  511. SndOutput((BYTE)(0xB0 | voice), 0);
  512. }
  513. /* --- write parameters to chip ------------------------*/
  514. /*
  515. * switch chip to rhythm (percussive) mode, set the amplitude and
  516. * vibrato depth and switch on any percussion voices that are on
  517. */
  518. void SndSAmVibRhythm(void)
  519. {
  520. // we always set amdepth, vibdepth to 0 and perc mode on
  521. // t1 = (BYTE)(amDepth ? 0x80 : 0);
  522. // t1 |= vibDepth ? 0x40 : 0;
  523. // t1 |= (percussionmode ? 0x20 : 0);
  524. SndOutput((BYTE)0xBD, (BYTE)(0x20|percBits));
  525. }
  526. /****************************************************************************
  527. * @doc INTERNAL
  528. *
  529. * @api void | SndSNoteSel | Sets the NoteSel value.
  530. *
  531. * @rdesc There is no return value.
  532. ***************************************************************************/
  533. void SndSNoteSel(BOOL bNoteSel)
  534. {
  535. SndOutput(0x08, (BYTE)(bNoteSel ? 64 : 0));
  536. }
  537. /****************************************************************************
  538. * @doc INTERNAL
  539. *
  540. * @api void | SndSKslLevel | Sets the KSL and LEVEL values.
  541. *
  542. * @parm BYTE | slot | Specifies which slot to set.
  543. *
  544. * @rdesc There is no return value.
  545. ***************************************************************************/
  546. void SndSKslLevel(BYTE slot)
  547. {
  548. WORD t1;
  549. t1 = GetLocPrm(slot, prmLevel) & 0x3f;
  550. t1 += slotAtten[slot];
  551. t1 = min (t1, 0x3f);
  552. t1 |= GetLocPrm(slot, prmKsl) << 6;
  553. SndOutput((BYTE)(0x40 | offsetSlot[slot]), (BYTE) t1);
  554. }
  555. /****************************************************************************
  556. * @doc INTERNAL
  557. *
  558. * @api void | SndSAVEK | Sets the AM, VIB, EG-TYP (sustaining), KSR, and
  559. * MULTI values.
  560. *
  561. * @parm BYTE | slot | Specifies which slot to set.
  562. *
  563. * @rdesc There is no return value.
  564. ***************************************************************************/
  565. void SndSAVEK(BYTE slot)
  566. {
  567. BYTE t1;
  568. t1 = (BYTE)(GetLocPrm(slot, prmAm) ? 0x80 : 0);
  569. t1 += GetLocPrm(slot, prmVib) ? 0x40 : 0;
  570. t1 += GetLocPrm(slot, prmStaining) ? 0x20 : 0;
  571. t1 += GetLocPrm(slot, prmKsr) ? 0x10 : 0;
  572. t1 += GetLocPrm(slot, prmMulti) & 0xf;
  573. SndOutput((BYTE)(0x20 | offsetSlot[slot]), t1);
  574. }
  575. /****************************************************************************
  576. * @doc INTERNAL
  577. *
  578. * @api void | SndSFeedFm | Sets the FEEDBACK and FM (connection) values.
  579. * Applicable only to operator 0 for melodic voices.
  580. *
  581. * @parm BYTE | slot | Specifies which slot to set.
  582. *
  583. * @rdesc There is no return value.
  584. ***************************************************************************/
  585. void SndSFeedFm(BYTE slot)
  586. {
  587. BYTE t1;
  588. if (operSlot[slot])
  589. return;
  590. t1 = (BYTE)(GetLocPrm(slot, prmFeedBack) << 1);
  591. t1 |= GetLocPrm(slot, prmFm) ? 0 : 1;
  592. SndOutput((BYTE)(0xC0 | voiceSlot[slot]), t1);
  593. }
  594. /****************************************************************************
  595. * @doc INTERNAL
  596. *
  597. * @api void | SndSAttDecay | Sets the ATTACK and DECAY values.
  598. *
  599. * @parm BYTE | slot | Specifies which slot to set.
  600. *
  601. * @rdesc There is no return value.
  602. ***************************************************************************/
  603. void SndSAttDecay(BYTE slot)
  604. {
  605. BYTE t1;
  606. t1 = (BYTE)(GetLocPrm(slot, prmAttack) << 4);
  607. t1 |= GetLocPrm(slot, prmDecay) & 0xf;
  608. SndOutput((BYTE)(0x60 | offsetSlot[slot]), t1);
  609. }
  610. /****************************************************************************
  611. * @doc INTERNAL
  612. *
  613. * @api void | SndSSusRelease | Sets the SUSTAIN and RELEASE values.
  614. *
  615. * @parm BYTE | slot | Specifies which slot to set.
  616. *
  617. * @rdesc There is no return value.
  618. ***************************************************************************/
  619. void SndSSusRelease(BYTE slot)
  620. {
  621. BYTE t1;
  622. t1 = (BYTE)(GetLocPrm(slot, prmSustain) << 4);
  623. t1 |= GetLocPrm(slot, prmRelease) & 0xf;
  624. SndOutput((BYTE)(0x80 | offsetSlot[slot]), t1);
  625. }
  626. /****************************************************************************
  627. * @doc INTERNAL
  628. *
  629. * @api void | SndWaveSelect | Sets the wave-select parameter.
  630. *
  631. * @parm BYTE | slot | Specifies which slot to set.
  632. *
  633. * @rdesc There is no return value.
  634. ***************************************************************************/
  635. void SndWaveSelect(BYTE slot)
  636. {
  637. BYTE wave;
  638. wave = (BYTE)(GetLocPrm(slot, prmWaveSel) & 0x03);
  639. SndOutput((BYTE)(0xE0 | offsetSlot[slot]), wave);
  640. }
  641. /****************************************************************************
  642. * @doc INTERNAL
  643. *
  644. * @api void | SndSetAllPrm | Transfers all the parameters from slot <p slot>
  645. * to the chip.
  646. *
  647. * @parm BYTE | slot | Specifies which slot to set.
  648. *
  649. * @rdesc There is no return value.
  650. ***************************************************************************/
  651. void SndSetAllPrm(BYTE slot)
  652. {
  653. /* global am-depth and vib-depth settings */
  654. SndSAmVibRhythm();
  655. /* note sel is always false */
  656. SndSNoteSel(FALSE);
  657. /* slot-specific parameters */
  658. /* initialise volume to minimum to avoid clicks if the note is
  659. * off but still playing (during decay phase).
  660. *
  661. * only applies to carrier slots.
  662. */
  663. if (operSlot[slot]) {
  664. /* its a carrier slot */
  665. slotAtten[slot] = 0x3f; // max attenuation
  666. }
  667. SndSKslLevel(slot);
  668. SndSFeedFm(slot);
  669. SndSAttDecay(slot);
  670. SndSSusRelease(slot);
  671. SndSAVEK(slot);
  672. SndWaveSelect(slot);
  673. }
  674. /* --- setting slot parameters ------------------ */
  675. /****************************************************************************
  676. * @doc INTERNAL
  677. *
  678. * @api void | SetSlotParam | Sets the 14 parameters (13 in <p param>,
  679. * 1 in <p waveSel>) of slot <p slot>. Updates both the parameter array
  680. * and the chip.
  681. *
  682. * @parm BYTE | slot | Specifies which slot to set.
  683. *
  684. * @parm NPBYTE | param | Pointer to the new parameter array.
  685. *
  686. * @parm BYTE | waveSel | The new waveSel value.
  687. *
  688. * @rdesc There is no return value.
  689. ***************************************************************************/
  690. void SetSlotParam(BYTE slot, NPOPERATOR pOper, BYTE waveSel)
  691. {
  692. LPBYTE ptr;
  693. ptr = &paramSlot[slot][0];
  694. *ptr++ = pOper->ksl;
  695. *ptr++ = pOper->freqMult;
  696. *ptr++ = pOper->feedBack;
  697. *ptr++ = pOper->attack;
  698. *ptr++ = pOper->sustLevel;
  699. *ptr++ = pOper->sustain;
  700. *ptr++ = pOper->decay;
  701. *ptr++ = pOper->release;
  702. *ptr++ = pOper->output;
  703. *ptr++ = pOper->am;
  704. *ptr++ = pOper->vib;
  705. *ptr++ = pOper->ksr;
  706. *ptr++ = pOper->fm;
  707. *ptr = waveSel & 0x3;
  708. // set default volume settings
  709. slotAtten[slot] = 0;
  710. SndSetAllPrm(slot);
  711. }
  712. /*
  713. * set this voice up to the correct parameters for a timbre
  714. * copy the parameters to the slot array and write them to the
  715. * chip
  716. *
  717. */
  718. void SetVoiceTimbre(BYTE voice, NPTIMBRE pTimbre)
  719. {
  720. if (voice < BD) { // melodic only
  721. SetSlotParam(slotVoice[voice][0], &pTimbre->op0, pTimbre->wave0);
  722. SetSlotParam(slotVoice[voice][1], &pTimbre->op1, pTimbre->wave1);
  723. }
  724. else if (voice == BD) { // bass drum
  725. SetSlotParam(slotPerc[0][0], &pTimbre->op0, pTimbre->wave0);
  726. SetSlotParam(slotPerc[0][1], &pTimbre->op1, pTimbre->wave1);
  727. } else { // percussion, 1 slot
  728. SetSlotParam(slotPerc[voice - BD][0], &pTimbre->op0, pTimbre->wave0);
  729. }
  730. }
  731. /* --- frequency calculation -------------------- */
  732. /* convert the given pitch (0 .. 95) into a frequency
  733. * and write to the chip.
  734. *
  735. * this will turn the note on if keyon is true.
  736. */
  737. VOID SetFreq(BYTE voice, BYTE pitch, BYTE keyOn)
  738. {
  739. WORD FNum;
  740. BYTE t1;
  741. // remember the keyon and pitch of the voice
  742. voiceKeyOn[voice] = keyOn;
  743. notePitch[voice] = pitch;
  744. pitch += halfToneOffset[voice];
  745. if (pitch > 95)
  746. pitch = 95;
  747. // get the FNum for the voice
  748. FNum = * (fNumFreqPtr[voice] + pitch % 12);
  749. // output the FNum, KeyOn and Block values
  750. SndOutput((BYTE)(0xA0 | voice), (BYTE)FNum); // FNum bits 0 - 7 (D0 - D7)
  751. t1 = (BYTE)(keyOn ? 32 : 0); // Key On (D5)
  752. t1 += (pitch / 12 << 2); // Block (D2 - D4)
  753. t1 += (0x3 & (FNum >> 8)); // FNum bits 8 - 9 (D0 - D1)
  754. SndOutput((BYTE)(0xB0 | voice), t1);
  755. }
  756. /****************************************************************************
  757. * @doc INTERNAL
  758. *
  759. * @api void | ChangePitch | This routine sets the <t halfToneOffset[]> and
  760. * <t fNumFreqPtr[]> arrays. These two global variables are used to
  761. * determine the frequency variation to use when a note is played.
  762. *
  763. * @parm BYTE | voice | Specifies which voice to use.
  764. *
  765. * @parm WORD | pitchBend | Specifies the pitch bend value (0 to 0x3fff,
  766. * where 0x2000 is exact tuning).
  767. *
  768. * @rdesc There is no return value.
  769. ***************************************************************************/
  770. void ChangePitch(BYTE voice, WORD pitchBend)
  771. {
  772. int t1;
  773. int t2;
  774. int delta;
  775. int pitchrange;
  776. /* pitch bend range 0-3fff is +-PITCHRANGE semitones. We move
  777. * NR_STEP_PITCH steps per semitone.
  778. * so the bend range is +- (PITCHRANGE * NR_STEP_PITCH) steps.
  779. */
  780. pitchrange = PITCHRANGE * NR_STEP_PITCH;
  781. t1 = (int)(((long)((int)pitchBend - MID_PITCH) * pitchrange) / MID_PITCH);
  782. if (t1 < 0)
  783. {
  784. t2 = NR_STEP_PITCH - 1 - t1;
  785. halfToneOffset[voice] = -(t2 / NR_STEP_PITCH);
  786. delta = (t2 - NR_STEP_PITCH + 1) % NR_STEP_PITCH;
  787. if (delta) {
  788. delta = NR_STEP_PITCH - delta;
  789. }
  790. }
  791. else
  792. {
  793. halfToneOffset[voice] = t1 / NR_STEP_PITCH;
  794. delta = t1 % NR_STEP_PITCH;
  795. }
  796. fNumFreqPtr[voice] = fNumNotes[delta];
  797. }
  798. /****************************************************************************
  799. * @doc INTERNAL
  800. *
  801. * @api void | SetVoicePitch | Changes the pitch value of a voice. Does
  802. * not affect the percussive voices, except for the bass drum. The change
  803. * takes place immediately.
  804. *
  805. * @parm BYTE | voice | Specifies which voice to set.
  806. *
  807. * @parm WORD | pitchBend | Specifies the new pitch bend value (0 to 0x3fff,
  808. * where 0x2000 == exact tuning).
  809. *
  810. * @comm The variation in pitch is a function of the previous call to
  811. * <f SetPitchRange> and the value of <p pitchBend>. A value of 0 means
  812. * -half-tone * pitchRangeStep, 0x2000 means no variation (exact pitch) and
  813. * 0x3fff means +half-tone * pitchRangeStep.
  814. *
  815. * @rdesc There is no return value.
  816. ***************************************************************************/
  817. void SetVoicePitch(BYTE voice, WORD pitchBend)
  818. {
  819. if (voice <= BD) { // melodic and bass drum voices
  820. if (pitchBend > MAX_PITCH) {
  821. pitchBend = MAX_PITCH;
  822. }
  823. ChangePitch(voice, pitchBend);
  824. SetFreq(voice, notePitch[voice], voiceKeyOn[voice]);
  825. }
  826. }
  827. /* --- volume calculation ------------------------ */
  828. /*
  829. * set the attenuation for a slot (combine the channel attenuation
  830. * setting with the key velocity).
  831. */
  832. VOID SetVoiceAtten(BYTE voice, BYTE bChannel, BYTE bVelocity)
  833. {
  834. BYTE bAtten;
  835. BYTE slot;
  836. PBYTE slots;
  837. // scale up the volume since the patch maps are too quiet
  838. //bVelocity = loudervol[bVelocity];
  839. /*
  840. * set channel attenuation
  841. */
  842. bAtten = gbVelocityAtten[bVelocity >> 2] + gbChanAtten[bChannel];
  843. /*
  844. * add on any global (volume-setting) attenuation
  845. */
  846. bAtten += wSynthAtten;
  847. /* save this for each non-modifier slot */
  848. if (voice <= BD) { // melodic voice
  849. slots = slotVoice[voice];
  850. slotAtten[slots[1]] = bAtten;
  851. SndSKslLevel(slots[1]);
  852. if (!GetLocPrm(slots[0], prmFm)) {
  853. // additive synthesis: set volume of first slot too
  854. slotAtten[slots[0]] = bAtten;
  855. SndSKslLevel(slots[0]);
  856. }
  857. }
  858. else { // percussive voice
  859. slot = slotPerc[voice - BD][0];
  860. slotAtten[slot] = bAtten;
  861. SndSKslLevel(slot);
  862. }
  863. }
  864. /* adjust each slot attenuation to allow for a global volume
  865. * change - note that we only need to change the
  866. * carrier, not the modifier slots.
  867. *
  868. * change for channel bChannel, or all channels if bChannel is
  869. * 0xff
  870. */
  871. VOID ChangeAtten(BYTE bChannel, int iChangeAtten)
  872. {
  873. BYTE voice;
  874. BYTE slot;
  875. PBYTE slots;
  876. /* find voices using this channel */
  877. for (voice = 0; voice < NUMVOICES; voice++) {
  878. if ((voices[voice].channel == bChannel) || (bChannel == 0xff)) {
  879. if (voice <= BD) {
  880. /* melodic voice */
  881. slots = slotVoice[voice];
  882. slotAtten[slots[1]] += iChangeAtten;
  883. SndSKslLevel(slots[1]);
  884. if (!GetLocPrm(slots[0], prmFm)) {
  885. // additive synthesis: set volume of first slot too
  886. slotAtten[slots[0]] += iChangeAtten;
  887. SndSKslLevel(slots[0]);
  888. }
  889. } else {
  890. slot = slotPerc[voice - BD][0];
  891. slotAtten[slot] += iChangeAtten;
  892. SndSKslLevel(slot);
  893. }
  894. }
  895. }
  896. }
  897. /* --- note on/off ------------------------------- */
  898. /* switch off the note a given voice is playing */
  899. void NoteOff(BYTE voice)
  900. {
  901. if (voice < BD) {
  902. /* melodic voice */
  903. SetFreq(voice, notePitch[voice], 0);
  904. } else {
  905. percBits &= ~percMasks[voice-BD];
  906. SndSAmVibRhythm();
  907. }
  908. }
  909. /* switch on a voice at a given note (0 - 127, where 60 is middle c) */
  910. void NoteOn(BYTE voice, BYTE bNote)
  911. {
  912. BYTE bPitch;
  913. /* convert note to chip pitch */
  914. if (bNote < (MID_C - CHIP_MID_C)) {
  915. bPitch = 0;
  916. } else {
  917. bPitch = bNote - (MID_C - CHIP_MID_C);
  918. }
  919. if (voice < BD) {
  920. /* melodic voice */
  921. /* set frequency and start note */
  922. SetFreq(voice, bPitch, 1);
  923. } else {
  924. /*
  925. * nb we don't change the pitch of some percussion instruments.
  926. *
  927. * also note that for percussive instruments (including BD),
  928. * the note-on setting should always be 0. You switch the percussion
  929. * on by writing to the AmVibRhythm register.
  930. */
  931. if (voice == BD) {
  932. SetFreq(voice, bPitch, 0);
  933. } else if (voice == TOM) {
  934. /*
  935. * for best sounds, we do change the TOM freq, but we always keep
  936. * the SD 7 semi-tones above TOM.
  937. */
  938. SetFreq(TOM, bPitch, 0);
  939. SetFreq(SD, (BYTE)(bPitch + TOM_TO_SD), 0);
  940. }
  941. /* other instruments never change */
  942. percBits |= percMasks[voice - BD];
  943. SndSAmVibRhythm();
  944. }
  945. }
  946. /* -- voice allocation -------- */
  947. /*
  948. * find the voice that is currently playing a given channel/note pair
  949. * (if any)
  950. */
  951. BYTE
  952. FindVoice(BYTE bNote, BYTE bChannel)
  953. {
  954. BYTE i;
  955. for (i = 0; i < (BYTE)NUMVOICES; i++) {
  956. if ((voices[i].alloc) && (voices[i].note == bNote)
  957. && (voices[i].channel == bChannel)) {
  958. voices[i].dwTimeStamp = dwAge++;
  959. return(i);
  960. }
  961. }
  962. /* no voice is playing this */
  963. return(0xff);
  964. }
  965. /*
  966. * mark a voice as unused
  967. */
  968. VOID FreeVoice(voice)
  969. {
  970. voices[voice].alloc = 0;
  971. }
  972. /*
  973. * GetNewVoice - allocate a voice to play this note. if no voices are
  974. * free, re-use the note with the oldest timestamp.
  975. */
  976. BYTE GetNewVoice(BYTE patch, BYTE note, BYTE channel)
  977. {
  978. BYTE i;
  979. BYTE voice;
  980. BYTE bVoiceToUse, bVoiceSame, bVoiceOldest;
  981. DWORD dwOldestTime = dwAge + 1; // init to past current "time"
  982. DWORD dwOldestSame = dwAge + 1;
  983. DWORD dwOldestOff = dwAge + 1;
  984. if (patches[patch].mode) { // it's a percussive patch
  985. voice = patches[patch].percVoice; // use fixed percussion voice
  986. voices[voice].alloc = TRUE;
  987. voices[voice].note = note;
  988. voices[voice].channel = channel;
  989. voices[voice].dwTimeStamp = MAKELONG(patch, 0);
  990. SetVoiceTimbre(voice, &patches[patch]);
  991. return voice;
  992. }
  993. bVoiceToUse = bVoiceSame = bVoiceOldest = 0xff;
  994. // find a free melodic voice to use
  995. for (i = 0; i < (BYTE)NUMMELODIC; i++) { // it's a melodic patch
  996. if (!voices[i].alloc) {
  997. if (voices[i].dwTimeStamp < dwOldestOff) {
  998. bVoiceToUse = i;
  999. dwOldestOff = voices[i].dwTimeStamp;
  1000. }
  1001. } else if (voices[i].channel == channel) {
  1002. if (voices[i].dwTimeStamp < dwOldestSame) {
  1003. dwOldestSame = voices[i].dwTimeStamp;
  1004. bVoiceSame = i;
  1005. }
  1006. } else if (voices[i].dwTimeStamp < dwOldestTime) {
  1007. dwOldestTime = voices[i].dwTimeStamp;
  1008. bVoiceOldest = i; // remember oldest one to steal
  1009. }
  1010. }
  1011. // choose a free voice if we have found one. If not, choose the
  1012. // oldest voice of the same channel. if none, choose the oldest voice.
  1013. if (bVoiceToUse == 0xff) {
  1014. if (bVoiceSame != 0xff) {
  1015. bVoiceToUse = bVoiceSame;
  1016. } else {
  1017. bVoiceToUse = bVoiceOldest;
  1018. }
  1019. }
  1020. if (voices[bVoiceToUse].alloc) { // if we stole it, turn it off
  1021. NoteOff(bVoiceToUse);
  1022. }
  1023. voices[bVoiceToUse].alloc = 1;
  1024. voices[bVoiceToUse].note = note;
  1025. voices[bVoiceToUse].channel = channel;
  1026. voices[bVoiceToUse].dwTimeStamp = dwAge++;
  1027. SetVoiceTimbre(bVoiceToUse, &patches[patch]);
  1028. return bVoiceToUse;
  1029. }
  1030. /* --- externally-called functions ------------------------------ */
  1031. /*
  1032. * Adlib_NoteOn - This turns a note on. (Including drums, with
  1033. * a patch # of the drum Note + 128)
  1034. *
  1035. * inputs
  1036. * BYTE bPatch - MIDI patch number
  1037. * BYTE bNote - MIDI note number
  1038. * BYTE bChannel - MIDI channel #
  1039. * BYTE bVelocity - Velocity #
  1040. * short iBend - current pitch bend from -32768, to 32767
  1041. * returns
  1042. * none
  1043. */
  1044. VOID NEAR PASCAL Adlib_NoteOn (BYTE bPatch,
  1045. BYTE bNote, BYTE bChannel, BYTE bVelocity,
  1046. short iBend)
  1047. {
  1048. BYTE voice;
  1049. WORD wBend;
  1050. if (bVelocity == 0) { // 0 velocity means note off
  1051. Adlib_NoteOff(bPatch, bNote, bChannel);
  1052. return;
  1053. }
  1054. // octave registration for melodic patches
  1055. if (bPatch < 128) {
  1056. bNote += patchKeyOffset[bPatch];
  1057. if ((bNote < 0) || (bNote > 127)) {
  1058. bNote -= patchKeyOffset[bPatch];
  1059. }
  1060. }
  1061. if (bPatch >= 128) {
  1062. /*
  1063. * it's a percussion note
  1064. */
  1065. bNote = bPatch - 128;
  1066. if ((bNote < FIRSTDRUMNOTE) || (bNote > LASTDRUMNOTE)) {
  1067. return;
  1068. }
  1069. /* use the drum patch table to map the note to a given
  1070. * TIMBRE/note pair
  1071. */
  1072. bPatch = drumpatch[bNote - FIRSTDRUMNOTE].patch;
  1073. bNote = drumpatch[bNote - FIRSTDRUMNOTE].note;
  1074. /* each drum patch plays on one specific voice.
  1075. * find that voice
  1076. */
  1077. voice = patches[bPatch].percVoice;
  1078. /* switch note off if playing */
  1079. if (voices[voice].alloc) {
  1080. NoteOff(voice);
  1081. }
  1082. /* call GetNewVoice to set the voice params and timestamp
  1083. * even if we found it.
  1084. */
  1085. voice = GetNewVoice(bPatch, bNote, bChannel);
  1086. } else {
  1087. /* switch note off if it's playing */
  1088. if ( (voice = FindVoice(bNote, bChannel)) != 0xFF ) {
  1089. NoteOff(voice);
  1090. } else {
  1091. voice = GetNewVoice(bPatch, bNote, bChannel);
  1092. }
  1093. }
  1094. /* convert the velocity to an attenuation setting, and
  1095. * write that to the device
  1096. */
  1097. SetVoiceAtten(voice, bChannel, bVelocity);
  1098. /*
  1099. * apply pitch bend. note that we are passed a pitch bend in the
  1100. * range 8000-7fff, but our code assumes 0-3fff, so we convert here.
  1101. */
  1102. wBend = (((WORD)iBend + 0x8000) >> 2) & 0x3fff;
  1103. SetVoicePitch(voice, wBend);
  1104. // play the note
  1105. NoteOn(voice, bNote);
  1106. }
  1107. /* Adlib_NoteOff - This turns a note off. (Including drums,
  1108. * with a patch # of the drum note + 128)
  1109. *
  1110. * inputs
  1111. * BYTE bPatch - MIDI patch #
  1112. * BYTE bNote - MIDI note number
  1113. * BYTE bChannel - MIDI channel #
  1114. * returns
  1115. * none
  1116. */
  1117. VOID FAR PASCAL Adlib_NoteOff (BYTE bPatch,
  1118. BYTE bNote, BYTE bChannel)
  1119. {
  1120. BYTE bVoice;
  1121. if (bPatch > 127) {
  1122. /* drum note. These all use a fixed voice */
  1123. if ((bNote < FIRSTDRUMNOTE) || (bNote > LASTDRUMNOTE)) {
  1124. return;
  1125. }
  1126. /* use the drum patch table to map the note to a given
  1127. * TIMBRE/note pair
  1128. */
  1129. bPatch = drumpatch[bNote - FIRSTDRUMNOTE].patch;
  1130. bNote = drumpatch[bNote - FIRSTDRUMNOTE].note;
  1131. bVoice = patches[bPatch].percVoice;
  1132. /* switch note off if playing our patch */
  1133. if (LOWORD(voices[bVoice].dwTimeStamp) == bPatch) {
  1134. NoteOff(bVoice);
  1135. }
  1136. } else {
  1137. bVoice = FindVoice(bNote, bChannel);
  1138. if (bVoice != 0xff) {
  1139. if (voices[bVoice].note) {
  1140. NoteOff(bVoice);
  1141. FreeVoice(bVoice);
  1142. }
  1143. }
  1144. }
  1145. }
  1146. /* Adlib_AllNotesOff - turn off all notes
  1147. *
  1148. * inputs - none
  1149. * returns - none
  1150. */
  1151. VOID Adlib_AllNotesOff(void)
  1152. {
  1153. BYTE i;
  1154. for (i = 0; i < NUMVOICES; i++) {
  1155. NoteOff(i);
  1156. }
  1157. }
  1158. /* Adlib_NewVolume - This should be called if a volume level
  1159. * has changed. This will adjust the levels of all the playing
  1160. * voices.
  1161. *
  1162. * inputs
  1163. * WORD wLeft - left attenuation (1.5 db units)
  1164. * WORD wRight - right attenuation (ignore if mono)
  1165. * returns
  1166. * none
  1167. */
  1168. VOID FAR PASCAL Adlib_NewVolume (WORD wLeft, WORD wRight)
  1169. {
  1170. /* ignore the right attenuation since this is a mono device */
  1171. int iChange;
  1172. wLeft = min(wLeft, wRight) << 1;
  1173. iChange = wLeft - wSynthAtten;
  1174. wSynthAtten = wLeft;
  1175. /* change attenuation for all channels */
  1176. ChangeAtten(0xff, iChange);
  1177. }
  1178. /* Adlib_ChannelVolume - set the volume level for an individual channel.
  1179. *
  1180. * inputs
  1181. * BYTE bChannel - channel number to change
  1182. * WORD wAtten - attenuation in 1.5 db units
  1183. *
  1184. * returns
  1185. * none
  1186. */
  1187. VOID FAR PASCAL Adlib_ChannelVolume(BYTE bChannel, WORD wAtten)
  1188. {
  1189. int iChange;
  1190. iChange = wAtten - gbChanAtten[bChannel];
  1191. gbChanAtten[bChannel] = (BYTE)wAtten;
  1192. /* change attenuation for this channel */
  1193. ChangeAtten(bChannel, iChange);
  1194. }
  1195. /* Adlib_SetPan - set the left-right pan position.
  1196. *
  1197. * inputs
  1198. * BYTE bChannel - channel number to alter
  1199. * BYTE bPan - 0 for left, 127 for right or somewhere in the middle.
  1200. *
  1201. * returns - none
  1202. *
  1203. * does nothing - this is a mono device
  1204. */
  1205. VOID FAR PASCAL Adlib_SetPan(BYTE bChannel, BYTE bPan)
  1206. {
  1207. /* do nothing */
  1208. }
  1209. /* Adlib_PitchBend - This pitch bends a channel.
  1210. *
  1211. * inputs
  1212. * BYTE bChannel - channel
  1213. * short iBend - Values from -32768 to 32767, being
  1214. * -2 to +2 half steps
  1215. * returns
  1216. * none
  1217. */
  1218. VOID NEAR PASCAL Adlib_PitchBend (BYTE bChannel, short iBend)
  1219. {
  1220. BYTE i;
  1221. WORD w;
  1222. /* note that our code expects 0 - 0x3fff not 0x8000 - 0x7fff */
  1223. w = (((WORD) iBend + 0x8000) >> 2) & 0x3fff;
  1224. for (i = 0; i < NUMVOICES; i++) {
  1225. if ((voices[i].alloc) && (voices[i].channel == bChannel)) {
  1226. SetVoicePitch(i, w);
  1227. }
  1228. }
  1229. }
  1230. /* Adlib_BoardInit - initialise board and load patches as necessary.
  1231. *
  1232. * inputs - none
  1233. * returns - 0 for success or the error code
  1234. */
  1235. WORD Adlib_BoardInit(void)
  1236. {
  1237. BYTE i;
  1238. wSynthAtten = 0;
  1239. /* build the freq table */
  1240. InitFNums();
  1241. /* silence and free all voices */
  1242. for (i = 0; i <= 8; i++) {
  1243. SoundChut(i);
  1244. FreeVoice(i);
  1245. }
  1246. /* switch to percussive mode and set fixed frequencies */
  1247. SetFreq(TOM, TOM_PITCH, 0);
  1248. SetFreq(SD, SD_PITCH, 0);
  1249. percBits = 0;
  1250. SndSAmVibRhythm();
  1251. /* init all slots to sine-wave */
  1252. for (i= 0; i < 18; i++) {
  1253. SndOutput((BYTE)(0xE0 | offsetSlot[i]), 0);
  1254. }
  1255. /* enable wave-form selection */
  1256. SndOutput(1, 0x20);
  1257. LoadPatches();
  1258. LoadDrumPatches();
  1259. // don't initialise - the data is static and will thus
  1260. // be initialised to 0 at load time. no other change should be made
  1261. // since the mci sequencer will not re-send channel volume change
  1262. // messages.
  1263. //
  1264. // /* init all channels to loudest */
  1265. // for (i = 0; i < NUMCHANNELS; i++) {
  1266. // gbChanAtten[i] = 4;
  1267. // }
  1268. return(0);
  1269. }
  1270. /*
  1271. * Adlib_BoardReset - silence the board and set all voices off.
  1272. */
  1273. VOID Adlib_BoardReset(void)
  1274. {
  1275. BYTE i;
  1276. /* silence and free all voices */
  1277. for (i = 0; i <= 8; i++) {
  1278. SoundChut(i);
  1279. FreeVoice(i);
  1280. }
  1281. /* switch to percussive mode and set fixed frequencies */
  1282. SetFreq(TOM, TOM_PITCH, 0);
  1283. SetFreq(SD, SD_PITCH, 0);
  1284. percBits = 0;
  1285. SndSAmVibRhythm();
  1286. }