ref: 7c285b049475f2139c234f1ce7a760e564fbee49
parent: 0acd2208855ac7e5c1e2499614c50828a1ace0de
author: Sigrid Haflínudóttir <[email protected]>
date: Sun Dec 29 22:57:08 EST 2019
somewhat first working version
--- a/README.md
+++ b/README.md
@@ -3,7 +3,38 @@
Tools to compile [FAUST](https://faust.grame.fr) DSP code to a 9p
server, provide UI to control DSP, etc.
-WIP, nothing to look at yet
+## Testing
+
+So far only one instrument provided, which is a kick drum.
+
+```
+% ./6.out -m /n/kick
+% cd /n/kick
+
+# allocate one instance
+% cd `{cat clone}
+
+# check the A oscillator frequency
+# the order is: type key value initial min max step
+# it's different for different UI elements
+% cat K*/a/frequency/ctl
+vslider 0 100.000000 100.000000 10.000000 200.000000 5.000000
+
+# raise frequency to 160Hz
+% echo 160 > K*/a/f*/ctl
+
+# toggle the gate, we need to compute once in between for it to actually be processed
+# then listen to the sound
+% echo 0 > 'Kick Drum/control/gate/ctl' && \
+ dd -if data -of /dev/null -count 1 -quiet 1 && \
+ echo 1 > 'Kick Drum/control/gate/ctl' && \
+ audio/pcmconv -i f32c2r44100 -l 128000 < data > /dev/audio
+
+# increase the delay of A oscillator
+% echo 0.2 > 'Kick Drum/a/delay/ctl' # make it
+
+# now you can repeat the listen command to hear the difference
+```
## Description
--- a/arch.c
+++ b/arch.c
@@ -1,7 +1,4 @@
-/*
-Plan 9 C architecture for Faust. This provides a file system with UI
-elements exported as files and directories.
-*/
+/* mydsp Plan 9 C architecture for Faust. */
#include <u.h>
#include <libc.h>
@@ -30,29 +27,9 @@
.compute = computemydsp,
};
-static void
-usage(char *prog)
+void *
+class_init(int rate)
{
- print("usage: %s [-s SAMPLE_RATE]\n", prog);
- exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
- int sample_rate;
-
- sample_rate = 44100;
- ARGBEGIN{
- case 's':
- sample_rate = atoi(ARGF());
- break;
- default:
- usage(argv[0]);
- }ARGEND
-
- classInitmydsp(sample_rate);
- build_fs(&dspf);
-
- exits(nil);
+ classInitmydsp(rate);
+ return &dspf;
}
--- /dev/null
+++ b/aux.h
@@ -1,0 +1,52 @@
+enum {
+ Xctl,
+ Xmetadata,
+ Xclone,
+ Xdsp,
+ Xdspctl,
+ Xdspdata,
+ UITBox,
+ UIHBox,
+ UIVBox,
+ UIButton,
+ UICheck,
+ UIVSlider,
+ UIHSlider,
+ UINum,
+ UIHBarGraph,
+ UIVBarGraph,
+ Xuictl,
+};
+
+typedef struct Aux Aux;
+typedef struct Auxdsp Auxdsp;
+typedef struct UI UI;
+
+struct Auxdsp {
+ void *dsp;
+ FAUSTFLOAT **in, **out;
+ int numin, numout;
+ int inmax, outmax;
+};
+
+struct Aux {
+ int type;
+ int id;
+ Auxdsp dsp;
+ int ctl;
+ int data;
+ UI *ui;
+};
+
+struct UI {
+ const char *key;
+ const char *value;
+ const char *label;
+ FAUSTFLOAT *zone;
+ FAUSTFLOAT init;
+ FAUSTFLOAT min;
+ FAUSTFLOAT max;
+ FAUSTFLOAT step;
+ char *(*readstr)(Aux *a, UI *ui, int type, char *s, int sz);
+ int (*write)(Aux *a, UI *ui, int type, char *s);
+};
--- a/dspf.h
+++ b/dspf.h
@@ -11,4 +11,4 @@
void (*compute)(DSP *dsp, int count, FAUSTFLOAT **in, FAUSTFLOAT **out);
}DSPf;
-void build_fs(void *dspf);
+void *class_init(int rate);
--- a/fs.c
+++ b/fs.c
@@ -1,18 +1,109 @@
#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 "aux.h"
-typedef struct {
- void *metaInterface;
- void (*declare)(void *metaInterface, const char *key, const char *value);
-}MetaGlue;
+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);
+ default:
+ sysfatal("trying to get aux out of type %d", *type);
+ }
+
+ return nil;
+}
+
+static Aux *
+newobj(char *name)
+{
+ File *f;
+ Aux *o;
+ int i;
+
+ 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;
+ o->dsp.dsp = dspf->new();
+ sprint(name, "%d", o->id);
+
+ o->dsp.in = o->dsp.out = nil;
+ if ((o->dsp.numin = dspf->num_in(o->dsp.dsp)) > 0) {
+ o->dsp.in = malloc(sizeof(*o->dsp.in) * o->dsp.numin);
+ o->dsp.inmax = Inmax;
+ for (i = 0; i < o->dsp.numin; i++)
+ o->dsp.in[i] = malloc(sizeof(**o->dsp.in) * o->dsp.inmax);
+ }
+ if ((o->dsp.numout = dspf->num_out(o->dsp.dsp)) > 0) {
+ o->dsp.out = malloc(sizeof(*o->dsp.out) * o->dsp.numout);
+ o->dsp.outmax = Outmax;
+ for (i = 0; i < o->dsp.numout; i++)
+ o->dsp.out[i] = malloc(sizeof(**o->dsp.out) * o->dsp.outmax);
+ }
+
+ f = createfile(fs.tree->root, name, nil, DMDIR|0775, o);
+ createfile(f, "ctl", nil, 0664, &o->ctl);
+ createfile(f, "data", nil, 0664, &o->data);
+ dspf->init(o->dsp.dsp, rate);
+ uiglue.uiInterface = f;
+ dspf->build_ui(o->dsp.dsp, &uiglue);
+
+ return o;
+}
+
static void
+freeobj(Aux *o)
+{
+ if (o == nil)
+ return;
+
+ objs[o->id] = nil;
+ dspf->delete(o->dsp.dsp);
+ free(o->dsp.in);
+ free(o->dsp.out);
+ free(o);
+}
+
+static void
addmeta(void *metaInterface, const char *k, const char *v)
{
int klen, vlen;
@@ -35,12 +126,148 @@
}
void
-build_fs(void *dspf)
+fsopen(Req *r)
{
- DSPf *f;
+ respond(r, nil);
+}
+
+void
+fsread(Req *r)
+{
+ Aux *a, *o;
+ 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 {
+ respond(r, "no free objects");
+ break;
+ }
+ }
+ respond(r, nil);
+ break;
+ case Xuictl:
+ o = auxtype2obj(&a->type);
+ if (o->ui->readstr != nil)
+ readstr(r, o->ui->readstr(o, o->ui, Xuictl, b, sizeof(b)));
+ respond(r, nil);
+ break;
+ case Xdspdata:
+ o = auxtype2obj(&a->type);
+ framesz = o->dsp.numout * sizeof(*p);
+ n = r->ifcall.count;
+ for (p = (FAUSTFLOAT*)r->ofcall.data; n >= framesz;) {
+ numframes = n / framesz;
+ if (numframes > o->dsp.outmax)
+ numframes = o->dsp.outmax;
+ dspf->compute(o->dsp.dsp, numframes, o->dsp.in, o->dsp.out);
+ for (i = 0; i < numframes; i++) {
+ for (j = 0; j < o->dsp.numout; j++)
+ *p++ = o->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';
+
+ a = r->fid->file->aux;
+ switch (a->type) {
+ case Xuictl:
+ o = auxtype2obj(&a->type);
+ st = o->ui->write != nil ? o->ui->write(o, o->ui, Xuictl, b) : -1;
+ respond(r, st == 0 ? nil : "write failed");
+ break;
+ case Xctl: /* FIXME reset, changing sampling rate, etc */
+ case Xmetadata: /* FIXME should be possible to add new key/value */
+ default:
+ respond(r, "not implemented");
+ break;
+ }
+}
+
+Srv fs = {
+ .open = fsopen,
+ .read = fsread,
+ .write = fswrite,
+};
+
+static void
+usage(char *prog)
+{
+ print("usage: %s [-s srv] [-m mtpt] [-r rate]\n", prog);
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ char *srv, *mtpt;
MetaGlue mg;
- f = dspf;
+ srv = nil;
+ mtpt = nil;
+ ARGBEGIN{
+ case 'D':
+ chatty9p++;
+ break;
+ case 's':
+ srv = EARGF(usage(argv[0]));
+ break;
+ case 'm':
+ mtpt = EARGF(usage(argv[0]));
+ break;
+ case 'r':
+ rate = atoi(EARGF(usage(argv[0])));
+ break;
+ default:
+ usage(argv[0]);
+ }ARGEND
+
+ if (srv == nil && mtpt == nil)
+ sysfatal("must specify -s or -m option");
+
mg.declare = addmeta;
- f->metadata(&mg);
+ dspf = class_init(rate);
+ dspf->metadata(&mg);
+
+ fs.tree = alloctree(nil, nil, DMDIR|0775, nil);
+ 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);
}
--- a/gen.sh
+++ b/gen.sh
@@ -2,6 +2,11 @@
set -e
for i in *.dsp; do
- class=$(grep -o declare.*name.* kick_drum.dsp | head -1 | sed 's/^[^"]*//g;s/[^A-Za-z0-9]//g')
- faust -lang c -a arch.c -cn $class $@ $i -o /dev/stdout | sed 's/new\([^(]*\)() /new\1(void) /' > $i.c
+ class=$(grep -o declare.*name.* $i | head -1 | sed 's/^[^"]*//g;s/[^A-Za-z0-9]//g')
+ # in C () is not the same as (void) so fix it
+ # mark "dsp", "samplingFreq", and "inputs" args as USED
+ faust -lang c -a arch.c -cn $class $@ $i -o /dev/stdout \
+ | sed 's/new\([^(]*\)() /new\1(void) /' \
+ | sed 's/'$class'[A-Z0]*\* dsp.*{/&\n\tUSED(dsp);/g' \
+ | sed 's/ \(samplingFreq\|inputs\).*{/&\n\tUSED(\1);/g' > $i.c
done
--- /dev/null
+++ b/kick_drum.dsp.c
@@ -1,0 +1,461 @@
+/* ------------------------------------------------------------
+name: "Kick Drum"
+Code generated with Faust 2.5.23 (https://faust.grame.fr)
+Compilation options: 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*)malloc(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 samplingFreq) {
+ USED(samplingFreq);
+ 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* output) {
+ USED(dsp);
+ /* C99 loop */
+ {
+ int i;
+ for (i = 0; (i < count); i = (i + 1)) {
+ dsp->iRec0[0] = (dsp->iRec0[1] + 1);
+ output[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 {
+
+ int fSamplingFreq;
+ float fConst0;
+ float fConst1;
+ FAUSTFLOAT fVslider0;
+ FAUSTFLOAT fVslider1;
+ FAUSTFLOAT fCheckbox0;
+ FAUSTFLOAT fButton0;
+ float fVec0[2];
+ FAUSTFLOAT fVslider2;
+ FAUSTFLOAT fVslider3;
+ float fVec1[2];
+ float fRec2[2];
+ float fConst2;
+ float fRec1[2];
+ FAUSTFLOAT fVslider4;
+ float fRec3[2];
+ FAUSTFLOAT fVslider5;
+ FAUSTFLOAT fVslider6;
+ float fRec5[2];
+ float fRec4[2];
+
+} KickDrum;
+
+KickDrum* newKickDrum(void) {
+ KickDrum* dsp = (KickDrum*)malloc(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.0");
+ 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");
+ 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->fSamplingFreq; }
+
+int getNumInputsKickDrum(KickDrum* dsp) {
+ USED(dsp);
+ return 0;
+
+}
+int getNumOutputsKickDrum(KickDrum* dsp) {
+ USED(dsp);
+ return 2;
+
+}
+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;
+ }
+ case 1: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+
+ }
+ return rate;
+
+}
+
+void classInitKickDrum(int samplingFreq) {
+ USED(samplingFreq);
+ KickDrumSIG0* sig0 = newKickDrumSIG0();
+ instanceInitKickDrumSIG0(sig0, samplingFreq);
+ fillKickDrumSIG0(sig0, 65536, ftbl0KickDrumSIG0);
+ deleteKickDrumSIG0(sig0);
+
+}
+
+void instanceResetUserInterfaceKickDrum(KickDrum* dsp) {
+ USED(dsp);
+ dsp->fVslider0 = (FAUSTFLOAT)100.0f;
+ dsp->fVslider1 = (FAUSTFLOAT)200.0f;
+ dsp->fCheckbox0 = (FAUSTFLOAT)0.0f;
+ dsp->fButton0 = (FAUSTFLOAT)0.0f;
+ dsp->fVslider2 = (FAUSTFLOAT)0.001f;
+ dsp->fVslider3 = (FAUSTFLOAT)0.001f;
+ dsp->fVslider4 = (FAUSTFLOAT)0.001f;
+ dsp->fVslider5 = (FAUSTFLOAT)0.001f;
+ dsp->fVslider6 = (FAUSTFLOAT)0.01f;
+
+}
+
+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->fVec1[l2] = 0.0f;
+
+ }
+
+ }
+ /* C99 loop */
+ {
+ int l3;
+ for (l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
+ dsp->fRec2[l3] = 0.0f;
+
+ }
+
+ }
+ /* C99 loop */
+ {
+ int l4;
+ for (l4 = 0; (l4 < 2); l4 = (l4 + 1)) {
+ dsp->fRec1[l4] = 0.0f;
+
+ }
+
+ }
+ /* C99 loop */
+ {
+ int l5;
+ for (l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
+ dsp->fRec3[l5] = 0.0f;
+
+ }
+
+ }
+ /* C99 loop */
+ {
+ int l6;
+ for (l6 = 0; (l6 < 2); l6 = (l6 + 1)) {
+ dsp->fRec5[l6] = 0.0f;
+
+ }
+
+ }
+ /* C99 loop */
+ {
+ int l7;
+ for (l7 = 0; (l7 < 2); l7 = (l7 + 1)) {
+ dsp->fRec4[l7] = 0.0f;
+
+ }
+
+ }
+
+}
+
+void instanceConstantsKickDrum(KickDrum* dsp, int samplingFreq) {
+ USED(samplingFreq);
+ USED(dsp);
+ dsp->fSamplingFreq = samplingFreq;
+ dsp->fConst0 = min(192000.0f, max(1.0f, (float)dsp->fSamplingFreq));
+ dsp->fConst1 = (1.0f / dsp->fConst0);
+ dsp->fConst2 = (1.0f / dsp->fConst0);
+
+}
+
+void instanceInitKickDrum(KickDrum* dsp, int samplingFreq) {
+ USED(samplingFreq);
+ USED(dsp);
+ instanceConstantsKickDrum(dsp, samplingFreq);
+ instanceResetUserInterfaceKickDrum(dsp);
+ instanceClearKickDrum(dsp);
+}
+
+void initKickDrum(KickDrum* dsp, int samplingFreq) {
+ USED(samplingFreq);
+ USED(dsp);
+ classInitKickDrum(samplingFreq);
+ instanceInitKickDrum(dsp, samplingFreq);
+}
+
+void buildUserInterfaceKickDrum(KickDrum* dsp, UIGlue* ui_interface) {
+ USED(dsp);
+ ui_interface->openVerticalBox(ui_interface->uiInterface, "Kick Drum");
+ ui_interface->openHorizontalBox(ui_interface->uiInterface, "a");
+ ui_interface->declare(ui_interface->uiInterface, &dsp->fVslider0, "0", "");
+ ui_interface->addVerticalSlider(ui_interface->uiInterface, "frequency", &dsp->fVslider0, 100.0f, 10.0f, 200.0f, 5.0f);
+ ui_interface->declare(ui_interface->uiInterface, &dsp->fVslider5, "1", "");
+ ui_interface->addVerticalSlider(ui_interface->uiInterface, "attack", &dsp->fVslider5, 0.00100000005f, 9.99999975e-06f, 0.200000003f, 0.00100000005f);
+ ui_interface->declare(ui_interface->uiInterface, &dsp->fVslider6, "2", "");
+ ui_interface->addVerticalSlider(ui_interface->uiInterface, "delay", &dsp->fVslider6, 0.00999999978f, 9.99999975e-06f, 1.0f, 0.00100000005f);
+ ui_interface->declare(ui_interface->uiInterface, &dsp->fVslider4, "3", "");
+ ui_interface->addVerticalSlider(ui_interface->uiInterface, "release", &dsp->fVslider4, 0.00100000005f, 9.99999975e-06f, 1.0f, 0.00100000005f);
+ ui_interface->closeBox(ui_interface->uiInterface);
+ ui_interface->openHorizontalBox(ui_interface->uiInterface, "b");
+ ui_interface->declare(ui_interface->uiInterface, &dsp->fVslider2, "0", "");
+ ui_interface->addVerticalSlider(ui_interface->uiInterface, "attack", &dsp->fVslider2, 0.00100000005f, 9.99999975e-06f, 0.200000003f, 0.00100000005f);
+ ui_interface->declare(ui_interface->uiInterface, &dsp->fVslider1, "1", "");
+ ui_interface->addVerticalSlider(ui_interface->uiInterface, "frequency", &dsp->fVslider1, 200.0f, -400.0f, 400.0f, 5.0f);
+ ui_interface->declare(ui_interface->uiInterface, &dsp->fVslider3, "2", "");
+ ui_interface->addVerticalSlider(ui_interface->uiInterface, "release", &dsp->fVslider3, 0.00100000005f, 9.99999975e-06f, 0.200000003f, 0.00100000005f);
+ ui_interface->closeBox(ui_interface->uiInterface);
+ ui_interface->openHorizontalBox(ui_interface->uiInterface, "control");
+ ui_interface->declare(ui_interface->uiInterface, &dsp->fButton0, "0", "");
+ ui_interface->addButton(ui_interface->uiInterface, "gate", &dsp->fButton0);
+ ui_interface->declare(ui_interface->uiInterface, &dsp->fCheckbox0, "1", "");
+ ui_interface->addCheckButton(ui_interface->uiInterface, "b enable", &dsp->fCheckbox0);
+ 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];
+ FAUSTFLOAT* output1 = outputs[1];
+ float fSlow0 = (float)dsp->fVslider0;
+ float fSlow1 = ((float)dsp->fVslider1 * (float)dsp->fCheckbox0);
+ float fSlow2 = (float)dsp->fButton0;
+ float fSlow3 = (float)dsp->fVslider2;
+ float fSlow4 = (fSlow3 + (float)dsp->fVslider3);
+ float fSlow5 = (dsp->fConst0 * fSlow4);
+ float fSlow6 = (dsp->fConst0 * fSlow3);
+ float fSlow7 = (1.0f / (0.0f - (dsp->fConst0 * (fSlow3 - fSlow4))));
+ float fSlow8 = (dsp->fConst2 / fSlow3);
+ int iSlow9 = (fSlow2 > 0.0f);
+ int iSlow10 = (iSlow9 > 0);
+ float fSlow11 = (float)dsp->fVslider4;
+ float fSlow12 = (dsp->fConst0 * fSlow11);
+ int iSlow13 = ((fSlow2 == 0.0f) > 0);
+ float fSlow14 = (float)dsp->fVslider5;
+ float fSlow15 = (fSlow14 + (float)dsp->fVslider6);
+ float fSlow16 = (dsp->fConst0 * fSlow15);
+ float fSlow17 = (dsp->fConst0 * fSlow14);
+ float fSlow18 = (9.99999997e-07f * fSlow2);
+ float fSlow19 = ((fSlow18 + -1.0f) / (0.0f - (dsp->fConst0 * (fSlow14 - fSlow15))));
+ float fSlow20 = (dsp->fConst2 / fSlow14);
+ float fSlow21 = (dsp->fConst2 / fSlow11);
+ /* C99 loop */
+ {
+ int i;
+ for (i = 0; (i < count); i = (i + 1)) {
+ dsp->fVec0[0] = fSlow2;
+ dsp->fVec1[0] = fSlow4;
+ dsp->fRec2[0] = ((((fSlow2 - dsp->fVec0[1]) > 0.0f) > 0)?0.0f:min(fSlow5, ((dsp->fRec2[1] + (dsp->fConst0 * (fSlow4 - dsp->fVec1[1]))) + 1.0f)));
+ int iTemp0 = (dsp->fRec2[0] < fSlow6);
+ float fTemp1 = (dsp->fRec1[1] + (dsp->fConst1 * (fSlow0 + (fSlow1 * (iTemp0?((dsp->fRec2[0] < 0.0f)?0.0f:(iTemp0?(fSlow8 * dsp->fRec2[0]):1.0f)):((dsp->fRec2[0] < fSlow5)?((fSlow7 * (0.0f - (dsp->fRec2[0] - fSlow6))) + 1.0f):0.0f))))));
+ dsp->fRec1[0] = (fTemp1 - floorf(fTemp1));
+ dsp->fRec3[0] = (iSlow10?0.0f:min(fSlow12, (dsp->fRec3[1] + 1.0f)));
+ dsp->fRec5[0] = (iSlow13?0.0f:min(fSlow16, (dsp->fRec5[1] + 1.0f)));
+ int iTemp2 = (dsp->fRec5[0] < fSlow17);
+ dsp->fRec4[0] = (iSlow9?((float)iSlow9 * (iTemp2?((dsp->fRec5[0] < 0.0f)?0.0f:(iTemp2?(fSlow20 * dsp->fRec5[0]):1.0f)):((dsp->fRec5[0] < fSlow16)?((fSlow19 * (dsp->fRec5[0] - fSlow17)) + 1.0f):fSlow18))):dsp->fRec4[1]);
+ float fTemp3 = (ftbl0KickDrumSIG0[(int)(65536.0f * dsp->fRec1[0])] * ((dsp->fRec3[0] < 0.0f)?dsp->fRec4[0]:((dsp->fRec3[0] < fSlow12)?(dsp->fRec4[0] + (fSlow21 * (dsp->fRec3[0] * (0.0f - dsp->fRec4[0])))):0.0f)));
+ output0[i] = (FAUSTFLOAT)fTemp3;
+ output1[i] = (FAUSTFLOAT)fTemp3;
+ dsp->fVec0[1] = dsp->fVec0[0];
+ dsp->fVec1[1] = dsp->fVec1[0];
+ dsp->fRec2[1] = dsp->fRec2[0];
+ dsp->fRec1[1] = dsp->fRec1[0];
+ dsp->fRec3[1] = dsp->fRec3[0];
+ dsp->fRec5[1] = dsp->fRec5[0];
+ dsp->fRec4[1] = dsp->fRec4[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/mkfile
+++ b/mkfile
@@ -5,6 +5,7 @@
OFILES=\
fs.$O\
kick_drum.dsp.$O\
+ uiglue.$O\
default:V: all
--- /dev/null
+++ b/uiglue.c
@@ -1,0 +1,225 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include "uiglue.h"
+#include "aux.h"
+
+static FAUSTFLOAT *declzone;
+static const char *declkey;
+static const char *declvalue;
+
+static char *
+ui_readstr(Aux *a, UI *ui, int type, char *s, int sz)
+{
+ if (type != Xuictl)
+ sysfatal("unknown ui file");
+
+ switch (a->type) {
+ case UITBox: snprint(s, sz, "tbox\n"); return s;
+ case UIHBox: snprint(s, sz, "hbox\n"); return s;
+ case UIVBox: snprint(s, sz, "vbox\n"); return s;
+ case UIButton: snprint(s, sz, "button\t%s\t%d\n", ui->key, !!*ui->zone); return s;
+ case UICheck: snprint(s, sz, "check\t%s\t%d\n", ui->key, !!*ui->zone); return s;
+ case UIVSlider: snprint(s, sz, "vslider\t%s\t%f\t%f\t%f\t%f\t%f\n", ui->key, *ui->zone, ui->init, ui->min, ui->max, ui->step); return s;
+ case UIHSlider: snprint(s, sz, "hslider\t%s\t%f\t%f\t%f\t%f\t%f\n", ui->key, *ui->zone, ui->init, ui->min, ui->max, ui->step); return s;
+ case UINum: snprint(s, sz, "num\t%s\t%f\t%f\t%f\t%f\t%f\n", ui->key, *ui->zone, ui->init, ui->min, ui->max, ui->step); return s;
+ case UIHBarGraph: snprint(s, sz, "hbargraph\t%s\t%f\t%f\t%f\n", ui->key, *ui->zone, ui->min, ui->max); return s;
+ case UIVBarGraph: snprint(s, sz, "vbargraph\t%s\t%f\t%f\t%f\n", ui->key, *ui->zone, ui->min, ui->max); return s;
+ }
+ sysfatal("unknown ui type %d", a->type);
+ return nil;
+}
+
+static int
+ui_write(Aux *a, UI *ui, int type, char *s)
+{
+ float v;
+
+ if (type != Xuictl)
+ sysfatal("unknown ui file");
+
+ /* FIXME optional argument should specify at which frame to apply the change */
+
+ v = 0.0f;
+ 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 = atof(s);
+ }
+
+ if (ui->zone != nil) {
+ if (a->type == UIButton || a->type == UICheck)
+ v = !!v;
+ else if (*ui->zone < ui->min)
+ v = ui->min;
+ else if (*ui->zone > ui->max)
+ 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));
+ a->ui = (UI*)(a+1);
+ a->ctl = Xuictl;
+ a->type = type;
+ a->ui->label = label;
+ a->ui->readstr = ui_readstr;
+ a->ui->write = ui_write;
+ if ((uiglue.uiInterface = createfile(f, label, nil, DMDIR|0775, a)) == nil)
+ sysfatal("failed to create ui: %r");
+ if (createfile(uiglue.uiInterface, "ctl", nil, 0664, &a->ctl) == nil)
+ sysfatal("failed to create ui ctl: %r");
+
+ return a->ui;
+}
+
+static void
+ui_tbox(void *f, const char *label)
+{
+ newui(f, label, UITBox);
+}
+
+static void
+ui_hbox(void *f, const char *label)
+{
+ newui(f, label, UIHBox);
+}
+
+static void
+ui_vbox(void *f, const char *label)
+{
+ newui(f, label, UIVBox);
+}
+
+static void
+ui_close(void *file)
+{
+ File *f;
+
+ f = file;
+ uiglue.uiInterface = f->parent;
+}
+
+static UI *
+ui_define(File *f, int type, const char *label, FAUSTFLOAT *zone)
+{
+ UI *ui;
+
+ if (zone != declzone)
+ sysfatal("zone mismatch");
+ ui = newui(f, label, type);
+ ui->zone = declzone;
+ ui->key = declkey;
+ ui->value = declvalue;
+ uiglue.uiInterface = f;
+
+ return ui;
+}
+
+static void
+ui_button(void *f, const char *label, FAUSTFLOAT *zone)
+{
+ ui_define(f, UIButton, label, zone);
+}
+
+static void
+ui_check(void *f, const char *label, FAUSTFLOAT *zone)
+{
+ ui_define(f, UICheck, 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_num(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+ UI *ui;
+
+ ui = ui_define(f, UINum, 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);
+
+ declzone = zone;
+ declkey = key;
+ declvalue = value;
+}
+
+UIGlue uiglue = {
+ .openTabBox = ui_tbox,
+ .openHorizontalBox = ui_hbox,
+ .openVerticalBox = ui_vbox,
+ .closeBox = ui_close,
+ .addButton = ui_button,
+ .addCheckButton = ui_check,
+ .addVerticalSlider = ui_vslider,
+ .addHorizontalSlider = ui_hslider,
+ .addNumEntry = ui_num,
+ .addHorizontalBargraph = ui_hbargraph,
+ .addVerticalBargraph = ui_vbargraph,
+ .declare = ui_declare,
+};
--- a/uiglue.h
+++ b/uiglue.h
@@ -2,10 +2,13 @@
#define FAUSTFLOAT float
#endif
-typedef struct {
+typedef struct UIGlue UIGlue;
+typedef struct MetaGlue MetaGlue;
+
+struct UIGlue {
void *uiInterface;
void (*openTabBox)(void *uiInterface, const char *label);
- void (*openHorizontalBox) (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);
@@ -16,9 +19,11 @@
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);
-}UIGlue;
+};
-typedef struct {
+struct MetaGlue {
void *metaInterface;
void (*declare)(void *metaInterface, const char *key, const char *value);
-}MetaGlue;
+};
+
+extern UIGlue uiglue;