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"
41#include "WaveTrack.h"
42#include "TimeStretching.h"
43#include "../widgets/valnum.h"
44
45
46enum
47{
48 ID_Amp = 10000,
51};
52
54{
56 // Interactive case
58 > parameters;
59
61 Ratio
62 > batchParameters{
63 // If invoking Amplify from a macro, mCanClip is not a parameter
64 // but is always true
65 [](EffectAmplify &, EffectSettings &, EffectAmplify &e, bool) {
66 e.mCanClip = true;
67 return true;
68 },
69 };
70
71 // Parameters differ depending on batch mode. Option to disable clipping
72 // is interactive only.
74 return batchParameters;
75 else
76 return parameters;
77}
78
79//
80// EffectAmplify
81//
82
84{ XO("Amplify") };
85
87
88BEGIN_EVENT_TABLE(EffectAmplify, wxEvtHandler)
94
96{
97 // In case the dialog is cancelled before effect processing
98 static_cast<EffectAmplify&>(GetEffect()).DestroyOutputTracks();
99}
100
102{
103 mAmp = Amp.def;
104 // Ratio.def == DB_TO_LINEAR(Amp.def)
105 Parameters().Reset(*this);
106 mRatioClip = 0.0;
107 mPeak = 0.0;
108
110}
111
113{
114}
115
116// ComponentInterface implementation
117
119{
120 return Symbol;
121}
122
124{
125 // Note: This is useful only after ratio has been set.
126 return XO("Increases or decreases the volume of the audio you have selected");
127}
128
130{
131 return L"Amplify";
132}
133
134// EffectDefinitionInterface implementation
135
137{
138 return EffectTypeProcess;
139}
140
142{
143 return 1;
144}
145
147{
148 return 1;
149}
150
152 const float *const *inBlock, float *const *outBlock, size_t blockLen)
153{
154 for (decltype(blockLen) i = 0; i < blockLen; i++)
155 {
156 outBlock[0][i] = inBlock[0][i] * mRatio;
157 }
158
159 return blockLen;
160}
161
164{
165 // To do: externalize state so const_cast isn't needed
166 return const_cast<EffectAmplify&>(*this).DoLoadFactoryDefaults(settings);
167}
168
170{
171 Init();
172
173 mRatioClip = 0.0;
174 if (mPeak > 0.0)
175 {
176 mRatio = 1.0 / mPeak;
178 }
179 else
180 {
181 mRatio = 1.0;
182 }
183 mCanClip = false;
184
185 ClampRatio();
186 return { nullptr };
187}
188
189// Effect implementation
190
192{
193 auto range = inputTracks()->Selected<const WaveTrack>();
194 bool hasPitchOrSpeed = any_of(begin(range), end(range), [this](auto* pTrack) {
195 return TimeStretching::HasPitchOrSpeed(*pTrack, mT0, mT1);
196 });
197 if (hasPitchOrSpeed)
198 range = MakeOutputTracks()->Get().Selected<const WaveTrack>();
199 mPeak = 0.0;
200 for (auto t : range) {
201 for (const auto pChannel : t->Channels()) {
202 auto pair =
203 WaveChannelUtilities::GetMinMax(*pChannel, mT0, mT1); // may throw
204 const float min = pair.first, max = pair.second;
205 const float newpeak = std::max(fabs(min), fabs(max));
206 mPeak = std::max<double>(mPeak, newpeak);
207 }
208 }
209 return true;
210}
211
213{
214 return { std::pair{
216 } };
217}
218
219std::unique_ptr<EffectEditor> EffectAmplify::PopulateOrExchange(
221 const EffectOutputs *)
222{
223 mUIParent = S.GetParent();
224
225 enum{ precision = 3 }; // allow (a generous) 3 decimal places for Amplification (dB)
226
227 bool batch = IsBatchProcessing();
228 if ( batch )
229 {
230 mCanClip = true;
231 mPeak = 1.0;
232 }
233 else
234 {
235 if (mPeak > 0.0)
236 {
237 mRatio = 1.0 / mPeak;
239 }
240 else
241 {
242 mRatio = 1.0;
243 }
244 }
245
246 // At this point mNewPeak is still uninitialized; this will initialize it
247 ClampRatio();
248
249 S.AddSpace(0, 5);
250
251 S.StartVerticalLay(0);
252 {
253 // Amplitude
254 S.StartMultiColumn(2, wxCENTER);
255 {
256 mAmpT = S.Id(ID_Amp)
257 .Validator<FloatingPointValidator<double>>(
258 precision, &mAmp, NumValidatorStyle::ONE_TRAILING_ZERO, Amp.min, Amp.max )
259 .AddTextBox(XXO("&Amplification (dB):"), L"", 12);
260 }
261 S.EndMultiColumn();
262
263 // Amplitude
264 S.StartHorizontalLay(wxEXPAND);
265 {
266 mAmpS = S.Id(ID_Amp)
267 .Style(wxSL_HORIZONTAL)
268 .Name(XO("Amplification dB"))
269 .AddSlider( {}, 0, Amp.max * Amp.scale, Amp.min * Amp.scale);
270 }
271 S.EndHorizontalLay();
272
273 // Peak
274 S.StartMultiColumn(2, wxCENTER);
275 {
276 mNewPeakT = S.Id(ID_Peak)
277 .Validator<FloatingPointValidator<double>>(
278 // One extra decimal place so that rounding is visible to user
279 // (see: bug 958)
280 precision + 1,
281 &mNewPeak, NumValidatorStyle::ONE_TRAILING_ZERO,
282 // min and max need same precision as what we're validating (bug 963)
283 RoundValue( precision + 1, Amp.min + LINEAR_TO_DB(mPeak) ),
284 RoundValue( precision + 1, Amp.max + LINEAR_TO_DB(mPeak) ) )
285 .AddTextBox(XXO("&New Peak Amplitude (dB):"), L"", 12);
286 }
287 S.EndMultiColumn();
288
289 // Clipping
290 S.StartHorizontalLay(wxCENTER);
291 {
292
293 mClip = S.Id(ID_Clip).Disable( batch )
294 .AddCheckBox(XXO("Allo&w clipping"), false);
295 }
296 S.EndHorizontalLay();
297 }
298 S.EndVerticalLay();
299
300 return nullptr;
301}
302
304{
305 // limit range of gain
306 double dBInit = LINEAR_TO_DB(mRatio);
307 double dB = std::clamp<double>(dBInit, Amp.min, Amp.max);
308 if (dB != dBInit)
309 mRatio = DB_TO_LINEAR(dB);
310
313}
314
316{
317 mAmpT->GetValidator()->TransferToWindow();
318
319 mAmpS->SetValue((int) (mAmp * Amp.scale + 0.5f));
320
321 mNewPeakT->GetValidator()->TransferToWindow();
322
323 mClip->SetValue(mCanClip);
324
325 CheckClip();
326
327 return true;
328}
329
331{
332 if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
333 {
334 return false;
335 }
336
337 mRatio = DB_TO_LINEAR(std::clamp<double>(mAmp * Amp.scale, Amp.min * Amp.scale, Amp.max * Amp.scale) / Amp.scale);
338
339 mCanClip = mClip->GetValue();
340
341 if (!mCanClip && mRatio * mPeak > 1.0)
342 {
343 mRatio = 1.0 / mPeak;
344 }
345
346 ClampRatio();
347
348 return true;
349}
350
351std::shared_ptr<EffectInstance> EffectAmplify::MakeInstance() const
352{
353 // Cheat with const_cast to return an object that calls through to
354 // non-const methods of a stateful effect.
355 return std::make_shared<Instance>(const_cast<EffectAmplify&>(*this));
356}
357
358// EffectAmplify implementation
359
361{
363 mClip->GetValue() || (mPeak > 0.0 && mRatio <= mRatioClip));
364}
365
366void EffectAmplify::OnAmpText(wxCommandEvent & WXUNUSED(evt))
367{
368 if (!mAmpT->GetValidator()->TransferFromWindow())
369 {
371 return;
372 }
373
374 mRatio = DB_TO_LINEAR(std::clamp<double>(mAmp * Amp.scale, Amp.min * Amp.scale, Amp.max * Amp.scale) / Amp.scale);
375
376 mAmpS->SetValue((int) (LINEAR_TO_DB(mRatio) * Amp.scale + 0.5));
377
379 mNewPeakT->GetValidator()->TransferToWindow();
380
381 CheckClip();
382}
383
384void EffectAmplify::OnPeakText(wxCommandEvent & WXUNUSED(evt))
385{
386 if (!mNewPeakT->GetValidator()->TransferFromWindow())
387 {
389 return;
390 }
391
392 if (mNewPeak == 0.0)
394 else
396
397 double ampInit = LINEAR_TO_DB(mRatio);
398 mAmp = std::clamp<double>(ampInit, Amp.min, Amp.max);
399 if (mAmp != ampInit)
401
402 mAmpT->GetValidator()->TransferToWindow();
403
404 mAmpS->SetValue((int) (mAmp * Amp.scale + 0.5f));
405
406 CheckClip();
407}
408
409void EffectAmplify::OnAmpSlider(wxCommandEvent & evt)
410{
411 double dB = evt.GetInt() / Amp.scale;
412 mRatio = DB_TO_LINEAR(std::clamp<double>(dB, Amp.min, Amp.max));
413
414 double dB2 = (evt.GetInt() - 1) / Amp.scale;
415 double ratio2 = DB_TO_LINEAR(std::clamp<double>(dB2, Amp.min, Amp.max));
416
417 if (!mClip->GetValue() && mRatio * mPeak > 1.0 && ratio2 * mPeak < 1.0)
418 {
419 mRatio = 1.0 / mPeak;
420 }
421
423 mAmpT->GetValidator()->TransferToWindow();
424
426 mNewPeakT->GetValidator()->TransferToWindow();
427
428 CheckClip();
429}
430
431void EffectAmplify::OnClipCheckBox(wxCommandEvent & WXUNUSED(evt))
432{
433 CheckClip();
434}
@ ID_Clip
Definition: Amplify.cpp:50
@ ID_Peak
Definition: Amplify.cpp:49
@ ID_Amp
Definition: Amplify.cpp:48
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:338
#define DB_TO_LINEAR(x)
Definition: MemoryX.h:337
#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:163
void ClampRatio()
Definition: Amplify.cpp:303
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
Definition: Amplify.cpp:146
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:112
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:351
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:431
wxSlider * mAmpS
Definition: Amplify.h:95
void OnAmpSlider(wxCommandEvent &evt)
Definition: Amplify.cpp:409
EffectType GetType() const override
Type determines how it behaves.
Definition: Amplify.cpp:136
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
Definition: Amplify.cpp:141
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
Definition: Amplify.cpp:129
bool Init() override
Definition: Amplify.cpp:191
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:219
bool TransferDataToWindow(const EffectSettings &settings) override
Definition: Amplify.cpp:315
bool TransferDataFromWindow(EffectSettings &settings) override
Definition: Amplify.cpp:330
const EffectParameterMethods & Parameters() const override
Definition: Amplify.cpp:53
wxCheckBox * mClip
Definition: Amplify.h:98
void OnAmpText(wxCommandEvent &evt)
Definition: Amplify.cpp:366
OptionalMessage DoLoadFactoryDefaults(EffectSettings &settings)
Definition: Amplify.cpp:169
TranslatableString GetDescription() const override
Definition: Amplify.cpp:123
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:212
void OnPeakText(wxCommandEvent &evt)
Definition: Amplify.cpp:384
ComponentInterfaceSymbol GetSymbol() const override
Definition: Amplify.cpp:118
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:151
wxTextCtrl * mAmpT
Definition: Amplify.h:96
void CheckClip()
Definition: Amplify.cpp:360
double mT1
Definition: EffectBase.h:114
void SetLinearEffectFlag(bool linearEffectFlag)
Definition: EffectBase.cpp:210
const TrackList * inputTracks() const
Definition: EffectBase.h:91
double mT0
Definition: EffectBase.h:113
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:640
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:967
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
Definition: WaveTrack.h:203
WAVE_TRACK_API bool HasPitchOrSpeed(const WaveTrack &track, double t0, double t1)
WAVE_TRACK_API std::pair< float, float > GetMinMax(const WaveChannel &channel, double t0, double t1, bool mayThrow=true)
BuiltinEffectsModule::Registration< EffectAmplify > reg
Definition: Amplify.cpp:86
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
const char * begin(const char *str) noexcept
Definition: StringUtils.h:101
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.