From c534e07424e934488f8870368943ef3c379ff763 Mon Sep 17 00:00:00 2001 From: Max Maisel Date: Mon, 15 Feb 2021 19:08:59 +0100 Subject: [PATCH] Replace Compressor2 dynamic makeup gain with fixed output gain. Signed-off-by: Max Maisel --- scripts/debug/compressor2_trace.m | 8 ++--- src/effects/Compressor2.cpp | 49 ++++++++++++------------------- src/effects/Compressor2.h | 5 +--- tests/octave/compressor2_test.m | 31 ++++++++++--------- 4 files changed, 39 insertions(+), 54 deletions(-) diff --git a/scripts/debug/compressor2_trace.m b/scripts/debug/compressor2_trace.m index 0307a0a9c..f7b2721d8 100644 --- a/scripts/debug/compressor2_trace.m +++ b/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 diff --git a/src/effects/Compressor2.cpp b/src/effects/Compressor2.cpp index 5af30a1ae..98a2a65ae 100644 --- a/src/effects/Compressor2.cpp +++ b/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); diff --git a/src/effects/Compressor2.h b/src/effects/Compressor2.h index de09581e8..f1be14686 100644 --- a/src/effects/Compressor2.h +++ b/src/effects/Compressor2.h @@ -209,7 +209,6 @@ public: private: // EffectCompressor2 implementation - void InitGainCalculation(); double CompressorGain(double env); std::unique_ptr 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; diff --git a/tests/octave/compressor2_test.m b/tests/octave/compressor2_test.m index 81c5783eb..46404c188 100644 --- a/tests/octave/compressor2_test.m +++ b/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));