shithub: qk1

Download patch

ref: d204ae749ad120af2e41b864d147a66380830891
parent: 120cbddefb31ed3ac9d159f32300e15c13837665
author: Konstantinn Bonnet <qu7uux@gmail.com>
date: Sat Sep 5 21:32:31 EDT 2015

implement cdaudio via mixfs(1), simplify snd.c a bit

--- a/README
+++ b/README
@@ -1,8 +1,8 @@
 qk1 - (9) quake
 ===============
 port of linux/x11 quake to plan9front. tested on amd64 and 386 only.
-currently lacks networking and music. save for a rare crash and some stupid
-bugs, it works and plays reasonably well. on my machines.
+currently lacks networking. save for a rare crash and some stupid bugs,
+it works and plays reasonably well. on my machines.
 
 
 installation
@@ -19,6 +19,10 @@
 
 % quake
 
+qk1 reads /mnt/cd/aNNN files as in cdfs(1) to play music. the directory needn't
+be populated by cdfs(1), so long as the files are in the format described by
+audio(3). this currently requires the use of mixfs(1).
+
 installing an expansion or mod, for example rogue:
 
 % mkdir $home/lib/quake/rogue
@@ -29,14 +33,23 @@
 % quake -game rogue
 
 
-todo
-----
+todo/bugs
+---------
 - udp/ip, plan9 style
-- cdaudio: reading and mixing music from e.g. cdfs(4)
+- sound: don't require mixfs and fix soundbuffer write race
+- crash in d_sprite.c:D_SpriteDrawSpans after several hours of looping the
+  demos
+- resolutions other than 4:3: some vertical and horizontal strips on the edge
+  of the screen aren't drawn
+- console print recently screwed anew; console color print still screwed up
+  (printf/print differences)
+- #define PARANOID reveals several points of failure that are otherwise ignored
+- (?) sprites not scaled correctly on higher resolutions
+- screenshot code outputs garbage
 - more testing, cleanups and bug fixes (g '/\* FIXME')
 - (bjnh) bring asm for 386/amd64 back
-- (bjnh) plan9 code style everywhere
-- (bjnh) better performance
+- (bjnh) style(6)
+- (bjnh) make it run super fast on a pentium 2
 - (bjnh) redesign everything to be super cool (e.g. pakfs, console shit,
   args, etc.)
 
@@ -51,6 +64,9 @@
 - added m_windowed cvar (replacing _windowed_mouse), for mouse grabbing
 - ungrabs the mouse when main menu is accessed
 - removed -record, -playback: broken and unused
+- removed -sndbits, -sndspeed, -sndmono
+- removed -cddev -nocdaudio; cdaudio is just reading files
+- removed cd [on|off|reset|remap]: not quake's problem
 
 
 shitty workarounds and other bullshit
@@ -66,24 +82,6 @@
   done better)
 - removal of stdio stuff probably not really warranted and possibly introduced
   bugs
-
-
-bugs
-----
-- crash in d_sprite.c:D_SpriteDrawSpans() after several hours of looping the
-  demos
-- sound dies after a few hours: (snd.c) wpos and SNDDMA_GetDMAPos() probably
-  wrong, mix buffer being overwritten while writing to /dev/audio, etc.
-- resolutions other than 4:3: some vertical and horizontal strips on the edge
-  of the screen aren't drawn
-- console color print is still screwed up (printf/print differences)
-- resolutions under around 328x160 don't work, possibly because menu text isn't
-  scaled down or something
-- #define PARANOID reveals several points of failure that are otherwise ignored
-- (?) sprites not scaled correctly on higher resolutions
-- m_windowed 1: in a paused game (in menu or console during sp game), can still
-  look around the frozen world
-- screenshot code outputs garbage
 
 
 legal
--- a/cd.c
+++ b/cd.c
@@ -1,286 +1,197 @@
 #include <u.h>
 #include <libc.h>
 #include <stdio.h>
+#include <thread.h>
+#include <regexp.h>
 #include "quakedef.h"
 
-qboolean cdValid = false;
-qboolean playing = false;
-qboolean wasPlaying = false;
-qboolean initialized = false;
-qboolean enabled = true;
-qboolean playLooping = false;
-float cdvolume;
-byte remap[100];
-byte playTrack;
-byte maxTrack;
-int cdfd = -1;
-char cd_dev[64] = "/dev/cdrom";
+static int cdread;
+static int cdloop;
+static int cdvol;
+static int chtrk;
+static int ntrk;
+static int trk;
+static int ctid = -1;
+static Reprog *pat;
 
 
-int CDAudio_GetAudioDiskInfo (void)
+static int
+cdinfo(void)
 {
-	cdValid = false;
-	Con_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
-	return -1;
+	int fd, i, n;
+	Dir *d;
 
-	/*
-	struct cdrom_tochdr tochdr;
+	ntrk = 0;
 
-	if(tochdr.cdth_trk0 < 1){
-		Con_DPrintf("CDAudio: no music tracks\n");
+	if((fd = open("/mnt/cd", OREAD)) < 0)
+		goto err;
+	if((n = dirreadall(fd, &d)) < 0)
+		goto err;
+	close(fd);
+	for(i = 0; i < n; i++)
+		if(regexec(pat, d[i].name, nil, 0))
+			ntrk++;
+	free(d);
+	if(ntrk < 1)
 		return -1;
-	}
-	cdValid = true;
-	maxTrack = tochdr.cdth_trk1;
 	return 0;
-	*/
+
+err:
+	close(fd);
+	fprint(2, "cdinfo: %r");
+	return -1;
 }
 
-void CDAudio_Play (byte track, qboolean /*looping*/)
+static void
+cproc(void *)
 {
-	if(cdfd == -1 || !enabled)
-		return;
-	if(!cdValid){
-		CDAudio_GetAudioDiskInfo();
-		if(!cdValid)
-			return;
-	}
+	int a, n, afd, fd;
+	char s[24];
+	uchar buf[SNBUF];
+	short *p;
 
-	track = remap[track];
-	if(track < 1 || track > maxTrack){
-		Con_DPrintf("CDAudio: Bad track number %ud.\n", track);
+	if((afd = open("/dev/audio", OWRITE)) < 0)
 		return;
+	fd = -1;
+	for(;;){
+		if(chtrk > 0){
+			close(fd);
+			trk = chtrk;
+			snprint(s, sizeof s, "/mnt/cd/a%03ud", trk);
+			if((fd = open(s, OREAD)) < 0)
+				fprint(2, "cproc: %r");
+			chtrk = 0;
+		}
+		if(!cdread || fd < 0){
+			sleep(1);
+			continue;
+		}
+		if((n = read(fd, buf, sizeof buf)) < 0)
+			break;
+		if(n == 0){
+			if(cdloop)
+				seek(fd, 0, 0);
+			else
+				break;
+		}
+		p = (short *)buf;
+		while((uintptr)p < (uintptr)(buf + sizeof buf)){
+			a = *p * cdvol >> 8;
+			if(a < (short)0x8000)
+				a = 0x8000;
+			*p++ = a;
+		}
+		if(write(afd, buf, n) != n)
+			break;
 	}
+	close(afd);
+	close(fd);
+}
 
-	Con_DPrintf("CDAudio_Play: PORTME\n");
-	return;
-
-	/*
-	struct cdrom_tocentry entry;
-	struct cdrom_ti ti;
-
-	// don't try to play a non-audio track
-	entry.cdte_track = track;
-	entry.cdte_format = CDROM_MSF;
-	if(ioctl(cdfd, CDROMREADTOCENTRY, &entry) == -1){
-		Con_DPrintf("ioctl cdromreadtocentry failed\n");
+void
+CDAudio_Play(byte nt, qboolean loop)
+{
+	if(ctid < 0)
 		return;
-	}
-	if(entry.cdte_ctrl == CDROM_DATA_TRACK){
-		Con_Printf("CDAudio: track %d is not audio\n", track);
+	if(nt < 1 || nt > ntrk){
+		Con_Printf("cd: invalid track number %ud\n", nt);
 		return;
 	}
 
-	if(playing){
-		if(playTrack == track)
-			return;
-		CDAudio_Stop();
-	}
-
-	ti.cdti_trk0 = track;
-	ti.cdti_trk1 = track;
-	ti.cdti_ind0 = 1;
-	ti.cdti_ind1 = 99;
-	if(ioctl(cdfd, CDROMPLAYTRKIND, &ti) == -1) {
-		Con_DPrintf("ioctl cdromplaytrkind failed\n");
-		return;
-	}
-	if(ioctl(cdfd, CDROMRESUME) == -1) 
-		Con_DPrintf("ioctl cdromresume failed\n");
-
-	playLooping = looping;
-	playTrack = track;
-	playing = true;
-
-	if(cdvolume == 0.0)
-		CDAudio_Pause();
-	*/
+	chtrk = nt;
+	cdloop = loop;
+	if(cdvol > 0)
+		cdread = 1;
 }
 
-void CDAudio_Stop (void)
+void
+CDAudio_Stop(void)
 {
-	if(cdfd == -1 || !enabled || !playing)
-		return;
-	wasPlaying = false;
-	playing = false;
+	cdread = 0;
+	cdloop = 0;
 }
 
-void CDAudio_Pause (void)
+void
+CDAudio_Pause(void)
 {
-	if(cdfd == -1 || !enabled || !playing)
-		return;
-	wasPlaying = playing;
-	playing = false;
+	cdread = 0;
 }
 
-void CDAudio_Resume (void)
+void
+CDAudio_Resume(void)
 {
-	if(cdfd == -1 || !enabled || !cdValid || !wasPlaying)
-		return;
-	playing = true;
+	cdread = 1;
 }
 
-void CD_f (void)
+void
+CD_f(void)
 {
-	int ret, n;
-	char *command;
+	char *cmd;
 
 	if(Cmd_Argc() < 2)
 		return;
-	command = Cmd_Argv(1);
-	if(cistrcmp(command, "on") == 0){
-		enabled = true;
-		return;
-	}
-	if(cistrcmp(command, "off") == 0){
-		if(playing)
-			CDAudio_Stop();
-		enabled = false;
-		return;
-	}
-	if(cistrcmp(command, "reset") == 0){
-		enabled = true;
-		if(playing)
-			CDAudio_Stop();
-		for(n = 0; n < 100; n++)
-			remap[n] = n;
-		CDAudio_GetAudioDiskInfo();
-		return;
-	}
-	if(cistrcmp(command, "remap") == 0){
-		ret = Cmd_Argc() - 2;
-		if(ret <= 0){
-			for(n = 1; n < 100; n++)
-				if(remap[n] != n)
-					Con_Printf("  %ud -> %ud\n", n, remap[n]);
-			return;
-		}
-		for(n = 1; n <= ret; n++)
-			remap[n] = atoi(Cmd_Argv(n+1));
-		return;
-	}
-	if(!cdValid){
-		CDAudio_GetAudioDiskInfo();
-		if(!cdValid){
-			Con_Printf("No CD in player.\n");
-			return;
-		}
-	}
-	if(cistrcmp(command, "play") == 0){
+	cmd = Cmd_Argv(1);
+	if(cistrcmp(cmd, "play") == 0){
 		CDAudio_Play((uchar)atoi(Cmd_Argv(2)), false);
 		return;
-	}
-	if(cistrcmp(command, "loop") == 0){
+	}else if(cistrcmp(cmd, "loop") == 0){
 		CDAudio_Play((uchar)atoi(Cmd_Argv(2)), true);
 		return;
-	}
-	if(cistrcmp(command, "stop") == 0){
+	}else if(cistrcmp(cmd, "stop") == 0){
 		CDAudio_Stop();
 		return;
-	}
-	if (cistrcmp(command, "pause") == 0){
+	}else if(cistrcmp(cmd, "pause") == 0){
 		CDAudio_Pause();
 		return;
-	}
-	if(cistrcmp(command, "resume") == 0){
+	}else if(cistrcmp(cmd, "resume") == 0){
 		CDAudio_Resume();
 		return;
-	}
-	if(cistrcmp(command, "info") == 0){
-		Con_Printf("%ud tracks\n", maxTrack);
-		if(playing)
-			Con_Printf("Currently %s track %ud\n", playLooping ? "looping" : "playing", playTrack);
-		else if(wasPlaying)
-			Con_Printf("Paused %s track %ud\n", playLooping ? "looping" : "playing", playTrack);
-		Con_Printf("Volume is %f\n", cdvolume);
+	}else if(cistrcmp(cmd, "info") == 0){
+		Con_Printf("track %ud/%ud; loop %d; vol %f\n", trk, ntrk, cdloop, cdvol);
 		return;
 	}
 }
 
-void CDAudio_Update (void)
+void
+CDAudio_Update(void)
 {
-	static long lastchk;
+	int v;
 
-	if(!enabled)
-		return;
-
-	if(bgmvolume.value != cdvolume){
-		if(cdvolume){
-			Cvar_SetValue("bgmvolume", 0.0);
-			cdvolume = bgmvolume.value;
-			CDAudio_Pause();
-		}else{
-			Cvar_SetValue("bgmvolume", 1.0);
-			cdvolume = bgmvolume.value;
-			CDAudio_Resume();
-		}
-	}
-	if(playing && lastchk < time(nil)){
-		lastchk = time(nil) + 2;	//two seconds between chks
-
-		Con_DPrintf("CDAudio_Update: PORTME\n");
-
-		/*
-		struct cdrom_subchnl subchnl;
-
-		subchnl.cdsc_format = CDROM_MSF;
-		if(ioctl(cdfd, CDROMSUBCHNL, &subchnl) == -1 ) {
-			Con_DPrintf("ioctl cdromsubchnl failed\n");
-			playing = false;
-			return;
-		}
-		if(subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY
-		&& subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED){
-			playing = false;
-			if(playLooping)
-				CDAudio_Play(playTrack, true);
-		}
-		*/
-	}
+	v = cdvol;
+	cdvol = bgmvolume.value * 256;
+	if(v <= 0 && cdvol > 0)
+		cdread = 1;
+	else if(v > 0 && cdvol <= 0)
+		cdread = 0;
 }
 
-int CDAudio_Init(void)
+int
+CDAudio_Init(void)
 {
-	int i;
-
 	if(cls.state == ca_dedicated)
 		return -1;
-	if(COM_CheckParm("-nocdaudio"))
+	pat = regcomp("a[0-9][0-9][0-9]");
+	if(cdinfo() < 0)
 		return -1;
+	if((ctid = proccreate(cproc, nil, 16384)) < 0)
+		sysfatal("proccreate: %r");
 
-	if((i = COM_CheckParm("-cddev")) != 0 && i < com_argc - 1) {
-		strncpy(cd_dev, com_argv[i + 1], sizeof(cd_dev));
-		cd_dev[sizeof(cd_dev)-1] = 0;
-	}
-
-	if((cdfd = open(cd_dev, OREAD)) == -1){
-		fprint(2, "open: %r\n");
-		cdfd = -1;
-		return -1;
-	}
-
-	for (i = 0; i < 100; i++)
-		remap[i] = i;
-	initialized = true;
-	enabled = true;
-
-	if(CDAudio_GetAudioDiskInfo()){
-		Con_Printf("CDAudio_Init: No CD in player.\n");
-		cdValid = false;
-	}
-
 	Cmd_AddCommand("cd", CD_f);
 
 	Con_Printf("CD Audio Initialized\n");
-
 	return 0;
 }
 
-void CDAudio_Shutdown (void)
+void
+CDAudio_Shutdown(void)
 {
-	if(!initialized)
+	if(ctid < 0)
 		return;
+
 	CDAudio_Stop();
-	close(cdfd);
-	cdfd = -1;
+	postnote(PNPROC, ctid, "shutdown");
+	ctid = -1;
+	free(pat);
+	pat = nil;
+	cdread = cdloop = 0;
 }
--- a/common.c
+++ b/common.c
@@ -5,13 +5,13 @@
 #include <stdio.h>
 #include "quakedef.h"
 
-#define NUM_SAFE_ARGVS  7
+#define NUM_SAFE_ARGVS  6
 
 static char     *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
 static char     *argvdummy = " ";
 
 static char     *safeargvs[NUM_SAFE_ARGVS] =
-	{"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly"};
+	{"-stdvid", "-nolan", "-nosound", "-nojoy", "-nomouse", "-dibonly"};
 
 cvar_t  registered = {"registered","0"};
 cvar_t  cmdline = {"cmdline","0", false, true};
--- a/snd.c
+++ b/snd.c
@@ -5,10 +5,10 @@
 #include "quakedef.h"
 
 enum{
-	Nbuf	= 8
+	Nbuf = 8
 };
 static int afd;
-static int sndon;
+static int stid = -1;
 static uint wpos;
 static Channel *schan;
 static QLock sndlock;
@@ -17,30 +17,22 @@
 static void
 sproc(void *)
 {
-	int n, sz;
+	int n;
 
-	threadsetgrp(THsnd);
-
 	for(;;){
 		if(recv(schan, nil) < 0)
 			break;
-		sz = shm->samplebits/8 * shm->samples;
-		if((n = write(afd, shm->buffer, sz)) != sz)
+		if((n = write(afd, shm->buffer, SNBUF)) != SNBUF)
 			break;
 		qlock(&sndlock);
 		wpos += n;
 		qunlock(&sndlock);
 	}
-	fprint(2, "sproc %d: %r\n", threadpid(threadid()));
 }
 
 qboolean
 SNDDMA_Init(void)
 {
-	int i;
-
-	sndon = 0;
-
 	if((afd = open("/dev/audio", OWRITE)) < 0){
 		fprint(2, "open: %r\n");
 		return 0;
@@ -48,32 +40,19 @@
 
 	shm = &sn;
 	shm->splitbuffer = 0;
-
-	if((i = COM_CheckParm("-sndbits")) != 0)
-		shm->samplebits = atoi(com_argv[i+1]);
-	if(shm->samplebits != 16 && shm->samplebits != 8)
-		shm->samplebits = 16;
-
-	if((i = COM_CheckParm("-sndspeed")) != 0)
-		shm->speed = atoi(com_argv[i+1]);
-	else
-		shm->speed = 44100;
-
-	shm->channels = 2;
-	if(COM_CheckParm("-sndmono") != 0)
-		shm->channels = 1;
-
-	shm->samples = 4096;
 	shm->submission_chunk = 1;
-
-	if((shm->buffer = mallocz(shm->samplebits/8 * shm->samples, 1)) == nil)
-		sysfatal("SNDDMA_Init:mallocz: %r\n");
+	shm->samplebits = SAMPLESZ;
+	shm->speed = RATE;
+	shm->channels = 2;
+	shm->samples = NSAMPLE;
 	shm->samplepos = 0;
-	sndon = 1;
+	if((shm->buffer = mallocz(SNBUF, 1)) == nil)
+		sysfatal("mallocz: %r\n");
+
 	wpos = 0;
 	if((schan = chancreate(sizeof(int), Nbuf)) == nil)
 		sysfatal("SNDDMA_Init:chancreate: %r");
-	if(proccreate(sproc, nil, 8192) < 0)
+	if((stid = proccreate(sproc, nil, 8192)) < 0)
 		sysfatal("SNDDMA_Init:proccreate: %r");
 	return 1;
 }
@@ -81,10 +60,10 @@
 uint
 SNDDMA_GetDMAPos(void)
 {
-	if(!sndon)
+	if(stid < 0)
 		return 0;
 	qlock(&sndlock);
-	shm->samplepos = wpos / (shm->samplebits/8);
+	shm->samplepos = wpos / SAMPLEB;
 	qunlock(&sndlock);
 	return shm->samplepos;
 }
@@ -92,17 +71,16 @@
 void
 SNDDMA_Shutdown(void)
 {
-	if(!sndon)
+	if(stid < 0)
 		return;
 
-	threadkillgrp(THsnd);
+	threadint(stid);
+	stid = -1;
 	close(afd);
 	free(shm->buffer);
-	if(schan != nil){
+	if(schan != nil)
 		chanfree(schan);
-		schan = nil;
-	}
-	sndon = 0;
+	schan = nil;
 }
 
 void
--- a/snd_dma.c
+++ b/snd_dma.c
@@ -21,7 +21,7 @@
 
 int				snd_blocked = 0;
 static qboolean	snd_ambient = 1;
-qboolean		snd_initialized = false;
+static qboolean	snd_initialized;
 
 // pointer should go away
 volatile dma_t *shm;
--- a/sound.h
+++ b/sound.h
@@ -1,7 +1,12 @@
 // sound.h -- client sound i/o functions
 
-#ifndef __SOUND__
-#define __SOUND__
+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
@@ -140,8 +145,6 @@
 extern	cvar_t bgmvolume;
 extern	cvar_t volume;
 
-extern qboolean	snd_initialized;
-
 extern int		snd_blocked;
 
 void S_LocalSound (char *s);
@@ -154,5 +157,3 @@
 
 void S_AmbientOff (void);
 void S_AmbientOn (void);
-
-#endif
--- a/sys.h
+++ b/sys.h
@@ -2,7 +2,6 @@
 
 enum{
 	THin	= 1,
-	THsnd	= 2,
 	THnet	= 3
 };