mirror of
https://github.com/cookiengineer/audacity
synced 2025-04-29 23:29:41 +02:00
Implement compressor gain calculation and preview.
Signed-off-by: Max Maisel <max.maisel@posteo.de>
This commit is contained in:
parent
ac277c61d7
commit
7326edbefe
@ -18,6 +18,7 @@
|
|||||||
#include "Compressor2.h"
|
#include "Compressor2.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
#include <wx/intl.h>
|
#include <wx/intl.h>
|
||||||
#include <wx/valgen.h>
|
#include <wx/valgen.h>
|
||||||
@ -270,6 +271,9 @@ void EffectCompressor2::PopulateOrExchange(ShuttleGui & S)
|
|||||||
plot = mGainPlot->GetPlotData(0);
|
plot = mGainPlot->GetPlotData(0);
|
||||||
plot->pen = std::unique_ptr<wxPen>(
|
plot->pen = std::unique_ptr<wxPen>(
|
||||||
safenew wxPen(AColor::WideEnvelopePen));
|
safenew wxPen(AColor::WideEnvelopePen));
|
||||||
|
plot->xdata.resize(61);
|
||||||
|
plot->ydata.resize(61);
|
||||||
|
std::iota(plot->xdata.begin(), plot->xdata.end(), -60);
|
||||||
|
|
||||||
mResponsePlot = S.MinSize( { 200, 200 } )
|
mResponsePlot = S.MinSize( { 200, 200 } )
|
||||||
.AddPlot({}, 0, 5, -0.2, 1.2, XO("s"), XO(""),
|
.AddPlot({}, 0, 5, -0.2, 1.2, XO("s"), XO(""),
|
||||||
@ -465,6 +469,46 @@ bool EffectCompressor2::TransferDataFromWindow()
|
|||||||
|
|
||||||
// EffectCompressor2 implementation
|
// 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;
|
||||||
|
double envDB = LINEAR_TO_DB(env);
|
||||||
|
|
||||||
|
// envDB can become NaN is env is exactly zero.
|
||||||
|
// As solution, use a very low dB value to prevent NaN propagation.
|
||||||
|
if(isnan(envDB))
|
||||||
|
envDB = -200;
|
||||||
|
|
||||||
|
kneeCond = 2.0 * (envDB - mThresholdDB);
|
||||||
|
if(kneeCond < -mKneeWidthDB)
|
||||||
|
{
|
||||||
|
// Below threshold: only apply make-up gain
|
||||||
|
return mMakeupGain;
|
||||||
|
}
|
||||||
|
else if(kneeCond >= mKneeWidthDB)
|
||||||
|
{
|
||||||
|
// Above threshold: apply compression and make-up gain
|
||||||
|
return DB_TO_LINEAR(mThresholdDB +
|
||||||
|
(envDB - mThresholdDB) / mRatio + mMakeupGainDB - envDB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Within knee: apply interpolated compression and make-up gain
|
||||||
|
return DB_TO_LINEAR(
|
||||||
|
(1.0 / mRatio - 1.0)
|
||||||
|
* pow(envDB - mThresholdDB + mKneeWidthDB / 2.0, 2)
|
||||||
|
/ (2.0 * mKneeWidthDB) + mMakeupGainDB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void EffectCompressor2::OnUpdateUI(wxCommandEvent & WXUNUSED(evt))
|
void EffectCompressor2::OnUpdateUI(wxCommandEvent & WXUNUSED(evt))
|
||||||
{
|
{
|
||||||
if(!mIgnoreGuiEvents)
|
if(!mIgnoreGuiEvents)
|
||||||
@ -474,14 +518,30 @@ void EffectCompressor2::OnUpdateUI(wxCommandEvent & WXUNUSED(evt))
|
|||||||
|
|
||||||
void EffectCompressor2::UpdateUI()
|
void EffectCompressor2::UpdateUI()
|
||||||
{
|
{
|
||||||
PlotData* plot;
|
UpdateCompressorPlot();
|
||||||
plot = mGainPlot->GetPlotData(0);
|
|
||||||
plot->xdata = {-60, -40, 0};
|
|
||||||
plot->ydata = {-60, -40, -20};
|
|
||||||
mGainPlot->Refresh(false);
|
|
||||||
|
|
||||||
|
// TODO: update plots
|
||||||
|
PlotData* plot;
|
||||||
plot = mResponsePlot->GetPlotData(1);
|
plot = mResponsePlot->GetPlotData(1);
|
||||||
plot->xdata = {0, 2, 2, 3, 3, 5};
|
plot->xdata = {0, 2, 2, 3, 3, 5};
|
||||||
plot->ydata = {0, 0.5, 1, 1, 0.5, 0};
|
plot->ydata = {0, 0.5, 1, 1, 0.5, 0};
|
||||||
mResponsePlot->Refresh(false);
|
mResponsePlot->Refresh(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EffectCompressor2::UpdateCompressorPlot()
|
||||||
|
{
|
||||||
|
PlotData* plot;
|
||||||
|
plot = mGainPlot->GetPlotData(0);
|
||||||
|
wxASSERT(plot->xdata.size() == plot->ydata.size());
|
||||||
|
|
||||||
|
InitGainCalculation();
|
||||||
|
size_t xsize = plot->xdata.size();
|
||||||
|
for(size_t i = 0; i < xsize; ++i)
|
||||||
|
plot->ydata[i] = plot->xdata[i] +
|
||||||
|
LINEAR_TO_DB(CompressorGain(DB_TO_LINEAR(plot->xdata[i])));
|
||||||
|
|
||||||
|
// XXX: accessibility but fails with TranslatableString required
|
||||||
|
// mGainPlot->SetName(wxString::Format(
|
||||||
|
// "Compressor gain reduction: %.1f dB", plot->ydata[xsize-1]));
|
||||||
|
mGainPlot->Refresh(false);
|
||||||
|
}
|
||||||
|
@ -58,12 +58,14 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// EffectCompressor2 implementation
|
// EffectCompressor2 implementation
|
||||||
|
void InitGainCalculation();
|
||||||
|
double CompressorGain(double env);
|
||||||
|
|
||||||
bool UpdateProgress();
|
bool UpdateProgress();
|
||||||
void OnUpdateUI(wxCommandEvent & evt);
|
void OnUpdateUI(wxCommandEvent & evt);
|
||||||
void UpdateUI();
|
void UpdateUI();
|
||||||
|
void UpdateCompressorPlot();
|
||||||
|
|
||||||
private:
|
|
||||||
int mAlgorithm;
|
int mAlgorithm;
|
||||||
int mCompressBy;
|
int mCompressBy;
|
||||||
bool mStereoInd;
|
bool mStereoInd;
|
||||||
@ -78,6 +80,10 @@ private:
|
|||||||
double mMakeupGainPct;
|
double mMakeupGainPct;
|
||||||
double mDryWetPct;
|
double mDryWetPct;
|
||||||
|
|
||||||
|
// cached intermediate values
|
||||||
|
double mMakeupGain;
|
||||||
|
double mMakeupGainDB;
|
||||||
|
|
||||||
Plot* mGainPlot;
|
Plot* mGainPlot;
|
||||||
Plot* mResponsePlot;
|
Plot* mResponsePlot;
|
||||||
bool mIgnoreGuiEvents;
|
bool mIgnoreGuiEvents;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user