stew

a monorepo of some sort
Log | Files | Refs

commit e06ef51dbdc7c641031859d911127f963175f810
parent 33a4d7ac6a987fb463649f51cdeb144f7d8cea5d
Author: rpa <rpa@laika>
Date:   Sun, 15 Jan 2023 00:18:22 +0000

wave: wfedit display samples and some simple commands

Diffstat:
Msrc/wave/wavetable.c | 59++++++++++++++++++++++++++++++++++-------------------------
Msrc/wave/wavetable.h | 2+-
Msrc/wave/wfedit.c | 339+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
3 files changed, 334 insertions(+), 66 deletions(-)

diff --git a/src/wave/wavetable.c b/src/wave/wavetable.c @@ -2,34 +2,43 @@ #include <libc.h> #include "wavetable.h" -double -wfosc(s16int *wf, double T) +int +pstep(Phasor *p, int freq, int phase, int linear) { - double t = fmod(T, 1) * WFSize; - int n = floor(t); - return wf[n]; - //double v1 = wf[n]; - //double v2 = (n == WFSize - 1) ? wf[0] : wf[n + 1]; - //double d = fmod(t, 1); - //return v1 * (1.0 - d) + v2 * d; + int t = (p->t + phase) * WFSize / 44100; + p->t += freq; + if (linear == 0) return t % WFSize; + else return t; } -double -wtosc(s16int *wt, int C, double T) +u32int +wtfunc(s16int *wtp, int phase, int mod, int vol, int pan) { - int n; - double d, v1, v2; - if (C < 0) C = 0; - if (C > 0xffff) C = 0xffff; - - n = C >> 8; - d = fmod(C & 0xff, WTSize) / (double)WTSize; + int m1, m2, x, y, d, v, mono; + union { + u32int i; + s16int s[2]; + } out; + d = mod % WTSize; + m1 = phase + (mod / WTSize) * WFSize; + m2 = m1 + WFSize; + x = wtp[m1 % (WTSize * WFSize)]; + y = wtp[m2 % (WTSize * WFSize)]; + v = (x * (WTSize - d) + y * d) / WTSize; + mono = v * vol / 0x7fff; + out.s[0] = mono; + out.s[1] = mono; + if (pan > 0) out.s[0] = mono * (0x7fff - pan) / 0x7fff; + else if (pan < 0) out.s[1] = mono * (0x7fff + pan) / 0x7fff; + return out.i; +} - if (n >= WTSize) { - n = WTSize - 1; - d = 1; - v2 = wfosc(wt + (n * WFSize), T); - } else v2 = wfosc(wt + ((n + 1) * WFSize), T); - v1 = wfosc(wt + (n * WFSize), T); - return v1 * (1 - d) + v2 * d; +u32int +wtstep(Synth *s, Phasor *p) +{ + s16int *wtp; + int phase; + wtp = s->table[s->mod.wtsel % 64]; + phase = pstep(p, s->mod.freq, s->mod.phase, s->flag); + return wtfunc(wtp, phase, s->mod.mod, s->mod.vol, s->mod.pan); } diff --git a/src/wave/wavetable.h b/src/wave/wavetable.h @@ -28,6 +28,6 @@ struct Synth { int flag; }; -u32int wtfunc(s16int *wtp, int phase, int mod, int vol, int pan); int pstep(Phasor *, int, int, int); +u32int wtfunc(s16int *wtp, int phase, int mod, int vol, int pan); u32int wtstep(Synth *, Phasor *); diff --git a/src/wave/wfedit.c b/src/wave/wfedit.c @@ -4,6 +4,7 @@ #include <u.h> #include <libc.h> +#include <bio.h> #include <thread.h> #include <draw.h> #include <mouse.h> @@ -13,33 +14,71 @@ #include "wavetable.h" enum { - BufMax = 8, + BufMax = 6, BufSize = sizeof(s16int) * WFSize, - CmdBufSize = 256, + MsgSize = 256, }; -typedef struct CmdCtl CmdCtl; -typedef struct Command Command; +typedef struct Cmdctl Cmdctl; +typedef struct Uictl Uictl; -struct CmdCtl { +typedef int (*cmdfunc)(Cmdctl *, int, char **); + +struct Cmdctl { Channel *c; + Channel *updatec; +}; + +struct Uictl { + Mousectl *mctl; + Rectangle grid[BufMax]; + Image *winbg, *wfbg, *hi, *lo; + Channel *updatec; +}; + +#define CMD(name) int name(Cmdctl *cmd, int argc, char **argv) +CMD(cmdexit); +CMD(cmdecho); +CMD(cmdload); +CMD(cmdsave); +CMD(cmdnoise); +CMD(cmdcos); +CMD(cmdmove); +CMD(cmdampmod); +CMD(cmdphasemod); + +struct Dict{ + const char *name; + cmdfunc cmd; }; -struct Command { - int in; - int out; - void (*op)(void *); - char **args; +struct Dict dict[] = { + {"q", cmdexit}, + {"exit", cmdexit}, + {"quit", cmdexit}, + {"bye", cmdexit}, + {"echo", cmdecho}, + {"load", cmdload}, + {"save", cmdsave}, + {"noise", cmdnoise}, + {"cos", cmdcos}, + {nil, nil}, }; + void usage(void); void threadcmd(void *); -int getinput(char *); -int getoutput(char *); -void* getop(char *); -void bufcpy(int, int); - s16int *buf[BufMax]; +cmdfunc getcmd(char *); + +Uictl *initui(void); +void threadui(void *); +void resize(Uictl *); +void drawwaveform(Image *, Rectangle, s16int *, Image *, Image *, Image *); +void drawgrid(Uictl *ui); + +Cmdctl cmdctl; +Uictl *uictl; void threadmain(int argc, char **argv) @@ -50,7 +89,27 @@ threadmain(int argc, char **argv) default: usage(); } ARGEND; + if (argc > 1) usage(); + + uictl = initui(); + + cmdctl.c = chancreate(MsgSize, 0); + cmdctl.updatec = uictl->updatec; + proccreate(threadcmd, &cmdctl, 64 * 1024); + if (argc == 1) { + cmdload(&cmdctl, 1, argv); + } + + Biobuf *bfd = Bfdopen(0, OREAD); + char *s; + char cmdbuf[MsgSize]; + while((s = Brdstr(bfd, '\n', 1)) != nil) { + memset(cmdbuf, 0, MsgSize); + strncpy(cmdbuf, s, MsgSize); + send(cmdctl.c, cmdbuf); + free(s); + } } void @@ -64,47 +123,247 @@ void threadcmd(void *v) { int n; - Command cmd; - char cmdbuf[CmdBufSize], *args[64]; - CmdCtl *rctl = v; - while (recv(v,cmdbuf) > 0) { + char cmdbuf[MsgSize], *args[64]; + Cmdctl *rctl = v; + while (recv(rctl->c, cmdbuf) > 0) { n = tokenize(cmdbuf, args, 64); - cmd = (Command) { - getinput(args[0]), - getoutput(args[n-1]), - getop(args[1]), - args + 2, - }; - args[n - 1] = nil; - if ((cmd.in >= 0) && (cmd.out >= 0) && (cmd.op != nil)) { - bufcpy(cmd.in, 0); - cmd.op(args); - bufcpy(0, cmd.out); - } else { - // TODO: output error message here? - } + if (n <= 0) continue; + cmdfunc cmd = getcmd(args[0]); + if (cmd != nil) { + cmd(rctl, n - 1, args + 1); + } else fprint(2, "?\n"); } } +cmdfunc +getcmd(char *name) +{ + struct Dict *dp; + for (dp = dict; dp->name != nil; dp++) { + if (strcmp(dp->name, name) == 0) return dp->cmd; + } + return nil; +} + int -getinput(char *) +cmdexit(Cmdctl *, int, char**) { + threadexitsall(nil); return 0; } -int -getoutput(char *) +CMD(cmdecho) { + int i; + for (i = 0; i < argc; i++) { + if (i > 0) print(" "); + print("%s", argv[i]); + } + print("\n"); return 0; } -void * -getop(char *) +CMD(cmdload) { - return nil; + int fd; + if (argc == 0) { + fprint(2, "usage: load file\n"); + return 1; + } + fd = open(argv[0], OREAD); + if (fd < 0) { + fprint(2, "cmdload: %r\n"); + return 1; + } + read(fd, buf[0], WFSize * sizeof(s16int)); + close(fd); + if (cmd->updatec != nil) nbsendul(cmd->updatec, 0); + return 0; +} + +CMD(cmdsave) +{ + int fd; + if (argc == 0) { + fprint(2, "usage: save file\n"); + return 1; + } + fd = create(argv[0], OWRITE, 0666); + if (fd < 0) { + fprint(2, "cmdsave: %r\n"); + return 1; + } + write(fd, buf[0], WFSize * sizeof(s16int)); + close(fd); + if (cmd->updatec != nil) nbsendul(cmd->updatec, 0); + return 0; +} + +CMD(cmdnoise) +{ + int i; + ulong targ = 0; + if (argc > 1) { + fprint(2, "usage: noise [id]\n"); + return 1; + } + if (argc == 1) targ = atoi(argv[0]); + if (targ > BufMax) { + fprint(2, "invalid id\n"); + return 1; + } + for (i = 0; i < WFSize; i++) { + buf[targ][i] = truerand(); + } + if (cmd->updatec != nil) nbsendul(cmd->updatec, targ); + return 0; +} + +CMD(cmdcos) +{ + int i; + ulong targ = 0; + if (argc > 1) { + fprint(2, "usage: noise [id]\n"); + return 1; + } + if (argc == 1) targ = atoi(argv[0]); + if (targ > BufMax) { + fprint(2, "invalid id\n"); + return 1; + } + for (i = 0; i < WFSize; i++) { + buf[targ][i] = cos((double)i / WFSize * PI * 2) * 0x7fff; + } + if (cmd->updatec != nil) nbsendul(cmd->updatec, targ); + return 0; +} + +CMD(cmdmove) +{ + if (cmd->updatec != nil) nbsendul(cmd->updatec, 0); + return 0; +} + +CMD(cmdampmod) +{ + if (cmd->updatec != nil) nbsendul(cmd->updatec, 0); + return 0; +} + +CMD(cmdphasemod) +{ + if (cmd->updatec != nil) nbsendul(cmd->updatec, 0); + return 0; +} + + + +Uictl * +initui(void) +{ + Uictl *ui = mallocz(sizeof(Uictl), 1); + newwindow(nil); + if (initdraw(nil, nil, "wfedit") < 0) sysfatal("%r"); + if ((ui->mctl = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r"); + ui->winbg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1 , DWhite); + ui->wfbg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1 , DBlack); + ui->hi = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1 , DRed); + ui->lo = allocimagemix(display, DRed, DBlack); + ui->updatec = chancreate(sizeof(ulong), BufMax); + resize(ui); + proccreate(threadui, ui, 64 * 1024); + return ui; } void -bufcpy(int, int) +threadui(void *v) { + ulong upd; + Uictl *ui = v; + + draw(screen, screen->r, ui->winbg, nil, ZP); + nbsendul(ui->updatec, -1); + + Alt alts[] = { + {ui->mctl->resizec, nil, CHANRCV}, + {ui->mctl->c, nil, CHANRCV}, + {ui->updatec, &upd, CHANRCV}, + {nil, nil, CHANEND}, + }; + + for (;;) { + switch (alt(alts)) { + case 0: /* resize */ + if (getwindow(display, Refnone) < 0) sysfatal("resize: %r"); + resize(ui); + draw(screen, screen->r, ui->winbg, nil, ZP); + nbsendul(ui->updatec, -1); + break; + case 1: /* mouse */ + break; + case 2: /* update */ + if (upd >= BufMax) drawgrid(ui); + else { + drawwaveform(screen, ui->grid[upd], buf[upd], ui->wfbg, ui->hi, ui->lo); + }; + flushimage(display, 1); + break; + } + } +} + +void +resize(Uictl *ui) +{ + int i; + Point min, max, mid; + Rectangle l, r, scr; + scr = insetrect(screen->r, 1); + min = scr.min; + max = scr.max; + mid = addpt(min, Pt(Dx(scr)/2, Dy(scr)/(BufMax/2))); + l = Rpt(min, mid); + r = Rect(mid.x, min.y, max.x, mid.y); + for (i = 0; i < BufMax; i+=2) { + ui->grid[i] = insetrect(l, 1); + ui->grid[i + 1] = insetrect(r, 1); + l = rectaddpt(l, Pt(0, Dy(l))); + r = rectaddpt(r, Pt(0, Dy(r))); + } +} + +void +drawwaveform(Image *screen, Rectangle r, s16int *wf, Image *bg, Image *hi, Image *lo) +{ + Rectangle bar; + int i, w, h, mid, s, e, m1, m2; + w = Dx(r); + h = Dy(r); + mid = h/2; + draw(screen, r, bg, nil, ZP); + for (i = 0; i < w; i++) { + s = i * WFSize / w; + e = (i == w - 1) ? 0 : (i + 1) * WFSize / w; + m1 = wf[s] * mid / 0x7fff; + m2 = wf[e] * mid / 0x7fff; + if (m1 == m2) m1 += (m1 > 0) ? -1 : +1; + bar = Rpt(Pt(i, mid), Pt(i + 1, mid + m1)); + bar = canonrect(bar); + bar = rectaddpt(bar, r.min); + draw(screen, bar, lo, nil, ZP); + bar = Rpt(Pt(i, mid + m2), Pt(i + 1, mid + m1)); + bar = canonrect(bar); + bar = rectaddpt(bar, r.min); + draw(screen, bar, hi, nil, ZP); + } +} + +void +drawgrid(Uictl *ui) +{ + int i; + for (i = 0; i < BufMax; i++) { + drawwaveform(screen, ui->grid[i], buf[i], ui->wfbg, ui->hi, ui->lo); + } }