ref: 74a87e0582e0549e6e21568b8c68ebbdecdec48a
dir: /tomst.c/
#include <u.h> #include <libc.h> #include <bio.h> struct Tracker { uchar *data; char ended; uvlong t; int cmd; } *tr; typedef struct Tracker Tracker; int fd, tempo = 500000, ntrack; Biobuf *bf; uvlong T; char *ntab[] = { "c-1","c♯-1","d-1","d♯-1","e-1","f-1","f♯-1","g-1","g♯-1","a-1","a♯-1","b-1", "c0","c♯0","d0","d♯0","e0","f0","f♯0","g0","g♯0","a0","a♯0","b0", "c1","c♯1","d1","d♯1","e1","f1","f♯1","g1","g♯1","a1","a♯1","b1", "c2","c♯2","d2","d♯2","e2","f2","f♯2","g2","g♯2","a2","a♯2","b2", "c3","c♯3","d3","d♯3","e3","f3","f♯3","g3","g♯3","a3","a♯3","b3", "c4","c♯4","d4","d♯4","e4","f4","f♯4","g4","g♯4","a4","a♯4","b4", "c5","c♯5","d5","d♯5","e5","f5","f♯5","g5","g♯5","a5","a♯5","b5", "c6","c♯6","d6","d♯6","e6","f6","f♯6","g6","g♯6","a6","a♯6","b6", "c7","c♯7","d7","d♯7","e7","f7","f♯7","g7","g♯7","a7","a♯7","b7", "c8","c♯8","d8","d♯8","e8","f8","f♯8","g8","g♯8","a8","a♯8","b8", "c9","c♯9","d9","d♯9","e9","f9","f♯9","g9" }; char nts[512], *ntp = nts; void * emallocz(int size) { void *v; v = malloc(size); if(v == nil) sysfatal("malloc: %r"); memset(v, 0, size); return v; } int get8(Tracker *src) { uchar c; if(src == nil){ if(read(fd, &c, 1) == 0) sysfatal("unexpected eof"); return c; } return *src->data++; } int get16(Tracker *src) { int x; x = get8(src) << 8; return x | get8(src); } int get32(Tracker *src) { int x; x = get16(src) << 16; return x | get16(src); } int getvar(Tracker *src) { int k, x; x = get8(src); k = x & 0x7F; while(x & 0x80){ k <<= 7; x = get8(src); k |= x & 0x7F; } return k; } int peekvar(Tracker *src) { uchar *p; int v; p = src->data; v = getvar(src); src->data = p; return v; } void skip(Tracker *src, int x) { if(x) do get8(src); while(--x); } void paste(int dt) { /* FIXME: attempt to use note duration instead of clocks */ Bprint(bf, "c%d %s\n", dt, ntp!=nts?nts:"+"); } void readevent(Tracker *src, int dt) { int n, v, t; if(dt != 0){ paste(dt); ntp = nts; } src->t += getvar(src); t = get8(src); if((t & 0x80) == 0){ src->data--; t = src->cmd; if((t & 0x80) == 0) sysfatal("invalid midi"); }else src->cmd = t; n = t >> 4; switch(n){ case 0x8: n = get8(src); get8(src); off: ntp = seprint(ntp, nts + sizeof nts, " %d%s,0", t & 15, ntab[n]); break; case 0x9: n = get8(src); v = get8(src); if(v == 0) goto off; ntp = seprint(ntp, nts + sizeof nts, " %d%s", t & 15, ntab[n]); if(v != 64) ntp = seprint(ntp, nts + sizeof nts, ",%d", v); ntp = strecpy(ntp, nts + sizeof nts, "-"); break; case 0xB: get16(src); break; case 0xC: get8(src); break; case 0xE: get16(src); break; case 0xF: if((t & 0xF) == 0){ while(get8(src) != 0xF7) ; return; } v = get8(src); n = get8(src); switch(v){ case 0x2F: src->ended = 1; break; case 0x51: v = get16(src) << 8; v |= get8(src); if(v != tempo){ Bprint(bf, "t %d\n", 60000000/v); tempo = v; } break; default: skip(src, n); } break; default: sysfatal("unknown event type %x", t>>4); } } void main(int argc, char **argv) { int i, size; uvlong T, t, mint, dt; Tracker *x, *minx; if(argc > 1) fd = open(argv[1], OREAD); if(fd < 0) sysfatal("open: %r"); bf = Bfdopen(1, OWRITE); if(bf == nil) sysfatal("Bfdopen: %r"); if(get32(nil) != 0x4D546864 || get32(nil) != 6) sysfatal("invalid file header"); i = get16(nil); if(i != 0 && i != 1) sysfatal("unsupported midi format %d\n", i); ntrack = get16(nil); Bprint(bf, "div %d\n", get16(nil)); tr = emallocz(ntrack * sizeof(*tr)); for(i = 0; i < ntrack; i++){ if(get32(nil) != 0x4D54726B) sysfatal("invalid track header"); size = get32(nil); tr[i].data = emallocz(size); readn(fd, tr[i].data, size); } T = 0; for(;;){ minx = nil; mint = 0; for(x = tr; x < tr + ntrack; x++){ if(x->ended) continue; t = peekvar(x) + x->t; if(t < mint || minx == nil){ mint = t; minx = x; } } if(minx == nil) exits(nil); dt = mint - T; readevent(minx, dt); T += dt; } }