ref: fd7be1f5cae97cba175519e97fa5b0b60b93ea70
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" enum{ Ndelay = 44100 / 25, Nchunk = Ndelay * 4, Nreadsz = 4*1024*1024, }; ulong nbuf; uchar *buf, *bufp, *bufe, *viewp, *viewe, *viewmax, *loops, *loope; int T; int stereo; int zoom = 1; static Keyboardctl *kc; static Mousectl *mc; static QLock lck; static int pause; static int cat; static void athread(void *) { int n, fd; if((fd = cat ? 1 : open("/dev/audio", OWRITE)) < 0) sysfatal("open: %r"); for(;;){ qlock(&lck); n = bufp + Nchunk >= loope ? loope - bufp : Nchunk; if(write(fd, bufp, n) != n) break; bufp += n; if(bufp >= loope) bufp = 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 setzoom(int n) { int m; m = zoom + n; if(m < 1 || m > nbuf / Dx(screen->r)) return; zoom = m; if(nbuf / zoom / Dx(screen->r) != T) redrawbg(); } static void setpan(int n) { n *= T * 4 * 16; if(zoom == 1 || viewp == buf && n < 0 || viewp == viewmax && n > 0) return; viewp += n; redrawbg(); } static void setloop(void) { int n; uchar *p; n = (mc->xy.x - screen->r.min.x) * T * 4; p = viewp + n; if(p < buf || p > bufe) return; if(p < bufp) loops = p; else loope = p; drawview(); } static void setpos(void) { int n; uchar *p; n = (mc->xy.x - screen->r.min.x) * T * 4; p = viewp + n; if(p < loops || p > loope - Nchunk) return; bufp = p; update(); } static void bufrealloc(ulong n) { int off; off = bufp - buf; if((buf = realloc(buf, n)) == nil) sysfatal("realloc: %r"); bufe = buf + n; bufp = buf + off; } static void initbuf(int fd) { int n, sz; bufrealloc(nbuf += Nreadsz); if((sz = iounit(fd)) == 0) sz = 8192; while((n = read(fd, bufp, sz)) > 0){ bufp += n; if(bufp + sz >= bufe) bufrealloc(nbuf += Nreadsz); } if(n < 0) sysfatal("read: %r"); bufrealloc(nbuf = bufp - buf); } static void usage(void) { fprint(2, "usage: %s [-cs] [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 's': stereo = 1; break; default: usage(); }ARGEND if((fd = *argv != nil ? open(*argv, OREAD) : 0) < 0) sysfatal("open: %r"); initbuf(fd); close(fd); nbuf /= 4; bufp = buf; viewp = buf; loops = buf; loope = bufe; initview(); 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"); redrawbg(); mo = mc->Mouse; break; case 1: switch(mc->buttons){ case 1: setpos(); break; case 2: setloop(); break; case 4: setpan(mo.xy.x - mc->xy.x); break; case 8: setzoom(1); break; case 16: setzoom(-1); break; } mo = mc->Mouse; break; case 2: switch(r){ case ' ': if(pause ^= 1) qlock(&lck); else qunlock(&lck); break; case 'b': bufp = loops; update(); break; case 'r': loops = buf; loope = bufe; drawview(); break; case Kdel: case 'q': threadexitsall(nil); case 'z': if(zoom == 1) break; zoom = 1; redrawbg(); break; case '-': setzoom(-1); break; case '=': case '+': setzoom(1); break; case 'w': if((p = prompt()) != nil) writepcm(p); break; } break; } } }