Path: blob/master/editor/audio/editor_audio_buses.cpp
9896 views
/**************************************************************************/1/* editor_audio_buses.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "editor_audio_buses.h"3132#include "core/config/project_settings.h"33#include "core/input/input.h"34#include "core/io/resource_saver.h"35#include "core/os/keyboard.h"36#include "editor/docks/filesystem_dock.h"37#include "editor/editor_node.h"38#include "editor/editor_string_names.h"39#include "editor/editor_undo_redo_manager.h"40#include "editor/gui/editor_bottom_panel.h"41#include "editor/gui/editor_file_dialog.h"42#include "editor/settings/editor_command_palette.h"43#include "editor/settings/editor_settings.h"44#include "editor/themes/editor_scale.h"45#include "editor/themes/editor_theme_manager.h"46#include "scene/gui/separator.h"47#include "scene/resources/font.h"48#include "servers/audio_server.h"4950void EditorAudioBus::_update_visible_channels() {51int i = 0;52for (; i < cc; i++) {53if (!channel[i].vu_l->is_visible()) {54channel[i].vu_l->show();55}56if (!channel[i].vu_r->is_visible()) {57channel[i].vu_r->show();58}59}6061for (; i < CHANNELS_MAX; i++) {62if (channel[i].vu_l->is_visible()) {63channel[i].vu_l->hide();64}65if (channel[i].vu_r->is_visible()) {66channel[i].vu_r->hide();67}68}69}7071void EditorAudioBus::_notification(int p_what) {72switch (p_what) {73case NOTIFICATION_THEME_CHANGED: {74Ref<Texture2D> active_bus_texture = get_editor_theme_icon(SNAME("BusVuActive"));75for (int i = 0; i < CHANNELS_MAX; i++) {76channel[i].vu_l->set_under_texture(active_bus_texture);77channel[i].vu_l->set_tint_under(Color(0.75, 0.75, 0.75));78channel[i].vu_l->set_progress_texture(active_bus_texture);7980channel[i].vu_r->set_under_texture(active_bus_texture);81channel[i].vu_r->set_tint_under(Color(0.75, 0.75, 0.75));82channel[i].vu_r->set_progress_texture(active_bus_texture);83channel[i].prev_active = true;84}8586disabled_vu = get_editor_theme_icon(SNAME("BusVuFrozen"));8788Color solo_color = EditorThemeManager::is_dark_theme() ? Color(1.0, 0.89, 0.22) : Color(1.9, 1.74, 0.83);89Color mute_color = EditorThemeManager::is_dark_theme() ? Color(1.0, 0.16, 0.16) : Color(2.35, 1.03, 1.03);90Color bypass_color = EditorThemeManager::is_dark_theme() ? Color(0.13, 0.8, 1.0) : Color(1.03, 2.04, 2.35);91float darkening_factor = EditorThemeManager::is_dark_theme() ? 0.15 : 0.65;92Color solo_color_darkened = solo_color.darkened(darkening_factor);93Color mute_color_darkened = mute_color.darkened(darkening_factor);94Color bypass_color_darkened = bypass_color.darkened(darkening_factor);9596Ref<StyleBoxFlat>(solo->get_theme_stylebox(SceneStringName(pressed)))->set_border_color(solo_color_darkened);97Ref<StyleBoxFlat>(mute->get_theme_stylebox(SceneStringName(pressed)))->set_border_color(mute_color_darkened);98Ref<StyleBoxFlat>(bypass->get_theme_stylebox(SceneStringName(pressed)))->set_border_color(bypass_color_darkened);99Ref<StyleBoxFlat>(solo->get_theme_stylebox("hover_pressed"))->set_border_color(solo_color_darkened);100Ref<StyleBoxFlat>(mute->get_theme_stylebox("hover_pressed"))->set_border_color(mute_color_darkened);101Ref<StyleBoxFlat>(bypass->get_theme_stylebox("hover_pressed"))->set_border_color(bypass_color_darkened);102103solo->set_button_icon(get_editor_theme_icon(SNAME("AudioBusSolo")));104solo->add_theme_color_override("icon_pressed_color", solo_color);105solo->add_theme_color_override("icon_hover_pressed_color", solo_color_darkened);106mute->set_button_icon(get_editor_theme_icon(SNAME("AudioBusMute")));107mute->add_theme_color_override("icon_pressed_color", mute_color);108mute->add_theme_color_override("icon_hover_pressed_color", mute_color_darkened);109bypass->set_button_icon(get_editor_theme_icon(SNAME("AudioBusBypass")));110bypass->add_theme_color_override("icon_pressed_color", bypass_color);111bypass->add_theme_color_override("icon_hover_pressed_color", bypass_color_darkened);112113bus_options->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));114115audio_value_preview_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SceneStringName(font_color), SNAME("TooltipLabel")));116audio_value_preview_label->add_theme_color_override("font_shadow_color", get_theme_color(SNAME("font_shadow_color"), SNAME("TooltipLabel")));117audio_value_preview_box->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TooltipPanel")));118119for (int i = 0; i < effect_options->get_item_count(); i++) {120String class_name = effect_options->get_item_metadata(i);121Ref<Texture> icon = EditorNode::get_singleton()->get_class_icon(class_name);122effect_options->set_item_icon(i, icon);123}124} break;125126case NOTIFICATION_READY: {127update_bus();128set_process(true);129} break;130131case NOTIFICATION_ACCESSIBILITY_UPDATE: {132RID ae = get_accessibility_element();133ERR_FAIL_COND(ae.is_null());134135DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_STATIC_TEXT);136DisplayServer::get_singleton()->accessibility_update_set_value(ae, TTR(vformat("The %s is not accessible at this time.", "Audio bus editor")));137} break;138139case NOTIFICATION_DRAW: {140if (is_master) {141draw_style_box(get_theme_stylebox(SNAME("master"), SNAME("EditorAudioBus")), Rect2(Vector2(), get_size()));142} else if (has_focus()) {143draw_style_box(get_theme_stylebox(SNAME("focus"), SNAME("EditorAudioBus")), Rect2(Vector2(), get_size()));144} else {145draw_style_box(get_theme_stylebox(SNAME("normal"), SNAME("EditorAudioBus")), Rect2(Vector2(), get_size()));146}147148if (get_index() != 0 && hovering_drop) {149Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));150accent.a *= 0.7;151draw_rect(Rect2(Point2(), get_size()), accent, false);152}153} break;154155case NOTIFICATION_PROCESS: {156if (cc != AudioServer::get_singleton()->get_bus_channels(get_index())) {157cc = AudioServer::get_singleton()->get_bus_channels(get_index());158_update_visible_channels();159}160161for (int i = 0; i < cc; i++) {162float real_peak[2] = { -100, -100 };163bool activity_found = false;164165if (AudioServer::get_singleton()->is_bus_channel_active(get_index(), i)) {166activity_found = true;167real_peak[0] = MAX(real_peak[0], AudioServer::get_singleton()->get_bus_peak_volume_left_db(get_index(), i));168real_peak[1] = MAX(real_peak[1], AudioServer::get_singleton()->get_bus_peak_volume_right_db(get_index(), i));169}170171if (real_peak[0] > channel[i].peak_l) {172channel[i].peak_l = real_peak[0];173} else {174channel[i].peak_l -= get_process_delta_time() * 60.0;175}176177if (real_peak[1] > channel[i].peak_r) {178channel[i].peak_r = real_peak[1];179} else {180channel[i].peak_r -= get_process_delta_time() * 60.0;181}182183channel[i].vu_l->set_value(channel[i].peak_l);184channel[i].vu_r->set_value(channel[i].peak_r);185186if (activity_found != channel[i].prev_active) {187if (activity_found) {188channel[i].vu_l->set_over_texture(Ref<Texture2D>());189channel[i].vu_r->set_over_texture(Ref<Texture2D>());190} else {191channel[i].vu_l->set_over_texture(disabled_vu);192channel[i].vu_r->set_over_texture(disabled_vu);193}194195channel[i].prev_active = activity_found;196}197}198} break;199200case NOTIFICATION_VISIBILITY_CHANGED: {201for (int i = 0; i < CHANNELS_MAX; i++) {202channel[i].peak_l = -100;203channel[i].peak_r = -100;204channel[i].prev_active = true;205}206207set_process(is_visible_in_tree());208} break;209210case NOTIFICATION_MOUSE_EXIT:211case NOTIFICATION_DRAG_END: {212if (hovering_drop) {213hovering_drop = false;214queue_redraw();215}216} break;217}218}219220void EditorAudioBus::update_send() {221send->clear();222if (is_master) {223send->set_disabled(true);224send->set_text(TTR("Speakers"));225} else {226send->set_disabled(false);227StringName current_send = AudioServer::get_singleton()->get_bus_send(get_index());228int current_send_index = 0; //by default to master229230for (int i = 0; i < get_index(); i++) {231StringName send_name = AudioServer::get_singleton()->get_bus_name(i);232send->add_item(send_name);233if (send_name == current_send) {234current_send_index = i;235}236}237238send->select(current_send_index);239}240}241242void EditorAudioBus::update_bus() {243if (updating_bus) {244return;245}246247updating_bus = true;248249int index = get_index();250251float db_value = AudioServer::get_singleton()->get_bus_volume_db(index);252slider->set_value(_scaled_db_to_normalized_volume(db_value));253track_name->set_text(AudioServer::get_singleton()->get_bus_name(index));254if (is_master) {255track_name->set_editable(false);256}257258solo->set_pressed(AudioServer::get_singleton()->is_bus_solo(index));259mute->set_pressed(AudioServer::get_singleton()->is_bus_mute(index));260bypass->set_pressed(AudioServer::get_singleton()->is_bus_bypassing_effects(index));261// effects..262effects->clear();263264TreeItem *root = effects->create_item();265for (int i = 0; i < AudioServer::get_singleton()->get_bus_effect_count(index); i++) {266Ref<AudioEffect> afx = AudioServer::get_singleton()->get_bus_effect(index, i);267268TreeItem *fx = effects->create_item(root);269fx->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);270fx->set_editable(0, true);271fx->set_checked(0, AudioServer::get_singleton()->is_bus_effect_enabled(index, i));272fx->set_text(0, afx->get_name());273fx->set_metadata(0, i);274}275276TreeItem *add = effects->create_item(root);277add->set_cell_mode(0, TreeItem::CELL_MODE_CUSTOM);278add->set_editable(0, true);279add->set_selectable(0, false);280add->set_text(0, TTR("Add Effect"));281282update_send();283284updating_bus = false;285}286287void EditorAudioBus::_name_changed(const String &p_new_name) {288if (updating_bus) {289return;290}291updating_bus = true;292track_name->release_focus();293294if (p_new_name == AudioServer::get_singleton()->get_bus_name(get_index())) {295updating_bus = false;296return;297}298299String attempt = p_new_name;300int attempts = 1;301302while (true) {303bool name_free = true;304for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {305if (AudioServer::get_singleton()->get_bus_name(i) == attempt) {306name_free = false;307break;308}309}310311if (name_free) {312break;313}314315attempts++;316attempt = p_new_name + " " + itos(attempts);317}318319EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();320321StringName current = AudioServer::get_singleton()->get_bus_name(get_index());322323ur->create_action(TTR("Rename Audio Bus"));324325ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", get_index(), attempt);326ur->add_undo_method(AudioServer::get_singleton(), "set_bus_name", get_index(), current);327328for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {329if (AudioServer::get_singleton()->get_bus_send(i) == current) {330ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", i, attempt);331ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", i, current);332}333}334335ur->add_do_method(buses, "_update_bus", get_index());336ur->add_undo_method(buses, "_update_bus", get_index());337338ur->add_do_method(buses, "_update_sends");339ur->add_undo_method(buses, "_update_sends");340341ur->commit_action();342343updating_bus = false;344}345346void EditorAudioBus::_volume_changed(float p_normalized) {347if (updating_bus) {348return;349}350351updating_bus = true;352353const float p_db = _normalized_volume_to_scaled_db(p_normalized);354355if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {356// Snap the value when holding Ctrl for easier editing.357// To do so, it needs to be converted back to normalized volume (as the slider uses that unit).358slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db)));359}360361EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();362ur->create_action(TTR("Change Audio Bus Volume"), UndoRedo::MERGE_ENDS);363ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), p_db);364ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), AudioServer::get_singleton()->get_bus_volume_db(get_index()));365ur->add_do_method(buses, "_update_bus", get_index());366ur->add_undo_method(buses, "_update_bus", get_index());367ur->commit_action();368369updating_bus = false;370}371372float EditorAudioBus::_normalized_volume_to_scaled_db(float normalized) {373/* There are three different formulas for the conversion from normalized374* values to relative decibal values.375* One formula is an exponential graph which intends to counteract376* the logarithmic nature of human hearing. This is an approximation377* of the behavior of a 'logarithmic potentiometer' found on most378* musical instruments and also emulated in popular software.379* The other two equations are hand-tuned linear tapers that intend to380* try to ease the exponential equation in areas where it makes sense.*/381382if (normalized > 0.6f) {383return 22.22f * normalized - 16.2f;384} else if (normalized < 0.05f) {385return 830.72 * normalized - 80.0f;386} else {387return 45.0f * Math::pow(normalized - 1.0, 3);388}389}390391float EditorAudioBus::_scaled_db_to_normalized_volume(float db) {392/* Inversion of equations found in _normalized_volume_to_scaled_db.393* IMPORTANT: If one function changes, the other much change to reflect it. */394if (db > -2.88) {395return (db + 16.2f) / 22.22f;396} else if (db < -38.602f) {397return (db + 80.00f) / 830.72f;398} else {399if (db < 0.0) {400/* To accommodate for NaN on negative numbers for root, we will mirror the401* results of the positive db range in order to get the desired numerical402* value on the negative side. */403float positive_x = Math::pow(Math::abs(db) / 45.0f, 1.0f / 3.0f) + 1.0f;404Vector2 translation = Vector2(1.0f, 0.0f) - Vector2(positive_x, Math::abs(db));405Vector2 reflected_position = Vector2(1.0, 0.0f) + translation;406return reflected_position.x;407} else {408return Math::pow(db / 45.0f, 1.0f / 3.0f) + 1.0f;409}410}411}412413void EditorAudioBus::_show_value(float slider_value) {414float db;415if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {416// Display the correct (snapped) value when holding Ctrl417db = Math::round(_normalized_volume_to_scaled_db(slider_value));418} else {419db = _normalized_volume_to_scaled_db(slider_value);420}421422String text;423if (Math::is_zero_approx(Math::snapped(db, 0.1))) {424// Prevent displaying `-0.0 dB` and show ` 0.0 dB` instead.425// The leading space makes the text visually line up with its positive/negative counterparts.426text = " 0.0 dB";427} else {428// Show an explicit `+` sign if positive.429text = vformat("%+.1f dB", db);430}431432// Also set the preview text as a standard Control tooltip.433// This way, it can be seen when the slider is merely hovered (instead of dragged).434slider->set_tooltip_text(text);435audio_value_preview_label->set_text(text);436const Vector2 slider_size = slider->get_size();437const Vector2 slider_position = slider->get_global_position();438const float vert_padding = 10.0f;439const Vector2 box_position = Vector2(slider_size.x, (slider_size.y - vert_padding) * (1.0f - slider->get_value()) - vert_padding);440audio_value_preview_box->set_position(slider_position + box_position);441audio_value_preview_box->set_size(audio_value_preview_label->get_size());442if (slider->has_focus() && !audio_value_preview_box->is_visible()) {443audio_value_preview_box->show();444}445preview_timer->start();446}447448void EditorAudioBus::_hide_value_preview() {449audio_value_preview_box->hide();450}451452void EditorAudioBus::_solo_toggled() {453updating_bus = true;454455EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();456ur->create_action(TTR("Toggle Audio Bus Solo"));457ur->add_do_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), solo->is_pressed());458ur->add_undo_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), AudioServer::get_singleton()->is_bus_solo(get_index()));459ur->add_do_method(buses, "_update_bus", get_index());460ur->add_undo_method(buses, "_update_bus", get_index());461ur->commit_action();462463updating_bus = false;464}465466void EditorAudioBus::_mute_toggled() {467updating_bus = true;468469EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();470ur->create_action(TTR("Toggle Audio Bus Mute"));471ur->add_do_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), mute->is_pressed());472ur->add_undo_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), AudioServer::get_singleton()->is_bus_mute(get_index()));473ur->add_do_method(buses, "_update_bus", get_index());474ur->add_undo_method(buses, "_update_bus", get_index());475ur->commit_action();476477updating_bus = false;478}479480void EditorAudioBus::_bypass_toggled() {481updating_bus = true;482483EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();484ur->create_action(TTR("Toggle Audio Bus Bypass Effects"));485ur->add_do_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), bypass->is_pressed());486ur->add_undo_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), AudioServer::get_singleton()->is_bus_bypassing_effects(get_index()));487ur->add_do_method(buses, "_update_bus", get_index());488ur->add_undo_method(buses, "_update_bus", get_index());489ur->commit_action();490491updating_bus = false;492}493494void EditorAudioBus::_send_selected(int p_which) {495updating_bus = true;496497EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();498ur->create_action(TTR("Select Audio Bus Send"));499ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", get_index(), send->get_item_text(p_which));500ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", get_index(), AudioServer::get_singleton()->get_bus_send(get_index()));501ur->add_do_method(buses, "_update_bus", get_index());502ur->add_undo_method(buses, "_update_bus", get_index());503ur->commit_action();504505updating_bus = false;506}507508void EditorAudioBus::_effect_selected() {509TreeItem *effect = effects->get_selected();510if (!effect) {511return;512}513updating_bus = true;514515if (effect->get_metadata(0) != Variant()) {516int index = effect->get_metadata(0);517Ref<AudioEffect> effect2 = AudioServer::get_singleton()->get_bus_effect(get_index(), index);518if (effect2.is_valid()) {519EditorNode::get_singleton()->push_item(effect2.ptr());520}521}522523updating_bus = false;524}525526void EditorAudioBus::_effect_edited() {527if (updating_bus) {528return;529}530531TreeItem *effect = effects->get_edited();532if (!effect) {533return;534}535536if (effect->get_metadata(0) == Variant()) {537Rect2 area = effects->get_item_rect(effect);538539effect_options->set_position(effects->get_screen_position() + area.position + Vector2(0, area.size.y));540effect_options->reset_size();541effect_options->popup();542//add effect543} else {544int index = effect->get_metadata(0);545updating_bus = true;546547EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();548ur->create_action(TTR("Select Audio Bus Send"));549ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, effect->is_checked(0));550ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, AudioServer::get_singleton()->is_bus_effect_enabled(get_index(), index));551ur->add_do_method(buses, "_update_bus", get_index());552ur->add_undo_method(buses, "_update_bus", get_index());553ur->commit_action();554555updating_bus = false;556}557}558559void EditorAudioBus::_effect_add(int p_which) {560if (updating_bus) {561return;562}563564StringName name = effect_options->get_item_metadata(p_which);565566Object *fx = ClassDB::instantiate(name);567ERR_FAIL_NULL(fx);568AudioEffect *afx = Object::cast_to<AudioEffect>(fx);569ERR_FAIL_NULL(afx);570Ref<AudioEffect> afxr = Ref<AudioEffect>(afx);571572afxr->set_name(effect_options->get_item_text(p_which));573574EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();575ur->create_action(TTR("Add Audio Bus Effect"));576ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), afxr, -1);577ur->add_undo_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect_count(get_index()));578ur->add_do_method(buses, "_update_bus", get_index());579ur->add_undo_method(buses, "_update_bus", get_index());580ur->commit_action();581}582583void EditorAudioBus::gui_input(const Ref<InputEvent> &p_event) {584ERR_FAIL_COND(p_event.is_null());585586Ref<InputEventMouseButton> mb = p_event;587if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {588bus_popup->set_position(get_screen_position() + mb->get_position());589bus_popup->reset_size();590bus_popup->popup();591}592593Ref<InputEventKey> k = p_event;594if (k.is_valid() && k->is_pressed() && k->is_action("ui_menu", true)) {595bus_popup->set_position(get_screen_position());596bus_popup->reset_size();597bus_popup->popup();598599accept_event();600}601}602603void EditorAudioBus::_effects_gui_input(Ref<InputEvent> p_event) {604Ref<InputEventKey> k = p_event;605if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == Key::KEY_DELETE) {606TreeItem *current_effect = effects->get_selected();607if (current_effect && current_effect->get_metadata(0).get_type() == Variant::INT) {608_delete_effect_pressed(0);609accept_event();610}611}612}613614void EditorAudioBus::_bus_popup_pressed(int p_option) {615if (p_option == 2) {616// Reset volume617emit_signal(SNAME("vol_reset_request"));618} else if (p_option == 1) {619emit_signal(SNAME("delete_request"));620} else if (p_option == 0) {621//duplicate622emit_signal(SNAME("duplicate_request"), get_index());623}624}625626Variant EditorAudioBus::get_drag_data(const Point2 &p_point) {627if (get_index() == 0) {628return Variant();629}630631Control *c = memnew(Control);632Panel *p = memnew(Panel);633c->add_child(p);634p->set_modulate(Color(1, 1, 1, 0.7));635p->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("focus"), SNAME("Button")));636p->set_size(get_size());637p->set_position((p_point == Vector2(Math::INF, Math::INF)) ? Vector2() : -p_point);638set_drag_preview(c);639Dictionary d;640d["type"] = "move_audio_bus";641d["index"] = get_index();642643if (get_index() < AudioServer::get_singleton()->get_bus_count() - 1) {644emit_signal(SNAME("drop_end_request"));645}646647return d;648}649650bool EditorAudioBus::can_drop_data(const Point2 &p_point, const Variant &p_data) const {651if (get_index() == 0) {652return false;653}654655Dictionary d = p_data;656if (d.has("type") && String(d["type"]) == "move_audio_bus" && (int)d["index"] != get_index()) {657hovering_drop = true;658return true;659}660661return false;662}663664void EditorAudioBus::drop_data(const Point2 &p_point, const Variant &p_data) {665Dictionary d = p_data;666emit_signal(SNAME("dropped"), d["index"], get_index());667}668669Variant EditorAudioBus::get_drag_data_fw(const Point2 &p_point, Control *p_from) {670TreeItem *item = (p_point == Vector2(Math::INF, Math::INF)) ? effects->get_selected() : effects->get_item_at_position(p_point);671if (!item) {672return Variant();673}674675Variant md = item->get_metadata(0);676if (md.get_type() == Variant::INT) {677Dictionary fxd;678fxd["type"] = "audio_bus_effect";679fxd["bus"] = get_index();680fxd["effect"] = md;681682Label *l = memnew(Label);683l->set_focus_mode(FOCUS_ACCESSIBILITY);684l->set_text(item->get_text(0));685l->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);686effects->set_drag_preview(l);687688return fxd;689}690691return Variant();692}693694bool EditorAudioBus::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {695Dictionary d = p_data;696if (!d.has("type") || String(d["type"]) != "audio_bus_effect") {697return false;698}699700TreeItem *item = (p_point == Vector2(Math::INF, Math::INF)) ? effects->get_selected() : effects->get_item_at_position(p_point);701if (!item) {702return false;703}704705effects->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);706707return true;708}709710void EditorAudioBus::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {711Dictionary d = p_data;712713TreeItem *item = (p_point == Vector2(Math::INF, Math::INF)) ? effects->get_selected() : effects->get_item_at_position(p_point);714if (!item) {715return;716}717int pos = (p_point == Vector2(Math::INF, Math::INF)) ? effects->get_drop_section_at_position(effects->get_item_rect(item).position) : effects->get_drop_section_at_position(p_point);718Variant md = item->get_metadata(0);719720int paste_at;721int bus = d["bus"];722int effect = d["effect"];723724if (md.get_type() == Variant::INT) {725paste_at = md;726if (pos > 0) {727paste_at++;728}729730if (bus == get_index() && paste_at > effect) {731paste_at--;732}733} else {734paste_at = -1;735}736737bool enabled = AudioServer::get_singleton()->is_bus_effect_enabled(bus, effect);738739EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();740ur->create_action(TTR("Move Bus Effect"));741ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", bus, effect);742ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(bus, effect), paste_at);743744if (paste_at == -1) {745paste_at = AudioServer::get_singleton()->get_bus_effect_count(get_index());746if (bus == get_index()) {747paste_at--;748}749}750if (!enabled) {751ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), paste_at, false);752}753754ur->add_undo_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), paste_at);755ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", bus, AudioServer::get_singleton()->get_bus_effect(bus, effect), effect);756if (!enabled) {757ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", bus, effect, false);758}759760ur->add_do_method(buses, "_update_bus", get_index());761ur->add_undo_method(buses, "_update_bus", get_index());762if (get_index() != bus) {763ur->add_do_method(buses, "_update_bus", bus);764ur->add_undo_method(buses, "_update_bus", bus);765}766ur->commit_action();767}768769void EditorAudioBus::_delete_effect_pressed(int p_option) {770TreeItem *item = effects->get_selected();771if (!item) {772return;773}774775if (item->get_metadata(0).get_type() != Variant::INT) {776return;777}778779int index = item->get_metadata(0);780781EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();782ur->create_action(TTR("Delete Bus Effect"));783ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), index);784ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(get_index(), index), index);785ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, AudioServer::get_singleton()->is_bus_effect_enabled(get_index(), index));786ur->add_do_method(buses, "_update_bus", get_index());787ur->add_undo_method(buses, "_update_bus", get_index());788ur->commit_action();789}790791void EditorAudioBus::_effect_rmb(const Vector2 &p_pos, MouseButton p_button) {792if (p_button != MouseButton::RIGHT) {793return;794}795796TreeItem *item = effects->get_selected();797if (!item) {798return;799}800801if (item->get_metadata(0).get_type() != Variant::INT) {802return;803}804805delete_effect_popup->set_position(get_screen_position() + get_local_mouse_position());806delete_effect_popup->reset_size();807delete_effect_popup->popup();808}809810void EditorAudioBus::_bind_methods() {811ClassDB::bind_method("update_bus", &EditorAudioBus::update_bus);812ClassDB::bind_method("update_send", &EditorAudioBus::update_send);813814ADD_SIGNAL(MethodInfo("duplicate_request"));815ADD_SIGNAL(MethodInfo("delete_request"));816ADD_SIGNAL(MethodInfo("vol_reset_request"));817ADD_SIGNAL(MethodInfo("drop_end_request"));818ADD_SIGNAL(MethodInfo("dropped"));819}820821EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {822buses = p_buses;823is_master = p_is_master;824825set_tooltip_text(TTR("Drag & drop to rearrange."));826827VBoxContainer *vb = memnew(VBoxContainer);828vb->add_theme_constant_override("separation", 4 * EDSCALE);829add_child(vb);830831set_v_size_flags(SIZE_EXPAND_FILL);832833track_name = memnew(LineEdit);834track_name->set_accessibility_name(TTRC("Track Name"));835track_name->connect(SceneStringName(text_submitted), callable_mp(this, &EditorAudioBus::_name_changed));836track_name->connect(SceneStringName(focus_exited), callable_mp(this, &EditorAudioBus::_name_focus_exit));837vb->add_child(track_name);838839HBoxContainer *hbc = memnew(HBoxContainer);840vb->add_child(hbc);841solo = memnew(Button);842solo->set_theme_type_variation(SceneStringName(FlatButton));843solo->set_toggle_mode(true);844solo->set_tooltip_text(TTR("Solo"));845solo->set_focus_mode(FOCUS_ACCESSIBILITY);846solo->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBus::_solo_toggled));847hbc->add_child(solo);848mute = memnew(Button);849mute->set_theme_type_variation(SceneStringName(FlatButton));850mute->set_toggle_mode(true);851mute->set_tooltip_text(TTR("Mute"));852mute->set_focus_mode(FOCUS_ACCESSIBILITY);853mute->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBus::_mute_toggled));854hbc->add_child(mute);855bypass = memnew(Button);856bypass->set_theme_type_variation(SceneStringName(FlatButton));857bypass->set_toggle_mode(true);858bypass->set_tooltip_text(TTR("Bypass"));859bypass->set_focus_mode(FOCUS_ACCESSIBILITY);860bypass->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBus::_bypass_toggled));861hbc->add_child(bypass);862hbc->add_spacer();863864Ref<StyleBoxEmpty> sbempty = memnew(StyleBoxEmpty);865for (int i = 0; i < hbc->get_child_count(); i++) {866Control *child = Object::cast_to<Control>(hbc->get_child(i));867child->begin_bulk_theme_override();868child->add_theme_style_override(CoreStringName(normal), sbempty);869child->add_theme_style_override(SceneStringName(hover), sbempty);870child->add_theme_style_override("hover_mirrored", sbempty);871child->add_theme_style_override("focus", sbempty);872child->add_theme_style_override("focus_mirrored", sbempty);873874Ref<StyleBoxFlat> sbflat = memnew(StyleBoxFlat);875sbflat->set_content_margin_all(0);876sbflat->set_bg_color(Color(1, 1, 1, 0));877sbflat->set_border_width(Side::SIDE_BOTTOM, Math::round(3 * EDSCALE));878child->add_theme_style_override(SceneStringName(pressed), sbflat);879child->add_theme_style_override("pressed_mirrored", sbflat);880child->add_theme_style_override("hover_pressed", sbflat);881child->add_theme_style_override("hover_pressed_mirrored", sbflat);882883child->end_bulk_theme_override();884}885886HSeparator *separator = memnew(HSeparator);887separator->set_mouse_filter(MOUSE_FILTER_PASS);888vb->add_child(separator);889890Control *spacer_top = memnew(Control);891spacer_top->set_custom_minimum_size(Size2(0, 6 * EDSCALE));892vb->add_child(spacer_top);893894HBoxContainer *hb = memnew(HBoxContainer);895vb->add_child(hb);896897Control *spacer_bottom = memnew(Control);898spacer_bottom->set_custom_minimum_size(Size2(0, 2 * EDSCALE));899vb->add_child(spacer_bottom);900901slider = memnew(VSlider);902slider->set_min(0.0);903slider->set_max(1.0);904slider->set_step(0.0001);905slider->set_clip_contents(false);906slider->set_accessibility_name(TTRC("Volume"));907908audio_value_preview_box = memnew(Panel);909slider->add_child(audio_value_preview_box);910audio_value_preview_box->set_as_top_level(true);911audio_value_preview_box->set_mouse_filter(MOUSE_FILTER_PASS);912audio_value_preview_box->hide();913914HBoxContainer *audioprev_hbc = memnew(HBoxContainer);915audioprev_hbc->set_v_size_flags(SIZE_EXPAND_FILL);916audioprev_hbc->set_h_size_flags(SIZE_EXPAND_FILL);917audio_value_preview_box->add_child(audioprev_hbc);918919audio_value_preview_label = memnew(Label);920audio_value_preview_label->set_focus_mode(FOCUS_ACCESSIBILITY);921audio_value_preview_label->set_v_size_flags(SIZE_EXPAND_FILL);922audio_value_preview_label->set_h_size_flags(SIZE_EXPAND_FILL);923audio_value_preview_label->set_mouse_filter(MOUSE_FILTER_PASS);924audioprev_hbc->add_child(audio_value_preview_label);925926preview_timer = memnew(Timer);927preview_timer->set_wait_time(0.8f);928preview_timer->set_one_shot(true);929add_child(preview_timer);930931slider->connect(SceneStringName(value_changed), callable_mp(this, &EditorAudioBus::_volume_changed));932slider->connect(SceneStringName(value_changed), callable_mp(this, &EditorAudioBus::_show_value));933preview_timer->connect("timeout", callable_mp(this, &EditorAudioBus::_hide_value_preview));934hb->add_child(slider);935936cc = 0;937for (int i = 0; i < CHANNELS_MAX; i++) {938channel[i].vu_l = memnew(TextureProgressBar);939channel[i].vu_l->set_fill_mode(TextureProgressBar::FILL_BOTTOM_TO_TOP);940hb->add_child(channel[i].vu_l);941channel[i].vu_l->set_min(-80);942channel[i].vu_l->set_max(24);943channel[i].vu_l->set_step(0.1);944channel[i].vu_l->set_accessibility_name(vformat(TTR("Channel %d, Left VU"), i));945946channel[i].vu_r = memnew(TextureProgressBar);947channel[i].vu_r->set_fill_mode(TextureProgressBar::FILL_BOTTOM_TO_TOP);948hb->add_child(channel[i].vu_r);949channel[i].vu_r->set_min(-80);950channel[i].vu_r->set_max(24);951channel[i].vu_r->set_step(0.1);952channel[i].vu_r->set_accessibility_name(vformat(TTR("Channel %d, Right VU"), i));953954channel[i].peak_l = 0.0f;955channel[i].peak_r = 0.0f;956}957958EditorAudioMeterNotches *scale = memnew(EditorAudioMeterNotches);959960for (float db = 6.0f; db >= -80.0f; db -= 6.0f) {961bool renderNotch = (db >= -6.0f || db == -24.0f || db == -72.0f);962scale->add_notch(_scaled_db_to_normalized_volume(db), db, renderNotch);963}964scale->set_mouse_filter(MOUSE_FILTER_PASS);965hb->add_child(scale);966967effects = memnew(Tree);968effects->set_accessibility_name(TTRC("Effects"));969effects->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);970effects->set_hide_root(true);971effects->set_custom_minimum_size(Size2(0, 80) * EDSCALE);972effects->set_hide_folding(true);973effects->set_v_size_flags(SIZE_EXPAND_FILL);974vb->add_child(effects);975effects->connect("item_edited", callable_mp(this, &EditorAudioBus::_effect_edited));976effects->connect("cell_selected", callable_mp(this, &EditorAudioBus::_effect_selected));977effects->connect(SceneStringName(focus_exited), callable_mp(effects, &Tree::deselect_all));978effects->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);979SET_DRAG_FORWARDING_GCD(effects, EditorAudioBus);980effects->connect("item_mouse_selected", callable_mp(this, &EditorAudioBus::_effect_rmb));981effects->set_allow_rmb_select(true);982effects->set_focus_mode(FOCUS_CLICK);983effects->set_allow_reselect(true);984effects->set_theme_type_variation("TreeSecondary");985effects->connect(SceneStringName(gui_input), callable_mp(this, &EditorAudioBus::_effects_gui_input));986987send = memnew(OptionButton);988send->set_accessibility_name(TTRC("Send"));989send->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);990send->set_clip_text(true);991send->connect(SceneStringName(item_selected), callable_mp(this, &EditorAudioBus::_send_selected));992vb->add_child(send);993994set_focus_mode(FOCUS_CLICK);995996effect_options = memnew(PopupMenu);997effect_options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // Don't translate class names.998effect_options->connect("index_pressed", callable_mp(this, &EditorAudioBus::_effect_add));999add_child(effect_options);1000LocalVector<StringName> effect_list;1001ClassDB::get_inheriters_from_class("AudioEffect", effect_list);1002effect_list.sort_custom<StringName::AlphCompare>();1003for (const StringName &E : effect_list) {1004if (!ClassDB::can_instantiate(E) || ClassDB::is_virtual(E)) {1005continue;1006}10071008String name = E.operator String().replace("AudioEffect", "");1009effect_options->add_item(name);1010effect_options->set_item_metadata(-1, E);1011}10121013bus_options = memnew(MenuButton);1014bus_options->set_shortcut_context(this);1015bus_options->set_h_size_flags(SIZE_SHRINK_END);1016bus_options->set_anchor(SIDE_RIGHT, 0.0);1017bus_options->set_tooltip_text(TTR("Bus Options"));1018hbc->add_child(bus_options);10191020bus_popup = bus_options->get_popup();1021bus_popup->add_shortcut(ED_SHORTCUT("audio_bus_editor/duplicate_selected_bus", TTRC("Duplicate Bus"), KeyModifierMask::CMD_OR_CTRL | Key::D));1022bus_popup->add_shortcut(ED_SHORTCUT("audio_bus_editor/delete_selected_bus", TTRC("Delete Bus"), Key::KEY_DELETE));1023bus_popup->set_item_disabled(1, is_master);1024bus_popup->add_item(TTR("Reset Volume"));1025bus_popup->connect("index_pressed", callable_mp(this, &EditorAudioBus::_bus_popup_pressed));10261027delete_effect_popup = memnew(PopupMenu);1028delete_effect_popup->add_item(TTR("Delete Effect"));1029add_child(delete_effect_popup);1030delete_effect_popup->connect("index_pressed", callable_mp(this, &EditorAudioBus::_delete_effect_pressed));1031}10321033void EditorAudioBusDrop::_notification(int p_what) {1034switch (p_what) {1035case NOTIFICATION_DRAW: {1036draw_style_box(get_theme_stylebox(CoreStringName(normal), SNAME("Button")), Rect2(Vector2(), get_size()));10371038if (hovering_drop) {1039Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));1040accent.a *= 0.7;1041draw_rect(Rect2(Point2(), get_size()), accent, false);1042}1043} break;10441045case NOTIFICATION_MOUSE_ENTER: {1046if (!hovering_drop) {1047hovering_drop = true;1048queue_redraw();1049}1050} break;10511052case NOTIFICATION_MOUSE_EXIT:1053case NOTIFICATION_DRAG_END: {1054if (hovering_drop) {1055hovering_drop = false;1056queue_redraw();1057}1058} break;1059}1060}10611062bool EditorAudioBusDrop::can_drop_data(const Point2 &p_point, const Variant &p_data) const {1063Dictionary d = p_data;1064return (d.has("type") && String(d["type"]) == "move_audio_bus");1065}10661067void EditorAudioBusDrop::drop_data(const Point2 &p_point, const Variant &p_data) {1068Dictionary d = p_data;1069emit_signal(SNAME("dropped"), d["index"], AudioServer::get_singleton()->get_bus_count());1070}10711072void EditorAudioBusDrop::_bind_methods() {1073ADD_SIGNAL(MethodInfo("dropped"));1074}10751076void EditorAudioBuses::_rebuild_buses() {1077for (int i = bus_hb->get_child_count() - 1; i >= 0; i--) {1078EditorAudioBus *audio_bus = Object::cast_to<EditorAudioBus>(bus_hb->get_child(i));1079if (audio_bus) {1080bus_hb->remove_child(audio_bus);1081audio_bus->queue_free();1082}1083}10841085if (drop_end) {1086bus_hb->remove_child(drop_end);1087drop_end->queue_free();1088drop_end = nullptr;1089}10901091for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {1092bool is_master = (i == 0);1093EditorAudioBus *audio_bus = memnew(EditorAudioBus(this, is_master));1094bus_hb->add_child(audio_bus);1095audio_bus->connect("delete_request", callable_mp(this, &EditorAudioBuses::_delete_bus).bind(audio_bus), CONNECT_DEFERRED);1096audio_bus->connect("duplicate_request", callable_mp(this, &EditorAudioBuses::_duplicate_bus), CONNECT_DEFERRED);1097audio_bus->connect("vol_reset_request", callable_mp(this, &EditorAudioBuses::_reset_bus_volume).bind(audio_bus), CONNECT_DEFERRED);1098audio_bus->connect("drop_end_request", callable_mp(this, &EditorAudioBuses::_request_drop_end));1099audio_bus->connect("dropped", callable_mp(this, &EditorAudioBuses::_drop_at_index), CONNECT_DEFERRED);1100}1101}11021103EditorAudioBuses *EditorAudioBuses::register_editor() {1104EditorAudioBuses *audio_buses = memnew(EditorAudioBuses);1105EditorNode::get_bottom_panel()->add_item(TTRC("Audio"), audio_buses, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_audio_bottom_panel", TTRC("Toggle Audio Bottom Panel"), KeyModifierMask::ALT | Key::A));1106return audio_buses;1107}11081109void EditorAudioBuses::_notification(int p_what) {1110switch (p_what) {1111case NOTIFICATION_THEME_CHANGED: {1112bus_scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));1113} break;11141115case NOTIFICATION_READY: {1116_rebuild_buses();1117} break;11181119case NOTIFICATION_DRAG_END: {1120if (drop_end) {1121bus_hb->remove_child(drop_end);1122drop_end->queue_free();1123drop_end = nullptr;1124}1125} break;11261127case NOTIFICATION_PROCESS: {1128// Check if anything was edited.1129bool edited = AudioServer::get_singleton()->is_edited();1130for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {1131for (int j = 0; j < AudioServer::get_singleton()->get_bus_effect_count(i); j++) {1132Ref<AudioEffect> effect = AudioServer::get_singleton()->get_bus_effect(i, j);1133if (effect->is_edited()) {1134edited = true;1135effect->set_edited(false);1136}1137}1138}11391140if (edited) {1141AudioServer::get_singleton()->set_edited(false);1142save_timer->start();1143}1144} break;1145}1146}11471148void EditorAudioBuses::_add_bus() {1149EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();11501151ur->create_action(TTR("Add Audio Bus"));1152ur->add_do_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count() + 1);1153ur->add_undo_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count());1154ur->commit_action();1155}11561157void EditorAudioBuses::_update_bus(int p_index) {1158if (p_index >= bus_hb->get_child_count()) {1159return;1160}11611162bus_hb->get_child(p_index)->call("update_bus");1163}11641165void EditorAudioBuses::_update_sends() {1166for (int i = 0; i < bus_hb->get_child_count(); i++) {1167bus_hb->get_child(i)->call("update_send");1168}1169}11701171void EditorAudioBuses::_delete_bus(Object *p_which) {1172EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which);1173int index = bus->get_index();1174if (index == 0) {1175EditorNode::get_singleton()->show_warning(TTR("Master bus can't be deleted!"));1176return;1177}11781179EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();11801181ur->create_action(TTR("Delete Audio Bus"));1182ur->add_do_method(AudioServer::get_singleton(), "remove_bus", index);1183ur->add_undo_method(AudioServer::get_singleton(), "add_bus", index);1184ur->add_undo_method(AudioServer::get_singleton(), "set_bus_name", index, AudioServer::get_singleton()->get_bus_name(index));1185ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", index, AudioServer::get_singleton()->get_bus_volume_db(index));1186ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", index, AudioServer::get_singleton()->get_bus_send(index));1187ur->add_undo_method(AudioServer::get_singleton(), "set_bus_solo", index, AudioServer::get_singleton()->is_bus_solo(index));1188ur->add_undo_method(AudioServer::get_singleton(), "set_bus_mute", index, AudioServer::get_singleton()->is_bus_mute(index));1189ur->add_undo_method(AudioServer::get_singleton(), "set_bus_bypass_effects", index, AudioServer::get_singleton()->is_bus_bypassing_effects(index));1190for (int i = 0; i < AudioServer::get_singleton()->get_bus_effect_count(index); i++) {1191ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", index, AudioServer::get_singleton()->get_bus_effect(index, i));1192ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", index, i, AudioServer::get_singleton()->is_bus_effect_enabled(index, i));1193}1194ur->commit_action();1195}11961197void EditorAudioBuses::_duplicate_bus(int p_which) {1198int add_at_pos = p_which + 1;1199EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1200ur->create_action(TTR("Duplicate Audio Bus"));1201ur->add_do_method(AudioServer::get_singleton(), "add_bus", add_at_pos);1202ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", add_at_pos, AudioServer::get_singleton()->get_bus_name(p_which) + " Copy");1203ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", add_at_pos, AudioServer::get_singleton()->get_bus_volume_db(p_which));1204ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", add_at_pos, AudioServer::get_singleton()->get_bus_send(p_which));1205ur->add_do_method(AudioServer::get_singleton(), "set_bus_solo", add_at_pos, AudioServer::get_singleton()->is_bus_solo(p_which));1206ur->add_do_method(AudioServer::get_singleton(), "set_bus_mute", add_at_pos, AudioServer::get_singleton()->is_bus_mute(p_which));1207ur->add_do_method(AudioServer::get_singleton(), "set_bus_bypass_effects", add_at_pos, AudioServer::get_singleton()->is_bus_bypassing_effects(p_which));1208for (int i = 0; i < AudioServer::get_singleton()->get_bus_effect_count(p_which); i++) {1209ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", add_at_pos, AudioServer::get_singleton()->get_bus_effect(p_which, i));1210ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", add_at_pos, i, AudioServer::get_singleton()->is_bus_effect_enabled(p_which, i));1211}1212ur->add_do_method(this, "_update_bus", add_at_pos);1213ur->add_undo_method(AudioServer::get_singleton(), "remove_bus", add_at_pos);1214ur->commit_action();1215}12161217void EditorAudioBuses::_reset_bus_volume(Object *p_which) {1218EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which);1219int index = bus->get_index();12201221EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1222ur->create_action(TTR("Reset Bus Volume"));1223ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", index, 0.f);1224ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", index, AudioServer::get_singleton()->get_bus_volume_db(index));1225ur->add_do_method(this, "_update_bus", index);1226ur->add_undo_method(this, "_update_bus", index);1227ur->commit_action();1228}12291230void EditorAudioBuses::_request_drop_end() {1231if (!drop_end && bus_hb->get_child_count()) {1232drop_end = memnew(EditorAudioBusDrop);12331234bus_hb->add_child(drop_end);1235drop_end->set_custom_minimum_size(Object::cast_to<Control>(bus_hb->get_child(0))->get_size());1236drop_end->connect("dropped", callable_mp(this, &EditorAudioBuses::_drop_at_index), CONNECT_DEFERRED);1237}1238}12391240void EditorAudioBuses::_drop_at_index(int p_bus, int p_index) {1241EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1242ur->create_action(TTR("Move Audio Bus"));12431244ur->add_do_method(AudioServer::get_singleton(), "move_bus", p_bus, p_index);1245int real_bus = p_index > p_bus ? p_bus : p_bus + 1;1246int real_index = p_index > p_bus ? p_index - 1 : p_index;1247ur->add_undo_method(AudioServer::get_singleton(), "move_bus", real_index, real_bus);12481249ur->commit_action();1250}12511252void EditorAudioBuses::_server_save() {1253Ref<AudioBusLayout> state = AudioServer::get_singleton()->generate_bus_layout();1254ResourceSaver::save(state, edited_path);1255}12561257void EditorAudioBuses::_select_layout() {1258FileSystemDock::get_singleton()->navigate_to_path(edited_path);1259}12601261void EditorAudioBuses::_save_as_layout() {1262file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);1263file_dialog->set_title(TTR("Save Audio Bus Layout As..."));1264file_dialog->set_current_path(edited_path);1265file_dialog->popup_file_dialog();1266new_layout = false;1267}12681269void EditorAudioBuses::_new_layout() {1270file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);1271file_dialog->set_title(TTR("Location for New Layout..."));1272file_dialog->set_current_path(edited_path);1273file_dialog->popup_file_dialog();1274new_layout = true;1275}12761277void EditorAudioBuses::_load_layout() {1278file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);1279file_dialog->set_title(TTR("Open Audio Bus Layout"));1280file_dialog->set_current_path(edited_path);1281file_dialog->popup_file_dialog();1282new_layout = false;1283}12841285void EditorAudioBuses::_load_default_layout() {1286open_layout(GLOBAL_GET("audio/buses/default_bus_layout"));1287}12881289void EditorAudioBuses::_file_dialog_callback(const String &p_string) {1290if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {1291if (new_layout) {1292Ref<AudioBusLayout> empty_state;1293empty_state.instantiate();1294AudioServer::get_singleton()->set_bus_layout(empty_state);1295}12961297Error err = ResourceSaver::save(AudioServer::get_singleton()->generate_bus_layout(), p_string);1298if (err != OK) {1299EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file: %s"), p_string));1300return;1301}1302}1303open_layout(p_string);1304}13051306void EditorAudioBuses::_bind_methods() {1307ClassDB::bind_method("_update_bus", &EditorAudioBuses::_update_bus);1308ClassDB::bind_method("_update_sends", &EditorAudioBuses::_update_sends);1309}13101311EditorAudioBuses::EditorAudioBuses() {1312top_hb = memnew(HBoxContainer);1313add_child(top_hb);13141315edited_path = ResourceUID::ensure_path(GLOBAL_GET("audio/buses/default_bus_layout"));13161317file = memnew(Label);1318file->set_text(vformat("%s %s", TTR("Layout:"), edited_path.get_file()));1319file->set_clip_text(true);1320file->set_h_size_flags(SIZE_EXPAND_FILL);1321top_hb->add_child(file);13221323add = memnew(Button);1324top_hb->add_child(add);1325add->set_text(TTR("Add Bus"));1326add->set_tooltip_text(TTR("Add a new Audio Bus to this layout."));1327add->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBuses::_add_bus));13281329VSeparator *separator = memnew(VSeparator);1330top_hb->add_child(separator);13311332load = memnew(Button);1333load->set_text(TTR("Load"));1334load->set_tooltip_text(TTR("Load an existing Bus Layout."));1335top_hb->add_child(load);1336load->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBuses::_load_layout));13371338save_as = memnew(Button);1339save_as->set_text(TTR("Save As"));1340save_as->set_tooltip_text(TTR("Save this Bus Layout to a file."));1341top_hb->add_child(save_as);1342save_as->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBuses::_save_as_layout));13431344_default = memnew(Button);1345_default->set_text(TTR("Load Default"));1346_default->set_tooltip_text(TTR("Load the default Bus Layout."));1347top_hb->add_child(_default);1348_default->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBuses::_load_default_layout));13491350_new = memnew(Button);1351_new->set_text(TTR("Create"));1352_new->set_tooltip_text(TTR("Create a new Bus Layout."));1353top_hb->add_child(_new);1354_new->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBuses::_new_layout));13551356bus_scroll = memnew(ScrollContainer);1357bus_scroll->set_v_size_flags(SIZE_EXPAND_FILL);1358bus_scroll->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);1359add_child(bus_scroll);1360bus_hb = memnew(HBoxContainer);1361bus_hb->set_v_size_flags(SIZE_EXPAND_FILL);1362bus_scroll->add_child(bus_hb);13631364save_timer = memnew(Timer);1365save_timer->set_wait_time(0.8);1366save_timer->set_one_shot(true);1367add_child(save_timer);1368save_timer->connect("timeout", callable_mp(this, &EditorAudioBuses::_server_save));13691370set_v_size_flags(SIZE_EXPAND_FILL);13711372file_dialog = memnew(EditorFileDialog);1373List<String> ext;1374ResourceLoader::get_recognized_extensions_for_type("AudioBusLayout", &ext);1375for (const String &E : ext) {1376file_dialog->add_filter("*." + E, TTR("Audio Bus Layout"));1377}1378add_child(file_dialog);1379file_dialog->connect("file_selected", callable_mp(this, &EditorAudioBuses::_file_dialog_callback));13801381AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &EditorAudioBuses::_rebuild_buses));13821383set_process(true);1384}13851386void EditorAudioBuses::open_layout(const String &p_path) {1387EditorNode::get_bottom_panel()->make_item_visible(this);13881389const String path = ResourceUID::ensure_path(p_path);13901391if (!ResourceLoader::exists(path)) {1392EditorNode::get_singleton()->show_warning(vformat(TTR(R"(Can't open audio bus layout: "%s" doesn't exist.)"), path));1393return;1394}13951396Ref<AudioBusLayout> state = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);1397if (state.is_null()) {1398EditorNode::get_singleton()->show_warning(vformat(TTR(R"(Can't open audio bus layout: "%s" is not a valid audio bus layout.)"), path));1399return;1400}14011402edited_path = path;1403file->set_text(vformat("%s %s", TTR("Layout:"), path.get_file()));1404AudioServer::get_singleton()->set_bus_layout(state);1405_rebuild_buses();1406EditorUndoRedoManager::get_singleton()->clear_history(EditorUndoRedoManager::GLOBAL_HISTORY);1407callable_mp(this, &EditorAudioBuses::_select_layout).call_deferred();1408}14091410void AudioBusesEditorPlugin::edit(Object *p_node) {1411if (Object::cast_to<AudioBusLayout>(p_node)) {1412String path = Object::cast_to<AudioBusLayout>(p_node)->get_path();1413if (path.is_resource_file()) {1414audio_bus_editor->open_layout(path);1415}1416}1417}14181419bool AudioBusesEditorPlugin::handles(Object *p_node) const {1420return (Object::cast_to<AudioBusLayout>(p_node) != nullptr);1421}14221423void AudioBusesEditorPlugin::make_visible(bool p_visible) {1424}14251426AudioBusesEditorPlugin::AudioBusesEditorPlugin(EditorAudioBuses *p_node) {1427audio_bus_editor = p_node;1428}14291430void EditorAudioMeterNotches::add_notch(float p_normalized_offset, float p_db_value, bool p_render_value) {1431notches.push_back(AudioNotch(p_normalized_offset, p_db_value, p_render_value));1432}14331434Size2 EditorAudioMeterNotches::get_minimum_size() const {1435Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));1436int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));1437float font_height = font->get_height(font_size);14381439float width = 0;1440float height = top_padding + btm_padding;14411442for (const EditorAudioMeterNotches::AudioNotch ¬ch : notches) {1443if (notch.render_db_value) {1444width = MAX(width, font->get_string_size(String::num(Math::abs(notch.db_value)) + "dB", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x);1445height += font_height;1446}1447}1448width += line_length + label_space;14491450return Size2(width, height);1451}14521453void EditorAudioMeterNotches::_update_theme_item_cache() {1454Control::_update_theme_item_cache();14551456theme_cache.notch_color = get_theme_color(SceneStringName(font_color), EditorStringName(Editor));14571458theme_cache.font = get_theme_font(SceneStringName(font), SNAME("Label"));1459theme_cache.font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));1460}14611462void EditorAudioMeterNotches::_bind_methods() {1463ClassDB::bind_method("add_notch", &EditorAudioMeterNotches::add_notch);1464ClassDB::bind_method("_draw_audio_notches", &EditorAudioMeterNotches::_draw_audio_notches);1465}14661467void EditorAudioMeterNotches::_notification(int p_what) {1468switch (p_what) {1469case NOTIFICATION_DRAW: {1470_draw_audio_notches();1471} break;1472}1473}14741475void EditorAudioMeterNotches::_draw_audio_notches() {1476float font_height = theme_cache.font->get_height(theme_cache.font_size);14771478for (const AudioNotch &n : notches) {1479draw_line(Vector2(0, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding),1480Vector2(line_length * EDSCALE, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding),1481theme_cache.notch_color,1482Math::round(EDSCALE));14831484if (n.render_db_value) {1485draw_string(theme_cache.font,1486Vector2((line_length + label_space) * EDSCALE,1487(1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + (font_height / 4) + top_padding),1488String::num(Math::abs(n.db_value)) + "dB",1489HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size,1490theme_cache.notch_color);1491}1492}1493}149414951496