102 lines
2.6 KiB
Plaintext
102 lines
2.6 KiB
Plaintext
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 ###
|
|
|
|
![](/articles/oscillators/sine.gif)
|
|
|
|
```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 ###
|
|
|
|
![](/articles/oscillators/sqrt.gif)
|
|
|
|
```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);
|
|
v.f = r.w.s;
|
|
a.f = amplitude;
|
|
r.v.u = (a.u & 0x7fffffff) | (v.u & 0x80000000);
|
|
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 ###
|
|
|
|
![](/articles/oscillators/sawt.gif)
|
|
|
|
```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 = 2.f * 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 * 2.f;
|
|
}
|
|
|
|
```
|
|
|
|
### Edits ###
|
|
- Fixed initial value based on phase in sqrtwave, proper range for sawtwave.
|
|
- Added waveform gifs.
|