oscillators article

This commit is contained in:
veclav talica 2023-05-22 14:43:09 +05:00
parent a4bfe111cf
commit ef17694125

View File

@ -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;
}
```