Make the Compressor more class-like

This commit is contained in:
Chris Robinson
2018-12-24 09:17:00 -08:00
parent d49eeb576c
commit 95631aa358
4 changed files with 162 additions and 153 deletions
+5 -6
View File
@@ -1550,7 +1550,7 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode)
}
static Compressor *CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold)
static std::unique_ptr<Compressor> CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold)
{
return CompressorInit(device->RealOut.NumChannels, device->Frequency,
AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, 0.002f,
@@ -1816,6 +1816,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
device->Uhj_Encoder = nullptr;
device->Bs2b = nullptr;
device->Limiter = nullptr;
device->ChannelDelay.clear();
device->ChannelDelay.shrink_to_fit();
@@ -2044,14 +2045,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
if(device->DitherDepth > 0.0f)
thrshld -= 1.0f / device->DitherDepth;
device->Limiter.reset(CreateDeviceLimiter(device, std::log10(thrshld) * 20.0f));
auto limiter = CreateDeviceLimiter(device, std::log10(thrshld) * 20.0f);
/* Convert the lookahead from samples to nanosamples to nanoseconds. */
device->FixedLatency += std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::seconds(GetCompressorLookAhead(device->Limiter.get()))
) / device->Frequency;
std::chrono::seconds(limiter->getLookAhead())) / device->Frequency;
device->Limiter = std::move(limiter);
}
else
device->Limiter = nullptr;
TRACE("Output limiter %s\n", device->Limiter ? "enabled" : "disabled");
aluSelectPostProcess(device);
+2 -2
View File
@@ -1745,8 +1745,8 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples)
}
/* Apply compression, limiting sample amplitude if needed or desired. */
if(device->Limiter)
ApplyCompression(device->Limiter.get(), SamplesToDo, device->RealOut.Buffer);
if(Compressor *comp{device->Limiter.get()})
comp->process(SamplesToDo, device->RealOut.Buffer);
/* Apply delays and attenuation for mismatched speaker distances. */
ApplyDistanceComp(device->RealOut.Buffer, device->ChannelDelay, device->TempBuffer[0],
+123 -115
View File
@@ -15,11 +15,11 @@
static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2");
struct SlidingHold {
ALfloat Values[BUFFERSIZE];
ALsizei Expiries[BUFFERSIZE];
ALsizei LowerIndex;
ALsizei UpperIndex;
ALsizei Length;
ALfloat mValues[BUFFERSIZE];
ALsizei mExpiries[BUFFERSIZE];
ALsizei mLowerIndex;
ALsizei mUpperIndex;
ALsizei mLength;
};
@@ -34,14 +34,17 @@ using namespace std::placeholders;
*
* http://www.richardhartersworld.com/cri/2001/slidingmin.html
*/
static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in)
ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in)
{
static constexpr ALsizei mask{BUFFERSIZE - 1};
const ALsizei length{Hold->Length};
ALfloat (&values)[BUFFERSIZE] = Hold->Values;
ALsizei (&expiries)[BUFFERSIZE] = Hold->Expiries;
ALsizei lowerIndex{Hold->LowerIndex};
ALsizei upperIndex{Hold->UpperIndex};
const ALsizei length{Hold->mLength};
ALfloat (&values)[BUFFERSIZE] = Hold->mValues;
ALsizei (&expiries)[BUFFERSIZE] = Hold->mExpiries;
ALsizei lowerIndex{Hold->mLowerIndex};
ALsizei upperIndex{Hold->mUpperIndex};
ASSUME(upperIndex >= 0);
ASSUME(lowerIndex >= 0);
if(i >= expiries[upperIndex])
upperIndex = (upperIndex + 1) & mask;
@@ -68,41 +71,42 @@ static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALflo
expiries[lowerIndex] = i + length;
}
Hold->LowerIndex = lowerIndex;
Hold->UpperIndex = upperIndex;
Hold->mLowerIndex = lowerIndex;
Hold->mUpperIndex = upperIndex;
return values[upperIndex];
}
static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n)
void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n)
{
ASSUME(Hold->UpperIndex >= 0);
ASSUME(Hold->LowerIndex >= 0);
ASSUME(Hold->mUpperIndex >= 0);
ASSUME(Hold->mLowerIndex >= 0);
auto exp_begin = std::begin(Hold->Expiries) + Hold->UpperIndex;
auto exp_last = std::begin(Hold->Expiries) + Hold->LowerIndex;
auto exp_begin = std::begin(Hold->mExpiries) + Hold->mUpperIndex;
auto exp_last = std::begin(Hold->mExpiries) + Hold->mLowerIndex;
if(exp_last < exp_begin)
{
std::transform(exp_begin, std::end(Hold->Expiries), exp_begin,
std::transform(exp_begin, std::end(Hold->mExpiries), exp_begin,
std::bind(std::minus<ALsizei>{}, _1, n));
exp_begin = std::begin(Hold->Expiries);
exp_begin = std::begin(Hold->mExpiries);
}
std::transform(exp_begin, exp_last+1, exp_begin, std::bind(std::minus<ALsizei>{}, _1, n));
}
/* Multichannel compression is linked via the absolute maximum of all
* channels.
*/
void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, const ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE])
{
const ALsizei index{Comp->LookAhead};
const ALsizei numChans{Comp->NumChans};
const ALsizei index{Comp->mLookAhead};
const ALsizei numChans{Comp->mNumChans};
ASSUME(SamplesToDo > 0);
ASSUME(numChans > 0);
ASSUME(index >= 0);
auto side_begin = std::begin(Comp->SideChain) + index;
auto side_begin = std::begin(Comp->mSideChain) + index;
std::fill(side_begin, side_begin+SamplesToDo, 0.0f);
auto fill_max = [SamplesToDo,side_begin](const ALfloat *input) -> void
@@ -121,10 +125,10 @@ void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, const ALfloat (*R
*/
static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo)
{
const ALfloat a_crest{Comp->CrestCoeff};
const ALsizei index{Comp->LookAhead};
ALfloat y2_peak{Comp->LastPeakSq};
ALfloat y2_rms{Comp->LastRmsSq};
const ALfloat a_crest{Comp->mCrestCoeff};
const ALsizei index{Comp->mLookAhead};
ALfloat y2_peak{Comp->mLastPeakSq};
ALfloat y2_rms{Comp->mLastRmsSq};
ASSUME(SamplesToDo > 0);
ASSUME(index >= 0);
@@ -137,11 +141,11 @@ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo)
y2_rms = lerp(x2, y2_rms, a_crest);
return y2_peak / y2_rms;
};
auto side_begin = std::begin(Comp->SideChain) + index;
std::transform(side_begin, side_begin+SamplesToDo, std::begin(Comp->CrestFactor), calc_crest);
auto side_begin = std::begin(Comp->mSideChain) + index;
std::transform(side_begin, side_begin+SamplesToDo, std::begin(Comp->mCrestFactor), calc_crest);
Comp->LastPeakSq = y2_peak;
Comp->LastRmsSq = y2_rms;
Comp->mLastPeakSq = y2_peak;
Comp->mLastRmsSq = y2_rms;
}
/* The side-chain starts with a simple peak detector (based on the absolute
@@ -150,13 +154,13 @@ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo)
*/
void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo)
{
const ALsizei index{Comp->LookAhead};
const ALsizei index{Comp->mLookAhead};
ASSUME(SamplesToDo > 0);
ASSUME(index >= 0);
/* Clamp the minimum amplitude to near-zero and convert to logarithm. */
auto side_begin = std::begin(Comp->SideChain) + index;
auto side_begin = std::begin(Comp->mSideChain) + index;
std::transform(side_begin, side_begin+SamplesToDo, side_begin,
std::bind(static_cast<float(&)(float)>(std::log), std::bind(maxf, 0.000001f, _1)));
}
@@ -167,19 +171,19 @@ void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo)
*/
void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo)
{
const ALsizei index{Comp->LookAhead};
const ALsizei index{Comp->mLookAhead};
ASSUME(SamplesToDo > 0);
ASSUME(index >= 0);
SlidingHold *hold{Comp->Hold};
SlidingHold *hold{Comp->mHold};
ALsizei i{0};
auto detect_peak = [&i,hold](const ALfloat x_abs) -> ALfloat
{
const ALfloat x_G{std::log(maxf(0.000001f, x_abs))};
return UpdateSlidingHold(hold, i++, x_G);
};
auto side_begin = std::begin(Comp->SideChain) + index;
auto side_begin = std::begin(Comp->mSideChain) + index;
std::transform(side_begin, side_begin+SamplesToDo, side_begin, detect_peak);
ShiftSlidingHold(hold, SamplesToDo);
@@ -192,29 +196,29 @@ void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo)
*/
void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo)
{
const bool autoKnee{Comp->Auto.Knee};
const bool autoAttack{Comp->Auto.Attack};
const bool autoRelease{Comp->Auto.Release};
const bool autoPostGain{Comp->Auto.PostGain};
const bool autoDeclip{Comp->Auto.Declip};
const ALsizei lookAhead{Comp->LookAhead};
const ALfloat threshold{Comp->Threshold};
const ALfloat slope{Comp->Slope};
const ALfloat attack{Comp->Attack};
const ALfloat release{Comp->Release};
const ALfloat c_est{Comp->GainEstimate};
const ALfloat a_adp{Comp->AdaptCoeff};
const ALfloat (&crestFactor)[BUFFERSIZE] = Comp->CrestFactor;
ALfloat (&sideChain)[BUFFERSIZE*2] = Comp->SideChain;
ALfloat postGain{Comp->PostGain};
ALfloat knee{Comp->Knee};
const bool autoKnee{Comp->mAuto.Knee};
const bool autoAttack{Comp->mAuto.Attack};
const bool autoRelease{Comp->mAuto.Release};
const bool autoPostGain{Comp->mAuto.PostGain};
const bool autoDeclip{Comp->mAuto.Declip};
const ALsizei lookAhead{Comp->mLookAhead};
const ALfloat threshold{Comp->mThreshold};
const ALfloat slope{Comp->mSlope};
const ALfloat attack{Comp->mAttack};
const ALfloat release{Comp->mRelease};
const ALfloat c_est{Comp->mGainEstimate};
const ALfloat a_adp{Comp->mAdaptCoeff};
const ALfloat (&crestFactor)[BUFFERSIZE] = Comp->mCrestFactor;
ALfloat (&sideChain)[BUFFERSIZE*2] = Comp->mSideChain;
ALfloat postGain{Comp->mPostGain};
ALfloat knee{Comp->mKnee};
ALfloat t_att{attack};
ALfloat t_rel{release - attack};
ALfloat a_att{std::exp(-1.0f / t_att)};
ALfloat a_rel{std::exp(-1.0f / t_rel)};
ALfloat y_1{Comp->LastRelease};
ALfloat y_L{Comp->LastAttack};
ALfloat c_dev{Comp->LastGainDev};
ALfloat y_1{Comp->mLastRelease};
ALfloat y_L{Comp->mLastAttack};
ALfloat c_dev{Comp->mLastGainDev};
ASSUME(SamplesToDo > 0);
ASSUME(lookAhead >= 0);
@@ -279,9 +283,9 @@ void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo)
sideChain[i] = std::exp(postGain - y_L);
}
Comp->LastRelease = y_1;
Comp->LastAttack = y_L;
Comp->LastGainDev = c_dev;
Comp->mLastRelease = y_1;
Comp->mLastAttack = y_L;
Comp->mLastGainDev = c_dev;
}
/* Combined with the hold time, a look-ahead delay can improve handling of
@@ -292,9 +296,9 @@ void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo)
void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE])
{
static constexpr ALsizei mask{BUFFERSIZE - 1};
const ALsizei numChans{Comp->NumChans};
const ALsizei indexIn{Comp->DelayIndex};
const ALsizei indexOut{Comp->DelayIndex - Comp->LookAhead};
const ALsizei numChans{Comp->mNumChans};
const ALsizei indexIn{Comp->mDelayIndex};
const ALsizei indexOut{Comp->mDelayIndex - Comp->mLookAhead};
ASSUME(SamplesToDo > 0);
ASSUME(numChans > 0);
@@ -302,7 +306,7 @@ void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT
for(ALsizei c{0};c < numChans;c++)
{
ALfloat *RESTRICT inout{al::assume_aligned<16>(OutBuffer[c])};
ALfloat *RESTRICT delay{al::assume_aligned<16>(Comp->Delay[c])};
ALfloat *RESTRICT delay{al::assume_aligned<16>(Comp->mDelay[c])};
for(ALsizei i{0};i < SamplesToDo;i++)
{
const ALfloat sig{inout[i]};
@@ -312,7 +316,7 @@ void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT
}
}
Comp->DelayIndex = (indexIn + SamplesToDo) & mask;
Comp->mDelayIndex = (indexIn + SamplesToDo) & mask;
}
} // namespace
@@ -341,7 +345,7 @@ void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT
* ReleaseTimeMin - Release time (in seconds). Acts as a maximum when
* automating release time.
*/
Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate,
std::unique_ptr<Compressor> CompressorInit(const ALsizei NumChans, const ALuint SampleRate,
const ALboolean AutoKnee, const ALboolean AutoAttack,
const ALboolean AutoRelease, const ALboolean AutoPostGain,
const ALboolean AutoDeclip, const ALfloat LookAheadTime,
@@ -354,74 +358,82 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate,
clampf(std::round(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE-1));
auto hold = static_cast<ALsizei>(clampf(std::round(HoldTime*SampleRate), 0.0f, BUFFERSIZE-1));
Compressor *Comp;
size_t size{sizeof(*Comp)};
std::unique_ptr<Compressor> Comp;
size_t size{sizeof(Compressor)};
if(lookAhead > 0)
{
size += sizeof(*Comp->Delay) * NumChans;
size += sizeof(*Comp->mDelay) * 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.
*/
if(hold > 1)
size += sizeof(*Comp->Hold);
size += sizeof(*Comp->mHold);
}
Comp = new (al_calloc(16, size)) Compressor{};
Comp->NumChans = NumChans;
Comp->SampleRate = SampleRate;
Comp->Auto.Knee = AutoKnee != AL_FALSE;
Comp->Auto.Attack = AutoAttack != AL_FALSE;
Comp->Auto.Release = AutoRelease != AL_FALSE;
Comp->Auto.PostGain = AutoPostGain != AL_FALSE;
Comp->Auto.Declip = AutoPostGain && AutoDeclip;
Comp->LookAhead = lookAhead;
Comp->PreGain = std::pow(10.0f, PreGainDb / 20.0f);
Comp->PostGain = PostGainDb * std::log(10.0f) / 20.0f;
Comp->Threshold = ThresholdDb * std::log(10.0f) / 20.0f;
Comp->Slope = 1.0f / maxf(1.0f, Ratio) - 1.0f;
Comp->Knee = maxf(0.0f, KneeDb * std::log(10.0f) / 20.0f);
Comp->Attack = maxf(1.0f, AttackTime * SampleRate);
Comp->Release = maxf(1.0f, ReleaseTime * SampleRate);
Comp = std::unique_ptr<Compressor>{new (al_calloc(16, size)) Compressor{}};
Comp->mNumChans = NumChans;
Comp->mSampleRate = SampleRate;
Comp->mAuto.Knee = AutoKnee != AL_FALSE;
Comp->mAuto.Attack = AutoAttack != AL_FALSE;
Comp->mAuto.Release = AutoRelease != AL_FALSE;
Comp->mAuto.PostGain = AutoPostGain != AL_FALSE;
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);
/* Knee width automation actually treats the compressor as a limiter. By
* varying the knee width, it can effectively be seen as applying
* compression over a wide range of ratios.
*/
if(AutoKnee)
Comp->Slope = -1.0f;
Comp->mSlope = -1.0f;
if(lookAhead > 0)
{
if(hold > 1)
{
Comp->Hold = new ((void*)(Comp + 1)) SlidingHold{};
Comp->Hold->Values[0] = -std::numeric_limits<float>::infinity();
Comp->Hold->Expiries[0] = hold;
Comp->Hold->Length = hold;
Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp->Hold + 1);
Comp->mHold = new ((void*)(Comp.get() + 1)) SlidingHold{};
Comp->mHold->mValues[0] = -std::numeric_limits<float>::infinity();
Comp->mHold->mExpiries[0] = hold;
Comp->mHold->mLength = hold;
Comp->mDelay = (ALfloat(*)[BUFFERSIZE])(Comp->mHold + 1);
}
else
{
Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp + 1);
Comp->mDelay = (ALfloat(*)[BUFFERSIZE])(Comp.get() + 1);
}
}
Comp->CrestCoeff = std::exp(-1.0f / (0.200f * SampleRate)); // 200ms
Comp->GainEstimate = Comp->Threshold * -0.5f * Comp->Slope;
Comp->AdaptCoeff = std::exp(-1.0f / (2.0f * SampleRate)); // 2s
Comp->mCrestCoeff = std::exp(-1.0f / (0.200f * SampleRate)); // 200ms
Comp->mGainEstimate = Comp->mThreshold * -0.5f * Comp->mSlope;
Comp->mAdaptCoeff = std::exp(-1.0f / (2.0f * SampleRate)); // 2s
return Comp;
}
void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*OutBuffer)[BUFFERSIZE])
Compressor::~Compressor()
{
const ALsizei numChans{Comp->NumChans};
if(mHold)
mHold->~SlidingHold();
mHold = nullptr;
}
void Compressor::process(const ALsizei SamplesToDo, ALfloat (*OutBuffer)[BUFFERSIZE])
{
const ALsizei numChans{mNumChans};
ASSUME(SamplesToDo > 0);
ASSUME(numChans > 0);
const ALfloat preGain{Comp->PreGain};
const ALfloat preGain{mPreGain};
if(preGain != 1.0f)
{
auto apply_gain = [SamplesToDo,preGain](ALfloat *input) noexcept -> void
@@ -433,26 +445,26 @@ void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*Out
std::for_each(OutBuffer, OutBuffer+numChans, apply_gain);
}
LinkChannels(Comp, SamplesToDo, OutBuffer);
LinkChannels(this, SamplesToDo, OutBuffer);
if(Comp->Auto.Attack || Comp->Auto.Release)
CrestDetector(Comp, SamplesToDo);
if(mAuto.Attack || mAuto.Release)
CrestDetector(this, SamplesToDo);
if(Comp->Hold)
PeakHoldDetector(Comp, SamplesToDo);
if(mHold)
PeakHoldDetector(this, SamplesToDo);
else
PeakDetector(Comp, SamplesToDo);
PeakDetector(this, SamplesToDo);
GainCompressor(Comp, SamplesToDo);
GainCompressor(this, SamplesToDo);
if(Comp->Delay)
SignalDelay(Comp, SamplesToDo, OutBuffer);
if(mDelay)
SignalDelay(this, SamplesToDo, OutBuffer);
const ALfloat (&sideChain)[BUFFERSIZE*2] = Comp->SideChain;
const ALfloat (&sideChain)[BUFFERSIZE*2] = mSideChain;
auto apply_comp = [SamplesToDo,&sideChain](ALfloat *input) noexcept -> void
{
ALfloat *buffer{al::assume_aligned<16>(input)};
const ALfloat *gains{al::assume_aligned<16>(sideChain)};
const ALfloat *gains{al::assume_aligned<16>(&sideChain[0])};
/* Mark the gains "input-1 type" as restrict, so the compiler can
* vectorize this loop (otherwise it assumes a write to buffer[n] can
* change gains[n+1]).
@@ -462,11 +474,7 @@ void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*Out
};
std::for_each(OutBuffer, OutBuffer+numChans, apply_comp);
ASSUME(Comp->LookAhead >= 0);
auto side_begin = std::begin(Comp->SideChain) + SamplesToDo;
std::copy(side_begin, side_begin+Comp->LookAhead, std::begin(Comp->SideChain));
ASSUME(mLookAhead >= 0);
auto side_begin = std::begin(mSideChain) + SamplesToDo;
std::copy(side_begin, side_begin+mLookAhead, std::begin(mSideChain));
}
ALsizei GetCompressorLookAhead(const Compressor *Comp)
{ return Comp->LookAhead; }
+32 -30
View File
@@ -1,6 +1,8 @@
#ifndef MASTERING_H
#define MASTERING_H
#include <memory>
#include "AL/al.h"
#include "almalloc.h"
@@ -21,8 +23,8 @@ struct SlidingHold;
* http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/
*/
struct Compressor {
ALsizei NumChans;
ALuint SampleRate;
ALsizei mNumChans{0};
ALuint mSampleRate{0u};
struct {
bool Knee : 1;
@@ -30,36 +32,41 @@ struct Compressor {
bool Release : 1;
bool PostGain : 1;
bool Declip : 1;
} Auto;
} mAuto{};
ALsizei LookAhead;
ALsizei mLookAhead{0};
ALfloat PreGain;
ALfloat PostGain;
ALfloat mPreGain{0.0f};
ALfloat mPostGain{0.0f};
ALfloat Threshold;
ALfloat Slope;
ALfloat Knee;
ALfloat mThreshold{0.0f};
ALfloat mSlope{0.0f};
ALfloat mKnee{0.0f};
ALfloat Attack;
ALfloat Release;
ALfloat mAttack{0.0f};
ALfloat mRelease{0.0f};
alignas(16) ALfloat SideChain[2*BUFFERSIZE];
alignas(16) ALfloat CrestFactor[BUFFERSIZE];
alignas(16) ALfloat mSideChain[2*BUFFERSIZE]{};
alignas(16) ALfloat mCrestFactor[BUFFERSIZE]{};
SlidingHold *Hold;
ALfloat (*Delay)[BUFFERSIZE];
ALsizei DelayIndex;
SlidingHold *mHold{nullptr};
ALfloat (*mDelay)[BUFFERSIZE]{nullptr};
ALsizei mDelayIndex{0};
ALfloat CrestCoeff;
ALfloat GainEstimate;
ALfloat AdaptCoeff;
ALfloat mCrestCoeff{0.0f};
ALfloat mGainEstimate{0.0f};
ALfloat mAdaptCoeff{0.0f};
ALfloat LastPeakSq;
ALfloat LastRmsSq;
ALfloat LastRelease;
ALfloat LastAttack;
ALfloat LastGainDev;
ALfloat mLastPeakSq{0.0f};
ALfloat mLastRmsSq{0.0f};
ALfloat mLastRelease{0.0f};
ALfloat mLastAttack{0.0f};
ALfloat mLastGainDev{0.0f};
~Compressor();
void process(const ALsizei SamplesToDo, ALfloat (*OutBuffer)[BUFFERSIZE]);
ALsizei getLookAhead() const noexcept { return mLookAhead; }
DEF_PLACE_NEWDEL()
};
@@ -88,7 +95,7 @@ struct Compressor {
* ReleaseTimeMin - Release time (in seconds). Acts as a maximum when
* automating release time.
*/
Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate,
std::unique_ptr<Compressor> CompressorInit(const ALsizei NumChans, const ALuint SampleRate,
const ALboolean AutoKnee, const ALboolean AutoAttack,
const ALboolean AutoRelease, const ALboolean AutoPostGain,
const ALboolean AutoDeclip, const ALfloat LookAheadTime,
@@ -97,9 +104,4 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate,
const ALfloat Ratio, const ALfloat KneeDb,
const ALfloat AttackTime, const ALfloat ReleaseTime);
void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo,
ALfloat (*OutBuffer)[BUFFERSIZE]);
ALsizei GetCompressorLookAhead(const Compressor *Comp);
#endif /* MASTERING_H */