Audacity  2.2.2
BassTreble.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4  Audacity(R) is copyright (c) 1999-2016 Audacity Team.
5  License: GPL v2. See License.txt.
6 
7  BassTreble.cpp
8  Steve Daulton
9 
10 ******************************************************************//*******************************************************************/
16 
17 #include "../Audacity.h"
18 #include "BassTreble.h"
19 
20 #include <math.h>
21 #include <algorithm>
22 
23 #include <wx/button.h>
24 #include <wx/intl.h>
25 #include <wx/panel.h>
26 #include <wx/sizer.h>
27 
28 #include "../Prefs.h"
29 #include "../ShuttleGui.h"
30 #include "../WaveTrack.h"
31 #include "../widgets/valnum.h"
32 
33 enum
34 {
35  ID_Bass = 10000,
39 };
40 
41 // Define keys, defaults, minimums, and maximums for the effect parameters
42 //
43 // Name Type Key Def Min Max Scale
44 Param( Bass, double, wxT("Bass"), 0.0, -30.0, 30.0, 1 );
45 Param( Treble, double, wxT("Treble"), 0.0, -30.0, 30.0, 1 );
46 Param( Gain, double, wxT("Gain"), 0.0, -30.0, 30.0, 1 );
47 Param( Link, bool, wxT("Link Sliders"), false, false, true, 1 );
48 
49 #include <wx/arrimpl.cpp>
50 WX_DEFINE_OBJARRAY(EffectBassTrebleStateArray);
51 
52 // Used to communicate the type of the filter.
54 {
57 };
58 
59 BEGIN_EVENT_TABLE(EffectBassTreble, wxEvtHandler)
60  EVT_SLIDER(ID_Bass, EffectBassTreble::OnBassSlider)
61  EVT_SLIDER(ID_Treble, EffectBassTreble::OnTrebleSlider)
62  EVT_SLIDER(ID_Gain, EffectBassTreble::OnGainSlider)
63  EVT_TEXT(ID_Bass, EffectBassTreble::OnBassText)
64  EVT_TEXT(ID_Treble, EffectBassTreble::OnTrebleText)
65  EVT_TEXT(ID_Gain, EffectBassTreble::OnGainText)
66  EVT_CHECKBOX(ID_Link, EffectBassTreble::OnLinkCheckbox)
68 
70 {
71  mBass = DEF_Bass;
72  mTreble = DEF_Treble;
73  mGain = DEF_Gain;
74  mLink = DEF_Link;
75 
76  SetLinearEffectFlag(true);
77 }
78 
80 {
81 }
82 
83 // IdentInterface implementation
84 
86 {
88 }
89 
91 {
92  return _("Simple tone control effect");
93 }
94 
96 {
97  return wxT("Bass_and_Treble");
98 }
99 
100 // EffectIdentInterface implementation
101 
103 {
104  return EffectTypeProcess;
105 }
106 
108 {
109 #if defined(EXPERIMENTAL_REALTIME_AUDACITY_EFFECTS)
110  return true;
111 #else
112  return false;
113 #endif
114 }
115 
116 
117 // EffectClientInterface implementation
118 
120 {
121  return 1;
122 }
123 
125 {
126  return 1;
127 }
128 
129 bool EffectBassTreble::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap))
130 {
132 
133  return true;
134 }
135 
136 size_t EffectBassTreble::ProcessBlock(float **inBlock, float **outBlock, size_t blockLen)
137 {
138  return InstanceProcess(mMaster, inBlock, outBlock, blockLen);
139 }
140 
142 {
143  SetBlockSize(512);
144 
145  mSlaves.Clear();
146 
147  return true;
148 }
149 
150 bool EffectBassTreble::RealtimeAddProcessor(unsigned WXUNUSED(numChannels), float sampleRate)
151 {
152  EffectBassTrebleState slave;
153 
154  InstanceInit(slave, sampleRate);
155 
156  mSlaves.Add(slave);
157 
158  return true;
159 }
160 
162 {
163  mSlaves.Clear();
164 
165  return true;
166 }
167 
169  float **inbuf,
170  float **outbuf,
171  size_t numSamples)
172 {
173  return InstanceProcess(mSlaves[group], inbuf, outbuf, numSamples);
174 }
175 
176 bool EffectBassTreble::GetAutomationParameters(EffectAutomationParameters & parms)
177 {
178  parms.Write(KEY_Bass, mBass);
179  parms.Write(KEY_Treble, mTreble);
180  parms.Write(KEY_Gain, mGain);
181  parms.Write(KEY_Link, mLink);
182 
183  return true;
184 }
185 
186 bool EffectBassTreble::SetAutomationParameters(EffectAutomationParameters & parms)
187 {
188  ReadAndVerifyDouble(Bass);
189  ReadAndVerifyDouble(Treble);
190  ReadAndVerifyDouble(Gain);
191  ReadAndVerifyBool(Link);
192 
193  mBass = Bass;
194  mTreble = Treble;
195  mGain = Gain;
196  mLink = Link;
197 
198  return true;
199 }
200 
202 {
203  return (mBass == 0.0 && mTreble == 0.0 && mGain == 0.0);
204 }
205 
206 
207 // Effect implementation
208 
210 {
211  S.SetBorder(5);
212  S.AddSpace(0, 5);
213 
214  S.StartStatic(_("Tone controls"));
215  {
216  S.StartMultiColumn(3, wxEXPAND);
217  {
218  S.SetStretchyCol(2);
219 
220  // Bass control
221  FloatingPointValidator<double> vldBass(1, &mBass);
222  vldBass.SetRange(MIN_Bass, MAX_Bass);
223  mBassT = S.Id(ID_Bass).AddTextBox(_("Ba&ss (dB):"), wxT(""), 10);
224  mBassT->SetName(_("Bass (dB):"));
225  mBassT->SetValidator(vldBass);
226 
227  S.SetStyle(wxSL_HORIZONTAL);
228  mBassS = S.Id(ID_Bass).AddSlider( {}, 0, MAX_Bass * SCL_Bass, MIN_Bass * SCL_Bass);
229  mBassS->SetName(_("Bass"));
230 
231  // Treble control
232  FloatingPointValidator<double> vldTreble(1, &mTreble);
233  vldTreble.SetRange(MIN_Treble, MAX_Treble);
234  mTrebleT = S.Id(ID_Treble).AddTextBox(_("&Treble (dB):"), wxT(""), 10);
235  mTrebleT->SetValidator(vldTreble);
236 
237  S.SetStyle(wxSL_HORIZONTAL);
238  mTrebleS = S.Id(ID_Treble).AddSlider( {}, 0, MAX_Treble * SCL_Treble, MIN_Treble * SCL_Treble);
239  mTrebleS->SetName(_("Treble"));
240  }
241  S.EndMultiColumn();
242  }
243  S.EndStatic();
244 
245  S.StartStatic(_("Output"));
246  {
247  S.StartMultiColumn(3, wxEXPAND);
248  {
249  S.SetStretchyCol(2);
250 
251  // Gain control
252  FloatingPointValidator<double> vldGain(1, &mGain);
253  vldGain.SetRange(MIN_Gain, MAX_Gain);
254  mGainT = S.Id(ID_Gain).AddTextBox(_("&Volume (dB):"), wxT(""), 10);
255  mGainT->SetValidator(vldGain);
256 
257  S.SetStyle(wxSL_HORIZONTAL);
258  mGainS = S.Id(ID_Gain).AddSlider( {}, 0, MAX_Gain * SCL_Gain, MIN_Gain * SCL_Gain);
259  mGainS->SetName(_("Level"));
260  }
261  S.EndMultiColumn();
262 
263  S.StartMultiColumn(2, wxCENTER);
264  {
265  // Link checkbox
266  mLinkCheckBox = S.Id(ID_Link).AddCheckBox(_("&Link Volume control to Tone controls"),
267  DEF_Link ? wxT("true") : wxT("false"));
268  }
269  S.EndMultiColumn();
270  }
271  S.EndStatic();
272 }
273 
275 {
276  if (!mUIParent->TransferDataToWindow())
277  {
278  return false;
279  }
280 
281  mBassS->SetValue((int) (mBass * SCL_Bass));
282  mTrebleS->SetValue((int) mTreble *SCL_Treble);
283  mGainS->SetValue((int) mGain * SCL_Gain);
284  mLinkCheckBox->SetValue(mLink);
285 
286  return true;
287 }
288 
290 {
291  if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
292  {
293  return false;
294  }
295 
296  return true;
297 }
298 
299 
300 // EffectBassTreble implementation
301 
303 {
304  data.samplerate = sampleRate;
305  data.slope = 0.4f; // same slope for both filters
306  data.hzBass = 250.0f; // could be tunable in a more advanced version
307  data.hzTreble = 4000.0f; // could be tunable in a more advanced version
308 
309  data.a0Bass = 1;
310  data.a1Bass = 0;
311  data.a2Bass = 0;
312  data.b0Bass = 0;
313  data.b1Bass = 0;
314  data.b2Bass = 0;
315 
316  data.a0Treble = 1;
317  data.a1Treble = 0;
318  data.a2Treble = 0;
319  data.b0Treble = 0;
320  data.b1Treble = 0;
321  data.b2Treble = 0;
322 
323  data.xn1Bass = 0;
324  data.xn2Bass = 0;
325  data.yn1Bass = 0;
326  data.yn2Bass = 0;
327 
328  data.xn1Treble = 0;
329  data.xn2Treble = 0;
330  data.yn1Treble = 0;
331  data.yn2Treble = 0;
332 
333  data.bass = -1;
334  data.treble = -1;
335  data.gain = DB_TO_LINEAR(mGain);
336 
337 }
338 
339 
340 // EffectClientInterface implementation
341 
342 
344  float **inBlock,
345  float **outBlock,
346  size_t blockLen)
347 {
348  float *ibuf = inBlock[0];
349  float *obuf = outBlock[0];
350 
351  // Set value to ensure correct rounding
352  double oldBass = DB_TO_LINEAR(mBass);
353  double oldTreble = DB_TO_LINEAR(mTreble);
354 
355  data.gain = DB_TO_LINEAR(mGain);
356 
357  // Compute coefficents of the low shelf biquand IIR filter
358  if (data.bass != oldBass)
359  Coefficents(data.hzBass, data.slope, mBass, data.samplerate, kBass,
360  data.a0Bass, data.a1Bass, data.a2Bass,
361  data.b0Bass, data.b1Bass, data.b2Bass);
362 
363  // Compute coefficents of the high shelf biquand IIR filter
364  if (data.treble != oldTreble)
365  Coefficents(data.hzTreble, data.slope, mTreble, data.samplerate, kTreble,
366  data.a0Treble, data.a1Treble, data.a2Treble,
367  data.b0Treble, data.b1Treble, data.b2Treble);
368 
369  for (decltype(blockLen) i = 0; i < blockLen; i++) {
370  obuf[i] = DoFilter(data, ibuf[i]) * data.gain;
371  }
372 
373  return blockLen;
374 }
375 
376 
377 
378 // Effect implementation
379 
380 
381 void EffectBassTreble::Coefficents(double hz, double slope, double gain, double samplerate, int type,
382  double& a0, double& a1, double& a2,
383  double& b0, double& b1, double& b2)
384 {
385  double w = 2 * M_PI * hz / samplerate;
386  double a = exp(log(10.0) * gain / 40);
387  double b = sqrt((a * a + 1) / slope - (pow((a - 1), 2)));
388 
389  if (type == kBass)
390  {
391  b0 = a * ((a + 1) - (a - 1) * cos(w) + b * sin(w));
392  b1 = 2 * a * ((a - 1) - (a + 1) * cos(w));
393  b2 = a * ((a + 1) - (a - 1) * cos(w) - b * sin(w));
394  a0 = ((a + 1) + (a - 1) * cos(w) + b * sin(w));
395  a1 = -2 * ((a - 1) + (a + 1) * cos(w));
396  a2 = (a + 1) + (a - 1) * cos(w) - b * sin(w);
397  }
398  else //assumed kTreble
399  {
400  b0 = a * ((a + 1) + (a - 1) * cos(w) + b * sin(w));
401  b1 = -2 * a * ((a - 1) + (a + 1) * cos(w));
402  b2 = a * ((a + 1) + (a - 1) * cos(w) - b * sin(w));
403  a0 = ((a + 1) - (a - 1) * cos(w) + b * sin(w));
404  a1 = 2 * ((a - 1) - (a + 1) * cos(w));
405  a2 = (a + 1) - (a - 1) * cos(w) - b * sin(w);
406  }
407 }
408 
410 {
411  // Bass filter
412  float out = (data.b0Bass * in + data.b1Bass * data.xn1Bass + data.b2Bass * data.xn2Bass -
413  data.a1Bass * data.yn1Bass - data.a2Bass * data.yn2Bass) / data.a0Bass;
414  data.xn2Bass = data.xn1Bass;
415  data.xn1Bass = in;
416  data.yn2Bass = data.yn1Bass;
417  data.yn1Bass = out;
418 
419  // Treble filter
420  in = out;
421  out = (data.b0Treble * in + data.b1Treble * data.xn1Treble + data.b2Treble * data.xn2Treble -
422  data.a1Treble * data.yn1Treble - data.a2Treble * data.yn2Treble) / data.a0Treble;
423  data.xn2Treble = data.xn1Treble;
424  data.xn1Treble = in;
425  data.yn2Treble = data.yn1Treble;
426  data.yn1Treble = out;
427 
428  return out;
429 }
430 
431 
432 void EffectBassTreble::OnBassText(wxCommandEvent & WXUNUSED(evt))
433 {
434  double oldBass = mBass;
435 
436  if (!EnableApply(mUIParent->TransferDataFromWindow()))
437  {
438  return;
439  }
440 
441  if (mLink) UpdateGain(oldBass, kBass);
442  mBassS->SetValue((int) (mBass * SCL_Bass));
443 }
444 
445 void EffectBassTreble::OnTrebleText(wxCommandEvent & WXUNUSED(evt))
446 {
447  double oldTreble = mTreble;
448 
449  if (!EnableApply(mUIParent->TransferDataFromWindow()))
450  {
451  return;
452  }
453 
454  if (mLink) UpdateGain(oldTreble, kTreble);
455  mTrebleS->SetValue((int) (mTreble * SCL_Treble));
456 }
457 
458 void EffectBassTreble::OnGainText(wxCommandEvent & WXUNUSED(evt))
459 {
460  if (!EnableApply(mUIParent->TransferDataFromWindow()))
461  {
462  return;
463  }
464 
465  mGainS->SetValue((int) (mGain * SCL_Gain));
466 }
467 
468 void EffectBassTreble::OnBassSlider(wxCommandEvent & evt)
469 {
470  double oldBass = mBass;
471  mBass = (double) evt.GetInt() / SCL_Bass;
472  mBassT->GetValidator()->TransferToWindow();
473 
474  if (mLink) UpdateGain(oldBass, kBass);
475  EnableApply(mUIParent->Validate());
476 }
477 
478 void EffectBassTreble::OnTrebleSlider(wxCommandEvent & evt)
479 {
480  double oldTreble = mTreble;
481  mTreble = (double) evt.GetInt() / SCL_Treble;
482  mTrebleT->GetValidator()->TransferToWindow();
483 
484  if (mLink) UpdateGain(oldTreble, kTreble);
485  EnableApply(mUIParent->Validate());
486 }
487 
488 void EffectBassTreble::OnGainSlider(wxCommandEvent & evt)
489 {
490  mGain = (double) evt.GetInt() / SCL_Gain;
491  mGainT->GetValidator()->TransferToWindow();
492 
493  EnableApply(mUIParent->Validate());
494 }
495 
496 void EffectBassTreble::OnLinkCheckbox(wxCommandEvent& /*evt*/)
497 {
498  mLink = mLinkCheckBox->GetValue();
499 }
500 
501 void EffectBassTreble::UpdateGain(double oldVal, int control)
502 {
503  double newVal;
504  oldVal = (oldVal > 0)? oldVal / 2.0 : oldVal / 4.0;
505 
506  if (control == kBass)
507  newVal = (mBass > 0)? mBass / 2.0 : mBass / 4.0;
508  else
509  newVal = (mTreble > 0)? mTreble / 2.0 : mTreble / 4.0;
510 
511  mGain -= newVal - oldVal;
512  mGain = std::min(MAX_Gain, std::max(MIN_Gain, mGain));
513 
514  mGainS->SetValue(mGain);
515  mGainT->GetValidator()->TransferToWindow();
516 
517 }
bool RealtimeFinalize() override
Definition: BassTreble.cpp:161
wxTextCtrl * mGainT
Definition: BassTreble.h:122
Param(Bass, double, wxT("Bass"), 0.0,-30.0, 30.0, 1)
size_t RealtimeProcess(int group, float **inbuf, float **outbuf, size_t numSamples) override
Definition: BassTreble.cpp:168
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:366
EffectBassTrebleStateArray mSlaves
Definition: BassTreble.h:109
bool TransferDataFromWindow() override
Definition: BassTreble.cpp:289
bool GetAutomationParameters(EffectAutomationParameters &parms) override
Definition: BassTreble.cpp:176
void OnLinkCheckbox(wxCommandEvent &evt)
Definition: BassTreble.cpp:496
size_t SetBlockSize(size_t maxBlockSize) override
Definition: Effect.cpp:347
wxSlider * mGainS
Definition: BassTreble.h:118
void EndMultiColumn()
WX_DEFINE_OBJARRAY(EffectBassTrebleStateArray)
A high shelf and low shelf filter.
Definition: BassTreble.h:44
bool CheckWhetherSkipEffect() override
Definition: BassTreble.cpp:201
bool TransferDataToWindow() override
Definition: BassTreble.cpp:274
wxString GetDescription() override
Definition: BassTreble.cpp:90
#define BASSTREBLE_PLUGIN_SYMBOL
Definition: BassTreble.h:26
bool RealtimeAddProcessor(unsigned numChannels, float sampleRate) override
Definition: BassTreble.cpp:150
double mSampleRate
Definition: Effect.h:455
EffectType GetType() override
Definition: BassTreble.cpp:102
wxString GetSymbol() override
Definition: BassTreble.cpp:85
wxSlider * mTrebleS
Definition: BassTreble.h:117
void UpdateGain(double oldVal, int control)
Definition: BassTreble.cpp:501
wxTextCtrl * mTrebleT
Definition: BassTreble.h:121
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
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
Definition: ShuttleGui.cpp:998
bool RealtimeInitialize() override
Definition: BassTreble.cpp:141
void InstanceInit(EffectBassTrebleState &data, float sampleRate)
Definition: BassTreble.cpp:302
ShuttleGui & Id(int id)
void SetStyle(int Style)
Definition: ShuttleGui.h:252
#define ReadAndVerifyDouble(name)
Definition: Effect.h:787
wxString ManualPage() override
Definition: BassTreble.cpp:95
float DoFilter(EffectBassTrebleState &data, float in)
Definition: BassTreble.cpp:409
int min(int a, int b)
bool SetAutomationParameters(EffectAutomationParameters &parms) override
Definition: BassTreble.cpp:186
unsigned GetAudioOutCount() override
Definition: BassTreble.cpp:124
bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap=NULL) override
Definition: BassTreble.cpp:129
size_t ProcessBlock(float **inBlock, float **outBlock, size_t blockLen) override
Definition: BassTreble.cpp:136
unsigned GetAudioInCount() override
Definition: BassTreble.cpp:119
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 &)
void OnGainText(wxCommandEvent &evt)
Definition: BassTreble.cpp:458
wxSlider * mBassS
Definition: BassTreble.h:116
size_t InstanceProcess(EffectBassTrebleState &data, float **inBlock, float **outBlock, size_t blockLen)
Definition: BassTreble.cpp:343
EffectBassTrebleState mMaster
Definition: BassTreble.h:108
#define M_PI
Definition: Distortion.cpp:28
void OnGainSlider(wxCommandEvent &evt)
Definition: BassTreble.cpp:488
wxStaticBox * StartStatic(const wxString &Str, int iProp=0)
Definition: ShuttleGui.cpp:701
bool SupportsRealtime() override
Definition: BassTreble.cpp:107
#define ReadAndVerifyBool(name)
Definition: Effect.h:789
virtual ~EffectBassTreble()
Definition: BassTreble.cpp:79
void OnBassSlider(wxCommandEvent &evt)
Definition: BassTreble.cpp:468
wxTextCtrl * mBassT
Definition: BassTreble.h:120
END_EVENT_TABLE()
wxSizerItem * AddSpace(int width, int height)
wxCheckBox * mLinkCheckBox
Definition: BassTreble.h:124
void Coefficents(double hz, double slope, double gain, double samplerate, int type, double &a0, double &a1, double &a2, double &b0, double &b1, double &b2)
Definition: BassTreble.cpp:381
void OnBassText(wxCommandEvent &evt)
Definition: BassTreble.cpp:432
void SetBorder(int Border)
Definition: ShuttleGui.h:251
const double MIN_Threshold_Linear DB_TO_LINEAR(MIN_Threshold_dB)
void OnTrebleSlider(wxCommandEvent &evt)
Definition: BassTreble.cpp:478
kShelfType
Definition: BassTreble.cpp:53
void PopulateOrExchange(ShuttleGui &S) override
Definition: BassTreble.cpp:209
void SetStretchyCol(int i)
Used to modify an already placed FlexGridSizer to make a column stretchy.
Definition: ShuttleGui.cpp:192
virtual bool EnableApply(bool enable=true)
Definition: Effect.cpp:1879
void OnTrebleText(wxCommandEvent &evt)
Definition: BassTreble.cpp:445
wxSlider * AddSlider(const wxString &Prompt, int pos, int Max, int Min=0)
Definition: ShuttleGui.cpp:456