VolumeBar
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
using namespace ImGui;
|
||||
|
||||
void draw_volume_bar(float volume, float peak, const ImVec2& size_arg, const char* label) {
|
||||
void draw_volume_bar(float volume_dB, float peak_dB, const ImVec2& size_arg, const char* label) {
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return;
|
||||
@@ -21,19 +21,24 @@ void draw_volume_bar(float volume, float peak, const ImVec2& size_arg, const cha
|
||||
|
||||
window->DrawList->PushClipRect(bb.Min, bb.Max, true);
|
||||
// Render
|
||||
volume = ImSaturate(volume);
|
||||
// volume_dB = ImSaturate(volume_dB);
|
||||
RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
|
||||
bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize));
|
||||
|
||||
const float y = bb.Max.y - ImLerp(0.0f, size.y, volume);
|
||||
const float y_indicator = map_db_to_non_linear_volume_indicator(volume_dB, -90.0f, 12.0f, 0.0f, size.y);
|
||||
|
||||
// const float y = bb.Max.y - ImLerp(0.0f, size.y, volume_dB);
|
||||
const float y = bb.Max.y - y_indicator;
|
||||
|
||||
const ImVec2 fill_min = ImVec2(bb.Min.x, y);
|
||||
const ImVec2 fill_br = ImVec2(bb.Max.x, bb.Max.y);
|
||||
window->DrawList->AddRectFilled(fill_min, fill_br, GetColorU32(ImGuiCol_PlotHistogram));
|
||||
|
||||
// Peak
|
||||
if (peak > 0.0f) {
|
||||
const float peak_y = bb.Max.y - ImLerp(0.0f, size.y, peak);
|
||||
if (peak_dB > -90.f) {
|
||||
const float peak_y_indicator = map_db_to_non_linear_volume_indicator(peak_dB, -90.0f, 12.0f, 0.0f, size.y);
|
||||
// const float peak_y = bb.Max.y - ImLerp(0.0f, size.y, peak_dB);
|
||||
const float peak_y = bb.Max.y - peak_y_indicator;
|
||||
if (peak_y < fill_min.y + 1.0f) // Draw line at the top of the fill
|
||||
window->DrawList->AddLine(ImVec2(bb.Min.x, peak_y), ImVec2(bb.Max.x, peak_y), GetColorU32(ImGuiCol_Text));
|
||||
}
|
||||
|
||||
@@ -2,4 +2,55 @@
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
void draw_volume_bar(float volume, float peak, const ImVec2& size_arg, const char* label);
|
||||
void draw_volume_bar(float volume_dB, float peak_dB, const ImVec2& size_arg, const char* label);
|
||||
|
||||
// 计算RMS值
|
||||
inline float calculate_rms(const std::vector<float>& samples) {
|
||||
float sum = 0.0;
|
||||
for (const float sample : samples) {
|
||||
sum += sample * sample;
|
||||
}
|
||||
return std::sqrt(sum / samples.size());
|
||||
}
|
||||
|
||||
// 将RMS值转换为dB
|
||||
inline float rms_2_db(float rms, float rms_ref) {
|
||||
return 20.0 * std::log10(rms / rms_ref);
|
||||
}
|
||||
|
||||
template<class T, class T2>
|
||||
static constexpr inline auto get_range_pct(T min_value, T max_value, T2 in_value)
|
||||
{
|
||||
// Avoid Divide by Zero.
|
||||
// But also if our range is a point, output whether Value is before or after.
|
||||
const T divisor = max_value - min_value;
|
||||
|
||||
if (divisor == 0)
|
||||
{
|
||||
using RetType = decltype(T() / T2());
|
||||
return (in_value >= max_value) ? (RetType)1 : (RetType)0;
|
||||
}
|
||||
|
||||
return (in_value - min_value) / divisor;
|
||||
}
|
||||
|
||||
// 对数映射分贝值到非线性音量指示器
|
||||
inline float map_db_to_non_linear_volume_indicator(float dB, const float min_db, const float max_db, const float min_indicator, const float max_indicator) {
|
||||
// 确保dB值在合理范围内
|
||||
dB = std::max(min_db, std::min(dB, max_db));
|
||||
|
||||
// 转换dB值为正数,以便于映射,并计算指数
|
||||
const float normalized_db = dB - min_db;
|
||||
const float normalized_max_db = max_db - min_db;
|
||||
|
||||
// 计算对数映射的指数部分
|
||||
const float exp_value = normalized_db == 0 ? 0 : (log10(normalized_db) / log10(normalized_max_db));
|
||||
|
||||
// 映射到指示器范围
|
||||
float indicator_value = exp_value * (max_indicator - min_indicator) + min_indicator;
|
||||
|
||||
// 确保指示器值在合理范围内
|
||||
indicator_value = std::max(min_indicator, std::min(indicator_value, max_indicator));
|
||||
|
||||
return indicator_value;
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
widget_mixer_track::widget_mixer_track(mixer_track* in_mixer_track): mixer_track_(in_mixer_track) {
|
||||
name_ = mixer_track_->get_name();
|
||||
peak_.resize(in_mixer_track->buffer.get_num_channels());
|
||||
for (auto& p: peak_) {
|
||||
p = -90.f;
|
||||
}
|
||||
peak_decay_.resize(in_mixer_track->buffer.get_num_channels());
|
||||
}
|
||||
|
||||
@@ -26,15 +29,20 @@ void widget_mixer_track::on_paint(ImGuiIO& io) {
|
||||
for (uint32_t i = 0; i < mixer_track_->ui_buffers.size(); i++) {
|
||||
auto& bu_buffer = mixer_track_->ui_buffers[i];
|
||||
sample_count = std::min(sample_count, bu_buffer.Num());
|
||||
float temp_max = 0.f;
|
||||
for (int i = 0; i < sample_count; ++i) {
|
||||
float sample = bu_buffer.Pop();
|
||||
temp_max = std::max(temp_max, std::abs(sample));
|
||||
}
|
||||
// float temp_max = 0.f;
|
||||
std::vector<float> samples(sample_count);
|
||||
bu_buffer.Pop(samples.data(), sample_count);
|
||||
const float rms = calculate_rms(samples);
|
||||
const float dB = rms_2_db(rms, 1.0f);
|
||||
// for (uint32_t i = 0; i < sample_count; ++i) {
|
||||
// temp_max = std::max(temp_max, std::abs(samples[i]));
|
||||
// }
|
||||
|
||||
update_peak(i, temp_max, io.DeltaTime);
|
||||
update_peak(i, dB, io.DeltaTime);
|
||||
|
||||
draw_volume_bar(temp_max, peak_[i], ImVec2(5.0f, 100.0f), "");
|
||||
// const float peak = get_range_pct(-90.0f, 6.0f, peak_[i]);
|
||||
|
||||
draw_volume_bar(dB, peak_[i], ImVec2(5.0f, 100.0f), "");
|
||||
ImGui::SameLine();
|
||||
}
|
||||
}
|
||||
@@ -50,8 +58,8 @@ void widget_mixer_track::update_peak(uint32_t channel, float new_peak, float del
|
||||
}
|
||||
current_decay -= delta_time;
|
||||
if (current_decay < 0.0f) {
|
||||
current_peak -= delta_time * 0.5f;
|
||||
current_peak = std::max(current_peak, 0.0f);
|
||||
current_peak -= delta_time * 30.f;
|
||||
current_peak = std::max(current_peak, -120.f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user