stew

a monorepo of some sort
Log | Files | Refs

commit 78c02efce9ae30194bcbf675e946ba48f5500def
parent 929b9460ccadc21e0b41ee5e787a11eb82319089
Author: rpa <rpa@laika>
Date:   Thu,  5 Jan 2023 21:41:18 +0000

wave: some code?

Diffstat:
Msrc/wave/mkfile | 5+++--
Msrc/wave/notes | 17+++++++++++++++++
Msrc/wave/piano.c | 4----
Msrc/wave/sampler.c | 89+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Asrc/wave/wavetable.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/wave/wavetable.h | 36++++++++++++++++++++++++++++++++++++
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);