shithub: etoys

Download patch

ref: 1600d38f2374f2418c124feec565f50cf7c8f7c4
parent: 596bb7a2ddf8b005602fcb0f4db741333d5f0b30
author: rodri <rgl@antares-labs.eu>
date: Mon Jun 9 12:18:46 EDT 2025

new toy: beatlet

--- /dev/null
+++ b/beatlet.c
@@ -1,0 +1,204 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <geometry.h>
+
+enum {
+	NSAMP	= 1323,		/* 30ms */
+};
+
+static int debug;
+
+static Point2 ZP2 = {0,0,1};
+RFrame beatrf;
+Image *screenb;
+Channel *drawc;
+
+Point2
+p2(Point p)
+{
+	return Pt2(p.x, p.y, 1);
+}
+
+Point
+p2p(Point2 p)
+{
+	return Pt(p.x, p.y);
+}
+
+Point
+toscreen(Point2 p)
+{
+	return p2p(invrframexform(p, beatrf));
+}
+
+void
+redraw(void)
+{
+	lockdisplay(display);
+	draw(screen, screen->r, screenb, nil, screenb->r.min);
+	flushimage(display, 1);
+	unlockdisplay(display);
+}
+
+void
+drawproc(void *arg)
+{
+	Channel *c;
+
+	threadsetname("drawproc");
+
+	c = arg;
+
+	for(;;){
+		recv(c, nil);
+		redraw();
+	}
+}
+
+void
+beatproc(void *arg)
+{
+	Point2 v;
+	Point poly[NSAMP];
+	u32int ss[NSAMP];	/* stereo samples */
+	s32int as[NSAMP], s;	/* avg'd samples */
+	u16int min, max;
+	int fd, i, ns;
+	double θ;
+	uvlong frame, t0, t1;
+	char buf[32];
+
+	threadsetname("beatproc");
+
+	fd = *(int*)arg;
+	ns = frame = 0;
+
+	t0 = nsec();
+	while(readn(fd, ss, 2*2*NSAMP) > 0){
+		min = 1<<15 - 1;
+		max = 0;
+		for(i = 0; i < nelem(ss); i++){
+			s = (s16int)(ss[i] & 0xFFFF) + (s16int)(ss[i]>>16 & 0xFFFF);
+			/* [-2¹⁶, 2¹⁶) → [0, 2¹⁵) */
+			s = (s/2 + (1<<15))/2;
+			min = s < min? s: min;
+			max = s > max? s: max;
+			as[i] = s;
+		}
+		lockdisplay(display);
+		for(i = 0; i < nelem(as); i++){
+			θ = 2*PI * ((double)(ns++ % NSAMP)/NSAMP);
+			v = Vec2(cos(θ), sin(θ));
+			s = as[i];
+			poly[i] = toscreen(addpt2(ZP2, mulpt2(v, 4*(s-min)*100/max)));
+//			line(screenb, toscreen(ZP2), toscreen(addpt2(ZP2, mulpt2(v, 400))), 0, 0, 0, display->black, ZP);
+//			line(screenb, toscreen(ZP2), toscreen(addpt2(ZP2, mulpt2(v, 4*(s-min)*100/max))), 0, 0, 0, display->white, ZP);
+		}
+		draw(screenb, screenb->r, display->black, nil, ZP);
+		fillpoly(screenb, poly, nelem(poly), 1, display->white, ZP);
+
+		if(debug){
+			t1 = nsec();
+			snprint(buf, sizeof(buf), "%llud (%3.0fHz)", ++frame, 1e9/(t1-t0));
+			t0 = t1;
+			stringbg(screenb, addpt(screen->r.min, Pt(20, 20)), display->white, ZP, font, buf, display->black, ZP);
+		}
+		unlockdisplay(display);
+		nbsend(drawc, nil);
+	}
+}
+
+void
+key(Rune r)
+{
+	switch(r){
+	case Kdel:
+	case 'q':
+		threadexitsall(nil);
+	}
+}
+
+void
+resized(void)
+{
+	lockdisplay(display);
+	if(getwindow(display, Refnone) < 0)
+		sysfatal("resize failed");
+	freeimage(screenb);
+	screenb = allocimage(display, screen->r, screen->chan, 0, DBlack);
+	beatrf.p = p2(divpt(addpt(screen->r.min, screen->r.max), 2));
+	unlockdisplay(display);
+	nbsend(drawc, nil);
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s /dev/audio\n", argv0);
+	exits("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+	Mousectl *mc;
+	Keyboardctl *kc;
+	Rune r;
+	int fd;
+
+	ARGBEGIN{
+	case 'd': debug++; break;
+	default: usage();
+	}ARGEND;
+	if(argc != 1)
+		usage();
+
+	fd = open(argv[0], OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+
+	if(initdraw(nil, nil, nil) < 0)
+		sysfatal("initdraw: %r");
+	if((mc = initmouse(nil, screen)) == nil)
+		sysfatal("initmouse: %r");
+	if((kc = initkeyboard(nil)) == nil)
+		sysfatal("initkeyboard: %r");
+
+	beatrf.p = p2(divpt(addpt(screen->r.min, screen->r.max), 2));
+	beatrf.bx = Vec2(1, 0);
+	beatrf.by = Vec2(0,-1);
+	screenb = allocimage(display, screen->r, screen->chan, 0, DBlack);
+	if(screenb == nil)
+		sysfatal("allocimage: %r");
+
+	drawc = chancreate(sizeof(void*), 1);
+	proccreate(drawproc, drawc, 8*1024);
+	proccreate(beatproc, &fd, 32*1024);
+
+	display->locking = 1;
+	unlockdisplay(display);
+	nbsend(drawc, nil);
+
+	for(;;){
+		enum { MOUSE, RESIZE, KEYBOARD };
+		Alt a[] = {
+			{mc->c, &mc->Mouse, CHANRCV},
+			{mc->resizec, nil, CHANRCV},
+			{kc->c, &r, CHANRCV},
+			{nil, nil, CHANEND}
+		};
+
+		switch(alt(a)){
+		case RESIZE:
+			resized();
+			break;
+		case KEYBOARD:
+			key(r);
+			break;
+		}
+	}
+}
--- a/mkfile
+++ b/mkfile
@@ -16,5 +16,6 @@
 	barycentric\
 	lineXcircle\
 	linetiler\
+	beatlet\
 
 </sys/src/cmd/mkmany
--