1 /** 2 * Copyright 2017 Cut Through Recordings 3 * License: MIT License 4 * Author(s): Ethan Reker 5 */ 6 module ddsp.effect.expander; 7 8 import ddsp.util.functions; 9 import ddsp.effect.dynamics; 10 11 import dplug.core.nogc; 12 13 import std.algorithm; 14 import std.math; 15 16 /// Basic Expander 17 class Expander : DynamicsProcessor 18 { 19 public: 20 nothrow: 21 @nogc: 22 23 override float getNextSample(const float input) 24 { 25 detector.detect(input); 26 float detectorValue = floatToDecibel(detector.getEnvelope()); 27 28 return input * calcExpanderGain(detectorValue, _threshold, _ratio, _kneeWidth); 29 } 30 31 private: 32 33 bool _gate; 34 35 /// This is the function that does most of the work with calculating compression 36 float calcExpanderGain(float detectorValue, float threshold, float ratio, float kneeWidth) 37 { 38 float ES = 1.0f / ratio - 1.0f; 39 40 if(_gate) 41 ES = -1.0f; 42 43 if(kneeWidth > 0 && detectorValue > (threshold - kneeWidth / 2.0f) && 44 detectorValue < threshold + kneeWidth / 2.0f) 45 { 46 x[0] = threshold - kneeWidth / 2.0f; 47 x[1] = threshold + kneeWidth / 2.0f; 48 x[1] = clamp(x[1], -96.0f, 0.0f); 49 y[0] = ES; 50 y[1] = 0.0f; 51 52 ES = lagrpol(x, y, 2, detectorValue); 53 } 54 55 float yG = ES * (threshold - detectorValue); 56 57 yG = clamp(yG, -96.0, 0); 58 59 return pow(10.0f, yG / 20.0f); 60 } 61 } 62 63 class Gate : Expander 64 { 65 public: 66 nothrow: 67 @nogc: 68 this() 69 { 70 _gate = true; 71 } 72 }