plan9front/sys/src/games/mus.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);
}