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 
54 //
55 // EffectAmplify
56 //
57 
58 BEGIN_EVENT_TABLE(EffectAmplify, wxEvtHandler)
59  EVT_SLIDER(ID_Amp, EffectAmplify::OnAmpSlider)
60  EVT_TEXT(ID_Amp, EffectAmplify::OnAmpText)
61  EVT_TEXT(ID_Peak, EffectAmplify::OnPeakText)
62  EVT_CHECKBOX(ID_Clip, EffectAmplify::OnClipCheckBox)
64 
66 {
67  mAmp = DEF_Amp;
68  mRatio = DB_TO_LINEAR(mAmp);
69  mRatioClip = 0.0;
70  mCanClip = false;
71  mPeak = 0.0;
72 
73  SetLinearEffectFlag(true);
74 }
75 
77 {
78 }
79 
80 // IdentInterface implementation
81 
83 {
84  return AMPLIFY_PLUGIN_SYMBOL;
85 }
86 
88 {
89  // Note: This is useful only after ratio has been set.
90  return _("Increases or decreases the volume of the audio you have selected");
91 }
92 
94 {
95  return wxT("Amplify");
96 }
97 
98 // EffectIdentInterface implementation
99 
101 {
102  return EffectTypeProcess;
103 }
104 
105 // EffectClientInterface implementation
106 
108 {
109  return 1;
110 }
111 
113 {
114  return 1;
115 }
116 
117 size_t EffectAmplify::ProcessBlock(float **inBlock, float **outBlock, size_t blockLen)
118 {
119  for (decltype(blockLen) i = 0; i < blockLen; i++)
120  {
121  outBlock[0][i] = inBlock[0][i] * mRatio;
122  }
123 
124  return blockLen;
125 }
126 
127 bool EffectAmplify::GetAutomationParameters(EffectAutomationParameters & parms)
128 {
129  parms.WriteFloat(KEY_Ratio, mRatio);
130 
131  return true;
132 }
133 
134 bool EffectAmplify::SetAutomationParameters(EffectAutomationParameters & parms)
135 {
136  ReadAndVerifyFloat(Ratio);
137 
138  mRatio = Ratio;
139 
140  return true;
141 }
142 
144 {
145  Init();
146 
147  mRatioClip = 0.0;
148  if (mPeak > 0.0)
149  {
150  mRatio = 1.0 / mPeak;
151  mRatioClip = mRatio;
152  }
153  else
154  {
155  mRatio = 1.0;
156  }
157  mCanClip = false;
158 
159  return TransferDataToWindow();
160 }
161 
162 // Effect implementation
163 
165 {
166  mPeak = 0.0;
167 
169 
170  for (Track *t = iter.First(); t; t = iter.Next())
171  {
172  auto pair = ((WaveTrack *)t)->GetMinMax(mT0, mT1); // may throw
173  const float min = pair.first, max = pair.second;
174  float newpeak = (fabs(min) > fabs(max) ? fabs(min) : fabs(max));
175 
176  if (newpeak > mPeak)
177  {
178  mPeak = newpeak;
179  }
180  }
181 
182  return true;
183 }
184 
185 void EffectAmplify::Preview(bool dryOnly)
186 {
187  auto cleanup1 = valueRestorer( mRatio );
188  auto cleanup2 = valueRestorer( mPeak );
189 
190  Effect::Preview(dryOnly);
191 }
192 
194 {
195  if (IsBatchProcessing())
196  {
197  mPeak = 1.0;
198  }
199  else
200  {
201  if (mPeak > 0.0)
202  {
203  mRatio = 1.0 / mPeak;
204  mRatioClip = mRatio;
205  }
206  else
207  {
208  mRatio = 1.0;
209  }
210  }
211 
212  S.AddSpace(0, 5);
213 
214  S.StartVerticalLay(0);
215  {
216  int precission = 3; // allow (a generous) 3 decimal places for Amplification (dB)
217  // Amplitude
218  S.StartMultiColumn(2, wxCENTER);
219  {
220  FloatingPointValidator<double> vldAmp(precission, &mAmp, NUM_VAL_ONE_TRAILING_ZERO);
221  vldAmp.SetRange(MIN_Amp, MAX_Amp);
222  mAmpT = S.Id(ID_Amp).AddTextBox(_("Amplification (dB):"), wxT(""), 12);
223  mAmpT->SetValidator(vldAmp);
224  }
225  S.EndMultiColumn();
226 
227  // Amplitude
228  S.StartHorizontalLay(wxEXPAND);
229  {
230  S.SetStyle(wxSL_HORIZONTAL);
231  mAmpS = S.Id(ID_Amp).AddSlider( {}, 0, MAX_Amp * SCL_Amp, MIN_Amp * SCL_Amp);
232  mAmpS->SetName(_("Amplification dB"));
233  }
234  S.EndHorizontalLay();
235 
236  // Peak
237  S.StartMultiColumn(2, wxCENTER);
238  {
239  // One extra decimal place so that rounding is visible to user (see: bug 958)
240  FloatingPointValidator<double> vldNewPeak(precission + 1, &mNewPeak, NUM_VAL_ONE_TRAILING_ZERO);
241  double minAmp = MIN_Amp + LINEAR_TO_DB(mPeak);
242  double maxAmp = MAX_Amp + LINEAR_TO_DB(mPeak);
243 
244  // min and max need same precision as what we're validating (bug 963)
245  minAmp = Internat::CompatibleToDouble(Internat::ToString(minAmp, precission +1));
246  maxAmp = Internat::CompatibleToDouble(Internat::ToString(maxAmp, precission +1));
247 
248  vldNewPeak.SetRange(minAmp, maxAmp);
249  mNewPeakT = S.Id(ID_Peak).AddTextBox(_("New Peak Amplitude (dB):"), wxT(""), 12);
250  mNewPeakT->SetValidator(vldNewPeak);
251  }
252  S.EndMultiColumn();
253 
254  // Clipping
255  S.StartHorizontalLay(wxCENTER);
256  {
257  mClip = S.Id(ID_Clip).AddCheckBox(_("Allow clipping"), wxT("false"));
258  if (IsBatchProcessing())
259  {
260  mClip->Enable(false);
261  mCanClip = true;
262  }
263  }
264  S.EndHorizontalLay();
265  }
266  S.EndVerticalLay();
267 
268  return;
269 }
270 
272 {
273  // limit range of gain
274  double dBInit = LINEAR_TO_DB(mRatio);
275  double dB = TrapDouble(dBInit, MIN_Amp, MAX_Amp);
276  if (dB != dBInit)
277  mRatio = DB_TO_LINEAR(dB);
278 
280  mAmpT->GetValidator()->TransferToWindow();
281 
282  mAmpS->SetValue((int) (mAmp * SCL_Amp + 0.5f));
283 
285  mNewPeakT->GetValidator()->TransferToWindow();
286 
287  mClip->SetValue(mCanClip);
288 
289  CheckClip();
290 
291  return true;
292 }
293 
295 {
296  if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
297  {
298  return false;
299  }
300 
301  mRatio = DB_TO_LINEAR(TrapDouble(mAmp * SCL_Amp, MIN_Amp * SCL_Amp, MAX_Amp * SCL_Amp) / SCL_Amp);
302 
303  mCanClip = mClip->GetValue();
304 
305  if (!mCanClip && mRatio * mPeak > 1.0)
306  {
307  mRatio = 1.0 / mPeak;
308  }
309 
310  return true;
311 }
312 
313 // EffectAmplify implementation
314 
316 {
317  EnableApply(mClip->GetValue() || (mPeak > 0.0 && mRatio <= mRatioClip));
318 }
319 
320 void EffectAmplify::OnAmpText(wxCommandEvent & WXUNUSED(evt))
321 {
322  if (!mAmpT->GetValidator()->TransferFromWindow())
323  {
324  EnableApply(false);
325  return;
326  }
327 
328  mRatio = DB_TO_LINEAR(TrapDouble(mAmp * SCL_Amp, MIN_Amp * SCL_Amp, MAX_Amp * SCL_Amp) / SCL_Amp);
329 
330  mAmpS->SetValue((int) (LINEAR_TO_DB(mRatio) * SCL_Amp + 0.5));
331 
333  mNewPeakT->GetValidator()->TransferToWindow();
334 
335  CheckClip();
336 }
337 
338 void EffectAmplify::OnPeakText(wxCommandEvent & WXUNUSED(evt))
339 {
340  if (!mNewPeakT->GetValidator()->TransferFromWindow())
341  {
342  EnableApply(false);
343  return;
344  }
345 
346  if (mNewPeak == 0.0)
347  mRatio = mRatioClip;
348  else
350 
351  double ampInit = LINEAR_TO_DB(mRatio);
352  mAmp = TrapDouble(ampInit, MIN_Amp, MAX_Amp);
353  if (mAmp != ampInit)
355 
356  mAmpT->GetValidator()->TransferToWindow();
357 
358  mAmpS->SetValue((int) (mAmp * SCL_Amp + 0.5f));
359 
360  CheckClip();
361 }
362 
363 void EffectAmplify::OnAmpSlider(wxCommandEvent & evt)
364 {
365  double dB = evt.GetInt() / SCL_Amp;
366  mRatio = DB_TO_LINEAR(TrapDouble(dB, MIN_Amp, MAX_Amp));
367 
368  double dB2 = (evt.GetInt() - 1) / SCL_Amp;
369  double ratio2 = DB_TO_LINEAR(TrapDouble(dB2, MIN_Amp, MAX_Amp));
370 
371  if (!mClip->GetValue() && mRatio * mPeak > 1.0 && ratio2 * mPeak < 1.0)
372  {
373  mRatio = 1.0 / mPeak;
374  }
375 
377  mAmpT->GetValidator()->TransferToWindow();
378 
380  mNewPeakT->GetValidator()->TransferToWindow();
381 
382  CheckClip();
383 }
384 
385 void EffectAmplify::OnClipCheckBox(wxCommandEvent & WXUNUSED(evt))
386 {
387  CheckClip();
388 }
double mT1
Definition: Effect.h:460
EffectType GetType() override
Definition: Amplify.cpp:100
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:366
#define ReadAndVerifyFloat(name)
Definition: Effect.h:788
void OnAmpText(wxCommandEvent &evt)
Definition: Amplify.cpp:320
unsigned GetAudioOutCount() override
Definition: Amplify.cpp:112
wxTextCtrl * mNewPeakT
Definition: Amplify.h:83
double mRatio
Definition: Amplify.h:75
void EndMultiColumn()
bool TransferDataToWindow() override
Definition: Amplify.cpp:271
unsigned GetAudioInCount() override
Definition: Amplify.cpp:107
wxString GetSymbol() override
Definition: Amplify.cpp:82
wxCheckBox * mClip
Definition: Amplify.h:84
bool Init() override
Definition: Amplify.cpp:164
#define AMPLIFY_PLUGIN_SYMBOL
Definition: Amplify.h:26
TrackList * inputTracks() const
Definition: Effect.h:457
void PopulateOrExchange(ShuttleGui &S) override
Definition: Amplify.cpp:193
void EndHorizontalLay()
Definition: ShuttleGui.cpp:975
Track * Next(bool skiplinked=false) override
Definition: Track.cpp:513
void OnAmpSlider(wxCommandEvent &evt)
Definition: Amplify.cpp:363
void Preview() override
Definition: Effect.cpp:784
void EndVerticalLay()
Definition: ShuttleGui.cpp:991
static wxString ToString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, always uses the dot as decimal separator.
Definition: Internat.cpp:137
wxTextCtrl * AddTextBox(const wxString &Caption, const wxString &Value, const int nChars)
Definition: ShuttleGui.cpp:493
wxCheckBox * AddCheckBox(const wxString &Prompt, const wxString &Selected)
Definition: ShuttleGui.cpp:267
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:121
bool mCanClip
Definition: Amplify.h:79
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:966
void OnPeakText(wxCommandEvent &evt)
Definition: Amplify.cpp:338
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
Definition: ShuttleGui.cpp:998
bool TransferDataFromWindow() override
Definition: Amplify.cpp:294
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
ShuttleGui & Id(int id)
wxString ManualPage() override
Definition: Amplify.cpp:93
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:67
void SetStyle(int Style)
Definition: ShuttleGui.h:252
void CheckClip()
Definition: Amplify.cpp:315
size_t ProcessBlock(float **inBlock, float **outBlock, size_t blockLen) override
Definition: Amplify.cpp:117
wxSlider * mAmpS
Definition: Amplify.h:81
int min(int a, int b)
double mPeak
Definition: Amplify.h:73
wxWindow * mUIParent
Definition: Effect.h:471
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
double TrapDouble(double x, double min, double max)
Definition: Effect.h:724
ValueRestorer< T > valueRestorer(T &var)
Definition: MemoryX.h:875
#define LINEAR_TO_DB(x)
Definition: Audacity.h:210
wxString GetDescription() override
Definition: Amplify.cpp:87
void OnClipCheckBox(wxCommandEvent &evt)
Definition: Amplify.cpp:385
An Effect that makes a sound louder or softer.
Definition: Amplify.h:30
double mRatioClip
Definition: Amplify.h:76
bool LoadFactoryDefaults() override
Definition: Amplify.cpp:143
Track * First(TrackList *val=NULL) override
Definition: Track.cpp:502
double mAmp
Definition: Amplify.h:77
virtual bool IsBatchProcessing()
Definition: Effect.cpp:1132
END_EVENT_TABLE()
wxSizerItem * AddSpace(int width, int height)
wxTextCtrl * mAmpT
Definition: Amplify.h:82
const double MIN_Threshold_Linear DB_TO_LINEAR(MIN_Threshold_dB)
bool SetAutomationParameters(EffectAutomationParameters &parms) override
Definition: Amplify.cpp:134
double mNewPeak
Definition: Amplify.h:78
virtual bool EnableApply(bool enable=true)
Definition: Effect.cpp:1879
double mT0
Definition: Effect.h:459
bool GetAutomationParameters(EffectAutomationParameters &parms) override
Definition: Amplify.cpp:127
wxSlider * AddSlider(const wxString &Prompt, int pos, int Max, int Min=0)
Definition: ShuttleGui.cpp:456
virtual ~EffectAmplify()
Definition: Amplify.cpp:76
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:982