371 lines · 5.9 KB · C
RawDownload
#include	"u.h"#include	"lib.h"#include	"dat.h"#include	"fns.h"#include	"error.h"#include	"devaudio.h" enum{	Qdir		= 0,	Qaudio,	Qvolume, 	Aclosed		= 0,	Aread,	Awrite, 	Speed		= 44100,	Ncmd		= 50,		/* max volume command words */}; Dirtabaudiodir[] ={	".",	{Qdir, 0, QTDIR},		0,	DMDIR|0555,	"audio",	{Qaudio},		0,	0666,	"volume",	{Qvolume},		0,	0666,}; static	struct{	QLock	lk;	Rendez	vous;	int	amode;		/* Aclosed/Aread/Awrite for /audio */} audio; #define aqlock(a) qlock(&(a)->lk)#define aqunlock(a) qunlock(&(a)->lk) static	struct{	char*	name;	int	flag;	int	ilval;		/* initial values */	int	irval;} volumes[] ={	"audio",	Fout, 		50,	50,	"synth",	Fin|Fout,	0,	0,	"cd",		Fin|Fout,	0,	0,	"line",	Fin|Fout,	0,	0,	"mic",	Fin|Fout|Fmono,	0,	0,	"speaker",	Fout|Fmono,	0,	0, 	"treb",		Fout, 		50,	50,	"bass",		Fout, 		50,	50, 	"speed",	Fin|Fout|Fmono,	Speed,	Speed,	0}; static	char	Emode[]		= "illegal open mode";static	char	Evolume[]	= "illegal volume specifier"; static	voidresetlevel(void){	int i; 	for(i=0; volumes[i].name; i++)		audiodevsetvol(i, volumes[i].ilval, volumes[i].irval);} static voidaudioinit(void){} static Chan*audioattach(char *param){	return devattach('A', param);} static Walkqid*audiowalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);} static intaudiostat(Chan *c, uchar *db, int n){	return devstat(c, db, n, audiodir, nelem(audiodir), devgen);} static Chan*audioopen(Chan *c, int omode){	int amode; 	switch((ulong)c->qid.path) {	default:		error(Eperm);		break; 	case Qvolume:	case Qdir:		break; 	case Qaudio:		amode = Awrite;		if((omode&7) == OREAD)			amode = Aread;		aqlock(&audio);		if(waserror()){			aqunlock(&audio);			nexterror();		}		if(audio.amode != Aclosed)			error(Einuse);		audiodevopen();		audio.amode = amode;		poperror();		aqunlock(&audio);		break;	}	c = devopen(c, omode, audiodir, nelem(audiodir), devgen);	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0; 	return c;} static voidaudioclose(Chan *c){	switch((ulong)c->qid.path) {	default:		error(Eperm);		break; 	case Qdir:	case Qvolume:		break; 	case Qaudio:		if(c->flag & COPEN) {			aqlock(&audio);			audiodevclose();			audio.amode = Aclosed;			aqunlock(&audio);		}		break;	}} static longaudioread(Chan *c, void *v, long n, vlong off){	int liv, riv, lov, rov;	long m;	char buf[300];	int j;	ulong offset = off;	char *a; 	a = v;	switch((ulong)c->qid.path) {	default:		error(Eperm);		break; 	case Qdir:		return devdirread(c, a, n, audiodir, nelem(audiodir), devgen); 	case Qaudio:		if(audio.amode != Aread)			error(Emode);		aqlock(&audio);		if(waserror()){			aqunlock(&audio);			nexterror();		}		n = audiodevread(v, n);		poperror();		aqunlock(&audio);		break; 	case Qvolume:		j = 0;		buf[0] = 0;		for(m=0; volumes[m].name; m++){			audiodevgetvol(m, &lov, &rov);			liv = lov;			riv = rov;			j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);			if((volumes[m].flag & Fmono) || (liv==riv && lov==rov)){				if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)					j += snprint(buf+j, sizeof(buf)-j, " %d", liv);				else{					if(volumes[m].flag & Fin)						j += snprint(buf+j, sizeof(buf)-j,							" in %d", liv);					if(volumes[m].flag & Fout)						j += snprint(buf+j, sizeof(buf)-j,							" out %d", lov);				}			}else{				if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&				    liv==lov && riv==rov)					j += snprint(buf+j, sizeof(buf)-j,						" left %d right %d",						liv, riv);				else{					if(volumes[m].flag & Fin)						j += snprint(buf+j, sizeof(buf)-j,							" in left %d right %d",							liv, riv);					if(volumes[m].flag & Fout)						j += snprint(buf+j, sizeof(buf)-j,							" out left %d right %d",							lov, rov);				}			}			j += snprint(buf+j, sizeof(buf)-j, "\n");		}		return readstr(offset, a, n, buf);	}	return n;} static longaudiowrite(Chan *c, void *vp, long n, vlong off){	long m;	int i, v, left, right, in, out;	Cmdbuf *cb; 	USED(off);	switch((ulong)c->qid.path) {	default:		error(Eperm);		break; 	case Qvolume:		v = Vaudio;		left = 1;		right = 1;		in = 1;		out = 1;		cb = parsecmd(vp, n);		if(waserror()){			free(cb);			nexterror();		} 		for(i = 0; i < cb->nf; i++){			/*			 * a number is volume			 */			if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {				m = strtoul(cb->f[i], 0, 10);				USED(in);				if(!out)					goto cont0;				if(left && right)					audiodevsetvol(v, m, m);				else if(left)					audiodevsetvol(v, m, -1);				else if(right)					audiodevsetvol(v, -1, m);				goto cont0;			} 			for(m=0; volumes[m].name; m++) {				if(strcmp(cb->f[i], volumes[m].name) == 0) {					v = m;					in = 1;					out = 1;					left = 1;					right = 1;					goto cont0;				}			} 			if(strcmp(cb->f[i], "reset") == 0) {				resetlevel();				goto cont0;			}			if(strcmp(cb->f[i], "in") == 0) {				in = 1;				out = 0;				goto cont0;			}			if(strcmp(cb->f[i], "out") == 0) {				in = 0;				out = 1;				goto cont0;			}			if(strcmp(cb->f[i], "left") == 0) {				left = 1;				right = 0;				goto cont0;			}			if(strcmp(cb->f[i], "right") == 0) {				left = 0;				right = 1;				goto cont0;			}			error(Evolume);			break;		cont0:;		}		free(cb);		poperror();		break; 	case Qaudio:		if(audio.amode != Awrite)			error(Emode);		aqlock(&audio);		if(waserror()){			aqunlock(&audio);			nexterror();		}		n = audiodevwrite(vp, n);		poperror();		aqunlock(&audio);		break;	}	return n;} voidaudioswab(uchar *a, uint n){	ulong *p, *ep, b; 	p = (ulong*)a;	ep = p + (n>>2);	while(p < ep) {		b = *p;		b = (b>>24) | (b<<24) |			((b&0xff0000) >> 8) |			((b&0x00ff00) << 8);		*p++ = b;	}} Dev audiodevtab = {	'A',	"audio", 	devreset,	audioinit,	devshutdown,	audioattach,	audiowalk,	audiostat,	audioopen,	devcreate,	audioclose,	audioread,	devbread,	audiowrite,	devbwrite,	devremove,	devwstat,};