Audacity 3.2.0
Phaser.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 Phaser.cpp
6
7 Dominic Mazzoni (with the help of wxDesigner)
8 Vaughan Johnson (Preview)
9
10**********************************************************************/
11#include "Phaser.h"
12#include "EffectEditor.h"
13#include "LoadEffects.h"
14
15#include <math.h>
16
17#include <wx/slider.h>
18
19#include "ShuttleGui.h"
20#include "../widgets/valnum.h"
21#include <wx/weakref.h>
22
24
25
28{
29 Editor(const EffectUIServices& services,
31 ) : EffectEditor{ services, access }
33 {}
34 virtual ~Editor() = default;
35
36 bool ValidateUI() override;
37 bool UpdateUI() override;
38
40
41 wxWeakRef<wxWindow> mUIParent;
43
44 wxTextCtrl* mStagesT;
45 wxTextCtrl* mDryWetT;
46 wxTextCtrl* mFreqT;
47 wxTextCtrl* mPhaseT;
48 wxTextCtrl* mDepthT;
49 wxTextCtrl* mFeedbackT;
50 wxTextCtrl* mOutGainT;
51
52 wxSlider* mStagesS;
53 wxSlider* mDryWetS;
54 wxSlider* mFreqS;
55 wxSlider* mPhaseS;
56 wxSlider* mDepthS;
57 wxSlider* mFeedbackS;
58 wxSlider* mOutGainS;
59
60 void OnStagesSlider(wxCommandEvent& evt);
61 void OnDryWetSlider(wxCommandEvent& evt);
62 void OnFeedbackSlider(wxCommandEvent& evt);
63 void OnDepthSlider(wxCommandEvent& evt);
64 void OnPhaseSlider(wxCommandEvent& evt);
65 void OnFreqSlider(wxCommandEvent& evt);
66 void OnGainSlider(wxCommandEvent& evt);
67
68 void OnStagesText(wxCommandEvent& evt);
69 void OnDryWetText(wxCommandEvent& evt);
70 void OnFeedbackText(wxCommandEvent& evt);
71 void OnDepthText(wxCommandEvent& evt);
72 void OnPhaseText(wxCommandEvent& evt);
73 void OnFreqText(wxCommandEvent& evt);
74 void OnGainText(wxCommandEvent& evt);
75
76
78 {
79 EnableApply(mUIParent, mUIParent->Validate());
80 }
81
83 {
84 return EnableApply(mUIParent, mUIParent->TransferDataFromWindow());
85 }
86
87};
88
89// Effect implementation
90std::unique_ptr<EffectEditor> EffectPhaser::MakeEditor(
92 const EffectOutputs *) const
93{
94 auto& settings = access.Get();
95 auto& myEffSettings = GetSettings(settings);
96
97 auto result = std::make_unique<Editor>(*this, access, myEffSettings);
98 result->PopulateOrExchange(S);
99 return result;
100}
101
103{
104 mUIParent = S.GetParent();
105 auto& ms = mSettings;
106
107 S.SetBorder(5);
108 S.AddSpace(0, 5);
109
110 S.StartMultiColumn(3, wxEXPAND);
111 {
112 S.SetStretchyCol(2);
113
114 mStagesT = S
115 .Validator<IntegerValidator<int>>(
116 &ms.mStages, NumValidatorStyle::DEFAULT, Stages.min, Stages.max)
117 .AddTextBox(XXO("&Stages:"), L"", 15);
118 BindTo(*mStagesT, wxEVT_TEXT, &Editor::OnStagesText);
119
120 mStagesS = S
121 .Name(XO("Stages"))
122 .Style(wxSL_HORIZONTAL)
123 .MinSize( { 100, -1 } )
124 .AddSlider( {}, Stages.def * Stages.scale, Stages.max * Stages.scale, Stages.min * Stages.scale);
125 mStagesS->SetLineSize(2);
126 BindTo(*mStagesS, wxEVT_SLIDER, &Editor::OnStagesSlider);
127
128 mDryWetT = S
129 .Validator<IntegerValidator<int>>(
130 &ms.mDryWet, NumValidatorStyle::DEFAULT, DryWet.min, DryWet.max)
131 .AddTextBox(XXO("&Dry/Wet:"), L"", 15);
132 BindTo(*mDryWetT, wxEVT_TEXT, &Editor::OnDryWetText);
133
134 mDryWetS = S
135 .Name(XO("Dry Wet"))
136 .Style(wxSL_HORIZONTAL)
137 .MinSize( { 100, -1 } )
138 .AddSlider( {}, DryWet.def * DryWet.scale, DryWet.max * DryWet.scale, DryWet.min * DryWet.scale);
139 BindTo(*mDryWetS, wxEVT_SLIDER, &Editor::OnDryWetSlider);
140
141 mFreqT = S
142 .Validator<FloatingPointValidator<double>>(
143 5, &ms.mFreq, NumValidatorStyle::ONE_TRAILING_ZERO, Freq.min, Freq.max)
144 .AddTextBox(XXO("LFO Freq&uency (Hz):"), L"", 15);
145 BindTo(*mFreqT, wxEVT_TEXT, &Editor::OnFreqText);
146
147 mFreqS = S
148 .Name(XO("LFO frequency in hertz"))
149 .Style(wxSL_HORIZONTAL)
150 .MinSize( { 100, -1 } )
151 .AddSlider( {}, Freq.def * Freq.scale, Freq.max * Freq.scale, 0.0);
152 BindTo(*mFreqS, wxEVT_SLIDER, &Editor::OnFreqSlider);
153
154 mPhaseT = S
155 .Validator<FloatingPointValidator<double>>(
156 1, &ms.mPhase, NumValidatorStyle::DEFAULT, Phase.min, Phase.max)
157 .AddTextBox(XXO("LFO Sta&rt Phase (deg.):"), L"", 15);
158 BindTo(*mPhaseT, wxEVT_TEXT, &Editor::OnPhaseText);
159
160 mPhaseS = S
161 .Name(XO("LFO start phase in degrees"))
162 .Style(wxSL_HORIZONTAL)
163 .MinSize( { 100, -1 } )
164 .AddSlider( {}, Phase.def * Phase.scale, Phase.max * Phase.scale, Phase.min * Phase.scale);
165 mPhaseS->SetLineSize(10);
166 BindTo(*mPhaseS, wxEVT_SLIDER, &Editor::OnPhaseSlider);
167
168 mDepthT = S
169 .Validator<IntegerValidator<int>>(
170 &ms.mDepth, NumValidatorStyle::DEFAULT, Depth.min, Depth.max)
171 .AddTextBox(XXO("Dept&h:"), L"", 15);
172 BindTo(*mDepthT, wxEVT_TEXT, &Editor::OnDepthText);
173
174 mDepthS = S
175 .Name(XO("Depth in percent"))
176 .Style(wxSL_HORIZONTAL)
177 .MinSize( { 100, -1 } )
178 .AddSlider( {}, Depth.def * Depth.scale, Depth.max * Depth.scale, Depth.min * Depth.scale);
179 BindTo(*mDepthS, wxEVT_SLIDER, &Editor::OnDepthSlider);
180
181 mFeedbackT = S
182 .Validator<IntegerValidator<int>>(
183 &ms.mFeedback, NumValidatorStyle::DEFAULT, Feedback.min, Feedback.max)
184 .AddTextBox(XXO("Feedbac&k (%):"), L"", 15);
186
187 mFeedbackS = S
188 .Name(XO("Feedback in percent"))
189 .Style(wxSL_HORIZONTAL)
190 .MinSize( { 100, -1 } )
192 mFeedbackS->SetLineSize(10);
194
195 mOutGainT = S
196 .Validator<FloatingPointValidator<double>>(
197 1, &ms.mOutGain, NumValidatorStyle::DEFAULT, OutGain.min, OutGain.max)
198 .AddTextBox(XXO("&Output gain (dB):"), L"", 12);
199 BindTo(*mOutGainT, wxEVT_TEXT, &Editor::OnGainText);
200
201 mOutGainS = S
202 .Name(XO("Output gain (dB)"))
203 .Style(wxSL_HORIZONTAL)
204 .MinSize( { 100, -1 } )
206 BindTo(*mOutGainS, wxEVT_SLIDER, &Editor::OnGainSlider);
207 }
208 S.EndMultiColumn();
209
210}
211
213{
214 // get the settings from the MessageBuffer and write them to our local copy
215 const auto& settings = mAccess.Get();
216
217 mSettings = GetSettings(settings);
218
219 if (!mUIParent->TransferDataToWindow())
220 {
221 return false;
222 }
223
224 mStagesS-> SetValue((int) (mSettings.mStages * Stages.scale));
225 mDryWetS-> SetValue((int) (mSettings.mDryWet * DryWet.scale));
226 mFreqS-> SetValue((int) (mSettings.mFreq * Freq.scale));
227 mPhaseS-> SetValue((int) (mSettings.mPhase * Phase.scale));
228 mDepthS-> SetValue((int) (mSettings.mDepth * Depth.scale));
229 mFeedbackS->SetValue((int) (mSettings.mFeedback * Feedback.scale));
230 mOutGainS-> SetValue((int) (mSettings.mOutGain * OutGain.scale));
231
232 return true;
233}
234
235
237{
238 // This bit was copied from the original override of TransferDataFromWindow
239 if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
240 {
241 return false;
242 }
243
244 auto& ms = mSettings;
245
246 if (ms.mStages & 1) // must be even
247 {
248 ms.mStages &= ~1;
249 mStagesT->GetValidator()->TransferToWindow();
250 }
251
252 mAccess.ModifySettings
253 (
254 [this](EffectSettings& settings)
255 {
256 // pass back the modified settings to the MessageBuffer
257
258 GetSettings(settings) = mSettings;
259 return nullptr;
260 }
261 );
262
263 return true;
264}
265
266void EffectPhaser::Editor::OnStagesSlider(wxCommandEvent & evt)
267{
268 auto& ms = mSettings;
269
270 ms.mStages = (evt.GetInt() / Stages.scale) & ~1; // must be even;
271 mStagesT->GetValidator()->TransferToWindow();
272 EnableApplyFromValidate();
273
274 ValidateUI();
275 Publish(EffectSettingChanged{});
276}
277
278void EffectPhaser::Editor::OnDryWetSlider(wxCommandEvent & evt)
279{
280 auto& ms = mSettings;
281
282 ms.mDryWet = evt.GetInt() / DryWet.scale;
283 mDryWetT->GetValidator()->TransferToWindow();
284 EnableApplyFromValidate();
285
286 ValidateUI();
287 Publish(EffectSettingChanged{});
288}
289
290void EffectPhaser::Editor::OnFreqSlider(wxCommandEvent & evt)
291{
292 auto& ms = mSettings;
293
294 ms.mFreq = (double) evt.GetInt() / Freq.scale;
295 if (ms.mFreq < Freq.min) ms.mFreq = Freq.min;
296 mFreqT->GetValidator()->TransferToWindow();
297 EnableApplyFromValidate();
298
299 ValidateUI();
300 Publish(EffectSettingChanged{});
301}
302
303void EffectPhaser::Editor::OnPhaseSlider(wxCommandEvent & evt)
304{
305 auto& ms = mSettings;
306
307 int val = ((evt.GetInt() + 5) / 10) * 10; // round to nearest multiple of 10
308 val = val > Phase.max * Phase.scale ? Phase.max * Phase.scale : val;
309 mPhaseS->SetValue(val);
310 ms.mPhase = (double) val / Phase.scale;
311 mPhaseT->GetValidator()->TransferToWindow();
312 EnableApplyFromValidate();
313
314 ValidateUI();
315 Publish(EffectSettingChanged{});
316}
317
318void EffectPhaser::Editor::OnDepthSlider(wxCommandEvent & evt)
319{
320 auto& ms = mSettings;
321
322 ms.mDepth = evt.GetInt() / Depth.scale;
323 mDepthT->GetValidator()->TransferToWindow();
324 EnableApplyFromValidate();
325
326 ValidateUI();
327 Publish(EffectSettingChanged{});
328}
329
331{
332 auto& ms = mSettings;
333
334 int val = evt.GetInt();
335 val = ((val + (val > 0 ? 5 : -5)) / 10) * 10; // round to nearest multiple of 10
336 val = val > Feedback.max * Feedback.scale ? Feedback.max * Feedback.scale : val;
337 mFeedbackS->SetValue(val);
338 ms.mFeedback = val / Feedback.scale;
339 mFeedbackT->GetValidator()->TransferToWindow();
340 EnableApplyFromValidate();
341
342 ValidateUI();
343 Publish(EffectSettingChanged{});
344}
345
346void EffectPhaser::Editor::OnGainSlider(wxCommandEvent & evt)
347{
348 auto& ms = mSettings;
349
350 ms.mOutGain = evt.GetInt() / OutGain.scale;
351 mOutGainT->GetValidator()->TransferToWindow();
352 EnableApplyFromValidate();
353
354 ValidateUI();
355 Publish(EffectSettingChanged{});
356}
357
358void EffectPhaser::Editor::OnStagesText(wxCommandEvent & WXUNUSED(evt))
359{
360 auto& ms = mSettings;
361
362 if (!EnableApplyFromTransferDataFromWindow())
363 {
364 return;
365 }
366
367 mStagesS->SetValue((int) (ms.mStages * Stages.scale));
368
369 ValidateUI();
370 Publish(EffectSettingChanged{});
371}
372
373void EffectPhaser::Editor::OnDryWetText(wxCommandEvent & WXUNUSED(evt))
374{
375 auto& ms = mSettings;
376
377 if (!EnableApplyFromTransferDataFromWindow())
378 {
379 return;
380 }
381
382 mDryWetS->SetValue((int) (ms.mDryWet * DryWet.scale));
383
384 ValidateUI();
385 Publish(EffectSettingChanged{});
386}
387
388void EffectPhaser::Editor::OnFreqText(wxCommandEvent & WXUNUSED(evt))
389{
390 auto& ms = mSettings;
391
392 if (!EnableApplyFromTransferDataFromWindow())
393 {
394 return;
395 }
396
397 mFreqS->SetValue((int) (ms.mFreq * Freq.scale));
398
399 ValidateUI();
400 Publish(EffectSettingChanged{});
401}
402
403void EffectPhaser::Editor::OnPhaseText(wxCommandEvent & WXUNUSED(evt))
404{
405 auto& ms = mSettings;
406
407 if (!EnableApplyFromTransferDataFromWindow())
408 {
409 return;
410 }
411
412 mPhaseS->SetValue((int) (ms.mPhase * Phase.scale));
413
414 ValidateUI();
415 Publish(EffectSettingChanged{});
416}
417
418void EffectPhaser::Editor::OnDepthText(wxCommandEvent & WXUNUSED(evt))
419{
420 auto& ms = mSettings;
421
422 if (!EnableApplyFromTransferDataFromWindow())
423 {
424 return;
425 }
426
427 mDepthS->SetValue((int) (ms.mDepth * Depth.scale));
428
429 ValidateUI();
430 Publish(EffectSettingChanged{});
431}
432
433void EffectPhaser::Editor::OnFeedbackText(wxCommandEvent & WXUNUSED(evt))
434{
435 auto& ms = mSettings;
436
437 if (!EnableApplyFromTransferDataFromWindow())
438 {
439 return;
440 }
441
442 mFeedbackS->SetValue((int) (ms.mFeedback * Feedback.scale));
443
444 ValidateUI();
445 Publish(EffectSettingChanged{});
446}
447
448void EffectPhaser::Editor::OnGainText(wxCommandEvent & WXUNUSED(evt))
449{
450 auto& ms = mSettings;
451
452 if (!EnableApplyFromTransferDataFromWindow())
453 {
454 return;
455 }
456
457 mOutGainS->SetValue((int) (ms.mOutGain * OutGain.scale));
458
459 ValidateUI();
460 Publish(EffectSettingChanged{});
461}
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:51
bool ValidateUI(const EffectPlugin &context, EffectSettings &) const override
static bool EnableApply(wxWindow *parent, bool enable=true)
Enable or disable the Apply button of the dialog that contains parent.
void BindTo(wxEvtHandler &src, const EventTag &eventType, void(Class::*pmf)(Event &))
Definition: EffectEditor.h:85
Performs effect computation.
Hold values to send to effect output meters.
std::unique_ptr< EffectEditor > MakeEditor(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs) const override
Called only from PopulateUI, to add controls to effect panel.
Definition: Phaser.cpp:90
virtual const EffectSettings & Get()=0
static EffectPhaserSettings & GetSettings(EffectSettings &settings)
Assume settings originated from MakeSettings() and copies thereof.
Definition: Effect.h:166
static constexpr EffectParameter Depth
Definition: PhaserBase.h:178
static constexpr EffectParameter DryWet
Definition: PhaserBase.h:155
static constexpr EffectParameter Feedback
Definition: PhaserBase.h:185
static constexpr EffectParameter Freq
Definition: PhaserBase.h:164
static constexpr EffectParameter Phase
Definition: PhaserBase.h:171
static constexpr EffectParameter Stages
Definition: PhaserBase.h:146
static constexpr EffectParameter OutGain
Definition: PhaserBase.h:194
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:640
BuiltinEffectsModule::Registration< EffectPhaser > reg
Definition: Phaser.cpp:23
const Type scale
Scaling factor, for slider control.
const Type def
Default value.
const Type min
Minimum value.
const Type max
Maximum value.
wxWeakRef< wxWindow > mUIParent
Definition: Phaser.cpp:41
bool EnableApplyFromTransferDataFromWindow()
Definition: Phaser.cpp:82
wxSlider * mPhaseS
Definition: Phaser.cpp:55
bool ValidateUI() override
Get settings data from the panel; may make error dialogs and return false.
Definition: Phaser.cpp:236
void OnGainSlider(wxCommandEvent &evt)
Definition: Phaser.cpp:346
bool UpdateUI() override
Update appearance of the panel for changes in settings.
Definition: Phaser.cpp:212
void OnStagesSlider(wxCommandEvent &evt)
Definition: Phaser.cpp:266
wxSlider * mFreqS
Definition: Phaser.cpp:54
Editor(const EffectUIServices &services, EffectSettingsAccess &access, const EffectPhaserSettings &settings)
Definition: Phaser.cpp:29
wxTextCtrl * mDryWetT
Definition: Phaser.cpp:45
wxTextCtrl * mOutGainT
Definition: Phaser.cpp:50
wxSlider * mOutGainS
Definition: Phaser.cpp:58
void OnFreqSlider(wxCommandEvent &evt)
Definition: Phaser.cpp:290
void OnGainText(wxCommandEvent &evt)
Definition: Phaser.cpp:448
wxSlider * mDepthS
Definition: Phaser.cpp:56
void OnFeedbackSlider(wxCommandEvent &evt)
Definition: Phaser.cpp:330
EffectPhaserSettings mSettings
Definition: Phaser.cpp:42
void OnPhaseSlider(wxCommandEvent &evt)
Definition: Phaser.cpp:303
wxSlider * mFeedbackS
Definition: Phaser.cpp:57
void OnPhaseText(wxCommandEvent &evt)
Definition: Phaser.cpp:403
wxTextCtrl * mFeedbackT
Definition: Phaser.cpp:49
wxSlider * mDryWetS
Definition: Phaser.cpp:53
void OnFeedbackText(wxCommandEvent &evt)
Definition: Phaser.cpp:433
void OnDryWetText(wxCommandEvent &evt)
Definition: Phaser.cpp:373
wxTextCtrl * mDepthT
Definition: Phaser.cpp:48
wxTextCtrl * mFreqT
Definition: Phaser.cpp:46
void EnableApplyFromValidate()
Definition: Phaser.cpp:77
void OnDryWetSlider(wxCommandEvent &evt)
Definition: Phaser.cpp:278
void OnDepthSlider(wxCommandEvent &evt)
Definition: Phaser.cpp:318
void OnFreqText(wxCommandEvent &evt)
Definition: Phaser.cpp:388
wxTextCtrl * mStagesT
Definition: Phaser.cpp:44
virtual ~Editor()=default
void OnStagesText(wxCommandEvent &evt)
Definition: Phaser.cpp:358
void OnDepthText(wxCommandEvent &evt)
Definition: Phaser.cpp:418
wxTextCtrl * mPhaseT
Definition: Phaser.cpp:47
void PopulateOrExchange(ShuttleGui &S)
Definition: Phaser.cpp:102
wxSlider * mStagesS
Definition: Phaser.cpp:52
Message sent by EffectEditor when a setting is changed by the user.
Definition: EffectEditor.h:26
Externalized state of a plug-in.