Browse Source

Replace Compressor2 dynamic makeup gain with fixed output gain.

Signed-off-by: Max Maisel <max.maisel@posteo.de>
pull/186/head
Max Maisel 10 months ago
parent
commit
c534e07424
  1. 8
      scripts/debug/compressor2_trace.m
  2. 49
      src/effects/Compressor2.cpp
  3. 5
      src/effects/Compressor2.h
  4. 31
      tests/octave/compressor2_test.m

8
scripts/debug/compressor2_trace.m

@ -19,7 +19,7 @@ data.attack_time = raw_data(:,4);
data.release_time = raw_data(:,5);
data.lookahead_time = raw_data(:,6);
data.lookbehind_time = raw_data(:,7);
data.makeup_gain_pct = raw_data(:,8);
data.output_gain_DB = raw_data(:,8);
if stereo
data.in = horzcat(raw_data(:,9), raw_data(:,10));
@ -44,7 +44,7 @@ plot(data.attack_time.*10, 'c', "linewidth", 2);
plot(data.release_time.*10, 'c', "linewidth", 2);
plot(data.lookahead_time, 'm');
plot(data.lookbehind_time, 'm');
plot(data.makeup_gain_pct, 'r');
plot(data.output_gain_DB, 'r');
plot(data.env.*100, 'k', "linewidth", 2);
plot(data.gain.*50, 'k', "linestyle", '--');
hold off;
@ -53,9 +53,9 @@ grid;
if stereo
legend("in*100", "in*100", "out*100", "out*100", "threshold", "ratio", ...
"kneewidth", "attack*10", "release*10", "lookahead", "lookbehind", ...
"makeup", "env*100", "gain*50");
"out_gain", "env*100", "gain*50");
else
legend("in*100", "out*100", "threshold", "ratio", ...
"kneewidth", "attack*10", "release*10", "lookahead", "lookbehind", ...
"makeup", "env*100", "gain*50");
"out_gain", "env*100", "gain*50");
end

49
src/effects/Compressor2.cpp

@ -89,7 +89,7 @@ Param( AttackTime, double, wxT("AttackTime"), 0.2, 0.0001, 30.
Param( ReleaseTime, double, wxT("ReleaseTime"), 1.0, 0.0001, 30.0, 2000.0 );
Param( LookaheadTime, double, wxT("LookaheadTime"), 0.0, 0.0, 10.0, 200.0 );
Param( LookbehindTime, double, wxT("LookbehindTime"), 0.1, 0.0, 10.0, 200.0 );
Param( MakeupGain, double, wxT("MakeupGain"), 0.0, 0.0, 100.0, 1.0 );
Param( OutputGain, double, wxT("OutputGain"), 0.0, 0.0, 50.0, 10.0 );
inline int ScaleToPrecision(double scale)
{
@ -548,7 +548,7 @@ EffectCompressor2::EffectCompressor2()
mReleaseTime = DEF_ReleaseTime; // seconds
mLookaheadTime = DEF_LookaheadTime;
mLookbehindTime = DEF_LookbehindTime;
mMakeupGainPct = DEF_MakeupGain;
mOutputGainDB = DEF_OutputGain;
SetLinearEffectFlag(false);
}
@ -682,7 +682,7 @@ bool EffectCompressor2::DefineParams( ShuttleParams & S )
S.SHUTTLE_PARAM(mReleaseTime, ReleaseTime);
S.SHUTTLE_PARAM(mLookaheadTime, LookaheadTime);
S.SHUTTLE_PARAM(mLookbehindTime, LookbehindTime);
S.SHUTTLE_PARAM(mMakeupGainPct, MakeupGain);
S.SHUTTLE_PARAM(mOutputGainDB, OutputGain);
return true;
}
@ -700,7 +700,7 @@ bool EffectCompressor2::GetAutomationParameters(CommandParameters & parms)
parms.Write(KEY_ReleaseTime, mReleaseTime);
parms.Write(KEY_LookaheadTime, mLookaheadTime);
parms.Write(KEY_LookbehindTime, mLookbehindTime);
parms.Write(KEY_MakeupGain, mMakeupGainPct);
parms.Write(KEY_OutputGain, mOutputGainDB);
return true;
}
@ -718,7 +718,7 @@ bool EffectCompressor2::SetAutomationParameters(CommandParameters & parms)
ReadAndVerifyDouble(ReleaseTime);
ReadAndVerifyDouble(LookaheadTime);
ReadAndVerifyDouble(LookbehindTime);
ReadAndVerifyDouble(MakeupGain);
ReadAndVerifyDouble(OutputGain);
mAlgorithm = Algorithm;
mCompressBy = CompressBy;
@ -731,7 +731,7 @@ bool EffectCompressor2::SetAutomationParameters(CommandParameters & parms)
mReleaseTime = ReleaseTime;
mLookaheadTime = LookaheadTime;
mLookbehindTime = LookbehindTime;
mMakeupGainPct = MakeupGain;
mOutputGainDB = OutputGain;
return true;
}
@ -760,7 +760,7 @@ bool EffectCompressor2::Startup()
mReleaseTime = DEF_ReleaseTime; // seconds
mLookaheadTime = DEF_LookaheadTime;
mLookbehindTime = DEF_LookbehindTime;
mMakeupGainPct = DEF_MakeupGain;
mOutputGainDB = DEF_OutputGain;
SaveUserPreset(GetCurrentSettingsGroup());
@ -805,7 +805,6 @@ bool EffectCompressor2::Process()
mProcStereo = range.size() > 1;
InitGainCalculation();
mPreproc = InitPreprocessor(mSampleRate);
mEnvelope = InitEnvelope(mSampleRate, mPipeline[0].capacity());
@ -973,16 +972,15 @@ void EffectCompressor2::PopulateOrExchange(ShuttleGui & S)
S.AddVariableText(XO("dB"), true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
/* i18n-hint: Make-up, i.e. correct for any reduction, rather than fabricate it.*/
S.AddVariableText(XO("Make-up Gain:"), true,
S.AddVariableText(XO("Output Gain:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
ctrl = S.Name(XO("Make-up Gain"))
ctrl = S.Name(XO("Output Gain"))
.Style(SliderTextCtrl::HORIZONTAL)
.AddSliderTextCtrl({}, DEF_MakeupGain, MAX_MakeupGain,
MIN_MakeupGain, ScaleToPrecision(SCL_MakeupGain),
&mMakeupGainPct);
.AddSliderTextCtrl({}, DEF_OutputGain, MAX_OutputGain,
MIN_OutputGain, ScaleToPrecision(SCL_OutputGain),
&mOutputGainDB);
ctrl->SetMinTextboxWidth(textbox_width);
S.AddVariableText(XO("%"), true,
S.AddVariableText(XO("dB"), true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
}
S.EndMultiColumn();
@ -1075,13 +1073,6 @@ bool EffectCompressor2::TransferDataFromWindow()
// EffectCompressor2 implementation
void EffectCompressor2::InitGainCalculation()
{
mMakeupGainDB = mMakeupGainPct / 100.0 *
-(mThresholdDB * (1.0 - 1.0 / mRatio));
mMakeupGain = DB_TO_LINEAR(mMakeupGainDB);
}
double EffectCompressor2::CompressorGain(double env)
{
double kneeCond;
@ -1096,13 +1087,13 @@ double EffectCompressor2::CompressorGain(double env)
if(kneeCond < -mKneeWidthDB)
{
// Below threshold: only apply make-up gain
return mMakeupGain;
return DB_TO_LINEAR(mOutputGainDB);
}
else if(kneeCond >= mKneeWidthDB)
{
// Above threshold: apply compression and make-up gain
return DB_TO_LINEAR(mThresholdDB +
(envDB - mThresholdDB) / mRatio + mMakeupGainDB - envDB);
(envDB - mThresholdDB) / mRatio + mOutputGainDB - envDB);
}
else
{
@ -1110,7 +1101,7 @@ double EffectCompressor2::CompressorGain(double env)
return DB_TO_LINEAR(
(1.0 / mRatio - 1.0)
* pow(envDB - mThresholdDB + mKneeWidthDB / 2.0, 2)
/ (2.0 * mKneeWidthDB) + mMakeupGainDB);
/ (2.0 * mKneeWidthDB) + mOutputGainDB);
}
}
@ -1500,7 +1491,7 @@ inline void EffectCompressor2::CompressSample(float env, size_t wp)
float ReleaseTime = mReleaseTime;
float LookaheadTime = mLookaheadTime;
float LookbehindTime = mLookbehindTime;
float MakeupGainPct = mMakeupGainPct;
float OutputGainDB = mOutputGainDB;
debugfile.write((char*)&ThresholdDB, sizeof(float));
debugfile.write((char*)&Ratio, sizeof(float));
@ -1509,7 +1500,7 @@ inline void EffectCompressor2::CompressSample(float env, size_t wp)
debugfile.write((char*)&ReleaseTime, sizeof(float));
debugfile.write((char*)&LookaheadTime, sizeof(float));
debugfile.write((char*)&LookbehindTime, sizeof(float));
debugfile.write((char*)&MakeupGainPct, sizeof(float));
debugfile.write((char*)&OutputGainDB, sizeof(float));
debugfile.write((char*)&mPipeline[0][0][wp], sizeof(float));
if(mProcStereo)
debugfile.write((char*)&mPipeline[0][1][wp], sizeof(float));
@ -1641,10 +1632,9 @@ void EffectCompressor2::UpdateCompressorPlot()
return;
if(!IsInRange(mKneeWidthDB, MIN_KneeWidth, MAX_KneeWidth))
return;
if(!IsInRange(mMakeupGainPct, MIN_MakeupGain, MAX_MakeupGain))
if(!IsInRange(mOutputGainDB, MIN_OutputGain, MAX_OutputGain))
return;
InitGainCalculation();
size_t xsize = plot->xdata.size();
for(size_t i = 0; i < xsize; ++i)
plot->ydata[i] = plot->xdata[i] +
@ -1678,7 +1668,6 @@ void EffectCompressor2::UpdateResponsePlot()
lookahead_size -= (lookahead_size > 0);
ssize_t block_size = float(TAU_FACTOR) * (mAttackTime + 1.0) * plot_rate;
InitGainCalculation();
preproc = InitPreprocessor(plot_rate, true);
envelope = InitEnvelope(plot_rate, block_size, true);

5
src/effects/Compressor2.h

@ -209,7 +209,6 @@ public:
private:
// EffectCompressor2 implementation
void InitGainCalculation();
double CompressorGain(double env);
std::unique_ptr<SamplePreprocessor> InitPreprocessor(
double rate, bool preview = false);
@ -269,11 +268,9 @@ private:
double mReleaseTime;
double mLookaheadTime;
double mLookbehindTime;
double mMakeupGainPct;
double mOutputGainDB;
// cached intermediate values
double mMakeupGain;
double mMakeupGainDB;
size_t mLookaheadLength;
static const size_t RESPONSE_PLOT_SAMPLES = 200;

31
tests/octave/compressor2_test.m

@ -48,8 +48,7 @@ function y = env_PT1_asym(x, fs, t_a, t_r, gain = 0)
end
## Compressor gain helper function
function gain = comp_gain(env, thresh_DB, ratio, kneeW_DB, makeup)
makeupG_DB = -thresh_DB * (1-1/ratio) * makeup / 100;
function gain = comp_gain(env, thresh_DB, ratio, kneeW_DB, outG_DB)
env_DB = 20*log10(env);
kneeCond_DB = 2*(env_DB-thresh_DB);
@ -59,15 +58,15 @@ function gain = comp_gain(env, thresh_DB, ratio, kneeW_DB, makeup)
withinKnee = (kneeCond_DB >= -kneeW_DB) & (kneeCond_DB < kneeW_DB);
gain_DB = zeros(size(env));
gain_DB(belowKnee) = makeupG_DB;
gain_DB(belowKnee) = outG_DB;
gain_DB(aboveKnee) = thresh_DB + ...
(env_DB(aboveKnee) - thresh_DB) / ratio + ...
makeupG_DB - env_DB(aboveKnee);
outG_DB - env_DB(aboveKnee);
# Prevent division by zero
kneeW_DB(kneeW_DB==0) = 0.000001;
gain_DB(withinKnee) = (1/ratio-1) * ...
(env_DB(withinKnee) - thresh_DB + kneeW_DB/2).^2 / ...
(2*kneeW_DB) + makeupG_DB;
(2*kneeW_DB) + outG_DB;
gain = 10.^(gain_DB/20);
end
@ -173,7 +172,7 @@ CURRENT_TEST = "Compressor2, mono compression PT1 - sinewave - asymetric attack
x2 = sin(2*pi*300/fs*(1:1:20*fs)).';
remove_all_tracks();
x = export_to_aud(x2, fs, "Compressor-mono-sine-test.wav");
aud_do("DynamicCompressor: Threshold=-6 Algorithm=1 CompressBy=0 Ratio=2.0 AttackTime=1.0 ReleaseTime=0.3 LookaheadTime=0 LookbehindTime=0 KneeWidth=0 MakeupGain=0\n");
aud_do("DynamicCompressor: Threshold=-6 Algorithm=1 CompressBy=0 Ratio=2.0 AttackTime=1.0 ReleaseTime=0.3 LookaheadTime=0 LookbehindTime=0 KneeWidth=0 OutputGain=0\n");
y = import_from_aud(1);
do_test_equ(settled(y, fs, 1), ...
@ -184,22 +183,22 @@ do_test_equ(settled(y, fs, 1), ...
CURRENT_TEST = "Compressor2, mono asymmetric lookaround max";
remove_all_tracks();
x = export_to_aud(x1, fs);
aud_do("DynamicCompressor: Threshold=-17 Algorithm=1 CompressBy=0 Ratio=1.2 AttackTime=0.3 ReleaseTime=0.3 LookaheadTime=0.2 LookbehindTime=0.1 KneeWidth=5 MakeupGain=50\n");
aud_do("DynamicCompressor: Threshold=-17 Algorithm=1 CompressBy=0 Ratio=1.2 AttackTime=0.3 ReleaseTime=0.3 LookaheadTime=0.2 LookbehindTime=0.1 KneeWidth=5 OutputGain=1\n");
y = import_from_aud(1);
do_test_equ(settled(y, fs, 0.6), ...
comp_gain(settled(env_PT1(lookaround_max(x, fs, 0.2, 0.1), fs, 0.3, 1), fs, 0.6), ...
-17, 1.2, 5, 50).*settled(x, fs, 0.6));
-17, 1.2, 5, 1).*settled(x, fs, 0.6));
## Test Compressor, mono lookaround RMS
CURRENT_TEST = "Compressor2, mono asymmetric lookaround RMS";
remove_all_tracks();
x = export_to_aud(x1, fs);
aud_do("DynamicCompressor: Threshold=-20 Algorithm=1 CompressBy=1 Ratio=3 AttackTime=1 ReleaseTime=1 LookaheadTime=0.1 LookbehindTime=0.2 KneeWidth=3 MakeupGain=80\n");
aud_do("DynamicCompressor: Threshold=-20 Algorithm=1 CompressBy=1 Ratio=3 AttackTime=1 ReleaseTime=1 LookaheadTime=0.1 LookbehindTime=0.2 KneeWidth=3 OutputGain=2\n");
y = import_from_aud(1);
do_test_equ(settled(y, fs, 2), ...
comp_gain(settled(env_PT1(lookaround_RMS(x, fs, 0.1, 0.2), fs, 1), fs, 2), -20, 3, 3, 80) ...
comp_gain(settled(env_PT1(lookaround_RMS(x, fs, 0.1, 0.2), fs, 1), fs, 2), -20, 3, 3, 2) ...
.*settled(x, fs, 2));
## Test Compressor, mono lookaround max with selection
@ -208,13 +207,13 @@ remove_all_tracks();
x = export_to_aud(x1, fs);
aud_do("Select: Start=2 End=5 Mode=Set\n");
aud_do("DynamicCompressor: Threshold=-17 Algorithm=1 CompressBy=0 Ratio=1.2 AttackTime=0.3 ReleaseTime=0.3 LookaheadTime=0.2 LookbehindTime=0.2 KneeWidth=5 MakeupGain=50\n");
aud_do("DynamicCompressor: Threshold=-17 Algorithm=1 CompressBy=0 Ratio=1.2 AttackTime=0.3 ReleaseTime=0.3 LookaheadTime=0.2 LookbehindTime=0.2 KneeWidth=5 OutputGain=0.5\n");
y = import_from_aud(1);
x = x(2*fs+1:5*fs);
do_test_equ(settled(y, fs, 0.1), ...
comp_gain(settled(env_PT1(lookaround_max(x, fs, 0.2, 0.2), fs, 0.3, 1), fs, 0.1), ...
-17, 1.2, 5, 50).*settled(x, fs, 0.1));
-17, 1.2, 5, 0.5).*settled(x, fs, 0.1));
## Test Compressor, mono, ultra short attack time
CURRENT_TEST = "Compressor2, mono, ultra short attack time";
@ -287,20 +286,20 @@ do_test_equ(settled(y(:,2), fs, 1), ...
CURRENT_TEST = "Compressor2, stereo lookaround max";
remove_all_tracks();
x = export_to_aud(x1, fs);
aud_do("DynamicCompressor: Threshold=-17 Algorithm=1 Ratio=1.2 AttackTime=0.3 ReleaseTime=0.3 LookaheadTime=0.2 LookbehindTime=0.2 KneeWidth=5 MakeupGain=50\n");
aud_do("DynamicCompressor: Threshold=-17 Algorithm=1 Ratio=1.2 AttackTime=0.3 ReleaseTime=0.3 LookaheadTime=0.2 LookbehindTime=0.2 KneeWidth=5 OutputGain=1\n");
y = import_from_aud(2);
do_test_equ(settled(y, fs, 0.6), ...
comp_gain(settled(env_PT1(lookaround_max(x, fs, 0.2, 0.2), fs, 0.3, 1), fs, 0.6), ...
-17, 1.2, 5, 50).*settled(x, fs, 0.6));
-17, 1.2, 5, 1).*settled(x, fs, 0.6));
## Test Compressor, stereo lookaround RMS
CURRENT_TEST = "Compressor2, stereo lookaround RMS";
remove_all_tracks();
x = export_to_aud(x1, fs);
aud_do("DynamicCompressor: Threshold=-20 Algorithm=1 Ratio=3 AttackTime=1 ReleaseTime=1 LookaheadTime=0.1 LookbehindTime=0.1 KneeWidth=3 CompressBy=1 MakeupGain=60\n");
aud_do("DynamicCompressor: Threshold=-20 Algorithm=1 Ratio=3 AttackTime=1 ReleaseTime=1 LookaheadTime=0.1 LookbehindTime=0.1 KneeWidth=3 CompressBy=1 OutputGain=1.3\n");
y = import_from_aud(2);
do_test_equ(settled(y, fs, 2.5), ...
comp_gain(settled(env_PT1(lookaround_RMS(x, fs, 0.1, 0.1), fs, 1), fs, 2.5), -20, 3, 3, 60) ...
comp_gain(settled(env_PT1(lookaround_RMS(x, fs, 0.1, 0.1), fs, 1), fs, 2.5), -20, 3, 3, 1.3) ...
.*settled(x, fs, 2.5));
Loading…
Cancel
Save