From ef176941257ca7ebe33d8fb78cdfbc54463c7547 Mon Sep 17 00:00:00 2001 From: veclav talica Date: Mon, 22 May 2023 14:43:09 +0500 Subject: [PATCH] oscillators article --- articles/oscillators/page.mmd | 89 +++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 articles/oscillators/page.mmd diff --git a/articles/oscillators/page.mmd b/articles/oscillators/page.mmd new file mode 100644 index 0000000..db17af3 --- /dev/null +++ b/articles/oscillators/page.mmd @@ -0,0 +1,89 @@ +Title: Programmatic Oscillators +Brief: Sine, cosine, saw and square oscillators with minimal binary footprint. +Date: 1684748529 +Tags: Programming, Music, C +CSS: /style.css + +Wanted to have some beep bops for my [4mb-jam](https://itch.io/jam/4mb-jam-2023) entry, so +I ended up with implementations of three oscillators that would require minimal amount of calculations. + +Idea is to precalculate initial state offline and only have short frame generation procedure in final binary. +Thinking about using it in tracker format of sorts that would have runtime generated samples. + +Inspirations are taken from [musicdsp](https://www.musicdsp.org/). + +### Sine/Cosine ### + +```c +/* Intended to be executed offline with values then embedded in the binary. + * By having usage of glibc sin and cos functions strictly offline it's easier to have it freestanding + */ +struct sinewave { + float f, s, c; +} init_sinewave(float frequency, float phase, float amplitude) { + struct sinewave r; + r.f = 2.f * sinf((float)M_PI * frequency / AUDIO_FRAME_RATE); + r.s = amplitude * sinf(phase); + r.c = amplitude * cosf(phase); + return r; +} + +/* Use `s` for sine value and `c` for cosine on caller side */ +void pump_sinewave(struct sinewave *wave) { + wave->s -= wave->f * wave->c; + wave->c += wave->f * wave->s; +} + +``` + +### Square ### + +```c +/* Implemented over sinewave */ +struct sqrtwave { + struct sinewave w; + union { + float f; + uint32_t u; + } v; +} init_sqrtwave(float frequency, float phase, float amplitude) { + struct sqrtwave r; + r.w = init_sinewave(frequency, phase, 1.f); + r.v.f = amplitude; + return r; +} + +/* Use floating point bit representation to infer sign, all other bits are set to amplitude */ +void pump_sqrtwave(struct sqrtwave *wave) { + union { + float f; + uint32_t u; + } v; + pump_sinewave(&wave->w); + v.f = wave->w.s; + wave->v.u = (wave->v.u & 0x7fffffff) | (v.u & 0x80000000); +} + +``` + +### Saw ### + +```c +struct sawtwave { + float v, a, i; +} init_sawtwave(float frequency, float phase, float amplitude) { + struct sawtwave r; + r.v = sinf(phase) * amplitude; + r.a = amplitude; + r.i = frequency / AUDIO_FRAME_RATE * amplitude; + return r; +} + +/* Simple amplitude overflow check with truncation */ +void pump_sawtwave(struct sawtwave *wave) { + wave->v += wave->i; + if (wave->v > wave->a) + wave->v -= wave->a; +} + +```