diff --git a/src/effects/BassTreble.cpp b/src/effects/BassTreble.cpp index 5f6801ad0..d15034b53 100644 --- a/src/effects/BassTreble.cpp +++ b/src/effects/BassTreble.cpp @@ -1,7 +1,7 @@ /********************************************************************** Audacity: A Digital Audio Editor - Audacity(R) is copyright (c) 1999-2013 Audacity Team. + Audacity(R) is copyright (c) 1999-2016 Audacity Team. License: GPL v2. See License.txt. BassTreble.cpp @@ -12,10 +12,6 @@ \class EffectBassTreble \brief A high shelf and low shelf filter. - The first pass applies the equalization and calculates the - peak value. The second pass, if enabled, normalizes to the - level set by the level control. - *//*******************************************************************/ #include "../Audacity.h" @@ -37,21 +33,20 @@ enum { ID_Bass = 10000, ID_Treble, - ID_Level, - ID_Normalize, + ID_Gain, + ID_Link }; // Define keys, defaults, minimums, and maximums for the effect parameters // -// Name Type Key Def Min Max Scale -Param( Bass, double, XO("Bass"), 0.0, -30.0, 30.0, 1 ); -Param( Treble, double, XO("Treble"), 0.0, -30.0, 30.0, 1 ); -Param( Level, double, XO("Level"), -1.0, -30.0, 0.0, 1 ); -Param( Normalize, bool, XO("Normalize"), true, false, true, 1 ); +// Name Type Key Def Min Max Scale +Param( Bass, double, XO("Bass"), 0.0, -30.0, 30.0, 1 ); +Param( Treble, double, XO("Treble"), 0.0, -30.0, 30.0, 1 ); +Param( Gain, double, XO("Gain"), 0.0, -30.0, 30.0, 1 ); +Param( Link, bool, XO("Link Sliders"), false, false, true, 1 ); -// Sliders are integer, so range is x 10 -// to allow 1 decimal place resolution -static const int kSliderScale = 10; +#include +WX_DEFINE_OBJARRAY(EffectBassTrebleStateArray); // Used to communicate the type of the filter. enum kShelfType @@ -61,23 +56,23 @@ enum kShelfType }; BEGIN_EVENT_TABLE(EffectBassTreble, wxEvtHandler) - EVT_SLIDER(ID_Bass, EffectBassTreble::OnBassSlider) - EVT_SLIDER(ID_Treble, EffectBassTreble::OnTrebleSlider) - EVT_SLIDER(ID_Level, EffectBassTreble::OnLevelSlider) - EVT_TEXT(ID_Bass, EffectBassTreble::OnBassText) - EVT_TEXT(ID_Treble, EffectBassTreble::OnTrebleText) - EVT_TEXT(ID_Level, EffectBassTreble::OnLevelText) - EVT_CHECKBOX(ID_Normalize, EffectBassTreble::OnNormalize) + EVT_SLIDER(ID_Bass, EffectBassTreble::OnBassSlider) + EVT_SLIDER(ID_Treble, EffectBassTreble::OnTrebleSlider) + EVT_SLIDER(ID_Gain, EffectBassTreble::OnGainSlider) + EVT_TEXT(ID_Bass, EffectBassTreble::OnBassText) + EVT_TEXT(ID_Treble, EffectBassTreble::OnTrebleText) + EVT_TEXT(ID_Gain, EffectBassTreble::OnGainText) + EVT_CHECKBOX(ID_Link, EffectBassTreble::OnLinkCheckbox) END_EVENT_TABLE() EffectBassTreble::EffectBassTreble() { - dB_bass = DEF_Bass; - dB_treble = DEF_Treble; - dB_level = DEF_Level; - mbNormalize = DEF_Normalize; + mBass = DEF_Bass; + mTreble = DEF_Treble; + mGain = DEF_Gain; + mLink = DEF_Link; - SetLinearEffectFlag(false); + SetLinearEffectFlag(true); } EffectBassTreble::~EffectBassTreble() @@ -93,7 +88,7 @@ wxString EffectBassTreble::GetSymbol() wxString EffectBassTreble::GetDescription() { - return XO("Increases or decreases the lower frequencies and higher frequencies of your audio independently"); + return XO("Simple tone control effect"); } // EffectIdentInterface implementation @@ -103,6 +98,16 @@ EffectType EffectBassTreble::GetType() return EffectTypeProcess; } +bool EffectBassTreble::SupportsRealtime() +{ +#if defined(EXPERIMENTAL_REALTIME_AUDACITY_EFFECTS) + return true; +#else + return false; +#endif +} + + // EffectClientInterface implementation int EffectBassTreble::GetAudioInCount() @@ -117,61 +122,57 @@ int EffectBassTreble::GetAudioOutCount() bool EffectBassTreble::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap)) { - if (GetPass() == 1) - { - const float slope = 0.4f; // same slope for both filters - const double hzBass = 250.0f; - const double hzTreble = 4000.0f; - - //(re)initialise filter parameters - xn1Bass=xn2Bass=yn1Bass=yn2Bass=0; - xn1Treble=xn2Treble=yn1Treble=yn2Treble=0; - - // Compute coefficents of the low shelf biquand IIR filter - Coefficents(hzBass, slope, dB_bass, kBass, - a0Bass, a1Bass, a2Bass, - b0Bass, b1Bass, b2Bass); - - // Compute coefficents of the high shelf biquand IIR filter - Coefficents(hzTreble, slope, dB_treble, kTreble, - a0Treble, a1Treble, a2Treble, - b0Treble, b1Treble, b2Treble); - } + InstanceInit(mMaster, mSampleRate); return true; } sampleCount EffectBassTreble::ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen) { - float *ibuf = inBlock[0]; - float *obuf = outBlock[0]; + return InstanceProcess(mMaster, inBlock, outBlock, blockLen); +} - if (GetPass() == 1) - { - for (sampleCount i = 0; i < blockLen; i++) - { - obuf[i] = DoFilter(ibuf[i]) / mPreGain; - } - } - else - { - float gain = DB_TO_LINEAR(dB_level) / mMax; - for (sampleCount i = 0; i < blockLen; i++) - { - // Normalize to specified level - obuf[i] = ibuf[i] * (mPreGain * gain); - } - } +bool EffectBassTreble::RealtimeInitialize() +{ + SetBlockSize(512); - return blockLen; + mSlaves.Clear(); + + return true; +} + +bool EffectBassTreble::RealtimeAddProcessor(int WXUNUSED(numChannels), float sampleRate) +{ + EffectBassTrebleState slave; + + InstanceInit(slave, sampleRate); + + mSlaves.Add(slave); + + return true; +} + +bool EffectBassTreble::RealtimeFinalize() +{ + mSlaves.Clear(); + + return true; +} + +sampleCount EffectBassTreble::RealtimeProcess(int group, + float **inbuf, + float **outbuf, + sampleCount numSamples) +{ + return InstanceProcess(mSlaves[group], inbuf, outbuf, numSamples); } bool EffectBassTreble::GetAutomationParameters(EffectAutomationParameters & parms) { - parms.Write(KEY_Bass, dB_bass); - parms.Write(KEY_Treble, dB_treble); - parms.Write(KEY_Level, dB_level); - parms.Write(KEY_Normalize, mbNormalize); + parms.Write(KEY_Bass, mBass); + parms.Write(KEY_Treble, mTreble); + parms.Write(KEY_Gain, mGain); + parms.Write(KEY_Link, mLink); return true; } @@ -180,144 +181,88 @@ bool EffectBassTreble::SetAutomationParameters(EffectAutomationParameters & parm { ReadAndVerifyDouble(Bass); ReadAndVerifyDouble(Treble); - ReadAndVerifyDouble(Level); - ReadAndVerifyBool(Normalize); + ReadAndVerifyDouble(Gain); + ReadAndVerifyBool(Link); - dB_bass = Bass; - dB_treble = Treble; - dB_level = Level; - mbNormalize = Normalize; + mBass = Bass; + mTreble = Treble; + mGain = Gain; + mLink = Link; return true; } +bool EffectBassTreble::CheckWhetherSkipEffect() +{ + return (mBass == 0.0 && mTreble == 0.0 && mGain == 0.0); +} + + // Effect implementation -bool EffectBassTreble::Startup() -{ - wxString base = wxT("/Effects/BassTreble/"); - - // Migrate settings from 2.1.0 or before - - // Already migrated, so bail - if (gPrefs->Exists(base + wxT("Migrated"))) - { - return true; - } - - // Load the old "current" settings - if (gPrefs->Exists(base)) - { - int readBool; - gPrefs->Read(base + wxT("Bass"), &dB_bass, 0.0); - gPrefs->Read(base + wxT("Treble"), &dB_treble, 0.0); - gPrefs->Read(base + wxT("Level"), &dB_level, -1.0); - gPrefs->Read(base + wxT("Normalize"), &readBool, 1 ); - - // Validate data - dB_level = (dB_level > 0) ? 0 : dB_level; - mbNormalize = (readBool != 0); - - SaveUserPreset(GetCurrentSettingsGroup()); - - // Do not migrate again - gPrefs->Write(base + wxT("Migrated"), true); - gPrefs->Flush(); - } - - return true; -} - -bool EffectBassTreble::InitPass1() -{ - mMax = 0.0; - - // Integer format tracks require headroom to avoid clipping - // when saved between passes (bug 619) - - if (mbNormalize) // don't need to calculate this if only doing one pass. - { - // Up to (gain + 6dB) headroom required for treble boost (experimental). - mPreGain = (dB_treble > 0) ? (dB_treble + 6.0) : 0.0; - if (dB_bass >= 0) - { - mPreGain = (mPreGain > dB_bass) ? mPreGain : dB_bass; - } - else - { - // Up to 6 dB headroom reaquired for bass cut (experimental) - mPreGain = (mPreGain > 6.0) ? mPreGain : 6.0; - } - mPreGain = (exp(log(10.0) * mPreGain / 20)); // to linear - } - else - { - mPreGain = 1.0; // Unity gain - } - - return true; -} - -bool EffectBassTreble::InitPass2() -{ - return mbNormalize && mMax != 0; -} - void EffectBassTreble::PopulateOrExchange(ShuttleGui & S) { - S.StartVerticalLay(0); + S.SetBorder(5); + S.AddSpace(0, 5); + + S.StartStatic(_("Tone controls")); { S.StartMultiColumn(3, wxEXPAND); - S.SetStretchyCol(2); { + S.SetStretchyCol(2); + // Bass control - FloatingPointValidator vldBass(1, &dB_bass); + FloatingPointValidator vldBass(1, &mBass); vldBass.SetRange(MIN_Bass, MAX_Bass); mBassT = S.Id(ID_Bass).AddTextBox(_("&Bass (dB):"), wxT(""), 10); mBassT->SetName(_("Bass (dB):")); mBassT->SetValidator(vldBass); S.SetStyle(wxSL_HORIZONTAL); - mBassS = S.Id(ID_Bass).AddSlider(wxT(""), 0, MAX_Bass * kSliderScale, MIN_Bass * kSliderScale); + mBassS = S.Id(ID_Bass).AddSlider(wxT(""), 0, MAX_Bass * SCL_Bass, MIN_Bass * SCL_Bass); mBassS->SetName(_("Bass")); - mBassS->SetPageSize(30); // Treble control - FloatingPointValidator vldTreble(1, &dB_treble); + FloatingPointValidator vldTreble(1, &mTreble); vldTreble.SetRange(MIN_Treble, MAX_Treble); mTrebleT = S.Id(ID_Treble).AddTextBox(_("&Treble (dB):"), wxT(""), 10); mTrebleT->SetValidator(vldTreble); S.SetStyle(wxSL_HORIZONTAL); - mTrebleS = S.Id(ID_Treble).AddSlider(wxT(""), 0, MAX_Treble * kSliderScale, MIN_Treble * kSliderScale); + mTrebleS = S.Id(ID_Treble).AddSlider(wxT(""), 0, MAX_Treble * SCL_Treble, MIN_Treble * SCL_Treble); mTrebleS->SetName(_("Treble")); - mTrebleS->SetPageSize(30); + } + S.EndMultiColumn(); + } + S.EndStatic(); - // Level control - FloatingPointValidator vldLevel(1, &dB_level); - vldLevel.SetRange(MIN_Level, MAX_Level); - mLevelT = S.Id(ID_Level).AddTextBox(_("&Level (dB):"), wxT(""), 10); - mLevelT->SetValidator(vldLevel); + S.StartStatic("Output"); + { + S.StartMultiColumn(3, wxEXPAND); + { + S.SetStretchyCol(2); + + // Gain control + FloatingPointValidator vldGain(1, &mGain); + vldGain.SetRange(MIN_Gain, MAX_Gain); + mGainT = S.Id(ID_Gain).AddTextBox(_("&Volume (dB):"), wxT(""), 10); + mGainT->SetValidator(vldGain); S.SetStyle(wxSL_HORIZONTAL); - mLevelS = S.Id(ID_Level).AddSlider(wxT(""), 0, MAX_Level * kSliderScale, MIN_Level * kSliderScale); - mLevelS->SetName(_("Level")); - mLevelS->SetPageSize(30); + mGainS = S.Id(ID_Gain).AddSlider(wxT(""), 0, MAX_Gain * SCL_Gain, MIN_Gain * SCL_Gain); + mGainS->SetName(_("Level")); } S.EndMultiColumn(); - // Normalize checkbox - S.StartHorizontalLay(wxLEFT, true); + S.StartMultiColumn(2, wxCENTER); { - mNormalizeCheckBox = S.Id(ID_Normalize).AddCheckBox(_("&Enable level control"), - DEF_Normalize ? wxT("true") : wxT("false")); - mWarning = S.AddVariableText(wxT(""), false, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT); + // Link checkbox + mLinkCheckBox = S.Id(ID_Link).AddCheckBox(_("Link Volume control to Tone controls"), + DEF_Link ? wxT("true") : wxT("false")); } - S.EndHorizontalLay(); + S.EndMultiColumn(); } - S.EndVerticalLay(); - - return; + S.EndStatic(); } bool EffectBassTreble::TransferDataToWindow() @@ -327,12 +272,10 @@ bool EffectBassTreble::TransferDataToWindow() return false; } - mBassS->SetValue((int) dB_bass * kSliderScale + 0.5); - mTrebleS->SetValue((int) dB_treble * kSliderScale + 0.5); - mLevelS->SetValue((int) dB_level * kSliderScale + 0.5); - mNormalizeCheckBox->SetValue(mbNormalize); - - UpdateUI(); + mBassS->SetValue((int) (mBass * SCL_Bass)); + mTrebleS->SetValue((int) mTreble *SCL_Treble); + mGainS->SetValue((int) mGain * SCL_Gain); + mLinkCheckBox->SetValue(mLink); return true; } @@ -344,18 +287,96 @@ bool EffectBassTreble::TransferDataFromWindow() return false; } - mbNormalize = mNormalizeCheckBox->GetValue(); - return true; } + // EffectBassTreble implementation -void EffectBassTreble::Coefficents(double hz, float slope, double gain, int type, - float& a0, float& a1, float& a2, - float& b0, float& b1, float& b2) +void EffectBassTreble::InstanceInit(EffectBassTrebleState & data, float sampleRate) { - double w = 2 * M_PI * hz / mSampleRate; + data.samplerate = sampleRate; + data.slope = 0.4f; // same slope for both filters + data.hzBass = 250.0f; // could be tunable in a more advanced version + data.hzTreble = 4000.0f; // could be tunable in a more advanced version + + data.a0Bass = 1; + data.a1Bass = 0; + data.a2Bass = 0; + data.b0Bass = 0; + data.b1Bass = 0; + data.b2Bass = 0; + + data.a0Treble = 1; + data.a1Treble = 0; + data.a2Treble = 0; + data.b0Treble = 0; + data.b1Treble = 0; + data.b2Treble = 0; + + data.xn1Bass = 0; + data.xn2Bass = 0; + data.yn1Bass = 0; + data.yn2Bass = 0; + + data.xn1Treble = 0; + data.xn2Treble = 0; + data.yn1Treble = 0; + data.yn2Treble = 0; + + data.bass = -1; + data.treble = -1; + data.gain = DB_TO_LINEAR(mGain); + +} + + +// EffectClientInterface implementation + + +sampleCount EffectBassTreble::InstanceProcess(EffectBassTrebleState & data, + float **inBlock, + float **outBlock, + sampleCount blockLen) +{ + float *ibuf = inBlock[0]; + float *obuf = outBlock[0]; + + // Set value to ensure correct rounding + double oldBass = DB_TO_LINEAR(mBass); + double oldTreble = DB_TO_LINEAR(mTreble); + + data.gain = DB_TO_LINEAR(mGain); + + // Compute coefficents of the low shelf biquand IIR filter + if (data.bass != oldBass) + Coefficents(data.hzBass, data.slope, mBass, data.samplerate, kBass, + data.a0Bass, data.a1Bass, data.a2Bass, + data.b0Bass, data.b1Bass, data.b2Bass); + + // Compute coefficents of the high shelf biquand IIR filter + if (data.treble != oldTreble) + Coefficents(data.hzTreble, data.slope, mTreble, data.samplerate, kTreble, + data.a0Treble, data.a1Treble, data.a2Treble, + data.b0Treble, data.b1Treble, data.b2Treble); + + for (sampleCount i = 0; i < blockLen; i++) { + obuf[i] = DoFilter(data, ibuf[i]) * data.gain; + } + + return blockLen; +} + + + +// Effect implementation + + +void EffectBassTreble::Coefficents(double hz, double slope, double gain, double samplerate, int type, + double& a0, double& a1, double& a2, + double& b0, double& b1, double& b2) +{ + double w = 2 * M_PI * hz / samplerate; double a = exp(log(10.0) * gain / 40); double b = sqrt((a * a + 1) / slope - (pow((a - 1), 2))); @@ -379,109 +400,112 @@ void EffectBassTreble::Coefficents(double hz, float slope, double gain, int type } } -float EffectBassTreble::DoFilter(float in) +float EffectBassTreble::DoFilter(EffectBassTrebleState & data, float in) { // Bass filter - float out = (b0Bass * in + b1Bass * xn1Bass + b2Bass * xn2Bass - - a1Bass * yn1Bass - a2Bass * yn2Bass) / a0Bass; - xn2Bass = xn1Bass; - xn1Bass = in; - yn2Bass = yn1Bass; - yn1Bass = out; + float out = (data.b0Bass * in + data.b1Bass * data.xn1Bass + data.b2Bass * data.xn2Bass - + data.a1Bass * data.yn1Bass - data.a2Bass * data.yn2Bass) / data.a0Bass; + data.xn2Bass = data.xn1Bass; + data.xn1Bass = in; + data.yn2Bass = data.yn1Bass; + data.yn1Bass = out; // Treble filter in = out; - out = (b0Treble * in + b1Treble * xn1Treble + b2Treble * xn2Treble - - a1Treble * yn1Treble - a2Treble * yn2Treble) / a0Treble; - xn2Treble = xn1Treble; - xn1Treble = in; - yn2Treble = yn1Treble; - yn1Treble = out; + out = (data.b0Treble * in + data.b1Treble * data.xn1Treble + data.b2Treble * data.xn2Treble - + data.a1Treble * data.yn1Treble - data.a2Treble * data.yn2Treble) / data.a0Treble; + data.xn2Treble = data.xn1Treble; + data.xn1Treble = in; + data.yn2Treble = data.yn1Treble; + data.yn1Treble = out; - // Retain the maximum value for use in the normalization pass - if(mMax < fabs(out)) - mMax = fabs(out); return out; } -void EffectBassTreble::UpdateUI() -{ - double bass, treble, level; - mBassT->GetValue().ToDouble(&bass); - mTrebleT->GetValue().ToDouble(&treble); - mLevelT->GetValue().ToDouble(&level); - bool enable = mNormalizeCheckBox->GetValue(); - - // Disallow level control if disabled - mLevelT->Enable(enable); - mLevelS->Enable(enable); - - if (bass == 0 && treble == 0 && !enable) - { - // Disallow Apply if nothing to do - EnableApply(false); - mWarning->SetLabel(_(" No change to apply.")); - } - else - { - if (level > 0 && enable) - { - // Disallow Apply if level enabled and > 0 - EnableApply(false); - mWarning->SetLabel(_(": Maximum 0 dB.")); - } - else - { - // Apply enabled - EnableApply(true); - mWarning->SetLabel(wxT("")); - } - } -} void EffectBassTreble::OnBassText(wxCommandEvent & WXUNUSED(evt)) { - mBassT->GetValidator()->TransferFromWindow(); - mBassS->SetValue((int) floor(dB_bass * kSliderScale + 0.5)); - UpdateUI(); + double oldBass = mBass; + + if (!EnableApply(mUIParent->TransferDataFromWindow())) + { + return; + } + + if (mLink) UpdateGain(oldBass, kBass); + mBassS->SetValue((int) (mBass * SCL_Bass)); } void EffectBassTreble::OnTrebleText(wxCommandEvent & WXUNUSED(evt)) { - mTrebleT->GetValidator()->TransferFromWindow(); - mTrebleS->SetValue((int) floor(dB_treble * kSliderScale + 0.5)); - UpdateUI(); + double oldTreble = mTreble; + + if (!EnableApply(mUIParent->TransferDataFromWindow())) + { + return; + } + + if (mLink) UpdateGain(oldTreble, kTreble); + mTrebleS->SetValue((int) (mTreble * SCL_Treble)); } -void EffectBassTreble::OnLevelText(wxCommandEvent & WXUNUSED(evt)) +void EffectBassTreble::OnGainText(wxCommandEvent & WXUNUSED(evt)) { - mLevelT->GetValidator()->TransferFromWindow(); - mLevelS->SetValue((int) floor(dB_level * kSliderScale + 0.5)); - UpdateUI(); + if (!EnableApply(mUIParent->TransferDataFromWindow())) + { + return; + } + + mGainS->SetValue((int) (mGain * SCL_Gain)); } void EffectBassTreble::OnBassSlider(wxCommandEvent & evt) { - dB_bass = (double) evt.GetInt() / kSliderScale; + double oldBass = mBass; + mBass = (double) evt.GetInt() / SCL_Bass; mBassT->GetValidator()->TransferToWindow(); - UpdateUI(); + + if (mLink) UpdateGain(oldBass, kBass); + EnableApply(mUIParent->Validate()); } void EffectBassTreble::OnTrebleSlider(wxCommandEvent & evt) { - dB_treble = (double) evt.GetInt() / kSliderScale; + double oldTreble = mTreble; + mTreble = (double) evt.GetInt() / SCL_Treble; mTrebleT->GetValidator()->TransferToWindow(); - UpdateUI(); + + if (mLink) UpdateGain(oldTreble, kTreble); + EnableApply(mUIParent->Validate()); } -void EffectBassTreble::OnLevelSlider(wxCommandEvent & evt) +void EffectBassTreble::OnGainSlider(wxCommandEvent & evt) { - dB_level = (double) evt.GetInt() / kSliderScale; - mLevelT->GetValidator()->TransferToWindow(); - UpdateUI(); + mGain = (double) evt.GetInt() / SCL_Gain; + mGainT->GetValidator()->TransferToWindow(); + + EnableApply(mUIParent->Validate()); } -void EffectBassTreble::OnNormalize(wxCommandEvent& WXUNUSED(evt)) +void EffectBassTreble::OnLinkCheckbox(wxCommandEvent& evt) { - UpdateUI(); + mLink = mLinkCheckBox->GetValue(); +} + +void EffectBassTreble::UpdateGain(double oldVal, int control) +{ + double newVal; + oldVal = (oldVal > 0)? oldVal / 2.0 : oldVal / 4.0; + + if (control == kBass) + newVal = (mBass > 0)? mBass / 2.0 : mBass / 4.0; + else + newVal = (mTreble > 0)? mTreble / 2.0 : mTreble / 4.0; + + mGain -= newVal - oldVal; + mGain = std::min(MAX_Gain, std::max(MIN_Gain, mGain)); + + mGainS->SetValue(mGain); + mGainT->GetValidator()->TransferToWindow(); + } diff --git a/src/effects/BassTreble.h b/src/effects/BassTreble.h index 4f76b163a..1aff7abb0 100644 --- a/src/effects/BassTreble.h +++ b/src/effects/BassTreble.h @@ -1,7 +1,7 @@ /********************************************************************** Audacity: A Digital Audio Editor - Audacity(R) is copyright (c) 1999-2013 Audacity Team. + Audacity(R) is copyright (c) 1999-2016 Audacity Team. License: GPL v2. See License.txt. BassTreble.h (two shelf filters) @@ -12,12 +12,12 @@ #ifndef __AUDACITY_EFFECT_BASS_TREBLE__ #define __AUDACITY_EFFECT_BASS_TREBLE__ -#include #include #include #include #include #include +#include #include "Effect.h" @@ -25,7 +25,23 @@ class ShuttleGui; #define BASSTREBLE_PLUGIN_SYMBOL XO("Bass and Treble") -class EffectBassTreble final : public Effect +class EffectBassTrebleState +{ +public: + float samplerate; + double treble; + double bass; + double gain; + double slope, hzBass, hzTreble; + double a0Bass, a1Bass, a2Bass, b0Bass, b1Bass, b2Bass; + double a0Treble, a1Treble, a2Treble, b0Treble, b1Treble, b2Treble; + double xn1Bass, xn2Bass, yn1Bass, yn2Bass; + double xn1Treble, xn2Treble, yn1Treble, yn2Treble; +}; + +WX_DECLARE_OBJARRAY(EffectBassTrebleState, EffectBassTrebleStateArray); + +class EffectBassTreble : public Effect { public: EffectBassTreble(); @@ -33,12 +49,13 @@ public: // IdentInterface implementation - wxString GetSymbol() override; - wxString GetDescription() override; + virtual wxString GetSymbol(); + virtual wxString GetDescription(); // EffectIdentInterface implementation EffectType GetType() override; + bool SupportsRealtime() override; // EffectClientInterface implementation @@ -46,57 +63,64 @@ public: int GetAudioOutCount() override; bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap = NULL) override; sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen) override; + bool RealtimeInitialize() override; + bool RealtimeAddProcessor(int numChannels, float sampleRate) override; + bool RealtimeFinalize() override; + sampleCount RealtimeProcess(int group, + float **inbuf, + float **outbuf, + sampleCount numSamples) override; bool GetAutomationParameters(EffectAutomationParameters & parms) override; bool SetAutomationParameters(EffectAutomationParameters & parms) override; - // Effect Implementation - bool Startup() override; - bool InitPass1() override; - bool InitPass2() override; + // Effect Implementation void PopulateOrExchange(ShuttleGui & S) override; bool TransferDataToWindow() override; bool TransferDataFromWindow() override; + bool CheckWhetherSkipEffect() override; + private: // EffectBassTreble implementation - void Coefficents(double hz, float slope, double gain, int type, - float& a0, float& a1, float& a2, float& b0, float& b1, float& b2); - float DoFilter(float in); - void UpdateUI(); + void InstanceInit(EffectBassTrebleState & data, float sampleRate); + sampleCount InstanceProcess(EffectBassTrebleState & data, float **inBlock, float **outBlock, sampleCount blockLen); + + void Coefficents(double hz, double slope, double gain, double samplerate, int type, + double& a0, double& a1, double& a2, double& b0, double& b1, double& b2); + float DoFilter(EffectBassTrebleState & data, float in); void OnBassText(wxCommandEvent & evt); void OnTrebleText(wxCommandEvent & evt); - void OnLevelText(wxCommandEvent & evt); + void OnGainText(wxCommandEvent & evt); void OnBassSlider(wxCommandEvent & evt); void OnTrebleSlider(wxCommandEvent & evt); - void OnLevelSlider(wxCommandEvent & evt); - void OnNormalize(wxCommandEvent & evt); + void OnGainSlider(wxCommandEvent & evt); + void OnLinkCheckbox(wxCommandEvent & evt); + + // Auto-adjust gain to reduce variation in peak level + void UpdateGain(double oldVal, int control ); private: - float xn1Bass, xn2Bass, yn1Bass, yn2Bass, - wBass, swBass, cwBass, aBass, bBass, - a0Bass, a1Bass, a2Bass, b0Bass, b1Bass, b2Bass; - // High shelf - float xn1Treble, xn2Treble, yn1Treble, yn2Treble, - wTreble, swTreble, cwTreble, aTreble, bTreble, - b0Treble, b1Treble, b2Treble, a0Treble, a1Treble, a2Treble; + EffectBassTrebleState mMaster; + EffectBassTrebleStateArray mSlaves; - double dB_bass, dB_treble, dB_level; - double mMax; - bool mbNormalize; - double mPreGain; + double mBass; + double mTreble; + double mGain; + bool mLink; - wxSlider *mBassS; - wxSlider *mTrebleS; - wxSlider *mLevelS; - wxTextCtrl *mBassT; - wxTextCtrl *mTrebleT; - wxTextCtrl *mLevelT; - wxCheckBox *mNormalizeCheckBox; - wxStaticText *mWarning; + wxSlider *mBassS; + wxSlider *mTrebleS; + wxSlider *mGainS; + + wxTextCtrl *mBassT; + wxTextCtrl *mTrebleT; + wxTextCtrl *mGainT; + + wxCheckBox *mLinkCheckBox; DECLARE_EVENT_TABLE(); };