|
Sound Byte Libs 0.5.1-121-g3358a44
C++ firmware library for audio applications on 32-bit ARM Cortex-M processors
|
Cross-cutting math used at every audio layer. More...
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 |
|
inlineconstexpr |
x held to [lo, hi]; NaN → lo.
Definition at line 13 of file clamp.hpp.
Referenced by clamp01(), sbl::dsp::primitives::ThiranAllpass< N >::set_delay(), sbl::dsp::pm::MassSpringDamper::set_frequency(), sbl::dsp::pm::StringLoop::set_junction(), sbl::dsp::pm::MassSpringDamper::set_mass(), sbl::dsp::pm::MassSpringDamper::set_q(), and sbl::dsp::pm::MassSpringDamper::set_resonance().
|
inlineconstexpr |
x held to [0, 1]; NaN → 0.
Definition at line 18 of file clamp.hpp.
References clamp().
Referenced by sbl::dsp::pm::ThermalFriction::advance(), sbl::dsp::modules::Ladder::set_cutoff_su(), sbl::dsp::primitives::OnePole::set_cutoff_su(), sbl::dsp::widgets::Svf::set_cutoff_su(), sbl::dsp::pm::StringBase< Exciter, Load, MaxPeriod >::set_damping_su(), sbl::dsp::pm::StringLoop::set_damping_su(), sbl::dsp::modules::Ladder::set_drive_su(), sbl::dsp::pm::StringLoop::set_loop_gain(), sbl::dsp::pm::ModalResonator< MaxModes >::set_mode(), sbl::dsp::pm::ModalResonator< MaxModes >::set_modes(), sbl::dsp::pm::StringBase< Exciter, Load, MaxPeriod >::set_pickup_su(), sbl::dsp::pm::StringBase< Exciter, Load, MaxPeriod >::set_pitch_su(), sbl::dsp::pm::StringBase< Exciter, Load, MaxPeriod >::set_position_su(), sbl::dsp::pm::Bow< Law >::set_pressure_su(), sbl::dsp::modules::Ladder::set_resonance_su(), sbl::dsp::widgets::Svf::set_resonance_su(), sbl::dsp::pm::TableSet::set_select_su(), sbl::dsp::pm::BowSet::set_select_su(), sbl::dsp::pm::Bow< Law >::set_velocity_su(), and sbl::dsp::pm::StringBase< Exciter, Load, MaxPeriod >::update_period().
|
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.
| base | Center frequency in Hz (e.g., filter cutoff) |
| mod | Normalized modulation value, typically [-1.0, 1.0] |
| depth | Modulation depth in octaves (e.g., 2.0 = ±2 octaves) |
| lo | Minimum output frequency in Hz (default 20) |
| hi | Maximum output frequency in Hz (default 20000) |
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().
|
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).
| mod | Normalized modulation signal buffer [-1.0, 1.0] |
| freq_out | Output frequency buffer (Hz) |
| n | Frame count |
| base | Center frequency in Hz |
| depth | Modulation depth in octaves |
| lo | Minimum output frequency in Hz (default 20) |
| hi | Maximum output frequency in Hz (default 20000) |
Definition at line 71 of file exp_mod.hpp.
References exp_mod().
|
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)
| x | Input angle in radians, must be in [0, π/2] |
Definition at line 41 of file fast_math.hpp.
|
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).
| f | Normalized frequency (freq_hz / sample_rate), must be < 0.497 |
Definition at line 71 of file fast_math.hpp.
References PI.
Referenced by sbl::dsp::widgets::Svf::process().
|
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)
| x | Exponent (e.g., ±2.0 for ±2 octave modulation) |
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().
|
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).
| x | Input value (any range, clamped for |x| > 3) |
Definition at line 141 of file fast_math.hpp.
Referenced by sbl::dsp::modules::Ladder::process().
|
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().
|
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().
|
inlineconstexpr |
Linear crossfade between two values.
| a | Value at t=0 |
| b | Value at t=1 |
| t | Blend factor [0.0, 1.0] |
Definition at line 26 of file interpolate.hpp.
|
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.
| t | Input [0.0, 1.0] (not clamped) |
Definition at line 40 of file interpolate.hpp.
|
inlineconstexpr |
Integer crossfade for 16-bit values.
| a | Value at t=0 |
| b | Value at t=1 |
| t | Blend factor [0, 65535] (0 = all a, 65535 = all b) |
Definition at line 52 of file interpolate.hpp.
|
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).
| a | Value at t=0 (dry) |
| b | Value at t=1 (wet) |
| t | Blend factor [0.0, 1.0] |
Definition at line 68 of file interpolate.hpp.
|
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.
|
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.
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
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().
|
inline |
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().
|
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().
|
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().
|
inline |
MIDI note to frequency in Hz. A4 = 440 Hz.
Definition at line 58 of file pitch.hpp.
References note_to_ratio().
Referenced by note_to_phase_increment(), sbl::dsp::modules::MorphOsc< MaxFrames >::set_pitch_su(), and sbl::dsp::pm::StringBase< Exciter, Load, MaxPeriod >::update_period().
|
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.
|
inlineconstexpr |
Definition at line 75 of file pitch.hpp.
References PITCH_SU_MIN_NOTE, and PITCH_SU_NOTE_RANGE.
Referenced by sbl::dsp::modules::MorphOsc< MaxFrames >::set_pitch_su(), and sbl::dsp::pm::StringBase< Exciter, Load, MaxPeriod >::update_period().
|
inlineconstexpr |
Definition at line 76 of file pitch.hpp.
References PITCH_SU_MIN_NOTE, and PITCH_SU_NOTE_RANGE.
|
inlineconstexpr |
Definition at line 11 of file constants.hpp.
Referenced by fast_tan_pif().
|
inlineconstexpr |
Definition at line 12 of file constants.hpp.
Referenced by sbl::dsp::pm::StringLoop::reset(), and sbl::dsp::pm::MassSpringDamper::set_resonance().
|
inlineconstexpr |
Definition at line 13 of file constants.hpp.
|
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().
|
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().
|
inlineconstexpr |
|
inlineconstexpr |
Definition at line 73 of file pitch.hpp.
Referenced by note_of_su(), and su_of_note().