shithub: qk1

ref: bf02a0915ffa42a3b051ea6e41c9ed1528d04614
dir: /cd.c/

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <regexp.h>
#include "dat.h"
#include "quakedef.h"
#include "fns.h"

cvar_t bgmvolume = {"bgmvolume", "1", 1};

static char cdfile[13];
static int trk, chtrk, ntrk;
static int cdread, cdloop;

static void
cproc(void *)
{
	int n, afd, fd, v;
	char f[32];
	s16int buf[4096];
	short *p;
	double vol;

	if((afd = open("/dev/audio", OWRITE)) < 0){
		Con_DPrintf("cd: open: %r\n");
		return;
	}
	fd = -1;
	for(;;){
		if(chtrk > 0){
			close(fd);
			trk = chtrk;
			snprint(f, sizeof f, "%s%03ud", cdfile, trk);
			if((fd = open(f, OREAD)) < 0)
				Con_DPrintf("cd: open: %r\n");
			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{
				close(fd);
				fd = -1;
			}
			continue;
		}
		vol = bgmvolume.value;
		for(p=buf; p<buf+n/sizeof*buf; p++){
			v = *p * vol;
			if(v > 0x7fff)
				v = 0x7fff;
			else if(v < -0x8000)
				v = -0x8000;
			*p = v;
		}
		if(write(afd, buf, n) != n)
			break;
	}
}

void
stopcd(void)
{
	cdread = 0;
	cdloop = 0;
}

void
pausecd(void)
{
	cdread = 0;
}

void
resumecd(void)
{
	cdread = 1;
}

void
shutcd(void)
{
	stopcd();
}

void
stepcd(void)
{
	if(bgmvolume.value <= 0.0 || cdread == 0)
		return;
	cdread = bgmvolume.value > 0.0;
}

void
playcd(int nt, int loop)
{
	if(ntrk < 1)
		return;
	nt -= 1;	/* d001 assumed part of track list */
	if(nt < 1 || nt > ntrk){
		Con_Printf("cd: invalid track number %d\n", nt);
		return;
	}
	chtrk = nt;
	cdloop = loop;
	cdread = bgmvolume.value > 0.0;
}

static void
cdcmd(void)
{
	char *c;

	if(Cmd_Argc() < 2){
usage:
		Con_Printf("cd (play|loop|stop|pause|resume|info) [track]\n");
		return;
	}
	c = Cmd_Argv(1);
	if(cistrcmp(c, "play") == 0){
		if(Cmd_Argc() < 3)
			goto usage;
		playcd(atoi(Cmd_Argv(2)), 0);
	}else if(cistrcmp(c, "loop") == 0){
		if(Cmd_Argc() < 3)
			goto usage;
		playcd(atoi(Cmd_Argv(2)), 1);
	}else if(cistrcmp(c, "stop") == 0)
		stopcd();
	else if(cistrcmp(c, "pause") == 0)
		pausecd();
	else if(cistrcmp(c, "resume") == 0)
		resumecd();
	else if(cistrcmp(c, "info") == 0)
		Con_Printf("track %d/%d; loop %d; vol %.1f\n", trk, ntrk, cdloop, bgmvolume.value);
	else
		goto usage;
}

static int
cdinfo(void)
{
	int fd, i, n;
	char type;
	Reprog *pat;
	Dir *d;

	ntrk = 0;
	if((fd = open("/mnt/cd", OREAD)) < 0)
		return -1;
	n = dirreadall(fd, &d);
	close(fd);
	if(n < 0)
		return -1;
	pat = regcomp("[au][0-9][0-9][0-9]");
	for(type=0, i=0; i<n; i++)
		if(regexec(pat, d[i].name, nil, 0)){
			if(type == 0)
				type = d[i].name[0];
			ntrk++;
		}
	free(pat);
	free(d);
	if(ntrk < 1)
		return -1;
	snprint(cdfile, sizeof cdfile, "/mnt/cd/%c", type);
	return 0;
}

int
initcd(void)
{
	if(cdinfo() < 0){
		Con_DPrintf("cdinfo: %r\n");
		return -1;
	}
	if(proccreate(cproc, nil, 16384) < 0)
		sysfatal("proccreate: %r");
	Cvar_RegisterVariable(&bgmvolume);
	Cmd_AddCommand("cd", cdcmd);
	return 0;
}