Version 1.0

Added: Configuration Editor, which allows to edit configurations in a graphical user interface. Contains GUIs for most commands supported by E-APO, but as lines can also be edited directly, all commands can be used.
Added: Command "GraphicEQ", which can act as a regular, fixed-band graphic equalizer (via the GUI) but also supports variable bands so that any desired frequency response can be specified. Internally, it is implemented via convolution with a generated IR.
Added: Command "Convolution", which allows to convolve the signal with a user-provided impulse response to achieve e.g. equalization or reverberation effects.
Improved: Configurator performs checks for registry values that are needed for the operation of E-APO, which may be changed by driver installations, fixing the values if necessary.
Improved: Configurator shows which is the default device as a hint to the user.
This commit is contained in:
jthedering committed 2015-09-27 16:01:21 +00:00
1 parent d68b958bc8
commit b8cdd47f71
284 files changed
+17622 -322

No files matched your search

+1
View File
@@ -17,6 +17,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include "BiQuad.h"
using namespace std;
+1
View File
@@ -17,6 +17,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include "helpers/MemoryHelper.h"
#include "BiQuadFilter.h"
+3 -3
View File
@@ -28,9 +28,9 @@ class BiQuadFilter : public IFilter
public:
BiQuadFilter(BiQuad::Type type, double dbGain, double freq, double bandwidthOrQOrS, bool isBandwidth, bool isCornerFreq);
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);
bool getInPlace() override {return true;}
std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames) override;
void process(float** output, float** input, unsigned frameCount) override;
BiQuad::Type getType() const;
double getDbGain() const;
+1
View File
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#define _USE_MATH_DEFINES
#include <cmath>
#include <regex>
+4 -4
View File
@@ -20,7 +20,7 @@
#pragma once
#include <string>
#include <hash_map>
#include <unordered_map>
#include "IFilterFactory.h"
#include "IFilter.h"
@@ -30,11 +30,11 @@ class BiQuadFilterFactory : public IFilterFactory
{
public:
BiQuadFilterFactory();
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
private:
double getFreq(const std::wstring& freqString);
stdext::hash_map<std::wstring, BiQuad::Type> filterNameToTypeMap;
stdext::hash_map<BiQuad::Type, std::wstring> filterTypeToDescriptionMap;
std::unordered_map<std::wstring, BiQuad::Type> filterNameToTypeMap;
std::unordered_map<BiQuad::Type, std::wstring> filterTypeToDescriptionMap;
};
+3 -1
View File
@@ -17,11 +17,13 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include <sstream>
#include <algorithm>
#include "helpers/MemoryHelper.h"
#include "helpers/LogHelper.h"
#include "helpers/ChannelHelper.h"
#include "ChannelFilter.h"
using namespace std;
@@ -48,7 +50,7 @@ vector<wstring> ChannelFilter::initialize(float sampleRate, unsigned maxFrameCou
if(currentWord == L"ALL")
selectedChannels = vector<bool>(channelCount, true);
else
channelNr = getChannelIndex(currentWord, channelNames);
channelNr = ChannelHelper::getChannelIndex(currentWord, channelNames);
if(channelNr != -1 && channelNr < (int)channelCount)
{
+4 -4
View File
@@ -30,10 +30,10 @@ 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);
bool getAllChannels() override {return true;}
bool getSelectChannels() override {return true;}
std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames) override;
void process(float** output, float** input, unsigned frameCount) override;
private:
std::vector<std::wstring> words;
+1
View File
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include "helpers/MemoryHelper.h"
#include "helpers/StringHelper.h"
#include "helpers/LogHelper.h"
+1 -1
View File
@@ -27,5 +27,5 @@
class ChannelFilterFactory : public IFilterFactory
{
public:
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
};
+136
View File
@@ -0,0 +1,136 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2015 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 "stdafx.h"
#include <cmath>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1
#include <sndfile.h>
#include <fftw3.h>
#include "helpers/LogHelper.h"
#include "helpers/MemoryHelper.h"
#include "ConvolutionFilter.h"
using namespace std;
ConvolutionFilter::ConvolutionFilter(wstring filename)
{
this->filename = filename;
filters = NULL;
}
ConvolutionFilter::~ConvolutionFilter()
{
cleanup();
}
vector<wstring> ConvolutionFilter::initialize(float sampleRate, unsigned maxFrameCount, vector<wstring> channelNames)
{
cleanup();
channelCount = (unsigned)channelNames.size();
SF_INFO info;
SNDFILE* inFile = sf_wchar_open(filename.c_str(), SFM_READ, &info);
if(inFile == NULL)
{
LogF(L"Error while reading impulse response file: %S", sf_strerror(inFile));
}
else if(abs(sampleRate - info.samplerate) > 1.0f)
{
LogF(L"Impulse response sample rate (%d Hz) does not match device sample rate (%f Hz)", info.samplerate, sampleRate);
}
else
{
TraceF(L"Convolving using impulse response file %s", filename.c_str());
unsigned fileChannelCount = info.channels;
unsigned frameCount = (unsigned)info.frames;
float* interleavedBuf = new float[frameCount * fileChannelCount];
sf_count_t numRead = 0;
while(numRead < frameCount)
numRead += sf_readf_float(inFile, interleavedBuf + numRead * fileChannelCount, frameCount - numRead);
sf_close(inFile);
inFile = NULL;
float** bufs = new float*[fileChannelCount];
for(unsigned i=0; i<fileChannelCount; i++)
{
float* buf = new float[frameCount];
float* p = interleavedBuf + i;
for(unsigned j=0; j<frameCount; j++)
{
buf[j] = p[j*fileChannelCount];
}
bufs[i] = buf;
}
filters = (HConvSingle*)MemoryHelper::alloc(sizeof(HConvSingle) * channelCount);
for(unsigned i=0; i<channelCount; i++)
{
hcInitSingle(&filters[i], bufs[i % fileChannelCount], frameCount, maxFrameCount, 1);
}
for(unsigned i=0; i<fileChannelCount; i++)
{
delete[] bufs[i];
}
delete bufs;
delete interleavedBuf;
}
return channelNames;
}
#pragma AVRT_CODE_BEGIN
void ConvolutionFilter::process(float** output, float** input, unsigned frameCount)
{
if(filters == NULL)
return;
for(unsigned i=0; i<channelCount; i++)
{
float* inputChannel = input[i];
float* outputChannel = output[i];
HConvSingle* filter = &filters[i];
hcPutSingle(filter, inputChannel);
hcProcessSingle(filter);
hcGetSingle(filter, outputChannel);
}
}
#pragma AVRT_CODE_END
void ConvolutionFilter::cleanup()
{
if(filters != NULL)
{
for(unsigned i=0; i<channelCount; i++)
hcCloseSingle(&filters[i]);
MemoryHelper::free(filters);
filters = NULL;
}
}
+42
View File
@@ -0,0 +1,42 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2015 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 "libHybridConv-0.1.1/libHybridConv_eapo.h"
#pragma AVRT_VTABLES_BEGIN
class ConvolutionFilter : public IFilter
{
public:
ConvolutionFilter(std::wstring filename);
virtual ~ConvolutionFilter();
bool getInPlace() override {return true;}
std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames) override;
void process(float** output, float** input, unsigned frameCount) override;
private:
void cleanup();
std::wstring filename;
HConvSingle* filters;
unsigned channelCount;
};
#pragma AVRT_VTABLES_END
+64
View File
@@ -0,0 +1,64 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2015 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 "stdafx.h"
#include <Shlwapi.h>
#include "helpers/MemoryHelper.h"
#include "helpers/StringHelper.h"
#include "helpers/LogHelper.h"
#include "ConvolutionFilter.h"
#include "ConvolutionFilterFactory.h"
using namespace std;
vector<IFilter*> ConvolutionFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
ConvolutionFilter* filter = NULL;
if(command == L"Convolution")
{
wstring value = parameters;
while(value.length() > 0 && iswspace(value[0]))
value = value.substr(1);
wstring absolutePath;
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());
absolutePath = filePath;
}
else
absolutePath = value;
void* mem = MemoryHelper::alloc(sizeof(ConvolutionFilter));
filter = new(mem) ConvolutionFilter(absolutePath);
}
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) 2015 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 ConvolutionFilterFactory : public IFilterFactory
{
public:
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
};
+10 -3
View File
@@ -17,11 +17,13 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include <algorithm>
#include <sstream>
#include "helpers/LogHelper.h"
#include "helpers/MemoryHelper.h"
#include "helpers/ChannelHelper.h"
#include "CopyFilter.h"
using namespace std;
@@ -54,7 +56,7 @@ vector<wstring> CopyFilter::initialize(float sampleRate, unsigned maxFrameCount,
Assignment& a = assignments[i];
wstring channelName = a.targetChannel;
int channelIndex = getChannelIndex(a.targetChannel, channelNames, true);
int channelIndex = ChannelHelper::getChannelIndex(a.targetChannel, channelNames, true);
if(channelIndex != -1)
channelName = channelNames[channelIndex];
vector<wstring>::const_iterator it = find(outChannelNames.begin(), outChannelNames.end(), channelName);
@@ -69,9 +71,9 @@ vector<wstring> CopyFilter::initialize(float sampleRate, unsigned maxFrameCount,
{
InternalAssignment::InternalSummand& is = ia.sourceSum[j];
Assignment::Summand& s = a.sourceSum[j];
if(s.channel != L"")
is.channel = getChannelIndex(s.channel, channelNames);
is.channel = ChannelHelper::getChannelIndex(s.channel, channelNames);
else
is.channel = -1;
@@ -165,3 +167,8 @@ void CopyFilter::cleanup()
internalAssignments = NULL;
}
}
std::vector<Assignment> CopyFilter::getAssignments() const
{
return assignments;
}
+6 -4
View File
@@ -44,10 +44,12 @@ 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);
bool getAllChannels() override {return true;}
bool getInPlace() override {return false;}
std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames) override;
void process(float** output, float** input, unsigned frameCount) override;
std::vector<Assignment> getAssignments() const;
private:
void cleanup();
+1
View File
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include "helpers/MemoryHelper.h"
#include "helpers/StringHelper.h"
#include "helpers/LogHelper.h"
+1 -1
View File
@@ -27,5 +27,5 @@
class CopyFilterFactory : public IFilterFactory
{
public:
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
};
+12 -1
View File
@@ -17,6 +17,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include <cmath>
#include "helpers/MemoryHelper.h"
@@ -109,4 +110,14 @@ void DelayFilter::cleanup()
MemoryHelper::free(buffers);
buffers = NULL;
}
}
}
bool DelayFilter::getIsMs() const
{
return isMs;
}
double DelayFilter::getDelay() const
{
return delay;
}
+6 -3
View File
@@ -27,9 +27,12 @@ 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);
bool getInPlace() override {return false;}
std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames) override;
void process(float** output, float** input, unsigned frameCount) override;
double getDelay() const;
bool getIsMs() const;
private:
void cleanup();
+4 -3
View File
@@ -17,6 +17,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include <sstream>
#include "helpers/MemoryHelper.h"
@@ -36,12 +37,12 @@ vector<IFilter*> DelayFilterFactory::createFilter(const wstring& configPath, wst
//Conversion to period as decimal mark, if needed
wstring value = StringHelper::replaceCharacters(parameters, L",", L".");
double delay = 0;
double delay = -1;
wstring unit;
wstringstream stream(value);
stream >> delay >> unit;
if(delay > 0)
if(delay >= 0)
{
if(StringHelper::toLowerCase(unit) == L"ms")
{
@@ -61,4 +62,4 @@ vector<IFilter*> DelayFilterFactory::createFilter(const wstring& configPath, wst
if(filter == NULL)
return vector<IFilter*>(0);
return vector<IFilter*>(1, filter);
}
}
+1 -1
View File
@@ -27,5 +27,5 @@
class DelayFilterFactory : public IFilterFactory
{
public:
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
};
+63 -51
View File
@@ -17,13 +17,17 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include "helpers/LogHelper.h"
#include "helpers/StringHelper.h"
#ifndef NO_FILTERENGINE
#include "FilterEngine.h"
#endif
#include "DeviceFilterFactory.h"
using namespace std;
#ifndef NO_FILTERENGINE
void DeviceFilterFactory::initialize(FilterEngine* engine)
{
deviceString = engine->getDeviceName() + L" " + engine->getConnectionName() + L" " + engine->getDeviceGuid();
@@ -33,6 +37,7 @@ void DeviceFilterFactory::initialize(FilterEngine* engine)
parser->DefineConst(L"connectionName", engine->getConnectionName());
parser->DefineConst(L"deviceGuid", engine->getDeviceGuid());
}
#endif
vector<IFilter*> DeviceFilterFactory::startOfConfiguration()
{
@@ -45,58 +50,9 @@ vector<IFilter*> DeviceFilterFactory::createFilter(const wstring& configPath, ws
{
if(command == L"Device")
{
wstring value = StringHelper::trim(parameters) + L";";
bool matches = matchDevice(deviceString, parameters);
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());
TraceF(L"%satching pattern \"%s\" with device \"%s\"", matches ? L"M" : L"Not m", StringHelper::trim(parameters).c_str(), deviceString.c_str());
deviceMatches = matches;
}
@@ -114,3 +70,59 @@ std::vector<IFilter*> DeviceFilterFactory::endOfFile(const std::wstring& configP
return vector<IFilter*>();
}
bool DeviceFilterFactory::matchDevice(const std::wstring& deviceString, const std::wstring& pattern)
{
wstring value = StringHelper::trim(pattern) + 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;
}
return matches;
}
+8 -4
View File
@@ -27,10 +27,14 @@
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);
#ifndef NO_FILTERENGINE
void initialize(FilterEngine* engine) override;
#endif
std::vector<IFilter*> startOfConfiguration() override;
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
std::vector<IFilter*> endOfFile(const std::wstring& configPath) override;
static bool matchDevice(const std::wstring& deviceString, const std::wstring& pattern);
private:
bool deviceMatches;
+1
View File
@@ -17,6 +17,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include <sstream>
#include "helpers/LogHelper.h"
+2 -2
View File
@@ -28,8 +28,8 @@
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);
void initialize(FilterEngine* engine) override;
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
private:
mup::ParserX* parser;
+186
View File
@@ -0,0 +1,186 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2015 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 "stdafx.h"
#define _USE_MATH_DEFINES
#include <cmath>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1
#include <sndfile.h>
#include "helpers/LogHelper.h"
#include "helpers/MemoryHelper.h"
#include "GraphicEQFilter.h"
using namespace std;
GraphicEQFilter::GraphicEQFilter(const std::vector<FilterNode>& nodes, unsigned filterLength)
:nodes(nodes), filterLength(filterLength)
{
filters = NULL;
}
GraphicEQFilter::~GraphicEQFilter()
{
cleanup();
}
vector<wstring> GraphicEQFilter::initialize(float sampleRate, unsigned maxFrameCount, vector<wstring> channelNames)
{
cleanup();
channelCount = (unsigned)channelNames.size();
fftwf_complex* timeData = fftwf_alloc_complex(filterLength * 2);
fftwf_complex* freqData = fftwf_alloc_complex(filterLength * 2);
fftwf_plan planForward = fftwf_plan_dft_1d(filterLength * 2, timeData, freqData, FFTW_FORWARD, FFTW_ESTIMATE);
fftwf_plan planReverse = fftwf_plan_dft_1d(filterLength * 2, freqData, timeData, FFTW_BACKWARD, FFTW_ESTIMATE);
GainIterator gainIterator(nodes);
for(unsigned i=0; i<filterLength; i++)
{
double freq = i*1.0*sampleRate/(filterLength * 2);
double dbGain = gainIterator.gainAt(freq);
float gain = (float)pow(10.0, dbGain / 20.0);
freqData[i][0] = gain;
freqData[i][1] = 0;
freqData[2*filterLength-i-1][0] = gain;
freqData[2*filterLength-i-1][1] = 0;
}
mps(timeData, freqData, planForward, planReverse);
fftwf_execute(planReverse);
for(unsigned i=0; i<2*filterLength; i++)
{
timeData[i][0] /= 2*filterLength;
timeData[i][1] /= 2*filterLength;
}
for(unsigned i=0; i<filterLength; i++)
{
float factor=(float)(0.5*(1+cos(2*M_PI*i*1.0/(2*filterLength))));
timeData[i][0] *= factor;
timeData[i][1] *= factor;
}
float* buf = new float[filterLength];
for(unsigned i=0; i<filterLength; i++)
{
buf[i] = timeData[i][0];
}
fftwf_free(timeData);
fftwf_free(freqData);
fftwf_destroy_plan(planForward);
fftwf_destroy_plan(planReverse);
filters = (HConvSingle*)MemoryHelper::alloc(sizeof(HConvSingle) * channelCount);
for(unsigned i=0; i<channelCount; i++)
{
hcInitSingle(&filters[i], buf, filterLength, maxFrameCount, 1);
}
delete buf;
return channelNames;
}
#pragma AVRT_CODE_BEGIN
void GraphicEQFilter::process(float** output, float** input, unsigned frameCount)
{
if(filters == NULL)
return;
for(unsigned i=0; i<channelCount; i++)
{
float* inputChannel = input[i];
float* outputChannel = output[i];
HConvSingle* filter = &filters[i];
hcPutSingle(filter, inputChannel);
hcProcessSingle(filter);
hcGetSingle(filter, outputChannel);
}
}
#pragma AVRT_CODE_END
const std::vector<FilterNode>& GraphicEQFilter::getNodes()
{
return nodes;
}
void GraphicEQFilter::cleanup()
{
if(filters != NULL)
{
for(unsigned i=0; i<channelCount; i++)
hcCloseSingle(&filters[i]);
MemoryHelper::free(filters);
filters = NULL;
}
}
// Minimum phase spectrum from coefficients
void GraphicEQFilter::mps(fftwf_complex* timeData, fftwf_complex* freqData, fftwf_plan planForward, fftwf_plan planReverse)
{
double threshold=pow(10.0, -100.0/20.0);
float logThreshold=(float)log(threshold);
for(unsigned i=0; i<filterLength * 2; i++)
{
if(freqData[i][0] < threshold)
freqData[i][0] = logThreshold;
else
freqData[i][0] = log(freqData[i][0]);
freqData[i][1]=0;
}
fftwf_execute(planReverse);
for(unsigned i=0; i<filterLength * 2; i++)
{
timeData[i][0] /= filterLength * 2;
timeData[i][1] /= filterLength * 2;
}
for(unsigned i=1; i<filterLength; i++)
{
timeData[i][0] += timeData[filterLength*2 - i][0];
timeData[i][1] -= timeData[filterLength*2 - i][1];
timeData[filterLength*2 - i][0] = 0;
timeData[filterLength*2 - i][1] = 0;
}
timeData[filterLength][1] *= -1;
fftwf_execute(planForward);
for(unsigned i=0; i<filterLength * 2; i++)
{
double eR=exp(freqData[i][0]);
freqData[i][0]=float(eR*cos(freqData[i][1]));
freqData[i][1]=float(eR*sin(freqData[i][1]));
}
}
+49
View File
@@ -0,0 +1,49 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2015 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 <fftw3.h>
#include "IFilter.h"
#include "libHybridConv-0.1.1/libHybridConv_eapo.h"
#include "helpers/GainIterator.h"
#pragma AVRT_VTABLES_BEGIN
class GraphicEQFilter : public IFilter
{
public:
GraphicEQFilter(const std::vector<FilterNode>& nodes, unsigned filterLength);
virtual ~GraphicEQFilter();
bool getInPlace() override {return true;}
std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames) override;
void process(float** output, float** input, unsigned frameCount) override;
const std::vector<FilterNode>& getNodes();
private:
void cleanup();
void mps(fftwf_complex* timeData, fftwf_complex* freqData, fftwf_plan planForward, fftwf_plan planReverse);
std::vector<FilterNode> nodes;
unsigned filterLength;
HConvSingle* filters;
unsigned channelCount;
};
#pragma AVRT_VTABLES_END
+70
View File
@@ -0,0 +1,70 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2015 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 "stdafx.h"
#include <regex>
#include "helpers/MemoryHelper.h"
#include "helpers/StringHelper.h"
#include "helpers/LogHelper.h"
#include "GraphicEQFilter.h"
#include "GraphicEQFilterFactory.h"
using namespace std;
static wregex regexNumber(L"[-+0-9.eE]+");
vector<IFilter*> GraphicEQFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
{
GraphicEQFilter* filter = NULL;
if(command == L"GraphicEQ")
{
wstring value = parameters;
if(value.find(L'.') == wstring::npos)
value = StringHelper::replaceCharacters(value, L",", L".");
wsregex_iterator begin(value.begin(), value.end(), regexNumber);
wsregex_iterator end;
vector<FilterNode> nodes;
for(wsregex_iterator it = begin; it != end; it++)
{
wsmatch freqMatch = *it++;
if(it != end)
{
wsmatch gainMatch = *it;
double freq = wcstod(freqMatch.str(0).c_str(), NULL);
double gain = wcstod(gainMatch.str(0).c_str(), NULL);
FilterNode node(freq, gain);
nodes.push_back(node);
}
}
sort(nodes.begin(), nodes.end());
TraceF(L"Graphic equalizer with %d nodes", nodes.size());
void* mem = MemoryHelper::alloc(sizeof(GraphicEQFilter));
filter = new(mem) GraphicEQFilter(nodes, 16384);
}
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) 2015 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 GraphicEQFilterFactory : public IFilterFactory
{
public:
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
};
+1
View File
@@ -17,6 +17,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include "helpers/MemoryHelper.h"
#include "IIRFilter.h"
+3 -3
View File
@@ -27,9 +27,9 @@ 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);
bool getInPlace() override {return true;}
std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames) override;
void process(float** output, float** input, unsigned frameCount) override;
private:
unsigned order;
+1
View File
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#define _USE_MATH_DEFINES
#include <cmath>
#include <regex>
+1 -2
View File
@@ -20,7 +20,6 @@
#pragma once
#include <string>
#include <hash_map>
#include "IFilterFactory.h"
#include "IFilter.h"
@@ -29,5 +28,5 @@ class IIRFilterFactory : public IFilterFactory
{
public:
IIRFilterFactory();
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
};
+1
View File
@@ -17,6 +17,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include "helpers/LogHelper.h"
#include "helpers/StringHelper.h"
#include "parser/RegexFunctions.h"
+5 -5
View File
@@ -28,11 +28,11 @@
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);
void initialize(FilterEngine* engine) override;
std::vector<IFilter*> startOfConfiguration() override;
std::vector<IFilter*> startOfFile(const std::wstring& configPath) override;
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
std::vector<IFilter*> endOfFile(const std::wstring& configPath) override;
private:
mup::ParserX* parser;
+1
View File
@@ -17,6 +17,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include <Shlwapi.h>
#include "helpers/LogHelper.h"
+2 -2
View File
@@ -27,8 +27,8 @@
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);
void initialize(FilterEngine* engine) override;
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
private:
FilterEngine* engine;
+1
View File
@@ -17,6 +17,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#define _USE_MATH_DEFINES
#include <cmath>
+4 -2
View File
@@ -26,8 +26,10 @@ 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);
std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames) override;
void process(float** output, float** input, unsigned frameCount) override;
double getDbGain() const {return dbGain;}
private:
float gain;
+2 -1
View File
@@ -17,6 +17,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include "helpers/MemoryHelper.h"
#include "helpers/StringHelper.h"
#include "helpers/LogHelper.h"
@@ -48,4 +49,4 @@ vector<IFilter*> PreampFilterFactory::createFilter(const wstring& configPath, ws
if(filter == NULL)
return vector<IFilter*>(0);
return vector<IFilter*>(1, filter);
}
}
+1 -1
View File
@@ -27,5 +27,5 @@
class PreampFilterFactory : public IFilterFactory
{
public:
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
};
+1
View File
@@ -17,6 +17,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include "helpers/LogHelper.h"
#include "helpers/StringHelper.h"
#include "FilterEngine.h"
+5 -5
View File
@@ -27,11 +27,11 @@
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);
void initialize(FilterEngine* engine) override;
std::vector<IFilter*> startOfConfiguration() override;
std::vector<IFilter*> startOfFile(const std::wstring& configPath) override;
std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) override;
std::vector<IFilter*> endOfFile(const std::wstring& configPath) override;
private:
bool preMix;