diff --git a/AsuroTool/ApplicationData.cpp b/AsuroTool/ApplicationData.cpp index 23fd263..a74b774 100644 --- a/AsuroTool/ApplicationData.cpp +++ b/AsuroTool/ApplicationData.cpp @@ -26,6 +26,8 @@ AudioDevice::AudioDevice(IMMDevice* device, LPCWSTR deviceId) err = device->Activate(__uuidof(IAudioMeterInformation), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&meterInterface); isError(err, "Failed to get audio meter interface: "); + getVolumeLimit(volumeInterface, &minVolumeDb, &maxVolumeDb); + if (propertyStore) { propertyStore->Release(); @@ -35,7 +37,8 @@ AudioDevice::AudioDevice(IMMDevice* device, LPCWSTR deviceId) AudioDevice::AudioDevice(AudioDevice&& other) noexcept : device(other.device), volumeInterface(other.volumeInterface), meterInterface(other.meterInterface), id(other.id), name(other.name), state(other.state), - isDefaultConsole(other.isDefaultConsole), isDefaultMedia(other.isDefaultMedia), isDefaultCommunication(other.isDefaultCommunication) + isDefaultConsole(other.isDefaultConsole), isDefaultMedia(other.isDefaultMedia), isDefaultCommunication(other.isDefaultCommunication), + minVolumeDb(other.minVolumeDb), maxVolumeDb(other.maxVolumeDb) { other.device = nullptr; other.volumeInterface = nullptr; @@ -53,6 +56,8 @@ AudioDevice& AudioDevice::operator=(AudioDevice&& other) noexcept this->isDefaultConsole = other.isDefaultConsole; this->isDefaultMedia = other.isDefaultMedia; this->isDefaultCommunication = other.isDefaultCommunication; + this->minVolumeDb = other.minVolumeDb; + this->maxVolumeDb = other.maxVolumeDb; other.device = nullptr; other.volumeInterface = nullptr; diff --git a/AsuroTool/ApplicationData.h b/AsuroTool/ApplicationData.h index cc8e829..0db4407 100644 --- a/AsuroTool/ApplicationData.h +++ b/AsuroTool/ApplicationData.h @@ -14,9 +14,11 @@ public: std::wstring id = {}; std::string name = {}; unsigned long state = {}; - bool isDefaultConsole = {}; - bool isDefaultMedia = {}; - bool isDefaultCommunication = {}; + bool isDefaultConsole = false; + bool isDefaultMedia = false; + bool isDefaultCommunication = false; + float minVolumeDb = 0.f; + float maxVolumeDb = 0.f; AudioDevice(IMMDevice* device, LPCWSTR deviceId); AudioDevice(AudioDevice&& other) noexcept; diff --git a/AsuroTool/AsuroTool.cpp b/AsuroTool/AsuroTool.cpp index c4e74b9..63481d1 100644 --- a/AsuroTool/AsuroTool.cpp +++ b/AsuroTool/AsuroTool.cpp @@ -10,6 +10,7 @@ #include +#include #include #include #include @@ -304,8 +305,8 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector& dev ImGui::TableNextColumn(); if (dev.state == DEVICE_STATE_ACTIVE) { - // Log scale because it looks better (no actual reason for these exact numbers) - float meterValue = log10f(getMeterValue(dev.meterInterface) * 9. + 1.); + static std::array meterValues{}; + UINT channelCount = getMeterValues(dev.meterInterface, meterValues); auto drawList = ImGui::GetWindowDrawList(); ImVec2 windowPos = ImGui::GetWindowPos(); @@ -316,21 +317,32 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector& dev const float linePaddingX = 3.; cursorPos.x += linePaddingX; + // BG line drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + (space.x - 2. * linePaddingX), lineY), IM_COL32(120, 120, 120, 255), 2.); - drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + (space.x - 2. * linePaddingX) * meterValue, lineY), IM_COL32(200, 200, 255, 255), 3.); + + // Channel lines + if (channelCount == 1) + { + drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + (space.x - 2. * linePaddingX) * meterValues[0], lineY), IM_COL32(200, 200, 255, 255), 3.); + } + if (channelCount == 2) + { + drawList->AddLine(ImVec2(cursorPos.x, lineY - 2), ImVec2(cursorPos.x + (space.x - 2. * linePaddingX) * meterValues[0], lineY - 2), IM_COL32(200, 200, 255, 255), 3.); + drawList->AddLine(ImVec2(cursorPos.x, lineY + 2), ImVec2(cursorPos.x + (space.x - 2. * linePaddingX) * meterValues[1], lineY + 2), IM_COL32(200, 200, 255, 255), 3.); + } + + ImGui::SetNextItemWidth(space.x); + ImGui::PushID(&dev.id); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0, 0, 0, 0)); float volume = getVolume(dev.volumeInterface); - float prevVolume = volume; - ImGui::SetNextItemWidth(space.x); - ImGui::PushID(dev.device); - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0, 0, 0, 0)); - ImGui::SliderFloat("", &volume, 0., 1., "", ImGuiSliderFlags_NoRoundToFormat | ImGuiSliderFlags_AlwaysClamp); - ImGui::PopStyleColor(); - ImGui::PopID(); - if (prevVolume != volume) + if (ImGui::SliderFloat("", &volume, 0., 1., "", ImGuiSliderFlags_NoRoundToFormat | ImGuiSliderFlags_AlwaysClamp)) { setVolume(dev.volumeInterface, volume); } + + ImGui::PopStyleColor(); + ImGui::PopID(); } // Defaults diff --git a/AsuroTool/AudioApi.cpp b/AsuroTool/AudioApi.cpp index 45c92dd..88f2532 100644 --- a/AsuroTool/AudioApi.cpp +++ b/AsuroTool/AudioApi.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -156,13 +157,18 @@ void setVolume(IAudioEndpointVolume* volumeInterface, float newVolume) isError(hr, "Failed to set volume level: "); } -float getMeterValue(IAudioMeterInformation* meterInterface) +UINT getMeterValues(IAudioMeterInformation* meterInterface, std::array& outLevels) { - float volume; - if (FAILED(meterInterface->GetPeakValue(&volume))) - { - volume = 0.; - } + UINT channelCount; + if (FAILED(meterInterface->GetMeteringChannelCount(&channelCount)) || channelCount > 2) return 0; - return volume; + if (FAILED(meterInterface->GetChannelsPeakValues(channelCount, &outLevels[0]))) return 0; + + return channelCount; } + +void getVolumeLimit(IAudioEndpointVolume* volumeInterface, float* outMin, float* outMax) +{ + float dummy; + volumeInterface->GetVolumeRange(outMin, outMax, &dummy); +} \ No newline at end of file diff --git a/AsuroTool/AudioApi.h b/AsuroTool/AudioApi.h index 2ee8620..e041fea 100644 --- a/AsuroTool/AudioApi.h +++ b/AsuroTool/AudioApi.h @@ -14,4 +14,5 @@ void setDefaultAudioDevice(AudioData& audioData, const wchar_t* deviceId, ERole float getVolume(IAudioEndpointVolume* volumeInterface); void setVolume(IAudioEndpointVolume* volumeInterface, float newVolume); -float getMeterValue(IAudioMeterInformation* meterInterface); +UINT getMeterValues(IAudioMeterInformation* meterInterface, std::array& levels); +void getVolumeLimit(IAudioEndpointVolume* volumeInterface, float* outMin, float* outMax); \ No newline at end of file