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:
1 parent
11e52f6210
commit
90ee2b0aa9
89 files changed
+6396
-1375
No files matched your search
+63
-26
@@ -17,20 +17,27 @@
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
#include <cstdio>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <sndfile.h>
|
||||
#include <tclap/CmdLine.h>
|
||||
#include <mpParser.h>
|
||||
|
||||
#include "../version.h"
|
||||
#include "../ParametricEQ.h"
|
||||
#include "../LogHelper.h"
|
||||
#include "../StringHelper.h"
|
||||
#include "PerformanceCounter.h"
|
||||
#include "version.h"
|
||||
#include "FilterEngine.h"
|
||||
#include "helpers/LogHelper.h"
|
||||
#include "helpers/StringHelper.h"
|
||||
#include "helpers/PrecisionTimer.h"
|
||||
#include "helpers/MemoryHelper.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace mup;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
@@ -54,13 +61,18 @@ int main(int argc, char** argv)
|
||||
TCLAP::ValueArg<string> inputArg("i", "input", "File to load sound data from instead of generating sweep", false, "", "string", cmd);
|
||||
TCLAP::ValueArg<unsigned> rateArg("r", "rate", "Sample rate of generated sweep (Default: 44100)", false, 44100, "integer", cmd);
|
||||
TCLAP::ValueArg<float> toArg("t", "to", "End frequency of generated sweep in Hz (Default: 20000.0)", false, 20000.0f, "float", cmd);
|
||||
TCLAP::ValueArg<float> fromArg("f", "from", "Start frequency of generated sweep in Hz (Default: 0.1)", false, 0.1f, "float", cmd);
|
||||
TCLAP::ValueArg<float> fromArg("f", "from", "Start frequency of generated sweep in Hz (Default: 0.1)", false, 1.0f, "float", cmd);
|
||||
TCLAP::ValueArg<float> lengthArg("l", "length", "Length of generated sweep in seconds (Default: 200.0)", false, 200.0f, "float", cmd);
|
||||
TCLAP::ValueArg<unsigned> channelArg("c", "channels", "Number of channels of generated sweep (Default: 2)", false, 2, "integer", cmd);
|
||||
|
||||
cmd.parse(argc, argv);
|
||||
|
||||
LogHelper::set(stderr, verboseArg.getValue(), true, true);
|
||||
bool verbose = verboseArg.getValue();
|
||||
LogHelper::set(stderr, verbose, true, true);
|
||||
#ifdef _DEBUG
|
||||
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
|
||||
//_CrtSetBreakAlloc(3318);
|
||||
#endif
|
||||
|
||||
unsigned sampleRate;
|
||||
unsigned channelCount;
|
||||
@@ -80,8 +92,12 @@ int main(int argc, char** argv)
|
||||
string input = inputArg.getValue();
|
||||
if(input != "")
|
||||
{
|
||||
SF_INFO info;
|
||||
printf("Reading sound data from %s\n", input.c_str());
|
||||
|
||||
PrecisionTimer timer;
|
||||
timer.start();
|
||||
|
||||
SF_INFO info;
|
||||
SNDFILE* inFile = sf_open(input.c_str(), SFM_READ, &info);
|
||||
if(inFile == NULL)
|
||||
{
|
||||
@@ -103,6 +119,9 @@ int main(int argc, char** argv)
|
||||
|
||||
sf_close(inFile);
|
||||
inFile = NULL;
|
||||
|
||||
double readTime = timer.stop();
|
||||
printf("Reading input file took %g seconds\n", readTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -117,32 +136,49 @@ int main(int argc, char** argv)
|
||||
|
||||
printf("No input file given, so generating linear sine sweep from %g to %g Hz over %g seconds\n", sweepFrom, sweepTo, length);
|
||||
|
||||
PrecisionTimer timer;
|
||||
timer.start();
|
||||
|
||||
buf = new float[frameCount * channelCount];
|
||||
for(unsigned i=0; i<frameCount; i++)
|
||||
{
|
||||
double t=i*1.0 / sampleRate;
|
||||
float s = (float)sin(((sweepFrom + sweepDiff*(t/length)/2)*t)*2*M_PI);
|
||||
|
||||
for(unsigned i=0;i<frameCount;i++)
|
||||
for(unsigned j=0;j<channelCount;j++)
|
||||
{
|
||||
float t=(i*1.0f / sampleRate);
|
||||
for(unsigned j=0; j<channelCount; j++)
|
||||
buf[i*channelCount + j] = s;
|
||||
}
|
||||
|
||||
buf[i*channelCount + j] = sin(((sweepFrom + sweepDiff*(t/length)/2)*t)*2*(float)M_PI);
|
||||
}
|
||||
double genTime = timer.stop();
|
||||
printf("Generating sweep took %g seconds\n", genTime);
|
||||
}
|
||||
|
||||
printf("\nProcessing %d frames from %d channel(s)\n", frameCount, channelCount);
|
||||
unsigned batchsize = batchsizeArg.getValue();
|
||||
|
||||
ParametricEQ peq;
|
||||
peq.setDeviceInfo(StringHelper::toWString(devicenameArg.getValue(), CP_ACP),
|
||||
StringHelper::toWString(connectionnameArg.getValue(), CP_ACP),
|
||||
StringHelper::toWString(guidArg.getValue(), CP_ACP));
|
||||
peq.initialize((float)sampleRate, channelCount, channelMask);
|
||||
float* buf2 = new float[frameCount * channelCount];
|
||||
for(unsigned i=0;i<frameCount*channelCount;i++)
|
||||
buf2[i]=0.0f;
|
||||
|
||||
PrecisionTimer timer;
|
||||
timer.start();
|
||||
|
||||
unsigned batchsize = batchsizeArg.getValue();
|
||||
FilterEngine engine;
|
||||
engine.setDeviceInfo(false, StringHelper::toWString(devicenameArg.getValue(), CP_ACP),
|
||||
StringHelper::toWString(connectionnameArg.getValue(), CP_ACP),
|
||||
StringHelper::toWString(guidArg.getValue(), CP_ACP));
|
||||
engine.initialize((float)sampleRate, channelCount, channelCount, channelCount, channelMask, batchsize);
|
||||
|
||||
double initTime = timer.stop();
|
||||
if(!verbose)
|
||||
printf("\nLoading configuration took %g ms\n", initTime * 1000.0);
|
||||
|
||||
printf("\nProcessing %d frames from %d channel(s)\n", frameCount, channelCount);
|
||||
|
||||
timer.start();
|
||||
|
||||
for(unsigned i=0; i<frameCount; i+=batchsize)
|
||||
{
|
||||
peq.process(buf + i*channelCount, buf + i*channelCount, min(batchsize, frameCount - i));
|
||||
engine.process(buf2 + i*channelCount, buf + i*channelCount, min(batchsize, frameCount - i));
|
||||
}
|
||||
|
||||
double time = timer.stop();
|
||||
@@ -154,7 +190,7 @@ int main(int argc, char** argv)
|
||||
float max = 0;
|
||||
for(unsigned i=0; i<frameCount*channelCount; i++)
|
||||
{
|
||||
float f = fabs(buf[i]);
|
||||
float f = fabs(buf2[i]);
|
||||
if(f > max)
|
||||
max = f;
|
||||
if(f > 1.0f)
|
||||
@@ -188,12 +224,13 @@ int main(int argc, char** argv)
|
||||
|
||||
sf_count_t numWritten = 0;
|
||||
while(numWritten < frameCount)
|
||||
numWritten += sf_writef_float(outFile, buf + numWritten * channelCount, frameCount - numWritten);
|
||||
numWritten += sf_writef_float(outFile, buf2 + numWritten * channelCount, frameCount - numWritten);
|
||||
|
||||
sf_close(outFile);
|
||||
outFile = NULL;
|
||||
|
||||
delete[] buf;
|
||||
delete[] buf2;
|
||||
|
||||
if(!noPauseArg.getValue())
|
||||
system("pause");
|
||||
@@ -202,7 +239,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
catch(TCLAP::ArgException e)
|
||||
{
|
||||
printf("Error: %s for arg %s\n", e.error(), e.argId());
|
||||
printf("Error: %s for arg %s\n", e.error().c_str(), e.argId().c_str());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
-23
@@ -64,23 +64,23 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>C:\Program Files\tclap-1.2.1\include;C:\Program Files\libsndfile\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files\libsndfile\lib;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>$(SolutionDir);C:\Program Files\tclap-1.2.1\include;C:\Program Files\libsndfile\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files (x86)\libsndfile\lib;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>C:\Program Files\tclap-1.2.1\include;C:\Program Files\libsndfile\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files\libsndfile\lib64;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>$(SolutionDir);C:\Program Files\tclap-1.2.1\include;C:\Program Files\libsndfile\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files\libsndfile\lib;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>C:\Program Files\tclap-1.2.1\include;C:\Program Files\libsndfile\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files\libsndfile\lib;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>$(SolutionDir);C:\Program Files\tclap-1.2.1\include;C:\Program Files\libsndfile\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files (x86)\libsndfile\lib;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>C:\Program Files\tclap-1.2.1\include;C:\Program Files\libsndfile\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files\libsndfile\lib64;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>$(SolutionDir);C:\Program Files\tclap-1.2.1\include;C:\Program Files\libsndfile\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files\libsndfile\lib;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
@@ -93,7 +93,7 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>version.lib;Shlwapi.lib;libsndfile-1.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>muparserxd.lib;version.lib;Shlwapi.lib;libsndfile-1.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -107,7 +107,7 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>version.lib;Shlwapi.lib;libsndfile-1.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>muparserxd.lib;version.lib;Shlwapi.lib;libsndfile-1.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@@ -126,7 +126,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>version.lib;Shlwapi.lib;libsndfile-1.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>muparserx.lib;version.lib;Shlwapi.lib;libsndfile-1.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -145,24 +145,71 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>version.lib;Shlwapi.lib;libsndfile-1.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>muparserx.lib;version.lib;Shlwapi.lib;libsndfile-1.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\BiQuad.cpp" />
|
||||
<ClCompile Include="..\LogHelper.cpp" />
|
||||
<ClCompile Include="..\ParametricEQ.cpp" />
|
||||
<ClCompile Include="..\RegistryHelper.cpp" />
|
||||
<ClCompile Include="..\StringHelper.cpp" />
|
||||
<ClCompile Include="..\FilterConfiguration.cpp" />
|
||||
<ClCompile Include="..\FilterEngine.cpp" />
|
||||
<ClCompile Include="..\filters\BiQuad.cpp" />
|
||||
<ClCompile Include="..\filters\BiQuadFilter.cpp" />
|
||||
<ClCompile Include="..\filters\BiQuadFilterFactory.cpp" />
|
||||
<ClCompile Include="..\filters\ChannelFilter.cpp" />
|
||||
<ClCompile Include="..\filters\ChannelFilterFactory.cpp" />
|
||||
<ClCompile Include="..\filters\CopyFilter.cpp" />
|
||||
<ClCompile Include="..\filters\CopyFilterFactory.cpp" />
|
||||
<ClCompile Include="..\filters\DelayFilter.cpp" />
|
||||
<ClCompile Include="..\filters\DelayFilterFactory.cpp" />
|
||||
<ClCompile Include="..\filters\DeviceFilterFactory.cpp" />
|
||||
<ClCompile Include="..\filters\ExpressionFilterFactory.cpp" />
|
||||
<ClCompile Include="..\filters\IfFilterFactory.cpp" />
|
||||
<ClCompile Include="..\filters\IIRFilter.cpp" />
|
||||
<ClCompile Include="..\filters\IIRFilterFactory.cpp" />
|
||||
<ClCompile Include="..\filters\IncludeFilterFactory.cpp" />
|
||||
<ClCompile Include="..\filters\PreampFilter.cpp" />
|
||||
<ClCompile Include="..\filters\PreampFilterFactory.cpp" />
|
||||
<ClCompile Include="..\filters\StageFilterFactory.cpp" />
|
||||
<ClCompile Include="..\helpers\LogHelper.cpp" />
|
||||
<ClCompile Include="..\helpers\MemoryHelper.cpp" />
|
||||
<ClCompile Include="..\helpers\RegistryHelper.cpp" />
|
||||
<ClCompile Include="..\helpers\StringHelper.cpp" />
|
||||
<ClCompile Include="..\IFilter.cpp" />
|
||||
<ClCompile Include="..\parser\RegexFunctions.cpp" />
|
||||
<ClCompile Include="..\parser\RegistryFunctions.cpp" />
|
||||
<ClCompile Include="..\parser\StringOperators.cpp" />
|
||||
<ClCompile Include="Benchmark.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\BiQuad.h" />
|
||||
<ClInclude Include="..\LogHelper.h" />
|
||||
<ClInclude Include="..\ParametricEQ.h" />
|
||||
<ClInclude Include="..\RegistryHelper.h" />
|
||||
<ClInclude Include="..\StringHelper.h" />
|
||||
<ClInclude Include="PerformanceCounter.h" />
|
||||
<ClInclude Include="..\FilterConfiguration.h" />
|
||||
<ClInclude Include="..\FilterEngine.h" />
|
||||
<ClInclude Include="..\filters\BiQuad.h" />
|
||||
<ClInclude Include="..\filters\BiQuadFilter.h" />
|
||||
<ClInclude Include="..\filters\BiQuadFilterFactory.h" />
|
||||
<ClInclude Include="..\filters\ChannelFilter.h" />
|
||||
<ClInclude Include="..\filters\ChannelFilterFactory.h" />
|
||||
<ClInclude Include="..\filters\CopyFilter.h" />
|
||||
<ClInclude Include="..\filters\CopyFilterFactory.h" />
|
||||
<ClInclude Include="..\filters\DelayFilter.h" />
|
||||
<ClInclude Include="..\filters\DelayFilterFactory.h" />
|
||||
<ClInclude Include="..\filters\DeviceFilterFactory.h" />
|
||||
<ClInclude Include="..\filters\ExpressionFilterFactory.h" />
|
||||
<ClInclude Include="..\filters\IfFilterFactory.h" />
|
||||
<ClInclude Include="..\filters\IIRFilter.h" />
|
||||
<ClInclude Include="..\filters\IIRFilterFactory.h" />
|
||||
<ClInclude Include="..\filters\IncludeFilterFactory.h" />
|
||||
<ClInclude Include="..\filters\PreampFilter.h" />
|
||||
<ClInclude Include="..\filters\PreampFilterFactory.h" />
|
||||
<ClInclude Include="..\filters\StageFilterFactory.h" />
|
||||
<ClInclude Include="..\helpers\LogHelper.h" />
|
||||
<ClInclude Include="..\helpers\MemoryHelper.h" />
|
||||
<ClInclude Include="..\helpers\PrecisionTimer.h" />
|
||||
<ClInclude Include="..\helpers\RegistryHelper.h" />
|
||||
<ClInclude Include="..\helpers\StringHelper.h" />
|
||||
<ClInclude Include="..\IFilter.h" />
|
||||
<ClInclude Include="..\IFilterFactory.h" />
|
||||
<ClInclude Include="..\parser\RegexFunctions.h" />
|
||||
<ClInclude Include="..\parser\RegistryFunctions.h" />
|
||||
<ClInclude Include="..\parser\StringOperators.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\FilterEngine.cpp" />
|
||||
<ClCompile Include="Benchmark.cpp" />
|
||||
<ClCompile Include="..\FilterConfiguration.cpp" />
|
||||
<ClCompile Include="..\IFilter.cpp" />
|
||||
<ClCompile Include="..\parser\RegexFunctions.cpp">
|
||||
<Filter>parser</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\parser\RegistryFunctions.cpp">
|
||||
<Filter>parser</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\BiQuad.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\BiQuadFilter.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\BiQuadFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\ChannelFilter.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\ChannelFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\CopyFilter.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\CopyFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\DelayFilter.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\DelayFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\DeviceFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\ExpressionFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\IncludeFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\PreampFilter.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\PreampFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\StageFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\helpers\LogHelper.cpp">
|
||||
<Filter>helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\helpers\MemoryHelper.cpp">
|
||||
<Filter>helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\helpers\RegistryHelper.cpp">
|
||||
<Filter>helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\helpers\StringHelper.cpp">
|
||||
<Filter>helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\IfFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\IIRFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\filters\IIRFilter.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\parser\StringOperators.cpp">
|
||||
<Filter>parser</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\FilterEngine.h" />
|
||||
<ClInclude Include="..\FilterConfiguration.h" />
|
||||
<ClInclude Include="..\IFilterFactory.h" />
|
||||
<ClInclude Include="..\IFilter.h" />
|
||||
<ClInclude Include="..\parser\RegexFunctions.h">
|
||||
<Filter>parser</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\parser\RegistryFunctions.h">
|
||||
<Filter>parser</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\BiQuad.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\BiQuadFilter.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\BiQuadFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\ChannelFilter.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\ChannelFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\CopyFilter.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\CopyFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\DelayFilter.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\DelayFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\DeviceFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\ExpressionFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\IncludeFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\PreampFilter.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\PreampFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\StageFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\helpers\LogHelper.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\helpers\MemoryHelper.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\helpers\PrecisionTimer.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\helpers\RegistryHelper.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\helpers\StringHelper.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\IfFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\IIRFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\filters\IIRFilter.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\parser\StringOperators.h">
|
||||
<Filter>parser</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="parser">
|
||||
<UniqueIdentifier>{af133437-31da-454b-abde-b62ce82af9b1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="filters">
|
||||
<UniqueIdentifier>{80c1c047-44e8-49fc-81d6-349c41e979a7}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="helpers">
|
||||
<UniqueIdentifier>{4bf76d90-8b50-493a-848b-019f88fa1f11}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "EqualizerAPO.h"
|
||||
#include "LogHelper.h"
|
||||
#include "helpers/LogHelper.h"
|
||||
#include "ClassFactory.h"
|
||||
|
||||
long ClassFactory::lockCount = 0;
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include "../StringHelper.h"
|
||||
#include "../RegistryHelper.h"
|
||||
#include "helpers/StringHelper.h"
|
||||
#include "helpers/RegistryHelper.h"
|
||||
#include "Configurator.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "resource.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "../DeviceAPOInfo.h"
|
||||
#include "DeviceAPOInfo.h"
|
||||
|
||||
class Configurator
|
||||
{
|
||||
|
||||
@@ -20,15 +20,20 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\DeviceAPOInfo.h" />
|
||||
<ClInclude Include="..\RegistryHelper.h" />
|
||||
<ClInclude Include="..\StringHelper.h" />
|
||||
<ClInclude Include="..\helpers\LogHelper.h" />
|
||||
<ClInclude Include="..\helpers\MemoryHelper.h" />
|
||||
<ClInclude Include="..\helpers\PrecisionTimer.h" />
|
||||
<ClInclude Include="..\helpers\RegistryHelper.h" />
|
||||
<ClInclude Include="..\helpers\StringHelper.h" />
|
||||
<ClInclude Include="Configurator.h" />
|
||||
<ClInclude Include="Resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\DeviceAPOInfo.cpp" />
|
||||
<ClCompile Include="..\RegistryHelper.cpp" />
|
||||
<ClCompile Include="..\StringHelper.cpp" />
|
||||
<ClCompile Include="..\helpers\LogHelper.cpp" />
|
||||
<ClCompile Include="..\helpers\MemoryHelper.cpp" />
|
||||
<ClCompile Include="..\helpers\RegistryHelper.cpp" />
|
||||
<ClCompile Include="..\helpers\StringHelper.cpp" />
|
||||
<ClCompile Include="Configurator.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -89,35 +94,39 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<IncludePath>$(SolutionDir);$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<LibraryPath>$(LibraryPath);$(DDK_PATH)\lib\win7\i386</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<IncludePath>$(SolutionDir);$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<LibraryPath>$(LibraryPath);$(DDK_PATH)\lib\win7\amd64</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<IncludePath>$(SolutionDir);$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<LibraryPath>$(LibraryPath);$(DDK_PATH)\lib\win7\i386</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<IncludePath>$(SolutionDir);$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<LibraryPath>$(LibraryPath);$(DDK_PATH)\lib\win7\amd64</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;USE_WINDDK;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>version.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>audioeng.lib;version.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -125,12 +134,12 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;USE_WINDDK;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>version.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>audioeng.lib;version.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@@ -140,14 +149,14 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;USE_WINDDK;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>version.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>audioeng.lib;version.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -157,14 +166,14 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;USE_WINDDK;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>version.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>audioeng.lib;version.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\DeviceAPOInfo.cpp" />
|
||||
<ClCompile Include="Configurator.cpp" />
|
||||
<ClCompile Include="..\helpers\LogHelper.cpp">
|
||||
<Filter>helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\helpers\MemoryHelper.cpp">
|
||||
<Filter>helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\helpers\RegistryHelper.cpp">
|
||||
<Filter>helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\helpers\StringHelper.cpp">
|
||||
<Filter>helpers</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\DeviceAPOInfo.h" />
|
||||
<ClInclude Include="Configurator.h" />
|
||||
<ClInclude Include="Resource.h" />
|
||||
<ClInclude Include="..\helpers\LogHelper.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\helpers\MemoryHelper.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\helpers\PrecisionTimer.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\helpers\RegistryHelper.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\helpers\StringHelper.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Configurator.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Configurator.ico" />
|
||||
<None Include="small.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="Configurator.exe.manifest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="helpers">
|
||||
<UniqueIdentifier>{2584359f-ce98-42d5-b685-6c295bb97f68}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+128
-71
@@ -22,13 +22,12 @@
|
||||
#include "DeviceAPOInfo.h"
|
||||
|
||||
#include "EqualizerAPO.h"
|
||||
#include "ParametricEQ.h"
|
||||
#include "StringHelper.h"
|
||||
#include "RegistryHelper.h"
|
||||
#include "helpers/StringHelper.h"
|
||||
#include "helpers/RegistryHelper.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define commonKeyPath L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\MMDevices\\Audio"
|
||||
#define commonKeyPath L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\MMDevices\\Audio"
|
||||
#define renderKeyPath commonKeyPath L"\\Render"
|
||||
#define captureKeyPath commonKeyPath L"\\Capture"
|
||||
static const wchar_t* connectionValueName = L"{a45c254e-df1c-4efd-8020-67d146a850e0},2";
|
||||
@@ -84,51 +83,87 @@ bool DeviceAPOInfo::load(const wstring& deviceGuid)
|
||||
isInstalled = false;
|
||||
isLFX = false;
|
||||
isAPO2 = false;
|
||||
foundAPO2Values = false;
|
||||
installAsAPO2 = false;
|
||||
|
||||
if(!RegistryHelper::keyExists(keyPath + L"\\FxProperties"))
|
||||
{
|
||||
originalApoGuid = APOGUID_NOKEY;
|
||||
originalLfxGuid = APOGUID_NOKEY;
|
||||
originalGfxGuid = APOGUID_NOKEY;
|
||||
}
|
||||
else
|
||||
{
|
||||
originalApoGuid = APOGUID_NOVALUE;
|
||||
originalLfxGuid = APOGUID_NOVALUE;
|
||||
originalGfxGuid = APOGUID_NOVALUE;
|
||||
|
||||
bool found = tryAPOGuid(keyPath, lfxGuidValueName, true, false);
|
||||
if(!found)
|
||||
found = tryAPOGuid(keyPath, gfxGuidValueName, false, false);
|
||||
if(!found)
|
||||
found = tryAPOGuid(keyPath, lfxGuidValueName2, true, true);
|
||||
if(!found)
|
||||
found = tryAPOGuid(keyPath, gfxGuidValueName2, false, true);
|
||||
|
||||
foundAPO2Values = RegistryHelper::isWindowsVersionAtLeast(6, 3) // Windows 8.1
|
||||
installAsAPO2 = RegistryHelper::isWindowsVersionAtLeast(6, 3) // Windows 8.1
|
||||
&& (RegistryHelper::valueExists(keyPath + L"\\FxProperties", lfxGuidValueName2)
|
||||
|| RegistryHelper::valueExists(keyPath + L"\\FxProperties", gfxGuidValueName2));
|
||||
|
||||
if(found)
|
||||
wstring lfxValueName;
|
||||
wstring gfxValueName;
|
||||
if(installAsAPO2)
|
||||
{
|
||||
if(RegistryHelper::valueExists(APP_REGPATH L"\\Child APOs", deviceGuid))
|
||||
originalApoGuid = RegistryHelper::readValue(APP_REGPATH L"\\Child APOs", deviceGuid);
|
||||
lfxValueName = lfxGuidValueName2;
|
||||
gfxValueName = gfxGuidValueName2;
|
||||
}
|
||||
else
|
||||
{
|
||||
wstring guidValueName;
|
||||
if(isInput)
|
||||
{
|
||||
guidValueName = lfxGuidValueName;
|
||||
if(foundAPO2Values)
|
||||
guidValueName = lfxGuidValueName2;
|
||||
}
|
||||
else
|
||||
{
|
||||
guidValueName = gfxGuidValueName;
|
||||
if(foundAPO2Values)
|
||||
guidValueName = gfxGuidValueName2;
|
||||
}
|
||||
lfxValueName = lfxGuidValueName;
|
||||
gfxValueName = gfxGuidValueName;
|
||||
}
|
||||
|
||||
if(RegistryHelper::valueExists(keyPath + L"\\FxProperties", guidValueName))
|
||||
originalApoGuid = RegistryHelper::readValue(keyPath + L"\\FxProperties", guidValueName);
|
||||
bool found = false;
|
||||
if(isInput)
|
||||
found = tryAPOGuid(keyPath, lfxValueName, EQUALIZERAPO_LFX_GUID, true, installAsAPO2);
|
||||
else
|
||||
found = tryAPOGuid(keyPath, lfxValueName, EQUALIZERAPO_LFX_GUID, true, installAsAPO2) && tryAPOGuid(keyPath, gfxValueName, EQUALIZERAPO_GFX_GUID, false, installAsAPO2);
|
||||
isDual = found;
|
||||
|
||||
if(!found)
|
||||
found = tryAPOGuid(keyPath, lfxGuidValueName, EQUALIZERAPO_GFX_GUID, true, false);
|
||||
if(!found)
|
||||
found = tryAPOGuid(keyPath, gfxGuidValueName, EQUALIZERAPO_GFX_GUID, false, false);
|
||||
if(!found)
|
||||
found = tryAPOGuid(keyPath, lfxGuidValueName2, EQUALIZERAPO_GFX_GUID, true, true);
|
||||
if(!found)
|
||||
found = tryAPOGuid(keyPath, gfxGuidValueName2, EQUALIZERAPO_GFX_GUID, false, true);
|
||||
isInstalled = found;
|
||||
|
||||
if(found)
|
||||
{
|
||||
if(RegistryHelper::keyExists(APP_REGPATH L"\\Child APOs\\" + deviceGuid))
|
||||
{
|
||||
if(isAPO2)
|
||||
{
|
||||
originalLfxGuid = RegistryHelper::readValue(APP_REGPATH L"\\Child APOs\\" + deviceGuid, lfxGuidValueName2);
|
||||
originalGfxGuid = RegistryHelper::readValue(APP_REGPATH L"\\Child APOs\\" + deviceGuid, gfxGuidValueName2);
|
||||
}
|
||||
else
|
||||
{
|
||||
originalLfxGuid = RegistryHelper::readValue(APP_REGPATH L"\\Child APOs\\" + deviceGuid, lfxGuidValueName);
|
||||
originalGfxGuid = RegistryHelper::readValue(APP_REGPATH L"\\Child APOs\\" + deviceGuid, gfxGuidValueName);
|
||||
}
|
||||
}
|
||||
else if(RegistryHelper::valueExists(APP_REGPATH L"\\Child APOs", deviceGuid))
|
||||
{
|
||||
if(isLFX)
|
||||
{
|
||||
originalLfxGuid = RegistryHelper::readValue(APP_REGPATH L"\\Child APOs", deviceGuid);
|
||||
originalGfxGuid = L"";
|
||||
}
|
||||
else
|
||||
{
|
||||
originalLfxGuid = L"";
|
||||
originalGfxGuid = RegistryHelper::readValue(APP_REGPATH L"\\Child APOs", deviceGuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(RegistryHelper::valueExists(keyPath + L"\\FxProperties", lfxValueName))
|
||||
originalLfxGuid = RegistryHelper::readValue(keyPath + L"\\FxProperties", lfxValueName);
|
||||
if(RegistryHelper::valueExists(keyPath + L"\\FxProperties", gfxValueName))
|
||||
originalGfxGuid = RegistryHelper::readValue(keyPath + L"\\FxProperties", gfxValueName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,38 +172,45 @@ bool DeviceAPOInfo::load(const wstring& deviceGuid)
|
||||
|
||||
bool DeviceAPOInfo::canBeUpgraded()
|
||||
{
|
||||
return isInstalled && (!isInput && isLFX || !isAPO2 && foundAPO2Values);
|
||||
return isInstalled && !isDual;
|
||||
}
|
||||
|
||||
bool DeviceAPOInfo::isExperimental()
|
||||
{
|
||||
return !isInstalled && originalApoGuid == APOGUID_NOKEY;
|
||||
return !isInstalled && originalGfxGuid == APOGUID_NOKEY;
|
||||
}
|
||||
|
||||
void DeviceAPOInfo::install()
|
||||
{
|
||||
RegistryHelper::createKey(APP_REGPATH L"\\Child APOs");
|
||||
RegistryHelper::createKey(APP_REGPATH L"\\Child APOs\\" + deviceGuid);
|
||||
|
||||
RegistryHelper::writeValue(APP_REGPATH L"\\Child APOs", deviceGuid, originalApoGuid);
|
||||
|
||||
wstring keyPath;
|
||||
wstring guidValueName;
|
||||
if(isInput)
|
||||
wstring lfxValueName;
|
||||
wstring gfxValueName;
|
||||
if(installAsAPO2)
|
||||
{
|
||||
keyPath = captureKeyPath L"\\" + deviceGuid;
|
||||
guidValueName = lfxGuidValueName;
|
||||
if(foundAPO2Values)
|
||||
guidValueName = lfxGuidValueName2;
|
||||
lfxValueName = lfxGuidValueName2;
|
||||
gfxValueName = gfxGuidValueName2;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyPath = renderKeyPath L"\\" + deviceGuid;
|
||||
guidValueName = gfxGuidValueName;
|
||||
if(foundAPO2Values)
|
||||
guidValueName = gfxGuidValueName2;
|
||||
lfxValueName = lfxGuidValueName;
|
||||
gfxValueName = gfxGuidValueName;
|
||||
}
|
||||
|
||||
if(originalApoGuid == APOGUID_NOKEY)
|
||||
RegistryHelper::writeValue(APP_REGPATH L"\\Child APOs\\" + deviceGuid, lfxValueName, originalLfxGuid);
|
||||
if(isInput)
|
||||
RegistryHelper::writeValue(APP_REGPATH L"\\Child APOs\\" + deviceGuid, gfxValueName, L"");
|
||||
else
|
||||
RegistryHelper::writeValue(APP_REGPATH L"\\Child APOs\\" + deviceGuid, gfxValueName, originalGfxGuid);
|
||||
|
||||
wstring keyPath;
|
||||
if(isInput)
|
||||
keyPath = captureKeyPath L"\\" + deviceGuid;
|
||||
else
|
||||
keyPath = renderKeyPath L"\\" + deviceGuid;
|
||||
|
||||
if(originalGfxGuid == APOGUID_NOKEY)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -187,13 +229,22 @@ void DeviceAPOInfo::install()
|
||||
RegistryHelper::writeMultiValue(keyPath + L"\\FxProperties", sfxProcessingModesValueName, defaultProcessingModeValue);
|
||||
RegistryHelper::writeMultiValue(keyPath + L"\\FxProperties", mfxProcessingModesValueName, defaultProcessingModeValue);
|
||||
}
|
||||
else if(originalApoGuid != APOGUID_NOVALUE)
|
||||
else
|
||||
{
|
||||
RegistryHelper::saveToFile(keyPath + L"\\FxProperties", guidValueName,
|
||||
L"backup_" + StringHelper::replaceIllegalCharacters(deviceName) + L"_" + StringHelper::replaceIllegalCharacters(connectionName) + L".reg");
|
||||
vector<wstring> valuenames;
|
||||
if(originalLfxGuid != APOGUID_NOVALUE)
|
||||
valuenames.push_back(lfxValueName);
|
||||
if(!isInput && originalGfxGuid != APOGUID_NOVALUE)
|
||||
valuenames.push_back(gfxValueName);
|
||||
|
||||
if(!valuenames.empty())
|
||||
RegistryHelper::saveToFile(keyPath + L"\\FxProperties", valuenames,
|
||||
L"backup_" + StringHelper::replaceIllegalCharacters(deviceName) + L"_" + StringHelper::replaceIllegalCharacters(connectionName) + L".reg");
|
||||
}
|
||||
|
||||
RegistryHelper::writeValue(keyPath + L"\\FxProperties", guidValueName, RegistryHelper::getGuidString(__uuidof(EqualizerAPO)));
|
||||
RegistryHelper::writeValue(keyPath + L"\\FxProperties", lfxValueName, RegistryHelper::getGuidString(EQUALIZERAPO_LFX_GUID));
|
||||
if(!isInput)
|
||||
RegistryHelper::writeValue(keyPath + L"\\FxProperties", gfxValueName, RegistryHelper::getGuidString(EQUALIZERAPO_GFX_GUID));
|
||||
}
|
||||
|
||||
void DeviceAPOInfo::uninstall()
|
||||
@@ -204,40 +255,47 @@ void DeviceAPOInfo::uninstall()
|
||||
else
|
||||
keyPath = captureKeyPath L"\\" + deviceGuid;
|
||||
|
||||
if(originalApoGuid == APOGUID_NOKEY)
|
||||
if(originalLfxGuid == APOGUID_NOKEY || originalGfxGuid == APOGUID_NOKEY)
|
||||
{
|
||||
RegistryHelper::deleteKey(keyPath + L"\\FxProperties");
|
||||
}
|
||||
else
|
||||
{
|
||||
wstring guidValueName;
|
||||
if(isLFX)
|
||||
wstring lfxValueName;
|
||||
wstring gfxValueName;
|
||||
if(isAPO2)
|
||||
{
|
||||
guidValueName = lfxGuidValueName;
|
||||
if(isAPO2)
|
||||
guidValueName = lfxGuidValueName2;
|
||||
lfxValueName = lfxGuidValueName2;
|
||||
gfxValueName = gfxGuidValueName2;
|
||||
}
|
||||
else
|
||||
{
|
||||
guidValueName = gfxGuidValueName;
|
||||
if(isAPO2)
|
||||
guidValueName = gfxGuidValueName2;
|
||||
lfxValueName = lfxGuidValueName;
|
||||
gfxValueName = gfxGuidValueName;
|
||||
}
|
||||
|
||||
if(originalApoGuid == APOGUID_NOVALUE)
|
||||
RegistryHelper::deleteValue(keyPath + L"\\FxProperties", guidValueName);
|
||||
else
|
||||
RegistryHelper::writeValue(keyPath + L"\\FxProperties", guidValueName, originalApoGuid);
|
||||
if(originalLfxGuid == APOGUID_NOVALUE)
|
||||
RegistryHelper::deleteValue(keyPath + L"\\FxProperties", lfxValueName);
|
||||
else if(originalLfxGuid != L"")
|
||||
RegistryHelper::writeValue(keyPath + L"\\FxProperties", lfxValueName, originalLfxGuid);
|
||||
|
||||
if(originalGfxGuid == APOGUID_NOVALUE)
|
||||
RegistryHelper::deleteValue(keyPath + L"\\FxProperties", gfxValueName);
|
||||
else if(originalGfxGuid != L"")
|
||||
RegistryHelper::writeValue(keyPath + L"\\FxProperties", gfxValueName, originalGfxGuid);
|
||||
}
|
||||
|
||||
if(RegistryHelper::valueExists(APP_REGPATH L"\\Child APOs", deviceGuid))
|
||||
RegistryHelper::deleteValue(APP_REGPATH L"\\Child APOs", deviceGuid);
|
||||
|
||||
if(RegistryHelper::valueCount(APP_REGPATH L"\\Child APOs") == 0)
|
||||
if(RegistryHelper::keyExists(APP_REGPATH L"\\Child APOs\\" + deviceGuid))
|
||||
RegistryHelper::deleteKey(APP_REGPATH L"\\Child APOs\\" + deviceGuid);
|
||||
|
||||
if(RegistryHelper::keyEmpty(APP_REGPATH L"\\Child APOs"))
|
||||
RegistryHelper::deleteKey(APP_REGPATH L"\\Child APOs");
|
||||
}
|
||||
|
||||
bool DeviceAPOInfo::tryAPOGuid(const wstring& keyPath, const wchar_t* valueName, bool lfx, bool apo2)
|
||||
bool DeviceAPOInfo::tryAPOGuid(const wstring& keyPath, const wstring& valueName, GUID guid, bool lfx, bool apo2)
|
||||
{
|
||||
if(RegistryHelper::valueExists(keyPath + L"\\FxProperties", valueName))
|
||||
{
|
||||
@@ -246,9 +304,8 @@ bool DeviceAPOInfo::tryAPOGuid(const wstring& keyPath, const wchar_t* valueName,
|
||||
GUID apoGuid;
|
||||
if(SUCCEEDED(CLSIDFromString(apoGuidString.c_str(), &apoGuid)))
|
||||
{
|
||||
if(apoGuid == __uuidof(EqualizerAPO))
|
||||
if(apoGuid == guid)
|
||||
{
|
||||
isInstalled = true;
|
||||
isLFX = lfx;
|
||||
isAPO2 = apo2;
|
||||
|
||||
|
||||
+5
-3
@@ -39,13 +39,15 @@ public:
|
||||
std::wstring deviceName;
|
||||
std::wstring connectionName;
|
||||
std::wstring deviceGuid;
|
||||
std::wstring originalApoGuid;
|
||||
std::wstring originalLfxGuid;
|
||||
std::wstring originalGfxGuid;
|
||||
bool isInput;
|
||||
bool isInstalled;
|
||||
bool isLFX;
|
||||
bool isAPO2;
|
||||
bool foundAPO2Values;
|
||||
bool isDual;
|
||||
bool installAsAPO2;
|
||||
|
||||
private:
|
||||
bool tryAPOGuid(const std::wstring& keyPath, const wchar_t* valueName, bool lfx, bool apo2);
|
||||
bool tryAPOGuid(const std::wstring& keyPath, const std::wstring& valueName, GUID guid, bool lfx, bool apo2);
|
||||
};
|
||||
+39
-16
@@ -23,8 +23,8 @@
|
||||
|
||||
#include "EqualizerAPO.h"
|
||||
#include "ClassFactory.h"
|
||||
#include "RegistryHelper.h"
|
||||
#include "LogHelper.h"
|
||||
#include "helpers/RegistryHelper.h"
|
||||
#include "helpers/LogHelper.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -48,7 +48,7 @@ STDAPI DllCanUnloadNow()
|
||||
|
||||
STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv)
|
||||
{
|
||||
if(clsid != __uuidof(EqualizerAPO))
|
||||
if(clsid != EQUALIZERAPO_GFX_GUID && clsid != EQUALIZERAPO_LFX_GUID)
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
|
||||
ClassFactory* factory = new ClassFactory();
|
||||
@@ -66,26 +66,43 @@ STDAPI DllRegisterServer()
|
||||
wchar_t filename[1024];
|
||||
GetModuleFileNameW(hModule, filename, sizeof(filename)/sizeof(wchar_t));
|
||||
|
||||
HRESULT hr = RegisterAPO(EqualizerAPO::regProperties);
|
||||
HRESULT hr = RegisterAPO(EqualizerAPO::regGfxProperties);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
UnregisterAPO(__uuidof(EqualizerAPO));
|
||||
UnregisterAPO(EQUALIZERAPO_GFX_GUID);
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = RegisterAPO(EqualizerAPO::regLfxProperties);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
UnregisterAPO(EQUALIZERAPO_GFX_GUID);
|
||||
UnregisterAPO(EQUALIZERAPO_LFX_GUID);
|
||||
return hr;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
wstring apoClsidString = RegistryHelper::getGuidString(__uuidof(EqualizerAPO));
|
||||
wstring apoClsidString = RegistryHelper::getGuidString(EQUALIZERAPO_GFX_GUID);
|
||||
|
||||
RegistryHelper::createKey(L"SOFTWARE\\Classes\\CLSID\\" + apoClsidString);
|
||||
RegistryHelper::writeValue(L"SOFTWARE\\Classes\\CLSID\\" + apoClsidString, L"", L"EqualizerAPO Class");
|
||||
RegistryHelper::createKey(L"SOFTWARE\\Classes\\CLSID\\" + apoClsidString + L"\\InprocServer32");
|
||||
RegistryHelper::writeValue(L"SOFTWARE\\Classes\\CLSID\\" + apoClsidString + L"\\InprocServer32", L"", filename);
|
||||
RegistryHelper::writeValue(L"SOFTWARE\\Classes\\CLSID\\" + apoClsidString + L"\\InprocServer32", L"ThreadingModel", L"Both");
|
||||
RegistryHelper::createKey(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString);
|
||||
RegistryHelper::writeValue(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString, L"", L"EqualizerAPO GFX Class");
|
||||
RegistryHelper::createKey(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString + L"\\InprocServer32");
|
||||
RegistryHelper::writeValue(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString + L"\\InprocServer32", L"", filename);
|
||||
RegistryHelper::writeValue(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString + L"\\InprocServer32", L"ThreadingModel", L"Both");
|
||||
|
||||
apoClsidString = RegistryHelper::getGuidString(EQUALIZERAPO_LFX_GUID);
|
||||
|
||||
RegistryHelper::createKey(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString);
|
||||
RegistryHelper::writeValue(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString, L"", L"EqualizerAPO LFX Class");
|
||||
RegistryHelper::createKey(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString + L"\\InprocServer32");
|
||||
RegistryHelper::writeValue(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString + L"\\InprocServer32", L"", filename);
|
||||
RegistryHelper::writeValue(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString + L"\\InprocServer32", L"ThreadingModel", L"Both");
|
||||
}
|
||||
catch(RegistryException e)
|
||||
{
|
||||
UnregisterAPO(__uuidof(EqualizerAPO));
|
||||
UnregisterAPO(EQUALIZERAPO_GFX_GUID);
|
||||
UnregisterAPO(EQUALIZERAPO_LFX_GUID);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
@@ -96,17 +113,23 @@ STDAPI DllUnregisterServer()
|
||||
{
|
||||
try
|
||||
{
|
||||
wstring apoClsidString = RegistryHelper::getGuidString(__uuidof(EqualizerAPO));
|
||||
wstring apoClsidString = RegistryHelper::getGuidString(EQUALIZERAPO_GFX_GUID);
|
||||
|
||||
RegistryHelper::deleteKey(L"SOFTWARE\\Classes\\CLSID\\" + apoClsidString + L"\\InprocServer32");
|
||||
RegistryHelper::deleteKey(L"SOFTWARE\\Classes\\CLSID\\" + apoClsidString);
|
||||
RegistryHelper::deleteKey(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString + L"\\InprocServer32");
|
||||
RegistryHelper::deleteKey(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString);
|
||||
|
||||
apoClsidString = RegistryHelper::getGuidString(EQUALIZERAPO_LFX_GUID);
|
||||
|
||||
RegistryHelper::deleteKey(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString + L"\\InprocServer32");
|
||||
RegistryHelper::deleteKey(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\" + apoClsidString);
|
||||
}
|
||||
catch(RegistryException e)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
HRESULT hr = UnregisterAPO(__uuidof(EqualizerAPO));
|
||||
HRESULT hr = UnregisterAPO(EQUALIZERAPO_GFX_GUID);
|
||||
UnregisterAPO(EQUALIZERAPO_LFX_GUID);
|
||||
|
||||
return hr;
|
||||
}
|
||||
+154
-81
@@ -22,20 +22,23 @@
|
||||
#define INITGUID
|
||||
#include <mmdeviceapi.h>
|
||||
|
||||
#include "LogHelper.h"
|
||||
#include "RegistryHelper.h"
|
||||
#include "helpers/LogHelper.h"
|
||||
#include "helpers/RegistryHelper.h"
|
||||
#include "DeviceAPOInfo.h"
|
||||
#include "EqualizerAPO.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
long EqualizerAPO::instCount = 0;
|
||||
const CRegAPOProperties<1> EqualizerAPO::regProperties(
|
||||
__uuidof(EqualizerAPO), L"EqualizerAPO", L"Copyright (C) 2012", 1, 0, __uuidof(IAudioProcessingObject),
|
||||
const CRegAPOProperties<1> EqualizerAPO::regGfxProperties(
|
||||
EQUALIZERAPO_GFX_GUID, L"EqualizerAPO", L"Copyright (C) 2014", 1, 0, __uuidof(IAudioProcessingObject),
|
||||
(APO_FLAG)( APO_FLAG_FRAMESPERSECOND_MUST_MATCH | APO_FLAG_BITSPERSAMPLE_MUST_MATCH | APO_FLAG_INPLACE));
|
||||
const CRegAPOProperties<1> EqualizerAPO::regLfxProperties(
|
||||
EQUALIZERAPO_LFX_GUID, L"EqualizerAPO", L"Copyright (C) 2014", 1, 0, __uuidof(IAudioProcessingObject),
|
||||
(APO_FLAG)( APO_FLAG_FRAMESPERSECOND_MUST_MATCH | APO_FLAG_BITSPERSAMPLE_MUST_MATCH | APO_FLAG_INPLACE));
|
||||
|
||||
EqualizerAPO::EqualizerAPO(IUnknown* pUnkOuter)
|
||||
:CBaseAudioProcessingObject(regProperties)
|
||||
:CBaseAudioProcessingObject(regGfxProperties)
|
||||
{
|
||||
refCount = 1;
|
||||
if(pUnkOuter != NULL)
|
||||
@@ -101,6 +104,16 @@ HRESULT EqualizerAPO::Initialize(UINT32 cbDataSize, BYTE* pbyData)
|
||||
resetChild();
|
||||
|
||||
APOInitSystemEffects* initStruct = (APOInitSystemEffects*)pbyData;
|
||||
GUID apoGuid = initStruct->APOInit.clsid;
|
||||
try
|
||||
{
|
||||
TraceF(L"APO GUID: %s", RegistryHelper::getGuidString(apoGuid).c_str());
|
||||
}
|
||||
catch(RegistryException e)
|
||||
{
|
||||
LogF(L"Could not convert apo guid to guid string");
|
||||
}
|
||||
engine.setLfx((apoGuid == EQUALIZERAPO_LFX_GUID) != 0);
|
||||
|
||||
PROPVARIANT var;
|
||||
PropVariantInit(&var);
|
||||
@@ -113,34 +126,32 @@ HRESULT EqualizerAPO::Initialize(UINT32 cbDataSize, BYTE* pbyData)
|
||||
wstring deviceGuid = var.pwszVal;
|
||||
TraceF(L"Endpoint GUID: %s", deviceGuid.c_str());
|
||||
|
||||
wstring childApoGuid;
|
||||
|
||||
try
|
||||
{
|
||||
DeviceAPOInfo apoInfo;
|
||||
if(apoInfo.load(deviceGuid))
|
||||
peq.setDeviceInfo(apoInfo.deviceName, apoInfo.connectionName, apoInfo.deviceGuid);
|
||||
{
|
||||
engine.setDeviceInfo(apoInfo.isInput, apoInfo.deviceName, apoInfo.connectionName, apoInfo.deviceGuid);
|
||||
|
||||
if(apoGuid == EQUALIZERAPO_LFX_GUID)
|
||||
childApoGuid = apoInfo.originalLfxGuid;
|
||||
else
|
||||
childApoGuid = apoInfo.originalGfxGuid;
|
||||
}
|
||||
}
|
||||
catch(RegistryException e)
|
||||
{
|
||||
LogF(L"Could not read endpoint device info because of: %s", e.getMessage());
|
||||
LogF(L"Could not read endpoint device info because of: %s", e.getMessage().c_str());
|
||||
}
|
||||
|
||||
wstring apoGuid;
|
||||
try
|
||||
{
|
||||
apoGuid = RegistryHelper::readValue(APP_REGPATH L"\\Child APOs", var.pwszVal);
|
||||
}
|
||||
catch(RegistryException e)
|
||||
{
|
||||
LogF(L"Can't read child apo guid because of: %s", e.getMessage());
|
||||
return E_NOTFOUND;
|
||||
}
|
||||
TraceF(L"Child APO GUID: %s", childApoGuid.c_str());
|
||||
|
||||
TraceF(L"Child APO GUID: %s", apoGuid.c_str());
|
||||
|
||||
if(apoGuid != APOGUID_NULL && apoGuid != APOGUID_NOKEY && apoGuid != APOGUID_NOVALUE)
|
||||
if(childApoGuid != L"" && childApoGuid != APOGUID_NULL && childApoGuid != APOGUID_NOKEY && childApoGuid != APOGUID_NOVALUE)
|
||||
{
|
||||
GUID childGuid;
|
||||
hr = CLSIDFromString(apoGuid.c_str(), &childGuid);
|
||||
hr = CLSIDFromString(childApoGuid.c_str(), &childGuid);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
LogF(L"Can't convert guid string to guid");
|
||||
@@ -210,18 +221,17 @@ HRESULT EqualizerAPO::IsInputFormatSupported(IAudioMediaType* pOutputFormat,
|
||||
LogF(L"Error in second GetUncompressedAudioFormat");
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
TraceF(L"Output format = { %08X, %u, %u, %u, %f, %08X }",
|
||||
outFormat.guidFormatType.Data1, outFormat.dwSamplesPerFrame, outFormat.dwBytesPerSampleContainer,
|
||||
outFormat.dwValidBitsPerSample, outFormat.fFramesPerSecond, outFormat.dwChannelMask);
|
||||
|
||||
|
||||
if(childAPO)
|
||||
{
|
||||
hr = childAPO->IsInputFormatSupported(pOutputFormat, pRequestedInputFormat, ppSupportedInputFormat);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
TraceF(L"Success in IsInputFormatSupported of child apo");
|
||||
return hr;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -230,42 +240,38 @@ HRESULT EqualizerAPO::IsInputFormatSupported(IAudioMediaType* pOutputFormat,
|
||||
}
|
||||
}
|
||||
|
||||
return CBaseAudioProcessingObject::IsInputFormatSupported(pOutputFormat, pRequestedInputFormat, ppSupportedInputFormat);
|
||||
}
|
||||
if(!childAPO || !SUCCEEDED(hr))
|
||||
{
|
||||
hr = CBaseAudioProcessingObject::IsInputFormatSupported(pOutputFormat, pRequestedInputFormat, ppSupportedInputFormat);
|
||||
|
||||
void EqualizerAPO::APOProcess(UINT32 u32NumInputConnections,
|
||||
APO_CONNECTION_PROPERTY** ppInputConnections, UINT32 u32NumOutputConnections,
|
||||
APO_CONNECTION_PROPERTY** ppOutputConnections)
|
||||
{
|
||||
switch( ppInputConnections[0]->u32BufferFlags )
|
||||
{
|
||||
case BUFFER_VALID:
|
||||
{
|
||||
float* inputFrames = reinterpret_cast<float*>(ppInputConnections[0]->pBuffer);
|
||||
float* outputFrames = reinterpret_cast<float*>(ppOutputConnections[0]->pBuffer);
|
||||
// we do not support downmixing currently
|
||||
if(hr == S_OK && inFormat.dwSamplesPerFrame > 2 && inFormat.dwSamplesPerFrame > outFormat.dwSamplesPerFrame)
|
||||
{
|
||||
*ppSupportedInputFormat = pOutputFormat;
|
||||
hr = S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if(childRT)
|
||||
{
|
||||
childRT->APOProcess(u32NumInputConnections, ppInputConnections, u32NumOutputConnections, ppOutputConnections);
|
||||
|
||||
peq.process(outputFrames, outputFrames, ppInputConnections[0]->u32ValidFrameCount);
|
||||
}
|
||||
else
|
||||
peq.process(outputFrames, inputFrames, ppInputConnections[0]->u32ValidFrameCount);
|
||||
if(hr == S_FALSE)
|
||||
{
|
||||
UNCOMPRESSEDAUDIOFORMAT supportedFormat;
|
||||
HRESULT hr2 = (*ppSupportedInputFormat)->GetUncompressedAudioFormat(&supportedFormat);
|
||||
if(FAILED(hr2))
|
||||
{
|
||||
LogF(L"Error in third GetUncompressedAudioFormat");
|
||||
return hr2;
|
||||
}
|
||||
|
||||
ppOutputConnections[0]->u32ValidFrameCount = ppInputConnections[0]->u32ValidFrameCount;
|
||||
ppOutputConnections[0]->u32BufferFlags = ppInputConnections[0]->u32BufferFlags;
|
||||
TraceF(L"InputFormat not accepted, SupportedInputFormat = { %08X, %u, %u, %u, %f, %08X }",
|
||||
supportedFormat.guidFormatType.Data1, supportedFormat.dwSamplesPerFrame, supportedFormat.dwBytesPerSampleContainer,
|
||||
supportedFormat.dwValidBitsPerSample, supportedFormat.fFramesPerSecond, supportedFormat.dwChannelMask);
|
||||
}
|
||||
else if(hr == S_OK)
|
||||
{
|
||||
TraceF(L"InputFormat accepted");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case BUFFER_SILENT:
|
||||
{
|
||||
ppOutputConnections[0]->u32ValidFrameCount = ppInputConnections[0]->u32ValidFrameCount;
|
||||
ppOutputConnections[0]->u32BufferFlags = ppInputConnections[0]->u32BufferFlags;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT EqualizerAPO::LockForProcess(UINT32 u32NumInputConnections,
|
||||
@@ -273,6 +279,35 @@ HRESULT EqualizerAPO::LockForProcess(UINT32 u32NumInputConnections,
|
||||
APO_CONNECTION_DESCRIPTOR** ppOutputConnections)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
UNCOMPRESSEDAUDIOFORMAT inFormat;
|
||||
hr = ppInputConnections[0]->pFormat->GetUncompressedAudioFormat(&inFormat);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
LogF(L"Error in GetUncompressedAudioFormat in LockForProcess");
|
||||
return hr;
|
||||
}
|
||||
|
||||
unsigned maxInputFrameCount = ppInputConnections[0]->u32MaxFrameCount;
|
||||
|
||||
TraceF(L"Input format in LockForProcess = { %08X, %u, %u, %u, %f, %08X, %u }",
|
||||
inFormat.guidFormatType.Data1, inFormat.dwSamplesPerFrame, inFormat.dwBytesPerSampleContainer,
|
||||
inFormat.dwValidBitsPerSample, inFormat.fFramesPerSecond, inFormat.dwChannelMask, maxInputFrameCount);
|
||||
|
||||
UNCOMPRESSEDAUDIOFORMAT outFormat;
|
||||
hr = ppOutputConnections[0]->pFormat->GetUncompressedAudioFormat(&outFormat);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
LogF(L"Error in second GetUncompressedAudioFormat in LockForProcess");
|
||||
return hr;
|
||||
}
|
||||
|
||||
unsigned maxOutputFrameCount = ppOutputConnections[0]->u32MaxFrameCount;
|
||||
|
||||
TraceF(L"Output format in LockForProcess = { %08X, %u, %u, %u, %f, %08X, %u }",
|
||||
outFormat.guidFormatType.Data1, outFormat.dwSamplesPerFrame, outFormat.dwBytesPerSampleContainer,
|
||||
outFormat.dwValidBitsPerSample, outFormat.fFramesPerSecond, outFormat.dwChannelMask, maxOutputFrameCount);
|
||||
|
||||
if(childCfg != NULL)
|
||||
{
|
||||
hr = childCfg->LockForProcess(u32NumInputConnections, ppInputConnections, u32NumOutputConnections,
|
||||
@@ -288,35 +323,36 @@ HRESULT EqualizerAPO::LockForProcess(UINT32 u32NumInputConnections,
|
||||
LogF(L"Error in CBaseAudioProcessingObject::LockForProcess");
|
||||
return hr;
|
||||
}
|
||||
|
||||
UNCOMPRESSEDAUDIOFORMAT inFormat;
|
||||
hr = ppInputConnections[0]->pFormat->GetUncompressedAudioFormat(&inFormat);
|
||||
if(FAILED(hr))
|
||||
else if(hr == S_OK)
|
||||
{
|
||||
LogF(L"Error in GetUncompressedAudioFormat in LockForProcess");
|
||||
return hr;
|
||||
TraceF(L"LockForProcess successful");
|
||||
}
|
||||
|
||||
TraceF(L"Input format in LockForProcess = { %08X, %u, %u, %u, %f, %08X }",
|
||||
inFormat.guidFormatType.Data1, inFormat.dwSamplesPerFrame, inFormat.dwBytesPerSampleContainer,
|
||||
inFormat.dwValidBitsPerSample, inFormat.fFramesPerSecond, inFormat.dwChannelMask);
|
||||
|
||||
UNCOMPRESSEDAUDIOFORMAT outFormat;
|
||||
hr = ppOutputConnections[0]->pFormat->GetUncompressedAudioFormat(&outFormat);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
LogF(L"Error in second GetUncompressedAudioFormat in LockForProcess");
|
||||
return hr;
|
||||
}
|
||||
|
||||
TraceF(L"Output format in LockForProcess = { %08X, %u, %u, %u, %f, %08X }",
|
||||
outFormat.guidFormatType.Data1, outFormat.dwSamplesPerFrame, outFormat.dwBytesPerSampleContainer,
|
||||
outFormat.dwValidBitsPerSample, outFormat.fFramesPerSecond, outFormat.dwChannelMask);
|
||||
unsigned maxFrameCount = maxInputFrameCount;
|
||||
if(maxFrameCount == 0)
|
||||
maxFrameCount = maxOutputFrameCount;
|
||||
|
||||
if(outFormat.dwChannelMask == 0 && inFormat.dwSamplesPerFrame == outFormat.dwSamplesPerFrame)
|
||||
peq.initialize(outFormat.fFramesPerSecond, outFormat.dwSamplesPerFrame, inFormat.dwChannelMask);
|
||||
unsigned realChannelCount;
|
||||
if(childCfg != NULL)
|
||||
realChannelCount = outFormat.dwSamplesPerFrame;
|
||||
else
|
||||
peq.initialize(outFormat.fFramesPerSecond, outFormat.dwSamplesPerFrame, outFormat.dwChannelMask);
|
||||
realChannelCount = inFormat.dwSamplesPerFrame;
|
||||
|
||||
unsigned channelMask;
|
||||
if(engine.isCapture())
|
||||
{
|
||||
channelMask = inFormat.dwChannelMask;
|
||||
if(channelMask == 0 && inFormat.dwSamplesPerFrame == outFormat.dwSamplesPerFrame)
|
||||
channelMask = outFormat.dwChannelMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
channelMask = outFormat.dwChannelMask;
|
||||
if(channelMask == 0 && inFormat.dwSamplesPerFrame == outFormat.dwSamplesPerFrame)
|
||||
channelMask = inFormat.dwChannelMask;
|
||||
}
|
||||
|
||||
engine.initialize(outFormat.fFramesPerSecond, inFormat.dwSamplesPerFrame, realChannelCount, outFormat.dwSamplesPerFrame, channelMask, maxFrameCount);
|
||||
|
||||
return hr;
|
||||
}
|
||||
@@ -357,6 +393,43 @@ void EqualizerAPO::resetChild()
|
||||
}
|
||||
}
|
||||
|
||||
#pragma AVRT_CODE_BEGIN
|
||||
void EqualizerAPO::APOProcess(UINT32 u32NumInputConnections,
|
||||
APO_CONNECTION_PROPERTY** ppInputConnections, UINT32 u32NumOutputConnections,
|
||||
APO_CONNECTION_PROPERTY** ppOutputConnections)
|
||||
{
|
||||
switch( ppInputConnections[0]->u32BufferFlags )
|
||||
{
|
||||
case BUFFER_VALID:
|
||||
{
|
||||
float* inputFrames = reinterpret_cast<float*>(ppInputConnections[0]->pBuffer);
|
||||
float* outputFrames = reinterpret_cast<float*>(ppOutputConnections[0]->pBuffer);
|
||||
|
||||
if(childRT)
|
||||
{
|
||||
childRT->APOProcess(u32NumInputConnections, ppInputConnections, u32NumOutputConnections, ppOutputConnections);
|
||||
|
||||
engine.process(outputFrames, outputFrames, ppInputConnections[0]->u32ValidFrameCount);
|
||||
}
|
||||
else
|
||||
engine.process(outputFrames, inputFrames, ppInputConnections[0]->u32ValidFrameCount);
|
||||
|
||||
ppOutputConnections[0]->u32ValidFrameCount = ppInputConnections[0]->u32ValidFrameCount;
|
||||
ppOutputConnections[0]->u32BufferFlags = ppInputConnections[0]->u32BufferFlags;
|
||||
|
||||
break;
|
||||
}
|
||||
case BUFFER_SILENT:
|
||||
{
|
||||
ppOutputConnections[0]->u32ValidFrameCount = ppInputConnections[0]->u32ValidFrameCount;
|
||||
ppOutputConnections[0]->u32BufferFlags = ppInputConnections[0]->u32BufferFlags;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma AVRT_CODE_END
|
||||
|
||||
HRESULT EqualizerAPO::NonDelegatingQueryInterface(const IID& iid, void** ppv)
|
||||
{
|
||||
if(iid == __uuidof(IUnknown))
|
||||
@@ -393,4 +466,4 @@ ULONG EqualizerAPO::NonDelegatingRelease()
|
||||
}
|
||||
|
||||
return refCount;
|
||||
}
|
||||
}
|
||||
+15
-9
@@ -22,7 +22,7 @@
|
||||
#include <Unknwn.h>
|
||||
#include <audioenginebaseapo.h>
|
||||
#include <BaseAudioProcessingObject.h>
|
||||
#include "ParametricEQ.h"
|
||||
#include "FilterEngine.h"
|
||||
|
||||
class INonDelegatingUnknown
|
||||
{
|
||||
@@ -31,7 +31,12 @@ class INonDelegatingUnknown
|
||||
virtual ULONG __stdcall NonDelegatingRelease() = 0;
|
||||
};
|
||||
|
||||
class __declspec(uuid("{EC1CC9CE-FAED-4822-828A-82A81A6F018F}")) EqualizerAPO
|
||||
// {EACD2258-FCAC-4FF4-B36D-419E924A6D79}
|
||||
const GUID EQUALIZERAPO_LFX_GUID = { 0xeacd2258, 0xfcac, 0x4ff4, { 0xb3, 0x6d, 0x41, 0x9e, 0x92, 0x4a, 0x6d, 0x79 } };
|
||||
// {EC1CC9CE-FAED-4822-828A-82A81A6F018F}
|
||||
const GUID EQUALIZERAPO_GFX_GUID = { 0xec1cc9ce, 0xfaed, 0x4822, { 0x82, 0x8a, 0x82, 0xa8, 0x1a, 0x6f, 0x01, 0x8f } };
|
||||
|
||||
class EqualizerAPO
|
||||
: public CBaseAudioProcessingObject, public IAudioSystemEffects, public INonDelegatingUnknown
|
||||
{
|
||||
public:
|
||||
@@ -49,29 +54,30 @@ public:
|
||||
virtual HRESULT __stdcall IsInputFormatSupported(IAudioMediaType* pOutputFormat,
|
||||
IAudioMediaType* pRequestedInputFormat, IAudioMediaType** ppSupportedInputFormat);
|
||||
|
||||
// IAudioProcessingObjectRT
|
||||
virtual void __stdcall APOProcess(UINT32 u32NumInputConnections,
|
||||
APO_CONNECTION_PROPERTY** ppInputConnections, UINT32 u32NumOutputConnections,
|
||||
APO_CONNECTION_PROPERTY** ppOutputConnections);
|
||||
|
||||
// IAudioProcessingObjectConfiguration
|
||||
virtual HRESULT __stdcall LockForProcess(UINT32 u32NumInputConnections,
|
||||
APO_CONNECTION_DESCRIPTOR** ppInputConnections, UINT32 u32NumOutputConnections,
|
||||
APO_CONNECTION_DESCRIPTOR** ppOutputConnections);
|
||||
virtual HRESULT __stdcall UnlockForProcess(void);
|
||||
|
||||
// IAudioProcessingObjectRT
|
||||
virtual void __stdcall APOProcess(UINT32 u32NumInputConnections,
|
||||
APO_CONNECTION_PROPERTY** ppInputConnections, UINT32 u32NumOutputConnections,
|
||||
APO_CONNECTION_PROPERTY** ppOutputConnections);
|
||||
|
||||
// INonDelegatingUnknown
|
||||
virtual HRESULT __stdcall NonDelegatingQueryInterface(const IID& iid, void** ppv);
|
||||
virtual ULONG __stdcall NonDelegatingAddRef();
|
||||
virtual ULONG __stdcall NonDelegatingRelease();
|
||||
|
||||
static long instCount;
|
||||
static const CRegAPOProperties<1> regProperties;
|
||||
static const CRegAPOProperties<1> regGfxProperties;
|
||||
static const CRegAPOProperties<1> regLfxProperties;
|
||||
|
||||
private:
|
||||
long refCount;
|
||||
IUnknown* pUnkOuter;
|
||||
ParametricEQ peq;
|
||||
FilterEngine engine;
|
||||
|
||||
void resetChild();
|
||||
|
||||
|
||||
+70
-22
@@ -66,22 +66,22 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<IncludePath>$(SolutionDir);$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<LibraryPath>$(LibraryPath);$(DDK_PATH)\lib\win7\i386</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<IncludePath>$(SolutionDir);$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<LibraryPath>$(LibraryPath);$(DDK_PATH)\lib\win7\amd64</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<IncludePath>$(SolutionDir);$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<LibraryPath>$(LibraryPath);$(DDK_PATH)\lib\win7\i386</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<IncludePath>$(SolutionDir);$(IncludePath);$(DDK_PATH)\inc\api</IncludePath>
|
||||
<LibraryPath>$(LibraryPath);$(DDK_PATH)\lib\win7\amd64</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
@@ -89,12 +89,12 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;EQUALIZERAPO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;USE_WINDDK;_DEBUG;_WINDOWS;_USRDLL;EQUALIZERAPO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>version.lib;wmcodecdspuuid.lib;AudioBaseProcessingObject.lib;audiomediatypecrt.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>muparserxd.lib;audioeng.lib;version.lib;wmcodecdspuuid.lib;AudioBaseProcessingObject.lib;audiomediatypecrt.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>EqualizerAPO.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
<Midl>
|
||||
@@ -106,12 +106,12 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;EQUALIZERAPO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;USE_WINDDK;_DEBUG;_WINDOWS;_USRDLL;EQUALIZERAPO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>version.lib;wmcodecdspuuid.lib;AudioBaseProcessingObject.lib;audiomediatypecrt.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>muparserxd.lib;audioeng.lib;version.lib;wmcodecdspuuid.lib;AudioBaseProcessingObject.lib;audiomediatypecrt.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>EqualizerAPO.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
<Midl>
|
||||
@@ -125,7 +125,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;EQUALIZERAPO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;USE_WINDDK;NDEBUG;_WINDOWS;_USRDLL;EQUALIZERAPO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@@ -133,7 +133,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>version.lib;wmcodecdspuuid.lib;AudioBaseProcessingObject.lib;audiomediatypecrt.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>muparserx.lib;audioeng.lib;version.lib;wmcodecdspuuid.lib;AudioBaseProcessingObject.lib;audiomediatypecrt.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>EqualizerAPO.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -144,7 +144,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;EQUALIZERAPO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;USE_WINDDK;NDEBUG;_WINDOWS;_USRDLL;EQUALIZERAPO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@@ -152,32 +152,80 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>version.lib;wmcodecdspuuid.lib;AudioBaseProcessingObject.lib;audiomediatypecrt.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>muparserx.lib;audioeng.lib;version.lib;wmcodecdspuuid.lib;AudioBaseProcessingObject.lib;audiomediatypecrt.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>EqualizerAPO.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BiQuad.h" />
|
||||
<ClInclude Include="ClassFactory.h" />
|
||||
<ClInclude Include="DeviceAPOInfo.h" />
|
||||
<ClInclude Include="EqualizerAPO.h" />
|
||||
<ClInclude Include="LogHelper.h" />
|
||||
<ClInclude Include="ParametricEQ.h" />
|
||||
<ClInclude Include="RegistryHelper.h" />
|
||||
<ClInclude Include="FilterConfiguration.h" />
|
||||
<ClInclude Include="FilterEngine.h" />
|
||||
<ClInclude Include="filters\BiQuad.h" />
|
||||
<ClInclude Include="filters\BiQuadFilter.h" />
|
||||
<ClInclude Include="filters\BiQuadFilterFactory.h" />
|
||||
<ClInclude Include="filters\ChannelFilter.h" />
|
||||
<ClInclude Include="filters\ChannelFilterFactory.h" />
|
||||
<ClInclude Include="filters\CopyFilter.h" />
|
||||
<ClInclude Include="filters\CopyFilterFactory.h" />
|
||||
<ClInclude Include="filters\DelayFilter.h" />
|
||||
<ClInclude Include="filters\DelayFilterFactory.h" />
|
||||
<ClInclude Include="filters\DeviceFilterFactory.h" />
|
||||
<ClInclude Include="filters\ExpressionFilterFactory.h" />
|
||||
<ClInclude Include="filters\IfFilterFactory.h" />
|
||||
<ClInclude Include="filters\IIRFilter.h" />
|
||||
<ClInclude Include="filters\IIRFilterFactory.h" />
|
||||
<ClInclude Include="filters\IncludeFilterFactory.h" />
|
||||
<ClInclude Include="filters\PreampFilter.h" />
|
||||
<ClInclude Include="filters\PreampFilterFactory.h" />
|
||||
<ClInclude Include="filters\StageFilterFactory.h" />
|
||||
<ClInclude Include="helpers\LogHelper.h" />
|
||||
<ClInclude Include="helpers\MemoryHelper.h" />
|
||||
<ClInclude Include="helpers\PrecisionTimer.h" />
|
||||
<ClInclude Include="helpers\RegistryHelper.h" />
|
||||
<ClInclude Include="helpers\StringHelper.h" />
|
||||
<ClInclude Include="IFilter.h" />
|
||||
<ClInclude Include="IFilterFactory.h" />
|
||||
<ClInclude Include="parser\RegexFunctions.h" />
|
||||
<ClInclude Include="parser\RegistryFunctions.h" />
|
||||
<ClInclude Include="parser\StringOperators.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="StringHelper.h" />
|
||||
<ClInclude Include="version.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BiQuad.cpp" />
|
||||
<ClCompile Include="ClassFactory.cpp" />
|
||||
<ClCompile Include="DeviceAPOInfo.cpp" />
|
||||
<ClCompile Include="DllMain.cpp" />
|
||||
<ClCompile Include="EqualizerAPO.cpp" />
|
||||
<ClCompile Include="LogHelper.cpp" />
|
||||
<ClCompile Include="ParametricEQ.cpp" />
|
||||
<ClCompile Include="RegistryHelper.cpp" />
|
||||
<ClCompile Include="StringHelper.cpp" />
|
||||
<ClCompile Include="FilterConfiguration.cpp" />
|
||||
<ClCompile Include="FilterEngine.cpp" />
|
||||
<ClCompile Include="filters\BiQuad.cpp" />
|
||||
<ClCompile Include="filters\BiQuadFilter.cpp" />
|
||||
<ClCompile Include="filters\BiQuadFilterFactory.cpp" />
|
||||
<ClCompile Include="filters\ChannelFilter.cpp" />
|
||||
<ClCompile Include="filters\ChannelFilterFactory.cpp" />
|
||||
<ClCompile Include="filters\CopyFilter.cpp" />
|
||||
<ClCompile Include="filters\CopyFilterFactory.cpp" />
|
||||
<ClCompile Include="filters\DelayFilter.cpp" />
|
||||
<ClCompile Include="filters\DelayFilterFactory.cpp" />
|
||||
<ClCompile Include="filters\DeviceFilterFactory.cpp" />
|
||||
<ClCompile Include="filters\ExpressionFilterFactory.cpp" />
|
||||
<ClCompile Include="filters\IfFilterFactory.cpp" />
|
||||
<ClCompile Include="filters\IIRFilter.cpp" />
|
||||
<ClCompile Include="filters\IIRFilterFactory.cpp" />
|
||||
<ClCompile Include="filters\IncludeFilterFactory.cpp" />
|
||||
<ClCompile Include="filters\PreampFilter.cpp" />
|
||||
<ClCompile Include="filters\PreampFilterFactory.cpp" />
|
||||
<ClCompile Include="filters\StageFilterFactory.cpp" />
|
||||
<ClCompile Include="helpers\LogHelper.cpp" />
|
||||
<ClCompile Include="helpers\MemoryHelper.cpp" />
|
||||
<ClCompile Include="helpers\RegistryHelper.cpp" />
|
||||
<ClCompile Include="helpers\StringHelper.cpp" />
|
||||
<ClCompile Include="IFilter.cpp" />
|
||||
<ClCompile Include="parser\RegexFunctions.cpp" />
|
||||
<ClCompile Include="parser\RegistryFunctions.cpp" />
|
||||
<ClCompile Include="parser\StringOperators.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="EqualizerAPO.def" />
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ClassFactory.cpp" />
|
||||
<ClCompile Include="DeviceAPOInfo.cpp" />
|
||||
<ClCompile Include="DllMain.cpp" />
|
||||
<ClCompile Include="EqualizerAPO.cpp" />
|
||||
<ClCompile Include="FilterEngine.cpp" />
|
||||
<ClCompile Include="FilterConfiguration.cpp" />
|
||||
<ClCompile Include="IFilter.cpp" />
|
||||
<ClCompile Include="parser\RegexFunctions.cpp">
|
||||
<Filter>parser</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="parser\RegistryFunctions.cpp">
|
||||
<Filter>parser</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\BiQuad.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\BiQuadFilter.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\BiQuadFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\ChannelFilter.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\ChannelFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\CopyFilter.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\CopyFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\DelayFilter.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\DelayFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\DeviceFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\ExpressionFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\IncludeFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\PreampFilter.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\PreampFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\StageFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="helpers\LogHelper.cpp">
|
||||
<Filter>helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="helpers\MemoryHelper.cpp">
|
||||
<Filter>helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="helpers\RegistryHelper.cpp">
|
||||
<Filter>helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="helpers\StringHelper.cpp">
|
||||
<Filter>helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\IfFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\IIRFilterFactory.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filters\IIRFilter.cpp">
|
||||
<Filter>filters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="parser\StringOperators.cpp">
|
||||
<Filter>parser</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ClassFactory.h" />
|
||||
<ClInclude Include="DeviceAPOInfo.h" />
|
||||
<ClInclude Include="EqualizerAPO.h" />
|
||||
<ClInclude Include="FilterEngine.h" />
|
||||
<ClInclude Include="IFilter.h" />
|
||||
<ClInclude Include="IFilterFactory.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="version.h" />
|
||||
<ClInclude Include="FilterConfiguration.h" />
|
||||
<ClInclude Include="parser\RegexFunctions.h">
|
||||
<Filter>parser</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="parser\RegistryFunctions.h">
|
||||
<Filter>parser</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\BiQuad.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\BiQuadFilter.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\BiQuadFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\ChannelFilter.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\ChannelFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\CopyFilter.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\CopyFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\DelayFilter.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\DelayFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\DeviceFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\ExpressionFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\IncludeFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\PreampFilter.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\PreampFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\StageFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="helpers\LogHelper.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="helpers\MemoryHelper.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="helpers\PrecisionTimer.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="helpers\RegistryHelper.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="helpers\StringHelper.h">
|
||||
<Filter>helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\IfFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\IIRFilterFactory.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filters\IIRFilter.h">
|
||||
<Filter>filters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="parser\StringOperators.h">
|
||||
<Filter>parser</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="EqualizerAPO.rc" />
|
||||
<ResourceCompile Include="EqualizerAPO64.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="EqualizerAPO.def" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="filters">
|
||||
<UniqueIdentifier>{d8adcbe6-a53a-44e1-93fd-272b6e8983fb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="helpers">
|
||||
<UniqueIdentifier>{792503e3-923f-4123-808f-5acbf7da01fe}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="parser">
|
||||
<UniqueIdentifier>{df98049b-1ada-41ad-a5ab-0a175600a767}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
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 "FilterEngine.h"
|
||||
#include "helpers/MemoryHelper.h"
|
||||
#include "FilterConfiguration.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
FilterConfiguration::FilterConfiguration(FilterEngine* engine, const vector<FilterInfo*>& filterInfos, unsigned allChannelCount)
|
||||
{
|
||||
this->allChannelCount = allChannelCount;
|
||||
realChannelCount = engine->getRealChannelCount();
|
||||
outputChannelCount = engine->getOutputChannelCount();
|
||||
unsigned maxFrameCount = engine->getMaxFrameCount();
|
||||
|
||||
allSamples = (float**)MemoryHelper::alloc(allChannelCount * sizeof(float*));
|
||||
for(size_t i=0; i<allChannelCount; i++)
|
||||
allSamples[i] = (float*)MemoryHelper::alloc(maxFrameCount * sizeof(float));
|
||||
allSamples2 = (float**)MemoryHelper::alloc(allChannelCount * sizeof(float*));
|
||||
for(size_t i=0; i<allChannelCount; i++)
|
||||
allSamples2[i] = (float*)MemoryHelper::alloc(maxFrameCount * sizeof(float));
|
||||
currentSamples = (float**)MemoryHelper::alloc(allChannelCount * sizeof(float*));
|
||||
currentSamples2 = (float**)MemoryHelper::alloc(allChannelCount * sizeof(float*));
|
||||
|
||||
filterCount = (unsigned)filterInfos.size();
|
||||
this->filterInfos = (FilterInfo**)MemoryHelper::alloc(filterCount * sizeof(FilterInfo*));
|
||||
for(size_t i=0; i<filterCount; i++)
|
||||
this->filterInfos[i] = filterInfos[i];
|
||||
}
|
||||
|
||||
FilterConfiguration::~FilterConfiguration()
|
||||
{
|
||||
MemoryHelper::free(currentSamples2);
|
||||
MemoryHelper::free(currentSamples);
|
||||
|
||||
for(size_t i=0; i<allChannelCount; i++)
|
||||
MemoryHelper::free(allSamples2[i]);
|
||||
MemoryHelper::free(allSamples2);
|
||||
|
||||
for(size_t i=0; i<allChannelCount; i++)
|
||||
MemoryHelper::free(allSamples[i]);
|
||||
MemoryHelper::free(allSamples);
|
||||
|
||||
for(size_t i=0; i<filterCount; i++)
|
||||
{
|
||||
filterInfos[i]->filter->~IFilter();
|
||||
MemoryHelper::free(filterInfos[i]->filter);
|
||||
if(filterInfos[i]->inChannels != NULL)
|
||||
MemoryHelper::free(filterInfos[i]->inChannels);
|
||||
if(filterInfos[i]->outChannels != NULL)
|
||||
MemoryHelper::free(filterInfos[i]->outChannels);
|
||||
MemoryHelper::free(filterInfos[i]);
|
||||
}
|
||||
MemoryHelper::free(filterInfos);
|
||||
}
|
||||
|
||||
#pragma AVRT_CODE_BEGIN
|
||||
void FilterConfiguration::process(float* input, unsigned frameCount)
|
||||
{
|
||||
#define DEINTERLEAVE_MACRO(ccount) \
|
||||
{\
|
||||
for (size_t c=0; c<ccount; c++)\
|
||||
{\
|
||||
float* sampleChannel = allSamples[c];\
|
||||
float* i2 = input + c;\
|
||||
for (size_t i = 0; i < frameCount; i++)\
|
||||
{\
|
||||
sampleChannel[i] = i2[i*ccount];\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
|
||||
switch(realChannelCount)
|
||||
{
|
||||
case 1:
|
||||
DEINTERLEAVE_MACRO(1)
|
||||
break;
|
||||
case 2:
|
||||
DEINTERLEAVE_MACRO(2)
|
||||
break;
|
||||
case 6:
|
||||
DEINTERLEAVE_MACRO(6)
|
||||
break;
|
||||
case 8:
|
||||
DEINTERLEAVE_MACRO(8)
|
||||
break;
|
||||
default:
|
||||
DEINTERLEAVE_MACRO(realChannelCount)
|
||||
}
|
||||
|
||||
for(unsigned c=realChannelCount; c<allChannelCount; c++)
|
||||
memset(allSamples[c], 0, frameCount * sizeof(float));
|
||||
|
||||
// for real mono input and >= stereo output, upmix to stereo as the Windows audio system would do automatically if no APO was present
|
||||
if(realChannelCount == 1 && outputChannelCount >= 2)
|
||||
memcpy(allSamples[1], allSamples[0], frameCount * sizeof(float));
|
||||
|
||||
for(size_t i=0; i<filterCount; i++)
|
||||
{
|
||||
FilterInfo* filterInfo = filterInfos[i];
|
||||
for(size_t j=0; j<filterInfo->inChannelCount; j++)
|
||||
currentSamples[j] = allSamples[filterInfo->inChannels[j]];
|
||||
if(filterInfo->inPlace)
|
||||
{
|
||||
for(size_t j=0; j<filterInfo->outChannelCount; j++)
|
||||
currentSamples2[j] = allSamples[filterInfo->outChannels[j]];
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t j=0; j<filterInfo->outChannelCount; j++)
|
||||
currentSamples2[j] = allSamples2[filterInfo->outChannels[j]];
|
||||
}
|
||||
|
||||
filterInfo->filter->process(currentSamples2, currentSamples, frameCount);
|
||||
|
||||
if(!filterInfo->inPlace)
|
||||
{
|
||||
for(size_t j=0; j<filterInfo->outChannelCount; j++)
|
||||
swap(allSamples[filterInfo->outChannels[j]], allSamples2[filterInfo->outChannels[j]]);
|
||||
swap(currentSamples, currentSamples2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FilterConfiguration::write(float* output, unsigned frameCount)
|
||||
{
|
||||
#define INTERLEAVE_MACRO(ccount) \
|
||||
for (size_t c=0; c<ccount; c++)\
|
||||
{\
|
||||
float* sampleChannel = allSamples[c];\
|
||||
float* o2 = output + c;\
|
||||
for (unsigned i = 0; i < frameCount; i++)\
|
||||
{\
|
||||
o2[i*ccount] = sampleChannel[i];\
|
||||
}\
|
||||
}
|
||||
|
||||
switch(outputChannelCount)
|
||||
{
|
||||
case 1:
|
||||
INTERLEAVE_MACRO(1)
|
||||
break;
|
||||
case 2:
|
||||
INTERLEAVE_MACRO(2)
|
||||
break;
|
||||
case 6:
|
||||
INTERLEAVE_MACRO(6)
|
||||
break;
|
||||
case 8:
|
||||
INTERLEAVE_MACRO(8)
|
||||
break;
|
||||
default:
|
||||
INTERLEAVE_MACRO(outputChannelCount)
|
||||
}
|
||||
}
|
||||
#pragma AVRT_CODE_END
|
||||
|
||||
bool FilterConfiguration::isEmpty()
|
||||
{
|
||||
return filterCount == 0;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
class FilterEngine;
|
||||
|
||||
struct FilterInfo
|
||||
{
|
||||
IFilter* filter;
|
||||
bool inPlace;
|
||||
size_t* inChannels;
|
||||
size_t inChannelCount;
|
||||
size_t* outChannels;
|
||||
size_t outChannelCount;
|
||||
};
|
||||
|
||||
#pragma AVRT_VTABLES_BEGIN
|
||||
class FilterConfiguration
|
||||
{
|
||||
public:
|
||||
FilterConfiguration(FilterEngine* engine, const std::vector<FilterInfo*>& filterInfos, unsigned allChannelCount);
|
||||
~FilterConfiguration();
|
||||
|
||||
void process(float* input, unsigned frameCount);
|
||||
void write(float* output, unsigned frameCount);
|
||||
float** getOutputSamples() {return allSamples;}
|
||||
bool isEmpty();
|
||||
|
||||
private:
|
||||
unsigned realChannelCount;
|
||||
unsigned outputChannelCount;
|
||||
unsigned allChannelCount;
|
||||
float** allSamples;
|
||||
float** allSamples2;
|
||||
float** currentSamples;
|
||||
float** currentSamples2;
|
||||
FilterInfo** filterInfos;
|
||||
unsigned filterCount;
|
||||
};
|
||||
#pragma AVRT_VTABLES_END
|
||||
@@ -0,0 +1,667 @@
|
||||
/*
|
||||
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 <sstream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <Ks.h>
|
||||
#include <KsMedia.h>
|
||||
#include <mpPackageCommon.h>
|
||||
#include <mpPackageNonCmplx.h>
|
||||
#include <mpPackageStr.h>
|
||||
#include <mpPackageMatrix.h>
|
||||
|
||||
#include "helpers/RegistryHelper.h"
|
||||
#include "helpers/StringHelper.h"
|
||||
#include "helpers/LogHelper.h"
|
||||
#include "helpers/MemoryHelper.h"
|
||||
#include "FilterEngine.h"
|
||||
#include "filters/ExpressionFilterFactory.h"
|
||||
#include "filters/DeviceFilterFactory.h"
|
||||
#include "filters/StageFilterFactory.h"
|
||||
#include "filters/IfFilterFactory.h"
|
||||
#include "filters/ChannelFilterFactory.h"
|
||||
#include "filters/BiQuadFilterFactory.h"
|
||||
#include "filters/IIRFilterFactory.h"
|
||||
#include "filters/PreampFilterFactory.h"
|
||||
#include "filters/DelayFilterFactory.h"
|
||||
#include "filters/CopyFilterFactory.h"
|
||||
#include "filters/IncludeFilterFactory.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace mup;
|
||||
|
||||
FilterEngine::FilterEngine()
|
||||
:parser(0)
|
||||
{
|
||||
lfx = false;
|
||||
capture = false;
|
||||
inputChannelCount = 0;
|
||||
lastInputWasSilent = false;
|
||||
lastInputSize = -1;
|
||||
threadHandle = NULL;
|
||||
currentConfig = NULL;
|
||||
nextConfig = NULL;
|
||||
previousConfig = NULL;
|
||||
transitionCounter = 0;
|
||||
InitializeCriticalSection(&loadSection);
|
||||
loadSemaphore = CreateSemaphore(NULL, 1, 1, NULL);
|
||||
parser.EnableAutoCreateVar(true);
|
||||
|
||||
factories.push_back(new DeviceFilterFactory());
|
||||
factories.push_back(new IfFilterFactory());
|
||||
factories.push_back(new ExpressionFilterFactory());
|
||||
factories.push_back(new IncludeFilterFactory());
|
||||
factories.push_back(new StageFilterFactory());
|
||||
factories.push_back(new ChannelFilterFactory());
|
||||
factories.push_back(new IIRFilterFactory());
|
||||
factories.push_back(new BiQuadFilterFactory());
|
||||
factories.push_back(new PreampFilterFactory());
|
||||
factories.push_back(new DelayFilterFactory());
|
||||
factories.push_back(new CopyFilterFactory());
|
||||
|
||||
channelNameToPosMap[L"L"] = SPEAKER_FRONT_LEFT;
|
||||
channelNameToPosMap[L"R"] = SPEAKER_FRONT_RIGHT;
|
||||
channelNameToPosMap[L"C"] = SPEAKER_FRONT_CENTER;
|
||||
channelNameToPosMap[L"SUB"] = SPEAKER_LOW_FREQUENCY;
|
||||
channelNameToPosMap[L"RL"] = SPEAKER_BACK_LEFT;
|
||||
channelNameToPosMap[L"RR"] = SPEAKER_BACK_RIGHT;
|
||||
channelNameToPosMap[L"RC"] = SPEAKER_BACK_CENTER;
|
||||
channelNameToPosMap[L"SL"] = SPEAKER_SIDE_LEFT;
|
||||
channelNameToPosMap[L"SR"] = SPEAKER_SIDE_RIGHT;
|
||||
|
||||
for(hash_map<wstring, int>::iterator it=channelNameToPosMap.begin(); it!=channelNameToPosMap.end(); it++)
|
||||
channelPosToNameMap[it->second] = it->first;
|
||||
}
|
||||
|
||||
FilterEngine::~FilterEngine()
|
||||
{
|
||||
// Make sure notification thread is terminated before cleaning up, otherwise deleted memory might be accessed in loadConfig
|
||||
if(threadHandle != NULL)
|
||||
{
|
||||
SetEvent(shutdownEvent);
|
||||
if(WaitForSingleObject(threadHandle, INFINITE) == WAIT_OBJECT_0)
|
||||
{
|
||||
TraceF(L"Successfully terminated directory change notification thread");
|
||||
}
|
||||
CloseHandle(shutdownEvent);
|
||||
CloseHandle(threadHandle);
|
||||
threadHandle = NULL;
|
||||
}
|
||||
|
||||
cleanupConfigurations();
|
||||
|
||||
for(vector<IFilterFactory*>::iterator it = factories.begin(); it != factories.end(); it++)
|
||||
delete *it;
|
||||
|
||||
CloseHandle(loadSemaphore);
|
||||
DeleteCriticalSection(&loadSection);
|
||||
}
|
||||
|
||||
void FilterEngine::setLfx(bool lfx)
|
||||
{
|
||||
this->lfx = lfx;
|
||||
}
|
||||
|
||||
void FilterEngine::setDeviceInfo(bool capture, const wstring& deviceName, const wstring& connectionName, const wstring& deviceGuid)
|
||||
{
|
||||
this->capture = capture;
|
||||
this->deviceName = deviceName;
|
||||
this->connectionName = connectionName;
|
||||
this->deviceGuid = deviceGuid;
|
||||
}
|
||||
|
||||
void FilterEngine::initialize(float sampleRate, unsigned inputChannelCount, unsigned realChannelCount, unsigned outputChannelCount, unsigned channelMask, unsigned maxFrameCount)
|
||||
{
|
||||
EnterCriticalSection(&loadSection);
|
||||
|
||||
cleanupConfigurations();
|
||||
|
||||
this->sampleRate = sampleRate;
|
||||
this->inputChannelCount = inputChannelCount;
|
||||
this->realChannelCount = realChannelCount;
|
||||
this->outputChannelCount = outputChannelCount;
|
||||
this->maxFrameCount = maxFrameCount;
|
||||
this->transitionCounter = 0;
|
||||
this->transitionLength = (unsigned)(sampleRate / 100);
|
||||
|
||||
unsigned deviceChannelCount;
|
||||
if(capture)
|
||||
deviceChannelCount = inputChannelCount;
|
||||
else
|
||||
deviceChannelCount = outputChannelCount;
|
||||
|
||||
if(channelMask == 0)
|
||||
{
|
||||
switch(deviceChannelCount)
|
||||
{
|
||||
case 1:
|
||||
channelMask = KSAUDIO_SPEAKER_MONO;
|
||||
break;
|
||||
case 2:
|
||||
channelMask = KSAUDIO_SPEAKER_STEREO;
|
||||
break;
|
||||
case 4:
|
||||
channelMask = KSAUDIO_SPEAKER_QUAD;
|
||||
break;
|
||||
case 6:
|
||||
channelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND;
|
||||
break;
|
||||
case 8:
|
||||
channelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this->channelMask = channelMask;
|
||||
|
||||
wstringstream channelStream;
|
||||
unsigned c=0;
|
||||
for(int i=0; i<31; i++)
|
||||
{
|
||||
int channelPos = 1<<i;
|
||||
if(channelMask & channelPos)
|
||||
{
|
||||
c++;
|
||||
if(channelStream.tellp() > 0)
|
||||
channelStream << L" ";
|
||||
if(channelPosToNameMap.find(channelPos) != channelPosToNameMap.end())
|
||||
channelStream << channelPosToNameMap[channelPos];
|
||||
else
|
||||
channelStream << c;
|
||||
}
|
||||
}
|
||||
TraceF(L"%d channels for this device: %s", deviceChannelCount, channelStream.str().c_str());
|
||||
|
||||
try
|
||||
{
|
||||
configPath = RegistryHelper::readValue(APP_REGPATH, L"ConfigPath");
|
||||
}
|
||||
catch(RegistryException e)
|
||||
{
|
||||
LogF(L"Can't read config path because of: %s", e.getMessage().c_str());
|
||||
LeaveCriticalSection(&loadSection);
|
||||
return;
|
||||
}
|
||||
|
||||
parser.ClearConst();
|
||||
parser.ClearFun();
|
||||
parser.ClearInfixOprt();
|
||||
parser.ClearOprt();
|
||||
parser.ClearPostfixOprt();
|
||||
parser.AddPackage(PackageCommon::Instance());
|
||||
parser.AddPackage(PackageNonCmplx::Instance());
|
||||
parser.AddPackage(PackageStr::Instance());
|
||||
parser.AddPackage(PackageMatrix::Instance());
|
||||
|
||||
for(vector<IFilterFactory*>::const_iterator it = factories.cbegin(); it != factories.cend(); it++)
|
||||
{
|
||||
IFilterFactory* factory = *it;
|
||||
factory->initialize(this);
|
||||
}
|
||||
|
||||
if(configPath != L"")
|
||||
{
|
||||
loadConfig();
|
||||
|
||||
if(threadHandle == NULL)
|
||||
{
|
||||
shutdownEvent = CreateEventW(NULL, true, false, NULL);
|
||||
threadHandle = CreateThread(NULL, 0, notificationThread, this, 0, NULL);
|
||||
if(threadHandle == INVALID_HANDLE_VALUE)
|
||||
threadHandle = NULL;
|
||||
else
|
||||
TraceF(L"Successfully created directory change notification thread %d for %s and its subtree", GetThreadId(threadHandle), configPath.c_str());
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&loadSection);
|
||||
}
|
||||
|
||||
void FilterEngine::loadConfig()
|
||||
{
|
||||
EnterCriticalSection(&loadSection);
|
||||
timer.start();
|
||||
if(previousConfig != NULL)
|
||||
{
|
||||
previousConfig->~FilterConfiguration();
|
||||
MemoryHelper::free(previousConfig);
|
||||
previousConfig = NULL;
|
||||
}
|
||||
|
||||
allChannelNames.clear();
|
||||
unsigned c=1;
|
||||
for(int i=0; i<31; i++)
|
||||
{
|
||||
int channelPos = 1<<i;
|
||||
if(channelMask & channelPos)
|
||||
{
|
||||
if(channelPosToNameMap.find(channelPos) != channelPosToNameMap.end())
|
||||
allChannelNames.push_back(channelPosToNameMap[channelPos]);
|
||||
else
|
||||
allChannelNames.push_back(to_wstring((unsigned long long)c));
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
// handle channels not covered by channelMask
|
||||
for(; c<=max(realChannelCount, outputChannelCount); c++)
|
||||
allChannelNames.push_back(to_wstring((unsigned long long)c));
|
||||
|
||||
currentChannelNames = allChannelNames;
|
||||
lastChannelNames.clear();
|
||||
lastNewChannelNames.clear();
|
||||
watchRegistryKeys.clear();
|
||||
parser.ClearVar();
|
||||
|
||||
for(vector<IFilterFactory*>::const_iterator it = factories.cbegin(); it != factories.cend(); it++)
|
||||
{
|
||||
IFilterFactory* factory = *it;
|
||||
vector<IFilter*> newFilters = factory->startOfConfiguration();
|
||||
if(!newFilters.empty())
|
||||
addFilters(newFilters);
|
||||
}
|
||||
|
||||
loadConfig(configPath + L"\\config.txt");
|
||||
|
||||
for(vector<IFilterFactory*>::const_iterator it = factories.cbegin(); it != factories.cend(); it++)
|
||||
{
|
||||
IFilterFactory* factory = *it;
|
||||
vector<IFilter*> newFilters = factory->endOfConfiguration();
|
||||
if(!newFilters.empty())
|
||||
addFilters(newFilters);
|
||||
}
|
||||
|
||||
void* mem = MemoryHelper::alloc(sizeof(FilterConfiguration));
|
||||
FilterConfiguration* config = new (mem) FilterConfiguration(this, filterInfos, (unsigned)allChannelNames.size());
|
||||
|
||||
filterInfos.clear();
|
||||
|
||||
double loadTime = timer.stop();
|
||||
TraceF(L"Finished loading configuration after %lf milliseconds", loadTime * 1000.0);
|
||||
|
||||
if(currentConfig == NULL)
|
||||
currentConfig = config;
|
||||
else
|
||||
nextConfig = config;
|
||||
|
||||
LeaveCriticalSection(&loadSection);
|
||||
}
|
||||
|
||||
void FilterEngine::loadConfig(const wstring& path)
|
||||
{
|
||||
TraceF(L"Loading configuration from %s", path.c_str());
|
||||
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||||
while(hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hFile = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
if(error != ERROR_SHARING_VIOLATION)
|
||||
{
|
||||
LogF(L"Error while reading configuration file: %s", StringHelper::getSystemErrorString(error).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// file is being written, so wait
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
stringstream inputStream;
|
||||
|
||||
char buf[8192];
|
||||
unsigned long bytesRead = -1;
|
||||
while(ReadFile(hFile, buf, sizeof(buf), &bytesRead, NULL) && bytesRead != 0)
|
||||
{
|
||||
inputStream.write(buf, bytesRead);
|
||||
}
|
||||
|
||||
CloseHandle(hFile);
|
||||
|
||||
inputStream.seekg(0);
|
||||
|
||||
vector<wstring> savedChannelNames = currentChannelNames;
|
||||
|
||||
for(vector<IFilterFactory*>::const_iterator it = factories.cbegin(); it != factories.cend(); it++)
|
||||
{
|
||||
IFilterFactory* factory = *it;
|
||||
vector<IFilter*> newFilters = factory->startOfFile(path);
|
||||
if(!newFilters.empty())
|
||||
addFilters(newFilters);
|
||||
}
|
||||
|
||||
while(!inputStream.eof())
|
||||
{
|
||||
string encodedLine;
|
||||
getline(inputStream, encodedLine);
|
||||
if(encodedLine.size() > 0 && encodedLine[encodedLine.size()-1] == '\r')
|
||||
encodedLine.resize(encodedLine.size()-1);
|
||||
|
||||
wstring line = StringHelper::toWString(encodedLine, CP_UTF8);
|
||||
if(line.find(L'\uFFFD') != -1)
|
||||
line = StringHelper::toWString(encodedLine, CP_ACP);
|
||||
|
||||
size_t pos = line.find(L':');
|
||||
if(pos != -1)
|
||||
{
|
||||
wstring key = line.substr(0, pos);
|
||||
wstring value = line.substr(pos + 1);
|
||||
|
||||
// allow to use indentation
|
||||
key = StringHelper::trim(key);
|
||||
|
||||
for(vector<IFilterFactory*>::const_iterator it = factories.cbegin(); it != factories.cend(); it++)
|
||||
{
|
||||
IFilterFactory* factory = *it;
|
||||
|
||||
vector<IFilter*> newFilters;
|
||||
try
|
||||
{
|
||||
newFilters = factory->createFilter(path, key, value);
|
||||
}
|
||||
catch(exception e)
|
||||
{
|
||||
LogF(L"%S", e.what());
|
||||
}
|
||||
|
||||
if(key == L"")
|
||||
break;
|
||||
if(!newFilters.empty())
|
||||
{
|
||||
addFilters(newFilters);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(vector<IFilterFactory*>::const_iterator it = factories.cbegin(); it != factories.cend(); it++)
|
||||
{
|
||||
IFilterFactory* factory = *it;
|
||||
vector<IFilter*> newFilters = factory->endOfFile(path);
|
||||
if(!newFilters.empty())
|
||||
addFilters(newFilters);
|
||||
}
|
||||
|
||||
// restore channels selected in outer configuration file
|
||||
currentChannelNames = savedChannelNames;
|
||||
}
|
||||
|
||||
void FilterEngine::watchRegistryKey(const std::wstring& key)
|
||||
{
|
||||
watchRegistryKeys.insert(key);
|
||||
}
|
||||
|
||||
#pragma AVRT_CODE_BEGIN
|
||||
void FilterEngine::process(float *output, float *input, unsigned frameCount)
|
||||
{
|
||||
bool inputSilent = true;
|
||||
|
||||
if(lastInputSize != frameCount)
|
||||
{
|
||||
if(lastInputSize != -1)
|
||||
LogF(L"Input size changed from %d to %d", lastInputSize, frameCount);
|
||||
lastInputSize = frameCount;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < frameCount * realChannelCount; i++)
|
||||
{
|
||||
if(input[i] != 0)
|
||||
{
|
||||
inputSilent = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(inputSilent)
|
||||
{
|
||||
if(lastInputWasSilent)
|
||||
{
|
||||
//Avoid processing cost if silence would be output anyway
|
||||
if(input != output)
|
||||
memset(output, 0, frameCount * outputChannelCount * sizeof(float));
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
lastInputWasSilent = true;
|
||||
}
|
||||
else
|
||||
lastInputWasSilent = false;
|
||||
|
||||
if(currentConfig->isEmpty() && nextConfig == NULL)
|
||||
{
|
||||
// avoid (de-)interleaving cost if no processing will happen anyway
|
||||
if(realChannelCount == outputChannelCount)
|
||||
{
|
||||
if(input != output)
|
||||
memcpy(output, input, outputChannelCount * frameCount * sizeof(float));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
currentConfig->process(input, frameCount);
|
||||
|
||||
if(nextConfig != NULL)
|
||||
{
|
||||
nextConfig->process(input, frameCount);
|
||||
float** currentSamples = currentConfig->getOutputSamples();
|
||||
float** nextSamples = nextConfig->getOutputSamples();
|
||||
|
||||
for(unsigned f=0; f<frameCount; f++)
|
||||
{
|
||||
float factor = 0.5f * (1.0f - cos(transitionCounter * (float)M_PI / transitionLength));
|
||||
if(transitionCounter >= transitionLength)
|
||||
factor = 1.0f;
|
||||
|
||||
for(unsigned c=0; c<outputChannelCount; c++)
|
||||
currentSamples[c][f] = currentSamples[c][f] * (1-factor) + nextSamples[c][f] * factor;
|
||||
|
||||
transitionCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
currentConfig->write(output, frameCount);
|
||||
|
||||
if(nextConfig != NULL && transitionCounter >= transitionLength)
|
||||
{
|
||||
previousConfig = currentConfig;
|
||||
currentConfig = nextConfig;
|
||||
nextConfig = NULL;
|
||||
transitionCounter = 0;
|
||||
ReleaseSemaphore(loadSemaphore, 1, NULL);
|
||||
}
|
||||
}
|
||||
#pragma AVRT_CODE_END
|
||||
|
||||
void FilterEngine::addFilters(vector<IFilter*> filters)
|
||||
{
|
||||
for(vector<IFilter*>::iterator it = filters.begin(); it != filters.end(); it++)
|
||||
{
|
||||
IFilter* filter = *it;
|
||||
FilterInfo* filterInfo = (FilterInfo*)MemoryHelper::alloc(sizeof(FilterInfo));
|
||||
filterInfo->filter = filter;
|
||||
filterInfo->inPlace = filter->getInPlace();
|
||||
vector<wstring> savedChannelNames = currentChannelNames;
|
||||
bool allChannels = filter->getAllChannels();
|
||||
if(allChannels)
|
||||
currentChannelNames = allChannelNames;
|
||||
|
||||
if(lastChannelNames == currentChannelNames)
|
||||
{
|
||||
filterInfo->inChannelCount = 0;
|
||||
filterInfo->inChannels = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
filterInfo->inChannelCount = currentChannelNames.size();
|
||||
filterInfo->inChannels = (size_t*)MemoryHelper::alloc(filterInfo->inChannelCount * sizeof(size_t));
|
||||
|
||||
size_t c = 0;
|
||||
for(vector<wstring>::iterator it2 = currentChannelNames.begin(); it2 != currentChannelNames.end(); it2++)
|
||||
{
|
||||
vector<wstring>::iterator pos = find(allChannelNames.begin(), allChannelNames.end(), *it2);
|
||||
filterInfo->inChannels[c++] = pos - allChannelNames.begin();
|
||||
}
|
||||
}
|
||||
|
||||
lastChannelNames = currentChannelNames;
|
||||
|
||||
vector<wstring> newChannelNames = filter->initialize(sampleRate, maxFrameCount, currentChannelNames);
|
||||
|
||||
if(filterInfo->inPlace && lastInPlace && lastNewChannelNames == newChannelNames)
|
||||
{
|
||||
filterInfo->outChannelCount = 0;
|
||||
filterInfo->outChannels = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
filterInfo->outChannelCount = newChannelNames.size();
|
||||
filterInfo->outChannels = (size_t*)MemoryHelper::alloc(filterInfo->outChannelCount * sizeof(size_t));
|
||||
|
||||
size_t c = 0;
|
||||
for(vector<wstring>::iterator it2 = newChannelNames.begin(); it2 != newChannelNames.end(); it2++)
|
||||
{
|
||||
vector<wstring>::iterator pos = find(allChannelNames.begin(), allChannelNames.end(), *it2);
|
||||
if(pos == allChannelNames.end())
|
||||
{
|
||||
filterInfo->outChannels[c++] = allChannelNames.size();
|
||||
allChannelNames.push_back(*it2);
|
||||
}
|
||||
else
|
||||
{
|
||||
filterInfo->outChannels[c++] = pos - allChannelNames.begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastNewChannelNames = newChannelNames;
|
||||
lastInPlace = filterInfo->inPlace;
|
||||
if(!lastInPlace)
|
||||
swap(lastChannelNames, lastNewChannelNames);
|
||||
|
||||
filterInfos.push_back(filterInfo);
|
||||
|
||||
if(filter->getSelectChannels())
|
||||
currentChannelNames = newChannelNames;
|
||||
else
|
||||
currentChannelNames = savedChannelNames;
|
||||
}
|
||||
}
|
||||
|
||||
void FilterEngine::cleanupConfigurations()
|
||||
{
|
||||
if(currentConfig != NULL)
|
||||
{
|
||||
currentConfig->~FilterConfiguration();
|
||||
MemoryHelper::free(currentConfig);
|
||||
currentConfig = NULL;
|
||||
}
|
||||
|
||||
if(nextConfig != NULL)
|
||||
{
|
||||
nextConfig->~FilterConfiguration();
|
||||
MemoryHelper::free(nextConfig);
|
||||
nextConfig = NULL;
|
||||
}
|
||||
|
||||
if(previousConfig != NULL)
|
||||
{
|
||||
previousConfig->~FilterConfiguration();
|
||||
MemoryHelper::free(previousConfig);
|
||||
previousConfig = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long __stdcall FilterEngine::notificationThread(void* parameter)
|
||||
{
|
||||
FilterEngine* engine = (FilterEngine*)parameter;
|
||||
|
||||
HANDLE notificationHandle = FindFirstChangeNotificationW(engine->configPath.c_str(), true, FILE_NOTIFY_CHANGE_LAST_WRITE);
|
||||
if(notificationHandle == INVALID_HANDLE_VALUE)
|
||||
notificationHandle = NULL;
|
||||
|
||||
HANDLE registryEvent = CreateEventW(NULL, true, false, NULL);
|
||||
|
||||
HANDLE handles[3] = {engine->shutdownEvent, notificationHandle, registryEvent};
|
||||
while(true)
|
||||
{
|
||||
vector<HKEY> keyHandles;
|
||||
for(auto it = engine->watchRegistryKeys.begin(); it != engine->watchRegistryKeys.end(); it++)
|
||||
{
|
||||
try
|
||||
{
|
||||
HKEY keyHandle = RegistryHelper::openKey(*it, KEY_NOTIFY | KEY_WOW64_64KEY);
|
||||
keyHandles.push_back(keyHandle);
|
||||
RegNotifyChangeKeyValue(keyHandle, false, REG_NOTIFY_CHANGE_LAST_SET, registryEvent, true);
|
||||
}
|
||||
catch(RegistryException e)
|
||||
{
|
||||
LogFStatic(L"%s", e.getMessage().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
DWORD which = WaitForMultipleObjects(3, handles, false, INFINITE);
|
||||
|
||||
for(auto it = keyHandles.begin(); it != keyHandles.end(); it++)
|
||||
{
|
||||
RegCloseKey(*it);
|
||||
}
|
||||
|
||||
if(which == WAIT_OBJECT_0)
|
||||
{
|
||||
//Shutdown
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(which == WAIT_OBJECT_0 + 1)
|
||||
{
|
||||
FindNextChangeNotification(notificationHandle);
|
||||
//Wait for second event within 10 milliseconds to avoid loading twice
|
||||
WaitForMultipleObjects(1, ¬ificationHandle, false, 10);
|
||||
}
|
||||
|
||||
HANDLE handles[2] = {engine->shutdownEvent, engine->loadSemaphore};
|
||||
DWORD which = WaitForMultipleObjects(2, handles, false, INFINITE);
|
||||
if(which == WAIT_OBJECT_0)
|
||||
{
|
||||
//Shutdown
|
||||
break;
|
||||
}
|
||||
|
||||
engine->loadConfig();
|
||||
FindNextChangeNotification(notificationHandle);
|
||||
ResetEvent(registryEvent);
|
||||
}
|
||||
}
|
||||
|
||||
FindCloseChangeNotification(notificationHandle);
|
||||
CloseHandle(registryEvent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
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 <hash_map>
|
||||
#include <hash_set>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <mpParser.h>
|
||||
|
||||
#include "IFilterFactory.h"
|
||||
#include "FilterConfiguration.h"
|
||||
#include "helpers/PrecisionTimer.h"
|
||||
#include "helpers/MemoryHelper.h"
|
||||
|
||||
#pragma AVRT_VTABLES_BEGIN
|
||||
class FilterEngine
|
||||
{
|
||||
public:
|
||||
FilterEngine();
|
||||
~FilterEngine();
|
||||
|
||||
void setLfx(bool lfx);
|
||||
void setDeviceInfo(bool capture, const std::wstring& deviceName, const std::wstring& connectionName, const std::wstring& deviceGuid);
|
||||
void initialize(float sampleRate, unsigned inputChannelCount, unsigned realChannelCount, unsigned outputChannelCount, unsigned channelMask, unsigned maxFrameCount);
|
||||
void loadConfig();
|
||||
void loadConfig(const std::wstring& path);
|
||||
void watchRegistryKey(const std::wstring& key);
|
||||
void process(float *output, float *input, unsigned frameCount);
|
||||
|
||||
bool isLfx() const {return lfx;}
|
||||
bool isCapture() const {return capture;}
|
||||
std::wstring getDeviceName() const {return deviceName;}
|
||||
std::wstring getConnectionName() const {return connectionName;}
|
||||
std::wstring getDeviceGuid() const {return deviceGuid;}
|
||||
unsigned getInputChannelCount() const {return inputChannelCount;}
|
||||
unsigned getRealChannelCount() const {return realChannelCount;}
|
||||
unsigned getOutputChannelCount() const {return outputChannelCount;}
|
||||
unsigned getChannelMask() const {return channelMask;}
|
||||
float getSampleRate() const {return sampleRate;}
|
||||
unsigned getMaxFrameCount() const {return maxFrameCount;}
|
||||
mup::ParserX* getParser() {return &parser;}
|
||||
|
||||
private:
|
||||
void addFilters(std::vector<IFilter*> filters);
|
||||
void cleanupConfigurations();
|
||||
static unsigned long __stdcall notificationThread(void* parameter);
|
||||
|
||||
std::vector<IFilterFactory*> factories;
|
||||
|
||||
bool lfx;
|
||||
bool capture;
|
||||
std::wstring deviceName;
|
||||
std::wstring connectionName;
|
||||
std::wstring deviceGuid;
|
||||
std::wstring configPath;
|
||||
float sampleRate;
|
||||
// number of input channels that originally existed before child APO processing
|
||||
unsigned inputChannelCount;
|
||||
// number of input channels in process (including channels coming from child APO output)
|
||||
unsigned realChannelCount;
|
||||
unsigned outputChannelCount;
|
||||
unsigned channelMask;
|
||||
unsigned maxFrameCount;
|
||||
|
||||
// only used during loading
|
||||
std::vector<FilterInfo*> filterInfos;
|
||||
std::vector<std::wstring> currentChannelNames;
|
||||
std::vector<std::wstring> lastChannelNames;
|
||||
std::vector<std::wstring> lastNewChannelNames;
|
||||
std::vector<std::wstring> allChannelNames;
|
||||
bool lastInPlace;
|
||||
mup::ParserX parser;
|
||||
|
||||
FilterConfiguration* currentConfig;
|
||||
FilterConfiguration* nextConfig;
|
||||
FilterConfiguration* previousConfig;
|
||||
|
||||
unsigned transitionCounter;
|
||||
unsigned transitionLength;
|
||||
HANDLE loadSemaphore;
|
||||
CRITICAL_SECTION loadSection;
|
||||
PrecisionTimer timer;
|
||||
void* threadHandle;
|
||||
void* shutdownEvent;
|
||||
stdext::hash_set<std::wstring> watchRegistryKeys;
|
||||
bool lastInputWasSilent;
|
||||
unsigned lastInputSize;
|
||||
stdext::hash_map<std::wstring, int> channelNameToPosMap;
|
||||
stdext::hash_map<int, std::wstring> channelPosToNameMap;
|
||||
};
|
||||
#pragma AVRT_VTABLES_END
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
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 "helpers/LogHelper.h"
|
||||
#include "IFilter.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int IFilter::getChannelIndex(std::wstring word, const std::vector<std::wstring>& channelNames, bool allowNew)
|
||||
{
|
||||
int channelIndex = -1;
|
||||
|
||||
if(iswdigit(word[0]))
|
||||
{
|
||||
channelIndex = wcstol(word.c_str(), NULL, 10) - 1;
|
||||
|
||||
if(channelIndex < 0 || channelIndex >= (int)channelNames.size())
|
||||
{
|
||||
LogF(L"Channel number %s out of range (1 - %d)", word.c_str(), channelNames.size());
|
||||
channelIndex = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vector<wstring>::const_iterator pos = find(channelNames.begin(), channelNames.end(), word);
|
||||
|
||||
if(pos == channelNames.end())
|
||||
{
|
||||
//Special handling to accept "wrong", but unambiguous positions
|
||||
if(word == L"SL")
|
||||
pos = find(channelNames.begin(), channelNames.end(), L"RL");
|
||||
else if(word == L"SR")
|
||||
pos = find(channelNames.begin(), channelNames.end(), L"RR");
|
||||
else if(word == L"RL")
|
||||
pos = find(channelNames.begin(), channelNames.end(), L"SL");
|
||||
else if(word == L"RR")
|
||||
pos = find(channelNames.begin(), channelNames.end(), L"SR");
|
||||
}
|
||||
|
||||
if(pos != channelNames.end())
|
||||
channelIndex = (int)(pos - channelNames.begin());
|
||||
else if(!allowNew)
|
||||
LogF(L"Invalid channel position %s", word.c_str());
|
||||
}
|
||||
|
||||
return channelIndex;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
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 "helpers/MemoryHelper.h"
|
||||
|
||||
#pragma AVRT_VTABLES_BEGIN
|
||||
class IFilter
|
||||
{
|
||||
public:
|
||||
virtual ~IFilter() {}
|
||||
|
||||
// request to get all channel names instead of selection
|
||||
virtual bool getAllChannels() {return false;}
|
||||
// request that output and input do not point to the same memory locations
|
||||
virtual bool getInPlace() {return true;}
|
||||
// request that the channelNames returned by initialize become the new selection
|
||||
virtual bool getSelectChannels() {return false;}
|
||||
// return value is the channelNames vector, which may contain additional or fewer channel names
|
||||
virtual std::vector<std::wstring> initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames) = 0;
|
||||
virtual void process(float** output, float** input, unsigned frameCount) = 0;
|
||||
|
||||
protected:
|
||||
int getChannelIndex(std::wstring word, const std::vector<std::wstring>& channelNames, bool allowNew = false);
|
||||
};
|
||||
#pragma AVRT_VTABLES_END
|
||||
@@ -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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include "helpers/MemoryHelper.h"
|
||||
#include "IFilter.h"
|
||||
|
||||
class FilterEngine;
|
||||
|
||||
#pragma AVRT_VTABLES_BEGIN
|
||||
class IFilterFactory
|
||||
{
|
||||
public:
|
||||
virtual ~IFilterFactory() {}
|
||||
|
||||
virtual void initialize(FilterEngine* engine) {}
|
||||
virtual std::vector<IFilter*> startOfConfiguration() {return std::vector<IFilter*>();}
|
||||
virtual std::vector<IFilter*> startOfFile(const std::wstring& configPath) {return std::vector<IFilter*>();}
|
||||
// command and parameter may be altered by the factory
|
||||
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters) = 0;
|
||||
virtual std::vector<IFilter*> endOfFile(const std::wstring& configPath) {return std::vector<IFilter*>();}
|
||||
virtual std::vector<IFilter*> endOfConfiguration() {return std::vector<IFilter*>();}
|
||||
};
|
||||
#pragma AVRT_VTABLES_END
|
||||
@@ -1,736 +0,0 @@
|
||||
/*
|
||||
This file is part of EqualizerAPO, a system-wide equalizer.
|
||||
Copyright (C) 2012 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 <cstdio>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <regex>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <Ks.h>
|
||||
#include <KsMedia.h>
|
||||
|
||||
#include "StringHelper.h"
|
||||
#include "RegistryHelper.h"
|
||||
#include "LogHelper.h"
|
||||
#include "ParametricEQ.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace stdext;
|
||||
|
||||
static wregex regexType(L"^\\s*ON\\s+([A-Za-z]+)");
|
||||
static wregex regexFreq(L"\\s+Fc\\s*([0-9.\u00A0]+)\\s*H\\s*z");
|
||||
static wregex regexGain(L"\\s+Gain\\s*([-+0-9.]+)\\s*dB");
|
||||
static wregex regexQ(L"\\s+Q\\s*([0-9.]+)");
|
||||
static wregex regexBW(L"\\s+BW\\s+Oct\\s*([0-9.]+)");
|
||||
static wregex regexSlope(L"^\\s*([0-9.]+)\\s*dB");
|
||||
|
||||
ChannelData::ChannelData()
|
||||
{
|
||||
preamp = 1.0f;
|
||||
filterCount = 0;
|
||||
}
|
||||
|
||||
ParametricEQ::ParametricEQ()
|
||||
{
|
||||
channelCount = 0;
|
||||
channelData = NULL;
|
||||
lastInputWasSilent = false;
|
||||
threadHandle = NULL;
|
||||
|
||||
channelNameToPosMap[L"L"] = SPEAKER_FRONT_LEFT;
|
||||
channelNameToPosMap[L"R"] = SPEAKER_FRONT_RIGHT;
|
||||
channelNameToPosMap[L"C"] = SPEAKER_FRONT_CENTER;
|
||||
channelNameToPosMap[L"SUB"] = SPEAKER_LOW_FREQUENCY;
|
||||
channelNameToPosMap[L"RL"] = SPEAKER_BACK_LEFT;
|
||||
channelNameToPosMap[L"RR"] = SPEAKER_BACK_RIGHT;
|
||||
channelNameToPosMap[L"RC"] = SPEAKER_BACK_CENTER;
|
||||
channelNameToPosMap[L"SL"] = SPEAKER_SIDE_LEFT;
|
||||
channelNameToPosMap[L"SR"] = SPEAKER_SIDE_RIGHT;
|
||||
|
||||
for(hash_map<wstring, int>::iterator it=channelNameToPosMap.begin(); it!=channelNameToPosMap.end(); it++)
|
||||
channelPosToNameMap[it->second] = it->first;
|
||||
|
||||
filterNameToTypeMap[L"PK"] = BiQuad::PEAKING;
|
||||
filterNameToTypeMap[L"PEQ"] = BiQuad::PEAKING;
|
||||
filterNameToTypeMap[L"Modal"] = BiQuad::PEAKING;
|
||||
filterNameToTypeMap[L"LP"] = BiQuad::LOW_PASS;
|
||||
filterNameToTypeMap[L"HP"] = BiQuad::HIGH_PASS;
|
||||
filterNameToTypeMap[L"LPQ"] = BiQuad::LOW_PASS;
|
||||
filterNameToTypeMap[L"HPQ"] = BiQuad::HIGH_PASS;
|
||||
filterNameToTypeMap[L"BP"] = BiQuad::BAND_PASS;
|
||||
filterNameToTypeMap[L"LS"] = BiQuad::LOW_SHELF;
|
||||
filterNameToTypeMap[L"HS"] = BiQuad::HIGH_SHELF;
|
||||
filterNameToTypeMap[L"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";
|
||||
}
|
||||
|
||||
ParametricEQ::~ParametricEQ()
|
||||
{
|
||||
// Make sure notification thread is terminated before cleaning up, otherwise deleted memory might be accessed in loadConfig
|
||||
if(threadHandle != NULL)
|
||||
{
|
||||
SetEvent(shutdownEvent);
|
||||
if(WaitForSingleObject(threadHandle, INFINITE) == WAIT_OBJECT_0)
|
||||
{
|
||||
TraceF(L"Successfully terminated directory change notification thread");
|
||||
}
|
||||
CloseHandle(shutdownEvent);
|
||||
CloseHandle(threadHandle);
|
||||
threadHandle = NULL;
|
||||
}
|
||||
|
||||
if(channelData != NULL)
|
||||
{
|
||||
delete[] channelData;
|
||||
channelData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ParametricEQ::setDeviceInfo(const wstring& deviceName, const wstring& connectionName, const wstring& deviceGuid)
|
||||
{
|
||||
this->deviceName = deviceName;
|
||||
this->connectionName = connectionName;
|
||||
this->deviceGuid = deviceGuid;
|
||||
}
|
||||
|
||||
void ParametricEQ::initialize(float sampleRate, unsigned channelCount, unsigned channelMask)
|
||||
{
|
||||
this->sampleRate = sampleRate;
|
||||
this->channelCount = channelCount;
|
||||
channelData = new ChannelData[channelCount];
|
||||
|
||||
if(channelMask == 0)
|
||||
{
|
||||
switch(channelCount)
|
||||
{
|
||||
case 1:
|
||||
channelMask = KSAUDIO_SPEAKER_MONO;
|
||||
break;
|
||||
case 2:
|
||||
channelMask = KSAUDIO_SPEAKER_STEREO;
|
||||
break;
|
||||
case 4:
|
||||
channelMask = KSAUDIO_SPEAKER_QUAD;
|
||||
break;
|
||||
case 6:
|
||||
channelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND;
|
||||
break;
|
||||
case 8:
|
||||
channelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this->channelMask = channelMask;
|
||||
|
||||
wstringstream channelNames;
|
||||
unsigned c=0;
|
||||
for(int i=0; i<31; i++)
|
||||
{
|
||||
int channelPos = 1<<i;
|
||||
if(channelMask & channelPos)
|
||||
{
|
||||
c++;
|
||||
if(channelNames.tellp() > 0)
|
||||
channelNames << L" ";
|
||||
if(channelPosToNameMap.find(channelPos) != channelPosToNameMap.end())
|
||||
channelNames << channelPosToNameMap[channelPos];
|
||||
else
|
||||
channelNames << c;
|
||||
}
|
||||
}
|
||||
TraceF(L"%d channels for this device: %s", channelCount, channelNames.str().c_str());
|
||||
|
||||
try
|
||||
{
|
||||
configPath = RegistryHelper::readValue(APP_REGPATH, L"ConfigPath");
|
||||
}
|
||||
catch(RegistryException e)
|
||||
{
|
||||
LogF(L"Can't read config path because of: %s", e.getMessage().c_str());
|
||||
return;
|
||||
}
|
||||
if(configPath != L"")
|
||||
{
|
||||
loadConfig();
|
||||
|
||||
if(threadHandle == NULL)
|
||||
{
|
||||
shutdownEvent = CreateEventW(NULL, true, false, NULL);
|
||||
threadHandle = CreateThread(NULL, 0, notificationThread, this, 0, NULL);
|
||||
if(threadHandle == INVALID_HANDLE_VALUE)
|
||||
threadHandle = NULL;
|
||||
else
|
||||
{
|
||||
TraceF(L"Successfully created directory change notification thread for %s and its subtree", configPath.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParametricEQ::loadConfig()
|
||||
{
|
||||
for(unsigned c=0; c<channelCount; c++)
|
||||
{
|
||||
channelData[c].loadPreamp = 1.0f;
|
||||
channelData[c].loadFilterCount = 0;
|
||||
}
|
||||
|
||||
vector<bool> selectedChannels(channelCount, true);
|
||||
loadConfig(configPath + L"\\config.txt", selectedChannels);
|
||||
|
||||
unsigned loadFilterCount = 0;
|
||||
for(unsigned c=0; c<channelCount; c++)
|
||||
{
|
||||
channelData[c].preamp = channelData[c].loadPreamp;
|
||||
channelData[c].filterCount = channelData[c].loadFilterCount;
|
||||
loadFilterCount += channelData[c].loadFilterCount;
|
||||
}
|
||||
|
||||
wstringstream channelFilterCounts;
|
||||
unsigned c=0;
|
||||
for(int i=0; i<31; i++)
|
||||
{
|
||||
int channelPos = 1<<i;
|
||||
if(channelMask & channelPos)
|
||||
{
|
||||
c++;
|
||||
if(channelFilterCounts.tellp() > 0)
|
||||
channelFilterCounts << L" ";
|
||||
if(channelPosToNameMap.find(channelPos) != channelPosToNameMap.end())
|
||||
channelFilterCounts << channelPosToNameMap[channelPos];
|
||||
else
|
||||
channelFilterCounts << c;
|
||||
|
||||
channelFilterCounts << ":" << channelData[c-1].loadFilterCount;
|
||||
}
|
||||
}
|
||||
|
||||
TraceF(L"%d filters loaded: %s", loadFilterCount, channelFilterCounts.str().c_str());
|
||||
}
|
||||
|
||||
void ParametricEQ::loadConfig(const wstring& path, vector<bool> selectedChannels)
|
||||
{
|
||||
TraceF(L"Loading configuration from %s", path.c_str());
|
||||
|
||||
ifstream inputStream(path);
|
||||
if(!inputStream.good())
|
||||
{
|
||||
LogF(L"Config file not found at %s!", path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
boolean deviceMatches = true;
|
||||
wstring deviceString = StringHelper::toLowerCase(deviceName + L" " + connectionName + L" " + deviceGuid);
|
||||
|
||||
while(!inputStream.eof())
|
||||
{
|
||||
string encodedLine;
|
||||
getline(inputStream, encodedLine);
|
||||
|
||||
wstring line = StringHelper::toWString(encodedLine, CP_UTF8);
|
||||
if(line.find(L'\uFFFD') != -1)
|
||||
line = StringHelper::toWString(encodedLine, CP_ACP);
|
||||
|
||||
size_t pos = line.find(L':');
|
||||
if(pos != -1)
|
||||
{
|
||||
wstring key = line.substr(0, pos);
|
||||
wstring value = line.substr(pos + 1);
|
||||
|
||||
if(key == L"Device")
|
||||
{
|
||||
value = value + 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;
|
||||
}
|
||||
}
|
||||
|
||||
boolean 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(deviceString.find(word) == -1)
|
||||
{
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(matches)
|
||||
break;
|
||||
}
|
||||
|
||||
TraceF(L"%satching pattern \"%s\" with device \"%s\" \"%s\" \"%s\"", matches ? L"M" : L"Not m", value.substr(0, value.length()-1).c_str(), deviceName.c_str(), connectionName.c_str(), deviceGuid.c_str());
|
||||
deviceMatches = matches;
|
||||
}
|
||||
|
||||
if(!deviceMatches)
|
||||
continue;
|
||||
|
||||
if(key == L"Channel")
|
||||
{
|
||||
selectedChannels = vector<bool>(channelCount, false);
|
||||
|
||||
value = value + L" ";
|
||||
|
||||
wstring currentWord;
|
||||
for(unsigned i=0; i<value.length(); i++)
|
||||
{
|
||||
wchar_t c = towupper(value[i]);
|
||||
|
||||
if(c == L' ')
|
||||
{
|
||||
if(currentWord.length() > 0)
|
||||
{
|
||||
int channelNr = -1;
|
||||
|
||||
if(currentWord == L"ALL")
|
||||
{
|
||||
selectedChannels = vector<bool>(channelCount, true);
|
||||
}
|
||||
else if(iswdigit(currentWord[0]))
|
||||
{
|
||||
channelNr = wcstol(currentWord.c_str(), NULL, 10) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int channelPos = -1;
|
||||
if(channelNameToPosMap.find(currentWord) != channelNameToPosMap.end())
|
||||
channelPos = channelNameToPosMap[currentWord];
|
||||
else
|
||||
LogF(L"Invalid channel position %s", currentWord.c_str());
|
||||
|
||||
if(channelPos != -1)
|
||||
channelNr = getChannelNumber(channelPos);
|
||||
}
|
||||
|
||||
if(channelNr != -1 && channelNr < (int)channelCount)
|
||||
{
|
||||
selectedChannels[channelNr] = true;
|
||||
}
|
||||
|
||||
currentWord.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
currentWord += c;
|
||||
}
|
||||
}
|
||||
|
||||
wstringstream channelNumbers;
|
||||
for(unsigned 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());
|
||||
}
|
||||
else if(key.find(L"Filter") == 0)
|
||||
{
|
||||
//Conversion to period as decimal mark, if needed
|
||||
value = StringHelper::replaceCharacters(value, L",", L".");
|
||||
|
||||
wsmatch match;
|
||||
wstring typeString;
|
||||
|
||||
bool found = regex_search(value, match, regexType);
|
||||
if(found)
|
||||
{
|
||||
typeString = match.str(1);
|
||||
if(filterNameToTypeMap.find(typeString) != filterNameToTypeMap.end())
|
||||
{
|
||||
BiQuad::Type type = filterNameToTypeMap[typeString];
|
||||
wstring typeDescription = filterTypeToDescriptionMap[type];
|
||||
value = match.suffix().str();
|
||||
|
||||
wstringstream stream;
|
||||
stream << L"Adding " << typeDescription << L" filter";
|
||||
|
||||
float freq = 0;
|
||||
float gain = 0;
|
||||
float bandwidthOrQOrS = 0;
|
||||
bool isBandwidth = false;
|
||||
bool error = false;
|
||||
|
||||
found = regex_search(value, match, regexFreq);
|
||||
if(found)
|
||||
{
|
||||
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(), value.c_str());
|
||||
error = true;
|
||||
}
|
||||
|
||||
found = regex_search(value, match, regexGain);
|
||||
if(found)
|
||||
{
|
||||
if(type == BiQuad::LOW_PASS || type == BiQuad::HIGH_PASS || type == BiQuad::NOTCH || type == BiQuad::ALL_PASS)
|
||||
TraceF(L"Ignoring gain for filter of type %s", typeDescription.c_str());
|
||||
else
|
||||
{
|
||||
wstring gainString = match.str(1);
|
||||
gain = (float)wcstod(gainString.c_str(), NULL);
|
||||
if(type == BiQuad::PEAKING)
|
||||
stream << ", gain " << gain << " dB";
|
||||
else
|
||||
stream << " and gain " << gain << " dB";
|
||||
}
|
||||
}
|
||||
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(), value.c_str());
|
||||
error = true;
|
||||
}
|
||||
|
||||
found = regex_search(value, match, regexQ);
|
||||
if(found)
|
||||
{
|
||||
if(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
|
||||
TraceF(L"Ignoring Q for filter of type %s", typeDescription.c_str());
|
||||
else
|
||||
{
|
||||
wstring qString = match.str(1);
|
||||
bandwidthOrQOrS = (float)wcstod(qString.c_str(), NULL);
|
||||
stream << " and Q " << bandwidthOrQOrS;
|
||||
}
|
||||
}
|
||||
|
||||
found = regex_search(value, match, regexBW);
|
||||
if(found)
|
||||
{
|
||||
if(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
|
||||
TraceF(L"Ignoring bandwidth for filter of type %s", typeDescription.c_str());
|
||||
else
|
||||
{
|
||||
wstring bwString = match.str(1);
|
||||
bandwidthOrQOrS = (float)wcstod(bwString.c_str(), NULL);
|
||||
isBandwidth = true;
|
||||
stream << " and bandwidth " << bandwidthOrQOrS << " octaves";
|
||||
}
|
||||
}
|
||||
|
||||
found = regex_search(value, match, regexSlope);
|
||||
if(found)
|
||||
{
|
||||
if(!(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF))
|
||||
TraceF(L"Ignoring slope for filter of type %s", typeDescription.c_str());
|
||||
else
|
||||
{
|
||||
wstring slopeString = match.str(1);
|
||||
bandwidthOrQOrS = (float)wcstod(slopeString.c_str(), NULL);
|
||||
stream << " and slope " << bandwidthOrQOrS << " dB";
|
||||
}
|
||||
}
|
||||
|
||||
if(bandwidthOrQOrS == 0)
|
||||
{
|
||||
if(type == BiQuad::PEAKING || type == BiQuad::ALL_PASS)
|
||||
{
|
||||
LogF(L"No Q or bandwidth given in filter string %s%s", typeString.c_str(), value.c_str());
|
||||
error = true;
|
||||
}
|
||||
else if(type == BiQuad::LOW_PASS || type == BiQuad::HIGH_PASS || type == BiQuad::BAND_PASS)
|
||||
{
|
||||
bandwidthOrQOrS = (float)M_SQRT1_2;
|
||||
}
|
||||
else if(type == BiQuad::LOW_SHELF || type == BiQuad::HIGH_SHELF)
|
||||
{
|
||||
bandwidthOrQOrS = 0.9f; // found out by experimentation with RoomEQWizard
|
||||
}
|
||||
else if(type == BiQuad::NOTCH)
|
||||
{
|
||||
bandwidthOrQOrS = 30.0f; // 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.0f;
|
||||
if(typeString[typeString.length()-1] != L'C')
|
||||
{
|
||||
// frequency adjustment for DCX2496
|
||||
float centerFreqFactor = pow(10.0f, abs(gain) / 80.0f / bandwidthOrQOrS);
|
||||
if(type == BiQuad::LOW_SHELF)
|
||||
freq *= centerFreqFactor;
|
||||
else
|
||||
freq /= centerFreqFactor;
|
||||
}
|
||||
}
|
||||
|
||||
if(!error)
|
||||
{
|
||||
TraceF(L"%s", stream.str().c_str());
|
||||
|
||||
for(unsigned c=0; c<channelCount; c++)
|
||||
{
|
||||
if(selectedChannels[c] && channelData[c].loadFilterCount < (sizeof(channelData[c].filters)/sizeof(BiQuad)))
|
||||
{
|
||||
channelData[c].filters[channelData[c].loadFilterCount++] = BiQuad(type, gain, freq, sampleRate, bandwidthOrQOrS, isBandwidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(typeString != L"None")
|
||||
{
|
||||
LogF(L"Invalid filter type %s", typeString.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(key == L"Preamp")
|
||||
{
|
||||
//Conversion to period as decimal mark, if needed
|
||||
value = StringHelper::replaceCharacters(value, L",", L".");
|
||||
|
||||
float preamp_dB;
|
||||
int matched = swscanf_s(value.c_str(), L" %f dB", &preamp_dB);
|
||||
if(matched == 1)
|
||||
{
|
||||
for(unsigned c=0; c<channelCount; c++)
|
||||
{
|
||||
if(selectedChannels[c])
|
||||
{
|
||||
channelData[c].loadPreamp *= pow(10.0f, preamp_dB / 20.0f);
|
||||
}
|
||||
}
|
||||
|
||||
TraceF(L"Adjusting preamp by %g dB", preamp_dB);
|
||||
}
|
||||
}
|
||||
else if(key == L"Include")
|
||||
{
|
||||
while(value.length() > 0 && iswspace(value[0]))
|
||||
value = value.substr(1);
|
||||
|
||||
wstring includePath;
|
||||
if(PathIsRelativeW(value.c_str()))
|
||||
{
|
||||
wchar_t filePath[MAX_PATH];
|
||||
path._Copy_s(filePath, sizeof(filePath), MAX_PATH);
|
||||
if(path.size() < MAX_PATH)
|
||||
filePath[path.size()] = L'\0';
|
||||
else
|
||||
filePath[MAX_PATH - 1] = L'\0';
|
||||
PathRemoveFileSpecW(filePath);
|
||||
PathAppendW(filePath, value.c_str());
|
||||
includePath = filePath;
|
||||
}
|
||||
else
|
||||
includePath = value;
|
||||
|
||||
loadConfig(includePath, selectedChannels);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParametricEQ::process(float *output, float *input, unsigned frameCount)
|
||||
{
|
||||
bool inputSilent = true;
|
||||
|
||||
for (unsigned i = 0; i < frameCount * channelCount; i++)
|
||||
{
|
||||
if(input[i] != 0)
|
||||
{
|
||||
inputSilent = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(inputSilent)
|
||||
{
|
||||
if(lastInputWasSilent)
|
||||
{
|
||||
//Avoid processing cost if silence would be output anyway
|
||||
if(input != output)
|
||||
memset(output, 0, frameCount * channelCount * sizeof(float));
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
lastInputWasSilent = true;
|
||||
}
|
||||
else
|
||||
lastInputWasSilent = false;
|
||||
|
||||
//Avoid denormals
|
||||
for (unsigned c=0; c<channelCount; c++)
|
||||
{
|
||||
for(unsigned f=0; f<channelData[c].filterCount; f++)
|
||||
{
|
||||
channelData[c].filters[f].removeDenormals();
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < frameCount * channelCount; i+=channelCount)
|
||||
for (unsigned c=0; c<channelCount; c++)
|
||||
{
|
||||
float sample = input[i+c];
|
||||
|
||||
for(unsigned f=0; f<channelData[c].filterCount; f++)
|
||||
{
|
||||
sample = channelData[c].filters[f].process(sample);
|
||||
}
|
||||
|
||||
output[i+c] = sample * channelData[c].preamp;
|
||||
}
|
||||
}
|
||||
|
||||
float ParametricEQ::getFreq(const wstring& freqString)
|
||||
{
|
||||
float 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"%f", &result);
|
||||
if(matched == 1)
|
||||
{
|
||||
if(s.length() >= 5)
|
||||
{
|
||||
if(s[s.length() - 4] == L'.')
|
||||
{
|
||||
//Interpret as thousands separator because of Room EQ Wizard
|
||||
result *= 1000.0f;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
unsigned ParametricEQ::getChannelNumber(unsigned position)
|
||||
{
|
||||
//Special handling to accept "wrong", but unambiguous positions
|
||||
if(channelMask == KSAUDIO_SPEAKER_5POINT1_SURROUND)
|
||||
{
|
||||
if(position == SPEAKER_BACK_LEFT)
|
||||
return 4;
|
||||
else if(position == SPEAKER_BACK_RIGHT)
|
||||
return 5;
|
||||
}
|
||||
else if(channelMask == KSAUDIO_SPEAKER_5POINT1)
|
||||
{
|
||||
if(position == SPEAKER_SIDE_LEFT)
|
||||
return 4;
|
||||
else if(position == SPEAKER_SIDE_RIGHT)
|
||||
return 5;
|
||||
}
|
||||
|
||||
if((channelMask & position) == 0)
|
||||
return -1;
|
||||
|
||||
int channelNr = 0;
|
||||
for(unsigned i=1; i<position; i<<=1)
|
||||
{
|
||||
if(channelMask & i)
|
||||
channelNr++;
|
||||
}
|
||||
|
||||
return channelNr;
|
||||
}
|
||||
|
||||
unsigned long __stdcall ParametricEQ::notificationThread(void* parameter)
|
||||
{
|
||||
ParametricEQ* peq = (ParametricEQ*)parameter;
|
||||
|
||||
HANDLE notificationHandle = FindFirstChangeNotificationW(peq->configPath.c_str(), true, FILE_NOTIFY_CHANGE_LAST_WRITE);
|
||||
if(notificationHandle == INVALID_HANDLE_VALUE)
|
||||
notificationHandle = NULL;
|
||||
|
||||
HANDLE handles[2] = {peq->shutdownEvent, notificationHandle};
|
||||
while(true)
|
||||
{
|
||||
DWORD which = WaitForMultipleObjects(2, handles, false, INFINITE);
|
||||
|
||||
if(which == WAIT_OBJECT_0)
|
||||
{
|
||||
//Shutdown
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
FindNextChangeNotification(notificationHandle);
|
||||
//Wait for second event within 100 milliseconds to avoid loading twice
|
||||
WaitForMultipleObjects(1, ¬ificationHandle, false, 100);
|
||||
peq->loadConfig();
|
||||
FindNextChangeNotification(notificationHandle);
|
||||
}
|
||||
}
|
||||
|
||||
FindCloseChangeNotification(notificationHandle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
This file is part of EqualizerAPO, a system-wide equalizer.
|
||||
Copyright (C) 2012 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 <hash_map>
|
||||
|
||||
#include "BiQuad.h"
|
||||
|
||||
struct ChannelData
|
||||
{
|
||||
ChannelData();
|
||||
|
||||
float preamp;
|
||||
unsigned filterCount;
|
||||
BiQuad filters[100];
|
||||
|
||||
// used while loading instead of overwriting immediately
|
||||
float loadPreamp;
|
||||
unsigned loadFilterCount;
|
||||
};
|
||||
|
||||
class ParametricEQ
|
||||
{
|
||||
public:
|
||||
ParametricEQ();
|
||||
~ParametricEQ();
|
||||
|
||||
void setDeviceInfo(const std::wstring& deviceName, const std::wstring& connectionName, const std::wstring& deviceGuid);
|
||||
void initialize(float sampleRate, unsigned channelCount, unsigned channelMask);
|
||||
void loadConfig();
|
||||
void process(float *output, float *input, unsigned frameCount);
|
||||
|
||||
private:
|
||||
void loadConfig(const std::wstring& path, std::vector<bool> selectedChannels);
|
||||
float getFreq(const std::wstring& freqString);
|
||||
unsigned getChannelNumber(unsigned position);
|
||||
static unsigned long __stdcall notificationThread(void* parameter);
|
||||
|
||||
std::wstring deviceName;
|
||||
std::wstring connectionName;
|
||||
std::wstring deviceGuid;
|
||||
std::wstring configPath;
|
||||
float sampleRate;
|
||||
unsigned channelCount;
|
||||
unsigned channelMask;
|
||||
ChannelData* channelData;
|
||||
bool lastInputWasSilent;
|
||||
void* threadHandle;
|
||||
void* shutdownEvent;
|
||||
stdext::hash_map<std::wstring, int> channelNameToPosMap;
|
||||
stdext::hash_map<int, std::wstring> channelPosToNameMap;
|
||||
stdext::hash_map<std::wstring, BiQuad::Type> filterNameToTypeMap;
|
||||
stdext::hash_map<BiQuad::Type, std::wstring> filterTypeToDescriptionMap;
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
[{000214A0-0000-0000-C000-000000000046}]
|
||||
Prop3=19,2
|
||||
[InternetShortcut]
|
||||
URL=http://sourceforge.net/p/equalizerapo/wiki/Configuration%20reference
|
||||
IDList=
|
||||
HotKey=0
|
||||
@@ -118,6 +118,7 @@ Section "Install" SecInstall
|
||||
File "${LIBPATH}\msvcr100.dll"
|
||||
|
||||
File "Configuration tutorial (online).url"
|
||||
File "Configuration reference (online).url"
|
||||
|
||||
CreateDirectory "$INSTDIR\config"
|
||||
|
||||
@@ -126,6 +127,8 @@ Section "Install" SecInstall
|
||||
File /oname=config\example.txt "config\example.txt"
|
||||
File /oname=config\demo.txt "config\demo.txt"
|
||||
File /oname=config\multichannel.txt "config\multichannel.txt"
|
||||
File /oname=config\iir_lowpass.txt "config\iir_lowpass.txt"
|
||||
File /oname=config\selective_delay.txt "config\selective_delay.txt"
|
||||
SetOverwrite on
|
||||
|
||||
;Grant write access to the config directory for all users
|
||||
@@ -141,6 +144,7 @@ Section "Install" SecInstall
|
||||
;Create shortcuts
|
||||
CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Configuration tutorial (online).lnk" "$INSTDIR\Configuration tutorial (online).url"
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Configuration reference (online).lnk" "$INSTDIR\Configuration reference (online).url"
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Configurator.lnk" "$INSTDIR\Configurator.exe"
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Benchmark.lnk" "$INSTDIR\Benchmark.exe"
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
||||
@@ -184,6 +188,7 @@ Section "-un.Uninstall"
|
||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder
|
||||
RMDir /r "$SMPROGRAMS\$StartMenuFolder"
|
||||
|
||||
Delete "$INSTDIR\Configuration reference (online).url"
|
||||
Delete "$INSTDIR\Configuration tutorial (online).url"
|
||||
|
||||
Delete /REBOOTOK "$INSTDIR\msvcr100.dll"
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# This shows how to create a lowpass biquad filter using the IIR filter type
|
||||
# The result should be equivalent to the command
|
||||
# Filter: ON LP Fc 3000 Hz
|
||||
|
||||
Do: `freq = 3000`
|
||||
Do: `Q = 1/sqrt(2)`
|
||||
Do: `omega = 2 * pi * freq / sampleRate`
|
||||
Do: `sn = sin(omega)`
|
||||
Do: `cs = cos(omega)`
|
||||
Do: `alpha = sin(omega) / (2 * Q)`
|
||||
Do: `a0 = (1 - cs) / 2`
|
||||
Do: `a1 = 1 - cs`
|
||||
Do: `a2 = (1 - cs) / 2`
|
||||
Do: `b0 = 1 + alpha`
|
||||
Do: `b1 = -2 * cs`
|
||||
Do: `b2 = 1 - alpha`
|
||||
|
||||
Filter: ON IIR Order 2 Coefficients `a0` `a1` `a2` `b0` `b1` `b2`
|
||||
@@ -0,0 +1,11 @@
|
||||
# Copy channels to virtual channels to filter them while keeping the originals
|
||||
Copy: L2=L R2=R
|
||||
# Select channels for filtering
|
||||
Channel: L2 R2
|
||||
# Limit frequency range for delay
|
||||
Filter: ON HP Fc 200 Hz
|
||||
Filter: ON LP Fc 2000 Hz
|
||||
# Apply delay
|
||||
Delay: 500 ms
|
||||
# Add the delayed signal back to the original channels
|
||||
Copy: L=0.5*L+0.5*L2 R=0.5*R+0.5*R2
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
This file is part of EqualizerAPO, a system-wide equalizer.
|
||||
Copyright (C) 2013 Jonas Thedering
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include "StringHelper.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
wstring StringHelper::replaceCharacters(wstring s, wstring chars, wstring replacement)
|
||||
{
|
||||
wstring result;
|
||||
result.reserve(s.length());
|
||||
|
||||
for(unsigned i=0; i<s.length(); i++)
|
||||
{
|
||||
wchar_t c = s[i];
|
||||
if(chars.find(c) == -1)
|
||||
result += c;
|
||||
else
|
||||
result += replacement;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
wstring StringHelper::replaceIllegalCharacters(wstring filename)
|
||||
{
|
||||
return replaceCharacters(filename, L"<>:\"/\\|?*", L"_");
|
||||
}
|
||||
|
||||
wstring StringHelper::toWString(string s, unsigned codepage)
|
||||
{
|
||||
int length = MultiByteToWideChar(codepage, 0, s.c_str(), -1, NULL, 0);
|
||||
wchar_t* charBuf = new wchar_t[length];
|
||||
MultiByteToWideChar(codepage, 0, s.c_str(), -1, charBuf, length);
|
||||
wstring result = charBuf;
|
||||
delete charBuf;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
wstring StringHelper::toLowerCase(wstring s)
|
||||
{
|
||||
wchar_t* charBuf = new wchar_t[s.length() + 1];
|
||||
memcpy(charBuf, s.c_str(), (s.length() + 1) * sizeof(wchar_t));
|
||||
errno_t err = _wcslwr_s(charBuf, s.length() + 1);
|
||||
|
||||
wstring result = charBuf;
|
||||
delete charBuf;
|
||||
|
||||
if(err == 0)
|
||||
return result;
|
||||
else
|
||||
return s;
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
This page describes the configuration file format and the commands supported by Equalizer APO. This information is meant for advanced users. To get an introduction to using Equalizer APO or if you need troubleshooting go to the [user documentation](https://sourceforge.net/p/equalizerapo/wiki/).
|
||||
|
||||
**Table of contents:**
|
||||
|
||||
[TOC]
|
||||
|
||||
# Configuration file format
|
||||
|
||||
The configuration files of Equalizer APO are organized as lines of the following format:
|
||||
|
||||
Command: Parameters
|
||||
|
||||
All lines not conforming to this format are silently ignored, like the comment lines that start with # in the example below.
|
||||
Lines that contain any command name not supported are also silently ignored.
|
||||
|
||||
Example:
|
||||
|
||||
:::perl
|
||||
Device: High Definition Audio Device Speakers; Benchmark
|
||||
#All lines below will only be applied to the specified device and the benchmark application
|
||||
Preamp: -6 db
|
||||
Include: example.txt
|
||||
Filter 1: ON PK Fc 50 Hz Gain -3.0 dB Q 10.00
|
||||
Filter 2: ON PEQ Fc 100 Hz Gain 1.0 dB BW Oct 0.167
|
||||
|
||||
Channel: L
|
||||
#Additional preamp for left channel
|
||||
Preamp: -5 dB
|
||||
#Filters only for left channel
|
||||
Include: demo.txt
|
||||
Filter 1: ON LS Fc 300 Hz Gain 5.0 dB
|
||||
|
||||
Channel: 2 C
|
||||
#Filters for second(right) and center channel
|
||||
Filter 1: ON HP Fc 30 Hz
|
||||
Filter 2: ON LPQ Fc 10000 Hz Q 0.400
|
||||
|
||||
Device: Microphone
|
||||
#From here, the lines only apply to microphone devices
|
||||
Filter: ON NO Fc 50 Hz
|
||||
|
||||
<br>
|
||||
# Filtering commands
|
||||
|
||||
These commands directly change the audio on the selected channels.
|
||||
|
||||
## Preamp
|
||||
**Syntax:**
|
||||
Preamp: <Negative number> dB
|
||||
|
||||
**Description:**
|
||||
Sets a preamplification value in decibels. This is useful when you are using filters with positive gain, to make sure that no clipping occurs. Since version 0.8, when multiple preamps apply to the same channel, the resulting preamp is the sum in dB.
|
||||
|
||||
**Example:**
|
||||
|
||||
:::perl
|
||||
Preamp: -6.5 dB
|
||||
|
||||
<br>
|
||||
## Filter
|
||||
**Syntax:**
|
||||
Filter <n>: ON <Type> Fc <Frequency> Hz Gain <Gain value> dB Q <Q value>
|
||||
Filter <n>: ON <Type> Fc <Frequency> Hz Gain <Gain value> dB BW Oct <Bandwidth value>
|
||||
|
||||
**Description:**
|
||||
Adds a filter of the specified type with the specified frequency, gain and Q / bandwidth. The supported filter types and their parameters are listed below. The first parameter variant (with Q) is the filter text format used by Room EQ Wizard for equalizer type "Generic" while the second variant (with bandwidth) is used for equalizer type "FBQ2496". The filter number (n) is not interpreted and can be omitted.
|
||||
|
||||
The following table lists the filter types supported by Equalizer APO since version 0.8.1. The columns Fc, Gain and Q/BW show the parameters supported by the filter type. An 'X' means that the parameter is required while an 'O' denotes an optional parameter. The filter types supported cover all filters of the "Generic" and the "FBQ2496" equalizer type. Other equalizer types may also be compatible if their filter text format is. There is one exception however: The band-pass filter supported by Equalizer APO is a real band-pass filter that does not support gain, like low/high-pass filters, but unlike the DCX2496's "BP" filter, which is actually a peaking filter.
|
||||
|
||||
Type | Description | Fc | Gain | Q/BW | Example for filter parameters
|
||||
- | - | - | - | - | -
|
||||
PK<br>Modal<br>PEQ | Peaking filter<br>(Parametric EQ) | X | X | X | ON PK Fc 50.0 Hz Gain -10.0 dB Q 2.50<br>ON Modal Fc 100 Hz Gain 3.0 dB Q 5.41 T60 target 100 ms<br>ON PEQ Fc 100 Hz Gain 1.0 dB BW Oct 0.167
|
||||
LP<br>LPQ | Low-pass filter | X | | O | ON LP Fc 8000 Hz<br>ON LPQ Fc 10000 Hz Q 0.400
|
||||
HP<br>HPQ | High-pass filter | X | | O | ON HP Fc 30.0 Hz<br>ON HPQ Fc 20.0 Hz Q 0.500
|
||||
BP | Band-pass filter<br>(not from DCX2496) | X | | O | ON BP Fc 1000 Hz Q 0.100
|
||||
LS<br>LSC x dB | Low-shelf filter<br>(with center freq.,<br>x dB per oct. (LSC)) | X | X | | ON LS Fc 300 Hz Gain 5.0 dB<br>ON LSC 10.8 dB Fc 300 Hz Gain 5.0 dB
|
||||
HS<br>HSC x dB | High-shelf filter<br>(with center freq.,<br>x dB per oct. (HSC)) | X | X | | ON HS Fc 1000 Hz Gain -3.0 dB<br>ON HSC 6 dB Fc 100 Hz Gain -6.0 dB
|
||||
LS 6dB<br>LS 12dB | Low-shelf filter<br>(6 / 12 dB per octave<br>with corner freq.) | X | X | | ON LS 6dB Fc 50.0 Hz Gain 7.2 dB<br>ON LS 12dB Fc 2000 Hz Gain -5.0 dB
|
||||
HS 6dB<br>HS 12dB | High-shelf filter<br>(6 / 12 dB per octave<br>with corner freq.) | X | X | | ON HS 6dB Fc 12000 Hz Gain 10.0 dB<br>ON HS 12dB Fc 500 Hz Gain 5.0 dB
|
||||
NO | Notch filter | X | | O | ON NO Fc 800 Hz
|
||||
AP | All-pass filter | X | | X | ON AP Fc 900 Hz Q 0.707
|
||||
|
||||
<br>
|
||||
## Filter with custom coefficients (since version 0.9)
|
||||
**Syntax:**
|
||||
Filter <n>: ON IIR Order <m> Coefficients <b0> <b1> ... <bm> <a0> <a1> ... <am>
|
||||
|
||||
**Description:**
|
||||
Adds a generic IIR filter with the given order and coefficients. The number of coefficients must be 2*(order+1).
|
||||
The transfer function of the filter is
|
||||
|
||||
<img src="/p/equalizerapo/wiki/Images/attachment/Transfer function.png">
|
||||
|
||||
As the filter coefficients are normally dependent on the sample rate, the If command or inline expressions should be used to supply the correct coefficients for the current sample rate.
|
||||
|
||||
Although it is possible to use the IIR filter type to implement the same BiQuad filters that are supported by the other filter types, this is not advisable because the execution time will be higher.
|
||||
|
||||
**Example:**
|
||||
|
||||
:::perl
|
||||
# A lowpass biquad filter with Fc 3000 Hz for the sample rate 48 kHz
|
||||
Filter: ON IIR Order 2 Coefficients 0.0380602 0.0761205 0.0380602 1.2706 -1.84776 0.729402
|
||||
|
||||
<br>
|
||||
## Delay (since version 0.9)
|
||||
**Syntax:**
|
||||
Delay: <t> ms
|
||||
Delay: <n> samples
|
||||
|
||||
**Description:**
|
||||
Delays the audio on the selected channels by t milliseconds or n samples. Milliseconds should be preferred because they will give equal delay independent of the sample rate.
|
||||
|
||||
**Example:**
|
||||
|
||||
:::perl
|
||||
# Delays the audio by 50.5 ms independent of sample rate
|
||||
Delay: 50.5 ms
|
||||
# Delays the audio by 480 samples (10 ms at 48 kHz)
|
||||
Delay: 480 samples
|
||||
|
||||
<br>
|
||||
## Copy (since version 0.9)
|
||||
**Syntax:**
|
||||
Copy: <Target channel>=<Factor>*<Source channel>+...
|
||||
Copy: <Target channel>=<Source channel>+...
|
||||
Copy: <Target channel>=<Constant value>+...
|
||||
|
||||
**Description:**
|
||||
Replaces the audio on the target channel by the sum of the given source channels with optional factors. To add instead of replace the audio on the target channel, the target channel itself can also be a source channel. The factor can also be specified in dB by appending dB. Multiple channel assignments can be specified on a single line by separating them with spaces, therefore a single assignment must not contain spaces. Instead of channel and factor, a constant value can be specified. To avoid ambiguity with numerical channel indices, the constant value must contain a decimal point.
|
||||
|
||||
**Example:**
|
||||
|
||||
:::perl
|
||||
# Adds the audio on channel R multiplied by 0.5 to channel L
|
||||
Copy: L=L+0.5*R
|
||||
# Replaces the audio on channel L by the audio on channel R
|
||||
# plus the audio on channel C attenuated by 6 dB
|
||||
Copy: L=R+-6dB*C
|
||||
# Replaces the audio on the first channel by the audio previously on channel R
|
||||
# Also sets the audio on channel R to the constant value 0.5
|
||||
Copy: 1=R R=0.5
|
||||
# Attention: Sets the audio on channel L to the audio on the second channel
|
||||
# (not to constant value 2, because no decimal point is present)
|
||||
Copy: L=2
|
||||
|
||||
<br>
|
||||
# Control commands
|
||||
These command do not directly affect the audio but control which commands are executed or how they affect the audio.
|
||||
|
||||
## Include
|
||||
**Syntax:**
|
||||
Include: <File name>
|
||||
|
||||
**Description:**
|
||||
Loads the given file as a configuration file. Instead of directly replacing config.txt, it can be better to load the actual filter definition from a separate file so that you can e.g. set a preamp before.
|
||||
|
||||
**Example:**
|
||||
|
||||
:::perl
|
||||
Include: example.txt
|
||||
|
||||
<br>
|
||||
## Device (since version 0.7)
|
||||
**Syntax:**
|
||||
Device: <Device pattern 1>; <Device pattern 2>; ...
|
||||
|
||||
**Description:**
|
||||
Matches the given pattern to the connection name, device name and GUID of the current output device. If the pattern does not match, all following commands except Device commands are ignored. The pattern consists of words separated by space that must all be found in the string "***Device_name*** ***Connection_name*** ***GUID***". Multiple patterns of which one must match can be specified by separating the patterns with ';'. The special pattern "all" matches always. The benchmark application uses the device name "Benchmark" and connection name "File output". The easiest way to generate a Device command is to use the button in the Configurator application.
|
||||
|
||||
**Example:**
|
||||
|
||||
:::perl
|
||||
# Matches the device "High Definition Audio Device" with connection "Speakers"
|
||||
# and also the device "Benchmark" used by the benchmark application
|
||||
Device: High Definition Audio Device Speakers; Benchmark
|
||||
|
||||
<br>
|
||||
## Channel (since version 0.8)
|
||||
**Syntax:**
|
||||
Channel: <Channel position 1> <Channel position 2> ...
|
||||
|
||||
**Description:**
|
||||
Selects the channels to which the following Filter and Preamp commands will be applied. Channel positions can be given by identifier (acronym of 1 up to 3 characters) or by number (counted from 1). The supported channel configurations are listed below. If a channel configuration is not supported, channels can only be selected by number. Multiple channels can be specified by separating with space. The special position "all" selects all channels.
|
||||
|
||||
**Channel configurations:**
|
||||
The following table lists the channel configurations that are supported by Equalizer APO. The channel identifiers in the column titles resemble the channels in Start -> Control Panel -> Sound -> Configure. If a channel position is supported for a configuration, the cell in the corresponding row contains the channel number.
|
||||
|
||||
Configuration | Left<br>L | Right<br>R | Center<br>C | Subwoofer<br>SUB | Rear left<br>RL | Rear right<br>RR | Rear center<br>RC | Side left<br>SL | Side right<br>SR
|
||||
- | - | - | - | - | - | - | - | - | -
|
||||
Mono | | | 1 | | | | | |
|
||||
Stereo | 1 | 2 | | | | | | |
|
||||
Quadraphonic | 1 | 2 | | | 3 | 4 | | |
|
||||
Surround | 1 | 2 | 3 | | | | 4 | |
|
||||
5.1 Surround | 1 | 2 | 3 | 4 | | | | 5 | 6
|
||||
5.1 Surround | 1 | 2 | 3 | 4 | 5 | 6 | | |
|
||||
7.1 Surround | 1 | 2 | 3 | 4 | 5 | 6 | | 7 | 8
|
||||
|
||||
<div style="border: 2px solid red; padding: 3px">
|
||||
|
||||
<b>Attention:</b><br>
|
||||
|
||||
Although it might be tempting to assign low frequency filters only to the subwoofer channel, this might not lead to the expected results. Many audio systems apply bass redirection after Equalizer APO has processed the signal, so filters applied to the subwoofer channel won't be effective for redirected sound. Furthermore, as crossover filters only gradually fade in, the low frequency audio might be played over multiple speakers, not just the subwoofer, reducing the effectivity of subwoofer-only filters. Therefore, to avoid these problems, it's recommended to <b>apply low frequency filters to all channels</b>.
|
||||
</div>
|
||||
<br>
|
||||
**Example:**
|
||||
|
||||
:::perl
|
||||
# Selects the left channel and the rear left channel
|
||||
Channel: L RL
|
||||
# Selects the first, second and center channel
|
||||
Channel: 1 2 C
|
||||
|
||||
<br>
|
||||
## Stage (since version 0.9)
|
||||
**Syntax:**
|
||||
Stage: <stage 1> <stage 2>
|
||||
|
||||
**Description:**
|
||||
Specifies on which stage(s) the following filtering commands will be executed. For output devices, there are two stages: pre-mix and post-mix as illustrated in the following (simplified) diagram:
|
||||
<a href="/p/equalizerapo/wiki/Images/attachment/Stages.svg"><img src="/p/equalizerapo/wiki/Images/attachment/Stages.png"></a>
|
||||
For input devices, there is only the capture stage. Initially, the selected stages are post-mix and capture, so that the filtering commands are executed exactly once for output and input devices. The post-mix stage is preferred to the pre-mix stage because the filtering happens per-application in the pre-mix stage and is therefore more cpu-intensive. However, for specific purposes such as upmixing the pre-mix stage has to be used as it can do filtering based on the number of input channels.
|
||||
|
||||
**Example:**
|
||||
|
||||
:::perl
|
||||
Stage: pre-mix
|
||||
# do upmixing
|
||||
If: inputChannelCount == 2
|
||||
# note that there may be audio on SL, SR from another APO
|
||||
Copy: SL=SL+L SR=SR+R
|
||||
EndIf:
|
||||
# ...
|
||||
Stage: post-mix
|
||||
# do room correction
|
||||
# ...
|
||||
|
||||
<br>
|
||||
# Expression commands (since version 0.9)
|
||||
These commands use expressions to alter the processing behaviour based on runtime variables. Expressions are a tiny language embedded in the configuration file language with a syntax that is closer to scripting languages. The language consists of constants, variables, operators and functions.
|
||||
|
||||
**Constants:**
|
||||
|
||||
Name | Description
|
||||
- | -
|
||||
e, pi | Mathematical constants
|
||||
inputChannelCount | Number of channels that are input to the current APO stage
|
||||
outputChannelCount | Number of channels that are output from the current APO stage
|
||||
sampleRate | Sample rate (in Hz) of the audio in process
|
||||
deviceName | Name of the audio device
|
||||
connectionName | Name of the connection on the audio device
|
||||
deviceGuid | GUID of the audio device endpoint
|
||||
stage | Current APO stage (can be pre-mix, post-mix or capture)
|
||||
|
||||
**Variables:**
|
||||
User-defined variables that are valid while loading the configuration can be defined using the assignment operator (=). The variables will not be retained between configuration reloads, they are just meant to carry temporary values that will be used later in the configuration file.
|
||||
|
||||
**Operators:**
|
||||
|
||||
Name | Description
|
||||
- | -
|
||||
+, -, *, /, ^ | Arithmetic operators
|
||||
=, +=, -=, *=, /= | Assignment operators
|
||||
and, or, xor | Logical operators
|
||||
==, !=, <, >, <=, >= | Comparison operators
|
||||
&, |, <<, >> | Bit-wise / bit-shift operators
|
||||
+ | String concatenation (at least one argument must be a string)
|
||||
(float), (int) | Type conversion (from numerical type)
|
||||
condition ? then : else | Conditional operator (ternary if-then-else)
|
||||
{1,2} | Array creation
|
||||
array\[0\] | Array access
|
||||
|
||||
**Functions:**
|
||||
|
||||
Name | Description
|
||||
- | -
|
||||
abs | Absolute value
|
||||
sin, cos, tan,<br>sinh, cosh, tanh | Trigonometric functions
|
||||
ln, log, log10, exp | Logarithmic / exponential functions
|
||||
sqrt | Square root
|
||||
min, max, sum | Minimum / maximum / sum of arguments
|
||||
str2dbl | Conversion from string to float value
|
||||
strlen | Length of string
|
||||
tolower, toupper | Conversion to lower / upper case
|
||||
sizeof | Length of array
|
||||
regexSearch | Searches first match in string (second argument) to regular expression (first argument). Result is empty if not matching. If matching, result is array with whole match as first value and capturing groups as further values.
|
||||
regexReplace | Replaces all matches in string (second argument) to regular expression (first argument) with string (third argument). Result is string with replacements.
|
||||
readRegString | Reads value (second argument) from specified key (first argument) in the registry. Value must be of type string (REG_SZ). Automatically monitors the registry key for changes and initiates a configuration reload on any value change.
|
||||
readRegDWORD | Reads value (second argument) from specified key (first argument) in the registry. Value must be of type integer (REG_DWORD). Automatically monitors the registry key for changes and initiates a configuration reload on any value change.
|
||||
|
||||
The types supported in expressions are string, boolean, int, float and matrix/array. In error messages, these types are abbreviated to 's', 'b', 'i', 'f' and 'm'. String constants are specified in quotes ("). Backslashes (\\) and quotes need to be escaped by prefixing them with a backslash. Boolean constants are specified as true or false. Integer and float constants are specified without thousands separators and using point (.) as the decimal separator in case of float. Array constants are specified using the {} operator.
|
||||
|
||||
Multiple expressions can be combined into one expression by separating them with semicolon (;). The result will be the value of the last expression.
|
||||
|
||||
**Examples:**
|
||||
|
||||
:::perl
|
||||
# User-defined variables
|
||||
Eval: a=0; b=pi
|
||||
# Comparison
|
||||
Eval: a > b ? "a is larger" : "b is larger"
|
||||
# Trigonometric functions and exponentiation operator
|
||||
Eval: sin(a)^2 + cos(a)^2 == 1
|
||||
# Matching device name with regular expression
|
||||
Eval: a=regexSearch("High Definition .*", deviceName); sizeof(a) > 0 ? "found" : "not found"
|
||||
# Reading configuration path from registry
|
||||
Eval: readRegString("HKEY_LOCAL_MACHINE\\SOFTWARE\\EqualizerAPO", "ConfigPath")
|
||||
|
||||
<br>
|
||||
## If / ElseIf / Else / EndIf
|
||||
**Syntax:**
|
||||
If: <expression>
|
||||
ElseIf: <expression>
|
||||
Else:
|
||||
EndIf:
|
||||
|
||||
**Description:**
|
||||
Conditionally executes the commands between If and EndIf. This resembles the if/else conditional statements found in most programming languages.
|
||||
|
||||
When the command If is encountered, its expression is evaluated and converted to a boolean value. If the result is true, the following commands are executed, otherwise they are skipped.
|
||||
|
||||
When an ElseIf command is encountered after an If or ElseIf command which evaluated to true, the following commands until EndIf are skipped. If the previous If or ElseIf command evaluated to false, the expression of the ElseIf command is evaluated and the following commands are executed if the expression evaluated to true.
|
||||
|
||||
The Else command behaves as an ElseIf command whose expression always evaluates to true.
|
||||
|
||||
The EndIf command ends the conditional execution.
|
||||
|
||||
Conditional execution can be nested, so between If and EndIf can be another If statement. ElseIf and Else always refer to the latest If which was not ended by EndIf. To improve the readability, lines can be indented by inserting space or tab characters at the beginning.
|
||||
|
||||
For technical reasons, If statements can not be used to conditionally execute Device statements as Device statements have a higher priority.
|
||||
|
||||
**Example:**
|
||||
|
||||
:::perl
|
||||
# Executes statements according to the current sample rate and channel count
|
||||
If: sampleRate == 44100
|
||||
...
|
||||
ElseIf: sampleRate == 48000
|
||||
...
|
||||
If: inputChannelCount == 1
|
||||
...
|
||||
ElseIf: inputChannelCount == 2
|
||||
...
|
||||
ElseIf: inputChannelCount == 6
|
||||
...
|
||||
EndIf:
|
||||
Else:
|
||||
...
|
||||
EndIf:
|
||||
|
||||
<br>
|
||||
## Eval and inline expressions
|
||||
**Syntax:**
|
||||
Eval: <expression>
|
||||
<Command>: ... \`<expression>\` ...
|
||||
|
||||
**Description:**
|
||||
The Eval command just evaluates the expression without using its result any further. It is mainly useful to define variables or for testing purposes.
|
||||
|
||||
Inline expressions are used to embed the result of an expression into the parameter string of a command. The result of the expression is converted into a string and replaces the inline expression from the first backtick(`) to the second backtick, inclusive.
|
||||
|
||||
For technical reasons, inline expressions cannot be used in Device and If/ElseIf commands, but they can be used in Eval commands (to evaluate a calculated expression).
|
||||
|
||||
**Example:**
|
||||
|
||||
:::perl
|
||||
# Specify gain linearly
|
||||
Eval: linGain = 0.5
|
||||
Filter: ON PK Fc 1000 Hz Gain `20*log10(linGain)` dB Q 10.0
|
||||
|
||||
<br>
|
||||
+2
-85
@@ -1,4 +1,4 @@
|
||||
Welcome to the Wiki of Equalizer APO. This is the documentation for users of Equalizer APO. Developers might also be interested in reading the [developer documentation](https://sourceforge.net/p/equalizerapo/wiki/Developer%20documentation/). To begin using Equalizer APO, you should read the <a href="#install_tutorial">tutorials</a>.
|
||||
Welcome to the Wiki of Equalizer APO. This is the documentation for users of Equalizer APO. Developers might also be interested in reading the [developer documentation](https://sourceforge.net/p/equalizerapo/wiki/Developer%20documentation/). To begin using Equalizer APO, you should read the <a href="#install_tutorial">tutorials</a>. After that, you can look at more detailed information in the [configuration reference](https://sourceforge.net/p/equalizerapo/wiki/Configuration%20reference/).
|
||||
|
||||
**Table of contents:**
|
||||
|
||||
@@ -36,90 +36,7 @@ A detailed explanation of the usage of Room EQ Wizard is out of the scope of thi
|
||||
Congratulations, you have now created your first configuration for Equalizer APO. To learn more about the usage of RoomEQWizard, you can look into its [help file](http://www.hometheatershack.com/roomeq/wizardhelpv5/help_en-GB/html/index.html). The process can even be automated to some extent, as is explained in this [forum thread](/p/equalizerapo/discussion/general/thread/3ba39cad/).
|
||||
|
||||
# Configuration file format
|
||||
|
||||
The configuration files of Equalizer APO are organized as lines of the following format:
|
||||
|
||||
Command: Parameters
|
||||
|
||||
All lines not conforming to this format are silently ignored, like the comment lines that start with # in the example below.
|
||||
|
||||
Example:
|
||||
|
||||
Device: High Definition Audio Device Speakers; Benchmark
|
||||
#All lines below will only be applied to the specified device and the benchmark application
|
||||
Preamp: -6 db
|
||||
Include: example.txt
|
||||
Filter 1: ON PK Fc 50 Hz Gain -3.0 dB Q 10.00
|
||||
Filter 2: ON PEQ Fc 100 Hz Gain 1.0 dB BW Oct 0.167
|
||||
|
||||
Channel: L
|
||||
#Additional preamp for left channel
|
||||
Preamp: -5 dB
|
||||
#Filters only for left channel
|
||||
Include: demo.txt
|
||||
Filter 1: ON LS Fc 300 Hz Gain 5.0 dB
|
||||
|
||||
Channel: 2 C
|
||||
#Filters for second(right) and center channel
|
||||
Filter 1: ON HP Fc 30 Hz
|
||||
Filter 2: ON LPQ Fc 10000 Hz Q 0.400
|
||||
|
||||
Device: Microphone
|
||||
#From here, the lines only apply to microphone devices
|
||||
Filter: ON NO Fc 50 Hz
|
||||
|
||||
The commands currently defined are:
|
||||
|
||||
Command | Parameters | Description
|
||||
-|-|-
|
||||
Preamp | ***Negative number*** dB | Sets a preamplification value in decibels. This is useful when you are using filters with positive gain, to make sure that no clipping occurs. Since version 0.8, when multiple preamps apply to the same channel, the resulting preamp is the sum in dB.
|
||||
Include | ***File name*** | Loads the given file as a configuration file. Instead of directly replacing config.txt, it can be better to load the actual filter definition from a separate file so that you can e.g. set a preamp before.
|
||||
Filter ***n*** | ON ***Type*** Fc ***Frequency*** Hz Gain ***Gain value*** dB Q ***Q value*** | Adds a filter of the given type with the given frequency, gain and Q. The supported filter types and their parameters are listed <a href="filter_types">below</a>. This is the filter text format used by Room EQ Wizard for equalizer type "Generic". The filter number (n) is not interpreted and can be omitted.
|
||||
Filter ***n*** | ON ***Type*** Fc ***Frequency*** Hz Gain ***Gain value*** dB BW Oct ***Bandwidth value*** | Adds a filter of the given type with the given frequency, gain and bandwidth. The supported filter types and their parameters are listed <a href="filter_types">below</a>. This is the filter text format used by Room EQ Wizard for equalizer type "FBQ2496". The filter number (n) is not interpreted and can be omitted.
|
||||
Device | ***Device identification pattern*** | Matches the given pattern to the connection name, device name and GUID of the current output device. If the pattern does not match, all following commands except Device commands are ignored. The pattern consists of words separated by space that must all be found in the string "***Device_name*** ***Connection_name*** ***GUID***". Multiple patterns of which one must match can be specified by separating the patterns with ';'. The special pattern "all" matches always. The benchmark application uses the device name "Benchmark" and connection name "File output". The easiest way to generate a Device command is to use the button in the Configurator application. (added in version 0.7)
|
||||
Channel | *** Channel positions *** | Selects the channels to which the following Filter and Preamp commands will be applied. Channel positions can be given by identifier (acronym of 1 up to 3 characters) or by number (counted from 1). The supported channel configurations are listed <a href="channel_configs">below</a>. If a channel configuration is not supported, channels can only be selected by number. Multiple channels can be specified by separating with space. The special position "all" selects all channels. (added in version 0.8)
|
||||
|
||||
Lines that contain any command name not in this list are silently ignored.
|
||||
|
||||
<a name="filter_types"></a>
|
||||
# Filter types
|
||||
|
||||
The following table lists the filter types supported by Equalizer APO since version 0.8.1. The columns Fc, Gain and Q/BW show the parameters supported by the filter type. An 'X' means that the parameter is required while an 'O' denotes an optional parameter. The filter types supported cover all filters of the "Generic" and the "FBQ2496" equalizer type. Other equalizer types may also be compatible if their filter text format is. There is one exception however: The band-pass filter supported by Equalizer APO is a real band-pass filter that does not support gain, like low/high-pass filters, but unlike the DCX2496's "BP" filter, which is actually a peaking filter.
|
||||
|
||||
Type | Description | Fc | Gain | Q/BW | Example for filter parameters
|
||||
- | - | - | - | - | -
|
||||
PK<br>Modal<br>PEQ | Peaking filter<br>(Parametric EQ) | X | X | X | ON PK Fc 50.0 Hz Gain -10.0 dB Q 2.50<br>ON Modal Fc 100 Hz Gain 3.0 dB Q 5.41 T60 target 100 ms<br>ON PEQ Fc 100 Hz Gain 1.0 dB BW Oct 0.167
|
||||
LP<br>LPQ | Low-pass filter | X | | O | ON LP Fc 8000 Hz<br>ON LPQ Fc 10000 Hz Q 0.400
|
||||
HP<br>HPQ | High-pass filter | X | | O | ON HP Fc 30.0 Hz<br>ON HPQ Fc 20.0 Hz Q 0.500
|
||||
BP | Band-pass filter<br>(not from DCX2496) | X | | O | ON BP Fc 1000 Hz Q 0.100
|
||||
LS<br>LSC x dB | Low-shelf filter<br>(with center freq.,<br>x dB per oct. (LSC)) | X | X | | ON LS Fc 300 Hz Gain 5.0 dB<br>ON LSC 10.8 dB Fc 300 Hz Gain 5.0 dB
|
||||
HS<br>HSC x dB | High-shelf filter<br>(with center freq.,<br>x dB per oct. (HSC)) | X | X | | ON HS Fc 1000 Hz Gain -3.0 dB<br>ON HSC 6 dB Fc 100 Hz Gain -6.0 dB
|
||||
LS 6dB<br>LS 12dB | Low-shelf filter<br>(6 / 12 dB per octave<br>with corner freq.) | X | X | | ON LS 6dB Fc 50.0 Hz Gain 7.2 dB<br>ON LS 12dB Fc 2000 Hz Gain -5.0 dB
|
||||
HS 6dB<br>HS 12dB | High-shelf filter<br>(6 / 12 dB per octave<br>with corner freq.) | X | X | | ON HS 6dB Fc 12000 Hz Gain 10.0 dB<br>ON HS 12dB Fc 500 Hz Gain 5.0 dB
|
||||
NO | Notch filter | X | | O | ON NO Fc 800 Hz
|
||||
AP | All-pass filter | X | | X | ON AP Fc 900 Hz Q 0.707
|
||||
|
||||
<a name="channel_configs"></a>
|
||||
# Channel configurations
|
||||
|
||||
The following table lists the channel configurations that are supported by Equalizer APO. The channel identifiers in the column titles resemble the channels in Start -> Control Panel -> Sound -> Configure. If a channel position is supported for a configuration, the cell in the corresponding row contains the channel number.
|
||||
|
||||
Configuration | Left<br>L | Right<br>R | Center<br>C | Subwoofer<br>SUB | Rear left<br>RL | Rear right<br>RR | Rear center<br>RC | Side left<br>SL | Side right<br>SR
|
||||
- | - | - | - | - | - | - | - | - | -
|
||||
Mono | | | 1 | | | | | |
|
||||
Stereo | 1 | 2 | | | | | | |
|
||||
Quadraphonic | 1 | 2 | | | 3 | 4 | | |
|
||||
Surround | 1 | 2 | 3 | | | | 4 | |
|
||||
5.1 Surround | 1 | 2 | 3 | 4 | | | | 5 | 6
|
||||
5.1 Surround | 1 | 2 | 3 | 4 | 5 | 6 | | |
|
||||
7.1 Surround | 1 | 2 | 3 | 4 | 5 | 6 | | 7 | 8
|
||||
|
||||
<div style="border: 2px solid red; padding: 3px">
|
||||
|
||||
<b>Attention:</b><br>
|
||||
|
||||
Although it might be tempting to assign low frequency filters only to the subwoofer channel, this might not lead to the expected results. Many audio systems apply bass redirection after Equalizer APO has processed the signal, so filters applied to the subwoofer channel won't be effective for redirected sound. Furthermore, as crossover filters only gradually fade in, the low frequency audio might be played over multiple speakers, not just the subwoofer, reducing the effectivity of subwoofer-only filters. Therefore, to avoid these problems, it's recommended to <b>apply low frequency filters to all channels</b>.
|
||||
</div>
|
||||
This information has been moved to the [configuration reference](https://sourceforge.net/p/equalizerapo/wiki/Configuration%20reference/).
|
||||
|
||||
<a name="troubleshooting"></a>
|
||||
# Troubleshooting
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
+393
@@ -0,0 +1,393 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<svg version="1.2" baseProfile="tiny" width="210mm" height="297mm" viewBox="0 0 21000 29700" preserveAspectRatio="xMidYMid" fill-rule="evenodd" clip-path="url(#presentation_clip_path)" stroke-width="28.222" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" xmlns:ooo="http://xml.openoffice.org/svg/export" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve">
|
||||
<defs class="ClipPathGroup">
|
||||
<clipPath id="presentation_clip_path" clipPathUnits="userSpaceOnUse">
|
||||
<rect x="0" y="0" width="21000" height="29700"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<defs>
|
||||
<font id="EmbeddedFont_1" horiz-adv-x="2048">
|
||||
<font-face font-family="Liberation Sans embedded" units-per-em="2048" font-weight="normal" font-style="normal" ascent="1852" descent="423"/>
|
||||
<missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
|
||||
<glyph unicode="x" horiz-adv-x="954" d="M 801,0 L 510,444 217,0 23,0 408,556 41,1082 240,1082 510,661 778,1082 979,1082 612,558 1002,0 801,0 Z"/>
|
||||
<glyph unicode="v" horiz-adv-x="1006" d="M 613,0 L 400,0 7,1082 199,1082 437,378 C 446,351 469,272 506,141 L 541,258 580,376 826,1082 1017,1082 613,0 Z"/>
|
||||
<glyph unicode="u" horiz-adv-x="848" d="M 314,1082 L 314,396 C 314,325 321,269 335,230 349,191 371,162 402,145 433,128 478,119 537,119 624,119 692,149 742,208 792,267 817,350 817,455 L 817,1082 997,1082 997,231 C 997,105 999,28 1003,0 L 833,0 C 832,3 832,12 831,27 830,42 830,59 829,78 828,97 826,132 825,185 L 822,185 C 781,110 733,58 679,27 624,-4 557,-20 476,-20 357,-20 271,10 216,69 161,128 133,225 133,361 L 133,1082 314,1082 Z"/>
|
||||
<glyph unicode="t" horiz-adv-x="504" d="M 554,8 C 495,-8 434,-16 372,-16 228,-16 156,66 156,229 L 156,951 31,951 31,1082 163,1082 216,1324 336,1324 336,1082 536,1082 536,951 336,951 336,268 C 336,216 345,180 362,159 379,138 408,127 450,127 474,127 509,132 554,141 L 554,8 Z"/>
|
||||
<glyph unicode="s" horiz-adv-x="901" d="M 950,299 C 950,197 912,118 835,63 758,8 650,-20 511,-20 376,-20 273,2 200,47 127,91 79,160 57,254 L 216,285 C 231,227 263,185 311,158 359,131 426,117 511,117 602,117 669,131 712,159 754,187 775,229 775,285 775,328 760,362 731,389 702,416 654,438 589,455 L 460,489 C 357,516 283,542 240,568 196,593 162,624 137,661 112,698 100,743 100,796 100,895 135,970 206,1022 276,1073 378,1099 513,1099 632,1099 727,1078 798,1036 868,994 912,927 931,834 L 769,814 C 759,862 732,899 689,925 645,950 586,963 513,963 432,963 372,951 333,926 294,901 275,864 275,814 275,783 283,758 299,738 315,718 339,701 370,687 401,673 467,654 568,629 663,605 732,583 774,563 816,542 849,520 874,495 898,470 917,442 930,410 943,377 950,340 950,299 Z"/>
|
||||
<glyph unicode="r" horiz-adv-x="504" d="M 142,0 L 142,830 C 142,906 140,990 136,1082 L 306,1082 C 311,959 314,886 314,861 L 318,861 C 347,954 380,1017 417,1051 454,1085 507,1102 575,1102 599,1102 623,1099 648,1092 L 648,927 C 624,934 592,937 552,937 477,937 420,905 381,841 342,776 322,684 322,564 L 322,0 142,0 Z"/>
|
||||
<glyph unicode="p" horiz-adv-x="901" d="M 1053,546 C 1053,169 920,-20 655,-20 488,-20 376,43 319,168 L 314,168 C 317,163 318,106 318,-2 L 318,-425 138,-425 138,861 C 138,972 136,1046 132,1082 L 306,1082 C 307,1079 308,1070 309,1054 310,1037 312,1012 314,978 315,944 316,921 316,908 L 320,908 C 352,975 394,1024 447,1055 500,1086 569,1101 655,1101 788,1101 888,1056 954,967 1020,878 1053,737 1053,546 Z M 864,542 C 864,693 844,800 803,865 762,930 698,962 609,962 538,962 482,947 442,917 401,887 371,840 350,777 329,713 318,630 318,528 318,386 341,281 386,214 431,147 505,113 607,113 696,113 762,146 803,212 844,277 864,387 864,542 Z"/>
|
||||
<glyph unicode="o" horiz-adv-x="954" d="M 1053,542 C 1053,353 1011,212 928,119 845,26 724,-20 565,-20 407,-20 288,28 207,125 126,221 86,360 86,542 86,915 248,1102 571,1102 736,1102 858,1057 936,966 1014,875 1053,733 1053,542 Z M 864,542 C 864,691 842,800 798,868 753,935 679,969 574,969 469,969 393,935 346,866 299,797 275,689 275,542 275,399 298,292 345,221 391,149 464,113 563,113 671,113 748,148 795,217 841,286 864,395 864,542 Z"/>
|
||||
<glyph unicode="n" horiz-adv-x="848" d="M 825,0 L 825,686 C 825,757 818,813 804,852 790,891 768,920 737,937 706,954 661,963 602,963 515,963 447,933 397,874 347,815 322,732 322,627 L 322,0 142,0 142,851 C 142,977 140,1054 136,1082 L 306,1082 C 307,1079 307,1070 308,1055 309,1040 310,1024 311,1005 312,986 313,950 314,897 L 317,897 C 358,972 406,1025 461,1056 515,1087 582,1102 663,1102 782,1102 869,1073 924,1014 979,955 1006,857 1006,721 L 1006,0 825,0 Z"/>
|
||||
<glyph unicode="m" horiz-adv-x="1430" d="M 768,0 L 768,686 C 768,791 754,863 725,903 696,943 645,963 570,963 493,963 433,934 388,875 343,816 321,734 321,627 L 321,0 142,0 142,851 C 142,977 140,1054 136,1082 L 306,1082 C 307,1079 307,1070 308,1055 309,1040 310,1024 311,1005 312,986 313,950 314,897 L 317,897 C 356,974 400,1027 450,1057 500,1087 561,1102 633,1102 715,1102 780,1086 828,1053 875,1020 908,968 927,897 L 930,897 C 967,970 1013,1022 1066,1054 1119,1086 1183,1102 1258,1102 1367,1102 1447,1072 1497,1013 1546,954 1571,856 1571,721 L 1571,0 1393,0 1393,686 C 1393,791 1379,863 1350,903 1321,943 1270,963 1195,963 1116,963 1055,934 1012,876 968,817 946,734 946,627 L 946,0 768,0 Z"/>
|
||||
<glyph unicode="l" horiz-adv-x="160" d="M 138,0 L 138,1484 318,1484 318,0 138,0 Z"/>
|
||||
<glyph unicode="i" horiz-adv-x="160" d="M 137,1312 L 137,1484 317,1484 317,1312 137,1312 Z M 137,0 L 137,1082 317,1082 317,0 137,0 Z"/>
|
||||
<glyph unicode="h" horiz-adv-x="848" d="M 317,897 C 356,968 402,1020 457,1053 511,1086 580,1102 663,1102 780,1102 867,1073 923,1015 978,956 1006,858 1006,721 L 1006,0 825,0 825,686 C 825,762 818,819 804,856 790,893 767,920 735,937 703,954 659,963 602,963 517,963 450,934 399,875 348,816 322,737 322,638 L 322,0 142,0 142,1484 322,1484 322,1098 C 322,1057 321,1015 319,972 316,929 315,904 314,897 L 317,897 Z"/>
|
||||
<glyph unicode="g" horiz-adv-x="901" d="M 548,-425 C 430,-425 336,-402 266,-355 196,-309 151,-243 131,-158 L 312,-132 C 324,-182 351,-220 392,-247 433,-274 486,-288 553,-288 732,-288 822,-183 822,27 L 822,201 820,201 C 786,132 739,80 680,45 621,10 551,-8 472,-8 339,-8 242,36 180,124 117,212 86,350 86,539 86,730 120,872 187,963 254,1054 355,1099 492,1099 569,1099 635,1082 692,1047 748,1012 791,962 822,897 L 824,897 C 824,917 825,952 828,1001 831,1050 833,1077 836,1082 L 1007,1082 C 1003,1046 1001,971 1001,858 L 1001,31 C 1001,-273 850,-425 548,-425 Z M 822,541 C 822,629 810,705 786,769 762,832 728,881 685,915 641,948 591,965 536,965 444,965 377,932 335,865 293,798 272,690 272,541 272,393 292,287 331,222 370,157 438,125 533,125 590,125 640,142 684,175 728,208 762,256 786,319 810,381 822,455 822,541 Z"/>
|
||||
<glyph unicode="f" horiz-adv-x="557" d="M 361,951 L 361,0 181,0 181,951 29,951 29,1082 181,1082 181,1204 C 181,1303 203,1374 246,1417 289,1460 356,1482 445,1482 495,1482 537,1478 572,1470 L 572,1333 C 542,1338 515,1341 492,1341 446,1341 413,1329 392,1306 371,1283 361,1240 361,1179 L 361,1082 572,1082 572,951 361,951 Z"/>
|
||||
<glyph unicode="e" horiz-adv-x="954" d="M 276,503 C 276,379 302,283 353,216 404,149 479,115 578,115 656,115 719,131 766,162 813,193 844,233 861,281 L 1019,236 C 954,65 807,-20 578,-20 418,-20 296,28 213,123 129,218 87,360 87,548 87,727 129,864 213,959 296,1054 416,1102 571,1102 889,1102 1048,910 1048,527 L 1048,503 276,503 Z M 862,641 C 852,755 823,838 775,891 727,943 658,969 568,969 481,969 412,940 361,882 310,823 282,743 278,641 L 862,641 Z"/>
|
||||
<glyph unicode="d" horiz-adv-x="901" d="M 821,174 C 788,105 744,55 689,25 634,-5 565,-20 484,-20 347,-20 247,26 183,118 118,210 86,349 86,536 86,913 219,1102 484,1102 566,1102 634,1087 689,1057 744,1027 788,979 821,914 L 823,914 821,1035 821,1484 1001,1484 1001,223 C 1001,110 1003,36 1007,0 L 835,0 C 833,11 831,35 829,74 826,113 825,146 825,174 L 821,174 Z M 275,542 C 275,391 295,282 335,217 375,152 440,119 530,119 632,119 706,154 752,225 798,296 821,405 821,554 821,697 798,802 752,869 706,936 633,969 532,969 441,969 376,936 336,869 295,802 275,693 275,542 Z"/>
|
||||
<glyph unicode="c" horiz-adv-x="875" d="M 275,546 C 275,402 298,295 343,226 388,157 457,122 548,122 612,122 666,139 709,174 752,209 778,262 788,334 L 970,322 C 956,218 912,135 837,73 762,11 668,-20 553,-20 402,-20 286,28 207,124 127,219 87,359 87,542 87,724 127,863 207,959 287,1054 402,1102 551,1102 662,1102 754,1073 827,1016 900,959 945,880 964,779 L 779,765 C 770,825 746,873 708,908 670,943 616,961 546,961 451,961 382,929 339,866 296,803 275,696 275,546 Z"/>
|
||||
<glyph unicode="b" horiz-adv-x="901" d="M 1053,546 C 1053,169 920,-20 655,-20 573,-20 505,-5 451,25 396,54 352,102 318,168 L 316,168 C 316,147 315,116 312,74 309,31 307,7 306,0 L 132,0 C 136,36 138,110 138,223 L 138,1484 318,1484 318,1061 C 318,1018 317,967 314,908 L 318,908 C 351,977 396,1027 451,1057 506,1087 574,1102 655,1102 792,1102 892,1056 957,964 1021,872 1053,733 1053,546 Z M 864,540 C 864,691 844,800 804,865 764,930 699,963 609,963 508,963 434,928 388,859 341,790 318,680 318,529 318,387 341,282 386,215 431,147 505,113 607,113 698,113 763,147 804,214 844,281 864,389 864,540 Z"/>
|
||||
<glyph unicode="a" horiz-adv-x="1033" d="M 414,-20 C 305,-20 224,9 169,66 114,123 87,202 87,302 87,414 124,500 198,560 271,620 390,652 554,656 L 797,660 797,719 C 797,807 778,870 741,908 704,946 645,965 565,965 484,965 426,951 389,924 352,897 330,853 323,793 L 135,810 C 166,1005 310,1102 569,1102 705,1102 807,1071 876,1009 945,946 979,856 979,738 L 979,272 C 979,219 986,179 1000,152 1014,125 1041,111 1080,111 1097,111 1117,113 1139,118 L 1139,6 C 1094,-5 1047,-10 1000,-10 933,-10 885,8 855,43 824,78 807,132 803,207 L 797,207 C 751,124 698,66 637,32 576,-3 501,-20 414,-20 Z M 455,115 C 521,115 580,130 631,160 682,190 723,231 753,284 782,336 797,390 797,445 L 797,534 600,530 C 515,529 451,520 408,504 364,488 330,463 307,430 284,397 272,353 272,299 272,240 288,195 320,163 351,131 396,115 455,115 Z"/>
|
||||
<glyph unicode="P" horiz-adv-x="1059" d="M 1258,985 C 1258,852 1215,746 1128,667 1041,588 922,549 773,549 L 359,549 359,0 168,0 168,1409 761,1409 C 919,1409 1041,1372 1128,1298 1215,1224 1258,1120 1258,985 Z M 1066,983 C 1066,1165 957,1256 738,1256 L 359,1256 359,700 746,700 C 959,700 1066,794 1066,983 Z"/>
|
||||
<glyph unicode="O" horiz-adv-x="1404" d="M 1495,711 C 1495,564 1467,435 1411,324 1354,213 1273,128 1168,69 1063,10 938,-20 795,-20 650,-20 526,9 421,68 316,127 235,212 180,323 125,434 97,563 97,711 97,936 159,1113 282,1240 405,1367 577,1430 797,1430 940,1430 1065,1402 1170,1345 1275,1288 1356,1205 1412,1096 1467,987 1495,859 1495,711 Z M 1300,711 C 1300,886 1256,1024 1169,1124 1081,1224 957,1274 797,1274 636,1274 511,1225 423,1126 335,1027 291,889 291,711 291,534 336,394 425,291 514,187 637,135 795,135 958,135 1083,185 1170,286 1257,386 1300,528 1300,711 Z"/>
|
||||
<glyph unicode="A" horiz-adv-x="1324" d="M 1167,0 L 1006,412 364,412 202,0 4,0 579,1409 796,1409 1362,0 1167,0 Z M 685,1265 L 676,1237 C 659,1182 635,1111 602,1024 L 422,561 949,561 768,1026 C 749,1072 731,1124 712,1182 L 685,1265 Z"/>
|
||||
<glyph unicode="6" horiz-adv-x="927" d="M 1049,461 C 1049,312 1009,195 928,109 847,23 736,-20 594,-20 435,-20 314,39 230,157 146,275 104,447 104,672 104,916 148,1103 235,1234 322,1365 447,1430 608,1430 821,1430 955,1334 1010,1143 L 838,1112 C 803,1227 725,1284 606,1284 503,1284 424,1236 368,1141 311,1045 283,906 283,725 316,786 362,832 421,864 480,895 548,911 625,911 755,911 858,870 935,789 1011,708 1049,598 1049,461 Z M 866,453 C 866,555 841,634 791,689 741,744 671,772 582,772 498,772 430,748 379,699 327,650 301,582 301,496 301,387 328,298 382,229 435,160 504,125 588,125 675,125 743,154 792,213 841,271 866,351 866,453 Z"/>
|
||||
<glyph unicode="2" horiz-adv-x="954" d="M 103,0 L 103,127 C 137,205 179,274 228,334 277,393 328,447 382,496 436,544 490,589 543,630 596,671 643,713 686,754 729,795 763,839 790,884 816,929 829,981 829,1038 829,1115 806,1175 761,1218 716,1261 653,1282 572,1282 495,1282 432,1261 383,1220 333,1178 304,1119 295,1044 L 111,1061 C 124,1174 172,1263 255,1330 337,1397 443,1430 572,1430 714,1430 823,1397 900,1330 976,1263 1014,1167 1014,1044 1014,989 1002,935 977,881 952,827 914,773 865,719 816,665 721,581 582,468 505,405 444,349 399,299 354,248 321,200 301,153 L 1036,153 1036,0 103,0 Z"/>
|
||||
<glyph unicode="-" horiz-adv-x="504" d="M 91,464 L 91,624 591,624 591,464 91,464 Z"/>
|
||||
<glyph unicode="+" horiz-adv-x="1007" d="M 671,608 L 671,180 524,180 524,608 100,608 100,754 524,754 524,1182 671,1182 671,754 1095,754 1095,608 671,608 Z"/>
|
||||
<glyph unicode=" " horiz-adv-x="556"/>
|
||||
</font>
|
||||
</defs>
|
||||
<defs class="TextShapeIndex">
|
||||
<g ooo:slide="id1" ooo:id-list="id3 id4 id5 id6 id7 id8 id9 id10 id11 id12 id13 id14 id15 id16 id17 id18 id19 id20 id21 id22 id23 id24"/>
|
||||
</defs>
|
||||
<defs class="EmbeddedBulletChars">
|
||||
<g id="bullet-char-template(57356)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 580,1141 L 1163,571 580,0 -4,571 580,1141 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(57354)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 8,1128 L 1137,1128 1137,0 8,0 8,1128 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(10146)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 174,0 L 602,739 174,1481 1456,739 174,0 Z M 1358,739 L 309,1346 659,739 1358,739 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(10132)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 2015,739 L 1276,0 717,0 1260,543 174,543 174,936 1260,936 717,1481 1274,1481 2015,739 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(10007)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 0,-2 C -7,14 -16,27 -25,37 L 356,567 C 262,823 215,952 215,954 215,979 228,992 255,992 264,992 276,990 289,987 310,991 331,999 354,1012 L 381,999 492,748 772,1049 836,1024 860,1049 C 881,1039 901,1025 922,1006 886,937 835,863 770,784 769,783 710,716 594,584 L 774,223 C 774,196 753,168 711,139 L 727,119 C 717,90 699,76 672,76 641,76 570,178 457,381 L 164,-76 C 142,-110 111,-127 72,-127 30,-127 9,-110 8,-76 1,-67 -2,-52 -2,-32 -2,-23 -1,-13 0,-2 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(10004)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 285,-33 C 182,-33 111,30 74,156 52,228 41,333 41,471 41,549 55,616 82,672 116,743 169,778 240,778 293,778 328,747 346,684 L 369,508 C 377,444 397,411 428,410 L 1163,1116 C 1174,1127 1196,1133 1229,1133 1271,1133 1292,1118 1292,1087 L 1292,965 C 1292,929 1282,901 1262,881 L 442,47 C 390,-6 338,-33 285,-33 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(9679)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 813,0 C 632,0 489,54 383,161 276,268 223,411 223,592 223,773 276,916 383,1023 489,1130 632,1184 813,1184 992,1184 1136,1130 1245,1023 1353,916 1407,772 1407,592 1407,412 1353,268 1245,161 1136,54 992,0 813,0 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(8226)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 346,457 C 273,457 209,483 155,535 101,586 74,649 74,723 74,796 101,859 155,911 209,963 273,989 346,989 419,989 480,963 531,910 582,859 608,796 608,723 608,648 583,586 532,535 482,483 420,457 346,457 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(8211)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M -4,459 L 1135,459 1135,606 -4,606 -4,459 Z"/>
|
||||
</g>
|
||||
</defs>
|
||||
<defs class="TextEmbeddedBitmaps"/>
|
||||
<g>
|
||||
<g id="id2" class="Master_Slide">
|
||||
<g id="bg-id2" class="Background"/>
|
||||
<g id="bo-id2" class="BackgroundObjects"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="SlideGroup">
|
||||
<g>
|
||||
<g id="id1" class="Slide" clip-path="url(#presentation_clip_path)">
|
||||
<g class="Page">
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id3">
|
||||
<path fill="rgb(255,211,32)" stroke="none" d="M 3500,8700 L 1700,8700 1700,6500 5300,6500 5300,8700 3500,8700 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="50" stroke-linejoin="round" d="M 3500,8700 L 1700,8700 1700,6500 5300,6500 5300,8700 3500,8700 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="1952" y="7821"><tspan fill="rgb(0,0,0)" stroke="none">Application</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id4">
|
||||
<path fill="rgb(174,207,0)" stroke="none" d="M 7300,8150 L 6300,8150 6300,7050 8300,7050 8300,8150 7300,8150 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="50" stroke-linejoin="round" d="M 7300,8150 L 6300,8150 6300,7050 8300,7050 8300,8150 7300,8150 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="6629" y="7821"><tspan fill="rgb(0,0,0)" stroke="none">APO</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id5">
|
||||
<path fill="rgb(255,66,14)" stroke="none" d="M 10350,10051 C 10775,10051 11100,10376 11100,10801 11100,11226 10775,11551 10350,11551 9925,11551 9600,11226 9600,10801 9600,10376 9925,10051 10350,10051 Z M 9600,10051 L 9600,10051 Z M 11101,11552 L 11101,11552 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="50" stroke-linejoin="round" d="M 10350,10051 C 10775,10051 11100,10376 11100,10801 11100,11226 10775,11551 10350,11551 9925,11551 9600,11226 9600,10801 9600,10376 9925,10051 10350,10051 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="9986" y="11022"><tspan fill="rgb(0,0,0)" stroke="none"> </tspan><tspan fill="rgb(0,0,0)" stroke="none">+ </tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id6">
|
||||
<path fill="rgb(255,211,32)" stroke="none" d="M 3501,11901 L 1701,11901 1701,9701 5301,9701 5301,11901 3501,11901 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="50" stroke-linejoin="round" d="M 3501,11901 L 1701,11901 1701,9701 5301,9701 5301,11901 3501,11901 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="1953" y="11022"><tspan fill="rgb(0,0,0)" stroke="none">Application</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id7">
|
||||
<path fill="rgb(174,207,0)" stroke="none" d="M 7301,11351 L 6301,11351 6301,10251 8301,10251 8301,11351 7301,11351 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="50" stroke-linejoin="round" d="M 7301,11351 L 6301,11351 6301,10251 8301,10251 8301,11351 7301,11351 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="6630" y="11022"><tspan fill="rgb(0,0,0)" stroke="none">APO</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id8">
|
||||
<path fill="rgb(255,211,32)" stroke="none" d="M 3501,15101 L 1701,15101 1701,12901 5301,12901 5301,15101 3501,15101 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="50" stroke-linejoin="round" d="M 3501,15101 L 1701,15101 1701,12901 5301,12901 5301,15101 3501,15101 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="1953" y="14222"><tspan fill="rgb(0,0,0)" stroke="none">Application</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id9">
|
||||
<path fill="rgb(174,207,0)" stroke="none" d="M 7301,14551 L 6301,14551 6301,13451 8301,13451 8301,14551 7301,14551 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="50" stroke-linejoin="round" d="M 7301,14551 L 6301,14551 6301,13451 8301,13451 8301,14551 7301,14551 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="6630" y="14222"><tspan fill="rgb(0,0,0)" stroke="none">APO</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id10">
|
||||
<path fill="rgb(174,207,0)" stroke="none" d="M 13202,11351 L 12202,11351 12202,10251 14202,10251 14202,11351 13202,11351 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="50" stroke-linejoin="round" d="M 13202,11351 L 12202,11351 12202,10251 14202,10251 14202,11351 13202,11351 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="12531" y="11022"><tspan fill="rgb(0,0,0)" stroke="none">APO</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id11">
|
||||
<path fill="rgb(131,202,255)" stroke="none" d="M 17164,11901 L 15364,11901 15364,9701 18964,9701 18964,11901 17164,11901 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="50" stroke-linejoin="round" d="M 17164,11901 L 15364,11901 15364,9701 18964,9701 18964,11901 17164,11901 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="16212" y="10666"><tspan fill="rgb(0,0,0)" stroke="none">Output</tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="16250" y="11377"><tspan fill="rgb(0,0,0)" stroke="none">device</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id12">
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 5300,7600 L 5825,7600 5775,7600 5906,7600"/>
|
||||
<path fill="rgb(0,0,0)" stroke="none" d="M 6300,7600 L 5888,7463 5888,7738 6300,7600 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="5662" y="7420"><tspan fill="rgb(0,0,0)" stroke="none">2</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id13">
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 5301,10801 L 5826,10801 5776,10801 5907,10801"/>
|
||||
<path fill="rgb(0,0,0)" stroke="none" d="M 6301,10801 L 5889,10664 5889,10939 6301,10801 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="5663" y="10621"><tspan fill="rgb(0,0,0)" stroke="none">2</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id14">
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 5301,14001 L 5826,14001 5776,14001 5907,14001"/>
|
||||
<path fill="rgb(0,0,0)" stroke="none" d="M 6301,14001 L 5889,13864 5889,14139 6301,14001 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="5663" y="13821"><tspan fill="rgb(0,0,0)" stroke="none">6</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id15">
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8301,10801 L 8826,10801 9075,10801 9206,10801"/>
|
||||
<path fill="rgb(0,0,0)" stroke="none" d="M 9600,10801 L 9188,10664 9188,10939 9600,10801 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="8813" y="10621"><tspan fill="rgb(0,0,0)" stroke="none">6</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id16">
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,7600 L 9624,9927"/>
|
||||
<path fill="rgb(0,0,0)" stroke="none" d="M 9819,10270 L 9735,9843 9496,9979 9819,10270 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="8922" y="8755"><tspan fill="rgb(0,0,0)" stroke="none">6</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id17">
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8301,14001 L 9624,11675"/>
|
||||
<path fill="rgb(0,0,0)" stroke="none" d="M 9819,11332 L 9496,11623 9735,11759 9819,11332 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="8922" y="12486"><tspan fill="rgb(0,0,0)" stroke="none">6</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id18">
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 11100,10801 L 11808,10801"/>
|
||||
<path fill="rgb(0,0,0)" stroke="none" d="M 12202,10801 L 11790,10664 11790,10939 12202,10801 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="11513" y="10621"><tspan fill="rgb(0,0,0)" stroke="none">6</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id19">
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14202,10801 L 14970,10801"/>
|
||||
<path fill="rgb(0,0,0)" stroke="none" d="M 15364,10801 L 14952,10664 14952,10939 15364,10801 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="14645" y="10621"><tspan fill="rgb(0,0,0)" stroke="none">6</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id20">
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 7300,15300 L 7202,15300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 7103,15300 L 7005,15300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6906,15300 L 6808,15300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6709,15300 L 6611,15300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6512,15300 L 6414,15300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6315,15300 L 6300,15300 6300,15217"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,15118 L 6300,15020"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,14921 L 6300,14823"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,14724 L 6300,14626"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,14527 L 6300,14429"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,14330 L 6300,14232"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,14133 L 6300,14035"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,13936 L 6300,13838"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,13739 L 6300,13641"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,13542 L 6300,13444"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,13345 L 6300,13247"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,13148 L 6300,13050"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,12951 L 6300,12853"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,12754 L 6300,12656"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,12557 L 6300,12459"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,12360 L 6300,12262"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,12163 L 6300,12065"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,11966 L 6300,11868"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,11769 L 6300,11671"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,11572 L 6300,11474"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,11375 L 6300,11277"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,11178 L 6300,11080"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,10981 L 6300,10883"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,10784 L 6300,10686"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,10587 L 6300,10489"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,10390 L 6300,10292"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,10193 L 6300,10095"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,9996 L 6300,9898"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,9799 L 6300,9701"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,9602 L 6300,9504"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,9405 L 6300,9307"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,9208 L 6300,9110"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,9011 L 6300,8913"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,8814 L 6300,8716"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,8617 L 6300,8519"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,8420 L 6300,8322"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,8223 L 6300,8125"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,8026 L 6300,7928"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,7829 L 6300,7731"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,7632 L 6300,7534"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,7435 L 6300,7337"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,7238 L 6300,7140"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,7041 L 6300,6943"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,6844 L 6300,6746"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,6647 L 6300,6549"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6300,6450 L 6300,6352"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6347,6300 L 6446,6300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6544,6300 L 6643,6300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6741,6300 L 6840,6300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 6938,6300 L 7037,6300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 7135,6300 L 7234,6300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 7332,6300 L 7431,6300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 7529,6300 L 7628,6300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 7726,6300 L 7825,6300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 7923,6300 L 8022,6300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8120,6300 L 8219,6300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,6317 L 8300,6416"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,6514 L 8300,6613"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,6711 L 8300,6810"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,6908 L 8300,7007"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,7105 L 8300,7204"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,7302 L 8300,7401"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,7499 L 8300,7598"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,7696 L 8300,7795"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,7893 L 8300,7992"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,8090 L 8300,8189"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,8287 L 8300,8386"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,8484 L 8300,8583"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,8681 L 8300,8780"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,8878 L 8300,8977"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,9075 L 8300,9174"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,9272 L 8300,9371"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,9469 L 8300,9568"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,9666 L 8300,9765"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,9863 L 8300,9962"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,10060 L 8300,10159"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,10257 L 8300,10356"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,10454 L 8300,10553"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,10651 L 8300,10750"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,10848 L 8300,10947"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,11045 L 8300,11144"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,11242 L 8300,11341"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,11439 L 8300,11538"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,11636 L 8300,11735"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,11833 L 8300,11932"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,12030 L 8300,12129"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,12227 L 8300,12326"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,12424 L 8300,12523"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,12621 L 8300,12720"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,12818 L 8300,12917"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,13015 L 8300,13114"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,13212 L 8300,13311"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,13409 L 8300,13508"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,13606 L 8300,13705"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,13803 L 8300,13902"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,14000 L 8300,14099"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,14197 L 8300,14296"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,14394 L 8300,14493"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,14591 L 8300,14690"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,14788 L 8300,14887"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,14985 L 8300,15084"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8300,15182 L 8300,15281"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8221,15300 L 8123,15300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 8024,15300 L 7926,15300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 7827,15300 L 7729,15300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 7630,15300 L 7532,15300"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 7433,15300 L 7335,15300"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.TextShape">
|
||||
<g id="id21">
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="6294" y="5101"><tspan fill="rgb(0,0,0)" stroke="none">pre-mix</tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="6576" y="5812"><tspan fill="rgb(0,0,0)" stroke="none">stage</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id22">
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 13200,12099 L 13102,12099"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 13003,12099 L 12905,12099"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12806,12099 L 12708,12099"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12609,12099 L 12511,12099"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12412,12099 L 12314,12099"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12215,12099 L 12200,12099 12200,12016"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,11917 L 12200,11819"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,11720 L 12200,11622"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,11523 L 12200,11425"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,11326 L 12200,11228"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,11129 L 12200,11031"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,10932 L 12200,10834"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,10735 L 12200,10637"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,10538 L 12200,10440"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,10341 L 12200,10243"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,10144 L 12200,10046"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,9947 L 12200,9849"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,9750 L 12200,9652"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12200,9553 L 12200,9500 12246,9500"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12344,9500 L 12443,9500"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12541,9500 L 12640,9500"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12738,9500 L 12837,9500"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 12935,9500 L 13034,9500"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 13132,9500 L 13231,9500"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 13329,9500 L 13428,9500"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 13526,9500 L 13625,9500"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 13723,9500 L 13822,9500"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 13920,9500 L 14019,9500"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14117,9500 L 14200,9500 14200,9516"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,9614 L 14200,9713"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,9811 L 14200,9910"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,10008 L 14200,10107"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,10205 L 14200,10304"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,10402 L 14200,10501"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,10599 L 14200,10698"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,10796 L 14200,10895"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,10993 L 14200,11092"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,11190 L 14200,11289"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,11387 L 14200,11486"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,11584 L 14200,11683"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,11781 L 14200,11880"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14200,11978 L 14200,12077"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 14124,12099 L 14026,12099"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 13927,12099 L 13829,12099"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 13730,12099 L 13632,12099"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 13533,12099 L 13435,12099"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 13336,12099 L 13238,12099"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.TextShape">
|
||||
<g id="id23">
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="12053" y="8303"><tspan fill="rgb(0,0,0)" stroke="none">post-mix</tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="635px" font-weight="400"><tspan class="TextPosition" x="12477" y="9014"><tspan fill="rgb(0,0,0)" stroke="none">stage</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.LineShape">
|
||||
<g id="id24">
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="50" stroke-linejoin="round" d="M 10900,14200 L 17206,14200"/>
|
||||
<path fill="rgb(0,0,0)" stroke="none" d="M 17600,14200 L 17188,14063 17188,14338 17600,14200 Z"/>
|
||||
<text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="12080" y="14020"><tspan fill="rgb(0,0,0)" stroke="none">number of channels</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 46 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
@@ -1,10 +1,20 @@
|
||||
call "%VS100COMNTOOLS%\vsvars32.bat"
|
||||
msbuild EqualizerAPO.sln /p:Configuration=release /p:platform=win32 /t:rebuild
|
||||
if %ERRORLEVEL% GEQ 1 goto done
|
||||
msbuild EqualizerAPO.sln /p:Configuration=release /p:platform=x64 /t:rebuild
|
||||
if %ERRORLEVEL% GEQ 1 goto done
|
||||
|
||||
if defined ProgramFiles(x86) (
|
||||
set nsis="%ProgramFiles(x86)%\NSIS\makensis.exe"
|
||||
) else (
|
||||
set nsis="%ProgramFiles%\NSIS\makensis.exe"
|
||||
)
|
||||
|
||||
cd Setup
|
||||
"%ProgramFiles%\NSIS\makensis.exe" Setup32.nsi
|
||||
"%ProgramFiles%\NSIS\makensis.exe" Setup64.nsi
|
||||
%nsis% Setup32.nsi
|
||||
if %ERRORLEVEL% GEQ 1 goto done
|
||||
%nsis% Setup64.nsi
|
||||
cd..
|
||||
|
||||
:done
|
||||
pause
|
||||
@@ -1,3 +1,21 @@
|
||||
/*
|
||||
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>
|
||||
@@ -6,18 +24,18 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
BiQuad::BiQuad(Type type, float dbGain, float freq, float srate, float bandwidthOrQOrS, bool isBandwidth)
|
||||
BiQuad::BiQuad(Type type, double dbGain, double freq, double srate, double bandwidthOrQOrS, bool isBandwidth)
|
||||
{
|
||||
float A;
|
||||
double A;
|
||||
if(type == PEAKING || type == LOW_SHELF || type == HIGH_SHELF)
|
||||
A = pow(10, dbGain / 40);
|
||||
else
|
||||
A = pow(10, dbGain / 20);
|
||||
float omega = 2 * (float)M_PI * freq / srate;
|
||||
float sn = sin(omega);
|
||||
float cs = cos(omega);
|
||||
float alpha;
|
||||
float beta = -1;
|
||||
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
|
||||
{
|
||||
@@ -25,11 +43,11 @@ BiQuad::BiQuad(Type type, float dbGain, float freq, float srate, float bandwidth
|
||||
beta = 2 * sqrt(A) * alpha;
|
||||
}
|
||||
else if(isBandwidth) // BW
|
||||
alpha = sn * sinh((float)M_LN2/2 * bandwidthOrQOrS * omega / sn);
|
||||
alpha = sn * sinh(M_LN2/2 * bandwidthOrQOrS * omega / sn);
|
||||
else // Q
|
||||
alpha = sn / (2 * bandwidthOrQOrS);
|
||||
|
||||
float b0, b1, b2, a0, a1, a2;
|
||||
|
||||
double b0, b1, b2, a0, a1, a2;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
@@ -99,11 +117,11 @@ BiQuad::BiQuad(Type type, float dbGain, float freq, float srate, float bandwidth
|
||||
break;
|
||||
}
|
||||
|
||||
this->a0 = b0 /a0;
|
||||
this->a[0] = b1 /a0;
|
||||
this->a[1] = b2 /a0;
|
||||
this->a[2] = -a1 /a0;
|
||||
this->a[3] = -a2 /a0;
|
||||
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;
|
||||
@@ -17,6 +17,8 @@
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#define IS_DENORMAL(f) (((*(unsigned int *)&(f))&0x7f800000) == 0)
|
||||
@@ -30,7 +32,7 @@ public:
|
||||
};
|
||||
|
||||
BiQuad() {}
|
||||
BiQuad(Type type, float dbGain, float freq, float srate, float bandwidthOrQOrS, bool isBandwidth);
|
||||
BiQuad(Type type, double dbGain, double freq, double srate, double bandwidthOrQOrS, bool isBandwidth);
|
||||
|
||||
__forceinline
|
||||
void removeDenormals()
|
||||
@@ -48,8 +50,8 @@ public:
|
||||
__forceinline
|
||||
float process(float sample)
|
||||
{
|
||||
float result = a0 * sample + a[0] * x1 + a[1] * x2 +
|
||||
a[2] * y1 + a[3] * y2;
|
||||
// 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;
|
||||
@@ -57,7 +59,6 @@ public:
|
||||
y2 = y1;
|
||||
y1 = result;
|
||||
|
||||
//Input for next stage
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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*>();
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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*>();
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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*>();
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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*>();
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -33,7 +33,7 @@ FILE* LogHelper::presetFP = NULL;
|
||||
bool LogHelper::compact = false;
|
||||
bool LogHelper::useConsoleColors = false;
|
||||
|
||||
void LogHelper::log(const char* file, int line, void* caller, bool trace, const wchar_t* format, ...)
|
||||
void LogHelper::log(const char* file, int line, const void* caller, bool trace, const wchar_t* format, ...)
|
||||
{
|
||||
if(!initialized)
|
||||
{
|
||||
@@ -85,8 +85,9 @@ void LogHelper::log(const char* file, int line, void* caller, bool trace, const
|
||||
{
|
||||
SYSTEMTIME ___st;
|
||||
GetLocalTime(&___st);
|
||||
fwprintf(fp, L"%04d-%02d-%02d %02d:%02d:%02d.%03d %08X (%S:%d): ",
|
||||
___st.wYear, ___st.wMonth, ___st.wDay, ___st.wHour, ___st.wMinute, ___st.wSecond, ___st.wMilliseconds, caller, file, line);
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
fwprintf(fp, L"%04d-%02d-%02d %02d:%02d:%02d.%03d %d %08X (%S:%d): ",
|
||||
___st.wYear, ___st.wMonth, ___st.wDay, ___st.wHour, ___st.wMinute, ___st.wSecond, ___st.wMilliseconds, threadId, caller, file, line);
|
||||
}
|
||||
|
||||
if(trace)
|
||||
@@ -124,4 +125,4 @@ void LogHelper::set(FILE* fp, bool enableTrace, bool compact, bool useConsoleCol
|
||||
LogHelper::enableTrace = enableTrace;
|
||||
LogHelper::compact = compact;
|
||||
LogHelper::useConsoleColors = useConsoleColors;
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
class LogHelper
|
||||
{
|
||||
public:
|
||||
static void log(const char* file, int line, void* caller, bool trace, const wchar_t* format, ...);
|
||||
static void log(const char* file, int line, const void* caller, bool trace, const wchar_t* format, ...);
|
||||
static void reset();
|
||||
static void set(FILE* fp, bool enableTrace, bool compact, bool useConsoleColors);
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
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 WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#ifdef _DEBUG
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
#ifdef USE_WINDDK
|
||||
// disable the declarations to use our own (see below)
|
||||
#define AERT_Allocate _AERT_Allocate_disabled
|
||||
#define AERT_Free _AERT_Free_disabled
|
||||
#include <BaseAudioProcessingObject.h>
|
||||
#undef AERT_Allocate
|
||||
#undef AERT_Free
|
||||
#endif
|
||||
|
||||
#include "LogHelper.h"
|
||||
#include "MemoryHelper.h"
|
||||
|
||||
#ifdef USE_WINDDK
|
||||
// someone forgot to add the __stdcall/WINAPI modifier to BaseAudioProcessingObject.h, so we can't use the existing declarations
|
||||
extern "C"
|
||||
{
|
||||
HRESULT __stdcall AERT_Allocate(size_t size, void **pMemory);
|
||||
HRESULT __stdcall AERT_Free(void *pMemory);
|
||||
}
|
||||
#endif
|
||||
|
||||
void* MemoryHelper::alloc(size_t size)
|
||||
{
|
||||
void* memory;
|
||||
bool alternative = false;
|
||||
size += 16;
|
||||
#ifdef USE_WINDDK
|
||||
HRESULT hr = AERT_Allocate(size, &memory);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
size += 16;
|
||||
memory = malloc(size);
|
||||
|
||||
alternative = true;
|
||||
}
|
||||
#else
|
||||
#ifdef _DEBUG
|
||||
memory = _malloc_dbg(size,_NORMAL_BLOCK, __FILE__, __LINE__);
|
||||
#else
|
||||
memory = malloc(size);
|
||||
#endif
|
||||
#endif
|
||||
if(memory == NULL)
|
||||
{
|
||||
LogFStatic(L"Allocation of %d bytes failed.", size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t offset = 16 - ((size_t)memory) % 16;
|
||||
if(alternative)
|
||||
offset += 16;
|
||||
void* ptr = ((char*)memory) + offset;
|
||||
((char*)ptr)[-1] = (char)offset;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void MemoryHelper::free(void* ptr)
|
||||
{
|
||||
bool alternative = false;
|
||||
char offset = ((char*)ptr)[-1];
|
||||
if(offset > 16)
|
||||
alternative = true;
|
||||
|
||||
void* memory = ((char*)ptr) - offset;
|
||||
|
||||
#ifdef USE_WINDDK
|
||||
if(alternative)
|
||||
{
|
||||
::free(memory);
|
||||
}
|
||||
else
|
||||
{
|
||||
HRESULT hr = AERT_Free(memory);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
LogFStatic(L"Memory release failed. Error code %X", hr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifdef _DEBUG
|
||||
_free_dbg(memory,_NORMAL_BLOCK);
|
||||
#else
|
||||
::free(memory);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -19,15 +19,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#ifdef USE_WINDDK
|
||||
#include <BaseAudioProcessingObject.h>
|
||||
#else
|
||||
#define AVRT_VTABLES_BEGIN
|
||||
#define AVRT_VTABLES_END
|
||||
#define AVRT_CODE_BEGIN
|
||||
#define AVRT_CODE_END
|
||||
#endif
|
||||
|
||||
class StringHelper
|
||||
class MemoryHelper
|
||||
{
|
||||
public:
|
||||
// replaces any occurrence of a character from chars in s with the replacement string
|
||||
static std::wstring replaceCharacters(std::wstring s, std::wstring chars, std::wstring replacement);
|
||||
static std::wstring replaceIllegalCharacters(std::wstring filename);
|
||||
static std::wstring toWString(std::string s, unsigned codepage);
|
||||
static std::wstring toLowerCase(std::wstring s);
|
||||
static void* alloc(size_t size);
|
||||
static void free(void* ptr);
|
||||
};
|
||||
File renamed without changes.
@@ -19,11 +19,10 @@
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <ObjBase.h>
|
||||
#include <aclapi.h>
|
||||
|
||||
#include "StringHelper.h"
|
||||
#include "RegistryHelper.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -34,25 +33,22 @@ wstring RegistryHelper::readValue(wstring key, wstring valuename)
|
||||
{
|
||||
wstring result;
|
||||
|
||||
LSTATUS status;
|
||||
HKEY keyHandle;
|
||||
status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &keyHandle);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while opening registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
HKEY keyHandle = openKey(key, KEY_QUERY_VALUE | KEY_WOW64_64KEY);
|
||||
|
||||
LSTATUS status;
|
||||
DWORD type;
|
||||
DWORD bufSize;
|
||||
status = RegQueryValueExW(keyHandle, valuename.c_str(), NULL, &type, NULL, &bufSize);
|
||||
if(status != ERROR_SUCCESS)
|
||||
{
|
||||
RegCloseKey(keyHandle);
|
||||
throw RegistryException(L"Error while reading registry value HKEY_LOCAL_MACHINE\\" + key + L"\\" + valuename + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while reading registry value " + key + L"\\" + valuename + L": " + StringHelper::getSystemErrorString(status));
|
||||
}
|
||||
|
||||
if(type != REG_SZ)
|
||||
{
|
||||
RegCloseKey(keyHandle);
|
||||
throw RegistryException(L"Registry value HKEY_LOCAL_MACHINE\\" + key + L"\\" + valuename + L" has wrong type");
|
||||
throw RegistryException(L"Registry value " + key + L"\\" + valuename + L" has wrong type");
|
||||
}
|
||||
|
||||
wchar_t* buf = new wchar_t[bufSize / sizeof(wchar_t) + 1];
|
||||
@@ -63,7 +59,7 @@ wstring RegistryHelper::readValue(wstring key, wstring valuename)
|
||||
if(status != ERROR_SUCCESS)
|
||||
{
|
||||
delete buf;
|
||||
throw RegistryException(L"Error while reading registry value HKEY_LOCAL_MACHINE\\" + key + L"\\" + valuename + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while reading registry value " + key + L"\\" + valuename + L": " + StringHelper::getSystemErrorString(status));
|
||||
}
|
||||
|
||||
//Remove zero-termination
|
||||
@@ -79,25 +75,22 @@ unsigned long RegistryHelper::readDWORDValue(wstring key, wstring valuename)
|
||||
{
|
||||
unsigned long result;
|
||||
|
||||
LSTATUS status;
|
||||
HKEY keyHandle;
|
||||
status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &keyHandle);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while opening registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
HKEY keyHandle = openKey(key, KEY_QUERY_VALUE | KEY_WOW64_64KEY);
|
||||
|
||||
LSTATUS status;
|
||||
DWORD type;
|
||||
DWORD bufSize;
|
||||
status = RegQueryValueExW(keyHandle, valuename.c_str(), NULL, &type, NULL, &bufSize);
|
||||
if(status != ERROR_SUCCESS)
|
||||
{
|
||||
RegCloseKey(keyHandle);
|
||||
throw RegistryException(L"Error while reading registry value HKEY_LOCAL_MACHINE\\" + key + L"\\" + valuename + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while reading registry value " + key + L"\\" + valuename + L": " + StringHelper::getSystemErrorString(status));
|
||||
}
|
||||
|
||||
if(type != REG_DWORD)
|
||||
{
|
||||
RegCloseKey(keyHandle);
|
||||
throw RegistryException(L"Registry value HKEY_LOCAL_MACHINE\\" + key + L"\\" + valuename + L" has wrong type");
|
||||
throw RegistryException(L"Registry value " + key + L"\\" + valuename + L" has wrong type");
|
||||
}
|
||||
|
||||
BYTE* buf = new BYTE[bufSize];
|
||||
@@ -108,7 +101,7 @@ unsigned long RegistryHelper::readDWORDValue(wstring key, wstring valuename)
|
||||
if(status != ERROR_SUCCESS)
|
||||
{
|
||||
delete buf;
|
||||
throw RegistryException(L"Error while reading registry value HKEY_LOCAL_MACHINE\\" + key + L"\\" + valuename + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while reading registry value " + key + L"\\" + valuename + L": " + StringHelper::getSystemErrorString(status));
|
||||
}
|
||||
|
||||
result = ((unsigned long*)buf)[0];
|
||||
@@ -119,93 +112,81 @@ unsigned long RegistryHelper::readDWORDValue(wstring key, wstring valuename)
|
||||
|
||||
void RegistryHelper::writeValue(wstring key, wstring valuename, wstring value)
|
||||
{
|
||||
LSTATUS status;
|
||||
HKEY keyHandle;
|
||||
status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_SET_VALUE | KEY_WOW64_64KEY, &keyHandle);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while opening registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
HKEY keyHandle = openKey(key, KEY_SET_VALUE | KEY_WOW64_64KEY);
|
||||
|
||||
status = RegSetValueExW(keyHandle, valuename.c_str(), 0, REG_SZ, (const BYTE*)value.c_str(), (DWORD)((value.size()+1)*sizeof(wchar_t)));
|
||||
LSTATUS status = RegSetValueExW(keyHandle, valuename.c_str(), 0, REG_SZ, (const BYTE*)value.c_str(), (DWORD)((value.size()+1)*sizeof(wchar_t)));
|
||||
|
||||
RegCloseKey(keyHandle);
|
||||
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while writing to registry value HKEY_LOCAL_MACHINE\\" + key + L"\\" + valuename + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while writing to registry value " + key + L"\\" + valuename + L": " + StringHelper::getSystemErrorString(status));
|
||||
}
|
||||
|
||||
void RegistryHelper::writeMultiValue(wstring key, wstring valuename, wstring value)
|
||||
{
|
||||
LSTATUS status;
|
||||
HKEY keyHandle;
|
||||
status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_SET_VALUE | KEY_WOW64_64KEY, &keyHandle);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while opening registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
HKEY keyHandle = openKey(key, KEY_SET_VALUE | KEY_WOW64_64KEY);
|
||||
|
||||
wchar_t* data = new wchar_t[value.size() + 2];
|
||||
value._Copy_s(data, (value.size()+2)*sizeof(wchar_t), value.size());
|
||||
data[value.size()] = L'\0';
|
||||
data[value.size()+1] = L'\0';
|
||||
|
||||
status = RegSetValueExW(keyHandle, valuename.c_str(), 0, REG_MULTI_SZ, (const BYTE*)data, (DWORD)((value.size()+2)*sizeof(wchar_t)));
|
||||
LSTATUS status = RegSetValueExW(keyHandle, valuename.c_str(), 0, REG_MULTI_SZ, (const BYTE*)data, (DWORD)((value.size()+2)*sizeof(wchar_t)));
|
||||
|
||||
delete data;
|
||||
|
||||
RegCloseKey(keyHandle);
|
||||
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while writing to registry value HKEY_LOCAL_MACHINE\\" + key + L"\\" + valuename + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while writing to registry value " + key + L"\\" + valuename + L": " + StringHelper::getSystemErrorString(status));
|
||||
}
|
||||
|
||||
void RegistryHelper::deleteValue(wstring key, wstring valuename)
|
||||
{
|
||||
LSTATUS status;
|
||||
HKEY keyHandle;
|
||||
status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_SET_VALUE | KEY_WOW64_64KEY, &keyHandle);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while opening registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
HKEY keyHandle = openKey(key, KEY_SET_VALUE | KEY_WOW64_64KEY);
|
||||
|
||||
status = RegDeleteValueW(keyHandle, valuename.c_str());
|
||||
LSTATUS status = RegDeleteValueW(keyHandle, valuename.c_str());
|
||||
|
||||
RegCloseKey(keyHandle);
|
||||
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while deleting registry value HKEY_LOCAL_MACHINE\\" + key + L"\\" + valuename + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while deleting registry value " + key + L"\\" + valuename + L": " + StringHelper::getSystemErrorString(status));
|
||||
}
|
||||
|
||||
void RegistryHelper::createKey(wstring key)
|
||||
{
|
||||
HKEY rootKey;
|
||||
wstring subKey = splitKey(key, &rootKey);
|
||||
|
||||
HKEY keyHandle;
|
||||
LSTATUS status;
|
||||
status = RegCreateKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, NULL, 0, KEY_SET_VALUE | KEY_WOW64_64KEY, NULL, &keyHandle, NULL);
|
||||
LSTATUS status = RegCreateKeyExW(rootKey, subKey.c_str(), 0, NULL, 0, KEY_SET_VALUE | KEY_WOW64_64KEY, NULL, &keyHandle, NULL);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while creating registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while creating registry key " + key + L": " + StringHelper::getSystemErrorString(status));
|
||||
|
||||
RegCloseKey(keyHandle);
|
||||
}
|
||||
|
||||
void RegistryHelper::deleteKey(wstring key)
|
||||
{
|
||||
LSTATUS status;
|
||||
status = RegDeleteKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), KEY_WOW64_64KEY, 0);
|
||||
HKEY rootKey;
|
||||
wstring subKey = splitKey(key, &rootKey);
|
||||
|
||||
LSTATUS status = RegDeleteKeyExW(rootKey, subKey.c_str(), KEY_WOW64_64KEY, 0);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while deleting registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while deleting registry key " + key + L": " + StringHelper::getSystemErrorString(status));
|
||||
}
|
||||
|
||||
void RegistryHelper::makeWritable(wstring key)
|
||||
{
|
||||
LSTATUS status;
|
||||
HKEY keyHandle;
|
||||
status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, READ_CONTROL | WRITE_DAC | KEY_WOW64_64KEY, &keyHandle);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while opening registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
HKEY keyHandle = openKey(key, READ_CONTROL | WRITE_DAC | KEY_WOW64_64KEY);
|
||||
|
||||
DWORD descriptorSize = 0;
|
||||
RegGetKeySecurity(keyHandle, DACL_SECURITY_INFORMATION, NULL, &descriptorSize);
|
||||
|
||||
PSECURITY_DESCRIPTOR oldSd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, descriptorSize);
|
||||
status = RegGetKeySecurity(keyHandle, DACL_SECURITY_INFORMATION, oldSd, &descriptorSize);
|
||||
LSTATUS status = RegGetKeySecurity(keyHandle, DACL_SECURITY_INFORMATION, oldSd, &descriptorSize);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while getting security information for registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while getting security information for registry key " + key + L": " + StringHelper::getSystemErrorString(status));
|
||||
|
||||
BOOL aclPresent, aclDefaulted;
|
||||
PACL oldAcl = NULL;
|
||||
@@ -242,7 +223,7 @@ void RegistryHelper::makeWritable(wstring key)
|
||||
|
||||
status = RegSetKeySecurity(keyHandle, DACL_SECURITY_INFORMATION, sd);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while setting security information for registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while setting security information for registry key " + key + L": " + StringHelper::getSystemErrorString(status));
|
||||
|
||||
FreeSid(sid);
|
||||
LocalFree(acl);
|
||||
@@ -268,11 +249,7 @@ void RegistryHelper::takeOwnership(wstring key)
|
||||
if(!AdjustTokenPrivileges(tokenHandle, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
|
||||
throw RegistryException(L"Error in AdjustTokenPrivileges while taking ownership");
|
||||
|
||||
LSTATUS status;
|
||||
HKEY keyHandle;
|
||||
status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, WRITE_OWNER | KEY_WOW64_64KEY, &keyHandle);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while opening registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
HKEY keyHandle = openKey(key, WRITE_OWNER | KEY_WOW64_64KEY);
|
||||
|
||||
PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
|
||||
if(NULL == sd)
|
||||
@@ -290,9 +267,9 @@ void RegistryHelper::takeOwnership(wstring key)
|
||||
if(!SetSecurityDescriptorOwner(sd, sid, FALSE))
|
||||
throw RegistryException(L"Error in SetSecurityDescriptorOwner while taking ownership");
|
||||
|
||||
status = RegSetKeySecurity(keyHandle, OWNER_SECURITY_INFORMATION, sd);
|
||||
LSTATUS status = RegSetKeySecurity(keyHandle, OWNER_SECURITY_INFORMATION, sd);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while setting security information for registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while setting security information for registry key " + key + L": " + StringHelper::getSystemErrorString(status));
|
||||
|
||||
tp.Privileges[0].Attributes = 0;
|
||||
|
||||
@@ -307,8 +284,11 @@ bool RegistryHelper::keyExists(wstring key)
|
||||
{
|
||||
bool result;
|
||||
|
||||
HKEY rootKey;
|
||||
wstring subKey = splitKey(key, &rootKey);
|
||||
|
||||
HKEY keyHandle;
|
||||
result = (RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &keyHandle) == ERROR_SUCCESS);
|
||||
result = (RegOpenKeyExW(rootKey, subKey.c_str(), 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &keyHandle) == ERROR_SUCCESS);
|
||||
|
||||
if(result)
|
||||
RegCloseKey(keyHandle);
|
||||
@@ -318,15 +298,11 @@ bool RegistryHelper::keyExists(wstring key)
|
||||
|
||||
bool RegistryHelper::valueExists(wstring key, wstring valuename)
|
||||
{
|
||||
LSTATUS status;
|
||||
HKEY keyHandle;
|
||||
status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &keyHandle);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while opening registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
HKEY keyHandle = openKey(key, KEY_QUERY_VALUE | KEY_WOW64_64KEY);
|
||||
|
||||
DWORD type;
|
||||
DWORD bufSize;
|
||||
status = RegQueryValueExW(keyHandle, valuename.c_str(), NULL, &type, NULL, &bufSize);
|
||||
LSTATUS status = RegQueryValueExW(keyHandle, valuename.c_str(), NULL, &type, NULL, &bufSize);
|
||||
RegCloseKey(keyHandle);
|
||||
return status == ERROR_SUCCESS;
|
||||
}
|
||||
@@ -335,17 +311,14 @@ vector<wstring> RegistryHelper::enumSubKeys(wstring key)
|
||||
{
|
||||
vector<wstring> result;
|
||||
|
||||
LSTATUS status;
|
||||
HKEY keyHandle;
|
||||
status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY, &keyHandle);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while opening registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
HKEY keyHandle = openKey(key, KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY);
|
||||
|
||||
wchar_t keyName[256];
|
||||
DWORD keyLength = sizeof(keyName) / sizeof(wchar_t);
|
||||
int i=0;
|
||||
int itemCount=0;
|
||||
|
||||
LSTATUS status;
|
||||
while((status = RegEnumKeyExW(keyHandle, i++, keyName, &keyLength, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS)
|
||||
{
|
||||
keyLength = sizeof(keyName) / sizeof(wchar_t);
|
||||
@@ -356,41 +329,42 @@ vector<wstring> RegistryHelper::enumSubKeys(wstring key)
|
||||
RegCloseKey(keyHandle);
|
||||
|
||||
if(status != ERROR_NO_MORE_ITEMS)
|
||||
throw RegistryException(L"Error while enumerating sub keys of registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while enumerating sub keys of registry key " + key + L": " + StringHelper::getSystemErrorString(status));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned long RegistryHelper::valueCount(wstring key)
|
||||
bool RegistryHelper::keyEmpty(wstring key)
|
||||
{
|
||||
LSTATUS status;
|
||||
HKEY keyHandle;
|
||||
status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &keyHandle);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while opening registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
HKEY keyHandle = openKey(key, KEY_QUERY_VALUE | KEY_WOW64_64KEY);
|
||||
|
||||
DWORD keyCount;
|
||||
DWORD valueCount;
|
||||
status = RegQueryInfoKeyW(keyHandle, NULL, NULL, NULL, NULL, NULL, NULL, &valueCount, NULL, NULL, NULL, NULL);
|
||||
LSTATUS status = RegQueryInfoKeyW(keyHandle, NULL, NULL, NULL, &keyCount, NULL, NULL, &valueCount, NULL, NULL, NULL, NULL);
|
||||
|
||||
RegCloseKey(keyHandle);
|
||||
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while reading info for registry key HKEY_LOCAL_MACHINE\\" + key + L": " + getSystemErrorString(status));
|
||||
throw RegistryException(L"Error while reading info for registry key " + key + L": " + StringHelper::getSystemErrorString(status));
|
||||
|
||||
return valueCount;
|
||||
return keyCount == 0 && valueCount == 0;
|
||||
}
|
||||
|
||||
void RegistryHelper::saveToFile(wstring key, wstring valuename, wstring filepath)
|
||||
void RegistryHelper::saveToFile(wstring key, vector<wstring> valuenames, wstring filepath)
|
||||
{
|
||||
wstring value = readValue(key, valuename);
|
||||
|
||||
wofstream stream(filepath);
|
||||
if(!stream.good())
|
||||
throw RegistryException(L"Error while opening file " + filepath + L" for writing");
|
||||
|
||||
stream << L"Windows Registry Editor Version 5.00\n" << endl;
|
||||
stream << L"[HKEY_LOCAL_MACHINE\\" << key << L"]" << endl;
|
||||
stream << L"\"" << valuename << L"\"=\"" << value << L"\"" << endl;
|
||||
for(vector<wstring>::iterator it = valuenames.begin(); it != valuenames.end(); it++)
|
||||
{
|
||||
wstring& valuename = *it;
|
||||
wstring value = readValue(key, valuename);
|
||||
|
||||
stream << L"\"" << valuename << L"\"=\"" << value << L"\"" << endl;
|
||||
}
|
||||
stream << endl;
|
||||
|
||||
stream.close();
|
||||
@@ -433,17 +407,41 @@ bool RegistryHelper::isWindowsVersionAtLeast(unsigned major, unsigned minor)
|
||||
return windowsVersion >= compareVersion;
|
||||
}
|
||||
|
||||
wstring RegistryHelper::getSystemErrorString(long status)
|
||||
HKEY RegistryHelper::openKey(const wstring& key, REGSAM samDesired)
|
||||
{
|
||||
wchar_t* buf;
|
||||
HKEY rootKey;
|
||||
wstring subKey = splitKey(key, &rootKey);
|
||||
|
||||
if(FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, status, 0, (LPTSTR)&buf, 0, NULL) != 0)
|
||||
{
|
||||
wstring result(buf);
|
||||
LocalFree(buf);
|
||||
HKEY keyHandle;
|
||||
LSTATUS status = RegOpenKeyExW(rootKey, subKey.c_str(), 0, samDesired, &keyHandle);
|
||||
if(status != ERROR_SUCCESS)
|
||||
throw RegistryException(L"Error while opening registry key " + key + L": " + StringHelper::getSystemErrorString(status));
|
||||
|
||||
return result;
|
||||
}
|
||||
return keyHandle;
|
||||
}
|
||||
|
||||
wstring RegistryHelper::splitKey(const wstring& key, HKEY* rootKey)
|
||||
{
|
||||
size_t pos = key.find(L'\\');
|
||||
if(pos == wstring::npos)
|
||||
throw RegistryException(L"Key " + key + L" has invalid format");
|
||||
|
||||
wstring rootPart = key.substr(0, pos);
|
||||
wstring pathPart = key.substr(pos+1);
|
||||
|
||||
wstring p = StringHelper::toUpperCase(rootPart);
|
||||
if(p == L"HKEY_CLASSES_ROOT")
|
||||
*rootKey = HKEY_CLASSES_ROOT;
|
||||
else if(p == L"HKEY_CURRENT_CONFIG")
|
||||
*rootKey = HKEY_CURRENT_CONFIG;
|
||||
else if(p == L"HKEY_CURRENT_USER")
|
||||
*rootKey = HKEY_CURRENT_USER;
|
||||
else if(p == L"HKEY_LOCAL_MACHINE")
|
||||
*rootKey = HKEY_LOCAL_MACHINE;
|
||||
else if(p == L"HKEY_USERS")
|
||||
*rootKey = HKEY_USERS;
|
||||
else
|
||||
return L"";
|
||||
}
|
||||
throw RegistryException(L"Unknown root key " + rootPart);
|
||||
|
||||
return pathPart;
|
||||
}
|
||||
@@ -22,8 +22,10 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#define APP_REGPATH L"SOFTWARE\\EqualizerAPO"
|
||||
#define APP_REGPATH L"HKEY_LOCAL_MACHINE\\SOFTWARE\\EqualizerAPO"
|
||||
|
||||
class RegistryHelper
|
||||
{
|
||||
@@ -40,13 +42,15 @@ public:
|
||||
static std::vector<std::wstring> enumSubKeys(std::wstring key);
|
||||
static bool keyExists(std::wstring key);
|
||||
static bool valueExists(std::wstring key, std::wstring valuename);
|
||||
static unsigned long valueCount(std::wstring key);
|
||||
static void saveToFile(std::wstring key, std::wstring valuename, std::wstring filepath);
|
||||
static bool keyEmpty(std::wstring key);
|
||||
static void saveToFile(std::wstring key, std::vector<std::wstring> valuenames, std::wstring filepath);
|
||||
static std::wstring getGuidString(GUID guid);
|
||||
static bool isWindowsVersionAtLeast(unsigned major, unsigned minor);
|
||||
static HKEY openKey(const std::wstring& key, REGSAM samDesired);
|
||||
|
||||
private:
|
||||
static std::wstring getSystemErrorString(long status);
|
||||
static std::wstring splitKey(const std::wstring& key, HKEY* rootKey);
|
||||
|
||||
static unsigned long windowsVersion;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
This file is part of EqualizerAPO, a system-wide equalizer.
|
||||
Copyright (C) 2013 Jonas Thedering
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include "StringHelper.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
wstring StringHelper::replaceCharacters(const wstring& s, const wstring& chars, const wstring& replacement)
|
||||
{
|
||||
wstring result;
|
||||
result.reserve(s.length());
|
||||
|
||||
for(unsigned i=0; i<s.length(); i++)
|
||||
{
|
||||
wchar_t c = s[i];
|
||||
if(chars.find(c) == -1)
|
||||
result += c;
|
||||
else
|
||||
result += replacement;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
wstring StringHelper::replaceIllegalCharacters(const wstring& filename)
|
||||
{
|
||||
return replaceCharacters(filename, L"<>:\"/\\|?*", L"_");
|
||||
}
|
||||
|
||||
wstring StringHelper::toWString(const string& s, unsigned codepage)
|
||||
{
|
||||
int length = MultiByteToWideChar(codepage, 0, s.c_str(), -1, NULL, 0);
|
||||
wchar_t* charBuf = new wchar_t[length];
|
||||
MultiByteToWideChar(codepage, 0, s.c_str(), -1, charBuf, length);
|
||||
wstring result = charBuf;
|
||||
delete charBuf;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
wstring StringHelper::toLowerCase(const wstring& s)
|
||||
{
|
||||
wchar_t* charBuf = new wchar_t[s.length() + 1];
|
||||
memcpy(charBuf, s.c_str(), (s.length() + 1) * sizeof(wchar_t));
|
||||
errno_t err = _wcslwr_s(charBuf, s.length() + 1);
|
||||
|
||||
wstring result = charBuf;
|
||||
delete charBuf;
|
||||
|
||||
if(err == 0)
|
||||
return result;
|
||||
else
|
||||
return s;
|
||||
}
|
||||
|
||||
wstring StringHelper::toUpperCase(const wstring& s)
|
||||
{
|
||||
wchar_t* charBuf = new wchar_t[s.length() + 1];
|
||||
memcpy(charBuf, s.c_str(), (s.length() + 1) * sizeof(wchar_t));
|
||||
errno_t err = _wcsupr_s(charBuf, s.length() + 1);
|
||||
|
||||
wstring result = charBuf;
|
||||
delete charBuf;
|
||||
|
||||
if(err == 0)
|
||||
return result;
|
||||
else
|
||||
return s;
|
||||
}
|
||||
|
||||
wstring StringHelper::trim(const wstring& s)
|
||||
{
|
||||
int firstNonSpace = -1;
|
||||
int lastNonSpace = -1;
|
||||
|
||||
for(unsigned i=0;i<s.length();i++)
|
||||
{
|
||||
wchar_t c = s[i];
|
||||
if(!iswspace(c))
|
||||
{
|
||||
if(firstNonSpace == -1)
|
||||
firstNonSpace = i;
|
||||
lastNonSpace = i;
|
||||
}
|
||||
}
|
||||
|
||||
if(firstNonSpace == -1)
|
||||
return L"";
|
||||
else
|
||||
return s.substr(firstNonSpace, lastNonSpace-firstNonSpace+1);
|
||||
}
|
||||
|
||||
vector<wstring> StringHelper::split(const wstring& s, wchar_t splitChar, bool skipEmpty)
|
||||
{
|
||||
vector<wstring> result;
|
||||
size_t prevPos = 0;
|
||||
size_t pos = 0;
|
||||
while((pos = s.find(splitChar, pos)) != wstring::npos)
|
||||
{
|
||||
wstring part = s.substr(prevPos, pos-prevPos);
|
||||
if(part.length() > 0 || !skipEmpty)
|
||||
result.push_back(part);
|
||||
prevPos = ++pos;
|
||||
}
|
||||
|
||||
wstring part = s.substr(prevPos);
|
||||
if(part.length() > 0 || !skipEmpty)
|
||||
result.push_back(part);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
wstring StringHelper::getSystemErrorString(long status)
|
||||
{
|
||||
wchar_t* buf;
|
||||
|
||||
if(FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, status, 0, (LPTSTR)&buf, 0, NULL) != 0)
|
||||
{
|
||||
wstring result(buf);
|
||||
LocalFree(buf);
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return L"";
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
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>
|
||||
#include <vector>
|
||||
|
||||
class StringHelper
|
||||
{
|
||||
public:
|
||||
// replaces any occurrence of a character from chars in s with the replacement string
|
||||
static std::wstring replaceCharacters(const std::wstring& s, const std::wstring& chars, const std::wstring& replacement);
|
||||
static std::wstring replaceIllegalCharacters(const std::wstring& filename);
|
||||
static std::wstring toWString(const std::string& s, unsigned codepage);
|
||||
static std::wstring toLowerCase(const std::wstring& s);
|
||||
static std::wstring toUpperCase(const std::wstring& s);
|
||||
static std::wstring trim(const std::wstring& s);
|
||||
static std::vector<std::wstring> split(const std::wstring& s, wchar_t splitChar, bool skipEmpty = true);
|
||||
static std::wstring getSystemErrorString(long status);
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
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 <regex>
|
||||
|
||||
#include "RegexFunctions.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace mup;
|
||||
|
||||
RegexSearchFunction::RegexSearchFunction()
|
||||
:ICallback(cmFUNC, L"regexSearch", 2)
|
||||
{
|
||||
}
|
||||
|
||||
void RegexSearchFunction::Eval(ptr_val_type& ret, const ptr_val_type *arg, int argc)
|
||||
{
|
||||
if(!arg[0]->IsString())
|
||||
throw ParserError(ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg[0]->GetType(), 's', 1));
|
||||
if(!arg[1]->IsString())
|
||||
throw ParserError(ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg[1]->GetType(), 's', 2));
|
||||
|
||||
wstring regexString = arg[0]->GetString();
|
||||
wstring string = arg[1]->GetString();
|
||||
|
||||
wregex regex(regexString);
|
||||
wsmatch match;
|
||||
bool found = regex_search(string, match, regex);
|
||||
|
||||
vector<Value> result;
|
||||
if(found)
|
||||
{
|
||||
for(unsigned i=0; i<match.size(); i++)
|
||||
result.push_back(match.str(i));
|
||||
}
|
||||
|
||||
*ret = result;
|
||||
}
|
||||
|
||||
const char_type* RegexSearchFunction::GetDesc() const
|
||||
{
|
||||
return L"regexSearch - searches first match to regular expression. result is empty if not matching";
|
||||
}
|
||||
|
||||
IToken* RegexSearchFunction::Clone() const
|
||||
{
|
||||
return new RegexSearchFunction(*this);
|
||||
}
|
||||
|
||||
RegexReplaceFunction::RegexReplaceFunction()
|
||||
:ICallback(cmFUNC, L"regexReplace", 3)
|
||||
{
|
||||
}
|
||||
|
||||
void RegexReplaceFunction::Eval(ptr_val_type& ret, const ptr_val_type *arg, int argc)
|
||||
{
|
||||
if(!arg[0]->IsString())
|
||||
throw ParserError(ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg[0]->GetType(), 's', 1));
|
||||
if(!arg[1]->IsString())
|
||||
throw ParserError(ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg[1]->GetType(), 's', 2));
|
||||
if(!arg[2]->IsString())
|
||||
throw ParserError(ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg[2]->GetType(), 's', 3));
|
||||
|
||||
wstring regexString = arg[0]->GetString();
|
||||
wstring string = arg[1]->GetString();
|
||||
wstring replacement = arg[2]->GetString();
|
||||
|
||||
wregex regex(regexString);
|
||||
wstring result = regex_replace(string, regex, replacement);
|
||||
|
||||
*ret = result;
|
||||
}
|
||||
|
||||
const char_type* RegexReplaceFunction::GetDesc() const
|
||||
{
|
||||
return L"regexReplace - replaces all matches to regular expression. result is replaced string";
|
||||
}
|
||||
|
||||
IToken* RegexReplaceFunction::Clone() const
|
||||
{
|
||||
return new RegexReplaceFunction(*this);
|
||||
}
|
||||
@@ -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 <mpParser.h>
|
||||
|
||||
class RegexSearchFunction:public mup::ICallback
|
||||
{
|
||||
public:
|
||||
RegexSearchFunction();
|
||||
virtual void Eval(mup::ptr_val_type& ret, const mup::ptr_val_type *arg, int argc);
|
||||
const mup::char_type* GetDesc() const;
|
||||
virtual mup::IToken* Clone() const;
|
||||
};
|
||||
|
||||
class RegexReplaceFunction:public mup::ICallback
|
||||
{
|
||||
public:
|
||||
RegexReplaceFunction();
|
||||
virtual void Eval(mup::ptr_val_type& ret, const mup::ptr_val_type *arg, int argc);
|
||||
const mup::char_type* GetDesc() const;
|
||||
virtual mup::IToken* Clone() const;
|
||||
};
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
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 "RegistryFunctions.h"
|
||||
#include "../helpers/RegistryHelper.h"
|
||||
#include "../FilterEngine.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace mup;
|
||||
|
||||
ReadRegStringFunction::ReadRegStringFunction(FilterEngine* engine)
|
||||
:ICallback(cmFUNC, L"readRegString", 2)
|
||||
{
|
||||
this->engine = engine;
|
||||
}
|
||||
|
||||
void ReadRegStringFunction::Eval(ptr_val_type& ret, const ptr_val_type *arg, int argc)
|
||||
{
|
||||
if(!arg[0]->IsString())
|
||||
throw ParserError(ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg[0]->GetType(), 's', 1));
|
||||
if(!arg[1]->IsString())
|
||||
throw ParserError(ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg[1]->GetType(), 's', 2));
|
||||
|
||||
wstring key = arg[0]->GetString();
|
||||
wstring valuename = arg[1]->GetString();
|
||||
|
||||
try
|
||||
{
|
||||
wstring value = RegistryHelper::readValue(key, valuename);
|
||||
|
||||
*ret = value;
|
||||
|
||||
engine->watchRegistryKey(key);
|
||||
}
|
||||
catch(RegistryException e)
|
||||
{
|
||||
throw ParserError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
const char_type* ReadRegStringFunction::GetDesc() const
|
||||
{
|
||||
return L"readRegString - read a string value from the registry";
|
||||
}
|
||||
|
||||
IToken* ReadRegStringFunction::Clone() const
|
||||
{
|
||||
return new ReadRegStringFunction(*this);
|
||||
}
|
||||
|
||||
ReadRegDWORDFunction::ReadRegDWORDFunction(FilterEngine* engine)
|
||||
:ICallback(cmFUNC, L"readRegDWORD", 2)
|
||||
{
|
||||
this->engine = engine;
|
||||
}
|
||||
|
||||
void ReadRegDWORDFunction::Eval(ptr_val_type& ret, const ptr_val_type *arg, int argc)
|
||||
{
|
||||
if(!arg[0]->IsString())
|
||||
throw ParserError(ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg[0]->GetType(), 's', 1));
|
||||
if(!arg[1]->IsString())
|
||||
throw ParserError(ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg[1]->GetType(), 's', 2));
|
||||
|
||||
wstring key = arg[0]->GetString();
|
||||
wstring valuename = arg[1]->GetString();
|
||||
|
||||
try
|
||||
{
|
||||
unsigned long value = RegistryHelper::readDWORDValue(key, valuename);
|
||||
|
||||
*ret = (long)value;
|
||||
|
||||
engine->watchRegistryKey(key);
|
||||
}
|
||||
catch(RegistryException e)
|
||||
{
|
||||
throw ParserError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
const char_type* ReadRegDWORDFunction::GetDesc() const
|
||||
{
|
||||
return L"readRegDWORD - read a DWORD value from the registry";
|
||||
}
|
||||
|
||||
IToken* ReadRegDWORDFunction::Clone() const
|
||||
{
|
||||
return new ReadRegDWORDFunction(*this);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
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 <mpParser.h>
|
||||
|
||||
class FilterEngine;
|
||||
|
||||
class ReadRegStringFunction:public mup::ICallback
|
||||
{
|
||||
public:
|
||||
ReadRegStringFunction(FilterEngine* engine);
|
||||
virtual void Eval(mup::ptr_val_type& ret, const mup::ptr_val_type *arg, int argc);
|
||||
const mup::char_type* GetDesc() const;
|
||||
virtual mup::IToken* Clone() const;
|
||||
|
||||
private:
|
||||
FilterEngine* engine;
|
||||
};
|
||||
|
||||
class ReadRegDWORDFunction:public mup::ICallback
|
||||
{
|
||||
public:
|
||||
ReadRegDWORDFunction(FilterEngine* engine);
|
||||
virtual void Eval(mup::ptr_val_type& ret, const mup::ptr_val_type *arg, int argc);
|
||||
const mup::char_type* GetDesc() const;
|
||||
virtual mup::IToken* Clone() const;
|
||||
|
||||
private:
|
||||
FilterEngine* engine;
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
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 "StringOperators.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace mup;
|
||||
|
||||
void AddOperator::Eval(ptr_val_type& ret, const ptr_val_type *arg, int argc)
|
||||
{
|
||||
if(!arg[0]->IsString() && !arg[1]->IsString())
|
||||
{
|
||||
OprtAdd::Eval(ret, arg, argc);
|
||||
return;
|
||||
}
|
||||
|
||||
wstring firstString;
|
||||
if(arg[0]->IsString())
|
||||
firstString = arg[0]->GetString();
|
||||
else
|
||||
firstString = arg[0]->ToString();
|
||||
|
||||
wstring secondString;
|
||||
if(arg[1]->IsString())
|
||||
secondString = arg[1]->GetString();
|
||||
else
|
||||
secondString = arg[1]->ToString();
|
||||
|
||||
*ret = firstString + secondString;
|
||||
}
|
||||
|
||||
const char_type* AddOperator::GetDesc() const
|
||||
{
|
||||
return L"x+y - Concatenation of strings and addition of noncomplex values";
|
||||
}
|
||||
|
||||
IToken* AddOperator::Clone() const
|
||||
{
|
||||
return new AddOperator(*this);
|
||||
}
|
||||
@@ -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 <mpParser.h>
|
||||
#include <mpOprtNonCmplx.h>
|
||||
|
||||
class AddOperator:public mup::OprtAdd
|
||||
{
|
||||
public:
|
||||
virtual void Eval(mup::ptr_val_type& ret, const mup::ptr_val_type *arg, int argc);
|
||||
const mup::char_type* GetDesc() const;
|
||||
virtual mup::IToken* Clone() const;
|
||||
};
|
||||
Reference in new issue
Block a user