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
parameter_smoother.hpp
Go to the documentation of this file.
1// sbl/dsp/primitives/parameter_smoother.hpp — One-pole parameter smoother
2//
3// Single-pole IIR for smoothing parameter transitions. Eliminates zipper
4// noise from discrete control updates (knob steps, MIDI CC, block-rate
5// parameter changes).
6//
7// Same y += a * (x - y) math as OnePole filter, but a different object with
8// a different API and purpose. Settling time is a time constant, not a signal.
9//
10// Usage:
11// sbl::dsp::ParameterSmoother sm;
12// sm.set_time_ms(15.0f, 1000.0f); // 15ms settling at 1kHz update rate
13// float smoothed = sm.process(target); // chase target value
14
15#ifndef SBL_DSP_PRIMITIVES_PARAMETER_SMOOTHER_HPP_
16#define SBL_DSP_PRIMITIVES_PARAMETER_SMOOTHER_HPP_
17
18#include <cstdint>
19
21
22namespace sbl::dsp::primitives {
23
25public:
26 /// @note All public methods are ISR-safe — bounded computation, no I/O.
27
28 /**
29 * @brief Set coefficient directly
30 *
31 * a = 0.0 → hold previous output, 1.0 → instant (no smoothing).
32 */
33 void set_coefficient(float a) { coeff_ = a; }
34
35 /**
36 * @brief Compute coefficient from settling time in milliseconds
37 *
38 * Sets coefficient so the smoother reaches ~95% of a step change in
39 * the given time at the given update rate.
40 *
41 * @param ms Settling time in milliseconds (95% of step)
42 * @param rate_hz Update rate in Hz (e.g., 1000 for block-rate at 1kHz)
43 */
44 void set_time_ms(float ms, float rate_hz) {
45 if (ms <= 0.0f || rate_hz <= 0.0f) {
46 coeff_ = 1.0f; // instant
47 return;
48 }
49 // 95% settling in T seconds requires τ = T/3 (since e^(-3) ≈ 0.05)
50 // α = 1 - exp(-1 / (τ * rate)) = 1 - exp(-3 / (ms/1000 * rate))
51 // Inverse Taylor: exp(-x) ≈ 1/(1 + x + x²/2 + x³/6)
52 coeff_ = math::one_minus_exp_neg(3000.0f / (ms * rate_hz));
53 }
54
55 /**
56 * @brief Process one sample toward target
57 * @param target The value to approach
58 * @return Smoothed value
59 */
60 float process(float target) {
61 state_ += coeff_ * (target - state_);
62 return state_;
63 }
64
65 /**
66 * @brief Advance n steps toward target in one call
67 *
68 * Exactly equivalent to n consecutive process() calls. Lets a smoother
69 * whose coefficient was computed for a per-sample rate be advanced at
70 * block rate without stretching its settling time — pass the block
71 * size as n.
72 *
73 * @param target The value to approach
74 * @param n Number of steps to advance
75 * @return Smoothed value after n steps
76 */
77 float process_steps(float target, uint32_t n) {
78 for (uint32_t i = 0; i < n; ++i) {
79 state_ += coeff_ * (target - state_);
80 }
81 return state_;
82 }
83
84 /** @brief Current smoothed value */
85 float value() const { return state_; }
86
87 /** @brief Current coefficient */
88 float coefficient() const { return coeff_; }
89
90 /** @brief Reset to zero */
91 void reset() { state_ = 0.0f; }
92
93 /** @brief Reset to a specific value */
94 void reset(float initial) { state_ = initial; }
95
96private:
97 float coeff_ = 0.0f;
98 float state_ = 0.0f;
99};
100
101} // namespace sbl::dsp::primitives
102
103#endif // SBL_DSP_PRIMITIVES_PARAMETER_SMOOTHER_HPP_
void set_time_ms(float ms, float rate_hz)
Compute coefficient from settling time in milliseconds.
float coefficient() const
Current coefficient.
float process_steps(float target, uint32_t n)
Advance n steps toward target in one call.
float process(float target)
Process one sample toward target.
void reset(float initial)
Reset to a specific value.
void set_coefficient(float a)
Set coefficient directly.
float value() const
Current smoothed value.
Fast analytical approximations (Audio Stack — Atoms)
constexpr float one_minus_exp_neg(float x)
Stateful, single-concern building blocks.