5 typedef struct Inst Inst;
6 typedef struct Opl Opl;
7 typedef struct Chan Chan;
8 typedef struct Trk Trk;
11 Ninst = 128 + 81-35+1,
14 Mwse = 1<<5, /* wave selection enable */
17 Mlvl = 63<<0, /* total level */
18 Mscl = 3<<6, /* scaling level */
21 Rnum = 0xa0, /* f number lsb */
23 Mmsb = 3<<0, /* f number msb */
51 Opl opl[18], *ople = opl + nelem(opl);
53 0x0, 0x1, 0x2, 0x8, 0x9, 0xa, 0x10, 0x11, 0x12,
54 0x100, 0x101, 0x102, 0x108, 0x109, 0x10a, 0x110, 0x111, 0x112
57 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,
58 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108
61 0, 32, 48, 58, 64, 70, 74, 77, 80, 83, 86, 88, 90, 92, 93, 95, 96,
62 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 108, 109, 110, 111,
63 112, 112, 113, 114, 114, 115, 116, 116, 117, 118, 118, 119, 119,
64 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 124, 125, 125,
65 126, 126, 126, 127, 127, 127, 128, 128
85 int mfmt, ntrk, div, tempo, opl2;
96 sysfatal("mallocz: %r");
97 setmalloctag(p, getcallerpc(&n));
102 bfdopen(int fd, int mode)
106 bf = Bfdopen(fd, mode);
108 sysfatal("bfdopen: %r");
114 bopen(char *file, int mode)
118 fd = open(file, mode);
120 sysfatal("bopen: %r");
121 return bfdopen(fd, mode);
125 bread(void *u, int n)
127 if(Bread(ib, u, n) != n)
128 sysfatal("bread: short read");
141 sysfatal("track overflow");
164 putcmd(u16int r, u8int v, u16int dt)
179 setinst(Opl *o, uchar *i)
184 putcmd(Roct+p, o->blk, 0);
185 putcmd(Rfed+p, i[6] & ~0x30 | o->c->pan, 0);
187 putcmd(Rctl+p, i[0], 0);
188 putcmd(Ratk+p, i[1], 0);
189 putcmd(Rsus+p, i[2], 0);
190 putcmd(Rwav+p, i[3] & 3, 0);
191 putcmd(Rctl+3+p, i[7], 0);
192 putcmd(Ratk+3+p, i[8], 0);
193 putcmd(Rsus+3+p, i[9], 0);
194 putcmd(Rwav+3+p, i[10] & 3, 0);
199 noteoff(Chan *c, int n, int)
203 for(o=opl; o<ople; o++)
204 if(o->c == c && o->midn == n){
205 putcmd(Roct+sport[o-opl], o->blk, 0);
216 for(o=opl; o<ople; o++){
232 d += o->i == o->c->i->i2 ? o->c->i->fine : 0;
233 n = o->n + d / 0x1000 & 0x7f;
234 e = freq[n] + (d % 0x1000) * (freq[n+1] - freq[n]) / 0x1000;
237 f = (e * (1 << 20)) / 49716;
238 for(b=1; b<8; b++, f>>=1)
241 o->blk = b << 2 & Moct | f >> 8 & Mmsb;
242 putcmd(Rnum+sport[o-opl], f & 0xff, 0);
243 putcmd(Roct+sport[o-opl], Mkon | o->blk, 0);
252 w = o->v * o->c->v / 127;
253 w = ovol[w * 64 / 127] * 63 / 128;
254 x = 63 + (o->i[5] & Mlvl) * w / 63 - w;
255 putcmd(Rsca+p, o->i[4] & Mscl | x, 0);
256 x = 63 + (o->i[12] & Mlvl) * w / 63 - w;
257 putcmd(Rsca+p+3, o->i[11] & Mscl | x, 0);
261 putnote(Chan *c, int midn, int n, int v, vlong t, uchar *i)
278 noteon(Chan *c, int n, int v, vlong t)
284 /* asspull workaround for percussions above gm set */
291 c->i = inst + 128 + m - 35;
299 x = m + (c->i->fixed ? 0 : c->i->base[0]);
304 putnote(c, n, x & 0xff, v, t, c->i->i);
306 x = m + (c->i->fixed ? 0 : c->i->base[1]);
311 putnote(c, n, x & 0xff, v, t, c->i->i2);
320 for(o=opl; o<ople; o++)
321 if(o->c == c && o->n >= 0){
322 putcmd(Rfed+sport[o-opl], o->i[6] & ~0x30 | c->pan, 0);
331 return ((uvlong)n * tempo * Rate / div) / 1000000;
350 sysfatal("invalid variable-length number");
379 putcmd(0, 0, dt > 0xffff ? 0xffff : dt);
390 samp(x->t += tc(getvar(x)));
396 sysfatal("invalid event");
402 case 0x8: noteoff(c, n, get8(x)); break;
403 case 0x9: noteon(c, n, get8(x), x->t); break;
407 case 0x00: case 0x01: case 0x20: break;
408 case 0x07: c->v = m; resetchan(c); break;
409 case 0x0a: c->pan = m < 32 ? 1<<4 : m > 96 ? 1<<5 : 3<<4; resetchan(c); break;
410 default: fprint(2, "unknown controller %d\n", n);
413 case 0xc: c->i = inst + n; break;
415 n = get8(x) << 7 | n;
416 c->bend = n - 0x4000 / 2;
421 while(get8(x) != 0xf7)
427 case 0x2f: x->p = x->e; return;
428 case 0x51: tempo = get16(x) << 8; tempo |= get8(x); break;
433 case 0xd: get8(x); break;
434 default: sysfatal("invalid event %#ux\n", e >> 4);
445 ib = bopen(file, OREAD);
447 if(memcmp(u, "#OPL_II#", sizeof u) != 0)
448 sysfatal("invalid patch file");
449 for(i=inst; i<inst+nelem(inst); i++){
452 i->dbl = opl2 ? 0 : n & 1<<2;
454 i->fine = (get8(nil) - 128) * 64;
456 bread(i->i, sizeof i->i);
460 i->base[0] = (s16int)n;
461 bread(i->i2, sizeof i->i2);
465 i->base[1] = (s16int)n;
477 ib = file != nil ? bopen(file, OREAD) : bfdopen(0, OREAD);
478 if(get32(nil) != 0x4d546864 || get32(nil) != 6)
479 sysfatal("invalid header");
484 if(mfmt < 0 || mfmt > 1)
485 sysfatal("unsupported format %d", mfmt);
487 tr = emalloc(ntrk * sizeof *tr);
488 for(x=tr; x<tr+ntrk; x++){
489 if(get32(nil) != 0x4d54726b)
490 sysfatal("invalid track");
504 fprint(2, "usage: %s [-2] [-i inst] [mid]\n", argv0);
509 main(int argc, char **argv)
518 i = "/mnt/wad/genmidi";
520 case '2': opl2 = 1; ople = opl + 9; break;
521 case 'i': i = EARGF(usage()); break;
526 ob = bfdopen(1, OWRITE);
528 for(n=0; n<nelem(freq); n++)
529 freq[n] = 440 * pow(f, n - 69);
530 for(c=chan; c<chan+nelem(chan); c++){
536 for(o=opl; o<ople; o++)
539 putcmd(Rwse, Mwse, 0);
544 for(x=tr; x<tr+ntrk; x++){
547 t = x->t + tc(peekvar(x));
548 if(t < mint || minx == nil){