amp.c (13044B)
1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <thread.h> 5 #include <mouse.h> 6 #include <cursor.h> 7 #include <keyboard.h> 8 #include <plumb.h> 9 10 enum { 11 FrameSize = sizeof(s16int) * 2, 12 PBufLen = 1024 * FrameSize, 13 DHeight = 32, 14 MaskCacheSize = 256, 15 ScrollBarWidth = 12, 16 Margin = 4, 17 18 PStop = 0, 19 PPlay = 1, 20 PPause = 2, 21 }; 22 23 Image * getmask(int); 24 long decoord(Point); 25 int row(int); 26 void clearcursor(void); 27 void clearmask(void); 28 void drawcursor(void); 29 void drawmask(Image *, int); 30 void drawpcm(Point, int); 31 void drawscroll(int); 32 void drawscrollbar(void); 33 void loadpcm(int); 34 void mouseidle(Mouse); 35 void mousescroll(Mouse); 36 void mouseselect(Mouse); 37 void mexit(void); 38 void mplumb(void); 39 void mredraw(void); 40 void msnarf(void); 41 void mwrite(void); 42 void mzoom(void); 43 void redraw(void); 44 void resize(void); 45 void setselect(long, long); 46 void threadflush(void *); 47 void threadplay(void *); 48 void threadplumb(void *); 49 void usage(void); 50 51 long monolen, scroll, smin, smax, ss, se, Zoomout = 512; 52 Image *Ibg, *Itrbg, *Itrfg, *Icur; 53 Rectangle rscroll, rbars; 54 int dwidth, needflush, maxbars; 55 char wpath[1024]; 56 Mousectl *mctl; 57 Keyboardctl *kctl; 58 char *menustr[] = {"snarf", "plumb", "redraw", "write", "zoom", "exit", nil}; 59 void (*menufunc[])(void) = {msnarf, mplumb, mredraw, mwrite, mzoom, mexit}; 60 void (*mousefp)(Mouse) = mouseidle; 61 Menu menu = {menustr, nil, 0}; 62 struct { 63 int send, recv; 64 char *port; 65 } plumb = {.port = "amp"}; 66 struct { 67 s8int *p; 68 int fid, len, mtime; 69 char *path; 70 } pcm; 71 struct { 72 char *path; 73 s8int *p; 74 int fid, state; 75 vlong len, cur; 76 } play = {.path = "/dev/audio"}; 77 struct { 78 Image *img[MaskCacheSize]; 79 int id[MaskCacheSize]; 80 } mask; 81 82 void 83 threadmain(int argc, char **argv) 84 { 85 Mouse mv; 86 Rune kv; 87 int rv[2]; 88 89 ARGBEGIN{ 90 default: 91 usage(); 92 }ARGEND; 93 94 if (argc == 0) usage(); 95 pcm.path = argv[0]; 96 pcm.fid = open(pcm.path, OREAD); 97 loadpcm(pcm.fid); 98 monolen = pcm.len / FrameSize; 99 100 plumb.send = plumbopen("send", OWRITE); 101 if (plumb.send < 0) fprint(2, "%r\n"); 102 plumb.recv = plumbopen(plumb.port, OREAD); 103 if (plumb.recv <0) fprint(2, "%r\n"); 104 105 if(initdraw(0, 0, "amp") < 0) 106 sysfatal("inidraw failed: %r"); 107 if((mctl = initmouse(0, screen)) == nil) 108 sysfatal("initmouse failed: %r"); 109 if((kctl = initkeyboard(0)) == nil) 110 sysfatal("initkeyboard failed: %r"); 111 112 display->locking = 1; 113 unlockdisplay(display); 114 115 proccreate(threadflush, nil, 1024); 116 proccreate(threadplumb, nil, 1024); 117 proccreate(threadplay, nil, 1024); 118 119 lockdisplay(display); 120 Ibg = allocimage(display, Rect(0,0,1,1), RGB24, 1, 0xBBBBBBFF); 121 Itrbg = allocimage(display, Rect(0,0,1,1), RGB24, 1, DWhite); 122 Itrfg = allocimage(display, Rect(0,0,1,1), RGB24, 1, DBlack); 123 Icur = allocimage(display, Rect(0,0,1,1), RGB24, 1, DRed); 124 resize(); 125 clearmask(); 126 unlockdisplay(display); 127 redraw(); 128 Alt alts[5] = { 129 {kctl->c, &kv, CHANRCV}, 130 {mctl->c, &mv, CHANRCV}, 131 {mctl->resizec, rv, CHANRCV}, 132 {0, 0, CHANEND}, 133 }; 134 for (;;) { 135 switch (alt(alts)) { 136 case 0: /* keyboard */ 137 if (kv == 0x7f) threadexitsall(nil); 138 if (kv == Kdown) drawscroll(maxbars/3); 139 if (kv == Kup) drawscroll(-maxbars/3); 140 if (kv == Kpgdown) drawscroll(maxbars); 141 if (kv == Kpgup) drawscroll(-maxbars); 142 if (kv == ' ') play.state = (play.state == PPlay) ? PPause : PPlay; 143 break; 144 case 1: /* mouse */ 145 mousefp(mv); 146 break; 147 case 2: /* resize */ 148 lockdisplay(display); 149 if(getwindow(display, Refnone) < 0) 150 sysfatal("resize failed: %r"); 151 resize(); 152 clearmask(); 153 unlockdisplay(display); 154 redraw(); 155 break; 156 } 157 } 158 } 159 160 void 161 threadflush(void *) 162 { 163 threadsetname("flush"); 164 for (;;) { 165 if (needflush != 0) { 166 lockdisplay(display); 167 flushimage(display, 1); 168 unlockdisplay(display); 169 needflush = 0; 170 } 171 sleep(1000/60); 172 } 173 } 174 175 void 176 threadplumb(void *) 177 { 178 Plumbmsg *m; 179 long s, e; 180 if (plumb.recv < 0) return; 181 threadsetname("plumb"); 182 for (;;) { 183 m = plumbrecv(plumb.recv); 184 if (m->ndata < 24) fprint(2, "plumb message too short\n"); 185 else if (strcmp(m->src, "amp") != 0){ 186 s = strtol(m->data, nil, 10); 187 e = strtol(m->data + 12, nil, 10); 188 setselect(s / (Zoomout * FrameSize), e / (Zoomout * FrameSize)); 189 } 190 plumbfree(m); 191 } 192 } 193 194 void 195 threadplay(void *) 196 { 197 vlong n, pend; 198 if ((play.fid = open(play.path, OWRITE)) < 0) { 199 fprint(2, "%r\n"); 200 return; 201 } 202 play.p = malloc(PBufLen); 203 if (play.p == nil) sysfatal("%r"); 204 for (;;) { 205 switch (play.state) { 206 case PStop: 207 play.cur = smin * Zoomout * FrameSize; 208 case PPause: 209 sleep(1000/60); 210 break; 211 case PPlay: 212 pend = (smin != smax) ? smax * Zoomout * FrameSize : pcm.len; 213 n = (PBufLen < pend - play.cur) ? PBufLen : pend - play.cur; 214 n = pread(pcm.fid, play.p, n, play.cur); 215 n = write(play.fid, play.p, n); 216 clearcursor(); 217 play.cur += n; 218 drawcursor(); 219 if (play.cur >= pend) play.state = PStop; 220 needflush = 1; 221 } 222 } 223 } 224 225 void 226 mouseidle(Mouse mv) 227 { 228 int n; 229 if ((mv.buttons != 0) && (ptinrect(mv.xy, rscroll) != 0)) { 230 mousefp = mousescroll; 231 mousescroll(mv); 232 } else switch(mv.buttons) { 233 case 1: 234 mousefp = mouseselect; 235 ss = decoord(mv.xy) / (Zoomout * FrameSize); 236 mouseselect(mv); 237 break; 238 case 4: 239 n = menuhit(3, mctl, &menu, nil); 240 if (n >= 0) menufunc[n](); 241 break; 242 case 8: 243 drawscroll(-1-row(mv.xy.y)); 244 break; 245 case 16: 246 drawscroll(1+row(mv.xy.y)); 247 break; 248 } 249 } 250 251 void 252 mousescroll(Mouse mv) 253 { 254 int tl; 255 switch(mv.buttons) { 256 case 0: 257 mousefp = mouseidle; 258 break; 259 case 1: 260 drawscroll(-1-row(mv.xy.y)); 261 break; 262 case 2: 263 tl = pcm.len / (FrameSize * Zoomout * dwidth); 264 scroll = tl * (mv.xy.y - rscroll.min.y) / Dy(rscroll); 265 if (scroll > tl) scroll = tl; 266 if (scroll < 0) scroll = 0; 267 redraw(); 268 needflush = 1; 269 break; 270 case 4: 271 drawscroll(1+row(mv.xy.y)); 272 break; 273 case 8: 274 drawscroll(-1-row(mv.xy.y)); 275 break; 276 case 16: 277 drawscroll(1+row(mv.xy.y)); 278 break; 279 } 280 } 281 282 void 283 mouseselect(Mouse mv) 284 { 285 if (mv.buttons == 0) { 286 mousefp = mouseidle; 287 return; 288 } 289 se = decoord(mv.xy) / (Zoomout * FrameSize); 290 setselect(ss, se); 291 } 292 293 void 294 resize(void) 295 { 296 rscroll = screen->r; 297 rscroll.min.x += Margin; 298 rscroll.min.y += Margin; 299 rscroll.max.x = rscroll.min.x + ScrollBarWidth; 300 rscroll.max.y -= Margin; 301 302 rbars = screen->r; 303 rbars.min.x += 2 * Margin + ScrollBarWidth; 304 rbars.max.x -= Margin; 305 rbars.min.y += Margin; 306 rbars.max.y -= Margin; 307 dwidth = Dx(rbars); 308 if (scroll > pcm.len/(FrameSize * Zoomout * dwidth)) 309 scroll = pcm.len/(FrameSize * Zoomout * dwidth); 310 maxbars = Dy(rbars) / (DHeight + Margin); 311 } 312 313 void 314 usage(void) 315 { 316 fprint(2, "usage: %s file.pcm\n", argv0); 317 threadexitsall("usage"); 318 } 319 320 Image * 321 getmask(int n) 322 { 323 int m; 324 m = n % MaskCacheSize; 325 if (mask.id[m] != n) { 326 mask.id[m] = n; 327 if (mask.img[m] == nil) { 328 mask.img[m] = allocimage(display, Rect(0, 0, dwidth, DHeight), 329 CMAP8, 0, DBlue); 330 } 331 drawmask(mask.img[m], n); 332 } 333 return mask.img[m]; 334 } 335 336 void 337 drawpcm(Point p, int n) 338 { 339 Image *mask; 340 Rectangle r; 341 long w; 342 ulong start; 343 mask = getmask(n); 344 r.min = p; 345 r.max.x = p.x + Dx(mask->clipr); 346 r.max.y = p.y + DHeight; 347 if (r.max.y > rbars.max.y) r.max.y = rbars.max.y; 348 start = n * dwidth; 349 lockdisplay(display); 350 if (start < smin) { 351 w = smin - start; 352 if (w > Dx(r)) w = Dx(r); 353 r.max.x = r.min.x + w; 354 draw(screen, r, mask, 0, ZP); 355 start += w; 356 r.min.x += w; 357 r.max.x = p.x + Dx(mask->clipr); 358 } 359 if (start < smax) { 360 w = smax - start; 361 if (w > Dx(r)) w = Dx(r); 362 r.max.x = r.min.x + w; 363 draw(screen, r, Itrbg, 0, ZP); 364 draw(screen, r, Itrfg, mask, Pt(r.min.x - p.x, 0)); 365 start += w; 366 r.min.x += w; 367 r.max.x = p.x + Dx(mask->clipr); 368 } 369 if ((start >= smax)) { 370 draw(screen, r, mask, 0, Pt(r.min.x - p.x, 0)); 371 } 372 unlockdisplay(display); 373 needflush = 1; 374 375 return; 376 } 377 378 void 379 redraw(void) 380 { 381 int d; 382 Point p; 383 p = rbars.min; 384 lockdisplay(display); 385 draw(screen, screen->r, Ibg, nil, ZP); 386 unlockdisplay(display); 387 drawscrollbar(); 388 d = scroll; 389 while (p.y < screen->r.max.y) { 390 if (d * dwidth > pcm.len / (FrameSize * Zoomout)) break; 391 drawpcm(p, d); 392 d++; 393 p.y += DHeight + Margin; 394 } 395 drawcursor(); 396 } 397 398 void 399 loadpcm(int fd) 400 { 401 long n; 402 s8int *buf; 403 buf = malloc(32 * 1024); 404 pcm.len = 0; 405 while((n = read(fd, buf, 32 * 1024)) > 0){ 406 pcm.p = realloc(pcm.p, pcm.len + n); 407 memcpy(pcm.p + pcm.len, buf, n); 408 pcm.len += n; 409 } 410 free(buf); 411 } 412 413 void 414 drawmask(Image *mask, int bn) 415 { 416 Rectangle r; 417 int min, max, mono; 418 long bsize; 419 s8int *rbuf; 420 u8int *buf, *bp; 421 uint dmin, dmax; 422 ulong n, i, j, rlen, FZ, start; 423 start = bn * dwidth; 424 FZ = FrameSize * Zoomout; 425 rbuf = malloc(dwidth * FZ); 426 rlen = pread(pcm.fid, rbuf, dwidth * FZ, start * FZ); 427 bsize = dwidth * DHeight; 428 buf = mallocz(bsize, 1); 429 bp = buf; 430 min = 0xff; 431 max = 0; 432 i = 0; 433 for (n = 0; (n < rlen) && (bp < buf + dwidth); n += FrameSize) { 434 mono = (rbuf[n + 1] + rbuf[n + 3] + 0xff) / 2; 435 if (min > mono) min = mono; 436 if (max < mono) max = mono; 437 if (i >= Zoomout - 1) { 438 i = 0; 439 dmin = min * DHeight / 256; 440 dmax = max * DHeight / 256; 441 if (dmin == dmax) dmax++; 442 for (j = 0; j < dmin; j++) *(bp + j * dwidth) = 0xff; 443 for (j = dmin; j < dmax; j++) *(bp + j * dwidth) = 0x00; 444 for (j = dmax; j < Dy(mask->r); j++) *(bp + j * dwidth) = 0xff; 445 min = 0xff; 446 max = 0; 447 bp++; 448 } else i++; 449 } 450 r = mask->r; 451 r.max.x = r.min.x + rlen / FZ; 452 lockdisplay(display); 453 loadimage(mask, mask->r, buf, bsize); 454 replclipr(mask, 0, r); 455 unlockdisplay(display); 456 free(buf); 457 free(rbuf); 458 } 459 460 int 461 row(int y) 462 { 463 return (y - rbars.min.y) / (DHeight + Margin); 464 } 465 466 void 467 drawscroll(int ds) 468 { 469 scroll += ds; 470 if (scroll < 0) { 471 ds -= scroll; 472 scroll = 0; 473 } 474 if (scroll > monolen / (Zoomout * dwidth)) { 475 ds -= scroll - monolen / (Zoomout * dwidth); 476 scroll = monolen / (Zoomout * dwidth); 477 } 478 if (ds == 0) return; 479 redraw(); 480 needflush = 1; 481 } 482 483 void 484 drawscrollbar(void) 485 { 486 Rectangle r, br; 487 int tl, offset, width; 488 r = rscroll; 489 490 tl = pcm.len / (FrameSize * Zoomout * dwidth); 491 492 offset = scroll * Dy(rbars) / tl; 493 width = maxbars * Dy(rbars) / tl; 494 495 br = Rect( 496 r.min.x, 497 r.min.y + offset, 498 r.max.x, 499 r.min.y + offset + width); 500 if (br.max.y > r.max.y) br.max.y = r.max.y; 501 lockdisplay(display); 502 draw(screen, r, Itrbg, nil, ZP); 503 draw(screen, br, Itrfg, nil, ZP); 504 unlockdisplay(display); 505 } 506 507 void 508 msnarf(void) 509 { 510 int fd, n, min, max; 511 char buf[25]; 512 min = smin * Zoomout * FrameSize; 513 max = smax * Zoomout * FrameSize; 514 n = snprint(buf, 25, "%11d %11d ", min, max); 515 if ((fd = open("/dev/snarf", OWRITE)) < 0) { 516 fprint(2, "%r\n"); 517 return; 518 } 519 write(fd, buf, n); 520 close(fd); 521 } 522 523 void 524 mplumb(void) 525 { 526 int min, max; 527 min = smin * Zoomout * FrameSize; 528 max = smax * Zoomout * FrameSize; 529 Plumbmsg *m; 530 m = mallocz(sizeof(Plumbmsg), 1); 531 m->src = smprint("amp"); 532 m->dst = strdup(plumb.port); 533 m->type = strdup("text"); 534 m->data = smprint("%11d %11d ", min, max); 535 m->ndata = strlen(m->data); 536 plumbsend(plumb.send, m); 537 plumbfree(m); 538 } 539 540 void 541 mredraw(void) 542 { 543 clearmask(); 544 redraw(); 545 } 546 547 void 548 mwrite(void) 549 { 550 int n, fd; 551 long min, max; 552 n = enter("write to:", wpath, 1024, mctl, kctl, nil); 553 if (n <= 0) return; 554 if ((fd = create(wpath, OWRITE, 0666)) < 0) { 555 fprint(2, "%r\n"); 556 return; 557 } 558 min = smin * Zoomout * FrameSize; 559 max = smax * Zoomout * FrameSize; 560 write(fd, pcm.p + min, max - min); 561 close(fd); 562 } 563 564 void 565 mzoom(void) 566 { 567 int n; 568 long nz; 569 char *s = malloc(1024); 570 snprint(s, 1024, "%ld", Zoomout); 571 n = enter("zoom", s, 1024, mctl, kctl, nil); 572 if (n <= 0) goto end; 573 nz = strtol(s, nil, 10); 574 if (nz > 0) { 575 Zoomout = nz; 576 clearmask(); 577 redraw(); 578 } 579 end: 580 free(s); 581 } 582 583 void 584 mexit(void) 585 { 586 threadexitsall(nil); 587 } 588 589 void 590 setselect(long s, long e) 591 { 592 if (s < e) smin = s, smax = e; 593 else smax = s, smin = e; 594 play.state = PStop; 595 play.cur = smin * FrameSize * Zoomout; 596 redraw(); 597 } 598 599 void 600 clearcursor(void) 601 { 602 int b, n, m; 603 Rectangle r; 604 Image *mask, *bg, *fg; 605 b = play.cur / (FrameSize * Zoomout); 606 n = b / dwidth; 607 m = b % dwidth; 608 if ((n < scroll) || (n >= scroll + maxbars)) return; 609 mask = getmask(n); 610 611 n -= scroll; 612 r.min.y = rbars.min.y + n * (DHeight + Margin); 613 r.max.y = r.min.y + DHeight; 614 r.min.x = rbars.min.x + m; 615 r.max.x = r.min.x + 1; 616 617 if ((b < smin) || (b >= smax)) { 618 bg = Itrfg; 619 fg = Itrbg; 620 } else { 621 bg = Itrbg; 622 fg = Itrfg; 623 } 624 lockdisplay(display); 625 draw(screen, r, bg, 0, ZP); 626 draw(screen, r, fg, mask, Pt(m, 0)); 627 unlockdisplay(display); 628 needflush = 1; 629 } 630 631 void 632 drawcursor(void) 633 { 634 int b, n, m; 635 Rectangle r; 636 b = play.cur / (FrameSize * Zoomout); 637 n = b / dwidth; 638 m = b % dwidth; 639 if ((n < scroll) || (n >= scroll + maxbars)) return; 640 n -= scroll; 641 r.min.y = rbars.min.y + n * (DHeight + Margin); 642 r.max.y = r.min.y + DHeight; 643 r.min.x = rbars.min.x + m; 644 r.max.x = r.min.x + 1; 645 646 647 lockdisplay(display); 648 draw(screen, r, Icur, 0, ZP); 649 unlockdisplay(display); 650 needflush = 1; 651 } 652 653 void 654 clearmask(void) 655 { 656 int i; 657 for (i = 0; i < MaskCacheSize; i++) { 658 mask.id[i] = -1; 659 if (mask.img[i] != nil) { 660 freeimage(mask.img[i]); 661 mask.img[i] = nil; 662 } 663 } 664 } 665 666 long 667 decoord(Point xy) 668 { 669 long p; 670 p = ((scroll + row(xy.y)) * dwidth + xy.x - rbars.min.x) * Zoomout * FrameSize; 671 if (p < 0) p = 0; 672 if (p > pcm.len) { 673 p = pcm.len; 674 } 675 return p; 676 }