shithub: neindaw

Download patch

ref: 6544a8049f57f231de744df73403f68428bbbe1f
parent: f1472b95fd6e0c724a2139461416b13628e0ee41
author: Sigrid Haflínudóttir <[email protected]>
date: Mon Mar 23 16:27:45 EDT 2020

add a very stupid waveform drawing code as a start

diff: cannot open b/waveform//null: file does not exist: 'b/waveform//null'
--- /dev/null
+++ b/waveform/mkfile
@@ -1,0 +1,11 @@
+</$objtype/mkfile
+
+TARG=waveform
+BIN=/$objtype/bin/daw
+
+OFILES=\
+	waveform.$O\
+
+default:V:	all
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/waveform/waveform.c
@@ -1,0 +1,207 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <thread.h>
+
+#define MIN(a,b) ((a)<=(b)?(a):(b))
+#define MAX(a,b) ((a)>=(b)?(a):(b))
+
+typedef struct Waveform Waveform;
+
+struct Waveform {
+	float *samples;
+	Image *image;
+	float min;
+	float max;
+	int nchan;
+	int nframes;
+	int rate;
+};
+
+static Waveform *
+wvform(int f, int nchan, int rate)
+{
+	Waveform *w;
+	int i, r, n, sz;
+
+	w = calloc(1, sizeof(*w));
+	w->nchan = nchan;
+	w->rate = rate;
+	sz = 128*nchan;
+	w->samples = malloc(sz*sizeof(float));
+	for (n = 0;;) {
+		if (sz-n < 1) {
+			sz *= 2;
+			w->samples = realloc(w->samples, sz*sizeof(float));
+		}
+		if ((r = read(f, w->samples+n, (sz-n)*sizeof(float))) < 0) {
+			free(w->samples);
+			free(w);
+			return nil;
+		}
+		r /= sizeof(float);
+		if (r == 0)
+			break;
+		if (n == 0)
+			w->min = w->max = w->samples[0];
+		for (i = 0; i < r; i++, n++) {
+			w->min = MIN(w->min, w->samples[n]);
+			w->max = MAX(w->max, w->samples[n]);
+		}
+	}
+
+	w->samples = realloc(w->samples, n*sizeof(float));
+	w->nframes = n / nchan;
+
+	return w;
+}
+
+static int
+wvimage(Waveform *w, int offset, int nframes, Rectangle r, float zoom)
+{
+	int i, yd, yi, bsz, xdone, ydone;
+	float x, ox, oyi, dyi;
+	u8int *b, col;
+
+	r = Rect(0, 0, Dx(r), Dy(r));
+	freeimage(w->image);
+	if ((w->image = allocimage(display, r, GREY8, 0, DNofill)) == nil)
+		return -1;
+	bsz = Dx(r)*Dy(r);
+	if ((b = malloc(bsz)) == nil) {
+		freeimage(w->image);
+		w->image = nil;
+		return -1;
+	}
+	memset(b, 0xff, bsz);
+
+	yd = Dy(r)/2;
+	if (w->max > 1.0f)
+		yd /= w->max;
+	yd--;
+	oyi = yd;
+	for (ox = x = 0, i = offset; i < offset+nframes; i++, x += 1.0f/zoom) {
+		yi = yd + w->samples[i*w->nchan+0] * yd;
+		if (yi >= 0 && yi < Dy(r) && x < Dx(r))
+			b[(int)x + yi*Dx(r)] = 0;
+		dyi = (yi < oyi ? -1.0f : 1.0f)/MAX(1.0f, zoom);
+		xdone = ydone = 0;
+		col = MIN(0x80, zoom*(abs(yi - oyi) + abs(x - ox)));
+		while (ox < Dx(r) && (!xdone || !ydone)) {
+			b[(int)ox + (int)oyi*Dx(r)] = col;
+			if (ox < x)
+				ox = MIN(ox + 1.0f/MAX(1.0f, zoom), x);
+			else
+				xdone = 1;
+			if ((dyi > 0 && oyi < yi) || (dyi < 0 && oyi > yi))
+				oyi = MAX(0, MIN(oyi+dyi, Dy(r)-1));
+			else
+				ydone = 1;
+		}
+		if (x >= Dx(r))
+			break;
+		ox = x;
+		oyi = yi;
+	}
+
+	return loadimage(w->image, r, b, bsz);
+}
+
+static void
+redraw(Waveform *w, int offset, float zoom)
+{
+	Rectangle r;
+
+	r = screen->r;
+	r.min.y += Dy(r)/4;
+	r.max.y -= Dy(r)/4;
+	if (wvimage(w, offset, w->nframes-offset, r, zoom) < 0)
+		sysfatal("couldn't create image: %r");
+
+	draw(screen, r, w->image, nil, ZP);
+	flushimage(display, 1);
+}
+
+void
+threadmain(int argc, char **argv)
+{
+	Waveform *w;
+	Mousectl *mctl;
+	Keyboardctl *kctl;
+	Rune key;
+	float zoom;
+	int offset;
+	Mouse m;
+	Alt a[] = {
+		{ nil, &m, CHANRCV },
+		{ nil, nil, CHANRCV },
+		{ nil, &key, CHANRCV },
+		{ nil, nil, CHANEND },
+	};
+
+	USED(argc); USED(argv);
+
+	if ((w = wvform(0, 1, 44100)) == nil)
+		sysfatal("%r");
+
+	if (initdraw(nil, nil, "daw/waveform") < 0)
+		sysfatal("initdraw: %r");
+	if ((mctl = initmouse(nil, screen)) == nil)
+		sysfatal("initmouse: %r");
+	if ((kctl = initkeyboard(nil)) == nil)
+		sysfatal("initkeyboard: %r");
+
+	a[0].c = mctl->c;
+	a[1].c = mctl->resizec;
+	a[2].c = kctl->c;
+
+	srand(time(0));
+	threadsetname("daw/cfg");
+
+	zoom = 1.0f;
+	offset = 0;
+	redraw(w, offset, zoom);
+	for (;;) {
+		switch (alt(a)) {
+		case 0: /* mouse */
+			break;
+
+		case 1: /* resize */
+			getwindow(display, Refnone);
+			redraw(w, offset, zoom);
+			break;
+
+		case 2: /* keyboard */
+			switch (key) {
+			case Kdel:
+				goto end;
+			case Kleft:
+				offset = MAX(0, offset-MAX(8, 8*MAX(1, 1/zoom)));
+				redraw(w, offset, zoom);
+				break;
+			case Kright:
+				offset = MIN(w->nframes-1, offset+MAX(8, 8*MAX(1, 1/zoom)));
+				redraw(w, offset, zoom);
+				break;
+			case '-':
+				zoom *= 2.0f;
+				if (zoom > 32.0f)
+					zoom = 32.0f;
+				redraw(w, offset, zoom);
+				break;
+			case '+':
+				zoom /= 2.0f;
+				if (zoom < 0.01f)
+					zoom = 0.01f;
+				redraw(w, offset, zoom);
+				break;
+			}
+			break;
+		}
+	}
+
+end:
+	threadexitsall(nil);
+}