Process one 512-sample block; returns [0…1] with inertia.
| 27 | |
| 28 | /// Process one 512-sample block; returns [0…1] with inertia. |
| 29 | float operator()(const int16_t* samples, size_t length) { |
| 30 | assert(length == 512); |
| 31 | // 1) block peak |
| 32 | float peak = 0.0f; |
| 33 | for (size_t i = 0; i < length; ++i) { |
| 34 | float v = fl::abs(samples[i]) * (1.0f/32768.0f); |
| 35 | peak = fl::max(peak, v); |
| 36 | } |
| 37 | |
| 38 | // 2) time delta |
| 39 | float dt = static_cast<float>(length) / mSampleRate; |
| 40 | |
| 41 | // 3) update mCurrentLevel with attack/decay |
| 42 | if (peak > mCurrentLevel) { |
| 43 | float riseFactor = 1.0f - fl::exp(-mAttackRate * dt); |
| 44 | mCurrentLevel += (peak - mCurrentLevel) * riseFactor; |
| 45 | } else { |
| 46 | float decayFactor = fl::exp(-mDecayRate * dt); |
| 47 | mCurrentLevel *= decayFactor; |
| 48 | } |
| 49 | |
| 50 | // 4) output inertia: smooth mSmoothedOutput → mCurrentLevel |
| 51 | float outFactor = 1.0f - fl::exp(-mOutputRate * dt); |
| 52 | mSmoothedOutput += (mCurrentLevel - mSmoothedOutput) * outFactor; |
| 53 | |
| 54 | return mSmoothedOutput; |
| 55 | } |
| 56 | |
| 57 | private: |
| 58 | float mAttackRate; // = 1/τ₁ |