amp.c (5793B)
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 9 enum { 10 DHeight = 32, 11 DCacheSize = 32, 12 Zoomout = 512, 13 Margin = 4, 14 }; 15 16 typedef struct DCache DCache; 17 struct DCache { 18 int c; 19 ulong start; 20 Image *img; 21 }; 22 23 DCache dcache[DCacheSize]; 24 25 s8int *pcm, *pp; 26 u8int *mono8; 27 long pcmlen, scroll; 28 Image *Ibg, *Itrbg, *Itrfg, *Irow; 29 Rectangle rbars; 30 int fid, dwidth, needflush, maxlines; 31 char *path; 32 33 void usage(void); 34 void clear(void); 35 void drawpcm(Point, ulong); 36 void drawcur(Point); 37 void redraw(ulong); 38 void resize(void); 39 void loadpcm(int); 40 u8int* mkmono8(s8int*, long); 41 int fillrow(ulong, ulong); 42 int row(int); 43 void drawscroll(int); 44 void threadflush(void *); 45 46 void 47 threadmain(int argc, char **argv) 48 { 49 Mousectl *mctl; 50 Keyboardctl *kctl; 51 Mouse mv; 52 Rune kv; 53 int rv[2]; 54 55 ARGBEGIN{ 56 default: 57 usage(); 58 }ARGEND; 59 60 if (argc == 0) usage(); 61 path = argv[0]; 62 fid = open(path, OREAD); 63 loadpcm(fid); 64 mono8 = mkmono8(pcm, pcmlen); 65 66 if (argc <= 0) usage(); 67 if(initdraw(0, 0, "amp") < 0) 68 sysfatal("inidraw failed: %r"); 69 if((mctl = initmouse(0, screen)) == nil) 70 sysfatal("initmouse failed: %r"); 71 if((kctl = initkeyboard(0)) == nil) 72 sysfatal("initkeyboard failed: %r"); 73 74 display->locking = 1; 75 unlockdisplay(display); 76 77 proccreate(threadflush, nil, 1024); 78 79 lockdisplay(display); 80 Ibg = allocimage(display, Rect(0,0,1,1), RGB24, 1, 0xBBBBBBFF); 81 Itrbg = allocimage(display, Rect(0,0,1,1), RGB24, 1, DWhite); 82 Itrfg = allocimage(display, Rect(0,0,1,1), RGB24, 1, DBlack); 83 resize(); 84 Irow = allocimage(display, Rect(0, 0, dwidth, DHeight), CMAP8, 0, DBlue); 85 clear(); 86 unlockdisplay(display); 87 redraw(0); 88 needflush = 1; 89 Alt alts[5] = { 90 {kctl->c, &kv, CHANRCV}, 91 {mctl->c, &mv, CHANRCV}, 92 {mctl->resizec, rv, CHANRCV}, 93 {0, 0, CHANEND}, 94 }; 95 for (;;) { 96 switch (alt(alts)) { 97 case 0: /* keyboard */ 98 if (kv == 0x7f) threadexitsall(nil); 99 if (kv == Kdown) drawscroll(maxlines/3); 100 if (kv == Kup) drawscroll(-maxlines/3); 101 if (kv == Kpgdown) drawscroll(maxlines); 102 if (kv == Kpgup) drawscroll(-maxlines); 103 break; 104 case 1: /* mouse */ 105 //if (mv.buttons == 0); 106 //if (mv.buttons == 1); 107 //if (mv.buttons == 4); 108 if (mv.buttons == 8) drawscroll(-row(mv.xy.y)); 109 if (mv.buttons == 16) drawscroll(row(mv.xy.y)); 110 break; 111 case 2: /* resize */ 112 lockdisplay(display); 113 if(getwindow(display, Refnone) < 0) 114 sysfatal("resize failed: %r"); 115 resize(); 116 freeimage(Irow); 117 Irow = allocimage(display, Rect(0, 0, dwidth, DHeight), 118 CMAP8, 0, DBlue); 119 clear(); 120 unlockdisplay(display); 121 redraw(scroll * dwidth); 122 needflush = 1; 123 break; 124 } 125 } 126 } 127 128 void 129 threadflush(void *) 130 { 131 threadsetname("flush"); 132 for (;;) { 133 if (needflush != 0) { 134 lockdisplay(display); 135 flushimage(display, 1); 136 unlockdisplay(display); 137 needflush = 0; 138 } 139 sleep(1000/60); 140 } 141 } 142 143 void 144 resize(void) 145 { 146 dwidth = Dx(screen->r) - Margin * 2; 147 rbars = screen->r; 148 rbars.min.x += Margin; 149 rbars.max.x -= Margin; 150 rbars.min.y += Margin; 151 rbars.max.y -= Margin; 152 if (scroll > pcmlen/(4 * Zoomout*dwidth)) 153 scroll = pcmlen/(4 * Zoomout*dwidth); 154 maxlines = Dy(rbars) / (DHeight + Margin); 155 } 156 157 void 158 usage(void) 159 { 160 fprint(2, "usage: %s file.pcm\n", argv0); 161 threadexitsall("usage"); 162 } 163 164 void 165 clear(void) 166 { 167 draw(screen, screen->r, Ibg, nil, ZP); 168 } 169 170 Image * 171 getmask(ulong start, ulong width) 172 { 173 Rectangle r; 174 r = Irow->r; 175 r.max.x = r.min.x + fillrow(start, width); 176 replclipr(Irow, 0, r); 177 return Irow; 178 } 179 180 void 181 drawpcm(Point p, ulong start) 182 { 183 Image *mask; 184 Rectangle r; 185 mask = getmask(start, dwidth); 186 r.min = p; 187 r.max.x = r.min.x + Dx(mask->clipr); 188 r.max.y = r.min.y + DHeight; 189 lockdisplay(display); 190 draw(screen, r, mask, 0, ZP); 191 unlockdisplay(display); 192 needflush = 1; 193 return; 194 } 195 196 void 197 redraw(ulong d) 198 { 199 Point p; 200 p = rbars.min; 201 while (p.y < screen->r.max.y) { 202 if (d > pcmlen/(4 * Zoomout)) break; 203 drawpcm(p, d); 204 d += dwidth; 205 p.y += DHeight + Margin; 206 } 207 } 208 209 void 210 loadpcm(int fd) 211 { 212 long n; 213 s8int *buf; 214 buf = malloc(32 * 1024); 215 pcmlen = 0; 216 while((n = read(fd, buf, 32 * 1024)) > 0){ 217 pcm = realloc(pcm, pcmlen + n); 218 memcpy(pcm + pcmlen, buf, n); 219 pcmlen += n; 220 } 221 pp = pcm; 222 free(buf); 223 } 224 225 int 226 fillrow(ulong start, ulong width) 227 { 228 u8int min, max; 229 uint dmin, dmax; 230 long end, bsize; 231 ulong n, i, j; 232 u8int *buf, *bp; 233 end = (start + width) * Zoomout; 234 if (end > pcmlen / 4) end = pcmlen / 4; 235 bsize = width * Dy(Irow->r); 236 buf = malloc(bsize); 237 bp = buf; 238 min = 0x7f; 239 max = -0x7f; 240 for (i=0, n=start*Zoomout; (n<end)&&(bp<buf+width); n++, i++) { 241 if (min > mono8[n]) min = mono8[n]; 242 if (max < mono8[n]) max = mono8[n]; 243 if (i >= Zoomout) { 244 i = 0; 245 dmin = min * DHeight / 256; 246 dmax = max * DHeight / 256; 247 for (j = 0; j < dmin; j++) *(bp + j * width) = 0xff; 248 for (j = dmin; j < dmax; j++) *(bp + j * width) = 0x00; 249 for (j = dmax; j < Dy(Irow->r); j++) *(bp + j * width) = 0xff; 250 min = 0x7f; 251 max = -0x7f; 252 bp++; 253 } 254 } 255 Rectangle r; 256 r = Irow->r; 257 r.max.x = r.min.x + width; 258 lockdisplay(display); 259 loadimage(Irow, r, buf, bsize); 260 unlockdisplay(display); 261 free(buf); 262 return bp - buf; 263 } 264 265 int 266 row(int y) 267 { 268 return 1 + (y - rbars.min.y) / (DHeight + Margin); 269 } 270 271 u8int* 272 mkmono8(s8int *pcm, long pcmlen) 273 { 274 long i, j; 275 u8int *mono8; 276 mono8 = malloc(sizeof(s8int) * pcmlen / 4); 277 for (i = 0, j = 0; i < pcmlen; i+=4, j++) { 278 mono8[j] = (pcm[i+1] + pcm[i+3] + 256) / 2; 279 } 280 return mono8; 281 } 282 283 void 284 drawscroll(int ds) 285 { 286 scroll += ds; 287 if (scroll < 0) { 288 ds -= scroll; 289 scroll = 0; 290 } 291 if (scroll > pcmlen / (4 * Zoomout * dwidth)) { 292 ds -= scroll - pcmlen / (4 * Zoomout * dwidth); 293 scroll = pcmlen / (4 * Zoomout * dwidth); 294 } 295 if (ds == 0) return; 296 lockdisplay(display); 297 clear(); 298 unlockdisplay(display); 299 needflush = 1; 300 redraw(scroll * dwidth); 301 }