code: plan9front

Download patch

ref: 080a7b01bfa0fb89951cf4e30070dc7665992c90
parent: bb36ba0617b5aa8263ea9b5ece8c1a5249fedc86
author: qwx <qwx@sciops.net>
date: Sat Jan 21 13:12:12 EST 2023

games/opl3: implement real time streaming mode

this pushes all responsibility for timing to opl3, absolving
dmid(1) and other writers from constantly sending sync
events to force opl3 to synthesize audio in between events.
it reduces cpu usage and syscalls dramatically and enables
applications other than dmid(1) to modify its state in real
time, for instance to use it as a synth.

--- a/sys/src/games/opl3/opl3m.c
+++ b/sys/src/games/opl3/opl3m.c
@@ -13,7 +13,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-r rate] [file]\n", argv0);
+	fprint(2, "usage: %s [-s] [-r rate] [file]\n", argv0);
 	exits("usage");
 }
 
@@ -20,12 +20,15 @@
 void
 main(int argc, char **argv)
 {
-	int rate, n, r, v, fd, pfd[2];
-	uchar sb[65536 * 4], u[5];
-	double f, dt;
+	int rate, stream, n, r, v, fd, pfd[2];
+	uchar sb[64*1024], u[5];
+	double f;
+	vlong dt, T;
 	Biobuf *bi;
+	QLock slock;
 
 	fd = 0;
+	stream = 0;
 	rate = OPLrate;
 	ARGBEGIN{
 	case 'r':
@@ -33,6 +36,9 @@
 		if(rate <= 0 || rate > OPLrate)
 			usage();
 		break;
+	case 's':
+		stream = 1;
+		break;
 	default:
 		usage();
 	}ARGEND;
@@ -60,19 +66,44 @@
 	}
 	f = (double)OPLrate / rate;
 	dt = 0;
+	T = nsec();
+	if(stream){
+		switch(rfork(RFPROC|RFMEM)){
+		case -1:
+			sysfatal("rfork: %r");
+		case 0:
+			for(;;){
+				qlock(&slock);
+				n = OPLrate / 1e3;
+				T += n * (1e9 / OPLrate);
+				n *= 4;
+				opl3out(sb, n);
+				n = write(pfd[1], sb, n);
+				dt = (T - nsec()) / 1e6;
+				qunlock(&slock);
+				if(n <= 0)
+					break;
+				if(dt > 0)
+					sleep(dt);
+			}
+		}
+	}
 	while((n = Bread(bi, u, sizeof u)) > 0){
 		r = u[1] << 8 | u[0];
 		v = u[2];
 		opl3wr(r, v);
 		dt += (u[4] << 8 | u[3]) * f;
+		qlock(&slock);
 		while((n = dt) > 0){
 			if(n > sizeof sb / 4)
 				n = sizeof sb / 4;
 			dt -= n;
+			T += n * (1e9 / OPLrate);
 			n *= 4;
 			opl3out(sb, n);
 			write(pfd[1], sb, n);
 		}
+		qunlock(&slock);
 	}
 	if(n < 0)
 		sysfatal("read: %r");