Improved: Shelving filters (LS(C), HS(C)) can now also use Q instead of slope.

This commit is contained in:
jthedering committed 2019-06-09 18:26:52 +00:00
1 parent 916eab4528
commit a7fc5de925
7 files changed
+91 -53

No files matched your search

+51 -17
View File
@@ -61,13 +61,13 @@ BiQuadFilterGUI::BiQuadFilterGUI(BiQuadFilter* filter)
ui->freqSpinBox->setValue(filter->getFreq()); ui->freqSpinBox->setValue(filter->getFreq());
if (type == BiQuad::PEAKING) if (type == BiQuad::PEAKING)
ui->qComboBox->setCurrentIndex(filter->getIsBandwidth() ? 1 : 0); ui->qComboBox->setCurrentIndex(filter->getIsBandwidthOrS() ? 1 : 0);
else if (type == BiQuad::LOW_PASS || type == BiQuad::HIGH_PASS || type == BiQuad::BAND_PASS) else if (type == BiQuad::LOW_PASS || type == BiQuad::HIGH_PASS || type == BiQuad::BAND_PASS)
ui->qComboBox->setCurrentIndex(filter->getBandwidthOrQOrS() == M_SQRT1_2 ? 0 : 1); ui->qComboBox->setCurrentIndex(filter->getBandwidthOrQOrS() == M_SQRT1_2 ? 0 : 1);
else if ((type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) && !filter->getIsCornerFreq()) else if ((type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF))
ui->qComboBox->setCurrentIndex(filter->getBandwidthOrQOrS() == 0.9 ? 0 : 1); ui->qComboBox->setCurrentIndex(filter->getIsBandwidthOrS() ? (filter->getBandwidthOrQOrS() == 0.9 || filter->getIsCornerFreq() ? 0 : 1) : (filter->getIsCornerFreq() ? 1 : 2));
if ((type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) && filter->getBandwidthOrQOrS() != 0.9) if ((type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) && filter->getIsBandwidthOrS() && filter->getBandwidthOrQOrS() != 0.9)
ui->qSpinBox->setValue(filter->getBandwidthOrQOrS() * 12.0); ui->qSpinBox->setValue(filter->getBandwidthOrQOrS() * 12.0);
else else
ui->qSpinBox->setValue(filter->getBandwidthOrQOrS()); ui->qSpinBox->setValue(filter->getBandwidthOrQOrS());
@@ -109,13 +109,13 @@ void BiQuadFilterGUI::store(QString& command, QString& parameters)
parameters += "BP"; parameters += "BP";
break; break;
case BiQuad::LOW_SHELF: case BiQuad::LOW_SHELF:
if (freqMode == 'E' && mode == 'S') if (freqMode == 'E' && mode != 'F')
parameters += "LSC"; parameters += "LSC";
else else
parameters += "LS"; parameters += "LS";
break; break;
case BiQuad::HIGH_SHELF: case BiQuad::HIGH_SHELF:
if (freqMode == 'E' && mode == 'S') if (freqMode == 'E' && mode != 'F')
parameters += "HSC"; parameters += "HSC";
else else
parameters += "HS"; parameters += "HS";
@@ -216,12 +216,12 @@ void BiQuadFilterGUI::on_typeComboBox_currentIndexChanged(int index)
ui->qComboBox->addItem(tr("Fixed Q"), 'F'); ui->qComboBox->addItem(tr("Fixed Q"), 'F');
else if ((type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) && freqMode == 'E') else if ((type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) && freqMode == 'E')
ui->qComboBox->addItem(tr("Fixed S"), 'F'); ui->qComboBox->addItem(tr("Fixed S"), 'F');
if (type == BiQuad::PEAKING || type == BiQuad::LOW_PASS || type == BiQuad::HIGH_PASS || type == BiQuad::ALL_PASS || type == BiQuad::BAND_PASS || type == BiQuad::NOTCH) if (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
ui->qComboBox->addItem(tr("Slope"), 'S');
if (type == BiQuad::PEAKING || type == BiQuad::LOW_PASS || type == BiQuad::HIGH_PASS || type == BiQuad::ALL_PASS || type == BiQuad::BAND_PASS || type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF || type == BiQuad::NOTCH)
ui->qComboBox->addItem(tr("Q factor"), 'Q'); ui->qComboBox->addItem(tr("Q factor"), 'Q');
if (type == BiQuad::PEAKING) if (type == BiQuad::PEAKING)
ui->qComboBox->addItem(tr("Bandwidth"), 'B'); ui->qComboBox->addItem(tr("Bandwidth"), 'B');
if (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
ui->qComboBox->addItem(tr("Slope"), 'S');
ui->qComboBox->setEnabled(ui->qComboBox->count() > 1); ui->qComboBox->setEnabled(ui->qComboBox->count() > 1);
int qIndex = ui->qComboBox->findData(mode); int qIndex = ui->qComboBox->findData(mode);
if (qIndex != -1 && sameTypeCategory) if (qIndex != -1 && sameTypeCategory)
@@ -257,6 +257,7 @@ void BiQuadFilterGUI::on_freqComboBox_currentIndexChanged(int index)
if (freqMode == 'E') if (freqMode == 'E')
ui->qComboBox->addItem(tr("Fixed S"), 'F'); ui->qComboBox->addItem(tr("Fixed S"), 'F');
ui->qComboBox->addItem(tr("Slope"), 'S'); ui->qComboBox->addItem(tr("Slope"), 'S');
ui->qComboBox->addItem(tr("Q factor"), 'Q');
ui->qComboBox->setEnabled(ui->qComboBox->count() > 1); ui->qComboBox->setEnabled(ui->qComboBox->count() > 1);
int qIndex = ui->qComboBox->findData(mode); int qIndex = ui->qComboBox->findData(mode);
if (qIndex != -1) if (qIndex != -1)
@@ -265,7 +266,16 @@ void BiQuadFilterGUI::on_freqComboBox_currentIndexChanged(int index)
ui->qSpinBox->setValue(qValue); ui->qSpinBox->setValue(qValue);
} }
double centerFreqFactor = pow(10.0, abs(ui->gainSpinBox->value()) / 80.0 / (ui->qSpinBox->value() / 12.0)); double dbGain = ui->gainSpinBox->value();
double s = (ui->qSpinBox->value() / 12.0);
if (mode == 'Q')
{
double q = ui->qSpinBox->value();
double a = pow(10, dbGain / 40);
s = 1.0 / ((1.0 / (q * q) - 2.0) / (a + 1.0 / a) + 1.0);
}
double centerFreqFactor = pow(10.0, abs(dbGain) / 80.0 / s);
double freq = ui->freqSpinBox->value(); double freq = ui->freqSpinBox->value();
if ((freqMode == 'E') == (type == BiQuad::LOW_SHELF)) if ((freqMode == 'E') == (type == BiQuad::LOW_SHELF))
freq *= centerFreqFactor; freq *= centerFreqFactor;
@@ -297,25 +307,49 @@ void BiQuadFilterGUI::on_qComboBox_currentIndexChanged(int index)
ui->qSpinBox->setValue(0.9); ui->qSpinBox->setValue(0.9);
else if (type == BiQuad::NOTCH) else if (type == BiQuad::NOTCH)
ui->qSpinBox->setValue(30); ui->qSpinBox->setValue(30);
qIsBwOrS = type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF;
} }
else if (qIsBw && mode == 'Q') else if (qIsBwOrS && mode == 'Q')
{ {
double n = ui->qSpinBox->value(); BiQuad::Type type = (BiQuad::Type)ui->typeComboBox->currentData().toInt();
double p2n = pow(2.0, n); double q;
double q = sqrt(p2n) / (p2n - 1.0); if (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) // from S
{
double s = ui->qSpinBox->value();
if (s != 0.9)
s /= 12.0;
double a = pow(10, ui->gainSpinBox->value() / 40);
q = 1.0 / sqrt((a + 1.0 / a) * (1.0 / s - 1.0) + 2.0);
}
else // from BW
{
double n = ui->qSpinBox->value();
double p2n = pow(2.0, n);
q = sqrt(p2n) / (p2n - 1.0);
}
ui->qSpinBox->setValue(q); ui->qSpinBox->setValue(q);
qIsBw = false; qIsBwOrS = false;
} }
else if (!qIsBw && mode == 'B') else if (!qIsBwOrS && mode == 'B')
{ {
double q = ui->qSpinBox->value(); double q = ui->qSpinBox->value();
double n = 2.0 / M_LN2 * asinh(1.0 / (2.0 * q)); double n = 2.0 / M_LN2 * asinh(1.0 / (2.0 * q));
ui->qSpinBox->setValue(n); ui->qSpinBox->setValue(n);
qIsBw = true; qIsBwOrS = true;
}
else if (!qIsBwOrS && mode == 'S')
{
double q = ui->qSpinBox->value();
double a = pow(10, ui->gainSpinBox->value() / 40);
double s = 1.0 / ((1.0 / (q * q) - 2.0) / (a + 1.0 / a) + 1.0);
ui->qSpinBox->setValue(s * 12.0);
qIsBwOrS = true;
} }
else if (mode == 'S') else if (mode == 'S')
{ {
ui->qSpinBox->setValue(12.0); ui->qSpinBox->setValue(12.0);
qIsBwOrS = true;
} }
emit updateModel(); emit updateModel();
+1 -1
View File
@@ -51,5 +51,5 @@ private:
Ui::BiQuadFilterGUI* ui; Ui::BiQuadFilterGUI* ui;
BiQuad::Type previousType = BiQuad::PEAKING; BiQuad::Type previousType = BiQuad::PEAKING;
bool qIsBw = false; bool qIsBwOrS = false;
}; };
+8 -10
View File
@@ -22,7 +22,7 @@
using namespace std; using namespace std;
BiQuad::BiQuad(Type type, double dbGain, double freq, double srate, double bandwidthOrQOrS, bool isBandwidth) BiQuad::BiQuad(Type type, double dbGain, double freq, double srate, double bandwidthOrQOrS, bool isBandwidthOrS)
{ {
double A; double A;
if (type == PEAKING || type == LOW_SHELF || type == HIGH_SHELF) if (type == PEAKING || type == LOW_SHELF || type == HIGH_SHELF)
@@ -33,17 +33,15 @@ BiQuad::BiQuad(Type type, double dbGain, double freq, double srate, double bandw
double sn = sin(omega); double sn = sin(omega);
double cs = cos(omega); double cs = cos(omega);
double alpha; double alpha;
double beta = -1;
if (type == LOW_SHELF || type == HIGH_SHELF) // S if (!isBandwidthOrS) // Q
{
alpha = sn / 2 * sqrt((A + 1 / A) * (1 / bandwidthOrQOrS - 1) + 2);
beta = 2 * sqrt(A) * alpha;
}
else if (isBandwidth) // BW
alpha = sn * sinh(M_LN2 / 2 * bandwidthOrQOrS * omega / sn);
else // Q
alpha = sn / (2 * bandwidthOrQOrS); alpha = sn / (2 * bandwidthOrQOrS);
else if (type == LOW_SHELF || type == HIGH_SHELF) // S
alpha = sn / 2 * sqrt((A + 1 / A) * (1 / bandwidthOrQOrS - 1) + 2);
else // BW
alpha = sn * sinh(M_LN2 / 2 * bandwidthOrQOrS * omega / sn);
double beta = 2 * sqrt(A) * alpha;
double b0, b1, b2, a0, a1, a2; double b0, b1, b2, a0, a1, a2;
+1 -1
View File
@@ -35,7 +35,7 @@ public:
}; };
BiQuad() {} BiQuad() {}
BiQuad(Type type, double dbGain, double freq, double srate, double bandwidthOrQOrS, bool isBandwidth); BiQuad(Type type, double dbGain, double freq, double srate, double bandwidthOrQOrS, bool isBandwidthOrS);
__forceinline __forceinline
void removeDenormals() void removeDenormals()
+14 -6
View File
@@ -23,8 +23,8 @@
using namespace std; using namespace std;
BiQuadFilter::BiQuadFilter(BiQuad::Type type, double dbGain, double freq, double bandwidthOrQOrS, bool isBandwidth, bool isCornerFreq) BiQuadFilter::BiQuadFilter(BiQuad::Type type, double dbGain, double freq, double bandwidthOrQOrS, bool isBandwidthOrS, bool isCornerFreq)
: type(type), dbGain(dbGain), freq(freq), bandwidthOrQOrS(bandwidthOrQOrS), isBandwidth(isBandwidth), isCornerFreq(isCornerFreq) : type(type), dbGain(dbGain), freq(freq), bandwidthOrQOrS(bandwidthOrQOrS), isBandwidthOrS(isBandwidthOrS), isCornerFreq(isCornerFreq)
{ {
channelCount = 0; channelCount = 0;
biquads = NULL; biquads = NULL;
@@ -46,8 +46,16 @@ vector<wstring> BiQuadFilter::initialize(float sampleRate, unsigned maxFrameCoun
double biquadFreq = freq; double biquadFreq = freq;
if (isCornerFreq && (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)) if (isCornerFreq && (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF))
{ {
double s = bandwidthOrQOrS;
if (!isBandwidthOrS) // Q
{
double q = bandwidthOrQOrS;
double a = pow(10, dbGain / 40);
s = 1.0 / ((1.0 / (q * q) - 2.0) / (a + 1.0 / a) + 1.0);
}
// frequency adjustment for DCX2496 // frequency adjustment for DCX2496
double centerFreqFactor = pow(10.0, abs(dbGain) / 80.0 / bandwidthOrQOrS); double centerFreqFactor = pow(10.0, abs(dbGain) / 80.0 / s);
if (type == BiQuad::LOW_SHELF) if (type == BiQuad::LOW_SHELF)
biquadFreq *= centerFreqFactor; biquadFreq *= centerFreqFactor;
else else
@@ -56,7 +64,7 @@ vector<wstring> BiQuadFilter::initialize(float sampleRate, unsigned maxFrameCoun
for (unsigned i = 0; i < channelCount; i++) for (unsigned i = 0; i < channelCount; i++)
{ {
new(biquads + i)BiQuad(type, dbGain, biquadFreq, sampleRate, bandwidthOrQOrS, isBandwidth); new(biquads + i)BiQuad(type, dbGain, biquadFreq, sampleRate, bandwidthOrQOrS, isBandwidthOrS);
} }
return channelNames; return channelNames;
@@ -100,9 +108,9 @@ double BiQuadFilter::getBandwidthOrQOrS() const
return bandwidthOrQOrS; return bandwidthOrQOrS;
} }
bool BiQuadFilter::getIsBandwidth() const bool BiQuadFilter::getIsBandwidthOrS() const
{ {
return isBandwidth; return isBandwidthOrS;
} }
bool BiQuadFilter::getIsCornerFreq() const bool BiQuadFilter::getIsCornerFreq() const
+5 -5
View File
@@ -26,9 +26,9 @@
class BiQuadFilter : public IFilter class BiQuadFilter : public IFilter
{ {
public: public:
BiQuadFilter(BiQuad::Type type, double dbGain, double freq, double bandwidthOrQOrS, bool isBandwidth, bool isCornerFreq); BiQuadFilter(BiQuad::Type type, double dbGain, double freq, double bandwidthOrQOrS, bool isBandwidthOrS, bool isCornerFreq);
virtual ~BiQuadFilter(); virtual~BiQuadFilter();
bool getInPlace() override {return true;} bool getInPlace() override{return true;}
std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames) override; std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames) override;
void process(float** output, float** input, unsigned frameCount) override; void process(float** output, float** input, unsigned frameCount) override;
@@ -36,7 +36,7 @@ public:
double getDbGain() const; double getDbGain() const;
double getFreq() const; double getFreq() const;
double getBandwidthOrQOrS() const; double getBandwidthOrQOrS() const;
bool getIsBandwidth() const; bool getIsBandwidthOrS() const;
bool getIsCornerFreq() const; bool getIsCornerFreq() const;
private: private:
@@ -44,7 +44,7 @@ private:
double dbGain; double dbGain;
double freq; double freq;
double bandwidthOrQOrS; double bandwidthOrQOrS;
bool isBandwidth; bool isBandwidthOrS;
bool isCornerFreq; bool isCornerFreq;
size_t channelCount; size_t channelCount;
+11 -13
View File
@@ -93,7 +93,7 @@ vector<IFilter*> BiQuadFilterFactory::createFilter(const wstring& configPath, ws
double freq = 0; double freq = 0;
double gain = 0; double gain = 0;
double bandwidthOrQOrS = 0; double bandwidthOrQOrS = 0;
bool isBandwidth = false; bool isBandwidthOrS = false;
bool isCornerFreq = false; bool isCornerFreq = false;
bool error = false; bool error = false;
@@ -134,14 +134,9 @@ vector<IFilter*> BiQuadFilterFactory::createFilter(const wstring& configPath, ws
found = regex_search(parameters, match, regexQ); found = regex_search(parameters, match, regexQ);
if (found) if (found)
{ {
if (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) wstring qString = match.str(1);
TraceF(L"Ignoring Q for filter of type %s", typeDescription.c_str()); bandwidthOrQOrS = wcstod(qString.c_str(), NULL);
else stream << " and Q " << bandwidthOrQOrS;
{
wstring qString = match.str(1);
bandwidthOrQOrS = wcstod(qString.c_str(), NULL);
stream << " and Q " << bandwidthOrQOrS;
}
} }
found = regex_search(parameters, match, regexBW); found = regex_search(parameters, match, regexBW);
@@ -153,7 +148,7 @@ vector<IFilter*> BiQuadFilterFactory::createFilter(const wstring& configPath, ws
{ {
wstring bwString = match.str(1); wstring bwString = match.str(1);
bandwidthOrQOrS = wcstod(bwString.c_str(), NULL); bandwidthOrQOrS = wcstod(bwString.c_str(), NULL);
isBandwidth = true; isBandwidthOrS = true;
stream << " and bandwidth " << bandwidthOrQOrS << " octaves"; stream << " and bandwidth " << bandwidthOrQOrS << " octaves";
} }
} }
@@ -167,6 +162,7 @@ vector<IFilter*> BiQuadFilterFactory::createFilter(const wstring& configPath, ws
{ {
wstring slopeString = match.str(1); wstring slopeString = match.str(1);
bandwidthOrQOrS = wcstod(slopeString.c_str(), NULL); bandwidthOrQOrS = wcstod(slopeString.c_str(), NULL);
isBandwidthOrS = true;
stream << " and slope " << bandwidthOrQOrS << " dB"; stream << " and slope " << bandwidthOrQOrS << " dB";
} }
} }
@@ -185,6 +181,7 @@ vector<IFilter*> BiQuadFilterFactory::createFilter(const wstring& configPath, ws
else if (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) else if (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
{ {
bandwidthOrQOrS = 0.9; // found out by experimentation with RoomEQWizard bandwidthOrQOrS = 0.9; // found out by experimentation with RoomEQWizard
isBandwidthOrS = true;
} }
else if (type == BiQuad::NOTCH) else if (type == BiQuad::NOTCH)
{ {
@@ -193,8 +190,9 @@ vector<IFilter*> BiQuadFilterFactory::createFilter(const wstring& configPath, ws
} }
else if (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) else if (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
{ {
// Maximum S is 1 for 12 dB if (isBandwidthOrS)
bandwidthOrQOrS /= 12.0; // Maximum S is 1 for 12 dB
bandwidthOrQOrS /= 12.0;
if (typeString[typeString.length() - 1] != L'C') if (typeString[typeString.length() - 1] != L'C')
isCornerFreq = true; isCornerFreq = true;
} }
@@ -204,7 +202,7 @@ vector<IFilter*> BiQuadFilterFactory::createFilter(const wstring& configPath, ws
TraceF(L"%s", stream.str().c_str()); TraceF(L"%s", stream.str().c_str());
void* mem = MemoryHelper::alloc(sizeof(BiQuadFilter)); void* mem = MemoryHelper::alloc(sizeof(BiQuadFilter));
filter = new(mem) BiQuadFilter(type, gain, freq, bandwidthOrQOrS, isBandwidth, isCornerFreq); filter = new(mem) BiQuadFilter(type, gain, freq, bandwidthOrQOrS, isBandwidthOrS, isCornerFreq);
} }
} }
else if (typeString != L"None") else if (typeString != L"None")