2013-01-01 15:50:12 +00:00
|
|
|
/**********************************************************************
|
|
|
|
|
|
|
|
Audacity: A Digital Audio Editor
|
2016-06-06 17:29:10 +00:00
|
|
|
Audacity(R) is copyright (c) 1999-2016 Audacity Team.
|
2013-01-01 15:50:12 +00:00
|
|
|
License: GPL v2. See License.txt.
|
|
|
|
|
|
|
|
BassTreble.cpp
|
|
|
|
Steve Daulton
|
|
|
|
|
|
|
|
******************************************************************//**
|
2013-01-01 01:59:02 +00:00
|
|
|
|
|
|
|
\class EffectBassTreble
|
2015-04-17 03:53:42 +00:00
|
|
|
\brief A high shelf and low shelf filter.
|
2013-04-07 16:49:16 +00:00
|
|
|
|
2013-01-01 01:59:02 +00:00
|
|
|
*//*******************************************************************/
|
|
|
|
|
2021-05-09 15:16:56 +00:00
|
|
|
|
2015-06-18 14:24:36 +00:00
|
|
|
#include "BassTreble.h"
|
2019-01-17 23:31:08 +00:00
|
|
|
#include "LoadEffects.h"
|
2013-01-01 01:59:02 +00:00
|
|
|
|
2015-04-17 03:53:42 +00:00
|
|
|
#include <math.h>
|
2016-06-07 10:23:11 +00:00
|
|
|
#include <algorithm>
|
2013-01-01 01:59:02 +00:00
|
|
|
|
|
|
|
#include <wx/button.h>
|
2018-11-11 22:30:55 +00:00
|
|
|
#include <wx/checkbox.h>
|
2015-04-17 03:53:42 +00:00
|
|
|
#include <wx/intl.h>
|
|
|
|
#include <wx/panel.h>
|
2013-04-07 16:49:16 +00:00
|
|
|
#include <wx/sizer.h>
|
2018-11-11 21:18:23 +00:00
|
|
|
#include <wx/slider.h>
|
2013-01-01 01:59:02 +00:00
|
|
|
|
2015-04-17 03:53:42 +00:00
|
|
|
#include "../Prefs.h"
|
2019-02-06 18:44:52 +00:00
|
|
|
#include "../Shuttle.h"
|
2015-06-18 14:24:36 +00:00
|
|
|
#include "../ShuttleGui.h"
|
2015-04-17 03:53:42 +00:00
|
|
|
#include "../WaveTrack.h"
|
|
|
|
#include "../widgets/valnum.h"
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
ID_Bass = 10000,
|
|
|
|
ID_Treble,
|
2016-06-06 17:29:10 +00:00
|
|
|
ID_Gain,
|
|
|
|
ID_Link
|
2015-04-17 03:53:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Define keys, defaults, minimums, and maximums for the effect parameters
|
|
|
|
//
|
2016-06-06 17:29:10 +00:00
|
|
|
// Name Type Key Def Min Max Scale
|
2017-10-03 22:07:04 +00:00
|
|
|
Param( Bass, double, wxT("Bass"), 0.0, -30.0, 30.0, 1 );
|
|
|
|
Param( Treble, double, wxT("Treble"), 0.0, -30.0, 30.0, 1 );
|
|
|
|
Param( Gain, double, wxT("Gain"), 0.0, -30.0, 30.0, 1 );
|
|
|
|
Param( Link, bool, wxT("Link Sliders"), false, false, true, 1 );
|
2013-04-07 16:49:16 +00:00
|
|
|
|
2015-04-17 03:53:42 +00:00
|
|
|
// Used to communicate the type of the filter.
|
|
|
|
enum kShelfType
|
|
|
|
{
|
|
|
|
kBass,
|
|
|
|
kTreble
|
|
|
|
};
|
|
|
|
|
2019-01-17 22:33:49 +00:00
|
|
|
const ComponentInterfaceSymbol EffectBassTreble::Symbol
|
|
|
|
{ XO("Bass and Treble") };
|
|
|
|
|
2019-01-17 23:31:08 +00:00
|
|
|
namespace{ BuiltinEffectsModule::Registration< EffectBassTreble > reg; }
|
|
|
|
|
2015-04-17 03:53:42 +00:00
|
|
|
BEGIN_EVENT_TABLE(EffectBassTreble, wxEvtHandler)
|
2016-06-06 17:29:10 +00:00
|
|
|
EVT_SLIDER(ID_Bass, EffectBassTreble::OnBassSlider)
|
|
|
|
EVT_SLIDER(ID_Treble, EffectBassTreble::OnTrebleSlider)
|
|
|
|
EVT_SLIDER(ID_Gain, EffectBassTreble::OnGainSlider)
|
|
|
|
EVT_TEXT(ID_Bass, EffectBassTreble::OnBassText)
|
|
|
|
EVT_TEXT(ID_Treble, EffectBassTreble::OnTrebleText)
|
|
|
|
EVT_TEXT(ID_Gain, EffectBassTreble::OnGainText)
|
|
|
|
EVT_CHECKBOX(ID_Link, EffectBassTreble::OnLinkCheckbox)
|
2015-04-17 03:53:42 +00:00
|
|
|
END_EVENT_TABLE()
|
2013-01-01 01:59:02 +00:00
|
|
|
|
|
|
|
EffectBassTreble::EffectBassTreble()
|
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
mBass = DEF_Bass;
|
|
|
|
mTreble = DEF_Treble;
|
|
|
|
mGain = DEF_Gain;
|
|
|
|
mLink = DEF_Link;
|
2015-05-15 11:47:51 +00:00
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
SetLinearEffectFlag(true);
|
2015-04-17 03:53:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EffectBassTreble::~EffectBassTreble()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-11-02 15:31:44 +00:00
|
|
|
// ComponentInterface implementation
|
2015-04-17 03:53:42 +00:00
|
|
|
|
2018-11-02 15:31:44 +00:00
|
|
|
ComponentInterfaceSymbol EffectBassTreble::GetSymbol()
|
2015-04-17 03:53:42 +00:00
|
|
|
{
|
2019-01-17 22:33:49 +00:00
|
|
|
return Symbol;
|
2015-04-17 03:53:42 +00:00
|
|
|
}
|
|
|
|
|
2019-12-08 18:53:48 +00:00
|
|
|
TranslatableString EffectBassTreble::GetDescription()
|
2015-04-17 03:53:42 +00:00
|
|
|
{
|
2019-12-08 18:53:48 +00:00
|
|
|
return XO("Simple tone control effect");
|
2015-04-17 03:53:42 +00:00
|
|
|
}
|
|
|
|
|
2021-06-06 16:18:35 +00:00
|
|
|
ManualPageID EffectBassTreble::ManualPage()
|
2017-05-20 13:40:09 +00:00
|
|
|
{
|
2021-06-06 16:18:35 +00:00
|
|
|
return L"Bass_and_Treble";
|
2017-05-20 13:40:09 +00:00
|
|
|
}
|
|
|
|
|
Automation: AudacityCommand
This is a squash of 50 commits.
This merges the capabilities of BatchCommands and Effects using a new
AudacityCommand class. AudacityCommand provides one function to specify the
parameters, and then we leverage that one function in automation, whether by chains,
mod-script-pipe or (future) Nyquist.
- Now have AudacityCommand which is using the same mechanism as Effect
- Has configurable parameters
- Has data-entry GUI (built using shuttle GUI)
- Registers with PluginManager.
- Menu commands now provided in chains, and to python batch.
- Tested with Zoom Toggle.
- ShuttleParams now can set, get, set defaults, validate and specify
the parameters.
- Bugfix: Don't overwrite values with defaults first time out.
- Add DefineParams function for all built-in effects.
- Extend CommandContext to carry output channels for results.
We abuse EffectsManager. It handles both Effects and
AudacityCommands now. In time an Effect should become a special case of
AudacityCommand and we'll split and rename the EffectManager class.
- Don't use 'default' as a parameter name.
- Massive renaming for CommandDefinitionInterface
- EffectIdentInterface becomes EffectDefinitionInterface
- EffectAutomationParameters becomes CommandAutomationParameters
- PluginType is now a bit field.
This way we can search for related types at the same time.
- Most old batch commands made into AudacityCommands.
The ones that weren't are for a reason. They are used by mod-script-pipe
to carry commands and responses across from a non-GUI thread to the GUI
thread.
- Major tidy up of ScreenshotCommand
- Reworking of SelectCommand
- GetPreferenceCommand and SetPreferenceCommand
- GetTrackInfo and SetTrackInfo
- GetInfoCommand
- Help, Open, Save, Import and Export commands.
- Removed obsolete commands ExecMenu, GetProjectInfo and SetProjectInfo
which are now better handled by other commands.
- JSONify "GetInfo: Commands" output, i.e. commas in the right places.
- General work on better Doxygen.
- Lyrics -> LyricsPanel
- Meter -> MeterPanel
- Updated Linux makefile.
- Scripting commands added into Extra menu.
- Distinct names for previously duplicated find-clipping parameters.
- Fixed longstanding error with erroneous status field number which
previously caused an ASSERT in debug.
- Sensible formatting of numbers in Chains, 0.1 not 0.1000000000137
2018-01-14 18:51:41 +00:00
|
|
|
// EffectDefinitionInterface implementation
|
2015-04-17 03:53:42 +00:00
|
|
|
|
|
|
|
EffectType EffectBassTreble::GetType()
|
|
|
|
{
|
|
|
|
return EffectTypeProcess;
|
2013-04-07 16:49:16 +00:00
|
|
|
}
|
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
bool EffectBassTreble::SupportsRealtime()
|
|
|
|
{
|
|
|
|
#if defined(EXPERIMENTAL_REALTIME_AUDACITY_EFFECTS)
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-17 03:53:42 +00:00
|
|
|
// EffectClientInterface implementation
|
|
|
|
|
2016-09-02 19:53:09 +00:00
|
|
|
unsigned EffectBassTreble::GetAudioInCount()
|
2013-04-07 16:49:16 +00:00
|
|
|
{
|
2015-04-17 03:53:42 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2016-09-02 19:53:09 +00:00
|
|
|
unsigned EffectBassTreble::GetAudioOutCount()
|
2015-04-17 03:53:42 +00:00
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EffectBassTreble::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap))
|
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
InstanceInit(mMaster, mSampleRate);
|
2013-04-07 16:49:16 +00:00
|
|
|
|
|
|
|
return true;
|
2013-01-01 01:59:02 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 13:19:27 +00:00
|
|
|
size_t EffectBassTreble::ProcessBlock(float **inBlock, float **outBlock, size_t blockLen)
|
2015-04-17 03:53:42 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
return InstanceProcess(mMaster, inBlock, outBlock, blockLen);
|
2013-01-01 01:59:02 +00:00
|
|
|
}
|
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
bool EffectBassTreble::RealtimeInitialize()
|
2013-01-01 01:59:02 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
SetBlockSize(512);
|
|
|
|
|
2018-02-02 18:24:53 +00:00
|
|
|
mSlaves.clear();
|
2013-01-01 01:59:02 +00:00
|
|
|
|
2015-04-17 03:53:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-02 19:53:09 +00:00
|
|
|
bool EffectBassTreble::RealtimeAddProcessor(unsigned WXUNUSED(numChannels), float sampleRate)
|
2015-04-17 03:53:42 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
EffectBassTrebleState slave;
|
|
|
|
|
|
|
|
InstanceInit(slave, sampleRate);
|
2013-01-01 01:59:02 +00:00
|
|
|
|
2018-02-02 18:24:53 +00:00
|
|
|
mSlaves.push_back(slave);
|
2013-01-31 00:36:37 +00:00
|
|
|
|
2013-01-01 01:59:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
bool EffectBassTreble::RealtimeFinalize()
|
2014-06-03 20:30:19 +00:00
|
|
|
{
|
2018-02-02 18:24:53 +00:00
|
|
|
mSlaves.clear();
|
2015-04-17 03:53:42 +00:00
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
return true;
|
|
|
|
}
|
2015-04-17 03:53:42 +00:00
|
|
|
|
2016-09-06 13:19:27 +00:00
|
|
|
size_t EffectBassTreble::RealtimeProcess(int group,
|
2016-06-06 17:29:10 +00:00
|
|
|
float **inbuf,
|
|
|
|
float **outbuf,
|
2016-09-06 13:19:27 +00:00
|
|
|
size_t numSamples)
|
2016-06-06 17:29:10 +00:00
|
|
|
{
|
|
|
|
return InstanceProcess(mSlaves[group], inbuf, outbuf, numSamples);
|
|
|
|
}
|
Automation: AudacityCommand
This is a squash of 50 commits.
This merges the capabilities of BatchCommands and Effects using a new
AudacityCommand class. AudacityCommand provides one function to specify the
parameters, and then we leverage that one function in automation, whether by chains,
mod-script-pipe or (future) Nyquist.
- Now have AudacityCommand which is using the same mechanism as Effect
- Has configurable parameters
- Has data-entry GUI (built using shuttle GUI)
- Registers with PluginManager.
- Menu commands now provided in chains, and to python batch.
- Tested with Zoom Toggle.
- ShuttleParams now can set, get, set defaults, validate and specify
the parameters.
- Bugfix: Don't overwrite values with defaults first time out.
- Add DefineParams function for all built-in effects.
- Extend CommandContext to carry output channels for results.
We abuse EffectsManager. It handles both Effects and
AudacityCommands now. In time an Effect should become a special case of
AudacityCommand and we'll split and rename the EffectManager class.
- Don't use 'default' as a parameter name.
- Massive renaming for CommandDefinitionInterface
- EffectIdentInterface becomes EffectDefinitionInterface
- EffectAutomationParameters becomes CommandAutomationParameters
- PluginType is now a bit field.
This way we can search for related types at the same time.
- Most old batch commands made into AudacityCommands.
The ones that weren't are for a reason. They are used by mod-script-pipe
to carry commands and responses across from a non-GUI thread to the GUI
thread.
- Major tidy up of ScreenshotCommand
- Reworking of SelectCommand
- GetPreferenceCommand and SetPreferenceCommand
- GetTrackInfo and SetTrackInfo
- GetInfoCommand
- Help, Open, Save, Import and Export commands.
- Removed obsolete commands ExecMenu, GetProjectInfo and SetProjectInfo
which are now better handled by other commands.
- JSONify "GetInfo: Commands" output, i.e. commas in the right places.
- General work on better Doxygen.
- Lyrics -> LyricsPanel
- Meter -> MeterPanel
- Updated Linux makefile.
- Scripting commands added into Extra menu.
- Distinct names for previously duplicated find-clipping parameters.
- Fixed longstanding error with erroneous status field number which
previously caused an ASSERT in debug.
- Sensible formatting of numbers in Chains, 0.1 not 0.1000000000137
2018-01-14 18:51:41 +00:00
|
|
|
bool EffectBassTreble::DefineParams( ShuttleParams & S ){
|
|
|
|
S.SHUTTLE_PARAM( mBass, Bass );
|
|
|
|
S.SHUTTLE_PARAM( mTreble, Treble );
|
|
|
|
S.SHUTTLE_PARAM( mGain, Gain );
|
|
|
|
S.SHUTTLE_PARAM( mLink, Link );
|
|
|
|
return true;
|
|
|
|
}
|
2015-04-17 03:53:42 +00:00
|
|
|
|
2018-02-21 14:24:25 +00:00
|
|
|
bool EffectBassTreble::GetAutomationParameters(CommandParameters & parms)
|
2016-06-06 17:29:10 +00:00
|
|
|
{
|
|
|
|
parms.Write(KEY_Bass, mBass);
|
|
|
|
parms.Write(KEY_Treble, mTreble);
|
|
|
|
parms.Write(KEY_Gain, mGain);
|
|
|
|
parms.Write(KEY_Link, mLink);
|
2013-04-07 16:49:16 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-02-21 14:24:25 +00:00
|
|
|
bool EffectBassTreble::SetAutomationParameters(CommandParameters & parms)
|
2013-04-07 16:49:16 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
ReadAndVerifyDouble(Bass);
|
|
|
|
ReadAndVerifyDouble(Treble);
|
|
|
|
ReadAndVerifyDouble(Gain);
|
|
|
|
ReadAndVerifyBool(Link);
|
2013-05-02 22:39:43 +00:00
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
mBass = Bass;
|
|
|
|
mTreble = Treble;
|
|
|
|
mGain = Gain;
|
|
|
|
mLink = Link;
|
2013-04-07 16:49:16 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
bool EffectBassTreble::CheckWhetherSkipEffect()
|
2013-04-07 16:49:16 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
return (mBass == 0.0 && mTreble == 0.0 && mGain == 0.0);
|
2015-04-17 03:53:42 +00:00
|
|
|
}
|
2013-04-07 16:49:16 +00:00
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
|
|
|
|
// Effect implementation
|
|
|
|
|
2015-04-17 03:53:42 +00:00
|
|
|
void EffectBassTreble::PopulateOrExchange(ShuttleGui & S)
|
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
S.SetBorder(5);
|
|
|
|
S.AddSpace(0, 5);
|
|
|
|
|
2019-12-22 19:58:36 +00:00
|
|
|
S.StartStatic(XO("Tone controls"));
|
2015-04-17 03:53:42 +00:00
|
|
|
{
|
2015-08-14 04:28:51 +00:00
|
|
|
S.StartMultiColumn(3, wxEXPAND);
|
2015-04-17 03:53:42 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
S.SetStretchyCol(2);
|
|
|
|
|
2015-08-14 04:28:51 +00:00
|
|
|
// Bass control
|
2017-10-30 16:23:41 +00:00
|
|
|
mBassT = S.Id(ID_Bass)
|
2017-10-29 14:27:23 +00:00
|
|
|
.Name(XO("Bass (dB):"))
|
2017-10-30 16:23:41 +00:00
|
|
|
.Validator<FloatingPointValidator<double>>(
|
|
|
|
1, &mBass, NumValidatorStyle::DEFAULT, MIN_Bass, MAX_Bass)
|
2020-05-11 15:28:14 +00:00
|
|
|
.AddTextBox(XXO("Ba&ss (dB):"), wxT(""), 10);
|
2015-08-14 04:28:51 +00:00
|
|
|
|
2017-10-29 14:27:23 +00:00
|
|
|
mBassS = S.Id(ID_Bass)
|
|
|
|
.Name(XO("Bass"))
|
2017-10-31 18:52:01 +00:00
|
|
|
.Style(wxSL_HORIZONTAL)
|
2017-10-29 14:27:23 +00:00
|
|
|
.AddSlider( {}, 0, MAX_Bass * SCL_Bass, MIN_Bass * SCL_Bass);
|
2015-08-14 04:28:51 +00:00
|
|
|
|
|
|
|
// Treble control
|
2017-10-30 16:23:41 +00:00
|
|
|
mTrebleT = S.Id(ID_Treble)
|
|
|
|
.Validator<FloatingPointValidator<double>>(
|
|
|
|
1, &mTreble, NumValidatorStyle::DEFAULT, MIN_Treble, MAX_Treble)
|
2020-05-11 15:28:14 +00:00
|
|
|
.AddTextBox(XXO("&Treble (dB):"), wxT(""), 10);
|
2015-08-14 04:28:51 +00:00
|
|
|
|
2017-10-29 14:27:23 +00:00
|
|
|
mTrebleS = S.Id(ID_Treble)
|
|
|
|
.Name(XO("Treble"))
|
2017-10-31 18:52:01 +00:00
|
|
|
.Style(wxSL_HORIZONTAL)
|
2017-10-29 14:27:23 +00:00
|
|
|
.AddSlider( {}, 0, MAX_Treble * SCL_Treble, MIN_Treble * SCL_Treble);
|
2016-06-06 17:29:10 +00:00
|
|
|
}
|
|
|
|
S.EndMultiColumn();
|
|
|
|
}
|
|
|
|
S.EndStatic();
|
|
|
|
|
2019-12-22 19:58:36 +00:00
|
|
|
S.StartStatic(XO("Output"));
|
2016-06-06 17:29:10 +00:00
|
|
|
{
|
|
|
|
S.StartMultiColumn(3, wxEXPAND);
|
|
|
|
{
|
|
|
|
S.SetStretchyCol(2);
|
2015-08-14 04:28:51 +00:00
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
// Gain control
|
2017-10-30 16:23:41 +00:00
|
|
|
mGainT = S.Id(ID_Gain)
|
|
|
|
.Validator<FloatingPointValidator<double>>(
|
|
|
|
1, &mGain, NumValidatorStyle::DEFAULT, MIN_Gain, MAX_Gain)
|
2020-05-11 15:28:14 +00:00
|
|
|
.AddTextBox(XXO("&Volume (dB):"), wxT(""), 10);
|
2015-08-14 04:28:51 +00:00
|
|
|
|
2017-10-29 14:27:23 +00:00
|
|
|
mGainS = S.Id(ID_Gain)
|
|
|
|
.Name(XO("Level"))
|
2017-10-31 18:52:01 +00:00
|
|
|
.Style(wxSL_HORIZONTAL)
|
2017-10-29 14:27:23 +00:00
|
|
|
.AddSlider( {}, 0, MAX_Gain * SCL_Gain, MIN_Gain * SCL_Gain);
|
2015-04-17 03:53:42 +00:00
|
|
|
}
|
2015-08-14 04:28:51 +00:00
|
|
|
S.EndMultiColumn();
|
2013-04-07 16:49:16 +00:00
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
S.StartMultiColumn(2, wxCENTER);
|
2015-04-17 03:53:42 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
// Link checkbox
|
2020-05-11 15:28:14 +00:00
|
|
|
mLinkCheckBox = S.Id(ID_Link).AddCheckBox(XXO("&Link Volume control to Tone controls"),
|
2018-02-02 02:37:34 +00:00
|
|
|
DEF_Link);
|
2015-04-17 03:53:42 +00:00
|
|
|
}
|
2016-06-06 17:29:10 +00:00
|
|
|
S.EndMultiColumn();
|
2015-04-17 03:53:42 +00:00
|
|
|
}
|
2016-06-06 17:29:10 +00:00
|
|
|
S.EndStatic();
|
2015-04-17 03:53:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool EffectBassTreble::TransferDataToWindow()
|
|
|
|
{
|
|
|
|
if (!mUIParent->TransferDataToWindow())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
mBassS->SetValue((int) (mBass * SCL_Bass));
|
|
|
|
mTrebleS->SetValue((int) mTreble *SCL_Treble);
|
|
|
|
mGainS->SetValue((int) mGain * SCL_Gain);
|
|
|
|
mLinkCheckBox->SetValue(mLink);
|
2015-04-17 03:53:42 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EffectBassTreble::TransferDataFromWindow()
|
|
|
|
{
|
|
|
|
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-01-01 01:59:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
|
2015-04-17 03:53:42 +00:00
|
|
|
// EffectBassTreble implementation
|
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
void EffectBassTreble::InstanceInit(EffectBassTrebleState & data, float sampleRate)
|
|
|
|
{
|
|
|
|
data.samplerate = sampleRate;
|
|
|
|
data.slope = 0.4f; // same slope for both filters
|
|
|
|
data.hzBass = 250.0f; // could be tunable in a more advanced version
|
|
|
|
data.hzTreble = 4000.0f; // could be tunable in a more advanced version
|
|
|
|
|
|
|
|
data.a0Bass = 1;
|
|
|
|
data.a1Bass = 0;
|
|
|
|
data.a2Bass = 0;
|
|
|
|
data.b0Bass = 0;
|
|
|
|
data.b1Bass = 0;
|
|
|
|
data.b2Bass = 0;
|
|
|
|
|
|
|
|
data.a0Treble = 1;
|
|
|
|
data.a1Treble = 0;
|
|
|
|
data.a2Treble = 0;
|
|
|
|
data.b0Treble = 0;
|
|
|
|
data.b1Treble = 0;
|
|
|
|
data.b2Treble = 0;
|
|
|
|
|
|
|
|
data.xn1Bass = 0;
|
|
|
|
data.xn2Bass = 0;
|
|
|
|
data.yn1Bass = 0;
|
|
|
|
data.yn2Bass = 0;
|
|
|
|
|
|
|
|
data.xn1Treble = 0;
|
|
|
|
data.xn2Treble = 0;
|
|
|
|
data.yn1Treble = 0;
|
|
|
|
data.yn2Treble = 0;
|
|
|
|
|
|
|
|
data.bass = -1;
|
|
|
|
data.treble = -1;
|
|
|
|
data.gain = DB_TO_LINEAR(mGain);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// EffectClientInterface implementation
|
|
|
|
|
|
|
|
|
2016-09-06 13:19:27 +00:00
|
|
|
size_t EffectBassTreble::InstanceProcess(EffectBassTrebleState & data,
|
2016-06-06 17:29:10 +00:00
|
|
|
float **inBlock,
|
|
|
|
float **outBlock,
|
2016-09-06 13:19:27 +00:00
|
|
|
size_t blockLen)
|
2016-06-06 17:29:10 +00:00
|
|
|
{
|
|
|
|
float *ibuf = inBlock[0];
|
|
|
|
float *obuf = outBlock[0];
|
|
|
|
|
|
|
|
// Set value to ensure correct rounding
|
|
|
|
double oldBass = DB_TO_LINEAR(mBass);
|
|
|
|
double oldTreble = DB_TO_LINEAR(mTreble);
|
|
|
|
|
|
|
|
data.gain = DB_TO_LINEAR(mGain);
|
|
|
|
|
2020-04-11 07:08:33 +00:00
|
|
|
// Compute coefficients of the low shelf biquand IIR filter
|
2016-06-06 17:29:10 +00:00
|
|
|
if (data.bass != oldBass)
|
2021-01-28 12:35:23 +00:00
|
|
|
Coefficients(data.hzBass, data.slope, mBass, data.samplerate, kBass,
|
2016-06-06 17:29:10 +00:00
|
|
|
data.a0Bass, data.a1Bass, data.a2Bass,
|
|
|
|
data.b0Bass, data.b1Bass, data.b2Bass);
|
|
|
|
|
2020-04-11 07:08:33 +00:00
|
|
|
// Compute coefficients of the high shelf biquand IIR filter
|
2016-06-06 17:29:10 +00:00
|
|
|
if (data.treble != oldTreble)
|
2021-01-28 12:35:23 +00:00
|
|
|
Coefficients(data.hzTreble, data.slope, mTreble, data.samplerate, kTreble,
|
2016-06-06 17:29:10 +00:00
|
|
|
data.a0Treble, data.a1Treble, data.a2Treble,
|
|
|
|
data.b0Treble, data.b1Treble, data.b2Treble);
|
|
|
|
|
2016-08-24 11:56:33 +00:00
|
|
|
for (decltype(blockLen) i = 0; i < blockLen; i++) {
|
2016-06-06 17:29:10 +00:00
|
|
|
obuf[i] = DoFilter(data, ibuf[i]) * data.gain;
|
|
|
|
}
|
|
|
|
|
|
|
|
return blockLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Effect implementation
|
|
|
|
|
|
|
|
|
2021-01-28 12:35:23 +00:00
|
|
|
void EffectBassTreble::Coefficients(double hz, double slope, double gain, double samplerate, int type,
|
2016-06-06 17:29:10 +00:00
|
|
|
double& a0, double& a1, double& a2,
|
|
|
|
double& b0, double& b1, double& b2)
|
2013-01-01 01:59:02 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
double w = 2 * M_PI * hz / samplerate;
|
2013-04-07 16:49:16 +00:00
|
|
|
double a = exp(log(10.0) * gain / 40);
|
|
|
|
double b = sqrt((a * a + 1) / slope - (pow((a - 1), 2)));
|
|
|
|
|
2015-04-17 03:53:42 +00:00
|
|
|
if (type == kBass)
|
2013-04-07 16:49:16 +00:00
|
|
|
{
|
|
|
|
b0 = a * ((a + 1) - (a - 1) * cos(w) + b * sin(w));
|
|
|
|
b1 = 2 * a * ((a - 1) - (a + 1) * cos(w));
|
|
|
|
b2 = a * ((a + 1) - (a - 1) * cos(w) - b * sin(w));
|
|
|
|
a0 = ((a + 1) + (a - 1) * cos(w) + b * sin(w));
|
|
|
|
a1 = -2 * ((a - 1) + (a + 1) * cos(w));
|
|
|
|
a2 = (a + 1) + (a - 1) * cos(w) - b * sin(w);
|
|
|
|
}
|
2015-04-17 03:53:42 +00:00
|
|
|
else //assumed kTreble
|
2013-04-07 16:49:16 +00:00
|
|
|
{
|
|
|
|
b0 = a * ((a + 1) + (a - 1) * cos(w) + b * sin(w));
|
|
|
|
b1 = -2 * a * ((a - 1) + (a + 1) * cos(w));
|
|
|
|
b2 = a * ((a + 1) + (a - 1) * cos(w) - b * sin(w));
|
2014-06-03 20:30:19 +00:00
|
|
|
a0 = ((a + 1) - (a - 1) * cos(w) + b * sin(w));
|
2013-04-07 16:49:16 +00:00
|
|
|
a1 = 2 * ((a - 1) - (a + 1) * cos(w));
|
|
|
|
a2 = (a + 1) - (a - 1) * cos(w) - b * sin(w);
|
2013-01-01 01:59:02 +00:00
|
|
|
}
|
2013-04-07 16:49:16 +00:00
|
|
|
}
|
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
float EffectBassTreble::DoFilter(EffectBassTrebleState & data, float in)
|
2013-04-07 16:49:16 +00:00
|
|
|
{
|
|
|
|
// Bass filter
|
2016-06-06 17:29:10 +00:00
|
|
|
float out = (data.b0Bass * in + data.b1Bass * data.xn1Bass + data.b2Bass * data.xn2Bass -
|
|
|
|
data.a1Bass * data.yn1Bass - data.a2Bass * data.yn2Bass) / data.a0Bass;
|
|
|
|
data.xn2Bass = data.xn1Bass;
|
|
|
|
data.xn1Bass = in;
|
|
|
|
data.yn2Bass = data.yn1Bass;
|
|
|
|
data.yn1Bass = out;
|
2013-04-07 16:49:16 +00:00
|
|
|
|
|
|
|
// Treble filter
|
|
|
|
in = out;
|
2016-06-06 17:29:10 +00:00
|
|
|
out = (data.b0Treble * in + data.b1Treble * data.xn1Treble + data.b2Treble * data.xn2Treble -
|
|
|
|
data.a1Treble * data.yn1Treble - data.a2Treble * data.yn2Treble) / data.a0Treble;
|
|
|
|
data.xn2Treble = data.xn1Treble;
|
|
|
|
data.xn1Treble = in;
|
|
|
|
data.yn2Treble = data.yn1Treble;
|
|
|
|
data.yn1Treble = out;
|
|
|
|
|
2013-04-07 16:49:16 +00:00
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
void EffectBassTreble::OnBassText(wxCommandEvent & WXUNUSED(evt))
|
|
|
|
{
|
|
|
|
double oldBass = mBass;
|
2013-04-07 16:49:16 +00:00
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
if (!EnableApply(mUIParent->TransferDataFromWindow()))
|
2015-04-17 03:53:42 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
return;
|
2015-04-09 01:13:18 +00:00
|
|
|
}
|
2013-01-01 01:59:02 +00:00
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
if (mLink) UpdateGain(oldBass, kBass);
|
|
|
|
mBassS->SetValue((int) (mBass * SCL_Bass));
|
2013-01-01 01:59:02 +00:00
|
|
|
}
|
|
|
|
|
2015-04-17 03:53:42 +00:00
|
|
|
void EffectBassTreble::OnTrebleText(wxCommandEvent & WXUNUSED(evt))
|
2013-01-01 01:59:02 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
double oldTreble = mTreble;
|
|
|
|
|
|
|
|
if (!EnableApply(mUIParent->TransferDataFromWindow()))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mLink) UpdateGain(oldTreble, kTreble);
|
|
|
|
mTrebleS->SetValue((int) (mTreble * SCL_Treble));
|
2013-01-01 01:59:02 +00:00
|
|
|
}
|
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
void EffectBassTreble::OnGainText(wxCommandEvent & WXUNUSED(evt))
|
2013-01-01 01:59:02 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
if (!EnableApply(mUIParent->TransferDataFromWindow()))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mGainS->SetValue((int) (mGain * SCL_Gain));
|
2013-01-01 01:59:02 +00:00
|
|
|
}
|
|
|
|
|
2015-04-17 03:53:42 +00:00
|
|
|
void EffectBassTreble::OnBassSlider(wxCommandEvent & evt)
|
2013-01-01 01:59:02 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
double oldBass = mBass;
|
|
|
|
mBass = (double) evt.GetInt() / SCL_Bass;
|
2015-04-17 03:53:42 +00:00
|
|
|
mBassT->GetValidator()->TransferToWindow();
|
2016-06-06 17:29:10 +00:00
|
|
|
|
|
|
|
if (mLink) UpdateGain(oldBass, kBass);
|
|
|
|
EnableApply(mUIParent->Validate());
|
2013-01-01 01:59:02 +00:00
|
|
|
}
|
|
|
|
|
2015-04-17 03:53:42 +00:00
|
|
|
void EffectBassTreble::OnTrebleSlider(wxCommandEvent & evt)
|
2013-01-01 01:59:02 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
double oldTreble = mTreble;
|
|
|
|
mTreble = (double) evt.GetInt() / SCL_Treble;
|
2015-04-17 03:53:42 +00:00
|
|
|
mTrebleT->GetValidator()->TransferToWindow();
|
2016-06-06 17:29:10 +00:00
|
|
|
|
|
|
|
if (mLink) UpdateGain(oldTreble, kTreble);
|
|
|
|
EnableApply(mUIParent->Validate());
|
|
|
|
}
|
|
|
|
|
|
|
|
void EffectBassTreble::OnGainSlider(wxCommandEvent & evt)
|
|
|
|
{
|
|
|
|
mGain = (double) evt.GetInt() / SCL_Gain;
|
|
|
|
mGainT->GetValidator()->TransferToWindow();
|
|
|
|
|
|
|
|
EnableApply(mUIParent->Validate());
|
2013-01-01 01:59:02 +00:00
|
|
|
}
|
|
|
|
|
2016-09-11 19:30:06 +00:00
|
|
|
void EffectBassTreble::OnLinkCheckbox(wxCommandEvent& /*evt*/)
|
2013-01-01 01:59:02 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
mLink = mLinkCheckBox->GetValue();
|
2013-01-01 01:59:02 +00:00
|
|
|
}
|
|
|
|
|
2016-06-06 17:29:10 +00:00
|
|
|
void EffectBassTreble::UpdateGain(double oldVal, int control)
|
2013-01-01 01:59:02 +00:00
|
|
|
{
|
2016-06-06 17:29:10 +00:00
|
|
|
double newVal;
|
|
|
|
oldVal = (oldVal > 0)? oldVal / 2.0 : oldVal / 4.0;
|
|
|
|
|
|
|
|
if (control == kBass)
|
|
|
|
newVal = (mBass > 0)? mBass / 2.0 : mBass / 4.0;
|
|
|
|
else
|
|
|
|
newVal = (mTreble > 0)? mTreble / 2.0 : mTreble / 4.0;
|
|
|
|
|
|
|
|
mGain -= newVal - oldVal;
|
|
|
|
mGain = std::min(MAX_Gain, std::max(MIN_Gain, mGain));
|
|
|
|
|
|
|
|
mGainS->SetValue(mGain);
|
|
|
|
mGainT->GetValidator()->TransferToWindow();
|
|
|
|
|
2013-01-01 01:59:02 +00:00
|
|
|
}
|