ref: 5288bbb7556c87e95b0813bf5769eec6b3caf9bc
parent: 35a6b626209bdb216d0c0df0237c4d9a4af3eae9
author: Konstantinn Bonnet <qu7uux@gmail.com>
date: Wed May 18 22:21:18 EDT 2016
add sound and music, misc fixes - fs . restore extension after everything is loaded for ver>SOD . fix wrong offsets for demos and epis . use end pointers rather than size where appropriate; remove unused array end pointers . skip pc sound effects forever . strip imf and al lumps to just the data - snd . implement sfx and music playback with an opl2 emulator based on fmopl.c from MAME . resample and mix pcm. resampling method is a sort-of simplified version of pcmconv(1)'s implementation of the method described on the "Digital Audio Resampling Home Page" at http://ccrma.stanford.edu/~jos/resample/ . opl2m: separate general purpose decoder using opl2.c for playback of pseudo-imf format streams - todo . pcm stereo positional attenuation - problems . imf playback cracks on loop, as in reference. this seems to stem from the inclusion of reset shit in the lumps themselves. it sucks. . al playback cracks way more than reference. this is a limitation of fmopl.c, and everything based on it inherits this (so, everything). it sucks. . unless sound is disabled, #A/audio is written to on every frame even if there is nothing to write, to avoid additional cracking. it fucking sucks. . opl2 keeps spinning even if music is disabled and nothing is playing, to properly simulate sfx echo, since some sounds are dependent on it. it sucking fucks. . resampling: unlike doom(?)/quake, pcm is sampled at 7kHz, then resampled by the hardware at 48kHz or whatever. we therefore need to do the same (for 44.1kHz). since the goal here is to recreate the functionality of the reference implementation, doing just e.g. (int)*p++ * 256 - 32768 and duplicating these n times sounds wrong. the real problem is i'm sick of working on this and i suck at signal processing. there. this stuff is way overkill (and cargocult, AGAIN), since both sampling rates are constant, the number of samples is always between 1 and 100, etc. it sucks, many times per second.
--- a/dat.h
+++ b/dat.h
@@ -23,6 +23,7 @@
Ke
};
extern int cson, kbon, mson;
+extern int sfxon, muson, pcmon;
extern Rune keys[];
extern void (*step)(void);
@@ -57,21 +58,21 @@
typedef struct Pic Pic;
typedef struct Fnt Fnt;
typedef struct Sfx Sfx;
+typedef struct Al Al;
struct Dat{
u16int sz;
uchar *p;
+ uchar *e;
};
-extern Dat *wals, *sprs, *spre;
-extern Dat *imfs, *imfe;
-extern Dat *maps, *mape, *map;
-extern Dat *exts, *exte;
-extern Dat *dems, *deme, *epis;
+extern Dat *wals, *sprs, *imfs;
+extern uchar **exts, **dems, **epis;
+extern uchar **maps, *map;
struct Pic{
int x;
int y;
- Dat;
+ uchar *p;
};
extern Pic *pics, *pice;
extern uchar *pict;
@@ -80,16 +81,21 @@
int h;
int ofs[256];
char w[256];
- Dat;
+ uchar *p;
};
extern Fnt fnts[], *fnt;
+struct Al{
+ int pri;
+ uchar inst[10];
+ int blk;
+ Dat;
+};
struct Sfx{
- Dat pc;
- Dat al;
+ Al;
Dat *pcm;
};
-extern Sfx *sfxs, *sfxe;
+extern Sfx *sfxs;
enum{
Shitwall,
--- a/fns.h
+++ b/fns.h
@@ -22,6 +22,12 @@
void gstep(void);
void dstep(void);
void initg(int);
+uchar* opl2out(uchar *, int);
+void opl2wr(int, int);
+void opl2init(int);
+void sndstep(void);
+void stopsfx(void);
void sfx(int);
void stopmus(void);
void mus(int);
+void initsnd(void);
--- a/fs.c
+++ b/fs.c
@@ -446,8 +446,8 @@
Planesz = Mapdxy * Mapdxy * Nplane,
Mapsz = Planesz * Nplane
};
-static Dat *snds;
-static uchar *swpb, *sndb, *mapb;
+static Dat *pcms;
+static uchar *swpb, *mapb;
static int alofs;
static u16int rlewtag;
@@ -642,18 +642,18 @@
while(++p < e){
Bseek(bf, 2, 1);
n = get16(bf);
- while(s->sz < n)
- s->sz += p++->sz;
- while(p->sz == 0 && p < e-1)
+ while(s->e < s->p + n)
+ s->e = p++->e;
+ while(p->p == nil && p < e-1)
p++;
s++;
- s->sz = p->sz;
s->p = p->p;
+ s->e = p->e;
}
n = s-wals;
wals = erealloc(wals, n * sizeof *wals);
sprs = wals + so;
- spre = wals + po;
+ pcms = wals + po;
}
static void
@@ -667,8 +667,8 @@
bf = bopen("vswap.", OREAD);
n = get16(bf);
- wals = emalloc((n-1) * sizeof *wals);
- e = wals + n-1;
+ s = wals = emalloc((n-1) * sizeof *wals);
+ e = s + n-1;
v = get16(bf);
w = get16(bf);
p = o = emalloc(n * sizeof *o);
@@ -675,16 +675,18 @@
while(p < o+n)
*p++ = get32(bf);
- for(s=wals; s<wals+n-1; s++)
- s->sz = get16(bf);
+ while(s < e)
+ s++->e = (uchar*)(uintptr)get16(bf);
u = swpb = emalloc(bsize(bf) - Bseek(bf, 0, 1));
Bseek(bf, 2, 1);
for(p=o, s=wals; s<e; s++, p++){
- if(s->sz == 0)
+ n = (uintptr)s->e;
+ if(n == 0)
continue;
Bseek(bf, *p, 0);
s->p = u;
- u += eread(bf, u, s->sz);
+ s->e = u + n;
+ u += eread(bf, u, n);
}
Bseek(bf, *p, 0);
free(o);
@@ -699,7 +701,7 @@
{
int n;
u32int v, p0, p1;
- uchar *u;
+ uchar *u, **d, **e;
Biobuf *hed, *dat;
hed = bopen("maphead.", OREAD);
@@ -706,13 +708,13 @@
dat = bopen("gamemaps.", OREAD);
n = ver==WL6 ? 60 : ver==WL1 ? 10 : ver==SDM ? 2 : 20;
rlewtag = get16(hed);
- maps = emalloc(n * sizeof *maps);
- mapb = emalloc(n * Mapsz);
-
- for(mape=maps, u=mapb; mape<maps+n; mape++){
+ d = maps = emalloc(n * sizeof *maps);
+ e = d + n;
+ u = mapb = emalloc(n * Mapsz);
+ while(d < e){
v = get32(hed);
if(v == 0xffffffff)
- sysfatal("sparse map %zud", mape-maps);
+ sysfatal("sparse map %zud", d-maps);
Bseek(dat, v, 0);
p0 = get32(dat);
p1 = get32(dat);
@@ -719,10 +721,9 @@
Bseek(dat, 10, 1);
if(get16(dat) != Mapdxy || get16(dat) != Mapdxy)
sysfatal("invalid map size");
- mape->p = u;
+ *d++ = u;
u += uncarmack(dat, (u16int*)u, p0);
u += uncarmack(dat, (u16int*)u, p1);
- mape->sz = u - mape->p;
}
Bterm(hed);
Bterm(dat);
@@ -754,7 +755,7 @@
}
p = pcmt[ver<SDM ? 0 : 1];
e = p + (ver==WL6 ? 46 : ver==WL1 ? 21 : ver==SDM ? 26 : 40);
- for(pcm=spre; p<e; p++, pcm++)
+ for(pcm=pcms; p<e; p++, pcm++)
if(*p != Send)
sfxs[*p].pcm = pcm;
sfxs[Sscream3].pcm = sfxs[ver<SDM ? Sscream2 : Sscream4].pcm; /* why */
@@ -761,49 +762,66 @@
}
static void
-audiot(void)
+al(Biobuf *dat, Biobuf *aux, int n)
{
- int n, c;
- u32int v, w;
- uchar *u;
- Sfx *s;
- Biobuf *hed, *dat;
+ int m;
+ u32int v;
+ uchar *p;
+ Sfx *s, *e;
- hed = bopen("audiohed.", OREAD);
- dat = bopen("audiot.", OREAD);
- n = ver < SDM ? Send : Ssend;
- sfxs = emalloc(n * sizeof *sfxs);
- sfxe = sfxs + n;
- u = sndb = emalloc(bsize(dat));
- v = get32(hed);
- for(c=0, s=sfxs; s<sfxe; s++){
- w = get32(hed);
+ s = sfxs = emalloc(n * sizeof *sfxs);
+ e = s + n;
+ while(s < e){
+ v = get32(aux);
Bseek(dat, v, 0);
- if(c++ < n){
- s->pc.sz = w-v;
- s->pc.p = u;
- }else{
- s->al.sz = w-v;
- s->al.p = u;
- }
- u += eread(dat, u, w-v);
- v = w;
- if(c == n)
- s = sfxs-1;
+ m = get32(dat);
+ s->pri = get16(dat);
+ eread(dat, s->inst, sizeof s->inst);
+ Bseek(dat, 6, 1);
+ s->blk = (get8(dat) & 7) << 2 | 1<<5;
+ p = emalloc(m);
+ eread(dat, p, m);
+ s->p = p;
+ s->e = p + m;
+ s++;
}
+}
- Bseek(hed, (n-1)*4, 1);
+static void
+imf(Biobuf *dat, Biobuf *aux)
+{
+ int n;
+ uchar *p;
+ u32int v;
+ Dat *d, *e;
+
n = ver < SDM ? 27 : 24;
- imfs = emalloc(n * sizeof *imfs);
- v = get32(hed);
- for(imfe=imfs; imfe<imfs+n; imfe++){
- w = get32(hed);
+ d = imfs = emalloc(n * sizeof *imfs);
+ e = d + n;
+ while(d < e){
+ v = get32(aux);
Bseek(dat, v, 0);
- imfe->sz = w-v;
- imfe->p = u;
- u += eread(dat, u, w-v);
- v = w;
+ n = get16(dat);
+ d->p = p = emalloc(n);
+ d->e = p + n;
+ eread(dat, p, n);
+ d++;
}
+}
+
+static void
+audiot(void)
+{
+ int n;
+ Biobuf *hed, *dat;
+
+ hed = bopen("audiohed.", OREAD);
+ dat = bopen("audiot.", OREAD);
+ n = ver < SDM ? Send : Ssend;
+ Bseek(hed, n*4, 0);
+ al(dat, hed, n);
+ Bseek(hed, n*4, 1);
+ imf(dat, hed);
Bterm(hed);
Bterm(dat);
@@ -847,7 +865,6 @@
deplane(p, u, s->x*s->y/4);
free(u);
s->p = p;
- s->sz = n;
}
pict = picts[ver];
}
@@ -859,9 +876,11 @@
u32int v, n;
uchar *u, *p;
char *w;
- Fnt *f;
+ Fnt *f, *e;
- for(f=fnts; f<fnts+2; f++){
+ f = fnts;
+ e = f + 2;
+ while(f < e){
v = get24(aux);
Bseek(dat, v, 0);
n = get32(dat);
@@ -874,9 +893,9 @@
*w = *p++;
n -= p-u;
f->p = emalloc(n);
- f->sz = n;
memcpy(f->p, p, n);
free(u);
+ f++;
}
}
@@ -884,23 +903,22 @@
getexts(Biobuf *dat, Biobuf *aux, u16int hf[])
{
int n, m;
- uchar *u;
+ uchar *u, **d, **e;
u32int v;
n = (bsize(aux) - Bseek(aux, 0, 1)) / 3 - 1;
- exts = emalloc(n * sizeof *exts);
- for(exte=exts; exte<exts+n; exte++){
+ d = exts = emalloc(n * sizeof *exts);
+ e = d + n;
+ while(d < e){
v = get24(aux);
Bseek(dat, v, 0);
m = get32(dat);
u = emalloc(m);
unhuff(dat, hf, u, m);
- exte->p = u;
- exte->sz = m;
+ *d++ = u;
}
- dems = exts + (ver==WL6 || ver==SDM ? 3 : ver==SOD ? 13 : 0);
- deme = dems + (ver==WL6 || ver==SOD ? 4 : ver==SDM ? 1 : 0);
- epis = exts + (ver==WL6 ? 7 : 17);
+ dems = exts + (ver < SOD ? 3 : 13);
+ epis = dems + (ver == SDM ? 1 : 4);
}
static void
@@ -942,16 +960,19 @@
void
dat(char *dir)
{
+ char *e;
+
rfork(RFNAMEG);
if(bind(".", dir, MBEFORE|MCREATE) < 0 || chdir(dir) < 0)
fprint(2, "dat: %r\n");
vswap();
gamemaps();
+ e = ext;
if(ver == SOD)
ext = "sod";
audiot();
gfx();
-
+ ext = e;
if(ver >= SDM)
fixpal();
pal = pals[C0];
--- a/game.c
+++ b/game.c
@@ -117,16 +117,10 @@
gx -= viewx;
gy -= viewy;
-//
-// calculate newx
-//
xt = FixedByFrac(gx,viewcos);
yt = FixedByFrac(gy,viewsin);
x = (xt - yt) >> TILESHIFT;
-//
-// calculate newy
-//
xt = FixedByFrac(gx,viewsin);
yt = FixedByFrac(gy,viewcos);
y = (yt + xt) >> TILESHIFT;
@@ -141,14 +135,6 @@
x = ATABLEMAX - 1;
leftchannel = lefttable[x][y + ATABLEMAX];
rightchannel = righttable[x][y + ATABLEMAX];
-
-#if 0
- CenterWindow(8,1);
- US_PrintSigned(leftchannel);
- US_Print(",");
- US_PrintSigned(rightchannel);
- VW_UpdateScreen();
-#endif
}
/*
@@ -1033,12 +1019,11 @@
==================
*/
-void PlayDemo (s16int demonumber)
+void PlayDemo (uchar *p)
{
s16int length;
- /* deme==dems → no demos, etc. */
- demoptr = dems+demonumber;
+ demoptr = p;
NewGame (1,0);
gamestate.mapon = *demoptr++;
--- a/in.c
+++ b/in.c
@@ -1,83 +1,13 @@
-#define KeyInt 9 // The keyboard ISR number
-
-
-/*
-=============================================================================
-
- GLOBAL VARIABLES
-
-=============================================================================
-*/
-
-//
-// configuration variables
-//
-int MousePresent;
-
-
-// Global variables
int Keyboard[NumCodes];
- int Paused;
- char LastASCII;
- u8int LastScan;
KeyboardDef KbdDefs = {0x1d,0x38,0x47,0x48,0x49,0x4b,0x4d,0x4f,0x50,0x51};
ControlType Controls[MaxPlayers];
- u32int MouseDownCount;
-
Demo DemoMode = demo_Off;
u8int _seg *DemoBuffer;
u16int DemoOffset,DemoSize;
-/*
-=============================================================================
- LOCAL VARIABLES
-
-=============================================================================
-*/
-static u8int far ASCIINames[] = // Unshifted ASCII for scan codes
- {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0 ,27 ,'1','2','3','4','5','6','7','8','9','0','-','=',8 ,9 , // 0
- 'q','w','e','r','t','y','u','i','o','p','[',']',13 ,0 ,'a','s', // 1
- 'd','f','g','h','j','k','l',';',39 ,'`',0 ,92 ,'z','x','c','v', // 2
- 'b','n','m',',','.','/',0 ,'*',0 ,' ',0 ,0 ,0 ,0 ,0 ,0 , // 3
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,'7','8','9','-','4','5','6','+','1', // 4
- '2','3','0',127,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 5
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 6
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 // 7
- },
- far ShiftNames[] = // Shifted ASCII for scan codes
- {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0 ,27 ,'!','@','#','$','%','^','&','*','(',')','_','+',8 ,9 , // 0
- 'Q','W','E','R','T','Y','U','I','O','P','{','}',13 ,0 ,'A','S', // 1
- 'D','F','G','H','J','K','L',':',34 ,'~',0 ,'|','Z','X','C','V', // 2
- 'B','N','M','<','>','?',0 ,'*',0 ,' ',0 ,0 ,0 ,0 ,0 ,0 , // 3
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,'7','8','9','-','4','5','6','+','1', // 4
- '2','3','0',127,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 5
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 6
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 // 7
- },
- far SpecialNames[] = // ASCII for 0xe0 prefixed codes
- {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 0
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,13 ,0 ,0 ,0 , // 1
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 2
- 0 ,0 ,0 ,0 ,0 ,'/',0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 3
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 4
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 5
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 6
- 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 // 7
- };
-
-
-static int CapsLock;
-static u8int CurCode,LastCode;
-
static Direction DirTable[] = // Quick lookup for total direction
{
dir_NorthWest, dir_North, dir_NorthEast,
@@ -85,204 +15,7 @@
dir_SouthWest, dir_South, dir_SouthEast
};
-static void (*INL_KeyHook)(void);
-static void interrupt (*OldKeyVect)(void);
-
-// Internal routines
-
-///////////////////////////////////////////////////////////////////////////
-//
-// INL_KeyService() - Handles a keyboard interrupt (key up/down)
-//
-///////////////////////////////////////////////////////////////////////////
-static void interrupt
-INL_KeyService(void)
-{
-static int special;
- u8int k,c,
- temp;
- s16int i;
-
- k = inportb(0x60); // Get the scan code
-
- // Tell the XT keyboard controller to clear the key
- outportb(0x61,(temp = inportb(0x61)) | 0x80);
- outportb(0x61,temp);
-
- if (k == 0xe0) // Special key prefix
- special = true;
- else if (k == 0xe1) // Handle Pause key
- Paused = true;
- else
- {
- if (k & 0x80) // Break code
- {
- k &= 0x7f;
-
-// DEBUG - handle special keys: ctl-alt-delete, print scrn
-
- Keyboard[k] = false;
- }
- else // Make code
- {
- LastCode = CurCode;
- CurCode = LastScan = k;
- Keyboard[k] = true;
-
- if (special)
- c = SpecialNames[k];
- else
- {
- if (k == sc_CapsLock)
- {
- CapsLock ^= true;
- // DEBUG - make caps lock light work
- }
-
- if (Keyboard[sc_LShift] || Keyboard[sc_RShift]) // If shifted
- {
- c = ShiftNames[k];
- if ((c >= 'A') && (c <= 'Z') && CapsLock)
- c += 'a' - 'A';
- }
- else
- {
- c = ASCIINames[k];
- if ((c >= 'a') && (c <= 'z') && CapsLock)
- c -= 'a' - 'A';
- }
- }
- if (c)
- LastASCII = c;
- }
-
- special = false;
- }
-
- if (INL_KeyHook && !special)
- INL_KeyHook();
- outportb(0x20,0x20);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// INL_GetMouseDelta() - Gets the amount that the mouse has moved from the
-// mouse driver
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-INL_GetMouseDelta(s16int *x,s16int *y)
-{
- Mouse(MDelta);
- *x = _CX;
- *y = _DX;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// INL_GetMouseButtons() - Gets the status of the mouse buttons from the
-// mouse driver
-//
-///////////////////////////////////////////////////////////////////////////
-static u16int
-INL_GetMouseButtons(void)
-{
- u16int buttons;
-
- Mouse(MButtons);
- buttons = _BX;
- return(buttons);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// INL_StartKbd() - Sets up my keyboard stuff for use
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-INL_StartKbd(void)
-{
- INL_KeyHook = NULL; // no key hook routine
-
- IN_ClearKeysDown();
-
- OldKeyVect = getvect(KeyInt);
- setvect(KeyInt,INL_KeyService);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// IN_Startup() - Starts up the Input Mgr
-//
-///////////////////////////////////////////////////////////////////////////
void
-IN_Startup(void)
-{
- INL_StartKbd();
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// IN_Default() - Sets up default conditions for the Input Mgr
-//
-///////////////////////////////////////////////////////////////////////////
-void
-IN_Default(int gotit,ControlType in)
-{
- if
- (
- (!gotit)
- || ((in == ctrl_Mouse) && !MousePresent)
- )
- in = ctrl_Keyboard1;
- IN_SetControlType(0,in);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// IN_Shutdown() - Shuts down the Input Mgr
-//
-///////////////////////////////////////////////////////////////////////////
-void
-IN_Shutdown(void)
-{
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// IN_SetKeyHook() - Sets the routine that gets called by INL_KeyService()
-// everytime a real make/break code gets hit
-//
-///////////////////////////////////////////////////////////////////////////
-void
-IN_SetKeyHook(void (*hook)())
-{
- INL_KeyHook = hook;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// IN_ClearKeysDown() - Clears the keyboard array
-//
-///////////////////////////////////////////////////////////////////////////
-void
-IN_ClearKeysDown(void)
-{
- s16int i;
-
- LastScan = sc_None;
- LastASCII = key_None;
- memset (Keyboard,0,sizeof(Keyboard));
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-//
-// IN_ReadControl() - Reads the device associated with the specified
-// player and fills in the control info struct
-//
-///////////////////////////////////////////////////////////////////////////
-void
IN_ReadControl(s16int player,ControlInfo *info)
{
int realdelta;
@@ -399,157 +132,4 @@
DemoBuffer[DemoOffset + 1] = dbyte;
}
}
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// IN_SetControlType() - Sets the control type to be used by the specified
-// player
-//
-///////////////////////////////////////////////////////////////////////////
-void
-IN_SetControlType(s16int player,ControlType type)
-{
- // DEBUG - check that requested type is present?
- Controls[player] = type;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// IN_WaitForKey() - Waits for a scan code, then clears LastScan and
-// returns the scan code
-//
-///////////////////////////////////////////////////////////////////////////
-u8int
-IN_WaitForKey(void)
-{
- u8int result;
-
- while (!(result = LastScan))
- ;
- LastScan = 0;
- return(result);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and
-// returns the ASCII value
-//
-///////////////////////////////////////////////////////////////////////////
-char
-IN_WaitForASCII(void)
-{
- char result;
-
- while (!(result = LastASCII))
- ;
- LastASCII = '\0';
- return(result);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// IN_Ack() - waits for a button or key press. If a button is down, upon
-// calling, it must be released for it to be recognized
-//
-///////////////////////////////////////////////////////////////////////////
-
-int btnstate[8];
-
-void IN_StartAck(void)
-{
- u16int i,buttons;
-
-//
-// get initial state of everything
-//
- IN_ClearKeysDown();
- memset (btnstate,0,sizeof(btnstate));
-
- if (MousePresent)
- buttons |= IN_MouseButtons ();
-
- for (i=0;i<8;i++,buttons>>=1)
- if (buttons&1)
- btnstate[i] = true;
-}
-
-
-int IN_CheckAck (void)
-{
- u16int i,buttons;
-
-//
-// see if something has been pressed
-//
- if (LastScan)
- return true;
-
- if (MousePresent)
- buttons |= IN_MouseButtons ();
-
- for (i=0;i<8;i++,buttons>>=1)
- if ( buttons&1 )
- {
- if (!btnstate[i])
- return true;
- }
- else
- btnstate[i]=false;
-
- return false;
-}
-
-
-void IN_Ack (void)
-{
- IN_StartAck ();
-
- while (!IN_CheckAck ())
- ;
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-//
-// IN_UserInput() - Waits for the specified delay time (in ticks) or the
-// user pressing a key or a mouse button. If the clear flag is set, it
-// then either clears the key or waits for the user to let the mouse
-// button up.
-//
-///////////////////////////////////////////////////////////////////////////
-int IN_UserInput(u32int delay)
-{
- u32int lasttime;
-
- lasttime = TimeCount;
- IN_StartAck ();
- do
- {
- if (IN_CheckAck())
- return true;
- } while (TimeCount - lasttime < delay);
- return(false);
-}
-
-//===========================================================================
-
-/*
-===================
-=
-= IN_MouseButtons
-=
-===================
-*/
-
-u8int IN_MouseButtons (void)
-{
- if (MousePresent)
- {
- Mouse(MButtons);
- return _BX;
- }
- else
- return 0;
}
--- a/in.h
+++ b/in.h
@@ -1,97 +1,6 @@
-//
-// ID Engine
-// ID_IN.h - Header file for Input Manager
-// v1.0d1
-// By Jason Blochowiak
-//
-
#define MaxPlayers 4
-#define MaxKbds 2
#define NumCodes 128
-#define sc_None 0
-#define sc_Bad 0xff
-#define sc_Return 0x1c
-#define sc_Enter sc_Return
-#define sc_Escape 0x01
-#define sc_Space 0x39
-#define sc_BackSpace 0x0e
-#define sc_Tab 0x0f
-#define sc_Alt 0x38
-#define sc_Control 0x1d
-#define sc_CapsLock 0x3a
-#define sc_LShift 0x2a
-#define sc_RShift 0x36
-#define sc_UpArrow 0x48
-#define sc_DownArrow 0x50
-#define sc_LeftArrow 0x4b
-#define sc_RightArrow 0x4d
-#define sc_Insert 0x52
-#define sc_Delete 0x53
-#define sc_Home 0x47
-#define sc_End 0x4f
-#define sc_PgUp 0x49
-#define sc_PgDn 0x51
-#define sc_F1 0x3b
-#define sc_F2 0x3c
-#define sc_F3 0x3d
-#define sc_F4 0x3e
-#define sc_F5 0x3f
-#define sc_F6 0x40
-#define sc_F7 0x41
-#define sc_F8 0x42
-#define sc_F9 0x43
-#define sc_F10 0x44
-#define sc_F11 0x57
-#define sc_F12 0x59
-
-#define sc_1 0x02
-#define sc_2 0x03
-#define sc_3 0x04
-#define sc_4 0x05
-#define sc_5 0x06
-#define sc_6 0x07
-#define sc_7 0x08
-#define sc_8 0x09
-#define sc_9 0x0a
-#define sc_0 0x0b
-
-#define sc_A 0x1e
-#define sc_B 0x30
-#define sc_C 0x2e
-#define sc_D 0x20
-#define sc_E 0x12
-#define sc_F 0x21
-#define sc_G 0x22
-#define sc_H 0x23
-#define sc_I 0x17
-#define sc_J 0x24
-#define sc_K 0x25
-#define sc_L 0x26
-#define sc_M 0x32
-#define sc_N 0x31
-#define sc_O 0x18
-#define sc_P 0x19
-#define sc_Q 0x10
-#define sc_R 0x13
-#define sc_S 0x1f
-#define sc_T 0x14
-#define sc_U 0x16
-#define sc_V 0x2f
-#define sc_W 0x11
-#define sc_X 0x2d
-#define sc_Y 0x15
-#define sc_Z 0x2c
-
-#define key_None 0
-#define key_Return 0x0d
-#define key_Enter key_Return
-#define key_Escape 0x1b
-#define key_Space 0x20
-#define key_BackSpace 0x08
-#define key_Tab 0x09
-#define key_Delete 0x7f
-
// Stuff for the mouse
#define MReset 0
#define MButtons 3
@@ -149,24 +58,3 @@
#define IN_KeyDown(code) (Keyboard[(code)])
#define IN_ClearKey(code) {Keyboard[code] = false;\
if (code == LastScan) LastScan = sc_None;}
-
-// DEBUG - put names in prototypes
-extern void IN_Startup(void),IN_Shutdown(void),
- IN_Default(int gotit,ControlType in),
- IN_SetKeyHook(void (*)()),
- IN_ClearKeysDown(void),
- IN_ReadCursor(CursorInfo *),
- IN_ReadControl(s16int,ControlInfo *),
- IN_SetControlType(s16int,ControlType),
- IN_StopDemo(void),IN_FreeDemoBuffer(void),
- IN_Ack(void),IN_AckBack(void);
-extern int IN_UserInput(u32int delay);
-extern char IN_WaitForASCII(void);
-extern u8int IN_WaitForKey(void);
-extern u8int *IN_GetScanName(u8int);
-
-
-u8int IN_MouseButtons (void);
-
-void IN_StartAck(void);
-int IN_CheckAck (void);
--- a/main.c
+++ b/main.c
@@ -490,27 +490,7 @@
return true;
}
-//===========================================================================
-
/*
-==========================
-=
-= ShutdownId
-=
-= Shuts down all ID_?? managers
-=
-==========================
-*/
-
-void ShutdownId (void)
-{
- SD_Shutdown ();
-}
-
-
-//===========================================================================
-
-/*
==================
=
= BuildTables
@@ -671,7 +651,6 @@
s16int i,x,y;
u16int *blockstart;
- SD_Startup ();
mapon = -1;
//
@@ -803,8 +782,6 @@
screen = Eerror;
}
- ShutdownId ();
-
if (error && *error)
{
movedata ((u16int)screen,7,0xb800,0,7*160);
@@ -887,6 +864,7 @@
while (1)
{
+ uchar *p = dems;
while (!NoWait)
{
//
@@ -928,12 +906,9 @@
//
// demo
//
-
- #ifndef SPEARDEMO
- PlayDemo (LastDemo++%4);
- #else
- PlayDemo (0);
- #endif
+ PlayDemo(p++);
+ if(p >= epis)
+ p = dems;
if (playstate == ex_abort)
break;
--- a/map.c
+++ b/map.c
@@ -3,4 +3,4 @@
#include "dat.h"
#include "fns.h"
-Dat *maps, *mape, *map;
+uchar **maps, *map;
--- a/mkfile
+++ b/mkfile
@@ -1,13 +1,16 @@
</$objtype/mkfile
-BIN=$home/bin/$objtype
-TARG=wl3d
+TARG=\
+ opl2\
+ wl3d\
-OFILES=\
+OFILES=
+WOFILES=\
fs.$O\
gm.$O\
map.$O\
mn.$O\
+ opl2.$O\
rend.$O\
snd.$O\
wl3d.$O\
@@ -14,4 +17,11 @@
HFILES= dat.h fns.h
-</sys/src/cmd/mkone
+</sys/src/cmd/mkmany
+BIN=$home/bin/$objtype
+
+$O.wl3d: $WOFILES
+ $LD -o $target $prereq
+
+$O.opl2: opl2.$O opl2m.$O
+ $LD -o $target $prereq
--- a/mn.c
+++ b/mn.c
@@ -325,7 +325,8 @@
m = i->m;
if(m == nil)
break;
- sfx(Sshoot);
+ if(m != ml+Lquit && m != ml+Lesc)
+ sfx(Sshoot);
reset(m);
}
if(r != 'i')
@@ -368,7 +369,7 @@
{
pic(0, 0, pict[Pid1]);
pic(0, 80, pict[Pid2]);
- palpic(exts[Eid].p);
+ palpic(exts[Eid]);
fadeop(mp->c, mp->qs->dt);
mus(Mnazjazz);
}
@@ -458,7 +459,7 @@
{
pic(0, 0, pict[Ptitle1]);
pic(0, 80, pict[Ptitle2]);
- palpic(exts[Etitpal].p);
+ palpic(exts[Etitpal]);
mus(Mtower);
}
--- /dev/null
+++ b/opl2.c
@@ -1,0 +1,740 @@
+#include <u.h>
+#include <libc.h>
+
+typedef char s8int;
+typedef short s16int;
+typedef int s32int;
+typedef struct Envelope Envelope;
+typedef struct Phase Phase;
+typedef struct Op Op;
+typedef struct Chan Chan;
+
+enum{
+ Rwse = 0x01,
+ Mwse = 1<<5, /* wave selection enable */
+ Rcsm = 0x08,
+ Mnse = 1<<6, /* note selection enable */
+ Rctl = 0x20,
+ Mame = 1<<7, /* enable amplitude modulation */
+ Mvbe = 1<<6, /* enable vibrato */
+ Msse = 1<<5, /* enable sustain */
+ Mkse = 1<<4, /* enable keyboard scaling */
+ Mmfq = 15<<0, /* modulator freq multiple */
+ Rsca = 0x40,
+ Mlvl = 63<<0, /* total level */
+ Mscl = 3<<6, /* scaling level */
+ Ratk = 0x60,
+ Mdec = 15<<0, /* decay rate */
+ Matk = 15<<4, /* attack rate */
+ Rsus = 0x80,
+ Mrel = 15<<0, /* release rate */
+ Msus = 15<<4, /* sustain level */
+ Rnum = 0xa0, /* f number lsb */
+ Roct = 0xb0,
+ Mmsb = 3<<0, /* f number msb */
+ Moct = 7<<2,
+ Mkon = 1<<5,
+ Ropm = 0xbd,
+ Mamp = 1<<7, /* amplitude mod depth */
+ Mvib = 1<<6, /* vibrato depth */
+ Mrms = 63<<0,
+ Mrhy = 1<<5, /* rhythm enable */
+ Mbas = 1<<4,
+ Msna = 1<<3,
+ Mtom = 1<<2,
+ Mcym = 1<<1,
+ Mhat = 1<<0,
+ Rfed = 0xc0,
+ Mmod = 1<<0, /* enable operator modulation */
+ Mfed = 7<<1, /* feedback strength */
+ Rwav = 0xe0,
+ Mwav = 3<<0,
+
+ Sfreq = 16,
+ Sfreqd = Sfreq - 10,
+ Seg = 16,
+ Slfo = 24,
+ Stm = 16,
+
+ Mfreq = (1 << Sfreq) - 1,
+
+ Lampb = 12,
+ Lsignb = 2,
+ Ly = Lampb * Lsignb,
+ Lx = 256,
+ Lxy = Lx * Ly,
+
+ Sinb = 10,
+ Sinlen = 1<<Sinb,
+ Sinm = Sinlen - 1,
+ Nsines = 4,
+
+ Erstep = 8,
+ Equiet = Lxy >> 4,
+ Eb = 10,
+ Elen = 1 << Eb,
+ Nerates = 16 + 16 * 4 + 16, /* infinite, regular, dummy */
+ Nlfoa = 210,
+ Attmax = (1 << Eb-1) - 1,
+ Attmin = 0
+};
+#define Clk 3579545.0
+#define Estep (128.0/Elen)
+
+enum{
+ Eoff,
+ Erel,
+ Esus,
+ Edec,
+ Eatk,
+};
+struct Envelope{
+ int state;
+ int key;
+ int son;
+ int sus;
+ int atksh;
+ int atk;
+ int decsh;
+ int dec;
+ int relsh;
+ int rel;
+ int lvl0;
+ int lvl;
+ s32int vol;
+ u32int tl;
+};
+struct Phase{
+ u32int fq;
+ u32int dfq;
+ int fbv;
+ int opmodoff;
+ int out[2];
+ int *p;
+};
+struct Op{
+ Envelope;
+ Phase;
+ int Aon;
+ int φon;
+ int atkn;
+ int decn;
+ int reln;
+ int mul;
+ int scl;
+ int ks;
+ int kssh;
+ u16int wav;
+};
+struct Chan{
+ Op *op;
+ u32int scl0;
+ u32int dfq0;
+ int fn;
+ int oct;
+ int kcode;
+};
+static int lta[Lxy];
+static uint sint[Sinlen * Nsines];
+static int wse, nse, rhythm;
+static u32int noise, noiseφ, noiseT;
+static u32int egtic, egt, egdt, egfdt;
+static u32int lfoA, lfoAt, lfoAdt, lfoφt, lfoφdt;
+static s32int lfoφ;
+static int lfoAd, lfoφd;
+static Chan chs[9];
+static Op ops[2*nelem(chs)];
+static int φmod, tout;
+
+static u32int fn[1024]; /* 20bit φ increment counter */
+/* 27 output levels (triangle waveform), 1 level takes one of 192, 256 or 448
+ * samples. each value is repeated on 64 consecutive samples. total length is
+ * then 64*210 samples. when am=1 data is used directly, else it is shl 2 before
+ * use. */
+static u8int lfoAs[Nlfoa] = {
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5,
+ 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10,
+ 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15,
+ 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
+ 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24,
+ 24, 24, 25, 25, 25, 25, 26, 26, 26, 25, 25, 25, 25, 24, 24, 24, 24, 23,
+ 23, 23, 23, 22, 22, 22, 22, 21, 21, 21, 21, 20, 20, 20, 20, 19, 19, 19,
+ 19, 18, 18, 18, 18, 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 14,
+ 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10,
+ 10, 9, 9, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4,
+ 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1
+};
+/* 8 output 1024 samples long levels (triangle waveform) with 16 values (depth 0
+ * then depth 1) each */
+static s8int lfoφs[8*8*2] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0,
+ 1, 0, 0, 0, -1, 0, 0, 0, 2, 1, 0, -1, -2, -1, 0, 1,
+ 1, 0, 0, 0, -1, 0, 0, 0, 3, 1, 0, -1, -3, -1, 0, 1,
+ 2, 1, 0, -1, -2, -1, 0, 1, 4, 2, 0, -2, -4, -2, 0, 2,
+ 2, 1, 0, -1, -2, -1, 0, 1, 5, 2, 0, -2, -5, -2, 0, 2,
+ 3, 1, 0, -1, -3, -1, 0, 1, 6, 3, 0, -3, -6, -3, 0, 3,
+ 3, 1, 0, -1, -3, -1, 0, 1, 7, 3, 0, -3, -7, -3, 0, 3
+};
+static uchar mul[16] = {
+ 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30
+};
+#define O (0.1875 / 2.0) /* convert 3 dB/oct → 6 dB/oct */
+static u32int lsca[8 * 16] = { /* 0.1875: bit0 weight of op->vol in dB */
+ 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O,
+ 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O,
+ 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O,
+ 0.000/O, 0.750/O, 1.125/O, 1.500/O, 1.875/O, 2.250/O, 2.625/O, 3.000/O,
+ 0.000/O, 0.000/O, 0.000/O, 0.000/O, 0.000/O, 1.125/O, 1.875/O, 2.625/O,
+ 3.000/O, 3.750/O, 4.125/O, 4.500/O, 4.875/O, 5.250/O, 5.625/O, 6.000/O,
+ 0.000/O, 0.000/O, 0.000/O, 1.875/O, 3.000/O, 4.125/O, 4.875/O, 5.625/O,
+ 6.000/O, 6.750/O, 7.125/O, 7.500/O, 7.875/O, 8.250/O, 8.625/O, 9.000/O,
+ 0.000/O, 0.000/O, 3.000/O, 4.875/O, 6.000/O, 7.125/O, 7.875/O, 8.625/O,
+ 9.000/O, 9.750/O, 10.125/O, 10.500/O, 10.875/O, 11.250/O, 11.625/O,
+ 12.000/O,
+ 0.000/O, 3.000/O, 6.000/O, 7.875/O, 9.000/O, 10.125/O, 10.875/O,
+ 11.625/O, 12.000/O, 12.750/O, 13.125/O, 13.500/O, 13.875/O, 14.250/O,
+ 14.625/O, 15.000/O,
+ 0.000/O, 6.000/O, 9.000/O, 10.875/O, 12.000/O, 13.125/O, 13.875/O,
+ 14.625/O, 15.000/O, 15.750/O, 16.125/O, 16.500/O, 16.875/O, 17.250/O,
+ 17.625/O, 18.000/O,
+ 0.000/O, 9.000/O, 12.000/O, 13.875/O, 15.000/O, 16.125/O, 16.875/O,
+ 17.625/O, 18.000/O, 18.750/O, 19.125/O, 19.500/O, 19.875/O, 20.250/O,
+ 20.625/O, 21.000/O
+};
+#undef O
+#define O(n) (n * (2.0/Estep)) /* n*3 dB */
+static u32int sust[16] = {
+ O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7), O(8), O(9), O(10),
+ O(11), O(12), O(13), O(14), O(31)
+};
+#undef O
+static uchar estep[15*Erstep] = {
+ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1, /* rate 0-12 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
+ 1, 2, 2, 2, 1, 2, 2, 2, /* rate 13 */
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4,
+ 2, 4, 4, 4, 2, 4, 4, 4, /* rate 14 */
+ 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, /* rate 15 + atk */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* rate ∞ (atk/dec) */
+};
+#define O(n) (n * Erstep)
+static uchar erate[Nerates] = { /* O(13) is directly in code */
+ O(14), O(14), O(14), O(14), O(14), O(14), O(14), O(14), O(14), O(14),
+ O(14), O(14), O(14), O(14), O(14), O(14), O(0), O(1), O(2), O(3), O(0),
+ O(1), O(2), O(3), O(0), O(1), O(2), O(3), O(0), O(1), O(2), O(3), O(0),
+ O(1), O(2), O(3), O(0), O(1), O(2), O(3), O(0), O(1), O(2), O(3), O(0),
+ O(1), O(2), O(3), O(0), O(1), O(2), O(3), O(0), O(1), O(2), O(3), O(0),
+ O(1), O(2), O(3), O(0), O(1), O(2), O(3), O(0), O(1), O(2), O(3), O(4),
+ O(5), O(6), O(7), O(8), O(9), O(10), O(11), O(12), O(12), O(12), O(12),
+ O(12), O(12), O(12), O(12), O(12), O(12), O(12), O(12), O(12), O(12),
+ O(12), O(12), O(12), O(12), O(12), O(12)
+};
+#undef O
+static uchar eratesh[Nerates] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 12, 11, 11,
+ 11, 11, 10, 10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
+ 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
+void opl2wr(int, int);
+
+/* 23-bit shift register noise generator. T=2²³-2 samples, sampling rate equal
+ * to that of the chip. */
+static void
+noiseg(void)
+{
+ int i;
+
+ noiseφ += noiseT;
+ i = noiseφ >> Sfreq;
+ noiseφ &= Mfreq;
+ while(i-- > 0){
+ if(noise & 1)
+ noise ^= 0x800302;
+ noise >>= 1;
+ }
+}
+
+static void
+advlfo(void)
+{
+ int a;
+
+ lfoAt += lfoAdt;
+ if(lfoAt >= (u32int)Nlfoa << Slfo)
+ lfoAt -= (u32int)Nlfoa << Slfo;
+ a = lfoAs[lfoAt >> Slfo];
+ lfoA = lfoAd ? a : a>>2;
+ lfoφt += lfoφdt;
+ lfoφ = lfoφt >> Slfo & 7 | lfoφd;
+}
+
+static void
+adv(void)
+{
+ int i, f, oc, v;
+ Chan *c;
+ Op *o;
+
+ egt += egfdt;
+ while(egt >= egdt){
+ egt -= egdt;
+ egtic++;
+ o = ops;
+ while(o < ops + nelem(ops)){
+ switch(o->state){
+ case Eatk:
+ if(egtic & (1 << o->atksh)-1)
+ break;
+ v = o->atk + (egtic >> o->atksh & 7);
+ /* sign extend it */
+ o->vol += (s32int)(~o->vol * estep[v]) >> 3;
+ if(o->vol <= Attmin){
+ o->vol = Attmin;
+ o->state = Edec;
+ }
+ break;
+ case Edec:
+ if(egtic & (1 << o->decsh)-1)
+ break;
+ v = o->dec + (egtic >> o->decsh & 7);
+ o->vol += estep[v];
+ if(o->vol >= o->sus)
+ o->state = Esus;
+ break;
+ case Esus:
+ if(o->son || egtic & (1 << o->relsh)-1)
+ break;
+ v = o->rel + (egtic >> o->relsh & 7);
+ o->vol += estep[v];
+ if(o->vol >= Attmax)
+ o->vol = Attmax;
+ break;
+ case Erel:
+ if(egtic & (1 << o->relsh)-1)
+ break;
+ v = o->rel + (egtic >> o->relsh & 7);
+ o->vol += estep[v];
+ if(o->vol >= Attmax){
+ o->vol = Attmax;
+ o->state = Eoff;
+ }
+ break;
+ }
+ o++;
+ }
+ }
+ o = ops;
+ while(o < ops + nelem(ops)){
+ c = chs + (o-ops)/2;
+ if(o->φon){
+ f = c->fn;
+ i = lfoφs[lfoφ + (f >> 7 << 4)];
+ if(i != 0){
+ f += i;
+ oc = 7 - c->oct + (f >> 10);
+ o->fq += (fn[f & 0x3ff] >> oc) * o->mul;
+ }else
+ o->fq += o->dfq;
+ }else
+ o->fq += o->dfq;
+ o++;
+ }
+ noiseg();
+}
+
+static int
+op(u32int φ, u32int v, int dφ, u16int w)
+{
+ u32int p;
+
+ p = (v<<4) + sint[w + ((int)((φ & ~Mfreq) + dφ) >> Sfreq & Sinm)];
+ return p < Lxy ? lta[p] : 0;
+}
+
+static void
+chan(Op *o)
+{
+ u32int v;
+ int out;
+
+ φmod = 0;
+ out = o->out[0] + o->out[1];
+ o->out[0] = o->out[1];
+ *o->p += o->out[0];
+ o->out[1] = 0;
+ v = o->tl;
+ if(v < Equiet){
+ if(o->fbv == 0)
+ out = 0;
+ o->out[1] = op(o->fq, v, out << o->fbv, o->wav);
+ }
+ o++, v = o->tl;
+ if(v < Equiet)
+ tout += op(o->fq, v, φmod << 16, o->wav);
+}
+
+static void
+rchan(void)
+{
+ int out, nr;
+ u32int u, v;
+ Op *o;
+
+ nr = noise & 1;
+ φmod = 0;
+ o = chs[6].op;
+ out = o->out[0] + o->out[1];
+ o->out[0] = o->out[1];
+ if(o->opmodoff == 0)
+ φmod = o->out[0];
+ o->out[1] = 0;
+
+ v = o->tl;
+ if(v < Equiet){
+ if(o->fbv == 0)
+ out = 0;
+ o->out[1] = op(o->fq, v, out << o->fbv, o->wav);
+ }
+ o++, v = o->tl;
+ if(v < Equiet)
+ tout += op(o->fq, v, φmod << 16, o->wav) * 2;
+ o++, v = o->tl;
+ if(v < Equiet){
+ u = ops[17].fq >> Sfreq;
+ if((u ^ u<<2) & 1<<5)
+ u = 0x200 | 0xd0 >> 2;
+ else{
+ u = o->fq >> Sfreq;
+ u = ((u ^ u<<5 | u<<4) & 1<<7) ? 0x200 | 0xd0>>2 : 0xd0;
+ }
+ if(nr)
+ u = u & 0x200 ? 0x200 | 0xd0 : 0xd0>>2;
+ tout += op(u << Sfreq, v, 0, o->wav) * 2;
+ }
+ o++, v = o->tl;
+ if(v < Equiet){
+ u = (ops[14].fq >> Sfreq & 1<<8) ? 1<<9 : 1<<8;
+ u = (u ^ nr << 8) << Sfreq;
+ tout += op(u, v, 0, o->wav) * 2;
+ }
+ o++, v = o->tl;
+ if(v < Equiet)
+ tout += op(o->fq, v, 0, o->wav) * 2;
+ o++, v = o->tl;
+ if(v < Equiet){
+ u = o->fq >> Sfreq;
+ if((u ^ u<<2) & 1<<5)
+ u = 0x300;
+ else{
+ u = ops[14].fq >> Sfreq;
+ u = ((u ^ u<<5 | u<<4) & 1<<7) ? 0x300 : 0x100;
+ }
+ tout += op(u << Sfreq, v, 0, o->wav) * 2;
+ }
+}
+
+static void
+setk(Op *o, int k, int on)
+{
+ if(on){
+ if(o->key == 0){
+ o->fq = 0;
+ o->state = Eatk;
+ }
+ o->key |= k;
+ }else{
+ if(o->key == 0)
+ return;
+
+ o->key &= ~k;
+ if(o->key == 0 && o->state > Erel)
+ o->state = Erel;
+ }
+}
+
+static void
+upop(Chan *c, Op *o)
+{
+ int n;
+
+ o->dfq = c->dfq0 * o->mul;
+ n = c->kcode >> o->kssh;
+
+ if(o->ks != n){
+ o->ks = n;
+ if(o->atkn + n < 16+62){
+ o->atksh = eratesh[o->atkn + n];
+ o->atk = erate[o->atkn + n];
+ }else{
+ o->atksh = 0;
+ o->atk = 13 * Erstep;
+ }
+ o->decsh = eratesh[o->decn + n];
+ o->dec = erate[o->decn + n];
+ o->relsh = eratesh[o->reln + n];
+ o->rel = erate[o->reln + n];
+ }
+}
+
+static void
+ctl(Chan *c, Op *o, int v)
+{
+ o->mul = mul[v & Mmfq];
+ o->kssh = v & Mkse ? 0 : 2;
+ o->son = v & Msse;
+ o->φon = v & Mvbe;
+ o->Aon = v & Mame ? ~0 : 0;
+ upop(c, o);
+}
+
+static void
+sca(Chan *c, Op *o, int v)
+{
+ uchar u;
+
+ u = v >> 6;
+ o->scl = u ? u % 3 : 31; /* shift to 0, 3, 1.5, 6 dB/oct */
+ o->lvl0 = (v & Mlvl) << Eb-1-7;
+ o->lvl = o->lvl0 + (c->scl0 >> o->scl);
+}
+
+static void
+atkdec(Op *o, int v)
+{
+ int a, n;
+
+ n = o->ks;
+ o->atkn = a = v >> 4 ? 16 + (v >> 4 << 2) : 0;
+ a += n;
+ if(a < 16+62){
+ o->atksh = eratesh[a];
+ o->atk = erate[a];
+ }else{
+ o->atksh = 0;
+ o->atk = 13 * Erstep;
+ }
+ o->decn = a = v & Mdec ? 16 + ((v & Mdec) << 2) : 0;
+ a += n;
+ o->decsh = eratesh[a];
+ o->dec = erate[a];
+}
+
+static void
+susrel(Op *o, int v)
+{
+ o->sus = sust[v >> 4];
+ o->reln = v & Mrel ? 16 + ((v & Mrel) << 2) : 0;
+ o->relsh = eratesh[o->reln + o->ks];
+ o->rel = erate[o->reln + o->ks];
+}
+
+static void
+opm(int v)
+{
+ lfoAd = v & Mamp;
+ lfoφd = v & Mvib ? 8 : 0;
+ rhythm = v & Mrms;
+ if(v & ~Mrhy)
+ v = 0;
+ setk(chs[6].op, 2, v & Mbas);
+ setk(chs[6].op+1, 2, v & Mbas);
+ setk(chs[7].op, 2, v & Mhat);
+ setk(chs[7].op+1, 2, v & Msna);
+ setk(chs[8].op, 2, v & Mtom);
+ setk(chs[8].op+1, 2, v & Mcym);
+}
+
+static void
+foct(int r, int v)
+{
+ int n, b, o, f;
+ u32int u;
+ Chan *c;
+ Op *op0, *op1;
+
+ n = r & 0xf;
+ if(n > 8)
+ return;
+ c = chs+n;
+ op0 = c->op;
+ op1 = op0 + 1;
+ o = c->oct;
+ if(r & 0x10){ /* Roct */
+ f = c->fn & 0xff | (v & Mmsb) << 8;
+ o = (v & Moct) >> 2;
+ setk(op0, 1, v & Mkon);
+ setk(op1, 1, v & Mkon);
+ }else
+ f = c->fn & 0x300 | v;
+ b = f | o << 10;
+
+ if(c->fn != f || c->oct != o){
+ c->fn = f;
+ c->oct = o;
+ c->scl0 = u = lsca[b >> 6];
+ c->dfq0 = fn[f] >> 7 - o;
+ /* ignore manual full of lies */
+ c->kcode = o << 1 | (nse ? f >> 8 : f >> 9) & 1;
+ op0->lvl = op0->lvl0 + (u >> op0->scl);
+ op1->lvl = op1->lvl0 + (u >> op1->scl);
+ upop(c, op0);
+ upop(c, op1);
+ }
+}
+
+static void
+feedb(int r, int v)
+{
+ int n;
+ Op *o;
+
+ if(r > 8)
+ return;
+ n = v & Mmod;
+ v = (v & Mfed) >> 1;
+ o = chs[r].op;
+ o->opmodoff = n;
+ o->fbv = v ? v + 7 : 0;
+ o->p = n ? &tout : &φmod;
+}
+
+static void
+tab(void)
+{
+ int i, x, n, *l, *p;
+ uint *s;
+ double o, m;
+
+ for(x=0; x<Lx; x++){
+ m = (1<<16) / pow(2, (x+1) * (Estep/4.0) / 8.0);
+ m = floor(m);
+ n = (int)m >> 4; /* always fits in 12 (16) bits */
+ n = (n>>1) + (n&1) << 1; /* rnr */
+ l = lta + x*2;
+ l[0] = n;
+ l[1] = -n;
+ for(i=1, p=l; i<12; i++){
+ p += 2*Lx;
+ p[0] = n >> i;
+ p[1] = -(n >> i);
+ }
+ }
+
+ for(i=0, s=sint; i<Sinlen; i++){
+ m = sin((i*2+1) * PI / Sinlen);
+ o = 8 * log((m > 0.0 ? 1.0 : -1.0)/m) / log(2.0); /* dB */
+ o /= Estep / 4.0;
+ n = o * 2.0;
+ n = (n>>1) + (n&1); /* rnr */
+ *s++ = n*2 + (m >= 0.0 ? 0 : 1);
+ }
+ for(i=0, s=sint; i<Sinlen; i++, s++){
+ /* half-sine, abs-sine, pulse-sine */
+ s[Sinlen] = i & 1<<Sinb-1 ? Lxy : *s;
+ s[Sinlen*2] = sint[i & Sinm>>1];
+ s[Sinlen*3] = i & 1<<Sinb-2 ? Lxy : sint[i & Sinm>>2];
+ }
+}
+
+uchar *
+opl2out(uchar *s, int n)
+{
+ int v, r;
+ uchar *e;
+ Op *o;
+
+ r = rhythm & Mrhy;
+ e = s + n;
+ while(s < e){
+ tout = 0;
+ advlfo();
+ for(o=ops; o<ops+nelem(ops); o++)
+ o->tl = o->lvl + (u32int)o->vol + (lfoA & o->Aon);
+ for(o=ops; o<ops+nelem(ops); o+=2){
+ if(o == ops+6*2 && r){
+ rchan();
+ break;
+ }
+ chan(o);
+ }
+ v = tout;
+ if(v > 32767)
+ v = 32767;
+ else if(v < -32768)
+ v = -32768;
+ s[0] = s[2] = v;
+ s[1] = s[3] = v>>8;
+ s += 4;
+ adv();
+ }
+ return s;
+}
+
+void
+opl2wr(int r, int v)
+{
+ int n;
+ Op *o;
+ Chan *c;
+
+ v &= 0xff;
+ n = r & 0x1f;
+ c = chs + ((n>>3)+(n>>3<<1) + (n+(n+1>>2&1)&3));
+ o = c->op + (n + 1 >> 2 & 1);
+ n = r & 6 ^ 6 && n < 22;
+
+ switch(r){
+ case Rwse: wse = v & Mwse; return;
+ case Rcsm: nse = v & Mnse; return;
+ case Ropm: opm(v); return;
+ }
+ switch(r & 0xe0){
+ case Rctl: if(n) ctl(c, o, v); break;
+ case Rsca: if(n) sca(c, o, v); break;
+ case Ratk: if(n) atkdec(o, v); break;
+ case Rsus: if(n) susrel(o, v); break;
+ case Rnum: foct(r, v); break;
+ case Rfed: feedb(r & 0xf, v); break;
+ case Rwav: if(wse && n) o->wav = (v & Mwav) * Sinlen; break;
+ }
+}
+
+void
+opl2init(int rate)
+{
+ int i;
+ u32int *fp;
+ double f0, n;
+ Chan *c;
+ Op *o;
+
+ tab();
+ f0 = (Clk / 72.0) / rate;
+ fp = fn;
+ n = 0;
+ while(fp < fn+nelem(fn))
+ *fp++ = n++ * 64 * f0 * (1 << Sfreqd);
+ lfoAdt = (1.0 / 64.0) * (1 << Slfo) * f0;
+ lfoφdt = (1.0 / 1024.0) * (1 << Slfo) * f0;
+ noiseT = 1.0 * (1 << Sfreq) * f0;
+ egfdt = (1 << Seg) * f0;
+ egdt = 1 << Seg;
+ noise = 1;
+
+ c = chs;
+ o = ops;
+ while(c < chs+nelem(chs)){
+ c++->op = o;
+ o->state = Eoff;
+ o++->vol = Attmax;
+ o->state = Eoff;
+ o++->vol = Attmax;
+ }
+ for(i=Rctl; i<Rwav+22; i++)
+ opl2wr(i, 0);
+}
--- /dev/null
+++ b/opl2m.c
@@ -1,0 +1,65 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+uchar* opl2out(uchar *, int);
+void opl2wr(int, int);
+void opl2init(int);
+
+enum{
+ Rate = 44100,
+ Hz = 700,
+ Samp = Rate / Hz
+};
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [-n nsamp] [file]\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ int n, r, v, dt, nsamp, fd;
+ uchar *sb, u[4];
+ Biobuf *bi, *bo;
+
+ fd = 0;
+ nsamp = Samp;
+ ARGBEGIN{
+ case 'n':
+ nsamp = Rate / atoi(EARGF(usage()));
+ break;
+ default:
+ usage();
+ }ARGEND;
+ if(*argv != nil){
+ fd = open(*argv, OREAD);
+ if(fd < 0)
+ sysfatal("open: %r");
+ }
+ bi = Bfdopen(fd, OREAD);
+ bo = Bfdopen(1, OWRITE);
+ if(bi == nil || bo == nil)
+ sysfatal("Bfdopen: %r");
+ nsamp *= 4;
+ sb = malloc(nsamp);
+ if(sb == nil)
+ sysfatal("malloc: %r");
+ opl2init(Rate);
+
+ while(n = Bread(bi, u, sizeof u), n > 0){
+ r = u[0];
+ v = u[1];
+ dt = u[3]<<8 | u[2];
+ opl2wr(r, v);
+ while(dt-- > 0){
+ opl2out(sb, nsamp);
+ Bwrite(bo, sb, nsamp);
+ }
+ }
+ if(n < 0)
+ sysfatal("Bread: %r");
+}
--- a/rend.c
+++ b/rend.c
@@ -5,9 +5,8 @@
Fnt fnts[2], *fnt;
Pic *pics, *pice;
-Dat *exts, *exte;
-Dat *dems, *deme, *epis;
-Dat *wals, *sprs, *spre;
+uchar **exts, **dems, **epis;
+Dat *wals, *sprs;
int scale, npx;
uchar *px;
--- a/sd.asm
+++ /dev/null
@@ -1,526 +1,0 @@
-;
-; ID_SD_A.ASM
-; Id Sound Manager assembly stuff
-
- .286C
- IDEAL
- MODEL MEDIUM,C
- JUMPS
-
- INCLUDE 'ID_SD.EQU'
-
-DEBUG = 0
-
- EXTRN SDL_DigitizedDone:FAR
- EXTRN alOut:FAR
-
-;============================================================================
-
-DATASEG
-
- EXTRN sqActive:WORD
- EXTRN ssSample:DWORD
- EXTRN ssLengthLeft:WORD
- EXTRN ssControl:WORD
- EXTRN ssStatus:WORD
- EXTRN ssData:WORD
- EXTRN ssOn:BYTE
- EXTRN ssOff:BYTE
-
- EXTRN pcSound:DWORD
- EXTRN pcLengthLeft:WORD
- EXTRN pcLastSample:BYTE
- EXTRN pcSoundLookup:WORD
-
- EXTRN alSound:DWORD
- EXTRN alBlock:WORD
- EXTRN alLengthLeft:WORD
- EXTRN alTimeCount:DWORD
-
- EXTRN sqHack:DWORD
- EXTRN sqHackPtr:DWORD
- EXTRN sqHackLen:WORD
- EXTRN sqHackSeqLen:WORD
- EXTRN sqHackTime:DWORD
-
- EXTRN HackCount:WORD
- EXTRN TimeCount:WORD
- EXTRN LocalTime:WORD
-
- EXTRN TimerCount:WORD
- EXTRN TimerDivisor:WORD
- EXTRN t0OldService:DWORD
-
- EXTRN SoundMode:WORD
- EXTRN DigiMode:WORD
-
- EXTRN SoundNumber:WORD
- EXTRN SoundPriority:WORD
-
-count_time dw ?
-count_fx dw ?
-
-pcdtab db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
- db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
- db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
- db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
- db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
- db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
- db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
- db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
- db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
- db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
- db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
- db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
- db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
- db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
- db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
- db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
-
-
-;============================================================================
-
-CODESEG
-
-MyDS dw ?
-
-pcindicate dw ?
-extreme dw ?
-
- PROC SDL_SetDS
- PUBLIC SDL_SetDS
-
- mov ax,ds
- mov [cs:MyDS],ds
- ret
-
- ENDP
-
-;
-; COMMONSTART
-; Macro used for common prefix code
-;
- MACRO COMMONSTART
- IF DEBUG
- push dx
- push ax
- mov dx,STATUS_REGISTER_1
- in al,dx
- mov dx,ATR_INDEX
- mov al,ATR_OVERSCAN
- out dx,al
- mov al,4 ; red
- out dx,al
- ENDIF
-
- push ds
- push ax
-
- mov ds,[cs:MyDS]
- inc [HackCount]
- ENDM
-
-;
-; DOFX
-; Macro used to do the sound effects code
-;
- MACRO DOFX
- les di,[pcSound] ; PC sound effects
- mov ax,es
- or ax,di
- jz @@nopc ; nil pointer - no PC sound effect going
-
- mov bl,[es:di] ; Get the byte
- inc [WORD PTR pcSound] ; Increment pointer
- cmp [pcLastSample],bl ; Is this sample the same as last?
- jz @@pcsame ; Yep - don't do anything
- mov [pcLastSample],bl ; No, save it for next time
-
- or bl,bl
- jz @@pcoff ; If 0, turn sounds off
- xor bh,bh
- shl bx,1
- mov bx,[pcSoundLookup+bx] ; Use byte as index into frequency table
-
- mov al,0b6h ; Write to channel 2 (speaker) timer
- out pcTAccess,al
- mov al,bl
- out pcTimer,al ; Low byte
- mov al,bh
- out pcTimer,al ; High byte
-
- in al,pcSpeaker ; Turn the speaker & gate on
- or al,3
- out pcSpeaker,al
-
- jmp @@pcsame
-
-@@pcoff:
- in al,pcSpeaker ; Turn the speaker & gate off
- and al,0fch ; ~3
- out pcSpeaker,al
-
-@@pcsame:
- dec [pcLengthLeft] ; Decrement length
- jnz @@nopc ; If not 0, we're not done with the sound
-
- mov ax,0
- mov [WORD PTR pcSound],ax ; Zero the pointer
- mov [WORD PTR pcSound + 2],ax
- mov [SoundNumber],ax ; Indicate no sound
- mov [SoundPriority],ax ; with no priority
-
- in al,pcSpeaker ; Turn the speaker off
- and al,0fdh ; ~2
- out pcSpeaker,al
-@@nopc:
-
- les di,[alSound] ; AdLib sound effects
- mov ax,es
- or ax,di
- jz @@noal ; nil pointer - no AdLib effect going
-
- xor ah,ah
- mov al,[es:di]
- or al,al
- jz @@aldone
-
- CALL alOut C,alFreqL,ax
- mov ax,[alBlock]
-
-@@aldone:
- CALL alOut C,alFreqH,ax
- inc [WORD PTR alSound]
- dec [alLengthLeft]
- jnz @@noal
-
- mov ax,0
- mov [WORD PTR alSound],ax ; Zero the pointer
- mov [WORD PTR alSound + 2],ax
- mov [SoundNumber],ax ; Indicate no sound
- mov [SoundPriority],ax ; with no priority
- CALL alOut C,alFreqH,ax ; Turn off the sound
-@@noal:
-
- ENDM
-
-;
-;
-;
- MACRO TIME
- cmp [count_time],2
- jb @@notime
- add [LocalTime],1
- adc [LocalTime+2],0
- add [TimeCount],1
- adc [TimeCount+2],0
- mov [count_time],0
-@@notime:
- ENDM
-
-;
-; COMMONEND
-; Macro used for common suffix code
-;
- MACRO COMMONEND
-@@fullexit:
- pop es
- popa
-
-@@nosave:
- mov ax,[TimerDivisor]
- add [TimerCount],ax
- jnc @@myack
-
- pushf
- call [t0OldService]
- jmp @@out
-
-@@myack:
- mov al,20h
- out 20h,al
-
-@@out:
- pop ax
- pop ds
-
- IF DEBUG
- mov dx,STATUS_REGISTER_1
- in al,dx
- mov dx,ATR_INDEX
- mov al,ATR_OVERSCAN
- out dx,al
- mov al,3 ; blue
- out dx,al
- mov al,20h ; normal
- out dx,al
- pop ax
- pop dx
- ENDIF
-
- iret
- ENDM
-
-;
-; SDL_IndicatePC
-;
- PROC SDL_IndicatePC on:WORD
- PUBLIC SDL_IndicatePC
-
- mov ax,[on]
- mov [cs:pcindicate],ax
- ret
-
- ENDP
-
-;
-; SDL_t0ExtremeAsmService
-; Timer 0 ISR 7000Hz interrupts
-;
- PROC SDL_t0ExtremeAsmService
- PUBLIC SDL_t0ExtremeAsmService
-
- push ax
- mov al,[BYTE PTR cs:pcindicate]
- or al,al
- jz @@done
-
- push ds
- push es
- pusha
-
- mov ds,[cs:MyDS]
-
- les di,[pcSound]
- mov ax,es
- or ax,di
- jz @@donereg ; nil pointer
-
- mov bl,[es:di] ; Get the byte
- inc [WORD PTR pcSound] ; Increment pointer
-
- and bl,11100000b ; Nuke some of the precision (DEBUG - do this in the table)
-
- xor bh,bh
- mov ah,[pcdtab+bx] ; Translate the byte
-
- in al,pcSpeaker
- and al,11111100b
- or al,ah
- out pcSpeaker,al
-
- dec [pcLengthLeft]
- jnz @@donereg
-
- mov [WORD PTR pcSound],0 ; We're done with this sample
- mov [WORD PTR pcSound+2],0
-
- in al,pcSpeaker
- and al,11111100b
- out pcSpeaker,al
-
- call SDL_DigitizedDone
-
-@@donereg:
- popa
- pop es
- pop ds
-
-@@done:
- inc [cs:extreme]
- cmp [cs:extreme],10
- jae @@tofast
-
- mov al,20h
- out 20h,al
- pop ax
- iret
-
-@@tofast:
- mov [cs:extreme],0
- pop ax
-
-; jmp SDL_t0FastAsmService ; Drops through to SDL_t0FastAsmService
-
- ENDP
-
-;
-; SDL_t0FastAsmService
-; Timer 0 ISR for 700Hz interrupts
-;
- PROC SDL_t0FastAsmService
- PUBLIC SDL_t0FastAsmService
-
- COMMONSTART
-
- inc [count_fx] ; Time to do PC/AdLib effects & time?
- cmp [count_fx],5
- jae @@dofull
-
- mov ax,[sqActive] ; Is the sequencer active?
- or ax,ax
- jnz @@dofull
-
- mov ax,[WORD PTR ssSample] ; Is there a sample for the Sound Src?
- or ax,[WORD PTR ssSample+2]
- jz @@nosave
-
-@@dofull:
- pusha
- push es
-
- cmp [count_fx],5
- jb @@nofx
- mov [count_fx],0
- DOFX
-
- inc [count_time]
- TIME
-@@nofx:
-
- mov ax,[sqActive]
- or ax,ax
- jz @@nosq
-
- mov ax,[sqHackLen]
- or ax,ax
- jz @@sqdone
-
- les di,[sqHackPtr]
-@@sqloop:
- mov ax,[WORD PTR sqHackTime+2]
- cmp ax,[WORD PTR alTimeCount+2]
- ja @@sqdone
- mov ax,[WORD PTR sqHackTime]
- cmp ax,[WORD PTR alTimeCount]
- ja @@sqdone
-
- mov ax,[es:di+2] ; Get time to next event
- add ax,[WORD PTR alTimeCount]
- mov [WORD PTR sqHackTime],ax
- mov ax,[WORD PTR alTimeCount+2]
- adc ax,0
- mov [WORD PTR sqHackTime+2],ax
-
- mov ax,[es:di] ; Get register/value pair
- xor bh,bh
- mov bl,ah
- xor ah,ah
- CALL alOut C,ax,bx
-
- add di,4
- mov [WORD PTR sqHackPtr],di
-
- sub [sqHackLen],4
- jnz @@sqloop
-
-@@sqdone:
- add [WORD PTR alTimeCount],1
- adc [WORD PTR alTimeCount+2],0
- mov ax,[sqHackLen]
- or ax,ax
- jnz @@nosq
-
- mov ax,[WORD PTR sqHack] ; Copy pointer
- mov [WORD PTR sqHackPtr],ax
- mov ax,[WORD PTR sqHack+2]
- mov [WORD PTR sqHackPtr+2],ax
-
- mov ax,[sqHackSeqLen] ; Copy length
- mov [sqHackLen],ax
-
- mov ax,0
- mov [WORD PTR alTimeCount],ax ; Reset time counts
- mov [WORD PTR alTimeCount+2],ax
- mov [WORD PTR sqHackTime],ax
- mov [WORD PTR sqHackTime+2],ax
-@@nosq:
-
- les di,[ssSample] ; Get pointer to Sound Source sample
- mov ax,es
- or ax,di
- jz @@ssdone ; If nil, skip this
-
-@@ssloop:
- mov dx,[ssStatus] ; Check to see if FIFO has any empty slots
- in al,dx
- test al,40h
- jnz @@ssdone ; Nope - don't push any more data out
-
- mov dx,[ssData]
- mov al,[es:di] ; al = *ssSample
- out dx,al ; Pump the value out
-
- mov dx,[ssControl] ; Pulse printer select
- mov al,[ssOff]
- out dx,al
- push ax
- pop ax
- mov al,[ssOn]
- out dx,al
-
- push ax ; Delay a short while
- pop ax
-
- inc di
- mov [WORD PTR ssSample],di ; ssSample++
-
- dec [ssLengthLeft]
- jnz @@ssloop
-
- mov [WORD PTR ssSample],0 ; We're done with this sample
- mov [WORD PTR ssSample+2],0
-
- call SDL_DigitizedDone
-@@ssdone:
-
- COMMONEND
-
- ENDP
-
-;
-; SDL_t0SlowAsmService
-; Timer 0 ISR for 140Hz interrupts
-;
- PROC SDL_t0SlowAsmService
- PUBLIC SDL_t0SlowAsmService
-
- IF DEBUG
- push dx
- push ax
- mov dx,STATUS_REGISTER_1
- in al,dx
- mov dx,ATR_INDEX
- mov al,ATR_OVERSCAN
- out dx,al
- mov al,4 ; red
- out dx,al
- ENDIF
-
- push ds
- push ax
-
- mov ds,[cs:MyDS]
-
- inc [count_time]
- TIME
-
- mov ax,[WORD PTR pcSound] ; Is there a PC sound effect going?
- or ax,[WORD PTR pcSound+2]
- jnz @@dofull
-
- mov ax,[WORD PTR alSound] ; Is there an AdLib sound effect going?
- or ax,[WORD PTR alSound+2]
- jz @@nosave
-
-@@dofull:
- pusha
- push es
-
- DOFX
-
- COMMONEND
-
- ENDP
-
- END
--- a/sd.c
+++ /dev/null
@@ -1,2162 +1,0 @@
-//
-// ID Engine
-// ID_SD.c - Sound Manager for Wolfenstein 3D
-// v1.2
-// By Jason Blochowiak
-//
-
-//
-// This module handles dealing with generating sound on the appropriate
-// hardware
-//
-// Depends on: User Mgr (for parm checking)
-//
-// Globals:
-// For User Mgr:
-// SoundSourcePresent - Sound Source thingie present?
-// SoundBlasterPresent - SoundBlaster card present?
-// AdLibPresent - AdLib card present?
-// SoundMode - What device is used for sound effects
-// (Use SM_SetSoundMode() to set)
-// MusicMode - What device is used for music
-// (Use SM_SetMusicMode() to set)
-// DigiMode - What device is used for digitized sound effects
-// (Use SM_SetDigiDevice() to set)
-//
-// For Cache Mgr:
-// NeedsDigitized - load digitized sounds?
-// NeedsMusic - load music?
-//
-
-#include "ID_HEADS.H"
-
-#define SDL_SoundFinished() {SoundNumber = SoundPriority = 0;}
-
-// Macros for SoundBlaster stuff
-#define sbOut(n,b) outportb((n) + sbLocation,b)
-#define sbIn(n) inportb((n) + sbLocation)
-#define sbWriteDelay() while (sbIn(sbWriteStat) & 0x80);
-#define sbReadDelay() while (sbIn(sbDataAvail) & 0x80);
-
-// Macros for AdLib stuff
-#define selreg(n) outportb(alFMAddr,n)
-#define writereg(n) outportb(alFMData,n)
-#define readstat() inportb(alFMStatus)
-
-// Imports from ID_SD_A.ASM
-extern void SDL_SetDS(void),
- SDL_IndicatePC(int on);
-extern void interrupt SDL_t0ExtremeAsmService(void),
- SDL_t0FastAsmService(void),
- SDL_t0SlowAsmService(void);
-
-// Global variables
- int SoundSourcePresent,
- AdLibPresent,
- SoundBlasterPresent,SBProPresent,
- NeedsDigitized,NeedsMusic,
- SoundPositioned;
- SDMode SoundMode;
- SMMode MusicMode;
- SDSMode DigiMode;
- u32int TimeCount;
- u16int HackCount;
- u16int *SoundTable; // Really * _seg *SoundTable, but that don't work
- s16int DigiMap[LASTSOUND];
-
-// Internal variables
-static int SD_Started;
- int nextsoundpos;
- u32int TimerDivisor,TimerCount;
-static void (*SoundUserHook)(void);
- soundnames SoundNumber,DigiNumber;
- u16int SoundPriority,DigiPriority;
- s16int LeftPosition,RightPosition;
- void interrupt (*t0OldService)(void);
- s32int LocalTime;
- u16int TimerRate;
-
- u16int NumDigi,DigiLeft,DigiPage;
- u16int _seg *DigiList;
- u16int DigiLastStart,DigiLastEnd;
- int DigiPlaying;
-static int DigiMissed,DigiLastSegment;
-static uchar *DigiNextAddr;
-static u16int DigiNextLen;
-
-// SoundBlaster variables
-static volatile int sbSamplePlaying;
-static u8int sbOldIntMask = -1;
-static volatile u8int huge *sbNextSegPtr;
-static u8int sbDMA = 1,
- sbDMAa1 = 0x83,sbDMAa2 = 2,sbDMAa3 = 3,
- sba1Vals[] = {0x87,0x83,0,0x82},
- sba2Vals[] = {0,2,0,6},
- sba3Vals[] = {1,3,0,7};
-static s16int sbLocation = -1,sbInterrupt = 7,sbIntVec = 0xf,
- sbIntVectors[] = {-1,-1,0xa,0xb,-1,0xd,-1,0xf,-1,-1,-1};
-static volatile u32int sbNextSegLen;
-static volatile SampledSound huge *sbSamples;
-static void interrupt (*sbOldIntHand)(void);
-static u8int sbpOldFMMix,sbpOldVOCMix;
-
-// SoundSource variables
- int ssActive;
- u16int ssControl,ssStatus,ssData;
- u8int ssOn,ssOff;
- volatile u8int far *ssSample;
- volatile u32int ssLengthLeft;
-
-// PC Sound variables
- volatile u8int pcLastSample,far *pcSound;
- u32int pcLengthLeft;
- u16int pcSoundLookup[255];
-
-// AdLib variables
- u8int far *alSound;
- u16int alBlock;
- u32int alLengthLeft;
- u32int alTimeCount;
- Instrument alZeroInst;
-
-// This table maps channel numbers to carrier and modulator op cells
-static u8int carriers[9] = { 3, 4, 5,11,12,13,19,20,21},
- modifiers[9] = { 0, 1, 2, 8, 9,10,16,17,18},
-// This table maps percussive voice numbers to op cells
- pcarriers[5] = {19,0xff,0xff,0xff,0xff},
- pmodifiers[5] = {16,17,18,20,21};
-
-// Sequencer variables
- int sqActive;
-static u16int alFXReg;
-static ActiveTrack *tracks[sqMaxTracks],
- mytracks[sqMaxTracks];
-static u16int sqMode,sqFadeStep;
- u16int far *sqHack,far *sqHackPtr,sqHackLen,sqHackSeqLen;
- s32int sqHackTime;
-
-// Internal routines
- void SDL_DigitizedDone(void);
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_SetTimer0() - Sets system timer 0 to the specified speed
-//
-///////////////////////////////////////////////////////////////////////////
-#pragma argsused
-static void
-SDL_SetTimer0(u16int speed)
-{
-asm pushf
-asm cli
-
- outportb(0x43,0x36); // Change timer 0
- outportb(0x40,speed);
- outportb(0x40,speed >> 8);
- // Kludge to handle special case for digitized PC sounds
- if (TimerDivisor == (1192030 / (TickBase * 100)))
- TimerDivisor = (1192030 / (TickBase * 10));
- else
- TimerDivisor = speed;
-
-asm popf
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of
-// interrupts generated by system timer 0 per second
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_SetIntsPerSec(u16int ints)
-{
- TimerRate = ints;
- SDL_SetTimer0(1192030 / ints);
-}
-
-static void
-SDL_SetTimerSpeed(void)
-{
- u16int rate;
- void interrupt (*isr)(void);
-
- if ((DigiMode == sds_PC) && DigiPlaying)
- {
- rate = TickBase * 100;
- isr = SDL_t0ExtremeAsmService;
- }
- else if
- (
- (MusicMode == smm_AdLib)
- || ((DigiMode == sds_SoundSource) && DigiPlaying)
- )
- {
- rate = TickBase * 10;
- isr = SDL_t0FastAsmService;
- }
- else
- {
- rate = TickBase * 2;
- isr = SDL_t0SlowAsmService;
- }
-
- if (rate != TimerRate)
- {
- setvect(8,isr);
- SDL_SetIntsPerSec(rate);
- TimerRate = rate;
- }
-}
-
-//
-// SoundBlaster code
-//
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_SBStopSample() - Stops any active sampled sound and causes DMA
-// requests from the SoundBlaster to cease
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_SBStopSample(void)
-{
- u8int is;
-
-asm pushf
-asm cli
-
- if (sbSamplePlaying)
- {
- sbSamplePlaying = false;
-
- sbWriteDelay();
- sbOut(sbWriteCmd,0xd0); // Turn off DSP DMA
-
- is = inportb(0x21); // Restore interrupt mask bit
- if (sbOldIntMask & (1 << sbInterrupt))
- is |= (1 << sbInterrupt);
- else
- is &= ~(1 << sbInterrupt);
- outportb(0x21,is);
- }
-
-asm popf
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_SBPlaySeg() - Plays a chunk of sampled sound on the SoundBlaster
-// Insures that the chunk doesn't cross a bank boundary, programs the DMA
-// controller, and tells the SB to start doing DMA requests for DAC
-//
-///////////////////////////////////////////////////////////////////////////
-static u32int
-SDL_SBPlaySeg(volatile u8int huge *data,u32int length)
-{
- u16int datapage;
- u32int dataofs,uselen;
-
- uselen = length;
- datapage = FP_SEG(data) >> 12;
- dataofs = ((FP_SEG(data) & 0xfff) << 4) + FP_OFF(data);
- if (dataofs >= 0x10000)
- {
- datapage++;
- dataofs -= 0x10000;
- }
-
- if (dataofs + uselen > 0x10000)
- uselen = 0x10000 - dataofs;
-
- uselen--;
-
- // Program the DMA controller
-asm pushf
-asm cli
- outportb(0x0a,sbDMA | 4); // Mask off DMA on channel sbDMA
- outportb(0x0c,0); // Clear byte ptr flip-flop to lower byte
- outportb(0x0b,0x49); // Set transfer mode for D/A conv
- outportb(sbDMAa2,(u8int)dataofs); // Give LSB of address
- outportb(sbDMAa2,(u8int)(dataofs >> 8)); // Give MSB of address
- outportb(sbDMAa1,(u8int)datapage); // Give page of address
- outportb(sbDMAa3,(u8int)uselen); // Give LSB of length
- outportb(sbDMAa3,(u8int)(uselen >> 8)); // Give MSB of length
- outportb(0x0a,sbDMA); // Re-enable DMA on channel sbDMA
-
- // Start playing the thing
- sbWriteDelay();
- sbOut(sbWriteCmd,0x14);
- sbWriteDelay();
- sbOut(sbWriteData,(u8int)uselen);
- sbWriteDelay();
- sbOut(sbWriteData,(u8int)(uselen >> 8));
-asm popf
-
- return(uselen + 1);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_SBService() - Services the SoundBlaster DMA interrupt
-//
-///////////////////////////////////////////////////////////////////////////
-static void interrupt
-SDL_SBService(void)
-{
- u32int used;
-
- sbIn(sbDataAvail); // Ack interrupt to SB
-
- if (sbNextSegPtr)
- {
- used = SDL_SBPlaySeg(sbNextSegPtr,sbNextSegLen);
- if (sbNextSegLen <= used)
- sbNextSegPtr = nil;
- else
- {
- sbNextSegPtr += used;
- sbNextSegLen -= used;
- }
- }
- else
- {
- SDL_SBStopSample();
- SDL_DigitizedDone();
- }
-
- outportb(0x20,0x20); // Ack interrupt
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_SBPlaySample() - Plays a sampled sound on the SoundBlaster. Sets up
-// DMA to play the sound
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_SBPlaySample(u8int huge *data,u32int len)
-{
- u32int used;
-
- SDL_SBStopSample();
-
-asm pushf
-asm cli
-
- used = SDL_SBPlaySeg(data,len);
- if (len <= used)
- sbNextSegPtr = nil;
- else
- {
- sbNextSegPtr = data + used;
- sbNextSegLen = len - used;
- }
-
- // Save old interrupt status and unmask ours
- sbOldIntMask = inportb(0x21);
- outportb(0x21,sbOldIntMask & ~(1 << sbInterrupt));
-
- sbWriteDelay();
- sbOut(sbWriteCmd,0xd4); // Make sure DSP DMA is enabled
-
- sbSamplePlaying = true;
-
-asm popf
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_PositionSBP() - Sets the attenuation levels for the left and right
-// channels by using the mixer chip on the SB Pro. This hits a hole in
-// the address map for normal SBs.
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_PositionSBP(s16int leftpos,s16int rightpos)
-{
- u8int v;
-
- if (!SBProPresent)
- return;
-
- leftpos = 15 - leftpos;
- rightpos = 15 - rightpos;
- v = ((leftpos & 0x0f) << 4) | (rightpos & 0x0f);
-
-asm pushf
-asm cli
-
- sbOut(sbpMixerAddr,sbpmVoiceVol);
- sbOut(sbpMixerData,v);
-
-asm popf
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_CheckSB() - Checks to see if a SoundBlaster resides at a
-// particular I/O location
-//
-///////////////////////////////////////////////////////////////////////////
-static int
-SDL_CheckSB(s16int port)
-{
- s16int i;
-
- sbLocation = port << 4; // Initialize stuff for later use
-
- sbOut(sbReset,true); // Reset the SoundBlaster DSP
-asm mov dx,0x388 // Wait >4usec
-asm in al, dx
-asm in al, dx
-asm in al, dx
-asm in al, dx
-asm in al, dx
-asm in al, dx
-asm in al, dx
-asm in al, dx
-asm in al, dx
-
- sbOut(sbReset,false); // Turn off sb DSP reset
-asm mov dx,0x388 // Wait >100usec
-asm mov cx,100
-usecloop:
-asm in al,dx
-asm loop usecloop
-
- for (i = 0;i < 100;i++)
- {
- if (sbIn(sbDataAvail) & 0x80) // If data is available...
- {
- if (sbIn(sbReadData) == 0xaa) // If it matches correct value
- return(true);
- else
- {
- sbLocation = -1; // Otherwise not a SoundBlaster
- return(false);
- }
- }
- }
- sbLocation = -1; // Retry count exceeded - fail
- return(false);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// Checks to see if a SoundBlaster is in the system. If the port passed is
-// -1, then it scans through all possible I/O locations. If the port
-// passed is 0, then it uses the default (2). If the port is >0, then
-// it just passes it directly to SDL_CheckSB()
-//
-///////////////////////////////////////////////////////////////////////////
-static int
-SDL_DetectSoundBlaster(s16int port)
-{
- s16int i;
-
- if (port == 0) // If user specifies default, use 2
- port = 2;
- if (port == -1)
- {
- if (SDL_CheckSB(2)) // Check default before scanning
- return(true);
-
- if (SDL_CheckSB(4)) // Check other SB Pro location before scan
- return(true);
-
- for (i = 1;i <= 6;i++) // Scan through possible SB locations
- {
- if ((i == 2) || (i == 4))
- continue;
-
- if (SDL_CheckSB(i)) // If found at this address,
- return(true); // return success
- }
- return(false); // All addresses failed, return failure
- }
- else
- return(SDL_CheckSB(port)); // User specified address or default
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_SBSetDMA() - Sets the DMA channel to be used by the SoundBlaster
-// code. Sets up sbDMA, and sbDMAa1-sbDMAa3 (used by SDL_SBPlaySeg()).
-//
-///////////////////////////////////////////////////////////////////////////
-void
-SDL_SBSetDMA(u8int channel)
-{
- if (channel > 3)
- Quit("SDL_SBSetDMA() - invalid SoundBlaster DMA channel");
-
- sbDMA = channel;
- sbDMAa1 = sba1Vals[channel];
- sbDMAa2 = sba2Vals[channel];
- sbDMAa3 = sba3Vals[channel];
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_StartSB() - Turns on the SoundBlaster
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_StartSB(void)
-{
- u8int timevalue,test;
-
- sbIntVec = sbIntVectors[sbInterrupt];
- if (sbIntVec < 0)
- Quit("SDL_StartSB: Illegal or unsupported interrupt number for SoundBlaster");
-
- sbOldIntHand = getvect(sbIntVec); // Get old interrupt handler
- setvect(sbIntVec,SDL_SBService); // Set mine
-
- sbWriteDelay();
- sbOut(sbWriteCmd,0xd1); // Turn on DSP speaker
-
- // Set the SoundBlaster DAC time constant for 7KHz
- timevalue = 256 - (1000000 / 7000);
- sbWriteDelay();
- sbOut(sbWriteCmd,0x40);
- sbWriteDelay();
- sbOut(sbWriteData,timevalue);
-
- SBProPresent = false;
-
- // Check to see if this is a SB Pro
- sbOut(sbpMixerAddr,sbpmFMVol);
- sbpOldFMMix = sbIn(sbpMixerData);
- sbOut(sbpMixerData,0xbb);
- test = sbIn(sbpMixerData);
- if (test == 0xbb)
- {
- // Boost FM output levels to be equivilent with digitized output
- sbOut(sbpMixerData,0xff);
- test = sbIn(sbpMixerData);
- if (test == 0xff)
- {
- SBProPresent = true;
-
- // Save old Voice output levels (SB Pro)
- sbOut(sbpMixerAddr,sbpmVoiceVol);
- sbpOldVOCMix = sbIn(sbpMixerData);
-
- // Turn SB Pro stereo DAC off
- sbOut(sbpMixerAddr,sbpmControl);
- sbOut(sbpMixerData,0); // 0=off,2=on
- }
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_ShutSB() - Turns off the SoundBlaster
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_ShutSB(void)
-{
- SDL_SBStopSample();
-
- if (SBProPresent)
- {
- // Restore FM output levels (SB Pro)
- sbOut(sbpMixerAddr,sbpmFMVol);
- sbOut(sbpMixerData,sbpOldFMMix);
-
- // Restore Voice output levels (SB Pro)
- sbOut(sbpMixerAddr,sbpmVoiceVol);
- sbOut(sbpMixerData,sbpOldVOCMix);
- }
-
- setvect(sbIntVec,sbOldIntHand); // Set vector back
-}
-
-// Sound Source Code
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_SSStopSample() - Stops a sample playing on the Sound Source
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_SSStopSample(void)
-{
-asm pushf
-asm cli
-
- (s32int)ssSample = 0;
-
-asm popf
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_SSService() - Handles playing the next sample on the Sound Source
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_SSService(void)
-{
- int gotit;
- u8int v;
-
- while (ssSample)
- {
- asm mov dx,[ssStatus] // Check to see if FIFO is currently empty
- asm in al,dx
- asm test al,0x40
- asm jnz done // Nope - don't push any more data out
-
- v = *ssSample++;
- if (!(--ssLengthLeft))
- {
- (s32int)ssSample = 0;
- SDL_DigitizedDone();
- }
-
- asm mov dx,[ssData] // Pump the value out
- asm mov al,[v]
- asm out dx,al
-
- asm mov dx,[ssControl] // Pulse printer select
- asm mov al,[ssOff]
- asm out dx,al
- asm push ax
- asm pop ax
- asm mov al,[ssOn]
- asm out dx,al
-
- asm push ax // Delay a short while
- asm pop ax
- asm push ax
- asm pop ax
- }
-done:;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_SSPlaySample() - Plays the specified sample on the Sound Source
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_SSPlaySample(u8int huge *data,u32int len)
-{
-asm pushf
-asm cli
-
- ssLengthLeft = len;
- ssSample = (volatile u8int far *)data;
-
-asm popf
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_StartSS() - Sets up for and turns on the Sound Source
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_StartSS(void)
-{
- ssControl = 0x3be; // If using LPT1
- ssStatus = ssControl - 1;
- ssData = ssStatus - 1;
-
- ssOn = 0x04;
- ssOff = 0x0c;
- outportb(ssControl,ssOn); // Enable SS
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_ShutSS() - Turns off the Sound Source
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_ShutSS(void)
-{
- outportb(ssControl,ssOff);
-}
-
-//
-// PC Sound code
-//
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_PCPlaySample() - Plays the specified sample on the PC speaker
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_PCPlaySample(u8int huge *data,u32int len)
-{
-asm pushf
-asm cli
-
- SDL_IndicatePC(true);
-
- pcLengthLeft = len;
- pcSound = (volatile u8int far *)data;
-
-asm popf
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_PCStopSample() - Stops a sample playing on the PC speaker
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_PCStopSample(void)
-{
-asm pushf
-asm cli
-
- (s32int)pcSound = 0;
-
- SDL_IndicatePC(false);
-
-asm in al,0x61 // Turn the speaker off
-asm and al,0xfd // ~2
-asm out 0x61,al
-
-asm popf
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_PCPlaySound() - Plays the specified sound on the PC speaker
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_PCPlaySound(PCSound far *sound)
-{
-asm pushf
-asm cli
-
- pcLastSample = -1;
- pcLengthLeft = sound->common.length;
- pcSound = sound->data;
-
-asm popf
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_PCStopSound() - Stops the current sound playing on the PC Speaker
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_PCStopSound(void)
-{
-asm pushf
-asm cli
-
- (s32int)pcSound = 0;
-
-asm in al,0x61 // Turn the speaker off
-asm and al,0xfd // ~2
-asm out 0x61,al
-
-asm popf
-}
-
-#if 0
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_PCService() - Handles playing the next sample in a PC sound
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_PCService(void)
-{
- u8int s;
- u16int t;
-
- if (pcSound)
- {
- s = *pcSound++;
- if (s != pcLastSample)
- {
- asm pushf
- asm cli
-
- pcLastSample = s;
- if (s) // We have a frequency!
- {
- t = pcSoundLookup[s];
- asm mov bx,[t]
-
- asm mov al,0xb6 // Write to channel 2 (speaker) timer
- asm out 43h,al
- asm mov al,bl
- asm out 42h,al // Low byte
- asm mov al,bh
- asm out 42h,al // High byte
-
- asm in al,0x61 // Turn the speaker & gate on
- asm or al,3
- asm out 0x61,al
- }
- else // Time for some silence
- {
- asm in al,0x61 // Turn the speaker & gate off
- asm and al,0xfc // ~3
- asm out 0x61,al
- }
-
- asm popf
- }
-
- if (!(--pcLengthLeft))
- {
- SDL_PCStopSound();
- SDL_SoundFinished();
- }
- }
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_ShutPC() - Turns off the pc speaker
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_ShutPC(void)
-{
-asm pushf
-asm cli
-
- pcSound = 0;
-
-asm in al,0x61 // Turn the speaker & gate off
-asm and al,0xfc // ~3
-asm out 0x61,al
-
-asm popf
-}
-
-//
-// Stuff for digitized sounds
-//
-uchar *
-SDL_LoadDigiSegment(u16int page)
-{
- uchar *addr;
-
-#if 0 // for debugging
-asm mov dx,STATUS_REGISTER_1
-asm in al,dx
-asm mov dx,ATR_INDEX
-asm mov al,ATR_OVERSCAN
-asm out dx,al
-asm mov al,10 // bright green
-asm out dx,al
-#endif
-
- addr = PM_GetSoundPage(page);
- PM_SetPageLock(PMSoundStart + page,pml_Locked);
-
-#if 0 // for debugging
-asm mov dx,STATUS_REGISTER_1
-asm in al,dx
-asm mov dx,ATR_INDEX
-asm mov al,ATR_OVERSCAN
-asm out dx,al
-asm mov al,3 // blue
-asm out dx,al
-asm mov al,0x20 // normal
-asm out dx,al
-#endif
-
- return(addr);
-}
-
-void
-SDL_PlayDigiSegment(uchar *addr,u16int len)
-{
- switch (DigiMode)
- {
- case sds_PC:
- SDL_PCPlaySample(addr,len);
- break;
- case sds_SoundSource:
- SDL_SSPlaySample(addr,len);
- break;
- case sds_SoundBlaster:
- SDL_SBPlaySample(addr,len);
- break;
- }
-}
-
-void
-SD_StopDigitized(void)
-{
- s16int i;
-
-asm pushf
-asm cli
-
- DigiLeft = 0;
- DigiNextAddr = nil;
- DigiNextLen = 0;
- DigiMissed = false;
- DigiPlaying = false;
- DigiNumber = DigiPriority = 0;
- SoundPositioned = false;
- if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
- SDL_SoundFinished();
-
- switch (DigiMode)
- {
- case sds_PC:
- SDL_PCStopSample();
- break;
- case sds_SoundSource:
- SDL_SSStopSample();
- break;
- case sds_SoundBlaster:
- SDL_SBStopSample();
- break;
- }
-
-asm popf
-
- for (i = DigiLastStart;i < DigiLastEnd;i++)
- PM_SetPageLock(i + PMSoundStart,pml_Unlocked);
- DigiLastStart = 1;
- DigiLastEnd = 0;
-}
-
-void
-SD_Poll(void)
-{
- if (DigiLeft && !DigiNextAddr)
- {
- DigiNextLen = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);
- DigiLeft -= DigiNextLen;
- if (!DigiLeft)
- DigiLastSegment = true;
- DigiNextAddr = SDL_LoadDigiSegment(DigiPage++);
- }
- if (DigiMissed && DigiNextAddr)
- {
- SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);
- DigiNextAddr = nil;
- DigiMissed = false;
- if (DigiLastSegment)
- {
- DigiPlaying = false;
- DigiLastSegment = false;
- }
- }
- SDL_SetTimerSpeed();
-}
-
-void
-SD_SetPosition(s16int leftpos,s16int rightpos)
-{
- if
- (
- (leftpos < 0)
- || (leftpos > 15)
- || (rightpos < 0)
- || (rightpos > 15)
- || ((leftpos == 15) && (rightpos == 15))
- )
- Quit("SD_SetPosition: Illegal position");
-
- switch (DigiMode)
- {
- case sds_SoundBlaster:
- SDL_PositionSBP(leftpos,rightpos);
- break;
- }
-}
-
-void
-SD_PlayDigitized(u16int which,s16int leftpos,s16int rightpos)
-{
- u16int len;
- uchar *addr;
-
- if (!DigiMode)
- return;
-
- SD_StopDigitized();
- if (which >= NumDigi)
- Quit("SD_PlayDigitized: bad sound number");
-
- SD_SetPosition(leftpos,rightpos);
-
- DigiPage = DigiList[(which * 2) + 0];
- DigiLeft = DigiList[(which * 2) + 1];
-
- DigiLastStart = DigiPage;
- DigiLastEnd = DigiPage + ((DigiLeft + (PMPageSize - 1)) / PMPageSize);
-
- len = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);
- addr = SDL_LoadDigiSegment(DigiPage++);
-
- DigiPlaying = true;
- DigiLastSegment = false;
-
- SDL_PlayDigiSegment(addr,len);
- DigiLeft -= len;
- if (!DigiLeft)
- DigiLastSegment = true;
-
- SD_Poll();
-}
-
-void
-SDL_DigitizedDone(void)
-{
- if (DigiNextAddr)
- {
- SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);
- DigiNextAddr = nil;
- DigiMissed = false;
- }
- else
- {
- if (DigiLastSegment)
- {
- DigiPlaying = false;
- DigiLastSegment = false;
- if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
- {
- SDL_SoundFinished();
- }
- else
- DigiNumber = DigiPriority = 0;
- SoundPositioned = false;
- }
- else
- DigiMissed = true;
- }
-}
-
-void
-SD_SetDigiDevice(SDSMode mode)
-{
- int devicenotpresent;
-
- if (mode == DigiMode)
- return;
-
- SD_StopDigitized();
-
- devicenotpresent = false;
- switch (mode)
- {
- case sds_SoundBlaster:
- if (!SoundBlasterPresent)
- {
- if (SoundSourcePresent)
- mode = sds_SoundSource;
- else
- devicenotpresent = true;
- }
- break;
- case sds_SoundSource:
- if (!SoundSourcePresent)
- devicenotpresent = true;
- break;
- }
-
- if (!devicenotpresent)
- {
- if (DigiMode == sds_SoundSource)
- SDL_ShutSS();
-
- DigiMode = mode;
-
- if (mode == sds_SoundSource)
- SDL_StartSS();
-
- SDL_SetTimerSpeed();
- }
-}
-
-void
-SDL_SetupDigi(void)
-{
- uchar *list;
- u16int far *p,
- pg;
- s16int i;
-
- PM_UnlockMainMem();
- MM_GetPtr(&list,PMPageSize);
- PM_CheckMainMem();
- p = (u16int far *)MK_FP(PM_GetPage(ChunksInFile - 1),0);
- _fmemcpy((void far *)list,(void far *)p,PMPageSize);
- pg = PMSoundStart;
- for (i = 0;i < PMPageSize / (sizeof(u16int) * 2);i++,p += 2)
- {
- if (pg >= ChunksInFile - 1)
- break;
- pg += (p[1] + (PMPageSize - 1)) / PMPageSize;
- }
- PM_UnlockMainMem();
- MM_GetPtr((uchar **)&DigiList,i * sizeof(u16int) * 2);
- _fmemcpy((void far *)DigiList,(void far *)list,i * sizeof(u16int) * 2);
- MM_FreePtr(&list);
- NumDigi = i;
-
- for (i = 0;i < LASTSOUND;i++)
- DigiMap[i] = -1;
-}
-
-// AdLib Code
-
-///////////////////////////////////////////////////////////////////////////
-//
-// alOut(n,b) - Puts b in AdLib card register n
-//
-///////////////////////////////////////////////////////////////////////////
-void
-alOut(u8int n,u8int b)
-{
-asm pushf
-asm cli
-
-asm mov dx,0x388
-asm mov al,[n]
-asm out dx,al
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm inc dx
-asm mov al,[b]
-asm out dx,al
-
-asm popf
-
-asm dec dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-asm in al,dx
-}
-
-#if 0
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_SetInstrument() - Puts an instrument into a generator
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_SetInstrument(s16int track,s16int which,Instrument far *inst,int percussive)
-{
- u8int c,m;
-
- if (percussive)
- {
- c = pcarriers[which];
- m = pmodifiers[which];
- }
- else
- {
- c = carriers[which];
- m = modifiers[which];
- }
-
- tracks[track - 1]->inst = *inst;
- tracks[track - 1]->percussive = percussive;
-
- alOut(m + alChar,inst->mChar);
- alOut(m + alScale,inst->mScale);
- alOut(m + alAttack,inst->mAttack);
- alOut(m + alSus,inst->mSus);
- alOut(m + alWave,inst->mWave);
-
- // Most percussive instruments only use one cell
- if (c != 0xff)
- {
- alOut(c + alChar,inst->cChar);
- alOut(c + alScale,inst->cScale);
- alOut(c + alAttack,inst->cAttack);
- alOut(c + alSus,inst->cSus);
- alOut(c + alWave,inst->cWave);
- }
-
- alOut(which + alFeedCon,inst->nConn); // DEBUG - I think this is right
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_ALStopSound() - Turns off any sound effects playing through the
-// AdLib card
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_ALStopSound(void)
-{
-asm pushf
-asm cli
-
- (s32int)alSound = 0;
- alOut(alFreqH + 0,0);
-
-asm popf
-}
-
-static void
-SDL_AlSetFXInst(Instrument far *inst)
-{
- u8int c,m;
-
- m = modifiers[0];
- c = carriers[0];
- alOut(m + alChar,inst->mChar);
- alOut(m + alScale,inst->mScale);
- alOut(m + alAttack,inst->mAttack);
- alOut(m + alSus,inst->mSus);
- alOut(m + alWave,inst->mWave);
- alOut(c + alChar,inst->cChar);
- alOut(c + alScale,inst->cScale);
- alOut(c + alAttack,inst->cAttack);
- alOut(c + alSus,inst->cSus);
- alOut(c + alWave,inst->cWave);
-
- // Note: Switch commenting on these lines for old MUSE compatibility
-// alOut(alFeedCon,inst->nConn);
- alOut(alFeedCon,0);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_ALPlaySound() - Plays the specified sound on the AdLib card
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_ALPlaySound(AdLibSound far *sound)
-{
- Instrument far *inst;
- u8int huge *data;
-
- SDL_ALStopSound();
-
-asm pushf
-asm cli
-
- alLengthLeft = sound->common.length;
- data = sound->data;
- data++;
- data--;
- alSound = (u8int far *)data;
- alBlock = ((sound->block & 7) << 2) | 0x20;
- inst = &sound->inst;
-
- if (!(inst->mSus | inst->cSus))
- {
- asm popf
- Quit("SDL_ALPlaySound() - Bad instrument");
- }
-
- SDL_AlSetFXInst(&alZeroInst); // DEBUG
- SDL_AlSetFXInst(inst);
-
-asm popf
-}
-
-#if 0
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_ALSoundService() - Plays the next sample out through the AdLib card
-//
-///////////////////////////////////////////////////////////////////////////
-//static void
-void
-SDL_ALSoundService(void)
-{
- u8int s;
-
- if (alSound)
- {
- s = *alSound++;
- if (!s)
- alOut(alFreqH + 0,0);
- else
- {
- alOut(alFreqL + 0,s);
- alOut(alFreqH + 0,alBlock);
- }
-
- if (!(--alLengthLeft))
- {
- (s32int)alSound = 0;
- alOut(alFreqH + 0,0);
- SDL_SoundFinished();
- }
- }
-}
-#endif
-
-#if 0
-void
-SDL_ALService(void)
-{
- u8int a,v;
- u16int w;
-
- if (!sqActive)
- return;
-
- while (sqHackLen && (sqHackTime <= alTimeCount))
- {
- w = *sqHackPtr++;
- sqHackTime = alTimeCount + *sqHackPtr++;
- asm mov dx,[w]
- asm mov [a],dl
- asm mov [v],dh
- alOut(a,v);
- sqHackLen -= 4;
- }
- alTimeCount++;
- if (!sqHackLen)
- {
- sqHackPtr = (u16int far *)sqHack;
- sqHackLen = sqHackSeqLen;
- alTimeCount = sqHackTime = 0;
- }
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_ShutAL() - Shuts down the AdLib card for sound effects
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_ShutAL(void)
-{
-asm pushf
-asm cli
-
- alOut(alEffects,0);
- alOut(alFreqH + 0,0);
- SDL_AlSetFXInst(&alZeroInst);
- alSound = 0;
-
-asm popf
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_CleanAL() - Totally shuts down the AdLib card
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_CleanAL(void)
-{
- s16int i;
-
-asm pushf
-asm cli
-
- alOut(alEffects,0);
- for (i = 1;i < 0xf5;i++)
- alOut(i,0);
-
-asm popf
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_StartAL() - Starts up the AdLib card for sound effects
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_StartAL(void)
-{
- alFXReg = 0;
- alOut(alEffects,alFXReg);
- SDL_AlSetFXInst(&alZeroInst);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster
-// emulating an AdLib) present
-//
-///////////////////////////////////////////////////////////////////////////
-static int
-SDL_DetectAdLib(void)
-{
- u8int status1,status2;
- s16int i;
-
- alOut(4,0x60); // Reset T1 & T2
- alOut(4,0x80); // Reset IRQ
- status1 = readstat();
- alOut(2,0xff); // Set timer 1
- alOut(4,0x21); // Start timer 1
-#if 0
- SDL_Delay(TimerDelay100);
-#else
-asm mov dx,0x388
-asm mov cx,100
-usecloop:
-asm in al,dx
-asm loop usecloop
-#endif
-
- status2 = readstat();
- alOut(4,0x60);
- alOut(4,0x80);
-
- if (((status1 & 0xe0) == 0x00) && ((status2 & 0xe0) == 0xc0))
- {
- for (i = 1;i <= 0xf5;i++) // Zero all the registers
- alOut(i,0);
-
- alOut(1,0x20); // Set WSE=1
- alOut(8,0); // Set CSM=0 & SEL=0
-
- return(true);
- }
- else
- return(false);
-}
-
-#if 0
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_t0Service() - My timer 0 ISR which handles the different timings and
-// dispatches to whatever other routines are appropriate
-//
-///////////////////////////////////////////////////////////////////////////
-static void interrupt
-SDL_t0Service(void)
-{
-static u16int count = 1;
-
-#if 1 // for debugging
-asm mov dx,STATUS_REGISTER_1
-asm in al,dx
-asm mov dx,ATR_INDEX
-asm mov al,ATR_OVERSCAN
-asm out dx,al
-asm mov al,4 // red
-asm out dx,al
-#endif
-
- HackCount++;
-
- if ((MusicMode == smm_AdLib) || (DigiMode == sds_SoundSource))
- {
- SDL_ALService();
- SDL_SSService();
-// if (!(++count & 7))
- if (!(++count % 10))
- {
- LocalTime++;
- TimeCount++;
- if (SoundUserHook)
- SoundUserHook();
- }
-// if (!(count & 3))
- if (!(count % 5))
- {
- switch (SoundMode)
- {
- case sdm_PC:
- SDL_PCService();
- break;
- case sdm_AdLib:
- SDL_ALSoundService();
- break;
- }
- }
- }
- else
- {
- if (!(++count & 1))
- {
- LocalTime++;
- TimeCount++;
- if (SoundUserHook)
- SoundUserHook();
- }
- switch (SoundMode)
- {
- case sdm_PC:
- SDL_PCService();
- break;
- case sdm_AdLib:
- SDL_ALSoundService();
- break;
- }
- }
-
-asm mov ax,[WORD PTR TimerCount]
-asm add ax,[WORD PTR TimerDivisor]
-asm mov [WORD PTR TimerCount],ax
-asm jnc myack
- t0OldService(); // If we overflow a u16int, time to call old long handler
-asm jmp olddone
-myack:;
- outportb(0x20,0x20); // Ack the interrupt
-olddone:;
-
-#if 1 // for debugging
-asm mov dx,STATUS_REGISTER_1
-asm in al,dx
-asm mov dx,ATR_INDEX
-asm mov al,ATR_OVERSCAN
-asm out dx,al
-asm mov al,3 // blue
-asm out dx,al
-asm mov al,0x20 // normal
-asm out dx,al
-#endif
-}
-#endif
-
-////////////////////////////////////////////////////////////////////////////
-//
-// SDL_ShutDevice() - turns off whatever device was being used for sound fx
-//
-////////////////////////////////////////////////////////////////////////////
-static void
-SDL_ShutDevice(void)
-{
- switch (SoundMode)
- {
- case sdm_PC:
- SDL_ShutPC();
- break;
- case sdm_AdLib:
- SDL_ShutAL();
- break;
- }
- SoundMode = sdm_Off;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_CleanDevice() - totally shuts down all sound devices
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_CleanDevice(void)
-{
- if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib))
- SDL_CleanAL();
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SDL_StartDevice() - turns on whatever device is to be used for sound fx
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-SDL_StartDevice(void)
-{
- switch (SoundMode)
- {
- case sdm_AdLib:
- SDL_StartAL();
- break;
- }
- SoundNumber = SoundPriority = 0;
-}
-
-// Public routines
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_SetSoundMode() - Sets which sound hardware to use for sound effects
-//
-///////////////////////////////////////////////////////////////////////////
-int
-SD_SetSoundMode(SDMode mode)
-{
- int result = false;
- u16int tableoffset;
-
- SD_StopSound();
-
- if ((mode == sdm_AdLib) && !AdLibPresent)
- mode = sdm_PC;
-
- switch (mode)
- {
- case sdm_Off:
- NeedsDigitized = false;
- result = true;
- break;
- case sdm_PC:
- tableoffset = STARTPCSOUNDS;
- NeedsDigitized = false;
- result = true;
- break;
- case sdm_AdLib:
- if (AdLibPresent)
- {
- tableoffset = STARTADLIBSOUNDS;
- NeedsDigitized = false;
- result = true;
- }
- break;
- }
-
- if (result && (mode != SoundMode))
- {
- SDL_ShutDevice();
- SoundMode = mode;
- SoundTable = (u16int *)(&audiosegs[tableoffset]);
- SDL_StartDevice();
- }
-
- SDL_SetTimerSpeed();
-
- return(result);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_SetMusicMode() - sets the device to use for background music
-//
-///////////////////////////////////////////////////////////////////////////
-int
-SD_SetMusicMode(SMMode mode)
-{
- int result = false;
-
- SD_FadeOutMusic();
- while (SD_MusicPlaying())
- ;
-
- switch (mode)
- {
- case smm_Off:
- NeedsMusic = false;
- result = true;
- break;
- case smm_AdLib:
- if (AdLibPresent)
- {
- NeedsMusic = true;
- result = true;
- }
- break;
- }
-
- if (result)
- MusicMode = mode;
-
- SDL_SetTimerSpeed();
-
- return(result);
-}
-
-void
-SD_Startup(void)
-{
- s16int i;
-
- if (SD_Started)
- return;
-
- SDL_SetDS();
-
- SoundUserHook = 0;
-
- t0OldService = getvect(8); // Get old timer 0 ISR
-
- LocalTime = TimeCount = alTimeCount = 0;
-
- SD_SetSoundMode(sdm_Off);
- SD_SetMusicMode(smm_Off);
-
- /* → detect and select sound card */
-
- SoundSourcePresent = true;
-
- if (1)
- {
- AdLibPresent = SDL_DetectAdLib();
- if (AdLibPresent)
- {
- s16int port = -1;
- char *env = getenv("BLASTER");
- if (env)
- {
- s32int temp;
- while (*env)
- {
- while (isspace(*env))
- env++;
-
- switch (toupper(*env))
- {
- case 'A':
- temp = strtol(env + 1,&env,16);
- if
- (
- (temp >= 0x210)
- && (temp <= 0x260)
- && (!(temp & 0x00f))
- )
- port = (temp - 0x200) >> 4;
- else
- Quit("SD_Startup: Unsupported address value in BLASTER");
- break;
- case 'I':
- temp = strtol(env + 1,&env,10);
- if
- (
- (temp >= 0)
- && (temp <= 10)
- && (sbIntVectors[temp] != -1)
- )
- {
- sbInterrupt = temp;
- sbIntVec = sbIntVectors[sbInterrupt];
- }
- else
- Quit("SD_Startup: Unsupported interrupt value in BLASTER");
- break;
- case 'D':
- temp = strtol(env + 1,&env,10);
- if ((temp == 0) || (temp == 1) || (temp == 3))
- SDL_SBSetDMA(temp);
- else
- Quit("SD_Startup: Unsupported DMA value in BLASTER");
- break;
- default:
- while (isspace(*env))
- env++;
- while (*env && !isspace(*env))
- env++;
- break;
- }
- }
- }
- SoundBlasterPresent = SDL_DetectSoundBlaster(port);
- }
- }
-
- for (i = 0;i < 255;i++)
- pcSoundLookup[i] = i * 60;
-
- if (SoundBlasterPresent)
- SDL_StartSB();
-
- SDL_SetupDigi();
-
- SD_Started = true;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_Default() - Sets up the default behaviour for the Sound Mgr whether
-// the config file was present or not.
-//
-///////////////////////////////////////////////////////////////////////////
-void
-SD_Default(int gotit,SDMode sd,SMMode sm)
-{
- int gotsd,gotsm;
-
- gotsd = gotsm = gotit;
-
- if (gotsd) // Make sure requested sound hardware is available
- {
- switch (sd)
- {
- case sdm_AdLib:
- gotsd = AdLibPresent;
- break;
- }
- }
- if (!gotsd)
- {
- if (AdLibPresent)
- sd = sdm_AdLib;
- else
- sd = sdm_PC;
- }
- if (sd != SoundMode)
- SD_SetSoundMode(sd);
-
-
- if (gotsm) // Make sure requested music hardware is available
- {
- switch (sm)
- {
- case sdm_AdLib:
- gotsm = AdLibPresent;
- break;
- }
- }
- if (!gotsm)
- {
- if (AdLibPresent)
- sm = smm_AdLib;
- }
- if (sm != MusicMode)
- SD_SetMusicMode(sm);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_Shutdown() - shuts down the Sound Mgr
-// Removes sound ISR and turns off whatever sound hardware was active
-//
-///////////////////////////////////////////////////////////////////////////
-void
-SD_Shutdown(void)
-{
- if (!SD_Started)
- return;
-
- SD_MusicOff();
- SD_StopSound();
- SDL_ShutDevice();
- SDL_CleanDevice();
-
- if (SoundBlasterPresent)
- SDL_ShutSB();
-
- if (SoundSourcePresent)
- SDL_ShutSS();
-
- asm pushf
- asm cli
-
- SDL_SetTimer0(0);
-
- setvect(8,t0OldService);
-
- asm popf
-
- SD_Started = false;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_SetUserHook() - sets the routine that the Sound Mgr calls every 1/70th
-// of a second from its timer 0 ISR
-//
-///////////////////////////////////////////////////////////////////////////
-void
-SD_SetUserHook(void (* hook)(void))
-{
- SoundUserHook = hook;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_PositionSound() - Sets up a stereo imaging location for the next
-// sound to be played. Each channel ranges from 0 to 15.
-//
-///////////////////////////////////////////////////////////////////////////
-void
-SD_PositionSound(s16int leftvol,s16int rightvol)
-{
- LeftPosition = leftvol;
- RightPosition = rightvol;
- nextsoundpos = true;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_PlaySound() - plays the specified sound on the appropriate hardware
-//
-///////////////////////////////////////////////////////////////////////////
-int
-SD_PlaySound(soundnames sound)
-{
- int ispos;
- SoundCommon far *s;
- s16int lp,rp;
-
- lp = LeftPosition;
- rp = RightPosition;
- LeftPosition = 0;
- RightPosition = 0;
-
- ispos = nextsoundpos;
- nextsoundpos = false;
-
- if (sound == -1)
- return(false);
-
- s = MK_FP(SoundTable[sound],0);
- if ((SoundMode != sdm_Off) && !s)
- Quit("SD_PlaySound() - Uncached sound");
-
- if ((DigiMode != sds_Off) && (DigiMap[sound] != -1))
- {
- if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
- {
- if (s->priority < SoundPriority)
- return(false);
-
- SDL_PCStopSound();
-
- SD_PlayDigitized(DigiMap[sound],lp,rp);
- SoundPositioned = ispos;
- SoundNumber = sound;
- SoundPriority = s->priority;
- }
- else
- {
- asm pushf
- asm cli
- if (DigiPriority && !DigiNumber)
- {
- asm popf
- Quit("SD_PlaySound: Priority without a sound");
- }
- asm popf
-
- if (s->priority < DigiPriority)
- return(false);
-
- SD_PlayDigitized(DigiMap[sound],lp,rp);
- SoundPositioned = ispos;
- DigiNumber = sound;
- DigiPriority = s->priority;
- }
-
- return(true);
- }
-
- if (SoundMode == sdm_Off)
- return(false);
- if (!s->length)
- Quit("SD_PlaySound() - Zero length sound");
- if (s->priority < SoundPriority)
- return(false);
-
- switch (SoundMode)
- {
- case sdm_PC:
- SDL_PCPlaySound((void far *)s);
- break;
- case sdm_AdLib:
- SDL_ALPlaySound((void far *)s);
- break;
- }
-
- SoundNumber = sound;
- SoundPriority = s->priority;
-
- return(false);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_SoundPlaying() - returns the sound number that's playing, or 0 if
-// no sound is playing
-//
-///////////////////////////////////////////////////////////////////////////
-u16int
-SD_SoundPlaying(void)
-{
- int result = false;
-
- switch (SoundMode)
- {
- case sdm_PC:
- result = pcSound? true : false;
- break;
- case sdm_AdLib:
- result = alSound? true : false;
- break;
- }
-
- if (result)
- return(SoundNumber);
- else
- return(false);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_StopSound() - if a sound is playing, stops it
-//
-///////////////////////////////////////////////////////////////////////////
-void
-SD_StopSound(void)
-{
- if (DigiPlaying)
- SD_StopDigitized();
-
- switch (SoundMode)
- {
- case sdm_PC:
- SDL_PCStopSound();
- break;
- case sdm_AdLib:
- SDL_ALStopSound();
- break;
- }
-
- SoundPositioned = false;
-
- SDL_SoundFinished();
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_WaitSoundDone() - waits until the current sound is done playing
-//
-///////////////////////////////////////////////////////////////////////////
-void
-SD_WaitSoundDone(void)
-{
- while (SD_SoundPlaying())
- ;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_MusicOn() - turns on the sequencer
-//
-///////////////////////////////////////////////////////////////////////////
-void
-SD_MusicOn(void)
-{
- sqActive = true;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_MusicOff() - turns off the sequencer and any playing notes
-//
-///////////////////////////////////////////////////////////////////////////
-void
-SD_MusicOff(void)
-{
- u16int i;
-
-
- switch (MusicMode)
- {
- case smm_AdLib:
- alFXReg = 0;
- alOut(alEffects,0);
- for (i = 0;i < sqMaxTracks;i++)
- alOut(alFreqH + i + 1,0);
- break;
- }
- sqActive = false;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_StartMusic() - starts playing the music pointed to
-//
-///////////////////////////////////////////////////////////////////////////
-void
-SD_StartMusic(MusicGroup far *music)
-{
- SD_MusicOff();
-asm pushf
-asm cli
-
- if (MusicMode == smm_AdLib)
- {
- sqHackPtr = sqHack = music->values;
- sqHackSeqLen = sqHackLen = music->length;
- sqHackTime = 0;
- alTimeCount = 0;
- SD_MusicOn();
- }
-
-asm popf
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()
-// to see if the fadeout is complete
-//
-///////////////////////////////////////////////////////////////////////////
-void
-SD_FadeOutMusic(void)
-{
- switch (MusicMode)
- {
- case smm_AdLib:
- // DEBUG - quick hack to turn the music off
- SD_MusicOff();
- break;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SD_MusicPlaying() - returns true if music is currently playing, false if
-// not
-//
-///////////////////////////////////////////////////////////////////////////
-int
-SD_MusicPlaying(void)
-{
- int result;
-
- switch (MusicMode)
- {
- case smm_AdLib:
- result = false;
- // DEBUG - not written
- break;
- default:
- result = false;
- }
-
- return(result);
-}
--- a/sd.h
+++ /dev/null
@@ -1,213 +1,0 @@
-void alOut(u8int n,u8int b);
-
-#define TickBase 70 // 70Hz per tick - used as a base for timer 0
-
-typedef enum {
- sdm_Off,
- sdm_PC,sdm_AdLib,
- } SDMode;
-typedef enum {
- smm_Off,smm_AdLib
- } SMMode;
-typedef enum {
- sds_Off,sds_PC,sds_SoundSource,sds_SoundBlaster
- } SDSMode;
-typedef struct
- {
- u32int length;
- u16int priority;
- } SoundCommon;
-
-// PC Sound stuff
-#define pcTimer 0x42
-#define pcTAccess 0x43
-#define pcSpeaker 0x61
-
-#define pcSpkBits 3
-
-typedef struct
- {
- SoundCommon common;
- u8int data[1];
- } PCSound;
-
-// Registers for the Sound Blaster card - needs to be offset by n0 (0x10,0x20,0x30,0x40,0x50,0x60)
-#define sbReset 0x206 // W
-#define sbFMStatus 0x208 // R
-#define sbFMAddr 0x208 // W
-#define sbFMData 0x209 // W
-#define sbReadData 0x20a // R
-#define sbWriteCmd 0x20c // W
-#define sbWriteData 0x20c // W
-#define sbWriteStat 0x20c // R
-#define sbDataAvail 0x20e // R
-
-// Registers for the Sound Blaster Pro card - needs to be offset by n0 (0x20 or 0x40)
-#define sbpLFMStatus 0x200 // R
-#define sbpLFMAddr 0x200 // W
-#define sbpLFMData 0x201 // W
-#define sbpRFMStatus 0x202 // R
-#define sbpRFMAddr 0x202 // W
-#define sbpRFMData 0x203 // W
-#define sbpMixerAddr 0x204 // W
-#define sbpMixerData 0x205 // RW
-#define sbpCDData 0x210 // R
-#define sbpCDCommand 0x210 // W
-#define sbpCDStatus 0x211 // R
-#define sbpCDReset 0x212 // W
-
-// SBPro Mixer addresses
-#define sbpmReset 0x00
-#define sbpmVoiceVol 0x04
-#define sbpmMicMix 0x0a
-#define sbpmFilterADC 0x0c
-#define sbpmControl 0x0e
-#define sbpmMasterVol 0x22
-#define sbpmFMVol 0x26
-#define sbpmCDVol 0x28
-#define sbpmLineVol 0x2e
-
-typedef struct
- {
- SoundCommon common;
- u16int hertz;
- u8int bits,
- reference,
- data[1];
- } SampledSound;
-
-// Registers for the AdLib card
-#define alFMStatus 0x388 // R
-#define alFMAddr 0x388 // W
-#define alFMData 0x389 // W
-
-// Register addresses
-// Operator stuff
-#define alChar 0x20
-#define alScale 0x40
-#define alAttack 0x60
-#define alSus 0x80
-#define alWave 0xe0
-// Channel stuff
-#define alFreqL 0xa0
-#define alFreqH 0xb0
-#define alFeedCon 0xc0
-// Global stuff
-#define alEffects 0xbd
-
-typedef struct
- {
- u8int mChar,cChar,
- mScale,cScale,
- mAttack,cAttack,
- mSus,cSus,
- mWave,cWave,
- nConn,
-
- // These are only for Muse - these bytes are really unused
- voice,
- mode,
- unused[3];
- } Instrument;
-
-typedef struct
- {
- SoundCommon common;
- Instrument inst;
- u8int block,
- data[1];
- } AdLibSound;
-
-//
-// Sequencing stuff
-//
-#define sqMaxTracks 10
-#define sqMaxMoods 1 // DEBUG
-
-#define sev_Null 0 // Does nothing
-#define sev_NoteOff 1 // Turns a note off
-#define sev_NoteOn 2 // Turns a note on
-#define sev_NotePitch 3 // Sets the pitch of a currently playing note
-#define sev_NewInst 4 // Installs a new instrument
-#define sev_NewPerc 5 // Installs a new percussive instrument
-#define sev_PercOn 6 // Turns a percussive note on
-#define sev_PercOff 7 // Turns a percussive note off
-#define sev_SeqEnd -1 // Terminates a sequence
-
-// Flags for MusicGroup.flags
-#define sf_Melodic 0
-#define sf_Percussive 1
-
-#if 1
-typedef struct
- {
- u16int length,
- values[1];
- } MusicGroup;
-#else
-typedef struct
- {
- u16int flags,
- count,
- offsets[1];
- } MusicGroup;
-#endif
-
-typedef struct
- {
- /* This part needs to be set up by the user */
- u16int mood,far *moods[sqMaxMoods];
-
- /* The rest is set up by the code */
- Instrument inst;
- int percussive;
- u16int far *seq;
- u32int nextevent;
- } ActiveTrack;
-
-#define sqmode_Normal 0
-#define sqmode_FadeIn 1
-#define sqmode_FadeOut 2
-
-#define sqMaxFade 64 // DEBUG
-
-
-// Global variables
-extern int AdLibPresent,
- SoundSourcePresent,
- SoundBlasterPresent,
- NeedsMusic, // For Caching Mgr
- SoundPositioned;
-extern SDMode SoundMode;
-extern SDSMode DigiMode;
-extern SMMode MusicMode;
-extern int DigiPlaying;
-extern int DigiMap[];
-extern u32int TimeCount; // Global time in ticks
-
-// Function prototypes
-extern void SD_Startup(void),
- SD_Shutdown(void),
- SD_Default(int gotit,SDMode sd,SMMode sm),
-
- SD_PositionSound(int leftvol,int rightvol);
-extern int SD_PlaySound(soundnames sound);
-extern void SD_SetPosition(int leftvol,int rightvol),
- SD_StopSound(void),
- SD_WaitSoundDone(void),
-
- SD_StartMusic(MusicGroup far *music),
- SD_MusicOn(void),
- SD_MusicOff(void),
- SD_FadeOutMusic(void),
-
- SD_SetUserHook(void (*hook)(void));
-extern int SD_MusicPlaying(void),
- SD_SetSoundMode(SDMode mode),
- SD_SetMusicMode(SMMode mode);
-extern u16int SD_SoundPlaying(void);
-
-extern void SD_SetDigiDevice(SDSMode),
- SD_PlayDigitized(u16int which,int leftpos,int rightpos),
- SD_StopDigitized(void),
- SD_Poll(void);
--- a/snd.c
+++ b/snd.c
@@ -4,29 +4,430 @@
#include "dat.h"
#include "fns.h"
-Dat *imfs, *imfe;
-Sfx *sfxs, *sfxe;
+Dat *imfs;
+Sfx *sfxs;
+int sfxon, muson, pcmon;
-static int mi;
+enum{
+ Rate = 44100,
+ PcmHz = 7000,
+ ImfHz = 700,
+ SfxHz = 140,
+ Nsamp = Rate/ImfHz * 4,
+ Mdiv = ImfHz / Tb,
+ Pdiv = PcmHz / Tb,
+ Nbuf = Nsamp * Mdiv,
+ Rwse = 0x01,
+ Rnum = 0xa0,
+ Roct = 0xb0,
+ Ropm = 0xbd,
+ Rfed = 0xc0
+};
+/* channel 0, op 0-1 registers */
+static uchar inst[] = {0x20, 0x23, 0x40, 0x43, 0x60, 0x63, 0x80, 0x83, 0xe0, 0xe3};
+static uchar *sfxp, *sfxe, *pcm, *pcme, *imf;
+static Sfx *sfxd, *pcmd;
+static Dat *imfd;
+static vlong stc, sdt, mdt;
+static int sfd = -1;
+static uchar sbuf[Nbuf];
+
+static int h[] = { /* stolen property coefficients */
+ 32767, 32766, 32764, 32760, 32755, 32749, 32741, 32731, 32721, 32708,
+ 32695, 32679, 32663, 32645, 32625, 32604, 32582, 32558, 32533, 32506,
+ 32478, 32448, 32417, 32385, 32351, 32316, 32279, 32241, 32202, 32161,
+ 32119, 32075, 32030, 31984, 31936, 31887, 31836, 31784, 31731, 31676,
+ 31620, 31563, 31504, 31444, 31383, 31320, 31256, 31191, 31124, 31056,
+ 30987, 30916, 30845, 30771, 30697, 30621, 30544, 30466, 30387, 30306,
+ 30224, 30141, 30057, 29971, 29884, 29796, 29707, 29617, 29525, 29433,
+ 29339, 29244, 29148, 29050, 28952, 28852, 28752, 28650, 28547, 28443,
+ 28338, 28232, 28125, 28017, 27908, 27797, 27686, 27574, 27461, 27346,
+ 27231, 27115, 26998, 26879, 26760, 26640, 26519, 26398, 26275, 26151,
+ 26027, 25901, 25775, 25648, 25520, 25391, 25262, 25131, 25000, 24868,
+ 24735, 24602, 24467, 24332, 24197, 24060, 23923, 23785, 23647, 23507,
+ 23368, 23227, 23086, 22944, 22802, 22659, 22515, 22371, 22226, 22081,
+ 21935, 21789, 21642, 21494, 21346, 21198, 21049, 20900, 20750, 20600,
+ 20449, 20298, 20146, 19995, 19842, 19690, 19537, 19383, 19230, 19076,
+ 18922, 18767, 18612, 18457, 18302, 18146, 17990, 17834, 17678, 17521,
+ 17365, 17208, 17051, 16894, 16737, 16579, 16422, 16264, 16106, 15949,
+ 15791, 15633, 15475, 15317, 15159, 15001, 14843, 14685, 14527, 14369,
+ 14212, 14054, 13896, 13739, 13581, 13424, 13266, 13109, 12952, 12795,
+ 12639, 12482, 12326, 12170, 12014, 11858, 11703, 11548, 11393, 11238,
+ 11084, 10929, 10776, 10622, 10469, 10316, 10164, 10011, 9860, 9708,
+ 9557, 9407, 9256, 9106, 8957, 8808, 8659, 8511, 8364, 8216, 8070,
+ 7924, 7778, 7633, 7488, 7344, 7200, 7057, 6914, 6773, 6631, 6490,
+ 6350, 6210, 6071, 5933, 5795, 5658, 5521, 5385, 5250, 5115, 4981,
+ 4848, 4716, 4584, 4452, 4322, 4192, 4063, 3935, 3807, 3680, 3554,
+ 3429, 3304, 3180, 3057, 2935, 2813, 2692, 2572, 2453, 2335, 2217,
+ 2101, 1985, 1870, 1755, 1642, 1529, 1418, 1307, 1197, 1088, 979, 872,
+ 765, 660, 555, 451, 348, 246, 145, 44, -54, -153, -250, -347, -443,
+ -537, -631, -724, -816, -908, -998, -1087, -1175, -1263, -1349, -1435,
+ -1519, -1603, -1685, -1767, -1848, -1928, -2006, -2084, -2161, -2237,
+ -2312, -2386, -2459, -2531, -2603, -2673, -2742, -2810, -2878, -2944,
+ -3009, -3074, -3137, -3200, -3261, -3322, -3381, -3440, -3498, -3554,
+ -3610, -3665, -3719, -3772, -3824, -3875, -3925, -3974, -4022, -4069,
+ -4116, -4161, -4205, -4249, -4291, -4333, -4374, -4413, -4452, -4490,
+ -4527, -4563, -4599, -4633, -4666, -4699, -4730, -4761, -4791, -4820,
+ -4848, -4875, -4901, -4926, -4951, -4974, -4997, -5019, -5040, -5060,
+ -5080, -5098, -5116, -5133, -5149, -5164, -5178, -5192, -5205, -5217,
+ -5228, -5238, -5248, -5257, -5265, -5272, -5278, -5284, -5289, -5293,
+ -5297, -5299, -5301, -5303, -5303, -5303, -5302, -5300, -5298, -5295,
+ -5291, -5287, -5282, -5276, -5270, -5263, -5255, -5246, -5237, -5228,
+ -5217, -5206, -5195, -5183, -5170, -5157, -5143, -5128, -5113, -5097,
+ -5081, -5064, -5047, -5029, -5010, -4991, -4972, -4952, -4931, -4910,
+ -4889, -4867, -4844, -4821, -4797, -4774, -4749, -4724, -4699, -4673,
+ -4647, -4620, -4593, -4566, -4538, -4510, -4481, -4452, -4422, -4393,
+ -4363, -4332, -4301, -4270, -4238, -4206, -4174, -4142, -4109, -4076,
+ -4042, -4009, -3975, -3940, -3906, -3871, -3836, -3801, -3765, -3729,
+ -3693, -3657, -3620, -3584, -3547, -3510, -3472, -3435, -3397, -3360,
+ -3322, -3283, -3245, -3207, -3168, -3129, -3091, -3052, -3013, -2973,
+ -2934, -2895, -2855, -2816, -2776, -2736, -2697, -2657, -2617, -2577,
+ -2537, -2497, -2457, -2417, -2377, -2337, -2297, -2256, -2216, -2176,
+ -2136, -2096, -2056, -2016, -1976, -1936, -1896, -1856, -1817, -1777,
+ -1737, -1698, -1658, -1619, -1579, -1540, -1501, -1462, -1423, -1384,
+ -1345, -1306, -1268, -1230, -1191, -1153, -1115, -1077, -1040, -1002,
+ -965, -927, -890, -854, -817, -780, -744, -708, -672, -636, -600,
+ -565, -530, -494, -460, -425, -391, -356, -322, -289, -255, -222,
+ -189, -156, -123, -91, -59, -27, 4, 35, 66, 97, 127, 158, 188, 218,
+ 247, 277, 306, 334, 363, 391, 419, 447, 474, 501, 528, 554, 581, 606,
+ 632, 657, 683, 707, 732, 756, 780, 803, 827, 850, 872, 895, 917, 939,
+ 960, 981, 1002, 1023, 1043, 1063, 1082, 1102, 1121, 1139, 1158, 1176,
+ 1194, 1211, 1228, 1245, 1262, 1278, 1294, 1309, 1325, 1340, 1354,
+ 1369, 1383, 1397, 1410, 1423, 1436, 1448, 1461, 1473, 1484, 1496,
+ 1507, 1517, 1528, 1538, 1548, 1557, 1566, 1575, 1584, 1592, 1600,
+ 1608, 1616, 1623, 1630, 1636, 1643, 1649, 1654, 1660, 1665, 1670,
+ 1675, 1679, 1683, 1687, 1690, 1694, 1697, 1700, 1702, 1704, 1706,
+ 1708, 1709, 1711, 1712, 1712, 1713, 1713, 1713, 1713, 1712, 1711,
+ 1710, 1709, 1708, 1706, 1704, 1702, 1700, 1697, 1694, 1691, 1688,
+ 1685, 1681, 1677, 1673, 1669, 1664, 1660, 1655, 1650, 1644, 1639,
+ 1633, 1627, 1621, 1615, 1609, 1602, 1596, 1589, 1582, 1575, 1567,
+ 1560, 1552, 1544, 1536, 1528, 1520, 1511, 1503, 1494, 1485, 1476,
+ 1467, 1458, 1448, 1439, 1429, 1419, 1409, 1399, 1389, 1379, 1368,
+ 1358, 1347, 1337, 1326, 1315, 1304, 1293, 1282, 1271, 1260, 1248,
+ 1237, 1225, 1213, 1202, 1190, 1178, 1166, 1154, 1142, 1130, 1118,
+ 1106, 1094, 1081, 1069, 1057, 1044, 1032, 1019, 1007, 994, 981, 969,
+ 956, 943, 931, 918, 905, 892, 879, 867, 854, 841, 828, 815, 802, 790,
+ 777, 764, 751, 738, 725, 713, 700, 687, 674, 662, 649, 636, 623, 611,
+ 598, 585, 573, 560, 548, 535, 523, 510, 498, 486, 473, 461, 449, 437,
+ 425, 413, 401, 389, 377, 365, 353, 341, 330, 318, 307, 295, 284, 272,
+ 261, 250, 239, 228, 217, 206, 195, 184, 173, 163, 152, 141, 131, 121,
+ 110, 100, 90, 80, 70, 60, 51, 41, 31, 22, 12, 3, -5, -14, -23, -32,
+ -41, -50, -59, -67, -76, -84, -93, -101, -109, -117, -125, -133, -140,
+ -148, -156, -163, -170, -178, -185, -192, -199, -206, -212, -219,
+ -226, -232, -239, -245, -251, -257, -263, -269, -275, -280, -286,
+ -291, -297, -302, -307, -312, -317, -322, -327, -332, -336, -341,
+ -345, -349, -354, -358, -362, -366, -369, -373, -377, -380, -384,
+ -387, -390, -394, -397, -400, -402, -405, -408, -411, -413, -416,
+ -418, -420, -422, -424, -426, -428, -430, -432, -433, -435, -436,
+ -438, -439, -440, -442, -443, -444, -445, -445, -446, -447, -447,
+ -448, -448, -449, -449, -449, -449, -449, -449, -449, -449, -449,
+ -449, -449, -448, -448, -447, -447, -446, -445, -444, -443, -443,
+ -442, -441, -440, -438, -437, -436, -435, -433, -432, -430, -429,
+ -427, -426, -424, -422, -420, -419, -417, -415, -413, -411, -409,
+ -407, -405, -403, -400, -398, -396, -393, -391, -389, -386, -384,
+ -381, -379, -376, -374, -371, -368, -366, -363, -360, -357, -355,
+ -352, -349, -346, -343, -340, -337, -334, -331, -328, -325, -322,
+ -319, -316, -313, -310, -307, -304, -301, -298, -294, -291, -288,
+ -285, -282, -278, -275, -272, -269, -265, -262, -259, -256, -252,
+ -249, -246, -243, -239, -236, -233, -230, -226, -223, -220, -217,
+ -213, -210, -207, -204, -200, -197, -194, -191, -187, -184, -181,
+ -178, -175, -172, -168, -165, -162, -159, -156, -153, -150, -147,
+ -143, -140, -137, -134, -131, -128, -125, -122, -120, -117, -114,
+ -111, -108, -105, -102, -99, -97, -94, -91, -88, -86, -83, -80, -78,
+ -75, -72, -70, -67, -65, -62, -59, -57, -55, -52, -50, -47, -45, -43,
+ -40, -38, -36, -33, -31, -29, -27, -25, -22, -20, -18, -16, -14, -12,
+ -10, -8, -6, -4, -2, 0, 0, 2, 4, 6, 8, 9, 11, 13, 14, 16, 17, 19, 21,
+ 22, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 37, 38, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
+ 59, 60, 61, 62, 62, 63, 63, 64, 64, 65, 66, 66, 66, 67, 67, 68, 68,
+ 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 71, 71, 71, 71, 71, 70, 70, 70, 70, 69, 69, 69, 69, 68, 68, 68,
+ 67, 67, 67, 66, 66, 66, 65, 65, 64, 64, 64, 63, 63, 62, 62, 62, 61,
+ 61, 60, 60, 59, 59, 58, 58, 58, 57, 57, 56, 56, 55, 55, 54, 54, 53,
+ 53, 52, 52, 51, 51, 50, 50, 49, 48, 48, 47, 47, 46, 46, 45, 45, 44,
+ 44, 43, 43, 42, 42, 41, 41, 40, 39, 39, 38, 38, 37, 37, 36, 36, 35,
+ 35, 34, 34, 33, 33, 32, 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27,
+ 26, 26, 25, 25, 24, 24, 23, 23, 23, 22, 22, 21, 21, 20, 20, 20, 19,
+ 19, 18, 18, 17, 17, 17, 16, 16, 15, 15, 15, 14, 14, 14, 13, 13, 12,
+ 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 7, 7, 7, 7, 6, 6,
+ 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+enum{
+ Nl = 8, /* 2^Nl samples per zero crossing in fir */
+ Nη = 8, /* phase bits for filter interpolation */
+ Np = Nl+Nη, /* phase bits (fract of fixed point) */
+ TΔ = ((uvlong)PcmHz<<Np) / Rate,
+ One = 1<<Np,
+ LΔ = 1<<Np,
+ Le = nelem(h)<<Nη,
+ Lscale = 13128,
+ Nextra = 1 + (Le / LΔ),
+ Npbuf = Nextra*2 + (Nsamp - 1)
+};
+static int hΔ[nelem(h)], xb[Npbuf], xbi;
+static ulong xt;
+
+static void
+stopal(void)
+{
+ if(sfxd == nil)
+ return;
+ opl2wr(Roct, 0);
+ opl2wr(Rfed, 0);
+ sfxp = sfxe = nil;
+ sfxd = nil;
+}
+
+static void
+imfcmd(void)
+{
+ int r, v, dt;
+ uchar *u;
+
+ dt = 0;
+ while(dt == 0){
+ u = imf;
+ r = u[0];
+ v = u[1];
+ dt = u[3]<<8 | u[2];
+ opl2wr(r, v);
+ imf += 4;
+ if(imf >= imfd->e)
+ imf = imfd->p;
+ }
+ mdt = stc + dt;
+}
+
+static void
+alcmd(void)
+{
+ int v;
+
+ if(sfxp >= sfxe){
+ stopal();
+ return;
+ }
+ v = *sfxp++;
+ if(v != 0){
+ opl2wr(Rnum, v);
+ opl2wr(Roct, sfxd->blk);
+ }else
+ opl2wr(Roct, 0);
+ sdt = stc + ImfHz / SfxHz;
+}
+
+/* this spins constantly even when there's no music being played continuously,
+ * in essence only because some sound effects need an echo to play correctly.
+ * it sucks. */
+static void
+opl2step(void)
+{
+ uchar *p, *e;
+
+ p = sbuf;
+ e = p + sizeof sbuf;
+ while(p < e){
+ if(stc == sdt && sfxd != nil)
+ alcmd();
+ if(stc == mdt && imfd != nil)
+ imfcmd();
+ p = opl2out(p, Nsamp);
+ stc++;
+ }
+}
+
+/* stolen property cargocult upsampling */
+static void
+filter(int *xb, uchar *s)
+{
+ ulong l, p, i;
+ int *x, o, a;
+ vlong v;
+
+ if(s >= sbuf+sizeof sbuf)
+ return;
+ v = 0;
+ x = &xb[xt>>Np]; /* left side */
+ l = p = xt & (1<<Np)-1;
+ while(l < Le){
+ i = l >> Nη;
+ a = ((int)(l & (1<<Nη)-1) * hΔ[i] >> Nη) + h[i];
+ v += (vlong)*(--x) * a;
+ l += LΔ;
+ }
+ x = &xb[xt>>Np]; /* right side */
+ l = One-p & (1<<Np)-1;
+ if(l == 0) /* h[0] was already summed above if p == 0 */
+ l += LΔ;
+ while(l < Le){
+ i = l >> Nη;
+ a = ((int)(l & (1<<Nη)-1) * hΔ[i] >> Nη) + h[i];
+ v += (vlong)*x++ * a;
+ l += LΔ;
+ }
+ v >>= 2; /* scale */
+ v *= Lscale;
+ v >>= 27;
+ o = (v >> 16) + (short)(s[0] | s[1]<<8); /* mix */
+ if(o > 32767)
+ o = 32767;
+ else if(o < -32768)
+ o = -32768;
+ s[0] = s[2] = o;
+ s[1] = s[3] = o>>8;
+}
+
+static void
+resample(uchar *p, int n)
+{
+ int i, s;
+ uchar *b;
+ ulong e;
+
+ b = sbuf;
+ do{
+ for(i=xbi; n>0 && i<Npbuf; n--, i++)
+ xb[i] = ((uint)*p++ << 24) - 0x7fffffff;
+ xbi = i;
+ if(i < 2*Nextra) /* minimum for filter */
+ break;
+ e = i - Nextra << Np;
+ while(xt < e){ /* process buffer and mix */
+ filter(xb, b);
+ b += 4;
+ xt += TΔ;
+ }
+ e = xt >> Np;
+ if(e >= Npbuf - Nextra){ /* wrap at eob */
+ xt = xt - (e << Np) + (Nextra << Np);
+ s = (xt >> Np) - Nextra;
+ e -= Nextra;
+ i -= e;
+ if(i > 0){
+ memmove(xb+s, xb+e, i * sizeof i);
+ s += i;
+ }
+ xbi = s;
+ }
+ }while(n > 0);
+}
+
+static void
+pcmstep(void)
+{
+ uchar *e, *p;
+
+ p = pcm;
+ e = pcme;
+ if(p == e)
+ return;
+ if(p + Pdiv < e)
+ e = p + Pdiv;
+ resample(p, e-p);
+ pcm = e;
+}
+
void
+sndstep(void)
+{
+ if(!muson && !sfxon)
+ return;
+ opl2step();
+ pcmstep();
+ write(sfd, sbuf, sizeof sbuf);
+}
+
+void
+stopsfx(void)
+{
+ stopal();
+ pcm = pcme = nil;
+ pcmd = nil;
+}
+
+void
sfx(int n)
{
Sfx *s;
+ uchar *r, *i, *e;
s = sfxs+n;
- USED(s);
+ if(sfd < 0 || !sfxon)
+ return;
+ if(pcmon && s->pcm != nil){
+ if(pcmd != nil && s->pri < pcmd->pri)
+ return;
+ pcmd = s;
+ pcm = s->pcm->p;
+ pcme = s->pcm->e;
+ xbi = Nextra;
+ xt = Nextra << Np;
+ }else{
+ if(sfxd != nil && s->pri < sfxd->pri)
+ return;
+ stopal();
+ sfxd = s;
+ sfxp = s->p;
+ sfxe = s->e;
+ sdt = stc;
+ i = s->inst;
+ r = inst;
+ e = r + sizeof inst;
+ while(r < e)
+ opl2wr(*r++, *i++);
+ }
}
void
stopmus(void)
{
+ int i;
+
+ stopsfx();
+ opl2wr(Ropm, 0);
+ for(i=Roct+1; i<Roct+9; i++)
+ opl2wr(i, 0);
+ imf = nil;
+ imfd = nil;
}
void
mus(int n)
{
- if(n == mi)
+ Dat *d;
+
+ d = imfs+n;
+ if(sfd < 0 || !muson || d == imfd)
return;
stopmus();
+ mdt = stc;
+ imfd = d;
+ imf = d->p;
+}
+
+void
+initsnd(void)
+{
+ int n, fd;
+
+ fd = open("/dev/audio", OWRITE);
+ if(fd < 0){
+ fprint(2, "initsnd: %r\n");
+ return;
+ }
+ opl2init(Rate);
+ opl2wr(Rwse, 0x20);
+ for(n=0; n<nelem(hΔ)-1; n++)
+ hΔ[n] = h[n+1] - h[n];
+ sfd = fd;
+ muson = sfxon = pcmon = 1;
}
--- a/wl3d.c
+++ b/wl3d.c
@@ -253,6 +253,7 @@
dat(datdir);
notify(croak);
+ initsnd();
if(initdraw(nil, nil, "wl3d") < 0)
sysfatal("initdraw: %r");
resetfb();
@@ -274,6 +275,7 @@
resetfb();
}
step();
+ sndstep();
t0 += Td;
t = nsec();
dt = (t0 - t) / Te6;