From 37ef30916cf30b47f92cf8f815caa23424263a5a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 8 Mar 2006 04:24:23 +0000 Subject: [PATCH] add audio --- Make.config | 1 + Make.unix | 2 + kern/Makefile | 2 + kern/devaudio-none.c | 35 ++++ kern/devaudio-unix.c | 182 +++++++++++++++++++++ kern/devaudio.c | 372 +++++++++++++++++++++++++++++++++++++++++++ kern/devtab.c | 2 + main.c | 1 + 8 files changed, 597 insertions(+) create mode 100644 kern/devaudio-none.c create mode 100644 kern/devaudio-unix.c create mode 100644 kern/devaudio.c diff --git a/Make.config b/Make.config index 2bd683e..850c1d7 100644 --- a/Make.config +++ b/Make.config @@ -1 +1,2 @@ +AUDIO=none include $(ROOT)/Make.$(CONF) diff --git a/Make.unix b/Make.unix index c5cecaa..eaec93d 100644 --- a/Make.unix +++ b/Make.unix @@ -13,6 +13,8 @@ GUI=x11 LDADD=-L$(X11)/lib -lX11 -ggdb LDFLAGS=$(PTHREAD) TARG=drawterm +# AUDIO=none +AUDIO=unix all: default diff --git a/kern/Makefile b/kern/Makefile index 73fe2a3..a506a24 100644 --- a/kern/Makefile +++ b/kern/Makefile @@ -8,6 +8,8 @@ OFILES=\ chan.$O\ data.$O\ dev.$O\ + devaudio.$O\ + devaudio-$(AUDIO).$O\ devcons.$O\ devdraw.$O\ devfs-$(OS).$O\ diff --git a/kern/devaudio-none.c b/kern/devaudio-none.c new file mode 100644 index 0000000..72709f5 --- /dev/null +++ b/kern/devaudio-none.c @@ -0,0 +1,35 @@ +/* + * Linux and BSD + */ +#include "u.h" +#include "lib.h" +#include "dat.h" +#include "fns.h" +#include "error.h" +#include "devaudio.h" + +/* maybe this should return -1 instead of sysfatal */ +void +audiodevopen(void) +{ + error("no audio support"); +} + +void +audiodevclose(void) +{ + error("no audio support"); +} + +void +audiodevsetvol(int what, int left, int right) +{ + error("no audio support"); +} + +void +audiodevgetvol(int what, int *left, int *right) +{ + error("no audio support"); +} + diff --git a/kern/devaudio-unix.c b/kern/devaudio-unix.c new file mode 100644 index 0000000..12e1b12 --- /dev/null +++ b/kern/devaudio-unix.c @@ -0,0 +1,182 @@ +/* + * Linux and BSD + */ +#include +#ifdef __linux__ +#include +#else +#include +#endif +#include "u.h" +#include "lib.h" +#include "dat.h" +#include "fns.h" +#include "error.h" +#include "devaudio.h" + +enum +{ + Channels = 2, + Rate = 44100, + Bits = 16, + Bigendian = 1, +}; + +static int afd = -1; +static int cfd= -1; +static int speed; + +/* maybe this should return -1 instead of sysfatal */ +void +audiodevopen(void) +{ + int t; + ulong ul; + + afd = -1; + cfd = -1; + if((afd = open("/dev/dsp", OWRITE)) < 0) + goto err; + if((cfd = open("/dev/mixer", ORDWR)) < 0) + goto err; + + t = Bits; + if(ioctl(afd, SNDCTL_DSP_SAMPLESIZE, &t) < 0) + goto err; + + t = Channels-1; + if(ioctl(afd, SNDCTL_DSP_STEREO, &t) < 0) + goto err; + + speed = Rate; + ul = Rate; + if(ioctl(afd, SNDCTL_DSP_SPEED, &ul) < 0) + goto err; + + return; + +err: + if(afd >= 0) + close(afd); + afd = -1; + oserror(); +} + +void +audiodevclose(void) +{ + close(afd); + close(cfd); + afd = -1; + cfd = -1; +} + +static struct { + int id9; + int id; +} names[] = { + Vaudio, SOUND_MIXER_VOLUME, + Vbass, SOUND_MIXER_BASS, + Vtreb, SOUND_MIXER_TREBLE, + Vline, SOUND_MIXER_LINE, + Vpcm, SOUND_MIXER_PCM, + Vsynth, SOUND_MIXER_SYNTH, + Vcd, SOUND_MIXER_CD, + Vmic, SOUND_MIXER_MIC, +// "record", SOUND_MIXER_RECLEV, +// "mix", SOUND_MIXER_IMIX, +// "pcm2", SOUND_MIXER_ALTPCM, + Vspeaker, SOUND_MIXER_SPEAKER +// "line1", SOUND_MIXER_LINE1, +// "line2", SOUND_MIXER_LINE2, +// "line3", SOUND_MIXER_LINE3, +// "digital1", SOUND_MIXER_DIGITAL1, +// "digital2", SOUND_MIXER_DIGITAL2, +// "digital3", SOUND_MIXER_DIGITAL3, +// "phonein", SOUND_MIXER_PHONEIN, +// "phoneout", SOUND_MIXER_PHONEOUT, +// "radio", SOUND_MIXER_RADIO, +// "video", SOUND_MIXER_VIDEO, +// "monitor", SOUND_MIXER_MONITOR, +// "igain", SOUND_MIXER_IGAIN, +// "ogain", SOUND_MIXER_OGAIN, +}; + +static int +lookname(int id9) +{ + int i; + + for(i=0; i>8)&0xFF; +} + +int +audiodevwrite(void *v, int n) +{ + int m, tot; + + for(tot=0; totlk) +#define aqunlock(a) qunlock(&(a)->lk) + +static struct +{ + char* name; + int flag; + int ilval; /* initial values */ + int irval; +} volumes[] = +{ +[Vaudio] "audio", Fout, 50, 50, +[Vsynth] "synth", Fin|Fout, 0, 0, +[Vcd] "cd", Fin|Fout, 0, 0, +[Vline] "line", Fin|Fout, 0, 0, +[Vmic] "mic", Fin|Fout|Fmono, 0, 0, +[Vspeaker] "speaker", Fout|Fmono, 0, 0, + +[Vtreb] "treb", Fout, 50, 50, +[Vbass] "bass", Fout, 50, 50, + +[Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed, + 0 +}; + +static char Emode[] = "illegal open mode"; +static char Evolume[] = "illegal volume specifier"; + +static void +resetlevel(void) +{ + int i; + + for(i=0; volumes[i].name; i++) + audiodevsetvol(i, volumes[i].ilval, volumes[i].irval); +} + +static void +audioinit(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 int +audiostat(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 void +audioclose(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 long +audioread(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 long +audiowrite(Chan *c, void *vp, long n, vlong off) +{ + long m; + int i, v, left, right, in, out; + Cmdbuf *cb; + char *a; + + USED(off); + a = vp; + 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); + 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; +} + +void +audioswab(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, +}; diff --git a/kern/devtab.c b/kern/devtab.c index d4efefe..181041c 100644 --- a/kern/devtab.c +++ b/kern/devtab.c @@ -14,6 +14,7 @@ extern Dev ipdevtab; extern Dev fsdevtab; extern Dev mntdevtab; extern Dev lfddevtab; +extern Dev audiodevtab; Dev *devtab[] = { &rootdevtab, @@ -26,6 +27,7 @@ Dev *devtab[] = { &fsdevtab, &mntdevtab, &lfddevtab, + &audiodevtab, 0 }; diff --git a/main.c b/main.c index 091a133..16e9ece 100644 --- a/main.c +++ b/main.c @@ -56,6 +56,7 @@ main(int argc, char **argv) panic("bind #I: %r"); if(bind("#U", "/", MAFTER) < 0) panic("bind #U: %r"); + bind("#A", "/dev", MAFTER); if(open("/dev/cons", OREAD) != 0) panic("open0: %r");