新增mixer控件
This commit is contained in:
parent
263504c1a2
commit
d325dc51bf
@ -22,6 +22,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
|
||||
# 添加链接库
|
||||
target_link_libraries(${PROJECT_NAME} core imgui)
|
||||
add_definitions(-DIMGUI_USER_CONFIG="widget/user_imconfig.h")
|
||||
#if (WIN32)
|
||||
# target_sources(${PROJECT_NAME} PRIVATE "manifest.rc")
|
||||
# set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/MANIFEST:NO")
|
||||
|
@ -1,9 +1,10 @@
|
||||
#include "arona_application.h"
|
||||
|
||||
#include "window/window_manager.h"
|
||||
#include "imgui.h"
|
||||
#include "widget/widgets.h"
|
||||
#include "audio/plugin_host/plugin_host_manager.h"
|
||||
#include "audio/plugin_host/plugin_host.h"
|
||||
#include "imgui.h"
|
||||
|
||||
application* g_application = nullptr;
|
||||
|
||||
@ -49,22 +50,8 @@ void configure_imgui(ImGuiIO& io) {
|
||||
void draw_imgui(float delta_time) {
|
||||
// 全局dockspace
|
||||
ImGui::DockSpaceOverViewport();
|
||||
ImGui::Begin("Instrument");
|
||||
auto instruments = get_plugin_host_manager()->get_instrument_hosts();
|
||||
for (int32_t i = 0; i < instruments.size(); ++i) {
|
||||
plugin_host* host = instruments.at(i);
|
||||
std::string button_label = host->name + "##" + std::to_string(i);
|
||||
if (ImGui::Button(button_label.c_str())) {
|
||||
host->toggle_editor();
|
||||
}
|
||||
}
|
||||
if (ImGui::Button("Add")) {
|
||||
get_arona_application()->test();
|
||||
}
|
||||
if (ImGui::Button("Test2")) {
|
||||
spdlog::info("log");
|
||||
}
|
||||
ImGui::End();
|
||||
draw_instrument_track();
|
||||
draw_mixer();
|
||||
}
|
||||
|
||||
void tick_imgui(float delta_time) {
|
||||
|
4
Arona/src/widget/user_imconfig.h
Normal file
4
Arona/src/widget/user_imconfig.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#define IMGUI_ENABLE_FREETYPE 1
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS 1
|
240
Arona/src/widget/widgets.cpp
Normal file
240
Arona/src/widget/widgets.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
#include "widgets.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#include "audio/plugin_host/plugin_host_manager.h"
|
||||
#include "audio/plugin_host/plugin_host.h"
|
||||
#include "arona_application.h"
|
||||
#include "audio/mixer/mixer.h"
|
||||
#include "audio/mixer/mixer_track.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "audio/device/audio_device_manager.h"
|
||||
|
||||
bool show_instrument_track = true;
|
||||
bool show_mixer = true;
|
||||
|
||||
void vertical_text(const char* text) {
|
||||
if (!text)
|
||||
return;
|
||||
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
const ImFont* font = io.Fonts->Fonts[0];
|
||||
float font_size = ImGui::GetFontSize();
|
||||
|
||||
ImVec2 cur_pos = window->DC.CursorPos;
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
ImVec2 text_size = ImGui::CalcTextSize(text, nullptr, true);
|
||||
ImRect bb(cur_pos, cur_pos + text_size);
|
||||
|
||||
for (const char* p = text; *p; p++)
|
||||
{
|
||||
const ImFontGlyph* glyph = font->FindGlyph(*p);
|
||||
if (!glyph)
|
||||
continue;
|
||||
|
||||
draw_list->PrimReserve(6, 4);
|
||||
draw_list->PrimRectUV(
|
||||
cur_pos,
|
||||
ImVec2(cur_pos.x + font_size, cur_pos.y + (glyph->Y1 - glyph->Y0) * io.FontGlobalScale),
|
||||
ImVec2(glyph->U0, glyph->V0),
|
||||
ImVec2(glyph->U1, glyph->V1),
|
||||
ImGui::GetColorU32(ImGuiCol_Text)
|
||||
);
|
||||
|
||||
cur_pos.y += (glyph->AdvanceX * io.FontGlobalScale);
|
||||
}
|
||||
ImGui::ItemSize(text_size, 0.0f);
|
||||
ImGui::ItemAdd(bb, 0);
|
||||
}
|
||||
|
||||
void draw_instrument_track() {
|
||||
ImGui::Begin("Instrument", &show_instrument_track);
|
||||
auto instruments = get_plugin_host_manager()->get_instrument_hosts();
|
||||
for (int32_t i = 0; i < instruments.size(); ++i) {
|
||||
plugin_host* host = instruments.at(i);
|
||||
std::string button_label = host->name + "##" + std::to_string(i);
|
||||
if (ImGui::Button(button_label.c_str())) {
|
||||
host->toggle_editor();
|
||||
}
|
||||
}
|
||||
if (ImGui::Button("Add")) {
|
||||
get_arona_application()->test();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void draw_mixer() {
|
||||
ImGui::Begin("Mixer", &show_mixer);
|
||||
auto mixer = get_mixer();
|
||||
auto mixer_tracks = mixer->get_tracks();
|
||||
float delta_time = ImGui::GetIO().DeltaTime;
|
||||
int32_t delta_sample_count = get_audio_device_manager()->get_sample_rate() * delta_time;
|
||||
|
||||
for (int32_t i = 0; i < mixer_tracks.size(); ++i) {
|
||||
mixer_track* track = mixer_tracks.at(i);
|
||||
draw_mixer_track(delta_sample_count, track, i);
|
||||
ImGui::SameLine();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void update_mixer_track_peak(float delta_time, mixer_track* track) {
|
||||
|
||||
}
|
||||
|
||||
void draw_mixer_track(uint32_t delta_sample_count, mixer_track* track, int32_t index) {
|
||||
float delta_time = ImGui::GetIO().DeltaTime;
|
||||
|
||||
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 volume_bar_id = "VolumeBar" + std::to_string(index);
|
||||
|
||||
ImGui::BeginGroup();
|
||||
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);
|
||||
float volume = track->get_volume();
|
||||
if (ImGui::VSliderFloat(slider_id.c_str(), slider_size,&volume, 0.0f, 1.2f)) {
|
||||
track->set_volume(volume);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
std::vector<sample_t> temp_buffer;
|
||||
temp_buffer.reserve(delta_sample_count);
|
||||
std::vector<float> sample_value;
|
||||
std::vector<float> sample_peak;
|
||||
for (int32_t i = 0; i < track->ui_buffers->size(); ++i) {
|
||||
auto& buffer = track->ui_buffers->at(i);
|
||||
auto& peak_info = track->ui_buffer_peaks.at(i);
|
||||
|
||||
// calculate peak
|
||||
uint32_t count = std::min(delta_sample_count, buffer.Num());
|
||||
temp_buffer.resize(count);
|
||||
buffer.Pop(temp_buffer.data(), count);
|
||||
auto peak_it = std::max_element(temp_buffer.begin(), temp_buffer.end(), [](sample_t a, sample_t b) {
|
||||
return std::abs(a) < std::abs(b);
|
||||
});
|
||||
sample_t peak = std::abs(*peak_it);
|
||||
|
||||
// update peak
|
||||
if (peak > peak_info.peak) {
|
||||
peak_info.peak = peak;
|
||||
peak_info.left_time = volume_bar_peak_duration;
|
||||
} else {
|
||||
peak_info.left_time -= delta_time;
|
||||
if (peak_info.left_time < 0.0f) {
|
||||
peak_info.peak -= delta_time * volume_bar_peak_decay;
|
||||
peak_info.left_time = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
sample_value.push_back(peak);
|
||||
sample_peak.push_back(peak_info.peak);
|
||||
}
|
||||
draw_volume_bar(volume_bar_id.c_str(), widget_height, sample_value, sample_peak);
|
||||
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) {
|
||||
// draw a 2d box
|
||||
// calculate the size
|
||||
#if BUILD_DEBUG
|
||||
if (sample_value.size() != sample_peak.size()) {
|
||||
spdlog::error("sample_value size is not equal to sample_peak size");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
|
||||
const ImGuiStyle& style = ImGui::GetStyle();
|
||||
int32_t channel_count = sample_value.size();
|
||||
float channel_width = 6.0f;
|
||||
float widget_width = channel_width * channel_count;
|
||||
float widget_height = height; // TODO: calculate the height
|
||||
ImVec2 size_arg = ImVec2(widget_width, widget_height);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 size = ImGui::CalcItemSize(size_arg, widget_width, widget_height);
|
||||
ImRect bb(pos, pos + size);
|
||||
ImGui::ItemSize(bb);
|
||||
if (!ImGui::ItemAdd(bb, ImGui::GetID(id))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 绘制背景
|
||||
ImGui::RenderFrame(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
|
||||
|
||||
constexpr float safe_level = 0.6f; // 60% 以下绘制绿色
|
||||
constexpr float warning_level = 0.8f; // 80% 以下绘制黄色
|
||||
constexpr float danger_level = 1.0f; // 100% 以下绘制红色
|
||||
const ImColor safe_color = ImColor(0, 255, 0, 255); // green
|
||||
const ImColor warning_color = ImColor(255, 255, 0, 255); // yellow
|
||||
const ImColor danger_color = ImColor(255, 0, 0, 255); // red
|
||||
|
||||
window->DrawList->PushClipRect(bb.Min, bb.Max, true);
|
||||
// 坐标系原点在左上角
|
||||
for (int32_t i = 0; i < channel_count; ++i) {
|
||||
float value = sample_value.at(i);
|
||||
float peak = sample_peak.at(i);
|
||||
|
||||
// 绘制矩形(60%以下的部分绘制绿色,80%以下的部分绘制黄色,100%以下的部分绘制红色)
|
||||
if (value > volume_bar_inf) {
|
||||
ImVec2 clip_bar_start = ImVec2(pos.x, pos.y + widget_height * (1.0f - value));
|
||||
ImVec2 clip_bar_end = ImVec2(pos.x + channel_width, pos.y + widget_height);
|
||||
ImRect bar_rect(clip_bar_start, clip_bar_end);
|
||||
window->DrawList->PushClipRect(bar_rect.Min, bar_rect.Max, true);
|
||||
// 绘制100%的部分
|
||||
{
|
||||
float bar_height = widget_height * danger_level;
|
||||
ImVec2 bar_start = ImVec2(pos.x, pos.y + widget_height - bar_height);
|
||||
ImVec2 bar_end = ImVec2(pos.x + channel_width, pos.y + widget_height);
|
||||
window->DrawList->AddRectFilled(bar_start, bar_end, danger_color);
|
||||
}
|
||||
// 绘制80%的部分
|
||||
{
|
||||
float bar_height = widget_height * warning_level;
|
||||
ImVec2 bar_start = ImVec2(pos.x, pos.y + widget_height - bar_height);
|
||||
ImVec2 bar_end = ImVec2(pos.x + channel_width, pos.y + widget_height);
|
||||
window->DrawList->AddRectFilled(bar_start, bar_end, warning_color);
|
||||
}
|
||||
// 绘制60%以下的部分
|
||||
{
|
||||
float bar_height = widget_height * safe_level;
|
||||
ImVec2 bar_start = ImVec2(pos.x, pos.y + widget_height - bar_height);
|
||||
ImVec2 bar_end = ImVec2(pos.x + channel_width, pos.y + widget_height);
|
||||
window->DrawList->AddRectFilled(bar_start, bar_end, safe_color);
|
||||
}
|
||||
window->DrawList->PopClipRect();
|
||||
}
|
||||
|
||||
// 绘制Peak
|
||||
if (peak > volume_bar_inf) {
|
||||
const ImColor peak_color = peak <= safe_level ? safe_color : peak <= warning_level ? warning_color : danger_color;
|
||||
float peak_height = pos.y + widget_height * (1 - peak);
|
||||
ImVec2 peak_start = ImVec2(pos.x, peak_height);
|
||||
ImVec2 peak_end = ImVec2(pos.x + channel_width, peak_height + 1);
|
||||
window->DrawList->AddRectFilled(peak_start, peak_end, peak_color);
|
||||
}
|
||||
|
||||
// 绘制垂直分割线
|
||||
if (i != channel_count - 1) {
|
||||
ImVec2 line_start = ImVec2(pos.x + channel_width, pos.y);
|
||||
ImVec2 line_end = ImVec2(pos.x + channel_width, pos.y + widget_height);
|
||||
window->DrawList->AddLine(line_start, line_end, ImGui::GetColorU32(ImGuiCol_Header));
|
||||
}
|
||||
|
||||
pos.x += channel_width;
|
||||
}
|
||||
window->DrawList->PopClipRect();
|
||||
}
|
16
Arona/src/widget/widgets.h
Normal file
16
Arona/src/widget/widgets.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
class mixer_track;
|
||||
|
||||
void vertical_text(const char* text);
|
||||
|
||||
void draw_instrument_track();
|
||||
void draw_mixer();
|
||||
void draw_mixer_track(uint32_t delta_sample_count, mixer_track* track, int32_t index);
|
||||
void draw_volume_bar(const char* id, float height, std::vector<float> sample_value, std::vector<float> sample_peak);
|
||||
|
||||
inline float volume_bar_peak_duration = 0.5f;
|
||||
inline float volume_bar_peak_decay = 0.1f;
|
||||
inline constexpr float volume_bar_inf = 0.0001f;
|
@ -1 +1 @@
|
||||
Subproject commit dc4576634d6a78c1d50a84dca321ee6f05e3a8a0
|
||||
Subproject commit 1c76e93d291ace5df5ccf55ad6549bf28e8dc4fa
|
Loading…
x
Reference in New Issue
Block a user