Sound Byte Libs 0.5.1-121-g3358a44
C++ firmware library for audio applications on 32-bit ARM Cortex-M processors
Loading...
Searching...
No Matches
sbl::dsp::math Namespace Reference

Cross-cutting math used at every audio layer. More...

Detailed Description

Cross-cutting math used at every audio layer.

Functions

constexpr float clamp (float x, float lo, float hi)
 x held to [lo, hi]; NaN → lo.
 
constexpr float clamp01 (float x)
 x held to [0, 1]; NaN → 0.
 
float exp_mod (float base, float mod, float depth, float lo=20.0f, float hi=20000.0f)
 
void exp_mod_block (const float *mod, float *freq_out, uint16_t n, float base, float depth, float lo=20.0f, float hi=20000.0f)
 
float fast_sinf (float x)
 
float fast_tan_pif (float f)
 
float fast_exp2f (float x)
 
float fast_tanhf (float x)
 
float su_to_hz (float su, float min_hz, float octaves)
 
constexpr float one_minus_exp_neg (float x)
 
constexpr float crossfade (float a, float b, float t)
 Linear crossfade between two values.
 
constexpr float smooth_step (float t)
 Hermite smooth step (3rd-order S-curve)
 
constexpr int32_t crossfade_i16 (int16_t a, int16_t b, uint16_t t)
 Integer crossfade for 16-bit values.
 
float crossfade_equal_power (float a, float b, float t)
 Equal-power crossfade between two values.
 
void crossfade_block (const float *a, const float *b, float *out, float mix, uint16_t frames)
 Linear crossfade over a block with constant mix.
 
void crossfade_block_equal_power (const float *a, const float *b, float *out, float mix, uint16_t frames)
 Equal-power crossfade over a block with constant mix.
 
constexpr float cc_to_float (uint8_t val)
 Normalize MIDI CC (0-127) to [0.0, 1.0].
 
constexpr float u16_to_float (uint16_t val)
 Normalize 16-bit unsigned (0-65535) to [0.0, 1.0].
 
constexpr float u14_to_float (uint16_t val)
 Normalize 14-bit MIDI (0-16383) to [0.0, 1.0] (pitch bend, NRPN)
 
constexpr float map_linear (float t, float min, float max)
 Linear mapping: t → min + (max - min) * t.
 
constexpr float map_quadratic (float t, float min, float max)
 
constexpr float map_scurve (float t, float min, float max)
 
constexpr float map_inv_quadratic (float t, float min, float max)
 
float map_exponential (float t, float min, float max)
 
float semitones_to_ratio (float semitones)
 
float semitones_to_ratio_safe (float semitones)
 
float note_to_ratio (float midi_note)
 
float note_to_frequency (float midi_note)
 MIDI note to frequency in Hz. A4 = 440 Hz.
 
uint32_t note_to_phase_increment (float midi_note, float sample_rate)
 
constexpr float note_of_su (float su)
 
constexpr float su_of_note (float note)
 

Variables

constexpr float PI = 3.14159265358979323846f
 
constexpr float TWO_PI = 2.0f * PI
 
constexpr float HALF_PI = 0.5f * PI
 
constexpr float PHASE_ACCUMULATOR_RANGE = 4294967296.0f
 The phase accumulator's full range: uint32_t [0, 2^32) is one cycle.
 
constexpr float PITCH_SU_MIN_NOTE = 24.0f
 
constexpr float PITCH_SU_MAX_NOTE = 120.0f
 
constexpr float PITCH_SU_NOTE_RANGE = PITCH_SU_MAX_NOTE - PITCH_SU_MIN_NOTE
 

Function Documentation

◆ clamp()

◆ clamp01()

◆ exp_mod()

float sbl::dsp::math::exp_mod ( float  base,
float  mod,
float  depth,
float  lo = 20.0f,
float  hi = 20000.0f 
)
inline

Apply exponential modulation to a base frequency (scalar).

Converts a normalized modulation signal to a frequency via: freq = base * 2^(mod * depth)

At depth = 2.0 and mod = 1.0, output is base * 4 (2 octaves up). At depth = 2.0 and mod = -1.0, output is base / 4 (2 octaves down). The relationship is perceptually uniform — equal mod deltas produce equal musical intervals regardless of the base frequency.

Parameters
baseCenter frequency in Hz (e.g., filter cutoff)
modNormalized modulation value, typically [-1.0, 1.0]
depthModulation depth in octaves (e.g., 2.0 = ±2 octaves)
loMinimum output frequency in Hz (default 20)
hiMaximum output frequency in Hz (default 20000)
Returns
Modulated frequency in Hz, clamped to [lo, hi]

Definition at line 50 of file exp_mod.hpp.

References fast_exp2f().

Referenced by exp_mod_block(), sbl::dsp::modules::Ladder::process(), and sbl::dsp::widgets::Svf::process().

◆ exp_mod_block()

void sbl::dsp::math::exp_mod_block ( const float *  mod,
float *  freq_out,
uint16_t  n,
float  base,
float  depth,
float  lo = 20.0f,
float  hi = 20000.0f 
)
inline

Apply exponential modulation to an entire block (buffer version).

Writes modulated frequencies to freq_out[] for each sample. Use this when you need the frequency buffer for direct coefficient computation (e.g., feeding into a filter's set_cutoff per-sample).

Parameters
modNormalized modulation signal buffer [-1.0, 1.0]
freq_outOutput frequency buffer (Hz)
nFrame count
baseCenter frequency in Hz
depthModulation depth in octaves
loMinimum output frequency in Hz (default 20)
hiMaximum output frequency in Hz (default 20000)

Definition at line 71 of file exp_mod.hpp.

References exp_mod().

◆ fast_sinf()

float sbl::dsp::math::fast_sinf ( float  x)
inline

Fast sine approximation for x in [0, π/2]

Uses 5th-order Taylor series: x - x³/6 + x⁵/120

Accuracy: x = 0.0 → error = 0 x = 0.589 → error < 0.00016 (SVF max at 18 kHz / 48 kHz) x = π/2 → error ≈ 0.00045 (theoretical max in domain)

Parameters
xInput angle in radians, must be in [0, π/2]
Returns
Approximation of sin(x)

Definition at line 41 of file fast_math.hpp.

◆ fast_tan_pif()

float sbl::dsp::math::fast_tan_pif ( float  f)
inline

Fast tan(π·f) for normalized frequency f ∈ [0, 0.497]

[5,4] Padé approximant of tan(x) evaluated at x = π·f:

tan(x) ≈ x · (945 - 105x² + x⁴) / (945 - 420x² + 15x⁴)

Unlike a polynomial, the Padé rational function correctly models the pole at f = 0.5 (Nyquist). The denominator goes to zero at x = π/2, matching the true singularity of tan.

Accuracy vs true tan(π·f): f = 0.10 (4.8 kHz) → error < 0.001% f = 0.35 (16.8 kHz) → error < 0.3% f = 0.45 (21.6 kHz) → error < 2.4% f = 0.497 (23.9 kHz) → error < 0.1%

The previous 5th-order polynomial (from MI stmlib) diverged badly above f ≈ 0.35, giving 45% error at f = 0.45 — causing audible artifacts (secondary resonant peaks) in the ZDF SVF.

Cost: ~8 FMA + 1 VDIV ≈ 20–25 cycles on M7 FPU (vs ~5 for the old polynomial, vs ~50–100 for newlib tanf).

Parameters
fNormalized frequency (freq_hz / sample_rate), must be < 0.497
Returns
Approximation of tan(π·f)

Definition at line 71 of file fast_math.hpp.

References PI.

Referenced by sbl::dsp::widgets::Svf::process().

◆ fast_exp2f()

float sbl::dsp::math::fast_exp2f ( float  x)
inline

Fast 2^x approximation for exponential modulation

Decomposes x into integer and fractional parts. The integer part is applied by shifting the IEEE 754 exponent field (exact). The fractional part uses a 3rd-order minimax polynomial (accurate to ~20 bits).

This is the "exponential converter" primitive — the analog equivalent of the circuit that makes 1V/oct work in a VCF or VCO.

Accuracy (vs std::exp2f): |x| <= 1 → max relative error < 0.02% |x| <= 4 → max relative error < 0.05% |x| > 16 → clamped (returns 0 for x < -16)

Parameters
xExponent (e.g., ±2.0 for ±2 octave modulation)
Returns
Approximation of 2^x

Definition at line 99 of file fast_math.hpp.

Referenced by exp_mod(), map_exponential(), sbl::dsp::modules::MorphOsc< MaxFrames >::process(), sbl::dsp::widgets::PolyBlepOsc::process(), sbl::dsp::comp::Lfo< TableSize >::set_rate_su(), and su_to_hz().

◆ fast_tanhf()

float sbl::dsp::math::fast_tanhf ( float  x)
inline

Fast tanh approximation using [3,2] Padé approximant

tanh(x) ≈ x · (27 + x²) / (27 + 9·x²) for |x| ≤ 3

Same rational function as SoftLimiter::limit() in soft_limiter.hpp, but with input clamping and NaN guard. SoftLimiter is deliberately unbounded (approaches x/9 for large x); this function saturates to ±1.

Accurate to < 1% relative error for |x| < 3, which covers the operating range of the Moog ladder filter (audio signals + moderate drive + feedback). Inputs outside ±3 are clamped to ±1.

Cost: ~8 cycles on M7 FPU (2 MUL, 2 FMA, 1 VDIV).

Parameters
xInput value (any range, clamped for |x| > 3)
Returns
Approximation of tanh(x)

Definition at line 141 of file fast_math.hpp.

Referenced by sbl::dsp::modules::Ladder::process().

◆ su_to_hz()

float sbl::dsp::math::su_to_hz ( float  su,
float  min_hz,
float  octaves 
)
inline

A unipolar signal to a frequency, exponentially: min_hz at 0, min_hz · 2^octaves at 1. The one su-to-Hz map for every cutoff and damping port.

Definition at line 152 of file fast_math.hpp.

References fast_exp2f().

Referenced by sbl::dsp::modules::Ladder::set_cutoff_su(), sbl::dsp::primitives::OnePole::set_cutoff_su(), and sbl::dsp::widgets::Svf::set_cutoff_su().

◆ one_minus_exp_neg()

constexpr float sbl::dsp::math::one_minus_exp_neg ( float  x)
inlineconstexpr

1 − e^(−x) by inverse Taylor, for a one-pole coefficient from a time constant or a cutoff (x = 3/(τ·rate), 4.6/n, ω). Cold path; no expf.

Definition at line 158 of file fast_math.hpp.

Referenced by sbl::dsp::primitives::CriticalDamp::set_time_ms(), and sbl::dsp::primitives::ParameterSmoother::set_time_ms().

◆ crossfade()

constexpr float sbl::dsp::math::crossfade ( float  a,
float  b,
float  t 
)
inlineconstexpr

Linear crossfade between two values.

Parameters
aValue at t=0
bValue at t=1
tBlend factor [0.0, 1.0]
Returns
a + (b - a) * t

Definition at line 26 of file interpolate.hpp.

◆ smooth_step()

constexpr float sbl::dsp::math::smooth_step ( float  t)
inlineconstexpr

Hermite smooth step (3rd-order S-curve)

Maps [0, 1] → [0, 1] with zero derivative at endpoints. Useful for equal-power-like crossfade curves, smooth transitions, and perceptually linear parameter morphing.

Parameters
tInput [0.0, 1.0] (not clamped)
Returns
t² × (3 - 2t)

Definition at line 40 of file interpolate.hpp.

◆ crossfade_i16()

constexpr int32_t sbl::dsp::math::crossfade_i16 ( int16_t  a,
int16_t  b,
uint16_t  t 
)
inlineconstexpr

Integer crossfade for 16-bit values.

Parameters
aValue at t=0
bValue at t=1
tBlend factor [0, 65535] (0 = all a, 65535 = all b)
Returns
Blended value

Definition at line 52 of file interpolate.hpp.

◆ crossfade_equal_power()

float sbl::dsp::math::crossfade_equal_power ( float  a,
float  b,
float  t 
)
inline

Equal-power crossfade between two values.

Maintains constant power across the fade (no dip at t=0.5). Uses sqrt approximation: a*sqrt(1-t) + b*sqrt(t).

Parameters
aValue at t=0 (dry)
bValue at t=1 (wet)
tBlend factor [0.0, 1.0]

Definition at line 68 of file interpolate.hpp.

◆ crossfade_block()

void sbl::dsp::math::crossfade_block ( const float *  a,
const float *  b,
float *  out,
float  mix,
uint16_t  frames 
)
inline

Linear crossfade over a block with constant mix.

out[i] = a[i] * (1-mix) + b[i] * mix. In-place safe (out can alias a or b).

Definition at line 79 of file interpolate.hpp.

◆ crossfade_block_equal_power()

void sbl::dsp::math::crossfade_block_equal_power ( const float *  a,
const float *  b,
float *  out,
float  mix,
uint16_t  frames 
)
inline

Equal-power crossfade over a block with constant mix.

out[i] = a[i] * sqrt(1-mix) + b[i] * sqrt(mix). Gains computed once.

Definition at line 92 of file interpolate.hpp.

◆ cc_to_float()

constexpr float sbl::dsp::math::cc_to_float ( uint8_t  val)
inlineconstexpr

Normalize MIDI CC (0-127) to [0.0, 1.0].

Definition at line 21 of file param.hpp.

◆ u16_to_float()

constexpr float sbl::dsp::math::u16_to_float ( uint16_t  val)
inlineconstexpr

Normalize 16-bit unsigned (0-65535) to [0.0, 1.0].

Definition at line 26 of file param.hpp.

◆ u14_to_float()

constexpr float sbl::dsp::math::u14_to_float ( uint16_t  val)
inlineconstexpr

Normalize 14-bit MIDI (0-16383) to [0.0, 1.0] (pitch bend, NRPN)

Definition at line 31 of file param.hpp.

◆ map_linear()

constexpr float sbl::dsp::math::map_linear ( float  t,
float  min,
float  max 
)
inlineconstexpr

Linear mapping: t → min + (max - min) * t.

Definition at line 38 of file param.hpp.

◆ map_quadratic()

constexpr float sbl::dsp::math::map_quadratic ( float  t,
float  min,
float  max 
)
inlineconstexpr

Quadratic mapping: t² curve. Good for frequency, cutoff, LFO rate. More resolution at low values, fast rise at high values.

Definition at line 44 of file param.hpp.

◆ map_scurve()

constexpr float sbl::dsp::math::map_scurve ( float  t,
float  min,
float  max 
)
inlineconstexpr

S-curve mapping via Hermite smooth step: t²(3 - 2t). Slow start, fast middle, slow finish. Good for crossfade morphs.

Definition at line 50 of file param.hpp.

◆ map_inv_quadratic()

constexpr float sbl::dsp::math::map_inv_quadratic ( float  t,
float  min,
float  max 
)
inlineconstexpr

Inverse quadratic mapping: (2t - t²) curve. More resolution at high values. Good for reverb decay, feedback — parameters where the interesting range is near the maximum.

Definition at line 58 of file param.hpp.

◆ map_exponential()

float sbl::dsp::math::map_exponential ( float  t,
float  min,
float  max 
)
inline

Exponential mapping: min * 2^(t * log2(max/min)). Equal ratio per knob turn — the musically correct curve for time parameters (attack, release, delay time) and frequency ranges. Requires min > 0 and max > min.

Definition at line 67 of file param.hpp.

References fast_exp2f().

◆ semitones_to_ratio()

float sbl::dsp::math::semitones_to_ratio ( float  semitones)
inline
Note
All functions in sbl::dsp (pitch) are ISR-safe — bounded computation, no I/O. Convert semitones to frequency ratio using two-table multiplication. Input range: -128.0 to +127.0 semitones. 0 = unison (ratio 1.0). Cost: 1 float multiply + table lookups.

Definition at line 28 of file pitch.hpp.

References sbl::dsp::lut::pitch_ratio_high_256, and sbl::dsp::lut::pitch_ratio_low_256.

Referenced by note_to_ratio(), semitones_to_ratio_safe(), and sbl::dsp::modules::MorphOsc< MaxFrames >::tick_drift().

◆ semitones_to_ratio_safe()

float sbl::dsp::math::semitones_to_ratio_safe ( float  semitones)
inline

Extended range version — handles semitones outside [-128, 127]. Uses octave doubling/halving for extreme values.

Definition at line 40 of file pitch.hpp.

References semitones_to_ratio().

◆ note_to_ratio()

float sbl::dsp::math::note_to_ratio ( float  midi_note)
inline

MIDI note to frequency ratio relative to A4 (note 69). note_to_ratio(69) = 1.0, note_to_ratio(81) = 2.0.

Definition at line 53 of file pitch.hpp.

References semitones_to_ratio().

Referenced by note_to_frequency().

◆ note_to_frequency()

float sbl::dsp::math::note_to_frequency ( float  midi_note)
inline

◆ note_to_phase_increment()

uint32_t sbl::dsp::math::note_to_phase_increment ( float  midi_note,
float  sample_rate 
)
inline

MIDI note to phase increment for a given sample rate. phase_inc = freq / sample_rate * 2^32

Definition at line 64 of file pitch.hpp.

References note_to_frequency(), and PHASE_ACCUMULATOR_RANGE.

◆ note_of_su()

constexpr float sbl::dsp::math::note_of_su ( float  su)
inlineconstexpr

◆ su_of_note()

constexpr float sbl::dsp::math::su_of_note ( float  note)
inlineconstexpr

Definition at line 76 of file pitch.hpp.

References PITCH_SU_MIN_NOTE, and PITCH_SU_NOTE_RANGE.

Variable Documentation

◆ PI

constexpr float sbl::dsp::math::PI = 3.14159265358979323846f
inlineconstexpr

Definition at line 11 of file constants.hpp.

Referenced by fast_tan_pif().

◆ TWO_PI

constexpr float sbl::dsp::math::TWO_PI = 2.0f * PI
inlineconstexpr

◆ HALF_PI

constexpr float sbl::dsp::math::HALF_PI = 0.5f * PI
inlineconstexpr

Definition at line 13 of file constants.hpp.

◆ PHASE_ACCUMULATOR_RANGE

constexpr float sbl::dsp::math::PHASE_ACCUMULATOR_RANGE = 4294967296.0f
inlineconstexpr

The phase accumulator's full range: uint32_t [0, 2^32) is one cycle.

Definition at line 16 of file constants.hpp.

Referenced by note_to_phase_increment().

◆ PITCH_SU_MIN_NOTE

constexpr float sbl::dsp::math::PITCH_SU_MIN_NOTE = 24.0f
inlineconstexpr

The pitch-su convention: a unipolar signal spans C1..C9 (MIDI 24..120), the mapping MorphOsc set and every pitched widget follows.

Definition at line 71 of file pitch.hpp.

Referenced by note_of_su(), and su_of_note().

◆ PITCH_SU_MAX_NOTE

constexpr float sbl::dsp::math::PITCH_SU_MAX_NOTE = 120.0f
inlineconstexpr

Definition at line 72 of file pitch.hpp.

◆ PITCH_SU_NOTE_RANGE

constexpr float sbl::dsp::math::PITCH_SU_NOTE_RANGE = PITCH_SU_MAX_NOTE - PITCH_SU_MIN_NOTE
inlineconstexpr

Definition at line 73 of file pitch.hpp.

Referenced by note_of_su(), and su_of_note().