46#include "../Core/DspMath.h"
47#include "../Core/AudioSpec.h"
48#include "../Core/AudioBuffer.h"
49#include "../Core/SmoothedValue.h"
50#include "../Core/RingBuffer.h"
51#include "../Core/DenormalGuard.h"
52#include "../Core/Hilbert.h"
53#include "../Core/TruePeakDetector.h"
54#include "../Core/StateBlob.h"
201 T thresh =
threshold_.load(std::memory_order_relaxed);
202 T rat =
ratio_.load(std::memory_order_relaxed);
203 T knee =
kneeWidth_.load(std::memory_order_relaxed);
224 int maxLaSamples =
static_cast<int>(
sampleRate_ * 0.01) + 1
233 lookaheadMs_.load(std::memory_order_relaxed), T(0), T(10)) / T(1000));
238 int maxRmsSamples =
static_cast<int>(
sampleRate_ * 0.5) + 1;
241 buf.assign(
static_cast<size_t>(maxRmsSamples), T(0));
310 if (channel < 0 || channel >=
kMaxChannels)
return input;
324 const bool advanceShared = (channel == 0);
325 T thresh, ratio, knee, makeupDb, colorAmt;
343 auto detType =
detectorType_.load(std::memory_order_relaxed);
344 auto topo =
topology_.load(std::memory_order_relaxed);
345 auto charType =
character_.load(std::memory_order_relaxed);
346 auto modeType =
mode_.load(std::memory_order_relaxed);
382 T levelDb =
detectLevel(detectorIn, channel, detTypeEff);
399 thresh, ratio, knee);
405 smoothedGR_Db =
applyBallistics(targetGR_Db, channel, splitAdaptive, law.slope);
409 T targetGR_Db =
computeGain(levelDb, thresh, ratio, knee, charType, modeType, guardDb);
424 makeup +=
computeGain(T(0), thresh, ratio, knee, charType,
428 T output = input * smoothedGainLinear;
432 const T sq = output * output;
435 const T grDepth = std::clamp(-smoothedGR_Db * T(0.1), T(0), T(1));
436 output += colorAmt *
kFetColorH2 * grDepth * (sq - dc);
464 std::fill(buf.begin(), buf.end(), T(0));
465 for (
auto& sum :
rmsSums_) sum = T(0);
496 if (!std::isfinite(dB))
return;
497 threshold_.store(dB, std::memory_order_relaxed);
503 if (!std::isfinite(ratio))
return;
504 ratio_.store(std::max(ratio, T(1)), std::memory_order_relaxed);
522 if (!std::isfinite(ms))
return;
523 attackMs_.store(std::max(ms, T(0.01)), std::memory_order_relaxed);
538 if (!std::isfinite(ms))
return;
539 releaseMs_.store(std::max(ms, T(1)), std::memory_order_relaxed);
546 if (!std::isfinite(dB))
return;
547 kneeWidth_.store(std::max(dB, T(0)), std::memory_order_relaxed);
553 if (!std::isfinite(dB))
return;
570 std::memory_order_relaxed);
590 if (!std::isfinite(amount))
return;
591 stereoLink_.store(std::clamp(amount, T(0), T(1)), std::memory_order_relaxed);
597 if (!std::isfinite(dryWet))
return;
598 mix_.store(std::clamp(dryWet, T(0), T(1)), std::memory_order_relaxed);
607 if (!std::isfinite(ms))
return;
608 lookaheadMs_.store(std::clamp(ms, T(0), T(10)), std::memory_order_relaxed);
630 if (!std::isfinite(ms))
return;
631 holdMs_.store(std::clamp(ms, T(0), T(500)), std::memory_order_relaxed);
645 if (!std::isfinite(dB))
return;
646 rangeDb_.store(std::max(dB, T(0)), std::memory_order_relaxed);
680 if (!std::isfinite(amount))
return;
681 characterColor_.store(std::clamp(amount, T(0), T(1)), std::memory_order_relaxed);
703 if (std::isfinite(cutoffHz) && cutoffHz > T(0))
704 scHpfFreq_.store(cutoffHz, std::memory_order_relaxed);
718 if (!std::isfinite(ms))
return;
750 const bool feedback =
753 if (feedback)
return 0;
754 const int hilbertComp =
760 const int lookNow =
static_cast<int>(
static_cast<T
>(
sampleRate_) * std::clamp(
761 lookaheadMs_.load(std::memory_order_relaxed), T(0), T(10)) / T(1000));
762 return lookNow + hilbertComp;
767 [[nodiscard]] std::vector<uint8_t>
getState()
const
772 w.
write(
"threshold",
static_cast<float>(
threshold_.load(std::memory_order_relaxed)));
773 w.
write(
"ratio",
static_cast<float>(
ratio_.load(std::memory_order_relaxed)));
774 w.
write(
"attack",
static_cast<float>(
attackMs_.load(std::memory_order_relaxed)));
775 w.
write(
"release",
static_cast<float>(
releaseMs_.load(std::memory_order_relaxed)));
776 w.
write(
"knee",
static_cast<float>(
kneeWidth_.load(std::memory_order_relaxed)));
777 w.
write(
"makeup",
static_cast<float>(
makeupGain_.load(std::memory_order_relaxed)));
780 w.
write(
"autoMakeupMode",
static_cast<int32_t
>(amMode));
781 w.
write(
"stereoLink",
static_cast<float>(
stereoLink_.load(std::memory_order_relaxed)));
782 w.
write(
"mix",
static_cast<float>(
mix_.load(std::memory_order_relaxed)));
783 w.
write(
"lookahead",
static_cast<float>(
lookaheadMs_.load(std::memory_order_relaxed)));
784 w.
write(
"hold",
static_cast<float>(
holdMs_.load(std::memory_order_relaxed)));
785 w.
write(
"range",
static_cast<float>(
rangeDb_.load(std::memory_order_relaxed)));
786 w.
write(
"detector",
static_cast<int32_t
>(
detectorType_.load(std::memory_order_relaxed)));
787 w.
write(
"topology",
static_cast<int32_t
>(
topology_.load(std::memory_order_relaxed)));
788 w.
write(
"character",
static_cast<int32_t
>(
character_.load(std::memory_order_relaxed)));
790 w.
write(
"mode",
static_cast<int32_t
>(
mode_.load(std::memory_order_relaxed)));
792 w.
write(
"scHpfFreq",
static_cast<float>(
scHpfFreq_.load(std::memory_order_relaxed)));
809 const int amLegacy = r.
read(
"autoMakeup",
false) ? 2 : 0;
811 std::clamp(r.
read(
"autoMakeupMode", amLegacy), 0, 2)));
838 template <
typename E>
839 [[nodiscard]]
static E
clampEnum(E value, E last)
noexcept
841 const int v = std::clamp(
static_cast<int>(value), 0,
static_cast<int>(last));
842 return static_cast<E
>(v);
859 const int nCh = std::min(audio.getNumChannels(),
kMaxChannels);
860 const int nS = audio.getNumSamples();
863 const int scCh = (sidechain.getNumSamples() >= nS)
864 ? sidechain.getNumChannels() : 0;
886 auto detType =
detectorType_.load(std::memory_order_relaxed);
887 auto topo =
topology_.load(std::memory_order_relaxed);
888 auto charType =
character_.load(std::memory_order_relaxed);
889 auto modeType =
mode_.load(std::memory_order_relaxed);
892 T sLink =
stereoLink_.load(std::memory_order_relaxed);
920 for (
int i = 0; i < nS; ++i)
928 T linkedLevel = T(-200);
933 mkupGain +=
computeGain(T(0), thresh, ratio, knee, charType,
937 for (
int ch = 0; ch < nCh; ++ch)
940 T sample = (scCh > 0) ? sidechain.getChannel(std::min(ch, scCh - 1))[i]
941 : audio.getChannel(ch)[i];
950 detectorIn = fbImplicit ? audio.getChannel(ch)[i] :
fbLastOutput_[ch];
955 T levelDb =
detectLevel(detectorIn, ch, detTypeEff);
958 if (levelDb > linkedLevel) linkedLevel = levelDb;
963 for (
int ch = 0; ch < nCh; ++ch)
966 T inputDb = chLevel + sLink * (linkedLevel - chLevel);
983 thresh, ratio, knee);
991 smoothedGR_Db =
applyBallistics(targetGR_Db, ch, splitAdaptive, law.slope);
995 T targetGR_Db =
computeGain(inputDb, thresh, ratio, knee, charType, modeType, guardDb);
1002 T makeup = mkupGain;
1007 if (activeLookahead > 0)
1014 input = audio.getChannel(ch)[i];
1017 T wet = input * smoothedGainLinear;
1026 const T sq = wet * wet;
1029 const T grDepth = std::clamp(-smoothedGR_Db * T(0.1), T(0), T(1));
1030 wet += colorAmt *
kFetColorH2 * grDepth * (sq - dc);
1039 audio.getChannel(ch)[i] = (mixVal < T(1))
1040 ? (input * (T(1) - mixVal) + wet * mixVal)
1043 if (ch == 0 || smoothedGR_Db < blockGR)
1044 blockGR = smoothedGR_Db;
1060 T attMs = std::max(
attackMs_.load(std::memory_order_relaxed), T(0.01));
1061 T relMs = std::max(
releaseMs_.load(std::memory_order_relaxed), T(1));
1065 auto tc = [fs](T ms) {
return std::exp(T(-1) / (fs * ms / T(1000))); };
1071 switch (
character_.load(std::memory_order_relaxed))
1105 const T rel = std::clamp(relMs, T(50), T(1100));
1123 const auto charNow =
character_.load(std::memory_order_relaxed);
1130 * (std::max(
ratio_.load(std::memory_order_relaxed), T(1)) - T(1));
1132 charAttCoeff_ = T(1) - (T(1) - rho) / (T(1) + rho * loopGain);
1146 fetDcCoeff_ = T(1) - std::exp(T(-2) * std::numbers::pi_v<T> * T(10) / fs);
1149 lookaheadMs_.load(std::memory_order_relaxed), T(0), T(10)) / T(1000));
1162 const T range =
rangeDb_.load(std::memory_order_relaxed);
1163 targetGR_Db = std::clamp(targetGR_Db, -range, range);
1169 if (std::abs(targetGR_Db) >= std::abs(held))
1174 else if (counter > 0)
1198 T level = std::abs(sample);
1206 T sq = sample * sample;
1213 if (len > 0 && len <=
static_cast<int>(buf.size()))
1218 if (++idx >= len) idx = 0;
1224 for (
int j = 0; j < len; ++j) sum += buf[j];
1228 level = std::sqrt(std::max(sum /
static_cast<T
>(len), T(0)));
1239 T pos = std::max(sample, T(0));
1240 T neg = std::max(-sample, T(0));
1257 level = std::sqrt(res.real * res.real + res.imag * res.imag);
1275 return ratio * (T(1) + excessDb / T(40));
1286 ? std::max(knee, T(10)) : knee;
1300 T guardDb)
const noexcept
1308 if (effectiveKnee <= T(0))
1311 if (inputDb <= thresh)
return T(0);
1312 return (thresh - inputDb) * (T(1) - T(1) / effectiveRatio);
1317 T halfKnee = effectiveKnee / T(2);
1318 T lower = thresh - halfKnee;
1319 T upper = thresh + halfKnee;
1321 if (inputDb <= lower)
return T(0);
1322 if (inputDb >= upper)
return (thresh - inputDb) * (T(1) - T(1) / effectiveRatio);
1324 T x = inputDb - lower;
1325 return (T(1) - T(1) / effectiveRatio) * x * x / (T(2) * effectiveKnee) * T(-1);
1341 T effectiveRatio = ratio;
1345 if (inputDb >= thresh)
return T(0);
1346 boost = (thresh - inputDb) * (T(1) - T(1) / effectiveRatio);
1350 T halfKnee = knee / T(2);
1351 T lower = thresh - halfKnee;
1352 T upper = thresh + halfKnee;
1354 if (inputDb >= upper)
return T(0);
1355 if (inputDb <= lower)
1357 boost = (thresh - inputDb) * (T(1) - T(1) / effectiveRatio);
1361 T x = upper - inputDb;
1362 boost = (T(1) - T(1) / effectiveRatio) * x * x / (T(2) * knee);
1366 const T silenceGuard = std::clamp((guardDb - (thresh - T(60))) / T(20), T(0), T(1));
1367 return boost * silenceGuard;
1397 const T a = r - T(1);
1400 if (eOut <= T(0))
return { T(0), T(0) };
1401 return { -a * eOut, a };
1403 const T halfW = w / T(2);
1404 if (eOut <= -halfW)
return { T(0), T(0) };
1405 if (eOut >= halfW / r)
return { -a * eOut, a };
1410 const T b = eOut + halfW;
1411 const T z = std::min(T(2) * s * b / w, T(1));
1412 const T u = std::min(T(2) * b / (T(1) + std::sqrt(T(1) - z)), w);
1413 const T su = s * u / w;
1414 return { -s * u * u / (T(2) * w), su / std::max(T(1) - su, T(1) / r) };
1430 const T eOut = outDb - thresh;
1436 for (
int pass = 0; pass < 2; ++pass)
1470 T ratio, T knee,
Character charType)
const noexcept
1474 const T halfW = w / T(2);
1475 const T a = r - T(1);
1478 T e = inDb + k - thresh;
1479 if (e <= ((w > T(0)) ? -halfW : T(0)))
1484 const T g3 = (k - effB * a * (inDb - thresh)) / (T(1) + effB * a);
1485 e = inDb + g3 - thresh;
1486 if (e >= ((w > T(0)) ? halfW / r : T(0)))
1487 return { g3, -a * e };
1493 const T q = (T(1) - effB) * s / (T(2) * w);
1494 const T b = (inDb - thresh + k) + halfW;
1495 const T disc = std::max(T(1) - T(4) * q * b, T(0));
1496 T u = T(2) * b / (T(1) + std::sqrt(disc));
1497 u = std::clamp(u, T(0), w);
1498 const T target = -s * u * u / (T(2) * w);
1499 return { k + effB * target, target };
1513 T thresh, T ratio, T knee)
noexcept
1518 const bool dual = wFast < T(1);
1529 const T range =
rangeDb_.load(std::memory_order_relaxed);
1530 const T slowTarget = std::clamp(
1533 const bool charging = slowTarget < slow;
1535 if (std::abs(slow) < T(1e-4)) slow = T(0);
1540 const T shownPrev = dual ? wFast * fast + (T(1) - wFast) * slow : fast;
1542 const bool engaging = probe < fast;
1544 const T beta = T(1) - coeff;
1546 const T k = dual ? wFast * coeff * fast + (T(1) - wFast) * slow : coeff * fast;
1547 const T effB = dual ? wFast * beta : beta;
1548 const auto sol =
solveFeedbackGain(inDb, k, effB, thresh, ratio, knee, charType);
1550 fast = sol.target + coeff * (fast - sol.target);
1551 if (std::abs(fast) < T(1e-4)) fast = T(0);
1552 T shown = dual ? wFast * fast + (T(1) - wFast) * slow : fast;
1560 if (bounded != shown)
1563 fast = dual ? (shown - (T(1) - wFast) * slow) / wFast : shown;
1593 T loopSlope = T(0)) noexcept
1603 const T outputLevel = std::min(std::abs(
fbLastOutput_[ch]), T(1));
1604 relCoeff += outputLevel * (relCoeff * relCoeff - relCoeff);
1606 if (loopSlope > T(0))
1611 const T floorCoeff = T(1) - T(0.5) / (T(1) + loopSlope);
1612 attCoeff = std::max(attCoeff, floorCoeff);
1613 relCoeff = std::max(relCoeff, floorCoeff);
1621 const bool engaging = targetGrDb < fast;
1622 fast = targetGrDb + (engaging ? attCoeff : relCoeff) * (fast - targetGrDb);
1623 if (std::abs(fast) < T(1e-4)) fast = T(0);
1632 const bool charging = targetGrDb < slow;
1634 if (std::abs(slow) < T(1e-4)) slow = T(0);
1646 const double scFreq = std::clamp(
1647 static_cast<double>(
scHpfFreq_.load(std::memory_order_relaxed)),
1684 int maxLen =
static_cast<int>(
rmsBuffers_[0].size());
Non-owning view over audio channel data.
High-fidelity modular compressor designed for real-time applications.
DetectorType
Level detection methodologies.
@ SplitPolarity
Asymmetric positive/negative half-wave tracking (ButterComp2 style).
@ TruePeak
4x oversampled peak detection (ITU-R BS.1770-4 compliant).
@ Rms
Sliding-window Root-Mean-Square. Smoother, responds to average energy.
@ Peak
Instantaneous absolute value tracking. Fast and standard.
static constexpr int kMaxChannels
T charChargeCoeff_
History charge coefficient of the memory stage.
void setThreshold(T dB) noexcept
Sets the compression threshold in dB.
void setHoldTime(T ms) noexcept
Sets the gain-reduction hold time.
std::array< RingBuffer< T >, kMaxChannels > lookaheadBuffers_
Lookahead delay lines.
void prepare(const AudioSpec &spec)
Allocates buffers and initializes internal DSP state.
std::array< T, kMaxChannels > heldGrDb_
std::atomic< bool > scHpfEnabled_
HPF toggle.
std::atomic< AutoMakeupMode > autoMakeupMode_
Auto-makeup behavior.
SmoothedValue< T > makeupSmooth_
De-zippered makeup gain (dB).
std::atomic< T > releaseMs_
Release time in milliseconds.
FeedbackSolve solveFeedbackGain(T inDb, T k, T effB, T thresh, T ratio, T knee, Character charType) const noexcept
Solves one feedback ballistics step against the current input.
std::array< T, kMaxChannels > fetDcState_
Per-channel DC estimate of wet^2.
std::atomic< T > stereoLink_
Stereo linking amount (0 to 1).
T charRelCoeff_
Release coefficient (fast stage).
std::atomic< T > gainReductionDb_
Publicly readable Gain Reduction meter.
T getGainReductionDb() const noexcept
Returns current active gain reduction in dB (negative value).
static E clampEnum(E value, E last) noexcept
Clamps an enum to its valid [first, last] range.
std::array< int, kMaxChannels > holdCounters_
Character getCharacter() const noexcept
Returns the currently active character.
T computeGainUpward(T inputDb, T thresh, T ratio, T knee, T guardDb) const noexcept
Upward compression curve calculation.
SmoothedValue< T > kneeSmooth_
De-zippered knee.
bool setState(const uint8_t *data, size_t size)
Restores parameters from a blob (tolerant; rejects foreign ids).
std::array< T, kMaxChannels > splitPosEnv_
Positive half-wave tracking.
std::atomic< bool > rmsWindowDirty_
Applied at the next block.
Character
Time-constant behavior and release curve shape.
void setRelease(T ms) noexcept
Sets the release time in milliseconds (clamped to >= 1 ms: below that the envelope stops smoothing at...
T detectLevel(T sample, int ch, DetectorType detType) noexcept
Computes level detection in Decibels.
T scHpfB1_
HPF internal feedback coefficient.
T charAttCoeff_
Attack coefficient of the fast envelope.
std::array< int, kMaxChannels > rmsIndices_
Write heads for RMS buffers.
T applySidechainHPF(T input, int ch) noexcept
Applies sidechain filtering for a specific channel.
void updateHpfCoefficients() noexcept
Updates the normalized DC-blocker / High-pass filter coefficients.
void setTopology(Topology topo) noexcept
Changes signal routing topology (FeedForward or FeedBack).
void setMakeupGain(T dB) noexcept
Sets manual static makeup gain in dB.
std::atomic< Character > character_
Selected ballistics.
T getCharacterColor() const noexcept
Returns the character colour amount (see setCharacterColor).
void setAutoMakeup(AutoMakeupMode mode) noexcept
Selects the automatic makeup behavior (default: Off).
std::array< std::vector< T >, kMaxChannels > rmsBuffers_
Pre-allocated RMS sliding windows.
SmoothedValue< T > thresholdSmooth_
De-zippered threshold.
T applyHoldAndRange(T targetGR_Db, int ch) noexcept
Applies the hold and range stages to the static gain target (dB).
SmoothedValue< T > mixSmooth_
De-zippered parallel mix.
void setLookahead(T ms) noexcept
Sets lookahead time in ms (0 = off, max = 10ms).
std::atomic< T > scHpfFreq_
HPF Cutoff frequency.
T computeGain(T inputDb, T thresh, T ratio, T knee, Character charType, Mode modeType, T guardDb) const noexcept
Calculates static target gain reduction based on knee and ratio.
T autoMakeupEnv_
Smoothed internal auto-makeup envelope.
std::vector< uint8_t > getState() const
Serializes the parameter state (setup/UI threads; allocates).
T autoMakeupCoeff_
Auto-makeup tracking factor.
std::array< T, kMaxChannels > envSlowDb_
Slow memory envelope per channel (dB).
std::array< T, kMaxChannels > scHpfState_
HPF y[n-1] state.
void setDetector(DetectorType type) noexcept
Changes the level detection algorithm (Peak, RMS, TruePeak, Hilbert).
std::atomic< bool > timeConstantsDirty_
Coefficients need a recompute.
std::atomic< T > mix_
Wet/Dry mix (1 = full wet).
SmoothedValue< T > ratioSmooth_
De-zippered ratio.
void setAutoMakeup(bool on) noexcept
Convenience overload: true selects Adaptive, false turns auto makeup off.
static T effectiveRatioFor(Character charType, T ratio, T excessDb) noexcept
Level-dependent effective ratio of the character (Varimu grows).
T processSample(T input, int channel) noexcept
Processes a single sample on one channel.
Topology
Signal routing topology for the detector sidechain.
@ FeedForward
Detector reads uncompressed input (modern, precise, transparent).
void setRmsWindow(T ms) noexcept
Sets the RMS analysis window size in milliseconds.
std::array< T, kMaxChannels > splitNegEnv_
Negative half-wave tracking.
static constexpr int kRmsRecomputePeriod
Re-summation interval to halt drift.
std::array< T, kMaxChannels > upwardGuardDb_
Peak-held sustained level (Upward guard).
T charFastWeight_
Fast/slow blend (1 = single envelope).
T charSlowRelCoeff_
Release coefficient of the memory stage.
void setMix(T dryWet) noexcept
Sets dry/wet balance for parallel (New York) compression (1.0 = fully wet).
void reset() noexcept
Resets all internal DSP history, states, and buffers to neutral.
void setRatio(T ratio) noexcept
Sets the compression ratio (1.0 = off, >20.0 = limiting).
T applyBallistics(T targetGrDb, int ch, bool splitAdaptive, T loopSlope=T(0)) noexcept
Smooths the static gain target with the active character's ballistics.
std::array< T, kMaxChannels > envFastDb_
Fast gain envelope per channel (dB).
void setSidechainHPF(bool enabled, T cutoffHz=T(80)) noexcept
Toggles the internal sidechain high-pass filter.
std::array< Hilbert< T >, kMaxChannels > hilbertDetectors_
Analytic signal generators for detection.
T splitDetAttCoeff_
Detector attack coefficient (sample-rate derived).
std::atomic< DetectorType > detectorType_
Selected detection method.
void setKnee(T dB) noexcept
Sets knee width in dB (0 = hard knee, >0 = soft knee).
double sampleRate_
Cached operating sample rate.
FeedbackLaw computeGainFeedback(T outDb, T thresh, T ratio, T knee, Character charType) const noexcept
Feedback target for detectors with memory (explicit path).
void setCharacterColor(T amount) noexcept
Sets the amount of the character's harmonic signature (0 to 1).
std::array< T, kMaxChannels > rmsSums_
Running sums for RMS.
std::atomic< T > lookaheadMs_
Lookahead latency target in ms.
void setCharacter(Character type) noexcept
Changes ballistics and envelope behavior character.
void prepare(double sampleRate) noexcept
Prepares the compressor using sample rate only (backward compatibility).
void processBlockImpl(AudioBufferView< T > audio, AudioBufferView< T > sidechain) noexcept
Core DSP loop executing sidechain detection, linking, ballistics, and gain application.
static constexpr T kFetColorH2
void setRange(T dB) noexcept
Limits the maximum gain change the compressor may apply.
std::atomic< T > rangeDb_
Max |gain change| in dB.
std::array< T, kMaxChannels > fbLastOutput_
Feedback topology history buffer.
Topology getTopology() const noexcept
Returns the currently active topology.
std::atomic< T > attackMs_
Attack time in milliseconds.
static T effectiveKneeFor(Character charType, T knee) noexcept
Physical knee floor of the character (dB).
T upwardGuardDecay_
Guard decay per sample (60 dB/s).
T fetDcCoeff_
~10 Hz DC-tracking coefficient.
AutoMakeupMode
Automatic makeup-gain behavior (applies in Downward mode).
@ Off
Manual makeup only (setMakeupGain).
int getLatency() const noexcept
Returns total processing latency in samples.
DetectorType getDetector() const noexcept
Returns the currently active detector type.
std::atomic< T > rmsWindowMsAtomic_
Control-thread published target.
T scHpfA0_
HPF normalized feedforward coefficient.
void updateRmsWindow() noexcept
Safely recalculates the RMS window size ensuring zero heap allocations.
AudioSpec spec_
Active audio environment specification.
std::atomic< Topology > topology_
Selected topology.
T applyBallisticsFeedbackImplicit(T inDb, int ch, Character charType, T thresh, T ratio, T knee) noexcept
Feedback ballistics with the loop resolved semi-implicitly.
std::array< T, kMaxChannels > channelLevelDb_
Raw detected level buffer.
static FeedbackLaw elementLaw(T eOut, T r, T w) noexcept
Downward element law for feedback detection, per output level.
std::atomic< Mode > mode_
Selected compression mode.
std::array< int, kMaxChannels > rmsRecomputeCounters_
Re-summation counters.
void processBlock(AudioBufferView< T > buffer) noexcept
Processes an audio buffer in-place using its own signal as the sidechain.
std::atomic< T > kneeWidth_
Knee width in dB.
void setMode(Mode mode) noexcept
Sets processing mode (Downward or Upward compression).
int lookaheadSamples_
Active lookahead latency in samples.
TruePeakDetector< T, kMaxChannels > truePeak_
std::atomic< T > threshold_
Threshold in dB.
void processBlock(AudioBufferView< T > audio, AudioBufferView< T > sidechain) noexcept
Processes audio with an independent external sidechain.
void updateTimeConstants(T fs) noexcept
Pre-calculates recursive exponential decay coefficients.
T rmsWindowMs_
Active RMS length in ms (audio-thread copy).
void setStereoLink(T amount) noexcept
Sets stereo linking amount (0.0 = unlinked dual mono, 1.0 = fully linked).
std::atomic< T > makeupGain_
Static makeup gain in dB.
T splitDetRelCoeff_
Detector release coefficient (sample-rate derived).
std::atomic< T > holdMs_
Gain-hold time in ms (0 = off).
void setAttack(T ms) noexcept
Sets the attack time in milliseconds.
int rmsWindowSamples_
Active RMS length in samples.
SmoothedValue< T > colorSmooth_
De-zippered character colour amount.
Mode
Processing direction.
@ Downward
Standard: Reduces dynamic range by attenuating signals above the threshold.
std::atomic< T > characterColor_
Character harmonic amount (0 to 1).
std::atomic< T > ratio_
Ratio (e.g., 4 = 4:1).
std::array< T, kMaxChannels > scHpfPrev_
HPF x[n-1] state.
RAII scope guard to disable denormalised (subnormal) floating-point numbers.
90-degree phase-differencing network (analytic-signal generator).
void prepare(double sampleRate) noexcept
Prepares the transformer. The FIR kernel is sample-rate independent; sampleRate is accepted for API s...
Zero-allocation parameter smoother for real-time audio.
Tolerant reader: missing keys yield defaults, unknown keys are skipped.
float read(const char *key, float defaultValue) const
Reads a float, or defaultValue when the key is absent.
bool isValid() const noexcept
uint32_t processorId() const noexcept
Serializes key/value parameters into a versioned blob.
std::vector< uint8_t > blob() const
Finalizes and returns the blob.
void write(const char *key, float value)
Writes a float parameter.
Per-channel 4x-oversampled inter-sample peak estimator.
T processSample(T sample, int channel) noexcept
Feeds one sample and returns the local true-peak estimate.
void reset() noexcept
Clears all channel histories. Safe on the audio thread.
Main namespace for the DSPark framework.
T decibelsToGain(T dB, T minusInfinityDb=T(-100)) noexcept
Converts a value in decibels to linear gain.
T gainToDecibels(T gain, T minusInfinityDb=T(-100)) noexcept
Converts a linear gain value to decibels.
constexpr uint32_t stateId(const char(&tag)[5]) noexcept
Builds a FOURCC processor id, e.g. dspark::stateId("COMP").
Describes the audio environment for a DSP processor.
constexpr bool isValid() const noexcept
Checks if the specification contains valid, processable parameters.
double sampleRate
Sample rate in Hz.
Element law result: static target (dB, <= 0) and its |slope|.
T slope
d|target| / d(level in dB): the incremental loop gain.
T target
Gain change the element commands at this output level.
Semi-implicit solve result: stepped gain and the law's target.
T target
The element law's static target at the solved level.
T gain
Blended gain (dB) after this sample's ballistics step.