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);
}