shithub: qk1

Download patch

ref: be176cb096df301fd3ca221c0b08a88cf812c8b9
parent: a13439378618f7b8b372ab6526ca5578b21e65cd
author: Konstantinn Bonnet <[email protected]>
date: Thu Mar 9 15:10:58 EST 2017

fix and simplify sound

- don't buffer writes to /dev/audio, nuke all the stupid cargocult multiproc
  bullshit
- write variable number of samples based on time from last write + a bit
  more to avoid underruns
- move all sound code to snd.c, refactor sampling code, remove useless cvars
  and commands

--- a/bspfile.h
+++ b/bspfile.h
@@ -177,15 +177,6 @@
 	int			lightofs;		// start of [numstyles*surfsize] samples
 } dface_t;
 
-
-
-#define	AMBIENT_WATER	0
-#define	AMBIENT_SKY		1
-#define	AMBIENT_SLIME	2
-#define	AMBIENT_LAVA	3
-
-#define	NUM_AMBIENTS			4		// automatic ambient sounds
-
 // leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas
 // all other leafs need visibility info
 typedef struct
@@ -199,7 +190,7 @@
 	unsigned short		firstmarksurface;
 	unsigned short		nummarksurfaces;
 
-	byte		ambient_level[NUM_AMBIENTS];
+	byte		ambient_level[Namb];
 } dleaf_t;
 
 #pragma pack off
--- a/cd.c
+++ b/cd.c
@@ -52,7 +52,7 @@
 {
 	int a, n, afd, fd;
 	char s[24];
-	uchar buf[SNBUF];
+	uchar buf[8192];
 	short *p;
 
 	if((afd = open("/dev/audio", OWRITE)) < 0)
--- a/cl_main.c
+++ b/cl_main.c
@@ -82,7 +82,7 @@
 void CL_Disconnect (void)
 {
 // stop sounds (especially looping!)
-	S_StopAllSounds (true);
+	stopallsfx();
 	
 // bring the console down and fade the colors back to normal
 //	SCR_BringDownConsole ();
--- a/cl_parse.c
+++ b/cl_parse.c
@@ -96,12 +96,12 @@
     if (field_mask & SND_VOLUME)
 		volume = MSG_ReadByte ();
 	else
-		volume = DEFAULT_SOUND_PACKET_VOLUME;
+		volume = Spktvol;
 	
     if (field_mask & SND_ATTENUATION)
 		attenuation = MSG_ReadByte () / 64.0;
 	else
-		attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
+		attenuation = Spktatt;
 	
 	channel = MSG_ReadShort ();
 	sound_num = MSG_ReadByte ();
@@ -115,7 +115,7 @@
 	for (i=0 ; i<3 ; i++)
 		pos[i] = MSG_ReadCoord ();
  
-    S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
+    startsfx (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
 }       
 
 /*
@@ -261,7 +261,7 @@
 			return;
 		}
 		strcpy (sound_precache[numsounds], str);
-		S_TouchSound (str);
+		touchsfx (str);
 	}
 
 //
@@ -279,13 +279,11 @@
 		CL_KeepaliveMessage ();
 	}
 
-	S_BeginPrecaching ();
 	for (i=1 ; i<numsounds ; i++)
 	{
-		cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]);
+		cl.sound_precache[i] = precachesfx (sound_precache[i]);
 		CL_KeepaliveMessage ();
 	}
-	S_EndPrecaching ();
 
 
 // local state
@@ -667,7 +665,7 @@
 	vol = MSG_ReadByte ();
 	atten = MSG_ReadByte ();
 	
-	S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
+	staticsfx (cl.sound_precache[sound_num], org, vol, atten);
 }
 
 
@@ -794,7 +792,7 @@
 			
 		case svc_stopsound:
 			i = MSG_ReadShort();
-			S_StopSound(i>>3, i&7);
+			stopsfx(i>>3, i&7);
 			break;
 		
 		case svc_updatename:
--- a/cl_tent.c
+++ b/cl_tent.c
@@ -8,13 +8,13 @@
 entity_t	cl_temp_entities[MAX_TEMP_ENTITIES];
 beam_t		cl_beams[MAX_BEAMS];
 
-sfx_t			*cl_sfx_wizhit;
-sfx_t			*cl_sfx_knighthit;
-sfx_t			*cl_sfx_tink1;
-sfx_t			*cl_sfx_ric1;
-sfx_t			*cl_sfx_ric2;
-sfx_t			*cl_sfx_ric3;
-sfx_t			*cl_sfx_r_exp3;
+Sfx			*cl_sfx_wizhit;
+Sfx			*cl_sfx_knighthit;
+Sfx			*cl_Sfxink1;
+Sfx			*cl_sfx_ric1;
+Sfx			*cl_sfx_ric2;
+Sfx			*cl_sfx_ric3;
+Sfx			*cl_sfx_r_exp3;
 
 /*
 =================
@@ -23,13 +23,13 @@
 */
 void CL_InitTEnts (void)
 {
-	cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav");
-	cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav");
-	cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav");
-	cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav");
-	cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav");
-	cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav");
-	cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav");
+	cl_sfx_wizhit = precachesfx ("wizard/hit.wav");
+	cl_sfx_knighthit = precachesfx ("hknight/hit.wav");
+	cl_Sfxink1 = precachesfx ("weapons/tink1.wav");
+	cl_sfx_ric1 = precachesfx ("weapons/ric1.wav");
+	cl_sfx_ric2 = precachesfx ("weapons/ric2.wav");
+	cl_sfx_ric3 = precachesfx ("weapons/ric3.wav");
+	cl_sfx_r_exp3 = precachesfx ("weapons/r_exp3.wav");
 }
 
 /*
@@ -103,7 +103,7 @@
 		pos[1] = MSG_ReadCoord ();
 		pos[2] = MSG_ReadCoord ();
 		R_RunParticleEffect (pos, vec3_origin, 20, 30);
-		S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
+		startsfx (-1, 0, cl_sfx_wizhit, pos, 1, 1);
 		break;
 		
 	case TE_KNIGHTSPIKE:			// spike hitting wall
@@ -111,7 +111,7 @@
 		pos[1] = MSG_ReadCoord ();
 		pos[2] = MSG_ReadCoord ();
 		R_RunParticleEffect (pos, vec3_origin, 226, 20);
-		S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
+		startsfx (-1, 0, cl_sfx_knighthit, pos, 1, 1);
 		break;
 		
 	case TE_SPIKE:			// spike hitting wall
@@ -120,16 +120,16 @@
 		pos[2] = MSG_ReadCoord ();
 		R_RunParticleEffect (pos, vec3_origin, 0, 10);
 		if ( rand() % 5 )
-			S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
+			startsfx (-1, 0, cl_Sfxink1, pos, 1, 1);
 		else
 		{
 			rnd = rand() & 3;
 			if (rnd == 1)
-				S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
+				startsfx (-1, 0, cl_sfx_ric1, pos, 1, 1);
 			else if (rnd == 2)
-				S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
+				startsfx (-1, 0, cl_sfx_ric2, pos, 1, 1);
 			else
-				S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
+				startsfx (-1, 0, cl_sfx_ric3, pos, 1, 1);
 		}
 		break;
 	case TE_SUPERSPIKE:			// super spike hitting wall
@@ -139,16 +139,16 @@
 		R_RunParticleEffect (pos, vec3_origin, 0, 20);
 
 		if ( rand() % 5 )
-			S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
+			startsfx (-1, 0, cl_Sfxink1, pos, 1, 1);
 		else
 		{
 			rnd = rand() & 3;
 			if (rnd == 1)
-				S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
+				startsfx (-1, 0, cl_sfx_ric1, pos, 1, 1);
 			else if (rnd == 2)
-				S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
+				startsfx (-1, 0, cl_sfx_ric2, pos, 1, 1);
 			else
-				S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
+				startsfx (-1, 0, cl_sfx_ric3, pos, 1, 1);
 		}
 		break;
 		
@@ -169,7 +169,7 @@
 		dl->radius = 350;
 		dl->die = cl.time + 0.5;
 		dl->decay = 300;
-		S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
+		startsfx (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
 		break;
 		
 	case TE_TAREXPLOSION:			// tarbaby explosion
@@ -178,7 +178,7 @@
 		pos[2] = MSG_ReadCoord ();
 		R_BlobExplosion (pos);
 
-		S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
+		startsfx (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
 		break;
 
 	case TE_LIGHTNING1:				// lightning bolts
@@ -225,7 +225,7 @@
 		dl->radius = 350;
 		dl->die = cl.time + 0.5;
 		dl->decay = 300;
-		S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
+		startsfx (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
 		break;
 
 	default:
--- a/client.h
+++ b/client.h
@@ -179,7 +179,7 @@
 // information that is static for the entire time connected to a server
 //
 	struct model_s		*model_precache[MAX_MODELS];
-	struct sfx_s		*sound_precache[MAX_SOUNDS];
+	Sfx *sound_precache[MAX_SOUNDS];
 
 	char		levelname[40];	// for display on solo scoreboard
 	int			viewentity;		// cl_entitites[cl.viewentity] = player
--- a/console.c
+++ b/console.c
@@ -223,7 +223,7 @@
 	if (txt[0] == 1)
 	{
 		mask = 128;		// go to colored text
-		S_LocalSound ("misc/talk.wav");
+		localsfx ("misc/talk.wav");
 	// play talk wav
 		txt++;
 	}
--- a/dat.h
+++ b/dat.h
@@ -1,3 +1,5 @@
+typedef struct Sfx Sfx;
+
 enum{
 	Npath = 64,
 	Nfspath = 128,
@@ -5,7 +7,9 @@
 	Nsav = 12,
 	Nsavcm = 40,
 	Nsavver = 5,
-	Nparms = 16
+	Nparms = 16,
+
+	Te9 = 1000000000
 };
 
 extern char fsdir[];
@@ -13,3 +17,21 @@
 
 extern char savs[][Nsavcm];
 extern int savcanld[];
+
+enum{
+	Fpsmin = 10,
+	Fpsmax = 72
+};
+
+enum{
+	Ambwater = 0,
+	Ambsky,
+	Ambslime,
+	Amblava,
+	Namb
+};
+
+enum{
+	Spktvol = 255
+};
+#define Spktatt 1.0
--- a/draw.c
+++ b/draw.c
@@ -809,10 +809,6 @@
 	int			x,y;
 	byte		*pbuf;
 
-	VID_UnlockBuffer ();
-	S_ExtraUpdate ();
-	VID_LockBuffer ();
-
 	for (y=0 ; y<vid.height ; y++)
 	{
 		int	t;
@@ -826,10 +822,6 @@
 				pbuf[x] = 0;
 		}
 	}
-
-	VID_UnlockBuffer ();
-	S_ExtraUpdate ();
-	VID_LockBuffer ();
 }
 
 //=============================================================================
--- a/fns.h
+++ b/fns.h
@@ -1,3 +1,13 @@
+void	stepsnd(vec3_t, vec3_t, vec3_t, vec3_t);
+void	stopallsfx(void);
+void	stopsfx(int, int);
+void	startsfx(int, int, Sfx *, vec3_t, float, float);
+void	localsfx(char *);
+void	staticsfx(Sfx *, vec3_t, float, float);
+void	touchsfx(char *);
+Sfx*	precachesfx(char *);
+void	shutsnd(void);
+int	initsnd(void);
 void	setcvar(char*, char*);
 void	setcvarv(char*, float);
 void	abortdemo(void);
--- a/fs.c
+++ b/fs.c
@@ -344,10 +344,10 @@
 	switch(mth){
 	case Fhunk: buf = Hunk_AllocName(m + 1, r); break;
 	case Fcache: buf = Cache_Alloc(loadcache, m + 1, r); break;
-	case Fstack: buf = m+1 <= loadsize ? loadbuf : Hunk_TempAlloc(m+1);
+	case Fstack: buf = m + 1 <= loadsize ? loadbuf : Hunk_TempAlloc(m + 1); break;
 	}
 	if(buf == nil)
-		fatal("loadlmp %s %d: memory allocation failed: %r", f, m+1);
+		fatal("loadlmp %s %d: memory allocation failed: %r", f, m + 1);
 	buf[m] = 0;
 	Draw_BeginDisc();
 	eread(bf, buf, m);
@@ -684,7 +684,7 @@
 		goto exit;
 	n = strtol(s, nil, 10);
 	if(n != Nsavver){
-		werrstr("invalid version %d\n", n);
+		werrstr("invalid version %d", n);
 		goto exit;
 	}
 	Brdline(bf, '\n');
--- a/host.c
+++ b/host.c
@@ -57,7 +57,6 @@
 
 cvar_t	temp1 = {"temp1","0"};
 
-
 /*
 ================
 Host_EndGame
@@ -426,43 +425,8 @@
 	memset(&cl, 0, sizeof cl);
 }
 
-
-//============================================================================
-
-
 /*
 ===================
-Host_FilterTime
-
-Returns false if the time is too short to run a frame
-===================
-*/
-qboolean Host_FilterTime (float time)
-{
-	realtime += time;
-
-	if (!cls.timedemo && realtime - oldrealtime < 1.0/72.0)
-		return false;		// framerate is too high
-
-	host_frametime = realtime - oldrealtime;
-	oldrealtime = realtime;
-
-	if (host_framerate.value > 0)
-		host_frametime = host_framerate.value;
-	else
-	{	// don't allow really long or short frames
-		if (host_frametime > 0.1)
-			host_frametime = 0.1;
-		if (host_frametime < 0.001)
-			host_frametime = 0.001;
-	}
-	
-	return true;
-}
-
-
-/*
-===================
 Host_GetConsoleCommands
 
 Add them exactly as if they had been typed at the console
@@ -511,15 +475,21 @@
 	SV_SendClientMessages ();
 }
 
+static int
+boundfps(float t)
+{
+	realtime += t;
+	if(!cls.timedemo && realtime - oldrealtime < 1.0 / Fpsmax)
+		return -1;
+	host_frametime = realtime - oldrealtime;
+	oldrealtime = realtime;
+	if(host_framerate.value > 0)
+		host_frametime = host_framerate.value;
+	else if(host_frametime > 1.0 / Fpsmin)
+		host_frametime = 1.0 / Fpsmin;
+	return 0;
+}
 
-
-/*
-==================
-Host_Frame
-
-Runs all active servers
-==================
-*/
 void _Host_Frame (float time)
 {
 	static double		time1 = 0;
@@ -532,10 +502,9 @@
 
 // keep the random time dependent
 	rand ();
-	
-// decide the simulation time
-	if (!Host_FilterTime (time))
-		return;			// don't run too fast, or packets will flood out
+
+	if(boundfps(time) < 0)
+		return;
 		
 // get new key events
 	Sys_SendKeyEvents ();
@@ -595,11 +564,11 @@
 // update audio
 	if (cls.signon == SIGNONS)
 	{
-		S_Update (r_origin, vpn, vright, vup);
+		stepsnd (r_origin, vpn, vright, vup);
 		CL_DecayLights ();
 	}
 	else
-		S_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin);
+		stepsnd (vec3_origin, vec3_origin, vec3_origin, vec3_origin);
 	
 	CDAudio_Update();
 
@@ -711,7 +680,8 @@
 		Draw_Init ();
 		SCR_Init ();
 		R_Init ();
-		S_Init ();
+		if(initsnd() < 0)
+			fprint(2, "initsnd: %r\n");
 		CDAudio_Init ();
 		Sbar_Init ();
 		CL_Init ();
@@ -753,7 +723,7 @@
 
 	CDAudio_Shutdown ();
 	NET_Shutdown ();
-	S_Shutdown();
+	shutsnd();
 	IN_Shutdown ();
 
 	if (cls.state != ca_dedicated)
--- a/menu.c
+++ b/menu.c
@@ -296,13 +296,13 @@
 		break;
 
 	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		if (++m_main_cursor >= MAIN_ITEMS)
 			m_main_cursor = 0;
 		break;
 
 	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		if (--m_main_cursor < 0)
 			m_main_cursor = MAIN_ITEMS - 1;
 		break;
@@ -375,13 +375,13 @@
 		break;
 
 	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS)
 			m_singleplayer_cursor = 0;
 		break;
 
 	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		if (--m_singleplayer_cursor < 0)
 			m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1;
 		break;
@@ -483,7 +483,7 @@
 		break;
 
 	case K_ENTER:
-		S_LocalSound ("misc/menu2.wav");
+		localsfx ("misc/menu2.wav");
 		if (!savcanld[load_cursor])
 			return;
 		m_state = m_none;
@@ -499,7 +499,7 @@
 
 	case K_UPARROW:
 	case K_LEFTARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		load_cursor--;
 		if (load_cursor < 0)
 			load_cursor = Nsav-1;
@@ -507,7 +507,7 @@
 
 	case K_DOWNARROW:
 	case K_RIGHTARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		load_cursor++;
 		if (load_cursor >= Nsav)
 			load_cursor = 0;
@@ -532,7 +532,7 @@
 
 	case K_UPARROW:
 	case K_LEFTARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		load_cursor--;
 		if (load_cursor < 0)
 			load_cursor = Nsav-1;
@@ -540,7 +540,7 @@
 
 	case K_DOWNARROW:
 	case K_RIGHTARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		load_cursor++;
 		if (load_cursor >= Nsav)
 			load_cursor = 0;
@@ -592,13 +592,13 @@
 		break;
 
 	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS)
 			m_multiplayer_cursor = 0;
 		break;
 
 	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		if (--m_multiplayer_cursor < 0)
 			m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1;
 		break;
@@ -700,7 +700,7 @@
 		break;
 
 	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		setup_cursor--;
 		if (setup_cursor < 0)
 			setup_cursor = NUM_SETUP_CMDS-1;
@@ -707,7 +707,7 @@
 		break;
 
 	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		setup_cursor++;
 		if (setup_cursor >= NUM_SETUP_CMDS)
 			setup_cursor = 0;
@@ -716,7 +716,7 @@
 	case K_LEFTARROW:
 		if (setup_cursor < 2)
 			return;
-		S_LocalSound ("misc/menu3.wav");
+		localsfx ("misc/menu3.wav");
 		if (setup_cursor == 2)
 			setup_top = setup_top - 1;
 		if (setup_cursor == 3)
@@ -726,7 +726,7 @@
 		if (setup_cursor < 2)
 			return;
 forward:
-		S_LocalSound ("misc/menu3.wav");
+		localsfx ("misc/menu3.wav");
 		if (setup_cursor == 2)
 			setup_top = setup_top + 1;
 		if (setup_cursor == 3)
@@ -916,13 +916,13 @@
 		break;
 
 	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		if (++m_net_cursor >= m_net_items)
 			m_net_cursor = 0;
 		break;
 
 	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		if (--m_net_cursor < 0)
 			m_net_cursor = m_net_items - 1;
 		break;
@@ -983,7 +983,7 @@
 
 void M_AdjustSliders (int dir)
 {
-	S_LocalSound ("misc/menu3.wav");
+	localsfx ("misc/menu3.wav");
 
 	switch (options_cursor)
 	{
@@ -1170,7 +1170,7 @@
 		return;
 
 	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		options_cursor--;
 		if (options_cursor < 0)
 			options_cursor = OPTIONS_ITEMS-1;
@@ -1177,7 +1177,7 @@
 		break;
 
 	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		options_cursor++;
 		if (options_cursor >= OPTIONS_ITEMS)
 			options_cursor = 0;
@@ -1340,7 +1340,7 @@
 
 	if (bind_grab)
 	{	// defining a key
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		if (k != '`')
 		{
 			sprint (cmd, "bind \"%s\" \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor][0]);
@@ -1359,7 +1359,7 @@
 
 	case K_LEFTARROW:
 	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		keys_cursor--;
 		if (keys_cursor < 0)
 			keys_cursor = NUMCOMMANDS-1;
@@ -1367,7 +1367,7 @@
 
 	case K_DOWNARROW:
 	case K_RIGHTARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		keys_cursor++;
 		if (keys_cursor >= NUMCOMMANDS)
 			keys_cursor = 0;
@@ -1375,7 +1375,7 @@
 
 	case K_ENTER:		// go into bind mode
 		M_FindKeysForCommand (bindnames[keys_cursor][0], keys);
-		S_LocalSound ("misc/menu2.wav");
+		localsfx ("misc/menu2.wav");
 		if (keys[1] != -1)
 			M_UnbindCommand (bindnames[keys_cursor][0]);
 		bind_grab = true;
@@ -1383,7 +1383,7 @@
 
 	case K_BACKSPACE:		// delete bindings
 	case K_DEL:				// delete bindings
-		S_LocalSound ("misc/menu2.wav");
+		localsfx ("misc/menu2.wav");
 		M_UnbindCommand (bindnames[keys_cursor][0]);
 		break;
 	}
@@ -1707,7 +1707,7 @@
 		break;
 
 	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		serialConfig_cursor--;
 		if (serialConfig_cursor < 0)
 			serialConfig_cursor = NUM_SERIALCONFIG_CMDS-1;
@@ -1714,7 +1714,7 @@
 		break;
 
 	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		serialConfig_cursor++;
 		if (serialConfig_cursor >= NUM_SERIALCONFIG_CMDS)
 			serialConfig_cursor = 0;
@@ -1723,7 +1723,7 @@
 	case K_LEFTARROW:
 		if (serialConfig_cursor > 2)
 			break;
-		S_LocalSound ("misc/menu3.wav");
+		localsfx ("misc/menu3.wav");
 
 		if (serialConfig_cursor == 0)
 		{
@@ -1755,7 +1755,7 @@
 		if (serialConfig_cursor > 2)
 			break;
 forward:
-		S_LocalSound ("misc/menu3.wav");
+		localsfx ("misc/menu3.wav");
 
 		if (serialConfig_cursor == 0)
 		{
@@ -1933,7 +1933,7 @@
 		break;
 
 	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		modemConfig_cursor--;
 		if (modemConfig_cursor < 0)
 			modemConfig_cursor = NUM_MODEMCONFIG_CMDS-1;
@@ -1940,7 +1940,7 @@
 		break;
 
 	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		modemConfig_cursor++;
 		if (modemConfig_cursor >= NUM_MODEMCONFIG_CMDS)
 			modemConfig_cursor = 0;
@@ -1954,7 +1954,7 @@
 				modemConfig_dialing = 'T';
 			else
 				modemConfig_dialing = 'P';
-			S_LocalSound ("misc/menu1.wav");
+			localsfx ("misc/menu1.wav");
 		}
 		break;
 
@@ -2135,7 +2135,7 @@
 		break;
 
 	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		lanConfig_cursor--;
 		if (lanConfig_cursor < 0)
 			lanConfig_cursor = NUM_LANCONFIG_CMDS-1;
@@ -2142,7 +2142,7 @@
 		break;
 
 	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		lanConfig_cursor++;
 		if (lanConfig_cursor >= NUM_LANCONFIG_CMDS)
 			lanConfig_cursor = 0;
@@ -2637,7 +2637,7 @@
 		break;
 
 	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		gameoptions_cursor--;
 		if (gameoptions_cursor < 0)
 			gameoptions_cursor = NUM_GAMEOPTIONS-1;
@@ -2644,7 +2644,7 @@
 		break;
 
 	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		gameoptions_cursor++;
 		if (gameoptions_cursor >= NUM_GAMEOPTIONS)
 			gameoptions_cursor = 0;
@@ -2653,7 +2653,7 @@
 	case K_LEFTARROW:
 		if (gameoptions_cursor == 0)
 			break;
-		S_LocalSound ("misc/menu3.wav");
+		localsfx ("misc/menu3.wav");
 		M_NetStart_Change (-1);
 		break;
 
@@ -2660,12 +2660,12 @@
 	case K_RIGHTARROW:
 		if (gameoptions_cursor == 0)
 			break;
-		S_LocalSound ("misc/menu3.wav");
+		localsfx ("misc/menu3.wav");
 		M_NetStart_Change (1);
 		break;
 
 	case K_ENTER:
-		S_LocalSound ("misc/menu2.wav");
+		localsfx ("misc/menu2.wav");
 		if (gameoptions_cursor == 0)
 		{
 			if (sv.active)
@@ -2821,7 +2821,7 @@
 
 	case K_UPARROW:
 	case K_LEFTARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		slist_cursor--;
 		if (slist_cursor < 0)
 			slist_cursor = hostCacheCount - 1;
@@ -2829,7 +2829,7 @@
 
 	case K_DOWNARROW:
 	case K_RIGHTARROW:
-		S_LocalSound ("misc/menu1.wav");
+		localsfx ("misc/menu1.wav");
 		slist_cursor++;
 		if (slist_cursor >= hostCacheCount)
 			slist_cursor = 0;
@@ -2836,7 +2836,7 @@
 		break;
 
 	case K_ENTER:
-		S_LocalSound ("misc/menu2.wav");
+		localsfx ("misc/menu2.wav");
 		m_return_state = m_state;
 		m_return_onerror = true;
 		slist_sorted = false;
@@ -2883,12 +2883,7 @@
 		scr_copyeverything = 1;
 
 		if (scr_con_current)
-		{
 			Draw_ConsoleBackground (vid.height);
-			VID_UnlockBuffer ();
-			S_ExtraUpdate ();
-			VID_LockBuffer ();
-		}
 		else
 			Draw_FadeScreen ();
 
@@ -2979,13 +2974,9 @@
 
 	if (m_entersound)
 	{
-		S_LocalSound ("misc/menu2.wav");
+		localsfx ("misc/menu2.wav");
 		m_entersound = false;
 	}
-
-	VID_UnlockBuffer ();
-	S_ExtraUpdate ();
-	VID_LockBuffer ();
 }
 
 void
--- a/mkfile
+++ b/mkfile
@@ -4,6 +4,7 @@
 TARG=quake
 
 OFILES=\
+	cd.$O\
 	cl_demo.$O\
 	cl_input.$O\
 	cl_main.$O\
@@ -30,14 +31,16 @@
 	fs.$O\
 	host.$O\
 	host_cmd.$O\
+	in.$O\
 	keys.$O\
-	menu.$O\
 	mathlib.$O\
+	menu.$O\
 	model.$O\
+	net_bsd.$O\
+	net_dgrm.$O\
 	net_loop.$O\
 	net_main.$O\
-	net_dgrm.$O\
-	net_bsd.$O\
+	net_udp.$O\
 	pr_cmds.$O\
 	pr_edict.$O\
 	pr_exec.$O\
@@ -45,36 +48,30 @@
 	r_aclip.$O\
 	r_alias.$O\
 	r_bsp.$O\
-	r_light.$O\
 	r_draw.$O\
 	r_efrag.$O\
 	r_edge.$O\
-	r_misc.$O\
+	r_light.$O\
 	r_main.$O\
+	r_misc.$O\
+	r_part.$O\
 	r_sky.$O\
 	r_sprite.$O\
 	r_surf.$O\
-	r_part.$O\
 	r_vars.$O\
 	screen.$O\
 	sbar.$O\
+	snd.$O\
 	sv_main.$O\
-	sv_phys.$O\
 	sv_move.$O\
+	sv_phys.$O\
 	sv_user.$O\
-	zone.$O\
+	sys.$O\
+	vid.$O\
 	view.$O\
 	wad.$O\
 	world.$O\
-	snd_dma.$O\
-	snd_mem.$O\
-	snd_mix.$O\
-	in.$O\
-	sys.$O\
-	vid.$O\
-	snd.$O\
-	cd.$O\
-	net_udp.$O\
+	zone.$O\
 
 HFILES=\
 	dat.h\
@@ -109,7 +106,6 @@
 	sbar.h\
 	screen.h\
 	server.h\
-	sound.h\
 	spritegn.h\
 	sys.h\
 	vid.h\
--- a/model.h
+++ b/model.h
@@ -141,7 +141,7 @@
 	msurface_t	**firstmarksurface;
 	int			nummarksurfaces;
 	int			key;			// BSP sequence number for leaf's contents
-	byte		ambient_sound_level[NUM_AMBIENTS];
+	byte		ambient_sound_level[Namb];
 } mleaf_t;
 
 // !!! if this is changed, it must be changed in asm_i386.h too !!!
--- a/quakedef.h
+++ b/quakedef.h
@@ -167,7 +167,15 @@
 #include "protocol.h"
 #include "cmd.h"
 #include "sbar.h"
-#include "sound.h"
+
+struct Sfx{
+	char s[Npath];
+	cache_user_t cu;
+};
+
+extern cvar_t bgmvolume;
+extern cvar_t volume;
+
 #include "render.h"
 #include "client.h"
 #include "progs.h"
--- a/r_edge.c
+++ b/r_edge.c
@@ -689,10 +689,6 @@
 	// the next scan
 		if (span_p >= max_span_p)
 		{
-			VID_UnlockBuffer ();
-			S_ExtraUpdate ();	// don't let sound get messed up if going slow
-			VID_LockBuffer ();
-		
 			if (r_drawculledpolys)
 			{
 				R_DrawCulledPolys ();
--- a/r_main.c
+++ b/r_main.c
@@ -881,13 +881,6 @@
 		db_time2 = Sys_FloatTime ();
 		se_time1 = db_time2;
 	}
-
-	if (!r_dspeeds.value)
-	{
-		VID_UnlockBuffer ();
-		S_ExtraUpdate ();	// don't let sound get messed up if going slow
-		VID_LockBuffer ();
-	}
 	
 	if (!(r_drawpolys | r_drawculledpolys))
 		R_ScanEdges ();
@@ -927,22 +920,8 @@
 
 	if (!cl_entities[0].model || !cl.worldmodel)
 		fatal ("R_RenderView: NULL worldmodel");
-		
-	if (!r_dspeeds.value)
-	{
-		VID_UnlockBuffer ();
-		S_ExtraUpdate ();	// don't let sound get messed up if going slow
-		VID_LockBuffer ();
-	}
 	
 	R_EdgeDrawing ();
-
-	if (!r_dspeeds.value)
-	{
-		VID_UnlockBuffer ();
-		S_ExtraUpdate ();	// don't let sound get messed up if going slow
-		VID_LockBuffer ();
-	}
 	
 	if (r_dspeeds.value)
 	{
--- a/screen.c
+++ b/screen.c
@@ -609,7 +609,7 @@
 */
 void SCR_BeginLoadingPlaque (void)
 {
-	S_StopAllSounds (true);
+	stopallsfx();
 
 	if (cls.state != ca_connected)
 		return;
@@ -702,9 +702,6 @@
 	scr_drawdialog = true;
 	SCR_UpdateScreen ();
 	scr_drawdialog = false;
-	
-	S_ClearBuffer ();		// so dma doesn't loop current sound
-
 	do
 	{
 		key_count = -1;		// wait for a key down and up
--- a/snd.c
+++ b/snd.c
@@ -1,94 +1,832 @@
 #include <u.h>
 #include <libc.h>
-#include <thread.h>
 #include "dat.h"
 #include "quakedef.h"
 #include "fns.h"
 
+cvar_t bgmvolume = {"bgmvolume", "1", 1};
+cvar_t volume = {"volume", "0.7", 1};
+
+typedef struct Chan Chan;
+
 enum{
-	Nbuf = 8
+	Srate = 44100,
+	Ssize = 2,
+	Sch = 2,
+	Sblk = Ssize * Sch,
+	Ssamp = Srate / Fpsmin,
+	Snbuf = Ssamp * Sblk,
+
+	Nchan = 128,
+	Ndyn = 8,
+	Sstat = Ndyn + Namb
 };
-static int afd;
-static int stid = -1;
-static uint wpos;
-static Channel *schan;
-static QLock sndlock;
+static float Clipdist = 1000.0;
 
+struct Chan{
+	Sfx *sfx;
+	int chvol;
+	int lvol;
+	int rvol;
+	vec_t attf;
+	vec3_t zp;
+	int entn;
+	int entch;
+	int p;
+	int n;
+};
+static Chan chans[Nchan], *che;
 
+static int afd = -1;
+static uchar mixbuf[Snbuf];
+static vlong sndt, sampt;
+static int nsamp;
+static int sampbuf[Ssamp*Sch*sizeof(int)];
+static int scalt[32][256];
+
+static Sfx *ambsfx[Namb];
+
+typedef struct
+{
+	int 	length;
+	int 	speed;
+	int 	width;
+	int 	stereo;
+	int loop;
+	byte	data[1];		// variable sized
+} sfxcache_t;
+
+typedef struct
+{
+	int		rate;
+	int		width;
+	int		channels;
+	int		loopofs;
+	int		samples;
+	int		dataofs;
+} wavinfo_t;
+
+static vec3_t		listener_origin;
+static vec3_t		listener_forward;
+static vec3_t		listener_right;
+static vec3_t		listener_up;
+#define	MAX_SFX		512
+static Sfx		*known_sfx;		// hunk allocated [MAX_SFX]
+static int			num_sfx;
+
+static cvar_t precache = {"precache", "1"};
+static cvar_t loadas8bit = {"loadas8bit", "0"};
+static cvar_t ambient_level = {"ambient_level", "0.3"};
+static cvar_t ambient_fade = {"ambient_fade", "100"};
+
+static byte	*data_p;
+static byte 	*iff_end;
+static byte 	*last_chunk;
+static byte 	*iff_data;
+
+/* TODO: refuctor wav loading */
 static void
-sproc(void *)
+resample(sfxcache_t *sc, byte *data, float stepscale)
 {
-	int n;
+	int inwidth;
+	int		outcount;
+	int		srcsample;
+	int		i;
+	int		sample, samplefrac, fracstep;
 
-	for(;;){
-		if(recv(schan, nil) < 0)
-			break;
-		if((n = write(afd, shm->buffer, SNBUF)) != SNBUF)
-			break;
-		qlock(&sndlock);
-		wpos += n;
-		qunlock(&sndlock);
+	inwidth = sc->width;
+	outcount = sc->length / stepscale;
+	sc->length = outcount;
+	sc->speed = Srate;
+	if (loadas8bit.value)
+		sc->width = 1;
+	else
+		sc->width = inwidth;
+	sc->stereo = 0;
+
+	if (stepscale == 1 && inwidth == 1 && sc->width == 1)
+	{
+// fast special case
+		for (i=0 ; i<outcount ; i++)
+			((signed char *)sc->data)[i]
+			= (int)( (unsigned char)(data[i]) - 128);
 	}
+	else
+	{
+// general case
+		samplefrac = 0;
+		fracstep = stepscale*256;
+		for (i=0 ; i<outcount ; i++)
+		{
+			srcsample = samplefrac >> 8;
+			samplefrac += fracstep;
+			if (inwidth == 2)
+				sample = LittleShort ( ((short *)data)[srcsample] );
+			else
+				sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
+			if (sc->width == 2)
+				((short *)sc->data)[i] = sample;
+			else
+				((signed char *)sc->data)[i] = sample >> 8;
+		}
+	}
 }
 
-qboolean
-SNDDMA_Init(void)
+static short
+GetLittleShort(void)
 {
-	if((afd = open("/dev/audio", OWRITE)) < 0){
-		fprint(2, "open: %r\n");
-		return 0;
+	short val;
+
+	val = *data_p;
+	val = val + (*(data_p+1)<<8);
+	data_p += 2;
+	return val;
+}
+
+static int
+GetLittleLong(void)
+{
+	int val;
+
+	val = *data_p;
+	val = val + (*(data_p+1)<<8);
+	val = val + (*(data_p+2)<<16);
+	val = val + (*(data_p+3)<<24);
+	data_p += 4;
+	return val;
+}
+
+static void
+FindNextChunk(char *name)
+{
+	int iff_chunk_len;
+
+	while (1)
+	{
+		data_p=last_chunk;
+
+		if (data_p >= iff_end)
+		{	// didn't find the chunk
+			data_p = nil;
+			return;
+		}
+		
+		data_p += 4;
+		iff_chunk_len = GetLittleLong();
+		if (iff_chunk_len < 0)
+		{
+			data_p = nil;
+			return;
+		}
+//		if (iff_chunk_len > 1024*1024)
+//			fatal ("FindNextChunk: %d length is past the 1 meg sanity limit", iff_chunk_len);
+		data_p -= 8;
+		last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
+		if(strncmp((char *)data_p, name, 4) == 0)
+			return;
 	}
+}
 
-	shm = &sn;
-	shm->splitbuffer = 0;
-	shm->submission_chunk = 1;
-	shm->samplebits = SAMPLESZ;
-	shm->speed = RATE;
-	shm->channels = 2;
-	shm->samples = NSAMPLE;
-	shm->samplepos = 0;
-	if((shm->buffer = mallocz(SNBUF, 1)) == nil)
-		sysfatal("mallocz: %r\n");
+static void
+FindChunk(char *name)
+{
+	last_chunk = iff_data;
+	FindNextChunk (name);
+}
 
-	wpos = 0;
-	if((schan = chancreate(sizeof(int), Nbuf)) == nil)
-		sysfatal("SNDDMA_Init:chancreate: %r");
-	if((stid = proccreate(sproc, nil, 8192)) < 0)
-		sysfatal("SNDDMA_Init:proccreate: %r");
-	return 1;
+static wavinfo_t
+GetWavinfo(char *name, byte *wav, vlong wavlength)
+{
+	wavinfo_t	info;
+	int     i;
+	int     format;
+	int		samples;
+
+	memset(&info, 0, sizeof info);
+
+	if (!wav)
+		return info;
+		
+	iff_data = wav;
+	iff_end = wav + wavlength;
+
+// find "RIFF" chunk
+	FindChunk("RIFF");
+	if(!(data_p && strncmp((char *)data_p+8, "WAVE", 4) == 0))
+	{
+		Con_Printf("Missing RIFF/WAVE chunks\n");
+		return info;
+	}
+
+// get "fmt " chunk
+	iff_data = data_p + 12;
+
+	FindChunk("fmt ");
+	if (!data_p)
+	{
+		Con_Printf("Missing fmt chunk\n");
+		return info;
+	}
+	data_p += 8;
+	format = GetLittleShort();
+	if (format != 1)
+	{
+		Con_Printf("Microsoft PCM format only\n");
+		return info;
+	}
+
+	info.channels = GetLittleShort();
+	info.rate = GetLittleLong();
+	data_p += 4+2;
+	info.width = GetLittleShort() / 8;
+
+// get cue chunk
+	FindChunk("cue ");
+	if (data_p)
+	{
+		data_p += 32;
+		info.loopofs = GetLittleLong();
+
+	// if the next chunk is a LIST chunk, look for a cue length marker
+		FindNextChunk ("LIST");
+		if (data_p)
+		{
+			if(strncmp((char *)data_p+28, "mark", 4) == 0)
+			{	// this is not a proper parse, but it works with cooledit...
+				data_p += 24;
+				i = GetLittleLong ();	// samples in loop
+				info.samples = info.loopofs + i;
+//				Con_Printf("looped length: %d\n", i);
+			}
+		}
+	}
+	else
+		info.loopofs = -1;
+
+// find data chunk
+	FindChunk("data");
+	if (!data_p)
+	{
+		Con_Printf("Missing data chunk\n");
+		return info;
+	}
+
+	data_p += 4;
+	samples = GetLittleLong () / info.width;
+
+	if (info.samples)
+	{
+		if (samples < info.samples)
+			fatal ("Sound %s has a bad loop length", name);
+	}
+	else
+		info.samples = samples;
+
+	info.dataofs = data_p - wav;
+	
+	return info;
 }
 
-uint
-SNDDMA_GetDMAPos(void)
+static sfxcache_t *
+loadsfx(Sfx *sfx)
 {
-	if(stid < 0)
-		return 0;
-	qlock(&sndlock);
-	shm->samplepos = wpos / SAMPLEB;
-	qunlock(&sndlock);
-	return shm->samplepos;
+	wavinfo_t info;
+	int len;
+	float stepscale;
+	sfxcache_t *sc;
+	uchar *u, buf[1024];	/* avoid dirtying the cache heap */
+
+	if(sc = Cache_Check(&sfx->cu), sc != nil)
+		return sc;
+	u = loadstklmp(va("sound/%s", sfx->s), buf, sizeof buf, &len);
+	if(u == nil){
+		fprint(2, "loadsfx: %r\n");
+		return nil;
+	}
+	info = GetWavinfo(sfx->s, u, len);
+	if(info.channels != 1){
+		fprint(2, "loadsfx: non mono wave %s\n", sfx->s);
+		return nil;
+	}
+	stepscale = (float)info.rate / Srate;	
+	len = info.samples / stepscale;
+	len *= info.width * info.channels;
+	if(sc = Cache_Alloc(&sfx->cu, len + sizeof *sc, sfx->s), sc == nil)
+		return nil;
+	sc->length = info.samples;
+	sc->loop = info.loopofs;
+	if(info.loopofs >= 0)
+		sc->loop /= stepscale;
+	sc->speed = info.rate;
+	sc->width = info.width;
+	sc->stereo = info.channels;
+	resample(sc, u + info.dataofs, stepscale);
+	return sc;
 }
 
+static void
+sndout(void)
+{
+	int v, vol, *pb, *pe;
+	uchar *p;
+
+	vol = volume.value * 256;
+	p = mixbuf;
+	pb = sampbuf;
+	pe = sampbuf + nsamp * 2;
+	while(pb < pe){
+		v = *pb++ * vol >> 8;
+		if(v > 0x7fff)
+			v = 0x7fff;
+		else if(v < -0x8000)
+			v = -0x8000;
+		p[0] = v;
+		p[1] = v >> 8;
+		p += 2;
+	}
+}
+
+static void
+sample8(Chan *c, void *d, int n)
+{
+	int v, *pb, *pe, *ls, *rs;
+	uchar *p;
+
+	if(c->lvol > 255)
+		c->lvol = 255;
+	if(c->rvol > 255)
+		c->rvol = 255;
+	ls = scalt[c->lvol >> 3];
+	rs = scalt[c->rvol >> 3];
+	p = (uchar *)d + c->p;
+	pb = sampbuf;
+	pe = sampbuf + n * 2;
+	while(pb < pe){
+		v = *p++;
+		*pb++ += ls[v];
+		*pb++ += rs[v];
+	}
+}
+
+static void
+sample16(Chan *c, void *d, int n)
+{
+	int v, *pb, *pe, lv, rv;
+	short *p;
+
+	lv = c->lvol;
+	rv = c->rvol;
+	p = (short *)d + c->p;
+	pb = sampbuf;
+	pe = sampbuf + n * 2;
+	while(pb < pe){
+		v = *p++;
+		*pb++ += v * lv >> 8;
+		*pb++ += v * rv >> 8;
+	}
+}
+
+static void
+samplesfx(void)
+{
+	int n, m;
+	Chan *c;
+	sfxcache_t *sc;
+	void (*sf)(Chan *, void *, int);
+
+	memset(sampbuf, 0, sizeof sampbuf);
+	for(c=chans; c<che; c++){
+		if(c->sfx == nil)
+			continue;
+		if(c->lvol == 0 && c->rvol == 0)
+			continue;
+		if(sc = loadsfx(c->sfx), sc == nil)
+			continue;
+		sf = sc->width == 1 ? sample8 : sample16;
+		n = nsamp;
+		while(n > 0){
+			m = n < c->n ? n : c->n;
+			if(m > 0)
+				sf(c, sc->data, m);
+			c->p += m;
+			c->n -= m;
+			n -= m;
+			if(c->n <= 0){
+				if(sc->loop >= 0){
+					c->p = sc->loop;
+					c->n = sc->length - c->p;
+				}else{
+					c->sfx = nil;
+					break;
+				}
+			}
+		}
+	}
+	sndout();
+}
+
+static void
+spatialize(Chan *c)
+{
+	vec_t Δr, m;
+	vec3_t src;
+
+	if(c->entn == cl.viewentity){
+		c->lvol = c->chvol;
+		c->rvol = c->chvol;
+		return;
+	}
+	VectorSubtract(c->zp, listener_origin, src);
+	Δr = 1.0 - VectorNormalize(src) * c->attf;
+	m = DotProduct(listener_right, src);
+	c->rvol = Δr * (1.0 + m) * c->chvol;
+	if(c->rvol < 0)
+		c->rvol = 0;
+	c->lvol = Δr * (1.0 - m) * c->chvol;
+	if(c->lvol < 0)
+		c->lvol = 0;
+}
+
+static void
+ambs(void)
+{
+	uchar *av;
+	float vol;
+	Chan *c, *e;
+	mleaf_t *l;
+	Sfx **sfx;
+
+	if(cl.worldmodel == nil)
+		return;
+	c = chans;
+	e = chans + Namb;
+	l = Mod_PointInLeaf(listener_origin, cl.worldmodel);
+	if(l == nil || !ambient_level.value){
+		while(c < e)
+			c++->sfx = nil;
+		return;
+	}
+	sfx = ambsfx;
+	av = l->ambient_sound_level;
+	while(c < e){
+		c->sfx = *sfx++;
+		vol = ambient_level.value * *av++;
+		if(vol < 8)
+			vol = 0;
+		if(c->chvol < vol){
+			c->chvol += host_frametime * ambient_fade.value;
+			if(c->chvol > vol)
+				c->chvol = vol;
+		}else if(c->chvol > vol){
+			c->chvol -= host_frametime * ambient_fade.value;
+			if(c->chvol < vol)
+				c->chvol = vol;
+		}
+		c->lvol = c->chvol;
+		c->rvol = c->chvol;
+		c++;
+	}
+}
+
 void
-SNDDMA_Shutdown(void)
+stepsnd(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
 {
-	if(stid < 0)
+	Chan *c, *sum;
+
+	if(afd < 0)
 		return;
+	VectorCopy(origin, listener_origin);
+	VectorCopy(forward, listener_forward);
+	VectorCopy(right, listener_right);
+	VectorCopy(up, listener_up);
+	ambs();
+	sum = nil;
+	for(c=chans+Namb; c<che; c++){
+		if(c->sfx == nil)
+			continue;
+		spatialize(c);
+		if(c->lvol == 0 && c->rvol == 0)
+			continue;
+		/* sum static sounds to avoid useless remixing */
+		if(c >= chans + Sstat){
+			if(sum != nil && sum->sfx == c->sfx){
+				sum->lvol += c->lvol;
+				sum->rvol += c->rvol;
+				c->lvol = c->rvol = 0;
+				continue;
+			}
+			for(sum=chans + Sstat; sum<c; sum++)
+				if(sum->sfx == c->sfx)
+					break;
+			if(sum == che)
+				sum = nil;
+			else if(sum != c){
+				sum->lvol += c->lvol;
+				sum->rvol += c->rvol;
+				c->lvol = c->rvol = 0;
+			}
+		}
+	}
+	if(sndt == 0)
+		sndt = nsec() - Te9 / Fpsmax;
+	nsamp = (nsec() - sndt) / (Te9 / Srate);
+	if(!cls.timedemo)
+		nsamp = nsamp + 15 & ~15;
+	if(nsamp > Ssamp)
+		nsamp = Ssamp;
+	samplesfx();
+	sampt += nsamp;
+	nsamp *= Sblk;
+	if(write(afd, mixbuf, nsamp) != nsamp){
+		fprint(2, "sndwrite: %r\n");
+		shutsnd();
+	}
+	sndt = nsec();
+}
 
-	threadint(stid);
-	stid = -1;
-	close(afd);
-	free(shm->buffer);
-	if(schan != nil)
-		chanfree(schan);
-	schan = nil;
+void
+stopallsfx(void)
+{
+	if(afd < 0)
+		return;
+	memset(chans, 0, sizeof chans);
+	che = chans + Sstat;
 }
 
 void
-SNDDMA_Submit(void)
+stopsfx(int n, int ch)
 {
-	if(nbsend(schan, nil) < 0){
-		fprint(2, "SNDDMA_Submit:nbsend: %r\n");
-		SNDDMA_Shutdown();
+	Chan *c, *e;
+
+	if(afd < 0)
+		return;
+	c = chans;
+	e = chans + Ndyn;
+	while(c < e){
+		if(c->entn == n && c->entch == ch){
+			c->sfx = nil;
+			return;
+		}
+		c++;
 	}
+}
+
+static Chan *
+pickchan(int entn, int entch)
+{
+	int Δt;
+	Chan *c, *p, *e;
+
+	p = nil;
+	Δt = 0x7fffffff;
+	for(c=chans+Namb, e=c+Ndyn; c<e; c++){
+		if(entch != 0 && c->entn == entn
+		&& (c->entch == entch || entch == -1)){
+			p = c;
+			break;
+		}
+		if(c->entn == cl.viewentity && entn != cl.viewentity && c->sfx != nil)
+			continue;
+		if(c->n < Δt){
+			Δt = c->n;
+			p = c;
+		}
+	}
+	if(p != nil)
+		p->sfx = nil;
+	return p;
+}       
+
+void
+startsfx(int entn, int entch, Sfx *sfx, vec3_t zp, float vol, float att)
+{
+	int skip;
+	Chan *c, *c2, *e;
+	sfxcache_t *sc;
+
+	if(afd < 0 || sfx == nil)
+		return;
+	if(c = pickchan(entn, entch), c == nil)
+		return;
+	memset(c, 0, sizeof *c);
+	VectorCopy(zp, c->zp);
+	c->attf = att / Clipdist;
+	c->chvol = vol * 255;
+	c->entn = entn;
+	c->entch = entch;
+	spatialize(c);
+	if(c->lvol == 0 && c->rvol == 0)
+		return;
+	if(sc = loadsfx(sfx), sc == nil)
+		return;
+	c->sfx = sfx;
+	c->p = 0;
+	c->n = sc->length;
+	/* don't sum identical sfx started on the same frame */
+	for(c2=chans+Namb, e=chans+Sstat; c2<e; c2++){
+		if(c2 == c || c2->sfx != sfx || c2->p != 0)
+			continue;
+		skip = nrand(Srate / Fpsmin);
+		if(skip >= c->n)
+			skip = c->n - 1;
+		c->p += skip;
+		c->n -= skip;
+		break;
+	}
+}
+
+void
+localsfx(char *s)
+{
+	Sfx *sfx;
+
+	if(afd < 0)
+		return;
+	sfx = precachesfx(s);
+	startsfx(cl.viewentity, -1, sfx, vec3_origin, 1, 1);
+}
+
+void
+staticsfx(Sfx *sfx, vec3_t zp, float vol, float att)
+{
+	Chan *c;
+	sfxcache_t *sc;
+
+	if(sfx == nil)
+		return;
+	if(che >= chans + nelem(chans)){
+		fprint(2, "staticsfx: channel overflow\n");
+		return;
+	}
+	c = che++;
+	if(sc = loadsfx(sfx), sc == nil)
+		return;
+	if(sc->loop < 0){
+		fprint(2, "staticsfx %s: nonlooped static sound\n", sfx->s);
+		return;
+	}
+	c->sfx = sfx;
+	VectorCopy(zp, c->zp);
+	c->chvol = vol;
+	c->attf = (att / 64) / Clipdist;
+	c->n = sc->length;
+	spatialize(c);
+}
+
+static Sfx *
+findsfx(char *s)
+{
+	Sfx *sfx, *e;
+
+	if(s == nil)
+		fatal("findsfx: nil pointer\n");
+	if(strlen(s) >= Npath)
+		fatal("findsfx: path too long %s", s);
+	sfx = known_sfx;
+	e = known_sfx + num_sfx;
+	while(sfx < e){
+		if(strcmp(sfx->s, s) == 0)
+			return sfx;
+		sfx++;
+	}
+	if(num_sfx == MAX_SFX)
+		fatal("findsfx: sfx list overflow");
+	strcpy(sfx->s, s);
+	num_sfx++;
+	return sfx;
+}
+
+void
+touchsfx(char *s)
+{
+	Sfx *sfx;
+
+	if(afd < 0)
+		return;
+	sfx = findsfx(s);
+	Cache_Check(&sfx->cu);
+}
+
+Sfx *
+precachesfx(char *s)
+{
+	Sfx *sfx;
+
+	if(afd < 0)
+		return nil;
+	sfx = findsfx(s);
+	if(precache.value)
+		loadsfx(sfx);
+	return sfx;
+}
+
+static void
+playsfx(void)
+{
+	static int hash = 345;
+	int i;
+	char *s;
+	Sfx *sfx;
+
+	if(Cmd_Argc() < 2){
+		Con_Printf("play wav [wav..]: play a wav lump\n");
+		return;
+	}
+	i = 1;
+	while(i < Cmd_Argc()){
+		if(strrchr(Cmd_Argv(i), '.') == nil)
+			s = va("%s.wav", Cmd_Argv(i));
+		else
+			s = Cmd_Argv(i);
+		sfx = precachesfx(s);
+		startsfx(hash++, 0, sfx, listener_origin, 1.0, 1.0);
+		i++;
+	}
+}
+
+static void
+playvolsfx(void)
+{
+	static int hash = 543;
+	int i;
+	float vol;
+	char *s;
+	Sfx *sfx;
+
+	if(Cmd_Argc() < 3){
+		Con_Printf("play wav vol [wav vol]..: play an amplified wav lump\n");
+		return;
+	}
+	i = 1;
+	while(i < Cmd_Argc()){
+		if(strrchr(Cmd_Argv(i), '.') == nil)
+			s = va("%s.wav", Cmd_Argv(i));
+		else
+			s = Cmd_Argv(i);
+		sfx = precachesfx(s);
+		vol = atof(Cmd_Argv(++i));
+		startsfx(hash++, 0, sfx, listener_origin, vol, 1.0);
+		i++;
+	}
+}
+
+static void
+sfxlist(void)
+{
+	char c;
+	int sz, sum;
+	Sfx *sfx, *e;
+	sfxcache_t *sc;
+
+	sum = 0;
+	for(sfx=known_sfx, e=known_sfx+num_sfx; sfx<e; sfx++){
+		if(sc = Cache_Check(&sfx->cu), sc == nil)
+			continue;
+		sz = sc->length * sc->width * (sc->stereo + 1);
+		sum += sz;
+		c = sc->loop >= 0 ? 'L' : ' ';
+		Con_Printf("%c(%2db) %6d : %s\n", c, sc->width * 8, sz, sfx->s);
+	}
+	Con_Printf("Total resident: %d\n", sum);
+}
+
+void
+shutsnd(void)
+{
+	if(afd < 0)
+		return;
+	close(afd);
+}
+
+int
+initsnd(void)
+{
+	int i, j, *p;
+
+	if(afd = open("/dev/audio", OWRITE), afd < 0)
+		return -1;
+	for(p=scalt[1], i=8; i<8*nelem(scalt); i+=8)
+		for(j=0; j<256; j++)
+			*p++ = (char)j * i;
+	Cmd_AddCommand("play", playsfx);
+	Cmd_AddCommand("playvol", playvolsfx);
+	Cmd_AddCommand("stopsound", stopallsfx);
+	Cmd_AddCommand("soundlist", sfxlist);
+	Cvar_RegisterVariable(&volume);
+	Cvar_RegisterVariable(&precache);
+	Cvar_RegisterVariable(&loadas8bit);
+	Cvar_RegisterVariable(&bgmvolume);
+	Cvar_RegisterVariable(&ambient_level);
+	Cvar_RegisterVariable(&ambient_fade);
+
+	if(host_parms.memsize < 0x800000){
+		setcvar("loadas8bit", "1");
+		fprint(2, "initsnd: forcing 8bit width\n");
+	}
+	known_sfx = Hunk_AllocName(MAX_SFX * sizeof *known_sfx, "Sfx");
+	num_sfx = 0;
+	ambsfx[Ambwater] = precachesfx("ambience/water1.wav");
+	ambsfx[Ambsky] = precachesfx("ambience/wind2.wav");
+	stopallsfx();
+	return 0;
 }
--- a/snd_dma.c
+++ /dev/null
@@ -1,916 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include "dat.h"
-#include "quakedef.h"
-#include "fns.h"
-
-void S_Play(void);
-void S_PlayVol(void);
-void S_SoundList(void);
-void S_Update_(void);
-void S_StopAllSounds(qboolean clear);
-void S_StopAllSoundsC(void);
-
-// =======================================================================
-// Internal sound data & structures
-// =======================================================================
-
-channel_t   channels[MAX_CHANNELS];
-int			total_channels;
-
-int				snd_blocked = 0;
-static qboolean	snd_ambient = 1;
-static qboolean	snd_initialized;
-
-// pointer should go away
-volatile dma_t *shm;
-volatile dma_t sn;
-
-vec3_t		listener_origin;
-vec3_t		listener_forward;
-vec3_t		listener_right;
-vec3_t		listener_up;
-vec_t		sound_nominal_clip_dist=1000.0;
-
-int			soundtime;		// sample PAIRS
-int   		paintedtime; 	// sample PAIRS
-
-
-#define	MAX_SFX		512
-sfx_t		*known_sfx;		// hunk allocated [MAX_SFX]
-int			num_sfx;
-
-sfx_t		*ambient_sfx[NUM_AMBIENTS];
-
-int 		desired_speed = 11025;
-int 		desired_bits = 16;
-
-int sound_started=0;
-
-cvar_t bgmvolume = {"bgmvolume", "1", true};
-cvar_t volume = {"volume", "0.7", true};
-
-cvar_t nosound = {"nosound", "0"};
-cvar_t precache = {"precache", "1"};
-cvar_t loadas8bit = {"loadas8bit", "0"};
-cvar_t bgmbuffer = {"bgmbuffer", "4096"};
-cvar_t ambient_level = {"ambient_level", "0.3"};
-cvar_t ambient_fade = {"ambient_fade", "100"};
-cvar_t snd_noextraupdate = {"snd_noextraupdate", "0"};
-cvar_t snd_show = {"snd_show", "0"};
-cvar_t _snd_mixahead = {"_snd_mixahead", "0.1", true};
-
-
-// ====================================================================
-// User-setable variables
-// ====================================================================
-
-
-//
-// Fake dma is a synchronous faking of the DMA progress used for
-// isolating performance in the renderer.  The fakedma_updates is
-// number of times S_Update() is called per second.
-//
-
-qboolean fakedma = false;
-int fakedma_updates = 15;
-
-
-void S_AmbientOff (void)
-{
-	snd_ambient = false;
-}
-
-
-void S_AmbientOn (void)
-{
-	snd_ambient = true;
-}
-
-
-void S_SoundInfo_f(void)
-{
-	if (!sound_started || !shm)
-	{
-		Con_Printf ("sound system not started\n");
-		return;
-	}
-
-    Con_Printf("%5d stereo\n", shm->channels - 1);
-    Con_Printf("%5d samples\n", shm->samples);
-    Con_Printf("%5d samplepos\n", shm->samplepos);
-    Con_Printf("%5d samplebits\n", shm->samplebits);
-    Con_Printf("%5d submission_chunk\n", shm->submission_chunk);
-    Con_Printf("%5d speed\n", shm->speed);
-    Con_Printf("%#p dma buffer\n", shm->buffer);
-	Con_Printf("%5d total_channels\n", total_channels);
-}
-
-
-/*
-================
-S_Startup
-================
-*/
-
-void S_Startup (void)
-{
-	int		rc;
-
-	if (!snd_initialized)
-		return;
-
-	if (!fakedma)
-	{
-		rc = SNDDMA_Init();
-
-		if (!rc)
-		{
-			Con_Printf("S_Startup: SNDDMA_Init failed.\n");
-			sound_started = 0;
-			return;
-		}
-	}
-
-	sound_started = 1;
-}
-
-
-/*
-================
-S_Init
-================
-*/
-void S_Init (void)
-{
-
-	Con_Printf("\nSound Initialization\n");
-
-	if (COM_CheckParm("-nosound"))
-		return;
-
-	if (COM_CheckParm("-simsound"))
-		fakedma = true;
-
-	Cmd_AddCommand("play", S_Play);
-	Cmd_AddCommand("playvol", S_PlayVol);
-	Cmd_AddCommand("stopsound", S_StopAllSoundsC);
-	Cmd_AddCommand("soundlist", S_SoundList);
-	Cmd_AddCommand("soundinfo", S_SoundInfo_f);
-
-	Cvar_RegisterVariable(&nosound);
-	Cvar_RegisterVariable(&volume);
-	Cvar_RegisterVariable(&precache);
-	Cvar_RegisterVariable(&loadas8bit);
-	Cvar_RegisterVariable(&bgmvolume);
-	Cvar_RegisterVariable(&bgmbuffer);
-	Cvar_RegisterVariable(&ambient_level);
-	Cvar_RegisterVariable(&ambient_fade);
-	Cvar_RegisterVariable(&snd_noextraupdate);
-	Cvar_RegisterVariable(&snd_show);
-	Cvar_RegisterVariable(&_snd_mixahead);
-
-	if (host_parms.memsize < 0x800000)
-	{
-		setcvar("loadas8bit", "1");
-		Con_Printf ("loading all sounds as 8bit\n");
-	}
-
-	snd_initialized = true;
-
-	S_Startup ();
-
-	SND_InitScaletable ();
-
-	known_sfx = Hunk_AllocName(MAX_SFX * sizeof *known_sfx, "sfx_t");
-	num_sfx = 0;
-
-// create a piece of DMA memory
-
-	if (fakedma)
-	{
-		shm = Hunk_AllocName(sizeof *shm, "shm");
-		shm->splitbuffer = 0;
-		shm->samplebits = 16;
-		shm->speed = 22050;
-		shm->channels = 2;
-		shm->samples = 32768;
-		shm->samplepos = 0;
-		shm->soundalive = true;
-		shm->gamealive = true;
-		shm->submission_chunk = 1;
-		shm->buffer = Hunk_AllocName(1<<16, "shmbuf");
-	}
-
-	if(shm != nil)
-		Con_Printf ("Sound sampling rate: %d\n", shm->speed);
-
-	// provides a tick sound until washed clean
-
-//	if (shm->buffer)
-//		shm->buffer[4] = shm->buffer[5] = 0x7f;	// force a pop for debugging
-
-	ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav");
-	ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav");
-
-	S_StopAllSounds (true);
-}
-
-
-// =======================================================================
-// Shutdown sound engine
-// =======================================================================
-
-void S_Shutdown(void)
-{
-	if(!sound_started)
-		return;
-	if(shm != nil)
-		shm->gamealive = 0;
-	if(!fakedma)
-		SNDDMA_Shutdown();
-	shm = nil;
-	sound_started = 0;
-}
-
-
-// =======================================================================
-// Load a sound
-// =======================================================================
-
-/*
-==================
-S_FindName
-
-==================
-*/
-sfx_t *S_FindName (char *name)
-{
-	int		i;
-	sfx_t	*sfx;
-
-	if (name == nil)
-		fatal ("S_FindName: NULL\n");
-
-	if(strlen(name) >= Npath)
-		fatal ("Sound name too long: %s", name);
-
-// see if already loaded
-	for (i=0 ; i < num_sfx ; i++)
-		if(strcmp(known_sfx[i].name, name) == 0)
-			return &known_sfx[i];
-
-	if (num_sfx == MAX_SFX)
-		fatal ("S_FindName: out of sfx_t");
-	
-	sfx = &known_sfx[i];
-	strcpy (sfx->name, name);
-
-	num_sfx++;
-	
-	return sfx;
-}
-
-
-/*
-==================
-S_TouchSound
-
-==================
-*/
-void S_TouchSound (char *name)
-{
-	sfx_t	*sfx;
-	
-	if (!sound_started)
-		return;
-
-	sfx = S_FindName (name);
-	Cache_Check (&sfx->cache);
-}
-
-/*
-==================
-S_PrecacheSound
-
-==================
-*/
-sfx_t *S_PrecacheSound (char *name)
-{
-	sfx_t	*sfx;
-
-	if (!sound_started || nosound.value)
-		return nil;
-
-	sfx = S_FindName (name);
-	
-// cache it in
-	if (precache.value)
-		S_LoadSound (sfx);
-	
-	return sfx;
-}
-
-
-//=============================================================================
-
-/*
-=================
-SND_PickChannel
-=================
-*/
-channel_t *SND_PickChannel(int entnum, int entchannel)
-{
-    int ch_idx;
-    int first_to_die;
-    int life_left;
-
-// Check for replacement sound, or find the best one to replace
-    first_to_die = -1;
-    life_left = 0x7fffffff;
-    for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
-    {
-		if (entchannel != 0		// channel 0 never overrides
-		&& channels[ch_idx].entnum == entnum
-		&& (channels[ch_idx].entchannel == entchannel || entchannel == -1) )
-		{	// allways override sound from same entity
-			first_to_die = ch_idx;
-			break;
-		}
-
-		// don't let monster sounds override player sounds
-		if (channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && channels[ch_idx].sfx)
-			continue;
-
-		if (channels[ch_idx].end - paintedtime < life_left)
-		{
-			life_left = channels[ch_idx].end - paintedtime;
-			first_to_die = ch_idx;
-		}
-   }
-
-	if (first_to_die == -1)
-		return nil;
-
-	if (channels[first_to_die].sfx)
-		channels[first_to_die].sfx = nil;
-
-    return &channels[first_to_die];    
-}       
-
-/*
-=================
-SND_Spatialize
-=================
-*/
-void SND_Spatialize(channel_t *ch)
-{
-    vec_t dot;
-    vec_t dist;
-    vec_t lscale, rscale, scale;
-    vec3_t source_vec;
-
-// anything coming from the view entity will allways be full volume
-	if (ch->entnum == cl.viewentity)
-	{
-		ch->leftvol = ch->master_vol;
-		ch->rightvol = ch->master_vol;
-		return;
-	}
-
-// calculate stereo seperation and distance attenuation
-
-	VectorSubtract(ch->origin, listener_origin, source_vec);
-	
-	dist = VectorNormalize(source_vec) * ch->dist_mult;
-	
-	dot = DotProduct(listener_right, source_vec);
-
-	if (shm->channels == 1)
-	{
-		rscale = 1.0;
-		lscale = 1.0;
-	}
-	else
-	{
-		rscale = 1.0 + dot;
-		lscale = 1.0 - dot;
-	}
-
-// add in distance effect
-	scale = (1.0 - dist) * rscale;
-	ch->rightvol = (int) (ch->master_vol * scale);
-	if (ch->rightvol < 0)
-		ch->rightvol = 0;
-
-	scale = (1.0 - dist) * lscale;
-	ch->leftvol = (int) (ch->master_vol * scale);
-	if (ch->leftvol < 0)
-		ch->leftvol = 0;
-}           
-
-
-// =======================================================================
-// Start a sound effect
-// =======================================================================
-
-void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
-{
-	channel_t *target_chan, *check;
-	sfxcache_t	*sc;
-	int		vol;
-	int		ch_idx;
-	int		skip;
-
-	if (!sound_started)
-		return;
-
-	if (!sfx)
-		return;
-
-	if (nosound.value)
-		return;
-
-	vol = fvol*255;
-
-// pick a channel to play on
-	target_chan = SND_PickChannel(entnum, entchannel);
-	if (!target_chan)
-		return;
-		
-// spatialize
-	memset(target_chan, 0, sizeof *target_chan);
-	VectorCopy(origin, target_chan->origin);
-	target_chan->dist_mult = attenuation / sound_nominal_clip_dist;
-	target_chan->master_vol = vol;
-	target_chan->entnum = entnum;
-	target_chan->entchannel = entchannel;
-	SND_Spatialize(target_chan);
-
-	if (!target_chan->leftvol && !target_chan->rightvol)
-		return;		// not audible at all
-
-// new channel
-	sc = S_LoadSound (sfx);
-	if (!sc)
-	{
-		target_chan->sfx = nil;
-		return;		// couldn't load the sound's data
-	}
-
-	target_chan->sfx = sfx;
-	target_chan->pos = 0.0;
-    target_chan->end = paintedtime + sc->length;	
-
-// if an identical sound has also been started this frame, offset the pos
-// a bit to keep it from just making the first one louder
-	check = &channels[NUM_AMBIENTS];
-    for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++)
-    {
-		if (check == target_chan)
-			continue;
-		if (check->sfx == sfx && !check->pos)
-		{
-			skip = rand () % (int)(0.1*shm->speed);
-			if (skip >= target_chan->end)
-				skip = target_chan->end - 1;
-			target_chan->pos += skip;
-			target_chan->end -= skip;
-			break;
-		}
-		
-	}
-}
-
-void S_StopSound(int entnum, int entchannel)
-{
-	int i;
-
-	for (i=0 ; i<MAX_DYNAMIC_CHANNELS ; i++)
-	{
-		if (channels[i].entnum == entnum
-			&& channels[i].entchannel == entchannel)
-		{
-			channels[i].end = 0;
-			channels[i].sfx = nil;
-			return;
-		}
-	}
-}
-
-void S_StopAllSounds(qboolean clear)
-{
-	int		i;
-
-	if (!sound_started)
-		return;
-
-	total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;	// no statics
-
-	for (i=0 ; i<MAX_CHANNELS ; i++)
-		if (channels[i].sfx)
-			channels[i].sfx = nil;
-
-	memset(channels, 0, sizeof channels);
-
-	if (clear)
-		S_ClearBuffer ();
-}
-
-void S_StopAllSoundsC (void)
-{
-	S_StopAllSounds (true);
-}
-
-void S_ClearBuffer (void)
-{
-	int		clear;
-		
-	if (!sound_started || shm == nil || shm->buffer == nil)
-		return;
-
-	if (shm->samplebits == 8)
-		clear = 0x80;
-	else
-		clear = 0;
-
-	memset(shm->buffer, clear, shm->samples * shm->samplebits/8);
-}
-
-
-/*
-=================
-S_StaticSound
-=================
-*/
-void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
-{
-	channel_t	*ss;
-	sfxcache_t		*sc;
-
-	if (!sfx)
-		return;
-
-	if (total_channels == MAX_CHANNELS)
-	{
-		Con_Printf ("total_channels == MAX_CHANNELS\n");
-		return;
-	}
-
-	ss = &channels[total_channels];
-	total_channels++;
-
-	sc = S_LoadSound (sfx);
-	if (!sc)
-		return;
-
-	if (sc->loopstart == -1)
-	{
-		Con_Printf ("Sound %s not looped\n", sfx->name);
-		return;
-	}
-	
-	ss->sfx = sfx;
-	VectorCopy (origin, ss->origin);
-	ss->master_vol = vol;
-	ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist;
-    ss->end = paintedtime + sc->length;	
-	
-	SND_Spatialize (ss);
-}
-
-
-//=============================================================================
-
-/*
-===================
-S_UpdateAmbientSounds
-===================
-*/
-void S_UpdateAmbientSounds (void)
-{
-	mleaf_t		*l;
-	float		vol;
-	int			ambient_channel;
-	channel_t	*chan;
-
-	if (!snd_ambient)
-		return;
-
-// calc ambient sound levels
-	if (!cl.worldmodel)
-		return;
-
-	l = Mod_PointInLeaf (listener_origin, cl.worldmodel);
-	if (!l || !ambient_level.value)
-	{
-		for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
-			channels[ambient_channel].sfx = nil;
-		return;
-	}
-
-	for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
-	{
-		chan = &channels[ambient_channel];	
-		chan->sfx = ambient_sfx[ambient_channel];
-	
-		vol = ambient_level.value * l->ambient_sound_level[ambient_channel];
-		if (vol < 8)
-			vol = 0;
-
-	// don't adjust volume too fast
-		if (chan->master_vol < vol)
-		{
-			chan->master_vol += host_frametime * ambient_fade.value;
-			if (chan->master_vol > vol)
-				chan->master_vol = vol;
-		}
-		else if (chan->master_vol > vol)
-		{
-			chan->master_vol -= host_frametime * ambient_fade.value;
-			if (chan->master_vol < vol)
-				chan->master_vol = vol;
-		}
-		
-		chan->leftvol = chan->rightvol = chan->master_vol;
-	}
-}
-
-
-/*
-============
-S_Update
-
-Called once each time through the main loop
-============
-*/
-void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
-{
-	int			i, j;
-	int			total;
-	channel_t	*ch;
-	channel_t	*combine;
-
-	if (!sound_started || (snd_blocked > 0))
-		return;
-
-	VectorCopy(origin, listener_origin);
-	VectorCopy(forward, listener_forward);
-	VectorCopy(right, listener_right);
-	VectorCopy(up, listener_up);
-	
-// update general area ambient sound sources
-	S_UpdateAmbientSounds ();
-
-	combine = nil;
-
-// update spatialization for static and dynamic sounds	
-	ch = channels+NUM_AMBIENTS;
-	for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)
-	{
-		if (!ch->sfx)
-			continue;
-		SND_Spatialize(ch);         // respatialize channel
-		if (!ch->leftvol && !ch->rightvol)
-			continue;
-
-	// try to combine static sounds with a previous channel of the same
-	// sound effect so we don't mix five torches every frame
-	
-		if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)
-		{
-		// see if it can just use the last one
-			if (combine && combine->sfx == ch->sfx)
-			{
-				combine->leftvol += ch->leftvol;
-				combine->rightvol += ch->rightvol;
-				ch->leftvol = ch->rightvol = 0;
-				continue;
-			}
-		// search for one
-			combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;
-			for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++)
-				if (combine->sfx == ch->sfx)
-					break;
-					
-			if (j == total_channels)
-			{
-				combine = nil;
-			}
-			else
-			{
-				if (combine != ch)
-				{
-					combine->leftvol += ch->leftvol;
-					combine->rightvol += ch->rightvol;
-					ch->leftvol = ch->rightvol = 0;
-				}
-				continue;
-			}
-		}
-		
-		
-	}
-
-//
-// debugging output
-//
-	if (snd_show.value)
-	{
-		total = 0;
-		ch = channels;
-		for (i=0 ; i<total_channels; i++, ch++)
-			if (ch->sfx && (ch->leftvol || ch->rightvol) )
-			{
-				//Con_Printf ("%3d %3d %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
-				total++;
-			}
-		
-		Con_Printf ("----(%d)----\n", total);
-	}
-
-// mix some sound
-	S_Update_();
-}
-
-void GetSoundtime(void)
-{
-	uint		samplepos;
-	static	int		buffers;
-	static	uint		oldsamplepos;
-	int		fullsamples;
-	
-	fullsamples = shm->samples / shm->channels;
-
-// it is possible to miscount buffers if it has wrapped twice between
-// calls to S_Update.  Oh well.
-	samplepos = SNDDMA_GetDMAPos();
-
-
-	if (samplepos < oldsamplepos)
-	{
-		buffers++;					// buffer wrapped
-		
-		if (paintedtime > 0x40000000)
-		{	// time to chop things off to avoid 32 bit limits
-			buffers = 0;
-			paintedtime = fullsamples;
-			S_StopAllSounds (true);
-		}
-	}
-	oldsamplepos = samplepos;
-
-	soundtime = buffers*fullsamples + samplepos/shm->channels;
-}
-
-void S_ExtraUpdate (void)
-{
-
-	if (snd_noextraupdate.value)
-		return;		// don't pollute timings
-	S_Update_();
-}
-
-void S_Update_(void)
-{
-	unsigned        endtime;
-	int				samps;
-	
-	if (!sound_started || (snd_blocked > 0))
-		return;
-
-// Updates DMA time
-	GetSoundtime();
-
-// check to make sure that we haven't overshot
-	if (paintedtime < soundtime)
-	{
-		//Con_Printf ("S_Update_ : overflow\n");
-		paintedtime = soundtime;
-	}
-
-// mix ahead of current position
-	endtime = soundtime + _snd_mixahead.value * shm->speed;
-	samps = shm->samples >> (shm->channels-1);
-	if (endtime - soundtime > samps)
-		endtime = soundtime + samps;
-
-	S_PaintChannels (endtime);
-
-	SNDDMA_Submit ();
-}
-
-/*
-===============================================================================
-
-console functions
-
-===============================================================================
-*/
-
-void S_Play(void)
-{
-	static int hash=345;
-	int 	i;
-	char name[256];
-	sfx_t	*sfx;
-	
-	i = 1;
-	while (i<Cmd_Argc())
-	{
-		if(strrchr(Cmd_Argv(i), '.') == nil)
-		{
-			strcpy(name, Cmd_Argv(i));
-			strcat(name, ".wav");
-		}
-		else
-			strcpy(name, Cmd_Argv(i));
-		sfx = S_PrecacheSound(name);
-		S_StartSound(hash++, 0, sfx, listener_origin, 1.0, 1.0);
-		i++;
-	}
-}
-
-void S_PlayVol(void)
-{
-	static int hash=543;
-	int i;
-	float vol;
-	char name[256];
-	sfx_t	*sfx;
-	
-	i = 1;
-	while (i<Cmd_Argc())
-	{
-		if(strrchr(Cmd_Argv(i), '.') == nil)
-		{
-			strcpy(name, Cmd_Argv(i));
-			strcat(name, ".wav");
-		}
-		else
-			strcpy(name, Cmd_Argv(i));
-		sfx = S_PrecacheSound(name);
-		vol = atof(Cmd_Argv(i+1));
-		S_StartSound(hash++, 0, sfx, listener_origin, vol, 1.0);
-		i+=2;
-	}
-}
-
-void S_SoundList(void)
-{
-	int		i;
-	sfx_t	*sfx;
-	sfxcache_t	*sc;
-	int		size, total;
-
-	total = 0;
-	for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
-	{
-		sc = Cache_Check (&sfx->cache);
-		if (!sc)
-			continue;
-		size = sc->length*sc->width*(sc->stereo+1);
-		total += size;
-		if (sc->loopstart >= 0)
-			Con_Printf ("L");
-		else
-			Con_Printf (" ");
-		Con_Printf("(%2db) %6d : %s\n",sc->width*8,  size, sfx->name);
-	}
-	Con_Printf ("Total resident: %d\n", total);
-}
-
-
-void S_LocalSound (char *sound)
-{
-	sfx_t	*sfx;
-
-	if (nosound.value)
-		return;
-	if (!sound_started)
-		return;
-		
-	sfx = S_PrecacheSound (sound);
-	if (!sfx)
-	{
-		Con_Printf ("S_LocalSound: can't cache %s\n", sound);
-		return;
-	}
-	S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1);
-}
-
-
-void S_ClearPrecache (void)
-{
-}
-
-
-void S_BeginPrecaching (void)
-{
-}
-
-
-void S_EndPrecaching (void)
-{
-}
-
--- a/snd_mem.c
+++ /dev/null
@@ -1,324 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include "dat.h"
-#include "quakedef.h"
-#include "fns.h"
-
-int			cache_full_cycle;
-
-byte *S_Alloc (int size);
-
-/*
-================
-ResampleSfx
-================
-*/
-void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
-{
-	int		outcount;
-	int		srcsample;
-	float	stepscale;
-	int		i;
-	int		sample, samplefrac, fracstep;
-	sfxcache_t	*sc;
-	
-	sc = Cache_Check (&sfx->cache);
-	if (!sc)
-		return;
-
-	stepscale = (float)inrate / shm->speed;	// this is usually 0.5, 1, or 2
-
-	outcount = sc->length / stepscale;
-	sc->length = outcount;
-	if (sc->loopstart != -1)
-		sc->loopstart = sc->loopstart / stepscale;
-
-	sc->speed = shm->speed;
-	if (loadas8bit.value)
-		sc->width = 1;
-	else
-		sc->width = inwidth;
-	sc->stereo = 0;
-
-// resample / decimate to the current source rate
-
-	if (stepscale == 1 && inwidth == 1 && sc->width == 1)
-	{
-// fast special case
-		for (i=0 ; i<outcount ; i++)
-			((signed char *)sc->data)[i]
-			= (int)( (unsigned char)(data[i]) - 128);
-	}
-	else
-	{
-// general case
-		samplefrac = 0;
-		fracstep = stepscale*256;
-		for (i=0 ; i<outcount ; i++)
-		{
-			srcsample = samplefrac >> 8;
-			samplefrac += fracstep;
-			if (inwidth == 2)
-				sample = LittleShort ( ((short *)data)[srcsample] );
-			else
-				sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
-			if (sc->width == 2)
-				((short *)sc->data)[i] = sample;
-			else
-				((signed char *)sc->data)[i] = sample >> 8;
-		}
-	}
-}
-
-//=============================================================================
-
-/*
-==============
-S_LoadSound
-==============
-*/
-sfxcache_t *S_LoadSound (sfx_t *s)
-{
-    char	namebuffer[256];
-	byte	*data;
-	wavinfo_t	info;
-	int		len;
-	float	stepscale;
-	sfxcache_t	*sc;
-	byte	stackbuf[1*1024];		// avoid dirtying the cache heap
-
-// see if still in memory
-	sc = Cache_Check (&s->cache);
-	if (sc)
-		return sc;
-
-//Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);
-// load it in
-	strcpy(namebuffer, "sound/");
-	strcat(namebuffer, s->name);
-
-//	Con_Printf ("loading %s\n",namebuffer);
-
-	data = loadstklmp(namebuffer, stackbuf, sizeof stackbuf, &len);
-	if(data == nil){
-		Con_Printf("Couldn't load %s: %r\n", namebuffer);
-		return nil;
-	}
-
-	info = GetWavinfo (s->name, data, len);
-	if (info.channels != 1)
-	{
-		Con_Printf ("%s is a stereo sample\n",s->name);
-		return nil;
-	}
-
-	stepscale = (float)info.rate / shm->speed;	
-	len = info.samples / stepscale;
-
-	len = len * info.width * info.channels;
-
-	sc = Cache_Alloc(&s->cache, len + sizeof *sc, s->name);
-	if (!sc)
-		return nil;
-	
-	sc->length = info.samples;
-	sc->loopstart = info.loopstart;
-	sc->speed = info.rate;
-	sc->width = info.width;
-	sc->stereo = info.channels;
-
-	ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
-
-	return sc;
-}
-
-
-
-/*
-===============================================================================
-
-WAV loading
-
-===============================================================================
-*/
-
-
-byte	*data_p;
-byte 	*iff_end;
-byte 	*last_chunk;
-byte 	*iff_data;
-int 	iff_chunk_len;
-
-
-short GetLittleShort(void)
-{
-	short val;
-
-	val = *data_p;
-	val = val + (*(data_p+1)<<8);
-	data_p += 2;
-	return val;
-}
-
-int GetLittleLong(void)
-{
-	int val;
-
-	val = *data_p;
-	val = val + (*(data_p+1)<<8);
-	val = val + (*(data_p+2)<<16);
-	val = val + (*(data_p+3)<<24);
-	data_p += 4;
-	return val;
-}
-
-void FindNextChunk(char *name)
-{
-	while (1)
-	{
-		data_p=last_chunk;
-
-		if (data_p >= iff_end)
-		{	// didn't find the chunk
-			data_p = nil;
-			return;
-		}
-		
-		data_p += 4;
-		iff_chunk_len = GetLittleLong();
-		if (iff_chunk_len < 0)
-		{
-			data_p = nil;
-			return;
-		}
-//		if (iff_chunk_len > 1024*1024)
-//			fatal ("FindNextChunk: %d length is past the 1 meg sanity limit", iff_chunk_len);
-		data_p -= 8;
-		last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
-		if(strncmp((char *)data_p, name, 4) == 0)
-			return;
-	}
-}
-
-void FindChunk(char *name)
-{
-	last_chunk = iff_data;
-	FindNextChunk (name);
-}
-
-
-void DumpChunks(void)
-{
-	char	str[5];
-	
-	str[4] = 0;
-	data_p=iff_data;
-	do
-	{
-		memcpy (str, data_p, 4);
-		data_p += 4;
-		iff_chunk_len = GetLittleLong();
-		Con_Printf ("0x%zud : %s (%d)\n", (uintptr)(data_p - 4), str, iff_chunk_len);
-		data_p += (iff_chunk_len + 1) & ~1;
-	} while (data_p < iff_end);
-}
-
-/*
-============
-GetWavinfo
-============
-*/
-wavinfo_t GetWavinfo (char *name, byte *wav, vlong wavlength)
-{
-	wavinfo_t	info;
-	int     i;
-	int     format;
-	int		samples;
-
-	memset(&info, 0, sizeof info);
-
-	if (!wav)
-		return info;
-		
-	iff_data = wav;
-	iff_end = wav + wavlength;
-
-// find "RIFF" chunk
-	FindChunk("RIFF");
-	if(!(data_p && strncmp((char *)data_p+8, "WAVE", 4) == 0))
-	{
-		Con_Printf("Missing RIFF/WAVE chunks\n");
-		return info;
-	}
-
-// get "fmt " chunk
-	iff_data = data_p + 12;
-// DumpChunks ();
-
-	FindChunk("fmt ");
-	if (!data_p)
-	{
-		Con_Printf("Missing fmt chunk\n");
-		return info;
-	}
-	data_p += 8;
-	format = GetLittleShort();
-	if (format != 1)
-	{
-		Con_Printf("Microsoft PCM format only\n");
-		return info;
-	}
-
-	info.channels = GetLittleShort();
-	info.rate = GetLittleLong();
-	data_p += 4+2;
-	info.width = GetLittleShort() / 8;
-
-// get cue chunk
-	FindChunk("cue ");
-	if (data_p)
-	{
-		data_p += 32;
-		info.loopstart = GetLittleLong();
-//		Con_Printf("loopstart=%d\n", sfx->loopstart);
-
-	// if the next chunk is a LIST chunk, look for a cue length marker
-		FindNextChunk ("LIST");
-		if (data_p)
-		{
-			if(strncmp((char *)data_p+28, "mark", 4) == 0)
-			{	// this is not a proper parse, but it works with cooledit...
-				data_p += 24;
-				i = GetLittleLong ();	// samples in loop
-				info.samples = info.loopstart + i;
-//				Con_Printf("looped length: %d\n", i);
-			}
-		}
-	}
-	else
-		info.loopstart = -1;
-
-// find data chunk
-	FindChunk("data");
-	if (!data_p)
-	{
-		Con_Printf("Missing data chunk\n");
-		return info;
-	}
-
-	data_p += 4;
-	samples = GetLittleLong () / info.width;
-
-	if (info.samples)
-	{
-		if (samples < info.samples)
-			fatal ("Sound %s has a bad loop length", name);
-	}
-	else
-		info.samples = samples;
-
-	info.dataofs = data_p - wav;
-	
-	return info;
-}
-
--- a/snd_mix.c
+++ /dev/null
@@ -1,278 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include "dat.h"
-#include "quakedef.h"
-#include "fns.h"
-
-#define DWORD	u32int
-
-#define	PAINTBUFFER_SIZE	512
-portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
-int		snd_scaletable[32][256];
-int 	*snd_p, snd_linear_count, snd_vol;
-short	*snd_out;
-
-
-void Snd_WriteLinearBlastStereo16 (void)
-{
-	int		i;
-	int		val;
-
-	for (i=0 ; i<snd_linear_count ; i+=2)
-	{
-		val = (snd_p[i]*snd_vol)>>8;
-		if (val > 0x7fff)
-			snd_out[i] = 0x7fff;
-		else if (val < (short)0x8000)
-			snd_out[i] = (short)0x8000;
-		else
-			snd_out[i] = val;
-
-		val = (snd_p[i+1]*snd_vol)>>8;
-		if (val > 0x7fff)
-			snd_out[i+1] = 0x7fff;
-		else if (val < (short)0x8000)
-			snd_out[i+1] = (short)0x8000;
-		else
-			snd_out[i+1] = val;
-	}
-}
-
-void S_TransferStereo16 (int endtime)
-{
-	int		lpos;
-	int		lpaintedtime;
-	DWORD	*pbuf;
-
-	snd_vol = volume.value*256;
-
-	snd_p = (int *) paintbuffer;
-	lpaintedtime = paintedtime;
-
-	pbuf = (DWORD *)shm->buffer;
-
-	while (lpaintedtime < endtime)
-	{
-	// handle recirculating buffer issues
-		lpos = lpaintedtime & ((shm->samples>>1)-1);
-
-		snd_out = (short *) pbuf + (lpos<<1);
-
-		snd_linear_count = (shm->samples>>1) - lpos;
-		if (lpaintedtime + snd_linear_count > endtime)
-			snd_linear_count = endtime - lpaintedtime;
-
-		snd_linear_count <<= 1;
-
-	// write a linear blast of samples
-		Snd_WriteLinearBlastStereo16 ();
-
-		snd_p += snd_linear_count;
-		lpaintedtime += (snd_linear_count>>1);
-	}
-}
-
-void S_TransferPaintBuffer(int endtime)
-{
-	int 	out_idx;
-	int 	count;
-	int 	out_mask;
-	int 	*p;
-	int 	step;
-	int		val;
-	int		snd_vol;
-	DWORD	*pbuf;
-
-	if (shm->samplebits == 16 && shm->channels == 2)
-	{
-		S_TransferStereo16 (endtime);
-		return;
-	}
-	
-	p = (int *) paintbuffer;
-	count = (endtime - paintedtime) * shm->channels;
-	out_mask = shm->samples - 1; 
-	out_idx = paintedtime * shm->channels & out_mask;
-	step = 3 - shm->channels;
-	snd_vol = volume.value*256;
-
-	pbuf = (DWORD *)shm->buffer;
-
-	if (shm->samplebits == 16)
-	{
-		short *out = (short *) pbuf;
-		while (count--)
-		{
-			val = (*p * snd_vol) >> 8;
-			p+= step;
-			if (val > 0x7fff)
-				val = 0x7fff;
-			else if (val < (short)0x8000)
-				val = (short)0x8000;
-			out[out_idx] = val;
-			out_idx = (out_idx + 1) & out_mask;
-		}
-	}
-	else if (shm->samplebits == 8)
-	{
-		unsigned char *out = (unsigned char *) pbuf;
-		while (count--)
-		{
-			val = (*p * snd_vol) >> 8;
-			p+= step;
-			if (val > 0x7fff)
-				val = 0x7fff;
-			else if (val < (short)0x8000)
-				val = (short)0x8000;
-			out[out_idx] = (val>>8) + 128;
-			out_idx = (out_idx + 1) & out_mask;
-		}
-	}
-}
-
-
-/*
-===============================================================================
-
-CHANNEL MIXING
-
-===============================================================================
-*/
-
-void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);
-void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);
-
-void S_PaintChannels(int endtime)
-{
-	int 	i;
-	int 	end;
-	channel_t *ch;
-	sfxcache_t	*sc;
-	int		ltime, count;
-
-	while (paintedtime < endtime)
-	{
-	// if paintbuffer is smaller than DMA buffer
-		end = endtime;
-		if (endtime - paintedtime > PAINTBUFFER_SIZE)
-			end = paintedtime + PAINTBUFFER_SIZE;
-
-	// clear the paint buffer
-		memset(paintbuffer, 0, (end - paintedtime) * sizeof *paintbuffer);
-
-	// paint in the channels.
-		ch = channels;
-		for (i=0; i<total_channels ; i++, ch++)
-		{
-			if (!ch->sfx)
-				continue;
-			if (!ch->leftvol && !ch->rightvol)
-				continue;
-			sc = S_LoadSound (ch->sfx);
-			if (!sc)
-				continue;
-
-			ltime = paintedtime;
-
-			while (ltime < end)
-			{	// paint up to end
-				if (ch->end < end)
-					count = ch->end - ltime;
-				else
-					count = end - ltime;
-
-				if (count > 0)
-				{	
-					if (sc->width == 1)
-						SND_PaintChannelFrom8(ch, sc, count);
-					else
-						SND_PaintChannelFrom16(ch, sc, count);
-	
-					ltime += count;
-				}
-
-			// if at end of loop, restart
-				if (ltime >= ch->end)
-				{
-					if (sc->loopstart >= 0)
-					{
-						ch->pos = sc->loopstart;
-						ch->end = ltime + sc->length - ch->pos;
-					}
-					else				
-					{	// channel just stopped
-						ch->sfx = nil;
-						break;
-					}
-				}
-			}
-															  
-		}
-
-	// transfer out according to DMA format
-		S_TransferPaintBuffer(end);
-		paintedtime = end;
-	}
-}
-
-void SND_InitScaletable (void)
-{
-	int		i, j;
-	
-	for (i=0 ; i<32 ; i++)
-		for (j=0 ; j<256 ; j++)
-			snd_scaletable[i][j] = ((signed char)j) * i * 8;
-}
-
-
-void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
-{
-	int 	data;
-	int	*lscale, *rscale;
-	uchar	*sfx;
-	int	i;
-
-	if (ch->leftvol > 255)
-		ch->leftvol = 255;
-	if (ch->rightvol > 255)
-		ch->rightvol = 255;
-		
-	lscale = snd_scaletable[ch->leftvol >> 3];
-	rscale = snd_scaletable[ch->rightvol >> 3];
-	sfx = (uchar *)((uintptr)sc->data + (uintptr)ch->pos);
-
-	for (i=0 ; i<count ; i++)
-	{
-		data = sfx[i];
-		paintbuffer[i].left += lscale[data];
-		paintbuffer[i].right += rscale[data];
-	}
-	
-	ch->pos += count;
-}
-
-
-void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
-{
-	int data;
-	int left, right;
-	int leftvol, rightvol;
-	signed short *sfx;
-	int	i;
-
-	leftvol = ch->leftvol;
-	rightvol = ch->rightvol;
-	sfx = (signed short *)sc->data + ch->pos;
-
-	for (i=0 ; i<count ; i++)
-	{
-		data = sfx[i];
-		left = (data * leftvol) >> 8;
-		right = (data * rightvol) >> 8;
-		paintbuffer[i].left += left;
-		paintbuffer[i].right += right;
-	}
-
-	ch->pos += count;
-}
-
--- a/sound.h
+++ /dev/null
@@ -1,159 +1,0 @@
-// sound.h -- client sound i/o functions
-
-enum{
-	NSAMPLE = 4096,
-	SAMPLESZ = 16,
-	SAMPLEB = SAMPLESZ / 8,
-	RATE = 44100,
-	SNBUF = SAMPLEB * NSAMPLE
-};
-
-#define DEFAULT_SOUND_PACKET_VOLUME 255
-#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
-
-// !!! if this is changed, it much be changed in asm_i386.h too !!!
-typedef struct
-{
-	int left;
-	int right;
-} portable_samplepair_t;
-
-typedef struct sfx_s
-{
-	char 	name[Npath];
-	cache_user_t	cache;
-} sfx_t;
-
-// !!! if this is changed, it much be changed in asm_i386.h too !!!
-typedef struct
-{
-	int 	length;
-	int 	loopstart;
-	int 	speed;
-	int 	width;
-	int 	stereo;
-	byte	data[1];		// variable sized
-} sfxcache_t;
-
-typedef struct
-{
-	qboolean		gamealive;
-	qboolean		soundalive;
-	qboolean		splitbuffer;
-	int				channels;
-	int				samples;				// mono samples in buffer
-	int				submission_chunk;		// don't mix less than this #
-	uint				samplepos;				// in mono samples
-	int				samplebits;
-	int				speed;
-	unsigned char	*buffer;
-} dma_t;
-
-// !!! if this is changed, it much be changed in asm_i386.h too !!!
-typedef struct
-{
-	sfx_t	*sfx;			// sfx number
-	int		leftvol;		// 0-255 volume
-	int		rightvol;		// 0-255 volume
-	int		end;			// end time in global paintsamples
-	int 	pos;			// sample position in sfx
-	int		looping;		// where to loop, -1 = no looping
-	int		entnum;			// to allow overriding a specific sound
-	int		entchannel;		//
-	vec3_t	origin;			// origin of sound effect
-	vec_t	dist_mult;		// distance multiplier (attenuation/clipK)
-	int		master_vol;		// 0-255 master volume
-} channel_t;
-
-typedef struct
-{
-	int		rate;
-	int		width;
-	int		channels;
-	int		loopstart;
-	int		samples;
-	int		dataofs;		// chunk starts this many bytes from file start
-} wavinfo_t;
-
-void S_Init (void);
-void S_Startup (void);
-void S_Shutdown (void);
-void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol,  float attenuation);
-void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation);
-void S_StopSound (int entnum, int entchannel);
-void S_StopAllSounds(qboolean clear);
-void S_ClearBuffer (void);
-void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up);
-void S_ExtraUpdate (void);
-
-sfx_t *S_PrecacheSound (char *sample);
-void S_TouchSound (char *sample);
-void S_ClearPrecache (void);
-void S_BeginPrecaching (void);
-void S_EndPrecaching (void);
-void S_PaintChannels(int endtime);
-void S_InitPaintChannels (void);
-
-// picks a channel based on priorities, empty slots, number of channels
-channel_t *SND_PickChannel(int entnum, int entchannel);
-
-// spatializes a channel
-void SND_Spatialize(channel_t *ch);
-
-// initializes cycling through a DMA buffer and returns information on it
-qboolean SNDDMA_Init(void);
-
-// gets the current DMA position
-uint SNDDMA_GetDMAPos(void);
-
-// shutdown the DMA xfer.
-void SNDDMA_Shutdown(void);
-
-// ====================================================================
-// User-setable variables
-// ====================================================================
-
-#define	MAX_CHANNELS			128
-#define	MAX_DYNAMIC_CHANNELS	8
-
-
-extern	channel_t   channels[MAX_CHANNELS];
-// 0 to MAX_DYNAMIC_CHANNELS-1	= normal entity sounds
-// MAX_DYNAMIC_CHANNELS to MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS -1 = water, etc
-// MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels = static sounds
-
-extern	int			total_channels;
-
-//
-// Fake dma is a synchronous faking of the DMA progress used for
-// isolating performance in the renderer.  The fakedma_updates is
-// number of times S_Update() is called per second.
-//
-
-extern qboolean 		fakedma;
-extern int 			fakedma_updates;
-extern int		paintedtime;
-extern vec3_t listener_origin;
-extern vec3_t listener_forward;
-extern vec3_t listener_right;
-extern vec3_t listener_up;
-extern volatile dma_t *shm;
-extern volatile dma_t sn;
-extern vec_t sound_nominal_clip_dist;
-
-extern	cvar_t loadas8bit;
-extern	cvar_t bgmvolume;
-extern	cvar_t volume;
-
-extern int		snd_blocked;
-
-void S_LocalSound (char *s);
-sfxcache_t *S_LoadSound (sfx_t *s);
-
-wavinfo_t GetWavinfo (char *name, byte *wav, vlong wavlength);
-
-void SND_InitScaletable (void);
-void SNDDMA_Submit(void);
-
-void S_AmbientOff (void);
-void S_AmbientOn (void);
--- a/sv_main.c
+++ b/sv_main.c
@@ -135,9 +135,9 @@
 	channel = (ent<<3) | channel;
 
 	field_mask = 0;
-	if (volume != DEFAULT_SOUND_PACKET_VOLUME)
+	if (volume != Spktvol)
 		field_mask |= SND_VOLUME;
-	if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
+	if (attenuation != Spktatt)
 		field_mask |= SND_ATTENUATION;
 
 // directed messages go only to the entity the are targeted on
--- a/sys.c
+++ b/sys.c
@@ -61,10 +61,8 @@
 static void
 croak(void *, char *note)
 {
-	if(strncmp(note, "sys:", 4) == 0){
+	if(strncmp(note, "sys:", 4) == 0)
 		IN_Shutdown();
-		SNDDMA_Shutdown();
-	}
 	noted(NDFLT);
 }
 
@@ -102,7 +100,7 @@
 
 	Host_Init(&parms);
 
-	oldtime = Sys_FloatTime() - 0.1;
+	oldtime = Sys_FloatTime() - 1.0 / Fpsmax;
 	for(;;){
 		// find time spent rendering last frame
 		newtime = Sys_FloatTime();