Version 0.9

Added: Filter type "IIR", which allows to specify a user-defined IIR filter of arbitrary order with custom coefficients.
Improved: For playback devices, the APO is now installed both as GFX (post-mix) and LFX (pre-mix) APO. Normally the filtering happens in GFX, but the command "Stage" allows to select LFX to apply effects based on the number of input channels.
Added: Expression language. The commands "If", "ElseIf", "Else", "EndIf", "Eval" and inline expressions allow to change the filter behaviour based on runtime conditions.
Added: Command "Copy", which copies audio data between channels.
Added: Command "Delay", which delays the audio on the currently selected channels.
Improved: Configuration files are now locked exclusively for writing while reading them.
Improved: There is now a transition (10 ms) from old to new configuration after loading.
Improved: Substantial internal restructuring to improve extensibility and maintainability. Filtering commands now work exactly in the order they were specified.
Fixed: When the microphone input was in stereo but the application requested a mono stream, the audio was heavily distorted.
Fixed: The sine sweep generated by the Benchmark application had floating-point precision issues leading to severe artifacts when certain filters were applied.
This commit is contained in:
jthedering committed 2014-08-10 18:35:59 +00:00
1 parent 11e52f6210
commit 90ee2b0aa9
89 files changed
+6396 -1375

No files matched your search

+148
View File
@@ -0,0 +1,148 @@
/*
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.
*/
#define _USE_MATH_DEFINES
#include <cmath>
#include <string>
#include "BiQuad.h"
using namespace std;
BiQuad::BiQuad(Type type, double dbGain, double freq, double srate, double bandwidthOrQOrS, bool isBandwidth)
{
double A;
if(type == PEAKING || type == LOW_SHELF || type == HIGH_SHELF)
A = pow(10, dbGain / 40);
else
A = pow(10, dbGain / 20);
double omega = 2 * M_PI * freq / srate;
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
alpha = sn / (2 * bandwidthOrQOrS);
double 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 = float(b0 / a0);
this->a[0] = float(b1 / a0);
this->a[1] = float(b2 / a0);
this->a[2] = float(a1 / a0);
this->a[3] = float(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;
}
+73
View File
@@ -0,0 +1,73 @@
/*
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.
*/
#pragma once
#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, double dbGain, double freq, double srate, double 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)
{
// changed order of additions leads to better pipelining
float result = a0 * sample + a[1] * x2 + a[0] * x1 - a[3] * y2 - a[2] * y1;
x2 = x1;
x1 = sample;
y2 = y1;
y1 = result;
return result;
}
float gainAt(float freq, float srate);
private:
__declspec(align(16)) float a[4];
float a0;
float x1, x2;
float y1, y2;
};
+69
View File
@@ -0,0 +1,69 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 "helpers/MemoryHelper.h"
#include "BiQuadFilter.h"
using namespace std;
BiQuadFilter::BiQuadFilter(BiQuad::Type type, double dbGain, double freq, double bandwidthOrQOrS, bool isBandwidth)
:type(type), dbGain(dbGain), freq(freq), bandwidthOrQOrS(bandwidthOrQOrS), isBandwidth(isBandwidth)
{
}
BiQuadFilter::~BiQuadFilter()
{
if(biquads != NULL)
{
MemoryHelper::free(biquads);
biquads = NULL;
}
}
vector<wstring> BiQuadFilter::initialize(float sampleRate, unsigned maxFrameCount, vector<wstring> channelNames)
{
this->channelCount = channelNames.size();
biquads = (BiQuad*)MemoryHelper::alloc(channelCount * sizeof(BiQuad));
for(unsigned i=0; i<channelCount; i++)
{
new (biquads + i) BiQuad(type, dbGain, freq, sampleRate, bandwidthOrQOrS, isBandwidth);
}
return channelNames;
}
#pragma AVRT_CODE_BEGIN
void BiQuadFilter::process(float** output, float** input, unsigned frameCount)
{
for(unsigned i=0; i<channelCount; i++)
{
BiQuad bq = biquads[i];
float* inputChannel = input[i];
float* outputChannel = output[i];
for(unsigned j=0; j<frameCount; j++)
outputChannel[j] = bq.process(inputChannel[j]);
bq.removeDenormals();
biquads[i] = bq;
}
}
#pragma AVRT_CODE_END
+45
View File
@@ -0,0 +1,45 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include "IFilter.h"
#include "BiQuad.h"
#pragma AVRT_VTABLES_BEGIN
class BiQuadFilter : public IFilter
{
public:
BiQuadFilter(BiQuad::Type type, double dbGain, double freq, double bandwidthOrQOrS, bool isBandwidth);
virtual ~BiQuadFilter();
virtual bool getInPlace() {return true;}
virtual std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames);
virtual void process(float** output, float** input, unsigned frameCount);
private:
BiQuad::Type type;
double dbGain;
double freq;
double bandwidthOrQOrS;
bool isBandwidth;
size_t channelCount;
BiQuad* biquads;
};
#pragma AVRT_VTABLES_END
+248
View File
@@ -0,0 +1,248 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#define _USE_MATH_DEFINES
#include <cmath>
#include <regex>
#include <sstream>
#include "helpers/MemoryHelper.h"
#include "helpers/StringHelper.h"
#include "helpers/LogHelper.h"
#include "BiQuadFilter.h"
#include "BiQuadFilterFactory.h"
using namespace std;
static wregex regexType(L"^\\s*ON\\s+([A-Za-z]+)");
static wregex regexFreq(L"\\s+Fc\\s*([-+0-9.eE\u00A0]+)\\s*H\\s*z");
static wregex regexGain(L"\\s+Gain\\s*([-+0-9.eE]+)\\s*dB");
static wregex regexQ(L"\\s+Q\\s*([-+0-9.eE]+)");
static wregex regexBW(L"\\s+BW\\s+Oct\\s*([-+0-9.eE]+)");
static wregex regexSlope(L"^\\s*([-+0-9.eE]+)\\s*dB");
BiQuadFilterFactory::BiQuadFilterFactory()
{
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"LSC"] = BiQuad::LOW_SHELF;
filterNameToTypeMap[L"HSC"] = 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";
}
vector<IFilter*> BiQuadFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
BiQuadFilter* filter = NULL;
if(command.find(L"Filter") == 0)
{
//Conversion to period as decimal mark, if needed
parameters = StringHelper::replaceCharacters(parameters, L",", L".");
wsmatch match;
wstring typeString;
bool found = regex_search(parameters, match, regexType);
if(found)
{
typeString = match.str(1);
if(filterNameToTypeMap.find(typeString) != filterNameToTypeMap.end())
{
BiQuad::Type type = filterNameToTypeMap[typeString];
wstring typeDescription = filterTypeToDescriptionMap[type];
parameters = match.suffix().str();
wstringstream stream;
stream << L"Adding " << typeDescription << L" filter";
double freq = 0;
double gain = 0;
double bandwidthOrQOrS = 0;
bool isBandwidth = false;
bool error = false;
found = regex_search(parameters, match, regexFreq);
if(found)
{
wstring freqString = match.str(1);
freq = getFreq(freqString);
stream << " with frequency " << freq << " Hz";
}
else
{
LogF(L"No frequency given in filter string %s%s", typeString.c_str(), parameters.c_str());
error = true;
}
found = regex_search(parameters, 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.c_str());
else
{
wstring gainString = match.str(1);
gain = wcstod(gainString.c_str(), NULL);
if(type == BiQuad::PEAKING)
stream << ", gain " << gain << " dB";
else
stream << " and gain " << gain << " dB";
}
}
else if(type == BiQuad::PEAKING || type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
{
LogF(L"No gain given in filter string %s%s", typeString.c_str(), parameters.c_str());
error = true;
}
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;
}
}
found = regex_search(parameters, match, regexBW);
if(found)
{
if(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
TraceF(L"Ignoring bandwidth for filter of type %s", typeDescription.c_str());
else
{
wstring bwString = match.str(1);
bandwidthOrQOrS = wcstod(bwString.c_str(), NULL);
isBandwidth = true;
stream << " and bandwidth " << bandwidthOrQOrS << " octaves";
}
}
found = regex_search(parameters, match, regexSlope);
if(found)
{
if(!(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF))
TraceF(L"Ignoring slope for filter of type %s", typeDescription.c_str());
else
{
wstring slopeString = match.str(1);
bandwidthOrQOrS = 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.c_str(), parameters.c_str());
error = true;
}
else if(type == BiQuad::LOW_PASS || type == BiQuad::HIGH_PASS || type == BiQuad::BAND_PASS)
{
bandwidthOrQOrS = M_SQRT1_2;
}
else if(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
{
bandwidthOrQOrS = 0.9; // found out by experimentation with RoomEQWizard
}
else if(type == BiQuad::NOTCH)
{
bandwidthOrQOrS = 30.0; // found out by experimentation with RoomEQWizard
}
}
else if(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
{
// Maximum S is 1 for 12 dB
bandwidthOrQOrS /= 12.0;
if(typeString[typeString.length()-1] != L'C')
{
// frequency adjustment for DCX2496
double centerFreqFactor = pow(10.0, abs(gain) / 80.0 / bandwidthOrQOrS);
if(type == BiQuad::LOW_SHELF)
freq *= centerFreqFactor;
else
freq /= centerFreqFactor;
}
}
if(!error)
{
TraceF(L"%s", stream.str().c_str());
void* mem = MemoryHelper::alloc(sizeof(BiQuadFilter));
filter = new(mem) BiQuadFilter(type, gain, freq, bandwidthOrQOrS, isBandwidth);
}
}
else if(typeString != L"None")
{
LogF(L"Invalid filter type %s", typeString.c_str());
}
}
}
if(filter == NULL)
return vector<IFilter*>(0);
return vector<IFilter*>(1, filter);
}
double BiQuadFilterFactory::getFreq(const wstring& freqString)
{
double result;
// remove thousand's separator for locales utilizing non-breaking space
wstring s = StringHelper::replaceCharacters(freqString, L"\u00A0", L"");
int matched = swscanf_s(s.c_str(), L"%lf", &result);
if(matched == 1)
{
if(s.length() >= 5 && s.find_first_of(L"eE") == wstring::npos)
{
if(s[s.length() - 4] == L'.')
{
//Interpret as thousands separator because of Room EQ Wizard
result *= 1000.0;
}
}
return result;
}
else
return -1.0;
}
+40
View File
@@ -0,0 +1,40 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include <hash_map>
#include "IFilterFactory.h"
#include "IFilter.h"
#include "BiQuad.h"
class BiQuadFilterFactory : public IFilterFactory
{
public:
BiQuadFilterFactory();
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
private:
double getFreq(const std::wstring& freqString);
stdext::hash_map<std::wstring, BiQuad::Type> filterNameToTypeMap;
stdext::hash_map<BiQuad::Type, std::wstring> filterTypeToDescriptionMap;
};
+88
View File
@@ -0,0 +1,88 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 <sstream>
#include <algorithm>
#include "helpers/MemoryHelper.h"
#include "helpers/LogHelper.h"
#include "ChannelFilter.h"
using namespace std;
ChannelFilter::ChannelFilter(const vector<wstring>& words)
:words(words)
{
}
ChannelFilter::~ChannelFilter()
{
}
vector<wstring> ChannelFilter::initialize(float sampleRate, unsigned maxFrameCount, vector<wstring> channelNames)
{
size_t channelCount = channelNames.size();
vector<bool> selectedChannels = vector<bool>(channelCount, false);
for(vector<wstring>::iterator it = words.begin(); it != words.end(); it++)
{
wstring currentWord = *it;
int channelNr = -1;
if(currentWord == L"ALL")
selectedChannels = vector<bool>(channelCount, true);
else
channelNr = getChannelIndex(currentWord, channelNames);
if(channelNr != -1 && channelNr < (int)channelCount)
{
selectedChannels[channelNr] = true;
}
}
vector<wstring> selectedChannelNames;
for(unsigned i=0; i<channelCount; i++)
{
if(selectedChannels[i])
selectedChannelNames.push_back(channelNames[i]);
}
wstringstream channelNumbers;
for(size_t c=0; c<channelCount; c++)
{
if(selectedChannels[c])
{
if(channelNumbers.tellp() > 0)
channelNumbers << L", ";
channelNumbers << c+1;
}
}
TraceF(L"Selecting channel(s) number %s", channelNumbers.str().c_str());
return selectedChannelNames;
}
#pragma AVRT_CODE_BEGIN
void ChannelFilter::process(float** output, float** input, unsigned frameCount)
{
// nothing to do
}
#pragma AVRT_CODE_END
+41
View File
@@ -0,0 +1,41 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include <vector>
#include "IFilter.h"
#pragma AVRT_VTABLES_BEGIN
class ChannelFilter : public IFilter
{
public:
ChannelFilter(const std::vector<std::wstring>& words);
virtual ~ChannelFilter();
virtual bool getAllChannels() {return true;}
virtual bool getSelectChannels() {return true;}
virtual std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames);
virtual void process(float** output, float** input, unsigned frameCount);
private:
std::vector<std::wstring> words;
};
#pragma AVRT_VTABLES_END
+64
View File
@@ -0,0 +1,64 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 "helpers/MemoryHelper.h"
#include "helpers/StringHelper.h"
#include "helpers/LogHelper.h"
#include "ChannelFilter.h"
#include "ChannelFilterFactory.h"
using namespace std;
vector<IFilter*> ChannelFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
ChannelFilter* filter = NULL;
if(command == L"Channel")
{
wstring value = parameters + L" ";
vector<wstring> words;
wstring currentWord;
for(unsigned i=0; i<value.length(); i++)
{
wchar_t c = towupper(value[i]);
if(c == L' ')
{
if(currentWord.length() > 0)
{
words.push_back(currentWord);
currentWord.clear();
}
}
else
{
currentWord += c;
}
}
void* mem = MemoryHelper::alloc(sizeof(ChannelFilter));
filter = new(mem) ChannelFilter(words);
}
if(filter == NULL)
return vector<IFilter*>(0);
return vector<IFilter*>(1, filter);
}
+31
View File
@@ -0,0 +1,31 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include "IFilterFactory.h"
#include "IFilter.h"
class ChannelFilterFactory : public IFilterFactory
{
public:
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
};
+167
View File
@@ -0,0 +1,167 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 <algorithm>
#include <sstream>
#include "helpers/LogHelper.h"
#include "helpers/MemoryHelper.h"
#include "CopyFilter.h"
using namespace std;
CopyFilter::CopyFilter(const vector<Assignment>& assignments)
{
this->assignments = assignments;
internalAssignments = NULL;
assignmentCount = 0;
}
CopyFilter::~CopyFilter()
{
cleanup();
}
vector<wstring> CopyFilter::initialize(float sampleRate, unsigned maxFrameCount, vector<wstring> channelNames)
{
cleanup();
assignmentCount = (unsigned)assignments.size();
internalAssignments = (InternalAssignment*)MemoryHelper::alloc(assignmentCount * sizeof(Assignment));
vector<wstring> outChannelNames;
for(unsigned i=0; i<assignmentCount; i++)
{
InternalAssignment& ia = internalAssignments[i];
Assignment& a = assignments[i];
wstring channelName = a.targetChannel;
int channelIndex = getChannelIndex(a.targetChannel, channelNames, true);
if(channelIndex != -1)
channelName = channelNames[channelIndex];
vector<wstring>::const_iterator it = find(outChannelNames.begin(), outChannelNames.end(), channelName);
ia.targetChannel = (int)(it-outChannelNames.begin());
if(it == outChannelNames.end())
outChannelNames.push_back(channelName);
ia.sourceCount = (unsigned)a.sourceSum.size();
ia.sourceSum = (InternalAssignment::InternalSummand*)MemoryHelper::alloc(ia.sourceCount * sizeof(InternalAssignment::InternalSummand));
for(unsigned j=0; j<ia.sourceCount; j++)
{
InternalAssignment::InternalSummand& is = ia.sourceSum[j];
Assignment::Summand& s = a.sourceSum[j];
if(s.channel != L"")
is.channel = getChannelIndex(s.channel, channelNames);
else
is.channel = -1;
if(s.isDecibel)
is.factor = (float)pow(10.0, s.factor / 20.0);
else
is.factor = (float)s.factor;
}
}
wstringstream stream;
stream << "Copying ";
for(unsigned i=0; i<assignmentCount; i++)
{
InternalAssignment& ia = internalAssignments[i];
if(i > 0)
stream << ", ";
stream << L"to channel " << outChannelNames[ia.targetChannel].c_str() << " ";
for(unsigned j=0; j<ia.sourceCount; j++)
{
InternalAssignment::InternalSummand& is = ia.sourceSum[j];
if(j > 0)
stream << ", ";
if(is.channel != -1)
stream << L"from channel " << channelNames[is.channel].c_str() << L" with factor " << is.factor;
else
stream << L"value " << is.factor;
}
}
TraceF(L"%s", stream.str().c_str());
return outChannelNames;
}
#pragma AVRT_CODE_BEGIN
void CopyFilter::process(float** output, float** input, unsigned frameCount)
{
for(unsigned i=0; i<assignmentCount; i++)
{
InternalAssignment& ia = internalAssignments[i];
if(ia.targetChannel == -1 || ia.sourceCount == 0)
continue;
{
InternalAssignment::InternalSummand& is = ia.sourceSum[0];
if(is.channel == -1)
for(unsigned f=0; f<frameCount; f++)
output[ia.targetChannel][f] = is.factor;
else if(is.factor == 1.0)
memcpy(output[ia.targetChannel], input[is.channel], frameCount * sizeof(float));
else
for(unsigned f=0; f<frameCount; f++)
output[ia.targetChannel][f] = is.factor * input[is.channel][f];
}
for(unsigned j=1; j<ia.sourceCount; j++)
{
InternalAssignment::InternalSummand& is = ia.sourceSum[j];
if(is.channel == -1)
for(unsigned f=0; f<frameCount; f++)
output[ia.targetChannel][f] += is.factor;
else if(is.factor == 1.0)
for(unsigned f=0; f<frameCount; f++)
output[ia.targetChannel][f] += input[is.channel][f];
else
for(unsigned f=0; f<frameCount; f++)
output[ia.targetChannel][f] += is.factor * input[is.channel][f];
}
}
}
#pragma AVRT_CODE_END
void CopyFilter::cleanup()
{
if(internalAssignments != NULL)
{
for(unsigned i=0; i<assignmentCount; i++)
{
InternalAssignment& ia = internalAssignments[i];
if(ia.sourceSum != NULL)
{
MemoryHelper::free(ia.sourceSum);
ia.sourceSum = NULL;
}
}
MemoryHelper::free(internalAssignments);
internalAssignments = NULL;
}
}
+74
View File
@@ -0,0 +1,74 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include <vector>
#include "IFilter.h"
struct Assignment
{
std::wstring targetChannel;
struct Summand
{
double factor;
bool isDecibel;
std::wstring channel;
};
std::vector<Summand> sourceSum;
};
#pragma AVRT_VTABLES_BEGIN
class CopyFilter : public IFilter
{
public:
CopyFilter(const std::vector<Assignment>& assignments);
virtual ~CopyFilter();
virtual bool getAllChannels() {return true;}
virtual bool getInPlace() {return false;}
virtual std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames);
virtual void process(float** output, float** input, unsigned frameCount);
private:
void cleanup();
std::vector<Assignment> assignments;
struct InternalAssignment
{
int targetChannel;
struct InternalSummand
{
float factor;
int channel;
};
InternalSummand* sourceSum;
unsigned sourceCount;
};
InternalAssignment* internalAssignments;
unsigned assignmentCount;
};
#pragma AVRT_VTABLES_END
+96
View File
@@ -0,0 +1,96 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 "helpers/MemoryHelper.h"
#include "helpers/StringHelper.h"
#include "helpers/LogHelper.h"
#include "CopyFilter.h"
#include "CopyFilterFactory.h"
using namespace std;
vector<IFilter*> CopyFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
CopyFilter* filter = NULL;
if(command == L"Copy")
{
vector<Assignment> assignments;
vector<wstring> assignmentStrings = StringHelper::split(parameters, L' ');
for(vector<wstring>::iterator it=assignmentStrings.begin(); it!=assignmentStrings.end(); it++)
{
Assignment assignment;
vector<wstring> parts = StringHelper::split(*it, L'=');
if(parts.size() == 2)
{
wstring target = parts[0];
wstring source = parts[1];
assignment.targetChannel = target;
vector<wstring> summands = StringHelper::split(source, '+');
for(vector<wstring>::iterator it2=summands.begin(); it2!=summands.end(); it2++)
{
vector<wstring> factors = StringHelper::split(*it2, '*');
wstring factor;
wstring channel;
if(factors.size() == 2)
{
factor = factors[0];
channel = factors[1];
}
else if(factors.size() == 1)
{
if(factors[0] == L"0" || factors[0].find(L'.') != wstring::npos)
factor = factors[0];
else
channel = factors[0];
}
Assignment::Summand summand;
if(factor == L"")
{
summand.factor = 1.0;
summand.isDecibel = false;
}
else
{
summand.factor = wcstod(factor.c_str(), NULL);
summand.isDecibel = factor.size() > 2 && StringHelper::toLowerCase(factor.substr(factor.size()-2)) == L"db";
}
summand.channel = channel;
assignment.sourceSum.push_back(summand);
}
}
if(assignment.targetChannel != L"" && !assignment.sourceSum.empty())
assignments.push_back(assignment);
}
void* mem = MemoryHelper::alloc(sizeof(CopyFilter));
filter = new(mem) CopyFilter(assignments);
}
if(filter == NULL)
return vector<IFilter*>(0);
return vector<IFilter*>(1, filter);
}
+31
View File
@@ -0,0 +1,31 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include "IFilterFactory.h"
#include "IFilter.h"
class CopyFilterFactory : public IFilterFactory
{
public:
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
};
+112
View File
@@ -0,0 +1,112 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 <cmath>
#include "helpers/MemoryHelper.h"
#include "DelayFilter.h"
using namespace std;
DelayFilter::DelayFilter(double delay, bool isMs)
:delay(delay), isMs(isMs)
{
buffers = NULL;
}
DelayFilter::~DelayFilter()
{
cleanup();
}
vector<wstring> DelayFilter::initialize(float sampleRate, unsigned maxFrameCount, vector<wstring> channelNames)
{
cleanup();
channelCount = (unsigned)channelNames.size();
if(isMs)
bufferLength = (unsigned)(sampleRate * delay / 1000.0 + 0.5);
else
bufferLength = (unsigned)(delay + 0.5);
buffers = (float**)MemoryHelper::alloc(sizeof(float*) * channelCount);
for(unsigned i=0; i<channelCount; i++)
{
buffers[i] = (float*)MemoryHelper::alloc(sizeof(float) * bufferLength);
memset(buffers[i], 0, sizeof(float) * bufferLength);
}
bufferOffset = 0;
return channelNames;
}
#pragma AVRT_CODE_BEGIN
void DelayFilter::process(float** output, float** input, unsigned frameCount)
{
for(unsigned i=0; i<channelCount; i++)
{
float* inputChannel = input[i];
float* outputChannel = output[i];
float* bufferChannel = buffers[i];
if(bufferLength <= frameCount)
{
memcpy(outputChannel, bufferChannel + bufferOffset, (bufferLength - bufferOffset) * sizeof(float));
memcpy(outputChannel + bufferLength - bufferOffset, bufferChannel, bufferOffset * sizeof(float));
memcpy(outputChannel + bufferLength, inputChannel, (frameCount - bufferLength) * sizeof(float));
memcpy(bufferChannel, inputChannel + frameCount - bufferLength, bufferLength * sizeof(float));
}
else
{
if(bufferLength < bufferOffset + frameCount)
{
memcpy(outputChannel, bufferChannel + bufferOffset, (bufferLength - bufferOffset) * sizeof(float));
memcpy(outputChannel + bufferLength - bufferOffset, bufferChannel, (frameCount - (bufferLength - bufferOffset)) * sizeof(float));
memcpy(bufferChannel + bufferOffset, inputChannel, (bufferLength - bufferOffset) * sizeof(float));
memcpy(bufferChannel, inputChannel + bufferLength - bufferOffset, (frameCount - (bufferLength - bufferOffset)) * sizeof(float));
}
else
{
memcpy(outputChannel, bufferChannel + bufferOffset, frameCount * sizeof(float));
memcpy(bufferChannel + bufferOffset, inputChannel, frameCount * sizeof(float));
}
}
}
if(bufferLength <= frameCount)
bufferOffset = 0;
else
bufferOffset = (bufferOffset + frameCount) % bufferLength;
}
#pragma AVRT_CODE_END
void DelayFilter::cleanup()
{
if(buffers != NULL)
{
for(unsigned i=0; i<channelCount; i++)
MemoryHelper::free(buffers[i]);
MemoryHelper::free(buffers);
buffers = NULL;
}
}
+44
View File
@@ -0,0 +1,44 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include "IFilter.h"
#pragma AVRT_VTABLES_BEGIN
class DelayFilter : public IFilter
{
public:
DelayFilter(double delay, bool isMs);
virtual ~DelayFilter();
virtual bool getInPlace() {return false;}
virtual std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames);
virtual void process(float** output, float** input, unsigned frameCount);
private:
void cleanup();
double delay;
bool isMs;
unsigned bufferLength;
unsigned channelCount;
float** buffers;
unsigned bufferOffset;
};
#pragma AVRT_VTABLES_END
+64
View File
@@ -0,0 +1,64 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 <sstream>
#include "helpers/MemoryHelper.h"
#include "helpers/StringHelper.h"
#include "helpers/LogHelper.h"
#include "DelayFilter.h"
#include "DelayFilterFactory.h"
using namespace std;
vector<IFilter*> DelayFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
DelayFilter* filter = NULL;
if(command == L"Delay")
{
//Conversion to period as decimal mark, if needed
wstring value = StringHelper::replaceCharacters(parameters, L",", L".");
double delay = 0;
wstring unit;
wstringstream stream(value);
stream >> delay >> unit;
if(delay > 0)
{
if(StringHelper::toLowerCase(unit) == L"ms")
{
TraceF(L"Delaying by %g ms", delay);
void* mem = MemoryHelper::alloc(sizeof(DelayFilter));
filter = new(mem) DelayFilter(delay, true);
}
else if(StringHelper::toLowerCase(unit) == L"samples")
{
TraceF(L"Delaying by %g samples", delay);
void* mem = MemoryHelper::alloc(sizeof(DelayFilter));
filter = new(mem) DelayFilter(delay, false);
}
}
}
if(filter == NULL)
return vector<IFilter*>(0);
return vector<IFilter*>(1, filter);
}
+31
View File
@@ -0,0 +1,31 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include "IFilterFactory.h"
#include "IFilter.h"
class DelayFilterFactory : public IFilterFactory
{
public:
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
};
+116
View File
@@ -0,0 +1,116 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 "helpers/LogHelper.h"
#include "helpers/StringHelper.h"
#include "FilterEngine.h"
#include "DeviceFilterFactory.h"
using namespace std;
void DeviceFilterFactory::initialize(FilterEngine* engine)
{
deviceString = engine->getDeviceName() + L" " + engine->getConnectionName() + L" " + engine->getDeviceGuid();
mup::ParserX* parser = engine->getParser();
parser->DefineConst(L"deviceName", engine->getDeviceName());
parser->DefineConst(L"connectionName", engine->getConnectionName());
parser->DefineConst(L"deviceGuid", engine->getDeviceGuid());
}
vector<IFilter*> DeviceFilterFactory::startOfConfiguration()
{
deviceMatches = true;
return vector<IFilter*>();
}
vector<IFilter*> DeviceFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
if(command == L"Device")
{
wstring value = StringHelper::trim(parameters) + L";";
vector<vector<wstring>> fullList;
vector<wstring> currentList;
wstring currentWord;
for(unsigned i=0; i<value.length(); i++)
{
wchar_t c = value[i];
if(c == L' ' || c == L';')
{
if(currentWord.length() > 0)
{
currentList.push_back(currentWord);
currentWord.clear();
}
if(c == L';' && currentList.size() > 0)
{
fullList.push_back(currentList);
currentList.clear();
}
}
else
{
currentWord += c;
}
}
bool matches = false;
for(unsigned i=0; i<fullList.size(); i++)
{
matches = true;
if(fullList[i].size() == 1 && StringHelper::toLowerCase(fullList[i][0]) == L"all")
break;
for(unsigned j=0; j<fullList[i].size(); j++)
{
wstring word = StringHelper::toLowerCase(fullList[i][j]);
if(StringHelper::toLowerCase(deviceString).find(word) == -1)
{
matches = false;
break;
}
}
if(matches)
break;
}
TraceF(L"%satching pattern \"%s\" with device \"%s\"", matches ? L"M" : L"Not m", value.substr(0, value.length()-1).c_str(), deviceString.c_str());
deviceMatches = matches;
}
if(!deviceMatches)
// skip line for further factories
command = L"";
return vector<IFilter*>();
}
std::vector<IFilter*> DeviceFilterFactory::endOfFile(const std::wstring& configPath)
{
// in outer file, the device must have matched, otherwise the inner file would not have been included
deviceMatches = true;
return vector<IFilter*>();
}
+38
View File
@@ -0,0 +1,38 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include "IFilterFactory.h"
#include "IFilter.h"
class DeviceFilterFactory : public IFilterFactory
{
public:
virtual void initialize(FilterEngine* engine);
virtual std::vector<IFilter*> startOfConfiguration();
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
virtual std::vector<IFilter*> endOfFile(const std::wstring& configPath);
private:
bool deviceMatches;
std::wstring deviceString;
};
+152
View File
@@ -0,0 +1,152 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 <sstream>
#include "helpers/LogHelper.h"
#include "helpers/StringHelper.h"
#include "parser/RegexFunctions.h"
#include "parser/RegistryFunctions.h"
#include "parser/StringOperators.h"
#include "FilterEngine.h"
#include "ExpressionFilterFactory.h"
using namespace std;
using namespace mup;
void ExpressionFilterFactory::initialize(FilterEngine* engine)
{
parser = engine->getParser();
parser->DefineConst(L"inputChannelCount", (int)engine->getInputChannelCount());
parser->DefineConst(L"outputChannelCount", (int)engine->getOutputChannelCount());
parser->DefineConst(L"sampleRate", engine->getSampleRate());
parser->DefineFun(new ReadRegStringFunction(engine));
parser->DefineFun(new ReadRegDWORDFunction(engine));
parser->DefineFun(new RegexSearchFunction());
parser->DefineFun(new RegexReplaceFunction());
parser->RemoveOprt(L"+");
parser->DefineOprt(new AddOperator());
}
vector<IFilter*> ExpressionFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
if(command.length() > 0 && command[0] == L'#')
return vector<IFilter*>();
bool inExpression = false;
bool lastWasBackslash = false;
wstring output;
wstring expression;
for(unsigned i=0; i<parameters.size(); i++)
{
wchar_t c = parameters[i];
if(c == L'`')
{
if(!inExpression)
{
if(lastWasBackslash)
{
output += c;
}
else
{
inExpression = true;
}
}
else
{
if(lastWasBackslash)
{
expression += c;
}
else
{
inExpression = false;
try
{
parser->SetExpr(expression);
Value result = parser->Eval();
wstring resultString;
if(result.GetType() == L's')
resultString = result.GetString();
else
resultString = result.ToString().c_str();
output += resultString;
TraceF(L"Inline expression %s evaluated to %s", expression.c_str(), resultString.c_str());
}
catch(ParserError e)
{
LogF(L"Error while evaluating inline expression %s: %s", expression.c_str(), e.GetMsg().c_str());
}
expression.clear();
}
}
lastWasBackslash = false;
}
else if(c == L'\\')
{
if(i >= parameters.size()-1 || parameters[i+1] != L'`')
{
if(inExpression)
expression += c;
else
output += c;
}
lastWasBackslash = true;
}
else
{
if(inExpression)
expression += c;
else
output += c;
lastWasBackslash = false;
}
}
parameters = output;
if(command == L"Eval")
{
try
{
expression = StringHelper::trim(parameters);
parser->SetExpr(expression);
Value result = parser->Eval();
wstring resultString;
if(result.GetType() == L's')
resultString = result.GetString();
else
resultString = result.ToString().c_str();
TraceF(L"Expression %s evaluated to %s", expression.c_str(), resultString.c_str());
}
catch(ParserError e)
{
LogF(L"Error while evaluating expression %s: %s", expression.c_str(), e.GetMsg().c_str());
}
// command has been handled
command = L"";
}
return vector<IFilter*>();
}
+36
View File
@@ -0,0 +1,36 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include <mpParser.h>
#include "IFilterFactory.h"
#include "IFilter.h"
class ExpressionFilterFactory : public IFilterFactory
{
public:
virtual void initialize(FilterEngine* engine);
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
private:
mup::ParserX* parser;
};
+123
View File
@@ -0,0 +1,123 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 "helpers/MemoryHelper.h"
#include "IIRFilter.h"
using namespace std;
#define IS_DENORMAL(f) (((*(unsigned int *)&(f))&0x7f800000) == 0)
IIRFilter::IIRFilter(const vector<double>& coefficients)
{
order = (unsigned)coefficients.size() / 2 - 1;
a = (float*)MemoryHelper::alloc(order * sizeof(float));
b = (float*)MemoryHelper::alloc(order * sizeof(float));
x = NULL;
y = NULL;
double a0 = coefficients[order+1];
b0 = float(coefficients[0] / a0);
for(unsigned i=0; i<order; i++)
{
b[i] = float(coefficients[i+1] / a0);
a[i] = float(-coefficients[i+order+2] / a0);
}
}
IIRFilter::~IIRFilter()
{
MemoryHelper::free(a);
MemoryHelper::free(b);
if(x != NULL)
MemoryHelper::free(x);
if(y != NULL)
MemoryHelper::free(y);
}
vector<wstring> IIRFilter::initialize(float sampleRate, unsigned maxFrameCount, vector<wstring> channelNames)
{
channelCount = (unsigned)channelNames.size();
if(x != NULL)
MemoryHelper::free(x);
if(y != NULL)
MemoryHelper::free(y);
x = (float*)MemoryHelper::alloc(order * channelCount * sizeof(float));
y = (float*)MemoryHelper::alloc(order * channelCount * sizeof(float));
memset(x, 0, order * channelCount * sizeof(float));
memset(y, 0, order * channelCount * sizeof(float));
return channelNames;
}
#pragma AVRT_CODE_BEGIN
void IIRFilter::process(float** output, float** input, unsigned frameCount)
{
for(unsigned i=0; i<channelCount; i++)
{
float* inputChannel = input[i];
float* outputChannel = output[i];
unsigned channelOffset = i*order;
float* xo = x+channelOffset;
float* yo = y+channelOffset;
for(unsigned j=0; j<frameCount; j++)
{
float sample = inputChannel[j];
float sum = b0 * sample;
for(unsigned k=order-1; k>0; k--)
{
sum += b[k] * xo[k];
}
sum += b[0] * xo[0];
for(unsigned k=order-1; k>0; k--)
{
sum += a[k] * yo[k];
}
sum += a[0] * yo[0];
for(unsigned k=order-1; k>0; k--)
{
xo[k] = xo[k-1];
yo[k] = yo[k-1];
}
xo[0] = sample;
yo[0] = sum;
outputChannel[j] = sum;
}
}
for(unsigned i=0; i<channelCount*order; i++)
{
if(IS_DENORMAL(x[i]))
x[i] = 0.0f;
if(IS_DENORMAL(y[i]))
y[i] = 0.0f;
}
}
#pragma AVRT_CODE_END
+43
View File
@@ -0,0 +1,43 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include "IFilter.h"
#pragma AVRT_VTABLES_BEGIN
class IIRFilter : public IFilter
{
public:
IIRFilter(const std::vector<double>& coefficients);
virtual ~IIRFilter();
virtual bool getInPlace() {return true;}
virtual std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames);
virtual void process(float** output, float** input, unsigned frameCount);
private:
unsigned order;
float b0;
float* a;
float* b;
unsigned channelCount;
float* x;
float* y;
};
#pragma AVRT_VTABLES_END
+108
View File
@@ -0,0 +1,108 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#define _USE_MATH_DEFINES
#include <cmath>
#include <regex>
#include <sstream>
#include "helpers/MemoryHelper.h"
#include "helpers/StringHelper.h"
#include "helpers/LogHelper.h"
#include "IIRFilter.h"
#include "IIRFilterFactory.h"
using namespace std;
static wregex regexType(L"^\\s*ON\\s+([A-Za-z]+)");
static wregex regexOrder(L"\\s*Order\\s+([0-9]+)");
static wregex regexCoefficients(L"\\s+Coefficients((?: [-+0-9.eE]+)+)");
IIRFilterFactory::IIRFilterFactory()
{
}
vector<IFilter*> IIRFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
IIRFilter* filter = NULL;
if(command.find(L"Filter") == 0)
{
wsmatch match;
wstring typeString;
bool found = regex_search(parameters, match, regexType);
if(found)
{
typeString = match.str(1);
if(typeString == L"IIR")
{
bool found = regex_search(parameters, match, regexOrder);
if(found)
{
wstring orderString = match.str(1);
unsigned order = wcstol(orderString.c_str(), NULL, 10);
if(order<1)
{
LogF(L"Order %d not supported, must at least be 1", order);
}
else
{
found = regex_search(parameters, match, regexCoefficients);
if(found)
{
wstring coefficientsString = match.str(1);
vector<wstring> coefficientStrings = StringHelper::split(coefficientsString, L' ');
if(coefficientStrings.size() != (order + 1) * 2)
{
LogF(L"Invalid number of coefficients. Expected %d coefficients instead of %d", (order + 1) * 2, coefficientStrings.size());
}
else
{
vector<double> coefficients;
for(auto it = coefficientStrings.begin(); it!=coefficientStrings.end(); it++)
{
coefficients.push_back(wcstod(it->c_str(), NULL));
}
wstringstream stream;
stream << L"Adding IIR filter of order " << order << " with coefficients";
for(unsigned i=0; i<=order; i++)
stream << L" b" << i << L"=" << coefficients[i];
for(unsigned i=0; i<=order; i++)
stream << L" a" << i << L"=" << coefficients[i + order + 1];
TraceF(L"%s", stream.str().c_str());
void* mem = MemoryHelper::alloc(sizeof(IIRFilter));
filter = new(mem) IIRFilter(coefficients);
}
}
}
}
}
}
}
if(filter == NULL)
return vector<IFilter*>(0);
return vector<IFilter*>(1, filter);
}
+33
View File
@@ -0,0 +1,33 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include <hash_map>
#include "IFilterFactory.h"
#include "IFilter.h"
class IIRFilterFactory : public IFilterFactory
{
public:
IIRFilterFactory();
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
};
+211
View File
@@ -0,0 +1,211 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 "helpers/LogHelper.h"
#include "helpers/StringHelper.h"
#include "parser/RegexFunctions.h"
#include "parser/RegistryFunctions.h"
#include "FilterEngine.h"
#include "IfFilterFactory.h"
using namespace std;
using namespace mup;
void IfFilterFactory::initialize(FilterEngine* engine)
{
parser = engine->getParser();
}
vector<IFilter*> IfFilterFactory::startOfConfiguration()
{
trueCount = 0;
falseCount = 0;
while(!trueCountStack.empty())
trueCountStack.pop();
return vector<IFilter*>();
}
std::vector<IFilter*> IfFilterFactory::startOfFile(const std::wstring& configPath)
{
trueCountStack.push(trueCount);
trueCount = 0;
if(falseCount != 0)
{
LogF(L"File was included inside If that evaluated to false!");
falseCount = 0;
}
return vector<IFilter*>();
}
vector<IFilter*> IfFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
wstring expression = StringHelper::trim(parameters);
if(command == L"If")
{
if(falseCount == 0)
{
try
{
parser->SetExpr(expression);
Value result = parser->Eval();
bool isTrue = toBoolean(result);
if(result.GetType() == L'b')
TraceF(L"If(%s) evaluated to %s", expression.c_str(), result.ToString().c_str());
else
TraceF(L"If(%s) evaluated to %s (%s)", expression.c_str(), result.ToString().c_str(), isTrue ? L"true" : L"false");
if(isTrue)
trueCount++;
else
falseCount++;
}
catch(ParserError e)
{
LogF(L"Error while evaluating If(%s): %s", expression.c_str(), e.GetMsg().c_str());
falseCount++;
}
}
else
{
falseCount++;
}
}
else if(command == L"ElseIf")
{
if(falseCount == 1)
{
try
{
parser->SetExpr(expression);
Value result = parser->Eval();
bool isTrue = toBoolean(result);
if(result.GetType() == L'b')
TraceF(L"ElseIf(%s) evaluated to %s", expression.c_str(), result.ToString().c_str());
else
TraceF(L"ElseIf(%s) evaluated to %s (%s)", expression.c_str(), result.ToString().c_str(), isTrue ? L"true" : L"false");
if(isTrue)
{
falseCount--;
trueCount++;
}
}
catch(ParserError e)
{
LogF(L"Error while evaluating ElseIf(%s): %s", expression.c_str(), e.GetMsg().c_str());
}
}
else if(falseCount == 0 && trueCount == 0)
{
LogF(L"ElseIf without If!");
}
}
else if(command == L"Else")
{
if(falseCount == 1)
{
falseCount--;
trueCount++;
}
else if(falseCount == 0 && trueCount == 0)
{
LogF(L"Else without If!");
}
}
else if(command == L"EndIf")
{
if(falseCount == 0)
{
if(trueCount == 0)
LogF(L"EndIf without If!");
else
trueCount--;
}
else
{
falseCount--;
}
}
if(falseCount > 0)
// skip line for further factories
command = L"";
return vector<IFilter*>();
}
std::vector<IFilter*> IfFilterFactory::endOfFile(const std::wstring& configPath)
{
if(trueCount != 0 || falseCount != 0)
{
LogF(L"If was not closed by EndIf!");
falseCount = 0;
}
trueCount = trueCountStack.top();
trueCountStack.pop();
return vector<IFilter*>();
}
bool IfFilterFactory::toBoolean(const Value& value)
{
bool result = false;
wchar_t type = value.GetType();
switch(type)
{
case 'i':
{
int i = value.GetInteger();
result = (i != 0);
}
break;
case 'f':
{
double f = value.GetFloat();
result = (f != 0.0 && f == f);
}
break;
case 'b':
{
result = value.GetBool();
}
break;
case 's':
{
wstring s = value.GetString();
result = s.length() > 0 && s != L"false" && s != L"0";
}
break;
case 'm':
{
Matrix<Value> m = value.GetArray();
result = m.GetRows() > 0 && m.GetCols() > 0;
}
break;
default:
result = false;
break;
}
return result;
}
+45
View File
@@ -0,0 +1,45 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include <mpParser.h>
#include "IFilterFactory.h"
#include "IFilter.h"
class IfFilterFactory : public IFilterFactory
{
public:
virtual void initialize(FilterEngine* engine);
virtual std::vector<IFilter*> startOfConfiguration();
virtual std::vector<IFilter*> startOfFile(const std::wstring& configPath);
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
virtual std::vector<IFilter*> endOfFile(const std::wstring& configPath);
private:
mup::ParserX* parser;
unsigned trueCount;
unsigned falseCount;
std::stack<unsigned> trueCountStack;
bool toBoolean(const mup::Value& value);
};
+63
View File
@@ -0,0 +1,63 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 <Shlwapi.h>
#include "helpers/LogHelper.h"
#include "helpers/StringHelper.h"
#include "FilterEngine.h"
#include "IncludeFilterFactory.h"
using namespace std;
void IncludeFilterFactory::initialize(FilterEngine* engine)
{
this->engine = engine;
}
vector<IFilter*> IncludeFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
if(command == L"Include")
{
wstring value = parameters;
while(value.length() > 0 && iswspace(value[0]))
value = value.substr(1);
wstring includePath;
if(PathIsRelativeW(value.c_str()))
{
wchar_t filePath[MAX_PATH];
configPath._Copy_s(filePath, sizeof(filePath)/sizeof(wchar_t), MAX_PATH);
if(configPath.size() < MAX_PATH)
filePath[configPath.size()] = L'\0';
else
filePath[MAX_PATH - 1] = L'\0';
PathRemoveFileSpecW(filePath);
PathAppendW(filePath, value.c_str());
includePath = filePath;
}
else
includePath = value;
engine->loadConfig(includePath);
command = L"";
}
return vector<IFilter*>();
}
+35
View File
@@ -0,0 +1,35 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include "IFilterFactory.h"
#include "IFilter.h"
class IncludeFilterFactory : public IFilterFactory
{
public:
virtual void initialize(FilterEngine* engine);
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
private:
FilterEngine* engine;
};
+51
View File
@@ -0,0 +1,51 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#define _USE_MATH_DEFINES
#include <cmath>
#include "PreampFilter.h"
using namespace std;
PreampFilter::PreampFilter(double dbGain)
:dbGain(dbGain)
{
gain = (float)pow(10.0, dbGain / 20.0);
}
vector<wstring> PreampFilter::initialize(float sampleRate, unsigned maxFrameCount, vector<wstring> channelNames)
{
this->channelCount = channelNames.size();
return channelNames;
}
#pragma AVRT_CODE_BEGIN
void PreampFilter::process(float** output, float** input, unsigned frameCount)
{
for(size_t i=0; i<channelCount; i++)
{
float* sampleChannel = input[i];
for(unsigned j=0; j<frameCount; j++)
sampleChannel[j] *= gain;
}
}
#pragma AVRT_CODE_END
+37
View File
@@ -0,0 +1,37 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include "IFilter.h"
#pragma AVRT_VTABLES_BEGIN
class PreampFilter : public IFilter
{
public:
PreampFilter(double dbGain);
virtual std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames);
virtual void process(float** output, float** input, unsigned frameCount);
private:
float gain;
double dbGain;
size_t channelCount;
};
#pragma AVRT_VTABLES_END
+51
View File
@@ -0,0 +1,51 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 "helpers/MemoryHelper.h"
#include "helpers/StringHelper.h"
#include "helpers/LogHelper.h"
#include "PreampFilter.h"
#include "PreampFilterFactory.h"
using namespace std;
vector<IFilter*> PreampFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
PreampFilter* filter = NULL;
if(command == L"Preamp")
{
//Conversion to period as decimal mark, if needed
wstring value = StringHelper::replaceCharacters(parameters, L",", L".");
double preamp_dB;
int matched = swscanf_s(value.c_str(), L" %lf dB", &preamp_dB);
if(matched == 1)
{
TraceF(L"Adjusting preamp by %g dB", preamp_dB);
void* mem = MemoryHelper::alloc(sizeof(PreampFilter));
filter = new(mem) PreampFilter(preamp_dB);
}
}
if(filter == NULL)
return vector<IFilter*>(0);
return vector<IFilter*>(1, filter);
}
+31
View File
@@ -0,0 +1,31 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include "IFilterFactory.h"
#include "IFilter.h"
class PreampFilterFactory : public IFilterFactory
{
public:
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
};
+112
View File
@@ -0,0 +1,112 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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 "helpers/LogHelper.h"
#include "helpers/StringHelper.h"
#include "FilterEngine.h"
#include "StageFilterFactory.h"
using namespace std;
void StageFilterFactory::initialize(FilterEngine* engine)
{
lfx = engine->isLfx();
capture = engine->isCapture();
engine->getParser()->DefineConst(L"stage", engine->isCapture() ? L"capture" : engine->isLfx() ? L"pre-mix" : L"post-mix");
}
vector<IFilter*> StageFilterFactory::startOfConfiguration()
{
stageMatches = capture || !lfx;
while(!stageMatchesStack.empty())
stageMatchesStack.pop();
return vector<IFilter*>();
}
std::vector<IFilter*> StageFilterFactory::startOfFile(const std::wstring& configPath)
{
stageMatchesStack.push(stageMatches);
return vector<IFilter*>();
}
vector<IFilter*> StageFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
if(command == L"Stage")
{
stageMatches = false;
wstring stageString = StringHelper::toLowerCase(StringHelper::trim(parameters));
vector<wstring> parts = StringHelper::split(stageString, L' ');
wstring matchingPart;
for(auto it=parts.begin(); it!=parts.end(); it++)
{
const wstring& part = *it;
if(part == L"pre-mix")
{
if(!capture && lfx)
{
stageMatches = true;
matchingPart = part;
}
}
else if(part == L"post-mix")
{
if(!capture && !lfx)
{
stageMatches = true;
matchingPart = part;
}
}
else if(part == L"capture")
{
if(capture)
{
stageMatches = true;
matchingPart = part;
}
}
else
{
LogF(L"Unknown stage \"%s\"! Only pre-mix, post-mix and capture are supported.", part.c_str());
}
}
if(stageMatches)
TraceF(L"Matching stage \"%s\"", matchingPart.c_str());
else
TraceF(L"Not matching stage set \"%s\"", stageString.c_str());
}
if(!stageMatches)
// skip line for further factories
command = L"";
return vector<IFilter*>();
}
std::vector<IFilter*> StageFilterFactory::endOfFile(const std::wstring& configPath)
{
stageMatches = stageMatchesStack.top();
stageMatchesStack.pop();
return vector<IFilter*>();
}
+42
View File
@@ -0,0 +1,42 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2014 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.
*/
#pragma once
#include <string>
#include "IFilterFactory.h"
#include "IFilter.h"
class StageFilterFactory : public IFilterFactory
{
public:
virtual void initialize(FilterEngine* engine);
virtual std::vector<IFilter*> startOfConfiguration();
virtual std::vector<IFilter*> startOfFile(const std::wstring& configPath);
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
virtual std::vector<IFilter*> endOfFile(const std::wstring& configPath);
private:
bool lfx;
bool capture;
bool stageMatches;
std::stack<bool> stageMatchesStack;
};