devaudio.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) 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 };