stew

a monorepo of some sort
git clone git://git.nsmpr.xyz/stew.git
Log | Files | Refs

draw.c (6786B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <draw.h>
      4 #include <thread.h>
      5 #include <mouse.h>
      6 #include <keyboard.h>
      7 
      8 #include "util.h"
      9 
     10 #define DefLength 169
     11 /*
     12  * This DefLength is equal to standard sample rate of 44100
     13  * divided by C4 note from chromatic scale frequency of 261.626
     14  */
     15 
     16 char *path;
     17 int autosaveflag, dirtyflag;
     18 u32int pcm[MaxLength];
     19 usize length;
     20 Mousectl *mctl;
     21 Keyboardctl *kctl;
     22 Image *bg, *lo, *hi;
     23 
     24 int readpcm(void);
     25 int writepcm(void);
     26 void keyboard(Rune);
     27 void mouse(Mouse);
     28 void resize(int *);
     29 void redraw(u32int *, u32int *);
     30 
     31 void sine(void);
     32 void noise(void);
     33 
     34 void save(void);
     35 
     36 
     37 void (*menucmd[])(void) = {
     38 	sine, noise
     39 };
     40 
     41 char *menuitems[] = {
     42 	"sine",
     43 	"noise",
     44 	nil,
     45 };
     46 
     47 Menu menu = {menuitems, nil, 0};
     48 
     49 void
     50 usage(void)
     51 {
     52 	fprint(2, "usage: [-a] %s [file]\n", argv0);
     53 	threadexitsall("usage");
     54 }
     55 
     56 void
     57 threadmain(int argc, char **argv)
     58 {
     59 	ARGBEGIN{
     60 	case 'a':
     61 		autosaveflag = 1;
     62 		break;
     63 	default:
     64 		usage();
     65 	}ARGEND
     66 
     67 	if (argc > 1) usage();
     68 	else if (argc == 0) {
     69 		path = strdup("");
     70 		length = DefLength;
     71 		sine();
     72 	} else {
     73 		path = strdup(argv[0]);
     74 		if (readpcm() != 0) {
     75 			fprint(2, "failed to open file %s: %r\n", argv[0]);
     76 			threadexitsall("failed to open file");
     77 		}
     78 	}
     79 
     80 	if (initdraw(nil, nil, "pcm/draw") < 0) sysfatal("initdraw: %r");
     81 	if ((mctl = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r");
     82 	if ((kctl = initkeyboard(nil)) == nil) sysfatal("initkeyboard: %r");
     83 
     84 	bg = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DBlack);
     85 	lo = allocimagemix(display, DRed, DBlack);
     86 	hi = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DRed);
     87 
     88 	draw(screen, screen->r, bg, nil, ZP);
     89 	redraw(nil, nil);
     90 	flushimage(display, 1);
     91 
     92 	Rune kv;
     93 	Mouse mv;
     94 	int rv[2];
     95 
     96 	Alt alts[] = {
     97 		{kctl->c, &kv, CHANRCV},
     98 		{mctl->c, &mv, CHANRCV},
     99 		{mctl->resizec, rv, CHANRCV},
    100 		{nil, nil, CHANEND},
    101 	};
    102 
    103 	for (;;) {
    104 		switch (alt(alts)) {
    105 		case 0:
    106 			keyboard(kv);
    107 			break;
    108 		case 1:
    109 			mouse(mv);
    110 			break;
    111 		case 2:
    112 			resize(rv);
    113 			break;
    114 		}
    115 	}
    116 }
    117 
    118 int
    119 readpcm(void)
    120 {
    121 	int fd;
    122 	if ((fd = open(path, OREAD)) < 0) {
    123 		fprint(2, "failed to open %s: %r\n", path);
    124 		return 1;
    125 	}
    126 	length = MaxLength;
    127 	length = read(fd, pcm, MaxLength * 4) / 4;
    128 	close(fd);
    129 	return 0;
    130 }
    131 
    132 int
    133 writepcm(void)
    134 {
    135 	int fd;
    136 	if ((fd = create(path, OWRITE, 0666)) < 0) {
    137 		fprint(2, "failed to open %s: %r\n", path);
    138 		return 1;
    139 	}
    140 	write(fd, pcm, length * 4);
    141 	close(fd);
    142 	return 0;
    143 }
    144 
    145 void
    146 keyboard(Rune rv)
    147 {
    148 	usize newlength;
    149 	char *rpt, ebuf[1024];
    150 
    151 	switch (rv) {
    152 	case 'r':
    153 	case 'w':
    154 		snprint(ebuf, sizeof(ebuf), "%C%s", rv, path);
    155 		break;
    156 	case 'l':
    157 		snprint(ebuf, sizeof(ebuf), "%C%ulld", rv, length);
    158 		break;
    159 	default:
    160 		snprint(ebuf, sizeof(ebuf), "%C", rv);
    161 	}
    162 
    163 	if (enter("% ", ebuf, sizeof(ebuf), mctl, kctl, nil) < 0) return;
    164 
    165 	switch(ebuf[0]) {
    166 	case 'q':
    167 		threadexitsall(nil);
    168 		break;
    169 	case 'w':
    170 		free(path);
    171 		path = strdup(ebuf + 1);
    172 		writepcm();
    173 		break;
    174 	case 'r':
    175 		free(path);
    176 		path = strdup(ebuf + 1);
    177 		readpcm();
    178 		redraw(nil, nil);
    179 		flushimage(display, 1);
    180 		break;
    181 	case 'l':
    182 		newlength = strtoull(ebuf + 1, &rpt, 0);
    183 		if ((rpt != ebuf + 1) && (newlength < MaxLength)) {
    184 			usize oldlength = length;
    185 			length = newlength;
    186 			int i;
    187 			if (oldlength != 0) {
    188 				for (i = oldlength; i < newlength; i++) pcm[i] = pcm[i%oldlength];
    189 			}
    190 			if (oldlength < newlength) {
    191 				redraw(pcm + oldlength, pcm + newlength);
    192 			} else {
    193 				draw(screen, rectaddpt(screen->r, Pt(newlength, 0)), bg, nil, ZP);
    194 			}
    195 			flushimage(display, 1);
    196 		}
    197 	}
    198 }
    199 
    200 void
    201 mouse(Mouse mv)
    202 {
    203 	u32int *buf;
    204 	Frame n;
    205 	int x, i, bsize, dir, h;
    206 	static Point oldpt;
    207 	Point pt = subpt(mv.xy, screen->r.min);
    208 	double d, val;
    209 
    210 	h = Dy(screen->r);
    211 	val = 1 - 2 * (double)pt.y / (double)h;
    212 
    213 	if (val < -1) val = -1;
    214 	if (val > 1) val = 1;
    215 	pt.y = val * (double)0x7fff;
    216 
    217 	switch (mv.buttons) {
    218 	case 0:
    219 		save();
    220 		oldpt = pt;
    221 		break;
    222 	case 1:
    223 		/* draw line in pcm from oldpt to pt) */
    224 		bsize = pt.x - oldpt.x;
    225 		dir = 1;
    226 		if (bsize < 0) bsize = -bsize, dir = -1;
    227 		for (
    228 		  i = 0, x = oldpt.x;
    229 		  x != pt.x;
    230 		  i++, x += dir) {
    231 			d = (double)i / (double)bsize;
    232 			n.c1 = (pt.y * d + oldpt.y * (1 - d));
    233 			n.c2 = n.c1;
    234 			if ((x >= 0) && (x < length)) {
    235 				Frame *fr = (Frame *)&pcm[x];
    236 				fr->c1 = n.c1;
    237 				fr->c2 = n.c2;
    238 			}
    239 		}
    240 		if ((pt.x >= 0) && (pt.x < length)) {
    241 			Frame *fr = (Frame *)&pcm[pt.x];
    242 		 	fr->c1 = pt.y;
    243 		 	fr->c2 = pt.y;
    244 		}
    245 
    246 		if (dir > 0) {
    247 			redraw(pcm + oldpt.x, pcm + pt.x + 2);
    248 		} else {
    249 			redraw(pcm + pt.x, pcm + oldpt.x + 2);
    250 		}
    251 		flushimage(display, 1);
    252 
    253 		oldpt = pt;
    254 		dirtyflag = 1;
    255 		break;
    256 	case 2:
    257 		/* shift pcm data left/right */
    258 		bsize = oldpt.x - pt.x;
    259 		while (bsize < 0) bsize += length;
    260 		bsize = (length == 0) ? 0 : bsize % length;
    261 
    262 		buf = malloc(length * 4);
    263 
    264 		memcpy(buf, pcm + bsize, (length - bsize) * 4);
    265 		memcpy(buf + length - bsize, pcm, (bsize) * 4);
    266 		memcpy(pcm, buf, length * 4);
    267 		free(buf);
    268 
    269 		redraw(nil, nil);
    270 		flushimage(display, 1);
    271 
    272 		oldpt = pt;
    273 		dirtyflag = 1;
    274 		break;
    275 	case 4:
    276 		/* menu */
    277 		x = menuhit(3, mctl, &menu, nil);
    278 		if (x >= 0) {
    279 			menucmd[x]();
    280 			redraw(nil, nil);
    281 			flushimage(display, 1);
    282 			dirtyflag = 1;
    283 		}
    284 		break;
    285 	}
    286 }
    287 
    288 void
    289 resize(int *)
    290 {
    291 	if (getwindow(display, Refnone) < 0) sysfatal("resize: %r");
    292 	draw(screen, screen->r, bg, nil, ZP);
    293 	redraw(nil, nil);
    294 	flushimage(display, 1);
    295 }
    296 
    297 void
    298 redraw(u32int *start, u32int *end)
    299 {
    300 	Frame *fr;
    301 	int h = Dy(screen->r);
    302 	int c = screen->r.min.y + h / 2;
    303 	int x, yv, yp = c;
    304 
    305 	if (start == nil) start = pcm;
    306 	if (end == nil) end = &pcm[length];
    307 	if (start > end) {
    308 		void *b;
    309 		b = end, end = start, start = b;
    310 	}
    311 	if (start > pcm) {
    312 		fr = (Frame *)(start - 1);
    313 		yp = c - (double)h * ((double)(fr->c1) / (double)0xffff);
    314 	}
    315 	if (start < pcm) start = pcm;
    316 	if (end > pcm + length) end = pcm + length;
    317 
    318 	u32int *p;
    319 	for (p = start, x = screen->r.min.x + (p - pcm); p < end; p++, x++) {
    320 		if (x > screen->r.max.x) break;
    321 
    322 		fr = (Frame *)p;
    323 		yv = c - (double)h * ((double)(fr->c1) / (double)0xffff);
    324 
    325 		Rectangle rlo, rhi;
    326 
    327 		rlo = canonrect(Rect(x, yv, x + 1, c));
    328 		rhi = canonrect(Rect(x, yv, x + 1, yp));
    329 		if (rhi.min.y == rhi.max.y) rhi.min.y--, rhi.max.y++;
    330 
    331 		draw(screen, Rect(x, screen->r.min.y, x + 1, screen->r.max.y), bg, nil, ZP);
    332 		draw(screen, rlo, lo, nil, ZP);
    333 		draw(screen, rhi, hi, nil, ZP);
    334 
    335 		yp = yv;
    336 	}
    337 }
    338 
    339 void
    340 sine(void)
    341 {
    342 	int i;
    343 	Frame *fr;
    344 	for (i = 0; i < length; i++) {
    345 		fr = (Frame *)&pcm[i];
    346 		fr->c1 = 0x7fff * sin((double)i / (double)length * PI * 2.0);
    347 		fr->c2 = fr->c1;
    348 	}	
    349 }
    350 
    351 void
    352 noise(void)
    353 {
    354 	int i;
    355 	Frame *fr;
    356 	srand(time(0) + lrand());
    357 	for (i = 0; i < length; i++) {
    358 		fr = (Frame *)&pcm[i];
    359 		fr->c1 = lrand() & 0xFFFF;
    360 		fr->c2 = fr->c1;
    361 	}
    362 }
    363 
    364 void
    365 save(void)
    366 {
    367 	if ((autosaveflag > 0) && (dirtyflag > 0)) {
    368 		writepcm();
    369 		dirtyflag = 0;
    370 	}
    371 }