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
186 for (auto t : inputTracks()->Selected< const WaveTrack >())
187 {
188 auto pair = t->GetMinMax(mT0, mT1); // may throw
189 const float min = pair.first, max = pair.second;
190 float newpeak = (fabs(min) > fabs(max) ? fabs(min) : fabs(max));
191
192 if (newpeak > mPeak)
193 {
194 mPeak = newpeak;
195 }
196 }
197
198 return true;
199}
200
202{
203 return { std::pair{
205 } };
206}
207
208std::unique_ptr<EffectEditor> EffectAmplify::PopulateOrExchange(
210 const EffectOutputs *)
211{
212 mUIParent = S.GetParent();
213
214 enum{ precision = 3 }; // allow (a generous) 3 decimal places for Amplification (dB)
215
216 bool batch = IsBatchProcessing();
217 if ( batch )
218 {
219 mCanClip = true;
220 mPeak = 1.0;
221 }
222 else
223 {
224 if (mPeak > 0.0)
225 {
226 mRatio = 1.0 / mPeak;
228 }
229 else
230 {
231 mRatio = 1.0;
232 }
233 }
234
235 // At this point mNewPeak is still uninitialized; this will initialize it
236 ClampRatio();
237
238 S.AddSpace(0, 5);
239
240 S.StartVerticalLay(0);
241 {
242 // Amplitude
243 S.StartMultiColumn(2, wxCENTER);
244 {
245 mAmpT = S.Id(ID_Amp)
246 .Validator<FloatingPointValidator<double>>(
247 precision, &mAmp, NumValidatorStyle::ONE_TRAILING_ZERO, Amp.min, Amp.max )
248 .AddTextBox(XXO("&Amplification (dB):"), L"", 12);
249 }
250 S.EndMultiColumn();
251
252 // Amplitude
253 S.StartHorizontalLay(wxEXPAND);
254 {
255 mAmpS = S.Id(ID_Amp)
256 .Style(wxSL_HORIZONTAL)
257 .Name(XO("Amplification dB"))
258 .AddSlider( {}, 0, Amp.max * Amp.scale, Amp.min * Amp.scale);
259 }
260 S.EndHorizontalLay();
261
262 // Peak
263 S.StartMultiColumn(2, wxCENTER);
264 {
265 mNewPeakT = S.Id(ID_Peak)
266 .Validator<FloatingPointValidator<double>>(
267 // One extra decimal place so that rounding is visible to user
268 // (see: bug 958)
269 precision + 1,
270 &mNewPeak, NumValidatorStyle::ONE_TRAILING_ZERO,
271 // min and max need same precision as what we're validating (bug 963)
272 RoundValue( precision + 1, Amp.min + LINEAR_TO_DB(mPeak) ),
273 RoundValue( precision + 1, Amp.max + LINEAR_TO_DB(mPeak) ) )
274 .AddTextBox(XXO("&New Peak Amplitude (dB):"), L"", 12);
275 }
276 S.EndMultiColumn();
277
278 // Clipping
279 S.StartHorizontalLay(wxCENTER);
280 {
281
282 mClip = S.Id(ID_Clip).Disable( batch )
283 .AddCheckBox(XXO("Allo&w clipping"), false);
284 }
285 S.EndHorizontalLay();
286 }
287 S.EndVerticalLay();
288
289 return nullptr;
290}
291
293{
294 // limit range of gain
295 double dBInit = LINEAR_TO_DB(mRatio);
296 double dB = std::clamp<double>(dBInit, Amp.min, Amp.max);
297 if (dB != dBInit)
298 mRatio = DB_TO_LINEAR(dB);
299
302}
303
305{
306 mAmpT->GetValidator()->TransferToWindow();
307
308 mAmpS->SetValue((int) (mAmp * Amp.scale + 0.5f));
309
310 mNewPeakT->GetValidator()->TransferToWindow();
311
312 mClip->SetValue(mCanClip);
313
314 CheckClip();
315
316 return true;
317}
318
320{
321 if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
322 {
323 return false;
324 }
325
326 mRatio = DB_TO_LINEAR(std::clamp<double>(mAmp * Amp.scale, Amp.min * Amp.scale, Amp.max * Amp.scale) / Amp.scale);
327
328 mCanClip = mClip->GetValue();
329
330 if (!mCanClip && mRatio * mPeak > 1.0)
331 {
332 mRatio = 1.0 / mPeak;
333 }
334
335 ClampRatio();
336
337 return true;
338}
339
340// EffectAmplify implementation
341
343{
345 mClip->GetValue() || (mPeak > 0.0 && mRatio <= mRatioClip));
346}
347
348void EffectAmplify::OnAmpText(wxCommandEvent & WXUNUSED(evt))
349{
350 if (!mAmpT->GetValidator()->TransferFromWindow())
351 {
353 return;
354 }
355
356 mRatio = DB_TO_LINEAR(std::clamp<double>(mAmp * Amp.scale, Amp.min * Amp.scale, Amp.max * Amp.scale) / Amp.scale);
357
358 mAmpS->SetValue((int) (LINEAR_TO_DB(mRatio) * Amp.scale + 0.5));
359
361 mNewPeakT->GetValidator()->TransferToWindow();
362
363 CheckClip();
364}
365
366void EffectAmplify::OnPeakText(wxCommandEvent & WXUNUSED(evt))
367{
368 if (!mNewPeakT->GetValidator()->TransferFromWindow())
369 {
371 return;
372 }
373
374 if (mNewPeak == 0.0)
376 else
378
379 double ampInit = LINEAR_TO_DB(mRatio);
380 mAmp = std::clamp<double>(ampInit, Amp.min, Amp.max);
381 if (mAmp != ampInit)
383
384 mAmpT->GetValidator()->TransferToWindow();
385
386 mAmpS->SetValue((int) (mAmp * Amp.scale + 0.5f));
387
388 CheckClip();
389}
390
391void EffectAmplify::OnAmpSlider(wxCommandEvent & evt)
392{
393 double dB = evt.GetInt() / Amp.scale;
394 mRatio = DB_TO_LINEAR(std::clamp<double>(dB, Amp.min, Amp.max));
395
396 double dB2 = (evt.GetInt() - 1) / Amp.scale;
397 double ratio2 = DB_TO_LINEAR(std::clamp<double>(dB2, Amp.min, Amp.max));
398
399 if (!mClip->GetValue() && mRatio * mPeak > 1.0 && ratio2 * mPeak < 1.0)
400 {
401 mRatio = 1.0 / mPeak;
402 }
403
405 mAmpT->GetValidator()->TransferToWindow();
406
408 mNewPeakT->GetValidator()->TransferToWindow();
409
410 CheckClip();
411}
412
413void EffectAmplify::OnClipCheckBox(wxCommandEvent & WXUNUSED(evt))
414{
415 CheckClip();
416}
@ 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:561
#define DB_TO_LINEAR(x)
Definition: MemoryX.h:560
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:87
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:292
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:413
wxSlider * mAmpS
Definition: Amplify.h:88
void OnAmpSlider(wxCommandEvent &evt)
Definition: Amplify.cpp:391
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:208
bool TransferDataToWindow(const EffectSettings &settings) override
Definition: Amplify.cpp:304
bool TransferDataFromWindow(EffectSettings &settings) override
Definition: Amplify.cpp:319
const EffectParameterMethods & Parameters() const override
Definition: Amplify.cpp:50
wxCheckBox * mClip
Definition: Amplify.h:91
void OnAmpText(wxCommandEvent &evt)
Definition: Amplify.cpp:348
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:201
void OnPeakText(wxCommandEvent &evt)
Definition: Amplify.cpp:366
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:342
double mT1
Definition: EffectBase.h:113
const TrackList * inputTracks() const
Definition: EffectBase.h:108
double mT0
Definition: EffectBase.h:112
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:302
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:625
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.