ref: f274c92b3e2b60f2c2b0b56cf94cd8f0a758748b
dir: /plan9.c/
#include "plan9.h" #include "field.h" #include "gbuffer.h" #include "sim.h" #include <draw.h> #include <mouse.h> #include <keyboard.h> #include <thread.h> #define MIN(x,y) ((x)<(y)?(x):(y)) #define MAX(x,y) ((x)>(y)?(x):(y)) enum { Txtoff = 16, }; static struct { u8int u[4]; Usz at; }noteoff[16*128]; /* 16 channels, 128 notes each */ static Rune *linebuf; static Usz tick; static int gridw = 8, gridh = 8; static int curx, cury; static Image *curbg; Usz orca_round_up_power2(Usz x) { x -= 1; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; return x + 1; } bool orca_is_valid_glyph(Glyph c) { if (c >= '0' && c <= '9') return true; if (c >= 'A' && c <= 'Z') return true; if (c >= 'a' && c <= 'z') return true; switch (c) { case '!': case '#': case '%': case '*': case '.': case ':': case ';': case '=': case '?': return true; } return false; } static void process(Oevent_list *events) { int i, off; Oevent *e; u8int u[4]; for (e = events->buffer, i = 0; i < events->count; i++, e++) { if (e->any.oevent_type == Oevent_type_midi_note) { Oevent_midi_note const *n = &e->midi_note; u[0] = 1; u[1] = 0x90 | n->channel; u[2] = (n->octave + 1)*12 + n->note; u[3] = n->velocity; write(1, u, 4); off = n->channel*128 + u[2]; noteoff[off].u[1] = 0x80 | n->channel; noteoff[off].u[2] = u[2]; noteoff[off].u[3] = 0; noteoff[off].at = tick + n->duration; } } sleep(150); for (i = 0; i < nelem(noteoff); i++) { if (noteoff[i].at > 0 && noteoff[i].at < tick) { write(1, noteoff[i].u, 4); noteoff[i].at = 0; } } } static void redraw(Field *f) { Point p, top; Rune cursor; int x, y; draw(screen, screen->r, display->black, nil, ZP); p = screen->r.min; p.x += Txtoff; p.y += Txtoff; top = p; for (y = 0; y < f->height; y++) { for (x = 0; x < f->width; x++) { Rune c = f->buffer[f->width*y + x]; if (c == L'.') c = L'·'; linebuf[x] = c; if (y == cury && x == curx) cursor = c; } linebuf[x] = 0; runestring(screen, p, display->white, ZP, font, linebuf); p.y += font->height; } p.y += 2 * font->height; p.x = screen->r.min.x + Txtoff; runesprint(linebuf, "%udx%ud", f->width, f->height); runestring(screen, p, display->white, ZP, font, linebuf); p.x += stringwidth(font, "99999x99999 "); runesprint(linebuf, "%ludf", tick); runestring(screen, p, display->white, ZP, font, linebuf); /* cursor */ p = top; p.x += curx*stringwidth(font, " "); p.y += cury*font->height; runestringnbgop(screen, p, display->black, ZP, font, &cursor, 1, curbg, ZP, SoverD); flushimage(display, 1); } static int loadfield(Field *field, char *path) { Field_load_error e; if ((e = field_load_file(path, field)) != Field_load_error_ok) { werrstr(field_load_error_string(e)); return -1; } return 0; } static void screensize(int *w, int *h) { *w = (Dx(screen->r) - 2*Txtoff) / stringwidth(font, "X"); *h = ((Dy(screen->r) - 2*Txtoff) - 3*font->height) / font->height; } static void select(void) { } static char *menu3i[] = { "load", "save", nil, }; static Menu menu3 = { .item = menu3i, }; void threadmain(int argc, char **argv) { Mbuf_reusable mbuf; Oevent_list events; Field field; Mousectl *mctl; Keyboardctl *kctl; Rune key; Mouse m; char tmp[256]; int oldw, oldh, w, h; Alt a[] = { { nil, &m, CHANRCV }, { nil, nil, CHANRCV }, { nil, &key, CHANRCV }, { nil, nil, CHANNOBLK}, }; USED(argc, argv); srand(time(0)); threadsetname("orca"); if(initdraw(nil, nil, "orca") < 0) sysfatal("initdraw: %r"); if ((mctl = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r"); if ((kctl = initkeyboard(nil)) == nil) sysfatal("initkeyboard: %r"); a[0].c = mctl->c; a[1].c = mctl->resizec; a[2].c = kctl->c; curbg = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, DYellow); screensize(&w, &h); field_init_fill(&field, h, w, '.'); linebuf = malloc(sizeof(Rune)*MAX(w+1, 64)); memset(noteoff, 0, sizeof(noteoff)); mbuf_reusable_init(&mbuf); mbuf_reusable_ensure_size(&mbuf, h, w); oevent_list_init(&events); for (tick = 0;; tick++) { mbuffer_clear(mbuf.buffer, h, w); oevent_list_clear(&events); orca_run(field.buffer, mbuf.buffer, h, w, tick, &events, 0); process(&events); redraw(&field); oldw = w = field.width; oldh = h = field.height; switch (alt(a)) { case 0: /* mouse */ switch (m.buttons & 7) { case 1: select(); break; case 2: break; case 4: switch (menuhit(3, mctl, &menu3, nil)) { case 0: tmp[0] = 0; if (enter("load file:", tmp, sizeof(tmp), mctl, kctl, nil) > 0) { if (loadfield(&field, tmp) == 0) { w = field.width; h = field.height; } else { /* FIXME display the error */ } } break; } break; } break; case 1: /* resize */ getwindow(display, Refnone); break; case 2: /* keyboard */ switch (key) { case Kup: cury = MAX(0, cury-1); break; case Kdown: cury = MIN(h-1, cury+1); break; case Kleft: curx = MAX(0, curx-1); break; case Kright: curx = MIN(w-1, curx+1); break; case 0x11: /* C-q */ goto end; case 0x12: /* C-r */ tick = -1; break; case '(': w = MAX(1, w-gridw); break; case ')': w += gridw; break; case '_': h = MAX(1, h-gridh); break; case '+': h += gridh; break; default: if (key == Kdel) key = '.'; if (orca_is_valid_glyph(key)) field.buffer[curx + w*cury] = key; else fprint(2, "unhandled key %04x\n", key); break; } if (w != oldw || h != oldh) { field_resize_raw(&field, h, w); if (w >= oldw && h >= oldh) memset(field.buffer + oldw*oldh, '.', w*h - oldw*oldh); } } if (w != oldw || h != oldh) { mbuf_reusable_ensure_size(&mbuf, h, w); linebuf = realloc(linebuf, sizeof(Rune)*MAX(w+1, 64)); } } end: mbuf_reusable_deinit(&mbuf); oevent_list_deinit(&events); field_deinit(&field); threadexitsall(nil); }