Audacity  2.3.1
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 #include "../Audacity.h"
22 #include "Amplify.h"
23 
24 #include <math.h>
25 #include <float.h>
26 
27 #include <wx/button.h>
28 #include <wx/checkbox.h>
29 #include <wx/intl.h>
30 #include <wx/sizer.h>
31 #include <wx/stattext.h>
32 #include <wx/textctrl.h>
33 #include <wx/valtext.h>
34 #include <wx/log.h>
35 
36 #include "../ShuttleGui.h"
37 #include "../WaveTrack.h"
38 #include "../widgets/valnum.h"
39 
40 
41 enum
42 {
43  ID_Amp = 10000,
46 };
47 
48 // Define keys, defaults, minimums, and maximums for the effect parameters
49 //
50 // Name Type Key Def Min Max Scale
51 Param( Ratio, float, wxT("Ratio"), 0.9f, 0.003162f, 316.227766f, 1.0f );
52 Param( Amp, float, wxT(""), -0.91515f, -50.0f, 50.0f, 10.0f );
53 Param( Clipping, bool, wxT("AllowClipping"), false, false, true, 1 );
54 
55 //
56 // EffectAmplify
57 //
58 
59 BEGIN_EVENT_TABLE(EffectAmplify, wxEvtHandler)
60  EVT_SLIDER(ID_Amp, EffectAmplify::OnAmpSlider)
61  EVT_TEXT(ID_Amp, EffectAmplify::OnAmpText)
62  EVT_TEXT(ID_Peak, EffectAmplify::OnPeakText)
63  EVT_CHECKBOX(ID_Clip, EffectAmplify::OnClipCheckBox)
65 
67 {
68  mAmp = DEF_Amp;
69  mRatio = DB_TO_LINEAR(mAmp);
70  mRatioClip = 0.0;
71  mCanClip = false;
72  mPeak = 0.0;
73 
74  SetLinearEffectFlag(true);
75 }
76 
78 {
79 }
80 
81 // ComponentInterface implementation
82 
84 {
85  return AMPLIFY_PLUGIN_SYMBOL;
86 }
87 
89 {
90  // Note: This is useful only after ratio has been set.
91  return _("Increases or decreases the volume of the audio you have selected");
92 }
93 
95 {
96  return wxT("Amplify");
97 }
98 
99 // EffectDefinitionInterface implementation
100 
102 {
103  return EffectTypeProcess;
104 }
105 
106 // EffectClientInterface implementation
107 
109 {
110  return 1;
111 }
112 
114 {
115  return 1;
116 }
117 
118 size_t EffectAmplify::ProcessBlock(float **inBlock, float **outBlock, size_t blockLen)
119 {
120  for (decltype(blockLen) i = 0; i < blockLen; i++)
121  {
122  outBlock[0][i] = inBlock[0][i] * mRatio;
123  }
124 
125  return blockLen;
126 }
128  S.SHUTTLE_PARAM( mRatio, Ratio );
129  if (!IsBatchProcessing())
130  S.SHUTTLE_PARAM( mCanClip, Clipping );
131  return true;
132 }
133 
135 {
136  parms.WriteFloat(KEY_Ratio, mRatio);
137  if (!IsBatchProcessing())
138  parms.WriteFloat(KEY_Clipping, mCanClip);
139 
140  return true;
141 }
142 
144 {
145  ReadAndVerifyFloat(Ratio);
146  mRatio = Ratio;
147 
148  if (!IsBatchProcessing()){
149  ReadAndVerifyBool(Clipping);
150  mCanClip = Clipping;
151  } else {
152  mCanClip = true;
153  }
154 
155  return true;
156 }
157 
159 {
160  Init();
161 
162  mRatioClip = 0.0;
163  if (mPeak > 0.0)
164  {
165  mRatio = 1.0 / mPeak;
166  mRatioClip = mRatio;
167  }
168  else
169  {
170  mRatio = 1.0;
171  }
172  mCanClip = false;
173 
174  return TransferDataToWindow();
175 }
176 
177 // Effect implementation
178 
180 {
181  mPeak = 0.0;
182 
183  for (auto t : inputTracks()->Selected< const WaveTrack >())
184  {
185  auto pair = t->GetMinMax(mT0, mT1); // may throw
186  const float min = pair.first, max = pair.second;
187  float newpeak = (fabs(min) > fabs(max) ? fabs(min) : fabs(max));
188 
189  if (newpeak > mPeak)
190  {
191  mPeak = newpeak;
192  }
193  }
194 
195  return true;
196 }
197 
198 void EffectAmplify::Preview(bool dryOnly)
199 {
200  auto cleanup1 = valueRestorer( mRatio );
201  auto cleanup2 = valueRestorer( mPeak );
202 
203  Effect::Preview(dryOnly);
204 }
205 
207 {
208  if (IsBatchProcessing())
209  {
210  mPeak = 1.0;
211  }
212  else
213  {
214  if (mPeak > 0.0)
215  {
216  mRatio = 1.0 / mPeak;
217  mRatioClip = mRatio;
218  }
219  else
220  {
221  mRatio = 1.0;
222  }
223  }
224 
225  S.AddSpace(0, 5);
226 
227  S.StartVerticalLay(0);
228  {
229  int precission = 3; // allow (a generous) 3 decimal places for Amplification (dB)
230  // Amplitude
231  S.StartMultiColumn(2, wxCENTER);
232  {
233  FloatingPointValidator<double> vldAmp(precission, &mAmp, NumValidatorStyle::ONE_TRAILING_ZERO);
234  vldAmp.SetRange(MIN_Amp, MAX_Amp);
235  mAmpT = S.Id(ID_Amp).AddTextBox(_("Amplification (dB):"), wxT(""), 12);
236  mAmpT->SetValidator(vldAmp);
237  }
238  S.EndMultiColumn();
239 
240  // Amplitude
241  S.StartHorizontalLay(wxEXPAND);
242  {
243  S.SetStyle(wxSL_HORIZONTAL);
244  mAmpS = S.Id(ID_Amp).AddSlider( {}, 0, MAX_Amp * SCL_Amp, MIN_Amp * SCL_Amp);
245  mAmpS->SetName(_("Amplification dB"));
246  }
247  S.EndHorizontalLay();
248 
249  // Peak
250  S.StartMultiColumn(2, wxCENTER);
251  {
252  // One extra decimal place so that rounding is visible to user (see: bug 958)
253  FloatingPointValidator<double> vldNewPeak(precission + 1, &mNewPeak, NumValidatorStyle::ONE_TRAILING_ZERO);
254  double minAmp = MIN_Amp + LINEAR_TO_DB(mPeak);
255  double maxAmp = MAX_Amp + LINEAR_TO_DB(mPeak);
256 
257  // min and max need same precision as what we're validating (bug 963)
258  minAmp = Internat::CompatibleToDouble(Internat::ToString(minAmp, precission +1));
259  maxAmp = Internat::CompatibleToDouble(Internat::ToString(maxAmp, precission +1));
260 
261  vldNewPeak.SetRange(minAmp, maxAmp);
262  mNewPeakT = S.Id(ID_Peak).AddTextBox(_("New Peak Amplitude (dB):"), wxT(""), 12);
263  mNewPeakT->SetValidator(vldNewPeak);
264  }
265  S.EndMultiColumn();
266 
267  // Clipping
268  S.StartHorizontalLay(wxCENTER);
269  {
270  mClip = S.Id(ID_Clip).AddCheckBox(_("Allow clipping"), wxT("false"));
271  if (IsBatchProcessing())
272  {
273  mClip->Enable(false);
274  mCanClip = true;
275  }
276  }
277  S.EndHorizontalLay();
278  }
279  S.EndVerticalLay();
280 
281  return;
282 }
283 
285 {
286  // limit range of gain
287  double dBInit = LINEAR_TO_DB(mRatio);
288  double dB = TrapDouble(dBInit, MIN_Amp, MAX_Amp);
289  if (dB != dBInit)
290  mRatio = DB_TO_LINEAR(dB);
291 
293  mAmpT->GetValidator()->TransferToWindow();
294 
295  mAmpS->SetValue((int) (mAmp * SCL_Amp + 0.5f));
296 
298  mNewPeakT->GetValidator()->TransferToWindow();
299 
300  mClip->SetValue(mCanClip);
301 
302  CheckClip();
303 
304  return true;
305 }
306 
308 {
309  if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
310  {
311  return false;
312  }
313 
314  mRatio = DB_TO_LINEAR(TrapDouble(mAmp * SCL_Amp, MIN_Amp * SCL_Amp, MAX_Amp * SCL_Amp) / SCL_Amp);
315 
316  mCanClip = mClip->GetValue();
317 
318  if (!mCanClip && mRatio * mPeak > 1.0)
319  {
320  mRatio = 1.0 / mPeak;
321  }
322 
323  return true;
324 }
325 
326 // EffectAmplify implementation
327 
329 {
330  EnableApply(mClip->GetValue() || (mPeak > 0.0 && mRatio <= mRatioClip));
331 }
332 
333 void EffectAmplify::OnAmpText(wxCommandEvent & WXUNUSED(evt))
334 {
335  if (!mAmpT->GetValidator()->TransferFromWindow())
336  {
337  EnableApply(false);
338  return;
339  }
340 
341  mRatio = DB_TO_LINEAR(TrapDouble(mAmp * SCL_Amp, MIN_Amp * SCL_Amp, MAX_Amp * SCL_Amp) / SCL_Amp);
342 
343  mAmpS->SetValue((int) (LINEAR_TO_DB(mRatio) * SCL_Amp + 0.5));
344 
346  mNewPeakT->GetValidator()->TransferToWindow();
347 
348  CheckClip();
349 }
350 
351 void EffectAmplify::OnPeakText(wxCommandEvent & WXUNUSED(evt))
352 {
353  if (!mNewPeakT->GetValidator()->TransferFromWindow())
354  {
355  EnableApply(false);
356  return;
357  }
358 
359  if (mNewPeak == 0.0)
360  mRatio = mRatioClip;
361  else
363 
364  double ampInit = LINEAR_TO_DB(mRatio);
365  mAmp = TrapDouble(ampInit, MIN_Amp, MAX_Amp);
366  if (mAmp != ampInit)
368 
369  mAmpT->GetValidator()->TransferToWindow();
370 
371  mAmpS->SetValue((int) (mAmp * SCL_Amp + 0.5f));
372 
373  CheckClip();
374 }
375 
376 void EffectAmplify::OnAmpSlider(wxCommandEvent & evt)
377 {
378  double dB = evt.GetInt() / SCL_Amp;
379  mRatio = DB_TO_LINEAR(TrapDouble(dB, MIN_Amp, MAX_Amp));
380 
381  double dB2 = (evt.GetInt() - 1) / SCL_Amp;
382  double ratio2 = DB_TO_LINEAR(TrapDouble(dB2, MIN_Amp, MAX_Amp));
383 
384  if (!mClip->GetValue() && mRatio * mPeak > 1.0 && ratio2 * mPeak < 1.0)
385  {
386  mRatio = 1.0 / mPeak;
387  }
388 
390  mAmpT->GetValidator()->TransferToWindow();
391 
393  mNewPeakT->GetValidator()->TransferToWindow();
394 
395  CheckClip();
396 }
397 
398 void EffectAmplify::OnClipCheckBox(wxCommandEvent & WXUNUSED(evt))
399 {
400  CheckClip();
401 }
double mT1
Definition: Effect.h:465
EffectType GetType() override
Definition: Amplify.cpp:101
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:409
#define ReadAndVerifyFloat(name)
Definition: Effect.h:800
void OnAmpText(wxCommandEvent &evt)
Definition: Amplify.cpp:333
EffectType
unsigned GetAudioOutCount() override
Definition: Amplify.cpp:113
wxTextCtrl * mNewPeakT
Definition: Amplify.h:84
double mRatio
Definition: Amplify.h:76
void EndMultiColumn()
bool TransferDataToWindow() override
Definition: Amplify.cpp:284
unsigned GetAudioInCount() override
Definition: Amplify.cpp:108
wxCheckBox * mClip
Definition: Amplify.h:85
bool Init() override
Definition: Amplify.cpp:179
bool GetAutomationParameters(CommandParameters &parms) override
Definition: Amplify.cpp:134
Shuttle that deals with parameters. This is a base class with lots of virtual functions that do nothi...
Definition: Shuttle.h:60
#define AMPLIFY_PLUGIN_SYMBOL
Definition: Amplify.h:26
void PopulateOrExchange(ShuttleGui &S) override
Definition: Amplify.cpp:206
void EndHorizontalLay()
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional...
bool WriteFloat(const wxString &key, float f)
void OnAmpSlider(wxCommandEvent &evt)
Definition: Amplify.cpp:376
void Preview() override
Definition: Effect.cpp:775
ComponentInterfaceSymbol GetSymbol() override
Definition: Amplify.cpp:83
void EndVerticalLay()
static wxString ToString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, always uses the dot as decimal separator.
Definition: Internat.cpp:138
wxTextCtrl * AddTextBox(const wxString &Caption, const wxString &Value, const int nChars)
Definition: ShuttleGui.cpp:548
wxCheckBox * AddCheckBox(const wxString &Prompt, const wxString &Selected)
Definition: ShuttleGui.cpp:298
Param(Ratio, float, wxT("Ratio"), 0.9f, 0.003162f, 316.227766f, 1.0f)
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
Definition: Internat.cpp:122
bool mCanClip
Definition: Amplify.h:80
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
void OnPeakText(wxCommandEvent &evt)
Definition: Amplify.cpp:351
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
bool TransferDataFromWindow() override
Definition: Amplify.cpp:307
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the Shuttle cla...
ShuttleGui & Id(int id)
wxString ManualPage() override
Definition: Amplify.cpp:94
void SetStyle(int Style)
Definition: ShuttleGui.h:287
void CheckClip()
Definition: Amplify.cpp:328
size_t ProcessBlock(float **inBlock, float **outBlock, size_t blockLen) override
Definition: Amplify.cpp:118
wxSlider * mAmpS
Definition: Amplify.h:82
int min(int a, int b)
double mPeak
Definition: Amplify.h:74
bool SetAutomationParameters(CommandParameters &parms) override
Definition: Amplify.cpp:143
wxWindow * mUIParent
Definition: Effect.h:476
double TrapDouble(double x, double min, double max)
Definition: Effect.h:730
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
Definition: MemoryX.h:426
#define LINEAR_TO_DB(x)
Definition: Audacity.h:217
wxString GetDescription() override
Definition: Amplify.cpp:88
const TrackList * inputTracks() const
Definition: Effect.h:462
void OnClipCheckBox(wxCommandEvent &evt)
Definition: Amplify.cpp:398
An Effect that makes a sound louder or softer.
Definition: Amplify.h:30
double mRatioClip
Definition: Amplify.h:77
bool LoadFactoryDefaults() override
Definition: Amplify.cpp:158
#define ReadAndVerifyBool(name)
Definition: Effect.h:801
double mAmp
Definition: Amplify.h:78
virtual bool IsBatchProcessing()
Definition: Effect.cpp:1142
END_EVENT_TABLE()
wxSizerItem * AddSpace(int width, int height)
wxTextCtrl * mAmpT
Definition: Amplify.h:83
bool DefineParams(ShuttleParams &S) override
Definition: Amplify.cpp:127
const double MIN_Threshold_Linear DB_TO_LINEAR(MIN_Threshold_dB)
double mNewPeak
Definition: Amplify.h:79
virtual bool EnableApply(bool enable=true)
Definition: Effect.cpp:1898
double mT0
Definition: Effect.h:464
wxSlider * AddSlider(const wxString &Prompt, int pos, int Max, int Min=0)
Definition: ShuttleGui.cpp:505
virtual ~EffectAmplify()
Definition: Amplify.cpp:77
void StartVerticalLay(int iProp=1)