Audacity 3.2.0
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 or later. See License.txt.
6
7 BassTreble.cpp
8 Steve Daulton
9
10******************************************************************//*******************************************************************/
16
17
18#include "BassTreble.h"
19#include "LoadEffects.h"
20
21#include <math.h>
22#include <algorithm>
23
24#include <wx/button.h>
25#include <wx/checkbox.h>
26#include <wx/intl.h>
27#include <wx/panel.h>
28#include <wx/sizer.h>
29#include <wx/slider.h>
30
31#include "Prefs.h"
32#include "../ShuttleGui.h"
33#include "../WaveTrack.h"
34#include "../widgets/valnum.h"
35
36enum
37{
38 ID_Bass = 10000,
42};
43
45{
48 > parameters;
49 return parameters;
50}
51
52// Used to communicate the type of the filter.
54{
57};
58
60{ XO("Bass and Treble") };
61
63
64BEGIN_EVENT_TABLE(EffectBassTreble, wxEvtHandler)
73
75{
76 Parameters().Reset(*this);
77
78 SetLinearEffectFlag(true);
79}
80
82{
83}
84
85// ComponentInterface implementation
86
88{
89 return Symbol;
90}
91
93{
94 return XO("Simple tone control effect");
95}
96
98{
99 return L"Bass_and_Treble";
100}
101
102// EffectDefinitionInterface implementation
103
105{
106 return EffectTypeProcess;
107}
108
110{
111 // TODO reenable after achieving statelessness
113// return RealtimeSince::Always;
114}
115
117{
118 return 1;
119}
120
122{
123 return 1;
124}
125
127 EffectSettings &, double sampleRate, sampleCount, ChannelNames)
128{
129 InstanceInit(mMaster, sampleRate);
130 return true;
131}
132
134 const float *const *inBlock, float *const *outBlock, size_t blockLen)
135{
136 return InstanceProcess(settings, mMaster, inBlock, outBlock, blockLen);
137}
138
140{
141 SetBlockSize(512);
142 mSlaves.clear();
143 return true;
144}
145
147 EffectSettings &, unsigned, float sampleRate)
148{
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 const float *const *inbuf, float *const *outbuf, size_t numSamples)
167{
168 if (group >= mSlaves.size())
169 return 0;
170 return InstanceProcess(settings, mSlaves[group], inbuf, outbuf, numSamples);
171}
172
174{
175 return (mBass == 0.0 && mTreble == 0.0 && mGain == 0.0);
176}
177
178
179// Effect implementation
180
181std::unique_ptr<EffectUIValidator> EffectBassTreble::PopulateOrExchange(
183{
184 S.SetBorder(5);
185 S.AddSpace(0, 5);
186
187 S.StartStatic(XO("Tone controls"));
188 {
189 S.StartMultiColumn(3, wxEXPAND);
190 {
191 S.SetStretchyCol(2);
192
193 // Bass control
194 mBassT = S.Id(ID_Bass)
195 .Name(XO("Bass (dB):"))
196 .Validator<FloatingPointValidator<double>>(
197 1, &mBass, NumValidatorStyle::DEFAULT, Bass.min, Bass.max)
198 .AddTextBox(XXO("Ba&ss (dB):"), L"", 10);
199
200 mBassS = S.Id(ID_Bass)
201 .Name(XO("Bass"))
202 .Style(wxSL_HORIZONTAL)
203 .AddSlider( {}, 0, Bass.max * Bass.scale, Bass.min * Bass.scale);
204
205 // Treble control
206 mTrebleT = S.Id(ID_Treble)
207 .Validator<FloatingPointValidator<double>>(
208 1, &mTreble, NumValidatorStyle::DEFAULT, Treble.min, Treble.max)
209 .AddTextBox(XXO("&Treble (dB):"), L"", 10);
210
211 mTrebleS = S.Id(ID_Treble)
212 .Name(XO("Treble"))
213 .Style(wxSL_HORIZONTAL)
214 .AddSlider( {}, 0, Treble.max * Treble.scale, Treble.min * Treble.scale);
215 }
216 S.EndMultiColumn();
217 }
218 S.EndStatic();
219
220 S.StartStatic(XO("Output"));
221 {
222 S.StartMultiColumn(3, wxEXPAND);
223 {
224 S.SetStretchyCol(2);
225
226 // Gain control
227 mGainT = S.Id(ID_Gain)
228 .Validator<FloatingPointValidator<double>>(
229 1, &mGain, NumValidatorStyle::DEFAULT, Gain.min, Gain.max)
230 .AddTextBox(XXO("&Volume (dB):"), L"", 10);
231
232 mGainS = S.Id(ID_Gain)
233 .Name(XO("Level"))
234 .Style(wxSL_HORIZONTAL)
235 .AddSlider( {}, 0, Gain.max * Gain.scale, Gain.min * Gain.scale);
236 }
237 S.EndMultiColumn();
238
239 S.StartMultiColumn(2, wxCENTER);
240 {
241 // Link checkbox
243 S
244 .Id(ID_Link)
245 .AddCheckBox(XXO("&Link Volume control to Tone controls"),
246 Link.def);
247 }
248 S.EndMultiColumn();
249 }
250 S.EndStatic();
251 return nullptr;
252}
253
255{
256 mBassS->SetValue((int) (mBass * Bass.scale));
257 mTrebleS->SetValue((int) mTreble *Treble.scale);
258 mGainS->SetValue((int) mGain * Gain.scale);
259 mLinkCheckBox->SetValue(mLink);
260 return true;
261}
262
263// EffectBassTreble implementation
264
266{
267 data.samplerate = sampleRate;
268 data.slope = 0.4f; // same slope for both filters
269 data.hzBass = 250.0f; // could be tunable in a more advanced version
270 data.hzTreble = 4000.0f; // could be tunable in a more advanced version
271
272 data.a0Bass = 1;
273 data.a1Bass = 0;
274 data.a2Bass = 0;
275 data.b0Bass = 0;
276 data.b1Bass = 0;
277 data.b2Bass = 0;
278
279 data.a0Treble = 1;
280 data.a1Treble = 0;
281 data.a2Treble = 0;
282 data.b0Treble = 0;
283 data.b1Treble = 0;
284 data.b2Treble = 0;
285
286 data.xn1Bass = 0;
287 data.xn2Bass = 0;
288 data.yn1Bass = 0;
289 data.yn2Bass = 0;
290
291 data.xn1Treble = 0;
292 data.xn2Treble = 0;
293 data.yn1Treble = 0;
294 data.yn2Treble = 0;
295
296 data.bass = -1;
297 data.treble = -1;
298 data.gain = DB_TO_LINEAR(mGain);
299
300}
301
304 const float *const *inBlock, float *const *outBlock, size_t blockLen)
305{
306 const float *ibuf = inBlock[0];
307 float *obuf = outBlock[0];
308
309 // Set value to ensure correct rounding
310 double oldBass = DB_TO_LINEAR(mBass);
311 double oldTreble = DB_TO_LINEAR(mTreble);
312
313 data.gain = DB_TO_LINEAR(mGain);
314
315 // Compute coefficients of the low shelf biquand IIR filter
316 if (data.bass != oldBass)
317 Coefficients(data.hzBass, data.slope, mBass, data.samplerate, kBass,
318 data.a0Bass, data.a1Bass, data.a2Bass,
319 data.b0Bass, data.b1Bass, data.b2Bass);
320
321 // Compute coefficients of the high shelf biquand IIR filter
322 if (data.treble != oldTreble)
324 data.a0Treble, data.a1Treble, data.a2Treble,
325 data.b0Treble, data.b1Treble, data.b2Treble);
326
327 for (decltype(blockLen) i = 0; i < blockLen; i++) {
328 obuf[i] = DoFilter(data, ibuf[i]) * data.gain;
329 }
330
331 return blockLen;
332}
333
334
335
336// Effect implementation
337
338
339void EffectBassTreble::Coefficients(double hz, double slope, double gain, double samplerate, int type,
340 double& a0, double& a1, double& a2,
341 double& b0, double& b1, double& b2)
342{
343 double w = 2 * M_PI * hz / samplerate;
344 double a = exp(log(10.0) * gain / 40);
345 double b = sqrt((a * a + 1) / slope - (pow((a - 1), 2)));
346
347 if (type == kBass)
348 {
349 b0 = a * ((a + 1) - (a - 1) * cos(w) + b * sin(w));
350 b1 = 2 * a * ((a - 1) - (a + 1) * cos(w));
351 b2 = a * ((a + 1) - (a - 1) * cos(w) - b * sin(w));
352 a0 = ((a + 1) + (a - 1) * cos(w) + b * sin(w));
353 a1 = -2 * ((a - 1) + (a + 1) * cos(w));
354 a2 = (a + 1) + (a - 1) * cos(w) - b * sin(w);
355 }
356 else //assumed kTreble
357 {
358 b0 = a * ((a + 1) + (a - 1) * cos(w) + b * sin(w));
359 b1 = -2 * a * ((a - 1) + (a + 1) * cos(w));
360 b2 = a * ((a + 1) + (a - 1) * cos(w) - b * sin(w));
361 a0 = ((a + 1) - (a - 1) * cos(w) + b * sin(w));
362 a1 = 2 * ((a - 1) - (a + 1) * cos(w));
363 a2 = (a + 1) - (a - 1) * cos(w) - b * sin(w);
364 }
365}
366
368{
369 // Bass filter
370 float out = (data.b0Bass * in + data.b1Bass * data.xn1Bass + data.b2Bass * data.xn2Bass -
371 data.a1Bass * data.yn1Bass - data.a2Bass * data.yn2Bass) / data.a0Bass;
372 data.xn2Bass = data.xn1Bass;
373 data.xn1Bass = in;
374 data.yn2Bass = data.yn1Bass;
375 data.yn1Bass = out;
376
377 // Treble filter
378 in = out;
379 out = (data.b0Treble * in + data.b1Treble * data.xn1Treble + data.b2Treble * data.xn2Treble -
380 data.a1Treble * data.yn1Treble - data.a2Treble * data.yn2Treble) / data.a0Treble;
381 data.xn2Treble = data.xn1Treble;
382 data.xn1Treble = in;
383 data.yn2Treble = data.yn1Treble;
384 data.yn1Treble = out;
385
386 return out;
387}
388
389
390void EffectBassTreble::OnBassText(wxCommandEvent & WXUNUSED(evt))
391{
392 double oldBass = mBass;
393
394 if (!EnableApply(mUIParent->TransferDataFromWindow()))
395 {
396 return;
397 }
398
399 if (mLink) UpdateGain(oldBass, kBass);
400 mBassS->SetValue((int) (mBass * Bass.scale));
401}
402
403void EffectBassTreble::OnTrebleText(wxCommandEvent & WXUNUSED(evt))
404{
405 double oldTreble = mTreble;
406
407 if (!EnableApply(mUIParent->TransferDataFromWindow()))
408 {
409 return;
410 }
411
412 if (mLink) UpdateGain(oldTreble, kTreble);
413 mTrebleS->SetValue((int) (mTreble * Treble.scale));
414}
415
416void EffectBassTreble::OnGainText(wxCommandEvent & WXUNUSED(evt))
417{
418 if (!EnableApply(mUIParent->TransferDataFromWindow()))
419 {
420 return;
421 }
422
423 mGainS->SetValue((int) (mGain * Gain.scale));
424}
425
426void EffectBassTreble::OnBassSlider(wxCommandEvent & evt)
427{
428 double oldBass = mBass;
429 mBass = (double) evt.GetInt() / Bass.scale;
430 mBassT->GetValidator()->TransferToWindow();
431
432 if (mLink) UpdateGain(oldBass, kBass);
433 EnableApply(mUIParent->Validate());
434}
435
436void EffectBassTreble::OnTrebleSlider(wxCommandEvent & evt)
437{
438 double oldTreble = mTreble;
439 mTreble = (double) evt.GetInt() / Treble.scale;
440 mTrebleT->GetValidator()->TransferToWindow();
441
442 if (mLink) UpdateGain(oldTreble, kTreble);
443 EnableApply(mUIParent->Validate());
444}
445
446void EffectBassTreble::OnGainSlider(wxCommandEvent & evt)
447{
448 mGain = (double) evt.GetInt() / Gain.scale;
449 mGainT->GetValidator()->TransferToWindow();
450
451 EnableApply(mUIParent->Validate());
452}
453
454void EffectBassTreble::OnLinkCheckbox(wxCommandEvent& /*evt*/)
455{
456 mLink = mLinkCheckBox->GetValue();
457}
458
459void EffectBassTreble::UpdateGain(double oldVal, int control)
460{
461 double newVal;
462 oldVal = (oldVal > 0)? oldVal / 2.0 : oldVal / 4.0;
463
464 if (control == kBass)
465 newVal = (mBass > 0)? mBass / 2.0 : mBass / 4.0;
466 else
467 newVal = (mTreble > 0)? mTreble / 2.0 : mTreble / 4.0;
468
469 mGain -= newVal - oldVal;
470 mGain = std::min(Gain.max, std::max(Gain.min, mGain));
471
472 mGainS->SetValue(mGain);
473 mGainT->GetValidator()->TransferToWindow();
474
475}
@ ID_Treble
Definition: BassTreble.cpp:39
@ ID_Gain
Definition: BassTreble.cpp:40
@ ID_Link
Definition: BassTreble.cpp:41
@ ID_Bass
Definition: BassTreble.cpp:38
kShelfType
Definition: BassTreble.cpp:54
@ kBass
Definition: BassTreble.cpp:55
@ kTreble
Definition: BassTreble.cpp:56
END_EVENT_TABLE()
int min(int a, int b)
#define M_PI
Definition: Distortion.cpp:29
EffectType
@ EffectTypeProcess
enum ChannelName * ChannelNames
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define DB_TO_LINEAR(x)
Definition: MemoryX.h:535
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:87
Generates EffectParameterMethods overrides from variadic template arguments.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
A high shelf and low shelf filter.
Definition: BassTreble.h:38
const EffectParameterMethods & Parameters() const override
Definition: BassTreble.cpp:44
static constexpr EffectParameter Treble
Definition: BassTreble.h:130
float DoFilter(EffectBassTrebleState &data, float in)
Definition: BassTreble.cpp:367
static constexpr EffectParameter Gain
Definition: BassTreble.h:132
wxCheckBox * mLinkCheckBox
Definition: BassTreble.h:123
bool CheckWhetherSkipEffect(const EffectSettings &settings) const override
After Init(), tell whether Process() should be skipped.
Definition: BassTreble.cpp:173
bool RealtimeInitialize(EffectSettings &settings, double sampleRate) override
Definition: BassTreble.cpp:139
void InstanceInit(EffectBassTrebleState &data, float sampleRate)
Definition: BassTreble.cpp:265
size_t InstanceProcess(EffectSettings &settings, EffectBassTrebleState &data, const float *const *inBlock, float *const *outBlock, size_t blockLen)
Definition: BassTreble.cpp:302
RealtimeSince RealtimeSupport() const override
Since which version of Audacity has the effect supported realtime?
Definition: BassTreble.cpp:109
static constexpr EffectParameter Bass
Definition: BassTreble.h:128
void Coefficients(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:339
bool ProcessInitialize(EffectSettings &settings, double sampleRate, sampleCount totalLen, ChannelNames chanMap) override
Definition: BassTreble.cpp:126
wxTextCtrl * mBassT
Definition: BassTreble.h:119
bool RealtimeFinalize(EffectSettings &settings) noexcept override
Definition: BassTreble.cpp:158
std::unique_ptr< EffectUIValidator > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access) override
Add controls to effect panel; always succeeds.
Definition: BassTreble.cpp:181
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
Definition: BassTreble.cpp:97
size_t RealtimeProcess(size_t group, EffectSettings &settings, const float *const *inbuf, float *const *outbuf, size_t numSamples) override
Definition: BassTreble.cpp:165
ComponentInterfaceSymbol GetSymbol() const override
Definition: BassTreble.cpp:87
virtual ~EffectBassTreble()
Definition: BassTreble.cpp:81
void OnTrebleText(wxCommandEvent &evt)
Definition: BassTreble.cpp:403
void OnGainText(wxCommandEvent &evt)
Definition: BassTreble.cpp:416
TranslatableString GetDescription() const override
Definition: BassTreble.cpp:92
static const ComponentInterfaceSymbol Symbol
Definition: BassTreble.h:42
wxSlider * mGainS
Definition: BassTreble.h:117
void UpdateGain(double oldVal, int control)
Definition: BassTreble.cpp:459
wxTextCtrl * mTrebleT
Definition: BassTreble.h:120
EffectType GetType() const override
Type determines how it behaves.
Definition: BassTreble.cpp:104
void OnBassSlider(wxCommandEvent &evt)
Definition: BassTreble.cpp:426
void OnGainSlider(wxCommandEvent &evt)
Definition: BassTreble.cpp:446
std::vector< EffectBassTrebleState > mSlaves
Definition: BassTreble.h:108
void OnTrebleSlider(wxCommandEvent &evt)
Definition: BassTreble.cpp:436
EffectBassTrebleState mMaster
Definition: BassTreble.h:107
bool TransferDataToWindow(const EffectSettings &settings) override
Update controls for the settings.
Definition: BassTreble.cpp:254
static constexpr EffectParameter Link
Definition: BassTreble.h:134
wxTextCtrl * mGainT
Definition: BassTreble.h:121
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
Definition: BassTreble.cpp:116
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
Definition: BassTreble.cpp:133
wxSlider * mTrebleS
Definition: BassTreble.h:116
void OnLinkCheckbox(wxCommandEvent &evt)
Definition: BassTreble.cpp:454
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
Definition: BassTreble.cpp:121
void OnBassText(wxCommandEvent &evt)
Definition: BassTreble.cpp:390
bool RealtimeAddProcessor(EffectSettings &settings, unsigned numChannels, float sampleRate) override
Definition: BassTreble.cpp:146
wxSlider * mBassS
Definition: BassTreble.h:115
RealtimeSince
In which versions of Audacity was an effect realtime capable?
bool EnableApply(bool enable=true)
Definition: Effect.cpp:613
wxWindow * mUIParent
Definition: Effect.h:270
Performs effect computation.
Interface for manipulations of an Effect's settings.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:628
size_t SetBlockSize(size_t maxBlockSize) override
Holds a msgid for the translation catalog; may also bind format arguments.
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
BuiltinEffectsModule::Registration< EffectBassTreble > reg
Definition: BassTreble.cpp:62
const Type scale
Scaling factor, for slider control.
Definition: Shuttle.h:32
const Type def
Default value.
Definition: Shuttle.h:29
const Type min
Minimum value.
Definition: Shuttle.h:30
const Type max
Maximum value.
Definition: Shuttle.h:31
Externalized state of a plug-in.