rodeo_dsp.h
Generated from the header
This page is rodeo-sdk/common/rodeo_dsp.h — its comments and declarations.
To change it, change the header.
Same philosophy as adc_convert.h and pot_ui.h: pure math and state, no libDaisy, no hardware, so it builds and is tested on the host and the firmware calls THESE functions rather than a reimplementation of them.
Written for rodeo-002 and moved here on 2026-10-01 because none of it is about a synthesiser. rodeo-001 had already hand-rolled its own one-pole smoother inline in main.cpp, which is the duplication this prevents the third instrument from repeating.
A note on what is NOT here: anything that needs a sample rate at construction. Every type takes its rate in Init(), so one header serves an audio-rate and a block-rate user in the same build — which matters, because getting that wrong is exactly how rodeo-002’s LFO ended up running 48x slow (initialised at the audio rate, ticked once per block).
kPi
constexpr float kPi = 3.14159265358979f;kTwoPi
constexpr float kTwoPi = 2.f * kPi;Clamp
inline float Clamp(float x, float lo, float hi);ExpMap
inline float ExpMap(float t, float lo, float hi);Exponential map of t in 0..1 onto lo..hi (lo > hi works too). Control rate.
TimeCoeff
inline float TimeCoeff(float seconds, float sample_rate);One-pole coefficient for a time constant in seconds. Control rate.
FreqCoeff
inline float FreqCoeff(float hz, float sample_rate);One-pole coefficient for a cutoff frequency in Hz. Control rate.
FastTanh
inline float FastTanh(float x);Padé tanh: within ~2% of tanhf, exactly +/-1 beyond +/-3, and continuous there. Several times cheaper than tanhf, which matters per sample.
FastSin01
inline float FastSin01(float p);sin(2pip) for p in [0, 1), parabolic approximation (~0.1% error).
Rng
struct Rngxorshift32 — deterministic, lock-free, and far cheaper than rand().
Members
uint32_t state = 0x9E3779B9u
Rng::Seed
void Seed(uint32_t s);Rng::Next
uint32_t Next();Rng::Uniform
float Uniform();0..1
Rng::Bipolar
float Bipolar();-1..1
Smoother
struct SmootherPer-sample one-pole smoother for control values. Set() the target from the control rate, Next() once per sample. Kills zipper noise from pots that only update ~100 times a second.
Members
float cur = 0.ffloat cur = 0.f, target = 0.ffloat cur = 0.f, target = 0.f, coeff = 0.01f
Smoother::Init
void Init(float sample_rate, float seconds, float value);Smoother::Set
void Set(float v);Smoother::Snap
void Snap(float v);Smoother::Next
float Next();Smoother::Settled
bool Settled(float eps = 1e-4f) const;OnePole
struct OnePoleOne-pole low-pass. The high-pass is x - Lp(x).
Members
float y = 0.ffloat y = 0.f, a = 1.f
OnePole::SetFreq
void SetFreq(float hz, float sample_rate);OnePole::Reset
void Reset();OnePole::Lp
float Lp(float x);OnePole::Hp
float Hp(float x);DcBlocker
struct DcBlockerDC blocker (~7 Hz at 48 kHz). Waveshapers with a bias offset make DC.
Members
float x1 = 0.ffloat x1 = 0.f, y1 = 0.f
DcBlocker::Reset
void Reset();DcBlocker::Process
float Process(float x);Lfo
class LfoTwo-phase LFO with the four Movement shapes. One phase accumulator; the second output is offset by a fraction of a cycle (stereo width, autopan).
Lfo::Shape
enum ShapekSine = 0kTrianglekSquarekRandomkNumShapes
Lfo::Init
void Init(float sample_rate);Lfo::ShapeName
static const char* ShapeName(int s);Lfo::SetFreq
void SetFreq(float hz);Lfo::SetShape
void SetShape(int s);Lfo::Process
void Process(float offset, float* a, float* b);Advance one sample. Writes bipolar (-1..1) values for phase and phase + offset (offset in cycles, 0..1).
ToneMeter
class ToneMeterPeak level and frequency of a test tone, measured over a fixed window. For loopback checks: send a known tone out, run what comes back through this, and compare. Frequency is counted from rising zero crossings, with hysteresis so noise near zero doesn’t count, and timed first crossing to last for better than 1/window resolution. A window with fewer than two crossings reports 0 Hz.
ToneMeter::Init
void Init(float sample_rate, float window_seconds = 0.5f, float hysteresis = 0.02f);ToneMeter::Process
bool Process(float x);One sample in. True when a window has just finished and Peak()/Hz() hold its results; they keep them until the next window finishes.
ToneMeter::Peak
float Peak() const;ToneMeter::Hz
float Hz() const;