home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / c / playadlb / adlib.c < prev    next >
C/C++ Source or Header  |  1991-10-05  |  23KB  |  976 lines

  1. /**
  2.     ADLIB.C, low level sound driver V1.03
  3.     ===== To be used with OUTCHIP.ASM file. =====
  4.  
  5.     Copyright Ad Lib Inc, 1988, 1989
  6.  
  7.     1988/06/22, Dale Glowinski, Marc Savary, Ad Lib Inc.
  8.     1989/04/20, Marc savary.
  9.  
  10.  
  11.  
  12.  
  13.     The following routines are public (see each routine for further    
  14.     documentation):
  15.  
  16.         SoundColdInit( port)
  17.         SoundWarmInit()
  18.         SetMode( mode)
  19.         Set3812( state)
  20.         SetPitchRange( pR)
  21.         SetGParam( amD, vibD, nSel)
  22.         SetVoiceTimbre( voice, paramArray)
  23.         SetVoiceVolume( voice, volume)
  24.         SetVoicePitch( voice, pitchBend)
  25.         NoteOn( voice, pitch)
  26.         NoteOff( voice)
  27.  
  28. **/
  29. #include <dos.h>
  30. #include "adlib.h"
  31.  
  32. /*
  33.     In percussive mode, the last 4 voices ( SD TOM HH CYMB) are created
  34.     using melodic voices 7 & 8. A noise generator use channels 7 & 8
  35.     frequency information for creating rhythm instruments. Best result
  36.     are obtained by setting TOM two octaves below mid C and SD 7 half-tones
  37.     above TOM.
  38.     In this implementation, only the TOM pitch may vary, with the SD always
  39.     set 7 half-tones above.
  40. */
  41.  
  42. #define TOM_PITCH    24                /* best frequency, in range of 0 to 95 */
  43. #define TOM_TO_SD    7                /* 7 half-tones between voice 7 & 8 */
  44. #define SD_PITCH    (TOM_PITCH + TOM_TO_SD)
  45.  
  46. #define NR_STEP_PITCH 25            /* 25 steps within a half-tone for pitch bend */
  47.  
  48. #define GetLocPrm( slot, prm)( (unsigned)paramSlot[ slot][ prm])
  49. #define HighByte( word) ( ((char *)(&word))[ 1])    /* 80x86-8 only .. */
  50. #define RhythmMode()     (percussion)
  51.  
  52. typedef char    SLOT_PARAM;
  53.  
  54.  
  55. /*
  56. -----------------------------------------------------------------
  57. */
  58.  
  59. unsigned genAddr;                        /* address of sound chip */
  60.  
  61. static char percBits;                    /* control bits of percussive voices */
  62. static char percMasks[] = {
  63.     0x10, 0x08, 0x04, 0x02, 0x01
  64.     };
  65.  
  66. static char notePitch[ 11];            /* pitch of last note-on of each voice */
  67. static char voiceKeyOn[ 11];            /* state of keyOn bit of each voice */
  68.  
  69. static char noteDIV12[ 96];            /* table of (0..95) DIV 12 */
  70. static char noteMOD12[ 96];            /* table of (0..95) MOD 12 */
  71.  
  72. static char slotRelVolume[ 18];        /* relative volume of slots */
  73.  
  74.  
  75. /* definition of the ELECTRIC-PIANO voice (opr0 & opr1) */
  76. static char pianoParamsOp0[ nbLocParam] = {
  77.     1, 1, 3, 15, 5, 0, 1, 3, 15, 0, 0, 0, 1, 0 };
  78. static char pianoParamsOp1[ nbLocParam] = {
  79.     0, 1, 1, 15, 7, 0, 2, 4, 0, 0, 0, 1, 0, 0 };
  80.  
  81.     /* definition of default percussive voices: */
  82. static char bdOpr0[] = { 0,  0, 0, 10,  4, 0, 8, 12, 11, 0, 0, 0, 1, 0 };
  83. static char bdOpr1[] = { 0,  0, 0, 13,  4, 0, 6, 15,  0, 0, 0, 0, 1, 0 };
  84. static char sdOpr[] =  { 0, 12, 0, 15, 11, 0, 8,  5,  0, 0, 0, 0, 0, 0 };
  85. static char tomOpr[] = { 0,  4, 0, 15, 11, 0, 7,  5,  0, 0, 0, 0, 0, 0 };
  86. static char cymbOpr[] ={ 0,  1, 0, 15, 11, 0, 5,  5,  0, 0, 0, 0, 0, 0 };
  87. static char hhOpr[] =  { 0,  1, 0, 15, 11, 0, 7,  5,  0, 0, 0, 0, 0, 0 };
  88.  
  89. static SLOT_PARAM paramSlot[ 18][ nbLocParam];    /* all the parameters of slots...  */
  90.  
  91. static char    amDepth;            /* chip global parameters .. */
  92. static char    vibDepth;            /* ... */
  93. static char    noteSel;            /* ... */
  94. static char    percussion;            /* percussion mode parameter */
  95.  
  96. /* Slot numbers as a function of the voice and the operator.
  97.     ( melodic only)
  98. */
  99. char slotVoice[] [ 2] = {
  100.     {0, 3},        /* voix 0 */
  101.     {1, 4},        /* 1 */
  102.     {2, 5},        /* 2 */
  103.     {6, 9},        /* 3 */
  104.     {7, 10},    /* 4 */
  105.     {8, 11},    /* 5 */
  106.     {12, 15},    /* 6 */
  107.     {13, 16},    /* 7 */
  108.     {14, 17}    /* 8 */
  109. };
  110.  
  111.  
  112. /* Slot numbers for the percussive voices.
  113.     0 indicates that there is only one slot.
  114. */
  115. char slotPerc[] [ 2] = {
  116.     {12, 15},        /* Bass Drum: slot 12 et 15 */
  117.     {16, 0},        /* SD: slot 16 */
  118.     {14, 0},        /* TOM: slot 14 */
  119.     {17, 0},        /* TOP-CYM: slot 17 */
  120.     {13, 0}            /* HH: slot 13 */
  121. };
  122.  
  123. /* 
  124.     This table gives the offset of each slot within the chip.
  125.     offset = fn( slot)
  126. */
  127. static char offsetSlot[] = {
  128.      0,  1,  2,  3,  4,  5,
  129.      8,  9, 10, 11, 12, 13,
  130.     16, 17, 18, 19, 20, 21
  131. };
  132.  
  133.  
  134. /* This table indicates if the slot is a modulator (0) or a carrier (1).
  135.     opr = fn( slot)
  136. */
  137. static char operSlot[] = {
  138.     0, 0, 0,        /* 1 2 3 */
  139.     1, 1, 1,        /* 4 5 6 */
  140.     0, 0, 0,         /* 7 8 9 */
  141.     1, 1, 1,         /* 10 11 12 */
  142.     0, 0, 0,         /* 13 14 15 */
  143.     1, 1, 1,        /* 16 17 18 */
  144. };
  145.  
  146. /* This table gives the voice number associated with each slot.
  147.     (melodic mode only)
  148.     voice = fn( slot)
  149. */
  150. static char voiceSlot[] = {
  151.     0, 1, 2,
  152.     0, 1, 2,
  153.     3, 4, 5,
  154.     3, 4, 5,
  155.     6, 7, 8,
  156.     6, 7, 8,
  157. };
  158.  
  159.  
  160. static unsigned fNumNotes[ NR_STEP_PITCH] [ 12];
  161. static int     halfToneOffset[ 11];
  162. static unsigned * fNumFreqPtr[ 11];
  163. static int     pitchRange;            /* pitch variation, half-tone [+1,+12] */
  164. static int     pitchRangeStep;        /* == pitchRange * NR_STEP_PITCH */
  165. static int        modeWaveSel;        /* != 0 if used with the 'wave-select' parameters */
  166.  
  167.  
  168. extern SndOutput();            /* in file OUTCHIP.ASM */
  169.  
  170.  
  171.  
  172. /*
  173. ----------------------------------------------------------
  174. */
  175.  
  176.  
  177.  
  178.  
  179. /*
  180.     Must be called for start-up initialisation.
  181.  
  182.     Return 0 if harware not found.
  183. */
  184. int SoundColdInit( port)
  185.     unsigned port;            /* io port address of sound board (0x388) */
  186.     {
  187.     int hardware;
  188.  
  189.     genAddr = port;
  190.     hardware =  BoardInstalled();
  191.     SoundWarmInit();
  192.     return hardware;
  193.     }    /* SoundColdInit() */
  194.  
  195.  
  196. /*
  197. -----------------------------------------------
  198.     Initialize the chip in melodic mode (mode == 0),
  199.     set all 9 voices to electric-piano timbres,
  200.     set the 3 global parameters to zero,
  201.     set the pitch bend range to 1 half-tone,
  202.     set the pitch bend of each voice to 0x2000 (no detune),
  203.     set the volume of each voice to maximum level,
  204.     and enable the wave-select parameter.
  205. -----------------------------------------------
  206. */
  207. SoundWarmInit()
  208.     {
  209.     int i;
  210.  
  211.     InitSlotVolume();
  212.     InitFNums();
  213.     SetMode( 0);                /* melodic mode */
  214.     SetGParam( 0, 0, 0);        /* init global parameters */
  215.     for( i = 0 ; i < 9; i++)
  216.         SoundChut( i);
  217.     SetPitchRange( 1);            /* default pitch range is 1 half-tone */
  218.     Set3812( 1);
  219.     }    /* SoundWarmInit() */
  220.  
  221.  
  222.  
  223. /*
  224. ---------------------------------------------
  225.     Put the chip in melodic mode (mode == 0),
  226.     or in percussive mode ( mode != 0).
  227.  
  228.     If the melodic mode is chosen, all voices are
  229.     set to electric-piano, else the first 5 are set
  230.     to electric-piano, and the percussion voices
  231.     to their default timbres.
  232. ---------------------------------------------
  233. */
  234. SetMode( mode)
  235.     int mode;
  236.     {
  237.  
  238.     if( mode){
  239.         SoundChut( BD);
  240.         SoundChut( SD);
  241.         SoundChut( TOM);
  242.         
  243.         /* set the frequency for the last 4 percussion voices: */
  244.         SetFreq( TOM, TOM_PITCH, 0);
  245.         SetFreq( SD, SD_PITCH, 0);
  246.         }
  247.     percussion = mode;
  248.     percBits = 0;
  249.  
  250.     InitSlotParams();
  251.     SndSAmVibRhythm();
  252.     }    /* SetMode() */
  253.  
  254.  
  255.  
  256.  
  257. /*
  258.     Enable (state != 0) / disable (state == 0)
  259.     the wave-select parameters.
  260.  
  261.     If you do not want to use the wave-select parameters, call
  262.     this function with a value of 0 AFTER calling SoundColdInit()
  263.     or SoundWarmInit().
  264. */
  265. Set3812( state)
  266.     {
  267.     int i;
  268.  
  269.     modeWaveSel = state ? 0x20 : 0;
  270.     for( i = 0; i < 18; i++)
  271.         SndOutput( 0xE0 + offsetSlot[ i], 0);
  272.     SndOutput( 1, modeWaveSel);
  273.     }    /* Set3812() */
  274.  
  275.  
  276.  
  277. /*
  278.     Routine to change the pitch bend range. The value can be from
  279.     1 to 12 (in half-tones).
  280.  
  281.     For example, the value 12 means that the pitch bend will 
  282.     range from -12 (pitchBend == 0, see function 'SetVoicePitch()')
  283.     to +12 (pitchBend == 0x3fff) half-tones.
  284.  
  285.     The change will be effective as of the next call to
  286.     'SetVoicePitch()'.
  287. */
  288. SetPitchRange( pR)
  289.     unsigned pR;
  290.     {
  291.     if( pR > 12)
  292.         pR = 12;
  293.     if( pR < 1)
  294.         pR = 1;
  295.     pitchRange = pR;
  296.     pitchRangeStep = pitchRange * NR_STEP_PITCH;
  297.     }    /* SetPitchRange() */
  298.  
  299.  
  300. /*
  301. ----------------------------------------------
  302.     Set the 3 global parameters AmDepth,
  303.     VibDepth & NoteSel
  304.  
  305.     The change takes place immediately.
  306. ----------------------------------------------
  307. */
  308. SetGParam( amD, vibD, nSel)
  309.     int amD, vibD, nSel;
  310.     {
  311.     amDepth = amD;
  312.     vibDepth = vibD;
  313.     noteSel = nSel;
  314.  
  315.     SndSAmVibRhythm();
  316.     SndSNoteSel();
  317.     }    /* SetGParam() */
  318.  
  319.  
  320.  
  321.  
  322.  
  323. /*
  324. -------------------------------------------------
  325.     Set the parameters of the voice 'voice'.
  326.  
  327.     In melodic mode, 'voice' varies from 0 to 8.
  328.     In percussive mode, voices 0 to 5 are melodic
  329.     and 6 to 10 are percussive.
  330.  
  331.     A timbre (melodic or percussive) is defined as follows:
  332.     the 13 first parameters of operator 0 ( ksl, multi, feedBack,
  333.     attack, sustain, eg-typem decay, release, level, am, vib, ksr, fm)
  334.     followed by the 13 parameters of operator 1 (if a percussive voice, all
  335.     the parameters are zero), followed by the wave-select parameter for
  336.     the operators 0 and 1.
  337.  
  338.     'paramArray' is structured as follows:
  339.         struct {
  340.             int opr0Prm[ 13];        first 13 parameters
  341.             int opr1Prm[ 13];        must be 0 if percussive timbre
  342.             int    opr0WaveSel;        last parameter
  343.             int opr1WaveSel;        must be 0 if percussive timbre
  344.         } TimbreDef;
  345.  
  346.     The old timbre files (*.INS) do not contain the parameters
  347.     'opr0WaveSel' and 'opr1WaveSel'. 
  348.     Set these two parameters to zero if you are using the old file
  349.     format.
  350. -------------------------------------------------
  351. */
  352. SetVoiceTimbre( voice, paramArray)
  353.     int voice, * paramArray;
  354.     {
  355.     int wave0, wave1;
  356.     int * prm1, * wavePtr;
  357.  
  358.     wavePtr = paramArray + 2 * ( nbLocParam -1);
  359.     wave0 = * wavePtr++;
  360.     wave1 = * wavePtr;
  361.     prm1 = paramArray + nbLocParam -1;
  362.  
  363.     if( !RhythmMode() || voice < BD) {    /* melodic only */
  364.         SetSlotParam( (int)slotVoice[ voice][ 0], paramArray, wave0);
  365.         SetSlotParam( (int)slotVoice[ voice][ 1], prm1, wave1);
  366.         }
  367.     else if( voice == BD) {    /* Bass Drum */
  368.         SetSlotParam( (int)slotPerc[ 0][ 0], paramArray, wave0);
  369.         SetSlotParam( (int)slotPerc[ 0][ 1], prm1, wave1);
  370.         }
  371.     else    /* percussion, 1 slot */
  372.         SetSlotParam( (int)slotPerc[ voice -BD][ 0], paramArray, wave0);
  373.     }   /* SetVoiceTimbre() */
  374.  
  375.  
  376.  
  377.  
  378. /*
  379. --------------------------------------------------
  380.     Set the volume of the voice 'voice' to 'volume'.
  381.  
  382.     The resulting output level is (timbreVolume * volume / 127).
  383.     The change takes place immediately.
  384.  
  385.     0 <= volume <= 127
  386. --------------------------------------------------
  387. */
  388. SetVoiceVolume( voice, volume)
  389.     unsigned volume;            /* 0 - 0x7f */
  390. {
  391.     int slot;
  392.     char * slots;
  393.  
  394. #if 1
  395.     if( !RhythmMode() || voice < BD)
  396.         slot = slotVoice[ voice][ 1];
  397.     else
  398.         slot = slotPerc[ voice -BD][ voice == BD ? 1 : 0];
  399.  
  400.     if( volume > MAX_VOLUME)
  401.         volume = MAX_VOLUME;
  402.     slotRelVolume[ slot] = volume;
  403.     SndSKslLevel( slot);
  404. #else    /* code that modify the two oper. volume of an additive sound: */
  405.     if( volume > MAX_VOLUME)
  406.         volume = MAX_VOLUME;
  407.  
  408.     if( !RhythmMode() || voice <= BD) {
  409.         slots = slotVoice[ voice];
  410.         slotRelVolume[ slots[ 1]] = volume;
  411.         SndSKslLevel( slots[ 1]);
  412.         if( !GetLocPrm( slots[ 0], prmFm)) {
  413.             /* additive syntesis: set volume of first slot too */
  414.             slotRelVolume[ slots[ 0]] = volume;
  415.             SndSKslLevel( slots[ 0]);
  416.             }
  417.         }
  418.     else {
  419.         slot = slotPerc[ voice -BD][ 0];
  420.         slotRelVolume[ slot] = volume;
  421.         SndSKslLevel( slot);
  422.         }
  423. #endif
  424. }    /* SetVoiceVolume() */
  425.  
  426.  
  427. /*
  428. -------------------------------------------------
  429.     Change the pitch value of a voice.
  430.  
  431.     The variation in pitch is a function of the previous call
  432.     to 'SetPitchRange()' and the value of 'pitchBend'.
  433.     A value of 0 means -half-tone * pitchRange,
  434.     0x2000 means no variation (exact pitch) and
  435.     0x3fff means +half-tone * pitchRange.
  436.  
  437.     Does not affect the percussive voices, except for the bass drum.
  438.  
  439.     The change takes place immediately.
  440.  
  441.     0 <= pitchBend <= 0x3fff, 0x2000 == exact tuning
  442. -------------------------------------------------
  443. */
  444. SetVoicePitch( voice, pitchBend)
  445.     unsigned voice;
  446.     unsigned pitchBend;
  447. {
  448.     if( ! RhythmMode() || voice <= BD) {
  449.         /* melodic + bass-drum */
  450.         if( pitchBend > MAX_PITCH)
  451.             pitchBend = MAX_PITCH;
  452.         ChangePitch( voice, pitchBend);
  453.         SetFreq( voice, notePitch[ voice], voiceKeyOn[ voice]);
  454.         }
  455. }    /* SetVoicePitch() */
  456.  
  457.  
  458.  
  459. /*
  460. -----------------------------------------------------------
  461.     Routine to start a note playing.
  462.  
  463.     0 <= voice <= 8    in melodic mode,
  464.     0 <= voice <= 10 in percussive mode;
  465.     0 <= pitch <= 127, 60 == MID_C ( the card can play between 12 and 107 )
  466. -----------------------------------------------------------
  467. */
  468. NoteOn( voice, pitch)
  469.     unsigned voice;
  470.     int pitch;            /* 0 - 127 */
  471.     {
  472.     pitch -= ( MID_C - CHIP_MID_C);
  473.     if( pitch < 0)
  474.         pitch = 0;
  475.     
  476.     if( voice < BD || ! RhythmMode())
  477.         /* this is a melodic voice */
  478.         SetFreq( voice, pitch, 1);
  479.     else {
  480.         /* this is a percussive voice */
  481.         if( voice == BD)
  482.             SetFreq( BD, pitch, 0);
  483.         else if( voice == TOM) {
  484.             /* for the last 4 percussions, only the TOM may change in frequency,
  485.                 modifying the three others: */
  486.             SetFreq( TOM, pitch, 0);
  487.             SetFreq( SD, pitch + TOM_TO_SD, 0);    /* f7 = 3 * f8 */
  488.             }
  489.         
  490.         percBits |= percMasks[ voice - BD];
  491.         SndSAmVibRhythm();
  492.         }
  493.     }    /* NoteOn() */
  494.  
  495.  
  496. /*
  497.     Routine to stop playing the note which was started in 'NoteOn()'.
  498.  
  499.     0 <= voice <= 8    in melodic mode,
  500.     0 <= voice <= 10 in percussive mode;
  501. */
  502. NoteOff( voice)
  503.     unsigned voice;    
  504.     {
  505.     if( !RhythmMode() || voice < BD)
  506.         SetFreq( voice, notePitch[ voice], 0); /* shut off */
  507.     else {
  508.         percBits &= ~percMasks[ voice - BD];
  509.         SndSAmVibRhythm();
  510.         }
  511.     }    /* NoteOff() */
  512.  
  513.  
  514.  
  515.  
  516.  
  517. /*
  518. ------------------------------------------------------------------------
  519.     static functions ...
  520. ------------------------------------------------------------------------
  521. */
  522.  
  523.  
  524. /*
  525.     In melodic mode, initialize all voices to electric-pianos.
  526.  
  527.     In percussive mode, initialize the first 6 voices to electric-pianos
  528.     and the percussive voices to their default timbres.
  529. */
  530. static InitSlotParams()
  531. {
  532.     int i;
  533.     
  534.     for( i = 0; i < 18; i++)
  535.         if( operSlot[ i])
  536.             SetCharSlotParam( i, pianoParamsOp1, 0);
  537.         else
  538.             SetCharSlotParam( i, pianoParamsOp0, 0);
  539.     if( RhythmMode()) {
  540.         SetCharSlotParam( 12, bdOpr0, 0);
  541.         SetCharSlotParam( 15, bdOpr1, 0);
  542.         SetCharSlotParam( 16, sdOpr, 0);
  543.         SetCharSlotParam( 14, tomOpr, 0);
  544.         SetCharSlotParam( 17, cymbOpr, 0);
  545.         SetCharSlotParam( 13, hhOpr, 0);
  546.         }
  547. }    /* InitSlotParams() */
  548.  
  549.  
  550.  
  551.  
  552. /*
  553.     Set the volume of all slots.
  554. */
  555. static InitSlotVolume()
  556. {
  557.     int i;
  558.  
  559.     for( i = 0; i < 18; i++)
  560.         slotRelVolume[ i] = MAX_VOLUME;
  561. }    /* InitSlotVolume() */
  562.  
  563.  
  564.  
  565.  
  566. /*
  567.     Return binary value of the frequency 260.44 ( C)
  568.     shifted by +/- numdeltaDemiTon/denDeltaDemiTon multiplied by 8.
  569.  
  570.     If the numerator (numDeltaDemiTon) is positive, the frequency is
  571.     increased; if negative, it is decreased.
  572.  
  573.     Fo = Fb( 1 + 0.06 num /den)
  574.     Fnum8 = Fo * 65536 * 72 / 3.58e6
  575.     
  576.     -100 <= numDeltaDemiTon <= +100
  577.     1 <= denDeltaDemiTon <= 100
  578. */
  579. static long CalcPremFNum( numDeltaDemiTon, denDeltaDemiTon)
  580. {
  581.     long    f8, fNum8, d100;
  582.  
  583.     d100 = denDeltaDemiTon * 100;
  584.     f8 = ( d100 + 6 * numDeltaDemiTon) * (26044L * 2L);    /* 260.44 * 100 * 2 */
  585.     f8 /= d100 * 25;
  586.     fNum8 = f8 * 16384;        /*( 16384L * 9L);    */
  587.     fNum8 *= 9L;
  588.     fNum8 /= 179L * 625L;
  589.     return fNum8;
  590. }    /* CalcPremFNum() */
  591.  
  592.  
  593. /*
  594.     Initialize a line in the frequency table with shifted frequency values.
  595.     The values are shifted a fraction (num/den) of a half-tone.
  596.     See following routine.
  597. */
  598. static SetFNum( fNumVec, num, den)
  599.     unsigned * fNumVec;
  600. {
  601.     int i;
  602.     long val;
  603.  
  604.     *fNumVec++ = (unsigned)(4 +(val = CalcPremFNum( num, den))) >> 3;
  605.     for ( i = 1; i < 12; i++) {
  606.         val *= 106;
  607.         *fNumVec++ = (unsigned)(4 +(val /= 100)) >> 3;
  608.         }
  609. }    /* SetFNum() */
  610.  
  611.  
  612. /*
  613.     Initialize all lines of the frequency table. Each line represents
  614.     12 half-tones shifted by (n/NR_STEP_PITCH), where 'n' is the line number
  615.     and ranges from 1 to NR_STEP_PITCH.
  616. */
  617. static InitFNums()
  618. {
  619.     unsigned i, j, k, num, numStep, pas;
  620.  
  621.     numStep = 100 / NR_STEP_PITCH;
  622.     for( num = pas = 0; pas < NR_STEP_PITCH; pas++, num += numStep)
  623.         SetFNum( fNumNotes[ pas], num, 100);
  624.     for( i = 0; i < 11; i++) {
  625.         fNumFreqPtr[ i] = (unsigned *) fNumNotes[ 0];
  626.         halfToneOffset[ i] = 0;
  627.         }
  628.  
  629.     k = 0;
  630.     for( i = 0; i < 8; i++)
  631.         for( j = 0; j < 12; j++, k++) {
  632.             noteDIV12[ k] = i;
  633.             noteMOD12[ k] = j;
  634.             }
  635. }    /* InitFNums() */
  636.  
  637.  
  638. /*
  639.     Routine to set 'halfToneOffset[]' & 'fNumFreqPtr[]'.
  640.     These two global variables are used to determine the frequency
  641.     variation to use when a note is played.
  642.  
  643.     0 <= pitchBend <= 3fffH
  644. */
  645. static ChangePitch( voice, pitchBend)
  646.     int voice;
  647.     int pitchBend;        /* 0 - 3fffH, 2000H == exact tuning */
  648.     {
  649.     int t1, t2, delta;
  650.     long l;
  651.     static long oldL = ~0;
  652.     static int oldHt;
  653.     static unsigned * oldPtr;
  654.  
  655.     l = (long)(pitchBend - MID_PITCH) * pitchRangeStep;
  656.     if( oldL == l) {    /* optimisation ... */
  657.         fNumFreqPtr[ voice] = oldPtr;
  658.         halfToneOffset[ voice] = oldHt;
  659.         }
  660.     else {
  661.         t1 = l / MID_PITCH;
  662.         if( t1 < 0) {
  663.             t2 = NR_STEP_PITCH -1 -t1;
  664.             oldHt = halfToneOffset[ voice] = -(t2 / NR_STEP_PITCH);
  665.             delta = (t2 - NR_STEP_PITCH +1) % NR_STEP_PITCH;
  666.             if( delta)
  667.                 delta = NR_STEP_PITCH - delta;
  668.             }
  669.         else {
  670.             oldHt = halfToneOffset[ voice] = t1 / NR_STEP_PITCH;
  671.             delta = t1 % NR_STEP_PITCH;
  672.             }
  673.         oldPtr = fNumFreqPtr[ voice] = (unsigned *) fNumNotes[ delta];
  674.         oldL = l;
  675.         }
  676.     }    /* ChangePitch() */
  677.  
  678.  
  679.  
  680. /*
  681.     Used to change the parameter 'param' of the slot 'slot'
  682.     with the value 'val'. The chip registers are updated.
  683. */
  684. SetASlotParam( slot, param, val)
  685.     int slot, val;
  686.     int param;        /* parameter number */
  687. {
  688.     paramSlot[ slot][ param] = val;
  689.     SndSetPrm( slot, param);
  690. }    /* SetASlotParam() */
  691.  
  692.     
  693.  
  694.  
  695.  
  696.  
  697.  
  698. /*
  699. ------------------------------------------------------
  700.     Set the 14 parameters ( 13 in 'param', 1 in 'waveSel')
  701.     of slot 'slot'. Update the parameter array and the chip.
  702. ------------------------------------------------------
  703. */
  704. static SetSlotParam( slot, param, waveSel)
  705.     unsigned slot, * param, waveSel;
  706. {
  707.     int i, k;
  708.     SLOT_PARAM * ptr;
  709.  
  710.     for( i = 0, ptr = ¶mSlot[ slot][ 0]; i < nbLocParam -1; i++)
  711.         *ptr++ = *param++;
  712.     *ptr = waveSel &= 0x3;
  713.     SndSetAllPrm( slot);
  714. }    /* SetSlotParam() */
  715.  
  716. SetCharSlotParam( slot, cParam, waveSel)
  717.     unsigned slot, waveSel;
  718.     char * cParam;
  719.     {
  720.     int param[ nbLocParam];
  721.     int i;
  722.  
  723.     for( i = 0; i < nbLocParam -1; i++)
  724.         param[ i] = *cParam++;
  725.     SetSlotParam( slot, param, waveSel);
  726.     }    /* SetCharSlotParam() */
  727.  
  728.  
  729. /*
  730. -----------------------------------------------
  731.     Update the parameter 'prm' for the slot 'slot'.
  732.     Update the chip registers.
  733. -----------------------------------------------
  734. */
  735. static SndSetPrm( slot, prm)
  736.     int slot, prm;
  737. {
  738.  
  739.     switch( prm) {
  740.         case prmPercussion:
  741.         case prmAmDepth:
  742.         case prmVibDepth:
  743.             SndSAmVibRhythm();
  744.             break;
  745.  
  746.         case prmNoteSel:
  747.             SndSNoteSel();
  748.             break;
  749.  
  750.         case prmKsl:
  751.         case prmLevel:
  752.             SndSKslLevel( slot);
  753.             break;
  754.  
  755.         case prmFm:
  756.         case prmFeedBack:
  757.             SndSFeedFm( slot);
  758.             break;
  759.  
  760.         case prmAttack:
  761.         case prmDecay:
  762.             SndSAttDecay( slot);
  763.             break;
  764.  
  765.         case prmRelease:
  766.         case prmSustain:
  767.             SndSSusRelease( slot);
  768.             break;
  769.  
  770.         case prmMulti:
  771.         case prmVib:
  772.         case prmStaining:
  773.         case prmKsr:
  774.         case prmAm:
  775.             SndSAVEK( slot);
  776.             break;
  777.  
  778.         case prmWaveSel:
  779.             SndWaveSelect( slot);
  780.             break;
  781.         }
  782. }    /* SndSetPrm() */
  783.  
  784.  
  785.  
  786. /*-------------------------------------------------
  787.     Transfer all the parameters from slot 'slot' to
  788.     the chip.
  789. */
  790. static SndSetAllPrm( slot)
  791. {
  792.     SndSAmVibRhythm();
  793.     SndSNoteSel();
  794.     SndSKslLevel( slot);
  795.     SndSFeedFm( slot);
  796.     SndSAttDecay( slot);
  797.     SndSSusRelease( slot);
  798.     SndSAVEK( slot);
  799.     SndWaveSelect( slot);
  800. }    /* SndSetAllPrm() */
  801.     
  802.  
  803. /*
  804.     KSL, LEVEL
  805. */
  806. static SndSKslLevel( slot)
  807. {
  808.     unsigned t1;
  809.  
  810.     t1 = 63 - (GetLocPrm( slot, prmLevel) & 0x3f);    /* amplitude */
  811.     t1 = slotRelVolume[ slot] * t1;
  812.     t1 += t1 + MAX_VOLUME;    /* round off to 0.5 */
  813.     t1 = 63 - t1 / ( 2 * MAX_VOLUME);
  814.  
  815.     t1 |= GetLocPrm( slot, prmKsl) << 6;
  816.     SndOutput( 0x40 + (int)offsetSlot[ slot], t1);
  817. }
  818.  
  819.  
  820. /* --------------------------------------------
  821.     Note sel
  822. */
  823. static SndSNoteSel()
  824. {
  825.     SndOutput( 0x08, noteSel ? 64 : 0);
  826. }    /* SndSNoteSel() */
  827.  
  828.  
  829.  
  830. /* --------------------------------------------
  831.     FEED-BACK and FM (connection).
  832.     Applicable only to operator 0 in melodic mode.
  833. */
  834. static SndSFeedFm( slot)
  835. {
  836.     unsigned t1;
  837.  
  838.     if( operSlot[ slot])
  839.         return;
  840.     t1 = GetLocPrm( slot, prmFeedBack) << 1;
  841.     t1 |= GetLocPrm( slot, prmFm) ? 0 : 1;
  842.     SndOutput( 0xC0 + (int)voiceSlot[ slot], t1);
  843. }
  844.  
  845.  
  846. /*
  847.     ATTACK, DECAY
  848. */
  849. static SndSAttDecay( slot)
  850. {
  851.     unsigned t1;
  852.  
  853.     t1 = GetLocPrm( slot, prmAttack) << 4;
  854.     t1 |= GetLocPrm( slot, prmDecay) & 0xf;
  855.     SndOutput( 0x60 + (int)offsetSlot[ slot], t1);
  856. }
  857.  
  858.  
  859. /*
  860.     SUSTAIN, RELEASE
  861. */
  862. static SndSSusRelease( slot)
  863. {
  864.     unsigned t1;
  865.  
  866.     t1 = GetLocPrm( slot, prmSustain) << 4;
  867.     t1 |= GetLocPrm( slot, prmRelease) & 0xf;
  868.     SndOutput( 0x80 + (int)offsetSlot[ slot], t1);
  869. }
  870.  
  871.  
  872.  
  873. /*
  874.     AM, VIB, EG-TYP( Sustaining), KSR, MULTI
  875. */
  876. static SndSAVEK( slot)
  877. {
  878.     unsigned t1;
  879.  
  880.     t1 = GetLocPrm( slot, prmAm) ? 0x80 : 0;
  881.     t1 += GetLocPrm( slot, prmVib) ? 0x40 : 0;
  882.     t1 += GetLocPrm( slot, prmStaining) ? 0x20 : 0;
  883.     t1 += GetLocPrm( slot, prmKsr) ? 0x10 : 0;
  884.     t1 += GetLocPrm( slot, prmMulti) & 0xf;
  885.     SndOutput( 0x20 + (int)offsetSlot[ slot], t1);
  886. }    /* SndSAVEK() */
  887.  
  888.  
  889. /*
  890.     Set the values: AM Depth, VIB depth & Rhythm
  891. */
  892. static SndSAmVibRhythm()
  893. {
  894.     unsigned t1;
  895.  
  896.     t1 = amDepth ? 0x80 : 0;
  897.     t1 |= vibDepth ? 0x40 : 0;
  898.     t1 |= RhythmMode() ? 0x20 : 0;
  899.     t1 |= percBits;
  900.     SndOutput( 0xBD, t1);
  901. }
  902.  
  903.  
  904. /*
  905.     Set the wave-select parameter.
  906. */
  907. static SndWaveSelect( slot)
  908.     {
  909.     unsigned wave;
  910.  
  911.     if( modeWaveSel)
  912.         wave = GetLocPrm( slot, prmWaveSel) & 0x03;
  913.     else
  914.         wave = 0;
  915.     SndOutput( 0xE0 + offsetSlot[ slot], wave);
  916.     }    /* SndWaveSelect() */
  917.  
  918.  
  919. /*
  920.     Change pitch of voices 0 to 8, for melodic or percussive mode.
  921. */
  922. SetFreq( voice, pitch, keyOn)
  923.     unsigned voice;                /* voice number */
  924.     int        pitch;                /* 0 - 95 */
  925.     unsigned    keyOn;            /* Set key-on/off */
  926.     {
  927.     unsigned int fNbr, t1;
  928.  
  929.     voiceKeyOn[ voice] = keyOn;
  930.     notePitch[ voice] = pitch;
  931.     pitch += halfToneOffset[ voice];
  932.     if( pitch > 95)
  933.         pitch = 95;
  934.     if( pitch < 0)
  935.         pitch = 0;
  936.     fNbr = * ( fNumFreqPtr[ voice] + noteMOD12[ pitch]);
  937.     SndOutput( 0xA0 +voice, fNbr);
  938.     t1 = keyOn ? 32 : 0;
  939.     t1 += ( (unsigned)noteDIV12[ pitch] << 2) + ( 0x3 & HighByte( fNbr) );
  940.     SndOutput( 0xB0 +voice, t1);
  941.     }
  942.  
  943.  
  944.  
  945. /*
  946.     Set the frequency of voice 'voice' to 0 hertz.
  947. */
  948. static SoundChut( voice)
  949.     int voice;
  950. {
  951.     SndOutput( 0xA0 +voice, 0);
  952.     SndOutput( 0xB0 +voice, 0);
  953. }    /* SoundChut() */
  954.  
  955.  
  956.  
  957. /*
  958.     Return 0 if board is not installed
  959. */
  960. int BoardInstalled()
  961.     {
  962.     unsigned t1, t2, i;
  963.  
  964.     SndOutput( 4, 0x60);    /* mask T1 & T2 */
  965.     SndOutput( 4, 0x80);    /* reset IRQ */
  966.     t1 = inp( genAddr);        /* read status register */
  967.     SndOutput( 2, 0xff);    /* set timer-1 latch */
  968.     SndOutput( 4, 0x21);    /* unmask & start T1 */
  969.     for( i = 0; i < 200; i++)    /* 100 uSec delay for timer-1 overflow */
  970.         inp( genAddr);
  971.     t2 = inp( genAddr);        /* read status register */
  972.     SndOutput( 4, 0x60);
  973.     SndOutput( 4, 0x80);
  974.     return (t1 & 0xE0) == 0 && (t2 & 0xE0) == 0xC0;
  975.     }
  976.