shithub: zuke

Download patch

ref: 951d3705a090855e9b8bd3278d1fa5ba2ac3771e
parent: 57ce0c691e141db6493ec4c683b55955e64d159b
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Wed Aug 12 10:44:50 EDT 2020

add seek bar

--- a/zuke.c
+++ b/zuke.c
@@ -20,13 +20,13 @@
 	Everror = 1,
 	Evready,
 
-	Bps = 44100*2*2, /* 44100KHz, stereo, s16 for a sample */
-	Seekbytes = Bps*10, /* 10 seconds */
-	Seekbytesfast = Bps*60, /* 1 minute */
+	Seek = 10, /* 10 seconds */
+	Seekfast = 60, /* a minute */
 
 	Scrollwidth = 14,
 	Scrollheight = 16,
 
+	Bps = 44100*2*2, /* 44100KHz, stereo, s16 for a sample */
 	Relbufsz = Bps/5, /* 0.2 second */
 };
 
@@ -35,7 +35,7 @@
 	Channel *ctl;
 	Channel *ev;
 	Channel *img;
-	vlong seekbytes;
+	double seek;
 	int pcur;
 };
 
@@ -49,7 +49,7 @@
 static int volume;
 static Player *playernext;
 static Player *playercurr;
-static u64int byteswritten;
+static vlong byteswritten;
 static int pcur, pcurplaying;
 static int scroll, scrollsz;
 static Font *f;
@@ -61,6 +61,7 @@
 static int mincolwidth[7];
 static char *cols = "AatD";
 static int *shuffle;
+static Rectangle seekbar;
 static char *covers[] = {"folder", "cover", "Cover", "scans/CD", "Scans/Front", "Covers/Front"};
 
 static char *menu3i[] = {
@@ -159,17 +160,20 @@
 	Image *col;
 	Point p, sp;
 	Rectangle sel, r;
-	int i, j, left, scrollcenter;
+	int i, j, left, right, scrollcenter;
 	char tmp[32];
 
 	lockdisplay(display);
+	scrollsz = (Dy(screen->r) - f->height - 4) / f->height - 1;
+	left = screen->r.min.x;
+	if(scrollsz < plnum) /* adjust for scrollbar */
+		left += Scrollwidth + 1;
+
 	if(full){
 		draw(screen, screen->r, colors[Dback].im, nil, ZP);
 
-		scrollsz = Dy(screen->r) / f->height - 1;
 		adjustcolumns();
-		left = screen->r.min.x;
-		if(scrollsz < plnum){ /* add a scrollbar */
+		if(scrollsz < plnum){ /* scrollbar */
 			p.x = sp.x = screen->r.min.x + Scrollwidth;
 			p.y = screen->r.min.y;
 			sp.y = screen->r.max.y;
@@ -185,8 +189,6 @@
 			r.min.y += scrollcenter + Scrollheight/4;
 			r.max.y = r.min.y + Scrollheight;
 			draw(screen, r, colors[Dfmed].im, nil, ZP);
-
-			left += Scrollwidth + 1;
 		}
 
 		p.x = sp.x = left;
@@ -259,10 +261,16 @@
 	}else
 		snprint(tmp, sizeof(tmp), "%s%d%%", shuffle != nil ? "∫ " : "", volume);
 	r = screen->r;
-	r.min.x = r.max.x - stringwidth(f, tmp) - 4;
+	right = r.max.x - stringwidth(f, tmp) - 4;
+	r.min.x = left;
 	r.min.y = r.max.y - f->height - 4;
+	if(pcurplaying < 0 || getmeta(pcurplaying)->duration == 0)
+		r.min.x = right;
 	draw(screen, r, colors[Dblow].im, nil, ZP);
-	string(screen, addpt(r.min, Pt(2, 2)), colors[Dfhigh].im, sp, f, tmp);
+	r.max.x = right;
+	p = addpt(Pt(right, r.min.y), Pt(2, 2));
+	string(screen, p, colors[Dfhigh].im, sp, f, tmp);
+	sel = r;
 
 	if(cover != nil && full){
 		r.max.x = r.min.x;
@@ -276,6 +284,17 @@
 		draw(screen, insetrect(r, 4), cover, nil, ZP);
 	}
 
+	/* seek bar */
+	seekbar = ZR;
+	if(pcurplaying >= 0 && getmeta(pcurplaying)->duration != 0){
+		r = insetrect(sel, 4);
+		draw(screen, r, colors[Dfmed].im, nil, ZP);
+		r = insetrect(r, 1);
+		seekbar = r;
+		r.max.x = r.min.x + Dx(r) * 1000.0*(double)byteswritten/Bps / (double)getmeta(pcurplaying)->duration;
+		draw(screen, r, colors[Dbinv].im, nil, ZP);
+	}
+
 	flushimage(display, 1);
 	unlockdisplay(display);
 }
@@ -424,7 +443,7 @@
 static void
 playerthread(void *player_)
 {
-	char *buf, cmd[256], *fmt;
+	char *buf, cmd[64], seekpos[12], *fmt;
 	Player *player;
 	Ioproc *io;
 	Image *thiscover;
@@ -431,13 +450,13 @@
 	ulong c;
 	int p[2], fd, pid, noinit, trycoverload;
 	long n, r;
-	vlong bytesfrom, bf;
+	vlong boffset, boffsetlast;
 	Meta *cur;
 
 	threadsetname("player");
 	player = player_;
 	noinit = 0;
-	bytesfrom = 0;
+	boffset = 0;
 	buf = nil;
 	trycoverload = 1;
 	io = nil;
@@ -463,7 +482,8 @@
 		close(p[1]);
 		if(*fmt){
 			snprint(cmd, sizeof(cmd), "/bin/audio/%sdec", fmt);
-			execl(cmd, cmd, nil);
+			snprint(seekpos, sizeof(seekpos), "%g", (double)boffset/Bps);
+			execl(cmd, cmd, "-s", seekpos, nil);
 		}else{
 			execl("/bin/play", "play", "-o", "/fd/1", cur->path, nil);
 		}
@@ -475,7 +495,6 @@
 		close(fd);
 	close(p[0]);
 
-	byteswritten = 0;
 	c = 0;
 	if(!noinit){
 		sendul(player->ev, Evready);
@@ -488,20 +507,17 @@
 			goto freeplayer;
 		if(n < 1)
 			goto next;
-		byteswritten = iowrite(io, audio, buf, n);
-		bytesfrom = 0;
+		boffset = iowrite(io, audio, buf, n);
 		noinit = 1;
 	}
 
+	byteswritten = boffsetlast = boffset;
 	pcurplaying = player->pcur;
-	if(c != Cseekrel || player->seekbytes >= 0)
+	if(c != Cseekrel)
 		redraw(1);
 
 	while(1){
-		n = Relbufsz;
-		if(bytesfrom > byteswritten && n > bytesfrom-byteswritten)
-			n = bytesfrom-byteswritten;
-		n = ioreadn(io, p[1], buf, n);
+		n = ioreadn(io, p[1], buf, Relbufsz);
 		if(n <= 0)
 			break;
 
@@ -512,7 +528,6 @@
 			redraw(1);
 			player->img = nil;
 		}
-		bf = bytesfrom != 0 ? bytesfrom : byteswritten;
 		r = nbrecv(player->ctl, &c);
 		if(r < 0){
 			goto stop;
@@ -521,36 +536,33 @@
 				if(recv(player->ctl, &c) < 0 || c == Cstop)
 					goto stop;
 			}else if(c == Cseekrel){
-				bytesfrom = MAX(0, bf + player->seekbytes);
-				if(player->seekbytes < 0){
-					n = 0; /* not an error */
-					break;
-				}
-			}else{ /* Cstop */
+				boffset = MAX(0, boffset + player->seek*Bps);
+				n = 0;
+				break;
+			}else if(c == Cstop){
 				goto stop;
 			}
 		}
 
-		if(bytesfrom <= byteswritten){
-			if(bytesfrom == byteswritten)
-				bytesfrom = 0;
-			if(iowrite(io, audio, buf, n) != n)
-				fprint(2, "player: %r\n");
-			if(trycoverload && byteswritten >= Bps){
-				player->img = chancreate(sizeof(Image*), 0);
-				proccreate(coverload, player, 4096);
-				trycoverload = 0;
-			}
+		boffset += n;
+		byteswritten = boffset;
+		if(iowrite(io, audio, buf, n) != n)
+			fprint(2, "player: %r\n");
+		if(trycoverload){
+			trycoverload = 0;
+			player->img = chancreate(sizeof(Image*), 0);
+			proccreate(coverload, player, 4096);
 		}
-		byteswritten += n;
-		if(bytesfrom == byteswritten || (byteswritten/Bps > (byteswritten-n)/Bps))
+		if(labs(boffset/Relbufsz - boffsetlast/Relbufsz) > 0){
+			boffsetlast = boffset;
 			redraw(0);
+		}
 	}
 
 	if(n < 1){ /* seeking backwards or end of the song */
 		close(p[1]);
 		p[1] = -1;
-		if(c != Cseekrel || player->seekbytes >= 0){
+		if(c != Cseekrel || boffset >= getmeta(pcurplaying)->duration/1000*Bps){
 next:
 			playercurr = nil;
 			playercurr = newplayer((player->pcur+1) % plnum, 1);
@@ -588,10 +600,10 @@
 }
 
 static void
-seekrel(Player *player, vlong off)
+seekrel(Player *player, double off)
 {
 	if(player != nil){
-		player->seekbytes = off;
+		player->seek = off;
 		sendul(player->ctl, Cseekrel);
 	}
 }
@@ -924,6 +936,12 @@
 
 			n = (m.xy.y - screen->r.min.y)/f->height;
 
+			if(oldbuttons == 0 && !scrolling && ptinrect(m.xy, seekbar)){
+				m.xy.x--;
+				double off = getmeta(pcurplaying)->duration * (double)(m.xy.x-seekbar.min.x) / (double)Dx(seekbar);
+				seekrel(playercurr, off/1000.0 - byteswritten/Bps);
+				break;
+			}
 			if(oldbuttons == 0 && m.xy.x <= screen->r.min.x+Scrollwidth){
 				if(m.buttons == 1){
 					scroll = MAX(0, scroll-n-1);
@@ -970,16 +988,16 @@
 		case 2:
 			switch(key){
 			case Kleft:
-				seekrel(playercurr, -(vlong)Seekbytes);
+				seekrel(playercurr, -(double)Seek);
 				break;
 			case Kright:
-				seekrel(playercurr, Seekbytes);
+				seekrel(playercurr, Seek);
 				break;
 			case ',':
-				seekrel(playercurr, -(vlong)Seekbytesfast);
+				seekrel(playercurr, -(double)Seekfast);
 				break;
 			case '.':
-				seekrel(playercurr, Seekbytesfast);
+				seekrel(playercurr, Seekfast);
 				break;
 			case Kup:
 				pcur--;