shithub: orca

Download patch

ref: 164c86c9a8d474a8a9e240d4894ba5081928a364
parent: c4982a97396bc85953177c51eccfa00e3900889a
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Mon Feb 10 17:43:04 EST 2020

plan9: make it play stuff through dmid+opl3 (still need proper timings and notes off)

--- a/plan9.c
+++ b/plan9.c
@@ -2,7 +2,18 @@
 #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;
@@ -42,17 +53,92 @@
 static void
 usage(void)
 {
-  print("usage: orca [-t ticks] [-f file]\n");
+  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
-main(int argc, char **argv)
+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':
@@ -61,6 +147,9 @@
   case 'f':
     input_file = EARGF(usage());
     break;
+  case 'q':
+    print_output = false;
+    break;
   }ARGEND;
 
   field_init(&field);
@@ -89,6 +178,8 @@
     }
     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);
@@ -95,17 +186,50 @@
   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, stdout);
+    field_fput(&field, stderr);
   field_deinit(&field);
 
-  exits(nil);
+  threadexitsall(nil);
 }