From 82efb29e2ac3d48892b05e1c4d23524d35da69c7 Mon Sep 17 00:00:00 2001
From: Chris Robinson <chris.kcat@gmail.com>
Date: Sat, 30 Dec 2023 06:27:33 -0800
Subject: Clean up some ugly pointer manipulation in the limiter

---
 core/mastering.cpp | 95 ++++++++++++++++++++++++++++--------------------------
 core/mastering.h   |  3 +-
 2 files changed, 51 insertions(+), 47 deletions(-)

(limited to 'core')

diff --git a/core/mastering.cpp b/core/mastering.cpp
index 5fecdb3f..9bb4c053 100644
--- a/core/mastering.cpp
+++ b/core/mastering.cpp
@@ -60,14 +60,16 @@ float UpdateSlidingHold(SlidingHold *Hold, const uint i, const float in)
     }
     else
     {
-        do {
+        auto findLowerIndex = [&lowerIndex,in,values]() noexcept -> bool
+        {
             do {
                 if(!(in >= values[lowerIndex]))
-                    goto found_place;
+                    return true;
             } while(lowerIndex--);
+            return false;
+        };
+        while(!findLowerIndex())
             lowerIndex = mask;
-        } while(true);
-    found_place:
 
         lowerIndex = (lowerIndex + 1) & mask;
         values[lowerIndex] = in;
@@ -82,15 +84,16 @@ float UpdateSlidingHold(SlidingHold *Hold, const uint i, const float in)
 
 void ShiftSlidingHold(SlidingHold *Hold, const uint n)
 {
-    auto exp_begin = std::begin(Hold->mExpiries) + Hold->mUpperIndex;
-    auto exp_last = std::begin(Hold->mExpiries) + Hold->mLowerIndex;
-    if(exp_last-exp_begin < 0)
+    auto exp_upper = Hold->mExpiries.begin() + Hold->mUpperIndex;
+    if(Hold->mLowerIndex < Hold->mUpperIndex)
     {
-        std::transform(exp_begin, std::end(Hold->mExpiries), exp_begin,
-            [n](uint e){ return e - n; });
-        exp_begin = std::begin(Hold->mExpiries);
+        std::transform(exp_upper, Hold->mExpiries.end(), exp_upper,
+            [n](const uint e) noexcept { return e - n; });
+        exp_upper = Hold->mExpiries.begin();
     }
-    std::transform(exp_begin, exp_last+1, exp_begin, [n](uint e){ return e - n; });
+    const auto exp_lower = Hold->mExpiries.begin() + Hold->mLowerIndex;
+    std::transform(exp_upper, exp_lower+1, exp_upper,
+        [n](const uint e) noexcept { return e - n; });
 }
 
 
@@ -104,7 +107,7 @@ void LinkChannels(Compressor *Comp, const uint SamplesToDo, const FloatBufferLin
     ASSUME(SamplesToDo > 0);
     ASSUME(numChans > 0);
 
-    auto side_begin = std::begin(Comp->mSideChain) + Comp->mLookAhead;
+    const auto side_begin = Comp->mSideChain.begin() + Comp->mLookAhead;
     std::fill(side_begin, side_begin+SamplesToDo, 0.0f);
 
     auto fill_max = [SamplesToDo,side_begin](const FloatBufferLine &input) -> void
@@ -132,14 +135,14 @@ void CrestDetector(Compressor *Comp, const uint SamplesToDo)
 
     auto calc_crest = [&y2_rms,&y2_peak,a_crest](const float x_abs) noexcept -> float
     {
-        const float x2{clampf(x_abs * x_abs, 0.000001f, 1000000.0f)};
+        const float x2{clampf(x_abs*x_abs, 0.000001f, 1000000.0f)};
 
-        y2_peak = maxf(x2, lerpf(x2, y2_peak, a_crest));
+        y2_peak = std::max(x2, lerpf(x2, y2_peak, a_crest));
         y2_rms = lerpf(x2, y2_rms, a_crest);
         return y2_peak / y2_rms;
     };
-    auto side_begin = std::begin(Comp->mSideChain) + Comp->mLookAhead;
-    std::transform(side_begin, side_begin+SamplesToDo, std::begin(Comp->mCrestFactor), calc_crest);
+    const auto side_begin = Comp->mSideChain.begin() + Comp->mLookAhead;
+    std::transform(side_begin, side_begin+SamplesToDo, Comp->mCrestFactor.begin(), calc_crest);
 
     Comp->mLastPeakSq = y2_peak;
     Comp->mLastRmsSq = y2_rms;
@@ -153,10 +156,10 @@ void PeakDetector(Compressor *Comp, const uint SamplesToDo)
 {
     ASSUME(SamplesToDo > 0);
 
-    /* Clamp the minimum amplitude to near-zero and convert to logarithm. */
-    auto side_begin = std::begin(Comp->mSideChain) + Comp->mLookAhead;
+    /* Clamp the minimum amplitude to near-zero and convert to logarithmic. */
+    const auto side_begin = Comp->mSideChain.begin() + Comp->mLookAhead;
     std::transform(side_begin, side_begin+SamplesToDo, side_begin,
-        [](float s) { return std::log(maxf(0.000001f, s)); });
+        [](float s) { return std::log(std::max(0.000001f, s)); });
 }
 
 /* An optional hold can be used to extend the peak detector so it can more
@@ -171,10 +174,10 @@ void PeakHoldDetector(Compressor *Comp, const uint SamplesToDo)
     uint i{0};
     auto detect_peak = [&i,hold](const float x_abs) -> float
     {
-        const float x_G{std::log(maxf(0.000001f, x_abs))};
+        const float x_G{std::log(std::max(0.000001f, x_abs))};
         return UpdateSlidingHold(hold, i++, x_G);
     };
-    auto side_begin = std::begin(Comp->mSideChain) + Comp->mLookAhead;
+    auto side_begin = Comp->mSideChain.begin() + Comp->mLookAhead;
     std::transform(side_begin, side_begin+SamplesToDo, side_begin, detect_peak);
 
     ShiftSlidingHold(hold, SamplesToDo);
@@ -192,14 +195,14 @@ void GainCompressor(Compressor *Comp, const uint SamplesToDo)
     const bool autoRelease{Comp->mAuto.Release};
     const bool autoPostGain{Comp->mAuto.PostGain};
     const bool autoDeclip{Comp->mAuto.Declip};
-    const uint lookAhead{Comp->mLookAhead};
     const float threshold{Comp->mThreshold};
     const float slope{Comp->mSlope};
     const float attack{Comp->mAttack};
     const float release{Comp->mRelease};
     const float c_est{Comp->mGainEstimate};
     const float a_adp{Comp->mAdaptCoeff};
-    const float *crestFactor{Comp->mCrestFactor.data()};
+    auto lookAhead = Comp->mSideChain.cbegin() + Comp->mLookAhead;
+    auto crestFactor = Comp->mCrestFactor.cbegin();
     float postGain{Comp->mPostGain};
     float knee{Comp->mKnee};
     float t_att{attack};
@@ -212,19 +215,19 @@ void GainCompressor(Compressor *Comp, const uint SamplesToDo)
 
     ASSUME(SamplesToDo > 0);
 
-    for(float &sideChain : al::span{Comp->mSideChain.data(), SamplesToDo})
+    auto process = [&](const float input) -> float
     {
         if(autoKnee)
-            knee = maxf(0.0f, 2.5f * (c_dev + c_est));
+            knee = std::max(0.0f, 2.5f * (c_dev + c_est));
         const float knee_h{0.5f * knee};
 
         /* This is the gain computer.  It applies a static compression curve
          * to the control signal.
          */
-        const float x_over{std::addressof(sideChain)[lookAhead] - threshold};
+        const float x_over{*(lookAhead++) - threshold};
         const float y_G{
             (x_over <= -knee_h) ? 0.0f :
-            (std::fabs(x_over) < knee_h) ? (x_over + knee_h) * (x_over + knee_h) / (2.0f * knee) :
+            (std::fabs(x_over) < knee_h) ? (x_over+knee_h) * (x_over+knee_h) / (2.0f * knee) :
             x_over};
 
         const float y2_crest{*(crestFactor++)};
@@ -244,7 +247,7 @@ void GainCompressor(Compressor *Comp, const uint SamplesToDo)
          * above to compensate for the chained operating mode.
          */
         const float x_L{-slope * y_G};
-        y_1 = maxf(x_L, lerpf(x_L, y_1, a_rel));
+        y_1 = std::max(x_L, lerpf(x_L, y_1, a_rel));
         y_L = lerpf(y_1, y_L, a_att);
 
         /* Knee width and make-up gain automation make use of a smoothed
@@ -263,13 +266,15 @@ void GainCompressor(Compressor *Comp, const uint SamplesToDo)
              * same output level.
              */
             if(autoDeclip)
-                c_dev = maxf(c_dev, sideChain - y_L - threshold - c_est);
+                c_dev = std::max(c_dev, input - y_L - threshold - c_est);
 
             postGain = -(c_dev + c_est);
         }
 
-        sideChain = std::exp(postGain - y_L);
-    }
+        return std::exp(postGain - y_L);
+    };
+    auto sideChain = al::span{Comp->mSideChain}.first(SamplesToDo);
+    std::transform(sideChain.begin(), sideChain.end(), sideChain.begin(), process);
 
     Comp->mLastRelease = y_1;
     Comp->mLastAttack = y_L;
@@ -326,7 +331,7 @@ std::unique_ptr<Compressor> Compressor::Create(const size_t NumChans, const floa
     size_t size{sizeof(Compressor)};
     if(lookAhead > 0)
     {
-        size += sizeof(*Compressor::mDelay) * NumChans;
+        size += sizeof(Compressor::mDelay[0]) * NumChans;
         /* The sliding hold implementation doesn't handle a length of 1. A 1-
          * sample hold is useless anyway, it would only ever give back what was
          * just given to it.
@@ -347,12 +352,12 @@ std::unique_ptr<Compressor> Compressor::Create(const size_t NumChans, const floa
     Comp->mAuto.Declip = AutoPostGain && AutoDeclip;
     Comp->mLookAhead = lookAhead;
     Comp->mPreGain = std::pow(10.0f, PreGainDb / 20.0f);
-    Comp->mPostGain = PostGainDb * std::log(10.0f) / 20.0f;
-    Comp->mThreshold = ThresholdDb * std::log(10.0f) / 20.0f;
-    Comp->mSlope = 1.0f / maxf(1.0f, Ratio) - 1.0f;
-    Comp->mKnee = maxf(0.0f, KneeDb * std::log(10.0f) / 20.0f);
-    Comp->mAttack = maxf(1.0f, AttackTime * SampleRate);
-    Comp->mRelease = maxf(1.0f, ReleaseTime * SampleRate);
+    Comp->mPostGain = std::log(10.0f)/20.0f * PostGainDb;
+    Comp->mThreshold = std::log(10.0f)/20.0f * ThresholdDb;
+    Comp->mSlope = 1.0f / std::max(1.0f, Ratio) - 1.0f;
+    Comp->mKnee = std::max(0.0f, std::log(10.0f)/20.0f * KneeDb);
+    Comp->mAttack = std::max(1.0f, AttackTime * SampleRate);
+    Comp->mRelease = std::max(1.0f, ReleaseTime * SampleRate);
 
     /* Knee width automation actually treats the compressor as a limiter. By
      * varying the knee width, it can effectively be seen as applying
@@ -369,11 +374,11 @@ std::unique_ptr<Compressor> Compressor::Create(const size_t NumChans, const floa
             Comp->mHold->mValues[0] = -std::numeric_limits<float>::infinity();
             Comp->mHold->mExpiries[0] = hold;
             Comp->mHold->mLength = hold;
-            Comp->mDelay = reinterpret_cast<FloatBufferLine*>(Comp->mHold + 1);
+            Comp->mDelay = {reinterpret_cast<FloatBufferLine*>(Comp->mHold + 1), NumChans};
         }
         else
-            Comp->mDelay = reinterpret_cast<FloatBufferLine*>(Comp.get() + 1);
-        std::uninitialized_fill_n(Comp->mDelay, NumChans, FloatBufferLine{});
+            Comp->mDelay = {reinterpret_cast<FloatBufferLine*>(Comp.get() + 1), NumChans};
+        std::uninitialized_fill(Comp->mDelay.begin(), Comp->mDelay.end(), FloatBufferLine{});
     }
 
     Comp->mCrestCoeff = std::exp(-1.0f / (0.200f * SampleRate)); // 200ms
@@ -388,9 +393,7 @@ Compressor::~Compressor()
     if(mHold)
         std::destroy_at(mHold);
     mHold = nullptr;
-    if(mDelay)
-        std::destroy_n(mDelay, mNumChans);
-    mDelay = nullptr;
+    std::destroy(mDelay.begin(), mDelay.end());
 }
 
 
@@ -408,7 +411,7 @@ void Compressor::process(const uint SamplesToDo, FloatBufferLine *OutBuffer)
         {
             float *buffer{al::assume_aligned<16>(input.data())};
             std::transform(buffer, buffer+SamplesToDo, buffer,
-                [preGain](float s) { return s * preGain; });
+                [preGain](const float s) noexcept { return s * preGain; });
         };
         std::for_each(OutBuffer, OutBuffer+numChans, apply_gain);
     }
@@ -425,7 +428,7 @@ void Compressor::process(const uint SamplesToDo, FloatBufferLine *OutBuffer)
 
     GainCompressor(this, SamplesToDo);
 
-    if(mDelay)
+    if(!mDelay.empty())
         SignalDelay(this, SamplesToDo, OutBuffer);
 
     const auto sideChain = al::span{mSideChain};
diff --git a/core/mastering.h b/core/mastering.h
index 8baea601..4a3b59cf 100644
--- a/core/mastering.h
+++ b/core/mastering.h
@@ -6,6 +6,7 @@
 
 #include "almalloc.h"
 #include "alnumeric.h"
+#include "alspan.h"
 #include "bufferline.h"
 
 struct SlidingHold;
@@ -50,7 +51,7 @@ struct Compressor {
     alignas(16) std::array<float,BufferLineSize> mCrestFactor{};
 
     SlidingHold *mHold{nullptr};
-    FloatBufferLine *mDelay{nullptr};
+    al::span<FloatBufferLine> mDelay;
 
     float mCrestCoeff{0.0f};
     float mGainEstimate{0.0f};
-- 
cgit v1.2.3