ref: c951f1864a755bb827da3031c03d9578b648b7a6
parent: dfa2da9cf2e227226350201c9c1d07c2194c2632
author: Sigrid Haflínudóttir <[email protected]>
date: Sat Mar 21 21:21:21 EDT 2020
split common logic out of AY and DSP
--- a/aux.h
+++ /dev/null
@@ -1,29 +1,0 @@
-typedef enum {
- Xclone,
- Xctl,
- Xmetadata,
-
- Xdsp,
- Xdspctl,
- Xdspdata,
-
- Xui,
- Xuictl,
- Xuimeta,
-}Auxtype;
-
-typedef struct Aux Aux;
-typedef struct Auxdsp Auxdsp;
-
-struct UI;
-
-struct Aux {
- Auxtype type;
- int id;
- int ctl;
- int data;
- int metadata;
-
- Auxdsp *dsp;
- struct UI *ui;
-};
--- a/ay/ay.c
+++ b/ay/ay.c
@@ -7,8 +7,8 @@
#define CHIPS_ASSERT assert
#include "ay38910.h"
#include "common.h"
-#include "uiglue.h"
-#include "aux.h"
+#include "ui.h"
+#include "fs.h"
#define MIN(a,b) ((a)<=(b)?(a):(b))
#define MAX(a,b) ((a)>=(b)?(a):(b))
@@ -38,21 +38,8 @@
int envmode;
};
-static Aux rootaux[] = {
- [Xctl] = {.type = Xctl},
- [Xmetadata] = {.type = Xmetadata},
- [Xclone] = {.type = Xclone},
-};
-
static int tickhz = 1773400;
-
-extern Srv fs;
-
static int rate = 44100;
-static Aux *objs[32];
-static char *meta =
- "name\tAY-3-8910\n"
- "group\tSynthesis\n";
static void
regw(ay38910_t *ay, int reg, int v)
@@ -106,9 +93,9 @@
}
static int
-writeay(UI *ui, int auxtype, char *s)
+writectl(UI *ui, int auxtype, char *s)
{
- Auxdsp *dsp;
+ struct Auxdsp *dsp;
ay38910_t *ay;
int r, i, level;
vlong pd;
@@ -187,254 +174,121 @@
return 0;
}
-static void
-buildui(Auxdsp *dsp, UIGlue *ui)
+#define BIND(x) do { ui = x; ui->userdata = dsp; ui->writestr = writectl; writectl(ui, Xuictl, "reset"); } while(0)
+
+extern File *uif;
+
+static Auxdsp *
+dspnew(void)
{
- float min, step, max;
+ struct Auxdsp *dsp;
+ UI *ui;
char s[32];
+ float min, step, max;
+ ay38910_desc_t desc = {
+ .type = AY38910_TYPE_8910,
+ .tick_hz = tickhz,
+ .sound_hz = rate,
+ .magnitude = 1.0,
+ };
int i;
+ if ((dsp = malloc(sizeof(*dsp))) == nil)
+ return nil;
+ ay38910_init(&dsp->ay, &desc);
+ regw(&dsp->ay, AY38910_REG_ENABLE, 0xff); /* disable everything */
+
min = ceil(tickhz/65520);
max = floor(tickhz/16);
step = MAX(1, ceil(tickhz/65504 - tickhz/65520));
- ui->userdata = dsp;
- ui->writestr = writeay;
- ui->openVerticalBox(ui->f, "AY-3-8910");
- ui->addHorizontalSlider(ui->f, "Volume", &dsp->ay.mag, 1.0f, 0.0f, 1.0f, 0.001f);
+ ui_vgroup("AY-3-8910");
+ BIND(ui_hslider("Volume", &dsp->ay.mag, 1.0f, 0.0f, 1.0f, 0.001f));
+
for (i = 0; i < nelem(dsp->chan); i++) {
sprint(s, "%c", 'A'+i);
- ui->openVerticalBox(ui->f, s);
+ ui_tgroup(s);
+ ui_hgroup("Tone");
+ ui_declare(&dsp->chan[i].freq, "0", "");
+ ui_declare(&dsp->chan[i].freq, "unit", "Hz");
+ BIND(ui_hslider("Frequency", &dsp->chan[i].freq, min, min, max, step));
- ui->openHorizontalBox(ui->f, "Tone");
- ui->declare(ui->f, &dsp->chan[i].freq, "0", "");
- ui->declare(ui->f, &dsp->chan[i].freq, "unit", "Hz");
- ui->addHorizontalSlider(ui->f, "Frequency", &dsp->chan[i].freq, min, min, max, step);
- ui->declare(ui->f, &dsp->chan[i].enable, "1", "");
- ui->addCheckButton(ui->f, "Enable", &dsp->chan[i].enable);
- ui->closeBox(ui->f);
+ ui_declare(&dsp->chan[i].enable, "1", "");
+ BIND(ui_checkbox("Enable", &dsp->chan[i].enable));
+ ui_endgroup();
- ui->declare(ui->f, &dsp->chan[i].amp, "0", "");
- ui->addHorizontalSlider(ui->f, "Volume", &dsp->chan[i].amp, 1.0f, 0.0f, 1.0f, 1.0f/15.0f);
+ ui_declare(&dsp->chan[i].amp, "0", "");
+ BIND(ui_hslider("Volume", &dsp->chan[i].amp, 1.0f, 0.0f, 1.0f, 1.0f/15.0f));
- ui->declare(ui->f, &dsp->chan[i].envelope, "1", "");
- ui->addCheckButton(ui->f, "Envelope", &dsp->chan[i].envelope);
+ ui_declare(&dsp->chan[i].envelope, "1", "");
+ BIND(ui_checkbox("Envelope", &dsp->chan[i].envelope));
- ui->declare(ui->f, &dsp->chan[i].noise, "2", "");
- ui->addCheckButton(ui->f, "Noise", &dsp->chan[i].noise);
-
- ui->closeBox(ui->f);
+ ui_declare(&dsp->chan[i].noise, "2", "");
+ BIND(ui_checkbox("Noise", &dsp->chan[i].noise));
+ ui_endgroup();
}
min = ceil(tickhz/496);
max = floor(tickhz/16);
step = MAX(1, tickhz/480 - tickhz/496);
- ui->declare(ui->f, &dsp->noisefreq, "unit", "Hz");
- ui->addHorizontalSlider(ui->f, "Noise", &dsp->noisefreq, min, min, max, step);
+ ui_declare(&dsp->noisefreq, "unit", "Hz");
+ BIND(ui_hslider("Noise", &dsp->noisefreq, min, min, max, step));
- ui->openVerticalBox(ui->f, "Envelope");
- min = MAX(1, 256000/tickhz);
- max = floor(16776960000LL/tickhz);
- ui->declare(ui->f, &dsp->envperiod, "0", "");
- ui->declare(ui->f, &dsp->envperiod, "unit", "ms");
- ui->addHorizontalSlider(ui->f, "Period", &dsp->envperiod, 500, min, max, 1);
- ui->declare(ui->f, &dsp->hold, "1", "");
- ui->addCheckButton(ui->f, "Hold", &dsp->hold);
- ui->declare(ui->f, &dsp->alternate, "2", "");
- ui->addCheckButton(ui->f, "Alternate", &dsp->alternate);
- ui->declare(ui->f, &dsp->attack, "3", "");
- ui->addCheckButton(ui->f, "Attack", &dsp->attack);
- ui->declare(ui->f, &dsp->cont, "4", "");
- ui->addCheckButton(ui->f, "Continue", &dsp->cont);
- ui->declare(ui->f, &dsp->hit, "5", "");
- ui->addButton(ui->f, "Hit", &dsp->hit);
- ui->closeBox(ui->f);
+ ui_vgroup("Envelope");
+ min = MAX(1, 256000/tickhz);
+ max = floor(16776960000LL/tickhz);
+ ui_declare(&dsp->envperiod, "0", "");
+ ui_declare(&dsp->envperiod, "unit", "ms");
+ BIND(ui_hslider("Period", &dsp->envperiod, 500, min, max, 1));
- ui->closeBox(ui->f);
-}
+ ui_declare(&dsp->hold, "1", "");
+ BIND(ui_checkbox("Hold", &dsp->hold));
-static Aux *
-newobj(char *name)
-{
- File *f;
- Aux *o;
- Auxdsp *dsp;
- int i;
- ay38910_desc_t d = {
- .type = AY38910_TYPE_8910,
- .tick_hz = tickhz,
- .sound_hz = rate,
- .magnitude = 1.0,
- };
+ ui_declare(&dsp->alternate, "2", "");
+ BIND(ui_checkbox("Alternate", &dsp->alternate));
- 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;
+ ui_declare(&dsp->attack, "3", "");
+ BIND(ui_checkbox("Attack", &dsp->attack));
- o->id = i;
- o->type = Xdsp;
- o->ctl = Xdspctl;
- o->data = Xdspdata;
- o->dsp = dsp = (Auxdsp*)(o+1);
- ay38910_init(&dsp->ay, &d);
- regw(&dsp->ay, AY38910_REG_ENABLE, 0xff); /* disable everything */
+ ui_declare(&dsp->cont, "4", "");
+ BIND(ui_checkbox("Continue", &dsp->cont));
- 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);
+ ui_declare(&dsp->hit, "5", "");
+ BIND(ui_button("Hit", &dsp->hit));
+ ui_endgroup();
- uiglue.f = f;
- buildui(dsp, &uiglue);
+ ui_endgroup();
- return o;
+ return dsp;
}
-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 void
-fsopen(Req *r)
+dspfree(Auxdsp *dsp)
{
- respond(r, nil);
+ free(dsp);
}
static void
-fsread(Req *r)
+dspreset(Auxdsp *dsp)
{
- Aux *a, *o;
- Auxdsp *dsp;
- char b[256];
- float *p;
- int n;
-
- 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;
- n = r->ifcall.count;
- for (p = (float*)r->ofcall.data; n >= sizeof(float); p++) {
- while (!ay38910_tick(&dsp->ay));
- *p = dsp->ay.sample;
- n -= sizeof(float);
- }
- r->ofcall.count = r->ifcall.count - n;
- respond(r, nil);
- break;
- default:
- respond(r, "not implemented");
- break;
- }
+ ay38910_reset(&dsp->ay);
}
-static void
-fswrite(Req *r)
+static int
+dspread(Auxdsp *dsp, float *b, int n)
{
- Aux *a, *o;
- char b[256];
+ int i;
- if (r->ifcall.count >= sizeof(b)) {
- respond(r, "can't fit into buffer");
- return;
+ for (i = 0; i < n; i++) {
+ while (!ay38910_tick(&dsp->ay));
+ b[i] = dsp->ay.sample;
}
- 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, "reset", 5) == 0) /* FIXME ui needs to be reset as well */
- ay38910_reset(&o->dsp->ay);
- respond(r, nil);
- break;
- case Xmetadata: /* FIXME should be possible to add new key/value */
- default:
- respond(r, "not implemented");
- break;
- }
+ return n;
}
-Srv fs = {
- .open = fsopen,
- .read = fsread,
- .write = fswrite,
-};
-
static void
-freeobj(Aux *o)
-{
- if (o == nil)
- return;
-
- if (o->type == Xdsp)
- objs[o->id] = nil;
-
- free(o);
-}
-
-static void
usage(void)
{
print("usage: %s [-s srv] [-m mtpt] [-r rate] [-t HZ]\n", argv0);
@@ -441,22 +295,16 @@
threadexitsall("usage");
}
-static void
-fsdestroyfile(File *f)
-{
- Aux *a;
+static Fs fs = {
+ .metadata ="name\tAY-3-8910\ngroup\tSynthesis\n",
+ .dsp = {
+ .new = dspnew,
+ .free = dspfree,
+ .reset = dspreset,
+ .read = dspread,
+ },
+};
- if ((a = f->aux) == nil)
- return;
- switch (a->type) {
- case Xdsp:
- case Xui:
- freeobj(a);
- f->aux = nil;
- break;
- }
-}
-
void
threadmain(int argc, char **argv)
{
@@ -490,10 +338,7 @@
if (srv == nil && mtpt == nil)
sysfatal("must specify -s or -m option");
- 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);
+ fsinit(&fs);
+ threadpostmountsrv(&fs.srv, srv, mtpt, MREPL);
threadexits(nil);
}
--- a/ay/mkfile
+++ b/ay/mkfile
@@ -1,20 +1,11 @@
</$objtype/mkfile
TARG=ay
-CFLAGS=$CFLAGS -p -I..
-BIN=/$objtype/bin/daw
OFILES=\
ay.$O\
- common.$O\
- uiglue.$O\
default:V: all
-</sys/src/cmd/mkone
-
-common.$O: ../common.c
- $CC $CFLAGS $prereq
-
-uiglue.$O: ../uiglue.c
- $CC $CFLAGS $prereq
+MANY=one
+<../mkfs
--- a/cfg/cfg.c
+++ b/cfg/cfg.c
@@ -19,6 +19,8 @@
const char *label;
int index;
+ uvlong qidpath;
+
int ivalue;
double value;
double init;
@@ -136,7 +138,7 @@
newui(char *path)
{
UI *ui;
- Dir *dirs;
+ Dir *dirs, *d;
char *s, *name, tmp[64];
long i, n;
int f;
@@ -170,7 +172,10 @@
ui->flags |= Hasclone;
} else if (strcmp(name, "ctl") == 0) {
ui->ctl = open(s, ORDWR);
- readctl(ui);
+ if (readctl(ui) == 0 && ui->ctl >= 0 && (d = dirfstat(ui->ctl)) != nil) {
+ ui->qidpath = d->qid.path;
+ free(d);
+ }
} else if (dirs[i].mode & DMDIR) {
ui->child = realloc(ui->child, (ui->numchild+1) * sizeof(*ui->child));
ui->child[ui->numchild++] = newui(s);
--- a/common.h
+++ b/common.h
@@ -1,4 +1,4 @@
-enum {
+typedef enum {
UITGroup,
UIHGroup,
UIVGroup,
@@ -10,6 +10,6 @@
UIHBarGraph,
UIVBarGraph,
UInum,
-};
+}UItype;
extern char *uitypenames[UInum];
--- a/dsp/fs.c
+++ /dev/null
@@ -1,331 +1,0 @@
-#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);
-}
--- /dev/null
+++ b/dsp/main.c
@@ -1,0 +1,169 @@
+#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 "fs.h"
+#include "ui.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 int rate = 44100;
+static DSPf *dspf;
+
+static Auxdsp *
+dspnew(void)
+{
+ Auxdsp *dsp;
+ int i;
+
+ if ((dsp = calloc(1, sizeof(*dsp))) == nil)
+ return nil;
+
+ 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);
+ }
+
+ dspf->init(dsp->dsp, rate);
+ dspf->build_ui(dsp->dsp, &uiglue);
+
+ return dsp;
+}
+
+static void
+dspfree(Auxdsp *dsp)
+{
+ int i;
+
+ dspf->delete(dsp->dsp);
+ for (i = 0; i < dsp->numin; i++)
+ free(dsp->in[i]);
+ free(dsp->in);
+ for (i = 0; i < dsp->numout; i++)
+ free(dsp->out[i]);
+ free(dsp->out);
+ free(dsp);
+}
+
+static void
+dspreset(Auxdsp *dsp)
+{
+ dspf->reset_ui(dsp->dsp);
+}
+
+static int
+dspread(Auxdsp *dsp, float *b, int n)
+{
+ int i, j, numframes;
+
+ numframes = n / dsp->numout;
+ dspf->compute(dsp->dsp, numframes, dsp->in, dsp->out);
+ for (i = 0; i < numframes; i++) {
+ for (j = 0; j < dsp->numout; j++)
+ *b++ = dsp->out[j][i];
+ }
+
+ return n;
+}
+
+static void
+usage(void)
+{
+ print("usage: %s [-s srv] [-m mtpt] [-r rate]\n", argv0);
+ exits("usage");
+}
+
+static Fs fs = {
+ .dsp = {
+ .new = dspnew,
+ .free = dspfree,
+ .reset = dspreset,
+ .read = dspread,
+ },
+};
+
+static void
+addmeta(void *metaInterface, const char *k, const char *v)
+{
+ int klen, vlen;
+ static int metalen;
+
+ USED(metaInterface);
+
+ if (strchr(k, '/') != nil) /* ignore library-specific meta */
+ return;
+
+ klen = strlen(k);
+ vlen = strlen(v);
+ fs.metadata = realloc(fs.metadata, metalen + klen + 1 + vlen + 2);
+ strcpy(fs.metadata+metalen, k);
+ metalen += klen;
+ fs.metadata[metalen++] = '\t';
+ strcpy(fs.metadata+metalen, v);
+ metalen += vlen;
+ fs.metadata[metalen++] = '\n';
+ fs.metadata[metalen] = 0;
+}
+
+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);
+
+ fsinit(&fs);
+ threadpostmountsrv(&fs.srv, srv, mtpt, MREPL);
+ threadexits(nil);
+}
--- a/dsp/mkfile
+++ b/dsp/mkfile
@@ -6,28 +6,19 @@
BIN=/$objtype/bin/daw
OFILES=\
- common.$O\
- fs.$O\
+ main.$O\
uiglue.$O\
CFLAGS=$CFLAGS -I..
-default:V: all
-
CLEANFILES=\
-</sys/src/cmd/mkmany
+MANY=many
+<../mkfs
+
%.c: %.dsp
os -d `{../osdir} ./dsp2c $"prereq || \
{ echo $target needs to be regenerated with "./dsp2c $prereq"; exit 1 }
-$BIN/%: $O.%
- mkdir -p $BIN
- cp $O.$stem $BIN/$stem
-
-common.$O: ../common.c
- $CC $CFLAGS $prereq
-
-uiglue.$O: ../uiglue.c
- $CC $CFLAGS $prereq
+</sys/src/cmd/mkmany
--- /dev/null
+++ b/fs.c
@@ -1,0 +1,214 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include "common.h"
+#include "ui.h"
+#include "fs.h"
+
+enum {
+ Maxobjs = 32,
+};
+
+static Aux *objs[Maxobjs];
+
+static Aux rootaux[] = {
+ [Xctl] = {.type = Xctl},
+ [Xmetadata] = {.type = Xmetadata},
+ [Xclone] = {.type = Xclone},
+};
+
+extern File *uif;
+
+static Fs *fs;
+
+static Aux *
+newobj(char *name)
+{
+ File *f;
+ Aux *o;
+ int i, mode;
+
+ for (i = 0, o = nil; o == nil && i < nelem(objs); i++) {
+ if (objs[i] == nil){
+ o = objs[i] = calloc(1, sizeof(*o));
+ break;
+ }
+ }
+ if (o == nil)
+ return nil;
+
+ o->id = i;
+ o->type = Xdsp;
+ o->ctl = Xdspctl;
+ o->data = Xdspdata;
+
+ sprint(name, "%d", o->id);
+ if ((f = createfile(fs->srv.tree->root, name, nil, DMDIR|0775, o)) == nil)
+ return nil;
+ closefile(createfile(f, "ctl", nil, 0664, &o->ctl));
+ mode = 0;
+ if (fs->dsp.read != nil)
+ mode |= 0444;
+ if (fs->dsp.write != nil)
+ mode |= 0222;
+ closefile(createfile(f, "data", nil, mode, &o->data));
+
+ uif = f;
+ o->dsp = fs->dsp.new();
+ closefile(f);
+
+ return o;
+}
+
+static void
+freeobj(Aux *o)
+{
+ if (o == nil)
+ return;
+
+ if (o->type == Xdsp) {
+ objs[o->id] = nil;
+ fs->dsp.free(o->dsp);
+ }
+
+ free(o);
+}
+
+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 void
+fsopen(Req *r)
+{
+ respond(r, nil);
+}
+
+static void
+fsread(Req *r)
+{
+ Aux *a, *o;
+ char b[256];
+
+ a = r->fid->file->aux;
+ switch (a->type) {
+ case Xctl:
+ respond(r, nil);
+ break;
+ case Xmetadata:
+ readstr(r, fs->metadata);
+ 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);
+ r->ofcall.count = fs->dsp.read(o->dsp, (float*)r->ofcall.data, r->ifcall.count/sizeof(float))*sizeof(float);
+ 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, "reset", 5) == 0) /* FIXME ui needs to be reset as well */
+ fs->dsp.reset(o->dsp);
+ 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;
+ }
+}
+
+void
+fsinit(void *fs_)
+{
+ fs = fs_;
+ fs->srv.open = fsopen;
+ fs->srv.read = fsread;
+ fs->srv.write = fswrite;
+ fs->srv.tree = alloctree(nil, nil, DMDIR|0775, fsdestroyfile);
+ closefile(createfile(fs->srv.tree->root, "ctl", nil, 0666, &rootaux[Xctl]));
+ closefile(createfile(fs->srv.tree->root, "metadata", nil, 0444, &rootaux[Xmetadata]));
+ closefile(createfile(fs->srv.tree->root, "clone", nil, 0444, &rootaux[Xclone]));
+}
--- /dev/null
+++ b/fs.h
@@ -1,0 +1,49 @@
+typedef struct Aux Aux;
+typedef struct Auxdsp Auxdsp;
+typedef struct Fs Fs;
+
+typedef enum {
+ Xclone,
+ Xctl,
+ Xmetadata,
+
+ Xdsp,
+ Xdspctl,
+ Xdspdata,
+
+ Xui,
+ Xuictl,
+ Xuimeta,
+}Auxtype;
+
+struct UI;
+
+struct Aux {
+ Auxtype type;
+ int id;
+ int ctl;
+ int data;
+ int metadata;
+
+ Auxdsp *dsp;
+ struct UI *ui;
+};
+
+struct Fs {
+ Srv srv;
+ char *metadata;
+
+ struct {
+ Auxdsp *(*new)(void);
+ void (*free)(Auxdsp *dsp);
+ void (*reset)(Auxdsp *dsp);
+
+ /* optional, n is always modulo number of channels */
+ int (*read)(Auxdsp *dsp, float *b, int n);
+
+ /* optional, n is always modulo number of channels */
+ int (*write)(Auxdsp *dsp, float *b, int n);
+ }dsp;
+};
+
+void fsinit(void *fs);
--- a/mkfile
+++ b/mkfile
@@ -12,8 +12,7 @@
BIN=/$objtype/bin/daw
-none:VQ:
- echo mk all, install, clean, nuke, or libs
+default:V: all
all install clean nuke:VQ:
for (i in $LIBS $CMDS) @{
--- /dev/null
+++ b/mkfs
@@ -1,0 +1,27 @@
+BIN=/$objtype/bin/daw
+
+CFLAGS=$CFLAGS -p -I..
+
+OFILES=\
+ $OFILES\
+ common.$O\
+ fs.$O\
+ ui.$O\
+
+</sys/src/cmd/mk$MANY
+
+$BIN/%: $O.%
+ mkdir -p $BIN
+ cp $O.$stem $BIN/$stem
+
+common.$O: ../common.c
+ $CC $CFLAGS $prereq
+
+fs.$O: ../fs.c
+ $CC $CFLAGS $prereq
+
+ui.$O: ../ui.c
+ $CC $CFLAGS $prereq
+
+uiglue.$O: ../uiglue.c
+ $CC $CFLAGS $prereq
--- /dev/null
+++ b/ui.c
@@ -1,0 +1,289 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include "common.h"
+#include "ui.h"
+#include "fs.h"
+#include "uiglue.h"
+
+static struct {
+ float *zone;
+ Meta *meta;
+ int nummeta;
+}decl;
+
+File *uif;
+
+char *
+ui_readstr(UI *ui, int auxtype, char *s, int sz)
+{
+ char *x, *t;
+ int i;
+
+ if (auxtype == Xuictl) {
+ if (ui->type < 0 || ui->type >= UInum)
+ sysfatal("unknown ui type %d", ui->type);
+ t = uitypenames[ui->type];
+ switch (ui->type) {
+ case UITGroup:
+ case UIHGroup:
+ case UIVGroup:
+ snprint(s, sz, "%s\n", t);
+ return s;
+ case UIButton:
+ case UICheckBox:
+ snprint(s, sz, "%s\t%g\n", t, *ui->zone);
+ return s;
+ case UIVSlider:
+ case UIHSlider:
+ case UINEntry:
+ snprint(s, sz, "%s\t%g\t%g\t%g\t%g\t%g\n", t, *ui->zone, ui->init, ui->min, ui->max, ui->step);
+ return s;
+ case UIHBarGraph:
+ case UIVBarGraph:
+ snprint(s, sz, "%s\t%g\t%g\t%g\n", t, *ui->zone, ui->min, ui->max);
+ return s;
+ default:
+ sysfatal("readstr not implemented for ui type %d", ui->type);
+ }
+ } else if (auxtype == Xuimeta) {
+ x = s;
+ *x = 0;
+ for (i = 0; i < ui->nummeta; i++)
+ x = seprint(x, s+sz-1, "%s\t%s\n", ui->meta[i].k, ui->meta[i].v);
+ return s;
+ } else {
+ sysfatal("unsupported ui aux %d", auxtype);
+ }
+
+ return nil;
+}
+
+int
+ui_writestr(UI *ui, int auxtype, char *s)
+{
+ char *e;
+ int failoor;
+ float v;
+
+ if (auxtype != Xuictl)
+ sysfatal("unsupported ui aux %d", auxtype);
+
+ /* FIXME optional argument should specify at which frame to apply the change */
+
+ v = 0.0f;
+ failoor = 0;
+ if (strncmp(s, "reset", 5) == 0) { /* FIXME reset for a box should reset ALL controls inside it */
+ v = ui->init;
+ } else if (strncmp(s, "add", 3) == 0) {
+ if (ui->zone != nil)
+ v = *ui->zone + atof(s+3);
+ } else if (strncmp(s, "sub", 3) == 0) {
+ if (ui->zone != nil)
+ v = *ui->zone - atof(s+3);
+ } else {
+ v = strtod(s, &e);
+ if (*e != 0 && *e != '\n')
+ return -1;
+ failoor = 1;
+ }
+
+ if (ui->zone != nil) {
+ if (ui->type == UIButton || ui->type == UICheckBox) {
+ *ui->zone = v > 0 ? 1 : 0;
+ } else {
+ if (v < ui->min) {
+ if (failoor)
+ return -1;
+ v = ui->min;
+ } else if (v > ui->max) {
+ if (failoor)
+ return -1;
+ v = ui->max;
+ }
+ *ui->zone = v;
+ }
+ }
+
+ return 0;
+}
+
+static UI *
+newui(const char *label, int type)
+{
+ Aux *a;
+ File *f, *d;
+
+ a = calloc(1, sizeof(*a) + sizeof(UI) + sizeof(Meta)*decl.nummeta);
+ a->type = Xui;
+ a->ui = (UI*)(a+1);
+ a->ui->type = type;
+ a->ui->meta = (Meta*)(a->ui+1);
+ a->ui->nummeta = decl.nummeta;
+ memmove(a->ui->meta, decl.meta, sizeof(Meta)*decl.nummeta);
+ a->ctl = Xuictl;
+ a->metadata = Xuimeta;
+ a->ui->zone = decl.zone;
+ a->ui->label = label;
+ a->ui->readstr = ui_readstr;
+ a->ui->writestr = ui_writestr;
+ if ((d = createfile(uif, label, nil, DMDIR|0775, a)) == nil)
+ sysfatal("failed to create '%s': %r", label);
+ if ((f = createfile(d, "ctl", nil, 0664, &a->ctl)) == nil)
+ sysfatal("failed to create '%s/ctl': %r", label);
+ closefile(f);
+ if ((f = createfile(d, "metadata", nil, 0664, &a->metadata)) == nil)
+ sysfatal("failed to create '%s/metadata': %r", label);
+ closefile(f);
+ closefile(d);
+
+ free(decl.meta);
+ decl.zone = nil;
+ decl.meta = nil;
+ decl.nummeta = 0;
+
+ if (type == UITGroup || type == UIHGroup || type == UIVGroup)
+ uif = d;
+
+ return a->ui;
+}
+
+static UI *
+newdef(int type, const char *label, float *zone)
+{
+ if (zone != decl.zone) { /* no "declare" called before */
+ decl.zone = zone;
+ free(decl.meta);
+ decl.meta = nil;
+ decl.nummeta = 0;
+ }
+ return newui(label, type);
+}
+
+void
+ui_tgroup(const char *label)
+{
+ newui(label, UITGroup);
+}
+
+void
+ui_hgroup(const char *label)
+{
+ newui(label, UIHGroup);
+}
+
+void
+ui_vgroup(const char *label)
+{
+ newui(label, UIVGroup);
+}
+
+void
+ui_endgroup(void)
+{
+ uif = uif->parent;
+}
+
+UI *
+ui_button(const char *label, float *zone)
+{
+ UI *ui;
+
+ ui = newdef(UIButton, label, zone);
+ *zone = 0;
+
+ return ui;
+}
+
+UI *
+ui_checkbox(const char *label, float *zone)
+{
+ UI *ui;
+
+ ui = newdef(UICheckBox, label, zone);
+ *zone = 0;
+
+ return ui;
+}
+
+UI *
+ui_vslider(const char *label, float *zone, float init, float min, float max, float step)
+{
+ UI *ui;
+
+ ui = newdef(UIVSlider, label, zone);
+ ui->init = *zone = init;
+ ui->min = min;
+ ui->max = max;
+ ui->step = step;
+
+ return ui;
+}
+
+UI *
+ui_hslider(const char *label, float *zone, float init, float min, float max, float step)
+{
+ UI *ui;
+
+ ui = newdef(UIHSlider, label, zone);
+ ui->init = *zone = init;
+ ui->min = min;
+ ui->max = max;
+ ui->step = step;
+
+ return ui;
+}
+
+UI *
+ui_nentry(const char *label, float *zone, float init, float min, float max, float step)
+{
+ UI *ui;
+
+ ui = newdef(UINEntry, label, zone);
+ ui->init = *zone = init;
+ ui->min = min;
+ ui->max = max;
+ ui->step = step;
+
+ return ui;
+}
+
+UI *
+ui_hbargraph(const char *label, float *zone, float min, float max)
+{
+ UI *ui;
+
+ ui = newdef(UIHBarGraph, label, zone);
+ ui->min = min;
+ ui->max = max;
+ *zone = 0;
+
+ return ui;
+}
+
+UI *
+ui_vbargraph(const char *label, float *zone, float min, float max)
+{
+ UI *ui;
+
+ ui = newdef(UIVBarGraph, label, zone);
+ ui->min = min;
+ ui->max = max;
+ *zone = 0;
+
+ return ui;
+}
+
+void
+ui_declare(float *zone, const char *key, const char *value)
+{
+ if (decl.zone != nil && decl.zone != zone)
+ sysfatal("%s=\"%s\": zone mismatch during declaration (%p != %p)", key, value, decl.zone, zone);
+ decl.zone = zone;
+ decl.meta = realloc(decl.meta, sizeof(Meta)*(decl.nummeta+1));
+ decl.meta[decl.nummeta].k = key;
+ decl.meta[decl.nummeta].v = value;
+ decl.nummeta++;
+}
--- /dev/null
+++ b/ui.h
@@ -1,0 +1,41 @@
+typedef struct Meta Meta;
+typedef struct UI UI;
+
+struct Meta {
+ const char *k;
+ const char *v;
+};
+
+struct UI {
+ int type;
+ const char *label;
+ float *zone;
+ float init;
+ float min;
+ float max;
+ float step;
+
+ Meta *meta;
+ int nummeta;
+
+ /* optional */
+ char *(*readstr)(UI *ui, int auxtype, char *s, int sz);
+ int (*writestr)(UI *ui, int auxtype, char *s);
+ void *userdata;
+};
+
+char *ui_readstr(UI *ui, int auxtype, char *s, int sz);
+int ui_writestr(UI *ui, int auxtype, char *s);
+
+void ui_tgroup(const char *label);
+void ui_hgroup(const char *label);
+void ui_vgroup(const char *label);
+void ui_endgroup(void);
+UI *ui_button(const char *label, float *zone);
+UI *ui_checkbox(const char *label, float *zone);
+UI *ui_vslider(const char *label, float *zone, float init, float min, float max, float step);
+UI *ui_hslider(const char *label, float *zone, float init, float min, float max, float step);
+UI *ui_nentry(const char *label, float *zone, float init, float min, float max, float step);
+UI *ui_hbargraph(const char *label, float *zone, float min, float max);
+UI *ui_vbargraph(const char *label, float *zone, float min, float max);
+void ui_declare(float *zone, const char *key, const char *value);
--- a/uiglue.c
+++ b/uiglue.c
@@ -4,298 +4,34 @@
#include <thread.h>
#include <9p.h>
#include "common.h"
+#include "ui.h"
+#include "fs.h"
#include "uiglue.h"
-#include "aux.h"
-static struct {
- float *zone;
- Meta *meta;
- int nummeta;
-}decl;
+static void openTabBox(void *, const char *label) { ui_tgroup(label); }
+static void openHorizontalBox(void *, const char *label) { ui_hgroup(label); }
+static void openVerticalBox(void *, const char *label) { ui_vgroup(label); }
+static void closeBox(void *) { ui_endgroup(); }
+static void addButton(void *, const char *label, float *zone) { ui_button(label, zone); }
+static void addCheckButton(void *, const char *label, float *zone) { ui_checkbox(label, zone); }
+static void addVerticalSlider(void *, const char *label, float *zone, float init, float min, float max, float step) { ui_vslider(label, zone, init, min, max, step); }
+static void addHorizontalSlider(void *, const char *label, float *zone, float init, float min, float max, float step) { ui_hslider(label, zone, init, min, max, step); }
+static void addNumEntry(void *, const char *label, float *zone, float init, float min, float max, float step) { ui_nentry(label, zone, init, min, max, step); }
+static void addVerticalBargraph(void *, const char *label, float *zone, float min, float max) { ui_vbargraph(label, zone, min, max); }
+static void addHorizontalBargraph(void *, const char *label, float *zone, float min, float max) { ui_hbargraph(label, zone, min, max); }
+static void declare(void *, float *zone, const char *key, const char *value) { ui_declare(zone, key, value); }
-char *
-ui_readstr(UI *ui, int auxtype, char *s, int sz)
-{
- char *x, *t;
- int i;
-
- if (auxtype == Xuictl) {
- if (ui->type < 0 || ui->type >= UInum)
- sysfatal("unknown ui type %d", ui->type);
- t = uitypenames[ui->type];
- switch (ui->type) {
- case UITGroup:
- case UIHGroup:
- case UIVGroup:
- snprint(s, sz, "%s\n", t);
- return s;
- case UIButton:
- case UICheckBox:
- snprint(s, sz, "%s\t%g\n", t, *ui->zone);
- return s;
- case UIVSlider:
- case UIHSlider:
- case UINEntry:
- snprint(s, sz, "%s\t%g\t%g\t%g\t%g\t%g\n", t, *ui->zone, ui->init, ui->min, ui->max, ui->step);
- return s;
- case UIHBarGraph:
- case UIVBarGraph:
- snprint(s, sz, "%s\t%g\t%g\t%g\n", t, *ui->zone, ui->min, ui->max);
- return s;
- default:
- sysfatal("readstr not implemented for ui type %d", ui->type);
- }
- } else if (auxtype == Xuimeta) {
- x = s;
- *x = 0;
- for (i = 0; i < ui->nummeta; i++)
- x = seprint(x, s+sz-1, "%s\t%s\n", ui->meta[i].k, ui->meta[i].v);
- return s;
- } else {
- sysfatal("unsupported ui aux %d", auxtype);
- }
-
- return nil;
-}
-
-int
-ui_writestr(UI *ui, int auxtype, char *s)
-{
- char *e;
- int failoor;
- float v;
-
- if (auxtype != Xuictl)
- sysfatal("unsupported ui aux %d", auxtype);
-
- /* FIXME optional argument should specify at which frame to apply the change */
-
- v = 0.0f;
- failoor = 0;
- if (strncmp(s, "reset", 5) == 0) { /* FIXME reset for a box should reset ALL controls inside it */
- v = ui->init;
- } else if (strncmp(s, "add", 3) == 0) {
- if (ui->zone != nil)
- v = *ui->zone + atof(s+3);
- } else if (strncmp(s, "sub", 3) == 0) {
- if (ui->zone != nil)
- v = *ui->zone - atof(s+3);
- } else {
- v = strtod(s, &e);
- if (*e != 0 && *e != '\n')
- return -1;
- failoor = 1;
- }
-
- if (ui->zone != nil) {
- if (ui->type == UIButton || ui->type == UICheckBox) {
- *ui->zone = v > 0 ? 1 : 0;
- } else {
- if (v < ui->min) {
- if (failoor)
- return -1;
- v = ui->min;
- } else if (v > ui->max) {
- if (failoor)
- return -1;
- v = ui->max;
- }
- *ui->zone = v;
- }
- }
-
- return 0;
-}
-
-static UI *
-newui(File *f, const char *label, int type)
-{
- Aux *a;
-
- a = calloc(1, sizeof(*a) + sizeof(UI) + sizeof(Meta)*decl.nummeta);
- a->type = Xui;
- a->ui = (UI*)(a+1);
- a->ui->type = type;
- a->ui->meta = (Meta*)(a->ui+1);
- a->ui->nummeta = decl.nummeta;
- memmove(a->ui->meta, decl.meta, sizeof(Meta)*decl.nummeta);
- a->ctl = Xuictl;
- a->metadata = Xuimeta;
- a->ui->zone = decl.zone;
- a->ui->label = label;
- a->ui->readstr = uiglue.readstr != nil ? uiglue.readstr : ui_readstr;
- a->ui->writestr = uiglue.writestr != nil ? uiglue.writestr : ui_writestr;
- a->ui->userdata = uiglue.userdata;
- if ((uiglue.f = createfile(f, label, nil, DMDIR|0775, a)) == nil)
- sysfatal("failed to create ui: %r");
- if ((f = createfile(uiglue.f, "ctl", nil, 0664, &a->ctl)) == nil)
- sysfatal("failed to create ui ctl: %r");
- closefile(f);
- if ((f = createfile(uiglue.f, "metadata", nil, 0664, &a->metadata)) == nil)
- sysfatal("failed to create ui metadata: %r");
- closefile(f);
- closefile(uiglue.f);
-
- free(decl.meta);
- decl.zone = nil;
- decl.meta = nil;
- decl.nummeta = 0;
-
- return a->ui;
-}
-
-static void
-ui_tgroup(void *f, const char *label)
-{
- newui(f, label, UITGroup);
-}
-
-static void
-ui_hgroup(void *f, const char *label)
-{
- newui(f, label, UIHGroup);
-}
-
-static void
-ui_vgroup(void *f, const char *label)
-{
- newui(f, label, UIVGroup);
-}
-
-static void
-ui_close_group(void *file)
-{
- File *f;
-
- f = file;
- uiglue.f = f->parent;
-}
-
-static UI *
-ui_define(File *f, int type, const char *label, float *zone)
-{
- UI *ui;
-
- if (zone != decl.zone) { /* no "declare" called before */
- decl.zone = zone;
- free(decl.meta);
- decl.meta = nil;
- decl.nummeta = 0;
- }
- ui = newui(f, label, type);
- uiglue.f = f;
-
- return ui;
-}
-
-static void
-ui_button(void *f, const char *label, float *zone)
-{
- UI *ui;
-
- ui = ui_define(f, UIButton, label, zone);
- *zone = 0;
- ui->writestr(ui, Xuictl, "reset");
-}
-
-static void
-ui_checkbox(void *f, const char *label, float *zone)
-{
- UI *ui;
-
- ui = ui_define(f, UICheckBox, label, zone);
- *zone = 0;
- ui->writestr(ui, Xuictl, "reset");
-}
-
-static void
-ui_vslider(void *f, const char *label, float *zone, float init, float min, float max, float step)
-{
- UI *ui;
-
- ui = ui_define(f, UIVSlider, label, zone);
- ui->init = *zone = init;
- ui->min = min;
- ui->max = max;
- ui->step = step;
- ui->writestr(ui, Xuictl, "reset");
-}
-
-static void
-ui_hslider(void *f, const char *label, float *zone, float init, float min, float max, float step)
-{
- UI *ui;
-
- ui = ui_define(f, UIHSlider, label, zone);
- ui->init = *zone = init;
- ui->min = min;
- ui->max = max;
- ui->step = step;
- ui->writestr(ui, Xuictl, "reset");
-}
-
-static void
-ui_nentry(void *f, const char *label, float *zone, float init, float min, float max, float step)
-{
- UI *ui;
-
- ui = ui_define(f, UINEntry, label, zone);
- ui->init = *zone = init;
- ui->min = min;
- ui->max = max;
- ui->step = step;
- ui->writestr(ui, Xuictl, "reset");
-}
-
-static void
-ui_hbargraph(void *f, const char *label, float *zone, float min, float max)
-{
- UI *ui;
-
- ui = ui_define(f, UIHBarGraph, label, zone);
- ui->min = min;
- ui->max = max;
- *zone = 0;
- ui->writestr(ui, Xuictl, "reset");
-}
-
-static void
-ui_vbargraph(void *f, const char *label, float *zone, float min, float max)
-{
- UI *ui;
-
- ui = ui_define(f, UIVBarGraph, label, zone);
- ui->min = min;
- ui->max = max;
- *zone = 0;
- ui->writestr(ui, Xuictl, "reset");
-}
-
-static void
-ui_declare(void *f, float *zone, const char *key, const char *value)
-{
- USED(f);
-
- if (decl.zone != nil && decl.zone != zone)
- sysfatal("%s=\"%s\": zone mismatch during declaration (%p != %p)", key, value, decl.zone, zone);
- decl.zone = zone;
- decl.meta = realloc(decl.meta, sizeof(Meta)*(decl.nummeta+1));
- decl.meta[decl.nummeta].k = key;
- decl.meta[decl.nummeta].v = value;
- decl.nummeta++;
-}
-
UIGlue uiglue = {
- .openTabBox = ui_tgroup,
- .openHorizontalBox = ui_hgroup,
- .openVerticalBox = ui_vgroup,
- .closeBox = ui_close_group,
- .addButton = ui_button,
- .addCheckButton = ui_checkbox,
- .addVerticalSlider = ui_vslider,
- .addHorizontalSlider = ui_hslider,
- .addNumEntry = ui_nentry,
- .addHorizontalBargraph = ui_hbargraph,
- .addVerticalBargraph = ui_vbargraph,
- .declare = ui_declare,
+ .openTabBox = openTabBox,
+ .openHorizontalBox = openHorizontalBox,
+ .openVerticalBox = openVerticalBox,
+ .closeBox = closeBox,
+ .addButton = addButton,
+ .addCheckButton = addCheckButton,
+ .addVerticalSlider = addVerticalSlider,
+ .addHorizontalSlider = addHorizontalSlider,
+ .addNumEntry = addNumEntry,
+ .addVerticalBargraph = addVerticalBargraph,
+ .addHorizontalBargraph = addHorizontalBargraph,
+ .declare = declare,
};
--- a/uiglue.h
+++ b/uiglue.h
@@ -1,37 +1,13 @@
-typedef struct UIGlue UIGlue;
typedef struct MetaGlue MetaGlue;
+typedef struct UIGlue UIGlue;
-struct File;
-
-typedef struct Meta Meta;
-typedef struct UI UI;
-
-struct Meta {
- const char *k;
- const char *v;
+struct MetaGlue {
+ void *metaInterface;
+ void (*declare)(void *metaInterface, const char *key, const char *value);
};
-struct UI {
- int type;
- const char *label;
- float *zone;
- float init;
- float min;
- float max;
- float step;
- char *(*readstr)(UI *ui, int auxtype, char *s, int sz);
- int (*writestr)(UI *ui, int auxtype, char *s);
-
- void *userdata;
- Meta *meta;
- int nummeta;
-};
-
struct UIGlue {
- union {
- void *uiInterface;
- struct File *f;
- };
+ void *uiInterface;
void (*openTabBox)(void *uiInterface, const char *label);
void (*openHorizontalBox)(void *uiInterface, const char *label);
void (*openVerticalBox)(void *uiInterface, const char *label);
@@ -44,19 +20,6 @@
void (*addHorizontalBargraph)(void *uiInterface, const char *label, float *zone, float min, float max);
void (*addVerticalBargraph)(void *uiInterface, const char *label, float *zone, float min, float max);
void (*declare)(void *uiInterface, float *zone, const char *key, const char *value);
-
- char *(*readstr)(UI *ui, int auxtype, char *s, int sz);
- int (*writestr)(UI *ui, int auxtype, char *s);
-
- void *userdata;
};
-struct MetaGlue {
- void *metaInterface;
- void (*declare)(void *metaInterface, const char *key, const char *value);
-};
-
extern UIGlue uiglue;
-
-char *ui_readstr(UI *ui, int auxtype, char *s, int sz);
-int ui_writestr(UI *ui, int auxtype, char *s);