This is the heart of the feed-forward compressor. It operates in the log * domain (to better match human hearing) and can apply some basic automation * to knee width, attack/release times, make-up/post gain, and clipping * reduction. */
| 185 | * reduction. |
| 186 | */ |
| 187 | void GainCompressor(Compressor *Comp, const uint SamplesToDo) |
| 188 | { |
| 189 | const bool autoKnee{Comp->mAuto.Knee}; |
| 190 | const bool autoAttack{Comp->mAuto.Attack}; |
| 191 | const bool autoRelease{Comp->mAuto.Release}; |
| 192 | const bool autoPostGain{Comp->mAuto.PostGain}; |
| 193 | const bool autoDeclip{Comp->mAuto.Declip}; |
| 194 | const uint lookAhead{Comp->mLookAhead}; |
| 195 | const float threshold{Comp->mThreshold}; |
| 196 | const float slope{Comp->mSlope}; |
| 197 | const float attack{Comp->mAttack}; |
| 198 | const float release{Comp->mRelease}; |
| 199 | const float c_est{Comp->mGainEstimate}; |
| 200 | const float a_adp{Comp->mAdaptCoeff}; |
| 201 | const float *crestFactor{Comp->mCrestFactor}; |
| 202 | float postGain{Comp->mPostGain}; |
| 203 | float knee{Comp->mKnee}; |
| 204 | float t_att{attack}; |
| 205 | float t_rel{release - attack}; |
| 206 | float a_att{std::exp(-1.0f / t_att)}; |
| 207 | float a_rel{std::exp(-1.0f / t_rel)}; |
| 208 | float y_1{Comp->mLastRelease}; |
| 209 | float y_L{Comp->mLastAttack}; |
| 210 | float c_dev{Comp->mLastGainDev}; |
| 211 | |
| 212 | ASSUME(SamplesToDo > 0); |
| 213 | |
| 214 | for(float &sideChain : al::span<float>{Comp->mSideChain, SamplesToDo}) |
| 215 | { |
| 216 | if(autoKnee) |
| 217 | knee = maxf(0.0f, 2.5f * (c_dev + c_est)); |
| 218 | const float knee_h{0.5f * knee}; |
| 219 | |
| 220 | /* This is the gain computer. It applies a static compression curve |
| 221 | * to the control signal. |
| 222 | */ |
| 223 | const float x_over{std::addressof(sideChain)[lookAhead] - threshold}; |
| 224 | const float y_G{ |
| 225 | (x_over <= -knee_h) ? 0.0f : |
| 226 | (std::fabs(x_over) < knee_h) ? (x_over + knee_h) * (x_over + knee_h) / (2.0f * knee) : |
| 227 | x_over}; |
| 228 | |
| 229 | const float y2_crest{*(crestFactor++)}; |
| 230 | if(autoAttack) |
| 231 | { |
| 232 | t_att = 2.0f*attack/y2_crest; |
| 233 | a_att = std::exp(-1.0f / t_att); |
| 234 | } |
| 235 | if(autoRelease) |
| 236 | { |
| 237 | t_rel = 2.0f*release/y2_crest - t_att; |
| 238 | a_rel = std::exp(-1.0f / t_rel); |
| 239 | } |
| 240 | |
| 241 | /* Gain smoothing (ballistics) is done via a smooth decoupled peak |
| 242 | * detector. The attack time is subtracted from the release time |
| 243 | * above to compensate for the chained operating mode. |
| 244 | */ |