235 lines
6.6 KiB
C++
235 lines
6.6 KiB
C++
//Disables console window
|
|
#if !_DEBUG
|
|
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
|
|
#endif
|
|
|
|
#include <windows.h>
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
|
|
#include "Util.h"
|
|
#include "AudioApi.h"
|
|
#include "resource.h"
|
|
#include "AsuroTool.h"
|
|
|
|
int main()
|
|
{
|
|
ApplicationData applicationData{};
|
|
|
|
startImgui(&applicationData, init, draw, "Asuro's Tool", 600, 400);
|
|
}
|
|
|
|
void init(DrawData& drawData, void* customData)
|
|
{
|
|
ApplicationData* appData = static_cast<ApplicationData*>(customData);
|
|
|
|
// Load text font
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
io.Fonts->AddFontFromFileTTF("Montserrat-Regular.ttf", 18.0f);
|
|
|
|
// Load icon font
|
|
static const ImWchar icons_ranges[] = { 0xEA01, 0xF2DF, 0 };
|
|
ImFontConfig icons_config;
|
|
icons_config.MergeMode = true;
|
|
icons_config.PixelSnapH = true;
|
|
io.Fonts->AddFontFromFileTTF("remixicon.ttf", 14.0f, &icons_config, icons_ranges);
|
|
|
|
// Set up audio device api
|
|
HRESULT audioResult;
|
|
audioResult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
isError(audioResult, "Failed to initialize COM: ");
|
|
|
|
audioResult = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&appData->deviceEnumerator));
|
|
isError(audioResult, "Failed to set up audio device enumerator: ");
|
|
|
|
appData->audioNotificationListener = new AudioNotificationListener(appData);
|
|
audioResult = appData->deviceEnumerator->RegisterEndpointNotificationCallback(appData->audioNotificationListener);
|
|
isError(audioResult, "Failed to register audio notification listener: ");
|
|
|
|
reloadDeviceLists(appData);
|
|
|
|
// Set window icon
|
|
LPWSTR iconId = MAKEINTRESOURCE(IDI_ICON1);
|
|
HANDLE iconLarge = LoadImageW(GetModuleHandle(NULL), iconId, IMAGE_ICON, 64, 64, 0);
|
|
HANDLE iconSmall = LoadImageW(GetModuleHandle(NULL), iconId, IMAGE_ICON, 32, 32, 0);
|
|
SendMessage(drawData.window_handle, WM_SETICON, ICON_BIG, (LPARAM)iconLarge);
|
|
SendMessage(drawData.window_handle, WM_SETICON, ICON_SMALL, (LPARAM)iconSmall);
|
|
SendMessage(drawData.window_handle, WM_SETICON, ICON_SMALL2, (LPARAM)iconSmall);
|
|
}
|
|
|
|
void draw(DrawData& drawData, void* customData)
|
|
{
|
|
ApplicationData* appData = static_cast<ApplicationData*>(customData);
|
|
float customYCursor = 0;
|
|
ImVec2 viewportSize = ImGui::GetMainViewport()->Size;
|
|
|
|
// Menu Bar
|
|
customYCursor += menuBar(appData).y;
|
|
|
|
// Playback Devices
|
|
ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
|
|
ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0));
|
|
customYCursor += audioDeviceWindow(appData, appData->playbackDevices, " \xEE\xB8\x84 Playback").y;
|
|
|
|
customYCursor += 5.;
|
|
|
|
// Recording devices
|
|
ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
|
|
ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0));
|
|
customYCursor += audioDeviceWindow(appData, appData->recordingDevices, " \xEE\xBD\x8F Recording").y;
|
|
|
|
// Resize viewport
|
|
if (appData->settings.fitWindowHeight)
|
|
{
|
|
drawData.window_size.y = customYCursor;
|
|
}
|
|
}
|
|
|
|
ImVec2 menuBar(ApplicationData* appData)
|
|
{
|
|
ImVec2 size{};
|
|
|
|
if (ImGui::BeginMainMenuBar())
|
|
{
|
|
if (ImGui::BeginMenu("Settings"))
|
|
{
|
|
ImGui::Checkbox("Show Disabled Devices", &appData->settings.showDisabledDevices);
|
|
ImGui::Checkbox("Fit Window Height", &appData->settings.fitWindowHeight);
|
|
ImGui::EndMenu();
|
|
}
|
|
|
|
if (ImGui::BeginMenu("Debug"))
|
|
{
|
|
if (ImGui::Button("Manual Refresh"))
|
|
{
|
|
reloadDeviceLists(appData);
|
|
}
|
|
ImGui::EndMenu();
|
|
}
|
|
size = ImGui::GetWindowSize();
|
|
ImGui::EndMainMenuBar();
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
bool customButton(const char* id_start, const char* id_end, const char* title, bool visible)
|
|
{
|
|
std::string buttonId(id_start);
|
|
buttonId.append(id_end);
|
|
|
|
bool result = false;
|
|
if (visible)
|
|
{
|
|
ImGui::PushID(buttonId.c_str());
|
|
result = ImGui::SmallButton(title);
|
|
ImGui::PopID();
|
|
}
|
|
else
|
|
{
|
|
ImGui::InvisibleButton(buttonId.c_str(), ImGui::CalcTextSize(title));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
ImVec2 audioDeviceWindow(ApplicationData* appData, std::vector<AudioDevice>& deviceList, const char* title)
|
|
{
|
|
if (ImGui::Begin(title, 0, ImGuiWindowFlags_NoResize))
|
|
{
|
|
if (ImGui::BeginTable("DeviceTable", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Borders | ImGuiTableFlags_NoSavedSettings))
|
|
{
|
|
ImGui::TableSetupColumn("Devices", ImGuiTableColumnFlags_WidthStretch, 3.);
|
|
ImGui::TableSetupColumn("Volume", ImGuiTableColumnFlags_WidthStretch, 1.);
|
|
ImGui::TableSetupColumn("Defaults", ImGuiTableColumnFlags_WidthFixed, 55.);
|
|
ImGui::TableHeadersRow();
|
|
|
|
for (auto& dev : deviceList)
|
|
{
|
|
std::string deviceIdUtf8 = utf8Encode(dev.id);
|
|
|
|
if (dev.state == DEVICE_STATE_ACTIVE)
|
|
{
|
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1., 1., 1., 1.));
|
|
}
|
|
else if (!appData->settings.showDisabledDevices)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(.7, .7, .7, 1.));
|
|
}
|
|
|
|
// Device Name
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text(dev.name.c_str());
|
|
|
|
// Volume
|
|
ImGui::TableNextColumn();
|
|
if (dev.state == DEVICE_STATE_ACTIVE)
|
|
{
|
|
|
|
|
|
float volume = log10f(getMeterValue(dev.meterInterface) * 9. + 1.);
|
|
|
|
auto drawList = ImGui::GetWindowDrawList();
|
|
ImVec2 windowPos = ImGui::GetWindowPos();
|
|
ImVec2 cursorPos = ImGui::GetCursorScreenPos();
|
|
ImVec2 space = ImGui::GetContentRegionAvail();
|
|
float lineY = cursorPos.y + ImGui::GetTextLineHeight() / 2.;
|
|
|
|
drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + space.x, lineY), IM_COL32(120, 120, 120, 255), 2.);
|
|
drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + space.x * volume, lineY), IM_COL32(200, 200, 255, 255), 3.);
|
|
}
|
|
|
|
// Defaults
|
|
ImGui::TableNextColumn();
|
|
if (dev.state == DEVICE_STATE_ACTIVE)
|
|
{
|
|
if (dev.isDefaultConsole)
|
|
{
|
|
drawCircle(5, IM_COL32(50, 50, 222, 255));
|
|
}
|
|
if (customButton("bn_d_", deviceIdUtf8.c_str(), "\xEE\xBE\x82", !dev.isDefaultConsole))
|
|
{
|
|
setDefaultAudioDevice(appData, dev.id.c_str(), ERole::eConsole);
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
if (dev.isDefaultCommunication)
|
|
{
|
|
drawCircle(5, IM_COL32(222, 50, 50, 255));
|
|
}
|
|
if (customButton("bn_c_", deviceIdUtf8.c_str(), "\xEE\xBF\xA9", !dev.isDefaultCommunication))
|
|
{
|
|
setDefaultAudioDevice(appData, dev.id.c_str(), ERole::eCommunications);
|
|
}
|
|
}
|
|
|
|
ImGui::PopStyleColor();
|
|
}
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
}
|
|
|
|
ImVec2 size = ImGui::GetWindowSize();
|
|
|
|
ImGui::End();
|
|
return size;
|
|
}
|
|
|
|
void drawCircle(float radius, ImU32 color)
|
|
{
|
|
ImGui::Dummy(ImVec2(0, 0));
|
|
ImGui::SameLine();
|
|
auto drawList = ImGui::GetWindowDrawList();
|
|
ImVec2 cursorPos = ImGui::GetCursorPos();
|
|
ImVec2 windowPos = ImGui::GetWindowPos();
|
|
drawList->AddCircleFilled(ImVec2(cursorPos.x + windowPos.x, cursorPos.y + windowPos.y + ImGui::GetTextLineHeight() / 2.), radius, color);
|
|
}
|