ref: 2f144ccad768088ec811f0945eb8611fbc1e0218
dir: /waveform/waveform.c/
#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 u8int sh[65] = { 0, 56, 57, 58, 59, 60, 61, 62, 63, 48, 49, 50, 51, 52, 53, 54, 55, 40, 41, 42, 43, 44, 45, 46, 47, 32, 33, 34, 35, 36, 37, 38, 39, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, }; static u64int * rotate90128(u64int *b, int h) { u64int *p; int i, j; u64int v; p = calloc(1, 128*h/8); for (i = 0; i < h; i++) { if ((v = b[i*2+1]) != 0) { for (j = 0; j < 64; j++) { if (v & (1ULL<<sh[j+1])) p[j*h/64 + i/64] |= 1ULL<<(63-sh[(i&63)+1]); } } if ((v = b[i*2+0]) != 0) { for (j = 0; j < 64; j++) { if (v & (1ULL<<sh[j+1])) p[(j+64)*h/64 + i/64] |= 1ULL<<(63-sh[(i&63)+1]); } } } for (i = 0; i < 128*h/64; i++) p[i] = ~p[i]; return p; } static int wvimage128(Waveform *w, int offset, int nframes, Rectangle r, float zoom) { float m, i; u64int *b, *p; int x, x2, y, incy, y2; r = Rect(0, 0, 128, MIN(nframes-offset, Dx(r))); if (badrect(r)) return -1; r.max.y += 64; b = calloc(1, 128*Dy(r)); 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 < nframes;) { x = m*w->samples[(int)(i*w->nchan)+0]; i += zoom; x2 = i < nframes ? m*w->samples[(int)(i*w->nchan)+0] : x; incy = x == x2 ? -999 : (x2 + x)/2; y2 = y + 1; do { if (x >= 0) b[y*2+1] |= 1ULL<<sh[64-x]; else b[y*2+0] |= 1ULL<<sh[-x]; if (x < x2) x++; else if (x > x2) x--; if (x == incy) y++; } while (x2 != x); y = y2; } y -= (y & 63); y += 64; 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 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; } loadimage(w->image, r, b, bsz); free(b); return 0; } 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; wvimage128(w, offset, w->nframes-offset, r, zoom); draw(screen, screen->r, display->white, nil, ZP); 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, 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 (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); oldb = 0; oldo = 0; oldp = ZP; 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, offset, zoom); } } oldb = m.buttons; 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 *= 1.1f; if (zoom > 32.0f) zoom = 32.0f; redraw(w, offset, zoom); break; case '+': zoom /= 1.1f; if (zoom < 0.01f) zoom = 0.01f; redraw(w, offset, zoom); break; } break; } } end: threadexitsall(nil); }