新增垂直音量控制器

This commit is contained in:
Nanako 2024-06-14 10:17:23 +08:00
parent 080d0986f5
commit eac45751d2
2 changed files with 95 additions and 19 deletions

View File

@ -1,5 +1,4 @@
#include "widgets.h"
#include "imgui.h"
#include "audio/plugin_host/plugin_host_manager.h"
#include "audio/plugin_host/plugin_host.h"
@ -88,7 +87,7 @@ void draw_mixer_track(uint32_t delta_sample_count, mixer_track* track, int32_t i
std::string track_label = track->get_name();
std::string child_id = "MixerTrack" + std::to_string(index);
std::string slider_id = "##" + std::to_string(index);
std::string slider_id = "MixerTrackVolume##" + std::to_string(index);
std::string volume_bar_id = "VolumeBar" + std::to_string(index);
ImGui::BeginGroup();
@ -96,9 +95,9 @@ void draw_mixer_track(uint32_t delta_sample_count, mixer_track* track, int32_t i
ImGui::Text(track_label.c_str());
float widget_height = ImGui::GetContentRegionAvail().y;
const ImVec2 slider_size = ImGui::CalcItemSize(ImVec2(20, widget_height), 20, widget_height);
const ImVec2 slider_size = ImGui::CalcItemSize(ImVec2(25, widget_height), 25, widget_height);
float volume = track->get_volume();
if (ImGui::VSliderFloat(slider_id.c_str(), slider_size,&volume, 0.0f, 1.2f)) {
if (vertical_volume_slider(slider_id.c_str(), slider_size, &volume, 0.f, 1.25f)) {
track->set_volume(volume);
}
ImGui::SameLine();
@ -139,13 +138,6 @@ void draw_mixer_track(uint32_t delta_sample_count, mixer_track* track, int32_t i
ImGui::SameLine();
ImGui::EndGroup();
// on hover
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::Text(track_label.c_str());
ImGui::EndTooltip();
}
}
void draw_volume_bar(const char* id, float height, std::vector<float> sample_value, std::vector<float> sample_peak) {
@ -188,11 +180,11 @@ void draw_volume_bar(const char* id, float height, std::vector<float> sample_val
ImVec2 temp_pos = pos;
// 坐标系原点在左上角
for (int32_t i = 0; i < channel_count; ++i) {
float value_db = sample_to_db(sample_value.at(i));
float value = db_to_percent(value_db);
float value_db = gain_to_db(sample_value.at(i));
float value = db_to_percentage_log(value_db, -75.0f, 6.0f);
float peak_db = sample_to_db(sample_peak.at(i));
float peak = db_to_percent(peak_db);
float peak_db = gain_to_db(sample_peak.at(i));
float peak = db_to_percentage_log(peak_db, -75.0f, 6.0f);
// 绘制矩形(60%以下的部分绘制绿色80%以下的部分绘制黄色100%以下的部分绘制红色)
if (value > volume_bar_inf) {
@ -251,3 +243,58 @@ void draw_volume_bar(const char* id, float height, std::vector<float> sample_val
window->DrawList->PopClipRect();
}
bool vertical_volume_slider(const char* id, ImVec2 size, float* volume, float min_volume, float max_volume) {
ImGuiWindow *window = ImGui::GetCurrentWindow();
ImGuiIO &io = ImGui::GetIO();
ImVec2 cur_pos = window->DC.CursorPos;
ImRect bb(cur_pos, cur_pos + size);
ImGui::ItemSize(size, 0.0f);
if (!ImGui::ItemAdd(bb, 0))
return false;
ImDrawList *draw_list = ImGui::GetWindowDrawList();
ImGui::RenderFrame(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_FrameBg), true, 0.0f);
float percent = mapping(*volume, min_volume, max_volume, 0.f, 1.0f);
ImVec2 pos = ImVec2(bb.Min.x, bb.Min.y + size.y * (1 - percent));
draw_list->AddRectFilled(pos, bb.Max, ImGui::GetColorU32(ImGuiCol_SliderGrabActive), 0.0f);
bool on_hovered = ImGui::IsItemHovered();
if (on_hovered) {
ImGui::BeginTooltip();
ImGui::Text("Volume: %.3fdb", 20.0f * log10f(*volume));
ImGui::EndTooltip();
}
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
*volume = 1.0f;
return true;
}
static float drag_start_value = 0.0f;
static ImGuiID dragging = 0;
const bool clicked = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
const bool released = ImGui::IsMouseReleased(ImGuiMouseButton_Left);
ImGuiID current_id = ImGui::GetID(id);
if (released) {
dragging = 0;
} else if (!dragging && on_hovered && clicked) {
drag_start_value = *volume;
dragging = current_id;
}
if (dragging != current_id) {
return false;
}
float mouse_drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Left).y;
float delta = (mouse_drag_delta / size.y) * (max_volume - min_volume);
*volume = std::clamp(drag_start_value - delta, min_volume, max_volume);
return true;
}

View File

@ -3,19 +3,48 @@
#include <cstdint>
#include <cmath>
#include "extern.h"
#include "imgui.h"
class mixer_track;
inline sample_t sample_to_db(sample_t sample) {
inline float mapping(float value, float in_min, float in_max, float out_min, float out_max) {
return (value - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
inline sample_t gain_to_db(sample_t sample) {
return 20.0f * log10f(sample);
}
// convert db(-60db, 10db) to percent in range [0, 1]
inline float db_to_percent(float db) {
return (db + 60.0f) / 70.0f;
inline float db_to_gain(sample_t db) {
return powf(10.0f, db / 20.0f);
}
inline float db_to_percentage_log(float db_value, float min_db = -60.0f, float max_db = 0.0f) {
if (db_value < min_db) db_value = min_db;
if (db_value > max_db) db_value = max_db;
// 计算对数比例
float log_min = std::log10(1.0f + std::pow(10.0f, min_db / 20.0f));
float log_max = std::log10(1.0f + std::pow(10.0f, max_db / 20.0f));
float log_value = std::log10(1.0f + std::pow(10.0f, db_value / 20.0f));
// 线性映射到0到100的范围
float percentage = (log_value - log_min) / (log_max - log_min);
return percentage;
}
inline float percentage_to_db(float percentage, float min_db = -60.0f, float max_db = 0.0f) {
// 计算对数比例
float log_min = std::log10(1.0f + std::pow(10.0f, min_db / 20.0f));
float log_max = std::log10(1.0f + std::pow(10.0f, max_db / 20.0f));
float log_value = log_min + percentage * (log_max - log_min);
// 计算db值
float db_value = 20.0f * std::log10(std::pow(10.0f, log_value) - 1.0f);
return db_value;
}
void vertical_text(const char* text);
bool vertical_volume_slider(const char* id, ImVec2 size, float* volume, float min_volume = 0.0f, float max_volume = 1.0f);
void draw_instrument_track();
void draw_mixer();