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 }