ref: 72ed94b46fa454fce4edfc2396cb0becee5bdb00
author: Tevo <[email protected]>
date: Sun Aug 30 16:16:54 EDT 2020
Initial rewrite
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,16 @@
+</$objtype/mkfile
+
+LIB=/$objtype/lib/libprismriver.a
+
+OFILES=\
+ p-pcm.$O \
+ p-utils.$O \
+ p-wavegen.$O
+
+HFILES=\
+ /sys/include/prismriver.h
+
+/sys/include/%.h: %.h
+ cp $stem.h /sys/include/$stem.h
+
+</sys/src/cmd/mksyslib
--- /dev/null
+++ b/p-internal.h
@@ -1,0 +1,31 @@
+
+static const double π = 3.1415926;
+
+static void*
+emallocz(ulong s)
+{
+ void *p = mallocz(s, 1);
+ if(p == nil)
+ sysfatal("mallocz: %r");
+ return p;
+}
+
+static void*
+erealloc(void *p, ulong s)
+{
+ p = realloc(p, s);
+ if(p == nil)
+ sysfatal("realloc: %r");
+ return p;
+}
+
+static sample
+truncate(double val)
+{
+ if(val > 1.0)
+ val = 1.0;
+ else if(val < -1.0)
+ val = -1.0;
+ /* FIXME this is off by 1 when val == -1 */
+ return (sample)(val * SAMPLE_MAX);
+}
--- /dev/null
+++ b/p-pcm.c
@@ -1,0 +1,38 @@
+#include <u.h>
+#include <libc.h>
+
+#include "prismriver.h"
+#include "p-internal.h"
+
+Buffer*
+createbuffer(ulong s)
+{
+ /* This could be a big contiguous area instead if you really need to
+ * save a malloc invocation
+ */
+ Buffer *b = emallocz(sizeof(Buffer));
+ b->size = s;
+ b->data = emallocz(s * sizeof(STuple));
+ return b;
+}
+
+Buffer*
+resizebuffer(Buffer *b, ulong ns)
+{
+ b->data = erealloc(b->data, ns * sizeof(STuple));
+ b->size = ns;
+ return b;
+}
+
+void
+destroybuffer(Buffer *b)
+{
+ free(b->data);
+ free(b);
+}
+
+void
+play(Buffer *b, int fd)
+{
+ write(fd, b->data, b->size * sizeof(STuple));
+}
--- /dev/null
+++ b/p-utils.c
@@ -1,0 +1,55 @@
+#include <u.h>
+#include <libc.h>
+
+#include "prismriver.h"
+#include "p-internal.h"
+
+enum
+{
+ C,
+ Db, // C#
+ D,
+ Eb, // D#
+ E,
+ F,
+ Gb, // F#
+ G,
+ Ab, // G#
+ A,
+ Bb, // A#
+ B
+};
+
+const double equaltemperament[] =
+{
+ [C] = 16.35,
+ [Db] = 17.32,
+ [D] = 18.35,
+ [Eb] = 19.45,
+ [E] = 20.60,
+ [F] = 21.83,
+ [Gb] = 23.12,
+ [G] = 24.50,
+ [Ab] = 25.96,
+ [A] = 27.50,
+ [Bb] = 29.14,
+ [B] = 30.87
+};
+
+double
+pitch(uint n, int o)
+{
+ return equaltemperament[n % 12] * pow(2, o + n/12);
+}
+
+ulong /* Duration (seconds) to samples */
+d2s(double d)
+{
+ return d * SAMPLE_RATE;
+}
+
+double /* Samples to duration (seconds) */
+s2d(ulong s)
+{
+ return (double)s / SAMPLE_RATE;
+}
--- /dev/null
+++ b/p-wavegen.c
@@ -1,0 +1,90 @@
+#include <u.h>
+#include <libc.h>
+
+#include "prismriver.h"
+#include "p-internal.h"
+
+void
+destroywavegen(Wavegen *gen)
+{
+ gen->destroy(gen);
+}
+
+Buffer*
+buffermap(Buffer *buf, Wavegen *gen, int d, ulong s, ulong sz)
+{
+ if(buf == nil)
+ buf = createbuffer(s + sz);
+
+ for(ulong c = s; c < sz; c++)
+ buf->data[c] = gen->fn(gen, c);
+
+ if(d)
+ destroywavegen(gen);
+
+ return buf;
+}
+
+/** Simple Waveforms **/
+
+typedef struct
+{
+ Wavegen;
+ double (*wavefn)(double);
+ double amp, freq, phase;
+} Waveprops;
+
+STuple
+waveformfn(Wavegen *w, ulong t)
+{
+ Waveprops *p = (Waveprops*)w;
+ double v = p->amp * p->wavefn(s2d(t) * p->freq + p->phase);
+ sample val = truncate(v);
+ return (STuple)
+ {
+ val, val
+ };
+}
+
+Wavegen*
+waveform(double (*fn)(double), double amp, double freq, double φ)
+{
+ Waveprops *p = emallocz(sizeof(Waveprops));
+ p->fn = waveformfn;
+ p->destroy = (void(*)(Wavegen*))free;
+ p->wavefn = fn;
+ p->amp = amp;
+ p->freq = freq;
+ p->phase = φ;
+ return p;
+}
+
+double
+sine(double num)
+{
+ return sin(2 * π * num);
+}
+
+double
+saw(double num)
+{
+ return 2 * (num - (int)num) - 1;
+}
+
+double
+pulse(double num, double threshold)
+{
+ return saw(num) < threshold ? -1.0 : 1.0;
+}
+
+double
+square(double num)
+{
+ return pulse(num, 0);
+}
+
+double
+triangle(double num)
+{
+ return 2 * fabs(saw(num)) - 1;
+}
--- /dev/null
+++ b/prismriver.h
@@ -1,0 +1,52 @@
+#pragma lib "libprismriver.a"
+
+typedef short sample;
+
+static const ulong SAMPLE_MAX = 32767;
+static const ulong SAMPLE_MIN = -32768;
+static const ulong SAMPLE_RATE = 44100;
+
+typedef struct
+{
+ sample l, r;
+} STuple;
+
+/** PCM API **/
+
+typedef struct
+{
+ ulong size;
+ STuple *data;
+} Buffer;
+
+Buffer* createbuffer(ulong size);
+Buffer* resizebuffer(Buffer *buf, ulong newsize);
+void destroybuffer(Buffer *buf);
+
+void play(Buffer *buf, int fd);
+
+/** Wave generators **/
+
+typedef struct Wavegen
+{
+ STuple (*fn)(struct Wavegen*, ulong);
+ void (*destroy)(struct Wavegen*);
+} Wavegen;
+
+void destroywavegen(Wavegen *gen);
+
+Buffer* buffermap(Buffer *buf, Wavegen *gen, int d, ulong s, ulong sz);
+
+Wavegen* waveform(double (*fn)(double), double amp, double freq, double φ);
+
+double sine(double);
+double saw(double);
+double square(double);
+double triangle(double);
+
+/** Utilities **/
+
+double pitch(uint note, int octave);
+
+ulong d2s(double seconds);
+double s2d(ulong samples);