audacia/src/effects/Equalization.h
Paul Licameli e653b4aaf8 Eliminate Experimental.h, configure compile options instead...
... This makes it impossible to forget to include the EXPERIMENTAL definitions
(such as when cutting and pasting code) and so get unintended quiet changes of
behavior.

The EXPERIMENTAL flags are now specified instead in new file Experimental.cmake
2021-04-27 12:40:07 -04:00

397 lines
10 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
Equalization.h
Mitch Golden
Vaughan Johnson (Preview)
***********************************************************************/
#ifndef __AUDACITY_EFFECT_EQUALIZATION__
#define __AUDACITY_EFFECT_EQUALIZATION__
#define NUMBER_OF_BANDS 31
#define NUM_PTS 180
#define PANELBORDER 1 // only increase from '1' for testing purposes - MJS
#include <wx/setup.h> // for wxUSE_* macros
#include "Effect.h"
#include "../RealFFTf.h"
// Flags to specialise the UI
const int kEqOptionGraphic =1;
const int kEqOptionCurve =1<<1;
// The legacy version offers both Graphic and curve on the same UI.
const int kEqLegacy = kEqOptionGraphic + kEqOptionCurve;
class wxBitmap;
class wxBoxSizer;
class wxButton;
class wxCheckBox;
class wxChoice;
class wxListCtrl;
class wxListEvent;
class wxRadioButton;
class wxSizer;
class wxSizerItem;
class wxSlider;
class wxStaticText;
class Envelope;
class EnvelopeEditor;
class EqualizationPanel;
class RulerPanel;
//
// One point in a curve
//
class EQPoint
{
public:
EQPoint( const double f, const double d ) { Freq = f; dB = d; }
bool operator < (const EQPoint &p1) const
{
return Freq < p1.Freq;
}
double Freq;
double dB;
};
//
// One curve in a list
//
// LLL: This "really" isn't needed as the array of points could be
// attached as wxClientData to the wxChoice entries. I
// didn't realize this until after the fact and am too
// lazy to change it. (But, hollar if you want me to.)
//
class EQCurve
{
public:
EQCurve( const wxString & name = {} ) { Name = name; }
EQCurve( const wxChar * name ) { Name = name; }
bool operator < (const EQCurve &that) const
{
return Name.CmpNoCase(that.Name) < 0;
}
wxString Name;
std::vector<EQPoint> points;
};
using EQCurveArray = std::vector<EQCurve>;
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
class EffectEqualization48x;
#endif
class EffectEqualization : public Effect,
public XMLTagHandler
{
public:
static const ComponentInterfaceSymbol Symbol;
EffectEqualization(int Options = kEqLegacy);
virtual ~EffectEqualization();
// ComponentInterface implementation
ComponentInterfaceSymbol GetSymbol() override;
TranslatableString GetDescription() override;
wxString ManualPage() override;
// EffectDefinitionInterface implementation
EffectType GetType() override;
// EffectClientInterface implementation
bool DefineParams( ShuttleParams & S ) override;
bool GetAutomationParameters(CommandParameters & parms) override;
bool SetAutomationParameters(CommandParameters & parms) override;
bool LoadFactoryDefaults() override;
RegistryPaths GetFactoryPresets() override;
bool LoadFactoryPreset(int id) override;
// EffectUIClientInterface implementation
bool ValidateUI() override;
// Effect implementation
bool Startup() override;
bool Init() override;
bool Process() override;
bool CloseUI() override;
void PopulateOrExchange(ShuttleGui & S) override;
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;
private:
// EffectEqualization implementation
wxString GetPrefsPrefix();
// Number of samples in an FFT window
static const size_t windowSize = 16384u; //MJS - work out the optimum for this at run time? Have a dialog box for it?
// Low frequency of the FFT. 20Hz is the
// low range of human hearing
enum {loFreqI=20};
bool ProcessOne(int count, WaveTrack * t,
sampleCount start, sampleCount len);
bool CalcFilter();
void Filter(size_t len, float *buffer);
void Flatten();
void ForceRecalc();
void EnvelopeUpdated();
void EnvelopeUpdated(Envelope *env, bool lin);
bool IsLinear();
void LoadCurves(const wxString &fileName = {}, bool append = false);
void SaveCurves(const wxString &fileName = {});
// Merge NEW curves only or update all factory presets.
void UpdateDefaultCurves( bool updateAll = false);
void Select(int sel);
void setCurve(int currentCurve);
void setCurve(const wxString &curveName);
void setCurve(void);
bool GetDefaultFileName(wxFileName &fileName);
// XMLTagHandler callback methods for loading and saving
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override;
XMLTagHandler *HandleXMLChild(const wxChar *tag) override;
void WriteXML(XMLWriter &xmlFile) const;
void UpdateCurves();
void UpdateDraw();
//void LayoutEQSliders();
void UpdateGraphic(void);
void EnvLogToLin(void);
void EnvLinToLog(void);
void ErrMin(void);
void GraphicEQ(Envelope *env);
void spline(double x[], double y[], size_t n, double y2[]);
double splint(double x[], double y[], size_t n, double y2[], double xr);
void OnErase( wxEvent &event );
void OnSize( wxSizeEvent & event );
void OnSlider( wxCommandEvent & event );
void OnInterp( wxCommandEvent & event );
void OnSliderM( wxCommandEvent & event );
void OnSliderDBMAX( wxCommandEvent & event );
void OnSliderDBMIN( wxCommandEvent & event );
void OnDrawMode( wxCommandEvent &event );
void OnGraphicMode( wxCommandEvent &event );
void OnCurve( wxCommandEvent & event );
void OnManage( wxCommandEvent & event );
void OnClear( wxCommandEvent & event );
void OnInvert( wxCommandEvent & event );
void OnGridOnOff( wxCommandEvent & event );
void OnLinFreq( wxCommandEvent & event );
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
void OnProcessingRadio( wxCommandEvent & event );
void OnBench( wxCommandEvent & event );
#endif
private:
int mOptions;
HFFT hFFT;
Floats mFFTBuffer, mFilterFuncR, mFilterFuncI;
size_t mM;
wxString mCurveName;
bool mLin;
float mdBMax;
float mdBMin;
bool mDrawMode;
int mInterp;
bool mDrawGrid;
double mWhens[NUM_PTS];
double mWhenSliders[NUMBER_OF_BANDS+1];
size_t mBandsInUse;
RulerPanel *mdBRuler;
RulerPanel *mFreqRuler;
bool mDisallowCustom;
double mLoFreq;
double mHiFreq;
size_t mWindowSize;
bool mDirty;
int mSlidersOld[NUMBER_OF_BANDS];
double mEQVals[NUMBER_OF_BANDS+1];
EQCurveArray mCurves;
std::unique_ptr<Envelope> mLogEnvelope, mLinEnvelope;
Envelope *mEnvelope;
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
bool mBench;
std::unique_ptr<EffectEqualization48x> mEffectEqualization48x;
friend class EffectEqualization48x;
#endif
wxSizer *szrC;
wxSizer *szrG;
wxSizer *szrV;
wxSizer *szrH;
wxSizer *szrI;
wxSizer *szrL;
wxSizer *szr1;
wxSizer *szr2;
wxSizer *szr3;
wxSizer *szr4;
wxSizer *szr5;
wxSizerItem *mLeftSpacer;
EqualizationPanel *mPanel;
//wxPanel *mGraphicPanel;
wxRadioButton *mDraw;
wxRadioButton *mGraphic;
wxCheckBox *mLinFreq;
wxCheckBox *mGridOnOff;
wxChoice *mInterpChoice;
wxChoice *mCurve;
wxButton *mManage;
wxStaticText *mMText;
wxSlider *mMSlider;
wxSlider *mdBMinSlider;
wxSlider *mdBMaxSlider;
wxSlider *mSliders[NUMBER_OF_BANDS];
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
wxRadioButton *mMathProcessingType[5]; // default, sse, sse threaded, AVX, AVX threaded (note AVX is not implemented yet
wxBoxSizer *szrM;
#endif
DECLARE_EVENT_TABLE()
friend class EqualizationPanel;
friend class EditCurvesDialog;
};
class EffectEqualizationCurve final : public EffectEqualization
{
public:
static const ComponentInterfaceSymbol Symbol;
EffectEqualizationCurve() : EffectEqualization( kEqOptionCurve ) {}
};
class EffectEqualizationGraphic final : public EffectEqualization
{
public:
static const ComponentInterfaceSymbol Symbol;
EffectEqualizationGraphic() : EffectEqualization( kEqOptionGraphic ) {}
};
class EqualizationPanel final : public wxPanelWrapper
{
public:
EqualizationPanel(
wxWindow *parent, wxWindowID winid, EffectEqualization *effect);
~EqualizationPanel();
// We don't need or want to accept focus.
bool AcceptsFocus() const { return false; }
// So that wxPanel is not included in Tab traversal - see wxWidgets bug 15581
bool AcceptsFocusFromKeyboard() const { return false; }
void ForceRecalc();
private:
void Recalc();
void OnMouseEvent(wxMouseEvent & event);
void OnCaptureLost(wxMouseCaptureLostEvent & event);
void OnPaint(wxPaintEvent & event);
void OnSize (wxSizeEvent & event);
public:
// int & mM;
// float & mdBMax;
// float & mdBMin;
// Envelope & mEnvelope;
private:
wxWindow *mParent;
EffectEqualization *mEffect;
std::unique_ptr<EnvelopeEditor> mLinEditor, mLogEditor;
bool mRecalcRequired;
std::unique_ptr<wxBitmap> mBitmap;
wxRect mEnvRect;
int mWidth;
int mHeight;
// size_t mWindowSize;
// float *mFilterFuncR;
// float *mFilterFuncI;
Floats mOutr, mOuti;
// double mLoFreq;
// double mHiFreq;
DECLARE_EVENT_TABLE()
};
// EditCurvesDialog. Note that the 'modified' curve used to be called 'custom' but is now called 'unnamed'
// Some things that deal with 'unnamed' curves still use, for example, 'mCustomBackup' as variable names.
class EditCurvesDialog final : public wxDialogWrapper
{
public:
EditCurvesDialog(wxWindow * parent, EffectEqualization * effect, int position);
~EditCurvesDialog();
private:
enum EQCurvesDialogControls
{
CurvesListID = 11000,
UpButtonID,
DownButtonID,
RenameButtonID,
DeleteButtonID,
ImportButtonID,
ExportButtonID,
LibraryButtonID,
DefaultsButtonID
};
wxListCtrl *mList; // List of curves.
EQCurveArray mEditCurves; // Copy of curves to muck about with
wxWindow *mParent; // the parent EQ Dialog
EffectEqualization *mEffect; // the parent EQ effect
int mPosition; // position of current curve in list
void Populate();
void PopulateOrExchange(ShuttleGui &S);
void PopulateList(int position);
void OnUp(wxCommandEvent &event);
void OnDown(wxCommandEvent &event);
long GetPreviousItem(long item);
void OnRename( wxCommandEvent &event );
void OnDelete( wxCommandEvent &event );
void OnImport( wxCommandEvent &event );
void OnExport( wxCommandEvent &event );
void OnLibrary( wxCommandEvent &event );
void OnDefaults( wxCommandEvent &event );
void OnOK(wxCommandEvent &event);
void OnListSelectionChange( wxListEvent &event );
DECLARE_EVENT_TABLE()
};
#endif