shithub: pplay

Download patch

ref: c923daa68daae862ccdd638cbb9e255c609b09de
parent: 0b8bc0b02656311de2b1542d5819d7118c789ab5
author: qwx <qwx@sciops.net>
date: Tue Jul 25 04:47:45 EDT 2023

haha draw go brrr

performance improvements and regression fixes
- get rid of secondary backing store
- limit drawproc updates to a given interval
- don't redraw entire image on update, erase and redraw markers and stats
- update view if changes occur while paused

makes code yet more complicated, but the latency was horrible;
ui is slowed down by the scheduling between athread and alt();
it makes little sense at this point, should replace athread with
an actual proc however inconvenient it might be, then micing will
not feel like swimming through larch vomit

--- a/dat.h
+++ b/dat.h
@@ -34,7 +34,7 @@
 extern QLock lsync;
 
 extern int stereo;
-extern int debug;
+extern int debug, paused;
 extern int debugdraw;
 
 #define MIN(x,y)	((x) < (y) ? (x) : (y))
--- a/draw.c
+++ b/draw.c
@@ -19,9 +19,8 @@
 	Ncol,
 };
 static Image *col[Ncol];
-static Image *viewbg, *view;
-static Rectangle liner;
-static Point statp;
+static Image *view;
+static Rectangle liner, statr;
 static usize views, viewe, viewmax;
 static int bgscalyl, bgscalyr;
 static double bgscalf;
@@ -75,10 +74,10 @@
 
 	if(pos <= views || pos >= viewe)
 		return 0;
-	r = view->r;
+	r = screen->r;
 	r.min.x += (pos - views) / T;
 	r.max.x = r.min.x + 1;
-	draw(view, r, c, nil, ZP);
+	draw(screen, r, c, nil, subpt(r.min, screen->r.min));
 	return 1;
 }
 
@@ -99,29 +98,38 @@
 static void
 drawsamps(void*)
 {
-	int x, lmin, lmax, rmin, rmax;
-	usize n, m, k;
+	int ox, n, lmin, lmax, rmin, rmax;
+	usize m, k;
 	s16int s;
+	double x;
 	uchar *p, *e;
 	Rectangle l, r;
+	Point range;
 	Dot d;
 
 	for(;;){
 end:
-		recvul(drawc);
+		if(recv(drawc, &range) < 0)
+			break;
 again:
+		r = view->r;
+		r.min.x = (range.x - views) / T;
+		r.max.x = (range.y - views) / T;
 		lockdisplay(display);
-		draw(viewbg, viewbg->r, col[Cbg], nil, ZP);
+		draw(view, r, col[Cbg], nil, ZP);
 		unlockdisplay(display);
 		d = *current;
-		d.from = 0;
-		d.cur = views;
-		d.to = d.totalsz;
-		m = viewe - views;
-		x = 0;
+		d.from = range.x;
+		d.cur = d.from;
+		d.to = range.y;
+		m = d.to - d.from;
+		ox = 0;
+		x = 0.0;
 		qlock(&lsync);
 		while(m > 0){
-			if(nbrecvul(drawc) == 1){
+			if((n = nbrecv(drawc, &range)) < 0)
+				return;
+			else if(n == 1){
 				qunlock(&lsync);
 				goto again;
 			}
@@ -156,18 +164,21 @@
 			}
 			l = Rect(x, bgscalyl - lmax / bgscalf,
 				x+sampwidth, bgscalyl - lmin / bgscalf);
-			r = Rect(x, bgscalyr - rmax / bgscalf,
-				x+sampwidth, bgscalyr - rmin / bgscalf);
 			lockdisplay(display);
-			draw(viewbg, l, col[Csamp], nil, ZP);
-			if(stereo)
-				draw(viewbg, r, col[Csamp], nil, ZP);
+			draw(view, l, col[Csamp], nil, ZP);
+			if(stereo){
+				r = Rect(x, bgscalyr - rmax / bgscalf,
+					x+sampwidth, bgscalyr - rmin / bgscalf);
+				draw(view, r, col[Csamp], nil, ZP);
+			}
 			unlockdisplay(display);
-			x = (d.cur - views) / T;
-			if(x % 320 == 0)
-				update();
+			if(x - ox >= 1600){
+				update(ox, x);
+				ox = x;
+			}
+			x += k / T;
 		}
-		update();
+		update(ox, Dx(screen->r));
 		qunlock(&lsync);
 	}
 }
@@ -178,8 +189,9 @@
 	char s[256];
 	Point p;
 
+	draw(screen, statr, col[Cbg], nil, ZP);
 	seprint(s, s+sizeof s, "T %zd @ %τ", T / Sampsz, current->cur);
-	p = string(screen, statp, col[Ctext], ZP, font, s);
+	p = string(screen, statr.min, col[Ctext], ZP, font, s);
 	if(current->from > 0 || current->to < current->totalsz){
 		seprint(s, s+sizeof s, " ↺ %τ - %τ", current->from, current->to);
 		p = string(screen, p, col[Cloop], ZP, font, s);
@@ -188,12 +200,12 @@
 		seprint(s, s+sizeof s, " ‡ %τ", current->off);
 		p = string(screen, p, col[Cins], ZP, font, s);
 	}
+	statr.max.x = p.x;
 }
 
 static void
-drawview(void)
+drawmarks(void)
 {
-	draw(view, view->r, viewbg, nil, ZP);
 	if(debugdraw)
 		drawchunks();
 	drawpos(current->from, col[Cloop]);
@@ -203,20 +215,22 @@
 }
 
 void
-update(void)
+update(int x, int x´)
 {
-	int x;
-	usize p;
+	Rectangle r;
 
-	p = current->cur;
+	r = liner;
 	lockdisplay(display);
-	drawview();
-	draw(screen, screen->r, view, nil, ZP);
-	x = screen->r.min.x + (p - views) / T;
-	liner.min.x = x;
-	liner.max.x = x + 1;
-	if(p >= views)
-		draw(screen, liner, col[Cline], nil, ZP);
+	draw(screen, liner, view, nil, subpt(r.min, screen->r.min));
+	if(x < x´){
+		r.min.x = screen->r.min.x + x;
+		r.max.x = screen->r.min.x + x´;
+		draw(screen, r, view, nil, subpt(r.min, screen->r.min));
+	}
+	liner.min.x = screen->r.min.x + (current->cur - views) / T;
+	liner.max.x = liner.min.x + 1;
+	drawpos(current->cur, col[Cline]);
+	drawmarks();
 	drawstat();
 	flushimage(display, 1);
 	unlockdisplay(display);
@@ -290,6 +304,10 @@
 {
 	assert((from & 3) == 0);
 	assert((to & 3) == 0);
+	if(current->from > views)
+		drawpos(current->from, view);
+	if(current->to < viewe)
+		drawpos(current->to, view);
 	current->from = from;
 	current->to = to;
 	if(current->cur < from || current->cur >= to)
@@ -305,7 +323,8 @@
 		return -1;
 	}
 	current->off = current->cur = off;
-	update();
+	if(paused)
+		update(0, 0);
 	return 0;
 }
 
@@ -320,7 +339,8 @@
 		setrange(off, current->to);
 	else
 		setrange(current->from, off);
-	update();
+	if(paused)
+		update(0, 0);
 }
 
 void
@@ -343,14 +363,12 @@
 
 	x = screen->r.min.x + (current->cur - views) / T;
 	viewr = rectsubpt(screen->r, screen->r.min);
-	statp = screen->r.min;
+	statr = screen->r;
 	if(stereo)
-		statp.y += (Dy(screen->r) - font->height) / 2 + 1;
+		statr.min.y += (Dy(screen->r) - font->height) / 2 + 1;
 	else
-		statp.y = screen->r.max.y - font->height;
-	freeimage(viewbg);
+		statr.min.y = screen->r.max.y - font->height;
 	freeimage(view);
-	viewbg = eallocimage(viewr, 0, DNofill);
 	view = eallocimage(viewr, 0, DNofill);
 	liner = screen->r;
 	liner.min.x = x;
@@ -364,6 +382,7 @@
 redraw(int all)
 {
 	usize span;
+	Point p;
 
 	lockdisplay(display);
 	T = (vlong)(current->totalsz / zoom / Dx(screen->r)) & ~3;
@@ -377,7 +396,8 @@
 	if(all)
 		resetdraw();
 	unlockdisplay(display);
-	nbsendul(drawc, 1);
+	p = Pt(views, viewe);
+	nbsend(drawc, &p);
 }
 
 void
@@ -404,7 +424,7 @@
 		col[Cloop] = eallocimage(Rect(0,0,1,1), 1, 0x8888CCFF);
 		col[Cchunk] = eallocimage(Rect(0,0,1,1), 1, 0xEE0000FF);
 	}
-	if((drawc = chancreate(sizeof(ulong), 4)) == nil)
+	if((drawc = chancreate(sizeof(Point), 4)) == nil)
 		sysfatal("chancreate: %r");
 	if(proccreate(drawsamps, nil, mainstacksize) < 0)
 		sysfatal("proccreate: %r");
--- a/fns.h
+++ b/fns.h
@@ -10,7 +10,7 @@
 Chunk*	loadfile(int, Dot*);
 int	cmd(char*);
 int	initcmd(int);
-void	update(void);
+void	update(int, int);
 void	setzoom(int, int);
 int	zoominto(vlong, vlong);
 void	setrange(usize, usize);
--- a/pplay.c
+++ b/pplay.c
@@ -10,7 +10,7 @@
 extern QLock lsync;
 
 int stereo;
-int debug;
+int debug, paused = 1;
 
 static Keyboardctl *kc;
 static Mousectl *mc;
@@ -42,7 +42,7 @@
 			threadexits("write");
 		}
 		nerr = 0;
-		update();
+		update(0, 0);
 skip:
 		yield();
 	}
@@ -51,20 +51,18 @@
 static void
 toggleplay(void)
 {
-	static int play;
-
-	if(play ^= 1){
+	if(paused ^= 1){
+		if(!cat)
+			close(afd);
+		afd = -1;
+	}else{
 		if((afd = cat ? 1 : open("/dev/audio", OWRITE)) < 0){
 			fprint(2, "toggleplay: %r\n");
-			play = 0;
+			paused ^= 1;
 			return;
 		}
 		if(threadcreate(athread, nil, 2*mainstacksize) < 0)
 			sysfatal("threadcreate: %r");
-	}else{
-		if(!cat)
-			close(afd);
-		afd = -1;
 	}
 }
 
@@ -155,7 +153,7 @@
 			case 'S': stereo ^= 1; redraw(1); break;
 			case ' ': toggleplay(); break;
 			case 'b': setjump(current->from); break;
-			case Kesc: setrange(0, current->totalsz); update(); break;
+			case Kesc: setrange(0, current->totalsz); update(0, 0); break;
 			case '\n': zoominto(current->from, current->to); break;
 			case 'z': zoominto(0, current->totalsz); break;
 			case '-': setzoom(-1, 0); break;
@@ -173,8 +171,8 @@
 				}
 				qlock(&lsync);
 				switch(cmd(p)){
-				case -1: fprint(2, "cmd \"%s\" failed: %r\n", p); update(); break;
-				case 0: update(); break;
+				case -1: fprint(2, "cmd \"%s\" failed: %r\n", p); update(0, 0); break;
+				case 0: update(0, 0); break;
 				case 1: redraw(0); break;
 				case 2: redraw(1); break;
 				}