ref: 7adfd4ca6b951bcc17d3c636bb810876c159950a
dir: /p-wavegen.c/
#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; }