ref: 1d4a36c69913f117516b0f062745fe95d35545ba
dir: /sys/src/games/mus.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); }