ref: 0d8d67d11e9fad2347795ebf330375651e5303ab
dir: /piper/piper.c/
#include <u.h> #include <libc.h> #include <thread.h> #include <bio.h> #include "piper.h" typedef struct Inst Inst; typedef struct Group Group; struct Inst { void *aux; int data; int id; }; struct Group { char *path; Synth *synth; Inst *inst; int numinst; int clone; }; static int bpm = 120; static float bar = 2.0; static QLock grouplock; static Group *groups; static int numgroups; static int audio; static Synth *synths[] = { &ay_3_8910, &kick_drum, }; static void usage(void) { print("usage: %s DIR...\n", argv0); threadexitsall("usage"); } static Inst * getinst(Group *g, int id) { Inst *inst; void *aux; char *path, tmp[8]; int i, n, f; for (i = 0; i < g->numinst; i++) { if (id == g->inst[i].id) return &g->inst[i]; } for (i = g->numinst; i <= id;) { /* first see if it already exists */ if ((path = smprint("%s/%d", g->path, i)) == nil) sysfatal("memory"); if ((f = open(path, OREAD)) >= 0) close(f); free(path); if (f < 0) { /* doesn't exist, clone */ seek(g->clone, 0, 0); if ((n = read(g->clone, tmp, sizeof(tmp))) < 1) sysfatal("clone failed"); tmp[n] = 0; i = atoi(tmp); } if ((path = smprint("%s/%d/%s", g->path, i, g->synth->name)) == nil) sysfatal("memory"); if ((aux = g->synth->alloc(path)) == nil) sysfatal("couldn't alloc instance: %r"); free(path); if ((path = smprint("%s/%d/data", g->path, i)) == nil) sysfatal("memory"); if ((f = open(path, OREAD)) < 0) sysfatal("couldn't open data: %r"); free(path); if ((g->inst = realloc(g->inst, sizeof(Inst)*(g->numinst+1))) == nil) sysfatal("memory"); inst = &g->inst[g->numinst]; inst->data = f; inst->id = i; inst->aux = aux; g->numinst++; if (i == id) return inst; if (f >= 0) i++; } return nil; } static char * parse(char *s, Group *g) { Cmd c; char *e; Inst *inst; int i, n; float f; for (i = 1; s[i] != 0 && s[i] != '\n' && s[i] != ';'; i++); e = (s[i] == 0 || s[i] == '\n') ? nil : s + i + 1; s[i] = 0; if (g != nil) { s++; if ((inst = getinst(g, i36(*s++))) != nil) { memset(&c, 0, sizeof(c)); c.type = -1; n = 0; nextnote: f = 1.0; if (*s == '!') { f = -1.0; s++; } if ((*s >= 'a' && *s <= 'g') || (*s >= 'A' && *s <= 'G')) { if (s[1] != 0) { f *= note2freq(s[0], s[1]); s += 2; c.type = CmdNote; c.note[n].freq = f; c.note[n].vel = 1.0; c.note[n].dur = bar / 16.0; if (*s != 0) { c.note[n].vel = (float)i36(*s) / 16.0; s++; if (*s != 0) { c.note[n].dur = bar / (float)i36(*s); s++; } } n++; if (*s == ':') { s++; /* for the lack of better ideas, overwrite */ if (n >= nelem(c.note)) n--; goto nextnote; } } c.numnotes = n; } else if (strncmp(s, "vol", 3) == 0) { c.type = CmdVol; c.vol = atof(s+3) / 100.0; } else if (*s != 0) { c.type = CmdRaw; c.raw = s; } if (c.type >= 0) g->synth->cmd(inst->aux, &c); } } else if (strncmp(s, "bpm", 3) == 0) { if ((i = atoi(s+3)) > 0) { bpm = i; bar = 240.0 / (float)bpm; } } return e; } void threadmain(int argc, char **argv) { char *s, t[256]; Synth *synth; Biobuf *b; int i, j, n; ARGBEGIN{ default: usage(); }ARGEND; if (argc < 1) usage(); quotefmtinstall(); /* go through all groups */ for (i = 0; i < argc; i++) { /* search for specific synth handler by its name */ s = smprint("%s/metadata", argv[i]); if ((b = Bopen(s, OREAD)) == nil) sysfatal("%r"); free(s); synth = nil; while ((s = Brdline(b, '\n')) != nil) { if (strncmp(s, "name\t", 5) == 0) { s[Blinelen(b)-1] = 0; for (j = 0; j < nelem(synths) && strcmp(synths[j]->name, s+5) != 0; j++); if (j >= nelem(synths)) sysfatal("unknown synth %q\n", s+5); if ((groups = realloc(groups, sizeof(Group)*(numgroups+1))) == nil) sysfatal("memory"); synth = synths[j]; memset(&groups[numgroups], 0, sizeof(Group)); if ((s = smprint("%s/clone", argv[i])) == nil) sysfatal("memory"); if ((groups[numgroups].clone = open(s, OREAD)) < 0) sysfatal("%r"); free(s); groups[numgroups].path = argv[i]; groups[numgroups++].synth = synth; break; } } Bterm(b); if (synth == nil) sysfatal("no name set in %s/metadata", argv[i]); } for (;;) { if ((n = read(0, t, sizeof(t)-1)) < 1) break; t[n] = 0; for (s = t; s != nil && *s;) { i = i36(s[0]); qlock(&grouplock); s = parse(s, i < numgroups ? &groups[i] : nil); qunlock(&grouplock); } } threadexitsall(nil); }