shithub: prismriver

ref: 7adfd4ca6b951bcc17d3c636bb810876c159950a
dir: /p-wavegen.c/

View raw version
#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, double freq, ulong *pc, 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, freq, c + (pc == nil ? 0 : *pc));

	if(d)
		destroywavegen(gen);

	if(pc != nil)
		*pc += sz;

	return buf;
}

/** Simple Waveforms **/

typedef struct
{
	Wavegen;
	double (*wavefn)(double);
	double amp, phase;
} Waveprops;

Stuple
waveformfn(Wavegen *w, double freq, ulong t)
{
	Waveprops *p = (Waveprops*)w;
	double v	= p->amp * p->wavefn(s2d(t) * freq + p->phase);
	sample val	= truncate(v);
	return (Stuple)
	{
		val, val
	};
}

Wavegen*
waveform(double (*fn)(double), double amp, double φ)
{
	Waveprops *p = emallocz(sizeof(Waveprops));
	p->fn		= waveformfn;
	p->destroy 	= (void(*)(Wavegen*))free;
	p->wavefn	= fn;
	p->amp		= amp;
	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;
}

/** PCM-backed wave "generators" **/

typedef struct
{
	Wavegen;
	Buffer *buf;
} Pcmprops;

Stuple
pcmfn(Wavegen *w, double freq, ulong t)
{
	(void)freq;
	Pcmprops *p = (Pcmprops*)w;
	if(t < p->buf->size)
		return p->buf->data[t];
	return (Stuple) { 0, 0 };
}

void
pcmdestroy(Wavegen *w)
{
	Pcmprops *p = (Pcmprops*)w;
	destroybuffer(p->buf);
	free(p);
}

Wavegen*
pcm(Buffer *buf)
{
	Pcmprops *p = emallocz(sizeof(*p));
	p->fn		= pcmfn;
	p->destroy	= pcmdestroy;
	p->buf		= buf;
	return p;
}

/** Unison **/

typedef struct
{
	Wavegen;
	Wavegen *gen;
	uint voices;
	double pitchΔ, phaseΔ;
} Unisonprops;

Stuple
unisonfn(Wavegen *w, double freq, ulong t)
{
	Unisonprops *p = (Unisonprops*)w;
	Stuple ret = (Stuple) { 0, 0 };
	int voices = p->voices;
	for(int c = 0; c < voices; c++)
	{
		Stuple r = p->gen->fn(p->gen, freq * p->pitchΔ * c, t);
		ret.l += r.l/voices;
		ret.r += r.r/voices;
	}
	return ret; 
}

void
unisoncleanup(Wavegen *w)
{
	Unisonprops *p = (Unisonprops*)w;
	destroywavegen(p->gen);
	free(p);
}

Wavegen*
unison(Wavegen *gen, uint voices, double pitchvar, double phasevar)
{
	Unisonprops *p = emallocz(sizeof(*p));
	p->fn		= unisonfn;
	p->destroy	= unisoncleanup;
	p->gen		= gen;
	p->voices	= voices;
	p->pitchΔ	= pitchvar;
	p->phaseΔ	= phasevar;
	return p;
}