1 /** 2 Attack and release basic smoother. 3 4 Copyright: Guillaume Piolat 2015-2022. 5 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 6 */ 7 module ar; 8 9 //import std.algorithm.comparison; 10 //import std.math; 11 12 import std.math: isFinite; 13 import dplug.core.math; 14 import dplug.core.ringbuf; 15 import dplug.core.nogc; 16 import dplug.core.vec; 17 18 struct AttackRelease(T) if (is(T == float) || is(T == double)) 19 { 20 public: 21 /// time: the time constant of the smoother. 22 /// threshold: absolute difference below which we consider current value and target equal 23 void initialize(float sampleRate, float timeAttackSecs, float timeReleaseSecs, T initialValue) nothrow @nogc 24 { 25 assert(isFinite(initialValue)); 26 _sampleRate = sampleRate; 27 _current = cast(T)(initialValue); 28 setAttackTime(timeAttackSecs); 29 setReleaseTime(timeReleaseSecs); 30 } 31 32 /// Changes attack time (given in seconds). 33 void setAttackTime(float timeAttackSecs) nothrow @nogc 34 { 35 _expFactorAttack = cast(T)(expDecayFactor(timeAttackSecs, _sampleRate)); 36 } 37 38 /// Changes release time (given in seconds). 39 void setReleaseTime(float timeReleaseSecs) nothrow @nogc 40 { 41 _expFactorRelease = cast(T)(expDecayFactor(timeReleaseSecs, _sampleRate)); 42 } 43 44 /// Advance smoothing and return the next smoothed sample with respect 45 /// to tau time and samplerate. 46 T nextSample(T target) nothrow @nogc 47 { 48 T diff = target - _current; 49 if (diff != 0) 50 { 51 if (fast_fabs(diff) < 1e-10f) // to avoid subnormal, and excess churn 52 { 53 _current = target; 54 } 55 else 56 { 57 double expFactor = (diff > 0) ? _expFactorAttack : _expFactorRelease; 58 double temp = _current + diff * expFactor; // Is double-precision really needed here? 59 T newCurrent = cast(T)(temp); 60 _current = newCurrent; 61 } 62 } 63 return _current; 64 } 65 66 void nextBuffer(const(T)* input, T* output, int frames) 67 { 68 for (int i = 0; i < frames; ++i) 69 { 70 output[i] = nextSample(input[i]); 71 } 72 } 73 74 void nextBuffer(T input, T* output, int frames) 75 { 76 for (int i = 0; i < frames; ++i) 77 { 78 output[i] = nextSample(input); 79 } 80 } 81 82 private: 83 T _current; 84 T _expFactorAttack; 85 T _expFactorRelease; 86 float _sampleRate; 87 } 88