shithub: neindaw

Download patch

ref: c787e8e5371c91b41172dc985d8e29fd9565f88f
parent: 10d66333fb0f3f6f333bb1bb4802a77d061628a7
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Fri Jan 17 08:56:19 EST 2020

move stuff around

--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
 At this moment the effort is mostly on getting tooling powered by
 [Faust](https://faust.grame.fr) to beep beep boop. Here, watch this:
 
-![code](kick.png) → ![result](cfg.png)
+![code](kick.jpg) → ![result](cfg.png)
 
 Wow.
 
@@ -16,7 +16,7 @@
 ```
 cd /tmp && \
 hget https://github.com/ftrvxmtrx/neindaw/archive/master.tar.gz | tar xz && \
-cd faust9p-master && mk install
+cd neindaw-master && mk install
 
 ls /bin/daw
 ```
@@ -73,6 +73,9 @@
 
 ## TODO and random notes
 
+ * buffer computated data and make 
+ * use llvm-generated object or asm instead of C? that would be having to
+   add Plan 9 target to llc I guess, or some kind of conversion tool for asm
  * renaming/removal of instance IDs and controls via Twstat and Tremove
  * GUI needs to support various styles like knobs, drop down menus,
    radio buttons etc
@@ -93,6 +96,7 @@
    together, should be controllable through daw/cfg. microui will need
    a lot of work
  * polyphonyfs to manage master/voices automatically for any DSP
+ * mixerfs with channels
  * full MIDI support
  * OSC support
  * port Orca to Plan 9 and use it for testing neindaw
--- a/arch.c
+++ /dev/null
@@ -1,35 +1,0 @@
-/* mydsp Plan 9 C architecture for Faust. */
-
-#include <u.h>
-#include <libc.h>
-#include "uiglue.h"
-
-#define max(x,y) (((x) > (y)) ? (x) : (y))
-#define min(x,y) (((x) < (y)) ? (x) : (y))
-
-<<includeIntrinsic>>
-<<includeclass>>
-
-#define DSP mydsp
-
-#include "dspf.h"
-
-static DSPf dspf = {
-	.new = newmydsp,
-	.init = instanceInitmydsp,
-	.delete = deletemydsp,
-	.metadata = metadatamydsp,
-	.num_in = getNumInputsmydsp,
-	.num_out = getNumOutputsmydsp,
-	.clear = instanceClearmydsp,
-	.reset_ui = instanceResetUserInterfacemydsp,
-	.build_ui = buildUserInterfacemydsp,
-	.compute = computemydsp,
-};
-
-void *
-class_init(int rate)
-{
-	classInitmydsp(rate);
-	return &dspf;
-}
--- a/aux.h
+++ /dev/null
@@ -1,56 +1,0 @@
-typedef enum {
-	Xclone,
-	Xctl,
-	Xmetadata,
-
-	Xdsp,
-	Xdspctl,
-	Xdspdata,
-
-	Xui,
-	Xuictl,
-	Xuimeta,
-}Auxtype;
-
-typedef struct Aux Aux;
-typedef struct Auxdsp Auxdsp;
-typedef struct Meta Meta;
-typedef struct UI UI;
-
-struct Auxdsp {
-	void *dsp;
-	FAUSTFLOAT **in, **out;
-	int numin, numout;
-	int inmax, outmax;
-};
-
-struct Aux {
-	Auxtype type;
-	int id;
-	int ctl;
-	int data;
-	int metadata;
-
-	Auxdsp *dsp;
-	UI *ui;
-};
-
-struct Meta {
-	const char *k;
-	const char *v;
-};
-
-struct UI {
-	UItype type;
-	const char *label;
-	FAUSTFLOAT *zone;
-	FAUSTFLOAT init;
-	FAUSTFLOAT min;
-	FAUSTFLOAT max;
-	FAUSTFLOAT step;
-	char *(*readstr)(UI *ui, int type, char *s, int sz);
-	int (*write)(UI *ui, int type, char *s);
-
-	Meta *meta;
-	int nummeta;
-};
--- /dev/null
+++ b/dsp/arch.c
@@ -1,0 +1,35 @@
+/* mydsp Plan 9 C architecture for Faust. */
+
+#include <u.h>
+#include <libc.h>
+#include "uiglue.h"
+
+#define max(x,y) (((x) > (y)) ? (x) : (y))
+#define min(x,y) (((x) < (y)) ? (x) : (y))
+
+<<includeIntrinsic>>
+<<includeclass>>
+
+#define DSP mydsp
+
+#include "dspf.h"
+
+static DSPf dspf = {
+	.new = newmydsp,
+	.init = instanceInitmydsp,
+	.delete = deletemydsp,
+	.metadata = metadatamydsp,
+	.num_in = getNumInputsmydsp,
+	.num_out = getNumOutputsmydsp,
+	.clear = instanceClearmydsp,
+	.reset_ui = instanceResetUserInterfacemydsp,
+	.build_ui = buildUserInterfacemydsp,
+	.compute = computemydsp,
+};
+
+void *
+class_init(int rate)
+{
+	classInitmydsp(rate);
+	return &dspf;
+}
--- /dev/null
+++ b/dsp/aux.h
@@ -1,0 +1,56 @@
+typedef enum {
+	Xclone,
+	Xctl,
+	Xmetadata,
+
+	Xdsp,
+	Xdspctl,
+	Xdspdata,
+
+	Xui,
+	Xuictl,
+	Xuimeta,
+}Auxtype;
+
+typedef struct Aux Aux;
+typedef struct Auxdsp Auxdsp;
+typedef struct Meta Meta;
+typedef struct UI UI;
+
+struct Auxdsp {
+	void *dsp;
+	FAUSTFLOAT **in, **out;
+	int numin, numout;
+	int inmax, outmax;
+};
+
+struct Aux {
+	Auxtype type;
+	int id;
+	int ctl;
+	int data;
+	int metadata;
+
+	Auxdsp *dsp;
+	UI *ui;
+};
+
+struct Meta {
+	const char *k;
+	const char *v;
+};
+
+struct UI {
+	UItype type;
+	const char *label;
+	FAUSTFLOAT *zone;
+	FAUSTFLOAT init;
+	FAUSTFLOAT min;
+	FAUSTFLOAT max;
+	FAUSTFLOAT step;
+	char *(*readstr)(UI *ui, int type, char *s, int sz);
+	int (*write)(UI *ui, int type, char *s);
+
+	Meta *meta;
+	int nummeta;
+};
--- /dev/null
+++ b/dsp/dspf.h
@@ -1,0 +1,14 @@
+typedef struct {
+	DSP *(*new)(void);
+	void (*init)(DSP *dsp, int sample_rate);
+	void (*delete)(DSP *dsp);
+	void (*metadata)(MetaGlue *glue);
+	int (*num_in)(DSP *dsp);
+	int (*num_out)(DSP *dsp);
+	void (*clear)(DSP *dsp);
+	void (*reset_ui)(DSP *dsp);
+	void (*build_ui)(DSP *dsp, UIGlue *glue);
+	void (*compute)(DSP *dsp, int count, FAUSTFLOAT **in, FAUSTFLOAT **out);
+}DSPf;
+
+void *class_init(int rate);
--- /dev/null
+++ b/dsp/fs.c
@@ -1,0 +1,321 @@
+#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);
+}
--- /dev/null
+++ b/dsp/kick_drum.c
@@ -1,0 +1,363 @@
+/* ------------------------------------------------------------
+name: "Kick Drum"
+Code generated with Faust 2.21.5 (https://faust.grame.fr)
+Compilation options: -lang c -scal -ftz 0
+------------------------------------------------------------ */
+
+#ifndef  __KickDrum_H__
+#define  __KickDrum_H__
+
+/* KickDrum Plan 9 C architecture for Faust. */
+
+#include <u.h>
+#include <libc.h>
+#include "uiglue.h"
+
+#define max(x,y) (((x) > (y)) ? (x) : (y))
+#define min(x,y) (((x) < (y)) ? (x) : (y))
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif 
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <math.h>
+#include <stdlib.h>
+
+typedef struct {
+	int iRec0[2];
+} KickDrumSIG0;
+
+static KickDrumSIG0* newKickDrumSIG0(void) { return (KickDrumSIG0*)calloc(1, sizeof(KickDrumSIG0)); }
+static void deleteKickDrumSIG0(KickDrumSIG0* dsp) {
+	USED(dsp); free(dsp); }
+
+int getNumInputsKickDrumSIG0(KickDrumSIG0* dsp) {
+	USED(dsp);
+	return 0;
+}
+int getNumOutputsKickDrumSIG0(KickDrumSIG0* dsp) {
+	USED(dsp);
+	return 1;
+}
+int getInputRateKickDrumSIG0(KickDrumSIG0* dsp, int channel) {
+	USED(dsp);
+	int rate;
+	switch ((channel)) {
+		default: {
+			rate = -1;
+			break;
+		}
+	}
+	return rate;
+}
+int getOutputRateKickDrumSIG0(KickDrumSIG0* dsp, int channel) {
+	USED(dsp);
+	int rate;
+	switch ((channel)) {
+		case 0: {
+			rate = 0;
+			break;
+		}
+		default: {
+			rate = -1;
+			break;
+		}
+	}
+	return rate;
+}
+
+static void instanceInitKickDrumSIG0(KickDrumSIG0* dsp, int sample_rate) {
+	USED(sample_rate);
+	USED(dsp);
+	/* C99 loop */
+	{
+		int l0;
+		for (l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
+			dsp->iRec0[l0] = 0;
+		}
+	}
+}
+
+static void fillKickDrumSIG0(KickDrumSIG0* dsp, int count, float* table) {
+	USED(dsp);
+	/* C99 loop */
+	{
+		int i;
+		for (i = 0; (i < count); i = (i + 1)) {
+			dsp->iRec0[0] = (dsp->iRec0[1] + 1);
+			table[i] = sinf((9.58738019e-05f * (float)(dsp->iRec0[0] + -1)));
+			dsp->iRec0[1] = dsp->iRec0[0];
+		}
+	}
+}
+
+static float ftbl0KickDrumSIG0[65536];
+
+#ifndef FAUSTCLASS 
+#define FAUSTCLASS KickDrum
+#endif
+#ifdef __APPLE__ 
+#define exp10f __exp10f
+#define exp10 __exp10
+#endif
+
+typedef struct {
+	FAUSTFLOAT fHslider0;
+	FAUSTFLOAT fButton0;
+	float fVec0[2];
+	int fSampleRate;
+	float fConst0;
+	float fConst1;
+	FAUSTFLOAT fHslider1;
+	FAUSTFLOAT fHslider2;
+	FAUSTFLOAT fCheckbox0;
+	FAUSTFLOAT fHslider3;
+	int iRec2[2];
+	FAUSTFLOAT fHslider4;
+	float fRec1[2];
+	FAUSTFLOAT fHslider5;
+	FAUSTFLOAT fHslider6;
+} KickDrum;
+
+KickDrum* newKickDrum(void) { 
+	KickDrum* dsp = (KickDrum*)calloc(1, sizeof(KickDrum));
+	return dsp;
+}
+
+void deleteKickDrum(KickDrum* dsp) {
+	USED(dsp); 
+	free(dsp);
+}
+
+void metadataKickDrum(MetaGlue* m) { 
+	m->declare(m->metaInterface, "basics.lib/name", "Faust Basic Element Library");
+	m->declare(m->metaInterface, "basics.lib/version", "0.1");
+	m->declare(m->metaInterface, "envelopes.lib/ar:author", "Yann Orlarey, Stéphane Letz");
+	m->declare(m->metaInterface, "envelopes.lib/author", "GRAME");
+	m->declare(m->metaInterface, "envelopes.lib/copyright", "GRAME");
+	m->declare(m->metaInterface, "envelopes.lib/license", "LGPL with exception");
+	m->declare(m->metaInterface, "envelopes.lib/name", "Faust Envelope Library");
+	m->declare(m->metaInterface, "envelopes.lib/version", "0.0");
+	m->declare(m->metaInterface, "filename", "kick_drum.dsp");
+	m->declare(m->metaInterface, "group", "Synthesis");
+	m->declare(m->metaInterface, "maths.lib/author", "GRAME");
+	m->declare(m->metaInterface, "maths.lib/copyright", "GRAME");
+	m->declare(m->metaInterface, "maths.lib/license", "LGPL with exception");
+	m->declare(m->metaInterface, "maths.lib/name", "Faust Math Library");
+	m->declare(m->metaInterface, "maths.lib/version", "2.1");
+	m->declare(m->metaInterface, "name", "Kick Drum");
+	m->declare(m->metaInterface, "oscillators.lib/name", "Faust Oscillator Library");
+	m->declare(m->metaInterface, "oscillators.lib/version", "0.0");
+}
+
+int getSampleRateKickDrum(KickDrum* dsp) {
+	USED(dsp);
+	return dsp->fSampleRate;
+}
+
+int getNumInputsKickDrum(KickDrum* dsp) {
+	USED(dsp);
+	return 0;
+}
+int getNumOutputsKickDrum(KickDrum* dsp) {
+	USED(dsp);
+	return 1;
+}
+int getInputRateKickDrum(KickDrum* dsp, int channel) {
+	USED(dsp);
+	int rate;
+	switch ((channel)) {
+		default: {
+			rate = -1;
+			break;
+		}
+	}
+	return rate;
+}
+int getOutputRateKickDrum(KickDrum* dsp, int channel) {
+	USED(dsp);
+	int rate;
+	switch ((channel)) {
+		case 0: {
+			rate = 1;
+			break;
+		}
+		default: {
+			rate = -1;
+			break;
+		}
+	}
+	return rate;
+}
+
+void classInitKickDrum(int sample_rate) {
+	USED(sample_rate);
+	KickDrumSIG0* sig0 = newKickDrumSIG0();
+	instanceInitKickDrumSIG0(sig0, sample_rate);
+	fillKickDrumSIG0(sig0, 65536, ftbl0KickDrumSIG0);
+	deleteKickDrumSIG0(sig0);
+}
+
+void instanceResetUserInterfaceKickDrum(KickDrum* dsp) {
+	USED(dsp);
+	dsp->fHslider0 = (FAUSTFLOAT)1.0f;
+	dsp->fButton0 = (FAUSTFLOAT)0.0f;
+	dsp->fHslider1 = (FAUSTFLOAT)100.0f;
+	dsp->fHslider2 = (FAUSTFLOAT)-5.0f;
+	dsp->fCheckbox0 = (FAUSTFLOAT)0.0f;
+	dsp->fHslider3 = (FAUSTFLOAT)0.001f;
+	dsp->fHslider4 = (FAUSTFLOAT)0.001f;
+	dsp->fHslider5 = (FAUSTFLOAT)0.001f;
+	dsp->fHslider6 = (FAUSTFLOAT)0.001f;
+}
+
+void instanceClearKickDrum(KickDrum* dsp) {
+	USED(dsp);
+	/* C99 loop */
+	{
+		int l1;
+		for (l1 = 0; (l1 < 2); l1 = (l1 + 1)) {
+			dsp->fVec0[l1] = 0.0f;
+		}
+	}
+	/* C99 loop */
+	{
+		int l2;
+		for (l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
+			dsp->iRec2[l2] = 0;
+		}
+	}
+	/* C99 loop */
+	{
+		int l3;
+		for (l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
+			dsp->fRec1[l3] = 0.0f;
+		}
+	}
+}
+
+void instanceConstantsKickDrum(KickDrum* dsp, int sample_rate) {
+	USED(sample_rate);
+	USED(dsp);
+	dsp->fSampleRate = sample_rate;
+	dsp->fConst0 = min(192000.0f, max(1.0f, (float)dsp->fSampleRate));
+	dsp->fConst1 = (1.0f / dsp->fConst0);
+}
+
+void instanceInitKickDrum(KickDrum* dsp, int sample_rate) {
+	USED(sample_rate);
+	USED(dsp);
+	instanceConstantsKickDrum(dsp, sample_rate);
+	instanceResetUserInterfaceKickDrum(dsp);
+	instanceClearKickDrum(dsp);
+}
+
+void initKickDrum(KickDrum* dsp, int sample_rate) {
+	USED(sample_rate);
+	USED(dsp);
+	classInitKickDrum(sample_rate);
+	instanceInitKickDrum(dsp, sample_rate);
+}
+
+void buildUserInterfaceKickDrum(KickDrum* dsp, UIGlue* ui_interface) {
+	USED(dsp);
+	ui_interface->openVerticalBox(ui_interface->uiInterface, "Kick Drum");
+	ui_interface->openVerticalBox(ui_interface->uiInterface, "A");
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider1, "0", "");
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider1, "unit", "Hz");
+	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Frequency", &dsp->fHslider1, 100.0f, 5.0f, 200.0f, 1.0f);
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider5, "1", "");
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider5, "unit", "s");
+	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Attack", &dsp->fHslider5, 0.00100000005f, 9.99999975e-06f, 0.200000003f, 0.00100000005f);
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider6, "3", "");
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider6, "unit", "s");
+	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Release", &dsp->fHslider6, 0.00100000005f, 9.99999975e-06f, 1.0f, 0.00100000005f);
+	ui_interface->closeBox(ui_interface->uiInterface);
+	ui_interface->openVerticalBox(ui_interface->uiInterface, "B");
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider2, "0", "");
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider2, "unit", "Hz");
+	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Frequency", &dsp->fHslider2, -5.0f, -5.0f, 200.0f, 5.0f);
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider3, "1", "");
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider3, "unit", "s");
+	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Attack", &dsp->fHslider3, 0.00100000005f, 9.99999975e-06f, 0.200000003f, 0.00100000005f);
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider4, "2", "");
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider4, "unit", "s");
+	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Release", &dsp->fHslider4, 0.00100000005f, 9.99999975e-06f, 1.0f, 0.00100000005f);
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fCheckbox0, "3", "");
+	ui_interface->addCheckButton(ui_interface->uiInterface, "Enable", &dsp->fCheckbox0);
+	ui_interface->closeBox(ui_interface->uiInterface);
+	ui_interface->openVerticalBox(ui_interface->uiInterface, "Control");
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider0, "0", "");
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider0, "style", "knob");
+	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Gain", &dsp->fHslider0, 1.0f, 0.0f, 1.0f, 0.00999999978f);
+	ui_interface->declare(ui_interface->uiInterface, &dsp->fButton0, "1", "");
+	ui_interface->addButton(ui_interface->uiInterface, "Gate", &dsp->fButton0);
+	ui_interface->closeBox(ui_interface->uiInterface);
+	ui_interface->closeBox(ui_interface->uiInterface);
+}
+
+void computeKickDrum(KickDrum* dsp, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+	USED(inputs);
+	USED(dsp);
+	FAUSTFLOAT* output0 = outputs[0];
+	float fSlow0 = (float)dsp->fHslider0;
+	float fSlow1 = (float)dsp->fButton0;
+	float fSlow2 = (float)dsp->fHslider1;
+	float fSlow3 = ((float)dsp->fHslider2 * (float)dsp->fCheckbox0);
+	float fSlow4 = max(1.0f, (dsp->fConst0 * (float)dsp->fHslider3));
+	float fSlow5 = (1.0f / fSlow4);
+	float fSlow6 = (1.0f / max(1.0f, (dsp->fConst0 * (float)dsp->fHslider4)));
+	float fSlow7 = max(1.0f, (dsp->fConst0 * (float)dsp->fHslider5));
+	float fSlow8 = (1.0f / fSlow7);
+	float fSlow9 = (1.0f / max(1.0f, (dsp->fConst0 * (float)dsp->fHslider6)));
+	/* C99 loop */
+	{
+		int i;
+		for (i = 0; (i < count); i = (i + 1)) {
+			dsp->fVec0[0] = fSlow1;
+			int iTemp0 = (fSlow1 > dsp->fVec0[1]);
+			dsp->iRec2[0] = (iTemp0 + ((fSlow1 <= dsp->fVec0[1]) * (dsp->iRec2[1] + (dsp->iRec2[1] > 0))));
+			float fTemp1 = (float)dsp->iRec2[0];
+			float fTemp2 = ((dsp->fRec1[1] * (1.0f - (float)(iTemp0 > 0))) + (dsp->fConst1 * (fSlow2 + (fSlow3 * max(0.0f, min((fSlow5 * fTemp1), (1.0f - (fSlow6 * (fTemp1 - fSlow4)))))))));
+			dsp->fRec1[0] = (fTemp2 - floorf(fTemp2));
+			output0[i] = (FAUSTFLOAT)(fSlow0 * (ftbl0KickDrumSIG0[(int)(65536.0f * dsp->fRec1[0])] * max(0.0f, min((fSlow8 * fTemp1), ((fSlow9 * (fSlow7 - fTemp1)) + 1.0f)))));
+			dsp->fVec0[1] = dsp->fVec0[0];
+			dsp->iRec2[1] = dsp->iRec2[0];
+			dsp->fRec1[1] = dsp->fRec1[0];
+		}
+	}
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#define DSP KickDrum
+
+#include "dspf.h"
+
+static DSPf dspf = {
+	.new = newKickDrum,
+	.init = instanceInitKickDrum,
+	.delete = deleteKickDrum,
+	.metadata = metadataKickDrum,
+	.num_in = getNumInputsKickDrum,
+	.num_out = getNumOutputsKickDrum,
+	.clear = instanceClearKickDrum,
+	.reset_ui = instanceResetUserInterfaceKickDrum,
+	.build_ui = buildUserInterfaceKickDrum,
+	.compute = computeKickDrum,
+};
+
+void *
+class_init(int rate)
+{
+	classInitKickDrum(rate);
+	return &dspf;
+}
+
+#endif
--- /dev/null
+++ b/dsp/kick_drum.dsp
@@ -1,0 +1,16 @@
+// Simple kick drum
+declare name "Kick Drum";
+declare group "Synthesis";
+import("stdfaust.lib");
+
+aFreq = hslider("v:A/[0]Frequency[unit:Hz]", 100, 5, 200, 1);
+aA = hslider("v:A/[1]Attack[unit:s]", 0.001, 0.00001, 0.2, 0.001);
+aR = hslider("v:A/[3]Release[unit:s]", 0.001, 0.00001, 1.0, 0.001);
+bA = hslider("v:B/[1]Attack[unit:s]", 0.001, 0.00001, 0.2, 0.001);
+bR = hslider("v:B/[2]Release[unit:s]", 0.001, 0.00001, 1, 0.001);
+bFreq = checkbox("v:B/[3]Enable") * hslider("v:B/[0]Frequency[unit:Hz]", -5, -5, 200, 5);
+
+gain = hslider("v:Control/[0]Gain[style:knob]", 1, 0, 1, 0.01);
+gate = button("v:Control/[1]Gate");
+
+process = os.hs_oscsin(aFreq + bFreq*en.ar(bA, bR, gate), gate : ba.impulsify) * gain * en.ar(aA, aR, gate);
--- /dev/null
+++ b/dsp/math.h
@@ -1,0 +1,8 @@
+#define cosf cos
+#define expf exp
+#define fabsf fabs
+#define floorf floor
+#define powf pow
+#define sinf sin
+#define sqrtf sqrt
+#define tanf tan
--- /dev/null
+++ b/dsp/mkfile
@@ -1,0 +1,24 @@
+</$objtype/mkfile
+
+TARG=\
+	kick_drum
+
+OFILES=\
+	common.$O\
+	fs.$O\
+	uiglue.$O\
+
+CFLAGS=$CFLAGS -I..
+
+default:V:	all
+
+CLEANFILES=\
+
+</sys/src/cmd/mkmany
+
+$BIN/%:	$O.%
+	mkdir -p $BIN
+	cp $O.$stem $BIN/$stem
+
+common.$O: ../common.c
+	$CC $CFLAGS $prereq
--- /dev/null
+++ b/dsp/uiglue.c
@@ -1,0 +1,281 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include "uiglue.h"
+#include "common.h"
+#include "aux.h"
+
+static struct {
+	FAUSTFLOAT *zone;
+	Meta *meta;
+	int nummeta;
+}decl;
+
+static char *
+ui_readstr(UI *ui, int type, char *s, int sz)
+{
+	char *x, *t;
+	int i;
+
+	if (type == 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 (type == 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("unknown ui file type %d", type);
+	}
+
+	return nil;
+}
+
+static int
+ui_write(UI *ui, int type, char *s)
+{
+	char *e;
+	int failoor;
+	float v;
+
+	if (type != Xuictl)
+		sysfatal("unknown ui file");
+
+	/* 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 = ui_readstr;
+	a->ui->write = ui_write;
+	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, FAUSTFLOAT *zone)
+{
+	UI *ui;
+
+	if (zone != decl.zone)
+		sysfatal("zone mismatch during definition");
+	ui = newui(f, label, type);
+	uiglue.f = f;
+
+	return ui;
+}
+
+static void
+ui_button(void *f, const char *label, FAUSTFLOAT *zone)
+{
+	ui_define(f, UIButton, label, zone);
+}
+
+static void
+ui_checkbox(void *f, const char *label, FAUSTFLOAT *zone)
+{
+	ui_define(f, UICheckBox, label, zone);
+}
+
+static void
+ui_vslider(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+	UI *ui;
+
+	ui = ui_define(f, UIVSlider, label, zone);
+	ui->init = init;
+	ui->min = min;
+	ui->max = max;
+	ui->step = step;
+}
+
+static void
+ui_hslider(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+	UI *ui;
+
+	ui = ui_define(f, UIHSlider, label, zone);
+	ui->init = init;
+	ui->min = min;
+	ui->max = max;
+	ui->step = step;
+}
+
+static void
+ui_nentry(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+	UI *ui;
+
+	ui = ui_define(f, UINEntry, label, zone);
+	ui->init = init;
+	ui->min = min;
+	ui->max = max;
+	ui->step = step;
+}
+
+static void
+ui_hbargraph(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT min, FAUSTFLOAT max)
+{
+	UI *ui;
+
+	ui = ui_define(f, UIHBarGraph, label, zone);
+	ui->min = min;
+	ui->max = max;
+}
+
+static void
+ui_vbargraph(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT min, FAUSTFLOAT max)
+{
+	UI *ui;
+
+	ui = ui_define(f, UIVBarGraph, label, zone);
+	ui->min = min;
+	ui->max = max;
+}
+
+static void
+ui_declare(void *f, FAUSTFLOAT *zone, const char *key, const char *value)
+{
+	USED(f);
+
+	if (decl.zone != nil && decl.zone != zone)
+		sysfatal("zone mismatch during declaration");
+	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,
+};
--- /dev/null
+++ b/dsp/uiglue.h
@@ -1,0 +1,34 @@
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+typedef struct UIGlue UIGlue;
+typedef struct MetaGlue MetaGlue;
+
+struct File;
+
+struct UIGlue {
+	union {
+		void *uiInterface;
+		struct File *f;
+	};
+	void (*openTabBox)(void *uiInterface, const char *label);
+	void (*openHorizontalBox)(void *uiInterface, const char *label);
+	void (*openVerticalBox)(void *uiInterface, const char *label);
+	void (*closeBox)(void *uiInterface);
+	void (*addButton)(void *uiInterface, const char *label, FAUSTFLOAT *zone);
+	void (*addCheckButton)(void *uiInterface, const char *label, FAUSTFLOAT *zone);
+	void (*addVerticalSlider)(void *uiInterface, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step);
+	void (*addHorizontalSlider)(void *uiInterface, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step);
+	void (*addNumEntry)(void *uiInterface, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step);
+	void (*addHorizontalBargraph)(void *uiInterface, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT min, FAUSTFLOAT max);
+	void (*addVerticalBargraph)(void *uiInterface, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT min, FAUSTFLOAT max);
+	void (*declare)(void *uiInterface, FAUSTFLOAT *zone, const char *key, const char *value);
+};
+
+struct MetaGlue {
+	void *metaInterface;
+	void (*declare)(void *metaInterface, const char *key, const char *value);
+};
+
+extern UIGlue uiglue;
--- a/dspf.h
+++ /dev/null
@@ -1,14 +1,0 @@
-typedef struct {
-	DSP *(*new)(void);
-	void (*init)(DSP *dsp, int sample_rate);
-	void (*delete)(DSP *dsp);
-	void (*metadata)(MetaGlue *glue);
-	int (*num_in)(DSP *dsp);
-	int (*num_out)(DSP *dsp);
-	void (*clear)(DSP *dsp);
-	void (*reset_ui)(DSP *dsp);
-	void (*build_ui)(DSP *dsp, UIGlue *glue);
-	void (*compute)(DSP *dsp, int count, FAUSTFLOAT **in, FAUSTFLOAT **out);
-}DSPf;
-
-void *class_init(int rate);
--- a/fs.c
+++ /dev/null
@@ -1,321 +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 */
-};
-
-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);
-}
binary files /dev/null b/kick.jpg differ
binary files a/kick.png /dev/null differ
--- a/kick_drum.c
+++ /dev/null
@@ -1,363 +1,0 @@
-/* ------------------------------------------------------------
-name: "Kick Drum"
-Code generated with Faust 2.21.5 (https://faust.grame.fr)
-Compilation options: -lang c -scal -ftz 0
------------------------------------------------------------- */
-
-#ifndef  __KickDrum_H__
-#define  __KickDrum_H__
-
-/* KickDrum Plan 9 C architecture for Faust. */
-
-#include <u.h>
-#include <libc.h>
-#include "uiglue.h"
-
-#define max(x,y) (((x) > (y)) ? (x) : (y))
-#define min(x,y) (((x) < (y)) ? (x) : (y))
-
-#ifndef FAUSTFLOAT
-#define FAUSTFLOAT float
-#endif 
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <math.h>
-#include <stdlib.h>
-
-typedef struct {
-	int iRec0[2];
-} KickDrumSIG0;
-
-static KickDrumSIG0* newKickDrumSIG0(void) { return (KickDrumSIG0*)calloc(1, sizeof(KickDrumSIG0)); }
-static void deleteKickDrumSIG0(KickDrumSIG0* dsp) {
-	USED(dsp); free(dsp); }
-
-int getNumInputsKickDrumSIG0(KickDrumSIG0* dsp) {
-	USED(dsp);
-	return 0;
-}
-int getNumOutputsKickDrumSIG0(KickDrumSIG0* dsp) {
-	USED(dsp);
-	return 1;
-}
-int getInputRateKickDrumSIG0(KickDrumSIG0* dsp, int channel) {
-	USED(dsp);
-	int rate;
-	switch ((channel)) {
-		default: {
-			rate = -1;
-			break;
-		}
-	}
-	return rate;
-}
-int getOutputRateKickDrumSIG0(KickDrumSIG0* dsp, int channel) {
-	USED(dsp);
-	int rate;
-	switch ((channel)) {
-		case 0: {
-			rate = 0;
-			break;
-		}
-		default: {
-			rate = -1;
-			break;
-		}
-	}
-	return rate;
-}
-
-static void instanceInitKickDrumSIG0(KickDrumSIG0* dsp, int sample_rate) {
-	USED(sample_rate);
-	USED(dsp);
-	/* C99 loop */
-	{
-		int l0;
-		for (l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
-			dsp->iRec0[l0] = 0;
-		}
-	}
-}
-
-static void fillKickDrumSIG0(KickDrumSIG0* dsp, int count, float* table) {
-	USED(dsp);
-	/* C99 loop */
-	{
-		int i;
-		for (i = 0; (i < count); i = (i + 1)) {
-			dsp->iRec0[0] = (dsp->iRec0[1] + 1);
-			table[i] = sinf((9.58738019e-05f * (float)(dsp->iRec0[0] + -1)));
-			dsp->iRec0[1] = dsp->iRec0[0];
-		}
-	}
-}
-
-static float ftbl0KickDrumSIG0[65536];
-
-#ifndef FAUSTCLASS 
-#define FAUSTCLASS KickDrum
-#endif
-#ifdef __APPLE__ 
-#define exp10f __exp10f
-#define exp10 __exp10
-#endif
-
-typedef struct {
-	FAUSTFLOAT fHslider0;
-	FAUSTFLOAT fButton0;
-	float fVec0[2];
-	int fSampleRate;
-	float fConst0;
-	float fConst1;
-	FAUSTFLOAT fHslider1;
-	FAUSTFLOAT fHslider2;
-	FAUSTFLOAT fCheckbox0;
-	FAUSTFLOAT fHslider3;
-	int iRec2[2];
-	FAUSTFLOAT fHslider4;
-	float fRec1[2];
-	FAUSTFLOAT fHslider5;
-	FAUSTFLOAT fHslider6;
-} KickDrum;
-
-KickDrum* newKickDrum(void) { 
-	KickDrum* dsp = (KickDrum*)calloc(1, sizeof(KickDrum));
-	return dsp;
-}
-
-void deleteKickDrum(KickDrum* dsp) {
-	USED(dsp); 
-	free(dsp);
-}
-
-void metadataKickDrum(MetaGlue* m) { 
-	m->declare(m->metaInterface, "basics.lib/name", "Faust Basic Element Library");
-	m->declare(m->metaInterface, "basics.lib/version", "0.1");
-	m->declare(m->metaInterface, "envelopes.lib/ar:author", "Yann Orlarey, Stéphane Letz");
-	m->declare(m->metaInterface, "envelopes.lib/author", "GRAME");
-	m->declare(m->metaInterface, "envelopes.lib/copyright", "GRAME");
-	m->declare(m->metaInterface, "envelopes.lib/license", "LGPL with exception");
-	m->declare(m->metaInterface, "envelopes.lib/name", "Faust Envelope Library");
-	m->declare(m->metaInterface, "envelopes.lib/version", "0.0");
-	m->declare(m->metaInterface, "filename", "kick_drum.dsp");
-	m->declare(m->metaInterface, "group", "Synthesis");
-	m->declare(m->metaInterface, "maths.lib/author", "GRAME");
-	m->declare(m->metaInterface, "maths.lib/copyright", "GRAME");
-	m->declare(m->metaInterface, "maths.lib/license", "LGPL with exception");
-	m->declare(m->metaInterface, "maths.lib/name", "Faust Math Library");
-	m->declare(m->metaInterface, "maths.lib/version", "2.1");
-	m->declare(m->metaInterface, "name", "Kick Drum");
-	m->declare(m->metaInterface, "oscillators.lib/name", "Faust Oscillator Library");
-	m->declare(m->metaInterface, "oscillators.lib/version", "0.0");
-}
-
-int getSampleRateKickDrum(KickDrum* dsp) {
-	USED(dsp);
-	return dsp->fSampleRate;
-}
-
-int getNumInputsKickDrum(KickDrum* dsp) {
-	USED(dsp);
-	return 0;
-}
-int getNumOutputsKickDrum(KickDrum* dsp) {
-	USED(dsp);
-	return 1;
-}
-int getInputRateKickDrum(KickDrum* dsp, int channel) {
-	USED(dsp);
-	int rate;
-	switch ((channel)) {
-		default: {
-			rate = -1;
-			break;
-		}
-	}
-	return rate;
-}
-int getOutputRateKickDrum(KickDrum* dsp, int channel) {
-	USED(dsp);
-	int rate;
-	switch ((channel)) {
-		case 0: {
-			rate = 1;
-			break;
-		}
-		default: {
-			rate = -1;
-			break;
-		}
-	}
-	return rate;
-}
-
-void classInitKickDrum(int sample_rate) {
-	USED(sample_rate);
-	KickDrumSIG0* sig0 = newKickDrumSIG0();
-	instanceInitKickDrumSIG0(sig0, sample_rate);
-	fillKickDrumSIG0(sig0, 65536, ftbl0KickDrumSIG0);
-	deleteKickDrumSIG0(sig0);
-}
-
-void instanceResetUserInterfaceKickDrum(KickDrum* dsp) {
-	USED(dsp);
-	dsp->fHslider0 = (FAUSTFLOAT)1.0f;
-	dsp->fButton0 = (FAUSTFLOAT)0.0f;
-	dsp->fHslider1 = (FAUSTFLOAT)100.0f;
-	dsp->fHslider2 = (FAUSTFLOAT)-5.0f;
-	dsp->fCheckbox0 = (FAUSTFLOAT)0.0f;
-	dsp->fHslider3 = (FAUSTFLOAT)0.001f;
-	dsp->fHslider4 = (FAUSTFLOAT)0.001f;
-	dsp->fHslider5 = (FAUSTFLOAT)0.001f;
-	dsp->fHslider6 = (FAUSTFLOAT)0.001f;
-}
-
-void instanceClearKickDrum(KickDrum* dsp) {
-	USED(dsp);
-	/* C99 loop */
-	{
-		int l1;
-		for (l1 = 0; (l1 < 2); l1 = (l1 + 1)) {
-			dsp->fVec0[l1] = 0.0f;
-		}
-	}
-	/* C99 loop */
-	{
-		int l2;
-		for (l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
-			dsp->iRec2[l2] = 0;
-		}
-	}
-	/* C99 loop */
-	{
-		int l3;
-		for (l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
-			dsp->fRec1[l3] = 0.0f;
-		}
-	}
-}
-
-void instanceConstantsKickDrum(KickDrum* dsp, int sample_rate) {
-	USED(sample_rate);
-	USED(dsp);
-	dsp->fSampleRate = sample_rate;
-	dsp->fConst0 = min(192000.0f, max(1.0f, (float)dsp->fSampleRate));
-	dsp->fConst1 = (1.0f / dsp->fConst0);
-}
-
-void instanceInitKickDrum(KickDrum* dsp, int sample_rate) {
-	USED(sample_rate);
-	USED(dsp);
-	instanceConstantsKickDrum(dsp, sample_rate);
-	instanceResetUserInterfaceKickDrum(dsp);
-	instanceClearKickDrum(dsp);
-}
-
-void initKickDrum(KickDrum* dsp, int sample_rate) {
-	USED(sample_rate);
-	USED(dsp);
-	classInitKickDrum(sample_rate);
-	instanceInitKickDrum(dsp, sample_rate);
-}
-
-void buildUserInterfaceKickDrum(KickDrum* dsp, UIGlue* ui_interface) {
-	USED(dsp);
-	ui_interface->openVerticalBox(ui_interface->uiInterface, "Kick Drum");
-	ui_interface->openVerticalBox(ui_interface->uiInterface, "A");
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider1, "0", "");
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider1, "unit", "Hz");
-	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Frequency", &dsp->fHslider1, 100.0f, 5.0f, 200.0f, 1.0f);
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider5, "1", "");
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider5, "unit", "s");
-	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Attack", &dsp->fHslider5, 0.00100000005f, 9.99999975e-06f, 0.200000003f, 0.00100000005f);
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider6, "3", "");
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider6, "unit", "s");
-	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Release", &dsp->fHslider6, 0.00100000005f, 9.99999975e-06f, 1.0f, 0.00100000005f);
-	ui_interface->closeBox(ui_interface->uiInterface);
-	ui_interface->openVerticalBox(ui_interface->uiInterface, "B");
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider2, "0", "");
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider2, "unit", "Hz");
-	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Frequency", &dsp->fHslider2, -5.0f, -5.0f, 200.0f, 5.0f);
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider3, "1", "");
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider3, "unit", "s");
-	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Attack", &dsp->fHslider3, 0.00100000005f, 9.99999975e-06f, 0.200000003f, 0.00100000005f);
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider4, "2", "");
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider4, "unit", "s");
-	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Release", &dsp->fHslider4, 0.00100000005f, 9.99999975e-06f, 1.0f, 0.00100000005f);
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fCheckbox0, "3", "");
-	ui_interface->addCheckButton(ui_interface->uiInterface, "Enable", &dsp->fCheckbox0);
-	ui_interface->closeBox(ui_interface->uiInterface);
-	ui_interface->openVerticalBox(ui_interface->uiInterface, "Control");
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider0, "0", "");
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider0, "style", "knob");
-	ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Gain", &dsp->fHslider0, 1.0f, 0.0f, 1.0f, 0.00999999978f);
-	ui_interface->declare(ui_interface->uiInterface, &dsp->fButton0, "1", "");
-	ui_interface->addButton(ui_interface->uiInterface, "Gate", &dsp->fButton0);
-	ui_interface->closeBox(ui_interface->uiInterface);
-	ui_interface->closeBox(ui_interface->uiInterface);
-}
-
-void computeKickDrum(KickDrum* dsp, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
-	USED(inputs);
-	USED(dsp);
-	FAUSTFLOAT* output0 = outputs[0];
-	float fSlow0 = (float)dsp->fHslider0;
-	float fSlow1 = (float)dsp->fButton0;
-	float fSlow2 = (float)dsp->fHslider1;
-	float fSlow3 = ((float)dsp->fHslider2 * (float)dsp->fCheckbox0);
-	float fSlow4 = max(1.0f, (dsp->fConst0 * (float)dsp->fHslider3));
-	float fSlow5 = (1.0f / fSlow4);
-	float fSlow6 = (1.0f / max(1.0f, (dsp->fConst0 * (float)dsp->fHslider4)));
-	float fSlow7 = max(1.0f, (dsp->fConst0 * (float)dsp->fHslider5));
-	float fSlow8 = (1.0f / fSlow7);
-	float fSlow9 = (1.0f / max(1.0f, (dsp->fConst0 * (float)dsp->fHslider6)));
-	/* C99 loop */
-	{
-		int i;
-		for (i = 0; (i < count); i = (i + 1)) {
-			dsp->fVec0[0] = fSlow1;
-			int iTemp0 = (fSlow1 > dsp->fVec0[1]);
-			dsp->iRec2[0] = (iTemp0 + ((fSlow1 <= dsp->fVec0[1]) * (dsp->iRec2[1] + (dsp->iRec2[1] > 0))));
-			float fTemp1 = (float)dsp->iRec2[0];
-			float fTemp2 = ((dsp->fRec1[1] * (1.0f - (float)(iTemp0 > 0))) + (dsp->fConst1 * (fSlow2 + (fSlow3 * max(0.0f, min((fSlow5 * fTemp1), (1.0f - (fSlow6 * (fTemp1 - fSlow4)))))))));
-			dsp->fRec1[0] = (fTemp2 - floorf(fTemp2));
-			output0[i] = (FAUSTFLOAT)(fSlow0 * (ftbl0KickDrumSIG0[(int)(65536.0f * dsp->fRec1[0])] * max(0.0f, min((fSlow8 * fTemp1), ((fSlow9 * (fSlow7 - fTemp1)) + 1.0f)))));
-			dsp->fVec0[1] = dsp->fVec0[0];
-			dsp->iRec2[1] = dsp->iRec2[0];
-			dsp->fRec1[1] = dsp->fRec1[0];
-		}
-	}
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#define DSP KickDrum
-
-#include "dspf.h"
-
-static DSPf dspf = {
-	.new = newKickDrum,
-	.init = instanceInitKickDrum,
-	.delete = deleteKickDrum,
-	.metadata = metadataKickDrum,
-	.num_in = getNumInputsKickDrum,
-	.num_out = getNumOutputsKickDrum,
-	.clear = instanceClearKickDrum,
-	.reset_ui = instanceResetUserInterfaceKickDrum,
-	.build_ui = buildUserInterfaceKickDrum,
-	.compute = computeKickDrum,
-};
-
-void *
-class_init(int rate)
-{
-	classInitKickDrum(rate);
-	return &dspf;
-}
-
-#endif
--- a/kick_drum.dsp
+++ /dev/null
@@ -1,16 +1,0 @@
-// Simple kick drum
-declare name "Kick Drum";
-declare group "Synthesis";
-import("stdfaust.lib");
-
-aFreq = hslider("v:A/[0]Frequency[unit:Hz]", 100, 5, 200, 1);
-aA = hslider("v:A/[1]Attack[unit:s]", 0.001, 0.00001, 0.2, 0.001);
-aR = hslider("v:A/[3]Release[unit:s]", 0.001, 0.00001, 1.0, 0.001);
-bA = hslider("v:B/[1]Attack[unit:s]", 0.001, 0.00001, 0.2, 0.001);
-bR = hslider("v:B/[2]Release[unit:s]", 0.001, 0.00001, 1, 0.001);
-bFreq = checkbox("v:B/[3]Enable") * hslider("v:B/[0]Frequency[unit:Hz]", -5, -5, 200, 5);
-
-gain = hslider("v:Control/[0]Gain[style:knob]", 1, 0, 1, 0.01);
-gate = button("v:Control/[1]Gate");
-
-process = os.hs_oscsin(aFreq + bFreq*en.ar(bA, bR, gate), gate : ba.impulsify) * gain * en.ar(aA, aR, gate);
--- a/math.h
+++ /dev/null
@@ -1,8 +1,0 @@
-#define cosf cos
-#define expf exp
-#define fabsf fabs
-#define floorf floor
-#define powf pow
-#define sinf sin
-#define sqrtf sqrt
-#define tanf tan
--- a/mkfile
+++ b/mkfile
@@ -1,20 +1,27 @@
 </$objtype/mkfile
 
-TARG=\
-	kick_drum\
+LIBS=\
+	microui\
 
+CMDS=\
+	dsp\
+	cfg\
+
 BIN=/$objtype/bin/daw
-OFILES=\
-	common.$O\
-	fs.$O\
-	uiglue.$O\
 
-default:V:	all
+none:VQ:
+	echo mk all, install, clean, nuke, or libs
 
-CLEANFILES=\
+all install clean nuke:VQ:
+	for (i in $LIBS $CMDS) @{
+		cd $i
+		mk $target
+	}
 
-</sys/src/cmd/mkmany
-
-$BIN/%:	$O.%
-	mkdir -p $BIN
-	cp $O.$stem $BIN/$stem
+libs:V:
+	for (i in $LIBS) @{
+		cd $i
+		mk clean
+		mk install
+		mk clean
+	}
--- /dev/null
+++ b/nix/faust2.nix
@@ -1,0 +1,218 @@
+{ stdenv
+, coreutils
+, cmake
+, fetchgit
+, makeWrapper
+, pkgconfig
+, llvm_9
+, openssl
+, libsndfile
+}:
+
+with stdenv.lib.strings;
+
+let
+  version = "latest";
+
+  src = fetchgit {
+    url = "https://github.com/grame-cncm/faust";
+    rev = "f16a1e4fbfacec2a00f16fa225733b8e4c758ff9";
+    sha256 = "0pj1wazlqw6jhqfj9pf6bbxvs57li8ngh0348n5p4m2gy0mg5xc2";
+    fetchSubmodules = true;
+  };
+
+  meta = with stdenv.lib; {
+    homepage = http://faust.grame.fr/;
+    downloadPage = https://sourceforge.net/projects/faudiostream/files/;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+
+  faust = stdenv.mkDerivation {
+
+    pname = "faust";
+    inherit version;
+
+    inherit src;
+
+    nativeBuildInputs = [ makeWrapper pkgconfig cmake ];
+    buildInputs = [ llvm_9 openssl libsndfile ];
+    dontUseCmakeConfigure = true;
+
+    passthru = {
+      inherit wrap wrapWithBuildEnv;
+    };
+
+    preConfigure = ''
+      makeFlags="$makeFlags DESTDIR=/ PREFIX=$out LLVM_CONFIG='${llvm_9}/bin/llvm-config' world"
+
+      # The faust makefiles use 'system ?= $(shell uname -s)' but nix
+      # defines 'system' env var, so undefine that so faust detects the
+      # correct system.
+      unset system
+    '';
+
+    # Remove most faust2appl scripts since they won't run properly
+    # without additional paths setup. See faust.wrap,
+    # faust.wrapWithBuildEnv.
+    postInstall = ''
+      # syntax error when eval'd directly
+      pattern="faust2!(*@(api|atomsnippets|graph|graphviewer|md|plot|sig|sigviewer|svg))"
+      (shopt -s extglob; rm "$out"/bin/$pattern)
+    '';
+
+    postFixup = ''
+      # Set faustpath explicitly.
+      substituteInPlace "$out"/bin/faustpath \
+        --replace "/usr/local /usr /opt /opt/local" "$out"
+
+      # The 'faustoptflags' is 'source'd into other faust scripts and
+      # not used as an executable, so patch 'uname' usage directly
+      # rather than use makeWrapper.
+      substituteInPlace "$out"/bin/faustoptflags \
+        --replace uname "${coreutils}/bin/uname"
+
+      # wrapper for scripts that don't need faust.wrap*
+      for script in "$out"/bin/faust2*; do
+        wrapProgram "$script" \
+          --prefix PATH : "$out"/bin
+      done
+    '';
+
+    meta = meta // {
+      description = "A functional programming language for realtime audio signal processing";
+      longDescription = ''
+        FAUST (Functional Audio Stream) is a functional programming
+        language specifically designed for real-time signal processing
+        and synthesis. FAUST targets high-performance signal processing
+        applications and audio plug-ins for a variety of platforms and
+        standards.
+        The Faust compiler translates DSP specifications into very
+        efficient C++ code. Thanks to the notion of architecture,
+        FAUST programs can be easily deployed on a large variety of
+        audio platforms and plugin formats (jack, alsa, ladspa, maxmsp,
+        puredata, csound, supercollider, pure, vst, coreaudio) without
+        any change to the FAUST code.
+
+        This package has just the compiler, libraries, and headers.
+        Install faust2* for specific faust2appl scripts.
+      '';
+    };
+
+  };
+
+  # Default values for faust2appl.
+  faust2ApplBase =
+    { baseName
+    , dir ? "tools/faust2appls"
+    , scripts ? [ baseName ]
+    , ...
+    }@args:
+
+    args // {
+      name = "${baseName}-${version}";
+
+      inherit src;
+
+      dontBuild = true;
+
+      installPhase = ''
+        runHook preInstall
+
+        mkdir -p "$out/bin"
+        for script in ${concatStringsSep " " scripts}; do
+          cp "${dir}/$script" "$out/bin/"
+        done
+
+        runHook postInstall
+      '';
+
+      postInstall = ''
+        # For the faust2appl script, change 'faustpath' and
+        # 'faustoptflags' to absolute paths.
+        for script in "$out"/bin/*; do
+          substituteInPlace "$script" \
+            --replace ". faustpath" ". '${faust}/bin/faustpath'" \
+            --replace ". faustoptflags" ". '${faust}/bin/faustoptflags'" \
+            --replace " error " "echo"
+        done
+      '';
+
+      meta = meta // {
+        description = "The ${baseName} script, part of faust functional programming language for realtime audio signal processing";
+      };
+    };
+
+  # Some 'faust2appl' scripts, such as faust2alsa, run faust to
+  # generate cpp code, then invoke the c++ compiler to build the code.
+  # This builder wraps these scripts in parts of the stdenv such that
+  # when the scripts are called outside any nix build, they behave as
+  # if they were running inside a nix build in terms of compilers and
+  # paths being configured (e.g. rpath is set so that compiled
+  # binaries link to the libs inside the nix store)
+  #
+  # The function takes two main args: the appl name (e.g.
+  # 'faust2alsa') and an optional list of propagatedBuildInputs. It
+  # returns a derivation that contains only the bin/${appl} script,
+  # wrapped up so that it will run as if it was inside a nix build
+  # with those build inputs.
+  #
+  # The build input 'faust' is automatically added to the
+  # propagatedBuildInputs.
+  wrapWithBuildEnv =
+    { baseName
+    , propagatedBuildInputs ? [ ]
+    , ...
+    }@args:
+
+    stdenv.mkDerivation ((faust2ApplBase args) // {
+
+      nativeBuildInputs = [ pkgconfig ];
+      buildInputs = [ makeWrapper ];
+
+      propagatedBuildInputs = [ faust ] ++ propagatedBuildInputs;
+
+
+      postFixup = ''
+
+        # export parts of the build environment
+        for script in "$out"/bin/*; do
+          wrapProgram "$script" \
+            --set FAUSTLIB "${faust}/share/faust" \
+            --set FAUST_LIB_PATH "${faust}/share/faust" \
+            --set FAUSTINC "${faust}/include/faust" \
+            --prefix PATH : "$PATH" \
+            --prefix PKG_CONFIG_PATH : "$PKG_CONFIG_PATH" \
+            --set NIX_CFLAGS_COMPILE "$NIX_CFLAGS_COMPILE" \
+            --set NIX_LDFLAGS "$NIX_LDFLAGS"
+        done
+      '';
+    });
+
+  # Builder for 'faust2appl' scripts, such as faust2firefox that
+  # simply need to be wrapped with some dependencies on PATH.
+  #
+  # The build input 'faust' is automatically added to the PATH.
+  wrap =
+    { baseName
+    , runtimeInputs ? [ ]
+    , ...
+    }@args:
+
+    let
+
+      runtimePath = concatStringsSep ":" (map (p: "${p}/bin") ([ faust ] ++ runtimeInputs));
+
+    in stdenv.mkDerivation ((faust2ApplBase args) // {
+
+      buildInputs = [ makeWrapper ];
+
+      postFixup = ''
+        for script in "$out"/bin/*; do
+          wrapProgram "$script" --prefix PATH : "${runtimePath}"
+        done
+      '';
+
+    });
+
+in faust
--- /dev/null
+++ b/nix/shell.nix
@@ -1,0 +1,9 @@
+{ pkgs ? import <nixpkgs> {} }:
+
+with pkgs; mkShell {
+  buildInputs = [
+    (callPackage ./faust2.nix {})
+    graphviz
+    gcc
+  ];
+}
--- /dev/null
+++ b/pull_subtree.sh
@@ -1,0 +1,2 @@
+#!/bin/sh
+git subtree pull --prefix microui git@github.com:ftrvxmtrx/microui.git master --squash
--- a/uiglue.c
+++ /dev/null
@@ -1,281 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <fcall.h>
-#include <thread.h>
-#include <9p.h>
-#include "uiglue.h"
-#include "common.h"
-#include "aux.h"
-
-static struct {
-	FAUSTFLOAT *zone;
-	Meta *meta;
-	int nummeta;
-}decl;
-
-static char *
-ui_readstr(UI *ui, int type, char *s, int sz)
-{
-	char *x, *t;
-	int i;
-
-	if (type == 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 (type == 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("unknown ui file type %d", type);
-	}
-
-	return nil;
-}
-
-static int
-ui_write(UI *ui, int type, char *s)
-{
-	char *e;
-	int failoor;
-	float v;
-
-	if (type != Xuictl)
-		sysfatal("unknown ui file");
-
-	/* 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 = ui_readstr;
-	a->ui->write = ui_write;
-	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, FAUSTFLOAT *zone)
-{
-	UI *ui;
-
-	if (zone != decl.zone)
-		sysfatal("zone mismatch during definition");
-	ui = newui(f, label, type);
-	uiglue.f = f;
-
-	return ui;
-}
-
-static void
-ui_button(void *f, const char *label, FAUSTFLOAT *zone)
-{
-	ui_define(f, UIButton, label, zone);
-}
-
-static void
-ui_checkbox(void *f, const char *label, FAUSTFLOAT *zone)
-{
-	ui_define(f, UICheckBox, label, zone);
-}
-
-static void
-ui_vslider(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-{
-	UI *ui;
-
-	ui = ui_define(f, UIVSlider, label, zone);
-	ui->init = init;
-	ui->min = min;
-	ui->max = max;
-	ui->step = step;
-}
-
-static void
-ui_hslider(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-{
-	UI *ui;
-
-	ui = ui_define(f, UIHSlider, label, zone);
-	ui->init = init;
-	ui->min = min;
-	ui->max = max;
-	ui->step = step;
-}
-
-static void
-ui_nentry(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-{
-	UI *ui;
-
-	ui = ui_define(f, UINEntry, label, zone);
-	ui->init = init;
-	ui->min = min;
-	ui->max = max;
-	ui->step = step;
-}
-
-static void
-ui_hbargraph(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT min, FAUSTFLOAT max)
-{
-	UI *ui;
-
-	ui = ui_define(f, UIHBarGraph, label, zone);
-	ui->min = min;
-	ui->max = max;
-}
-
-static void
-ui_vbargraph(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT min, FAUSTFLOAT max)
-{
-	UI *ui;
-
-	ui = ui_define(f, UIVBarGraph, label, zone);
-	ui->min = min;
-	ui->max = max;
-}
-
-static void
-ui_declare(void *f, FAUSTFLOAT *zone, const char *key, const char *value)
-{
-	USED(f);
-
-	if (decl.zone != nil && decl.zone != zone)
-		sysfatal("zone mismatch during declaration");
-	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,
-};
--- a/uiglue.h
+++ /dev/null
@@ -1,34 +1,0 @@
-#ifndef FAUSTFLOAT
-#define FAUSTFLOAT float
-#endif
-
-typedef struct UIGlue UIGlue;
-typedef struct MetaGlue MetaGlue;
-
-struct File;
-
-struct UIGlue {
-	union {
-		void *uiInterface;
-		struct File *f;
-	};
-	void (*openTabBox)(void *uiInterface, const char *label);
-	void (*openHorizontalBox)(void *uiInterface, const char *label);
-	void (*openVerticalBox)(void *uiInterface, const char *label);
-	void (*closeBox)(void *uiInterface);
-	void (*addButton)(void *uiInterface, const char *label, FAUSTFLOAT *zone);
-	void (*addCheckButton)(void *uiInterface, const char *label, FAUSTFLOAT *zone);
-	void (*addVerticalSlider)(void *uiInterface, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step);
-	void (*addHorizontalSlider)(void *uiInterface, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step);
-	void (*addNumEntry)(void *uiInterface, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step);
-	void (*addHorizontalBargraph)(void *uiInterface, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT min, FAUSTFLOAT max);
-	void (*addVerticalBargraph)(void *uiInterface, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT min, FAUSTFLOAT max);
-	void (*declare)(void *uiInterface, FAUSTFLOAT *zone, const char *key, const char *value);
-};
-
-struct MetaGlue {
-	void *metaInterface;
-	void (*declare)(void *metaInterface, const char *key, const char *value);
-};
-
-extern UIGlue uiglue;