ref: d226fadbe974f0e813d3f3ef5b20b2cabced437a
parent: 1e95b1cbb2a05e23ada69db3093b1a3d389c97f3
author: qwx <qwx@sciops.net>
date: Sat Jun 24 17:11:30 EDT 2023
mid2s: fix timing, configurable nchan and percussions, aging and remapping
--- a/mid2s.c
+++ b/mid2s.c
@@ -4,8 +4,9 @@
enum{
Rate = 44100,
- Nchan = 16,//6,
- Percch = 9,//5,
+ Nchan = 16,
+ Maxch = 16, // FIXME: could have more
+ Percch = 9,
};
typedef struct Trk Trk;
@@ -18,10 +19,10 @@
double t;
int ev;
int ended;
- int chan[16];
};
Trk *tr;
-int chan[16];
+int m2ich[Maxch], i2mch[Maxch], age[Maxch];
+int nch = Nchan, percch = Percch;
int trace;
int mfmt, ntrk, div = 1, tempo;
@@ -147,50 +148,66 @@
return v;
}
+// FIXME: common midi.c shit (midilib.c? midifile?)
void
samp(double n)
{
- double Δ;
- long t;
- static double ε;
+ double Δt;
+ long s;
+ static double t0, t1;
- /* FIXME: using nsec() might help with desyncs? ie. account for drift? */
- Δ = n * 1000 * tempo / div + ε;
- t = floor(Δ / 1000000);
- ε = Δ - t * 1000000;
- sleep(t);
+ if(t0 == 0.0)
+ t0 = nsec();
+ t1 = t0 + n * 1000 * tempo / div;
+ t0 = t1;
+ Δt = t1 - nsec();
+ s = floor(Δt / 1000000);
+ if(s > 0)
+ sleep(s);
}
int
-mapinst(Trk *x, int c, int e)
+mapinst(Trk *, int c, int e)
{
- int i;
+ int i, m, a;
- if(e >> 4 == 0xf)
- return e;
- if(e >> 4 != 0x9 || x->chan[c] >= 0)
- return e;
+ i = m2ich[c];
if(c == 9)
- i = Percch;
- else if(chan[c] >= 0)
+ i = percch;
+ else if(e >> 4 != 0x9){
+ if(e >> 4 == 0x8 && i >= 0){
+ i2mch[i] = -1;
+ m2ich[c] = -1;
+ }
return e;
- else{
- for(i=0; i<Nchan; i++){
- if(i == Percch)
+ }else if(i < 0){
+ for(i=0; i<nch; i++){
+ if(i == percch)
continue;
- if(chan[i] < 0)
+ if(i2mch[i] < 0)
break;
}
- /* hope for the best; either ignore it,
- * or hope the last channel isn't one of the main ones,
- * which is usually the case; but we no longer have our
- * settings */
- if(i == Nchan)
- i = Nchan-2;
+ if(i == nch){
+ for(m=i=a=0; i<nch; i++){
+ if(i == percch)
+ continue;
+ if(age[i] > age[m]){
+ m = i;
+ a = age[i];
+ }
+ }
+ if(a < 100){
+ fprint(2, "could not remap %d\n", c);
+ return e;
+ }
+ i = m;
+ fprint(2, "remapped %d → %d\n", c, i);
+ }
}
- x->chan[c] = i;
- chan[i] = Nchan * (x - tr) + c;
- return e & ~(16-1) | i;
+ age[i] = 0;
+ m2ich[c] = i;
+ i2mch[i] = c;
+ return e & ~(Nchan-1) | i;
}
int
@@ -199,7 +216,6 @@
int e, n, m;
x->q = x->p - 1;
- //*x->q = 0;
dprint(" [%zd] ", x - tr);
e = get8(x);
if((e & 0x80) == 0){
@@ -206,7 +222,6 @@
x->p--;
e = x->ev;
x->q--;
- //x->q[0] = 0;
x->q[1] = e;
if((e & 0x80) == 0)
sysfatal("invalid event");
@@ -217,6 +232,10 @@
e = mapinst(x, e & 15, e);
n = get8(x);
+ if((e & 15) == percch){
+ if(n < 36)
+ n += 36 - n;
+ }
switch(e >> 4){
case 0x8: get8(x); break;
case 0x9: get8(x); break;
@@ -278,7 +297,6 @@
x->p = s;
x->q = x->p;
x->e = s + n;
- memset(x->chan, 0x80, sizeof x->chan);
x->Δ = getvar(x); /* prearm */
if(x->Δ < z)
z = x->Δ;
@@ -291,7 +309,7 @@
void
usage(void)
{
- fprint(2, "usage: %s [-D] [mid]\n", argv0);
+ fprint(2, "usage: %s [-D] [-c nch] [-p percch] [mid]\n", argv0);
exits("usage");
}
@@ -298,18 +316,31 @@
void
main(int argc, char **argv)
{
- int end, debug;
+ int i, c, end, debug;
Trk *x;
debug = 0;
ARGBEGIN{
case 'D': debug = 1; break;
+ case 'c':
+ nch = atoi(EARGF(usage()));
+ break;
+ case 'p':
+ percch = atoi(EARGF(usage()));
+ break;
default: usage();
}ARGEND
+ if(nch <= 0 || nch > Maxch)
+ usage();
+ if(percch <= 0 || percch > nch)
+ usage();
readmid(*argv);
- memset(chan, 0x80, sizeof chan);
tempo = 500000;
trace = debug;
+ for(i=0; i<nelem(m2ich); i++){
+ m2ich[i] = i2mch[i] = -1;
+ age[i] = -1UL;
+ }
for(;;){
end = 1;
for(x=tr; x<tr+ntrk; x++){
@@ -319,10 +350,11 @@
x->Δ--;
while(x->Δ <= 0){
if(x->ended = ev(x, 0)){
- int c = x - tr;
- for(int i=0; i<Nchan; i++){
- if(chan[i] == c + i)
- chan[i] = -1;
+ c = x - tr;
+ i = m2ich[c];
+ if(i >= 0){
+ i2mch[i] = -1;
+ m2ich[c] = -1;
}
break;
}
@@ -334,6 +366,16 @@
break;
}
samp(1);
+ for(i=0; i<nch; i++){
+ if(i2mch[i] < 0)
+ continue;
+ age[i]++;
+ if(age[i] > 10000){
+ fprint(2, "reset %d\n", i2mch[i]);
+ m2ich[i2mch[i]] = -1;
+ i2mch[i] = -1;
+ }
+ }
}
exits(nil);
}