ref: d0a1ce234992b233df513abe9c2eb84d95b9a33e
dir: /pplay.c/
#include <u.h> #include <libc.h> #include <thread.h> #include <draw.h> #include <mouse.h> #include <keyboard.h> #include "dat.h" #include "fns.h" int ifd; uchar *pcmbuf; vlong filesz, nsamp; int file, stereo, zoom = 1; vlong seekp, T, loops, loope; static Keyboardctl *kc; static Mousectl *mc; static QLock lck; static int pause; static int cat; void * emalloc(ulong n) { void *p; if((p = mallocz(n, 1)) == nil) sysfatal("emalloc: %r"); setmalloctag(p, getcallerpc(&n)); return p; } static void athread(void *) { int n, fd; uchar *p; if((fd = cat ? 1 : open("/dev/audio", OWRITE)) < 0) sysfatal("open: %r"); p = pcmbuf; for(;;){ qlock(&lck); n = seekp + Nchunk >= loope ? loope - seekp : Nchunk; if(!file) p = pcmbuf + seekp; else if(read(ifd, pcmbuf, n) != n) fprint(2, "read: %r\n"); if(write(fd, p, n) != n){ fprint(2, "athread: %r\n"); break; } seekp += n; if(seekp >= loope) setpos(loops); update(); qunlock(&lck); yield(); } close(fd); } static char * prompt(void) { int n; static char buf[256]; memset(buf, 0, sizeof buf); if(!pause) qlock(&lck); n = enter("path:", buf, sizeof(buf)-UTFmax, mc, kc, nil); if(!pause) qunlock(&lck); if(n < 0) return nil; return buf; } static void reallocbuf(ulong n) { if((pcmbuf = realloc(pcmbuf, n)) == nil) sysfatal("realloc: %r"); } static void initbuf(int fd) { int n, sz; vlong ofs; Dir *d; reallocbuf(filesz += Nreadsz); ifd = fd; if(file){ if((d = dirfstat(fd)) == nil) sysfatal("dirfstat: %r"); filesz = d->length; nsamp = filesz / 4; free(d); return; } if((sz = iounit(fd)) == 0) sz = 8192; ofs = 0; while((n = read(fd, pcmbuf+ofs, sz)) > 0){ ofs += n; if(ofs + sz >= filesz) reallocbuf(filesz += Nreadsz); } if(n < 0) sysfatal("read: %r"); filesz = ofs; reallocbuf(filesz); nsamp = filesz / 4; close(fd); } static void usage(void) { fprint(2, "usage: %s [-cfs] [pcm]\n", argv0); threadexits("usage"); } void threadmain(int argc, char **argv) { int fd; char *p; Mouse mo; Rune r; ARGBEGIN{ case 'c': cat = 1; break; case 'f': file = 1; break; case 's': stereo = 1; break; default: usage(); }ARGEND if((fd = *argv != nil ? open(*argv, OREAD) : 0) < 0) sysfatal("open: %r"); initbuf(fd); initdrw(); if((kc = initkeyboard(nil)) == nil) sysfatal("initkeyboard: %r"); if((mc = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r"); Alt a[] = { {mc->resizec, nil, CHANRCV}, {mc->c, &mc->Mouse, CHANRCV}, {kc->c, &r, CHANRCV}, {nil, nil, CHANEND} }; if(threadcreate(athread, nil, mainstacksize) < 0) sysfatal("threadcreate: %r"); for(;;){ switch(alt(a)){ case 0: if(getwindow(display, Refnone) < 0) sysfatal("resize failed: %r"); mo = mc->Mouse; redraw(); break; case 1: switch(mc->buttons){ case 1: setofs(mc->xy.x - screen->r.min.x); break; case 2: setloop(mc->xy.x - screen->r.min.x); break; case 4: setpan(mo.xy.x - mc->xy.x); break; case 8: setzoom(1, 1); break; case 16: setzoom(-1, 1); break; } mo = mc->Mouse; break; case 2: switch(r){ case ' ': ((pause ^= 1) ? qlock : qunlock)(&lck); break; case 'b': setpos(loops); break; case 'r': loops = 0; loope = filesz; update(); break; case Kdel: case 'q': threadexitsall(nil); case 'z': setzoom(-zoom + 1, 0); break; case '-': setzoom(-1, 0); break; case '=': setzoom(1, 0); break; case '_': setzoom(-1, 1); break; case '+': setzoom(1, 1); break; case 'w': if((p = prompt()) != nil) writepcm(p); break; } break; } } }