Sigrid Haflínudóttirwaveform: 64px-wide version54d05616 years agoHistory
387 lines · 6.7 KB · C
RawDownload
#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 nvalid;	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 = w->nvalid = n / nchan; 	return w;} static u64int *rotate9064(u64int *b, int h){	u64int *p;	int i, j;	u64int v, i7; 	p = calloc(1, 64*h/8); 	for (i = 0; i < h; i++) {		i7 = 1ULL<<(i^7);		v = b[i];		for (j = 0; j < 64; j++) {			if (v & (1ULL<<(j^56)))				p[j*h/64 + i/64] |= i7;		}	}	for (i = 0; i < h; i++)		p[i] = ~p[i]; 	return p;} static u64int *rotate90128(u64int *b, int h){	u64int *p;	int i, j;	u64int v, v2, i7; 	p = calloc(1, 128*h/8); 	for (i = 0; i < h; i++) {		i7 = 1ULL<<(i^7);		v = b[i*2+0];		v2 = b[i*2+1];		for (j = 1; j < 65; j++) {			if (v & (1ULL<<(j^56)))				p[(j+63)*h/64 + i/64] |= i7;			if (v2 & (1ULL<<(j^56)))				p[j*h/64 + i/64] |= i7;		}	}	for (i = 0; i < 128*h/64; i++)		p[i] = ~p[i]; 	return p;} static intwvimage64(Waveform *w, int offset, Rectangle r, float zoom){	float m, i;	u64int *b, *p;	int x, x2, y, incy, y2; 	offset = MIN(offset, w->nvalid);	r = Rect(0, 0, 64, Dx(r));	if (badrect(r))		return -1;	y = (Dy(r)+63) & ~63;	b = calloc(1, 64*y);	m = MAX(abs(w->min), abs(w->max));	m = m > 1.0f ? 31.0f/m : 31.0f; 	for (y = 0, i = offset; y < Dy(r) && i < w->nvalid;) {		x = 31 + m*w->samples[(int)i];		i += zoom;		x2 = i < w->nvalid ? 31 + m*w->samples[(int)i] : x;		incy = (x2 + x)/2;		y2 = y + 1;		do {			b[y+1] |= 1ULL<<(x^7);			if (x == x2)				break;			else if (x < x2)				x++;			else if (x > x2)				x--;			else if (x == incy)				y++;		} while (1);		y = y2;	} 	y = (y+63) & ~63;	p = rotate9064(b, y);	free(b);	r.max.x = y;	r.max.y = 64;	if (w->image == nil || !eqrect(r, w->image->r)) {		freeimage(w->image);		if ((w->image = allocimage(display, r, GREY1, 0, DNofill)) == nil)			return -1;	} 	if (loadimage(w->image, r, (void*)p, 64*y) < 0)		fprint(2, "failed: %r\n");	free(p); 	return 0;} static intwvimage128(Waveform *w, int offset, Rectangle r, float zoom){	float m, i;	u64int *b, *p;	int x, x2, y, incy, y2; 	offset = MIN(offset, w->nvalid);	r = Rect(0, 0, 128, Dx(r));	if (badrect(r))		return -1;	y = (Dy(r)+63) & ~63;	b = calloc(1, 128*y);	m = MAX(abs(w->min), abs(w->max));	m = m > 1.0f ? 63.0f/m : 63.0f; 	for (y = 0, i = offset; y < Dy(r) && i < w->nvalid;) {		x = m*w->samples[(int)i];		i += zoom;		x2 = i < w->nvalid ? m*w->samples[(int)i] : x;		incy = (x2 + x)/2;		y2 = y + 1;		do {			if (x >= 0)				b[y*2+1] |= 1ULL<<(x^7);			else				b[y*2+0] |= 1ULL<<(-x^56);			if (x == x2)				break;			else if (x < x2)				x++;			else if (x > x2)				x--;			else if (x == incy)				y++;		} while (1);		y = y2;	} 	y = (y+63) & ~63;	p = rotate90128(b, y);	free(b);	r.max.x = y;	r.max.y = 128;	if (w->image == nil || !eqrect(r, w->image->r)) {		freeimage(w->image);		if ((w->image = allocimage(display, r, GREY1, 0, DNofill)) == nil)			return -1;	} 	if (loadimage(w->image, r, (void*)p, 128*y) < 0)		fprint(2, "failed: %r\n");	free(p); 	return 0;} static int offset;static float zoom; static voidredraw(Waveform *w){	Rectangle r; 	lockdisplay(display);	r = screen->r;	r.min.y += Dy(r)/4;	r.max.y -= Dy(r)/4;	draw(screen, screen->r, display->white, nil, ZP);	if (wvimage64(w, offset, r, zoom) == 0)		draw(screen, r, w->image, nil, ZP);	flushimage(display, 1);	unlockdisplay(display);} static Waveform *wvbuffer(int nsamples){	Waveform *w; 	w = calloc(1, sizeof(*w));	w->samples = malloc(nsamples*sizeof(float));	w->min = -1.0f;	w->max = 1.0f;	w->nchan = 1;	w->nframes = nsamples;	w->rate = 44100;	w->nvalid = 0; 	return w;} static voidwvproc(void *w_){	int fi, fo, n, i;	Waveform *w = w_;	int c; 	fi = 0;	fo = 1;	for (c = 0;; c++) {		if ((n = readn(fi, w->samples, sizeof(float)*w->nframes)) < 1)			break;		n /= sizeof(float);		w->nvalid = n;		for (i = 0; i < n; i++) {			w->min = MIN(-1.0f, MIN(w->min, w->samples[i]));			w->max = MAX(1.0f, MAX(w->max, w->samples[i]));		}		if (write(fo, w->samples, n*sizeof(float)) != n*sizeof(float))			break;		redraw(w);	} 	threadexits(nil);} voidthreadmain(int argc, char **argv){	Waveform *w;	Mousectl *mctl;	Keyboardctl *kctl;	Rune key;	int oldo;	Mouse m;	int oldb;	Point oldp;	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 ((w = wvbuffer(1024)) == nil)		sysfatal("%r");		*/ 	if (initdraw(nil, nil, "daw/waveform") < 0)		sysfatal("initdraw: %r");	display->locking = 1;	unlockdisplay(display);	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; 	threadsetname("daw/waveform"); 	zoom = 1.0f;	offset = 0;	oldb = 0;	oldo = 0;	oldp = ZP; 	//proccreate(wvproc, w, mainstacksize);	redraw(w); 	for (;;) {		switch (alt(a)) {		case 0: /* mouse */			if (m.buttons == 1) {				if (oldb == 0) {					oldp = m.xy;					oldo = offset;				} else if (oldb == 1) {					offset = MAX(0, oldo + (oldp.x - m.xy.x)*zoom);					redraw(w);				}			}			oldb = m.buttons;			break; 		case 1: /* resize */			getwindow(display, Refnone);			redraw(w);			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);				break;			case Kright:				offset = MIN(w->nframes-1, offset+MAX(8, 8*MAX(1, 1/zoom)));				redraw(w);				break;			case '-':				zoom *= 1.1f;				if (zoom > 32.0f)					zoom = 32.0f;				redraw(w);				break;			case '+':				zoom /= 1.1f;				if (zoom < 0.01f)					zoom = 0.01f;				redraw(w);				break;			}			break;		}	} end:	threadexitsall(nil);}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t