Audacity 3.2.0
Amplify.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 Amplify.cpp
6
7 Dominic Mazzoni
8 Vaughan Johnson (Preview)
9
10*******************************************************************//*******************************************************************/
20
21
22#include "Amplify.h"
23#include "EffectEditor.h"
24#include "LoadEffects.h"
25
26#include <math.h>
27#include <float.h>
28
29#include <wx/button.h>
30#include <wx/checkbox.h>
31#include <wx/sizer.h>
32#include <wx/slider.h>
33#include <wx/stattext.h>
34#include <wx/textctrl.h>
35#include <wx/valtext.h>
36#include <wx/log.h>
37
38#include "EffectOutputTracks.h"
39#include "ShuttleGui.h"
40#include "WaveTrack.h"
41#include "WaveTrackUtilities.h"
42#include "../widgets/valnum.h"
43
44
45enum
46{
47 ID_Amp = 10000,
50};
51
53{
55 // Interactive case
57 > parameters;
58
60 Ratio
61 > batchParameters{
62 // If invoking Amplify from a macro, mCanClip is not a parameter
63 // but is always true
64 [](EffectAmplify &, EffectSettings &, EffectAmplify &e, bool) {
65 e.mCanClip = true;
66 return true;
67 },
68 };
69
70 // Parameters differ depending on batch mode. Option to disable clipping
71 // is interactive only.
73 return batchParameters;
74 else
75 return parameters;
76}
77
78//
79// EffectAmplify
80//
81
83{ XO("Amplify") };
84
86
87BEGIN_EVENT_TABLE(EffectAmplify, wxEvtHandler)
93
95{
96 // In case the dialog is cancelled before effect processing
97 static_cast<EffectAmplify&>(GetEffect()).DestroyOutputTracks();
98}
99
101{
102 mAmp = Amp.def;
103 // Ratio.def == DB_TO_LINEAR(Amp.def)
104 Parameters().Reset(*this);
105 mRatioClip = 0.0;
106 mPeak = 0.0;
107
109}
110
112{
113}
114
115// ComponentInterface implementation
116
118{
119 return Symbol;
120}
121
123{
124 // Note: This is useful only after ratio has been set.
125 return XO("Increases or decreases the volume of the audio you have selected");
126}
127
129{
130 return L"Amplify";
131}
132
133// EffectDefinitionInterface implementation
134
136{
137 return EffectTypeProcess;
138}
139
141{
142 return 1;
143}
144
146{
147 return 1;
148}
149
151 const float *const *inBlock, float *const *outBlock, size_t blockLen)
152{
153 for (decltype(blockLen) i = 0; i < blockLen; i++)
154 {
155 outBlock[0][i] = inBlock[0][i] * mRatio;
156 }
157
158 return blockLen;
159}
160
163{
164 // To do: externalize state so const_cast isn't needed
165 return const_cast<EffectAmplify&>(*this).DoLoadFactoryDefaults(settings);
166}
167
169{
170 Init();
171
172 mRatioClip = 0.0;
173 if (mPeak > 0.0)
174 {
175 mRatio = 1.0 / mPeak;
177 }
178 else
179 {
180 mRatio = 1.0;
181 }
182 mCanClip = false;
183
184 ClampRatio();
185 return { nullptr };
186}
187
188// Effect implementation
189
191{
192 auto range = inputTracks()->Selected<const WaveTrack>();
193 bool hasPitchOrSpeed = any_of(begin(range), end(range), [this](auto* pTrack) {
195 });
196 if (hasPitchOrSpeed)
197 range = MakeOutputTracks()->Get().Selected<const WaveTrack>();
198 mPeak = 0.0;
199 for (auto t : range) {
200 for (const auto pChannel : t->Channels()) {
201 auto pair = pChannel->GetMinMax(mT0, mT1); // may throw
202 const float min = pair.first, max = pair.second;
203 const float newpeak = std::max(fabs(min), fabs(max));
204 mPeak = std::max<double>(mPeak, newpeak);
205 }
206 }
207 return true;
208}
209
211{
212 return { std::pair{
214 } };
215}
216
217std::unique_ptr<EffectEditor> EffectAmplify::PopulateOrExchange(
219 const EffectOutputs *)
220{
221 mUIParent = S.GetParent();
222
223 enum{ precision = 3 }; // allow (a generous) 3 decimal places for Amplification (dB)
224
225 bool batch = IsBatchProcessing();
226 if ( batch )
227 {
228 mCanClip = true;
229 mPeak = 1.0;
230 }
231 else
232 {
233 if (mPeak > 0.0)
234 {
235 mRatio = 1.0 / mPeak;
237 }
238 else
239 {
240 mRatio = 1.0;
241 }
242 }
243
244 // At this point mNewPeak is still uninitialized; this will initialize it
245 ClampRatio();
246
247 S.AddSpace(0, 5);
248
249 S.StartVerticalLay(0);
250 {
251 // Amplitude
252 S.StartMultiColumn(2, wxCENTER);
253 {
254 mAmpT = S.Id(ID_Amp)
255 .Validator<FloatingPointValidator<double>>(
256 precision, &mAmp, NumValidatorStyle::ONE_TRAILING_ZERO, Amp.min, Amp.max )
257 .AddTextBox(XXO("&Amplification (dB):"), L"", 12);
258 }
259 S.EndMultiColumn();
260
261 // Amplitude
262 S.StartHorizontalLay(wxEXPAND);
263 {
264 mAmpS = S.Id(ID_Amp)
265 .Style(wxSL_HORIZONTAL)
266 .Name(XO("Amplification dB"))
267 .AddSlider( {}, 0, Amp.max * Amp.scale, Amp.min * Amp.scale);
268 }
269 S.EndHorizontalLay();
270
271 // Peak
272 S.StartMultiColumn(2, wxCENTER);
273 {
274 mNewPeakT = S.Id(ID_Peak)
275 .Validator<FloatingPointValidator<double>>(
276 // One extra decimal place so that rounding is visible to user
277 // (see: bug 958)
278 precision + 1,
279 &mNewPeak, NumValidatorStyle::ONE_TRAILING_ZERO,
280 // min and max need same precision as what we're validating (bug 963)
281 RoundValue( precision + 1, Amp.min + LINEAR_TO_DB(mPeak) ),
282 RoundValue( precision + 1, Amp.max + LINEAR_TO_DB(mPeak) ) )
283 .AddTextBox(XXO("&New Peak Amplitude (dB):"), L"", 12);
284 }
285 S.EndMultiColumn();
286
287 // Clipping
288 S.StartHorizontalLay(wxCENTER);
289 {
290
291 mClip = S.Id(ID_Clip).Disable( batch )
292 .AddCheckBox(XXO("Allo&w clipping"), false);
293 }
294 S.EndHorizontalLay();
295 }
296 S.EndVerticalLay();
297
298 return nullptr;
299}
300
302{
303 // limit range of gain
304 double dBInit = LINEAR_TO_DB(mRatio);
305 double dB = std::clamp<double>(dBInit, Amp.min, Amp.max);
306 if (dB != dBInit)
307 mRatio = DB_TO_LINEAR(dB);
308
311}
312
314{
315 mAmpT->GetValidator()->TransferToWindow();
316
317 mAmpS->SetValue((int) (mAmp * Amp.scale + 0.5f));
318
319 mNewPeakT->GetValidator()->TransferToWindow();
320
321 mClip->SetValue(mCanClip);
322
323 CheckClip();
324
325 return true;
326}
327
329{
330 if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
331 {
332 return false;
333 }
334
335 mRatio = DB_TO_LINEAR(std::clamp<double>(mAmp * Amp.scale, Amp.min * Amp.scale, Amp.max * Amp.scale) / Amp.scale);
336
337 mCanClip = mClip->GetValue();
338
339 if (!mCanClip && mRatio * mPeak > 1.0)
340 {
341 mRatio = 1.0 / mPeak;
342 }
343
344 ClampRatio();
345
346 return true;
347}
348
349std::shared_ptr<EffectInstance> EffectAmplify::MakeInstance() const
350{
351 // Cheat with const_cast to return an object that calls through to
352 // non-const methods of a stateful effect.
353 return std::make_shared<Instance>(const_cast<EffectAmplify&>(*this));
354}
355
356// EffectAmplify implementation
357
359{
361 mClip->GetValue() || (mPeak > 0.0 && mRatio <= mRatioClip));
362}
363
364void EffectAmplify::OnAmpText(wxCommandEvent & WXUNUSED(evt))
365{
366 if (!mAmpT->GetValidator()->TransferFromWindow())
367 {
369 return;
370 }
371
372 mRatio = DB_TO_LINEAR(std::clamp<double>(mAmp * Amp.scale, Amp.min * Amp.scale, Amp.max * Amp.scale) / Amp.scale);
373
374 mAmpS->SetValue((int) (LINEAR_TO_DB(mRatio) * Amp.scale + 0.5));
375
377 mNewPeakT->GetValidator()->TransferToWindow();
378
379 CheckClip();
380}
381
382void EffectAmplify::OnPeakText(wxCommandEvent & WXUNUSED(evt))
383{
384 if (!mNewPeakT->GetValidator()->TransferFromWindow())
385 {
387 return;
388 }
389
390 if (mNewPeak == 0.0)
392 else
394
395 double ampInit = LINEAR_TO_DB(mRatio);
396 mAmp = std::clamp<double>(ampInit, Amp.min, Amp.max);
397 if (mAmp != ampInit)
399
400 mAmpT->GetValidator()->TransferToWindow();
401
402 mAmpS->SetValue((int) (mAmp * Amp.scale + 0.5f));
403
404 CheckClip();
405}
406
407void EffectAmplify::OnAmpSlider(wxCommandEvent & evt)
408{
409 double dB = evt.GetInt() / Amp.scale;
410 mRatio = DB_TO_LINEAR(std::clamp<double>(dB, Amp.min, Amp.max));
411
412 double dB2 = (evt.GetInt() - 1) / Amp.scale;
413 double ratio2 = DB_TO_LINEAR(std::clamp<double>(dB2, Amp.min, Amp.max));
414
415 if (!mClip->GetValue() && mRatio * mPeak > 1.0 && ratio2 * mPeak < 1.0)
416 {
417 mRatio = 1.0 / mPeak;
418 }
419
421 mAmpT->GetValidator()->TransferToWindow();
422
424 mNewPeakT->GetValidator()->TransferToWindow();
425
426 CheckClip();
427}
428
429void EffectAmplify::OnClipCheckBox(wxCommandEvent & WXUNUSED(evt))
430{
431 CheckClip();
432}
@ ID_Clip
Definition: Amplify.cpp:49
@ ID_Peak
Definition: Amplify.cpp:48
@ ID_Amp
Definition: Amplify.cpp:47
END_EVENT_TABLE()
int min(int a, int b)
EffectType
@ EffectTypeProcess
std::optional< std::unique_ptr< EffectSettingsAccess::Message > > OptionalMessage
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define LINEAR_TO_DB(x)
Definition: MemoryX.h:336
#define DB_TO_LINEAR(x)
Definition: MemoryX.h:335
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:69
Generates EffectParameterMethods overrides from variadic template arguments.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
An Effect that makes a sound louder or softer.
Definition: Amplify.h:28
OptionalMessage LoadFactoryDefaults(EffectSettings &settings) const override
Definition: Amplify.cpp:162
void ClampRatio()
Definition: Amplify.cpp:301
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
Definition: Amplify.cpp:145
static const ComponentInterfaceSymbol Symbol
Definition: Amplify.h:32
wxWeakRef< wxWindow > mUIParent
Definition: Amplify.h:85
static constexpr EffectParameter Ratio
Definition: Amplify.h:104
wxTextCtrl * mNewPeakT
Definition: Amplify.h:97
static constexpr EffectParameter Clipping
Definition: Amplify.h:109
virtual ~EffectAmplify()
Definition: Amplify.cpp:111
double mRatioClip
Definition: Amplify.h:90
std::shared_ptr< EffectInstance > MakeInstance() const override
Make an object maintaining short-term state of an Effect.
Definition: Amplify.cpp:349
static constexpr EffectParameter Amp
Definition: Amplify.h:107
double mPeak
Definition: Amplify.h:87
bool mCanClip
Definition: Amplify.h:93
void OnClipCheckBox(wxCommandEvent &evt)
Definition: Amplify.cpp:429
wxSlider * mAmpS
Definition: Amplify.h:95
void OnAmpSlider(wxCommandEvent &evt)
Definition: Amplify.cpp:407
EffectType GetType() const override
Type determines how it behaves.
Definition: Amplify.cpp:135
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
Definition: Amplify.cpp:140
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
Definition: Amplify.cpp:128
bool Init() override
Definition: Amplify.cpp:190
std::unique_ptr< EffectEditor > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs) override
Add controls to effect panel; always succeeds.
Definition: Amplify.cpp:217
bool TransferDataToWindow(const EffectSettings &settings) override
Definition: Amplify.cpp:313
bool TransferDataFromWindow(EffectSettings &settings) override
Definition: Amplify.cpp:328
const EffectParameterMethods & Parameters() const override
Definition: Amplify.cpp:52
wxCheckBox * mClip
Definition: Amplify.h:98
void OnAmpText(wxCommandEvent &evt)
Definition: Amplify.cpp:364
OptionalMessage DoLoadFactoryDefaults(EffectSettings &settings)
Definition: Amplify.cpp:168
TranslatableString GetDescription() const override
Definition: Amplify.cpp:122
double mAmp
Definition: Amplify.h:91
std::any BeginPreview(const EffectSettings &settings) override
Called when Preview() starts, to allow temporary effect state changes.
Definition: Amplify.cpp:210
void OnPeakText(wxCommandEvent &evt)
Definition: Amplify.cpp:382
ComponentInterfaceSymbol GetSymbol() const override
Definition: Amplify.cpp:117
double mRatio
Definition: Amplify.h:89
double mNewPeak
Definition: Amplify.h:92
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
Definition: Amplify.cpp:150
wxTextCtrl * mAmpT
Definition: Amplify.h:96
void CheckClip()
Definition: Amplify.cpp:358
double mT1
Definition: EffectBase.h:116
void SetLinearEffectFlag(bool linearEffectFlag)
Definition: EffectBase.cpp:215
const TrackList * inputTracks() const
Definition: EffectBase.h:91
double mT0
Definition: EffectBase.h:115
static bool EnableApply(wxWindow *parent, bool enable=true)
Enable or disable the Apply button of the dialog that contains parent.
bool IsBatchProcessing() const override
Definition: Effect.cpp:295
Performs effect computation.
Hold values to send to effect output meters.
Interface for manipulations of an Effect's settings.
virtual void Reset(Effect &effect) const =0
std::shared_ptr< EffectOutputTracks > MakeOutputTracks()
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:630
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:1114
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
Definition: WaveTrack.h:227
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
WAVE_TRACK_API bool HasPitchOrSpeed(const WaveTrack &track, double t0, double t1)
BuiltinEffectsModule::Registration< EffectAmplify > reg
Definition: Amplify.cpp:85
const Type scale
Scaling factor, for slider control.
const Type def
Default value.
const Type min
Minimum value.
const Type max
Maximum value.
Externalized state of a plug-in.