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 "ShuttleGui.h"
39#include "WaveTrack.h"
40#include "../widgets/valnum.h"
41
42
43enum
44{
45 ID_Amp = 10000,
48};
49
51{
53 // Interactive case
55 > parameters;
56
58 Ratio
59 > batchParameters{
60 // If invoking Amplify from a macro, mCanClip is not a parameter
61 // but is always true
62 [](EffectAmplify &, EffectSettings &, EffectAmplify &e, bool) {
63 e.mCanClip = true;
64 return true;
65 },
66 };
67
68 // Parameters differ depending on batch mode. Option to disable clipping
69 // is interactive only.
71 return batchParameters;
72 else
73 return parameters;
74}
75
76//
77// EffectAmplify
78//
79
81{ XO("Amplify") };
82
84
85BEGIN_EVENT_TABLE(EffectAmplify, wxEvtHandler)
91
93{
94 mAmp = Amp.def;
95 // Ratio.def == DB_TO_LINEAR(Amp.def)
96 Parameters().Reset(*this);
97 mRatioClip = 0.0;
98 mPeak = 0.0;
99
100 SetLinearEffectFlag(true);
101}
102
104{
105}
106
107// ComponentInterface implementation
108
110{
111 return Symbol;
112}
113
115{
116 // Note: This is useful only after ratio has been set.
117 return XO("Increases or decreases the volume of the audio you have selected");
118}
119
121{
122 return L"Amplify";
123}
124
125// EffectDefinitionInterface implementation
126
128{
129 return EffectTypeProcess;
130}
131
133{
134 return 1;
135}
136
138{
139 return 1;
140}
141
143 const float *const *inBlock, float *const *outBlock, size_t blockLen)
144{
145 for (decltype(blockLen) i = 0; i < blockLen; i++)
146 {
147 outBlock[0][i] = inBlock[0][i] * mRatio;
148 }
149
150 return blockLen;
151}
152
155{
156 // To do: externalize state so const_cast isn't needed
157 return const_cast<EffectAmplify&>(*this).DoLoadFactoryDefaults(settings);
158}
159
161{
162 Init();
163
164 mRatioClip = 0.0;
165 if (mPeak > 0.0)
166 {
167 mRatio = 1.0 / mPeak;
169 }
170 else
171 {
172 mRatio = 1.0;
173 }
174 mCanClip = false;
175
176 ClampRatio();
177 return { nullptr };
178}
179
180// Effect implementation
181
183{
184 mPeak = 0.0;
185 for (auto t : inputTracks()->Selected<const WaveTrack>()) {
186 for (const auto pChannel : t->Channels()) {
187 auto pair = pChannel->GetMinMax(mT0, mT1); // may throw
188 const float min = pair.first, max = pair.second;
189 const float newpeak = std::max(fabs(min), fabs(max));
190 mPeak = std::max<double>(mPeak, newpeak);
191 }
192 }
193 return true;
194}
195
197{
198 return { std::pair{
200 } };
201}
202
203std::unique_ptr<EffectEditor> EffectAmplify::PopulateOrExchange(
205 const EffectOutputs *)
206{
207 mUIParent = S.GetParent();
208
209 enum{ precision = 3 }; // allow (a generous) 3 decimal places for Amplification (dB)
210
211 bool batch = IsBatchProcessing();
212 if ( batch )
213 {
214 mCanClip = true;
215 mPeak = 1.0;
216 }
217 else
218 {
219 if (mPeak > 0.0)
220 {
221 mRatio = 1.0 / mPeak;
223 }
224 else
225 {
226 mRatio = 1.0;
227 }
228 }
229
230 // At this point mNewPeak is still uninitialized; this will initialize it
231 ClampRatio();
232
233 S.AddSpace(0, 5);
234
235 S.StartVerticalLay(0);
236 {
237 // Amplitude
238 S.StartMultiColumn(2, wxCENTER);
239 {
240 mAmpT = S.Id(ID_Amp)
241 .Validator<FloatingPointValidator<double>>(
242 precision, &mAmp, NumValidatorStyle::ONE_TRAILING_ZERO, Amp.min, Amp.max )
243 .AddTextBox(XXO("&Amplification (dB):"), L"", 12);
244 }
245 S.EndMultiColumn();
246
247 // Amplitude
248 S.StartHorizontalLay(wxEXPAND);
249 {
250 mAmpS = S.Id(ID_Amp)
251 .Style(wxSL_HORIZONTAL)
252 .Name(XO("Amplification dB"))
253 .AddSlider( {}, 0, Amp.max * Amp.scale, Amp.min * Amp.scale);
254 }
255 S.EndHorizontalLay();
256
257 // Peak
258 S.StartMultiColumn(2, wxCENTER);
259 {
260 mNewPeakT = S.Id(ID_Peak)
261 .Validator<FloatingPointValidator<double>>(
262 // One extra decimal place so that rounding is visible to user
263 // (see: bug 958)
264 precision + 1,
265 &mNewPeak, NumValidatorStyle::ONE_TRAILING_ZERO,
266 // min and max need same precision as what we're validating (bug 963)
267 RoundValue( precision + 1, Amp.min + LINEAR_TO_DB(mPeak) ),
268 RoundValue( precision + 1, Amp.max + LINEAR_TO_DB(mPeak) ) )
269 .AddTextBox(XXO("&New Peak Amplitude (dB):"), L"", 12);
270 }
271 S.EndMultiColumn();
272
273 // Clipping
274 S.StartHorizontalLay(wxCENTER);
275 {
276
277 mClip = S.Id(ID_Clip).Disable( batch )
278 .AddCheckBox(XXO("Allo&w clipping"), false);
279 }
280 S.EndHorizontalLay();
281 }
282 S.EndVerticalLay();
283
284 return nullptr;
285}
286
288{
289 // limit range of gain
290 double dBInit = LINEAR_TO_DB(mRatio);
291 double dB = std::clamp<double>(dBInit, Amp.min, Amp.max);
292 if (dB != dBInit)
293 mRatio = DB_TO_LINEAR(dB);
294
297}
298
300{
301 mAmpT->GetValidator()->TransferToWindow();
302
303 mAmpS->SetValue((int) (mAmp * Amp.scale + 0.5f));
304
305 mNewPeakT->GetValidator()->TransferToWindow();
306
307 mClip->SetValue(mCanClip);
308
309 CheckClip();
310
311 return true;
312}
313
315{
316 if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
317 {
318 return false;
319 }
320
321 mRatio = DB_TO_LINEAR(std::clamp<double>(mAmp * Amp.scale, Amp.min * Amp.scale, Amp.max * Amp.scale) / Amp.scale);
322
323 mCanClip = mClip->GetValue();
324
325 if (!mCanClip && mRatio * mPeak > 1.0)
326 {
327 mRatio = 1.0 / mPeak;
328 }
329
330 ClampRatio();
331
332 return true;
333}
334
335// EffectAmplify implementation
336
338{
340 mClip->GetValue() || (mPeak > 0.0 && mRatio <= mRatioClip));
341}
342
343void EffectAmplify::OnAmpText(wxCommandEvent & WXUNUSED(evt))
344{
345 if (!mAmpT->GetValidator()->TransferFromWindow())
346 {
348 return;
349 }
350
351 mRatio = DB_TO_LINEAR(std::clamp<double>(mAmp * Amp.scale, Amp.min * Amp.scale, Amp.max * Amp.scale) / Amp.scale);
352
353 mAmpS->SetValue((int) (LINEAR_TO_DB(mRatio) * Amp.scale + 0.5));
354
356 mNewPeakT->GetValidator()->TransferToWindow();
357
358 CheckClip();
359}
360
361void EffectAmplify::OnPeakText(wxCommandEvent & WXUNUSED(evt))
362{
363 if (!mNewPeakT->GetValidator()->TransferFromWindow())
364 {
366 return;
367 }
368
369 if (mNewPeak == 0.0)
371 else
373
374 double ampInit = LINEAR_TO_DB(mRatio);
375 mAmp = std::clamp<double>(ampInit, Amp.min, Amp.max);
376 if (mAmp != ampInit)
378
379 mAmpT->GetValidator()->TransferToWindow();
380
381 mAmpS->SetValue((int) (mAmp * Amp.scale + 0.5f));
382
383 CheckClip();
384}
385
386void EffectAmplify::OnAmpSlider(wxCommandEvent & evt)
387{
388 double dB = evt.GetInt() / Amp.scale;
389 mRatio = DB_TO_LINEAR(std::clamp<double>(dB, Amp.min, Amp.max));
390
391 double dB2 = (evt.GetInt() - 1) / Amp.scale;
392 double ratio2 = DB_TO_LINEAR(std::clamp<double>(dB2, Amp.min, Amp.max));
393
394 if (!mClip->GetValue() && mRatio * mPeak > 1.0 && ratio2 * mPeak < 1.0)
395 {
396 mRatio = 1.0 / mPeak;
397 }
398
400 mAmpT->GetValidator()->TransferToWindow();
401
403 mNewPeakT->GetValidator()->TransferToWindow();
404
405 CheckClip();
406}
407
408void EffectAmplify::OnClipCheckBox(wxCommandEvent & WXUNUSED(evt))
409{
410 CheckClip();
411}
@ ID_Clip
Definition: Amplify.cpp:47
@ ID_Peak
Definition: Amplify.cpp:46
@ ID_Amp
Definition: Amplify.cpp:45
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:562
#define DB_TO_LINEAR(x)
Definition: MemoryX.h:561
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:83
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:154
void ClampRatio()
Definition: Amplify.cpp:287
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
Definition: Amplify.cpp:137
static const ComponentInterfaceSymbol Symbol
Definition: Amplify.h:32
wxWeakRef< wxWindow > mUIParent
Definition: Amplify.h:78
static constexpr EffectParameter Ratio
Definition: Amplify.h:97
wxTextCtrl * mNewPeakT
Definition: Amplify.h:90
static constexpr EffectParameter Clipping
Definition: Amplify.h:102
virtual ~EffectAmplify()
Definition: Amplify.cpp:103
double mRatioClip
Definition: Amplify.h:83
static constexpr EffectParameter Amp
Definition: Amplify.h:100
double mPeak
Definition: Amplify.h:80
bool mCanClip
Definition: Amplify.h:86
void OnClipCheckBox(wxCommandEvent &evt)
Definition: Amplify.cpp:408
wxSlider * mAmpS
Definition: Amplify.h:88
void OnAmpSlider(wxCommandEvent &evt)
Definition: Amplify.cpp:386
EffectType GetType() const override
Type determines how it behaves.
Definition: Amplify.cpp:127
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
Definition: Amplify.cpp:132
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
Definition: Amplify.cpp:120
bool Init() override
Definition: Amplify.cpp:182
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:203
bool TransferDataToWindow(const EffectSettings &settings) override
Definition: Amplify.cpp:299
bool TransferDataFromWindow(EffectSettings &settings) override
Definition: Amplify.cpp:314
const EffectParameterMethods & Parameters() const override
Definition: Amplify.cpp:50
wxCheckBox * mClip
Definition: Amplify.h:91
void OnAmpText(wxCommandEvent &evt)
Definition: Amplify.cpp:343
OptionalMessage DoLoadFactoryDefaults(EffectSettings &settings)
Definition: Amplify.cpp:160
TranslatableString GetDescription() const override
Definition: Amplify.cpp:114
double mAmp
Definition: Amplify.h:84
std::any BeginPreview(const EffectSettings &settings) override
Called when Preview() starts, to allow temporary effect state changes.
Definition: Amplify.cpp:196
void OnPeakText(wxCommandEvent &evt)
Definition: Amplify.cpp:361
ComponentInterfaceSymbol GetSymbol() const override
Definition: Amplify.cpp:109
double mRatio
Definition: Amplify.h:82
double mNewPeak
Definition: Amplify.h:85
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
Definition: Amplify.cpp:142
wxTextCtrl * mAmpT
Definition: Amplify.h:89
void CheckClip()
Definition: Amplify.cpp:337
double mT1
Definition: EffectBase.h:116
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:301
Performs effect computation.
Hold values to send to effect output meters.
Interface for manipulations of an Effect's settings.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:630
Holds a msgid for the translation catalog; may also bind format arguments.
BuiltinEffectsModule::Registration< EffectAmplify > reg
Definition: Amplify.cpp:83
const Type scale
Scaling factor, for slider control.
const Type min
Minimum value.
const Type max
Maximum value.
Externalized state of a plug-in.