220 lines
3.6 KiB
C
220 lines
3.6 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
|
|
typedef struct Trk Trk;
|
|
struct Trk{
|
|
u32int len;
|
|
uchar *dat;
|
|
uchar *p;
|
|
uchar *end;
|
|
uchar v[16];
|
|
int done;
|
|
};
|
|
Trk t;
|
|
uchar *mcmd, *mp, *me;
|
|
int fd;
|
|
|
|
#define PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8
|
|
#define BBIT32(p,v) (p)[3]=(v);(p)[2]=(v)>>8;(p)[1]=(v)>>16;(p)[0]=(v)>>24
|
|
|
|
void
|
|
eread(int fd, void *u, long n)
|
|
{
|
|
if(readn(fd, u, n) != n)
|
|
sysfatal("readn: %r");
|
|
}
|
|
|
|
uchar
|
|
r8(void)
|
|
{
|
|
return *t.p++;
|
|
}
|
|
|
|
void
|
|
delay(void)
|
|
{
|
|
uchar v;
|
|
|
|
do{
|
|
v = r8();
|
|
*mp++ = v;
|
|
}while(v & 0x80);
|
|
}
|
|
|
|
void
|
|
putcmd(uchar *cmd, int n)
|
|
{
|
|
if(mp + n >= me){
|
|
me += 8192;
|
|
mcmd = realloc(mcmd, me - mcmd);
|
|
if(mcmd == nil)
|
|
sysfatal("realloc: %r");
|
|
}
|
|
memcpy(mp, cmd, n);
|
|
mp += n;
|
|
}
|
|
|
|
void
|
|
ev(void)
|
|
{
|
|
uchar e, v, cmd[3], *p;
|
|
|
|
e = r8();
|
|
p = cmd;
|
|
switch(e >> 4 & 7){
|
|
case 0:
|
|
v = r8() & 0x7f;
|
|
*p++ = e | 0x80;
|
|
*p++ = v;
|
|
*p++ = 0x40;
|
|
break;
|
|
case 1:
|
|
v = r8();
|
|
*p++ = e | 0x80;
|
|
*p++ = v & 0x7f;
|
|
if(v & 0x80)
|
|
t.v[e & 15] = r8() & 0x7f;
|
|
*p++ = t.v[e & 15];
|
|
break;
|
|
case 2:
|
|
v = r8();
|
|
*p++ = e | 0xc0;
|
|
PBIT16(p, v << 7 & 0x7f7f);
|
|
p += 2;
|
|
break;
|
|
case 3:
|
|
v = r8();
|
|
*p++ = 0xb | e & 15;
|
|
switch(v){
|
|
case 10: *p++ = 0x78; break;
|
|
case 11: *p++ = 0x7b; break;
|
|
case 12: *p++ = 0x7e; break;
|
|
case 13: *p++ = 0x7f; break;
|
|
case 14: *p++ = 0x79; break;
|
|
default: sysfatal("unknown system event %ux\n", v);
|
|
}
|
|
*p++ = 0;
|
|
break;
|
|
case 4:
|
|
v = r8();
|
|
if(v > 9)
|
|
sysfatal("unknown controller %ux\n", v);
|
|
*p++ = 0xb0 | e & 15;
|
|
switch(v){
|
|
case 1: *p++ = 0x00; break;
|
|
case 2: *p++ = 0x01; break;
|
|
case 3: *p++ = 0x07; break;
|
|
case 4: *p++ = 0x0a; break;
|
|
case 5: *p++ = 0x0b; break;
|
|
case 6: *p++ = 0x5b; break;
|
|
case 7: *p++ = 0x5d; break;
|
|
case 8: *p++ = 0x40; break;
|
|
case 9: *p++ = 0x43; break;
|
|
}
|
|
*p++ = r8() & 0x7f;
|
|
if(v == 0)
|
|
cmd[0] += 0x10;
|
|
break;
|
|
case 6:
|
|
*p++ = 0xff;
|
|
*p++ = 0x2f;
|
|
e = 0;
|
|
t.done++;
|
|
break;
|
|
default:
|
|
sysfatal("unknown event %ux\n", e >> 4 & 7);
|
|
}
|
|
if((e & 15) == 9)
|
|
cmd[0] |= 6;
|
|
if((e & 15) == 15)
|
|
cmd[0] &= ~6;
|
|
putcmd(cmd, p-cmd);
|
|
if(e & 0x80)
|
|
delay();
|
|
else
|
|
*mp++ = 0;
|
|
}
|
|
|
|
void
|
|
reset(void)
|
|
{
|
|
memset(t.v, 0x7f, sizeof t.v);
|
|
mcmd = mallocz(t.len * 2, 1);
|
|
if(mcmd == nil)
|
|
sysfatal("mallocz: %r");
|
|
mp = mcmd;
|
|
me = mcmd + t.len * 2;
|
|
}
|
|
|
|
void
|
|
barf(void)
|
|
{
|
|
static uchar hdr[] = {
|
|
'M', 'T', 'h', 'd',
|
|
0x00, 0x00, 0x00, 0x06,
|
|
0x00, 0x00,
|
|
0x00, 0x01,
|
|
0x01, 0x01,
|
|
'M', 'T', 'r', 'k',
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0xb0, 0x07, 0x7f,
|
|
0x00, 0xb1, 0x07, 0x7f,
|
|
0x00, 0xb2, 0x07, 0x7f,
|
|
0x00, 0xb3, 0x07, 0x7f,
|
|
0x00, 0xb4, 0x07, 0x7f,
|
|
0x00, 0xb5, 0x07, 0x7f,
|
|
0x00, 0xb6, 0x07, 0x7f,
|
|
0x00, 0xb7, 0x07, 0x7f,
|
|
0x00, 0xb8, 0x07, 0x7f,
|
|
0x00, 0xb9, 0x07, 0x7f,
|
|
0x00, 0xba, 0x07, 0x7f,
|
|
0x00, 0xbb, 0x07, 0x7f,
|
|
0x00, 0xbc, 0x07, 0x7f,
|
|
0x00, 0xbd, 0x07, 0x7f,
|
|
0x00, 0xbe, 0x07, 0x7f,
|
|
0x00, 0xbf, 0x07, 0x7f,
|
|
0x00, 0xff, 0x51, 0x03, 0x1b, 0x8a, 0x06,
|
|
0x00
|
|
};
|
|
int n;
|
|
|
|
n = sizeof(hdr) - 22 + mp - mcmd;
|
|
BBIT32(hdr + 18, n);
|
|
write(1, hdr, sizeof hdr);
|
|
write(1, mcmd, mp - mcmd);
|
|
}
|
|
|
|
void
|
|
main(int argc, char *argv[])
|
|
{
|
|
int n, ofs;
|
|
uchar s[8], b[1024];
|
|
|
|
if(argc > 1){
|
|
fd = open(argv[1], OREAD);
|
|
if(fd < 0)
|
|
sysfatal("open: %r");
|
|
}
|
|
eread(fd, s, sizeof s);
|
|
if(memcmp(s, "MUS\x1a", 4) != 0)
|
|
sysfatal("invalid mus file: %r");
|
|
t.len = s[5] << 8 | s[4];
|
|
ofs = (s[7] << 8 | s[6]) - 8;
|
|
while(ofs > 0){
|
|
n = ofs > sizeof b ? sizeof b : ofs;
|
|
eread(fd, b, n);
|
|
ofs -= n;
|
|
}
|
|
t.dat = malloc(t.len);
|
|
if(t.dat == nil)
|
|
sysfatal("malloc: %r");
|
|
t.p = t.dat;
|
|
t.end = t.dat + t.len;
|
|
eread(fd, t.dat, t.len);
|
|
reset();
|
|
while(!t.done && t.p < t.end)
|
|
ev();
|
|
barf();
|
|
exits(nil);
|
|
}
|