ref: 22f7e9038ca004a322d82d3ee543eb8ed42dbec9
dir: /dsp/fs.c/
#include <u.h> #include <libc.h> #include <fcall.h> #include <thread.h> #include <9p.h> #include "uiglue.h" typedef struct DSP DSP; #include "dspf.h" #include "common.h" #include "aux.h" enum { Inmax = 2048, /* float = 8192 bytes */ Outmax = 2048, /* float = 8192 bytes */ }; struct Auxdsp { void *dsp; float **in, **out; int numin, numout; int inmax, outmax; }; static Aux rootaux[] = { [Xctl] = {.type = Xctl}, [Xmetadata] = {.type = Xmetadata}, [Xclone] = {.type = Xclone}, }; static Aux *objs[32]; static char *meta = nil; static int metalen = 0; static int rate = 44100; static DSPf *dspf; extern Srv fs; static char Elocked[] = "file locked"; static void * auxtype2obj(int *type) { switch (*type) { case Xdspctl: case Xuictl: return (uchar*)type - offsetof(Aux, ctl); case Xdspdata: return (uchar*)type - offsetof(Aux, data); case Xuimeta: return (uchar*)type - offsetof(Aux, metadata); default: sysfatal("trying to get aux out of type %d", *type); } return nil; } static Aux * newobj(char *name) { File *f; Aux *o; Auxdsp *dsp; int i; for (i = 0, o = nil; o == nil && i < nelem(objs); i++) { if (objs[i] == nil){ o = objs[i] = calloc(1, sizeof(*o)+sizeof(Auxdsp)); break; } } if (o == nil) return nil; o->id = i; o->type = Xdsp; o->ctl = Xdspctl; o->data = Xdspdata; o->dsp = dsp = (Auxdsp*)(o+1); dsp->dsp = dspf->new(); dsp->in = dsp->out = nil; if ((dsp->numin = dspf->num_in(dsp->dsp)) > 0) { dsp->in = malloc(sizeof(*dsp->in) * dsp->numin); dsp->inmax = Inmax; for (i = 0; i < dsp->numin; i++) dsp->in[i] = malloc(sizeof(**dsp->in) * dsp->inmax); } if ((dsp->numout = dspf->num_out(dsp->dsp)) > 0) { dsp->out = malloc(sizeof(*dsp->out) * dsp->numout); dsp->outmax = Outmax; for (i = 0; i < dsp->numout; i++) dsp->out[i] = malloc(sizeof(**dsp->out) * dsp->outmax); } sprint(name, "%d", o->id); if ((f = createfile(fs.tree->root, name, nil, DMDIR|0775, o)) == nil) return nil; closefile(createfile(f, "ctl", nil, 0664, &o->ctl)); closefile(createfile(f, "data", nil, 0664, &o->data)); closefile(f); dspf->init(dsp->dsp, rate); uiglue.f = f; dspf->build_ui(dsp->dsp, &uiglue); return o; } static void freeobj(Aux *o) { int i; if (o == nil) return; if (o->type == Xdsp) { objs[o->id] = nil; dspf->delete(o->dsp->dsp); for (i = 0; i < o->dsp->numin; i++) free(o->dsp->in[i]); free(o->dsp->in); for (i = 0; i < o->dsp->numout; i++) free(o->dsp->out[i]); free(o->dsp->out); } free(o); } static void addmeta(void *metaInterface, const char *k, const char *v) { int klen, vlen; USED(metaInterface); if (strchr(k, '/') != nil) /* ignore library-specific meta */ return; klen = strlen(k); vlen = strlen(v); meta = realloc(meta, metalen + klen + 1 + vlen + 2); strcpy(meta+metalen, k); metalen += klen; meta[metalen++] = '\t'; strcpy(meta+metalen, v); metalen += vlen; meta[metalen++] = '\n'; meta[metalen] = 0; } static void fsopen(Req *r) { respond(r, nil); } static void fsread(Req *r) { Aux *a, *o; Auxdsp *dsp; char b[256]; float *p; int i, j, n, numframes, framesz; a = r->fid->file->aux; switch (a->type) { case Xctl: respond(r, nil); break; case Xmetadata: readstr(r, meta); respond(r, nil); break; case Xclone: if (r->ifcall.offset == 0) { if (newobj(b) != nil) { readstr(r, b); } else { snprint(b, sizeof(b), "no free objects: %r"); respond(r, b); break; } } respond(r, nil); break; case Xuictl: case Xuimeta: o = auxtype2obj(&a->type); if (o->ui->readstr != nil) readstr(r, o->ui->readstr(o->ui, a->type, b, sizeof(b))); respond(r, nil); break; case Xdspdata: o = auxtype2obj(&a->type); dsp = o->dsp; if (r->ifcall.offset == 0) /* clear every time the offset is reset */ dspf->clear(dsp->dsp); framesz = dsp->numout * sizeof(*p); n = r->ifcall.count; for (p = (float*)r->ofcall.data; n >= framesz;) { numframes = n / framesz; if (numframes > dsp->outmax) numframes = dsp->outmax; dspf->compute(dsp->dsp, numframes, dsp->in, dsp->out); for (i = 0; i < numframes; i++) { for (j = 0; j < dsp->numout; j++) *p++ = dsp->out[j][i]; } n -= numframes * framesz; } r->ofcall.count = r->ifcall.count - n; respond(r, nil); break; default: respond(r, "not implemented"); break; } } static void fswrite(Req *r) { Aux *a, *o; char b[256]; if (r->ifcall.count >= sizeof(b)) { respond(r, "can't fit into buffer"); return; } memmove(b, r->ifcall.data, r->ifcall.count); b[r->ifcall.count] = '\0'; r->ofcall.count = r->ifcall.count; a = r->fid->file->aux; switch (a->type) { case Xuictl: o = auxtype2obj(&a->type); if (o->ui->writestr == nil) respond(r, "not implemented"); else if (o->ui->writestr(o->ui, a->type, b) >= 0) respond(r, nil); else responderror(r); break; case Xdspctl: /* FIXME changing sampling rate */ o = auxtype2obj(&a->type); if (strncmp(b, "clear", 5) == 0) dspf->clear(o->dsp->dsp); else if (strncmp(b, "reset", 5) == 0) dspf->reset_ui(o->dsp->dsp); else if (strncmp(b, "init", 4) == 0) dspf->init(o->dsp->dsp, rate); respond(r, nil); break; case Xmetadata: /* FIXME should be possible to add new key/value */ default: respond(r, "not implemented"); break; } } static void fsdestroyfile(File *f) { Aux *a; if ((a = f->aux) == nil) return; switch (a->type) { case Xdsp: case Xui: freeobj(a); f->aux = nil; break; } } Srv fs = { .open = fsopen, .read = fsread, .write = fswrite, }; static void usage(void) { print("usage: %s [-s srv] [-m mtpt] [-r rate]\n", argv0); exits("usage"); } void threadmain(int argc, char **argv) { char *srv, *mtpt; MetaGlue mg; srv = nil; mtpt = nil; ARGBEGIN{ case 'D': chatty9p++; break; case 's': srv = EARGF(usage()); break; case 'm': mtpt = EARGF(usage()); break; case 'r': rate = atoi(EARGF(usage())); break; default: usage(); }ARGEND if (srv == nil && mtpt == nil) sysfatal("must specify -s or -m option"); mg.declare = addmeta; dspf = class_init(rate); dspf->metadata(&mg); fs.tree = alloctree(nil, nil, DMDIR|0775, fsdestroyfile); closefile(createfile(fs.tree->root, "ctl", nil, 0666, &rootaux[Xctl])); closefile(createfile(fs.tree->root, "metadata", nil, 0444, &rootaux[Xmetadata])); closefile(createfile(fs.tree->root, "clone", nil, 0444, &rootaux[Xclone])); threadpostmountsrv(&fs, srv, mtpt, MREPL); threadexits(nil); }