ref: c951f1864a755bb827da3031c03d9578b648b7a6
parent: dfa2da9cf2e227226350201c9c1d07c2194c2632
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
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);
--
⑨