ref: dd470b171237d28bca26abd57bdecbbedba13f48
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> static struct { u8int u[4]; int at; }noteoff[16*128]; /* 16 channels, 128 notes each */ static char *buf; Usz orca_round_up_power2(Usz x) { assert(x <= SIZE_MAX / 2 + 1); x -= 1; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; #if SIZE_MAX > UINT32_MAX x |= x >> 32; #endif 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 usage(void) { print("usage: orca [-q] [-t ticks] [-f file]\n"); exits("usage"); } static void process(Oevent_list *el, int tick) { int i, off; Oevent *e; u8int u[4]; for (i = 0; i < el->count; i++) { e = &el->buffer[i]; 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;//u[3]; 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 field_draw(Field *f, int tick) { Point p; int x, y; lockdisplay(display); draw(screen, screen->r, display->black, nil, ZP); p = screen->r.min; p.x += 8; p.y += 8; for (y = 0; y < f->height; y++) { for (x = 0; x < f->width; x++) { u8int c = f->buffer[f->width*y + x]; buf[x] = (c > '\n' && c < 128) ? c : '?'; } buf[x] = 0; string(screen, p, display->white, ZP, display->defaultfont, buf); p.y += display->defaultfont->height; } p.x = screen->r.min.x + 8; p.y += 2 * display->defaultfont->height; sprint(buf, "%df", tick); string(screen, p, display->white, ZP, display->defaultfont, buf); flushimage(display, 1); unlockdisplay(display); } void threadmain(int argc, char **argv) { const char *input_file = "/fd/0"; int ticks = 1; bool print_output = true; Field field; Mousectl *mctl; Keyboardctl *kctl; Rune key; Mouse m; Alt a[] = { { nil, &m, CHANRCV }, { nil, nil, CHANRCV }, { nil, &key, CHANRCV }, { nil, nil, CHANNOBLK}, }; ARGBEGIN{ case 't': ticks = atoi(EARGF(usage())); break; case 'f': input_file = EARGF(usage()); break; case 'q': print_output = false; break; }ARGEND; field_init(&field); Field_load_error fle = field_load_file(input_file, &field); if (fle != Field_load_error_ok) { field_deinit(&field); char const *errstr = "Unknown"; switch (fle) { case Field_load_error_ok: break; case Field_load_error_cant_open_file: errstr = "Unable to open file"; break; case Field_load_error_too_many_columns: errstr = "Grid file has too many columns"; break; case Field_load_error_too_many_rows: errstr = "Grid file has too many rows"; break; case Field_load_error_no_rows_read: errstr = "Grid file has no rows"; break; case Field_load_error_not_a_rectangle: errstr = "Grid file is not a rectangle"; break; } exits(errstr); } buf = malloc(field.width+1); memset(noteoff, 0, sizeof(noteoff)); Mbuf_reusable mbuf_r; mbuf_reusable_init(&mbuf_r); mbuf_reusable_ensure_size(&mbuf_r, field.height, field.width); Oevent_list oevent_list; oevent_list_init(&oevent_list); Usz max_ticks = (Usz)ticks; 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; unlockdisplay(display); srand(time(0)); threadsetname("orca"); for (Usz i = 0; i < max_ticks; ++i) { mbuffer_clear(mbuf_r.buffer, field.height, field.width); oevent_list_clear(&oevent_list); orca_run(field.buffer, mbuf_r.buffer, field.height, field.width, i, &oevent_list, 0); process(&oevent_list, i); field_draw(&field, i); switch (alt(a)) { case 0: /* mouse */ break; case 1: /* resize */ getwindow(display, Refnone); break; case 2: /* keyboard */ switch (key) { case Kdel: goto end; } } } end: mbuf_reusable_deinit(&mbuf_r); oevent_list_deinit(&oevent_list); if (print_output) field_fput(&field, stderr); field_deinit(&field); threadexitsall(nil); }