commit 2f0584a2ddafbf452298f0083caa2bcecf654bcd
parent 297b9b9a6ba2f7bf069ce58aa30124d3b425f466
Author: Matt Demanett <matt@demanett.net>
Date: Thu, 5 Mar 2020 22:57:50 -0500
VCF, LVCF: more fixes for low end ringing; drop type B. #101
Diffstat:
8 files changed, 118 insertions(+), 123 deletions(-)
diff --git a/res-src/VCF-src.svg b/res-src/VCF-src.svg
@@ -39,14 +39,6 @@
</g>
</symbol>
- <symbol id="knob-medium" viewBox="0 0 26px 26px">
- <g transform="translate(13 13)">
- <polyline points="-3,0 3,0" stroke-width="1" stroke="#00f" />
- <polyline points="0,-3 0,3" stroke-width="1" stroke="#00f" />
- <circle cx="0" cy="0" r="12.5" stroke-width="1" stroke="#00f" fill="none" />
- </g>
- </symbol>
-
<symbol id="knob-smallest" viewBox="0 0 16px 16px">
<g transform="translate(8 8)">
<polyline points="-3,0 3,0" stroke-width="1" stroke="#00f" />
@@ -160,21 +152,21 @@
</g>
</symbol>
- <symbol id="knobguide-slope" viewBox="0 0 45px 45px">
- <g transform="translate(22.5 22.5)">
- <text font-size="5.0pt" transform="rotate(-240) translate(18 0) rotate(240) translate(-2 3)">1</text>
- <polyline points="0,0 1.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-176) translate(15 0)" />
- <text font-size="5.0pt" transform="rotate(-149.6) translate(18 0) rotate(149.6) translate(-1.5 1)">2</text>
- <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-112.1) translate(15 0)" />
- <text font-size="5.0pt" transform="rotate(-83.3) translate(18 0) rotate(83.3) translate(-2 2)">4</text>
- <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-59.1) translate(15 0)" />
- <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-37.7) translate(15 0)" />
- <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-18.4) translate(15 0)" />
- <text font-size="5.0pt" transform="rotate(-0.7) translate(18 0) rotate(0.7) translate(-2 2)">8</text>
- <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(15.8) translate(15 0)" />
- <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(31.4) translate(15 0)" />
- <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(46) translate(15 0)" />
- <text font-size="5.0pt" transform="rotate(60) translate(18 0) rotate(-60) translate(-5 3)">12</text>
+ <symbol id="knobguide-slope" viewBox="0 0 50px 60px">
+ <g transform="translate(25 30)">
+ <text font-size="6.0pt" transform="rotate(-240) translate(24 0) rotate(240) translate(-2 3)">1</text>
+ <polyline points="0,0 2,0" stroke-width="0.5" stroke="#333" transform="rotate(-176) translate(22 0)" />
+ <text font-size="6.0pt" transform="rotate(-149.6) translate(24 0) rotate(149.6) translate(-1.5 1)">2</text>
+ <polyline points="0,0 3,0" stroke-width="0.5" stroke="#333" transform="rotate(-112.1) translate(22 0)" />
+ <text font-size="6.0pt" transform="rotate(-83.3) translate(24 0) rotate(83.3) translate(-2 2)">4</text>
+ <polyline points="0,0 3,0" stroke-width="0.5" stroke="#333" transform="rotate(-59.1) translate(22 0)" />
+ <polyline points="0,0 3,0" stroke-width="0.5" stroke="#333" transform="rotate(-37.7) translate(22 0)" />
+ <polyline points="0,0 3,0" stroke-width="0.5" stroke="#333" transform="rotate(-18.4) translate(22 0)" />
+ <text font-size="6.0pt" transform="rotate(-0.7) translate(24 0) rotate(0.7) translate(-2 2)">8</text>
+ <polyline points="0,0 3,0" stroke-width="0.5" stroke="#333" transform="rotate(15.8) translate(22 0)" />
+ <polyline points="0,0 3,0" stroke-width="0.5" stroke="#333" transform="rotate(31.4) translate(22 0)" />
+ <polyline points="0,0 3,0" stroke-width="0.5" stroke="#333" transform="rotate(46) translate(22 0)" />
+ <text font-size="6.0pt" transform="rotate(60) translate(24 0) rotate(-60) translate(-5 3)">12</text>
</g>
</symbol>
@@ -208,11 +200,6 @@
</g>
</symbol>
- <symbol id="switch" viewBox="0 0 14px 24px">
- <rect width="14px" height="24px" stroke-width="1" stroke="#000" fill="#ddd" />
- <rect width="14px" height="12px" stroke-width="0" fill="#000" />
- </symbol>
-
<symbol id="button-small" viewBox="0 0 9px 9px">
<g transform="translate(4.5 4.5)">
<circle r="4" stroke-width="1" stroke="#00f" fill="#f00" />
@@ -239,48 +226,45 @@
<rect width="3.0" height="3" fill="#ddd" transform="translate(24 -5)" />
</g>
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(75 0)" /> -->
+
<g transform="translate(21 25)">
<use id="FREQUENCY_PARAM" xlink:href="#knob-large" transform="translate(20 20)" />
<use xlink:href="#knobguide-frequency" transform="translate(-21 0)" />
</g>
- <g transform="translate(27 126)">
+ <g transform="translate(25 126)">
<text font-size="8pt" letter-spacing="2px" transform="translate(10 27) rotate(270)">CV</text>
<use id="FREQUENCY_CV_PARAM" xlink:href="#knob-smallest" transform="translate(20 12)" />
<use xlink:href="#knobguide-centertick" transform="translate(8 0)" />
</g>
- <g transform="translate(80 126)">
+ <g transform="translate(82 126)">
<text font-size="8pt" letter-spacing="2px" transform="translate(10 27) rotate(270)">FM</text>
<use id="FM_PARAM" xlink:href="#knob-smallest" transform="translate(20 12)" />
<use xlink:href="#knobguide-maxtick" transform="translate(8 0)" />
</g>
- <g transform="translate(9 171)">
- <text font-size="8pt" letter-spacing="2px" transform="translate(7 43.5) rotate(270)">RES/BW</text>
- <use id="Q_PARAM" xlink:href="#knob" transform="translate(18 0)" />
- <use xlink:href="#knobguide-linear-38" transform="translate(12 -6)" />
- </g>
-
- <g transform="translate(87 170)">
+ <g transform="translate(54 165)">
<text font-size="8pt" letter-spacing="2px" transform="translate(7 38) rotate(270)">MODE</text>
<use id="MODE_PARAM" xlink:href="#knob-smallest" transform="translate(13 11)" />
<use xlink:href="#knobguide-mode" transform="translate(-9 -11)" />
</g>
- <g transform="translate(20 228)">
- <text font-size="8pt" letter-spacing="2px" transform="translate(7 33.5) rotate(270)">SLOPE</text>
- <use id="SLOPE_PARAM" xlink:href="#knob-medium" transform="translate(18 0)" />
- <use xlink:href="#knobguide-slope" transform="translate(8.5 -9.5)" />
+ <g transform="translate(0 220)">
+ <!-- <rect width="75" height="54" fill="#ff0" transform="translate(1 -9)" /> -->
+ <!-- <rect width="64" height="54" fill="#f0f" transform="translate(5.5 -9)" /> -->
+ <text font-size="8pt" letter-spacing="2px" transform="translate(13.5 43.5) rotate(270)">RES/BW</text>
+ <use id="Q_PARAM" xlink:href="#knob" transform="translate(24.5 0)" />
+ <use xlink:href="#knobguide-linear-38" transform="translate(18.5 -6)" />
</g>
- <g transform="translate(93 222)">
- <text font-size="8pt" letter-spacing="2px" transform="translate(6 36) rotate(270)">TYPE</text>
- <g transform="translate(14 6)">
- <text font-size="5pt" letter-spacing="2px" transform="translate(3.5 -1)">A</text>
- <use id="TYPE_PARAM" xlink:href="#switch" transform="translate(-1 2)" />
- <text font-size="5pt" letter-spacing="2px" transform="translate(4 34)">B</text>
- </g>
+ <g transform="translate(75 220)">
+ <!-- <rect width="75" height="54" fill="#ff0" transform="translate(0 -9)" /> -->
+ <!-- <rect width="64" height="54" fill="#f0f" transform="translate(5.5 -9)" /> -->
+ <text font-size="8pt" letter-spacing="2px" transform="translate(13.4 38.5) rotate(270)">SLOPE</text>
+ <use id="SLOPE_PARAM" xlink:href="#knob" transform="translate(24.5 0)" />
+ <use xlink:href="#knobguide-slope" transform="translate(18.5 -11)" />
</g>
<g transform="translate(0 269)">
diff --git a/res/VCF.svg b/res/VCF.svg
Binary files differ.
diff --git a/src/LVCF.cpp b/src/LVCF.cpp
@@ -1,29 +1,48 @@
#include "LVCF.hpp"
-#define TYPE_KEY "type"
-#define A_TYPE_KEY "a"
-#define B_TYPE_KEY "b"
#define POLES_KEY "poles"
#define BANDWIDTH_MODE_KEY "bandwidthMode"
#define LINEAR_BANDWIDTH_MODE_KEY "linear"
#define PITCH_BANDWIDTH_MODE_KEY "pitched"
+void LVCF::Engine::setParams(
+ int poles,
+ MultimodeFilter::Mode mode,
+ float frequency,
+ float qbw,
+ MultimodeFilter::BandwidthMode bwm
+) {
+ frequency = semitoneToFrequency(_frequencySL.next(frequencyToSemitone(frequency)));
+
+ _filter.setParams(
+ _sampleRate,
+ MultimodeFilter::BUTTERWORTH_TYPE,
+ poles,
+ mode,
+ frequency,
+ qbw,
+ bwm
+ );
+}
+
+void LVCF::Engine::sampleRateChange(int modulationSteps) {
+ _sampleRate = APP->engine->getSampleRate();
+ _frequencySL.setParams(_sampleRate, 100.0f / (float)modulationSteps, frequencyToSemitone(MultimodeFilter::maxFrequency - MultimodeFilter::minFrequency));
+ _finalHP.setParams(_sampleRate, MultimodeFilter::BUTTERWORTH_TYPE, 2, MultimodeFilter::HIGHPASS_MODE, 80.0f, MultimodeFilter::minQbw);
+}
+
+void LVCF::Engine::reset() {
+ _filter.reset();
+}
+
+float LVCF::Engine::next(float sample) {
+ return _finalHP.next(_filter.next(sample));
+}
+
json_t* LVCF::dataToJson() {
json_t* root = json_object();
- switch (_typeSetting) {
- case MultimodeFilter::BUTTERWORTH_TYPE: {
- json_object_set_new(root, TYPE_KEY, json_string(A_TYPE_KEY));
- break;
- }
- case MultimodeFilter::CHEBYSHEV_TYPE: {
- json_object_set_new(root, TYPE_KEY, json_string(B_TYPE_KEY));
- break;
- }
- default: {}
- }
-
json_object_set_new(root, POLES_KEY, json_integer(_polesSetting));
switch (_bandwidthMode) {
@@ -42,16 +61,6 @@ json_t* LVCF::dataToJson() {
}
void LVCF::dataFromJson(json_t* root) {
- json_t* t = json_object_get(root, TYPE_KEY);
- if (t) {
- if (strcmp(json_string_value(t), B_TYPE_KEY) == 0) {
- _typeSetting = MultimodeFilter::CHEBYSHEV_TYPE;
- }
- else {
- _typeSetting = MultimodeFilter::BUTTERWORTH_TYPE;
- }
- }
-
json_t* p = json_object_get(root, POLES_KEY);
if (p) {
_polesSetting = clamp(json_integer_value(p), 1, 12);
@@ -68,6 +77,12 @@ void LVCF::dataFromJson(json_t* root) {
}
}
+void LVCF::sampleRateChange() {
+ for (int c = 0; c < _channels; ++c) {
+ _engines[c]->sampleRateChange(_modulationSteps);
+ }
+}
+
bool LVCF::active() {
return outputs[OUT_OUTPUT].isConnected();
}
@@ -87,8 +102,7 @@ void LVCF::removeChannel(int c) {
void LVCF::modulate() {
MultimodeFilter::Mode mode = (MultimodeFilter::Mode)(1 + clamp((int)params[MODE_PARAM].getValue(), 0, 4));
- if (_type != _typeSetting || _mode != mode || _poles != _polesSetting) {
- _type = _typeSetting;
+ if (_mode != mode || _poles != _polesSetting) {
_mode = mode;
_poles = _polesSetting;
for (int c = 0; c < _channels; ++c) {
@@ -124,8 +138,6 @@ void LVCF::modulateChannel(int c) {
f = clamp(f, MultimodeFilter::minFrequency, MultimodeFilter::maxFrequency);
e.setParams(
- APP->engine->getSampleRate(),
- _type,
_poles,
_mode,
f,
@@ -204,11 +216,6 @@ struct LVCFWidget : ModuleWidget {
assert(m);
menu->addChild(new MenuLabel());
- OptionsMenuItem* t = new OptionsMenuItem("Type");
- t->addItem(OptionMenuItem("A", [m]() { return m->_typeSetting == MultimodeFilter::BUTTERWORTH_TYPE; }, [m]() { m->_typeSetting = MultimodeFilter::BUTTERWORTH_TYPE; }));
- t->addItem(OptionMenuItem("B", [m]() { return m->_typeSetting == MultimodeFilter::CHEBYSHEV_TYPE; }, [m]() { m->_typeSetting = MultimodeFilter::CHEBYSHEV_TYPE; }));
- OptionsMenuItem::addToMenu(t, menu);
-
OptionsMenuItem* s = new OptionsMenuItem("Slope");
s->addItem(OptionMenuItem("1 pole", [m]() { return m->_polesSetting == 1; }, [m]() { m->_polesSetting = 1; }));
s->addItem(OptionMenuItem("2 poles", [m]() { return m->_polesSetting == 2; }, [m]() { m->_polesSetting = 2; }));
diff --git a/src/LVCF.hpp b/src/LVCF.hpp
@@ -37,16 +37,34 @@ struct LVCF : BGModule {
NUM_LIGHTS
};
- typedef MultimodeFilter Engine;
+ struct Engine {
+ MultimodeFilter _filter;
+ float _sampleRate;
+ bogaudio::dsp::SlewLimiter _frequencySL;
+ MultimodeFilter _finalHP;
+
+ Engine() {
+ sampleRateChange();
+ }
+
+ void setParams(
+ int poles,
+ MultimodeFilter::Mode mode,
+ float frequency,
+ float qbw,
+ MultimodeFilter::BandwidthMode bwm
+ );
+ void sampleRateChange(int modulationSteps = 100);
+ void reset();
+ float next(float sample);
+ };
- MultimodeFilter::Type _typeSetting = MultimodeFilter::BUTTERWORTH_TYPE;
- MultimodeFilter::Type _type = MultimodeFilter::UNKNOWN_TYPE;
MultimodeFilter::Mode _mode = MultimodeFilter::UNKNOWN_MODE;
int _polesSetting = 4;
int _poles = 0;
float _q = 0.0f;
MultimodeFilter::BandwidthMode _bandwidthMode = MultimodeFilter::PITCH_BANDWIDTH_MODE;
- Engine* _engines[maxChannels] {};
+ Engine* _engines[maxChannels];
float _lastFrequency = 0.0f;
LVCF() {
@@ -59,6 +77,7 @@ struct LVCF : BGModule {
json_t* dataToJson() override;
void dataFromJson(json_t* root) override;
+ void sampleRateChange() override;
bool active() override;
int channels() override;
void addChannel(int c) override;
diff --git a/src/VCF.cpp b/src/VCF.cpp
@@ -6,13 +6,14 @@
#define PITCH_BANDWIDTH_MODE_KEY "pitched"
void VCF::Engine::setParams(
- MultimodeFilter::Type type,
float slope,
MultimodeFilter::Mode mode,
float frequency,
float qbw,
MultimodeFilter::BandwidthMode bwm
) {
+ frequency = semitoneToFrequency(_frequencySL.next(frequencyToSemitone(frequency)));
+
int i = -1, j = -1;
std::fill(_gains, _gains + nFilters, 0.0f);
if (slope >= 1.0f) {
@@ -27,7 +28,7 @@ void VCF::Engine::setParams(
_filters[i].setParams(
_sampleRate,
- type,
+ MultimodeFilter::BUTTERWORTH_TYPE,
i + 1,
mode,
frequency,
@@ -37,7 +38,7 @@ void VCF::Engine::setParams(
if (j >= 0) {
_filters[j].setParams(
_sampleRate,
- type,
+ MultimodeFilter::BUTTERWORTH_TYPE,
j + 1,
mode,
frequency,
@@ -47,8 +48,10 @@ void VCF::Engine::setParams(
}
}
-void VCF::Engine::sampleRateChange() {
+void VCF::Engine::sampleRateChange(int modulationSteps) {
_sampleRate = APP->engine->getSampleRate();
+ _frequencySL.setParams(_sampleRate, 100.0f / (float)modulationSteps, frequencyToSemitone(MultimodeFilter::maxFrequency - MultimodeFilter::minFrequency));
+ _finalHP.setParams(_sampleRate, MultimodeFilter::BUTTERWORTH_TYPE, 2, MultimodeFilter::HIGHPASS_MODE, 80.0f, MultimodeFilter::minQbw);
for (int i = 0; i < nFilters; ++i) {
_gainSLs[i].setParams(_sampleRate, 50.0f, 1.0f);
}
@@ -68,7 +71,7 @@ float VCF::Engine::next(float sample) {
out += g * _filters[i].next(sample);
}
}
- return out;
+ return _finalHP.next(out);
}
json_t* VCF::dataToJson() {
@@ -101,7 +104,7 @@ void VCF::dataFromJson(json_t* root) {
void VCF::sampleRateChange() {
for (int c = 0; c < _channels; ++c) {
- _engines[c]->sampleRateChange();
+ _engines[c]->sampleRateChange(_modulationSteps);
}
}
@@ -123,10 +126,8 @@ void VCF::removeChannel(int c) {
}
void VCF::modulate() {
- MultimodeFilter::Type type = params[TYPE_PARAM].getValue() > 0.5f ? MultimodeFilter::BUTTERWORTH_TYPE : MultimodeFilter::CHEBYSHEV_TYPE;
MultimodeFilter::Mode mode = (MultimodeFilter::Mode)(1 + clamp((int)params[MODE_PARAM].getValue(), 0, 4));
- if (_type != type || _mode != mode) {
- _type = type;
+ if (_mode != mode) {
_mode = mode;
for (int c = 0; c < _channels; ++c) {
_engines[c]->reset();
@@ -163,20 +164,9 @@ void VCF::modulateChannel(int c) {
pitch += fm;
f += cvToFrequency(pitch);
}
- const float lowThreshold = 100.0f;
- if (f < lowThreshold) {
- float deltaF = std::max(1.0f, _lastFrequency) / MultimodeFilter::maxFrequency;
- deltaF = std::pow(deltaF, 1.5f);
- deltaF *= std::max(5.0f, 0.5f * MultimodeFilter::maxFrequency);
- f = std::max(_lastFrequency - deltaF, f);
-
- q = std::min(f / lowThreshold, q);
- }
- _lastFrequency = f;
f = clamp(f, MultimodeFilter::minFrequency, MultimodeFilter::maxFrequency);
e.setParams(
- _type,
slope,
_mode,
f,
@@ -214,12 +204,11 @@ struct VCFWidget : ModuleWidget {
// generated by svg_widgets.rb
auto frequencyParamPosition = Vec(41.0, 45.0);
- auto frequencyCvParamPosition = Vec(47.0, 138.0);
- auto fmParamPosition = Vec(100.0, 138.0);
- auto qParamPosition = Vec(27.0, 171.0);
- auto modeParamPosition = Vec(100.0, 181.0);
- auto slopeParamPosition = Vec(38.0, 228.0);
- auto typeParamPosition = Vec(105.5, 229.5);
+ auto frequencyCvParamPosition = Vec(45.0, 138.0);
+ auto fmParamPosition = Vec(102.0, 138.0);
+ auto modeParamPosition = Vec(67.0, 176.0);
+ auto qParamPosition = Vec(24.5, 220.0);
+ auto slopeParamPosition = Vec(99.5, 220.0);
auto frequencyCvInputPosition = Vec(31.0, 274.0);
auto pitchInputPosition = Vec(63.0, 274.0);
@@ -245,8 +234,7 @@ struct VCFWidget : ModuleWidget {
k->speed = 3.0;
addParam(w);
}
- addParam(createParam<Knob26>(slopeParamPosition, module, VCF::SLOPE_PARAM));
- addParam(createParam<SliderSwitch2State14>(typeParamPosition, module, VCF::TYPE_PARAM));
+ addParam(createParam<Knob38>(slopeParamPosition, module, VCF::SLOPE_PARAM));
addInput(createInput<Port24>(frequencyCvInputPosition, module, VCF::FREQUENCY_CV_INPUT));
addInput(createInput<Port24>(fmInputPosition, module, VCF::FM_INPUT));
diff --git a/src/VCF.hpp b/src/VCF.hpp
@@ -18,7 +18,6 @@ struct VCF : BGModule {
Q_PARAM,
MODE_PARAM,
SLOPE_PARAM,
- TYPE_PARAM,
NUM_PARAMS
};
@@ -45,13 +44,14 @@ struct VCF : BGModule {
float _gains[nFilters] {};
bogaudio::dsp::SlewLimiter _gainSLs[nFilters];
float _sampleRate;
+ bogaudio::dsp::SlewLimiter _frequencySL;
+ MultimodeFilter _finalHP;
Engine() {
sampleRateChange();
}
void setParams(
- MultimodeFilter::Type type,
float slope,
MultimodeFilter::Mode mode,
float frequency,
@@ -59,15 +59,13 @@ struct VCF : BGModule {
MultimodeFilter::BandwidthMode bwm
);
void reset();
- void sampleRateChange();
+ void sampleRateChange(int modulationSteps = 100);
float next(float sample);
};
- MultimodeFilter::Type _type = MultimodeFilter::UNKNOWN_TYPE;
MultimodeFilter::Mode _mode = MultimodeFilter::UNKNOWN_MODE;
MultimodeFilter::BandwidthMode _bandwidthMode = MultimodeFilter::PITCH_BANDWIDTH_MODE;
Engine* _engines[maxChannels] {};
- float _lastFrequency = 0.0f;
VCF() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
@@ -77,7 +75,6 @@ struct VCF : BGModule {
configParam(Q_PARAM, 0.0f, 1.0f, 0.0f, "Resonance / bandwidth", "%", 0.0f, 100.0f);
configParam(MODE_PARAM, 0.0f, 3.0f, 0.0f, "Mode");
configParam<ScaledSquaringParamQuantity<Engine::maxPoles - Engine::minPoles>>(SLOPE_PARAM, 0.0f, 1.0f, 0.52222f, "Slope", " poles", 0.0f, 1.0f, Engine::minPoles);
- configParam(TYPE_PARAM, 0.0f, 1.0f, 1.0f, "Type");
}
json_t* dataToJson() override;
diff --git a/src/dsp/filter.cpp b/src/dsp/filter.cpp
@@ -246,8 +246,8 @@ void MultimodeFilter::setParams(
_poles[j] = Pole(-re, im, re + re, re * re + im * im);
}
- // _outGain = 1.0 / (e * std::pow(2.0, (T)(_nPoles - 1)));
- _outGain = 1.0f / std::pow(2.0f, (T)(_nPoles - 1));
+ _outGain = 1.0 / (e * std::pow(2.0, (T)(_nPoles - 1)));
+ // _outGain = 1.0f / std::pow(2.0f, (T)(_nPoles - 1));
break;
}
diff --git a/src/dsp/filter.hpp b/src/dsp/filter.hpp
@@ -179,7 +179,7 @@ struct MultimodeFilter : Filter {
static constexpr int minPoles = 1;
static constexpr int maxPoles = 16;
static constexpr int modPoles = 1;
- static constexpr float minFrequency = 10.0f;
+ static constexpr float minFrequency = 1.0f;
static constexpr float maxFrequency = 21000.0f;
static constexpr float minQbw = 0.0f;
static constexpr float maxQbw = 1.0f;