commit 78c02efce9ae30194bcbf675e946ba48f5500def
parent 929b9460ccadc21e0b41ee5e787a11eb82319089
Author: rpa <rpa@laika>
Date: Thu, 5 Jan 2023 21:41:18 +0000
wave: some code?
Diffstat:
6 files changed, 179 insertions(+), 42 deletions(-)
diff --git a/src/wave/mkfile b/src/wave/mkfile
@@ -1,7 +1,8 @@
</$objtype/mkfile
-TARG=draw loop fade piano sampler harm
+TARG=draw loop fade piano sampler harm smoke
BIN=/$objtype/bin
-HFILES=util.h
+HFILES=util.h wavetable.h
+OFILES=wavetable.$O
</sys/src/cmd/mkmany
diff --git a/src/wave/notes b/src/wave/notes
@@ -1,2 +1,19 @@
The de-facto standard for wavetables seems to be 2048 samples per waveform,
up to 256 waveforms per table.
+
+wavetable:
+ 256*2048 array of s16int
+
+envelope:
+ len[]
+ val[]
+ loop
+ hold
+
+instrument:
+ wavetable
+ vol, pan, freq, filter, etc envelopes
+
+voice:
+ instrument
+ state (osc_t, pos on every envelope)
diff --git a/src/wave/piano.c b/src/wave/piano.c
@@ -86,15 +86,11 @@ main(int argc, char **argv)
last = r[runestrlen(r) - 1];
rp = runestrchr(keys, last);
if (rp != nil) {
- int k = (rp - keys) % 12;
- int o = (rp - keys) / 12;
- fprint(2, "%C%C%d, %f ", notes[k], semi[k], o + 4, freq[rp-keys]);
fprint(1, "%f\n", freq[rp-keys]);
} else last = 0;
break;
case 'K':
if ((last > 0) && (last != r[runestrlen(r) - 1])) {
- fprint(2, "off\n");
fprint(1, "0\n");
last = 0;
}
diff --git a/src/wave/sampler.c b/src/wave/sampler.c
@@ -4,40 +4,64 @@
#include <thread.h>
#include "util.h"
+#include "wavetable.h"
#define BufSize 256
#define BufSizeInBytes (BufSize * 2 * sizeof(s16int))
-#define BaseFreq 523.25
-
-Aud sample;
+Inst inst;
s16int buf[BufSize * 2];
int audio, fid;
Channel *ctl;
void synth(void *);
-Frame * lookup(void *, double);
void
usage(void)
{
- fprint(2, "usage: %s file\n", argv0);
+ fprint(2, "usage: %s wavetable\n", argv0);
threadexitsall("usage");
}
void
threadmain(int argc, char **argv)
{
- double in;
ARGBEGIN {
default:
usage();
} ARGEND
if (argc != 1) usage();
+ inst.wt = mallocz(sizeof(s16int) * WFSize * WTSize, 1);
+
+ inst.ampenv.n = 3;
+ inst.ampenv.val[0] = 256;
+ inst.ampenv.val[1] = 128;
+ inst.ampenv.val[2] = 0;
+ inst.ampenv.len[0] = 441 * 25;
+ inst.ampenv.len[1] = 441 * 50;
+ inst.ampenv.flags = EFHold;
+ inst.ampenv.hold[0] = 1;
+ inst.ampenv.hold[1] = 1;
+
+
+ inst.wtenv.n = 3;
+ inst.wtenv.val[0] = 0;
+ inst.wtenv.val[1] = 3;
+ inst.wtenv.val[2] = 0;
+ inst.wtenv.len[0] = 441 * 50;
+ inst.wtenv.len[1] = 441 * 50;
+ inst.wtenv.flags = EFLoop;
+ inst.wtenv.loop[0] = 0;
+ inst.wtenv.loop[1] = 2;
+
fid = open(argv[0], OREAD);
if (fid <= 0) sysfatal("%r");
- sample.n = read(fid, sample.p, MaxLength * sizeof(u32int)) / sizeof(u32int);
+ long n;
+ s16int *wp = inst.wt;
+ while ((n = read(fid, wp, WFSize * sizeof(s16int))) > 0) {
+ wp += n/sizeof(s16int);
+ }
close(fid);
audio = open("/dev/audio", OWRITE);
@@ -49,6 +73,7 @@ threadmain(int argc, char **argv)
bp = Bfdopen(0, OREAD);
for (;;) {
// TODO: use Brdstr or Brdline and extract double from it's output instead of this.
+ double in;
Bgetd(bp, &in);
send(ctl, &in);
if (Bgetc(bp) == Beof) break;
@@ -60,44 +85,36 @@ threadmain(int argc, char **argv)
void
synth(void *)
{
- int n;
- double t, freq, v;
+ int i, n, as[2] = {0, 0}, ws[2] = {0, 0}, hold = 0;
+ double f, t, freq, v, lfo;
freq = 0;
t = 0;
+ lfo = 0;
for(n = 0; n >= 0; n = nbrecv(ctl, &v)){
if (n > 0) {
- freq = v;
- if (freq == 0) t = 0;
+ if (v == 0) {
+ hold = 0;
+ }
+ else {
+ freq = v;
+ hold = 1;
+ t = 0;
+ as[0] = 0, as[1] = 0;
+ ws[0] = 0, ws[1] = 0;
+ }
}
- int i;
for (i = 0; i < BufSize; i++) {
- Frame *fr = lookup(&sample, t);
- buf[i * 2] = fr->c1;
- buf[1 + i * 2] = fr->c2;
- t += freq / BaseFreq;
+ f = wtosc(inst.wt, envget(&inst.wtenv, &ws[0], &ws[1], hold), t);
+ f *= envget(&inst.ampenv, &as[0], &as[1], hold) / 256.0 * 0x7fff;
+ as[1]++;
+ ws[1]++;
+ buf[i * 2] = f;
+ buf[1 + i * 2] = buf[i * 2];
+ t += freq / 44100.0;
+ lfo += 1.0 / 44100.0;
}
if (write(audio, buf, BufSizeInBytes) < BufSizeInBytes) {
sysfatal("synth: write to /dev/audio failed, %r");
}
}
}
-
-/*
-s16int
-lookup(void *, double t)
-{
- return 0x7fff * sin(t / 44100.0 * BaseFreq * PI * 2.0);
-}
-*/
-
-Frame *
-lookup(void *v, double t)
-{
- Aud *aud;
- Frame *fr;
- long T;
- aud = (Aud *)v;
- T = t;
- fr = (Frame *)(&aud->p[T%aud->n]);
- return fr;
-}
diff --git a/src/wave/wavetable.c b/src/wave/wavetable.c
@@ -0,0 +1,70 @@
+#include <u.h>
+#include <libc.h>
+#include "wavetable.h"
+
+double
+envget(Env *env, int *n, int *t, int hold)
+{
+ double d, v1, v2;
+
+ if ((env->flags & EFHold) && hold && (*n >= env->hold[1])) {
+ *n = env->hold[0];
+ if (env->hold[0] == env->hold[1]) *t = 0;
+ }
+ if ((env->flags & EFLoop) && (*n >= env->loop[1])) {
+ *n = env->loop[0];
+ if (env->loop[0] == env->loop[1]) *t = 0;
+ }
+
+ for (; (*t > env->len[*n]) && (*n < env->n); *t -= env->len[*n]) {
+ (*n)++;
+ if ((env->flags & EFHold) && hold && (*n >= env->hold[1])) {
+ *n = env->hold[0];
+ }
+ if ((env->flags & EFLoop) && (*n >= env->loop[1])) {
+ *n = env->loop[0];
+ }
+ }
+
+ if (*n >= env->n) {
+ *n = env->n - 1;
+ *t = 0;
+ }
+ if (*t == 0) return env->val[*n];
+
+ d = (env->len[*n] == 0) ? 0 : (double)*t / (double)env->len[*n];
+ v1 = env->val[*n];
+ v2 = env->val[*n + 1];
+ if ((env->flags & EFHold) && hold && (*n == env->hold[1]))
+ v2 = env->val[env->hold[0]];
+ if ((env->flags & EFLoop) && (*n == env->loop[1]))
+ v2 = env->val[env->loop[0]];
+ return v1 * (1 - d) + v2 * d;
+}
+
+double
+wfosc(s16int *wf, double T)
+{
+ double t = fmod(T, 1) * WFSize;
+ int n = floor(t);
+ 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) / (double)(0x7fff);
+}
+
+double
+wtosc(s16int *wt, double C, double T)
+{
+ int n;
+ double d, v1, v2;
+ n = floor(C);
+ d = fmod(C, 1);
+ if (n >= WTSize) {
+ n = WTSize - 1;
+ d = 1;
+ }
+ v1 = wfosc(wt + (n * WFSize), T);
+ v2 = wfosc(wt + ((n + 1) * WFSize), T);
+ return v1 * (1 - d) + v2 * d;
+}
diff --git a/src/wave/wavetable.h b/src/wave/wavetable.h
@@ -0,0 +1,36 @@
+enum {
+ EFHold = 1,
+ EFLoop = 2,
+ WFSize = 2048,
+ WTSize = 256,
+ EnvSize = 64,
+};
+
+typedef struct Env Env;
+typedef struct Inst Inst;
+typedef struct Voice Voice;
+
+struct Env {
+ int n;
+ int flags;
+ int hold[2];
+ int loop[2];
+ int val[EnvSize];
+ int len[EnvSize];
+};
+
+double envget(Env *, int *, int *, int);
+
+struct Inst {
+ s16int *wt;
+ Env wtenv, ampenv; // ???
+};
+
+struct Voice {
+ Inst *inst;
+ double freq;
+ double wtet, ampet; // ???
+};
+
+double wfosc(s16int *, double);
+double wtosc(s16int *, double, double);