shithub: prismriver

Download patch

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);