shithub: zuke

Download patch

ref: cdd5704e4cf115186593e45491a64e2998ce5cb4
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Sun Jun 23 19:27:07 EDT 2013

first revision

--- /dev/null
+++ b/mkfile
@@ -1,0 +1,9 @@
+</$objtype/mkfile
+MAN=/sys/man/1
+
+TARG=\
+	zuke\
+
+BIN=/$objtype/bin/audio
+
+</sys/src/cmd/mkmany
--- /dev/null
+++ b/zuke.c
@@ -1,0 +1,364 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <event.h>
+#include <keyboard.h>
+#include <bio.h>
+#include <thread.h>
+
+static int plen;
+static struct {
+	char *file;
+	char *name;
+}*plist;
+
+static int pid, pcur, pcurplaying;
+static int scroll, scrollsz, pause;
+static Image *cola, *colb;
+static Font *f;
+static Channel ctl;
+static int audio;
+
+int mainstacksize = 32768;
+
+static void
+redraw(Image *screen, int new)
+{
+	Point p, sp;
+	int i;
+
+	sp.x = sp.y = 0;
+	if(new)
+		draw(screen, screen->r, cola, nil, ZP);
+
+	p.x = screen->r.min.x + 2;
+	p.y = screen->r.min.y + 2;
+	scrollsz = Dy(screen->r) / f->height - 1;
+
+	for(i = scroll; i < plen; i++){
+		if(p.y > screen->r.max.y)
+			break;
+		if(pcurplaying == i){
+			Point right, left;
+			left.y = right.y = p.y - 1;
+			left.x = p.x;
+			right.x = screen->r.max.x;
+			line(screen, left, right, 0, 0, 0, colb, sp);
+			left.y = right.y = p.y + f->height;
+			line(screen, left, right, 0, 0, 0, colb, sp);
+		}
+		if(pcur == i){
+			Rectangle sel;
+			sel = screen->r;
+			sel.min.y = p.y;
+			sel.max.y = p.y + f->height;
+			draw(screen, sel, colb, nil, ZP);
+			string(screen, p, cola, sp, f, plist[i].name);
+		}
+		else
+			string(screen, p, colb, sp, f, plist[i].name);
+		p.y += f->height;
+	}
+
+	flushimage(display, 1);
+}
+
+typedef struct Relayctx Relayctx;
+struct Relayctx {
+	int     in, out;
+	Channel *ev;
+};
+
+typedef struct Decctx Decctx;
+struct Decctx {
+	int     in, out;
+	Channel *quit, *wait;
+};
+
+static void
+relay(void *v)
+{
+	int n;
+	char *buf;
+	Ioproc *io;
+	Relayctx *ctx;
+
+	ctx = v;
+	io = ioproc();
+	buf = malloc(65536);
+	sendp(ctx->ev, nil);
+	while((n = ioread(io, ctx->in, buf, 65536)) > 0){
+		if(iowrite(io, ctx->out, buf, n) != n)
+			break;
+	}
+	free(buf);
+	closeioproc(io);
+	sendp(ctx->ev, nil);
+}
+
+typedef struct Playctx Playctx;
+struct Playctx {
+	Channel *quit;
+	Channel *wait;
+	int     p[4];
+};
+
+static void
+player(void *dec_)
+{
+	Decctx *dec;
+	static Relayctx rel[2];
+	Alt a[3];
+
+	dec = dec_;
+	threadsetname("player");
+
+	if(rel[0].ev == nil){
+		rel[0].ev = chancreate(sizeof(void*), 0);
+		rel[1].ev = chancreate(sizeof(void*), 0);
+	}
+
+	audio = open("/dev/audio", OWRITE);
+	pcurplaying = pcur;
+
+again:
+	rel[0].in = open(plist[pcurplaying].file, OREAD);
+	rel[0].out = dec->in;
+	rel[1].in = dec->out;
+	rel[1].out = audio;
+
+	if(audio < 0 || rel[0].in < 0){
+		close(audio);
+		close(rel[0].in);
+		fprint(2, "%r\n");
+		threadexits(nil);
+	}
+
+	threadcreate(relay, &rel[0], 4096); recvp(rel[0].ev);
+	threadcreate(relay, &rel[1], 4096); recvp(rel[1].ev);
+
+	memset(a, 0, sizeof(a));
+	a[0].op = a[1].op = CHANRCV;
+	a[0].c = dec->quit;
+	a[1].c = rel[0].ev;
+	a[2].op = CHANEND;
+	while(1){
+		int r;
+
+		r = alt(a);
+		close(rel[0].in);
+
+		if(r == 1){
+			if(++pcurplaying >= plen)
+				pcurplaying = 0;
+			redraw(screen, 1);
+			goto again;
+		}
+		else{
+			close(rel[1].in);
+			close(rel[0].out);
+			recvp(rel[0].ev);
+			recvp(rel[1].ev);
+			close(audio);
+			sendp(dec->wait, nil);
+			break;
+		}
+	}
+
+	threadexits(nil);
+}
+
+static void
+play(void)
+{
+	static Decctx ctx;
+	int p[4];
+
+	if(ctx.quit == nil){
+		ctx.quit = chancreate(sizeof(void*), 0);
+		ctx.wait = chancreate(sizeof(void*), 0);
+	}
+
+	if(pcur == pcurplaying)
+		return;
+	if(pid != 0){
+		sendp(ctx.quit, nil);
+		recvp(ctx.wait);
+	}
+	pid = 0;
+	pcurplaying = -1;
+
+	if(pcur < 0)
+		return;
+
+	if(ctx.quit == nil)
+		ctx.quit = chancreate(sizeof(void*), 0);
+
+	pipe(&p[0]);
+	pipe(&p[2]);
+	if((pid = rfork(RFFDG|RFREND|RFPROC)) == 0){
+		close(p[1]); dup(p[0], 0);
+		close(p[2]); dup(p[3], 1);
+		close(2); open("/dev/null", OWRITE);
+		execl("/bin/rc", "-c", "play", "-o", "/fd/1", "/fd/0", nil);
+	}
+	if(pid < 0)
+		sysfatal("%r");
+	close(p[0]);
+	close(p[3]);
+	ctx.in = p[1];
+	ctx.out = p[2];
+	pid = proccreate(player, &ctx, 4096);
+	pcurplaying = pcur;
+}
+
+static void
+readplist(void)
+{
+	Biobuf b;
+
+	Binit(&b, 0, OREAD);
+	for(plen = 0;; plen++){
+		char *s[2];
+		int n;
+
+		s[0] = Brdstr(&b, '\n', 1);
+		if(s[0] == nil)
+			break;
+		plist = realloc(plist, sizeof(*plist)*(plen+1));
+		n = getfields(s[0], s, 2, 1, "\t");
+		if(n < 1)
+			break;
+		plist[plen].file = plist[plen].name = s[0];
+		if(n > 1)
+			plist[plen].name = s[1];
+		else if((plist[plen].name = strrchr(s[0], '/')) != nil)
+			plist[plen].name++; 
+	}
+}
+
+static void
+usage(void)
+{
+	fprint(2, "usage: zuke [-b]\n");
+	exits("usage");
+}
+
+void
+eresized(int new)
+{
+	if(getwindow(display, Refnone) < 0)
+		sysfatal("can't reattach to window: %r");
+	redraw(screen, new);
+}
+
+void
+threadmain(int argc, char **argv)
+{
+	int inv;
+
+	inv = 0;
+	ARGBEGIN{
+	case 'b':
+		inv = 1;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	readplist();
+
+	if(plen < 1){
+		fprint(2, "empty playlist\n");
+		exits("empty");
+	}
+
+	if(initdraw(0, 0, "zuke") < 0)
+		sysfatal("initdraw failed");
+
+	f = display->defaultfont;
+	cola = inv ? display->black : display->white;
+	colb = inv ? display->white : display->black;
+	einit(Emouse | Ekeyboard);
+	srand(time(0));
+	pcurplaying = -1;
+
+	redraw(screen, 1);
+
+	for(;;){
+		int oldpcur, oldpcurplaying, key;
+		Event e;
+
+		oldpcurplaying = pcurplaying;
+		oldpcur = pcur;
+		key = event(&e);
+
+		if(key == Emouse){
+			if(e.mouse.buttons > 0){
+				pcur = scroll + (e.mouse.xy.y - screen->r.min.y)/f->height;
+				if(e.mouse.buttons == 4)
+					play();
+			}
+		}
+		else if(key == Ekeyboard){
+			if(e.kbdc == Kup)
+				pcur--;
+			else if(e.kbdc == Kpgup)
+				pcur -= scrollsz;
+			else if(e.kbdc == Kdown)
+				pcur++;
+			else if(e.kbdc == Kpgdown)
+				pcur += scrollsz;
+			else if(e.kbdc == Kend)
+				pcur = plen-1;
+			else if(e.kbdc == Khome)
+				pcur = 0;
+			else if(e.kbdc == 0x0a)
+				play();
+			else if(e.kbdc == 'q' || e.kbdc == Kesc)
+				break;
+			else if(e.kbdc == 'o')
+				pcur = pcurplaying;
+			else if(e.kbdc == '>' && pcurplaying >= 0){
+				pcur = pcurplaying;
+				if(++pcur >= plen)
+					pcur = 0;
+				play();
+			}
+			else if(e.kbdc == '<' && pcurplaying >= 0){
+				pcur = pcurplaying;
+				if(--pcur < 0)
+					pcur = plen-1;
+				play();
+			}
+			else if(e.kbdc == 's' && pid > 0){
+				pcur = -1;
+				play();
+			}
+		}
+
+		if(pcur != oldpcur || oldpcurplaying != pcurplaying){
+			if(pcur < 0)
+				pcur = 0;
+			else if(pcur >= plen)
+				pcur = plen - 1;
+
+			if(pcur < scroll)
+				scroll = pcur;
+			else if(pcur > scroll + scrollsz)
+				scroll = pcur - scrollsz;
+
+			if(scroll > plen - scrollsz)
+				scroll = plen - scrollsz;
+			else if(scroll < 0)
+				scroll = 0;
+
+			if(pcur != oldpcur || oldpcurplaying != pcurplaying)
+				redraw(screen, 1);
+		}
+	}
+
+	pcur = -1;
+	play();
+	threadexitsall(nil);
+}