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 "LoadEffects.h"
24
25#include <math.h>
26#include <float.h>
27
28#include <wx/button.h>
29#include <wx/checkbox.h>
30#include <wx/intl.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 parameters;
72 else
73 return batchParameters;
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
154{
155 // To do: externalize state so const_cast isn't needed
156 return const_cast<EffectAmplify&>(*this).DoLoadFactoryDefaults();
157}
158
160{
161 Init();
162
163 mRatioClip = 0.0;
164 if (mPeak > 0.0)
165 {
166 mRatio = 1.0 / mPeak;
168 }
169 else
170 {
171 mRatio = 1.0;
172 }
173 mCanClip = false;
174
175 ClampRatio();
176 return true;
177}
178
179// Effect implementation
180
182{
183 mPeak = 0.0;
184
185 for (auto t : inputTracks()->Selected< const WaveTrack >())
186 {
187 auto pair = t->GetMinMax(mT0, mT1); // may throw
188 const float min = pair.first, max = pair.second;
189 float newpeak = (fabs(min) > fabs(max) ? fabs(min) : fabs(max));
190
191 if (newpeak > mPeak)
192 {
193 mPeak = newpeak;
194 }
195 }
196
197 return true;
198}
199
201{
202 auto cleanup1 = valueRestorer( mRatio );
203 auto cleanup2 = valueRestorer( mPeak );
204
205 Effect::Preview(access, dryOnly);
206}
207
208std::unique_ptr<EffectUIValidator> EffectAmplify::PopulateOrExchange(
210{
211 enum{ precision = 3 }; // allow (a generous) 3 decimal places for Amplification (dB)
212
213 bool batch = IsBatchProcessing();
214 if ( batch )
215 {
216 mCanClip = true;
217 mPeak = 1.0;
218 }
219 else
220 {
221 if (mPeak > 0.0)
222 {
223 mRatio = 1.0 / mPeak;
225 }
226 else
227 {
228 mRatio = 1.0;
229 }
230 }
231
232 // At this point mNewPeak is still uninitialized; this will initialize it
233 ClampRatio();
234
235 S.AddSpace(0, 5);
236
237 S.StartVerticalLay(0);
238 {
239 // Amplitude
240 S.StartMultiColumn(2, wxCENTER);
241 {
242 mAmpT = S.Id(ID_Amp)
243 .Validator<FloatingPointValidator<double>>(
244 precision, &mAmp, NumValidatorStyle::ONE_TRAILING_ZERO, Amp.min, Amp.max )
245 .AddTextBox(XXO("&Amplification (dB):"), L"", 12);
246 }
247 S.EndMultiColumn();
248
249 // Amplitude
250 S.StartHorizontalLay(wxEXPAND);
251 {
252 mAmpS = S.Id(ID_Amp)
253 .Style(wxSL_HORIZONTAL)
254 .Name(XO("Amplification dB"))
255 .AddSlider( {}, 0, Amp.max * Amp.scale, Amp.min * Amp.scale);
256 }
257 S.EndHorizontalLay();
258
259 // Peak
260 S.StartMultiColumn(2, wxCENTER);
261 {
262 mNewPeakT = S.Id(ID_Peak)
263 .Validator<FloatingPointValidator<double>>(
264 // One extra decimal place so that rounding is visible to user
265 // (see: bug 958)
266 precision + 1,
267 &mNewPeak, NumValidatorStyle::ONE_TRAILING_ZERO,
268 // min and max need same precision as what we're validating (bug 963)
269 RoundValue( precision + 1, Amp.min + LINEAR_TO_DB(mPeak) ),
270 RoundValue( precision + 1, Amp.max + LINEAR_TO_DB(mPeak) ) )
271 .AddTextBox(XXO("&New Peak Amplitude (dB):"), L"", 12);
272 }
273 S.EndMultiColumn();
274
275 // Clipping
276 S.StartHorizontalLay(wxCENTER);
277 {
278
279 mClip = S.Id(ID_Clip).Disable( batch )
280 .AddCheckBox(XXO("Allo&w clipping"), false);
281 }
282 S.EndHorizontalLay();
283 }
284 S.EndVerticalLay();
285
286 return nullptr;
287}
288
290{
291 // limit range of gain
292 double dBInit = LINEAR_TO_DB(mRatio);
293 double dB = std::clamp<double>(dBInit, Amp.min, Amp.max);
294 if (dB != dBInit)
295 mRatio = DB_TO_LINEAR(dB);
296
299}
300
302{
303 mAmpT->GetValidator()->TransferToWindow();
304
305 mAmpS->SetValue((int) (mAmp * Amp.scale + 0.5f));
306
307 mNewPeakT->GetValidator()->TransferToWindow();
308
309 mClip->SetValue(mCanClip);
310
311 CheckClip();
312
313 return true;
314}
315
317{
318 mRatio = DB_TO_LINEAR(std::clamp<double>(mAmp * Amp.scale, Amp.min * Amp.scale, Amp.max * Amp.scale) / Amp.scale);
319
320 mCanClip = mClip->GetValue();
321
322 if (!mCanClip && mRatio * mPeak > 1.0)
323 {
324 mRatio = 1.0 / mPeak;
325 }
326
327 ClampRatio();
328
329 return true;
330}
331
332// EffectAmplify implementation
333
335{
336 EnableApply(mClip->GetValue() || (mPeak > 0.0 && mRatio <= mRatioClip));
337}
338
339void EffectAmplify::OnAmpText(wxCommandEvent & WXUNUSED(evt))
340{
341 if (!mAmpT->GetValidator()->TransferFromWindow())
342 {
343 EnableApply(false);
344 return;
345 }
346
347 mRatio = DB_TO_LINEAR(std::clamp<double>(mAmp * Amp.scale, Amp.min * Amp.scale, Amp.max * Amp.scale) / Amp.scale);
348
349 mAmpS->SetValue((int) (LINEAR_TO_DB(mRatio) * Amp.scale + 0.5));
350
352 mNewPeakT->GetValidator()->TransferToWindow();
353
354 CheckClip();
355}
356
357void EffectAmplify::OnPeakText(wxCommandEvent & WXUNUSED(evt))
358{
359 if (!mNewPeakT->GetValidator()->TransferFromWindow())
360 {
361 EnableApply(false);
362 return;
363 }
364
365 if (mNewPeak == 0.0)
367 else
369
370 double ampInit = LINEAR_TO_DB(mRatio);
371 mAmp = std::clamp<double>(ampInit, Amp.min, Amp.max);
372 if (mAmp != ampInit)
374
375 mAmpT->GetValidator()->TransferToWindow();
376
377 mAmpS->SetValue((int) (mAmp * Amp.scale + 0.5f));
378
379 CheckClip();
380}
381
382void EffectAmplify::OnAmpSlider(wxCommandEvent & evt)
383{
384 double dB = evt.GetInt() / Amp.scale;
385 mRatio = DB_TO_LINEAR(std::clamp<double>(dB, Amp.min, Amp.max));
386
387 double dB2 = (evt.GetInt() - 1) / Amp.scale;
388 double ratio2 = DB_TO_LINEAR(std::clamp<double>(dB2, Amp.min, Amp.max));
389
390 if (!mClip->GetValue() && mRatio * mPeak > 1.0 && ratio2 * mPeak < 1.0)
391 {
392 mRatio = 1.0 / mPeak;
393 }
394
396 mAmpT->GetValidator()->TransferToWindow();
397
399 mNewPeakT->GetValidator()->TransferToWindow();
400
401 CheckClip();
402}
403
404void EffectAmplify::OnClipCheckBox(wxCommandEvent & WXUNUSED(evt))
405{
406 CheckClip();
407}
@ 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
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
Definition: MemoryX.h:226
#define LINEAR_TO_DB(x)
Definition: MemoryX.h:536
#define DB_TO_LINEAR(x)
Definition: MemoryX.h:535
#define S(N)
Definition: ToChars.cpp:64
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
bool DoLoadFactoryDefaults()
Definition: Amplify.cpp:159
void ClampRatio()
Definition: Amplify.cpp:289
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
Definition: Amplify.cpp:137
static const ComponentInterfaceSymbol Symbol
Definition: Amplify.h:32
std::unique_ptr< EffectUIValidator > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access) override
Add controls to effect panel; always succeeds.
Definition: Amplify.cpp:208
static constexpr EffectParameter Ratio
Definition: Amplify.h:94
wxTextCtrl * mNewPeakT
Definition: Amplify.h:87
static constexpr EffectParameter Clipping
Definition: Amplify.h:99
virtual ~EffectAmplify()
Definition: Amplify.cpp:103
double mRatioClip
Definition: Amplify.h:80
static constexpr EffectParameter Amp
Definition: Amplify.h:97
double mPeak
Definition: Amplify.h:77
bool mCanClip
Definition: Amplify.h:83
void OnClipCheckBox(wxCommandEvent &evt)
Definition: Amplify.cpp:404
wxSlider * mAmpS
Definition: Amplify.h:85
void OnAmpSlider(wxCommandEvent &evt)
Definition: Amplify.cpp:382
void Preview(EffectSettingsAccess &access, bool dryOnly) override
Definition: Amplify.cpp:200
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
Call once to set up state for whole list of tracks to be processed.
Definition: Amplify.cpp:181
bool TransferDataToWindow(const EffectSettings &settings) override
Update controls for the settings.
Definition: Amplify.cpp:301
bool TransferDataFromWindow(EffectSettings &settings) override
Update the given settings from controls.
Definition: Amplify.cpp:316
const EffectParameterMethods & Parameters() const override
Definition: Amplify.cpp:50
wxCheckBox * mClip
Definition: Amplify.h:88
void OnAmpText(wxCommandEvent &evt)
Definition: Amplify.cpp:339
TranslatableString GetDescription() const override
Definition: Amplify.cpp:114
double mAmp
Definition: Amplify.h:81
void OnPeakText(wxCommandEvent &evt)
Definition: Amplify.cpp:357
ComponentInterfaceSymbol GetSymbol() const override
Definition: Amplify.cpp:109
double mRatio
Definition: Amplify.h:79
double mNewPeak
Definition: Amplify.h:82
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:86
void CheckClip()
Definition: Amplify.cpp:334
bool LoadFactoryDefaults(EffectSettings &settings) const override
Change settings back to "factory default".
Definition: Amplify.cpp:153
double mT1
Definition: EffectBase.h:107
const TrackList * inputTracks() const
Definition: EffectBase.h:102
double mT0
Definition: EffectBase.h:106
void Preview(EffectSettingsAccess &access, bool dryOnly) override
Definition: EffectBase.cpp:328
bool EnableApply(bool enable=true)
Definition: Effect.cpp:613
bool IsBatchProcessing() const override
Definition: Effect.cpp:562
Performs effect computation.
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:628
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.
Definition: Shuttle.h:32
const Type min
Minimum value.
Definition: Shuttle.h:30
const Type max
Maximum value.
Definition: Shuttle.h:31
Externalized state of a plug-in.