Added: All remaining filter types (LP(Q), HP(Q), LS(6/12dB), HS(6/12dB), NO, AP) of RoomEQWizard's "Generic" equalizer. Syntax is compatible to REW's filter text file, of course.
This commit is contained in:
1 parent
3dab99a85a
commit
e2d5e64f21
7 files changed
+397
-91
No files matched your search
@@ -149,6 +149,7 @@
|
|||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\BiQuad.cpp" />
|
||||||
<ClCompile Include="..\LogHelper.cpp" />
|
<ClCompile Include="..\LogHelper.cpp" />
|
||||||
<ClCompile Include="..\ParametricEQ.cpp" />
|
<ClCompile Include="..\ParametricEQ.cpp" />
|
||||||
<ClCompile Include="..\RegistryHelper.cpp" />
|
<ClCompile Include="..\RegistryHelper.cpp" />
|
||||||
@@ -156,6 +157,7 @@
|
|||||||
<ClCompile Include="Benchmark.cpp" />
|
<ClCompile Include="Benchmark.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\BiQuad.h" />
|
||||||
<ClInclude Include="..\LogHelper.h" />
|
<ClInclude Include="..\LogHelper.h" />
|
||||||
<ClInclude Include="..\ParametricEQ.h" />
|
<ClInclude Include="..\ParametricEQ.h" />
|
||||||
<ClInclude Include="..\RegistryHelper.h" />
|
<ClInclude Include="..\RegistryHelper.h" />
|
||||||
|
|||||||
+130
@@ -0,0 +1,130 @@
|
|||||||
|
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
#include <cmath>
|
||||||
|
#include <string>
|
||||||
|
#include "BiQuad.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
BiQuad::BiQuad(Type type, float dbGain, float freq, float srate, float bandwidthOrQOrS, bool isBandwidth)
|
||||||
|
{
|
||||||
|
float A;
|
||||||
|
if(type == PEAKING || type == LOW_SHELF || type == HIGH_SHELF)
|
||||||
|
A = pow(10, dbGain / 40);
|
||||||
|
else
|
||||||
|
A = pow(10, dbGain / 20);
|
||||||
|
float omega = 2 * (float)M_PI * freq / srate;
|
||||||
|
float sn = sin(omega);
|
||||||
|
float cs = cos(omega);
|
||||||
|
float alpha;
|
||||||
|
float 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((float)M_LN2/2 * bandwidthOrQOrS * omega / sn);
|
||||||
|
else // Q
|
||||||
|
alpha = sn / (2 * bandwidthOrQOrS);
|
||||||
|
|
||||||
|
float b0, b1, b2, a0, a1, a2;
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case LOW_PASS:
|
||||||
|
b0 = (1 - cs) /2;
|
||||||
|
b1 = 1 - cs;
|
||||||
|
b2 = (1 - cs) /2;
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
a1 = -2 * cs;
|
||||||
|
a2 = 1 - alpha;
|
||||||
|
break;
|
||||||
|
case HIGH_PASS:
|
||||||
|
b0 = (1 + cs) /2;
|
||||||
|
b1 = -(1 + cs);
|
||||||
|
b2 = (1 + cs) /2;
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
a1 = -2 * cs;
|
||||||
|
a2 = 1 - alpha;
|
||||||
|
break;
|
||||||
|
case BAND_PASS:
|
||||||
|
b0 = alpha;
|
||||||
|
b1 = 0;
|
||||||
|
b2 = -alpha;
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
a1 = -2 * cs;
|
||||||
|
a2 = 1 - alpha;
|
||||||
|
break;
|
||||||
|
case NOTCH:
|
||||||
|
b0 = 1;
|
||||||
|
b1 = -2 * cs;
|
||||||
|
b2 = 1;
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
a1 = -2 * cs;
|
||||||
|
a2 = 1 - alpha;
|
||||||
|
break;
|
||||||
|
case ALL_PASS:
|
||||||
|
b0 = 1 - alpha;
|
||||||
|
b1 = -2 * cs;
|
||||||
|
b2 = 1 + alpha;
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
a1 = -2 * cs;
|
||||||
|
a2 = 1 - alpha;
|
||||||
|
break;
|
||||||
|
case PEAKING:
|
||||||
|
b0 = 1 + (alpha * A);
|
||||||
|
b1 = -2 * cs;
|
||||||
|
b2 = 1 - (alpha * A);
|
||||||
|
a0 = 1 + (alpha / A);
|
||||||
|
a1 = -2 * cs;
|
||||||
|
a2 = 1 - (alpha / A);
|
||||||
|
break;
|
||||||
|
case LOW_SHELF:
|
||||||
|
b0 = A * ((A + 1) - (A - 1) * cs + beta);
|
||||||
|
b1 = 2 * A * ((A - 1) - (A + 1) * cs);
|
||||||
|
b2 = A * ((A + 1) - (A - 1) * cs - beta);
|
||||||
|
a0 = (A + 1) + (A - 1) * cs + beta;
|
||||||
|
a1 = -2 * ((A - 1) + (A + 1) * cs);
|
||||||
|
a2 = (A + 1) + (A - 1) * cs - beta;
|
||||||
|
break;
|
||||||
|
case HIGH_SHELF:
|
||||||
|
b0 = A * ((A + 1) + (A - 1) * cs + beta);
|
||||||
|
b1 = -2 * A * ((A - 1) + (A + 1) * cs);
|
||||||
|
b2 = A * ((A + 1) + (A - 1) * cs - beta);
|
||||||
|
a0 = (A + 1) - (A - 1) * cs + beta;
|
||||||
|
a1 = 2 * ((A - 1) - (A + 1) * cs);
|
||||||
|
a2 = (A + 1) - (A - 1) * cs - beta;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->a0 = b0 /a0;
|
||||||
|
this->a[0] = b1 /a0;
|
||||||
|
this->a[1] = b2 /a0;
|
||||||
|
this->a[2] = -a1 /a0;
|
||||||
|
this->a[3] = -a2 /a0;
|
||||||
|
|
||||||
|
x1 = 0;
|
||||||
|
x2 = 0;
|
||||||
|
y1 = 0;
|
||||||
|
y2 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BiQuad::gainAt(float freq, float srate)
|
||||||
|
{
|
||||||
|
float omega = 2 * (float)M_PI * freq / srate;
|
||||||
|
float sn = sin(omega/2.0f);
|
||||||
|
float phi = sn * sn;
|
||||||
|
float b0 = this->a0;
|
||||||
|
float b1 = this->a[0];
|
||||||
|
float b2 = this->a[1];
|
||||||
|
float a0 = 1.0f;
|
||||||
|
float a1 = -this->a[2];
|
||||||
|
float a2 = -this->a[3];
|
||||||
|
|
||||||
|
float dbGain = 10*log10( pow(b0+b1+b2, 2) - 4*(b0*b1 + 4*b0*b2 + b1*b2)*phi + 16*b0*b2*phi*phi )
|
||||||
|
-10*log10( pow(a0+a1+a2, 2) - 4*(a0*a1 + 4*a0*a2 + a1*a2)*phi + 16*a0*a2*phi*phi );
|
||||||
|
|
||||||
|
return dbGain;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
This file is part of EqualizerAPO, a system-wide equalizer.
|
||||||
|
Copyright (C) 2013 Jonas Thedering
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define IS_DENORMAL(f) (((*(unsigned int *)&(f))&0x7f800000) == 0)
|
||||||
|
|
||||||
|
class BiQuad
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
LOW_PASS, HIGH_PASS, BAND_PASS, NOTCH, ALL_PASS, PEAKING, LOW_SHELF, HIGH_SHELF
|
||||||
|
};
|
||||||
|
|
||||||
|
BiQuad() {}
|
||||||
|
BiQuad(Type type, float dbGain, float freq, float srate, float bandwidthOrQOrS, bool isBandwidth);
|
||||||
|
|
||||||
|
__forceinline
|
||||||
|
void removeDenormals()
|
||||||
|
{
|
||||||
|
if(IS_DENORMAL(x1))
|
||||||
|
x1 = 0.0f;
|
||||||
|
if(IS_DENORMAL(x2))
|
||||||
|
x2 = 0.0f;
|
||||||
|
if(IS_DENORMAL(y1))
|
||||||
|
y1 = 0.0f;
|
||||||
|
if(IS_DENORMAL(y2))
|
||||||
|
y2 = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline
|
||||||
|
float process(float sample)
|
||||||
|
{
|
||||||
|
float result = a0 * sample + a[0] * x1 + a[1] * x2 +
|
||||||
|
a[2] * y1 + a[3] * y2;
|
||||||
|
|
||||||
|
x2 = x1;
|
||||||
|
x1 = sample;
|
||||||
|
|
||||||
|
y2 = y1;
|
||||||
|
y1 = result;
|
||||||
|
|
||||||
|
//Input for next stage
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float gainAt(float freq, float srate);
|
||||||
|
|
||||||
|
private:
|
||||||
|
__declspec(align(16)) float a[4];
|
||||||
|
float a0;
|
||||||
|
|
||||||
|
float x1, x2;
|
||||||
|
float y1, y2;
|
||||||
|
};
|
||||||
@@ -157,6 +157,7 @@
|
|||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="BiQuad.h" />
|
||||||
<ClInclude Include="ClassFactory.h" />
|
<ClInclude Include="ClassFactory.h" />
|
||||||
<ClInclude Include="DeviceAPOInfo.h" />
|
<ClInclude Include="DeviceAPOInfo.h" />
|
||||||
<ClInclude Include="EqualizerAPO.h" />
|
<ClInclude Include="EqualizerAPO.h" />
|
||||||
@@ -168,6 +169,7 @@
|
|||||||
<ClInclude Include="version.h" />
|
<ClInclude Include="version.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="BiQuad.cpp" />
|
||||||
<ClCompile Include="ClassFactory.cpp" />
|
<ClCompile Include="ClassFactory.cpp" />
|
||||||
<ClCompile Include="DeviceAPOInfo.cpp" />
|
<ClCompile Include="DeviceAPOInfo.cpp" />
|
||||||
<ClCompile Include="DllMain.cpp" />
|
<ClCompile Include="DllMain.cpp" />
|
||||||
|
|||||||
+4
-4
@@ -22,10 +22,10 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#define TraceF(format, ...) LogHelper::log(__FILE__, __LINE__, this, true, format, __VA_ARGS__);
|
#define TraceF(format, ...) LogHelper::log(__FILE__, __LINE__, this, true, format, __VA_ARGS__)
|
||||||
#define TraceFStatic(format, ...) LogHelper::log(__FILE__, __LINE__, NULL, true, format, __VA_ARGS__);
|
#define TraceFStatic(format, ...) LogHelper::log(__FILE__, __LINE__, NULL, true, format, __VA_ARGS__)
|
||||||
#define LogF(format, ...) LogHelper::log(__FILE__, __LINE__, this, false, format, __VA_ARGS__);
|
#define LogF(format, ...) LogHelper::log(__FILE__, __LINE__, this, false, format, __VA_ARGS__)
|
||||||
#define LogFStatic(format, ...) LogHelper::log(__FILE__, __LINE__, NULL, false, format, __VA_ARGS__);
|
#define LogFStatic(format, ...) LogHelper::log(__FILE__, __LINE__, NULL, false, format, __VA_ARGS__)
|
||||||
|
|
||||||
class LogHelper
|
class LogHelper
|
||||||
{
|
{
|
||||||
|
|||||||
+184
-45
@@ -23,6 +23,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <regex>
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <Shlwapi.h>
|
#include <Shlwapi.h>
|
||||||
@@ -37,30 +38,12 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace stdext;
|
using namespace stdext;
|
||||||
|
|
||||||
BiQuad::BiQuad(float dbGain, float freq, float srate, float bandwidthOrQ, bool isQ)
|
static wregex regexType(L"^\\s*ON\\s+([A-Za-z]+)");
|
||||||
{
|
static wregex regexFreq(L"\\s+Fc\\s*([0-9.]+)\\s*H\\s*z");
|
||||||
float A = pow(10, dbGain / 40);
|
static wregex regexGain(L"\\s+Gain\\s*([-+0-9.]+)\\s*dB");
|
||||||
float omega = 2 * (float)M_PI * freq / srate;
|
static wregex regexQ(L"\\s+Q\\s*([0-9.]+)");
|
||||||
float sn = sin(omega);
|
static wregex regexBW(L"\\s+BW\\s+Oct\\s*([0-9.]+)");
|
||||||
float cs = cos(omega);
|
static wregex regexSlope(L"^\\s*([0-9.]+)\\s*dB");
|
||||||
float alpha;
|
|
||||||
if(isQ)
|
|
||||||
alpha = sn / (2 * bandwidthOrQ);
|
|
||||||
else
|
|
||||||
alpha = sn * sinh((float)M_LN2/2 * bandwidthOrQ * omega / sn);
|
|
||||||
|
|
||||||
float temp = 1 + (alpha /A);
|
|
||||||
a0 = (1 + (alpha * A)) / temp;
|
|
||||||
a[0] = (-2 * cs) / temp;
|
|
||||||
a[1] = (1 - (alpha * A)) / temp;
|
|
||||||
a[2] = - (-2 * cs) / temp;
|
|
||||||
a[3] = - (1 - (alpha /A)) / temp;
|
|
||||||
|
|
||||||
x1 = 0;
|
|
||||||
x2 = 0;
|
|
||||||
y1 = 0;
|
|
||||||
y2 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChannelData::ChannelData()
|
ChannelData::ChannelData()
|
||||||
{
|
{
|
||||||
@@ -87,6 +70,28 @@ ParametricEQ::ParametricEQ()
|
|||||||
|
|
||||||
for(hash_map<wstring, int>::iterator it=channelNameToPosMap.begin(); it!=channelNameToPosMap.end(); it++)
|
for(hash_map<wstring, int>::iterator it=channelNameToPosMap.begin(); it!=channelNameToPosMap.end(); it++)
|
||||||
channelPosToNameMap[it->second] = it->first;
|
channelPosToNameMap[it->second] = it->first;
|
||||||
|
|
||||||
|
filterNameToTypeMap[L"PK"] = BiQuad::PEAKING;
|
||||||
|
filterNameToTypeMap[L"PEQ"] = BiQuad::PEAKING;
|
||||||
|
filterNameToTypeMap[L"Modal"] = BiQuad::PEAKING;
|
||||||
|
filterNameToTypeMap[L"LP"] = BiQuad::LOW_PASS;
|
||||||
|
filterNameToTypeMap[L"HP"] = BiQuad::HIGH_PASS;
|
||||||
|
filterNameToTypeMap[L"LPQ"] = BiQuad::LOW_PASS;
|
||||||
|
filterNameToTypeMap[L"HPQ"] = BiQuad::HIGH_PASS;
|
||||||
|
filterNameToTypeMap[L"BP"] = BiQuad::BAND_PASS;
|
||||||
|
filterNameToTypeMap[L"LS"] = BiQuad::LOW_SHELF;
|
||||||
|
filterNameToTypeMap[L"HS"] = BiQuad::HIGH_SHELF;
|
||||||
|
filterNameToTypeMap[L"NO"] = BiQuad::NOTCH;
|
||||||
|
filterNameToTypeMap[L"AP"] = BiQuad::ALL_PASS;
|
||||||
|
|
||||||
|
filterTypeToDescriptionMap[BiQuad::PEAKING] = L"peaking";
|
||||||
|
filterTypeToDescriptionMap[BiQuad::LOW_PASS] = L"low-pass";
|
||||||
|
filterTypeToDescriptionMap[BiQuad::HIGH_PASS] = L"high-pass";
|
||||||
|
filterTypeToDescriptionMap[BiQuad::BAND_PASS] = L"band-pass";
|
||||||
|
filterTypeToDescriptionMap[BiQuad::LOW_SHELF] = L"low-shelf";
|
||||||
|
filterTypeToDescriptionMap[BiQuad::HIGH_SHELF] = L"high-shelf";
|
||||||
|
filterTypeToDescriptionMap[BiQuad::NOTCH] = L"notch";
|
||||||
|
filterTypeToDescriptionMap[BiQuad::ALL_PASS] = L"all-pass";
|
||||||
}
|
}
|
||||||
|
|
||||||
ParametricEQ::~ParametricEQ()
|
ParametricEQ::~ParametricEQ()
|
||||||
@@ -211,7 +216,26 @@ void ParametricEQ::loadConfig()
|
|||||||
loadFilterCount += channelData[c].loadFilterCount;
|
loadFilterCount += channelData[c].loadFilterCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceF(L"%d filters loaded", loadFilterCount);
|
wstringstream channelFilterCounts;
|
||||||
|
unsigned c=0;
|
||||||
|
for(int i=0; i<31; i++)
|
||||||
|
{
|
||||||
|
int channelPos = 1<<i;
|
||||||
|
if(channelMask & channelPos)
|
||||||
|
{
|
||||||
|
c++;
|
||||||
|
if(channelFilterCounts.tellp() > 0)
|
||||||
|
channelFilterCounts << L" ";
|
||||||
|
if(channelPosToNameMap.find(channelPos) != channelPosToNameMap.end())
|
||||||
|
channelFilterCounts << channelPosToNameMap[channelPos];
|
||||||
|
else
|
||||||
|
channelFilterCounts << c;
|
||||||
|
|
||||||
|
channelFilterCounts << ":" << channelData[c-1].loadFilterCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceF(L"%d filters loaded: %s", loadFilterCount, channelFilterCounts.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParametricEQ::loadConfig(const wstring& path, vector<bool> selectedChannels)
|
void ParametricEQ::loadConfig(const wstring& path, vector<bool> selectedChannels)
|
||||||
@@ -373,35 +397,150 @@ void ParametricEQ::loadConfig(const wstring& path, vector<bool> selectedChannels
|
|||||||
//Conversion to period as decimal mark, if needed
|
//Conversion to period as decimal mark, if needed
|
||||||
value = StringHelper::replaceCharacters(value, L",", L'.');
|
value = StringHelper::replaceCharacters(value, L",", L'.');
|
||||||
|
|
||||||
wchar_t freqString[10];
|
wsmatch match;
|
||||||
float freq, gain, bandwidth;
|
wstring typeString;
|
||||||
|
|
||||||
int matched = swscanf_s(value.c_str(), L" ON PEQ Fc %9s Hz Gain %f dB BW Oct %f", &freqString, 10, &gain, &bandwidth);
|
bool found = regex_search(value, match, regexType);
|
||||||
if(matched == 3 && (freq = getFreq(freqString)) != -1.0f)
|
if(found)
|
||||||
{
|
{
|
||||||
for(unsigned c=0; c<channelCount; c++)
|
typeString = match.str(1);
|
||||||
|
if(filterNameToTypeMap.find(typeString) != filterNameToTypeMap.end())
|
||||||
{
|
{
|
||||||
if(selectedChannels[c] && channelData[c].loadFilterCount < (sizeof(channelData[c].filters)/sizeof(BiQuad)))
|
BiQuad::Type type = filterNameToTypeMap[typeString];
|
||||||
|
wstring typeDescription = filterTypeToDescriptionMap[type];
|
||||||
|
value = match.suffix().str();
|
||||||
|
|
||||||
|
wstringstream stream;
|
||||||
|
stream << L"Adding " << typeDescription << L" filter";
|
||||||
|
|
||||||
|
float freq = 0;
|
||||||
|
float gain = 0;
|
||||||
|
float bandwidthOrQOrS = 0;
|
||||||
|
bool isBandwidth = false;
|
||||||
|
bool error = false;
|
||||||
|
|
||||||
|
found = regex_search(value, match, regexFreq);
|
||||||
|
if(found)
|
||||||
{
|
{
|
||||||
channelData[c].filters[channelData[c].loadFilterCount++] = BiQuad(gain, freq, sampleRate, bandwidth, false);
|
wstring freqString = match.str(1);
|
||||||
|
freq = getFreq(freqString);
|
||||||
|
stream << " with center frequency " << freq << " Hz";
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
TraceF(L"Adding filter with center frequency %g Hz, gain %g dB and bandwidth %g octaves", freq, gain, bandwidth);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float q;
|
|
||||||
matched = swscanf_s(value.c_str(), L" ON PK Fc %9s Hz Gain %f dB Q %f", &freqString, 10, &gain, &q);
|
|
||||||
if(matched == 3 && (freq = getFreq(freqString)) != -1.0f)
|
|
||||||
{
|
|
||||||
for(unsigned c=0; c<channelCount; c++)
|
|
||||||
{
|
{
|
||||||
if(selectedChannels[c] && channelData[c].loadFilterCount < (sizeof(channelData[c].filters)/sizeof(BiQuad)))
|
LogF(L"No frequency given in filter string %s%s", typeString, value);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = regex_search(value, match, regexGain);
|
||||||
|
if(found)
|
||||||
|
{
|
||||||
|
if(type == BiQuad::LOW_PASS || type == BiQuad::HIGH_PASS || type == BiQuad::NOTCH || type == BiQuad::ALL_PASS)
|
||||||
|
TraceF(L"Ignoring gain for filter of type %s", typeDescription);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
channelData[c].filters[channelData[c].loadFilterCount++] = BiQuad(gain, freq, sampleRate, q, true);
|
wstring gainString = match.str(1);
|
||||||
|
gain = (float)wcstod(gainString.c_str(), NULL);
|
||||||
|
if(type == BiQuad::PEAKING)
|
||||||
|
stream << ", gain " << gain << " dB";
|
||||||
|
else
|
||||||
|
stream << " and gain " << gain << " dB";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TraceF(L"Adding filter with center frequency %g Hz, gain %g dB and Q %g", freq, gain, q);
|
else if(type == BiQuad::PEAKING || type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
|
||||||
|
{
|
||||||
|
LogF(L"No gain given in filter string %s%s", typeString, value);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = regex_search(value, match, regexQ);
|
||||||
|
if(found)
|
||||||
|
{
|
||||||
|
if(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
|
||||||
|
TraceF(L"Ignoring Q for filter of type %s", typeDescription);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wstring qString = match.str(1);
|
||||||
|
bandwidthOrQOrS = (float)wcstod(qString.c_str(), NULL);
|
||||||
|
stream << " and Q " << bandwidthOrQOrS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
found = regex_search(value, match, regexBW);
|
||||||
|
if(found)
|
||||||
|
{
|
||||||
|
if(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
|
||||||
|
TraceF(L"Ignoring bandwidth for filter of type %s", typeDescription);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wstring bwString = match.str(1);
|
||||||
|
bandwidthOrQOrS = (float)wcstod(bwString.c_str(), NULL);
|
||||||
|
isBandwidth = true;
|
||||||
|
stream << " and bandwidth " << bandwidthOrQOrS << " octaves";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
found = regex_search(value, match, regexSlope);
|
||||||
|
if(found)
|
||||||
|
{
|
||||||
|
if(!(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF))
|
||||||
|
TraceF(L"Ignoring slope for filter of type %s", typeDescription);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wstring slopeString = match.str(1);
|
||||||
|
bandwidthOrQOrS = (float)wcstod(slopeString.c_str(), NULL);
|
||||||
|
stream << " and slope " << bandwidthOrQOrS << " dB";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bandwidthOrQOrS == 0)
|
||||||
|
{
|
||||||
|
if(type == BiQuad::PEAKING || type == BiQuad::ALL_PASS)
|
||||||
|
{
|
||||||
|
LogF(L"No Q or bandwidth given in filter string %s%s", typeString, value);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
else if(type == BiQuad::LOW_PASS || type == BiQuad::HIGH_PASS || type == BiQuad::BAND_PASS)
|
||||||
|
{
|
||||||
|
bandwidthOrQOrS = (float)M_SQRT1_2;
|
||||||
|
}
|
||||||
|
else if(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
|
||||||
|
{
|
||||||
|
bandwidthOrQOrS = 0.9f; // found out by experimentation with RoomEQWizard
|
||||||
|
}
|
||||||
|
else if(type == BiQuad::NOTCH)
|
||||||
|
{
|
||||||
|
bandwidthOrQOrS = 31.0f; // only roughly matches RoomEQWizard's notch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
|
||||||
|
{
|
||||||
|
// Maximum S is 1 for 12 dB
|
||||||
|
bandwidthOrQOrS /= 12.0f;
|
||||||
|
// frequency adjustment for DCX2496
|
||||||
|
float centerFreqFactor = pow(10.0f, abs(gain) / 80.0f / bandwidthOrQOrS);
|
||||||
|
if(type == BiQuad::LOW_SHELF)
|
||||||
|
freq *= centerFreqFactor;
|
||||||
|
else
|
||||||
|
freq /= centerFreqFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!error)
|
||||||
|
{
|
||||||
|
TraceF(L"%s", stream.str().c_str());
|
||||||
|
|
||||||
|
for(unsigned c=0; c<channelCount; c++)
|
||||||
|
{
|
||||||
|
if(selectedChannels[c] && channelData[c].loadFilterCount < (sizeof(channelData[c].filters)/sizeof(BiQuad)))
|
||||||
|
{
|
||||||
|
channelData[c].filters[channelData[c].loadFilterCount++] = BiQuad(type, gain, freq, sampleRate, bandwidthOrQOrS, isBandwidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(typeString != L"None")
|
||||||
|
{
|
||||||
|
LogF(L"Invalid filter type %s", typeString.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-42
@@ -23,48 +23,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <hash_map>
|
#include <hash_map>
|
||||||
|
|
||||||
#define IS_DENORMAL(f) (((*(unsigned int *)&(f))&0x7f800000) == 0)
|
#include "BiQuad.h"
|
||||||
|
|
||||||
struct BiQuad
|
|
||||||
{
|
|
||||||
BiQuad() {}
|
|
||||||
BiQuad(float dbGain, float freq, float srate, float bandwidthOrQ, bool isQ);
|
|
||||||
|
|
||||||
__forceinline
|
|
||||||
void removeDenormals()
|
|
||||||
{
|
|
||||||
if(IS_DENORMAL(x1))
|
|
||||||
x1 = 0.0f;
|
|
||||||
if(IS_DENORMAL(x2))
|
|
||||||
x2 = 0.0f;
|
|
||||||
if(IS_DENORMAL(y1))
|
|
||||||
y1 = 0.0f;
|
|
||||||
if(IS_DENORMAL(y2))
|
|
||||||
y2 = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
__forceinline
|
|
||||||
float process(float sample)
|
|
||||||
{
|
|
||||||
float result = a0 * sample + a[0] * x1 + a[1] * x2 +
|
|
||||||
a[2] * y1 + a[3] * y2;
|
|
||||||
|
|
||||||
x2 = x1;
|
|
||||||
x1 = sample;
|
|
||||||
|
|
||||||
y2 = y1;
|
|
||||||
y1 = result;
|
|
||||||
|
|
||||||
//Input for next stage
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(align(16)) float a[4];
|
|
||||||
float a0;
|
|
||||||
|
|
||||||
float x1, x2;
|
|
||||||
float y1, y2;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ChannelData
|
struct ChannelData
|
||||||
{
|
{
|
||||||
@@ -109,4 +68,6 @@ private:
|
|||||||
void* shutdownEvent;
|
void* shutdownEvent;
|
||||||
stdext::hash_map<std::wstring, int> channelNameToPosMap;
|
stdext::hash_map<std::wstring, int> channelNameToPosMap;
|
||||||
stdext::hash_map<int, std::wstring> channelPosToNameMap;
|
stdext::hash_map<int, std::wstring> channelPosToNameMap;
|
||||||
|
stdext::hash_map<std::wstring, BiQuad::Type> filterNameToTypeMap;
|
||||||
|
stdext::hash_map<BiQuad::Type, std::wstring> filterTypeToDescriptionMap;
|
||||||
};
|
};
|
||||||
Reference in new issue
Block a user