ref: 46544df18a733fdcc2e43dde43b396e719f1a0b1
parent: b2bacf2993e5aef1de9edaa2e6f271cbb6030ad2
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Wed Feb 12 15:20:49 EST 2020
plan9: fix timing, fast bpm changing, handle more keys
--- a/plan9.c
+++ b/plan9.c
@@ -12,6 +12,8 @@
enum {
Txtoff = 16,
+
+ Msgredraw = 0,
};
static struct {
@@ -22,7 +24,7 @@
static Rune *linebuf;
static Usz tick;
static int gridw = 8, gridh = 8;
-static int bpm = 120, insert = 1;
+static int bpm = 120, insert = 1, pause;
static int curx, cury;
static Image *curbg;
static int charw, charh;
@@ -100,8 +102,6 @@
}
}
- sleep(150);
-
for (i = 0; i < nelem(noteoff); i++) {
if (noteoff[i].at > 0 && noteoff[i].at < tick) {
write(1, noteoff[i].u, 4);
@@ -110,17 +110,76 @@
}
}
+/*
+ * nsec() is wallclock and can be adjusted by timesync
+ * so need to use cycles() instead
+ *
+ * "fasthz" is how many ticks there are in a second
+ * can be read from /dev/time
+ */
+static uvlong
+nanosec(void)
+{
+ static double fasthz = 0.0;
+ uvlong x;
+ int f, n, i;
+ char tmp[128], *e;
+
+ if (fasthz < 1.0) {
+ if ((f = open("/dev/time", OREAD)) < 0)
+ sysfatal("failed to open /dev/time");
+ if ((n = read(f, tmp, sizeof(tmp)-1)) < 2)
+ sysfatal("failed to read /dev/time");
+ tmp[n] = 0;
+ e = tmp;
+ for (i = 0; i < 3; i++)
+ strtoll(e, &e, 10);
+ fasthz = strtod(e, nil);
+ if (fasthz < 1.0)
+ sysfatal("failed to read fasthz");
+ close(f);
+ }
+ cycles(&x);
+ return (double)x / (fasthz / 1000000000.0);
+}
+
static void
-orcathread(void *)
+orcathread(void *drawchan)
{
- int w, h;
+ vlong start, end, n, oldn;
+ int w, h, oldbpm;
- w = field.width;
- h = field.height;
- mbuffer_clear(mbuf.buffer, h, w);
- oevent_list_clear(&events);
- orca_run(field.buffer, mbuf.buffer, h, w, tick, &events, 0);
- process(&events);
+ threadsetname("orca/sim");
+ for (;;) {
+ start = nanosec();
+ w = field.width;
+ h = field.height;
+ mbuffer_clear(mbuf.buffer, h, w);
+ oevent_list_clear(&events);
+ orca_run(field.buffer, mbuf.buffer, h, w, tick, &events, 0);
+
+ process(&events);
+ tick++;
+ nbsendul(drawchan, Msgredraw);
+
+ oldn = start;
+ end = start + 1;
+ oldbpm = 0;
+ for (n = start; pause || n < end; n = nanosec()) {
+ if (bpm != oldbpm) {
+ end = start + (15000000000.0 / (double)bpm); /* 10^9 * 60 / 4 */
+ oldbpm = bpm;
+ }
+
+ /* doesn't suppose to jump back, but just in case do _something_ */
+ if (n < oldn)
+ end -= oldn - n;
+
+ oldn = n;
+ yield();
+ sleep(5);
+ }
+ }
}
static void
@@ -201,6 +260,8 @@
werrstr(field_load_error_string(e));
return -1;
}
+ curx = MIN(curx, field.width-1);
+ cury = MIN(cury, field.height-1);
return 0;
}
@@ -239,13 +300,14 @@
{ nil, &m, CHANRCV },
{ nil, nil, CHANRCV },
{ nil, &key, CHANRCV },
- { nil, nil, CHANNOBLK},
+ { nil, nil, CHANRCV },
+ { nil, nil, CHANEND },
};
USED(argc, argv);
srand(time(0));
- threadsetname("orca");
+ threadsetname("orca/draw");
if(initdraw(nil, nil, "orca") < 0)
sysfatal("initdraw: %r");
@@ -257,6 +319,7 @@
a[0].c = mctl->c;
a[1].c = mctl->resizec;
a[2].c = kctl->c;
+ a[3].c = chancreate(sizeof(ulong), 0); /* FIXME should it be buffered instead? */
curbg = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, DYellow);
charw = stringwidth(font, "X");
@@ -272,10 +335,10 @@
mbuf_reusable_ensure_size(&mbuf, h, w);
oevent_list_init(&events);
- for (tick = 0;; tick++) {
- orcathread(nil);
- redraw();
+ threadcreate(orcathread, a[3].c, mainstacksize);
+ for (;;) {
+ redraw();
oldw = w = field.width;
oldh = h = field.height;
@@ -327,10 +390,22 @@
case Kright:
curx = MIN(w-1, curx+1);
break;
+ case Khome:
+ curx = 0;
+ break;
+ case Kend:
+ curx = field.width-1;
+ break;
+ case Kpgup:
+ cury = 0;
+ break;
+ case Kpgdown:
+ cury = field.height-1;
+ break;
case 0x11: /* C-q */
goto end;
case 0x12: /* C-r */
- tick = -1;
+ tick = 0;
break;
case '(':
w = MAX(1, w-gridw);
@@ -358,6 +433,9 @@
insert = 1;
/* FIXME else remove selection */
break;
+ case ' ':
+ pause = !pause;
+ break;
default:
if (key == Kdel)
key = '.';
@@ -381,6 +459,9 @@
MIN(field.height, copyfield.height), MIN(field.width, copyfield.width)
);
}
+
+ case 3: /* redraw */
+ break;
}
if (w != oldw || h != oldh) {