ref: 066bcd8622204fee0063129953ab7a380110d325
parent: 334a20e5517576bf0a41ec642ef91d5fd4890ce0
author: qwx <qwx@sciops.net>
date: Wed Jan 11 03:42:35 EST 2023
games/dmid: fix tempo changes causing desyncs in multitrack files if tempo changes while older events are in flight at different timings in a multitrack file, and since there's no compensation for it, tracks desyncronise, the order of events get jumbled up and everything just falls apart. rather than doing dances with the old code to figure out what corrective factor to apply and where, just use the simplest and most robust way, advance one tic at a time. also add a tracing mode and don't always print useless and annoying warnings.
--- a/sys/src/games/dmid.c
+++ b/sys/src/games/dmid.c
@@ -77,14 +77,15 @@
u8int *s;
u8int *p;
u8int *e;
- uvlong t;
+ vlong Δ;
+ vlong t;
int ev;
};
Trk *tr;
+int trace;
double freq[128];
int mfmt, ntrk, div = 1, tempo, opl2, stream;
-uvlong T;
Biobuf *ib;
void *
@@ -129,6 +130,20 @@
sysfatal("bread: short read");
}
+void
+dprint(char *fmt, ...)
+{
+ char s[256];
+ va_list arg;
+
+ if(!trace)
+ return;
+ va_start(arg, fmt);
+ vseprint(s, s+sizeof s, fmt, arg);
+ va_end(arg);
+ fprint(2, "%s", s);
+}
+
u8int
get8(Trk *x)
{
@@ -140,7 +155,9 @@
}
if(x->p >= x->e)
sysfatal("track overflow");
- return *x->p++;
+ v = *x->p++;
+ dprint("%02ux", v);
+ return v;
}
u16int
@@ -326,10 +343,10 @@
}
}
-uvlong
-tc(int n)
+double
+tc(double n)
{
- return ((uvlong)n * tempo * Rate / div) / 1000000;
+ return (n * tempo * Rate / div) / 1e6;
}
void
@@ -356,29 +373,19 @@
return v;
}
-int
-peekvar(Trk *x)
-{
- int v;
- uchar *p;
-
- p = x->p;
- v = getvar(x);
- x->p = p;
- return v;
-}
-
void
-samp(uvlong t´)
+samp(double n)
{
- int dt;
- static uvlong t;
+ vlong t;
+ double Δ;
+ static double ε;
- dt = t´ - t;
- t += dt;
- while(dt > 0){
- putcmd(0, 0, dt > 0xffff ? 0xffff : dt);
- dt -= 0xffff;
+ Δ = tc(n) + ε;
+ t = Δ;
+ ε = Δ - t;
+ while(t > 0){
+ putcmd(0, 0, t > 0xffff ? 0xffff : t);
+ t -= 0xffff;
}
}
@@ -388,7 +395,7 @@
int e, n, m;
Chan *c;
- samp(x->t += tc(getvar(x)));
+ dprint(" [%zd] ", x - tr);
e = get8(x);
if((e & 0x80) == 0){
x->p--;
@@ -398,6 +405,7 @@
}else
x->ev = e;
c = chan + (e & 15);
+ dprint("(%02ux) ", e);
n = get8(x);
switch(e >> 4){
case 0x8: noteoff(c, n, get8(x)); break;
@@ -408,7 +416,7 @@
case 0x00: case 0x01: case 0x20: break;
case 0x07: c->v = m; resetchan(c); break;
case 0x0a: c->pan = m < 32 ? 1<<4 : m > 96 ? 1<<5 : 3<<4; resetchan(c); break;
- default: fprint(2, "unknown controller %d\n", n);
+ default: dprint("\nunknown controller %d", n);
}
break;
case 0xc: c->i = inst + n; break;
@@ -421,11 +429,11 @@
if((e & 0xf) == 0){
while(get8(x) != 0xf7)
;
- return;
+ break;
}
m = get8(x);
switch(n){
- case 0x2f: x->p = x->e; return;
+ case 0x2f: x->p = x->e; break;
case 0x51: tempo = get16(x) << 8; tempo |= get8(x); break;
default: skip(x, m);
}
@@ -434,6 +442,7 @@
case 0xd: get8(x); break;
default: sysfatal("invalid event %#ux\n", e >> 4);
}
+ dprint("\n");
}
void
@@ -489,7 +498,7 @@
void
readmid(char *file)
{
- u32int n;
+ u32int n, z;
uchar *s;
Trk *x;
@@ -506,7 +515,7 @@
sysfatal("unsupported format %d", mfmt);
div = get16(nil);
tr = emalloc(ntrk * sizeof *tr);
- for(x=tr; x<tr+ntrk; x++){
+ for(x=tr, z=-1UL; x<tr+ntrk; x++){
if(get32(nil) != 0x4d54726b)
sysfatal("invalid track");
n = get32(nil);
@@ -515,7 +524,12 @@
x->s = s;
x->p = s;
x->e = s + n;
+ x->Δ = getvar(x); /* prearm */
+ if(x->Δ < z)
+ z = x->Δ;
}
+ for(x=tr; x<tr+ntrk; x++)
+ x->Δ -= z;
Bterm(ib);
}
@@ -522,7 +536,7 @@
void
usage(void)
{
- fprint(2, "usage: %s [-2s] [-i inst] [mid]\n", argv0);
+ fprint(2, "usage: %s [-2Ds] [-i inst] [mid]\n", argv0);
exits("usage");
}
@@ -529,17 +543,19 @@
void
threadmain(int argc, char **argv)
{
- int n, t, mint;
+ int n, end, debug;
char *i;
double f;
uchar u[4];
Chan *c;
Opl *o;
- Trk xs, *x, *minx;
+ Trk xs, *x;
i = "/mnt/wad/genmidi";
+ debug = 0;
ARGBEGIN{
case '2': opl2 = 1; ople = opl + 9; break;
+ case 'D': debug = 1; break;
case 'i': i = EARGF(usage()); break;
case 's': stream = 1; break;
default: usage();
@@ -560,6 +576,7 @@
tempo = 500000;
putcmd(Rwse, Mwse, 0);
putcmd(Rop3, 1, 0);
+ trace = debug;
if(stream){
if(proccreate(tproc, nil, mainstacksize) < 0)
sysfatal("proccreate: %r");
@@ -574,20 +591,22 @@
}
threadexitsall(n < 0 ? "read: %r" : nil);
}
- for(;;){
- minx = nil;
- mint = 0;
+ for(end=0; !end;){
+ end = 1;
for(x=tr; x<tr+ntrk; x++){
if(x->p >= x->e)
continue;
- t = x->t + tc(peekvar(x));
- if(t < mint || minx == nil){
- mint = t;
- minx = x;
+ end = 0;
+ x->Δ--;
+ x->t += tc(1);
+ while(x->Δ <= 0){
+ ev(x);
+ if(x->p >= x->e)
+ break;
+ x->Δ = getvar(x);
}
}
- if(minx == nil)
- exits(nil);
- ev(minx);
+ samp(1);
}
+ exits(nil);
}
--
⑨