diff --git a/Editor/guis/BiQuadFilterGUI.cpp b/Editor/guis/BiQuadFilterGUI.cpp index 80f15b4..1f24a80 100644 --- a/Editor/guis/BiQuadFilterGUI.cpp +++ b/Editor/guis/BiQuadFilterGUI.cpp @@ -61,13 +61,13 @@ BiQuadFilterGUI::BiQuadFilterGUI(BiQuadFilter* filter) ui->freqSpinBox->setValue(filter->getFreq()); 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) ui->qComboBox->setCurrentIndex(filter->getBandwidthOrQOrS() == M_SQRT1_2 ? 0 : 1); - else if ((type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) && !filter->getIsCornerFreq()) - ui->qComboBox->setCurrentIndex(filter->getBandwidthOrQOrS() == 0.9 ? 0 : 1); + else if ((type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)) + 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); else ui->qSpinBox->setValue(filter->getBandwidthOrQOrS()); @@ -109,13 +109,13 @@ void BiQuadFilterGUI::store(QString& command, QString& parameters) parameters += "BP"; break; case BiQuad::LOW_SHELF: - if (freqMode == 'E' && mode == 'S') + if (freqMode == 'E' && mode != 'F') parameters += "LSC"; else parameters += "LS"; break; case BiQuad::HIGH_SHELF: - if (freqMode == 'E' && mode == 'S') + if (freqMode == 'E' && mode != 'F') parameters += "HSC"; else parameters += "HS"; @@ -216,12 +216,12 @@ void BiQuadFilterGUI::on_typeComboBox_currentIndexChanged(int index) ui->qComboBox->addItem(tr("Fixed Q"), 'F'); else if ((type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) && freqMode == 'E') 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'); if (type == BiQuad::PEAKING) 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); int qIndex = ui->qComboBox->findData(mode); if (qIndex != -1 && sameTypeCategory) @@ -257,6 +257,7 @@ void BiQuadFilterGUI::on_freqComboBox_currentIndexChanged(int index) if (freqMode == 'E') ui->qComboBox->addItem(tr("Fixed S"), 'F'); ui->qComboBox->addItem(tr("Slope"), 'S'); + ui->qComboBox->addItem(tr("Q factor"), 'Q'); ui->qComboBox->setEnabled(ui->qComboBox->count() > 1); int qIndex = ui->qComboBox->findData(mode); if (qIndex != -1) @@ -265,7 +266,16 @@ void BiQuadFilterGUI::on_freqComboBox_currentIndexChanged(int index) 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(); if ((freqMode == 'E') == (type == BiQuad::LOW_SHELF)) freq *= centerFreqFactor; @@ -297,25 +307,49 @@ void BiQuadFilterGUI::on_qComboBox_currentIndexChanged(int index) ui->qSpinBox->setValue(0.9); else if (type == BiQuad::NOTCH) 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(); - double p2n = pow(2.0, n); - double q = sqrt(p2n) / (p2n - 1.0); + BiQuad::Type type = (BiQuad::Type)ui->typeComboBox->currentData().toInt(); + double q; + 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); - qIsBw = false; + qIsBwOrS = false; } - else if (!qIsBw && mode == 'B') + else if (!qIsBwOrS && mode == 'B') { double q = ui->qSpinBox->value(); double n = 2.0 / M_LN2 * asinh(1.0 / (2.0 * q)); 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') { ui->qSpinBox->setValue(12.0); + qIsBwOrS = true; } emit updateModel(); diff --git a/Editor/guis/BiQuadFilterGUI.h b/Editor/guis/BiQuadFilterGUI.h index 2549616..2d2821b 100644 --- a/Editor/guis/BiQuadFilterGUI.h +++ b/Editor/guis/BiQuadFilterGUI.h @@ -51,5 +51,5 @@ private: Ui::BiQuadFilterGUI* ui; BiQuad::Type previousType = BiQuad::PEAKING; - bool qIsBw = false; + bool qIsBwOrS = false; }; diff --git a/filters/BiQuad.cpp b/filters/BiQuad.cpp index cda15d3..4b899ef 100644 --- a/filters/BiQuad.cpp +++ b/filters/BiQuad.cpp @@ -22,7 +22,7 @@ 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; 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 cs = cos(omega); double alpha; - double beta = -1; - if (type == LOW_SHELF || type == HIGH_SHELF) // S - { - 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 + if (!isBandwidthOrS) // Q 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; diff --git a/filters/BiQuad.h b/filters/BiQuad.h index e6a208a..28fb329 100644 --- a/filters/BiQuad.h +++ b/filters/BiQuad.h @@ -35,7 +35,7 @@ public: }; 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 void removeDenormals() diff --git a/filters/BiQuadFilter.cpp b/filters/BiQuadFilter.cpp index 1711b3a..9fab4b0 100644 --- a/filters/BiQuadFilter.cpp +++ b/filters/BiQuadFilter.cpp @@ -23,8 +23,8 @@ using namespace std; -BiQuadFilter::BiQuadFilter(BiQuad::Type type, double dbGain, double freq, double bandwidthOrQOrS, bool isBandwidth, bool isCornerFreq) - : type(type), dbGain(dbGain), freq(freq), bandwidthOrQOrS(bandwidthOrQOrS), isBandwidth(isBandwidth), isCornerFreq(isCornerFreq) +BiQuadFilter::BiQuadFilter(BiQuad::Type type, double dbGain, double freq, double bandwidthOrQOrS, bool isBandwidthOrS, bool isCornerFreq) + : type(type), dbGain(dbGain), freq(freq), bandwidthOrQOrS(bandwidthOrQOrS), isBandwidthOrS(isBandwidthOrS), isCornerFreq(isCornerFreq) { channelCount = 0; biquads = NULL; @@ -46,8 +46,16 @@ vector BiQuadFilter::initialize(float sampleRate, unsigned maxFrameCoun double biquadFreq = freq; 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 - 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) biquadFreq *= centerFreqFactor; else @@ -56,7 +64,7 @@ vector BiQuadFilter::initialize(float sampleRate, unsigned maxFrameCoun 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; @@ -100,9 +108,9 @@ double BiQuadFilter::getBandwidthOrQOrS() const return bandwidthOrQOrS; } -bool BiQuadFilter::getIsBandwidth() const +bool BiQuadFilter::getIsBandwidthOrS() const { - return isBandwidth; + return isBandwidthOrS; } bool BiQuadFilter::getIsCornerFreq() const diff --git a/filters/BiQuadFilter.h b/filters/BiQuadFilter.h index 270bf80..84b362f 100644 --- a/filters/BiQuadFilter.h +++ b/filters/BiQuadFilter.h @@ -26,9 +26,9 @@ class BiQuadFilter : public IFilter { public: - BiQuadFilter(BiQuad::Type type, double dbGain, double freq, double bandwidthOrQOrS, bool isBandwidth, bool isCornerFreq); - virtual ~BiQuadFilter(); - bool getInPlace() override {return true;} + BiQuadFilter(BiQuad::Type type, double dbGain, double freq, double bandwidthOrQOrS, bool isBandwidthOrS, bool isCornerFreq); + virtual~BiQuadFilter(); + bool getInPlace() override{return true;} std::vector initialize(float sampleRate, unsigned maxFrameCount, std::vector channelNames) override; void process(float** output, float** input, unsigned frameCount) override; @@ -36,7 +36,7 @@ public: double getDbGain() const; double getFreq() const; double getBandwidthOrQOrS() const; - bool getIsBandwidth() const; + bool getIsBandwidthOrS() const; bool getIsCornerFreq() const; private: @@ -44,7 +44,7 @@ private: double dbGain; double freq; double bandwidthOrQOrS; - bool isBandwidth; + bool isBandwidthOrS; bool isCornerFreq; size_t channelCount; diff --git a/filters/BiQuadFilterFactory.cpp b/filters/BiQuadFilterFactory.cpp index 4effc9a..2ab3659 100644 --- a/filters/BiQuadFilterFactory.cpp +++ b/filters/BiQuadFilterFactory.cpp @@ -93,7 +93,7 @@ vector BiQuadFilterFactory::createFilter(const wstring& configPath, ws double freq = 0; double gain = 0; double bandwidthOrQOrS = 0; - bool isBandwidth = false; + bool isBandwidthOrS = false; bool isCornerFreq = false; bool error = false; @@ -134,14 +134,9 @@ vector BiQuadFilterFactory::createFilter(const wstring& configPath, ws found = regex_search(parameters, match, regexQ); if (found) { - if (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) - TraceF(L"Ignoring Q for filter of type %s", typeDescription.c_str()); - else - { - wstring qString = match.str(1); - bandwidthOrQOrS = wcstod(qString.c_str(), NULL); - 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); @@ -153,7 +148,7 @@ vector BiQuadFilterFactory::createFilter(const wstring& configPath, ws { wstring bwString = match.str(1); bandwidthOrQOrS = wcstod(bwString.c_str(), NULL); - isBandwidth = true; + isBandwidthOrS = true; stream << " and bandwidth " << bandwidthOrQOrS << " octaves"; } } @@ -167,6 +162,7 @@ vector BiQuadFilterFactory::createFilter(const wstring& configPath, ws { wstring slopeString = match.str(1); bandwidthOrQOrS = wcstod(slopeString.c_str(), NULL); + isBandwidthOrS = true; stream << " and slope " << bandwidthOrQOrS << " dB"; } } @@ -185,6 +181,7 @@ vector BiQuadFilterFactory::createFilter(const wstring& configPath, ws else if (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) { bandwidthOrQOrS = 0.9; // found out by experimentation with RoomEQWizard + isBandwidthOrS = true; } else if (type == BiQuad::NOTCH) { @@ -193,8 +190,9 @@ vector BiQuadFilterFactory::createFilter(const wstring& configPath, ws } else if (type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF) { - // Maximum S is 1 for 12 dB - bandwidthOrQOrS /= 12.0; + if (isBandwidthOrS) + // Maximum S is 1 for 12 dB + bandwidthOrQOrS /= 12.0; if (typeString[typeString.length() - 1] != L'C') isCornerFreq = true; } @@ -204,7 +202,7 @@ vector BiQuadFilterFactory::createFilter(const wstring& configPath, ws TraceF(L"%s", stream.str().c_str()); 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")