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 }