1 /**********************************************************************
2 
3   Audacity: A Digital Audio Editor
4 
5   Equalization.h
6 
7   Mitch Golden
8   Vaughan Johnson (Preview)
9 
10 ***********************************************************************/
11 
12 #ifndef __AUDACITY_EFFECT_EQUALIZATION__
13 #define __AUDACITY_EFFECT_EQUALIZATION__
14 #define NUMBER_OF_BANDS 31
15 #define NUM_PTS 180
16 #define PANELBORDER 1   // only increase from '1' for testing purposes - MJS
17 
18 #include <wx/setup.h> // for wxUSE_* macros
19 
20 #include "Effect.h"
21 #include "RealFFTf.h"
22 
23 // Flags to specialise the UI
24 const int kEqOptionGraphic =1;
25 const int kEqOptionCurve   =1<<1;
26 // The legacy version offers both Graphic and curve on the same UI.
27 const int kEqLegacy = kEqOptionGraphic + kEqOptionCurve;
28 
29 class wxBitmap;
30 class wxBoxSizer;
31 class wxButton;
32 class wxCheckBox;
33 class wxChoice;
34 class wxListCtrl;
35 class wxListEvent;
36 class wxRadioButton;
37 class wxSizer;
38 class wxSizerItem;
39 class wxSlider;
40 class wxStaticText;
41 class Envelope;
42 class EnvelopeEditor;
43 class EqualizationPanel;
44 class RulerPanel;
45 
46 //
47 // One point in a curve
48 //
49 class EQPoint
50 {
51 public:
EQPoint(const double f,const double d)52    EQPoint( const double f, const double d ) { Freq = f; dB = d; }
53 
54    bool operator < (const EQPoint &p1) const
55    {
56       return Freq < p1.Freq;
57    }
58 
59    double Freq;
60    double dB;
61 };
62 
63 //
64 // One curve in a list
65 //
66 // LLL:  This "really" isn't needed as the array of points could be
67 //       attached as wxClientData to the wxChoice entries.  I
68 //       didn't realize this until after the fact and am too
69 //       lazy to change it.  (But, hollar if you want me to.)
70 //
71 class EQCurve
72 {
73 public:
74    EQCurve( const wxString & name = {} ) { Name = name; }
EQCurve(const wxChar * name)75    EQCurve( const wxChar * name ) { Name = name; }
76 
77    bool operator < (const EQCurve &that) const
78    {
79       return Name.CmpNoCase(that.Name) < 0;
80    }
81 
82    wxString Name;
83    std::vector<EQPoint> points;
84 };
85 
86 using EQCurveArray = std::vector<EQCurve>;
87 
88 #ifdef EXPERIMENTAL_EQ_SSE_THREADED
89 class EffectEqualization48x;
90 #endif
91 
92 class EffectEqualization : public Effect,
93                            public XMLTagHandler
94 {
95 public:
96    static const ComponentInterfaceSymbol Symbol;
97 
98    EffectEqualization(int Options = kEqLegacy);
99 
100    virtual ~EffectEqualization();
101 
102    // ComponentInterface implementation
103 
104    ComponentInterfaceSymbol GetSymbol() override;
105    TranslatableString GetDescription() override;
106    ManualPageID ManualPage() override;
107 
108    // EffectDefinitionInterface implementation
109 
110    EffectType GetType() override;
111 
112    // EffectClientInterface implementation
113 
114    bool DefineParams( ShuttleParams & S ) override;
115    bool GetAutomationParameters(CommandParameters & parms) override;
116    bool SetAutomationParameters(CommandParameters & parms) override;
117    bool LoadFactoryDefaults() override;
118 
119    RegistryPaths GetFactoryPresets() override;
120    bool LoadFactoryPreset(int id) override;
121 
122    // EffectUIClientInterface implementation
123 
124    bool ValidateUI() override;
125 
126    // Effect implementation
127 
128    bool Startup() override;
129    bool Init() override;
130    bool Process() override;
131 
132    bool CloseUI() override;
133    void PopulateOrExchange(ShuttleGui & S) override;
134    bool TransferDataToWindow() override;
135    bool TransferDataFromWindow() override;
136 
137 private:
138    // EffectEqualization implementation
139    wxString GetPrefsPrefix();
140 
141    // Number of samples in an FFT window
142    static const size_t windowSize = 16384u; //MJS - work out the optimum for this at run time?  Have a dialog box for it?
143 
144    // Low frequency of the FFT.  20Hz is the
145    // low range of human hearing
146    enum {loFreqI=20};
147 
148    bool ProcessOne(int count, WaveTrack * t,
149                    sampleCount start, sampleCount len);
150    bool CalcFilter();
151    void Filter(size_t len, float *buffer);
152 
153    void Flatten();
154    void ForceRecalc();
155    void EnvelopeUpdated();
156    void EnvelopeUpdated(Envelope *env, bool lin);
157    bool IsLinear();
158 
159    void LoadCurves(const wxString &fileName = {}, bool append = false);
160    void SaveCurves(const wxString &fileName = {});
161    // Merge NEW curves only or update all factory presets.
162    void UpdateDefaultCurves( bool updateAll = false);
163    void Select(int sel);
164    void setCurve(int currentCurve);
165    void setCurve(const wxString &curveName);
166    void setCurve(void);
167    bool GetDefaultFileName(wxFileName &fileName);
168 
169    // XMLTagHandler callback methods for loading and saving
170    bool HandleXMLTag(const std::string_view& tag, const AttributesList &attrs) override;
171    XMLTagHandler *HandleXMLChild(const std::string_view& tag) override;
172    void WriteXML(XMLWriter &xmlFile) const;
173 
174    void UpdateCurves();
175    void UpdateDraw();
176 
177    //void LayoutEQSliders();
178    void UpdateGraphic(void);
179    void EnvLogToLin(void);
180    void EnvLinToLog(void);
181    void ErrMin(void);
182    void GraphicEQ(Envelope *env);
183    void spline(double x[], double y[], size_t n, double y2[]);
184    double splint(double x[], double y[], size_t n, double y2[], double xr);
185 
186    void OnErase( wxEvent &event );
187    void OnSize( wxSizeEvent & event );
188    void OnSlider( wxCommandEvent & event );
189    void OnInterp( wxCommandEvent & event );
190    void OnSliderM( wxCommandEvent & event );
191    void OnSliderDBMAX( wxCommandEvent & event );
192    void OnSliderDBMIN( wxCommandEvent & event );
193    void OnDrawMode( wxCommandEvent &event );
194    void OnGraphicMode( wxCommandEvent &event );
195    void OnCurve( wxCommandEvent & event );
196    void OnManage( wxCommandEvent & event );
197    void OnClear( wxCommandEvent & event );
198    void OnInvert( wxCommandEvent & event );
199    void OnGridOnOff( wxCommandEvent & event );
200    void OnLinFreq( wxCommandEvent & event );
201 #ifdef EXPERIMENTAL_EQ_SSE_THREADED
202    void OnProcessingRadio( wxCommandEvent & event );
203    void OnBench( wxCommandEvent & event );
204 #endif
205 
206 private:
207    int mOptions;
208    HFFT hFFT;
209    Floats mFFTBuffer, mFilterFuncR, mFilterFuncI;
210    size_t mM;
211    wxString mCurveName;
212    bool mLin;
213    float mdBMax;
214    float mdBMin;
215    bool mDrawMode;
216    int mInterp;
217    bool mDrawGrid;
218 
219    double mWhens[NUM_PTS];
220    double mWhenSliders[NUMBER_OF_BANDS+1];
221    size_t mBandsInUse;
222    RulerPanel *mdBRuler;
223    RulerPanel *mFreqRuler;
224 
225    bool mDisallowCustom;
226    double mLoFreq;
227    double mHiFreq;
228    size_t mWindowSize;
229    bool mDirty;
230    int mSlidersOld[NUMBER_OF_BANDS];
231    double mEQVals[NUMBER_OF_BANDS+1];
232 
233    EQCurveArray mCurves;
234 
235    std::unique_ptr<Envelope> mLogEnvelope, mLinEnvelope;
236    Envelope *mEnvelope;
237 
238 #ifdef EXPERIMENTAL_EQ_SSE_THREADED
239    bool mBench;
240    std::unique_ptr<EffectEqualization48x> mEffectEqualization48x;
241    friend class EffectEqualization48x;
242 #endif
243 
244    wxSizer *szrC;
245    wxSizer *szrG;
246    wxSizer *szrV;
247    wxSizer *szrH;
248    wxSizer *szrI;
249    wxSizer *szrL;
250    wxSizer *szr1;
251    wxSizer *szr2;
252    wxSizer *szr3;
253    wxSizer *szr4;
254    wxSizer *szr5;
255 
256    wxSizerItem *mLeftSpacer;
257 
258    EqualizationPanel *mPanel;
259    //wxPanel *mGraphicPanel;
260    wxRadioButton *mDraw;
261    wxRadioButton *mGraphic;
262    wxCheckBox *mLinFreq;
263    wxCheckBox *mGridOnOff;
264    wxChoice *mInterpChoice;
265    wxChoice *mCurve;
266    wxButton *mManage;
267    wxStaticText *mMText;
268    wxSlider *mMSlider;
269    wxSlider *mdBMinSlider;
270    wxSlider *mdBMaxSlider;
271    wxSlider *mSliders[NUMBER_OF_BANDS];
272 
273 #ifdef EXPERIMENTAL_EQ_SSE_THREADED
274    wxRadioButton *mMathProcessingType[5]; // default, sse, sse threaded, AVX, AVX threaded (note AVX is not implemented yet
275    wxBoxSizer *szrM;
276 #endif
277 
278    DECLARE_EVENT_TABLE()
279 
280    friend class EqualizationPanel;
281    friend class EditCurvesDialog;
282 };
283 
284 class EffectEqualizationCurve final : public EffectEqualization
285 {
286 public:
287    static const ComponentInterfaceSymbol Symbol;
288 
EffectEqualizationCurve()289    EffectEqualizationCurve() : EffectEqualization( kEqOptionCurve ) {}
290 };
291 
292 class EffectEqualizationGraphic final : public EffectEqualization
293 {
294 public:
295    static const ComponentInterfaceSymbol Symbol;
296 
EffectEqualizationGraphic()297    EffectEqualizationGraphic() : EffectEqualization( kEqOptionGraphic ) {}
298 };
299 
300 class EqualizationPanel final : public wxPanelWrapper
301 {
302 public:
303    EqualizationPanel(
304       wxWindow *parent, wxWindowID winid, EffectEqualization *effect);
305    ~EqualizationPanel();
306 
307    // We don't need or want to accept focus.
AcceptsFocus()308    bool AcceptsFocus() const { return false; }
309    // So that wxPanel is not included in Tab traversal - see wxWidgets bug 15581
AcceptsFocusFromKeyboard()310    bool AcceptsFocusFromKeyboard() const { return false; }
311 
312    void ForceRecalc();
313 
314 private:
315    void Recalc();
316 
317    void OnMouseEvent(wxMouseEvent & event);
318    void OnCaptureLost(wxMouseCaptureLostEvent & event);
319    void OnPaint(wxPaintEvent & event);
320    void OnSize (wxSizeEvent & event);
321 
322 public:
323 //   int & mM;
324 //   float & mdBMax;
325 //   float & mdBMin;
326 //   Envelope & mEnvelope;
327 
328 private:
329    wxWindow *mParent;
330    EffectEqualization *mEffect;
331    std::unique_ptr<EnvelopeEditor> mLinEditor, mLogEditor;
332 
333    bool mRecalcRequired;
334 
335    std::unique_ptr<wxBitmap> mBitmap;
336    wxRect mEnvRect;
337    int mWidth;
338    int mHeight;
339 //   size_t mWindowSize;
340 //   float *mFilterFuncR;
341 //   float *mFilterFuncI;
342    Floats mOutr, mOuti;
343 
344 //   double mLoFreq;
345 //   double mHiFreq;
346 
347    DECLARE_EVENT_TABLE()
348 };
349 
350 // EditCurvesDialog.  Note that the 'modified' curve used to be called 'custom' but is now called 'unnamed'
351 // Some things that deal with 'unnamed' curves still use, for example, 'mCustomBackup' as variable names.
352 class EditCurvesDialog final : public wxDialogWrapper
353 {
354 public:
355    EditCurvesDialog(wxWindow * parent, EffectEqualization * effect, int position);
356    ~EditCurvesDialog();
357 
358 private:
359 
360    enum EQCurvesDialogControls
361    {
362       CurvesListID = 11000,
363       UpButtonID,
364       DownButtonID,
365       RenameButtonID,
366       DeleteButtonID,
367       ImportButtonID,
368       ExportButtonID,
369       LibraryButtonID,
370       DefaultsButtonID
371    };
372 
373    wxListCtrl *mList;   // List of curves.
374    EQCurveArray mEditCurves;   // Copy of curves to muck about with
375    wxWindow *mParent; // the parent EQ Dialog
376    EffectEqualization *mEffect;   // the parent EQ effect
377    int mPosition; // position of current curve in list
378    void Populate();
379    void PopulateOrExchange(ShuttleGui &S);
380    void PopulateList(int position);
381    void OnUp(wxCommandEvent &event);
382    void OnDown(wxCommandEvent &event);
383    long GetPreviousItem(long item);
384    void OnRename( wxCommandEvent &event );
385    void OnDelete( wxCommandEvent &event );
386    void OnImport( wxCommandEvent &event );
387    void OnExport( wxCommandEvent &event );
388    void OnLibrary( wxCommandEvent &event );
389    void OnDefaults( wxCommandEvent &event );
390    void OnOK(wxCommandEvent &event);
391 
392    void OnListSelectionChange( wxListEvent &event );
393    DECLARE_EVENT_TABLE()
394 };
395 
396 #endif
397