home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Stars of Shareware: Programmierung
/
SOURCE.mdf
/
programm
/
msdos
/
c
/
playadlb
/
adlib.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-05
|
23KB
|
976 lines
/**
ADLIB.C, low level sound driver V1.03
===== To be used with OUTCHIP.ASM file. =====
Copyright Ad Lib Inc, 1988, 1989
1988/06/22, Dale Glowinski, Marc Savary, Ad Lib Inc.
1989/04/20, Marc savary.
The following routines are public (see each routine for further
documentation):
SoundColdInit( port)
SoundWarmInit()
SetMode( mode)
Set3812( state)
SetPitchRange( pR)
SetGParam( amD, vibD, nSel)
SetVoiceTimbre( voice, paramArray)
SetVoiceVolume( voice, volume)
SetVoicePitch( voice, pitchBend)
NoteOn( voice, pitch)
NoteOff( voice)
**/
#include <dos.h>
#include "adlib.h"
/*
In percussive mode, the last 4 voices ( SD TOM HH CYMB) are created
using melodic voices 7 & 8. A noise generator use channels 7 & 8
frequency information for creating rhythm instruments. Best result
are obtained by setting TOM two octaves below mid C and SD 7 half-tones
above TOM.
In this implementation, only the TOM pitch may vary, with the SD always
set 7 half-tones above.
*/
#define TOM_PITCH 24 /* best frequency, in range of 0 to 95 */
#define TOM_TO_SD 7 /* 7 half-tones between voice 7 & 8 */
#define SD_PITCH (TOM_PITCH + TOM_TO_SD)
#define NR_STEP_PITCH 25 /* 25 steps within a half-tone for pitch bend */
#define GetLocPrm( slot, prm)( (unsigned)paramSlot[ slot][ prm])
#define HighByte( word) ( ((char *)(&word))[ 1]) /* 80x86-8 only .. */
#define RhythmMode() (percussion)
typedef char SLOT_PARAM;
/*
-----------------------------------------------------------------
*/
unsigned genAddr; /* address of sound chip */
static char percBits; /* control bits of percussive voices */
static char percMasks[] = {
0x10, 0x08, 0x04, 0x02, 0x01
};
static char notePitch[ 11]; /* pitch of last note-on of each voice */
static char voiceKeyOn[ 11]; /* state of keyOn bit of each voice */
static char noteDIV12[ 96]; /* table of (0..95) DIV 12 */
static char noteMOD12[ 96]; /* table of (0..95) MOD 12 */
static char slotRelVolume[ 18]; /* relative volume of slots */
/* definition of the ELECTRIC-PIANO voice (opr0 & opr1) */
static char pianoParamsOp0[ nbLocParam] = {
1, 1, 3, 15, 5, 0, 1, 3, 15, 0, 0, 0, 1, 0 };
static char pianoParamsOp1[ nbLocParam] = {
0, 1, 1, 15, 7, 0, 2, 4, 0, 0, 0, 1, 0, 0 };
/* definition of default percussive voices: */
static char bdOpr0[] = { 0, 0, 0, 10, 4, 0, 8, 12, 11, 0, 0, 0, 1, 0 };
static char bdOpr1[] = { 0, 0, 0, 13, 4, 0, 6, 15, 0, 0, 0, 0, 1, 0 };
static char sdOpr[] = { 0, 12, 0, 15, 11, 0, 8, 5, 0, 0, 0, 0, 0, 0 };
static char tomOpr[] = { 0, 4, 0, 15, 11, 0, 7, 5, 0, 0, 0, 0, 0, 0 };
static char cymbOpr[] ={ 0, 1, 0, 15, 11, 0, 5, 5, 0, 0, 0, 0, 0, 0 };
static char hhOpr[] = { 0, 1, 0, 15, 11, 0, 7, 5, 0, 0, 0, 0, 0, 0 };
static SLOT_PARAM paramSlot[ 18][ nbLocParam]; /* all the parameters of slots... */
static char amDepth; /* chip global parameters .. */
static char vibDepth; /* ... */
static char noteSel; /* ... */
static char percussion; /* percussion mode parameter */
/* Slot numbers as a function of the voice and the operator.
( melodic only)
*/
char slotVoice[] [ 2] = {
{0, 3}, /* voix 0 */
{1, 4}, /* 1 */
{2, 5}, /* 2 */
{6, 9}, /* 3 */
{7, 10}, /* 4 */
{8, 11}, /* 5 */
{12, 15}, /* 6 */
{13, 16}, /* 7 */
{14, 17} /* 8 */
};
/* Slot numbers for the percussive voices.
0 indicates that there is only one slot.
*/
char slotPerc[] [ 2] = {
{12, 15}, /* Bass Drum: slot 12 et 15 */
{16, 0}, /* SD: slot 16 */
{14, 0}, /* TOM: slot 14 */
{17, 0}, /* TOP-CYM: slot 17 */
{13, 0} /* HH: slot 13 */
};
/*
This table gives the offset of each slot within the chip.
offset = fn( slot)
*/
static char offsetSlot[] = {
0, 1, 2, 3, 4, 5,
8, 9, 10, 11, 12, 13,
16, 17, 18, 19, 20, 21
};
/* This table indicates if the slot is a modulator (0) or a carrier (1).
opr = fn( slot)
*/
static char operSlot[] = {
0, 0, 0, /* 1 2 3 */
1, 1, 1, /* 4 5 6 */
0, 0, 0, /* 7 8 9 */
1, 1, 1, /* 10 11 12 */
0, 0, 0, /* 13 14 15 */
1, 1, 1, /* 16 17 18 */
};
/* This table gives the voice number associated with each slot.
(melodic mode only)
voice = fn( slot)
*/
static char voiceSlot[] = {
0, 1, 2,
0, 1, 2,
3, 4, 5,
3, 4, 5,
6, 7, 8,
6, 7, 8,
};
static unsigned fNumNotes[ NR_STEP_PITCH] [ 12];
static int halfToneOffset[ 11];
static unsigned * fNumFreqPtr[ 11];
static int pitchRange; /* pitch variation, half-tone [+1,+12] */
static int pitchRangeStep; /* == pitchRange * NR_STEP_PITCH */
static int modeWaveSel; /* != 0 if used with the 'wave-select' parameters */
extern SndOutput(); /* in file OUTCHIP.ASM */
/*
----------------------------------------------------------
*/
/*
Must be called for start-up initialisation.
Return 0 if harware not found.
*/
int SoundColdInit( port)
unsigned port; /* io port address of sound board (0x388) */
{
int hardware;
genAddr = port;
hardware = BoardInstalled();
SoundWarmInit();
return hardware;
} /* SoundColdInit() */
/*
-----------------------------------------------
Initialize the chip in melodic mode (mode == 0),
set all 9 voices to electric-piano timbres,
set the 3 global parameters to zero,
set the pitch bend range to 1 half-tone,
set the pitch bend of each voice to 0x2000 (no detune),
set the volume of each voice to maximum level,
and enable the wave-select parameter.
-----------------------------------------------
*/
SoundWarmInit()
{
int i;
InitSlotVolume();
InitFNums();
SetMode( 0); /* melodic mode */
SetGParam( 0, 0, 0); /* init global parameters */
for( i = 0 ; i < 9; i++)
SoundChut( i);
SetPitchRange( 1); /* default pitch range is 1 half-tone */
Set3812( 1);
} /* SoundWarmInit() */
/*
---------------------------------------------
Put the chip in melodic mode (mode == 0),
or in percussive mode ( mode != 0).
If the melodic mode is chosen, all voices are
set to electric-piano, else the first 5 are set
to electric-piano, and the percussion voices
to their default timbres.
---------------------------------------------
*/
SetMode( mode)
int mode;
{
if( mode){
SoundChut( BD);
SoundChut( SD);
SoundChut( TOM);
/* set the frequency for the last 4 percussion voices: */
SetFreq( TOM, TOM_PITCH, 0);
SetFreq( SD, SD_PITCH, 0);
}
percussion = mode;
percBits = 0;
InitSlotParams();
SndSAmVibRhythm();
} /* SetMode() */
/*
Enable (state != 0) / disable (state == 0)
the wave-select parameters.
If you do not want to use the wave-select parameters, call
this function with a value of 0 AFTER calling SoundColdInit()
or SoundWarmInit().
*/
Set3812( state)
{
int i;
modeWaveSel = state ? 0x20 : 0;
for( i = 0; i < 18; i++)
SndOutput( 0xE0 + offsetSlot[ i], 0);
SndOutput( 1, modeWaveSel);
} /* Set3812() */
/*
Routine to change the pitch bend range. The value can be from
1 to 12 (in half-tones).
For example, the value 12 means that the pitch bend will
range from -12 (pitchBend == 0, see function 'SetVoicePitch()')
to +12 (pitchBend == 0x3fff) half-tones.
The change will be effective as of the next call to
'SetVoicePitch()'.
*/
SetPitchRange( pR)
unsigned pR;
{
if( pR > 12)
pR = 12;
if( pR < 1)
pR = 1;
pitchRange = pR;
pitchRangeStep = pitchRange * NR_STEP_PITCH;
} /* SetPitchRange() */
/*
----------------------------------------------
Set the 3 global parameters AmDepth,
VibDepth & NoteSel
The change takes place immediately.
----------------------------------------------
*/
SetGParam( amD, vibD, nSel)
int amD, vibD, nSel;
{
amDepth = amD;
vibDepth = vibD;
noteSel = nSel;
SndSAmVibRhythm();
SndSNoteSel();
} /* SetGParam() */
/*
-------------------------------------------------
Set the parameters of the voice 'voice'.
In melodic mode, 'voice' varies from 0 to 8.
In percussive mode, voices 0 to 5 are melodic
and 6 to 10 are percussive.
A timbre (melodic or percussive) is defined as follows:
the 13 first parameters of operator 0 ( ksl, multi, feedBack,
attack, sustain, eg-typem decay, release, level, am, vib, ksr, fm)
followed by the 13 parameters of operator 1 (if a percussive voice, all
the parameters are zero), followed by the wave-select parameter for
the operators 0 and 1.
'paramArray' is structured as follows:
struct {
int opr0Prm[ 13]; first 13 parameters
int opr1Prm[ 13]; must be 0 if percussive timbre
int opr0WaveSel; last parameter
int opr1WaveSel; must be 0 if percussive timbre
} TimbreDef;
The old timbre files (*.INS) do not contain the parameters
'opr0WaveSel' and 'opr1WaveSel'.
Set these two parameters to zero if you are using the old file
format.
-------------------------------------------------
*/
SetVoiceTimbre( voice, paramArray)
int voice, * paramArray;
{
int wave0, wave1;
int * prm1, * wavePtr;
wavePtr = paramArray + 2 * ( nbLocParam -1);
wave0 = * wavePtr++;
wave1 = * wavePtr;
prm1 = paramArray + nbLocParam -1;
if( !RhythmMode() || voice < BD) { /* melodic only */
SetSlotParam( (int)slotVoice[ voice][ 0], paramArray, wave0);
SetSlotParam( (int)slotVoice[ voice][ 1], prm1, wave1);
}
else if( voice == BD) { /* Bass Drum */
SetSlotParam( (int)slotPerc[ 0][ 0], paramArray, wave0);
SetSlotParam( (int)slotPerc[ 0][ 1], prm1, wave1);
}
else /* percussion, 1 slot */
SetSlotParam( (int)slotPerc[ voice -BD][ 0], paramArray, wave0);
} /* SetVoiceTimbre() */
/*
--------------------------------------------------
Set the volume of the voice 'voice' to 'volume'.
The resulting output level is (timbreVolume * volume / 127).
The change takes place immediately.
0 <= volume <= 127
--------------------------------------------------
*/
SetVoiceVolume( voice, volume)
unsigned volume; /* 0 - 0x7f */
{
int slot;
char * slots;
#if 1
if( !RhythmMode() || voice < BD)
slot = slotVoice[ voice][ 1];
else
slot = slotPerc[ voice -BD][ voice == BD ? 1 : 0];
if( volume > MAX_VOLUME)
volume = MAX_VOLUME;
slotRelVolume[ slot] = volume;
SndSKslLevel( slot);
#else /* code that modify the two oper. volume of an additive sound: */
if( volume > MAX_VOLUME)
volume = MAX_VOLUME;
if( !RhythmMode() || voice <= BD) {
slots = slotVoice[ voice];
slotRelVolume[ slots[ 1]] = volume;
SndSKslLevel( slots[ 1]);
if( !GetLocPrm( slots[ 0], prmFm)) {
/* additive syntesis: set volume of first slot too */
slotRelVolume[ slots[ 0]] = volume;
SndSKslLevel( slots[ 0]);
}
}
else {
slot = slotPerc[ voice -BD][ 0];
slotRelVolume[ slot] = volume;
SndSKslLevel( slot);
}
#endif
} /* SetVoiceVolume() */
/*
-------------------------------------------------
Change the pitch value of a voice.
The variation in pitch is a function of the previous call
to 'SetPitchRange()' and the value of 'pitchBend'.
A value of 0 means -half-tone * pitchRange,
0x2000 means no variation (exact pitch) and
0x3fff means +half-tone * pitchRange.
Does not affect the percussive voices, except for the bass drum.
The change takes place immediately.
0 <= pitchBend <= 0x3fff, 0x2000 == exact tuning
-------------------------------------------------
*/
SetVoicePitch( voice, pitchBend)
unsigned voice;
unsigned pitchBend;
{
if( ! RhythmMode() || voice <= BD) {
/* melodic + bass-drum */
if( pitchBend > MAX_PITCH)
pitchBend = MAX_PITCH;
ChangePitch( voice, pitchBend);
SetFreq( voice, notePitch[ voice], voiceKeyOn[ voice]);
}
} /* SetVoicePitch() */
/*
-----------------------------------------------------------
Routine to start a note playing.
0 <= voice <= 8 in melodic mode,
0 <= voice <= 10 in percussive mode;
0 <= pitch <= 127, 60 == MID_C ( the card can play between 12 and 107 )
-----------------------------------------------------------
*/
NoteOn( voice, pitch)
unsigned voice;
int pitch; /* 0 - 127 */
{
pitch -= ( MID_C - CHIP_MID_C);
if( pitch < 0)
pitch = 0;
if( voice < BD || ! RhythmMode())
/* this is a melodic voice */
SetFreq( voice, pitch, 1);
else {
/* this is a percussive voice */
if( voice == BD)
SetFreq( BD, pitch, 0);
else if( voice == TOM) {
/* for the last 4 percussions, only the TOM may change in frequency,
modifying the three others: */
SetFreq( TOM, pitch, 0);
SetFreq( SD, pitch + TOM_TO_SD, 0); /* f7 = 3 * f8 */
}
percBits |= percMasks[ voice - BD];
SndSAmVibRhythm();
}
} /* NoteOn() */
/*
Routine to stop playing the note which was started in 'NoteOn()'.
0 <= voice <= 8 in melodic mode,
0 <= voice <= 10 in percussive mode;
*/
NoteOff( voice)
unsigned voice;
{
if( !RhythmMode() || voice < BD)
SetFreq( voice, notePitch[ voice], 0); /* shut off */
else {
percBits &= ~percMasks[ voice - BD];
SndSAmVibRhythm();
}
} /* NoteOff() */
/*
------------------------------------------------------------------------
static functions ...
------------------------------------------------------------------------
*/
/*
In melodic mode, initialize all voices to electric-pianos.
In percussive mode, initialize the first 6 voices to electric-pianos
and the percussive voices to their default timbres.
*/
static InitSlotParams()
{
int i;
for( i = 0; i < 18; i++)
if( operSlot[ i])
SetCharSlotParam( i, pianoParamsOp1, 0);
else
SetCharSlotParam( i, pianoParamsOp0, 0);
if( RhythmMode()) {
SetCharSlotParam( 12, bdOpr0, 0);
SetCharSlotParam( 15, bdOpr1, 0);
SetCharSlotParam( 16, sdOpr, 0);
SetCharSlotParam( 14, tomOpr, 0);
SetCharSlotParam( 17, cymbOpr, 0);
SetCharSlotParam( 13, hhOpr, 0);
}
} /* InitSlotParams() */
/*
Set the volume of all slots.
*/
static InitSlotVolume()
{
int i;
for( i = 0; i < 18; i++)
slotRelVolume[ i] = MAX_VOLUME;
} /* InitSlotVolume() */
/*
Return binary value of the frequency 260.44 ( C)
shifted by +/- numdeltaDemiTon/denDeltaDemiTon multiplied by 8.
If the numerator (numDeltaDemiTon) is positive, the frequency is
increased; if negative, it is decreased.
Fo = Fb( 1 + 0.06 num /den)
Fnum8 = Fo * 65536 * 72 / 3.58e6
-100 <= numDeltaDemiTon <= +100
1 <= denDeltaDemiTon <= 100
*/
static long CalcPremFNum( numDeltaDemiTon, denDeltaDemiTon)
{
long f8, fNum8, d100;
d100 = denDeltaDemiTon * 100;
f8 = ( d100 + 6 * numDeltaDemiTon) * (26044L * 2L); /* 260.44 * 100 * 2 */
f8 /= d100 * 25;
fNum8 = f8 * 16384; /*( 16384L * 9L); */
fNum8 *= 9L;
fNum8 /= 179L * 625L;
return fNum8;
} /* CalcPremFNum() */
/*
Initialize a line in the frequency table with shifted frequency values.
The values are shifted a fraction (num/den) of a half-tone.
See following routine.
*/
static SetFNum( fNumVec, num, den)
unsigned * fNumVec;
{
int i;
long val;
*fNumVec++ = (unsigned)(4 +(val = CalcPremFNum( num, den))) >> 3;
for ( i = 1; i < 12; i++) {
val *= 106;
*fNumVec++ = (unsigned)(4 +(val /= 100)) >> 3;
}
} /* SetFNum() */
/*
Initialize all lines of the frequency table. Each line represents
12 half-tones shifted by (n/NR_STEP_PITCH), where 'n' is the line number
and ranges from 1 to NR_STEP_PITCH.
*/
static InitFNums()
{
unsigned i, j, k, num, numStep, pas;
numStep = 100 / NR_STEP_PITCH;
for( num = pas = 0; pas < NR_STEP_PITCH; pas++, num += numStep)
SetFNum( fNumNotes[ pas], num, 100);
for( i = 0; i < 11; i++) {
fNumFreqPtr[ i] = (unsigned *) fNumNotes[ 0];
halfToneOffset[ i] = 0;
}
k = 0;
for( i = 0; i < 8; i++)
for( j = 0; j < 12; j++, k++) {
noteDIV12[ k] = i;
noteMOD12[ k] = j;
}
} /* InitFNums() */
/*
Routine to set 'halfToneOffset[]' & 'fNumFreqPtr[]'.
These two global variables are used to determine the frequency
variation to use when a note is played.
0 <= pitchBend <= 3fffH
*/
static ChangePitch( voice, pitchBend)
int voice;
int pitchBend; /* 0 - 3fffH, 2000H == exact tuning */
{
int t1, t2, delta;
long l;
static long oldL = ~0;
static int oldHt;
static unsigned * oldPtr;
l = (long)(pitchBend - MID_PITCH) * pitchRangeStep;
if( oldL == l) { /* optimisation ... */
fNumFreqPtr[ voice] = oldPtr;
halfToneOffset[ voice] = oldHt;
}
else {
t1 = l / MID_PITCH;
if( t1 < 0) {
t2 = NR_STEP_PITCH -1 -t1;
oldHt = halfToneOffset[ voice] = -(t2 / NR_STEP_PITCH);
delta = (t2 - NR_STEP_PITCH +1) % NR_STEP_PITCH;
if( delta)
delta = NR_STEP_PITCH - delta;
}
else {
oldHt = halfToneOffset[ voice] = t1 / NR_STEP_PITCH;
delta = t1 % NR_STEP_PITCH;
}
oldPtr = fNumFreqPtr[ voice] = (unsigned *) fNumNotes[ delta];
oldL = l;
}
} /* ChangePitch() */
/*
Used to change the parameter 'param' of the slot 'slot'
with the value 'val'. The chip registers are updated.
*/
SetASlotParam( slot, param, val)
int slot, val;
int param; /* parameter number */
{
paramSlot[ slot][ param] = val;
SndSetPrm( slot, param);
} /* SetASlotParam() */
/*
------------------------------------------------------
Set the 14 parameters ( 13 in 'param', 1 in 'waveSel')
of slot 'slot'. Update the parameter array and the chip.
------------------------------------------------------
*/
static SetSlotParam( slot, param, waveSel)
unsigned slot, * param, waveSel;
{
int i, k;
SLOT_PARAM * ptr;
for( i = 0, ptr = ¶mSlot[ slot][ 0]; i < nbLocParam -1; i++)
*ptr++ = *param++;
*ptr = waveSel &= 0x3;
SndSetAllPrm( slot);
} /* SetSlotParam() */
SetCharSlotParam( slot, cParam, waveSel)
unsigned slot, waveSel;
char * cParam;
{
int param[ nbLocParam];
int i;
for( i = 0; i < nbLocParam -1; i++)
param[ i] = *cParam++;
SetSlotParam( slot, param, waveSel);
} /* SetCharSlotParam() */
/*
-----------------------------------------------
Update the parameter 'prm' for the slot 'slot'.
Update the chip registers.
-----------------------------------------------
*/
static SndSetPrm( slot, prm)
int slot, prm;
{
switch( prm) {
case prmPercussion:
case prmAmDepth:
case prmVibDepth:
SndSAmVibRhythm();
break;
case prmNoteSel:
SndSNoteSel();
break;
case prmKsl:
case prmLevel:
SndSKslLevel( slot);
break;
case prmFm:
case prmFeedBack:
SndSFeedFm( slot);
break;
case prmAttack:
case prmDecay:
SndSAttDecay( slot);
break;
case prmRelease:
case prmSustain:
SndSSusRelease( slot);
break;
case prmMulti:
case prmVib:
case prmStaining:
case prmKsr:
case prmAm:
SndSAVEK( slot);
break;
case prmWaveSel:
SndWaveSelect( slot);
break;
}
} /* SndSetPrm() */
/*-------------------------------------------------
Transfer all the parameters from slot 'slot' to
the chip.
*/
static SndSetAllPrm( slot)
{
SndSAmVibRhythm();
SndSNoteSel();
SndSKslLevel( slot);
SndSFeedFm( slot);
SndSAttDecay( slot);
SndSSusRelease( slot);
SndSAVEK( slot);
SndWaveSelect( slot);
} /* SndSetAllPrm() */
/*
KSL, LEVEL
*/
static SndSKslLevel( slot)
{
unsigned t1;
t1 = 63 - (GetLocPrm( slot, prmLevel) & 0x3f); /* amplitude */
t1 = slotRelVolume[ slot] * t1;
t1 += t1 + MAX_VOLUME; /* round off to 0.5 */
t1 = 63 - t1 / ( 2 * MAX_VOLUME);
t1 |= GetLocPrm( slot, prmKsl) << 6;
SndOutput( 0x40 + (int)offsetSlot[ slot], t1);
}
/* --------------------------------------------
Note sel
*/
static SndSNoteSel()
{
SndOutput( 0x08, noteSel ? 64 : 0);
} /* SndSNoteSel() */
/* --------------------------------------------
FEED-BACK and FM (connection).
Applicable only to operator 0 in melodic mode.
*/
static SndSFeedFm( slot)
{
unsigned t1;
if( operSlot[ slot])
return;
t1 = GetLocPrm( slot, prmFeedBack) << 1;
t1 |= GetLocPrm( slot, prmFm) ? 0 : 1;
SndOutput( 0xC0 + (int)voiceSlot[ slot], t1);
}
/*
ATTACK, DECAY
*/
static SndSAttDecay( slot)
{
unsigned t1;
t1 = GetLocPrm( slot, prmAttack) << 4;
t1 |= GetLocPrm( slot, prmDecay) & 0xf;
SndOutput( 0x60 + (int)offsetSlot[ slot], t1);
}
/*
SUSTAIN, RELEASE
*/
static SndSSusRelease( slot)
{
unsigned t1;
t1 = GetLocPrm( slot, prmSustain) << 4;
t1 |= GetLocPrm( slot, prmRelease) & 0xf;
SndOutput( 0x80 + (int)offsetSlot[ slot], t1);
}
/*
AM, VIB, EG-TYP( Sustaining), KSR, MULTI
*/
static SndSAVEK( slot)
{
unsigned t1;
t1 = GetLocPrm( slot, prmAm) ? 0x80 : 0;
t1 += GetLocPrm( slot, prmVib) ? 0x40 : 0;
t1 += GetLocPrm( slot, prmStaining) ? 0x20 : 0;
t1 += GetLocPrm( slot, prmKsr) ? 0x10 : 0;
t1 += GetLocPrm( slot, prmMulti) & 0xf;
SndOutput( 0x20 + (int)offsetSlot[ slot], t1);
} /* SndSAVEK() */
/*
Set the values: AM Depth, VIB depth & Rhythm
*/
static SndSAmVibRhythm()
{
unsigned t1;
t1 = amDepth ? 0x80 : 0;
t1 |= vibDepth ? 0x40 : 0;
t1 |= RhythmMode() ? 0x20 : 0;
t1 |= percBits;
SndOutput( 0xBD, t1);
}
/*
Set the wave-select parameter.
*/
static SndWaveSelect( slot)
{
unsigned wave;
if( modeWaveSel)
wave = GetLocPrm( slot, prmWaveSel) & 0x03;
else
wave = 0;
SndOutput( 0xE0 + offsetSlot[ slot], wave);
} /* SndWaveSelect() */
/*
Change pitch of voices 0 to 8, for melodic or percussive mode.
*/
SetFreq( voice, pitch, keyOn)
unsigned voice; /* voice number */
int pitch; /* 0 - 95 */
unsigned keyOn; /* Set key-on/off */
{
unsigned int fNbr, t1;
voiceKeyOn[ voice] = keyOn;
notePitch[ voice] = pitch;
pitch += halfToneOffset[ voice];
if( pitch > 95)
pitch = 95;
if( pitch < 0)
pitch = 0;
fNbr = * ( fNumFreqPtr[ voice] + noteMOD12[ pitch]);
SndOutput( 0xA0 +voice, fNbr);
t1 = keyOn ? 32 : 0;
t1 += ( (unsigned)noteDIV12[ pitch] << 2) + ( 0x3 & HighByte( fNbr) );
SndOutput( 0xB0 +voice, t1);
}
/*
Set the frequency of voice 'voice' to 0 hertz.
*/
static SoundChut( voice)
int voice;
{
SndOutput( 0xA0 +voice, 0);
SndOutput( 0xB0 +voice, 0);
} /* SoundChut() */
/*
Return 0 if board is not installed
*/
int BoardInstalled()
{
unsigned t1, t2, i;
SndOutput( 4, 0x60); /* mask T1 & T2 */
SndOutput( 4, 0x80); /* reset IRQ */
t1 = inp( genAddr); /* read status register */
SndOutput( 2, 0xff); /* set timer-1 latch */
SndOutput( 4, 0x21); /* unmask & start T1 */
for( i = 0; i < 200; i++) /* 100 uSec delay for timer-1 overflow */
inp( genAddr);
t2 = inp( genAddr); /* read status register */
SndOutput( 4, 0x60);
SndOutput( 4, 0x80);
return (t1 & 0xE0) == 0 && (t2 & 0xE0) == 0xC0;
}