20#include <wx/radiobut.h>
22#include <wx/checkbox.h>
23#include <wx/stattext.h>
25#include "../widgets/RulerPanel.h"
26#include "../widgets/LinearUpdater.h"
27#include "../widgets/LogarithmicUpdater.h"
28#include "../widgets/IntFormat.h"
29#include "../widgets/LinearDBFormat.h"
31#if wxUSE_ACCESSIBILITY
54 , mEqualizationUI { ui }
55 , mpParent { pParent }
58 mpParent->PushEventHandler(&ui);
69 mAccess.ModifySettings(
72 result = mEqualizationUI.ValidateUI(
settings);
82 mpParent->PopEventHandler();
89 wxWindow* mpParent {};
97 auto &logEnvelope = parameters.mLogEnvelope;
109 XO(
"To use this filter curve in a macro, please choose a new name for it.\nChoose the 'Save/Manage Curves...' button and rename the 'unnamed' curve, then use that one."),
110 XO(
"Filter Curve EQ needs a different name") );
126 const auto &M = parameters.
mM;
127 const auto &loFreq = parameters.mLoFreq;
128 const auto &hiFreq = parameters.mHiFreq;
131 auto &drawMode = parameters.mDrawMode;
135 S.SetSizerProportion(1);
136 S.Prop(1).StartMultiColumn(1, wxEXPAND);
152 S.SetSizerProportion(1);
153 S.Prop(1).StartMultiColumn(3, wxEXPAND);
159 S.StartVerticalLay(wxEXPAND, 1);
163 S.GetParent(), wxID_ANY, wxHORIZONTAL,
172 .TicksAtExtremes(
true)
173 .TickColour( { 0, 0, 0 } )
177 S.GetParent(), wxID_ANY, wxVERTICAL,
184 .TicksAtExtremes(
true)
185 .TickColour( { 0, 0, 0 } )
188 S.Prop(0).AddSpace(0, 1);
196 parameters.ChooseEnvelope().Flatten(0.);
197 parameters.ChooseEnvelope().SetTrackLen(1.0);
202 .MinSize( { wxDefaultCoord, wxDefaultCoord } )
206 S.StartVerticalLay();
208 S.AddVariableText(
XO(
"+ dB"),
false, wxCENTER);
211 .Style(wxSL_VERTICAL | wxSL_INVERSE)
212 .AddSlider( {}, 30, 60, 0);
213#if wxUSE_ACCESSIBILITY
221 .Style(wxSL_VERTICAL | wxSL_INVERSE)
222 .AddSlider( {}, -30, -10, -120);
223 S.AddVariableText(
XO(
"- dB"),
false, wxCENTER);
224#if wxUSE_ACCESSIBILITY
242 .Position(wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP | wxLEFT)
254 S.SetSizerProportion(1);
255 S.StartHorizontalLay(wxEXPAND, 1);
270 S.EndHorizontalLay();
275 S.SetSizerProportion(1);
276 S.Prop(1).StartMultiColumn(7, wxALIGN_CENTER_HORIZONTAL);
284 S.StartHorizontalLay(wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
286 S.AddPrompt(
XXO(
"&EQ Type:"));
288 S.EndHorizontalLay();
290 S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 1);
292 S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 1);
295 .Name(
XO(
"Draw Curves"))
296 .AddRadioButton(
XXO(
"&Draw"));
301 .Name(
XO(
"Graphic EQ"))
302 .AddRadioButtonToGroup(
XXO(
"&Graphic"));
306 S.EndHorizontalLay();
308 S.EndHorizontalLay();
311 S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0);
315 S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 1);
320 .Name(
XO(
"Interpolation type"))
325#if wxUSE_ACCESSIBILITY
332 S.EndHorizontalLay();
334 S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 1);
339 .Name(
XO(
"Linear Frequency Scale"))
340 .AddCheckBox(
XXO(
"Li&near Frequency Scale"),
false);
344 S.EndHorizontalLay();
346 S.EndHorizontalLay();
353 S.StartHorizontalLay(wxEXPAND, 0);
355 S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0);
357 S.AddPrompt(
XXO(
"Length of &Filter:"));
359 S.EndHorizontalLay();
361 S.StartHorizontalLay(wxEXPAND, 1);
364 .Name(
XO(
"Length of Filter"))
365 .Style(wxSL_HORIZONTAL)
366 .AddSlider( {}, (M - 1) / 2, 4095, 10);
370 S.EndHorizontalLay();
372 S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0);
381 S.EndHorizontalLay();
383 S.EndHorizontalLay();
392 S.StartHorizontalLay(wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
394 S.AddPrompt(
XXO(
"&Select Curve:"));
396 S.EndHorizontalLay();
398 S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 1);
400 S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 1);
403 .Name(
XO(
"Select Curve"))
407 for (
const auto &curve : curves)
415 S.EndHorizontalLay();
417 S.EndHorizontalLay();
419 const auto pButton =
S
420 .AddButton(
XXO(
"S&ave/Manage Curves..."));
424 S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 1);
427 .AddButton(
XXO(
"Fla&tten"));
431 .AddButton(
XXO(
"&Invert"));
435 .Name(
XO(
"Show grid lines"))
436 .AddCheckBox(
XXO(
"Show g&rid lines"),
false);
440 S.EndHorizontalLay();
465 wxSize sz =
szrV->GetMinSize();
466 sz += wxSize( 30, 0);
477 wxSize sz =
szrV->GetMinSize();
478 sz += wxSize( 400, 100);
479 szrV->SetMinSize(sz);
489 const auto &lin = parameters.
mLin;
490 const auto &drawGrid = parameters.mDrawGrid;
491 const auto &M = parameters.mM;
492 const auto &dBMin = parameters.mdBMin;
493 const auto &dBMax = parameters.mdBMax;
494 const auto &interp = parameters.mInterp;
496 auto &drawMode = parameters.mDrawMode;
500 wxCommandEvent dummyEvent;
524 mDraw->SetValue(drawMode);
540 wxGetTopLevelParent(
mUIParent)->Layout();
548 const auto &dBMin = parameters.
mdBMin;
549 const auto &dBMax = parameters.mdBMax;
574 const auto &lin = parameters.mLin;
575 const auto &hiFreq = parameters.mHiFreq;
579 wxASSERT( currentCurve < (
int) curves.size() );
582 int numPoints = (int) curves[currentCurve].points.size();
584 auto &env = parameters.ChooseEnvelope();
586 env.SetTrackLen(1.0);
589 if (numPoints == 0) {
597 if (numPoints == 1) {
599 when = curves[currentCurve].points[0].Freq;
601 when = when / hiFreq;
605 double loLog = log10((
double)loFreqI);
606 double hiLog = log10(hiFreq);
607 double denom = hiLog - loLog;
609 (log10(std::max<double>(loFreqI, when))
612 value = curves[currentCurve].points[0].dB;
613 env.Insert(
std::min(1.0, std::max(0.0, when)), value);
619 std::sort(curves[currentCurve].points.begin(),
620 curves[currentCurve].points.end());
622 if (curves[currentCurve].points[0].Freq < 0) {
629 for(
int pointCount = 0; pointCount < numPoints; pointCount++) {
630 when = curves[currentCurve].points[pointCount].Freq / hiFreq;
631 value = curves[currentCurve].points[pointCount].dB;
633 env.Insert(when, value);
641 double nextDB = curves[currentCurve].points[pointCount].dB;
642 if (pointCount > 0) {
643 double nextF = curves[currentCurve].points[pointCount].Freq;
644 double lastF = curves[currentCurve].points[pointCount-1].Freq;
645 double lastDB = curves[currentCurve].points[pointCount-1].dB;
648 ((hiFreq - lastF) / (nextF - lastF)));
652 env.Insert(when, value);
658 double loLog = log10((
double) loFreqI);
659 double hiLog = log10(hiFreq);
660 double denom = hiLog - loLog;
665 for (firstAbove20Hz = 0; firstAbove20Hz < numPoints; firstAbove20Hz++) {
666 if (curves[currentCurve].points[firstAbove20Hz].Freq > loFreqI)
670 if (firstAbove20Hz == numPoints) {
673 value = curves[currentCurve].points[numPoints-1].dB;
674 env.Insert(when, value);
679 if (firstAbove20Hz > 0) {
682 double prevF = curves[currentCurve].points[firstAbove20Hz-1].Freq;
683 prevF = log10(std::max(1.0, prevF));
684 double prevDB = curves[currentCurve].points[firstAbove20Hz-1].dB;
685 double nextF = log10(curves[currentCurve].points[firstAbove20Hz].Freq);
686 double nextDB = curves[currentCurve].points[firstAbove20Hz].dB;
688 value = nextDB - ((nextDB - prevDB) * ((nextF - loLog) / (nextF - prevF)));
689 env.Insert(when, value);
693 for(
int pointCount = firstAbove20Hz; pointCount < numPoints; pointCount++)
695 double flog = log10(curves[currentCurve].points[pointCount].Freq);
696 wxASSERT(curves[currentCurve].points[pointCount].Freq >= loFreqI);
698 when = (flog - loLog)/denom;
699 value = curves[currentCurve].points[pointCount].dB;
701 env.Insert(when, value);
717 if (pointCount > 0) {
718 double lastDB = curves[currentCurve].points[pointCount-1].dB;
720 log10(curves[currentCurve].points[pointCount-1].Freq);
723 ((log10(hiFreq) - logLastF) / (flog - logLastF)));
725 env.Insert(when, value);
743 for( i = 0; i < curves.size(); i++ )
744 if( curveName == curves[ i ].Name )
746 if( i == curves.size())
749 XO(
"Requested curve not found, using 'unnamed'"),
750 XO(
"Curve not found"),
774 bool selectedCurveExists =
false;
775 for (
size_t i = 0, cnt = curves.size(); i < cnt; i++)
777 if (curveName == curves[ i ].Name)
778 selectedCurveExists =
true;
780 mCurve->Append(curves[ i ].Name);
783 if (!selectedCurveExists)
784 curveName = curves[ (int)curves.size() - 1 ].Name;
786 mCurve->SetStringSelection(curveName);
790 mCurve->SetMinSize({-1, -1});
799 const auto &lin = parameters.
mLin;
800 auto &linEnvelope = parameters.mLinEnvelope;
801 auto &logEnvelope = parameters.mLogEnvelope;
802 const auto &hiFreq = parameters.mHiFreq;
804 size_t numPoints = logEnvelope.GetNumberOfPoints();
807 double deltadB = 0.1;
808 double dx, dy, dx1, dy1, err;
810 logEnvelope.GetPoints( when.get(), value.get(), numPoints );
820 logEnvelope.GetPoints( when.get(), value.get(), numPoints );
821 for (
size_t j = 0; j + 2 < numPoints; j++)
823 dx = when[j+2+numDeleted] - when[j+numDeleted];
824 dy = value[j+2+numDeleted] - value[j+numDeleted];
825 dx1 = when[j+numDeleted+1] - when[j+numDeleted];
827 err = fabs(value[j+numDeleted+1] - (value[j+numDeleted] + dy1));
830 logEnvelope.Delete(j+1);
850 wxGetTopLevelParent(
mUIParent)->Layout();
857 const auto &lin = parameters.
mLin;
858 auto &linEnvelope = parameters.mLinEnvelope;
859 auto &logEnvelope = parameters.mLogEnvelope;
860 const auto &loFreq = parameters.mLoFreq;
861 const auto &hiFreq = parameters.mHiFreq;
863 auto &drawMode = parameters.mDrawMode;
867 double step = pow(2., 1./12.);
869 for(
double freq=10.; freq<hiFreq; freq*=step)
872 value = linEnvelope.GetValue(when);
873 linEnvelope.Insert(when, value);
888 wxGetTopLevelParent(
mUIParent)->Layout();
890 wxGetTopLevelParent(
mUIParent)->Layout();
930 size_t m = 2 *
mMSlider->GetValue() + 1;
932 wxASSERT( (m & 1) == 1 );
937 tip.Printf(
wxT(
"%d"), (
int)M);
954 tip.Printf(
_(
"%d dB"), (
int)dBMin);
968 tip.Printf(
_(
"%d dB"), (
int)dBMax);
980 wxASSERT(
mCurve != NULL );
993 curves,
mCurve->GetSelection());
995 wxGetTopLevelParent(
mUIParent)->Layout();
1025 auto &lin = parameters.
mLin;
1026 const auto &loFreq = parameters.mLoFreq;
1027 const auto &hiFreq = parameters.mHiFreq;
1030 if(parameters.IsLinear())
const int kEqOptionGraphic
XXO("&Cut/Copy/Paste Toolbar")
TranslatableStrings Msgids(const EnumValueSymbol strings[], size_t nStrings)
Convenience function often useful when adding choice controls.
static Settings & settings()
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::vector< TranslatableString > TranslatableStrings
Serializer of curves into XML files.
void SaveCurves(const wxString &fileName={})
Performs effect computation.
Hold values to send to effect output meters.
EqualizationCurvesDialog manages the available preset curves.
EqualizationPanel is used with EqualizationDialog and controls a graph for EffectEqualization....
void OnIdle(wxIdleEvent &event)
void OnSliderDBMAX(wxCommandEvent &event)
void OnDrawMode(wxCommandEvent &event)
void OnManage(wxCommandEvent &event)
EqualizationCurvesList & mCurvesList
void OnGraphicMode(wxCommandEvent &event)
wxWeakRef< EqualizationPanel > mPanel
void OnClear(wxCommandEvent &event)
EffectSettingsManager & mManager
void OnLinFreq(wxCommandEvent &event)
void OnInterp(wxCommandEvent &event)
EffectUIServices & mUIServices
void OnCurve(wxCommandEvent &event)
void BindTo(wxEvtHandler &src, const EventTag &eventType, void(Class::*pmf)(Event &))
void OnSliderDBMIN(wxCommandEvent &event)
EqualizationBandSliders mBands
bool ValidateUI(EffectSettings &settings)
void OnInvert(wxCommandEvent &event)
const wxWeakRef< wxWindow > & mUIParent
void OnSliderM(wxCommandEvent &event)
std::unique_ptr< EffectEditor > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs)
bool TransferDataToWindow(const EffectSettings &settings)
void OnSize(wxSizeEvent &event)
wxWeakRef< wxChoice > mCurve
void OnGridOnOff(wxCommandEvent &event)
static const LinearUpdater & Instance()
static const LogarithmicUpdater & Instance()
void SetUpdater(const RulerUpdater *pUpdater)
void GetMaxSize(wxCoord *width, wxCoord *height)
void SetRange(double min, double max)
RulerPanel class allows you to work with a Ruler like any other wxWindow.
std::pair< double, double > Range
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
void Disconnect() override
On the first call only, may disconnect from further event handling.
bool ValidateUI() override
Calls mServices.ValidateUI()
~EqualizationUIEditor() override
Calls Disconnect.
EqualizationUI & mEqualizationUI
EqualizationUIEditor(EqualizationUI &ui, EffectUIServices &services, EffectSettingsAccess &access, wxWindow *pParent=nullptr)
int DoMessageBox(const TranslatableString &name, const TranslatableString &msg, const TranslatableString &titleStr, long style=wxOK|wxCENTRE)
Externalized state of a plug-in.
void AddBandSliders(ShuttleGui &S)
void GraphicEQ(Envelope &env)
EqualizationFilter & mParameters
static constexpr int loFreqI
static const EnumValueSymbol kInterpStrings[nInterpolations]
Options & LabelEdges(bool l)