2 #include "../port/lib.h"
7 #include "../port/error.h"
8 #include "../port/audioif.h"
10 typedef struct Audioprobe Audioprobe;
11 typedef struct Audiochan Audiochan;
38 static Dirtab audiodir[] = {
39 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
40 "audio", {Qaudio}, 0, 0666,
41 "audioctl", {Qaudioctl}, 0, 0222,
42 "audiostat", {Qaudiostat}, 0, 0444,
43 "volume", {Qvolume}, 0, 0666,
47 static int naudioprobes;
48 static Audioprobe audioprobes[16];
49 static Audio *audiodevs;
51 static char Evolume[] = "illegal volume specifier";
52 static char Ebusy[] = "device is busy";
55 addaudiocard(char *name, int (*probefn)(Audio *))
59 if(naudioprobes >= nelem(audioprobes))
62 probe = &audioprobes[naudioprobes++];
64 probe->probe = probefn;
75 *pp = malloc(sizeof(Audio));
77 for(i=0; i<naudioprobes; i++){
78 probe = &audioprobes[i];
82 print("audio: no memory\n");
85 memset(*pp, 0, sizeof(Audio));
86 (*pp)->ctlrno = ctlrno;
87 (*pp)->name = probe->name;
93 *pp = malloc(sizeof(Audio));
102 audioclone(Chan *c, Audio *adev)
106 ac = malloc(sizeof(Audiochan));
121 audioattach(char *spec)
123 static int attached = 0;
129 if(spec != nil && *spec != '\0')
130 i = strtol(spec, 0, 10);
133 for(adev = audiodevs; adev; adev = adev->next)
134 if(adev->ctlrno == i)
139 c = devattach('A', spec);
142 if((ac = audioclone(c, adev)) == nil)
146 if((attached & i) == 0){
147 static char *settings[] = {
149 "delay 1764", /* 40 ms */
157 for(i=0; i<nelem(settings) && adev->volwrite; i++){
158 strcpy(ac->buf, settings[i]);
160 adev->volwrite(adev, ac->buf, strlen(ac->buf), 0);
170 audioopen(Chan *c, int omode)
178 if(c->qid.path == Qaudio){
179 mode = openmode(omode);
180 if(mode == OWRITE || mode == ORDWR)
181 if(incref(&adev->audioopenw) != 1){
182 decref(&adev->audioopenw);
185 if(mode == OREAD || mode == ORDWR)
186 if(incref(&adev->audioopenr) != 1){
187 decref(&adev->audioopenr);
189 decref(&adev->audioopenw);
193 return devopen(c, omode, audiodir, nelem(audiodir), devgen);
197 audioread(Chan *c, void *a, long n, vlong off)
201 long (*fn)(Audio *, void *, long, vlong);
207 switch((ulong)c->qid.path){
209 audiodir[Qaudio].length = adev->buffered ? adev->buffered(adev) : 0;
210 return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
229 switch((ulong)c->qid.path){
232 /* generate the text on first read */
233 if(ac->data == nil || off == 0){
237 l = fn(adev, ac->buf, sizeof(ac->buf)-1, 0);
243 /* then serve all requests from buffer */
244 n = readstr(off, a, n, ac->data);
248 n = fn(adev, a, n, off);
256 audiowrite(Chan *c, void *a, long n, vlong off)
260 long (*fn)(Audio *, void *, long, vlong);
266 switch((ulong)c->qid.path){
285 switch((ulong)c->qid.path){
288 if(n >= sizeof(ac->buf))
291 /* copy data to audiochan buffer so it can be modified */
293 memmove(ac->buf, a, n);
298 n = fn(adev, a, n, off);
312 if((c->qid.path == Qaudio) && (c->flag & COPEN)){
315 adev->close(adev, c->mode);
319 if(c->mode == OWRITE || c->mode == ORDWR)
320 decref(&adev->audioopenw);
321 if(c->mode == OREAD || c->mode == ORDWR)
322 decref(&adev->audioopenr);
332 audiowalk(Chan *c, Chan *nc, char **name, int nname)
340 wq = devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
342 if(audioclone(wq->clone, adev) == nil){
351 audiostat(Chan *c, uchar *dp, int n)
358 if((ulong)c->qid.path == Qaudio)
359 audiodir[Qaudio].length = adev->buffered ? adev->buffered(adev) : 0;
360 return devstat(c, dp, n, audiodir, nelem(audiodir), devgen);
364 * audioread() made sure the buffer is big enougth so a full volume
365 * table can be serialized in one pass.
368 genaudiovolread(Audio *adev, void *a, long n, vlong,
369 Volume *vol, int (*volget)(Audio *, int, int *), ulong caps)
376 for(i = 0; vol[i].name != 0; ++i){
377 if(vol[i].cap && (vol[i].cap & caps) == 0)
381 if((*volget)(adev, i, v) != 0)
383 if(vol[i].type == Absolute)
384 p += snprint(p, e - p, "%s %d\n", vol[i].name, v[0]);
386 r = abs(vol[i].range);
400 p += snprint(p, e - p, "%s %d\n", vol[i].name, v[0]);
403 p += snprint(p, e - p, "%s %d\n", vol[i].name, v[1]);
406 p += snprint(p, e - p, "%s %d %d\n", vol[i].name, v[0], v[1]);
416 * genaudiovolwrite modifies the buffer that gets passed to it. this
417 * is ok as long as it is called from inside Audio.volwrite() because
418 * audiowrite() copies the data to Audiochan.buf[] and inserts a
419 * terminating \0 byte before calling Audio.volwrite().
422 genaudiovolwrite(Audio *adev, void *a, long n, vlong,
423 Volume *vol, int (*volset)(Audio *, int, int *), ulong caps)
425 int ntok, i, j, r, v[2];
426 char *p, *e, *x, *tok[4];
432 if(x = strchr(p, '\n'))
436 ntok = tokenize(p, tok, 4);
444 for(i = 0; vol[i].name != 0; i++){
445 if(vol[i].cap && (vol[i].cap & caps) == 0)
447 if(cistrcmp(vol[i].name, tok[0]))
450 if((ntok>2) && (!cistrcmp(tok[1], "out") || !cistrcmp(tok[1], "in")))
451 memmove(tok+1, tok+2, --ntok);
456 v[0] = v[1] = atoi(tok[1]);
459 if(vol[i].type == Absolute)
460 (*volset)(adev, i, v);
462 r = abs(vol[i].range);
464 v[j] = (50+(v[j]*r))/100;
472 (*volset)(adev, i, v);
476 if(vol[i].name == nil)