ref: 9acd599496f6e8013cc2ccd18d105de17f49fca8
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 */
};
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;
}
void
fsopen(Req *r)
{
respond(r, nil);
}
void
fsread(Req *r)
{
Aux *a, *o;
Auxdsp *dsp;
char b[256];
FAUSTFLOAT *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 = (FAUSTFLOAT*)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;
}
}
void
fswrite(Req *r)
{
Aux *a, *o;
char b[256];
int st;
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);
st = o->ui->write != nil ? o->ui->write(o->ui, a->type, b) : -1;
respond(r, st == 0 ? nil : "write failed");
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
main(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]));
postmountsrv(&fs, srv, mtpt, MREPL);
exits(nil);
}