79 lines
2.0 KiB
C
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;
|
|
}
|