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);
181 if(mode == OREAD || mode == ORDWR)
182 decref(&adev->audioopenr);
185 if(mode == OREAD || mode == ORDWR)
186 if(incref(&adev->audioopenr) != 1)
190 if(mode == OWRITE || mode == ORDWR)
191 decref(&adev->audioopenw);
194 if(mode == OWRITE || mode == ORDWR)
195 if(incref(&adev->audioopenw) != 1)
198 c = devopen(c, omode, audiodir, nelem(audiodir), devgen);
203 return devopen(c, omode, audiodir, nelem(audiodir), devgen);
207 audioread(Chan *c, void *a, long n, vlong off)
211 long (*fn)(Audio *, void *, long, vlong);
217 switch((ulong)c->qid.path){
219 audiodir[Qaudio].length = adev->buffered ? adev->buffered(adev) : 0;
220 return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
239 switch((ulong)c->qid.path){
242 /* generate the text on first read */
243 if(ac->data == nil || off == 0){
247 l = fn(adev, ac->buf, sizeof(ac->buf)-1, 0);
253 /* then serve all requests from buffer */
254 n = readstr(off, a, n, ac->data);
258 n = fn(adev, a, n, off);
266 audiowrite(Chan *c, void *a, long n, vlong off)
270 long (*fn)(Audio *, void *, long, vlong);
276 switch((ulong)c->qid.path){
295 switch((ulong)c->qid.path){
298 if(n >= sizeof(ac->buf))
301 /* copy data to audiochan buffer so it can be modified */
303 memmove(ac->buf, a, n);
308 n = fn(adev, a, n, off);
322 if((c->qid.path == Qaudio) && (c->flag & COPEN)){
325 adev->close(adev, c->mode);
329 if(c->mode == OWRITE || c->mode == ORDWR)
330 decref(&adev->audioopenw);
331 if(c->mode == OREAD || c->mode == ORDWR)
332 decref(&adev->audioopenr);
342 audiowalk(Chan *c, Chan *nc, char **name, int nname)
350 wq = devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
352 if(audioclone(wq->clone, adev) == nil){
361 audiostat(Chan *c, uchar *dp, int n)
368 if((ulong)c->qid.path == Qaudio)
369 audiodir[Qaudio].length = adev->buffered ? adev->buffered(adev) : 0;
370 return devstat(c, dp, n, audiodir, nelem(audiodir), devgen);
374 * audioread() made sure the buffer is big enougth so a full volume
375 * table can be serialized in one pass.
378 genaudiovolread(Audio *adev, void *a, long n, vlong,
379 Volume *vol, int (*volget)(Audio *, int, int *), ulong caps)
386 for(i = 0; vol[i].name != 0; ++i){
387 if(vol[i].cap && (vol[i].cap & caps) == 0)
391 if((*volget)(adev, i, v) != 0)
393 if(vol[i].type == Absolute)
394 p += snprint(p, e - p, "%s %d\n", vol[i].name, v[0]);
396 r = abs(vol[i].range);
410 p += snprint(p, e - p, "%s %d\n", vol[i].name, v[0]);
413 p += snprint(p, e - p, "%s %d\n", vol[i].name, v[1]);
416 p += snprint(p, e - p, "%s %d %d\n", vol[i].name, v[0], v[1]);
426 * genaudiovolwrite modifies the buffer that gets passed to it. this
427 * is ok as long as it is called from inside Audio.volwrite() because
428 * audiowrite() copies the data to Audiochan.buf[] and inserts a
429 * terminating \0 byte before calling Audio.volwrite().
432 genaudiovolwrite(Audio *adev, void *a, long n, vlong,
433 Volume *vol, int (*volset)(Audio *, int, int *), ulong caps)
435 int ntok, i, j, r, v[2];
436 char *p, *e, *x, *tok[4];
442 if(x = strchr(p, '\n'))
446 ntok = tokenize(p, tok, 4);
454 for(i = 0; vol[i].name != 0; i++){
455 if(vol[i].cap && (vol[i].cap & caps) == 0)
457 if(cistrcmp(vol[i].name, tok[0]))
460 if((ntok>2) && (!cistrcmp(tok[1], "out") || !cistrcmp(tok[1], "in")))
461 memmove(tok+1, tok+2, --ntok);
466 v[0] = v[1] = atoi(tok[1]);
469 if(vol[i].type == Absolute)
470 (*volset)(adev, i, v);
472 r = abs(vol[i].range);
474 v[j] = (50+(v[j]*r))/100;
482 (*volset)(adev, i, v);
486 if(vol[i].name == nil)