stew

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

wfedit.c (9045B)


      1 /*
      2  * Waveform Editor
      3  */
      4 
      5 #include <u.h>
      6 #include <libc.h>
      7 #include <bio.h>
      8 #include <thread.h>
      9 #include <draw.h>
     10 #include <mouse.h>
     11 #include <cursor.h>
     12 #include <keyboard.h>
     13 
     14 #include "wavetable.h"
     15 
     16 enum {
     17 	BufMax = 6,
     18 	BufSize = sizeof(s16int) * WFSize,
     19 	MsgSize = 256,
     20 };
     21 
     22 typedef struct Cmdctl Cmdctl;
     23 typedef struct Uictl Uictl;
     24 
     25 typedef int (*cmdfunc)(Cmdctl *, int, char **);
     26 
     27 struct Cmdctl {
     28 	Channel *c;
     29 	Channel *updatec;
     30 };
     31 
     32 struct Uictl {
     33 	Mousectl *mctl;
     34 	Rectangle grid[BufMax];
     35 	Image *winbg, *wfbg, *hi, *lo;
     36 	Channel *updatec;
     37 };
     38 
     39 #define CMD(name) int name(Cmdctl *cmd, int argc, char **argv)
     40 CMD(cmdexit);
     41 CMD(cmdecho);
     42 CMD(cmdload);
     43 CMD(cmdsave);
     44 CMD(cmdnoise);
     45 CMD(cmdcos);
     46 CMD(cmdhex);
     47 CMD(cmdmove);
     48 CMD(cmdmap);
     49 CMD(cmdampmod);
     50 CMD(cmdphasemod);
     51 CMD(cmdadd);
     52 
     53 struct Dict{
     54 	const char *name;
     55 	cmdfunc cmd;
     56 };
     57 
     58 struct Dict dict[] = {
     59 	{"q", cmdexit},
     60 	{"exit", cmdexit},
     61 	{"quit", cmdexit},
     62 	{"bye", cmdexit},
     63 	{"echo", cmdecho},
     64 	{"load", cmdload},
     65 	{"save", cmdsave},
     66 	{"noise", cmdnoise},
     67 	{"cos", cmdcos},
     68 	{"hex", cmdhex},
     69 	{"move", cmdmove},
     70 	{"map", cmdmap},
     71 	{"amp", cmdampmod},
     72 	{"phase", cmdphasemod},
     73 	{"add", cmdadd},
     74 	{nil, nil},
     75 };
     76 
     77 
     78 void usage(void);
     79 void threadcmd(void *);
     80 s16int *buf[BufMax];
     81 cmdfunc getcmd(char *);
     82 
     83 Uictl *initui(void);
     84 void threadui(void *);
     85 void resize(Uictl *);
     86 void drawwaveform(Image *, Rectangle, s16int *, Image *, Image *, Image *);
     87 void drawgrid(Uictl *ui);
     88 
     89 Cmdctl cmdctl;
     90 Uictl *uictl;
     91 
     92 void
     93 threadmain(int argc, char **argv)
     94 {
     95 	int i;
     96 	for (i = 0; i < BufMax; i++) buf[i] = sbrk(BufSize);
     97 	ARGBEGIN {
     98 	default:
     99 		usage();
    100 	} ARGEND;
    101 	if (argc > 1) usage();
    102 
    103 	uictl = initui();
    104 
    105 	cmdctl.c = chancreate(MsgSize, 0);
    106 	cmdctl.updatec = uictl->updatec;
    107 	proccreate(threadcmd, &cmdctl, 64 * 1024);
    108 
    109 	if (argc == 1) {
    110 		cmdload(&cmdctl, 1, argv);
    111 	}
    112 
    113 	Biobuf *bfd = Bfdopen(0, OREAD);
    114 	char *s;
    115 	char cmdbuf[MsgSize];
    116 	while((s = Brdstr(bfd, '\n', 1)) != nil) {
    117 		memset(cmdbuf, 0, MsgSize);
    118 		strncpy(cmdbuf, s, MsgSize);
    119 		send(cmdctl.c, cmdbuf);
    120 		free(s);
    121 	}
    122 }
    123 
    124 void
    125 usage(void)
    126 {
    127 	fprint(2, "usage: %s [file]\n", argv0);
    128 	threadexitsall("usage");
    129 }
    130 
    131 void
    132 threadcmd(void *v)
    133 {
    134 	int n;
    135 	char cmdbuf[MsgSize], *args[64];
    136 	Cmdctl *rctl = v;
    137 	while (recv(rctl->c, cmdbuf) > 0) {
    138 		n = tokenize(cmdbuf, args, 64);
    139 		if (n <= 0) continue;
    140 		cmdfunc cmd = getcmd(args[0]);
    141 		if (cmd != nil) {
    142 			cmd(rctl, n - 1, args + 1);
    143 		} else fprint(2, "?\n");
    144 	}
    145 }
    146 
    147 cmdfunc
    148 getcmd(char *name)
    149 {
    150 	struct Dict *dp;
    151 	for (dp = dict; dp->name != nil; dp++) {
    152 		if (strcmp(dp->name, name) == 0) return dp->cmd;
    153 	}
    154 	return nil;
    155 }
    156 
    157 int
    158 cmdexit(Cmdctl *, int, char**)
    159 {
    160 	threadexitsall(nil);
    161 	return 0;
    162 }
    163 
    164 CMD(cmdecho)
    165 {
    166 	int i;
    167 	for (i = 0; i < argc; i++) {
    168 		if (i > 0) print(" ");
    169 		print("%s", argv[i]);
    170 	}
    171 	print("\n");
    172 	return 0;
    173 }
    174 
    175 CMD(cmdload)
    176 {
    177 	int fd;
    178 	if (argc == 0) {
    179 		fprint(2, "usage: load file\n");
    180 		return 1;
    181 	}
    182 	fd = open(argv[0], OREAD);
    183 	if (fd < 0) {
    184 		fprint(2, "cmdload: %r\n");
    185 		return 1;
    186 	}
    187 	read(fd, buf[0], WFSize * sizeof(s16int));
    188 	close(fd);
    189 	if (cmd->updatec != nil) nbsendul(cmd->updatec, 0);
    190 	return 0;
    191 }
    192 
    193 CMD(cmdsave)
    194 {
    195 	int fd;
    196 	if (argc == 0) {
    197 		fprint(2, "usage: save file\n");
    198 		return 1;
    199 	}
    200 	fd = create(argv[0], OWRITE, 0666);
    201 	if (fd < 0) {
    202 		fprint(2, "cmdsave: %r\n");
    203 		return 1;
    204 	}
    205 	write(fd, buf[0], WFSize * sizeof(s16int));
    206 	close(fd);
    207 	if (cmd->updatec != nil) nbsendul(cmd->updatec, 0);
    208 	return 0;
    209 }
    210 
    211 CMD(cmdnoise)
    212 {
    213 	int i;
    214 	ulong targ = 0;
    215 	if (argc > 1) {
    216 		fprint(2, "usage: noise [targ]\n");
    217 		return 1;
    218 	}
    219 	if (argc == 1) targ = atoi(argv[0]);
    220 	if (targ > BufMax) {
    221 		fprint(2, "invalid targ\n");
    222 		return 1;
    223 	}
    224 	for (i = 0; i < WFSize; i++) {
    225 		buf[targ][i] = truerand();
    226 	}
    227 	if (cmd->updatec != nil) nbsendul(cmd->updatec, targ);
    228 	return 0;
    229 }
    230 
    231 CMD(cmdcos)
    232 {
    233 	int i;
    234 	ulong targ = 0;
    235 	if (argc > 1) {
    236 		fprint(2, "usage: noise [targ]\n");
    237 		return 1;
    238 	}
    239 	if (argc == 1) targ = atoi(argv[0]);
    240 	if (targ > BufMax) {
    241 		fprint(2, "invalid targ\n");
    242 		return 1;
    243 	}
    244 	for (i = 0; i < WFSize; i++) {
    245 		buf[targ][i] = cos((double)i / WFSize * PI * 2) * 0x7fff;
    246 	}
    247 	if (cmd->updatec != nil) nbsendul(cmd->updatec, targ);
    248 	return 0;
    249 }
    250 
    251 CMD(cmdhex)
    252 {
    253 	if (argc > 2) {
    254 		fprint(2, "usage: hex val [targ]\n");
    255 		return 1;
    256 	}
    257 	s16int val = strtol(argv[0], nil, 16);
    258 	int targ = 0;
    259 	if (argc == 2) targ = atoi(argv[1]);
    260 	int i;
    261 	for (i = 0; i < WFSize; i++) buf[targ][i] = val;
    262 	if (cmd->updatec != nil) nbsendul(cmd->updatec, targ);
    263 	return 0;
    264 }
    265 
    266 
    267 CMD(cmdmove)
    268 {
    269 	if (argc != 2) {
    270 		fprint(2, "usage: move src targ\n");
    271 		return 1;
    272 	}
    273 	int src = atoi(argv[0]);
    274 	int targ = atoi(argv[1]);
    275 	memcpy(buf[targ], buf[src], WFSize * sizeof(s16int));
    276 	if (cmd->updatec != nil) nbsendul(cmd->updatec, targ);
    277 	return 0;
    278 }
    279 
    280 CMD(cmdmap)
    281 {
    282 	if ((argc < 2) && (argc > 3)) {
    283 		fprint(2, "usage: map mod src [targ]\n");
    284 		return 1;
    285 	}
    286 	int mod = atoi(argv[0]);
    287 	int src = atoi(argv[1]);
    288 	int targ = 0;
    289 	if (argc == 3) targ = atoi(argv[2]);
    290 	int i;
    291 	for (i = 0; i < WFSize; i++) {
    292 		int d = (buf[mod][i] + 0x8000) * WFSize / 0xffff;
    293 		buf[targ][i] = buf[src][d];
    294 	}
    295 	if (cmd->updatec != nil) nbsendul(cmd->updatec, targ);
    296 	return 0;
    297 }
    298 
    299 CMD(cmdampmod)
    300 {
    301 	if ((argc < 2) && (argc > 3)) {
    302 		fprint(2, "usage: amp mod src [targ]\n");
    303 		return 1;
    304 	}
    305 	int mod = atoi(argv[0]);
    306 	int src = atoi(argv[1]);
    307 	int targ = 0;
    308 	if (argc == 3) targ = atoi(argv[2]);
    309 	int i;
    310 	for (i = 0; i < WFSize; i++) {
    311 		int d = buf[mod][i] * buf[src][i] / 0x8000;
    312 		if (d > 0x7fff) d = 0x7fff;
    313 		if (d < -0x8000) d = -0x8000;
    314 		buf[targ][i] = d;
    315 	}
    316 	if (cmd->updatec != nil) nbsendul(cmd->updatec, targ);
    317 	return 0;
    318 }
    319 
    320 CMD(cmdphasemod)
    321 {
    322 	if ((argc < 3) && (argc > 4)) {
    323 		fprint(2, "usage: phase amp mod src [targ]\n");
    324 		return 1;
    325 	}
    326 	double amp = strtod(argv[0], nil);
    327 	int mod = atoi(argv[1]);
    328 	int src = atoi(argv[2]);
    329 	int targ = 0;
    330 	if (argc == 4) targ = atoi(argv[3]);
    331 	int i;
    332 	for (i = 0; i < WFSize; i++) {
    333 		int d = i + (buf[mod][i] + 0x8000) * amp * WFSize / 0xffff;
    334 		d = d % WFSize;
    335 		buf[targ][i] = buf[src][d];
    336 	}
    337 	if (cmd->updatec != nil) nbsendul(cmd->updatec, targ);
    338 	return 0;
    339 }
    340 
    341 CMD(cmdadd)
    342 {
    343 	int n = 0;
    344 	if ((argc < 2) && (argc > 3)) {
    345 		fprint(2, "usage: add mod src [targ]\n");
    346 		return 1;
    347 	}
    348 	int mod = atoi(argv[n++]);
    349 	int src = atoi(argv[n++]);
    350 	int targ = 0;
    351 	if (argc == 3) targ = atoi(argv[n++]);
    352 	int i;
    353 	for (i = 0; i < WFSize; i++) {
    354 		s16int d = buf[mod][i] + buf[src][i];
    355 		
    356 		buf[targ][i] = d;
    357 	}
    358 	if (cmd->updatec != nil) nbsendul(cmd->updatec, targ);
    359 	return 0;
    360 
    361 }
    362 
    363 
    364 Uictl *
    365 initui(void)
    366 {
    367 	Uictl *ui = mallocz(sizeof(Uictl), 1);
    368 	newwindow(nil);
    369 	if (initdraw(nil, nil, "wfedit") < 0) sysfatal("%r");
    370 	if ((ui->mctl = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r");
    371 	ui->winbg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1 , DWhite);
    372 	ui->wfbg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1 , DBlack);
    373 	ui->hi = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1 , DRed);
    374 	ui->lo = allocimagemix(display, DRed, DBlack);
    375 	ui->updatec = chancreate(sizeof(ulong), BufMax);
    376 	resize(ui);
    377 	proccreate(threadui, ui, 64 * 1024);
    378 	return ui;
    379 }
    380 
    381 void
    382 threadui(void *v)
    383 {
    384 	ulong upd;
    385 	Uictl *ui = v;
    386 
    387 	draw(screen, screen->r, ui->winbg, nil, ZP);
    388 	nbsendul(ui->updatec, -1);
    389 
    390 	Alt alts[] = {
    391 		{ui->mctl->resizec, nil, CHANRCV},
    392 		{ui->mctl->c, nil, CHANRCV},
    393 		{ui->updatec, &upd, CHANRCV},
    394 		{nil, nil, CHANEND},
    395 	};
    396 
    397 	for (;;) {
    398 		switch (alt(alts)) {
    399 		case 0: /* resize */
    400 			if (getwindow(display, Refnone) < 0) sysfatal("resize: %r");
    401 			resize(ui);
    402 			draw(screen, screen->r, ui->winbg, nil, ZP);
    403 			nbsendul(ui->updatec, -1);
    404 			break;
    405 		case 1: /* mouse */
    406 			break;
    407 		case 2: /* update */
    408 			if (upd >= BufMax) drawgrid(ui);
    409 			else {
    410 				drawwaveform(screen, ui->grid[upd], buf[upd], ui->wfbg, ui->hi, ui->lo);
    411 			};
    412 			flushimage(display, 1);
    413 			break;
    414 		}
    415 	}
    416 }
    417 
    418 void
    419 resize(Uictl *ui)
    420 {
    421 	int i;
    422 	Point min, max, mid;
    423 	Rectangle l, r, scr;
    424 	scr = insetrect(screen->r, 1);
    425 	min = scr.min;
    426 	max = scr.max;
    427 	mid = addpt(min, Pt(Dx(scr)/2, Dy(scr)/(BufMax/2)));
    428 	l = Rpt(min, mid);
    429 	r = Rect(mid.x, min.y, max.x, mid.y);
    430 	for (i = 0; i < BufMax; i+=2) {
    431 		ui->grid[i] = insetrect(l, 1);
    432 		ui->grid[i + 1] = insetrect(r, 1);
    433 		l = rectaddpt(l, Pt(0, Dy(l)));
    434 		r = rectaddpt(r, Pt(0, Dy(r)));
    435 	}
    436 }
    437 
    438 void
    439 drawwaveform(Image *screen, Rectangle r, s16int *wf, Image *bg, Image *hi, Image *lo)
    440 {
    441 	Rectangle bar;
    442 	int i, w, h, mid, s, e, m1, m2;
    443 	w = Dx(r);
    444 	h = Dy(r);
    445 	mid = h/2;
    446 	draw(screen, r, bg, nil, ZP);
    447 	for (i = 0; i < w; i++) {
    448 		s = i * WFSize / w;
    449 		e = (i == w - 1) ? 0 : (i + 1) * WFSize / w;
    450 		m1 = wf[s] * mid / 0x7fff;
    451 		m2 = wf[e] * mid / 0x7fff;
    452 		if (m1 == m2) m1 += (m1 > 0) ? -1 : +1;
    453 		bar = Rpt(Pt(i, mid), Pt(i + 1, mid - m1));
    454 		bar = canonrect(bar);
    455 		bar = rectaddpt(bar, r.min);
    456 		draw(screen, bar, lo, nil, ZP);
    457 		bar = Rpt(Pt(i, mid - m2), Pt(i + 1, mid - m1));
    458 		bar = canonrect(bar);
    459 		bar = rectaddpt(bar, r.min);
    460 		draw(screen, bar, hi, nil, ZP);
    461 	}
    462 }
    463 
    464 void
    465 drawgrid(Uictl *ui)
    466 {
    467 	int i;
    468 	for (i = 0; i < BufMax; i++) {
    469 		drawwaveform(screen, ui->grid[i], buf[i], ui->wfbg, ui->hi, ui->lo);
    470 	}
    471 }