stew

a monorepo of some sort
Log | Files | Refs

commit ef4624e45334281860e4b8666626bd9f1a1d2108
parent 95a6c58dc965c7bbce03bf9d3e2a0100bce816f1
Author: glenda <glenda@device>
Date:   Mon, 24 Oct 2022 21:10:40 +0000

add src/mu

Diffstat:
Asrc/mu/mkfile | 8++++++++
Asrc/mu/mubox.c | 273+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/mu/throttle.c | 38++++++++++++++++++++++++++++++++++++++
Asrc/mu/tplay | 3+++
Asrc/mu/track | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/mu/track2 | 35+++++++++++++++++++++++++++++++++++
Asrc/mu/trk.c | 33+++++++++++++++++++++++++++++++++
7 files changed, 442 insertions(+), 0 deletions(-)

diff --git a/src/mu/mkfile b/src/mu/mkfile @@ -0,0 +1,8 @@ +</$objtype/mkfile + +TARG=trk mubox throttle + +</sys/src/cmd/mkmany + +test:V: $O.trk $O.mubox track + $O.trk < track | $O.mubox -r > /dev/audio diff --git a/src/mu/mubox.c b/src/mu/mubox.c @@ -0,0 +1,273 @@ +/* simplistic audio synth, + - 6-voice polyphony, 1 noise channel, 1 kick channel + - only triangle osc, only freq, vol and decay ctls + - controlled via stdin */ + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <thread.h> + +#define MaxArgs 32 +#define BSize 441 + +typedef struct Voice Voice; +struct Voice { + double stime; + double freq; + double amplitude; + double volume; + double decay; + double bend; +}; + +enum { + VKick = 6, + VNoise = 7, +}; + +Voice v[8], vv, *vp; +double T, mix[2]; +Biobuf *in; +int out; + +int realtime; + +/* + * Frequencies for equal-tempered scale + * from https://pages.mtu.edu/~suits/notefreqs.html + */ + +struct { + char *s; + double f; +} notes[12] = { + {"C-", 261.63}, + {"C#", 277.18}, + {"D-", 293.66}, + {"D#", 311.13}, + {"E-", 329.63}, + {"F-", 349.23}, + {"F#", 369.99}, + {"G-", 392.0 }, + {"G#", 415.30}, + {"A-", 440.0 }, + {"A#", 466.16}, + {"B-", 493.88}, +}; + +Voice * +newvoice(double freq) +{ + static int n = 0; + n = (n + 1) % 6; + v[n] = vv; + v[n].amplitude = 1; + v[n].stime = T; + v[n].freq = freq; + return &v[n]; +} + +int +note(char *s) +{ + int i, oct; + if ((s[2] < '0') || (s[2] > '9')) return -1; + oct = atoi(s+2) - 4; + for (i = 0; i < 12; i++) { + if (strncmp(s, notes[i].s, 2) == 0) { + double freq = notes[i].f; + while (oct < 0) { + freq = freq / 2; + oct++; + } + while (oct > 0) { + freq = freq * 2; + oct--; + } + vp = newvoice(freq); + return 0; + } + } + return -1; +} + +void +cmd(char *s) +{ + ulong i; + double f; + if (note(s) != 0) switch(s[0]) { + // noise channel commands + case 'N': + i = strtoul(s+1, nil, 16); + v[VNoise].volume = (double)i / 256.0; + v[VNoise].amplitude = 1; + break; + case 'n': + i = strtoul(s+1, nil, 16); + v[VNoise].decay = (double)i / 256.0; + break; + + // kick channel commands + case 'k': + v[VKick].stime = T; + v[VKick].freq = 200; + v[VKick].amplitude = 1; + break; + + // voice channel commands + case 'f': // freq + f = atof(s+1); + vp->freq = f; + vv.freq = f; + break; + case 'b': // bend + f = atof(s+1); + vp->bend = f; + vv.bend = f; + break; + case 'd': // decay; + f = atof(s+1); + vp->decay = f; + vv.decay = f; + break; + case 'v': + f = atof(s+1); + vp = newvoice(f); + break; + } +} + +void +threadread(void *) +{ + for (;;) { + char *s = Brdstr(in, '\n', 1); + if (s == nil) threadexitsall(nil); + char *args[MaxArgs]; + int n = tokenize(s, args, MaxArgs); + int i; + for (i = 0; i < n; i++) cmd(args[i]); + free(s); + } +} + +double +tri(double T) +{ + static double env[5] = { 0.0, 1.0, 0.0, -1.0, 0.0 }; + T = 4.0 * (T - floor(T)); + int i = floor(T); + double X = T - i; + return env[i+1] * X + env[i] * (1 - X); +} + +void +voice(Voice *v) +{ + double x = tri((T - v->stime) * v->freq) * v->amplitude * v->volume; + mix[0] += x; + mix[1] += x; +} + +void +noise(void) +{ + mix[0] += (1 - frand() * 2) * v[VNoise].amplitude * v[VNoise].volume; + mix[1] += (1 - frand() * 2) * v[VNoise].amplitude * v[VNoise].volume; +} + +void +kick(void) +{ + double x = sin(2.0 * PI * (T - v[VKick].stime) * v[VKick].freq) * v[VKick].amplitude * v[VKick].volume; + mix[0] += x; + mix[1] += x; +} + +void +modvoice(Voice *v) +{ + v->amplitude -= v->decay; + v->freq *= v->bend; + if (v->amplitude < 0) v->amplitude = 0; + if (v->freq < 0) v->freq = 0; +} + +void +output(void) +{ + s16int buf[BSize * 2]; + int i; + for (i = 0; i < BSize; i++) { + mix[0] = 0; + mix[1] = 0; + voice(&v[0]); + voice(&v[1]); + voice(&v[2]); + voice(&v[3]); + voice(&v[4]); + voice(&v[5]); + noise(); + kick(); + buf[i * 2] = 0x7fff * (mix[0] / 8); + buf[i * 2 + 1] = 0x7fff * (mix[1] / 8); + T += 1.0/44100.0; + } + for (i = 0; i < 8; i++) modvoice(&v[i]); + write(out, buf, BSize * 4); + //Dir *d = dirfstat(out); + //fprint(2, "%lld\n", d->length); + //free(d); +} + +void +usage(void) +{ + fprint(2, "usage: %s [-r]\n", argv0); + threadexitsall("usage"); +} + +void +threadmain(int argc, char **argv) +{ + ARGBEGIN { + case 'r': + realtime = 1; + break; + default: + usage(); + } ARGEND; + if (argc != 0) usage(); + v[VKick] = (Voice) { + 0, + 200, + 0, + 1, + 0.25, + 25.45/255.0, + }; + v[VNoise].decay = 1; + vv = (Voice) { + 0, + 440, + 1, + 1, + 0, + 1, + }; + + in = Bfdopen(0, OREAD); + // out = open("/dev/audio", OWRITE); + out = 1; + vp = &v[1]; + proccreate(threadread, nil, 1024 * 1024 * 64); + + vlong t = nsec() / 1000000; + for (;;) { + output(); + t += 10; + if (realtime != 0) sleep(t - (nsec() / 1000000)); + } +} diff --git a/src/mu/throttle.c b/src/mu/throttle.c @@ -0,0 +1,38 @@ +#include <u.h> +#include <libc.h> + +void +usage(void) +{ + fprint(2, "usage: %s [-t millisec] [-b bytes]\n", argv0); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + long b = 44 * 4; + long t = 1; + long T; + char *buf; + ARGBEGIN{ + case 't': + t = strtol(EARGF(usage()), nil, 10); + break; + case 'b': + b = strtol(EARGF(usage()), nil, 10); + break; + default: + usage(); + }ARGEND + + buf = sbrk(b); + long n; + T = nsec() / 1000000; + while ((n = read(0, buf, b)) > 0) { + write(1, buf, n); + T += t; + sleep(T - (nsec()/1000000)); + } + if (n != 0) fprint(2, "%r\n"); +} diff --git a/src/mu/tplay b/src/mu/tplay @@ -0,0 +1,3 @@ +#!/bin/rc +rfork e +6.trk | 6.mubox -r > /dev/audio diff --git a/src/mu/track b/src/mu/track @@ -0,0 +1,52 @@ +k + +k + +k + +n02 N1f + +############## +n04 N7f k v110 d0.01 +n08 N1f v110 +n04 N3f k v110 v220 v330 +n08 N1f v110 +n02 N5f k v220 +n08 N1f v440 +n04 N3f v110 +n08 N1f v220 +n04 N7f k v550 +n08 N1f v110 +n04 N3f k v220 +n04 N3f v440 +n02 N5f k v110 +n08 N1f v220 +n04 N3f v330 +n08 N1f v440 +############## +n04 N7f k v110 +n08 N1f v110 +n04 N3f k v220 v165 v110 +n08 N1f v330 +n02 N5f k v110 +n08 N1f v165 +n04 N3f v330 +n08 N1f v220 +n04 N7f k v440 +n08 N1f v110 +n04 N3f k v330 +n04 N3f v110 +n02 N5f k v220 +n08 N1f v110 +n04 N3f v165 +n08 N1f v330 +############## +v220 k +v110 +v55 k +v27 +v13 k + + + +# END diff --git a/src/mu/track2 b/src/mu/track2 @@ -0,0 +1,35 @@ +#C-2 C-5 k +#C#5 k +#E-5 N4f n02 +#F-5 k +#G-5 k +# +#N4f +# +# END +k + +k + +k + +k + +b0.999999 C-4 d0.01 k N3f n0f +C-5 d0.01 N3f +D#5 d0.01 N3f +F-5 d0.01 N3f +G-5 d0.01 N7f n08 +N3f n0f +A#5 k N3f +N3f +G-5 N3f +N3f +F-5 N3f +N3f +G-5 N7f n08 +N2f n0f +k N1f +N1f + +# END diff --git a/src/mu/trk.c b/src/mu/trk.c @@ -0,0 +1,33 @@ +/* read lines from stdin and print them at specified rate */ + +#include <u.h> +#include <libc.h> +#include <bio.h> + +void +cmd(char *) +{ +} + +void +main(void) +{ + vlong t; + Biobuf *in; + in = Bfdopen(0, OREAD); + t = nsec(); + for (;;) { + char *s = Brdstr(in, '\n', 1); + if (s == nil) break; + else if (s[0] == ':'); // labels + else if (s[0] == '.') cmd(s); // commands + else if (s[0] != '#'){ + t += 1000000000 / 4; + // fprint(2, "%lld ", t - nsec()); + print("%s\n", s); + + sleep((t - nsec()) / 1000000); + } + free(s); + } +}