vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

devaudio.c (6481B)


      1 #include	"u.h"
      2 #include	"lib.h"
      3 #include	"mem.h"
      4 #include	"dat.h"
      5 #include	"fns.h"
      6 #include	"error.h"
      7 #include	"devaudio.h"
      8 
      9 enum
     10 {
     11 	Qdir		= 0,
     12 	Qaudio,
     13 	Qvolume,
     14 
     15 	Aclosed		= 0,
     16 	Aread,
     17 	Awrite,
     18 
     19 	Speed		= 44100,
     20 	Ncmd		= 50,		/* max volume command words */
     21 };
     22 
     23 Dirtab
     24 audiodir[] =
     25 {
     26 	".",	{Qdir, 0, QTDIR},		0,	DMDIR|0555,
     27 	"audio",	{Qaudio},		0,	0666,
     28 	"volume",	{Qvolume},		0,	0666,
     29 };
     30 
     31 static	struct
     32 {
     33 	QLock	lk;
     34 	Rendez	vous;
     35 	int	amode;		/* Aclosed/Aread/Awrite for /audio */
     36 } audio[MaxAudio];
     37 
     38 #define aqlock(a) qlock(&(a)->lk)
     39 #define aqunlock(a) qunlock(&(a)->lk)
     40 
     41 static	struct
     42 {
     43 	char*	name;
     44 	int	flag;
     45 	int	ilval;		/* initial values */
     46 	int	irval;
     47 } volumes[] =
     48 {
     49 	"audio",	Fout, 		50,	50,
     50 	"pcm",	Fin|Fout,	0,	0,
     51 	"synth",	Fin|Fout,	0,	0,
     52 	"cd",		Fin|Fout,	0,	0,
     53 	"line",	Fin|Fout,	0,	0,
     54 	"mic",	Fin|Fout|Fmono,	0,	0,
     55 	"speaker",	Fout|Fmono,	0,	0,
     56 
     57 	"treb",		Fout, 		50,	50,
     58 	"bass",		Fout, 		50,	50,
     59 
     60 	"speed",	Fin|Fout|Fmono,	Speed,	Speed,
     61 	0
     62 };
     63 
     64 static	char	Emode[]		= "illegal open mode";
     65 static	char	Evolume[]	= "illegal volume specifier";
     66 
     67 static	void
     68 resetlevel(int dev)
     69 {
     70 	int i;
     71 
     72 	for(i=0; volumes[i].name; i++)
     73 		audiodevsetvol(dev, i, volumes[i].ilval, volumes[i].irval);
     74 }
     75 
     76 static void
     77 audioinit(void)
     78 {
     79 }
     80 
     81 static Chan*
     82 audioattach(char *spec)
     83 {
     84 	Chan *c;
     85 	int n;
     86 	
     87 	n = atoi(spec);
     88 	if(n < 0 || n >= nelem(audio))
     89 		error(Ebadspec);
     90 	
     91 	c = devattach('A', spec);
     92 	c->dev = n;
     93 	return c;
     94 }
     95 
     96 static Walkqid*
     97 audiowalk(Chan *c, Chan *nc, char **name, int nname)
     98 {
     99 	return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
    100 }
    101 
    102 static int
    103 audiostat(Chan *c, uchar *db, int n)
    104 {
    105 	return devstat(c, db, n, audiodir, nelem(audiodir), devgen);
    106 }
    107 
    108 static Chan*
    109 audioopen(Chan *c, int omode)
    110 {
    111 	int amode;
    112 
    113 	switch((ulong)c->qid.path) {
    114 	default:
    115 		error(Eperm);
    116 		break;
    117 
    118 	case Qvolume:
    119 	case Qdir:
    120 		break;
    121 
    122 	case Qaudio:
    123 		amode = Awrite;
    124 		if((omode&7) == OREAD)
    125 			amode = Aread;
    126 		aqlock(&audio[c->dev]);
    127 		if(waserror()){
    128 			aqunlock(&audio[c->dev]);
    129 			nexterror();
    130 		}
    131 		if(audio[c->dev].amode != Aclosed)
    132 			error(Einuse);
    133 		audiodevopen(c->dev);
    134 		audio[c->dev].amode = amode;
    135 		poperror();
    136 		aqunlock(&audio[c->dev]);
    137 		break;
    138 	}
    139 	c = devopen(c, omode, audiodir, nelem(audiodir), devgen);
    140 	c->mode = openmode(omode);
    141 	c->flag |= COPEN;
    142 	c->offset = 0;
    143 
    144 	return c;
    145 }
    146 
    147 static void
    148 audioclose(Chan *c)
    149 {
    150 	switch((ulong)c->qid.path) {
    151 	default:
    152 		error(Eperm);
    153 		break;
    154 
    155 	case Qdir:
    156 	case Qvolume:
    157 		break;
    158 
    159 	case Qaudio:
    160 		if(c->flag & COPEN) {
    161 			aqlock(&audio[c->dev]);
    162 			audiodevclose(c->dev);
    163 			audio[c->dev].amode = Aclosed;
    164 			aqunlock(&audio[c->dev]);
    165 		}
    166 		break;
    167 	}
    168 }
    169 
    170 static long
    171 audioread(Chan *c, void *v, long n, vlong off)
    172 {
    173 	int liv, riv, lov, rov;
    174 	long m;
    175 	char buf[300];
    176 	int j;
    177 	ulong offset = off;
    178 	char *a;
    179 
    180 	a = v;
    181 	switch((ulong)c->qid.path) {
    182 	default:
    183 		error(Eperm);
    184 		break;
    185 
    186 	case Qdir:
    187 		return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
    188 
    189 	case Qaudio:
    190 		if(audio[c->dev].amode != Aread)
    191 			error(Emode);
    192 		aqlock(&audio[c->dev]);
    193 		if(waserror()){
    194 			aqunlock(&audio[c->dev]);
    195 			nexterror();
    196 		}
    197 		n = audiodevread(c->dev, v, n);
    198 		poperror();
    199 		aqunlock(&audio[c->dev]);
    200 		break;
    201 
    202 	case Qvolume:
    203 		j = 0;
    204 		buf[0] = 0;
    205 		for(m=0; volumes[m].name; m++){
    206 			if(waserror())
    207 				continue;
    208 			audiodevgetvol(c->dev, m, &lov, &rov);
    209 			poperror();
    210 			liv = lov;
    211 			riv = rov;
    212 			j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
    213 			if((volumes[m].flag & Fmono) || (liv==riv && lov==rov)){
    214 				if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
    215 					j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
    216 				else{
    217 					if(volumes[m].flag & Fin)
    218 						j += snprint(buf+j, sizeof(buf)-j,
    219 							" in %d", liv);
    220 					if(volumes[m].flag & Fout)
    221 						j += snprint(buf+j, sizeof(buf)-j,
    222 							" out %d", lov);
    223 				}
    224 			}else{
    225 				if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&
    226 				    liv==lov && riv==rov)
    227 					j += snprint(buf+j, sizeof(buf)-j,
    228 						" left %d right %d",
    229 						liv, riv);
    230 				else{
    231 					if(volumes[m].flag & Fin)
    232 						j += snprint(buf+j, sizeof(buf)-j,
    233 							" in left %d right %d",
    234 							liv, riv);
    235 					if(volumes[m].flag & Fout)
    236 						j += snprint(buf+j, sizeof(buf)-j,
    237 							" out left %d right %d",
    238 							lov, rov);
    239 				}
    240 			}
    241 			j += snprint(buf+j, sizeof(buf)-j, "\n");
    242 		}
    243 		return readstr(offset, a, n, buf);
    244 	}
    245 	return n;
    246 }
    247 
    248 static long
    249 audiowrite(Chan *c, void *vp, long n, vlong off)
    250 {
    251 	long m;
    252 	int i, v, left, right, in, out;
    253 	Cmdbuf *cb;
    254 	char *a;
    255 
    256 	USED(off);
    257 	a = vp;
    258 	switch((ulong)c->qid.path) {
    259 	default:
    260 		error(Eperm);
    261 		break;
    262 
    263 	case Qvolume:
    264 		v = Vaudio;
    265 		left = 1;
    266 		right = 1;
    267 		in = 1;
    268 		out = 1;
    269 		cb = parsecmd(vp, n);
    270 		if(waserror()){
    271 			free(cb);
    272 			nexterror();
    273 		}
    274 
    275 		for(i = 0; i < cb->nf; i++){
    276 			/*
    277 			 * a number is volume
    278 			 */
    279 			if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {
    280 				m = strtoul(cb->f[i], 0, 10);
    281 				if(!out)
    282 					goto cont0;
    283 				if(left && right)
    284 					audiodevsetvol(c->dev, v, m, m);
    285 				else if(left)
    286 					audiodevsetvol(c->dev, v, m, -1);
    287 				else if(right)
    288 					audiodevsetvol(c->dev, v, -1, m);
    289 				goto cont0;
    290 			}
    291 
    292 			for(m=0; volumes[m].name; m++) {
    293 				if(strcmp(cb->f[i], volumes[m].name) == 0) {
    294 					v = m;
    295 					in = 1;
    296 					out = 1;
    297 					left = 1;
    298 					right = 1;
    299 					goto cont0;
    300 				}
    301 			}
    302 
    303 			if(strcmp(cb->f[i], "reset") == 0) {
    304 				resetlevel(c->dev);
    305 				goto cont0;
    306 			}
    307 			if(strcmp(cb->f[i], "in") == 0) {
    308 				in = 1;
    309 				out = 0;
    310 				goto cont0;
    311 			}
    312 			if(strcmp(cb->f[i], "out") == 0) {
    313 				in = 0;
    314 				out = 1;
    315 				goto cont0;
    316 			}
    317 			if(strcmp(cb->f[i], "left") == 0) {
    318 				left = 1;
    319 				right = 0;
    320 				goto cont0;
    321 			}
    322 			if(strcmp(cb->f[i], "right") == 0) {
    323 				left = 0;
    324 				right = 1;
    325 				goto cont0;
    326 			}
    327 			error(Evolume);
    328 			break;
    329 		cont0:;
    330 		}
    331 		free(cb);
    332 		poperror();
    333 		break;
    334 
    335 	case Qaudio:
    336 		if(audio[c->dev].amode != Awrite)
    337 			error(Emode);
    338 		aqlock(&audio[c->dev]);
    339 		if(waserror()){
    340 			aqunlock(&audio[c->dev]);
    341 			nexterror();
    342 		}
    343 		n = audiodevwrite(c->dev, vp, n);
    344 		poperror();
    345 		aqunlock(&audio[c->dev]);
    346 		break;
    347 	}
    348 	return n;
    349 }
    350 
    351 void
    352 audioswab(uchar *a, uint n)
    353 {
    354 	uint32 *p, *ep, b;
    355 
    356 	p = (uint32*)a;
    357 	ep = p + (n>>2);
    358 	while(p < ep) {
    359 		b = *p;
    360 		b = (b>>24) | (b<<24) |
    361 			((b&0xff0000) >> 8) |
    362 			((b&0x00ff00) << 8);
    363 		*p++ = b;
    364 	}
    365 }
    366 
    367 Dev audiodevtab = {
    368 	'A',
    369 	"audio",
    370 
    371 	devreset,
    372 	audioinit,
    373 	devshutdown,
    374 	audioattach,
    375 	audiowalk,
    376 	audiostat,
    377 	audioopen,
    378 	devcreate,
    379 	audioclose,
    380 	audioread,
    381 	devbread,
    382 	audiowrite,
    383 	devbwrite,
    384 	devremove,
    385 	devwstat,
    386 };