commit fd1313e58cce4cf2020ff9d53b130a9c9d4c4984
parent 78c02efce9ae30194bcbf675e946ba48f5500def
Author: rpa <rpa@laika>
Date: Fri, 6 Jan 2023 23:55:30 +0000
wave: start working on instrument editor
Diffstat:
4 files changed, 254 insertions(+), 2 deletions(-)
diff --git a/src/wave/inst.c b/src/wave/inst.c
@@ -0,0 +1,230 @@
+/*
+ Visual instrument editor
+ loads/modifies/saves envelopes
+ allows previewing settings by playing notes
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <mouse.h>
+#include <keyboard.h>
+
+#include "wavetable.h"
+
+enum {
+ NameBufSize = 256,
+ OutBufSize = 882,
+};
+
+typedef struct Widget Widget;
+typedef struct UI UI;
+
+struct UI {
+ Mousectl *mctl;
+ Mouse mv;
+ int rv[2];
+ Keyboardctl *kctl;
+ Rune kv;
+ Widget *hot;
+ Widget **wp;
+};
+
+struct Widget {
+ Rectangle r;
+ Image **palette;
+ void *aux;
+ void (*draw)(void *);
+ void (*activate)(UI *, void *);
+};
+
+struct wavetable {
+ s16int *p;
+ char fname[NameBufSize];
+};
+
+struct synth {
+ Inst inst;
+};
+
+void usage(void);
+void threadsynth(void *);
+void handlemouse(UI *);
+void wtdraw(void *);
+void wtactivate(UI *, void *);
+int loadwavetable(void *, char *);
+void rcalc(UI *);
+Widget * findhot(UI *);
+
+void
+threadmain(int argc, char **argv)
+{
+ struct synth synth;
+ struct wavetable wavetable;
+ Image *palette[8];
+ UI UI;
+ Widget wt;
+
+ ARGBEGIN{
+ default:
+ usage();
+ } ARGEND
+ if (argc != 1) usage();
+
+ wavetable.p = mallocz(sizeof(s16int) * WFSize * WTSize, 1);
+ if (loadwavetable(wavetable.p, argv[0]) != 0) {
+ fprint(2, "loading %s\n", argv[0]);
+ snprint(wavetable.fname, NameBufSize, "%s", argv[0]);
+ } else wavetable.fname[0] = '\0';
+
+ if (initdraw(nil, nil, "inst") == 0) sysfatal("%r");
+ if ((UI.mctl = initmouse(nil, nil)) == nil) sysfatal("%r");
+ if ((UI.kctl = initkeyboard(nil)) == nil) sysfatal("%r");
+ proccreate(threadsynth, &synth, 64 * 1024);
+
+ palette[0] = allocimage(display, Rect(0,0,1,1), XRGB32, 1, 0x7f3f00ff);
+ palette[1] = allocimage(display, Rect(0,0,1,1), XRGB32, 1, 0xffff00ff);
+
+ wt.palette = palette;
+ wt.aux = &wavetable;
+ wt.draw = wtdraw;
+ wt.activate = wtactivate;
+
+ Widget *wp[] = {&wt, nil};
+ UI.wp = wp;
+
+ rcalc(&UI);
+
+ draw(screen, screen->r, display->black, nil, ZP);
+ wt.draw(&wt);
+ flushimage(display, 1);
+
+ Alt alts[] = {
+ {UI.mctl->resizec, UI.rv, CHANRCV},
+ {UI.mctl->c, &(UI.mv), CHANRCV},
+ {UI.kctl->c, &(UI.kv), CHANRCV},
+ {nil, nil, CHANEND},
+ };
+
+ for (;;) switch (alt(alts)) {
+ case 0: /* resize */
+ if(getwindow(display, Refnone) < 0) sysfatal("resize failed: %r");
+ draw(screen, screen->r, display->black, nil, ZP);
+ rcalc(&UI);
+ wt.draw(&wt);
+ flushimage(display, 1);
+ break;
+ case 1: /* mouse */
+ handlemouse(&UI);
+ break;
+ case 2: /* keyboard */
+ break;
+ }
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s\n", argv0);
+ threadexitsall("usage");
+}
+
+void
+threadsynth(void *arg)
+{
+ struct synth *synth;
+ int audio;
+ s16int *buf;
+ synth = (struct synth *) arg;
+ audio = open("/dev/audio", OWRITE);
+ if (audio < 0) {
+ fprint(2, "threadsynth: %r\n");
+ return;
+ }
+ buf = mallocz(OutBufSize, 1);
+ while (write(audio, buf, OutBufSize) > 0) {
+ int i;
+ for (i = 0; i < OutBufSize - 1; i += 2) {
+ // TODO: insert synth code here
+ buf[i] = 0;
+ buf[i+1] = buf[i];
+ }
+ }
+ free(buf);
+}
+
+void
+handlemouse(UI *UI)
+{
+
+ enum { MFree, };
+ static state = MFree;
+ switch (state) {
+ case MFree:
+ UI->hot = findhot(UI);
+ if ((UI->mv.buttons != 0) && (UI->hot != nil)) {
+ UI->hot->activate(UI, UI->hot);
+ UI->hot->draw(UI->hot);
+ flushimage(display, 1);
+ }
+ if (UI->mv.buttons == 4) threadexitsall(nil);
+ break;
+ }
+}
+
+void
+wtdraw(void *arg)
+{
+ Widget *w = (Widget *) arg;
+ struct wavetable *wt = (struct wavetable *) w->aux;
+ char buf[256];
+ snprint(buf, NameBufSize, "wt: %s", wt->fname);
+ draw(screen, w->r, w->palette[0], nil, ZP);
+ string(screen, w->r.min, w->palette[1], ZP, font, buf);
+}
+
+void
+wtactivate(UI *UI, void *arg)
+{
+ Widget *w = (Widget *) arg;
+ struct wavetable *wt = (struct wavetable *) w->aux;
+ if (enter("wt:", wt->fname, NameBufSize, UI->mctl, UI->kctl, nil) != 0) {
+ loadwavetable(wt->p, wt->fname);
+ }
+}
+
+int
+loadwavetable(void *p, char *f)
+{
+ int fd;
+ long n;
+ fd = open(f, OREAD);
+ if (fd < 0) {
+ fprint(2, "%r\n");
+ return 0;
+ };
+ n = read(fd, p, sizeof(s16int) * WFSize * WTSize);
+ close(fd);
+ return n > 0;
+}
+
+void
+rcalc(UI *UI)
+{
+ Point min = screen->r.min;
+ Point max = screen->r.max;
+ Rectangle r = Rpt(min, Pt(max.x, min.y + font->height));
+ UI->wp[0]->r = r;
+}
+
+Widget *
+findhot(UI *UI)
+{
+ Widget **w = UI->wp;
+ Point xy = UI->mv.xy;
+ for (; *w != nil; w++) {
+ if (ptinrect(xy, (*w)->r) != 0) return *w;
+ }
+ return nil;
+}
diff --git a/src/wave/mkfile b/src/wave/mkfile
@@ -1,6 +1,6 @@
</$objtype/mkfile
-TARG=draw loop fade piano sampler harm smoke
+TARG=draw loop fade piano sampler harm smoke inst
BIN=/$objtype/bin
HFILES=util.h wavetable.h
OFILES=wavetable.$O
diff --git a/src/wave/piano.c b/src/wave/piano.c
@@ -99,4 +99,3 @@ main(int argc, char **argv)
}
}
}
-
diff --git a/src/wave/smoke.c b/src/wave/smoke.c
@@ -0,0 +1,23 @@
+/* crashalot */
+#include <u.h>
+#include <libc.h>
+#include "wavetable.h"
+
+void
+main(void)
+{
+ int i, n, t;
+ double x;
+ Env e;
+ e.n = 3;
+ e.val[0] = 15;
+ e.val[1] = 5;
+ e.val[2] = 0;
+ e.len[0] = 10;
+ e.len[1] = 10;
+ for (i = 0; i < 25; i++) {
+ x = envget(&e, &n, &t, 0);
+ print("[%d %d] %f\n", n, t, x);
+ t++;
+ }
+}