per channel peak meters

This commit is contained in:
2022-07-26 18:07:57 +02:00
parent eec9e25e12
commit cdffa1b50b
5 changed files with 49 additions and 23 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -10,6 +10,7 @@
#include <windows.h>
#include <array>
#include <functional>
#include <iostream>
#include <sstream>
@@ -304,8 +305,8 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& 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<float, 2> 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<AudioDevice>& 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

View File

@@ -3,6 +3,7 @@
#include <functiondiscoverykeys.h>
#include <endpointvolume.h>
#include <array>
#include <vector>
#include <algorithm>
@@ -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<float, 2>& 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);
}

View File

@@ -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<float, 2>& levels);
void getVolumeLimit(IAudioEndpointVolume* volumeInterface, float* outMin, float* outMax);