stfu/Source/oscillators.c
2024-06-13 16:43:53 +05:00

79 lines
2.0 KiB
C

#include <math.h>
#include <stdint.h>
#include "config.h"
/* https://multimed.org/student/eim/en/04-FM.pdf */
/* 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 stfu_sinewave {
float f, s, c;
} stfu_init_sinewave(float frequency, float phase, float amplitude) {
struct stfu_sinewave r;
r.f = 2.f * sinf((float)M_PI * frequency / STFU_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 */
struct stfu_sinewave stfu_pump_sinewave(struct stfu_sinewave wave) {
wave.s -= wave.f * wave.c;
wave.c += wave.f * wave.s;
return wave;
}
/* Implemented over sinewave */
struct stfu_sqrtwave {
struct stfu_sinewave w;
union {
float f;
uint32_t u;
} v;
} stfu_init_sqrtwave(float frequency, float phase, float amplitude) {
struct stfu_sqrtwave r;
union {
float f;
uint32_t u;
} v, a;
r.w = stfu_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 */
struct stfu_sqrtwave stfu_pump_sqrtwave(struct stfu_sqrtwave wave) {
union {
float f;
uint32_t u;
} v;
stfu_pump_sinewave(wave.w);
v.f = wave.w.s;
wave.v.u = (wave.v.u & 0x7fffffff) | (v.u & 0x80000000);
return wave;
}
struct stfu_sawtooth {
float v, a, i;
} stfu_init_sawtooth(float frequency, float phase, float amplitude) {
struct stfu_sawtooth r;
r.v = sinf(phase) * amplitude;
r.a = amplitude;
r.i = 2.f * frequency / STFU_AUDIO_FRAME_RATE * amplitude;
return r;
}
/* Simple amplitude overflow check with truncation */
struct stfu_sawtooth stfu_pump_sawtooth(struct stfu_sawtooth wave) {
wave.v += wave.i;
if (wave.v > wave.a)
wave.v -= wave.a * 2.f;
return wave;
}