69 if (sampleRate <= 0.0)
return;
70 sampleRate_ = sampleRate;
83 void setAttack(T ms)
noexcept { attackMs_ = std::max(ms, T(0.01)); recalculate(); }
86 void setDecay(T ms)
noexcept { decayMs_ = std::max(ms, T(0.01)); recalculate(); }
89 void setSustain(T level)
noexcept { sustainLevel_ = std::clamp(level, T(0), T(1)); }
92 void setRelease(T ms)
noexcept { releaseMs_ = std::max(ms, T(0.01)); recalculate(); }
103 attackMs_ = std::max(attackMs, T(0.01));
104 decayMs_ = std::max(decayMs, T(0.01));
105 sustainLevel_ = std::clamp(sustain, T(0), T(1));
106 releaseMs_ = std::max(releaseMs, T(0.01));
116 curve = std::clamp(curve, T(0.1), T(10));
117 attackCurve_ = decayCurve_ = releaseCurve_ = curve;
131 void setCurvature(T attackCurve, T decayCurve, T releaseCurve)
noexcept
133 attackCurve_ = std::clamp(attackCurve, T(0.1), T(10));
134 decayCurve_ = std::clamp(decayCurve, T(0.1), T(10));
135 releaseCurve_ = std::clamp(releaseCurve, T(0.1), T(10));
175 currentValue_ += attackRate_ * (1.0 + kAttack_ - currentValue_);
176 if (currentValue_ >= 1.0)
185 const double s =
static_cast<double>(sustainLevel_);
186 const double prev = currentValue_;
187 currentValue_ += decayRate_ * (s - (1.0 - s) * kDecay_ - currentValue_);
188 if (currentValue_ <= s)
202 currentValue_ += decayRate_ * (
static_cast<double>(sustainLevel_) - currentValue_);
206 currentValue_ += releaseRate_ * (-kRelease_ - currentValue_);
207 if (currentValue_ <= kSilence)
215 return static_cast<T
>(currentValue_);
233 while (i < numSamples)
238 while (i < numSamples)
244 const double target = 1.0 + kAttack_;
245 const double r = attackRate_;
246 double v = currentValue_;
247 while (i < numSamples)
249 v += r * (target - v);
257 output[i++] =
static_cast<T
>(v);
265 const double s =
static_cast<double>(sustainLevel_);
266 const double target = s - (1.0 - s) * kDecay_;
267 const double r = decayRate_;
268 double v = currentValue_;
269 while (i < numSamples)
271 const double prev = v;
272 v += r * (target - v);
278 output[i++] =
static_cast<T
>(v);
281 output[i++] =
static_cast<T
>(v);
289 const double s =
static_cast<double>(sustainLevel_);
290 const double r = decayRate_;
291 double v = currentValue_;
292 while (i < numSamples)
295 output[i++] =
static_cast<T
>(v);
303 const double target = -kRelease_;
304 const double r = releaseRate_;
305 double v = currentValue_;
306 while (i < numSamples)
308 v += r * (target - v);
316 output[i++] =
static_cast<T
>(v);
328 [[nodiscard]] T
getCurrentValue() const noexcept {
return static_cast<T
>(currentValue_); }
339 static constexpr double kSilence = 1e-4;
341 void recalculate() noexcept
355 auto stage = [
this](T timeMs, T curve,
double& rate,
double& k)
noexcept {
356 const double c =
static_cast<double>(curve);
357 const double ov = std::exp(-c);
359 const double samples = std::max(sampleRate_ * 0.001 *
static_cast<double>(timeMs), 1.0);
360 rate = 1.0 - std::exp(-c / samples);
363 stage(attackMs_, attackCurve_, attackRate_, kAttack_);
364 stage(decayMs_, decayCurve_, decayRate_, kDecay_);
365 stage(releaseMs_, releaseCurve_, releaseRate_, kRelease_);
368 double sampleRate_ = 48000.0;
372 T sustainLevel_ = T(0.7);
373 T releaseMs_ = T(200);
374 T attackCurve_ = T(3.0);
375 T decayCurve_ = T(3.0);
376 T releaseCurve_ = T(3.0);
379 double attackRate_ = 0.0;
380 double decayRate_ = 0.0;
381 double releaseRate_ = 0.0;
382 double kAttack_ = 0.0;
383 double kDecay_ = 0.0;
384 double kRelease_ = 0.0;
386 double currentValue_ = 0.0;
Describes the audio processing environment (sample rate, block size, channels).
Core mathematical utilities for digital signal processing.
Classic ADSR envelope generator with exponential curves.
void setRelease(T ms) noexcept
Sets release time in milliseconds (full scale -> silence).
void setCurvature(T attackCurve, T decayCurve, T releaseCurve) noexcept
Sets independent curvatures per stage.
void noteOn() noexcept
Triggers the attack phase (note on). Legato: continues from the current value.
T getNextValue() noexcept
Returns the next envelope value and advances the state machine.
void setDecay(T ms) noexcept
Sets decay time in milliseconds (1 -> sustain).
void prepare(double sampleRate) noexcept
Prepares the envelope for the given sample rate.
void setCurvature(T curve) noexcept
Sets the curvature of all exponential stages at once.
void setSustain(T level) noexcept
Sets sustain level (0.0 to 1.0).
void setAttack(T ms) noexcept
Sets attack time in milliseconds (0 -> 1).
T getCurrentValue() const noexcept
Returns the current envelope value.
void noteOff() noexcept
Triggers the release phase (note off).
State getState() const noexcept
Returns the current state.
bool isActive() const noexcept
Returns true if the envelope is actively producing output.
void setParameters(T attackMs, T decayMs, T sustain, T releaseMs) noexcept
Sets all ADSR parameters at once.
void reset() noexcept
Resets the envelope to idle with zero output.
void prepare(const AudioSpec &spec) noexcept
Prepares from AudioSpec (unified API).
void processBlock(T *output, int numSamples) noexcept
Fills a buffer with envelope values.
Main namespace for the DSPark framework.
Describes the audio environment for a DSP processor.