Added: Loudness correction filter by Alexander Walch that adjusts shelving filters based on the system volume. Also includes a GUI that allows calibration using a test sound.
This commit is contained in:
1 parent
534b63da5f
commit
ce857887af
33 files changed
+2146
-14
No files matched your search
@@ -65,6 +65,14 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
__forceinline
|
||||
void setCoefficients(double ain[], const double& a0in)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
a[i] = ain[i];
|
||||
a0 = a0in;
|
||||
}
|
||||
|
||||
double gainAt(double freq, double srate);
|
||||
|
||||
private:
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
This file is part of Equalizer APO, a system-wide equalizer.
|
||||
Copyright (C) 2017 Alexander Walch
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "LoudnessCorrectionFilter.h"
|
||||
#include "helpers/MemoryHelper.h"
|
||||
|
||||
#include "VolumeController.h"
|
||||
|
||||
#ifndef _USE_MATH_DEFINES
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
#include <math.h>
|
||||
|
||||
LoudnessCorrectionFilter::LoudnessCorrectionFilter(const FilterParameters& fParameters)
|
||||
{
|
||||
_parameters = fParameters;
|
||||
if (_parameters.attenuation > 1.0)
|
||||
{
|
||||
_parameters.attenuation = 1.0;
|
||||
}
|
||||
if (_parameters.attenuation < 0.0)
|
||||
{
|
||||
_parameters.attenuation = 0.0;
|
||||
}
|
||||
InitializeCriticalSection(&_parameterUpdateSection);
|
||||
}
|
||||
|
||||
LoudnessCorrectionFilter::~LoudnessCorrectionFilter()
|
||||
{
|
||||
if (_stopParameterUpdateThreadEvent)
|
||||
{
|
||||
SetEvent(_stopParameterUpdateThreadEvent);
|
||||
}
|
||||
WaitForSingleObject(_parameterUpdateThreadHandle, INFINITE);
|
||||
DeleteCriticalSection(&_parameterUpdateSection);
|
||||
CloseHandle(_stopParameterUpdateThreadEvent);
|
||||
CloseHandle(_parameterUpdateThreadHandle);
|
||||
CloseHandle(_parameterchangedEvent);
|
||||
}
|
||||
|
||||
std::vector<std::wstring> LoudnessCorrectionFilter::initialize(float sampleRate, unsigned maxFrameCount, std::vector<std::wstring> channelNames)
|
||||
{
|
||||
this->_channelCount = channelNames.size();
|
||||
_lowShelfBiquads.resize(_channelCount);
|
||||
_highShelfBiquads.resize(_channelCount);
|
||||
_sampleRate = sampleRate;
|
||||
_attFactor = 1.0;
|
||||
for (unsigned i = 0; i < _channelCount; i++)
|
||||
{
|
||||
_lowShelfBiquads[i] = BiQuad(BiQuad::LOW_SHELF, 0, 75, _sampleRate, 1, false);
|
||||
_highShelfBiquads[i] = BiQuad(BiQuad::HIGH_SHELF, 0, 10000, _sampleRate, 1, false);
|
||||
}
|
||||
_stopParameterUpdateThreadEvent = CreateEvent(NULL, true, false, NULL);
|
||||
_parameterchangedEvent = CreateEvent(NULL, true, false, NULL);
|
||||
_parameterUpdateThreadHandle = CreateThread(NULL, 0, ¶meterUpdateThread, this, 0, NULL);
|
||||
|
||||
return channelNames;
|
||||
}
|
||||
|
||||
void LoudnessCorrectionFilter::getLShelfParamter(const float& volume, double& frequence, double& q, double& gain, double& preAmp)
|
||||
{
|
||||
frequence = 75;
|
||||
q = 0.52;
|
||||
float volDiff = _parameters.referenceLevel - _parameters.referenceOffset - volume;
|
||||
if (volDiff > 0)
|
||||
{
|
||||
// old: gain=volDiff*0.55*_parameters.attenuation;
|
||||
gain = volDiff * 0.55 / (1 - 0.55) * _parameters.attenuation;
|
||||
preAmp = -gain;
|
||||
}
|
||||
else if (volDiff < 0)
|
||||
{
|
||||
preAmp = 0.0;
|
||||
gain = volDiff * 0.55 * exp(volDiff / 90.0) * _parameters.attenuation;
|
||||
}
|
||||
else
|
||||
{
|
||||
gain = 0;
|
||||
}
|
||||
}
|
||||
void LoudnessCorrectionFilter::getHShelfParamter(const float& volume, double& frequence, double& q, double& gain)
|
||||
{
|
||||
frequence = 10000;
|
||||
q = 0.9;
|
||||
float volDiff = _parameters.referenceLevel - _parameters.referenceOffset - volume;
|
||||
if (volDiff > 0)
|
||||
{
|
||||
gain = volDiff * 0.225 * exp(-volDiff / 100.0) * _parameters.attenuation;
|
||||
}
|
||||
else if (volDiff < 0)
|
||||
{
|
||||
gain = volDiff * 0.175 * exp(volDiff / 80.0) * _parameters.attenuation;
|
||||
}
|
||||
else
|
||||
{
|
||||
gain = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long __stdcall LoudnessCorrectionFilter::parameterUpdateThread(void* parameter)
|
||||
{
|
||||
LoudnessCorrectionFilter* lCorrection = (LoudnessCorrectionFilter*)parameter;
|
||||
VolumeController VolumeController;
|
||||
float volOld(lCorrection->_parameters.referenceLevel);
|
||||
float vol(lCorrection->_parameters.referenceLevel);
|
||||
double freqLS, qLS, gainLS, preAmp;
|
||||
double freqHS, qHS, gainHS;
|
||||
HRESULT res;
|
||||
while (WaitForSingleObject(lCorrection->_stopParameterUpdateThreadEvent, 0) == WAIT_TIMEOUT)
|
||||
{
|
||||
if (WaitForSingleObject(lCorrection->_parameterchangedEvent, 0) == WAIT_TIMEOUT)
|
||||
{
|
||||
res = VolumeController.getVolume(vol);
|
||||
if (res == S_OK)
|
||||
{
|
||||
if (vol != volOld)
|
||||
{
|
||||
lCorrection->getLShelfParamter(vol, freqLS, qLS, gainLS, preAmp);
|
||||
lCorrection->_attFactor = exp(preAmp / 6 * log(2));
|
||||
lCorrection->getHShelfParamter(vol + (float)preAmp, freqHS, qHS, gainHS);
|
||||
lCorrection->upDateBiquadCoefficients(freqHS, qHS, gainHS, true);
|
||||
lCorrection->upDateBiquadCoefficients(freqLS, qLS, gainLS, false);
|
||||
volOld = vol;
|
||||
|
||||
lCorrection->_neutralUpDate = std::max<double>(std::abs(gainLS), std::abs(gainHS)) < 0.2 ? true : false;
|
||||
|
||||
SetEvent(lCorrection->_parameterchangedEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
Sleep(10);
|
||||
// ==========================
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool LoudnessCorrectionFilter::upDateNeutral()
|
||||
{
|
||||
return _neutralUpDate;
|
||||
}
|
||||
|
||||
#pragma AVRT_CODE_BEGIN
|
||||
void LoudnessCorrectionFilter::process(float** output, float** input, unsigned frameCount)
|
||||
{
|
||||
if (_parameters.state == false)
|
||||
{
|
||||
for (unsigned int j = 0; j < frameCount; j++)
|
||||
{
|
||||
for (unsigned i = 0; i < _channelCount; i++)
|
||||
{
|
||||
output[i][j] = input[i][j];
|
||||
}
|
||||
}
|
||||
output = input;
|
||||
return;
|
||||
}
|
||||
if (WaitForSingleObject(_parameterchangedEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
for (unsigned i = 0; i < _channelCount; i++)
|
||||
{
|
||||
_lowShelfBiquads[i].setCoefficients(_aLS, _a0LS);
|
||||
_highShelfBiquads[i].setCoefficients(_aHS, _a0HS);
|
||||
}
|
||||
_neutral = upDateNeutral();
|
||||
ResetEvent(_parameterchangedEvent);
|
||||
}
|
||||
for (unsigned i = 0; i < _channelCount; i++)
|
||||
{
|
||||
float* inputChannel = input[i];
|
||||
float* outputChannel = output[i];
|
||||
for (unsigned j = 0; j < frameCount; j++)
|
||||
{
|
||||
_tempResult = _lowShelfBiquads[i].process(inputChannel[j]);
|
||||
_lowShelfBiquads[i].removeDenormals();
|
||||
_tempResult *= _attFactor;
|
||||
outputChannel[j] = (float)_highShelfBiquads[i].process(_tempResult);
|
||||
_highShelfBiquads[i].removeDenormals();
|
||||
|
||||
// if there is nearly no loudness correction necessary => set output=input to achive best quality
|
||||
if (_neutral)
|
||||
{
|
||||
outputChannel[j] = inputChannel[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LoudnessCorrectionFilter::upDateBiquadCoefficients(const double& freq, const double& bandwidthOrQOrS, const double& dbGain, bool highshelf)
|
||||
{
|
||||
double A;
|
||||
A = pow(10, dbGain / 40);
|
||||
|
||||
double omega = 2 * M_PI * freq / _sampleRate;
|
||||
double sn = sin(omega);
|
||||
double cs = cos(omega);
|
||||
double alpha;
|
||||
double beta = -1;
|
||||
|
||||
alpha = sn / 2 * sqrt((A + 1 / A) * (1 / bandwidthOrQOrS - 1) + 2);
|
||||
beta = 2 * sqrt(A) * alpha;
|
||||
|
||||
double a0;
|
||||
TryEnterCriticalSection(&_parameterUpdateSection);
|
||||
if (highshelf)
|
||||
{
|
||||
a0 = (A + 1) - (A - 1) * cs + beta;
|
||||
_a0HS = (float)((A * ((A + 1) + (A - 1) * cs + beta)) / a0);
|
||||
_aHS[0] = (float)((-2 * A * ((A - 1) + (A + 1) * cs)) / a0);
|
||||
_aHS[1] = (float)((A * ((A + 1) + (A - 1) * cs - beta)) / a0);
|
||||
|
||||
_aHS[2] = (float)((2 * ((A - 1) - (A + 1) * cs)) / a0);
|
||||
_aHS[3] = (float)(((A + 1) - (A - 1) * cs - beta) / a0);
|
||||
}
|
||||
else
|
||||
{
|
||||
a0 = (A + 1) + (A - 1) * cs + beta;
|
||||
_a0LS = (float)((A * ((A + 1) - (A - 1) * cs + beta)) / a0);
|
||||
_aLS[0] = (float)((2 * A * ((A - 1) - (A + 1) * cs)) / a0);
|
||||
_aLS[1] = (float)((A * ((A + 1) - (A - 1) * cs - beta)) / a0);
|
||||
|
||||
_aLS[2] = (float)((-2 * ((A - 1) + (A + 1) * cs)) / a0);
|
||||
_aLS[3] = (float)(((A + 1) + (A - 1) * cs - beta) / a0);
|
||||
}
|
||||
LeaveCriticalSection(&_parameterUpdateSection);
|
||||
}
|
||||
#pragma AVRT_CODE_END
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
This file is part of Equalizer APO, a system-wide equalizer.
|
||||
Copyright (C) 2017 Alexander Walch
|
||||
|
||||
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 "ParameterArchive.h"
|
||||
#include <IFilter.h>
|
||||
#include <filters/BiQuad.h>
|
||||
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
|
||||
#pragma AVRT_VTABLES_BEGIN
|
||||
class LoudnessCorrectionFilter : public IFilter
|
||||
{
|
||||
public:
|
||||
struct FilterParameters
|
||||
{
|
||||
bool state;
|
||||
float referenceLevel;
|
||||
float referenceOffset;
|
||||
float attenuation;
|
||||
std::vector<char> serialize()
|
||||
{
|
||||
ParameterArchive archive; // possibility to get string from name of variable: std::string name=NAME(on);
|
||||
archive.add(state, L"State");
|
||||
archive.add(referenceLevel, L"ReferenceLevel");
|
||||
archive.add(referenceOffset, L"ReferenceOffset");
|
||||
archive.add(attenuation, L"Attenuation");
|
||||
return archive.getSerializedParameters();
|
||||
}
|
||||
template<typename T> bool deSerialize(const T& parameters)
|
||||
{
|
||||
ParameterArchive archive(parameters);
|
||||
int error(0);
|
||||
error += archive.get(state, std::wregex(L"\\s*State\\s+(0|1)"));
|
||||
error += archive.get(referenceLevel, std::wregex(L"\\s*ReferenceLevel\\s+([-+0-9]+)"));
|
||||
error += archive.get(referenceOffset, std::wregex(L"\\s*ReferenceOffset\\s+([-+0-9]+)"));
|
||||
// attenuation is only an optional parameter
|
||||
int errorAtt = archive.get(attenuation, std::wregex(L"\\s*Attenuation\\s+((1((\\.|,)0+)?)|(0((\\.|,)[0-9]+)?))"));
|
||||
if (errorAtt > 0)
|
||||
{
|
||||
attenuation = 1.0;
|
||||
}
|
||||
return error == 0 ? false : true;
|
||||
}
|
||||
FilterParameters()
|
||||
: _isInitialized(false) {};
|
||||
template<typename T> FilterParameters(T input)
|
||||
{
|
||||
_isInitialized = !deSerialize<T>(input);
|
||||
}
|
||||
bool isInitialized()
|
||||
{
|
||||
return _isInitialized;
|
||||
}
|
||||
private:
|
||||
bool _isInitialized;
|
||||
};
|
||||
|
||||
LoudnessCorrectionFilter(const FilterParameters& fParameters);
|
||||
virtual ~LoudnessCorrectionFilter();
|
||||
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:
|
||||
void getLShelfParamter(const float& volume, double& frequence, double& q, double& gain, double& preAmp);
|
||||
void getHShelfParamter(const float& volume, double& frequence, double& q, double& gain);
|
||||
void upDateBiquadCoefficients(const double& freq, const double& bandwidthOrQOrS, const double& dbGain, bool highshelf);
|
||||
bool upDateNeutral();
|
||||
|
||||
void* _parameterUpdateThreadHandle;
|
||||
static unsigned long __stdcall parameterUpdateThread(void* parameter);
|
||||
void* _stopParameterUpdateThreadEvent;
|
||||
void* _parameterchangedEvent;
|
||||
CRITICAL_SECTION _parameterUpdateSection;
|
||||
|
||||
FilterParameters _parameters;
|
||||
size_t _channelCount;
|
||||
float _sampleRate;
|
||||
double _attFactor;
|
||||
std::vector<BiQuad> _lowShelfBiquads;
|
||||
std::vector<BiQuad> _highShelfBiquads;
|
||||
|
||||
bool _neutral;
|
||||
bool _neutralUpDate;
|
||||
double _tempResult;
|
||||
double _aLS[4];
|
||||
double _a0LS;
|
||||
double _aHS[4];
|
||||
double _a0HS;
|
||||
};
|
||||
#pragma AVRT_VTABLES_END
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
This file is part of Equalizer APO, a system-wide equalizer.
|
||||
Copyright (C) 2017 Alexander Walch
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
|
||||
#include "helpers/MemoryHelper.h"
|
||||
#include "helpers/StringHelper.h"
|
||||
#include "helpers/LogHelper.h"
|
||||
#include "LoudnessCorrectionFilter.h"
|
||||
#include "LoudnessCorrectionFilterFactory.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
LoudnessCorrectionFilterFactory::LoudnessCorrectionFilterFactory()
|
||||
{
|
||||
}
|
||||
|
||||
vector<IFilter*> LoudnessCorrectionFilterFactory::createFilter(const wstring& configPath, wstring& command, wstring& parameters)
|
||||
{
|
||||
vector<IFilter*> allFilter(0);
|
||||
|
||||
if (command == L"LoudnessCorrection")
|
||||
{
|
||||
LoudnessCorrectionFilter::FilterParameters filterParameters(parameters);
|
||||
if (filterParameters.isInitialized())
|
||||
{
|
||||
TraceF(L"Adding loudness correction filter");
|
||||
void* mem = MemoryHelper::alloc(sizeof(LoudnessCorrectionFilter));
|
||||
allFilter.push_back(new(mem) LoudnessCorrectionFilter(filterParameters));
|
||||
}
|
||||
}
|
||||
|
||||
return allFilter;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
This file is part of Equalizer APO, a system-wide equalizer.
|
||||
Copyright (C) 2017 Alexander Walch
|
||||
|
||||
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 LoudnessCorrectionFilterFactory : public IFilterFactory
|
||||
{
|
||||
public:
|
||||
LoudnessCorrectionFilterFactory();
|
||||
virtual std::vector<IFilter*> createFilter(const std::wstring& configPath, std::wstring& command, std::wstring& parameters);
|
||||
};
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
This file is part of Equalizer APO, a system-wide equalizer.
|
||||
Copyright (C) 2017 Alexander Walch
|
||||
|
||||
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 <regex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <helpers/StringHelper.h>
|
||||
|
||||
template<typename type> struct to_WString_type_traits
|
||||
{
|
||||
static inline std::wstring cast_ToWString(type& input) {return std::wstring();}
|
||||
};
|
||||
|
||||
template<> struct to_WString_type_traits<float>
|
||||
{
|
||||
static inline std::wstring cast_ToWString(const float& input) {return std::to_wstring((long double)input);}
|
||||
};
|
||||
|
||||
template<> struct to_WString_type_traits<double>
|
||||
{
|
||||
static inline std::wstring cast_ToWString(const double& input) {return std::to_wstring((long double)input);}
|
||||
};
|
||||
|
||||
template<> struct to_WString_type_traits<int>
|
||||
{
|
||||
static inline std::wstring cast_ToWString(const int& input) {return std::to_wstring((_Longlong)input);}
|
||||
};
|
||||
|
||||
template<> struct to_WString_type_traits<bool>
|
||||
{
|
||||
static inline std::wstring cast_ToWString(const bool& input) {return std::to_wstring((_Longlong)input);}
|
||||
};
|
||||
|
||||
template<> struct to_WString_type_traits<std::string>
|
||||
{
|
||||
static inline std::wstring cast_ToWString(const std::string& input) {return StringHelper::toWString(input, CP_ACP);}
|
||||
};
|
||||
|
||||
template<> struct to_WString_type_traits<std::wstring>
|
||||
{
|
||||
static inline std::wstring cast_ToWString(const std::wstring& input) {return input;}
|
||||
};
|
||||
|
||||
template<typename type> struct from_WString_type_traits
|
||||
{
|
||||
static inline type cast_fromWString(const std::wstring& input) {return (type)wcstod(input.c_str(), NULL);}
|
||||
};
|
||||
|
||||
template<> struct from_WString_type_traits<float>
|
||||
{
|
||||
static inline float cast_fromWString(const std::wstring& input) {return (float)wcstod(input.c_str(), NULL);}
|
||||
};
|
||||
|
||||
template<> struct from_WString_type_traits<double>
|
||||
{
|
||||
static inline double cast_fromWString(const std::wstring& input) {return wcstod(input.c_str(), NULL);}
|
||||
};
|
||||
|
||||
template<> struct from_WString_type_traits<int>
|
||||
{
|
||||
static inline int cast_fromWString(const std::wstring& input) {return (int)wcstol(input.c_str(), NULL, 10);}
|
||||
};
|
||||
|
||||
template<> struct from_WString_type_traits<bool>
|
||||
{
|
||||
static inline bool cast_fromWString(const std::wstring& input) {return wcstol(input.c_str(), NULL, 10) == 0 ? false : true;}
|
||||
};
|
||||
|
||||
template<> struct from_WString_type_traits<std::wstring>
|
||||
{
|
||||
static inline std::wstring cast_fromWString(const std::wstring& input) {return input;}
|
||||
};
|
||||
|
||||
template<typename type> struct constructor_traits
|
||||
{
|
||||
static inline std::wstring initFrom(type input) {return std::wstring();}
|
||||
};
|
||||
|
||||
template<> struct constructor_traits<std::wstring>
|
||||
{
|
||||
static inline std::wstring initFrom(std::wstring input) {return input;}
|
||||
};
|
||||
|
||||
template<> struct constructor_traits<std::vector<char> >
|
||||
{
|
||||
static inline std::wstring initFrom(std::vector<char> input)
|
||||
{
|
||||
input.push_back(0);
|
||||
std::string tempParams(&input[0]);
|
||||
return to_WString_type_traits<std::string>::cast_ToWString(tempParams);
|
||||
}
|
||||
};
|
||||
|
||||
class ParameterArchive
|
||||
{
|
||||
public:
|
||||
ParameterArchive()
|
||||
: _serializedParamters(std::wstring())
|
||||
{
|
||||
}
|
||||
template<typename T> ParameterArchive(T input)
|
||||
{
|
||||
_serializedParamters = constructor_traits<T>::initFrom(input);
|
||||
}
|
||||
|
||||
std::vector<char> getSerializedParameters()
|
||||
{
|
||||
size_t noBytes = _serializedParamters.length() * sizeof(std::wstring);
|
||||
std::vector<char> outputParameter(noBytes);
|
||||
CopyMemory(&outputParameter[0], reinterpret_cast<char*>(&_serializedParamters[0]), noBytes);
|
||||
return outputParameter;
|
||||
}
|
||||
|
||||
template<typename T, typename U> void add(const T& parameter, const U& name)
|
||||
{
|
||||
std::wstring nameStr = to_WString_type_traits<U>::cast_ToWString(name);
|
||||
if (!nameStr.empty())
|
||||
{
|
||||
_serializedParamters += nameStr;
|
||||
_serializedParamters += L" ";
|
||||
}
|
||||
_serializedParamters += to_WString_type_traits<T>::cast_ToWString(parameter);
|
||||
_serializedParamters += L" ";
|
||||
};
|
||||
|
||||
template<typename T> int get(T& parameter, const std::wregex& searchArgument)
|
||||
{
|
||||
std::wsmatch match;
|
||||
bool found = regex_search(_serializedParamters, match, searchArgument);
|
||||
if (!found)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
std::vector<std::wstring> splittedStrings = StringHelper::split(match.str(1), L' ');
|
||||
if (splittedStrings.empty())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
parameter = from_WString_type_traits<T>::cast_fromWString(splittedStrings.back());
|
||||
return 0;
|
||||
};
|
||||
|
||||
bool find(const std::wregex& searchArgument)
|
||||
{
|
||||
std::wsmatch match;
|
||||
return regex_search(_serializedParamters, match, searchArgument);
|
||||
}
|
||||
|
||||
private:
|
||||
std::wstring _serializedParamters;
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
This file is part of Equalizer APO, a system-wide equalizer.
|
||||
Copyright (C) 2017 Alexander Walch
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "VolumeController.h"
|
||||
#include <mmdeviceapi.h>
|
||||
|
||||
VolumeController::VolumeController()
|
||||
{
|
||||
HRESULT hr;
|
||||
CoInitialize(NULL);
|
||||
IMMDeviceEnumerator* deviceEnumerator = NULL;
|
||||
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID*)&deviceEnumerator);
|
||||
IMMDevice* defaultDevice = NULL;
|
||||
|
||||
hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &defaultDevice);
|
||||
deviceEnumerator->Release();
|
||||
deviceEnumerator = NULL;
|
||||
|
||||
_endpointVolume = NULL;
|
||||
hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&_endpointVolume);
|
||||
defaultDevice->Release();
|
||||
defaultDevice = NULL;
|
||||
float inkrement;
|
||||
_endpointVolume->GetVolumeRange(&_minVol, &_maxVol, &inkrement);
|
||||
}
|
||||
|
||||
HRESULT VolumeController::getVolume(float& currentVolume)
|
||||
{
|
||||
HRESULT res = _endpointVolume->GetMasterVolumeLevel(¤tVolume);
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT VolumeController::setVolume(float volume)
|
||||
{
|
||||
volume = min(volume, _maxVol);
|
||||
volume = max(volume, _minVol);
|
||||
return _endpointVolume->SetMasterVolumeLevel(volume, NULL);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
This file is part of Equalizer APO, a system-wide equalizer.
|
||||
Copyright (C) 2017 Alexander Walch
|
||||
|
||||
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
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <EndpointVolume.h>
|
||||
|
||||
class VolumeController
|
||||
{
|
||||
public:
|
||||
VolumeController();
|
||||
HRESULT getVolume(float& currentVolume);
|
||||
HRESULT setVolume(float volume);
|
||||
private:
|
||||
IAudioEndpointVolume* _endpointVolume;
|
||||
float _minVol;
|
||||
float _maxVol;
|
||||
};
|
||||
Reference in new issue
Block a user