Add user-friendliness

This commit is contained in:
nastys
2019-08-04 02:07:05 +02:00
parent a8f6f1e8ea
commit 058a2c68a3
29 changed files with 55872 additions and 4358 deletions
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{EE1A551A-49A0-40F2-8C2E-862D0AE55B43}</ProjectGuid>
<RootNamespace>DivaSound</RootNamespace>
<ProjectName>DivaSound</ProjectName>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<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|x64'">
<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|x64'">
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);detours/include;miniaudio;bassasio</IncludePath>
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;detours/lib;bassasio</LibraryPath>
<TargetExt>.dva</TargetExt>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);detours/include;miniaudio;bassasio</IncludePath>
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;detours/lib;bassasio</LibraryPath>
<TargetExt>.dva</TargetExt>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<AdditionalDependencies>detours.lib;syelog.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>detours.lib;syelog.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\dllmain.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\framework.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\framework.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -0,0 +1,160 @@
/*
BASSASIO 1.4 C/C++ header file
Copyright (c) 2005-2019 Un4seen Developments Ltd.
See the BASSASIO.CHM file for more detailed documentation
*/
/*
DivaSound version -- loads the required functions at runtime
*/
#ifndef BASSASIO_H
#define BASSASIO_H
#include <wtypes.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef BASSASIODEF
#define BASSASIODEF(f) WINAPI f
#endif
#define BASSASIOVERSION 0x104 // API version
// error codes returned by BASS_ASIO_ErrorGetCode
#define BASS_OK 0 // all is OK
#define BASS_ERROR_FILEOPEN 2 // can't open the file
#define BASS_ERROR_DRIVER 3 // can't find a free/valid driver
#define BASS_ERROR_HANDLE 5 // invalid handle
#define BASS_ERROR_FORMAT 6 // unsupported sample format
#define BASS_ERROR_INIT 8 // BASS_ASIO_Init has not been successfully called
#define BASS_ERROR_START 9 // BASS_ASIO_Start has/hasn't been called
#define BASS_ERROR_ALREADY 14 // already initialized/started
#define BASS_ERROR_NOCHAN 18 // no channels are enabled
#define BASS_ERROR_ILLPARAM 20 // an illegal parameter was specified
#define BASS_ERROR_DEVICE 23 // illegal device number
#define BASS_ERROR_NOTAVAIL 37 // not available
#define BASS_ERROR_UNKNOWN -1 // some other mystery error
// BASS_ASIO_Init flags
#define BASS_ASIO_THREAD 1 // host driver in dedicated thread
#define BASS_ASIO_JOINORDER 2 // order joined channels by when they were joined
// device info structure
typedef struct {
const char *name; // description
const char *driver; // driver
} BASS_ASIO_DEVICEINFO;
typedef struct {
char name[32]; // driver name
DWORD version; // driver version
DWORD inputs; // number of inputs
DWORD outputs; // number of outputs
DWORD bufmin; // minimum buffer length
DWORD bufmax; // maximum buffer length
DWORD bufpref; // preferred/default buffer length
int bufgran; // buffer length granularity
DWORD initflags; // BASS_ASIO_Init "flags" parameter
} BASS_ASIO_INFO;
typedef struct {
DWORD group;
DWORD format; // sample format (BASS_ASIO_FORMAT_xxx)
char name[32]; // channel name
} BASS_ASIO_CHANNELINFO;
// sample formats
#define BASS_ASIO_FORMAT_16BIT 16 // 16-bit integer
#define BASS_ASIO_FORMAT_24BIT 17 // 24-bit integer
#define BASS_ASIO_FORMAT_32BIT 18 // 32-bit integer
#define BASS_ASIO_FORMAT_FLOAT 19 // 32-bit floating-point
#define BASS_ASIO_FORMAT_DSD_LSB 32 // DSD (LSB 1st)
#define BASS_ASIO_FORMAT_DSD_MSB 33 // DSD (MSB 1st)
#define BASS_ASIO_FORMAT_DITHER 0x100 // flag: apply dither when converting from floating-point to integer
// BASS_ASIO_ChannelReset flags
#define BASS_ASIO_RESET_ENABLE 1 // disable channel
#define BASS_ASIO_RESET_JOIN 2 // unjoin channel
#define BASS_ASIO_RESET_PAUSE 4 // unpause channel
#define BASS_ASIO_RESET_FORMAT 8 // reset sample format to native format
#define BASS_ASIO_RESET_RATE 16 // reset sample rate to device rate
#define BASS_ASIO_RESET_VOLUME 32 // reset volume to 1.0
#define BASS_ASIO_RESET_JOINED 0x10000 // apply to joined channels too
// BASS_ASIO_ChannelIsActive return values
#define BASS_ASIO_ACTIVE_DISABLED 0
#define BASS_ASIO_ACTIVE_ENABLED 1
#define BASS_ASIO_ACTIVE_PAUSED 2
typedef DWORD (CALLBACK ASIOPROC)(BOOL input, DWORD channel, void *buffer, DWORD length, void *user);
/* ASIO channel callback function.
input : Input? else output
channel: Channel number
buffer : Buffer containing the sample data
length : Number of bytes
user : The 'user' parameter given when calling BASS_ASIO_ChannelEnable
RETURN : The number of bytes written (ignored with input channels) */
typedef void (CALLBACK ASIONOTIFYPROC)(DWORD notify, void *user);
/* Driver notification callback function.
notify : The notification (BASS_ASIO_NOTIFY_xxx)
user : The 'user' parameter given when calling BASS_ASIO_SetNotify */
// driver notifications
#define BASS_ASIO_NOTIFY_RATE 1 // sample rate change
#define BASS_ASIO_NOTIFY_RESET 2 // reset (reinitialization) request
// BASS_ASIO_ChannelGetLevel flags
#define BASS_ASIO_LEVEL_RMS 0x1000000
HMODULE bassAsioModule = LoadLibraryW(L"bassasio.dll");
DWORD(WINAPI* BASS_ASIO_GetVersion)() = (DWORD(WINAPI*)())GetProcAddress(bassAsioModule, "BASS_ASIO_GetVersion");
// BOOL BASSASIODEF(BASS_ASIO_SetUnicode)(BOOL unicode);
// DWORD BASSASIODEF(BASS_ASIO_ErrorGetCode)();
// BOOL BASSASIODEF(BASS_ASIO_GetDeviceInfo)(DWORD device, BASS_ASIO_DEVICEINFO *info);
// DWORD BASSASIODEF(BASS_ASIO_AddDevice)(const GUID *clsid, const char *driver, const char *name);
// BOOL BASSASIODEF(BASS_ASIO_SetDevice)(DWORD device);
// DWORD BASSASIODEF(BASS_ASIO_GetDevice)();
BOOL(WINAPI* BASS_ASIO_Init)(int device, DWORD flags) = (BOOL(WINAPI*)(int device, DWORD flags))GetProcAddress(bassAsioModule, "BASS_ASIO_Init");
BOOL(WINAPI* BASS_ASIO_Free)() = (BOOL(WINAPI*)())GetProcAddress(bassAsioModule, "BASS_ASIO_Free");
// BOOL BASSASIODEF(BASS_ASIO_Lock)(BOOL lock);
// BOOL BASSASIODEF(BASS_ASIO_SetNotify)(ASIONOTIFYPROC *proc, void *user);
BOOL(WINAPI* BASS_ASIO_ControlPanel)() = (BOOL(WINAPI*)())GetProcAddress(bassAsioModule, "BASS_ASIO_ControlPanel");
BOOL(WINAPI* BASS_ASIO_GetInfo)(BASS_ASIO_INFO *info) = (BOOL(WINAPI*)(BASS_ASIO_INFO *info))GetProcAddress(bassAsioModule, "BASS_ASIO_GetInfo");
BOOL(WINAPI* BASS_ASIO_CheckRate)(double rate) = (BOOL(WINAPI*)(double rate))GetProcAddress(bassAsioModule, "BASS_ASIO_CheckRate");
BOOL(WINAPI* BASS_ASIO_SetRate)(double rate) = (BOOL(WINAPI*)(double rate))GetProcAddress(bassAsioModule, "BASS_ASIO_SetRate");
double(WINAPI* BASS_ASIO_GetRate)() = (double(WINAPI*)())GetProcAddress(bassAsioModule, "BASS_ASIO_GetRate");
BOOL(WINAPI* BASS_ASIO_Start)(DWORD buflen, DWORD threads) = (BOOL(WINAPI*)(DWORD buflen, DWORD threads))GetProcAddress(bassAsioModule, "BASS_ASIO_Start");
BOOL(WINAPI* BASS_ASIO_Stop)() = (BOOL(WINAPI*)())GetProcAddress(bassAsioModule, "BASS_ASIO_Stop");
BOOL(WINAPI* BASS_ASIO_IsStarted)() = (BOOL(WINAPI*)())GetProcAddress(bassAsioModule, "BASS_ASIO_IsStarted");
// DWORD BASSASIODEF(BASS_ASIO_GetLatency)(BOOL input);
// float BASSASIODEF(BASS_ASIO_GetCPU)();
// BOOL BASSASIODEF(BASS_ASIO_Monitor)(int input, DWORD output, DWORD gain, DWORD state, DWORD pan);
// BOOL BASSASIODEF(BASS_ASIO_SetDSD)(BOOL dsd);
// BOOL BASSASIODEF(BASS_ASIO_Future)(DWORD selector, void *param);
// BOOL BASSASIODEF(BASS_ASIO_ChannelGetInfo)(BOOL input, DWORD channel, BASS_ASIO_CHANNELINFO *info);
// BOOL BASSASIODEF(BASS_ASIO_ChannelReset)(BOOL input, int channel, DWORD flags);
BOOL(WINAPI* BASS_ASIO_ChannelEnable)(BOOL input, DWORD channel, ASIOPROC *proc, void *user) = (BOOL(WINAPI*)(BOOL input, DWORD channel, ASIOPROC *proc, void *user))GetProcAddress(bassAsioModule, "BASS_ASIO_ChannelEnable");
// BOOL BASSASIODEF(BASS_ASIO_ChannelEnableMirror)(DWORD channel, BOOL input2, DWORD channel2);
// BOOL BASSASIODEF(BASS_ASIO_ChannelEnableBASS)(BOOL input, DWORD channel, DWORD handle, BOOL join);
BOOL(WINAPI* BASS_ASIO_ChannelJoin)(BOOL input, DWORD channel, int channel2) = (BOOL(WINAPI*)(BOOL input, DWORD channel, int channel2))GetProcAddress(bassAsioModule, "BASS_ASIO_ChannelJoin");
// BOOL BASSASIODEF(BASS_ASIO_ChannelPause)(BOOL input, DWORD channel);
// DWORD BASSASIODEF(BASS_ASIO_ChannelIsActive)(BOOL input, DWORD channel);
BOOL(WINAPI* BASS_ASIO_ChannelSetFormat)(BOOL input, DWORD channel, DWORD format) = (BOOL(WINAPI*)(BOOL input, DWORD channel, DWORD format))GetProcAddress(bassAsioModule, "BASS_ASIO_ChannelSetFormat");
// DWORD BASSASIODEF(BASS_ASIO_ChannelGetFormat)(BOOL input, DWORD channel);
BOOL(WINAPI* BASS_ASIO_ChannelSetRate)(BOOL input, DWORD channel, double rate) = (BOOL(WINAPI*)(BOOL input, DWORD channel, double rate))GetProcAddress(bassAsioModule, "BASS_ASIO_ChannelSetRate");
// double BASSASIODEF(BASS_ASIO_ChannelGetRate)(BOOL input, DWORD channel);
// BOOL BASSASIODEF(BASS_ASIO_ChannelSetVolume)(BOOL input, int channel, float volume);
// float BASSASIODEF(BASS_ASIO_ChannelGetVolume)(BOOL input, int channel);
// float BASSASIODEF(BASS_ASIO_ChannelGetLevel)(BOOL input, DWORD channel);
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,27 @@
//////////////////////////////////////////////////////////////////////////////
//
// Common version parameters.
//
// Microsoft Research Detours Package, Version 4.0.1
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
#define _USING_V110_SDK71_ 1
#include "winver.h"
#if 0
#include <windows.h>
#include <detours.h>
#else
#ifndef DETOURS_STRINGIFY
#define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x)
#define DETOURS_STRINGIFY_(x) #x
#endif
#define VER_FILEFLAGSMASK 0x3fL
#define VER_FILEFLAGS 0x0L
#define VER_FILEOS 0x00040004L
#define VER_FILETYPE 0x00000002L
#define VER_FILESUBTYPE 0x00000000L
#endif
#define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS)
@@ -0,0 +1,89 @@
//////////////////////////////////////////////////////////////////////////////
//
// Detours Test Program (syelog.h of syelog.lib)
//
// Microsoft Research Detours Package
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
#pragma once
#ifndef _SYELOGD_H_
#define _SYELOGD_H_
#include <stdarg.h>
#pragma pack(push, 1)
#pragma warning(push)
#pragma warning(disable: 4200)
//////////////////////////////////////////////////////////////////////////////
//
//
#define SYELOG_PIPE_NAMEA "\\\\.\\pipe\\syelog"
#define SYELOG_PIPE_NAMEW L"\\\\.\\pipe\\syelog"
#ifdef UNICODE
#define SYELOG_PIPE_NAME SYELOG_PIPE_NAMEW
#else
#define SYELOG_PIPE_NAME SYELOG_PIPE_NAMEA
#endif
//////////////////////////////////////////////////////////////////////////////
//
#define SYELOG_MAXIMUM_MESSAGE 4086 // 4096 - sizeof(header stuff)
typedef struct _SYELOG_MESSAGE
{
USHORT nBytes;
BYTE nFacility;
BYTE nSeverity;
DWORD nProcessId;
FILETIME ftOccurance;
BOOL fTerminate;
CHAR szMessage[SYELOG_MAXIMUM_MESSAGE];
} SYELOG_MESSAGE, *PSYELOG_MESSAGE;
// Facility Codes.
//
#define SYELOG_FACILITY_KERNEL 0x10 // OS Kernel
#define SYELOG_FACILITY_SECURITY 0x20 // OS Security
#define SYELOG_FACILITY_LOGGING 0x30 // OS Logging-internal
#define SYELOG_FACILITY_SERVICE 0x40 // User-mode system daemon
#define SYELOG_FACILITY_APPLICATION 0x50 // User-mode application
#define SYELOG_FACILITY_USER 0x60 // User self-generated.
#define SYELOG_FACILITY_LOCAL0 0x70 // Locally defined.
#define SYELOG_FACILITY_LOCAL1 0x71 // Locally defined.
#define SYELOG_FACILITY_LOCAL2 0x72 // Locally defined.
#define SYELOG_FACILITY_LOCAL3 0x73 // Locally defined.
#define SYELOG_FACILITY_LOCAL4 0x74 // Locally defined.
#define SYELOG_FACILITY_LOCAL5 0x75 // Locally defined.
#define SYELOG_FACILITY_LOCAL6 0x76 // Locally defined.
#define SYELOG_FACILITY_LOCAL7 0x77 // Locally defined.
#define SYELOG_FACILITY_LOCAL8 0x78 // Locally defined.
#define SYELOG_FACILITY_LOCAL9 0x79 // Locally defined.
// Severity Codes.
//
#define SYELOG_SEVERITY_FATAL 0x00 // System is dead.
#define SYELOG_SEVERITY_ALERT 0x10 // Take action immediately.
#define SYELOG_SEVERITY_CRITICAL 0x20 // Critical condition.
#define SYELOG_SEVERITY_ERROR 0x30 // Error
#define SYELOG_SEVERITY_WARNING 0x40 // Warning
#define SYELOG_SEVERITY_NOTICE 0x50 // Significant condition.
#define SYELOG_SEVERITY_INFORMATION 0x60 // Informational
#define SYELOG_SEVERITY_AUDIT_FAIL 0x66 // Audit Failed
#define SYELOG_SEVERITY_AUDIT_PASS 0x67 // Audit Succeeeded
#define SYELOG_SEVERITY_DEBUG 0x70 // Debugging
// Logging Functions.
//
VOID SyelogOpen(PCSTR pszIdentifier, BYTE nFacility);
VOID Syelog(BYTE nSeverity, PCSTR pszMsgf, ...);
VOID SyelogV(BYTE nSeverity, PCSTR pszMsgf, va_list args);
VOID SyelogClose(BOOL fTerminate);
#pragma warning(pop)
#pragma pack(pop)
#endif // _SYELOGD_H_
//
///////////////////////////////////////////////////////////////// End of File.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,412 @@
#include "framework.h"
#include <detours.h>
#pragma comment(lib, "detours.lib")
#include <windows.h>
#include <iostream>
#include <vector>
#include <strsafe.h>
#include <bassasio.h>
void InjectCode(void* address, const std::vector<uint8_t> data)
{
const size_t byteCount = data.size() * sizeof(uint8_t);
DWORD oldProtect;
VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(address, data.data(), byteCount);
VirtualProtect(address, byteCount, oldProtect, nullptr);
}
void NopBytes(void* address, unsigned int num)
{
std::vector<uint8_t> newbytes = {};
for (int i = 0; i < num; ++i) newbytes.push_back(0x90);
InjectCode(address, newbytes);
}
void resizeInternalBuffers(uint64_t frames)
{
divaBufSizeInFrames = frames;
divaAudioMixCls->mixbuffer = new float[divaBufSizeInFrames * 4];
divaAudioMixCls->mixbuffer_size = divaBufSizeInFrames * 4 * 4;
divaAudioMixCls->state2->buffer = new float[divaBufSizeInFrames * 4];
divaAudioMixCls->state2->buffer_size = divaBufSizeInFrames * 4 * 4;
divaAudCls->buffer_size = divaBufSizeInFrames;
printf("[DivaSound] Resized internal buffers to %d frames\n", frames);
}
void resizeTestLoop()
{
bool dir = true;
while (true)
{
Sleep(5000);
if (dir)
resizeInternalBuffers(divaBufSizeInFrames + 3000);
else
resizeInternalBuffers(divaBufSizeInFrames - 3000);
dir = !dir;
}
}
void audioCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{
(void)pDevice;
(void)pOutput;
(void)pInput;
(void)frameCount;
//printf("%d", divaAudCls->idk);
if (frameCount > divaBufSizeInFrames)
{
printf("[DivaSound] Warning: PDAFT buffer is too small\n");
//frameCount = divaBufSizeInFrames;
// allocate a larger buffer if necessary.
// add 128 frames of padding because this isn't normal and we want to avoid it happening again if possible.
resizeInternalBuffers(frameCount + 128);
}
divaAudioFillbuffer(divaAudioMixCls, (int16_t*)pOutput, frameCount, 0, 0);
//printf("%p %d\n", divaAudioMixCls, ((int16_t*)pOutput)[0]);
if (bitDepth > 16) // we should generate the output buffer ourselves
{
float volumes[4];
for (int i = 0; i < 4; i++)
{
volumes[i] = divaAudioMixCls->volume_master * divaAudioMixCls->volume_channels[i];
}
int startChannel = 4 - nChannels;
for (int i = 0; i < frameCount; i++)
{
for (int currentChannel = startChannel; currentChannel < 4; currentChannel++)
{
// note: currentChannel is for the game's buffer, outputChannel is for our output buffer.
// outputChannel should also be used for volumes.
int outputChannel = currentChannel - startChannel;
if (bitDepth == 24) // 24 bit int output
{
int32_t out_val = divaAudioMixCls->mixbuffer[i*4 + currentChannel] * volumes[outputChannel] * 8388607.0f;
if (out_val > 8388607) out_val = 8388607;
else if (out_val < -8388608) out_val = -8388608;
uint64_t out_pos = (i*nChannels + outputChannel) * 3;
((byte*)pOutput)[out_pos] = out_val;
((byte*)pOutput)[out_pos + 1] = out_val >> 8;
((byte*)pOutput)[out_pos + 2] = out_val >> 16;
}
else if (bitDepth == 32) // floating point output
{
((float*)pOutput)[i*nChannels + outputChannel] = divaAudioMixCls->mixbuffer[i*4 + currentChannel] * volumes[outputChannel];
}
}
}
}
}
DWORD asioCallback(bool input, DWORD channel, void* buffer, DWORD length, void* user)
{
ma_uint32 frames = length * 8 / bitDepth / nChannels;
audioCallback(&device, buffer, NULL, frames);
return length;
}
void asioClose()
{
if (BASS_ASIO_IsStarted()) BASS_ASIO_Stop();
BASS_ASIO_Free();
}
void loadConfig()
{
nChannels = GetPrivateProfileIntW(L"general", L"channels", 2, CONFIG_FILE);
if (nChannels != 4) nChannels = 2;
bitDepth = GetPrivateProfileIntW(L"general", L"bit_depth", 16, CONFIG_FILE);
if (bitDepth != 32 && bitDepth != 24) bitDepth = 16;
requestBuffer = GetPrivateProfileIntW(L"buffer", L"buffer_size", 10, CONFIG_FILE);
if (requestBuffer < 0) requestBuffer = 0;
nPeriods = GetPrivateProfileIntW(L"buffer", L"periods", 2, CONFIG_FILE);
if (nPeriods < 1) nPeriods = 1;
useOldInit = GetPrivateProfileIntW(L"general", L"alternate_init", 1, CONFIG_FILE) > 0 ? false : true;
GetPrivateProfileStringW(L"general", L"backend", L"wasapi", backendName, 32, CONFIG_FILE);
for (wchar_t& chr : backendName)
chr = towlower(chr);
useAsio = false;
maSharemode = ma_share_mode_shared;
if (lstrcmpW(backendName, L"asio") == 0)
{
StringCchCopyW(backendName, 32, L"ASIO");
useAsio = true;
}
else if (lstrcmpW(backendName, L"directsound") == 0)
{
StringCchCopyW(backendName, 32, L"DirectSound");
maBackend = ma_backend_dsound;
}
else if (lstrcmpW(backendName, L"wasapi_exclusive") == 0)
{
StringCchCopyW(backendName, 32, L"WASAPI (Exclusive mode)");
maBackend = ma_backend_wasapi;
maSharemode = ma_share_mode_exclusive;
}
else
{
StringCchCopyW(backendName, 32, L"WASAPI");
maBackend = ma_backend_wasapi;
}
asioDevice = GetPrivateProfileIntW(L"asio", L"device", -1, CONFIG_FILE);
showAsioPanel = GetPrivateProfileIntW(L"asio", L"show_config", 0, CONFIG_FILE) > 0 ? true : false;
}
void hookedAudioInit(initClass *cls, uint64_t unk, uint64_t unk2)
{
//printf("[DivaSound] Loaded\n");
printf("[DivaSound] Output config: %S %dch %dbit\n", backendName, nChannels, bitDepth);
divaAudCls = cls;
if (useOldInit)
{
printf("[DivaSound] Using old initialisation method\n");
// let the game set some stuff up
// might be necessary sometimes
divaAudioInit(divaAudCls, unk, unk2);
//printf("[DivaSound] Game audio initialised\n");
}
else
{
// setup some variables instead of using the original init function
divaAudCls->mixer = new audioMixer();
divaAudCls->mixer->volume_master = 1.0f;
divaAudCls->mixer->volume_channels[0] = 1.0f;
divaAudCls->mixer->volume_channels[1] = 1.0f;
divaAudCls->mixer->volume_channels[2] = 1.0f;
divaAudCls->mixer->volume_channels[3] = 1.0f;
divaAudCls->mixer->audioClass = divaAudCls;
mtx_init(&divaAudCls->mixer->volume_mutex, 2);
}
divaAudioMixCls = divaAudCls->mixer;
divaAudCls->channels = nChannels; // this could replace stereo patch
divaAudCls->rate = 44100; // really does nothing
divaAudCls->depth = bitDepth; // setting this to something other than 16 just removes output
if (useAsio)
{
if (BASS_ASIO_Init == NULL)
{
printf("[DivaSound] BASS ASIO not loaded...\n");
return;
}
if (HIWORD(BASS_ASIO_GetVersion()) != BASSASIOVERSION)
{
printf("[DivaSound] Incorrect BASS ASIO version. Use 1.4.0.0.\n");
return;
}
if (!BASS_ASIO_Init(asioDevice, BASS_ASIO_THREAD))
{
printf("[DivaSound] Failed to initialize device\n");
return;
}
if(showAsioPanel) BASS_ASIO_ControlPanel();
if (!BASS_ASIO_ChannelEnable(false, 0, (ASIOPROC*)asioCallback, NULL))
{
printf("[DivaSound] Failed to enable channels\n");
BASS_ASIO_Free();
return;
}
for (int i = 1; i < nChannels; i++)
{
if (!BASS_ASIO_ChannelJoin(false, i, 0))
{
printf("[DivaSound] Failed to enable channels\n");
BASS_ASIO_Free();
return;
}
}
if (BASS_ASIO_CheckRate(44100))
BASS_ASIO_SetRate(44100);
BASS_ASIO_ChannelSetRate(false, 0, 44100);
if (bitDepth == 32)
BASS_ASIO_ChannelSetFormat(false, 0, BASS_ASIO_FORMAT_FLOAT);
else if (bitDepth == 24)
BASS_ASIO_ChannelSetFormat(false, 0, BASS_ASIO_FORMAT_24BIT);
else
BASS_ASIO_ChannelSetFormat(false, 0, BASS_ASIO_FORMAT_16BIT);
BASS_ASIO_INFO asioInfo;
BASS_ASIO_GetInfo(&asioInfo);
double actualRate = BASS_ASIO_GetRate();
printf("[DivaSound] Output buffer size: %d (%dms at %dHz)\n", asioInfo.bufpref, (int)(asioInfo.bufpref * 1000 / actualRate), (int)actualRate);
divaBufSizeInFrames = asioInfo.bufpref * 44100 / actualRate;
divaBufSizeInMilliseconds = divaBufSizeInFrames * 1000 / 44100;
printf("[DivaSound] PDAFT buffer size: %d (%dms at %dHz)\n", divaBufSizeInFrames, divaBufSizeInMilliseconds, 44100);
divaAudioAllocMixer(divaAudioMixCls, unk, unk2, divaBufSizeInFrames);
printf("[DivaSound] Created internal audio mixer\n");
if (!BASS_ASIO_Start(asioInfo.bufpref, 1))
{
printf("[DivaSound] Failed to start playback device\n");
BASS_ASIO_Free();
return;
}
printf("[DivaSound] Started playback\n");
}
else
{
ma_backend backends[] = { maBackend };
contextConfig = ma_context_config_init();
contextConfig.threadPriority = ma_thread_priority_highest;
if (ma_context_init(backends, sizeof(backends) / sizeof(backends[0]), &contextConfig, &context) != MA_SUCCESS) {
printf("[DivaSound] Failed to initialize context\n");
return;
}
deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.playback.channels = nChannels;
deviceConfig.sampleRate = 44100;
deviceConfig.bufferSizeInMilliseconds = requestBuffer; // actual result may be larger
deviceConfig.periods = nPeriods;
deviceConfig.dataCallback = audioCallback;
deviceConfig.pUserData = NULL;
deviceConfig.playback.shareMode = maSharemode;
if (bitDepth == 32)
deviceConfig.playback.format = ma_format_f32;
else if (bitDepth == 24)
deviceConfig.playback.format = ma_format_s24;
else
deviceConfig.playback.format = ma_format_s16;
if (nChannels == 4)
{
deviceConfig.playback.channelMap[0] = MA_CHANNEL_FRONT_LEFT;
deviceConfig.playback.channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
deviceConfig.playback.channelMap[2] = MA_CHANNEL_BACK_LEFT;
deviceConfig.playback.channelMap[3] = MA_CHANNEL_BACK_RIGHT;
}
if (ma_device_init(&context, &deviceConfig, &device) != MA_SUCCESS) {
printf("[DivaSound] Failed to open playback device\n");
ma_context_uninit(&context);
return;
}
//printf("[DivaSound] Opened playback device\n");
maInternalBufferSizeInMilliseconds = device.playback.internalBufferSizeInFrames * 1000 / device.playback.internalSampleRate; // because miniaudio doesn't seem to have this
printf("[DivaSound] Output buffer size: %d (%dms at %dHz)\n", device.playback.internalBufferSizeInFrames, maInternalBufferSizeInMilliseconds, device.playback.internalSampleRate);
printf("[DivaSound] Buffer periods: %d\n", device.playback.internalPeriods);
divaBufSizeInFrames = device.playback.internalBufferSizeInFrames * device.sampleRate / device.playback.internalSampleRate; // +128; // 128 is just a bit extra in case resampling needs it or something. idk
divaBufSizeInMilliseconds = divaBufSizeInFrames * 1000 / device.sampleRate;
printf("[DivaSound] PDAFT buffer size: %d (%dms at %dHz)\n", divaBufSizeInFrames, divaBufSizeInMilliseconds, device.sampleRate);
divaAudioAllocMixer(divaAudioMixCls, unk, unk2, divaBufSizeInFrames);
printf("[DivaSound] Created internal audio mixer\n");
if (ma_device_start(&device) != MA_SUCCESS) {
printf("[DivaSound] Failed to start playback device\n");
ma_device_uninit(&device);
ma_context_uninit(&context);
return;
}
printf("[DivaSound] Started playback\n");
}
divaAudCls->buffer_size = divaBufSizeInFrames;
//loopThread = std::thread(resizeTestLoop);
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
loadConfig();
if (useOldInit)
{
// these patches are only needed if calling the game's own init function
// they shouldn't be necessary anymore
// force stereo mode
InjectCode((void*)0x0000000140A860C0, { 0x02 });
// remove a call to get device info and skip the check for it
NopBytes((void*)0x140626b56, 7);
NopBytes((void*)0x140626b8a, 8);
InjectCode((void*)0x140626b8a, { 0x48, 0x83, 0xEF, 0x18 }); // fix value of RDI because I changed the flow here
NopBytes((void*)0x140626ba9, 11);
// return from the original init early
InjectCode((void*)0x0000000140626C29, { 0x48, 0xE9 });
}
DisableThreadLibraryCalls(hModule);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)divaAudioInit, (PVOID)hookedAudioInit);
DetourTransactionCommit();
}
else if (ul_reason_for_call == DLL_PROCESS_DETACH)
{
if (useAsio) asioClose(); // this doesn't actually get called...
}
return TRUE;
}
@@ -0,0 +1,172 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
#include <string>
#include <vector>
#include <thread>
#define MINIAUDIO_IMPLEMENTATION
#include <miniaudio.h>
#include <bassasio.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
void (__cdecl* divaAudioInit)(void* cls, uint64_t unk, uint64_t unk2) = (void(__cdecl*)(void* cls, uint64_t unk, uint64_t unk2))0x1406269F0;
void (__cdecl* divaAudioFillbuffer)(void* mixer, int16_t* buf, uint64_t nFrames, bool disableHpVol, bool invertPhase) = (void(__cdecl*)(void* mixer, int16_t* buf, uint64_t nFrames, bool disableHpVol, bool invertPhase))0x140627370;
// mixer is a pointer to an audioMixer (from audio init's cls + 0x70)
// disableHpVol uses speaker volume for headphones (only works in 4ch mode)
// invertPhase inverts the output signal (only works if disableHpVol == false)
int (__cdecl* divaAudioAllocMixer)(void* cls, uint64_t unk, uint64_t unk2, int64_t nFrames) = (int(__cdecl*)(void* cls, uint64_t unk, uint64_t unk2, int64_t nFrames))0x140626710;
// unks are the same as from the init call. they seem to set the internal mixing channel counts(?)
// cls is the same as mixer in divaAudioFillbuffer
// nFrames is number of audio frames to hold in the mixing buffers (only used when divaAudioFillbuffer is called). Internally this is multiplied by 16 (buffers are built using 32bit floats)
int(__cdecl* mtx_init)(void* mutex, int type) = (int(__cdecl*)(void* mutex, int type))0x14081DEF4;
#pragma pack(push, 1)
struct _50 {
byte padding00[0x50];
};
struct _70 {
byte padding00[0x70];
};
struct streamingState {
std::vector<_50>* state;
float* buffer;
uint64_t buffer_size;
};
struct initClass;
struct audioMixer {
initClass* audioClass;
std::vector<_70>** state1;
uint64_t state1_len;
streamingState* state2;
uint64_t state2_len;
float* mixbuffer;
uint64_t mixbuffer_size;
void* volume_mutex; // not sure if this is pointer or not
float volume_master;
float volume_channels[4];
byte padding54[4];
};
struct initClass {
WAVEFORMATEXTENSIBLE wave_format;
IMMDeviceEnumerator *pEnumerator;
IMMDevice *pDevice;
IAudioClient *pAudioClient;
uint64_t buffer_size;
IAudioRenderClient *pRenderClient;
HANDLE hEvent;
uint64_t channels;
uint64_t rate; // should always =44100
uint64_t depth; // should always =16
audioMixer* mixer;
HANDLE hCallback;
int32_t idk;
};
#pragma pack(pop)
// known internal audio mixer variables (used by divaAudioFillbuffer and divaAudioAllocMixer)
// cls + 0x00 = pointer to main audio/init class
// cls + 0x08 = internal state 1 (SE?) vector pointer (or full class?)
// cls + 0x10 = internal state 1 (SE?) length (channels?)
// cls + 0x18 = internal state 2 (streaming?) vector pointer (or full class?)
// cls + 0x20 = internal state 2 (streaming?) length (channels?)
// cls + 0x28 = mixing buffer pointer (when a buffer is generated, this is filled with 32bit floats (four per frame)
// cls + 0x30 = mixing buffer size (frame count * 16)
//
// cls + 0x38 = mutex lock for volume
// cls + 0x40 = master volume float (multiply other volumes by this)
// cls + 0x44 = ch1 volume
// cls + 0x48 = ch2 volume
// cls + 0x4c = ch3 volume
// cls + 0x50 = ch4 volume
//
//
// known main/init audio class variables (used by divaAudioInit)
// cls + 0x0 = WAVEFORMATEXTENSIBLE wave_format (null with old method) (length 0x28)
// cls + 0x28 = IMMDeviceEnumerator *pEnumerator
// cls + 0x30 = IMMDevice *pDevice (default device)
// cls + 0x38 = IAudioClient *pAudioClient
//
// cls + 0x40 = buffer size in frames (null with old method)
//
// cls + 0x48 = IAudioRenderClient *pRenderClient (null with old method)
//
// cls + 0x50 = HANDLE hEvent (for original WASAPI buffer timing) (null with old method)
//
// cls + 0x58 = number of output channels
// cls + 0x60 = audio sample rate
// cls + 0x68 = audio bit depth (only 16bit works)
//
// cls + 0x70 = pointer to mixer class
//
// cls + 0x78 = HANDLE hCallback (handle to original callback thread) (null with old method)
initClass *divaAudCls;
audioMixer *divaAudioMixCls;
std::thread loopThread;
ma_context_config contextConfig;
ma_context context;
ma_device_config deviceConfig;
ma_device device;
int maInternalBufferSizeInMilliseconds;
int divaBufSizeInFrames;
int divaBufSizeInMilliseconds;
int nChannels; // this can only be 2 or 4
int bitDepth; // signed 16/24 bit integer or 32 bit float
int requestBuffer;
int nPeriods;
wchar_t backendName[32]; // wasapi or directsound
ma_backend maBackend;
ma_share_mode maSharemode;
bool useAsio;
int asioDevice;
bool showAsioPanel;
bool useOldInit;
std::wstring ExePath() {
WCHAR buffer[MAX_PATH];
GetModuleFileNameW(NULL, buffer, MAX_PATH);
return std::wstring(buffer);
}
std::wstring DirPath() {
std::wstring exepath = ExePath();
std::wstring::size_type pos = exepath.find_last_of(L"\\/");
return exepath.substr(0, pos);
}
std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\DivaSound.ini";
LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str();
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
#define SAFE_RELEASE(punk) \
if ((punk) != NULL) \
{ (punk)->Release(); (punk) = NULL; }