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