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
};