#include #include #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; }