add audio

This commit is contained in:
Russ Cox 2006-03-08 04:24:23 +00:00
parent b7aa0db730
commit 37ef30916c
8 changed files with 597 additions and 0 deletions

View File

@ -1 +1,2 @@
AUDIO=none
include $(ROOT)/Make.$(CONF)

View File

@ -13,6 +13,8 @@ GUI=x11
LDADD=-L$(X11)/lib -lX11 -ggdb
LDFLAGS=$(PTHREAD)
TARG=drawterm
# AUDIO=none
AUDIO=unix
all: default

View File

@ -8,6 +8,8 @@ OFILES=\
chan.$O\
data.$O\
dev.$O\
devaudio.$O\
devaudio-$(AUDIO).$O\
devcons.$O\
devdraw.$O\
devfs-$(OS).$O\

35
kern/devaudio-none.c Normal file
View File

@ -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");
}

182
kern/devaudio-unix.c Normal file
View File

@ -0,0 +1,182 @@
/*
* Linux and BSD
*/
#include <sys/ioctl.h>
#ifdef __linux__
#include <linux/soundcard.h>
#else
#include <sys/soundcard.h>
#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<nelem(names); i++)
if(names[i].id9 == id9)
return names[i].id;
return -1;
}
void
audiodevsetvol(int what, int left, int right)
{
int id;
ulong x;
int can, v;
if(cfd < 0)
error("audio device not open");
if(what == Vspeed){
x = left;
if(ioctl(afd, SNDCTL_DSP_SPEED, &x) < 0)
oserror();
speed = x;
return;
}
if((id = lookname(what)) < 0)
return;
if(ioctl(cfd, SOUND_MIXER_READ_DEVMASK, &can) < 0)
can = ~0;
if(!(can & (1<<id)))
return;
v = left | (right<<8);
if(ioctl(cfd, MIXER_WRITE(id), &v) < 0)
oserror();
}
void
audiodevgetvol(int what, int *left, int *right)
{
int id;
int can, v;
if(cfd < 0)
error("audio device not open");
if(what == Vspeed){
*left = *right = speed;
return;
}
if((id = lookname(what)) < 0)
return;
if(ioctl(cfd, SOUND_MIXER_READ_DEVMASK, &can) < 0)
can = ~0;
if(!(can & (1<<id)))
return;
if(ioctl(cfd, MIXER_READ(id), &v) < 0)
oserror();
*left = v&0xFF;
*right = (v>>8)&0xFF;
}
int
audiodevwrite(void *v, int n)
{
int m, tot;
for(tot=0; tot<n; tot+=m)
if((m = write(afd, (uchar*)v+tot, n-tot)) <= 0)
oserror();
return tot;
}
int
audiodevread(void *v, int n)
{
error("no reading");
}

372
kern/devaudio.c Normal file
View File

@ -0,0 +1,372 @@
#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 */
};
Dirtab
audiodir[] =
{
".", {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[] =
{
[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,
};

View File

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

1
main.c
View File

@ -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");