Use a unique_ptr for the Compressor
This commit is contained in:
+2
-9
@@ -2221,16 +2221,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
if(device->DitherDepth > 0.0f)
|
||||
thrshld -= 1.0f / device->DitherDepth;
|
||||
|
||||
al_free(device->Limiter);
|
||||
device->Limiter = CreateDeviceLimiter(device, std::log10(thrshld) * 20.0f);
|
||||
device->FixedLatency += (ALuint)(GetCompressorLookAhead(device->Limiter) *
|
||||
device->Limiter.reset(CreateDeviceLimiter(device, std::log10(thrshld) * 20.0f));
|
||||
device->FixedLatency += (ALuint)(GetCompressorLookAhead(device->Limiter.get()) *
|
||||
DEVICE_CLOCK_RES / device->Frequency);
|
||||
}
|
||||
else
|
||||
{
|
||||
al_free(device->Limiter);
|
||||
device->Limiter = nullptr;
|
||||
}
|
||||
TRACE("Output limiter %s\n", device->Limiter ? "enabled" : "disabled");
|
||||
|
||||
aluSelectPostProcess(device);
|
||||
@@ -2433,9 +2429,6 @@ ALCdevice_struct::~ALCdevice_struct()
|
||||
|
||||
al_free(Stablizer);
|
||||
Stablizer = nullptr;
|
||||
|
||||
al_free(Limiter);
|
||||
Limiter = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -1787,7 +1787,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples)
|
||||
SamplesToDo, device->RealOut.NumChannels);
|
||||
|
||||
if(device->Limiter)
|
||||
ApplyCompression(device->Limiter, SamplesToDo, device->RealOut.Buffer);
|
||||
ApplyCompression(device->Limiter.get(), SamplesToDo, device->RealOut.Buffer);
|
||||
|
||||
if(device->DitherDepth > 0.0f)
|
||||
ApplyDither(device->RealOut.Buffer, &device->DitherSeed, device->DitherDepth,
|
||||
|
||||
+32
-72
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "mastering.h"
|
||||
#include "alu.h"
|
||||
#include "almalloc.h"
|
||||
@@ -23,65 +25,13 @@ static double round(double val)
|
||||
/* These structures assume BUFFERSIZE is a power of 2. */
|
||||
static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2");
|
||||
|
||||
typedef struct SlidingHold {
|
||||
struct SlidingHold {
|
||||
ALfloat Values[BUFFERSIZE];
|
||||
ALsizei Expiries[BUFFERSIZE];
|
||||
ALsizei LowerIndex;
|
||||
ALsizei UpperIndex;
|
||||
ALsizei Length;
|
||||
} SlidingHold;
|
||||
|
||||
/* General topology and basic automation was based on the following paper:
|
||||
*
|
||||
* D. Giannoulis, M. Massberg and J. D. Reiss,
|
||||
* "Parameter Automation in a Dynamic Range Compressor,"
|
||||
* Journal of the Audio Engineering Society, v61 (10), Oct. 2013
|
||||
*
|
||||
* Available (along with supplemental reading) at:
|
||||
*
|
||||
* http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/
|
||||
*/
|
||||
typedef struct Compressor {
|
||||
ALsizei NumChans;
|
||||
ALuint SampleRate;
|
||||
|
||||
struct {
|
||||
ALuint Knee : 1;
|
||||
ALuint Attack : 1;
|
||||
ALuint Release : 1;
|
||||
ALuint PostGain : 1;
|
||||
ALuint Declip : 1;
|
||||
} Auto;
|
||||
|
||||
ALsizei LookAhead;
|
||||
|
||||
ALfloat PreGain;
|
||||
ALfloat PostGain;
|
||||
|
||||
ALfloat Threshold;
|
||||
ALfloat Slope;
|
||||
ALfloat Knee;
|
||||
|
||||
ALfloat Attack;
|
||||
ALfloat Release;
|
||||
|
||||
alignas(16) ALfloat SideChain[2*BUFFERSIZE];
|
||||
alignas(16) ALfloat CrestFactor[BUFFERSIZE];
|
||||
|
||||
SlidingHold *Hold;
|
||||
ALfloat (*Delay)[BUFFERSIZE];
|
||||
ALsizei DelayIndex;
|
||||
|
||||
ALfloat CrestCoeff;
|
||||
ALfloat GainEstimate;
|
||||
ALfloat AdaptCoeff;
|
||||
|
||||
ALfloat LastPeakSq;
|
||||
ALfloat LastRmsSq;
|
||||
ALfloat LastRelease;
|
||||
ALfloat LastAttack;
|
||||
ALfloat LastGainDev;
|
||||
} Compressor;
|
||||
};
|
||||
|
||||
|
||||
/* This sliding hold follows the input level with an instant attack and a
|
||||
@@ -446,7 +396,7 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate,
|
||||
size += sizeof(*Comp->Hold);
|
||||
}
|
||||
|
||||
Comp = static_cast<Compressor*>(al_calloc(16, size));
|
||||
Comp = new (al_calloc(16, size)) Compressor{};
|
||||
Comp->NumChans = NumChans;
|
||||
Comp->SampleRate = SampleRate;
|
||||
Comp->Auto.Knee = AutoKnee;
|
||||
@@ -474,7 +424,7 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate,
|
||||
{
|
||||
if(hold > 0)
|
||||
{
|
||||
Comp->Hold = (SlidingHold*)(Comp + 1);
|
||||
Comp->Hold = new ((void*)(Comp + 1)) SlidingHold{};
|
||||
Comp->Hold->Values[0] = -HUGE_VALF;
|
||||
Comp->Hold->Expiries[0] = hold;
|
||||
Comp->Hold->Length = hold;
|
||||
@@ -495,21 +445,23 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate,
|
||||
|
||||
void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE])
|
||||
{
|
||||
const ALsizei numChans = Comp->NumChans;
|
||||
const ALfloat preGain = Comp->PreGain;
|
||||
ALfloat *RESTRICT sideChain;
|
||||
ALsizei c, i;
|
||||
const ALsizei numChans{Comp->NumChans};
|
||||
|
||||
ASSUME(SamplesToDo > 0);
|
||||
ASSUME(numChans > 0);
|
||||
|
||||
const ALfloat preGain{Comp->PreGain};
|
||||
if(preGain != 1.0f)
|
||||
{
|
||||
for(c = 0;c < numChans;c++)
|
||||
{
|
||||
for(i = 0;i < SamplesToDo;i++)
|
||||
OutBuffer[c][i] *= preGain;
|
||||
}
|
||||
std::for_each(OutBuffer, OutBuffer+numChans,
|
||||
[SamplesToDo, preGain](ALfloat *buffer) noexcept -> void
|
||||
{
|
||||
std::for_each(buffer, buffer+SamplesToDo,
|
||||
[preGain](ALfloat &samp) noexcept -> void
|
||||
{ samp *= preGain; }
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
LinkChannels(Comp, SamplesToDo, OutBuffer);
|
||||
@@ -527,14 +479,22 @@ void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RES
|
||||
if(Comp->Delay)
|
||||
SignalDelay(Comp, SamplesToDo, OutBuffer);
|
||||
|
||||
sideChain = Comp->SideChain;
|
||||
for(c = 0;c < numChans;c++)
|
||||
{
|
||||
for(i = 0;i < SamplesToDo;i++)
|
||||
OutBuffer[c][i] *= sideChain[i];
|
||||
}
|
||||
ALfloat *RESTRICT sideChain{Comp->SideChain};
|
||||
std::for_each(OutBuffer, OutBuffer+numChans,
|
||||
[SamplesToDo, sideChain](ALfloat *buffer) noexcept -> void
|
||||
{
|
||||
/* Mark the sideChain "input-1 type" as restrict, so the compiler
|
||||
* can vectorize this loop (otherwise it assumes a write to
|
||||
* buffer[n] can change sideChain[n+1]).
|
||||
*/
|
||||
std::transform<ALfloat*RESTRICT>(sideChain, sideChain+SamplesToDo, buffer, buffer,
|
||||
[](const ALfloat gain, const ALfloat samp) noexcept -> ALfloat
|
||||
{ return samp * gain; }
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
memmove(sideChain, sideChain+SamplesToDo, Comp->LookAhead*sizeof(ALfloat));
|
||||
std::copy(sideChain+SamplesToDo, sideChain+SamplesToDo+Comp->LookAhead, sideChain);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+59
-9
@@ -3,14 +3,68 @@
|
||||
|
||||
#include "AL/al.h"
|
||||
|
||||
#include "almalloc.h"
|
||||
/* For BUFFERSIZE. */
|
||||
#include "alMain.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Compressor;
|
||||
struct SlidingHold;
|
||||
|
||||
/* General topology and basic automation was based on the following paper:
|
||||
*
|
||||
* D. Giannoulis, M. Massberg and J. D. Reiss,
|
||||
* "Parameter Automation in a Dynamic Range Compressor,"
|
||||
* Journal of the Audio Engineering Society, v61 (10), Oct. 2013
|
||||
*
|
||||
* Available (along with supplemental reading) at:
|
||||
*
|
||||
* http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/
|
||||
*/
|
||||
struct Compressor {
|
||||
ALsizei NumChans;
|
||||
ALuint SampleRate;
|
||||
|
||||
struct {
|
||||
ALuint Knee : 1;
|
||||
ALuint Attack : 1;
|
||||
ALuint Release : 1;
|
||||
ALuint PostGain : 1;
|
||||
ALuint Declip : 1;
|
||||
} Auto;
|
||||
|
||||
ALsizei LookAhead;
|
||||
|
||||
ALfloat PreGain;
|
||||
ALfloat PostGain;
|
||||
|
||||
ALfloat Threshold;
|
||||
ALfloat Slope;
|
||||
ALfloat Knee;
|
||||
|
||||
ALfloat Attack;
|
||||
ALfloat Release;
|
||||
|
||||
alignas(16) ALfloat SideChain[2*BUFFERSIZE];
|
||||
alignas(16) ALfloat CrestFactor[BUFFERSIZE];
|
||||
|
||||
SlidingHold *Hold;
|
||||
ALfloat (*Delay)[BUFFERSIZE];
|
||||
ALsizei DelayIndex;
|
||||
|
||||
ALfloat CrestCoeff;
|
||||
ALfloat GainEstimate;
|
||||
ALfloat AdaptCoeff;
|
||||
|
||||
ALfloat LastPeakSq;
|
||||
ALfloat LastRmsSq;
|
||||
ALfloat LastRelease;
|
||||
ALfloat LastAttack;
|
||||
ALfloat LastGainDev;
|
||||
|
||||
void *operator new(size_t size) = delete;
|
||||
void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; }
|
||||
void operator delete(void *block) noexcept { al_free(block); }
|
||||
};
|
||||
|
||||
/* The compressor is initialized with the following settings:
|
||||
*
|
||||
@@ -36,7 +90,7 @@ struct Compressor;
|
||||
* ReleaseTimeMin - Release time (in seconds). Acts as a maximum when
|
||||
* automating release time.
|
||||
*/
|
||||
struct Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate,
|
||||
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,
|
||||
@@ -50,8 +104,4 @@ void ApplyCompression(struct Compressor *Comp, const ALsizei SamplesToDo,
|
||||
|
||||
ALsizei GetCompressorLookAhead(const struct Compressor *Comp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* MASTERING_H */
|
||||
|
||||
@@ -711,7 +711,7 @@ struct ALCdevice_struct {
|
||||
|
||||
struct FrontStablizer *Stablizer{nullptr};
|
||||
|
||||
struct Compressor *Limiter{nullptr};
|
||||
std::unique_ptr<Compressor> Limiter;
|
||||
|
||||
/* The average speaker distance as determined by the ambdec configuration
|
||||
* (or alternatively, by the NFC-HOA reference delay). Only used for NFC.
|
||||
|
||||
Reference in New Issue
Block a user