Audacity  2.2.2
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 // IdentInterface 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 
184 
185  for (Track *t = iter.First(); t; t = iter.Next())
186  {
187  auto pair = ((WaveTrack *)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 
200 void EffectAmplify::Preview(bool dryOnly)
201 {
202  auto cleanup1 = valueRestorer( mRatio );
203  auto cleanup2 = valueRestorer( mPeak );
204 
205  Effect::Preview(dryOnly);
206 }
207 
209 {
210  if (IsBatchProcessing())
211  {
212  mPeak = 1.0;
213  }
214  else
215  {
216  if (mPeak > 0.0)
217  {
218  mRatio = 1.0 / mPeak;
219  mRatioClip = mRatio;
220  }
221  else
222  {
223  mRatio = 1.0;
224  }
225  }
226 
227  S.AddSpace(0, 5);
228 
229  S.StartVerticalLay(0);
230  {
231  int precission = 3; // allow (a generous) 3 decimal places for Amplification (dB)
232  // Amplitude
233  S.StartMultiColumn(2, wxCENTER);
234  {
235  FloatingPointValidator<double> vldAmp(precission, &mAmp, NumValidatorStyle::ONE_TRAILING_ZERO);
236  vldAmp.SetRange(MIN_Amp, MAX_Amp);
237  mAmpT = S.Id(ID_Amp).AddTextBox(_("Amplification (dB):"), wxT(""), 12);
238  mAmpT->SetValidator(vldAmp);
239  }
240  S.EndMultiColumn();
241 
242  // Amplitude
243  S.StartHorizontalLay(wxEXPAND);
244  {
245  S.SetStyle(wxSL_HORIZONTAL);
246  mAmpS = S.Id(ID_Amp).AddSlider( {}, 0, MAX_Amp * SCL_Amp, MIN_Amp * SCL_Amp);
247  mAmpS->SetName(_("Amplification dB"));
248  }
249  S.EndHorizontalLay();
250 
251  // Peak
252  S.StartMultiColumn(2, wxCENTER);
253  {
254  // One extra decimal place so that rounding is visible to user (see: bug 958)
255  FloatingPointValidator<double> vldNewPeak(precission + 1, &mNewPeak, NumValidatorStyle::ONE_TRAILING_ZERO);
256  double minAmp = MIN_Amp + LINEAR_TO_DB(mPeak);
257  double maxAmp = MAX_Amp + LINEAR_TO_DB(mPeak);
258 
259  // min and max need same precision as what we're validating (bug 963)
260  minAmp = Internat::CompatibleToDouble(Internat::ToString(minAmp, precission +1));
261  maxAmp = Internat::CompatibleToDouble(Internat::ToString(maxAmp, precission +1));
262 
263  vldNewPeak.SetRange(minAmp, maxAmp);
264  mNewPeakT = S.Id(ID_Peak).AddTextBox(_("New Peak Amplitude (dB):"), wxT(""), 12);
265  mNewPeakT->SetValidator(vldNewPeak);
266  }
267  S.EndMultiColumn();
268 
269  // Clipping
270  S.StartHorizontalLay(wxCENTER);
271  {
272  mClip = S.Id(ID_Clip).AddCheckBox(_("Allow clipping"), wxT("false"));
273  if (IsBatchProcessing())
274  {
275  mClip->Enable(false);
276  mCanClip = true;
277  }
278  }
279  S.EndHorizontalLay();
280  }
281  S.EndVerticalLay();
282 
283  return;
284 }
285 
287 {
288  // limit range of gain
289  double dBInit = LINEAR_TO_DB(mRatio);
290  double dB = TrapDouble(dBInit, MIN_Amp, MAX_Amp);
291  if (dB != dBInit)
292  mRatio = DB_TO_LINEAR(dB);
293 
295  mAmpT->GetValidator()->TransferToWindow();
296 
297  mAmpS->SetValue((int) (mAmp * SCL_Amp + 0.5f));
298 
300  mNewPeakT->GetValidator()->TransferToWindow();
301 
302  mClip->SetValue(mCanClip);
303 
304  CheckClip();
305 
306  return true;
307 }
308 
310 {
311  if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
312  {
313  return false;
314  }
315 
316  mRatio = DB_TO_LINEAR(TrapDouble(mAmp * SCL_Amp, MIN_Amp * SCL_Amp, MAX_Amp * SCL_Amp) / SCL_Amp);
317 
318  mCanClip = mClip->GetValue();
319 
320  if (!mCanClip && mRatio * mPeak > 1.0)
321  {
322  mRatio = 1.0 / mPeak;
323  }
324 
325  return true;
326 }
327 
328 // EffectAmplify implementation
329 
331 {
332  EnableApply(mClip->GetValue() || (mPeak > 0.0 && mRatio <= mRatioClip));
333 }
334 
335 void EffectAmplify::OnAmpText(wxCommandEvent & WXUNUSED(evt))
336 {
337  if (!mAmpT->GetValidator()->TransferFromWindow())
338  {
339  EnableApply(false);
340  return;
341  }
342 
343  mRatio = DB_TO_LINEAR(TrapDouble(mAmp * SCL_Amp, MIN_Amp * SCL_Amp, MAX_Amp * SCL_Amp) / SCL_Amp);
344 
345  mAmpS->SetValue((int) (LINEAR_TO_DB(mRatio) * SCL_Amp + 0.5));
346 
348  mNewPeakT->GetValidator()->TransferToWindow();
349 
350  CheckClip();
351 }
352 
353 void EffectAmplify::OnPeakText(wxCommandEvent & WXUNUSED(evt))
354 {
355  if (!mNewPeakT->GetValidator()->TransferFromWindow())
356  {
357  EnableApply(false);
358  return;
359  }
360 
361  if (mNewPeak == 0.0)
362  mRatio = mRatioClip;
363  else
365 
366  double ampInit = LINEAR_TO_DB(mRatio);
367  mAmp = TrapDouble(ampInit, MIN_Amp, MAX_Amp);
368  if (mAmp != ampInit)
370 
371  mAmpT->GetValidator()->TransferToWindow();
372 
373  mAmpS->SetValue((int) (mAmp * SCL_Amp + 0.5f));
374 
375  CheckClip();
376 }
377 
378 void EffectAmplify::OnAmpSlider(wxCommandEvent & evt)
379 {
380  double dB = evt.GetInt() / SCL_Amp;
381  mRatio = DB_TO_LINEAR(TrapDouble(dB, MIN_Amp, MAX_Amp));
382 
383  double dB2 = (evt.GetInt() - 1) / SCL_Amp;
384  double ratio2 = DB_TO_LINEAR(TrapDouble(dB2, MIN_Amp, MAX_Amp));
385 
386  if (!mClip->GetValue() && mRatio * mPeak > 1.0 && ratio2 * mPeak < 1.0)
387  {
388  mRatio = 1.0 / mPeak;
389  }
390 
392  mAmpT->GetValidator()->TransferToWindow();
393 
395  mNewPeakT->GetValidator()->TransferToWindow();
396 
397  CheckClip();
398 }
399 
400 void EffectAmplify::OnClipCheckBox(wxCommandEvent & WXUNUSED(evt))
401 {
402  CheckClip();
403 }
double mT1
Definition: Effect.h:461
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:799
void OnAmpText(wxCommandEvent &evt)
Definition: Amplify.cpp:335
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:286
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
TrackList * inputTracks() const
Definition: Effect.h:458
void PopulateOrExchange(ShuttleGui &S) override
Definition: Amplify.cpp:208
void EndHorizontalLay()
Track * Next(bool skiplinked=false) override
Definition: Track.cpp:569
bool WriteFloat(const wxString &key, float f)
void OnAmpSlider(wxCommandEvent &evt)
Definition: Amplify.cpp:378
void Preview() override
Definition: Effect.cpp:771
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:540
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:353
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
bool TransferDataFromWindow() override
Definition: Amplify.cpp:309
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the Shuttle cla...
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
ShuttleGui & Id(int id)
wxString ManualPage() override
Definition: Amplify.cpp:94
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:101
void SetStyle(int Style)
Definition: ShuttleGui.h:287
void CheckClip()
Definition: Amplify.cpp:330
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)
IdentInterfaceSymbol GetSymbol() override
Definition: Amplify.cpp:83
IdentInterfaceSymbol pairs a persistent string identifier used internally with an optional...
double mPeak
Definition: Amplify.h:74
bool SetAutomationParameters(CommandParameters &parms) override
Definition: Amplify.cpp:143
wxWindow * mUIParent
Definition: Effect.h:472
double TrapDouble(double x, double min, double max)
Definition: Effect.h:729
_("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)
Definition: MemoryX.h:494
#define LINEAR_TO_DB(x)
Definition: Audacity.h:217
wxString GetDescription() override
Definition: Amplify.cpp:88
EffectType
void OnClipCheckBox(wxCommandEvent &evt)
Definition: Amplify.cpp:400
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:800
Track * First(TrackList *val=NULL) override
Definition: Track.cpp:558
double mAmp
Definition: Amplify.h:78
virtual bool IsBatchProcessing()
Definition: Effect.cpp:1137
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:1886
double mT0
Definition: Effect.h:460
wxSlider * AddSlider(const wxString &Prompt, int pos, int Max, int Min=0)
Definition: ShuttleGui.cpp:497
virtual ~EffectAmplify()
Definition: Amplify.cpp:77
void StartVerticalLay(int iProp=1)