#include #include #include #define MAX(a,b) ((a) > (b) ? (a) : (b)) enum { Maxsamples = 64, Maxargs = 8, Bufsize = 4096, }; typedef struct Sample Sample; typedef struct Event Event; struct Sample { Sample *next; int len; short *data; char *name; }; struct Event { Event *next, *prev; int t, len; int vol; short *data; }; Event E = { .prev = &E, .next = &E }; Event P = { .prev = &P, .next = &P }; Sample *S; Biobuf in, out; int last; void unlink(Event *e) { e->prev->next = e->next; e->next->prev = e->prev; } void link(Event *h, Event *e) { e->prev = h->prev; e->next = h; h->prev->next = e; h->prev = e; } int playone(int t) { Event *e; int s; while((e = E.next) != &E && e->t == t){ unlink(e); link(&P, e); } for(s = 0, e = P.next; e != &P; e = e->next){ if(e->len == 0) unlink(e); s = s + e->vol * *e->data++; e->len--; } return s; } int find0xing(Sample *s, int k) { int sign; if(k < 0 || k >= s->len) return s->len; if(k == 0) return 0; sign = s->data[k-1] >= 0; for(; k < s->len && sign == (s->data[k] > 0); k++) ; return k; } void * readfile(char *name, int *len) { int fd; Dir *dir; void *p; int l; fd = open(name, OREAD); if(fd < 0) sysfatal("%s: %r", name); dir = dirfstat(fd); if(dir == nil) sysfatal("%s: %r", name); l = dir->length; p = malloc(l); if(readn(fd, p, l) != l) sysfatal("%s: %r", name); close(fd); *len = l; return p; } void parse(char *line, int no) { char *argv[Maxargs]; int argc; Event *e; Sample *s; argc = tokenize(line, argv, Maxargs); if(argc == 0) return; if(argv[0][0] == '#') return; if(argc < 3) goto err; if(argc > 3 && strtol(argv[3], 0, 0) == 0){ last = MAX(last, strtol(argv[0], 0, 0)); return; } for(s=S; s; s=s->next){ if(strcmp(s->name, argv[1]) == 0) break; } if(s == nil){ s = malloc(sizeof(*s)); s->data = readfile(argv[1], &s->len); s->name = strdup(argv[1]); s->len /= 2; s->next = S; S = s; } e = malloc(sizeof *e); e->t = strtol(argv[0], 0, 0); e->vol = strtol(argv[2], 0, 0); e->len = find0xing(s, argc > 3 ? strtol(argv[3], 0, 0) : -1); e->data = s->data; if(e->vol > 128 || e->vol < 0 || E.prev->t > e->t) goto err; link(&E, e); last = MAX(last, e->t + e->len); return; err: sysfatal("parser error on line %d", no); } void putsample(Biobuf *b, int s) { Bputc(b, s & 0xff); Bputc(b, (s >> 8) & 0xff); } void main(int, char *) { char *line; int no; int t, s; Binit(&in, 0, OREAD); Binit(&out, 1, OWRITE); for(no=1; (line = Brdline(&in, '\n')) != nil; no++){ line[Blinelen(&in)-1] = 0; parse(line, no); } for(t=0; t < last; t++){ s = playone(t) / 128; putsample(&out, s); putsample(&out, s); } Bterm(&in); Bterm(&out); exits(nil); }