83 void prepare(
double sampleRate,
double rampTimeMs = 20.0) noexcept
85 sampleRate_ = std::max(1.0, sampleRate);
86 rampTimeMs_ = std::max(0.1, rampTimeMs);
89 const double tau = rampTimeMs_ / 1000.0;
90 expCoeff_ = std::exp(-1.0 / (sampleRate_ * tau));
93 linearRate_ = 1000.0 / (rampTimeMs_ * sampleRate_);
96 const double srRatio = 44100.0 / sampleRate_;
97 chaseMultDecay_ = std::pow(0.9999, srRatio);
98 chaseAddDecay_ = 0.01 * srRatio;
114 if (newTarget != newTarget)
return;
115 if (newTarget != target_)
119 chaseSpeed_ = 2500.0;
129 const double target =
static_cast<double>(target_);
130 if (current_ == target)
return target_;
136 current_ = target + expCoeff_ * (current_ - target);
141 if (current_ < target)
142 current_ = std::min(current_ + linearRate_, target);
144 current_ = std::max(current_ - linearRate_, target);
154 chaseSpeed_ = std::max(350.0, std::min(2500.0, chaseSpeed_ * chaseMultDecay_ - chaseAddDecay_));
155 current_ = (current_ * chaseSpeed_ + target) / (chaseSpeed_ + 1.0);
163 const double eps = kEpsilon * std::max(1.0, std::abs(target));
164 if (std::abs(current_ - target) < eps)
167 return static_cast<T
>(current_);
183 const double target =
static_cast<double>(target_);
184 const size_t n = buffer.size();
185 if (current_ == target)
187 std::fill(buffer.begin(), buffer.end(), target_);
195 double current = current_;
196 const double eps = kEpsilon * std::max(1.0, std::abs(target));
203 const double coeff = expCoeff_;
206 current = target + coeff * (current - target);
207 if (std::abs(current - target) < eps) { current = target;
break; }
208 buffer[i] =
static_cast<T
>(current);
215 const double rate = linearRate_;
218 if (current < target) current = std::min(current + rate, target);
219 else if (current > target) current = std::max(current - rate, target);
220 if (std::abs(current - target) < eps) { current = target;
break; }
221 buffer[i] =
static_cast<T
>(current);
232 double speed = chaseSpeed_;
233 const double multDecay = chaseMultDecay_;
234 const double addDecay = chaseAddDecay_;
237 speed = std::max(350.0, std::min(2500.0, speed * multDecay - addDecay));
238 current = (current * speed + target) / (speed + 1.0);
239 if (std::abs(current - target) < eps) { current = target;
break; }
240 buffer[i] =
static_cast<T
>(current);
261 [[nodiscard]]
bool isSmoothing() const noexcept {
return current_ !=
static_cast<double>(target_); }
264 void skip() noexcept { current_ =
static_cast<double>(target_); chaseSpeed_ = 350.0; }
270 current_ =
static_cast<double>(value);
277 prepare(sampleRate, rampTimeMs);
281 double current_{ 0.0 };
286 double expCoeff_{ 0.0 };
287 double linearRate_{ 0.0 };
290 double chaseSpeed_{ 350.0 };
291 double chaseMultDecay_{ 0.9999 };
292 double chaseAddDecay_{ 0.01 };
294 double sampleRate_{ 44100.0 };
295 double rampTimeMs_{ 20.0 };
297 static constexpr double kEpsilon = 1e-7;
Core mathematical utilities for digital signal processing.
Zero-allocation parameter smoother for real-time audio.
void setSmoothingType(SmoothingType type) noexcept
Sets the smoothing algorithm.
SmoothedValue & operator=(const SmoothedValue &)=delete
void reset(T value=T(0)) noexcept
Hard-resets both current and target states to a specific value.
void setRampTime(double sampleRate, double rampTimeMs) noexcept
Updates sample rate and/or ramp time, recalculating internal steps.
T getNextValue() noexcept
Calculates and returns the next smoothed value.
T getCurrentValue() const noexcept
Returns the current internal value without advancing the state.
void skip() noexcept
Forces the current value to instantly match the target, bypassing time.
bool isSmoothing() const noexcept
Evaluates if the smoother is actively transitioning.
void setTargetValue(T newTarget) noexcept
Updates the target value. Safe to call continuously (e.g., from host automation).
@ Linear
Rate-limited ramp. Constant velocity, exact target arrival.
@ Disabled
Instant snapping, no smoothing applied.
@ Exponential
One-pole IIR. Natural, musical interpolation.
@ Chase
Adaptive speed (Airwindows style). Gentle start after a jump, accelerating settle.
void processBlock(std::span< T > buffer) noexcept
Computes a block of smoothed values into an output buffer.
SmoothedValue(const SmoothedValue &)=delete
Prevents accidental copying of stateful DSP objects.
SmoothingType getSmoothingType() const noexcept
Returns the current smoothing algorithm.
T getTargetValue() const noexcept
Returns the set target value.
void prepare(double sampleRate, double rampTimeMs=20.0) noexcept
Precalculates internal coefficients based on sample rate and timing.
Main namespace for the DSPark framework.