Fixed: Reimplemented Voicemeeter integration (based on official examples) to fix stuttering issues.
This commit is contained in:
1 parent
da3341ed42
commit
93af3de251
5 files changed
+331
-142
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of Equalizer APO, a system-wide equalizer.
|
This file is part of Equalizer APO, a system-wide equalizer.
|
||||||
Copyright (C) 2017 Jonas Thedering
|
Copyright (C) 2022 Jonas Thedering
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include <string>
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
@@ -29,15 +29,21 @@
|
|||||||
#define voicemeeterKeyPath L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VB:Voicemeeter {17359A74-1236-5467}"
|
#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 voicemeeterWowKeyPath L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VB:Voicemeeter {17359A74-1236-5467}"
|
||||||
#define uninstallStringValueName L"UninstallString"
|
#define uninstallStringValueName L"UninstallString"
|
||||||
|
#ifdef _WIN64
|
||||||
|
#define voicemeeterRemoteFileName L"VoicemeeterRemote64.dll"
|
||||||
|
#else
|
||||||
|
#define voicemeeterRemoteFileName L"VoicemeeterRemote.dll"
|
||||||
|
#endif
|
||||||
|
#define IDM_RESTART 200
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
long __stdcall callback(void* lpUser, long nCommand, void* lpData, long nnn);
|
static long __stdcall callback(void* lpUser, long nCommand, void* lpData, long nnn);
|
||||||
|
|
||||||
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
|
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
|
||||||
_In_opt_ HINSTANCE hPrevInstance,
|
_In_opt_ HINSTANCE hPrevInstance,
|
||||||
_In_ LPTSTR lpCmdLine,
|
_In_ LPWSTR lpCmdLine,
|
||||||
_In_ int nCmdShow)
|
_In_ int nShowCmd)
|
||||||
{
|
{
|
||||||
vector<wstring> outputs;
|
vector<wstring> outputs;
|
||||||
if (lpCmdLine[0] != 0)
|
if (lpCmdLine[0] != 0)
|
||||||
@@ -49,30 +55,17 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
|
|||||||
LocalFree(argv);
|
LocalFree(argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
VoicemeeterClient* client = new VoicemeeterClient(outputs);
|
try
|
||||||
|
|
||||||
MSG msg;
|
|
||||||
msg.wParam = 0;
|
|
||||||
|
|
||||||
bool loop = client->restart;
|
|
||||||
while (loop)
|
|
||||||
{
|
{
|
||||||
client->start();
|
VoicemeeterClient client(outputs);
|
||||||
client->restart = false;
|
client.run();
|
||||||
|
return 0;
|
||||||
while (GetMessage(&msg, NULL, 0, 0))
|
}
|
||||||
{
|
catch (InitError e)
|
||||||
TranslateMessage(&msg);
|
{
|
||||||
DispatchMessage(&msg);
|
MessageBoxW(NULL, e.getMessage().c_str(), L"Init Error", MB_APPLMODAL | MB_OK | MB_ICONERROR);
|
||||||
}
|
return -1;
|
||||||
|
|
||||||
loop = client->restart;
|
|
||||||
|
|
||||||
client->stop();
|
|
||||||
}
|
}
|
||||||
delete client;
|
|
||||||
|
|
||||||
return (int)msg.wParam;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VoicemeeterClient::VoicemeeterClient(const vector<wstring>& outputs)
|
VoicemeeterClient::VoicemeeterClient(const vector<wstring>& outputs)
|
||||||
@@ -87,108 +80,72 @@ VoicemeeterClient::VoicemeeterClient(const vector<wstring>& outputs)
|
|||||||
voicemeeterDirectory = RegistryHelper::readValue(voicemeeterWowKeyPath, uninstallStringValueName);
|
voicemeeterDirectory = RegistryHelper::readValue(voicemeeterWowKeyPath, uninstallStringValueName);
|
||||||
|
|
||||||
size_t index = voicemeeterDirectory.find_last_of(L'\\');
|
size_t index = voicemeeterDirectory.find_last_of(L'\\');
|
||||||
HMODULE voicemeeterModule = NULL;
|
|
||||||
|
|
||||||
if (index != wstring::npos)
|
if (index != wstring::npos)
|
||||||
{
|
|
||||||
wstring setupFilename = voicemeeterDirectory.substr(index + 1);
|
|
||||||
voicemeeterType = 1;
|
|
||||||
if (setupFilename == L"VoicemeeterProSetup.exe")
|
|
||||||
voicemeeterType = 2;// banana
|
|
||||||
else if (setupFilename == L"Voicemeeter8Setup.exe")
|
|
||||||
voicemeeterType = 3;// potato
|
|
||||||
|
|
||||||
voicemeeterDirectory = voicemeeterDirectory.substr(0, index);
|
voicemeeterDirectory = voicemeeterDirectory.substr(0, index);
|
||||||
|
else
|
||||||
|
throw InitError(L"Voicemeeter is not installed");
|
||||||
|
|
||||||
#ifdef _WIN64
|
HMODULE module = NULL;
|
||||||
voicemeeterModule = LoadLibraryW((voicemeeterDirectory + L"\\VoicemeeterRemote64.dll").c_str());
|
module = LoadLibraryW((voicemeeterDirectory + L"\\" voicemeeterRemoteFileName).c_str());
|
||||||
#else
|
if (module == NULL)
|
||||||
voicemeeterModule = LoadLibraryW((voicemeeterDirectory + L"\\VoicemeeterRemote.dll").c_str());
|
throw InitError(L"Failed to load " voicemeeterRemoteFileName);
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&vmr, 0, sizeof(T_VBVMR_INTERFACE));
|
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;
|
#define LOAD_PROC(proc) vmr.proc = (T_ ## proc)GetProcAddress(module, # proc);if (vmr.proc == NULL) throw InitError(L"Did not find function \"" # proc L"\" in " voicemeeterRemoteFileName)
|
||||||
}
|
LOAD_PROC(VBVMR_Login);
|
||||||
|
LOAD_PROC(VBVMR_Logout);
|
||||||
|
LOAD_PROC(VBVMR_GetVoicemeeterType);
|
||||||
|
LOAD_PROC(VBVMR_IsParametersDirty);
|
||||||
|
LOAD_PROC(VBVMR_AudioCallbackRegister);
|
||||||
|
LOAD_PROC(VBVMR_AudioCallbackStart);
|
||||||
|
LOAD_PROC(VBVMR_AudioCallbackStop);
|
||||||
|
LOAD_PROC(VBVMR_AudioCallbackUnregister);
|
||||||
|
|
||||||
|
initSoftware();
|
||||||
}
|
}
|
||||||
|
|
||||||
VoicemeeterClient::~VoicemeeterClient()
|
VoicemeeterClient::~VoicemeeterClient()
|
||||||
{
|
{
|
||||||
if (loggedIn)
|
if (wTimer != 0)
|
||||||
{
|
{
|
||||||
vmr.VBVMR_Logout();
|
KillTimer(NULL, wTimer);
|
||||||
loggedIn = false;
|
wTimer = 0;
|
||||||
}
|
}
|
||||||
|
endSoftware();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoicemeeterClient::start()
|
void VoicemeeterClient::run()
|
||||||
{
|
{
|
||||||
if (!loggedIn)
|
wTimer = SetTimer(NULL, 0, 500, NULL);
|
||||||
loggedIn = (vmr.VBVMR_Login() == 0);
|
PostThreadMessage(mainThreadId, WM_COMMAND, IDM_RESTART, 0);
|
||||||
|
|
||||||
if (loggedIn)
|
MSG msg;
|
||||||
|
while (GetMessage(&msg, NULL, 0, 0))
|
||||||
{
|
{
|
||||||
long type;
|
switch (msg.message)
|
||||||
if (vmr.VBVMR_GetVoicemeeterType(&type) == 0)
|
|
||||||
voicemeeterType = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned outputCount;
|
|
||||||
if (voicemeeterType == 3)
|
|
||||||
outputCount = 5;
|
|
||||||
else if (voicemeeterType == 2)
|
|
||||||
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();
|
case WM_COMMAND:
|
||||||
engine->setDeviceInfo(false, true, L"Voicemeeter", output, L"", L"Voicemeeter " + output);
|
handleCommand(msg.wParam, msg.lParam);
|
||||||
engines.push_back(engine);
|
break;
|
||||||
|
case WM_TIMER:
|
||||||
|
if (msg.wParam == wTimer)
|
||||||
|
{
|
||||||
|
// check if Voicemeeter type has changed
|
||||||
|
if (vmr.VBVMR_IsParametersDirty() >= 0)
|
||||||
|
{
|
||||||
|
if (!connected)
|
||||||
|
detectVoicemeeterType();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Voicemeeter has been shut down
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
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)
|
void VoicemeeterClient::handle(long nCommand, void* lpData, long nnn)
|
||||||
@@ -198,26 +155,18 @@ void VoicemeeterClient::handle(long nCommand, void* lpData, long nnn)
|
|||||||
case VBVMR_CBCOMMAND_STARTING:
|
case VBVMR_CBCOMMAND_STARTING:
|
||||||
{
|
{
|
||||||
VBVMR_LPT_AUDIOINFO audioInfo = (VBVMR_LPT_AUDIOINFO)lpData;
|
VBVMR_LPT_AUDIOINFO audioInfo = (VBVMR_LPT_AUDIOINFO)lpData;
|
||||||
|
sampleRate = (float)audioInfo->samplerate;
|
||||||
|
maxFrameCount = audioInfo->nbSamplePerFrame;
|
||||||
for (FilterEngine* engine : engines)
|
for (FilterEngine* engine : engines)
|
||||||
if (engine != NULL)
|
if (engine != NULL)
|
||||||
engine->initialize((float)audioInfo->samplerate, 8, 8, 8, 0, audioInfo->nbSamplePerFrame);
|
engine->initialize(sampleRate, 8, 8, 8, 0, maxFrameCount);
|
||||||
VoicemeeterAPOInfo::saveVoicemeeterSampleRate((unsigned)audioInfo->samplerate);
|
VoicemeeterAPOInfo::saveVoicemeeterSampleRate((unsigned)audioInfo->samplerate);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VBVMR_CBCOMMAND_ENDING:
|
case VBVMR_CBCOMMAND_ENDING:
|
||||||
{
|
|
||||||
restart = true;
|
|
||||||
PostThreadMessage(mainThreadId, WM_QUIT, 0, 0);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case VBVMR_CBCOMMAND_CHANGE:
|
case VBVMR_CBCOMMAND_CHANGE:
|
||||||
{
|
PostThreadMessage(mainThreadId, WM_COMMAND, IDM_RESTART, 0);
|
||||||
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;
|
break;
|
||||||
case VBVMR_CBCOMMAND_BUFFER_OUT:
|
case VBVMR_CBCOMMAND_BUFFER_OUT:
|
||||||
{
|
{
|
||||||
@@ -262,6 +211,113 @@ void VoicemeeterClient::handle(long nCommand, void* lpData, long nnn)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VoicemeeterClient::initSoftware()
|
||||||
|
{
|
||||||
|
long rep = vmr.VBVMR_Login();
|
||||||
|
if (rep < 0)
|
||||||
|
throw InitError(L"Failed To Login");
|
||||||
|
if (vmr.VBVMR_IsParametersDirty() == 0)
|
||||||
|
detectVoicemeeterType();
|
||||||
|
else
|
||||||
|
connected = false;
|
||||||
|
unsigned tries = 30;
|
||||||
|
bool loop = true;
|
||||||
|
while (loop)
|
||||||
|
{
|
||||||
|
loop = false;
|
||||||
|
char clientName[64] = "Equalizer APO";
|
||||||
|
rep = vmr.VBVMR_AudioCallbackRegister(VBVMR_AUDIOCALLBACK_OUT, callback, this, clientName);
|
||||||
|
if (rep == 1)
|
||||||
|
{
|
||||||
|
wchar_t message[512];
|
||||||
|
wsprintf(message, L"Voicemeeter Output Insert already in use by:\n%S", clientName);
|
||||||
|
throw InitError(message);
|
||||||
|
}
|
||||||
|
else if (rep != 0)
|
||||||
|
{
|
||||||
|
if (tries > 1)
|
||||||
|
{
|
||||||
|
// sometimes fails temporarily after restarting VoicemeeterClient
|
||||||
|
Sleep(100);
|
||||||
|
tries--;
|
||||||
|
loop = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw InitError(L"Failed to register audio callback");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoicemeeterClient::detectVoicemeeterType()
|
||||||
|
{
|
||||||
|
long vmType;
|
||||||
|
long rep = vmr.VBVMR_GetVoicemeeterType(&vmType);
|
||||||
|
if (rep == 0)
|
||||||
|
{
|
||||||
|
connected = true;
|
||||||
|
|
||||||
|
unsigned outputCount;
|
||||||
|
if (vmType == 3)
|
||||||
|
outputCount = 5;
|
||||||
|
else if (vmType == 2)
|
||||||
|
outputCount = 3;
|
||||||
|
else
|
||||||
|
outputCount = 1;
|
||||||
|
|
||||||
|
if (outputCount != engines.size())
|
||||||
|
{
|
||||||
|
idleSampleCounts.clear();
|
||||||
|
for (FilterEngine* engine : engines)
|
||||||
|
if (engine != NULL)
|
||||||
|
delete engine;
|
||||||
|
engines.clear();
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (sampleRate != 0.0f && maxFrameCount != 0)
|
||||||
|
engine->initialize(sampleRate, 8, 8, 8, 0, maxFrameCount);
|
||||||
|
engines.push_back(engine);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
engines.push_back(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
idleSampleCounts.push_back(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoicemeeterClient::endSoftware()
|
||||||
|
{
|
||||||
|
if (vmr.VBVMR_Logout != NULL)
|
||||||
|
vmr.VBVMR_Logout();
|
||||||
|
if (vmr.VBVMR_AudioCallbackUnregister != NULL)
|
||||||
|
vmr.VBVMR_AudioCallbackUnregister();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoicemeeterClient::handleCommand(WPARAM wparam, LPARAM lparam)
|
||||||
|
{
|
||||||
|
switch (LOWORD(wparam))
|
||||||
|
{
|
||||||
|
case IDM_RESTART:
|
||||||
|
Sleep(50);
|
||||||
|
if (vmr.VBVMR_AudioCallbackStart != NULL)
|
||||||
|
vmr.VBVMR_AudioCallbackStart();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool VoicemeeterClient::isBufferSilent(float** sampleData, long sampleCount)
|
bool VoicemeeterClient::isBufferSilent(float** sampleData, long sampleCount)
|
||||||
{
|
{
|
||||||
bool silent = true;
|
bool silent = true;
|
||||||
@@ -282,7 +338,7 @@ bool VoicemeeterClient::isBufferSilent(float** sampleData, long sampleCount)
|
|||||||
return silent;
|
return silent;
|
||||||
}
|
}
|
||||||
|
|
||||||
long __stdcall callback(void* lpUser, long nCommand, void* lpData, long nnn)
|
static long __stdcall callback(void* lpUser, long nCommand, void* lpData, long nnn)
|
||||||
{
|
{
|
||||||
VoicemeeterClient* client = (VoicemeeterClient*)lpUser;
|
VoicemeeterClient* client = (VoicemeeterClient*)lpUser;
|
||||||
client->handle(nCommand, lpData, nnn);
|
client->handle(nCommand, lpData, nnn);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of Equalizer APO, a system-wide equalizer.
|
This file is part of Equalizer APO, a system-wide equalizer.
|
||||||
Copyright (C) 2017 Jonas Thedering
|
Copyright (C) 2022 Jonas Thedering
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -29,20 +29,41 @@ class VoicemeeterClient
|
|||||||
public:
|
public:
|
||||||
VoicemeeterClient(const std::vector<std::wstring>& outputs);
|
VoicemeeterClient(const std::vector<std::wstring>& outputs);
|
||||||
~VoicemeeterClient();
|
~VoicemeeterClient();
|
||||||
void start();
|
void run();
|
||||||
void stop();
|
|
||||||
|
|
||||||
void handle(long nCommand, void* lpData, long nnn);
|
void handle(long nCommand, void* lpData, long nnn);
|
||||||
bool restart = false;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void initSoftware();
|
||||||
|
void detectVoicemeeterType();
|
||||||
|
void endSoftware();
|
||||||
|
void handleCommand(WPARAM wparam, LPARAM lparam);
|
||||||
bool isBufferSilent(float** sampleData, long sampleCount);
|
bool isBufferSilent(float** sampleData, long sampleCount);
|
||||||
|
|
||||||
|
std::vector<std::wstring> outputs;
|
||||||
unsigned long mainThreadId;
|
unsigned long mainThreadId;
|
||||||
T_VBVMR_INTERFACE vmr;
|
T_VBVMR_INTERFACE vmr;
|
||||||
|
size_t wTimer = 0;
|
||||||
|
bool connected = true;
|
||||||
|
float sampleRate = 0.0f;
|
||||||
|
unsigned maxFrameCount = 0;
|
||||||
|
|
||||||
std::vector<FilterEngine*> engines;
|
std::vector<FilterEngine*> engines;
|
||||||
std::vector<int> idleSampleCounts;
|
std::vector<int> idleSampleCounts;
|
||||||
bool loggedIn = false;
|
};
|
||||||
long voicemeeterType = 1;
|
|
||||||
std::vector<std::wstring> outputs;
|
class InitError
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InitError(const std::wstring& message)
|
||||||
|
: message(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring getMessage()
|
||||||
|
{
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::wstring message;
|
||||||
};
|
};
|
||||||
Binary file not shown.
@@ -1,22 +1,20 @@
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* Voicemeeter Remote API. V.Burel©2015 */
|
/* Voicemeeter Remote API. V.Burel©2015-2021 */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* This Library allows communication with Voicemeeter Applications */
|
/* This Library allows communication with Voicemeeter applications */
|
||||||
/* 4 Client Applications can be connected to remote Voicemeeter. */
|
/* 4 Client Applications can be connected to remote Voicemeeter. */
|
||||||
|
/* it also allows communication with MacroButtons application. */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* OFFICIAL LINK : WWW.VOICEMEETER.COM */
|
/* OFFICIAL LINK : WWW.VOICEMEETER.COM */
|
||||||
/* */
|
/* */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* COPYRIGHT: Vincent Burel(c)2015 All Rights Reserved */
|
/* COPYRIGHT: Vincent Burel(c)2015-2021 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, */
|
/* LICENSING: VoicemeeterRemote.dll usage is driven by a license agreement */
|
||||||
/* a commercial license needs to be purchased. thanks to contact */
|
/* given in VoicemeeterRemoteAPI.pdf or readme.txt */
|
||||||
/* us by e-mail (get our contact on www.vb-audio.com). */
|
/* */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* long = 32 bit integer */
|
/* long = 32 bit integer */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -61,9 +59,10 @@ long __stdcall VBVMR_Logout(void);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Run Voicemeeter Application (get installation directory and run Voicemeeter Application).
|
@brief Run Voicemeeter Application (get installation directory and run Voicemeeter Application).
|
||||||
@param vType : Voicemeeter type (1 = Voicemeeter, 2= Voicemeeter Banana).
|
@param vType : Voicemeeter type (1 = Voicemeeter, 2= Voicemeeter Banana, 3= Voicemeeter Potato, 6 = Potato x64 bits).
|
||||||
@return : 0: Ok.
|
@return : 0: Ok.
|
||||||
-1: not installed
|
-1: not installed (UninstallString not found in registry).
|
||||||
|
-2: unknown vType number
|
||||||
*/
|
*/
|
||||||
|
|
||||||
long __stdcall VBVMR_RunVoicemeeter(long vType);
|
long __stdcall VBVMR_RunVoicemeeter(long vType);
|
||||||
@@ -106,6 +105,11 @@ long __stdcall VBVMR_RunVoicemeeter(long vType);
|
|||||||
+---------+---------+---------+-------------+-----------+------+------+------+------+------+
|
+---------+---------+---------+-------------+-----------+------+------+------+------+------+
|
||||||
| 0 | 1 | 2 | 3 | 4 | 0 | 1 | 2 | 3 | 4 |
|
| 0 | 1 | 2 | 3 | 4 | 0 | 1 | 2 | 3 | 4 |
|
||||||
|
|
||||||
|
VOICEMEETER POTATO STRIP/BUS INDEX ASSIGNMENT
|
||||||
|
|
||||||
|
| Strip 1 | Strip 2 | Strip 2 | Strip 2 | Strip 2 |Virtual Input|Virtual AUX| VAIO3 |BUS A1|BUS A2|BUS A3|BUS A4|BUS A5|BUS B1|BUS B2|BUS B3|
|
||||||
|
+---------+---------+---------+---------+---------+-------------+-----------+-----------+------+------+------+------+------+------+------+------+
|
||||||
|
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|
||||||
|
|
||||||
|
|
||||||
@return : 0: OK (no error).
|
@return : 0: OK (no error).
|
||||||
@@ -255,6 +259,20 @@ long __stdcall VBVMR_GetParameterStringW(char * szParamName, unsigned short * ws
|
|||||||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||||||
| 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
|
| 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
|
||||||
|
|
||||||
|
VOICEMEETER POTATO CHANNEL ASSIGNMENT
|
||||||
|
|
||||||
|
| Strip 1 | Strip 2 | Strip 3 | Strip 4 | Strip 5 | Virtual Input | Virtual Input AUX | VAIO3 |
|
||||||
|
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||||||
|
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
|
||||||
|
|
||||||
|
| 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 |
|
||||||
|
|
||||||
|
|
||||||
@return : 0: OK (no error).
|
@return : 0: OK (no error).
|
||||||
-1: error
|
-1: error
|
||||||
@@ -681,6 +699,66 @@ long __stdcall VBVMR_AudioCallbackUnregister(void);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* Macro Buttons */
|
||||||
|
/* */
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/** @name Macro Buttons functions
|
||||||
|
* @{ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Check if Macro Buttons states changed.
|
||||||
|
Call this function periodically (typically every 50 or 500ms) to know if something happen on MacroButton states .
|
||||||
|
(this function must be called from one thread only)
|
||||||
|
|
||||||
|
@return: 0: no new status.
|
||||||
|
>0: last nu logical button status changed.
|
||||||
|
-1: error (unexpected)
|
||||||
|
-2: no server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
long __stdcall VBVMR_MacroButton_IsDirty(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief get current status of a given button.
|
||||||
|
@param nuLogicalButton : button index: 0 to 79)
|
||||||
|
@param pValue : Pointer on float (32bit float by reference) receiving the wanted value (0.0 = OFF / 1.0 = ON).
|
||||||
|
@param bitmode: define what kind of value you want to read (see MACROBUTTON_MODE below)
|
||||||
|
@return : 0: OK (no error).
|
||||||
|
-1: error
|
||||||
|
-2: no server.
|
||||||
|
-3: unknown parameter
|
||||||
|
-5: structure mismatch
|
||||||
|
*/
|
||||||
|
|
||||||
|
long __stdcall VBVMR_MacroButton_GetStatus(long nuLogicalButton, float * pValue, long bitmode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief set current button value.
|
||||||
|
@param nuLogicalButton : button index: 0 to 79)
|
||||||
|
@param fValue : float 32 bit value giving the status (0.0 = OFF / 1.0 = ON).
|
||||||
|
@param bitmode: define what kind of value you want to write/modify (see MACROBUTTON_MODE below)
|
||||||
|
@return : 0: OK (no error).
|
||||||
|
-1: error
|
||||||
|
-2: no server.
|
||||||
|
-3: unknown parameter
|
||||||
|
-5: structure mismatch
|
||||||
|
*/
|
||||||
|
|
||||||
|
long __stdcall VBVMR_MacroButton_SetStatus(long nuLogicalButton, float fValue, long bitmode);
|
||||||
|
|
||||||
|
#define VBVMR_MACROBUTTON_MODE_DEFAULT 0x00000000 //PUSH or RELEASE button
|
||||||
|
#define VBVMR_MACROBUTTON_MODE_STATEONLY 0x00000002 //change Displayed State only
|
||||||
|
#define VBVMR_MACROBUTTON_MODE_TRIGGER 0x00000003 //change Trigger State
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -725,6 +803,11 @@ typedef long (__stdcall *T_VBVMR_AudioCallbackStart)(void);
|
|||||||
typedef long (__stdcall *T_VBVMR_AudioCallbackStop)(void);
|
typedef long (__stdcall *T_VBVMR_AudioCallbackStop)(void);
|
||||||
typedef long (__stdcall *T_VBVMR_AudioCallbackUnregister)(void);
|
typedef long (__stdcall *T_VBVMR_AudioCallbackUnregister)(void);
|
||||||
|
|
||||||
|
typedef long (__stdcall *T_VBVMR_MacroButton_IsDirty)(void);
|
||||||
|
typedef long (__stdcall *T_VBVMR_MacroButton_GetStatus)(long nuLogicalButton, float * pValue, long bitmode);
|
||||||
|
typedef long (__stdcall *T_VBVMR_MacroButton_SetStatus)(long nuLogicalButton, float fValue, long bitmode);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct tagVBVMR_INTERFACE
|
typedef struct tagVBVMR_INTERFACE
|
||||||
{
|
{
|
||||||
@@ -759,6 +842,10 @@ typedef struct tagVBVMR_INTERFACE
|
|||||||
T_VBVMR_AudioCallbackStop VBVMR_AudioCallbackStop;
|
T_VBVMR_AudioCallbackStop VBVMR_AudioCallbackStop;
|
||||||
T_VBVMR_AudioCallbackUnregister VBVMR_AudioCallbackUnregister;
|
T_VBVMR_AudioCallbackUnregister VBVMR_AudioCallbackUnregister;
|
||||||
|
|
||||||
|
T_VBVMR_MacroButton_IsDirty VBVMR_MacroButton_IsDirty;
|
||||||
|
T_VBVMR_MacroButton_GetStatus VBVMR_MacroButton_GetStatus;
|
||||||
|
T_VBVMR_MacroButton_SetStatus VBVMR_MacroButton_SetStatus;
|
||||||
|
|
||||||
} T_VBVMR_INTERFACE, *PT_VBVMR_INTERFACE, *LPT_VBVMR_INTERFACE;
|
} T_VBVMR_INTERFACE, *PT_VBVMR_INTERFACE, *LPT_VBVMR_INTERFACE;
|
||||||
|
|
||||||
#ifdef VBUSE_LOCALLIB
|
#ifdef VBUSE_LOCALLIB
|
||||||
@@ -766,6 +853,31 @@ typedef struct tagVBVMR_INTERFACE
|
|||||||
void __stdcall VBVMR_SetHinstance(HINSTANCE hinst);
|
void __stdcall VBVMR_SetHinstance(HINSTANCE hinst);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* LOCAL FUNCTIONS */
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
long VBVMR_LocalInit(void);
|
||||||
|
long VBVMR_LocalEnd(void);
|
||||||
|
void * VBVMR_GetRequestVB0STREAMPTR(void);
|
||||||
|
|
||||||
|
long VBVMR_SetParametersWEx(unsigned short * szParamScript, long fCopyToClient);
|
||||||
|
|
||||||
|
long VBVMR_LoginEx(long properties);
|
||||||
|
|
||||||
|
long VBVMR_MB_PushSettings(void * lpParam);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
class PrecisionTimer
|
class PrecisionTimer
|
||||||
{
|
{
|
||||||
LARGE_INTEGER freq;
|
LARGE_INTEGER freq;
|
||||||
LARGE_INTEGER startCount;
|
LARGE_INTEGER startCount{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PrecisionTimer()
|
PrecisionTimer()
|
||||||
|
|||||||
Reference in new issue
Block a user