Added: Voicemeeter audio processing support. When Voicemeeter is installed, it can be selected in the Configurator.

This commit is contained in:
jthedering committed 2017-03-12 12:53:24 +00:00
1 parent 46d921945f
commit 989812ba36
55 files changed
+3044 -278

No files matched your search

+25
View File
@@ -0,0 +1,25 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2017 Jonas Thedering
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include "AbstractAPOInfo.h"
AbstractAPOInfo::~AbstractAPOInfo()
{
}
+45
View File
@@ -0,0 +1,45 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2017 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>
class AbstractAPOInfo
{
public:
virtual ~AbstractAPOInfo();
virtual std::wstring getConnectionName() const = 0;
virtual std::wstring getDeviceName() const = 0;
virtual std::wstring getDeviceGuid() const = 0;
virtual std::wstring getDeviceString() const = 0;
virtual unsigned getChannelCount() const = 0;
virtual unsigned getSampleRate() const = 0;
virtual unsigned long getChannelMask() const = 0;
virtual bool isInput() const = 0;
virtual bool isInstalled() const = 0;
virtual bool canBeUpgraded() const = 0;
virtual bool hasChanges() const = 0;
virtual bool isExperimental() const = 0;
virtual bool isEnhancementsDisabled() const = 0;
virtual bool isDefaultDevice() const = 0;
virtual void install() = 0;
virtual void uninstall() = 0;
virtual void reinstall() = 0;
};
+4 -3
View File
@@ -164,9 +164,10 @@ int main(int argc, char** argv)
timer.start();
FilterEngine engine;
engine.setDeviceInfo(false, true, StringHelper::toWString(devicenameArg.getValue(), CP_ACP),
StringHelper::toWString(connectionnameArg.getValue(), CP_ACP),
StringHelper::toWString(guidArg.getValue(), CP_ACP));
wstring deviceName = StringHelper::toWString(devicenameArg.getValue(), CP_ACP);
wstring connectionName = StringHelper::toWString(connectionnameArg.getValue(), CP_ACP);
wstring deviceGuid = StringHelper::toWString(guidArg.getValue(), CP_ACP);
engine.setDeviceInfo(false, true, deviceName, connectionName, deviceGuid, deviceName + L" " + connectionName + L" " + deviceGuid);
engine.initialize((float)sampleRate, channelCount, channelCount, channelCount, channelMask, batchsize);
double initTime = timer.stop();
+2
View File
@@ -224,7 +224,9 @@
<ClInclude Include="..\helpers\MemoryHelper.h" />
<ClInclude Include="..\helpers\PrecisionTimer.h" />
<ClInclude Include="..\helpers\RegistryHelper.h" />
<ClInclude Include="..\helpers\ScopeGuard.h" />
<ClInclude Include="..\helpers\StringHelper.h" />
<ClInclude Include="..\helpers\UncaughtExceptions.h" />
<ClInclude Include="..\IFilter.h" />
<ClInclude Include="..\IFilterFactory.h" />
<ClInclude Include="..\libHybridConv-0.1.1\libHybridConv_eapo.h" />
+6
View File
@@ -208,6 +208,12 @@
<Filter>filters</Filter>
</ClInclude>
<ClInclude Include="..\stdafx.h" />
<ClInclude Include="..\helpers\ScopeGuard.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="..\helpers\UncaughtExceptions.h">
<Filter>helpers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="parser">
+121 -71
View File
@@ -25,6 +25,7 @@
#include <ObjBase.h>
#include "helpers/StringHelper.h"
#include "helpers/RegistryHelper.h"
#include "VoicemeeterAPOInfo.h"
#include "Configurator.h"
using namespace std;
@@ -176,26 +177,37 @@ void Configurator::onInitDialog(HWND hDlg)
wstring defaultDevice = StringHelper::toLowerCase(DeviceAPOInfo::getDefaultDevice(i == 1));
int itemCount = 0;
for (vector<DeviceAPOInfo>::iterator it = apoInfos[i].begin(); it != apoInfos[i].end(); it++)
for (shared_ptr<AbstractAPOInfo>& apoInfo : apoInfos[i])
{
wcsncpy_s(stringBuf, sizeof(stringBuf) / sizeof(wchar_t), it->connectionName.c_str(), _TRUNCATE);
wcsncpy_s(stringBuf, sizeof(stringBuf) / sizeof(wchar_t), apoInfo->getConnectionName().c_str(), _TRUNCATE);
item.iItem = itemCount;
item.lParam = itemCount;
ListView_InsertItem(deviceList, &item);
wcsncpy_s(stringBuf, sizeof(stringBuf) / sizeof(wchar_t), it->deviceName.c_str(), _TRUNCATE);
wcsncpy_s(stringBuf, sizeof(stringBuf) / sizeof(wchar_t), apoInfo->getDeviceName().c_str(), _TRUNCATE);
ListView_SetItemText(deviceList, itemCount, 1, stringBuf);
if (it->isInstalled)
VoicemeeterAPOInfo* voicemeeterInfo = dynamic_cast<VoicemeeterAPOInfo*>(apoInfo.get());
if (apoInfo->isInstalled())
{
ListView_SetCheckState(deviceList, itemCount, TRUE);
if (it->canBeUpgraded())
LoadStringW(hInstance, IDS_WILL_BE_UPGRADED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
else if (it->isEnhancementsDisabled)
LoadStringW(hInstance, IDS_ENHANCEMENTS_WILL_BE_ENABLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
if (voicemeeterInfo != NULL && !voicemeeterInfo->isVoicemeeterInstalled())
{
ListView_SetCheckState(deviceList, itemCount, FALSE);
LoadStringW(hInstance, IDS_WILL_BE_UNINSTALLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
}
else
LoadStringW(hInstance, IDS_ALREADY_INSTALLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
{
ListView_SetCheckState(deviceList, itemCount, TRUE);
if (apoInfo->canBeUpgraded())
LoadStringW(hInstance, IDS_WILL_BE_UPGRADED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
else if (apoInfo->hasChanges())
LoadStringW(hInstance, IDS_WILL_BE_CHANGED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
else if (apoInfo->isEnhancementsDisabled())
LoadStringW(hInstance, IDS_ENHANCEMENTS_WILL_BE_ENABLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
else
LoadStringW(hInstance, IDS_ALREADY_INSTALLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
}
}
else if (it->isExperimental())
else if (apoInfo->isExperimental())
{
LoadStringW(hInstance, IDS_CAN_BE_INSTALLED_EXPERIMENTAL, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
}
@@ -204,7 +216,15 @@ void Configurator::onInitDialog(HWND hDlg)
LoadStringW(hInstance, IDS_CAN_BE_INSTALLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
}
if (it->isDefaultDevice)
if (voicemeeterInfo != NULL && !voicemeeterInfo->isVoicemeeterInstalled())
{
wstring statusText = stringBuf;
LoadStringW(hInstance, IDS_VOICEMEETER_WAS_UNINSTALLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
statusText = wstring(stringBuf) + L", " + statusText;
ListView_SetItemText(deviceList, itemCount, 2, const_cast<wchar_t*>(statusText.c_str()));
}
else if (apoInfo->isDefaultDevice())
{
wstring statusText = stringBuf;
LoadStringW(hInstance, IDS_DEFAULT_DEVICE, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
@@ -250,6 +270,8 @@ void Configurator::onLvnItemChanged(unsigned sourceId, LPNMLISTVIEW info)
bool Configurator::onButtonClicked(unsigned sourceId)
{
bool deviceUpdated = false;
switch (sourceId)
{
case IDOK:
@@ -268,16 +290,25 @@ bool Configurator::onButtonClicked(unsigned sourceId)
try
{
DeviceAPOInfo info = apoInfos[index][item.lParam];
if (ListView_GetCheckState(deviceList, i) && !info.isInstalled)
info.install();
else if (!ListView_GetCheckState(deviceList, i) && info.isInstalled)
info.uninstall();
else if (ListView_GetCheckState(deviceList, i) && (info.canBeUpgraded() || info.hasChanges() || info.isEnhancementsDisabled))
shared_ptr<AbstractAPOInfo>& info = apoInfos[index][item.lParam];
DeviceAPOInfo* deviceInfo = dynamic_cast<DeviceAPOInfo*>(info.get());
if (ListView_GetCheckState(deviceList, i) && !info->isInstalled())
{
info.uninstall();
info.load(info.deviceGuid);
info.install();
info->install();
if (deviceInfo != NULL)
deviceUpdated = true;
}
else if (!ListView_GetCheckState(deviceList, i) && info->isInstalled())
{
info->uninstall();
if (deviceInfo != NULL)
deviceUpdated = true;
}
else if (ListView_GetCheckState(deviceList, i) && (info->canBeUpgraded() || info->hasChanges() || info->isEnhancementsDisabled()))
{
info->reinstall();
if (deviceInfo != NULL)
deviceUpdated = true;
}
}
catch (RegistryException e)
@@ -286,6 +317,8 @@ bool Configurator::onButtonClicked(unsigned sourceId)
}
}
}
VoicemeeterAPOInfo::ensureVoicemeeterClientRunning();
}
break;
case IDC_COPY_DEVICE_COMMAND:
@@ -312,8 +345,8 @@ bool Configurator::onButtonClicked(unsigned sourceId)
else
command += L"; ";
DeviceAPOInfo info = apoInfos[index][item.lParam];
command += StringHelper::replaceCharacters(info.deviceName + L" " + info.connectionName + L" " + info.deviceGuid, L";", L" ");
shared_ptr<AbstractAPOInfo>& info = apoInfos[index][item.lParam];
command += StringHelper::replaceCharacters(info->getDeviceString(), L";", L" ");
}
}
@@ -357,31 +390,34 @@ bool Configurator::onButtonClicked(unsigned sourceId)
if (item.state & LVIS_SELECTED)
{
DeviceAPOInfo& info = apoInfos[index][item.lParam];
switch (sourceId)
shared_ptr<AbstractAPOInfo>& info = apoInfos[index][item.lParam];
DeviceAPOInfo* deviceInfo = dynamic_cast<DeviceAPOInfo*>(info.get());
if (deviceInfo != NULL)
{
case IDC_INSTALL_PRE_MIX:
info.selectedInstallState.installPreMix = Button_GetCheck(installPreMix) == BST_CHECKED;
break;
case IDC_INSTALL_POST_MIX:
info.selectedInstallState.installPostMix = Button_GetCheck(installPostMix) == BST_CHECKED;
break;
case IDC_USE_ORIGINAL_APO_PRE_MIX:
info.selectedInstallState.useOriginalAPOPreMix = Button_GetCheck(useOriginalAPOPreMix) == BST_CHECKED;
break;
case IDC_USE_ORIGINAL_APO_POST_MIX:
info.selectedInstallState.useOriginalAPOPostMix = Button_GetCheck(useOriginalAPOPostMix) == BST_CHECKED;
break;
case IDC_INSTALL_MODE_COMBOBOX:
info.selectedInstallState.installMode = (DeviceAPOInfo::InstallMode)ComboBox_GetCurSel(installModeComboBox);
break;
case IDC_ALLOW_SILENT_BUFFER:
info.selectedInstallState.allowSilentBufferModification = Button_GetCheck(allowSilentBuffer) == BST_CHECKED;
break;
}
switch (sourceId)
{
case IDC_INSTALL_PRE_MIX:
deviceInfo->getSelectedInstallState().installPreMix = Button_GetCheck(installPreMix) == BST_CHECKED;
break;
case IDC_INSTALL_POST_MIX:
deviceInfo->getSelectedInstallState().installPostMix = Button_GetCheck(installPostMix) == BST_CHECKED;
break;
case IDC_USE_ORIGINAL_APO_PRE_MIX:
deviceInfo->getSelectedInstallState().useOriginalAPOPreMix = Button_GetCheck(useOriginalAPOPreMix) == BST_CHECKED;
break;
case IDC_USE_ORIGINAL_APO_POST_MIX:
deviceInfo->getSelectedInstallState().useOriginalAPOPostMix = Button_GetCheck(useOriginalAPOPostMix) == BST_CHECKED;
break;
case IDC_INSTALL_MODE_COMBOBOX:
deviceInfo->getSelectedInstallState().installMode = (DeviceAPOInfo::InstallMode)ComboBox_GetCurSel(installModeComboBox);
break;
case IDC_ALLOW_SILENT_BUFFER:
deviceInfo->getSelectedInstallState().allowSilentBufferModification = Button_GetCheck(allowSilentBuffer) == BST_CHECKED;
break;
}
updateList(index, i);
updateList(index, i);
}
}
}
@@ -408,7 +444,7 @@ bool Configurator::onButtonClicked(unsigned sourceId)
LoadStringW(hInstance, IDS_AFTERINSTALL, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
MessageBoxW(hDlg, stringBuf, L"Info", MB_ICONINFORMATION | MB_OK);
}
else if (sourceId == IDOK && RegistryHelper::isWindowsVersionAtLeast(6, 3) // Windows 8.1
else if (sourceId == IDOK && deviceUpdated && RegistryHelper::isWindowsVersionAtLeast(6, 3) // Windows 8.1
|| askForReboot)
{
wchar_t captionBuf[255];
@@ -470,7 +506,6 @@ bool Configurator::isAnySelected()
item.iSubItem = 0;
item.mask = LVIF_PARAM;
ListView_GetItem(deviceList, &item);
DeviceAPOInfo apoInfo = apoInfos[index][item.lParam];
if (ListView_GetCheckState(deviceList, i) != 0)
{
anySelected = true;
@@ -497,9 +532,9 @@ bool Configurator::isChanged()
item.iSubItem = 0;
item.mask = LVIF_PARAM;
ListView_GetItem(deviceList, &item);
DeviceAPOInfo apoInfo = apoInfos[index][item.lParam];
if ((ListView_GetCheckState(deviceList, i) != 0) != apoInfo.isInstalled
|| ListView_GetCheckState(deviceList, i) && apoInfo.isInstalled && (apoInfo.canBeUpgraded() || apoInfo.hasChanges() || apoInfo.isEnhancementsDisabled))
shared_ptr<AbstractAPOInfo>& apoInfo = apoInfos[index][item.lParam];
if ((ListView_GetCheckState(deviceList, i) != 0) != apoInfo->isInstalled()
|| ListView_GetCheckState(deviceList, i) && apoInfo->isInstalled() && (apoInfo->canBeUpgraded() || apoInfo->hasChanges() || apoInfo->isEnhancementsDisabled()))
{
changed = true;
break;
@@ -525,8 +560,8 @@ bool Configurator::hasUpgrades()
item.iSubItem = 0;
item.mask = LVIF_PARAM;
ListView_GetItem(deviceList, &item);
DeviceAPOInfo apoInfo = apoInfos[index][item.lParam];
if (ListView_GetCheckState(deviceList, i) && apoInfo.isInstalled && (apoInfo.canBeUpgraded() || apoInfo.isEnhancementsDisabled))
shared_ptr<AbstractAPOInfo>& apoInfo = apoInfos[index][item.lParam];
if (ListView_GetCheckState(deviceList, i) && apoInfo->isInstalled() && (apoInfo->canBeUpgraded() || apoInfo->isEnhancementsDisabled()))
{
hasUpgrades = true;
break;
@@ -586,27 +621,36 @@ void Configurator::updateList(int listIndex, int itemIndex)
if (apoInfos[listIndex].size() == itemCount)
{
DeviceAPOInfo apoInfo = apoInfos[listIndex][itemIndex];
shared_ptr<AbstractAPOInfo>& apoInfo = apoInfos[listIndex][itemIndex];
bool checked = ListView_GetCheckState(deviceList, itemIndex) != 0;
wchar_t stringBuf[255];
if (checked && !apoInfo.isInstalled)
if (checked && !apoInfo->isInstalled())
LoadStringW(hInstance, IDS_WILL_BE_INSTALLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
else if (!checked && apoInfo.isInstalled)
else if (!checked && apoInfo->isInstalled())
LoadStringW(hInstance, IDS_WILL_BE_UNINSTALLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
else if (apoInfo.isInstalled && apoInfo.canBeUpgraded())
else if (apoInfo->isInstalled() && apoInfo->canBeUpgraded())
LoadStringW(hInstance, IDS_WILL_BE_UPGRADED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
else if (apoInfo.isInstalled && apoInfo.hasChanges())
else if (apoInfo->isInstalled() && apoInfo->hasChanges())
LoadStringW(hInstance, IDS_WILL_BE_CHANGED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
else if (apoInfo.isInstalled && apoInfo.isEnhancementsDisabled)
else if (apoInfo->isInstalled() && apoInfo->isEnhancementsDisabled())
LoadStringW(hInstance, IDS_ENHANCEMENTS_WILL_BE_ENABLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
else if (apoInfo.isInstalled)
else if (apoInfo->isInstalled())
LoadStringW(hInstance, IDS_ALREADY_INSTALLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
else if (apoInfo.isExperimental())
else if (apoInfo->isExperimental())
LoadStringW(hInstance, IDS_CAN_BE_INSTALLED_EXPERIMENTAL, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
else
LoadStringW(hInstance, IDS_CAN_BE_INSTALLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
if (apoInfo.isDefaultDevice)
VoicemeeterAPOInfo* voicemeeterInfo = dynamic_cast<VoicemeeterAPOInfo*>(apoInfo.get());
if (voicemeeterInfo != NULL && !voicemeeterInfo->isVoicemeeterInstalled())
{
wstring statusText = stringBuf;
LoadStringW(hInstance, IDS_VOICEMEETER_WAS_UNINSTALLED, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
statusText = wstring(stringBuf) + L", " + statusText;
ListView_SetItemText(deviceList, itemCount, 2, const_cast<wchar_t*>(statusText.c_str()));
}
else if (apoInfo->isDefaultDevice())
{
wstring statusText = stringBuf;
LoadStringW(hInstance, IDS_DEFAULT_DEVICE, stringBuf, sizeof(stringBuf) / sizeof(wchar_t));
@@ -658,11 +702,15 @@ void Configurator::updateButtons(int listIndex)
{
enable = ListView_GetCheckState(deviceList, selectedIndex) != 0;
DeviceAPOInfo apoInfo = apoInfos[listIndex][selectedIndex];
isInput = apoInfo.isInput;
hasOriginalAPOPreMix = apoInfo.getOriginalAPOPreMix() != L"";
hasOriginalAPOPostMix = apoInfo.getOriginalAPOPostMix() != L"";
installState = apoInfo.selectedInstallState;
shared_ptr<AbstractAPOInfo>& apoInfo = apoInfos[listIndex][selectedIndex];
DeviceAPOInfo* deviceApoInfo = dynamic_cast<DeviceAPOInfo*>(apoInfo.get());
if (deviceApoInfo != NULL)
{
isInput = deviceApoInfo->isInput();
hasOriginalAPOPreMix = deviceApoInfo->getOriginalAPOPreMix() != L"";
hasOriginalAPOPostMix = deviceApoInfo->getOriginalAPOPostMix() != L"";
installState = deviceApoInfo->getSelectedInstallState();
}
}
}
@@ -709,14 +757,14 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
{
for (int index = 0; index <= 1; index++)
{
vector<DeviceAPOInfo> apoInfos = DeviceAPOInfo::loadAllInfos(index == 1);
vector<shared_ptr<AbstractAPOInfo> > apoInfos = DeviceAPOInfo::loadAllInfos(index == 1);
for (vector<DeviceAPOInfo>::iterator it = apoInfos.begin(); it != apoInfos.end(); it++)
for (shared_ptr<AbstractAPOInfo>& apoInfo : apoInfos)
{
try
{
if (it->isInstalled)
it->uninstall();
if (apoInfo->isInstalled())
apoInfo->uninstall();
}
catch (RegistryException e)
{
@@ -725,6 +773,8 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
}
}
}
VoicemeeterAPOInfo::ensureVoicemeeterClientRunning();
}
else
{
+2 -1
View File
@@ -22,6 +22,7 @@
#include "resource.h"
#include <string>
#include <vector>
#include <memory>
#include "DeviceAPOInfo.h"
class Configurator
@@ -63,6 +64,6 @@ private:
void updateList(int listIndex, int itemIndex);
void updateButtons(int listIndex);
std::vector<DeviceAPOInfo> apoInfos[2];
std::vector<std::shared_ptr<AbstractAPOInfo> > apoInfos[2];
bool askForReboot = false;
};
Binary file not shown.
+6
View File
@@ -19,17 +19,22 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\AbstractAPOInfo.h" />
<ClInclude Include="..\DeviceAPOInfo.h" />
<ClInclude Include="..\helpers\LogHelper.h" />
<ClInclude Include="..\helpers\MemoryHelper.h" />
<ClInclude Include="..\helpers\PrecisionTimer.h" />
<ClInclude Include="..\helpers\RegistryHelper.h" />
<ClInclude Include="..\helpers\ScopeGuard.h" />
<ClInclude Include="..\helpers\StringHelper.h" />
<ClInclude Include="..\helpers\UncaughtExceptions.h" />
<ClInclude Include="..\stdafx.h" />
<ClInclude Include="..\VoicemeeterAPOInfo.h" />
<ClInclude Include="Configurator.h" />
<ClInclude Include="Resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\AbstractAPOInfo.cpp" />
<ClCompile Include="..\DeviceAPOInfo.cpp" />
<ClCompile Include="..\helpers\LogHelper.cpp" />
<ClCompile Include="..\helpers\MemoryHelper.cpp" />
@@ -41,6 +46,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\VoicemeeterAPOInfo.cpp" />
<ClCompile Include="Configurator.cpp" />
</ItemGroup>
<ItemGroup>
+12 -2
View File
@@ -12,10 +12,12 @@
<ClCompile Include="..\helpers\RegistryHelper.cpp">
<Filter>helpers</Filter>
</ClCompile>
<ClCompile Include="..\stdafx.cpp" />
<ClCompile Include="..\helpers\StringHelper.cpp">
<Filter>helpers</Filter>
</ClCompile>
<ClCompile Include="..\stdafx.cpp" />
<ClCompile Include="..\AbstractAPOInfo.cpp" />
<ClCompile Include="..\VoicemeeterAPOInfo.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\DeviceAPOInfo.h" />
@@ -33,10 +35,18 @@
<ClInclude Include="..\helpers\RegistryHelper.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="..\stdafx.h" />
<ClInclude Include="..\helpers\StringHelper.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="..\stdafx.h" />
<ClInclude Include="..\AbstractAPOInfo.h" />
<ClInclude Include="..\VoicemeeterAPOInfo.h" />
<ClInclude Include="..\helpers\ScopeGuard.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="..\helpers\UncaughtExceptions.h">
<Filter>helpers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Configurator.rc" />
Binary file not shown.
+115 -28
View File
@@ -23,6 +23,7 @@
#include <shellapi.h>
#include "DeviceAPOInfo.h"
#include "VoicemeeterAPOInfo.h"
#include "helpers/StringHelper.h"
#include "helpers/RegistryHelper.h"
@@ -69,23 +70,27 @@ static const wchar_t* disableEnhancementsValueName = L"{1da5d803-d492-4edd-8c23-
static const wchar_t* installVersion = L"2";
static PROPERTYKEY guidPropertyKey = {{0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e}, 4};
vector<DeviceAPOInfo> DeviceAPOInfo::loadAllInfos(bool input)
vector<shared_ptr<AbstractAPOInfo> > DeviceAPOInfo::loadAllInfos(bool input)
{
vector<DeviceAPOInfo> result;
vector<shared_ptr<AbstractAPOInfo> > result;
vector<wstring> deviceGuidStrings = RegistryHelper::enumSubKeys(input ? captureKeyPath : renderKeyPath);
wstring defaultDeviceGuid = getDefaultDevice(input);
for (vector<wstring>::iterator it = deviceGuidStrings.begin(); it != deviceGuidStrings.end(); it++)
{
wstring deviceGuidString = *it;
DeviceAPOInfo info;
if (info.load(deviceGuidString, defaultDeviceGuid))
shared_ptr<DeviceAPOInfo> info = make_shared<DeviceAPOInfo>();
if (info->load(deviceGuidString, defaultDeviceGuid))
{
info.selectedInstallState = info.currentInstallState;
result.push_back(info);
info->selectedInstallState = info->currentInstallState;
result.push_back(move(info));
}
}
if (!input)
VoicemeeterAPOInfo::prependInfos(result);
return result;
}
@@ -170,12 +175,12 @@ bool DeviceAPOInfo::load(const wstring& deviceGuid, wstring defaultDeviceGuid)
if (RegistryHelper::keyExists(renderKeyPath L"\\" + deviceGuid))
{
keyPath = renderKeyPath L"\\" + deviceGuid;
isInput = false;
input = false;
}
else
{
keyPath = captureKeyPath L"\\" + deviceGuid;
isInput = true;
input = true;
}
unsigned long deviceState = RegistryHelper::readDWORDValue(keyPath, L"DeviceState");
@@ -209,27 +214,27 @@ bool DeviceAPOInfo::load(const wstring& deviceGuid, wstring defaultDeviceGuid)
channelMask = RegistryHelper::readDWORDValue(keyPath + L"\\Properties", channelMaskValueName);
if (defaultDeviceGuid == L"")
defaultDeviceGuid = getDefaultDevice(isInput);
defaultDeviceGuid = getDefaultDevice(input);
GUID guid1, guid2;
if (SUCCEEDED(CLSIDFromString(deviceGuid.c_str(), &guid1)) && SUCCEEDED(CLSIDFromString(defaultDeviceGuid.c_str(), &guid2)))
isDefaultDevice = (guid1 == guid2) != 0;
defaultDevice = (guid1 == guid2) != 0;
else
isDefaultDevice = false;
defaultDevice = false;
isEnhancementsDisabled = false;
enhancementsDisabled = false;
if (RegistryHelper::keyExists(keyPath + L"\\FxProperties") && RegistryHelper::valueExists(keyPath + L"\\FxProperties", disableEnhancementsValueName))
isEnhancementsDisabled = RegistryHelper::readDWORDValue(keyPath + L"\\FxProperties", disableEnhancementsValueName) != 0;
enhancementsDisabled = RegistryHelper::readDWORDValue(keyPath + L"\\FxProperties", disableEnhancementsValueName) != 0;
isInstalled = false;
installed = false;
currentInstallState.installMode = INSTALL_LFX_GFX;
version = L"0";
preMixChildGuid = L"";
postMixChildGuid = L"";
currentInstallState.installPreMix = true;
currentInstallState.installPostMix = !isInput;
currentInstallState.installPostMix = !input;
currentInstallState.useOriginalAPOPreMix = true;
currentInstallState.useOriginalAPOPostMix = !isInput;
currentInstallState.useOriginalAPOPostMix = !input;
currentInstallState.allowSilentBufferModification = false;
if (!RegistryHelper::keyExists(keyPath + L"\\FxProperties"))
@@ -271,7 +276,7 @@ bool DeviceAPOInfo::load(const wstring& deviceGuid, wstring defaultDeviceGuid)
if (found)
{
isInstalled = true;
installed = true;
if (RegistryHelper::keyExists(childApoPath L"\\" + deviceGuid))
{
@@ -352,19 +357,19 @@ bool DeviceAPOInfo::load(const wstring& deviceGuid, wstring defaultDeviceGuid)
return true;
}
bool DeviceAPOInfo::canBeUpgraded()
bool DeviceAPOInfo::canBeUpgraded() const
{
return isInstalled && version != installVersion;
return installed && version != installVersion;
}
bool DeviceAPOInfo::hasChanges()
bool DeviceAPOInfo::hasChanges() const
{
return isInstalled && selectedInstallState != currentInstallState;
return installed && selectedInstallState != currentInstallState;
}
bool DeviceAPOInfo::isExperimental()
bool DeviceAPOInfo::isExperimental() const
{
return !isInstalled && originalApoGuids[0] == APOGUID_NOKEY;
return !installed && originalApoGuids[0] == APOGUID_NOKEY;
}
wstring DeviceAPOInfo::getOriginalAPOPreMix()
@@ -438,7 +443,7 @@ void DeviceAPOInfo::install()
RegistryHelper::createKey(childApoPath L"\\" + deviceGuid);
wstring keyPath;
if (!isInput)
if (!input)
keyPath = renderKeyPath L"\\" + deviceGuid;
else
keyPath = captureKeyPath L"\\" + deviceGuid;
@@ -502,7 +507,7 @@ void DeviceAPOInfo::install()
{
if (selectedInstallState.installPreMix)
RegistryHelper::writeValue(keyPath + L"\\FxProperties", lfxGuidValueName, RegistryHelper::getGuidString(EQUALIZERAPO_PRE_MIX_GUID));
if (selectedInstallState.installPostMix && !isInput)
if (selectedInstallState.installPostMix && !input)
RegistryHelper::writeValue(keyPath + L"\\FxProperties", gfxGuidValueName, RegistryHelper::getGuidString(EQUALIZERAPO_POST_MIX_GUID));
if (RegistryHelper::valueExists(keyPath + L"\\FxProperties", sfxGuidValueName))
RegistryHelper::deleteValue(keyPath + L"\\FxProperties", sfxGuidValueName);
@@ -523,7 +528,7 @@ void DeviceAPOInfo::install()
if (!RegistryHelper::valueExists(keyPath + L"\\FxProperties", sfxProcessingModesValueName))
RegistryHelper::writeMultiValue(keyPath + L"\\FxProperties", sfxProcessingModesValueName, defaultProcessingModeValue);
}
if (selectedInstallState.installPostMix && !isInput)
if (selectedInstallState.installPostMix && !input)
{
RegistryHelper::writeValue(keyPath + L"\\FxProperties", mfxGuidValueName, RegistryHelper::getGuidString(EQUALIZERAPO_POST_MIX_GUID));
if (!RegistryHelper::valueExists(keyPath + L"\\FxProperties", mfxProcessingModesValueName))
@@ -544,7 +549,7 @@ void DeviceAPOInfo::install()
RegistryHelper::writeMultiValue(keyPath + L"\\FxProperties", sfxProcessingModesValueName, defaultProcessingModeValue);
}
// don't change mfx
if (selectedInstallState.installPostMix && !isInput)
if (selectedInstallState.installPostMix && !input)
{
RegistryHelper::writeValue(keyPath + L"\\FxProperties", efxGuidValueName, RegistryHelper::getGuidString(EQUALIZERAPO_POST_MIX_GUID));
if (!RegistryHelper::valueExists(keyPath + L"\\FxProperties", efxProcessingModesValueName))
@@ -560,7 +565,7 @@ void DeviceAPOInfo::install()
void DeviceAPOInfo::uninstall()
{
wstring keyPath;
if (!isInput)
if (!input)
keyPath = renderKeyPath L"\\" + deviceGuid;
else
keyPath = captureKeyPath L"\\" + deviceGuid;
@@ -594,3 +599,85 @@ void DeviceAPOInfo::uninstall()
if (RegistryHelper::keyEmpty(childApoPath))
RegistryHelper::deleteKey(childApoPath);
}
void DeviceAPOInfo::reinstall()
{
uninstall();
load(deviceGuid);
install();
}
wstring DeviceAPOInfo::getConnectionName() const
{
return connectionName;
}
wstring DeviceAPOInfo::getDeviceName() const
{
return deviceName;
}
wstring DeviceAPOInfo::getDeviceGuid() const
{
return deviceGuid;
}
wstring DeviceAPOInfo::getDeviceString() const
{
return getConnectionName() + L" " + getDeviceName() + L" " + getDeviceGuid();
}
unsigned DeviceAPOInfo::getChannelCount() const
{
return channelCount;
}
unsigned DeviceAPOInfo::getSampleRate() const
{
return sampleRate;
}
unsigned long DeviceAPOInfo::getChannelMask() const
{
return channelMask;
}
bool DeviceAPOInfo::isInput() const
{
return input;
}
bool DeviceAPOInfo::isInstalled() const
{
return installed;
}
bool DeviceAPOInfo::isEnhancementsDisabled() const
{
return enhancementsDisabled;
}
bool DeviceAPOInfo::isDefaultDevice() const
{
return defaultDevice;
}
const DeviceAPOInfo::InstallState& DeviceAPOInfo::getCurrentInstallState()
{
return currentInstallState;
}
DeviceAPOInfo::InstallState& DeviceAPOInfo::getSelectedInstallState()
{
return selectedInstallState;
}
wstring DeviceAPOInfo::getPreMixChildGuid()
{
return preMixChildGuid;
}
wstring DeviceAPOInfo::getPostMixChildGuid()
{
return postMixChildGuid;
}
+31 -12
View File
@@ -21,12 +21,14 @@
#include <string>
#include <vector>
#include <memory>
#include "AbstractAPOInfo.h"
#define APOGUID_NULL L"{00000000-0000-0000-0000-000000000000}"
#define APOGUID_NOKEY L"!KEY"
#define APOGUID_NOVALUE L"!VALUE"
class DeviceAPOInfo
class DeviceAPOInfo : public AbstractAPOInfo
{
public:
enum InstallMode
@@ -55,33 +57,50 @@ public:
allowSilentBufferModification = false;
}
bool operator!=(InstallState& other)
bool operator!=(const InstallState& other) const
{
return memcmp(this, &other, sizeof(InstallState)) != 0;
}
};
static std::vector<DeviceAPOInfo> loadAllInfos(bool input);
static std::vector<std::shared_ptr<AbstractAPOInfo> > loadAllInfos(bool input);
static std::wstring getDefaultDevice(bool input, int role = 1);
static bool checkProtectedAudioDG(bool fix);
static bool checkAPORegistration(bool fix);
bool load(const std::wstring& deviceGuid, std::wstring defaultDeviceGuid = L"");
bool canBeUpgraded();
bool hasChanges();
bool isExperimental();
bool canBeUpgraded() const override;
bool hasChanges() const override;
bool isExperimental() const override;
std::wstring getOriginalAPOPreMix();
std::wstring getOriginalAPOPostMix();
void install();
void uninstall();
void install() override;
void uninstall() override;
void reinstall() override;
std::wstring getConnectionName() const override;
std::wstring getDeviceName() const override;
std::wstring getDeviceGuid() const override;
std::wstring getDeviceString() const override;
unsigned getChannelCount() const override;
unsigned getSampleRate() const override;
unsigned long getChannelMask() const override;
bool isInput() const override;
bool isInstalled() const override;
bool isEnhancementsDisabled() const override;
bool isDefaultDevice() const override;
const InstallState& getCurrentInstallState();
InstallState& getSelectedInstallState();
std::wstring getPreMixChildGuid();
std::wstring getPostMixChildGuid();
private:
std::wstring deviceName;
std::wstring connectionName;
std::wstring deviceGuid;
unsigned channelCount;
unsigned sampleRate;
unsigned long channelMask;
bool isDefaultDevice;
bool isEnhancementsDisabled;
bool defaultDevice;
bool enhancementsDisabled;
// used for creating child APO
std::wstring preMixChildGuid;
@@ -90,8 +109,8 @@ public:
// used for uninstallation
std::wstring originalApoGuids[5];
bool isInput;
bool isInstalled;
bool input;
bool installed;
std::wstring version;
InstallState currentInstallState;
// selection in GUI
+9 -7
View File
@@ -22,6 +22,8 @@
#include "FilterEngine.h"
#include "AnalysisThread.h"
using namespace std;
AnalysisThread::AnalysisThread()
{
}
@@ -50,10 +52,10 @@ AnalysisThread::~AnalysisThread()
fftwf_destroy_plan(planForward);
}
void AnalysisThread::setParameters(DeviceAPOInfo* device, int channelMask, int channelIndex, QString configPath, int frameCount)
void AnalysisThread::setParameters(shared_ptr<AbstractAPOInfo> device, int channelMask, int channelIndex, QString configPath, int frameCount)
{
QMutexLocker mutexLocker(&mutex);
this->device = *device;
this->device = device;
this->channelMask = channelMask;
this->channelIndex = channelIndex;
this->configPath = configPath;
@@ -125,7 +127,7 @@ void AnalysisThread::run()
break;
}
DeviceAPOInfo device = this->device;
shared_ptr<AbstractAPOInfo> device = this->device;
int channelMask = this->channelMask;
int channelIndex = this->channelIndex;
QString configPath = this->configPath;
@@ -136,8 +138,8 @@ void AnalysisThread::run()
QElapsedTimer timer;
timer.start();
unsigned channelCount = device.channelCount;
if (channelMask != 0 && channelMask != device.channelMask)
unsigned channelCount = device->getChannelCount();
if (channelMask != 0 && channelMask != device->getChannelMask())
{
channelCount = 0;
for (int i = 0; i < 31; i++)
@@ -148,11 +150,11 @@ void AnalysisThread::run()
}
}
unsigned sampleRate = device.sampleRate;
unsigned sampleRate = device->getSampleRate();
qint64 startTime = timer.nsecsElapsed();
FilterEngine engine;
engine.setDeviceInfo(device.isInput, true, device.deviceName, device.connectionName, device.deviceGuid);
engine.setDeviceInfo(device->isInput(), true, device->getDeviceName(), device->getConnectionName(), device->getDeviceGuid(), device->getDeviceString());
engine.initialize(sampleRate, channelCount, channelCount, channelCount, channelMask, frameCount, configPath.toStdWString());
double initializationTime = (timer.nsecsElapsed() - startTime) / 1e6;
+2 -2
View File
@@ -32,7 +32,7 @@ class AnalysisThread : public QThread
public:
AnalysisThread();
~AnalysisThread();
void setParameters(DeviceAPOInfo* device, int channelMask, int channelIndex, QString configPath, int frameCount);
void setParameters(std::shared_ptr<AbstractAPOInfo> device, int channelMask, int channelIndex, QString configPath, int frameCount);
void beginGetResult();
void endGetResult();
@@ -57,7 +57,7 @@ private:
bool quit = false;
// input
DeviceAPOInfo device;
std::shared_ptr<AbstractAPOInfo> device;
int channelMask;
int channelIndex;
QString configPath;
+8 -4
View File
@@ -114,7 +114,9 @@ SOURCES += main.cpp\
widgets/ExponentialSpinBox.cpp \
FilterTableMimeData.cpp \
helpers/DPIHelper.cpp \
CustomStyle.cpp
CustomStyle.cpp \
../AbstractAPOInfo.cpp \
../VoicemeeterAPOInfo.cpp
HEADERS += \
../helpers/LogHelper.h \
@@ -217,7 +219,9 @@ HEADERS += \
widgets/ExponentialSpinBox.h \
FilterTableMimeData.h \
helpers/DPIHelper.h \
CustomStyle.h
CustomStyle.h \
../AbstractAPOInfo.h \
../VoicemeeterAPOInfo.h
FORMS += \
guis/PreampFilterGUI.ui \
@@ -238,7 +242,7 @@ FORMS += \
guis/StageFilterGUI.ui
INCLUDEPATH += $$PWD/.. "C:/Program Files/libsndfile/include" "C:/Program Files/fftw3" "C:/Program Files/muparserx_v3_0_1/parser"
LIBS += advapi32.lib version.lib ole32.lib Shlwapi.lib authz.lib libsndfile-1.lib libfftw3f-3.lib
LIBS += user32.lib advapi32.lib version.lib ole32.lib Shlwapi.lib authz.lib libsndfile-1.lib libfftw3f-3.lib
build_pass:CONFIG(debug, debug|release) {
LIBS += muparserxd.lib
@@ -256,6 +260,6 @@ RESOURCES += \
Editor.qrc
TRANSLATIONS += translations/Editor_de.ts
RC_ICONS = icons/accessories-text-editor.ico
RC_FILE = Editor.rc
DISTFILES += ../uncrustify.cfg
+44
View File
@@ -0,0 +1,44 @@
# if defined(UNDER_CE)
# include <winbase.h>
# else
# include <windows.h>
# endif
#include "../version.h"
#define S2(x) #x
#define S(x) S2(x)
IDI_ICON1 ICON DISCARDABLE "icons\\accessories-text-editor.ico"
VS_VERSION_INFO VERSIONINFO
FILEVERSION MAJOR,MINOR,REVISION,0
PRODUCTVERSION MAJOR,MINOR,REVISION,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileDescription", "Equalizer APO Configuration Editor\0"
VALUE "FileVersion", S(MAJOR) "." S(MINOR) "." S(REVISION) ".0"
VALUE "LegalCopyright", "Copyright (C) 2017\0"
VALUE "OriginalFilename", "Editor.exe\0"
VALUE "ProductName", "Configuration Editor\0"
VALUE "ProductVersion", S(MAJOR) "." S(MINOR) "." S(REVISION) ".0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 1200
END
END
/* End of Version info */
+8 -6
View File
@@ -83,7 +83,7 @@ FilterTable::FilterTable(MainWindow* mainWindow, QWidget* parent)
QApplication::instance()->installEventFilter(this);
}
void FilterTable::initialize(QScrollArea* scrollArea, const QList<DeviceAPOInfo>& outputDevices, const QList<DeviceAPOInfo>& inputDevices)
void FilterTable::initialize(QScrollArea* scrollArea, const QList<shared_ptr<AbstractAPOInfo> >& outputDevices, const QList<shared_ptr<AbstractAPOInfo> >& inputDevices)
{
this->scrollArea = scrollArea;
this->outputDevices = outputDevices;
@@ -93,7 +93,7 @@ void FilterTable::initialize(QScrollArea* scrollArea, const QList<DeviceAPOInfo>
factory->initialize(this);
}
void FilterTable::updateDeviceAndChannelMask(DeviceAPOInfo* selectedDevice, int channelMask)
void FilterTable::updateDeviceAndChannelMask(shared_ptr<AbstractAPOInfo> selectedDevice, int channelMask)
{
this->selectedDevice = selectedDevice;
this->selectedChannelMask = channelMask;
@@ -222,7 +222,9 @@ void FilterTable::updateGuis()
void FilterTable::propagateChannels()
{
vector<wstring> channelNames = ChannelHelper::getChannelNames(selectedDevice->channelCount, selectedChannelMask);
vector<wstring> channelNames;
if (selectedDevice != NULL)
channelNames = ChannelHelper::getChannelNames(selectedDevice->getChannelCount(), selectedChannelMask);
for (Item* item : items)
{
@@ -1009,17 +1011,17 @@ const QSet<FilterTable::Item*>& FilterTable::getSelectedItems() const
return selected;
}
const QList<DeviceAPOInfo>& FilterTable::getOutputDevices() const
const QList<shared_ptr<AbstractAPOInfo> >& FilterTable::getOutputDevices() const
{
return outputDevices;
}
const QList<DeviceAPOInfo>& FilterTable::getInputDevices() const
const QList<shared_ptr<AbstractAPOInfo> >& FilterTable::getInputDevices() const
{
return inputDevices;
}
DeviceAPOInfo* FilterTable::getSelectedDevice() const
shared_ptr<AbstractAPOInfo> FilterTable::getSelectedDevice() const
{
return selectedDevice;
}
+8 -8
View File
@@ -56,8 +56,8 @@ public:
};
explicit FilterTable(MainWindow* mainWindow, QWidget* parent = 0);
void initialize(QScrollArea* scrollArea, const QList<DeviceAPOInfo>& outputDevices, const QList<DeviceAPOInfo>& inputDevices);
void updateDeviceAndChannelMask(DeviceAPOInfo* selectedDevice, int selectedChannelMask);
void initialize(QScrollArea* scrollArea, const QList<std::shared_ptr<AbstractAPOInfo> >& outputDevices, const QList<std::shared_ptr<AbstractAPOInfo> >& inputDevices);
void updateDeviceAndChannelMask(std::shared_ptr<AbstractAPOInfo> selectedDevice, int selectedChannelMask);
void updateGuis();
void propagateChannels();
QList<QString> getLines();
@@ -70,9 +70,9 @@ public:
void paste();
void deleteSelectedLines();
const QList<DeviceAPOInfo>& getOutputDevices() const;
const QList<DeviceAPOInfo>& getInputDevices() const;
DeviceAPOInfo* getSelectedDevice() const;
const QList<std::shared_ptr<AbstractAPOInfo> >& getOutputDevices() const;
const QList<std::shared_ptr<AbstractAPOInfo> >& getInputDevices() const;
std::shared_ptr<AbstractAPOInfo> getSelectedDevice() const;
int getSelectedChannelMask() const;
const QSet<Item*>& getSelectedItems() const;
@@ -131,9 +131,9 @@ private:
QList<IFilterGUIFactory*> factories;
bool scrollingNow = false;
QPoint scrollStartPoint;
QList<DeviceAPOInfo> outputDevices;
QList<DeviceAPOInfo> inputDevices;
DeviceAPOInfo* selectedDevice;
QList<std::shared_ptr<AbstractAPOInfo> > outputDevices;
QList<std::shared_ptr<AbstractAPOInfo> > inputDevices;
std::shared_ptr<AbstractAPOInfo> selectedDevice;
int selectedChannelMask;
QString configPath;
int minimumHeightHint = 0;
+39 -39
View File
@@ -51,15 +51,15 @@ using namespace std;
MainWindow::MainWindow(QDir configDir, QWidget* parent)
: QMainWindow(parent), ui(new Ui::MainWindow), configDir(configDir)
{
outputDevices = QList<DeviceAPOInfo>::fromVector(QVector<DeviceAPOInfo>::fromStdVector(DeviceAPOInfo::loadAllInfos(false)));
inputDevices = QList<DeviceAPOInfo>::fromVector(QVector<DeviceAPOInfo>::fromStdVector(DeviceAPOInfo::loadAllInfos(true)));
outputDevices = QList<shared_ptr<AbstractAPOInfo> >::fromVector(QVector<shared_ptr<AbstractAPOInfo> >::fromStdVector(DeviceAPOInfo::loadAllInfos(false)));
inputDevices = QList<shared_ptr<AbstractAPOInfo> >::fromVector(QVector<shared_ptr<AbstractAPOInfo> >::fromStdVector(DeviceAPOInfo::loadAllInfos(true)));
defaultOutputDevice = NULL;
for (DeviceAPOInfo& apoInfo : outputDevices)
for (shared_ptr<AbstractAPOInfo>& apoInfo : outputDevices)
{
if (apoInfo.isDefaultDevice)
if (apoInfo->isDefaultDevice())
{
defaultOutputDevice = &apoInfo;
defaultOutputDevice = apoInfo;
break;
}
}
@@ -106,7 +106,7 @@ MainWindow::MainWindow(QDir configDir, QWidget* parent)
QStandardItemModel* model = qobject_cast<QStandardItemModel*>(deviceComboBox->model());
if (defaultOutputDevice != NULL)
deviceComboBox->addItem(tr("Default") + " (" + QString::fromStdWString(defaultOutputDevice->connectionName) + " - " + QString::fromStdWString(defaultOutputDevice->deviceName) + ")", NULL);
deviceComboBox->addItem(tr("Default") + " (" + QString::fromStdWString(defaultOutputDevice->getConnectionName()) + " - " + QString::fromStdWString(defaultOutputDevice->getDeviceName()) + ")", NULL);
deviceComboBox->addItem(tr("Playback devices:"));
QStandardItem* item = model->item(model->rowCount() - 1);
@@ -115,18 +115,18 @@ MainWindow::MainWindow(QDir configDir, QWidget* parent)
item->setFont(font);
item->setSelectable(false);
for (DeviceAPOInfo& apoInfo : outputDevices)
if (apoInfo.isInstalled)
deviceComboBox->addItem(QString::fromStdWString(apoInfo.connectionName) + " - " + QString::fromStdWString(apoInfo.deviceName), QVariant::fromValue(&apoInfo));
for (shared_ptr<AbstractAPOInfo>& apoInfo : outputDevices)
if (apoInfo->isInstalled())
deviceComboBox->addItem(QString::fromStdWString(apoInfo->getConnectionName()) + " - " + QString::fromStdWString(apoInfo->getDeviceName()), QVariant::fromValue(apoInfo));
deviceComboBox->addItem(tr("Capture devices:"));
item = model->item(model->rowCount() - 1);
item->setFont(font);
item->setSelectable(false);
for (DeviceAPOInfo& apoInfo : inputDevices)
if (apoInfo.isInstalled)
deviceComboBox->addItem(QString::fromStdWString(apoInfo.connectionName) + " - " + QString::fromStdWString(apoInfo.deviceName), QVariant::fromValue(&apoInfo));
for (shared_ptr<AbstractAPOInfo>& apoInfo : inputDevices)
if (apoInfo->isInstalled())
deviceComboBox->addItem(QString::fromStdWString(apoInfo->getConnectionName()) + " - " + QString::fromStdWString(apoInfo->getDeviceName()), QVariant::fromValue(apoInfo));
connect(channelConfigurationComboBox, SIGNAL(activated(int)), this, SLOT(channelConfigurationSelected(int)));
@@ -183,7 +183,7 @@ void MainWindow::doChecks()
}
}
if (!defaultOutputDevice->isInstalled)
if (defaultOutputDevice != NULL && !defaultOutputDevice->isInstalled())
{
if (QMessageBox::warning(this, tr("APO not installed to device"), tr("Equalizer APO has not been installed to the selected device.\nDo you want to run the Configurator application to fix the problem?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{
@@ -192,23 +192,23 @@ void MainWindow::doChecks()
}
}
DeviceAPOInfo* disabledApoInfo = NULL;
for (DeviceAPOInfo& apoInfo : outputDevices)
AbstractAPOInfo* disabledApoInfo = NULL;
for (shared_ptr<AbstractAPOInfo>& apoInfo : outputDevices)
{
if (apoInfo.isInstalled && apoInfo.isEnhancementsDisabled)
if (apoInfo->isInstalled() && apoInfo->isEnhancementsDisabled())
{
disabledApoInfo = &apoInfo;
disabledApoInfo = apoInfo.get();
break;
}
}
if (disabledApoInfo == NULL)
{
for (DeviceAPOInfo& apoInfo : inputDevices)
for (shared_ptr<AbstractAPOInfo>& apoInfo : inputDevices)
{
if (apoInfo.isInstalled && apoInfo.isEnhancementsDisabled)
if (apoInfo->isInstalled() && apoInfo->isEnhancementsDisabled())
{
disabledApoInfo = &apoInfo;
disabledApoInfo = apoInfo.get();
break;
}
}
@@ -216,7 +216,7 @@ void MainWindow::doChecks()
if (disabledApoInfo != NULL)
{
if (QMessageBox::warning(this, tr("Audio enhancements disabled"), tr("Audio enhancements are not enabled for the device\n%0 %1.\nDo you want to run the Configurator application to fix the problem?").arg(QString::fromStdWString(disabledApoInfo->connectionName)).arg(QString::fromStdWString(disabledApoInfo->deviceName)), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
if (QMessageBox::warning(this, tr("Audio enhancements disabled"), tr("Audio enhancements are not enabled for the device\n%0 %1.\nDo you want to run the Configurator application to fix the problem?").arg(QString::fromStdWString(disabledApoInfo->getConnectionName())).arg(QString::fromStdWString(disabledApoInfo->getDeviceName())), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{
runConfigurator();
return;
@@ -402,7 +402,7 @@ void MainWindow::closeEvent(QCloseEvent* event)
void MainWindow::deviceSelected(int index)
{
DeviceAPOInfo* apoInfo = deviceComboBox->itemData(index).value<DeviceAPOInfo*>();
shared_ptr<AbstractAPOInfo> apoInfo = deviceComboBox->itemData(index).value<shared_ptr<AbstractAPOInfo> >();
if (apoInfo == NULL)
apoInfo = defaultOutputDevice;
@@ -415,7 +415,7 @@ void MainWindow::deviceSelected(int index)
const GUIChannelHelper::ChannelConfigurationInfo* selectedInfo = NULL;
for (const GUIChannelHelper::ChannelConfigurationInfo& info : infos)
{
if (info.channelMask == apoInfo->channelMask)
if (info.channelMask == apoInfo->getChannelMask())
{
selectedInfo = &info;
break;
@@ -425,7 +425,7 @@ void MainWindow::deviceSelected(int index)
if (selectedInfo != NULL)
channelConfigurationComboBox->addItem(tr("From device") + " (" + selectedInfo->name + ")", 0);
else
channelConfigurationComboBox->addItem(tr("From device") + " (" + apoInfo->channelCount + " channels)", 0);
channelConfigurationComboBox->addItem(tr("From device") + " (" + apoInfo->getChannelCount() + " channels)", 0);
}
for (const GUIChannelHelper::ChannelConfigurationInfo& info : infos)
@@ -436,7 +436,7 @@ void MainWindow::deviceSelected(int index)
void MainWindow::channelConfigurationSelected(int index)
{
DeviceAPOInfo* selectedDevice;
shared_ptr<AbstractAPOInfo> selectedDevice;
int channelMask;
getDeviceAndChannelMask(&selectedDevice, &channelMask);
@@ -451,8 +451,8 @@ void MainWindow::channelConfigurationSelected(int index)
if (selectedDevice != NULL)
{
unsigned channelCount = selectedDevice->channelCount;
if (channelMask != 0 && channelMask != selectedDevice->channelMask)
unsigned channelCount = selectedDevice->getChannelCount();
if (channelMask != 0 && channelMask != selectedDevice->getChannelMask())
{
channelCount = 0;
for (int i = 0; i < 31; i++)
@@ -816,7 +816,7 @@ FilterTable* MainWindow::addTab(QString title, QString tooltip, QString configPa
filterTable->setAcceptDrops(true);
filterTable->setFocusPolicy(Qt::WheelFocus);
DeviceAPOInfo* selectedDevice;
shared_ptr<AbstractAPOInfo> selectedDevice;
int channelMask;
getDeviceAndChannelMask(&selectedDevice, &channelMask);
filterTable->updateDeviceAndChannelMask(selectedDevice, channelMask);
@@ -829,19 +829,19 @@ FilterTable* MainWindow::addTab(QString title, QString tooltip, QString configPa
return filterTable;
}
void MainWindow::getDeviceAndChannelMask(DeviceAPOInfo** selectedDevice, int* channelMask)
void MainWindow::getDeviceAndChannelMask(shared_ptr<AbstractAPOInfo>* selectedDevice, int* channelMask)
{
*selectedDevice = deviceComboBox->currentData().value<DeviceAPOInfo*>();
*selectedDevice = deviceComboBox->currentData().value<shared_ptr<AbstractAPOInfo> >();
if (*selectedDevice == NULL)
*selectedDevice = defaultOutputDevice;
*channelMask = channelConfigurationComboBox->currentData().toInt();
if (*channelMask == 0 && selectedDevice != NULL)
{
*channelMask = (*selectedDevice)->channelMask;
*channelMask = (*selectedDevice)->getChannelMask();
if (*channelMask == 0)
*channelMask = ChannelHelper::getDefaultChannelMask((*selectedDevice)->channelCount);
*channelMask = ChannelHelper::getDefaultChannelMask((*selectedDevice)->getChannelCount());
}
}
@@ -894,7 +894,7 @@ bool MainWindow::askForClose(int tabIndex)
void MainWindow::startAnalysis()
{
DeviceAPOInfo* selectedDevice;
shared_ptr<AbstractAPOInfo> selectedDevice;
int channelMask;
getDeviceAndChannelMask(&selectedDevice, &channelMask);
@@ -933,15 +933,15 @@ void MainWindow::loadPreferences()
if (stateValue.isValid())
restoreState(stateValue.toByteArray());
instantModeCheckBox->setChecked(settings.value("instantMode", true).toBool());
QString selectedDeviceGuid = settings.value("selectedDeviceGuid").toString();
if (!selectedDeviceGuid.isEmpty())
QString selectedDevice = settings.value("selectedDevice").toString();
if (!selectedDevice.isEmpty())
{
for (int i = 0; i < deviceComboBox->count(); i++)
{
DeviceAPOInfo* apoInfo = deviceComboBox->itemData(i).value<DeviceAPOInfo*>();
shared_ptr<AbstractAPOInfo> apoInfo = deviceComboBox->itemData(i).value<shared_ptr<AbstractAPOInfo> >();
if (apoInfo != NULL)
{
if (QString::fromStdWString(apoInfo->deviceGuid).compare(selectedDeviceGuid, Qt::CaseInsensitive) == 0)
if (QString::fromStdWString(apoInfo->getDeviceString()).compare(selectedDevice, Qt::CaseInsensitive) == 0)
{
deviceComboBox->setCurrentIndex(i);
break;
@@ -1012,8 +1012,8 @@ void MainWindow::savePreferences()
settings.setValue("geometry", saveGeometry());
settings.setValue("windowState", saveState());
settings.setValue("instantMode", instantModeCheckBox->isChecked());
DeviceAPOInfo* selectedDevice = deviceComboBox->currentData().value<DeviceAPOInfo*>();
settings.setValue("selectedDeviceGuid", selectedDevice != NULL ? QString::fromStdWString(selectedDevice->deviceGuid) : "");
shared_ptr<AbstractAPOInfo> selectedDevice = deviceComboBox->currentData().value<shared_ptr<AbstractAPOInfo> >();
settings.setValue("selectedDevice", selectedDevice != NULL ? QString::fromStdWString(selectedDevice->getDeviceString()) : "");
int channelMask = channelConfigurationComboBox->currentData().toInt();
settings.setValue("selectedChannelMask", channelMask);
+5 -5
View File
@@ -91,7 +91,7 @@ private slots:
private:
FilterTable* addTab(QString title, QString tooltip, QString configPath, QList<QString> lines);
void getDeviceAndChannelMask(DeviceAPOInfo** selectedDevice, int* channelMask);
void getDeviceAndChannelMask(std::shared_ptr<AbstractAPOInfo>* selectedDevice, int* channelMask);
bool askForClose(int tabIndex);
void startAnalysis();
void loadPreferences();
@@ -104,9 +104,9 @@ private:
QCheckBox* instantModeCheckBox;
QComboBox* deviceComboBox;
QComboBox* channelConfigurationComboBox;
QList<DeviceAPOInfo> outputDevices;
QList<DeviceAPOInfo> inputDevices;
DeviceAPOInfo* defaultOutputDevice;
QList<std::shared_ptr<AbstractAPOInfo> > outputDevices;
QList<std::shared_ptr<AbstractAPOInfo> > inputDevices;
std::shared_ptr<AbstractAPOInfo> defaultOutputDevice;
AnalysisPlotScene* analysisPlotScene;
AnalysisThread* analysisThread;
bool restart = false;
@@ -115,4 +115,4 @@ private:
QStringList recentFiles;
};
Q_DECLARE_METATYPE(DeviceAPOInfo*)
Q_DECLARE_METATYPE(std::shared_ptr<AbstractAPOInfo>)
+7 -1
View File
@@ -22,13 +22,19 @@
#include "ConvolutionFilterGUI.h"
#include "ConvolutionFilterGUIFactory.h"
using namespace std;
ConvolutionFilterGUIFactory::ConvolutionFilterGUIFactory()
{
}
void ConvolutionFilterGUIFactory::initialize(FilterTable* filterTable)
{
deviceSampleRate = filterTable->getSelectedDevice()->sampleRate;
shared_ptr<AbstractAPOInfo> selectedDevice = filterTable->getSelectedDevice();
if (selectedDevice != NULL)
deviceSampleRate = filterTable->getSelectedDevice()->getSampleRate();
else
deviceSampleRate = 0;
}
QList<FilterTemplate> ConvolutionFilterGUIFactory::createFilterTemplates()
+23 -10
View File
@@ -21,6 +21,7 @@
#include "DeviceFilterGUI.h"
#include "DeviceFilterGUIDialog.h"
#include <filters/DeviceFilterFactory.h>
#include <VoicemeeterAPOInfo.h>
#include "ui_DeviceFilterGUI.h"
using namespace std;
@@ -63,27 +64,39 @@ void DeviceFilterGUI::load(const QString& parameters)
}
else
{
const QList<DeviceAPOInfo>& devices = factory->getDevices();
for (const DeviceAPOInfo& apoInfo : devices)
const QList<shared_ptr<AbstractAPOInfo> >& devices = factory->getDevices();
bool anyInstalled = false;
for (const shared_ptr<AbstractAPOInfo>& apoInfo : devices)
{
if (!apoInfo.isInstalled)
if (apoInfo->isInstalled() && DeviceFilterFactory::matchDevice(apoInfo->getDeviceString(), pattern.toStdWString()))
{
anyInstalled = true;
break;
}
}
for (const shared_ptr<AbstractAPOInfo>& apoInfo : devices)
{
if (anyInstalled && !apoInfo->isInstalled())
continue;
wstring deviceString = apoInfo.connectionName + L" " + apoInfo.deviceName + L" " + apoInfo.deviceGuid;
if (DeviceFilterFactory::matchDevice(deviceString, pattern.toStdWString()))
if (DeviceFilterFactory::matchDevice(apoInfo->getDeviceString(), pattern.toStdWString()))
{
QStringList values;
if (apoInfo.isInput)
if (apoInfo->isInput())
values.append(tr("Capture"));
else
values.append(tr("Playback"));
values.append(QString::fromStdWString(apoInfo.connectionName));
values.append(QString::fromStdWString(apoInfo.deviceName));
values.append(QString::fromStdWString(apoInfo->getConnectionName()));
values.append(QString::fromStdWString(apoInfo->getDeviceName()));
QString state;
if (apoInfo.isInstalled)
if (apoInfo->isInstalled())
state = tr("APO installed");
else
state = tr("APO not installed");
VoicemeeterAPOInfo* voicemeeterInfo = dynamic_cast<VoicemeeterAPOInfo*>(apoInfo.get());
if (voicemeeterInfo != NULL && !voicemeeterInfo->isVoicemeeterInstalled())
state += ", " + tr("Voicemeeter was uninstalled");
values.append(state);
lastItem = new QTreeWidgetItem(ui->treeWidget, values);
}
@@ -93,7 +106,7 @@ void DeviceFilterGUI::load(const QString& parameters)
{
QStringList values;
values.append("");
values.append(tr("No device matched!"));
values.append(tr("No device matched") + " \"" + pattern.trimmed() + "\"");
values.append("");
QTreeWidgetItem* item = new QTreeWidgetItem(ui->treeWidget, values);
+18 -16
View File
@@ -22,6 +22,7 @@
#include "ui_DeviceFilterGUIDialog.h"
#include <filters/DeviceFilterFactory.h>
#include <VoicemeeterAPOInfo.h>
using namespace std;
@@ -44,26 +45,28 @@ DeviceFilterGUIDialog::DeviceFilterGUIDialog(DeviceFilterGUI* gui, DeviceFilterG
outputNode->setExpanded(true);
QTreeWidgetItem* inputNode = new QTreeWidgetItem(ui->treeWidget, QStringList(tr("Capture devices")));
inputNode->setExpanded(true);
const QList<DeviceAPOInfo>& devices = factory->getDevices();
for (const DeviceAPOInfo& apoInfo : devices)
const QList<shared_ptr<AbstractAPOInfo> >& devices = factory->getDevices();
for (const shared_ptr<AbstractAPOInfo>& apoInfo : devices)
{
QStringList values;
values.append(QString::fromStdWString(apoInfo.connectionName));
values.append(QString::fromStdWString(apoInfo.deviceName));
values.append(QString::fromStdWString(apoInfo->getConnectionName()));
values.append(QString::fromStdWString(apoInfo->getDeviceName()));
QString state;
if (apoInfo.isInstalled)
if (apoInfo->isInstalled())
state = tr("APO installed");
else
state = tr("APO not installed");
VoicemeeterAPOInfo* voicemeeterInfo = dynamic_cast<VoicemeeterAPOInfo*>(apoInfo.get());
if (voicemeeterInfo != NULL && !voicemeeterInfo->isVoicemeeterInstalled())
state += ", " + tr("Voicemeeter was uninstalled");
values.append(state);
QTreeWidgetItem* item = new QTreeWidgetItem(apoInfo.isInput ? inputNode : outputNode, values);
QTreeWidgetItem* item = new QTreeWidgetItem(apoInfo->isInput() ? inputNode : outputNode, values);
wstring deviceString = apoInfo.connectionName + L" " + apoInfo.deviceName + L" " + apoInfo.deviceGuid;
bool matches = !all && DeviceFilterFactory::matchDevice(deviceString, pattern.toStdWString());
bool matches = !all && DeviceFilterFactory::matchDevice(apoInfo->getDeviceString(), pattern.toStdWString());
item->setCheckState(0, matches ? Qt::Checked : Qt::Unchecked);
item->setData(0, Qt::UserRole, QVariant::fromValue(&apoInfo));
item->setHidden(!matches && !apoInfo.isInstalled && ui->showOnlyInstalledCheckBox->isChecked());
if (!apoInfo.isInstalled)
item->setData(0, Qt::UserRole, QVariant::fromValue(apoInfo));
item->setHidden(!matches && !apoInfo->isInstalled() && ui->showOnlyInstalledCheckBox->isChecked());
if (!apoInfo->isInstalled())
for (int i = 0; i < ui->treeWidget->columnCount(); i++)
item->setForeground(i, QBrush(Qt::gray));
}
@@ -96,9 +99,8 @@ QString DeviceFilterGUIDialog::getPattern()
{
if (pattern != "")
pattern += "; ";
const DeviceAPOInfo* apoInfo = item->data(0, Qt::UserRole).value<const DeviceAPOInfo*>();
wstring deviceString = apoInfo->connectionName + L" " + apoInfo->deviceName + L" " + apoInfo->deviceGuid;
pattern += QString::fromStdWString(deviceString);
shared_ptr<AbstractAPOInfo> apoInfo = item->data(0, Qt::UserRole).value<shared_ptr<AbstractAPOInfo> >();
pattern += QString::fromStdWString(apoInfo->getDeviceString());
}
}
}
@@ -120,8 +122,8 @@ void DeviceFilterGUIDialog::on_showOnlyInstalledCheckBox_toggled(bool checked)
for (int j = 0; j < groupItem->childCount(); j++)
{
QTreeWidgetItem* item = groupItem->child(j);
const DeviceAPOInfo* apoInfo = item->data(0, Qt::UserRole).value<const DeviceAPOInfo*>();
item->setHidden(item->checkState(0) != Qt::Checked && !apoInfo->isInstalled && checked);
shared_ptr<AbstractAPOInfo> apoInfo = item->data(0, Qt::UserRole).value<shared_ptr<AbstractAPOInfo> >();
item->setHidden(item->checkState(0) != Qt::Checked && !apoInfo->isInstalled() && checked);
}
}
+1 -1
View File
@@ -47,4 +47,4 @@ private:
Ui::DeviceFilterGUIDialog* ui;
};
Q_DECLARE_METATYPE(const DeviceAPOInfo*)
Q_DECLARE_METATYPE(std::shared_ptr<AbstractAPOInfo>)
+3 -1
View File
@@ -21,6 +21,8 @@
#include "DeviceFilterGUI.h"
#include "DeviceFilterGUIFactory.h"
using namespace std;
DeviceFilterGUIFactory::DeviceFilterGUIFactory()
{
}
@@ -51,7 +53,7 @@ IFilterGUI* DeviceFilterGUIFactory::createFilterGUI(QString& command, QString& p
return result;
}
const QList<DeviceAPOInfo>& DeviceFilterGUIFactory::getDevices() const
const QList<shared_ptr<AbstractAPOInfo> >& DeviceFilterGUIFactory::getDevices() const
{
return devices;
}
+2 -2
View File
@@ -34,8 +34,8 @@ public:
QList<FilterTemplate> createFilterTemplates() override;
IFilterGUI* createFilterGUI(QString& command, QString& parameters) override;
const QList<DeviceAPOInfo>& getDevices() const;
const QList<std::shared_ptr<AbstractAPOInfo> >& getDevices() const;
private:
QList<DeviceAPOInfo> devices;
QList<std::shared_ptr<AbstractAPOInfo> > devices;
};
Binary file not shown.
+36 -22
View File
@@ -354,12 +354,12 @@ Wählen Sie eine andere Datei oder ändern Sie die Konfiguration des Geräts.</t
<translation type="vanished">Convolution (Faltung mit Impulsantwort)</translation>
</message>
<message>
<location filename="../guis/ConvolutionFilterGUIFactory.cpp" line="37"/>
<location filename="../guis/ConvolutionFilterGUIFactory.cpp" line="43"/>
<source>Advanced filters</source>
<translation>Fortgeschrittene Filter</translation>
</message>
<message>
<location filename="../guis/ConvolutionFilterGUIFactory.cpp" line="37"/>
<location filename="../guis/ConvolutionFilterGUIFactory.cpp" line="43"/>
<source>Convolution (Convolution with impulse response)</source>
<translation>Convolution (Faltung mit Impulsantwort)</translation>
</message>
@@ -524,54 +524,63 @@ Wählen Sie eine andere Datei oder ändern Sie die Konfiguration des Geräts.</t
<translation>Ändern...</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUI.cpp" line="47"/>
<location filename="../guis/DeviceFilterGUI.cpp" line="48"/>
<source>Type</source>
<translation>Typ</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUI.cpp" line="48"/>
<location filename="../guis/DeviceFilterGUI.cpp" line="49"/>
<source>Connection</source>
<translation>Anschluss</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUI.cpp" line="49"/>
<location filename="../guis/DeviceFilterGUI.cpp" line="50"/>
<source>Device</source>
<translation>Gerät</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUI.cpp" line="50"/>
<location filename="../guis/DeviceFilterGUI.cpp" line="51"/>
<source>State</source>
<translation>Status</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUI.cpp" line="59"/>
<location filename="../guis/DeviceFilterGUI.cpp" line="60"/>
<source>All devices</source>
<translation>Alle Geräte</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUI.cpp" line="77"/>
<location filename="../guis/DeviceFilterGUI.cpp" line="87"/>
<source>Capture</source>
<translation>Aufnahme</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUI.cpp" line="79"/>
<location filename="../guis/DeviceFilterGUI.cpp" line="89"/>
<source>Playback</source>
<translation>Wiedergabe</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUI.cpp" line="84"/>
<location filename="../guis/DeviceFilterGUI.cpp" line="94"/>
<source>APO installed</source>
<translation>APO installiert</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUI.cpp" line="86"/>
<location filename="../guis/DeviceFilterGUI.cpp" line="96"/>
<source>APO not installed</source>
<translation>APO nicht installiert</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUI.cpp" line="96"/>
<location filename="../guis/DeviceFilterGUI.cpp" line="99"/>
<source>Voicemeeter was uninstalled</source>
<translation>Voicemeeter wurde deinstalliert</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUI.cpp" line="109"/>
<source>No device matched</source>
<translation>Kein Gerät passt zu</translation>
</message>
<message>
<source>No device matched!</source>
<translation>Kein Gerät stimmt überein!</translation>
<translation type="vanished">Kein Gerät stimmt überein!</translation>
</message>
</context>
<context>
@@ -592,40 +601,45 @@ Wählen Sie eine andere Datei oder ändern Sie die Konfiguration des Geräts.</t
<translation>Nur Geräte mit installiertem APO zeigen</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="39"/>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="40"/>
<source>Connection</source>
<translation>Anschluss</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="40"/>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="41"/>
<source>Device</source>
<translation>Gerät</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="41"/>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="42"/>
<source>State</source>
<translation>Status</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="43"/>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="44"/>
<source>Playback devices</source>
<translation>Wiedergabegeräte</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="45"/>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="46"/>
<source>Capture devices</source>
<translation>Aufnahmegeräte</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="55"/>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="56"/>
<source>APO installed</source>
<translation>APO installiert</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="57"/>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="58"/>
<source>APO not installed</source>
<translation>APO nicht installiert</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUIDialog.cpp" line="61"/>
<source>Voicemeeter was uninstalled</source>
<translation>Voicemeeter wurde deinstalliert</translation>
</message>
</context>
<context>
<name>DeviceFilterGUIFactory</name>
@@ -634,12 +648,12 @@ Wählen Sie eine andere Datei oder ändern Sie die Konfiguration des Geräts.</t
<translation type="vanished">Device (Gerät auswählen)</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUIFactory.cpp" line="37"/>
<location filename="../guis/DeviceFilterGUIFactory.cpp" line="39"/>
<source>Control</source>
<translation>Steuerung</translation>
</message>
<message>
<location filename="../guis/DeviceFilterGUIFactory.cpp" line="37"/>
<location filename="../guis/DeviceFilterGUIFactory.cpp" line="39"/>
<source>Device (Select device)</source>
<translation>Device (Gerät auswählen)</translation>
</message>
+4 -4
View File
@@ -138,14 +138,14 @@ HRESULT EqualizerAPO::Initialize(UINT32 cbDataSize, BYTE* pbyData)
DeviceAPOInfo apoInfo;
if (apoInfo.load(deviceGuid))
{
engine.setDeviceInfo(apoInfo.isInput, apoInfo.currentInstallState.installPostMix, apoInfo.deviceName, apoInfo.connectionName, apoInfo.deviceGuid);
engine.setDeviceInfo(apoInfo.isInput(), apoInfo.getCurrentInstallState().installPostMix, apoInfo.getDeviceName(), apoInfo.getConnectionName(), apoInfo.getDeviceGuid(), apoInfo.getDeviceString());
if (apoGuid == EQUALIZERAPO_PRE_MIX_GUID)
childApoGuid = apoInfo.preMixChildGuid;
childApoGuid = apoInfo.getPreMixChildGuid();
else
childApoGuid = apoInfo.postMixChildGuid;
childApoGuid = apoInfo.getPostMixChildGuid();
allowSilentBufferModification = apoInfo.currentInstallState.allowSilentBufferModification;
allowSilentBufferModification = apoInfo.getCurrentInstallState().allowSilentBufferModification;
}
}
catch (RegistryException e)
BIN
View File
Binary file not shown.
+10
View File
@@ -12,6 +12,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Configurator", "Configurato
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Benchmark", "Benchmark\Benchmark.vcxproj", "{D4474852-5724-4253-95C6-7A6DC424F194}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VoicemeeterClient", "VoicemeeterClient\VoicemeeterClient.vcxproj", "{10F1DD37-EA50-46C2-810D-D01A1A0D4D2F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -44,6 +46,14 @@ Global
{D4474852-5724-4253-95C6-7A6DC424F194}.Release|Win32.Build.0 = Release|Win32
{D4474852-5724-4253-95C6-7A6DC424F194}.Release|x64.ActiveCfg = Release|x64
{D4474852-5724-4253-95C6-7A6DC424F194}.Release|x64.Build.0 = Release|x64
{10F1DD37-EA50-46C2-810D-D01A1A0D4D2F}.Debug|Win32.ActiveCfg = Debug|Win32
{10F1DD37-EA50-46C2-810D-D01A1A0D4D2F}.Debug|Win32.Build.0 = Debug|Win32
{10F1DD37-EA50-46C2-810D-D01A1A0D4D2F}.Debug|x64.ActiveCfg = Debug|x64
{10F1DD37-EA50-46C2-810D-D01A1A0D4D2F}.Debug|x64.Build.0 = Debug|x64
{10F1DD37-EA50-46C2-810D-D01A1A0D4D2F}.Release|Win32.ActiveCfg = Release|Win32
{10F1DD37-EA50-46C2-810D-D01A1A0D4D2F}.Release|Win32.Build.0 = Release|Win32
{10F1DD37-EA50-46C2-810D-D01A1A0D4D2F}.Release|x64.ActiveCfg = Release|x64
{10F1DD37-EA50-46C2-810D-D01A1A0D4D2F}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+6
View File
@@ -162,6 +162,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="AbstractAPOInfo.h" />
<ClInclude Include="ClassFactory.h" />
<ClInclude Include="DeviceAPOInfo.h" />
<ClInclude Include="EqualizerAPO.h" />
@@ -195,7 +196,9 @@
<ClInclude Include="helpers\MemoryHelper.h" />
<ClInclude Include="helpers\PrecisionTimer.h" />
<ClInclude Include="helpers\RegistryHelper.h" />
<ClInclude Include="helpers\ScopeGuard.h" />
<ClInclude Include="helpers\StringHelper.h" />
<ClInclude Include="helpers\UncaughtExceptions.h" />
<ClInclude Include="IFilter.h" />
<ClInclude Include="IFilterFactory.h" />
<ClInclude Include="libHybridConv-0.1.1\libHybridConv_eapo.h" />
@@ -205,8 +208,10 @@
<ClInclude Include="resource.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="version.h" />
<ClInclude Include="VoicemeeterAPOInfo.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="AbstractAPOInfo.cpp" />
<ClCompile Include="ClassFactory.cpp" />
<ClCompile Include="DeviceAPOInfo.cpp" />
<ClCompile Include="DllMain.cpp" />
@@ -252,6 +257,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="VoicemeeterAPOInfo.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="EqualizerAPO.def" />
+10
View File
@@ -105,6 +105,8 @@
<Filter>filters</Filter>
</ClCompile>
<ClCompile Include="stdafx.cpp" />
<ClCompile Include="AbstractAPOInfo.cpp" />
<ClCompile Include="VoicemeeterAPOInfo.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="ClassFactory.h" />
@@ -216,6 +218,14 @@
<Filter>filters</Filter>
</ClInclude>
<ClInclude Include="stdafx.h" />
<ClInclude Include="AbstractAPOInfo.h" />
<ClInclude Include="helpers\ScopeGuard.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="helpers\UncaughtExceptions.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="VoicemeeterAPOInfo.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="EqualizerAPO.rc" />
BIN
View File
Binary file not shown.
+36 -1
View File
@@ -75,7 +75,7 @@ FilterConfiguration::~FilterConfiguration()
}
#pragma AVRT_CODE_BEGIN
void FilterConfiguration::process(float* input, unsigned frameCount)
void FilterConfiguration::read(float* input, unsigned frameCount)
{
#define DEINTERLEAVE_MACRO(ccount)\
{\
@@ -107,7 +107,16 @@ void FilterConfiguration::process(float* input, unsigned frameCount)
default:
DEINTERLEAVE_MACRO(realChannelCount)
}
}
void FilterConfiguration::read(float** input, unsigned frameCount)
{
for (unsigned c = 0; c < realChannelCount; c++)
memcpy(allSamples[c], input[c], frameCount * sizeof(float));
}
void FilterConfiguration::process(unsigned frameCount)
{
for (unsigned c = realChannelCount; c < allChannelCount; c++)
memset(allSamples[c], 0, frameCount * sizeof(float));
@@ -142,6 +151,26 @@ void FilterConfiguration::process(float* input, unsigned frameCount)
}
}
unsigned FilterConfiguration::doTransition(FilterConfiguration* nextConfig, unsigned frameCount, unsigned transitionCounter, unsigned transitionLength)
{
float** currentSamples = allSamples;
float** nextSamples = nextConfig->allSamples;
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++;
}
return transitionCounter;
}
void FilterConfiguration::write(float* output, unsigned frameCount)
{
#define INTERLEAVE_MACRO(ccount)\
@@ -173,6 +202,12 @@ void FilterConfiguration::write(float* output, unsigned frameCount)
INTERLEAVE_MACRO(outputChannelCount)
}
}
void FilterConfiguration::write(float** output, unsigned frameCount)
{
for (unsigned i = 0; i < outputChannelCount; i++)
memcpy(output[i], allSamples[i], frameCount * sizeof(float));
}
#pragma AVRT_CODE_END
bool FilterConfiguration::isEmpty()
+5 -1
View File
@@ -43,8 +43,12 @@ public:
FilterConfiguration(FilterEngine* engine, const std::vector<FilterInfo*>& filterInfos, unsigned allChannelCount);
~FilterConfiguration();
void process(float* input, unsigned frameCount);
void read(float* input, unsigned frameCount);
void read(float** input, unsigned frameCount);
void process(unsigned frameCount);
unsigned doTransition(FilterConfiguration* nextConfig, unsigned frameCount, unsigned transitionCounter, unsigned transitionLength);
void write(float* output, unsigned frameCount);
void write(float** output, unsigned frameCount);
float** getOutputSamples() {return allSamples;}
bool isEmpty();
+43 -14
View File
@@ -118,13 +118,14 @@ void FilterEngine::setPreMix(bool preMix)
this->preMix = preMix;
}
void FilterEngine::setDeviceInfo(bool capture, bool postMixInstalled, const wstring& deviceName, const wstring& connectionName, const wstring& deviceGuid)
void FilterEngine::setDeviceInfo(bool capture, bool postMixInstalled, const wstring& deviceName, const wstring& connectionName, const wstring& deviceGuid, const wstring& deviceString)
{
this->capture = capture;
this->postMixInstalled = postMixInstalled;
this->deviceName = deviceName;
this->connectionName = connectionName;
this->deviceGuid = deviceGuid;
this->deviceString = deviceString;
}
void FilterEngine::initialize(float sampleRate, unsigned inputChannelCount, unsigned realChannelCount, unsigned outputChannelCount, unsigned channelMask, unsigned maxFrameCount, const wstring& customPath)
@@ -268,7 +269,7 @@ void FilterEngine::loadConfigFile(const wstring& path)
DWORD error = GetLastError();
if (error != ERROR_SHARING_VIOLATION)
{
LogF(L"Error while reading configuration file: %s", StringHelper::getSystemErrorString(error).c_str());
LogF(L"Error while reading configuration file %s: %s", path.c_str(), StringHelper::getSystemErrorString(error).c_str());
return;
}
@@ -377,27 +378,55 @@ void FilterEngine::process(float* output, float* input, unsigned frameCount)
}
}
currentConfig->process(input, frameCount);
currentConfig->read(input, frameCount);
currentConfig->process(frameCount);
if (nextConfig != NULL)
{
nextConfig->process(input, frameCount);
float** currentSamples = currentConfig->getOutputSamples();
float** nextSamples = nextConfig->getOutputSamples();
nextConfig->read(input, frameCount);
nextConfig->process(frameCount);
transitionCounter = currentConfig->doTransition(nextConfig, frameCount, transitionCounter, transitionLength);
}
for (unsigned f = 0; f < frameCount; f++)
currentConfig->write(output, frameCount);
if (nextConfig != NULL && transitionCounter >= transitionLength)
{
previousConfig = currentConfig;
currentConfig = nextConfig;
nextConfig = NULL;
transitionCounter = 0;
ReleaseSemaphore(loadSemaphore, 1, NULL);
}
}
void FilterEngine::process(float** output, float** input, unsigned frameCount)
{
if (currentConfig->isEmpty() && nextConfig == NULL)
{
// avoid double copying cost if no processing will happen anyway
if (realChannelCount == outputChannelCount)
{
float factor = 0.5f * (1.0f - cos(transitionCounter * (float)M_PI / transitionLength));
if (transitionCounter >= transitionLength)
factor = 1.0f;
if (input != output)
{
for (unsigned c = 0; c < realChannelCount; c++)
memcpy(output[c], input[c], frameCount * sizeof(float));
}
for (unsigned c = 0; c < outputChannelCount; c++)
currentSamples[c][f] = currentSamples[c][f] * (1 - factor) + nextSamples[c][f] * factor;
transitionCounter++;
return;
}
}
currentConfig->read(input, frameCount);
currentConfig->process(frameCount);
if (nextConfig != NULL)
{
nextConfig->read(input, frameCount);
nextConfig->process(frameCount);
transitionCounter = currentConfig->doTransition(nextConfig, frameCount, transitionCounter, transitionLength);
}
currentConfig->write(output, frameCount);
if (nextConfig != NULL && transitionCounter >= transitionLength)
+4 -1
View File
@@ -39,12 +39,13 @@ public:
~FilterEngine();
void setPreMix(bool preMix);
void setDeviceInfo(bool capture, bool postMixInstalled, const std::wstring& deviceName, const std::wstring& connectionName, const std::wstring& deviceGuid);
void setDeviceInfo(bool capture, bool postMixInstalled, const std::wstring& deviceName, const std::wstring& connectionName, const std::wstring& deviceGuid, const std::wstring& deviceString);
void initialize(float sampleRate, unsigned inputChannelCount, unsigned realChannelCount, unsigned outputChannelCount, unsigned channelMask, unsigned maxFrameCount, const std::wstring& customPath = L"");
void loadConfig(const std::wstring& customPath = L"");
void loadConfigFile(const std::wstring& path);
void watchRegistryKey(const std::wstring& key);
void process(float* output, float* input, unsigned frameCount);
void process(float** output, float** input, unsigned frameCount);
bool isPreMix() const {return preMix;}
bool isCapture() const {return capture;}
@@ -52,6 +53,7 @@ public:
std::wstring getDeviceName() const {return deviceName;}
std::wstring getConnectionName() const {return connectionName;}
std::wstring getDeviceGuid() const {return deviceGuid;}
std::wstring getDeviceString() const {return deviceString;}
unsigned getInputChannelCount() const {return inputChannelCount;}
unsigned getRealChannelCount() const {return realChannelCount;}
unsigned getOutputChannelCount() const {return outputChannelCount;}
@@ -73,6 +75,7 @@ private:
std::wstring deviceName;
std::wstring connectionName;
std::wstring deviceGuid;
std::wstring deviceString;
std::wstring configPath;
float sampleRate;
// number of input channels that originally existed before child APO processing
+3
View File
@@ -115,10 +115,12 @@ Section "Install" SecInstall
!insertmacro RenameAndDelete "$INSTDIR\msvcr100.dll"
!insertmacro RenameAndDelete "$INSTDIR\msvcp120.dll"
!insertmacro RenameAndDelete "$INSTDIR\msvcr120.dll"
!insertmacro RenameAndDelete "$INSTDIR\VoicemeeterClient.exe"
File "${BINPATH}\EqualizerAPO.dll"
File "${BINPATH}\Configurator.exe"
File "${BINPATH}\Benchmark.exe"
File "${BINPATH}\VoicemeeterClient.exe"
File "${BINPATH_EDITOR}\Editor.exe"
@@ -227,6 +229,7 @@ Section "-un.Uninstall"
Delete "$INSTDIR\Editor.exe"
Delete "$INSTDIR\VoicemeeterClient.exe"
Delete "$INSTDIR\Benchmark.exe"
Delete "$INSTDIR\Configurator.exe"
Delete /REBOOTOK "$INSTDIR\EqualizerAPO.dll"
+13 -13
View File
@@ -2,17 +2,17 @@
# 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`
Eval: freq = 3000
Eval: Q = 1/sqrt(2)
Eval: omega = 2 * pi * freq / sampleRate
Eval: sn = sin(omega)
Eval: cs = cos(omega)
Eval: alpha = sin(omega) / (2 * Q)
Eval: a0 = (1 - cs) / 2
Eval: a1 = 1 - cs
Eval: a2 = (1 - cs) / 2
Eval: b0 = 1 + alpha
Eval: b1 = -2 * cs
Eval: b2 = 1 - alpha
Filter: ON IIR Order 2 Coefficients `a0` `a1` `a2` `b0` `b1` `b2`
Filter: ON IIR Order 2 Coefficients `a0` `a1` `a2` `b0` `b1` `b2`
+501
View File
@@ -0,0 +1,501 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2017 Jonas Thedering
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "stdafx.h"
#include <ShlObj.h>
#include <fstream>
#include <algorithm>
#include <KsMedia.h>
#include <shellapi.h>
#include <TlHelp32.h>
#include <Winternl.h>
#include "helpers/RegistryHelper.h"
#include "VoicemeeterAPOInfo.h"
using namespace std;
#define voicemeeterKeyPath L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VB:Voicemeeter {17359A74-1236-5467}"
#define voicemeeterWowKeyPath L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VB:Voicemeeter {17359A74-1236-5467}"
#define uninstallStringValueName L"UninstallString"
static const wchar_t* startupFilename = L"Equalizer APO Voicemeeter Client.lnk";
static const wchar_t* clientFilename = L"VoicemeeterClient.exe";
static const wchar_t* voicemeeterClientKeyPath = USER_REGPATH L"\\Voicemeeter Client";
static const wchar_t* sampleRateValueName = L"sampleRate";
typedef NTSTATUS (NTAPI * pfnNtQueryInformationProcess)(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
void VoicemeeterAPOInfo::prependInfos(vector<shared_ptr<AbstractAPOInfo> >& list)
{
wstring voicemeeterDirectory;
if (RegistryHelper::keyExists(voicemeeterKeyPath))
voicemeeterDirectory = RegistryHelper::readValue(voicemeeterKeyPath, uninstallStringValueName);
else if (RegistryHelper::keyExists(voicemeeterWowKeyPath))
voicemeeterDirectory = RegistryHelper::readValue(voicemeeterWowKeyPath, uninstallStringValueName);
if (voicemeeterDirectory.length() > 0)
{
size_t index = voicemeeterDirectory.find_last_of(L'\\');
wstring setupFilename = voicemeeterDirectory.substr(index + 1);
bool banana = (setupFilename == L"VoicemeeterProSetup.exe");
unsigned outputCount;
if (banana)
outputCount = 3;
else
outputCount = 1;
bool defaultDevice = false;
list.erase(remove_if(list.begin(), list.end(), [&defaultDevice](shared_ptr<AbstractAPOInfo>& info) {
if (info->getDeviceName().find(L"VB-Audio VoiceMeeter") != wstring::npos)
{
if (info->isDefaultDevice())
defaultDevice = true;
return true;
}
return false;
}), list.end());
bool anyInstalled = false;
for (unsigned i = 0; i < outputCount; i++)
{
wstringstream sstream;
sstream << "Output A" << (i + 1);
shared_ptr<AbstractAPOInfo> info = *list.insert(list.begin() + i, make_shared<VoicemeeterAPOInfo>(sstream.str(), true));
if (info->isInstalled())
anyInstalled = true;
}
if (defaultDevice)
{
for (unsigned i = 0; i < outputCount; i++)
{
shared_ptr<VoicemeeterAPOInfo>& info = (shared_ptr<VoicemeeterAPOInfo>&)list[i];
if (!anyInstalled || info->isInstalled())
{
info->defaultDevice = true;
break;
}
}
}
}
else
{
// Voicemeeter was uninstalled but Voicemeeter Client might still be installed
wstring startupFilePath = getStartupPath();
wstring argString = getLinkArgs(startupFilePath);
vector<wstring> args = splitArgs(argString);
int i = 0;
for (wstring arg : args)
{
shared_ptr<AbstractAPOInfo> info = *list.insert(list.begin() + i, make_shared<VoicemeeterAPOInfo>(arg, false));
i++;
}
}
}
VoicemeeterAPOInfo::VoicemeeterAPOInfo(const wstring& connectionName, bool voicemeeterInstalled)
: connectionName(connectionName), voicemeeterInstalled(voicemeeterInstalled)
{
wstring startupFilePath = getStartupPath();
wstring path;
wstring argString = getLinkArgs(startupFilePath, &path);
vector<wstring> args = splitArgs(argString);
installed = find(args.begin(), args.end(), connectionName) != args.end();
sampleRate = 48000;
try
{
if (RegistryHelper::keyExists(voicemeeterClientKeyPath) && RegistryHelper::valueExists(voicemeeterClientKeyPath, sampleRateValueName))
sampleRate = (unsigned)RegistryHelper::readDWORDValue(voicemeeterClientKeyPath, sampleRateValueName);
}
catch (RegistryException e)
{
// ignore
}
wstring clientPath = getClientPath();
changes = (path != clientPath);
}
wstring VoicemeeterAPOInfo::getConnectionName() const
{
return connectionName;
}
wstring VoicemeeterAPOInfo::getDeviceName() const
{
return L"Voicemeeter";
}
wstring VoicemeeterAPOInfo::getDeviceGuid() const
{
return L"";
}
wstring VoicemeeterAPOInfo::getDeviceString() const
{
return getConnectionName() + L" " + getDeviceName();
}
unsigned VoicemeeterAPOInfo::getChannelCount() const
{
return 8;
}
unsigned VoicemeeterAPOInfo::getSampleRate() const
{
return sampleRate;
}
unsigned long VoicemeeterAPOInfo::getChannelMask() const
{
return KSAUDIO_SPEAKER_7POINT1_SURROUND;
}
bool VoicemeeterAPOInfo::isInput() const
{
return false;
}
bool VoicemeeterAPOInfo::isInstalled() const
{
return installed;
}
bool VoicemeeterAPOInfo::canBeUpgraded() const
{
return false;
}
bool VoicemeeterAPOInfo::hasChanges() const
{
return changes;
}
bool VoicemeeterAPOInfo::isExperimental() const
{
return false;
}
bool VoicemeeterAPOInfo::isEnhancementsDisabled() const
{
return false;
}
bool VoicemeeterAPOInfo::isDefaultDevice() const
{
return defaultDevice;
}
bool VoicemeeterAPOInfo::isVoicemeeterInstalled() const
{
return voicemeeterInstalled;
}
void VoicemeeterAPOInfo::install()
{
wstring startupFilePath = getStartupPath();
wstring argString = getLinkArgs(startupFilePath);
vector<wstring> args = splitArgs(argString);
vector<wstring>::iterator it = find(args.begin(), args.end(), connectionName);
if (it == args.end())
args.push_back(connectionName);
sort(args.begin(), args.end());
argString = joinArgs(args);
wstring clientPath = getClientPath();
createLink(startupFilePath, clientPath, argString);
}
void VoicemeeterAPOInfo::uninstall()
{
wstring startupFilePath = getStartupPath();
wstring argString = getLinkArgs(startupFilePath);
vector<wstring> args = splitArgs(argString);
vector<wstring>::iterator it = find(args.begin(), args.end(), connectionName);
if (it != args.end())
args.erase(it);
if (args.size() > 0)
{
sort(args.begin(), args.end());
argString = joinArgs(args);
wchar_t filename[MAX_PATH];
GetModuleFileNameW(NULL, filename, ARRAYSIZE(filename));
PathRemoveFileSpecW(filename);
wstring clientPath = filename;
clientPath = clientPath + L"\\" + clientFilename;
createLink(startupFilePath, clientPath, argString);
}
else
{
DeleteFileW(startupFilePath.c_str());
}
}
void VoicemeeterAPOInfo::reinstall()
{
uninstall();
install();
}
wstring VoicemeeterAPOInfo::getStartupPath()
{
PWSTR startupPath;
SHGetKnownFolderPath(FOLDERID_Startup, KF_FLAG_DONT_UNEXPAND, NULL, &startupPath);
wstring result(startupPath);
CoTaskMemFree(startupPath);
return result + L"\\" + startupFilename;
}
wstring VoicemeeterAPOInfo::getClientPath()
{
wchar_t filename[MAX_PATH];
GetModuleFileNameW(NULL, filename, ARRAYSIZE(filename));
PathRemoveFileSpecW(filename);
wstring clientPath = filename;
clientPath = clientPath + L"\\" + clientFilename;
return clientPath;
}
void VoicemeeterAPOInfo::createLink(const wstring& lnkPath, const wstring& path, const wstring& args)
{
IShellLink* shellLink;
HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&shellLink);
if (SUCCEEDED(hr))
{
shellLink->SetPath(path.c_str());
shellLink->SetArguments(args.c_str());
IPersistFile* persistFile;
hr = shellLink->QueryInterface(IID_IPersistFile, (LPVOID*)&persistFile);
if (SUCCEEDED(hr))
{
hr = persistFile->Save(lnkPath.c_str(), TRUE);
persistFile->Release();
}
shellLink->Release();
}
}
wstring VoicemeeterAPOInfo::getLinkArgs(const wstring& lnkPath, wstring* path)
{
wstring result;
IShellLink* shellLink;
HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&shellLink);
if (SUCCEEDED(hr))
{
IPersistFile* persistFile;
hr = shellLink->QueryInterface(IID_IPersistFile, (LPVOID*)&persistFile);
if (SUCCEEDED(hr))
{
hr = persistFile->Load(lnkPath.c_str(), STGM_READ);
if (SUCCEEDED(hr))
{
wchar_t buf[MAX_PATH];
hr = shellLink->GetArguments(buf, ARRAYSIZE(buf));
if (SUCCEEDED(hr))
result = buf;
if (path != NULL)
{
hr = shellLink->GetPath(buf, ARRAYSIZE(buf), NULL, 0);
if (SUCCEEDED(hr))
*path = buf;
}
}
persistFile->Release();
}
shellLink->Release();
}
return result;
}
vector<wstring> VoicemeeterAPOInfo::splitArgs(const wstring& argString)
{
vector<wstring> result;
if (argString.length() > 0)
{
int argc;
wchar_t** argv = CommandLineToArgvW(argString.c_str(), &argc);
for (int i = 0; i < argc; i++)
result.push_back(argv[i]);
LocalFree(argv);
}
return result;
}
wstring VoicemeeterAPOInfo::joinArgs(const vector<wstring>& args)
{
wstring result;
for (const wstring& arg : args)
{
if (result.length() > 0)
result += L" ";
if (arg.find(' ') != wstring::npos)
result += L"\"" + arg + L"\"";
else
result += arg;
}
return result;
}
void VoicemeeterAPOInfo::ensureVoicemeeterClientRunning()
{
wstring startupFilePath = getStartupPath();
wstring argString = getLinkArgs(startupFilePath);
vector<wstring> args = splitArgs(argString);
wstring clientPath = getClientPath();
HANDLE tokenHandle;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &tokenHandle))
throw RegistryException(L"Error in OpenProcessToken while taking ownership");
LUID luid;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
throw RegistryException(L"Error in LookupPrivilegeValue while taking ownership");
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(tokenHandle, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
throw RegistryException(L"Error in AdjustTokenPrivileges while taking ownership");
HMODULE module = LoadLibraryW(L"ntdll.dll");
if (module == NULL)
throw exception("Could not load ntdll.dll");
SCOPE_EXIT {FreeLibrary(module);};
pfnNtQueryInformationProcess NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(module, "NtQueryInformationProcess");
if (NtQueryInformationProcess == NULL)
throw exception("Function NtQueryInformationProcess not found in ntdll.dll");
HANDLE snapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshotHandle == INVALID_HANDLE_VALUE)
throw exception("Could not take a snapshot of all processes");
SCOPE_EXIT {CloseHandle(snapshotHandle);};
bool matchingProcessExists = false;
PROCESSENTRY32W entry;
entry.dwSize = sizeof(PROCESSENTRY32W);
bool loop = Process32FirstW(snapshotHandle, &entry) != 0;
while (loop)
{
if (wcscmp(entry.szExeFile, clientFilename) == 0)
{
HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, FALSE, entry.th32ProcessID);
if (processHandle == INVALID_HANDLE_VALUE)
throw exception("Could not open process");
SCOPE_EXIT {CloseHandle(processHandle);};
PROCESS_BASIC_INFORMATION basicInformation;
NTSTATUS status = NtQueryInformationProcess(processHandle, ProcessBasicInformation, &basicInformation, sizeof(basicInformation), NULL);
if (status < 0)
throw exception("Could not query process information");
_PEB peb;
if (!ReadProcessMemory(processHandle, basicInformation.PebBaseAddress, &peb, sizeof(peb), NULL))
throw exception("Could not read peb from process memory");
RTL_USER_PROCESS_PARAMETERS processParams;
if (!ReadProcessMemory(processHandle, peb.ProcessParameters, &processParams, sizeof(processParams), NULL))
throw exception("Could not read process parameters from process memory");
wchar_t* cmdLineBuf = new wchar_t[processParams.CommandLine.Length / sizeof(wchar_t)];
SCOPE_EXIT {delete cmdLineBuf;};
if (!ReadProcessMemory(processHandle, processParams.CommandLine.Buffer, cmdLineBuf, processParams.CommandLine.Length, NULL))
throw exception("Could not read command line from process memory");
wstring cmdLine(cmdLineBuf, processParams.CommandLine.Length / sizeof(wchar_t));
vector<wstring> processArgs = splitArgs(cmdLine);
wstring path = processArgs.front();
processArgs.erase(processArgs.begin());
if (path != clientPath || processArgs != args)
closeProcess(entry.th32ProcessID);
else
matchingProcessExists = true;
}
loop = Process32NextW(snapshotHandle, &entry) != 0;
}
if (!matchingProcessExists && !args.empty())
{
ShellExecuteW(NULL, NULL, clientPath.c_str(), argString.c_str(), NULL, SW_SHOWDEFAULT);
}
}
void VoicemeeterAPOInfo::saveVoicemeeterSampleRate(unsigned sampleRate)
{
try
{
RegistryHelper::createKey(voicemeeterClientKeyPath);
RegistryHelper::writeDWORDValue(voicemeeterClientKeyPath, sampleRateValueName, sampleRate);
}
catch (RegistryException e)
{
// ignore
}
}
void VoicemeeterAPOInfo::closeProcess(unsigned long processId)
{
HANDLE snapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (snapshotHandle == INVALID_HANDLE_VALUE)
throw exception("Could not take a snapshot of all processes");
SCOPE_EXIT {CloseHandle(snapshotHandle);};
THREADENTRY32 entry;
entry.dwSize = sizeof(THREADENTRY32);
bool loop = Thread32First(snapshotHandle, &entry) != 0;
while (loop)
{
if (entry.th32OwnerProcessID == processId)
// will just fail for threads not having a message queue
PostThreadMessageW(entry.th32ThreadID, WM_QUIT, 0, 0);
loop = Thread32Next(snapshotHandle, &entry) != 0;
}
}
+70
View File
@@ -0,0 +1,70 @@
/*
This file is part of EqualizerAPO, a system-wide equalizer.
Copyright (C) 2017 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 <memory>
#include "AbstractAPOInfo.h"
class VoicemeeterAPOInfo : public AbstractAPOInfo
{
public:
static void prependInfos(std::vector<std::shared_ptr<AbstractAPOInfo> >& list);
VoicemeeterAPOInfo(const std::wstring& connectionName, bool voicemeeterInstalled);
std::wstring getConnectionName() const override;
std::wstring getDeviceName() const override;
std::wstring getDeviceGuid() const override;
std::wstring getDeviceString() const override;
unsigned getChannelCount() const override;
unsigned getSampleRate() const override;
unsigned long getChannelMask() const override;
bool isInput() const override;
bool isInstalled() const override;
bool canBeUpgraded() const override;
bool hasChanges() const override;
bool isExperimental() const override;
bool isEnhancementsDisabled() const override;
bool isDefaultDevice() const override;
bool isVoicemeeterInstalled() const;
void install() override;
void uninstall() override;
void reinstall() override;
static void ensureVoicemeeterClientRunning();
static void saveVoicemeeterSampleRate(unsigned sampleRate);
private:
static std::wstring getStartupPath();
static std::wstring getClientPath();
static void createLink(const std::wstring& lnkPath, const std::wstring& path, const std::wstring& args);
static std::wstring getLinkArgs(const std::wstring& lnkPath, std::wstring* path = NULL);
static std::vector<std::wstring> splitArgs(const std::wstring& argString);
static std::wstring joinArgs(const std::vector<std::wstring>& args);
static void closeProcess(unsigned long processId);
std::wstring connectionName;
unsigned sampleRate;
bool installed;
bool defaultDevice = false;
bool voicemeeterInstalled;
bool changes = false;
};
+266
View File
@@ -0,0 +1,266 @@
#include "stdafx.h"
#include <string>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include "helpers/RegistryHelper.h"
#include "VoicemeeterClient.h"
#include "VoicemeeterAPOInfo.h"
#define voicemeeterKeyPath L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VB:Voicemeeter {17359A74-1236-5467}"
#define voicemeeterWowKeyPath L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VB:Voicemeeter {17359A74-1236-5467}"
#define uninstallStringValueName L"UninstallString"
using namespace std;
long __stdcall callback(void* lpUser, long nCommand, void* lpData, long nnn);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
vector<wstring> outputs;
if (lpCmdLine[0] != 0)
{
int argc;
wchar_t** argv = CommandLineToArgvW(lpCmdLine, &argc);
for (int i = 0; i < argc; i++)
outputs.push_back(argv[i]);
LocalFree(argv);
}
VoicemeeterClient* client = new VoicemeeterClient(outputs);
MSG msg;
msg.wParam = 0;
bool loop = client->restart;
while (loop)
{
client->start();
client->restart = false;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
loop = client->restart;
client->stop();
}
delete client;
return (int)msg.wParam;
}
VoicemeeterClient::VoicemeeterClient(const vector<wstring>& outputs)
: outputs(outputs)
{
mainThreadId = GetCurrentThreadId();
wstring voicemeeterDirectory;
if (RegistryHelper::keyExists(voicemeeterKeyPath))
voicemeeterDirectory = RegistryHelper::readValue(voicemeeterKeyPath, uninstallStringValueName);
else if (RegistryHelper::keyExists(voicemeeterWowKeyPath))
voicemeeterDirectory = RegistryHelper::readValue(voicemeeterWowKeyPath, uninstallStringValueName);
size_t index = voicemeeterDirectory.find_last_of(L'\\');
HMODULE voicemeeterModule = NULL;
if (index != wstring::npos)
{
wstring setupFilename = voicemeeterDirectory.substr(index + 1);
banana = (setupFilename == L"VoicemeeterProSetup.exe");
voicemeeterDirectory = voicemeeterDirectory.substr(0, index);
#ifdef _WIN64
voicemeeterModule = LoadLibraryW((voicemeeterDirectory + L"\\VoicemeeterRemote64.dll").c_str());
#else
voicemeeterModule = LoadLibraryW((voicemeeterDirectory + L"\\VoicemeeterRemote.dll").c_str());
#endif
}
memset(&vmr, 0, sizeof(T_VBVMR_INTERFACE));
#define LOAD_PROC(proc) vmr.proc = (T_ ## proc)GetProcAddress(voicemeeterModule, # proc)
if (voicemeeterModule != NULL)
{
LOAD_PROC(VBVMR_Login);
LOAD_PROC(VBVMR_Logout);
LOAD_PROC(VBVMR_AudioCallbackRegister);
LOAD_PROC(VBVMR_AudioCallbackStart);
LOAD_PROC(VBVMR_AudioCallbackStop);
LOAD_PROC(VBVMR_AudioCallbackUnregister);
LOAD_PROC(VBVMR_GetVoicemeeterType);
restart = true;
}
}
VoicemeeterClient::~VoicemeeterClient()
{
if (loggedIn)
{
vmr.VBVMR_Logout();
loggedIn = false;
}
}
void VoicemeeterClient::start()
{
if (!loggedIn)
loggedIn = (vmr.VBVMR_Login() == 0);
if (loggedIn)
{
long type;
if (vmr.VBVMR_GetVoicemeeterType(&type) == 0)
banana = (type == 2);
}
unsigned outputCount;
if (banana)
outputCount = 3;
else
outputCount = 1;
for (unsigned i = 0; i < outputCount; i++)
{
wstringstream sstream;
sstream << "Output A" << (i + 1);
wstring output = sstream.str();
if (find(outputs.begin(), outputs.end(), output) != outputs.end())
{
FilterEngine* engine = new FilterEngine();
engine->setDeviceInfo(false, true, L"Voicemeeter", output, L"", L"Voicemeeter " + output);
engines.push_back(engine);
}
else
{
engines.push_back(NULL);
}
idleSampleCounts.push_back(0);
}
if (vmr.VBVMR_AudioCallbackRegister(VBVMR_AUDIOCALLBACK_OUT, callback, this, "Equalizer APO") != 0)
{
PostThreadMessage(mainThreadId, WM_QUIT, 0, 0);
return;
}
vmr.VBVMR_AudioCallbackStart();
}
void VoicemeeterClient::stop()
{
vmr.VBVMR_AudioCallbackStop();
vmr.VBVMR_AudioCallbackUnregister();
idleSampleCounts.clear();
for (FilterEngine* engine : engines)
if (engine != NULL)
delete engine;
engines.clear();
}
void VoicemeeterClient::handle(long nCommand, void* lpData, long nnn)
{
switch (nCommand)
{
case VBVMR_CBCOMMAND_STARTING:
{
VBVMR_LPT_AUDIOINFO audioInfo = (VBVMR_LPT_AUDIOINFO)lpData;
for (FilterEngine* engine : engines)
if (engine != NULL)
engine->initialize((float)audioInfo->samplerate, 8, 8, 8, 0, audioInfo->nbSamplePerFrame);
VoicemeeterAPOInfo::saveVoicemeeterSampleRate((unsigned)audioInfo->samplerate);
}
break;
case VBVMR_CBCOMMAND_ENDING:
{
restart = true;
PostThreadMessage(mainThreadId, WM_QUIT, 0, 0);
}
break;
case VBVMR_CBCOMMAND_CHANGE:
{
VBVMR_LPT_AUDIOINFO audioInfo = (VBVMR_LPT_AUDIOINFO)lpData;
for (FilterEngine* engine : engines)
if (engine != NULL)
engine->initialize((float)audioInfo->samplerate, 8, 8, 8, 0, audioInfo->nbSamplePerFrame);
VoicemeeterAPOInfo::saveVoicemeeterSampleRate((unsigned)audioInfo->samplerate);
}
break;
case VBVMR_CBCOMMAND_BUFFER_OUT:
{
VBVMR_LPT_AUDIOBUFFER audioBuffer = (VBVMR_LPT_AUDIOBUFFER)lpData;
int nbi = audioBuffer->audiobuffer_nbi;
int nbo = audioBuffer->audiobuffer_nbo;
int n = min(nbi, nbo) / 8;
for (int i = 0; i < n; i++)
{
FilterEngine* engine = NULL;
if (i < engines.size())
engine = engines[i];
bool idle = true;
bool inputSilent = true;
if (engine != NULL)
{
inputSilent = isBufferSilent(audioBuffer->audiobuffer_r + 8 * i, audioBuffer->audiobuffer_nbs);
idle = inputSilent && idleSampleCounts[i] > 10 * engine->getSampleRate();
}
// avoid processing when idle (Voicemeeter does still call this when no audio is played)
if (!idle)
{
engine->process(audioBuffer->audiobuffer_w + 8 * i, audioBuffer->audiobuffer_r + 8 * i, audioBuffer->audiobuffer_nbs);
bool outputSilent = isBufferSilent(audioBuffer->audiobuffer_w + 8 * i, audioBuffer->audiobuffer_nbs);
if (inputSilent && outputSilent)
idleSampleCounts[i] += audioBuffer->audiobuffer_nbs;
else
idleSampleCounts[i] = 0;
}
else
{
for (int j = 0; j < 8; j++)
memcpy(audioBuffer->audiobuffer_w[8 * i + j], audioBuffer->audiobuffer_r[8 * i + j], audioBuffer->audiobuffer_nbs * sizeof(float));
}
}
}
break;
}
}
bool VoicemeeterClient::isBufferSilent(float** sampleData, long sampleCount)
{
bool silent = true;
for (int j = 0; j < 8; j++)
{
float* buf = sampleData[j];
for (int k = 0; k < sampleCount; k++)
{
if (buf[k] != 0.0f)
{
silent = false;
break;
}
}
}
return silent;
}
long __stdcall callback(void* lpUser, long nCommand, void* lpData, long nnn)
{
VoicemeeterClient* client = (VoicemeeterClient*)lpUser;
client->handle(nCommand, lpData, nnn);
return 0;
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include <string>
#include <vector>
#include "FilterEngine.h"
#include "VoicemeeterRemote.h"
class VoicemeeterClient
{
public:
VoicemeeterClient(const std::vector<std::wstring>& outputs);
~VoicemeeterClient();
void start();
void stop();
void handle(long nCommand, void* lpData, long nnn);
bool restart = false;
private:
bool isBufferSilent(float** sampleData, long sampleCount);
unsigned long mainThreadId;
T_VBVMR_INTERFACE vmr;
std::vector<FilterEngine*> engines;
std::vector<int> idleSampleCounts;
bool loggedIn = false;
bool banana = false;
std::vector<std::wstring> outputs;
};
Binary file not shown.
+249
View File
@@ -0,0 +1,249 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{10F1DD37-EA50-46C2-810D-D01A1A0D4D2F}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>VoicemeeterClient</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(SolutionDir);C:\Program Files\libsndfile\include;C:\Program Files\muparserx_v3_0_1\parser;C:\Program Files (x86)\fftw3;$(IncludePath)</IncludePath>
<LibraryPath>C:\Program Files (x86)\libsndfile\lib;C:\Program Files\muparserx_v3_0_1\lib;C:\Program Files (x86)\fftw3;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(SolutionDir);C:\Program Files\libsndfile\include;C:\Program Files\muparserx_v3_0_1\parser;C:\Program Files\fftw3;$(IncludePath)</IncludePath>
<LibraryPath>C:\Program Files\libsndfile\lib;C:\Program Files\muparserx_v3_0_1\lib64;C:\Program Files\fftw3;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(SolutionDir);C:\Program Files\libsndfile\include;C:\Program Files\muparserx_v3_0_1\parser;C:\Program Files (x86)\fftw3;$(IncludePath)</IncludePath>
<LibraryPath>C:\Program Files (x86)\libsndfile\lib;C:\Program Files\muparserx_v3_0_1\lib;C:\Program Files (x86)\fftw3;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(SolutionDir);C:\Program Files\libsndfile\include;C:\Program Files\muparserx_v3_0_1\parser;C:\Program Files\fftw3;$(IncludePath)</IncludePath>
<LibraryPath>C:\Program Files\libsndfile\lib;C:\Program Files\muparserx_v3_0_1\lib64;C:\Program Files\fftw3;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>muparserxd.lib;version.lib;Shlwapi.lib;authz.lib;libsndfile-1.lib;libfftw3f-3.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>muparserxd.lib;version.lib;Shlwapi.lib;authz.lib;libsndfile-1.lib;libfftw3f-3.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>muparserx.lib;version.lib;Shlwapi.lib;authz.lib;libsndfile-1.lib;libfftw3f-3.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>muparserx.lib;version.lib;Shlwapi.lib;authz.lib;libsndfile-1.lib;libfftw3f-3.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\..\..\..\Users\Jonas\Downloads\VoicemeeterRemoteAPI_Pack6\VoicemeeterRemote.h" />
<ClInclude Include="..\AbstractAPOInfo.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\ConvolutionFilter.h" />
<ClInclude Include="..\filters\ConvolutionFilterFactory.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\GraphicEQFilter.h" />
<ClInclude Include="..\filters\GraphicEQFilterFactory.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\ChannelHelper.h" />
<ClInclude Include="..\helpers\GainIterator.h" />
<ClInclude Include="..\helpers\LogHelper.h" />
<ClInclude Include="..\helpers\MemoryHelper.h" />
<ClInclude Include="..\helpers\RegistryHelper.h" />
<ClInclude Include="..\helpers\ScopeGuard.h" />
<ClInclude Include="..\helpers\StringHelper.h" />
<ClInclude Include="..\helpers\UncaughtExceptions.h" />
<ClInclude Include="..\IFilter.h" />
<ClInclude Include="..\IFilterFactory.h" />
<ClInclude Include="..\libHybridConv-0.1.1\libHybridConv_eapo.h" />
<ClInclude Include="..\parser\RegexFunctions.h" />
<ClInclude Include="..\parser\RegistryFunctions.h" />
<ClInclude Include="..\parser\StringOperators.h" />
<ClInclude Include="..\stdafx.h" />
<ClInclude Include="..\VoicemeeterAPOInfo.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="VoicemeeterClient.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\AbstractAPOInfo.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\ConvolutionFilter.cpp" />
<ClCompile Include="..\filters\ConvolutionFilterFactory.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\GraphicEQFilter.cpp" />
<ClCompile Include="..\filters\GraphicEQFilterFactory.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\ChannelHelper.cpp" />
<ClCompile Include="..\helpers\GainIterator.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="..\libHybridConv-0.1.1\libHybridConv_eapo.cpp" />
<ClCompile Include="..\parser\RegexFunctions.cpp" />
<ClCompile Include="..\parser\RegistryFunctions.cpp" />
<ClCompile Include="..\parser\StringOperators.cpp" />
<ClCompile Include="..\stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\VoicemeeterAPOInfo.cpp" />
<ClCompile Include="VoicemeeterClient.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="VoicemeeterClient.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,239 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="helpers">
<UniqueIdentifier>{0e9ead24-f831-4803-ab47-9b5208987e65}</UniqueIdentifier>
</Filter>
<Filter Include="filters">
<UniqueIdentifier>{e112c6dd-61fc-4742-808b-298e228688ed}</UniqueIdentifier>
</Filter>
<Filter Include="parser">
<UniqueIdentifier>{171427eb-7308-4b30-88c5-27068dd8a4f2}</UniqueIdentifier>
</Filter>
<Filter Include="libHybridConv-0.1.1">
<UniqueIdentifier>{898022d7-bfa6-4240-b443-e82e638cf0f6}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\helpers\RegistryHelper.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="VoicemeeterClient.h" />
<ClInclude Include="..\helpers\StringHelper.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="..\stdafx.h" />
<ClInclude Include="..\..\..\..\..\Users\Jonas\Downloads\VoicemeeterRemoteAPI_Pack6\VoicemeeterRemote.h" />
<ClInclude Include="..\FilterConfiguration.h" />
<ClInclude Include="..\FilterEngine.h" />
<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\ConvolutionFilter.h">
<Filter>filters</Filter>
</ClInclude>
<ClInclude Include="..\filters\ConvolutionFilterFactory.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\GraphicEQFilter.h">
<Filter>filters</Filter>
</ClInclude>
<ClInclude Include="..\filters\GraphicEQFilterFactory.h">
<Filter>filters</Filter>
</ClInclude>
<ClInclude Include="..\filters\IfFilterFactory.h">
<Filter>filters</Filter>
</ClInclude>
<ClInclude Include="..\filters\IIRFilter.h">
<Filter>filters</Filter>
</ClInclude>
<ClInclude Include="..\filters\IIRFilterFactory.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="..\parser\RegexFunctions.h">
<Filter>parser</Filter>
</ClInclude>
<ClInclude Include="..\parser\RegistryFunctions.h">
<Filter>parser</Filter>
</ClInclude>
<ClInclude Include="..\parser\StringOperators.h">
<Filter>parser</Filter>
</ClInclude>
<ClInclude Include="..\libHybridConv-0.1.1\libHybridConv_eapo.h">
<Filter>libHybridConv-0.1.1</Filter>
</ClInclude>
<ClInclude Include="..\IFilter.h" />
<ClInclude Include="..\IFilterFactory.h" />
<ClInclude Include="..\helpers\MemoryHelper.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="..\helpers\LogHelper.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="..\helpers\GainIterator.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="..\helpers\ChannelHelper.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="resource.h" />
<ClInclude Include="..\VoicemeeterAPOInfo.h" />
<ClInclude Include="..\AbstractAPOInfo.h" />
<ClInclude Include="..\helpers\ScopeGuard.h">
<Filter>helpers</Filter>
</ClInclude>
<ClInclude Include="..\helpers\UncaughtExceptions.h">
<Filter>helpers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\helpers\RegistryHelper.cpp">
<Filter>helpers</Filter>
</ClCompile>
<ClCompile Include="VoicemeeterClient.cpp" />
<ClCompile Include="..\helpers\StringHelper.cpp">
<Filter>helpers</Filter>
</ClCompile>
<ClCompile Include="..\stdafx.cpp" />
<ClCompile Include="..\FilterConfiguration.cpp" />
<ClCompile Include="..\FilterEngine.cpp" />
<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\ConvolutionFilter.cpp">
<Filter>filters</Filter>
</ClCompile>
<ClCompile Include="..\filters\ConvolutionFilterFactory.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\GraphicEQFilter.cpp">
<Filter>filters</Filter>
</ClCompile>
<ClCompile Include="..\filters\GraphicEQFilterFactory.cpp">
<Filter>filters</Filter>
</ClCompile>
<ClCompile Include="..\filters\IfFilterFactory.cpp">
<Filter>filters</Filter>
</ClCompile>
<ClCompile Include="..\filters\IIRFilter.cpp">
<Filter>filters</Filter>
</ClCompile>
<ClCompile Include="..\filters\IIRFilterFactory.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="..\parser\RegexFunctions.cpp">
<Filter>parser</Filter>
</ClCompile>
<ClCompile Include="..\parser\RegistryFunctions.cpp">
<Filter>parser</Filter>
</ClCompile>
<ClCompile Include="..\parser\StringOperators.cpp">
<Filter>parser</Filter>
</ClCompile>
<ClCompile Include="..\libHybridConv-0.1.1\libHybridConv_eapo.cpp">
<Filter>libHybridConv-0.1.1</Filter>
</ClCompile>
<ClCompile Include="..\IFilter.cpp" />
<ClCompile Include="..\helpers\MemoryHelper.cpp">
<Filter>helpers</Filter>
</ClCompile>
<ClCompile Include="..\helpers\LogHelper.cpp">
<Filter>helpers</Filter>
</ClCompile>
<ClCompile Include="..\helpers\GainIterator.cpp">
<Filter>helpers</Filter>
</ClCompile>
<ClCompile Include="..\helpers\ChannelHelper.cpp">
<Filter>helpers</Filter>
</ClCompile>
<ClCompile Include="..\VoicemeeterAPOInfo.cpp" />
<ClCompile Include="..\AbstractAPOInfo.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="VoicemeeterClient.rc" />
</ItemGroup>
</Project>
+775
View File
@@ -0,0 +1,775 @@
/******************************************************************************/
/* Voicemeeter Remote API. V.Burel©2015 */
/******************************************************************************/
/* This Library allows communication with Voicemeeter Applications */
/* 4 Client Applications can be connected to remote Voicemeeter. */
/******************************************************************************/
/* */
/* OFFICIAL LINK : WWW.VOICEMEETER.COM */
/* */
/******************************************************************************/
/* COPYRIGHT: Vincent Burel(c)2015 All Rights Reserved */
/******************************************************************************/
/* LICENSING: This header file and VoicemeeterRemote.dll are made available */
/* for evaluation and testing purpose only (to make demo and proof */
/* of concept). */
/* */
/* for any commercial exploitation or to get specific support, */
/* a commercial license needs to be purchased. thanks to contact */
/* us by e-mail (get our contact on www.vb-audio.com). */
/******************************************************************************/
/* long = 32 bit integer */
/******************************************************************************/
#ifndef __VOICEMEETER_REMOTE_H__
#define __VOICEMEETER_REMOTE_H__
#ifdef __cplusplus
extern "C" {
#endif
#define VBVMR_RESULT_OK 0
/******************************************************************************/
/* */
/* Login */
/* */
/******************************************************************************/
/** @name Communication Login / logout
* @{ */
/**
@brief Open Communication Pipe With Voicemeeter (typically called on software startup).
@return : 0: OK (no error).
1: OK but Voicemeeter Application not launched.
-1: cannot get client (unexpected)
-2: unexpected login (logout was expected before).
*/
long __stdcall VBVMR_Login(void);
/**
@brief Close Communication Pipe With Voicemeeter (typically called on software end).
@return : 0 if ok.
*/
long __stdcall VBVMR_Logout(void);
/**
@brief Run Voicemeeter Application (get installation directory and run Voicemeeter Application).
@param vType : Voicemeeter type (1 = Voicemeeter, 2= Voicemeeter Banana).
@return : 0: Ok.
-1: not installed
*/
long __stdcall VBVMR_RunVoicemeeter(long vType);
/** @} */
/******************************************************************************/
/* */
/* General Information */
/* */
/******************************************************************************/
/** @name General Information
* @{ */
/**
@brief Get Voicemeeter Type
@param pType : Pointer on 32bit long receiving the type (1 = Voicemeeter, 2= Voicemeeter Banana).
VOICEMEETER STRIP/BUS INDEX ASSIGNMENT
| Strip 1 | Strip 2 |Virtual Input| BUS A | BUS B |
+---------+---------+-------------+---------+---------+
| 0 | 1 | 2 | 0 | 1 |
VOICEMEETER BANANA STRIP/BUS INDEX ASSIGNMENT
| Strip 1 | Strip 2 | Strip 2 |Virtual Input|Virtual AUX|BUS A1|BUS A2|BUS A3|BUS B1|BUS B2|
+---------+---------+---------+-------------+-----------+------+------+------+------+------+
| 0 | 1 | 2 | 3 | 4 | 0 | 1 | 2 | 3 | 4 |
@return : 0: OK (no error).
-1: cannot get client (unexpected)
-2: no server.
*/
long __stdcall VBVMR_GetVoicemeeterType(long * pType);
/**
@brief Get Voicemeeter Version
@param pType : Pointer on 32bit integer receiving the version (v1.v2.v3.v4)
v1 = (version & 0xFF000000)>>24;
v2 = (version & 0x00FF0000)>>16;
v3 = (version & 0x0000FF00)>>8;
v4 = version & 0x000000FF;
@return : 0: OK (no error).
-1: cannot get client (unexpected)
-2: no server.
*/
long __stdcall VBVMR_GetVoicemeeterVersion(long * pVersion);
/** @} */
/******************************************************************************/
/* */
/* Get parameters */
/* */
/******************************************************************************/
/** @name Getting Parameters
* @{ */
/**
@brief Check if parameters have changed.
Call this function periodically (typically every 10 or 20ms).
(this function must be called from one thread only)
@return: 0: no new paramters.
1: New parameters -> update your display.
-1: error (unexpected)
-2: no server.
*/
long __stdcall VBVMR_IsParametersDirty(void);
/**
@brief get parameter value.
@param szParamName : Null Terminal ASCII String giving the name of the parameter (see parameters name table)
@param pValue : Pointer on float (32bit float by reference) receiving the wanted value.
@return : 0: OK (no error).
-1: error
-2: no server.
-3: unknown parameter
-5: structure mismatch
*/
long __stdcall VBVMR_GetParameterFloat(char * szParamName, float * pValue);
/**
@brief get parameter value.
@param szParamName : Null Terminal ASCII String giving the name of the parameter (see parameters name table)
@param pValue : Pointer on String (512 char or wchar) receiving the wanted value.
@return : 0: OK (no error).
-1: error
-2: no server.
-3: unknown parameter
-5: structure mismatch
*/
long __stdcall VBVMR_GetParameterStringA(char * szParamName, char * szString);
long __stdcall VBVMR_GetParameterStringW(char * szParamName, unsigned short * wszString);
/** @} */
/******************************************************************************/
/* */
/* Get levels */
/* */
/******************************************************************************/
/** @name Getting RT Data
* @{ */
/**
@brief Get Current levels.
(this function must be called from one thread only)
@param nType: 0= pre fader input levels.
1= post fader input levels.
2= post Mute input levels.
3= output levels.
@param nuChannel: audio channel zero based index
for input 0 = in#1 left, 1= in#1 Right, etc...
for output 0 = busA ch1, 1 = busA ch2...
VOICEMEETER CHANNEL ASSIGNMENT
| Strip 1 | Strip 2 | Virtual Input |
+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 |
| Output A1 / A2 | Virtual Output |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 |
VOICEMEETER BANANA CHANNEL ASSIGNMENT
| Strip 1 | Strip 2 | Strip 3 | Virtual Input | Virtual Input AUX |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| Output A1 | Output A2 | Output A3 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| Virtual Output B1 | Virtual Output B2 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
@return : 0: OK (no error).
-1: error
-2: no server.
-3: no level available
-4: out of range
*/
long __stdcall VBVMR_GetLevel(long nType, long nuChannel, float * pValue);
/**
@brief Get MIDI message from M.I.D.I. input device used by Voicemeeter M.I.D.I. mapping.
(this function must be called from one thread only)
@param pMIDIBuffer: pointer on MIDI Buffer. Expected message size is below 4 bytes,
but it's recommended to use 1024 Bytes local buffer to receive
possible multiple M.I.D.I. event message in optimal way:
unsigned char pBuffer[1024];
@return : >0: number of bytes placed in buffer (2 or 3 byte for usual M.I.D.I. message)
-1: error
-2: no server.
-5: no MIDI data
-6: no MIDI data
*/
long __stdcall VBVMR_GetMidiMessage(unsigned char *pMIDIBuffer, long nbByteMax);
/** @} */
/******************************************************************************/
/* */
/* Set Parameters */
/* */
/******************************************************************************/
/** @name Setting Parameters
* @{ */
/**
@brief Set a single float 32 bits parameters .
@param szParamName : Null Terminal ASCII String giving the name of the parameter (see parameters name table)
example:
Strip[1].gain
Strip[0].mute
Bus[0].gain
Bus[0].eq.channel[0].cell[0].gain
@param pValue : float 32bit containing the new value.
@return : 0: OK (no error).
-1: error
-2: no server.
-3: unknown parameter
*/
long __stdcall VBVMR_SetParameterFloat(char * szParamName, float Value);
/**
@brief Set a single string parameters .
@param szParamName : Null Terminal ASCII String giving the name of the parameter (see parameters name table)
example:
Strip[1].name
Strip[0].device.mme
Bus[0].device.asio
@param szString : zero terminal string.
@return : 0: OK (no error).
-1: error
-2: no server.
-3: unknown parameter
*/
long __stdcall VBVMR_SetParameterStringA(char * szParamName, char * szString);
long __stdcall VBVMR_SetParameterStringW(char * szParamName, unsigned short * wszString);
/**
@brief Set one or several parameters by a script ( < 48 kB ).
@param szParamName : Null Terminal ASCII String giving the script
(script allows to change several parameters in the same time - SYNCHRO).
Possible Instuction separators: ',' ';' or '\n'(CR)
EXAMPLE:
"Strip[0].gain = -6.0
Strip[0].A1 = 0
Strip[0].B1 = 1
Strip[1].gain = -6.0
Strip[2].gain = 0.0
Strip[3].name = "Skype Caller" "
@return : 0: OK (no error).
>0: number of line causing script error.
-1: error
-2: no server.
-3: unexpected error
-4: unexpected error
*/
long __stdcall VBVMR_SetParameters(char * szParamScript);
long __stdcall VBVMR_SetParametersW(unsigned short * szParamScript);
/** @} */
/******************************************************************************/
/* DEVICES ENUMERATOR */
/******************************************************************************/
/** @name Device Enumeration Functions
* @{ */
#define VBVMR_DEVTYPE_MME 1
#define VBVMR_DEVTYPE_WDM 3
#define VBVMR_DEVTYPE_KS 4
#define VBVMR_DEVTYPE_ASIO 5
/**
@brief Get number of Audio Output Device available on the system
@return : return number of device found.
*/
long __stdcall VBVMR_Output_GetDeviceNumber(void);
/**
@brief Return pointer on Output Device Descriptor according index
@param zindex : zero based index
@param nType : Pointer on 32bit long receiving the type (pointer can be NULL).
@param szName : Pointer on string (256 char min) receiving the device name (pointer can be NULL).
@param szHardwareId : Pointer on string (256 char min) receiving the hardware ID (pointer can be NULL).
@return : 0: OK (no error).
*/
long __stdcall VBVMR_Output_GetDeviceDescA(long zindex, long * nType, char * szDeviceName, char * szHardwareId);
long __stdcall VBVMR_Output_GetDeviceDescW(long zindex, long * nType, unsigned short * wszDeviceName, unsigned short * wszHardwareId);
/**
@brief Get number of Audio Input Device available on the system
@return : return number of device found.
*/
long __stdcall VBVMR_Input_GetDeviceNumber(void);
/**
@brief Return pointer on Input Device Descriptor according index
@param zindex : zero based index
@param nType : Pointer on 32bit long receiving the type (pointer can be NULL).
@param szName : Pointer on string (256 char min) receiving the device name (pointer can be NULL).
@param szHardwareId : Pointer on string (256 char min) receiving the hardware ID (pointer can be NULL).
@return : 0: OK (no error).
*/
long __stdcall VBVMR_Input_GetDeviceDescA(long zindex, long * nType, char * szDeviceName, char * szHardwareId);
long __stdcall VBVMR_Input_GetDeviceDescW(long zindex, long * nType, unsigned short * wszDeviceName, unsigned short * wszHardwareId);
/** @} */
/******************************************************************************/
/* VB-AUDIO CALLBACK */
/******************************************************************************/
/* 4x Functions to process all voicemeeter audio input and output channels */
/* */
/* VBVMR_AudioCallbackRegister :to register your audio callback(s) */
/* VBVMR_AudioCallbackStart :to start the audio stream */
/* VBVMR_AudioCallbackStop :to stop the audio stream */
/* VBVMR_AudioCallbackUnregister :to unregister / Release callback(s) */
/******************************************************************************/
/** @name VB-Audio Callback Functions
* @{ */
typedef struct tagVBVMR_AUDIOINFO
{
long samplerate;
long nbSamplePerFrame;
} VBVMR_T_AUDIOINFO, *VBVMR_PT_AUDIOINFO, *VBVMR_LPT_AUDIOINFO;
typedef struct tagVBVMR_AUDIOBUFFER
{
long audiobuffer_sr; //Sampling Rate
long audiobuffer_nbs; //number of sample per frame
long audiobuffer_nbi; //number of inputs
long audiobuffer_nbo; //number of outputs
float * audiobuffer_r[128]; //nbi input pointers containing frame of nbs sample (of 32bits float)
float * audiobuffer_w[128]; //nbo output pointers containing frame of nbs sample (of 32bits float)
} VBVMR_T_AUDIOBUFFER, *VBVMR_PT_AUDIOBUFFER, *VBVMR_LPT_AUDIOBUFFER;
/**
@brief VB-AUDIO Callback is called for different task to Initialize, perform and end your process.
VB-AUDIO Callback is part of single TIME CRITICAL Thread.
VB-AUDIO Callback is non re-entrant (cannot be called while in process)
VB-AUDIO Callback is supposed to be REAL TIME when called to process buffer.
(it means that the process has to be performed as fast as possible, waiting cycles are forbidden.
do not use O/S synchronization object, even Critical_Section can generate waiting cycle. Do not use
system functions that can generate waiting cycle like display, disk or communication functions for example).
@param lpUser: User pointer given on callback registration.
@param ncommand: reason why the callback is called.
@param lpData: pointer on structure, pending on nCommand.
@param nnn: additional data, unused
@return : 0: always 0 (unused).
*/
typedef long (__stdcall *T_VBVMR_VBAUDIOCALLBACK)(void * lpUser, long nCommand, void * lpData, long nnn);
#define VBVMR_CBCOMMAND_STARTING 1 //command to initialize data according SR and buffer size
//info = (VBVMR_LPT_AUDIOINFO)lpData
#define VBVMR_CBCOMMAND_ENDING 2 //command to release data
#define VBVMR_CBCOMMAND_CHANGE 3 //If change in audio stream, you will have to restart audio
#define VBVMR_CBCOMMAND_BUFFER_IN 10 //input insert
#define VBVMR_CBCOMMAND_BUFFER_OUT 11 //bus output insert
#define VBVMR_CBCOMMAND_BUFFER_MAIN 20 //all i/o
//audiobuffer = (VBVMR_LPT_AUDIOBUFFER)lpData
//nnn = synchro = 1 if synchro with Voicemeeter
/*
-----------------------------------------------------
AUDIO BUFFER for VBVMR_CBCOMMAND_BUFFER_IN
-----------------------------------------------------
VOICEMEETER
| Strip 1 | Strip 2 | Virtual Input |
+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 |
VOICEMEETER BANANA
| Strip 1 | Strip 2 | Strip 3 | Virtual Input | Virtual Input AUX |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
VOICEMEETER 8
| Strip 1 | Strip 2 | Strip 3 | Strip 4 | Strip 5 | Virtual Input | Virtual Input AUX | Virtual Input 8 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
-----------------------------------------------------
AUDIO BUFFER for VBVMR_CBCOMMAND_BUFFER_OUT
-----------------------------------------------------
VOICEMEETER
| Output A1 / A2 | Virtual Output |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 |
VOICEMEETER BANANA
| Output A1 | Output A2 | Output A3 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| Virtual Output B1 | Virtual Output B2 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
VOICEMEETER 8
| Output A1 | Output A2 | Output A3 | Output A4 | Output A5 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
| Virtual Output B1 | Virtual Output B2 | Virtual Output B3 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
-----------------------------------------------------
AUDIO BUFFER for VBVMR_CBCOMMAND_BUFFER_MAIN
-----------------------------------------------------
VOICEMEETER
| Strip 1 | Strip 2 | Virtual Input |
+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 |
| Output A1 / A2 | Virtual Output |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
Output buffer provides outputs only:
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 |
VOICEMEETER BANANA
| Strip 1 | Strip 2 | Strip 3 | Virtual Input | Virtual Input AUX |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| Output A1 | Output A2 | Output A3 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
Output buffer provides outputs only:
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| Virtual Output B1 | Virtual Output B2 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
Output buffer provides outputs only:
| 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
VOICEMEETER 8
| Strip 1 | Strip 2 | Strip 3 | Strip 4 | Strip 5 | Virtual Input | Virtual Input AUX | Virtual Input 8 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
| Output A1 | Output A2 | Output A3 | Output A4 | Output A5 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
Output buffer provides outputs only:
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
| Virtual Output B1 | Virtual Output B2 | Virtual Output B3 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
Output buffer provides outputs only:
| 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
*/
/**
@brief register your audio callback function to receive real time audio buffer
it's possible to register up to 3x different Audio Callback in the same application or in
3x different applications. In the same application, this is possible because Voicemeeter
provides 3 kind of audio Streams:
- AUDIO INPUT INSERT (to process all Voicemeeter inputs as insert)
- AUDIO OUTPUT INSERT (to process all Voicemeeter BUS outputs as insert)
- ALL AUDIO I/O (to process all Voicemeeter i/o).
Note: a single callback can be used to receive the 3 possible audio streams.
@param mode : callback type (main, input or bus output) see define below
@param pCallback : Pointer on your callback function.
@param lpUser : user pointer (pointer that will be passed in callback first argument).
@param szClientName[64]: IN: Name of the application registering the Callback.
OUT: Name of the application already registered.
@return : 0: OK (no error).
-1: error
1: callback already registered (by another application).
*/
long __stdcall VBVMR_AudioCallbackRegister(long mode, T_VBVMR_VBAUDIOCALLBACK pCallback, void * lpUser, char szClientName[64]);
#define VBVMR_AUDIOCALLBACK_IN 0x00000001 //to process input insert
#define VBVMR_AUDIOCALLBACK_OUT 0x00000002 //to process output bus insert
#define VBVMR_AUDIOCALLBACK_MAIN 0x00000004 //to receive all i/o
/**
@brief Start / Stop Audio processing
he Callback will be called with
@return : 0: OK (no error).
-1: error
-2: no callback registred.
*/
long __stdcall VBVMR_AudioCallbackStart(void);
long __stdcall VBVMR_AudioCallbackStop(void);
/**
@brief unregister your callback to release voicemeeter virtual driver
(this function will automatically call VBVMR_AudioCallbackStop() function)
@param pCallback : Pointer on your callback function.
@return : 0: OK (no error).
-1: error
1: callback already unregistered.
*/
long __stdcall VBVMR_AudioCallbackUnregister(void);
/** @} */
/******************************************************************************/
/* 'C' STRUCTURED INTERFACE */
/******************************************************************************/
typedef long (__stdcall *T_VBVMR_Login)(void);
typedef long (__stdcall *T_VBVMR_Logout)(void);
typedef long (__stdcall *T_VBVMR_RunVoicemeeter)(long vType);
typedef long (__stdcall *T_VBVMR_GetVoicemeeterType)(long * pType);
typedef long (__stdcall *T_VBVMR_GetVoicemeeterVersion)(long * pVersion);
typedef long (__stdcall *T_VBVMR_IsParametersDirty)(void);
typedef long (__stdcall *T_VBVMR_GetParameterFloat)(char * szParamName, float * pValue);
typedef long (__stdcall *T_VBVMR_GetParameterStringA)(char * szParamName, char * szString);
typedef long (__stdcall *T_VBVMR_GetParameterStringW)(char * szParamName, unsigned short * wszString);
typedef long (__stdcall *T_VBVMR_GetLevel)(long nType, long nuChannel, float * pValue);
typedef long (__stdcall *T_VBVMR_GetMidiMessage)(unsigned char *pMIDIBuffer, long nbByteMax);
typedef long (__stdcall *T_VBVMR_SetParameterFloat)(char * szParamName, float Value);
typedef long (__stdcall *T_VBVMR_SetParameters)(char * szParamScript);
typedef long (__stdcall *T_VBVMR_SetParametersW)(unsigned short * szParamScript);
typedef long (__stdcall *T_VBVMR_SetParameterStringA)(char * szParamName, char * szString);
typedef long (__stdcall *T_VBVMR_SetParameterStringW)(char * szParamName, unsigned short * wszString);
typedef long (__stdcall *T_VBVMR_Output_GetDeviceNumber)(void);
typedef long (__stdcall *T_VBVMR_Output_GetDeviceDescA)(long zindex, long * nType, char * szDeviceName, char * szHardwareId);
typedef long (__stdcall *T_VBVMR_Output_GetDeviceDescW)(long zindex, long * nType, unsigned short * wszDeviceName, unsigned short * wszHardwareId);
typedef long (__stdcall *T_VBVMR_Input_GetDeviceNumber)(void);
typedef long (__stdcall *T_VBVMR_Input_GetDeviceDescA)(long zindex, long * nType, char * szDeviceName, char * szHardwareId);
typedef long (__stdcall *T_VBVMR_Input_GetDeviceDescW)(long zindex, long * nType, unsigned short * wszDeviceName, unsigned short * wszHardwareId);
typedef long (__stdcall *T_VBVMR_AudioCallbackRegister)(long mode, T_VBVMR_VBAUDIOCALLBACK pCallback, void * lpUser, char szClientName[64]);
typedef long (__stdcall *T_VBVMR_AudioCallbackStart)(void);
typedef long (__stdcall *T_VBVMR_AudioCallbackStop)(void);
typedef long (__stdcall *T_VBVMR_AudioCallbackUnregister)(void);
typedef struct tagVBVMR_INTERFACE
{
T_VBVMR_Login VBVMR_Login;
T_VBVMR_Logout VBVMR_Logout;
T_VBVMR_RunVoicemeeter VBVMR_RunVoicemeeter;
T_VBVMR_GetVoicemeeterType VBVMR_GetVoicemeeterType;
T_VBVMR_GetVoicemeeterVersion VBVMR_GetVoicemeeterVersion;
T_VBVMR_IsParametersDirty VBVMR_IsParametersDirty;
T_VBVMR_GetParameterFloat VBVMR_GetParameterFloat;
T_VBVMR_GetParameterStringA VBVMR_GetParameterStringA;
T_VBVMR_GetParameterStringW VBVMR_GetParameterStringW;
T_VBVMR_GetLevel VBVMR_GetLevel;
T_VBVMR_GetMidiMessage VBVMR_GetMidiMessage;
T_VBVMR_SetParameterFloat VBVMR_SetParameterFloat;
T_VBVMR_SetParameters VBVMR_SetParameters;
T_VBVMR_SetParametersW VBVMR_SetParametersW;
T_VBVMR_SetParameterStringA VBVMR_SetParameterStringA;
T_VBVMR_SetParameterStringW VBVMR_SetParameterStringW;
T_VBVMR_Output_GetDeviceNumber VBVMR_Output_GetDeviceNumber;
T_VBVMR_Output_GetDeviceDescA VBVMR_Output_GetDeviceDescA;
T_VBVMR_Output_GetDeviceDescW VBVMR_Output_GetDeviceDescW;
T_VBVMR_Input_GetDeviceNumber VBVMR_Input_GetDeviceNumber;
T_VBVMR_Input_GetDeviceDescA VBVMR_Input_GetDeviceDescA;
T_VBVMR_Input_GetDeviceDescW VBVMR_Input_GetDeviceDescW;
T_VBVMR_AudioCallbackRegister VBVMR_AudioCallbackRegister;
T_VBVMR_AudioCallbackStart VBVMR_AudioCallbackStart;
T_VBVMR_AudioCallbackStop VBVMR_AudioCallbackStop;
T_VBVMR_AudioCallbackUnregister VBVMR_AudioCallbackUnregister;
} T_VBVMR_INTERFACE, *PT_VBVMR_INTERFACE, *LPT_VBVMR_INTERFACE;
#ifdef VBUSE_LOCALLIB
// internal used (not public)
void __stdcall VBVMR_SetHinstance(HINSTANCE hinst);
#endif
#ifdef __cplusplus
}
#endif
#endif /*__VOICEMEETER_REMOTE_H__*/
+14
View File
@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by VoicemeeterClient.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
+2 -2
View File
@@ -7,7 +7,7 @@ if %ERRORLEVEL% GEQ 1 goto done
if not exist build-Editor-Desktop_Qt_5_7_MSVC2013_32bit-Release mkdir build-Editor-Desktop_Qt_5_7_MSVC2013_32bit-Release
cd build-Editor-Desktop_Qt_5_7_MSVC2013_32bit-Release
call "%VCINSTALLDIR%vcvarsall.bat" x86
"C:\Qt\5.7\msvc2013\bin\qmake.exe" ..\Editor\Editor.pro -r -spec win32-msvc2013
"C:\Qt\5.7\msvc2013\bin\qmake.exe" ..\Editor\Editor.pro -r -spec win32-msvc2013 "CONFIG+=release"
"C:\Qt\Tools\QtCreator\bin\jom.exe" clean
"C:\Qt\Tools\QtCreator\bin\jom.exe"
if %ERRORLEVEL% GEQ 1 goto done
@@ -16,7 +16,7 @@ cd..
if not exist build-Editor-Desktop_Qt_5_7_MSVC2013_64bit-Release mkdir build-Editor-Desktop_Qt_5_7_MSVC2013_64bit-Release
cd build-Editor-Desktop_Qt_5_7_MSVC2013_64bit-Release
call "%VCINSTALLDIR%vcvarsall.bat" amd64
"C:\Qt\5.7\msvc2013_64\bin\qmake.exe" ..\Editor\Editor.pro -r -spec win32-msvc2013
"C:\Qt\5.7\msvc2013_64\bin\qmake.exe" ..\Editor\Editor.pro -r -spec win32-msvc2013 "CONFIG+=release"
"C:\Qt\Tools\QtCreator\bin\jom.exe" clean
"C:\Qt\Tools\QtCreator\bin\jom.exe"
if %ERRORLEVEL% GEQ 1 goto done
+1 -1
View File
@@ -30,7 +30,7 @@ using namespace std;
#ifndef NO_FILTERENGINE
void DeviceFilterFactory::initialize(FilterEngine* engine)
{
deviceString = engine->getDeviceName() + L" " + engine->getConnectionName() + L" " + engine->getDeviceGuid();
deviceString = engine->getDeviceString();
mup::ParserX* parser = engine->getParser();
parser->DefineConst(L"deviceName", engine->getDeviceName());
+115
View File
@@ -0,0 +1,115 @@
#ifndef SCOPEGUARD_H
#define SCOPEGUARD_H
// Taken from "Declarative Control Flow" (CppCon 2015)
// adjusted to work with Visual C++ 2013
#include <exception>
#include <utility>
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define noexcept
#endif
#include "UncaughtExceptions.h"
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#undef noexcept
#endif
#define CONCATENATE_IMPL(s1, s2) s1 ## s2
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
#ifdef __COUNTER__
#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __COUNTER__)
#else
#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__)
#endif
namespace detail {
enum class ScopeGuardOnExit
{
};
enum class ScopeGuardOnFail
{
};
enum class ScopeGuardOnSuccess
{
};
template<typename Fun> class ScopeGuard
{
public:
ScopeGuard(Fun&& fn)
: fn(std::move(fn))
{
}
~ScopeGuard()
{
fn();
}
private:
Fun fn;
};
class UncaughtExceptionCounter
{
int exceptionCount_;
public:
UncaughtExceptionCounter()
: exceptionCount_(folly::uncaught_exceptions())
{
}
bool newUncaughtException()
{
return folly::uncaught_exceptions() > exceptionCount_;
}
};
template<typename FunctionType, bool executeOnException> class ScopeGuardForNewException
{
FunctionType function_;
UncaughtExceptionCounter ec_;
public:
explicit ScopeGuardForNewException(const FunctionType& fn)
: function_(fn)
{
}
explicit ScopeGuardForNewException(FunctionType&& fn)
: function_(std::move(fn))
{
}
~ScopeGuardForNewException()
{
if (executeOnException == ec_.newUncaughtException())
{
function_();
}
}
};
template<typename Fun> ScopeGuard<Fun> operator+(ScopeGuardOnExit, Fun&& fn)
{
return ScopeGuard<Fun>(std::forward<Fun>(fn));
}
template<typename Fun> ScopeGuardForNewException<typename std::decay_t<Fun>, true> operator+(detail::ScopeGuardOnFail, Fun&& fn)
{
return ScopeGuardForNewException<typename std::decay_t<Fun>, true>(std::forward<Fun>(fn));
}
template<typename Fun> ScopeGuardForNewException<typename std::decay_t<Fun>, false> operator+(detail::ScopeGuardOnSuccess, Fun&& fn)
{
return ScopeGuardForNewException<typename std::decay_t<Fun>, false>(std::forward<Fun>(fn));
}
}
#define SCOPE_FAIL auto ANONYMOUS_VARIABLE(SCOPE_FAIL_STATE) = ::detail::ScopeGuardOnFail() +[&]()
#define SCOPE_SUCCESS auto ANONYMOUS_VARIABLE(SCOPE_FAIL_STATE) = ::detail::ScopeGuardOnSuccess() +[&]()
#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) = ::detail::ScopeGuardOnExit() +[&]()
#endif
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <exception>
#if defined(__GNUG__) || defined(__CLANG__)
#define FOLLY_EXCEPTION_COUNT_USE_CXA_GET_GLOBALS
namespace __cxxabiv1 {
// forward declaration (originally defined in unwind-cxx.h from from libstdc++)
struct __cxa_eh_globals;
// declared in cxxabi.h from libstdc++-v3
extern "C" __cxa_eh_globals* __cxa_get_globals() noexcept;
}
#elif defined(_MSC_VER) && (_MSC_VER >= 1400) && \
(_MSC_VER < 1900) // MSVC++ 8.0 or greater
#define FOLLY_EXCEPTION_COUNT_USE_GETPTD
// forward declaration (originally defined in mtdll.h from MSVCRT)
struct _tiddata;
extern "C" _tiddata* _getptd(); // declared in mtdll.h from MSVCRT
#elif defined(_MSC_VER) && (_MSC_VER >= 1900) // MSVC++ 2015
#define FOLLY_EXCEPTION_COUNT_USE_STD
#else
// Raise an error when trying to use this on unsupported platforms.
#error "Unsupported platform, don't include this header."
#endif
namespace folly {
/**
* Returns the number of uncaught exceptions.
*
* This function is based on Evgeny Panasyuk's implementation from here:
* http://fburl.com/15190026
*/
inline int uncaught_exceptions() noexcept {
#if defined(FOLLY_EXCEPTION_COUNT_USE_CXA_GET_GLOBALS)
// __cxa_get_globals returns a __cxa_eh_globals* (defined in unwind-cxx.h).
// The offset below returns __cxa_eh_globals::uncaughtExceptions.
return *(reinterpret_cast<unsigned int*>(static_cast<char*>(
static_cast<void*>(__cxxabiv1::__cxa_get_globals())) + sizeof(void*)));
#elif defined(FOLLY_EXCEPTION_COUNT_USE_GETPTD)
// _getptd() returns a _tiddata* (defined in mtdll.h).
// The offset below returns _tiddata::_ProcessingThrow.
return *(reinterpret_cast<int*>(static_cast<char*>(
static_cast<void*>(_getptd())) + sizeof(void*) * 28 + 0x4 * 8));
#elif defined(FOLLY_EXCEPTION_COUNT_USE_STD)
return std::uncaught_exceptions();
#endif
}
} // namespaces
+1
View File
@@ -17,3 +17,4 @@
#include <Shlwapi.h>
#include <Ks.h>
#include <KsMedia.h>
#include "helpers/ScopeGuard.h"