Path: blob/master/editor/audio/editor_audio_buses.cpp
20936 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/editor_dock_manager.h"37#include "editor/docks/filesystem_dock.h"38#include "editor/editor_node.h"39#include "editor/editor_string_names.h"40#include "editor/editor_undo_redo_manager.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/box_container.h"47#include "scene/gui/separator.h"48#include "scene/main/timer.h"49#include "scene/resources/font.h"50#include "scene/resources/style_box_flat.h"51#include "servers/audio/audio_server.h"5253void EditorAudioBus::_update_visible_channels() {54int i = 0;55for (; i < cc; i++) {56if (!channel[i].vu_l->is_visible()) {57channel[i].vu_l->show();58}59if (!channel[i].vu_r->is_visible()) {60channel[i].vu_r->show();61}62}6364for (; i < CHANNELS_MAX; i++) {65if (channel[i].vu_l->is_visible()) {66channel[i].vu_l->hide();67}68if (channel[i].vu_r->is_visible()) {69channel[i].vu_r->hide();70}71}72}7374void EditorAudioBus::_notification(int p_what) {75switch (p_what) {76case NOTIFICATION_THEME_CHANGED: {77Ref<Texture2D> active_bus_texture = get_editor_theme_icon(SNAME("BusVuActive"));78for (int i = 0; i < CHANNELS_MAX; i++) {79channel[i].vu_l->set_under_texture(active_bus_texture);80channel[i].vu_l->set_tint_under(Color(0.75, 0.75, 0.75));81channel[i].vu_l->set_progress_texture(active_bus_texture);8283channel[i].vu_r->set_under_texture(active_bus_texture);84channel[i].vu_r->set_tint_under(Color(0.75, 0.75, 0.75));85channel[i].vu_r->set_progress_texture(active_bus_texture);86channel[i].prev_active = true;87}8889disabled_vu = get_editor_theme_icon(SNAME("BusVuFrozen"));9091bool dark_icon_and_font = EditorThemeManager::is_dark_icon_and_font();92Color solo_color = dark_icon_and_font ? Color(1.0, 0.89, 0.22) : Color(1.9, 1.74, 0.83);93Color mute_color = dark_icon_and_font ? Color(1.0, 0.16, 0.16) : Color(2.35, 1.03, 1.03);94Color bypass_color = dark_icon_and_font ? Color(0.13, 0.8, 1.0) : Color(1.03, 2.04, 2.35);95float darkening_factor = dark_icon_and_font ? 0.15 : 0.65;96Color solo_color_darkened = solo_color.darkened(darkening_factor);97Color mute_color_darkened = mute_color.darkened(darkening_factor);98Color bypass_color_darkened = bypass_color.darkened(darkening_factor);99100Ref<StyleBoxFlat>(solo->get_theme_stylebox(SceneStringName(pressed)))->set_border_color(solo_color_darkened);101Ref<StyleBoxFlat>(mute->get_theme_stylebox(SceneStringName(pressed)))->set_border_color(mute_color_darkened);102Ref<StyleBoxFlat>(bypass->get_theme_stylebox(SceneStringName(pressed)))->set_border_color(bypass_color_darkened);103Ref<StyleBoxFlat>(solo->get_theme_stylebox("hover_pressed"))->set_border_color(solo_color_darkened);104Ref<StyleBoxFlat>(mute->get_theme_stylebox("hover_pressed"))->set_border_color(mute_color_darkened);105Ref<StyleBoxFlat>(bypass->get_theme_stylebox("hover_pressed"))->set_border_color(bypass_color_darkened);106107solo->set_button_icon(get_editor_theme_icon(SNAME("AudioBusSolo")));108solo->add_theme_color_override("icon_pressed_color", solo_color);109solo->add_theme_color_override("icon_hover_pressed_color", solo_color_darkened);110mute->set_button_icon(get_editor_theme_icon(SNAME("AudioBusMute")));111mute->add_theme_color_override("icon_pressed_color", mute_color);112mute->add_theme_color_override("icon_hover_pressed_color", mute_color_darkened);113bypass->set_button_icon(get_editor_theme_icon(SNAME("AudioBusBypass")));114bypass->add_theme_color_override("icon_pressed_color", bypass_color);115bypass->add_theme_color_override("icon_hover_pressed_color", bypass_color_darkened);116117bus_options->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));118119audio_value_preview_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SceneStringName(font_color), SNAME("TooltipLabel")));120audio_value_preview_label->add_theme_color_override("font_shadow_color", get_theme_color(SNAME("font_shadow_color"), SNAME("TooltipLabel")));121audio_value_preview_box->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TooltipPanel")));122123for (int i = 0; i < effect_options->get_item_count(); i++) {124String class_name = effect_options->get_item_metadata(i);125Ref<Texture> icon = EditorNode::get_singleton()->get_class_icon(class_name);126effect_options->set_item_icon(i, icon);127}128} break;129130case NOTIFICATION_READY: {131update_bus();132set_process(true);133} break;134135case NOTIFICATION_DRAW: {136if (is_master) {137draw_style_box(get_theme_stylebox(SNAME("master"), SNAME("EditorAudioBus")), Rect2(Vector2(), get_size()));138} else if (has_focus()) {139draw_style_box(get_theme_stylebox(SNAME("focus"), SNAME("EditorAudioBus")), Rect2(Vector2(), get_size()));140} else {141draw_style_box(get_theme_stylebox(SNAME("normal"), SNAME("EditorAudioBus")), Rect2(Vector2(), get_size()));142}143144if (get_index() != 0 && hovering_drop) {145Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));146accent.a *= 0.7;147draw_rect(Rect2(Point2(), get_size()), accent, false);148}149} break;150151case NOTIFICATION_PROCESS: {152if (cc != AudioServer::get_singleton()->get_bus_channels(get_index())) {153cc = AudioServer::get_singleton()->get_bus_channels(get_index());154_update_visible_channels();155}156157for (int i = 0; i < cc; i++) {158float real_peak[2] = { -100, -100 };159bool activity_found = false;160161if (AudioServer::get_singleton()->is_bus_channel_active(get_index(), i)) {162activity_found = true;163real_peak[0] = MAX(real_peak[0], AudioServer::get_singleton()->get_bus_peak_volume_left_db(get_index(), i));164real_peak[1] = MAX(real_peak[1], AudioServer::get_singleton()->get_bus_peak_volume_right_db(get_index(), i));165}166167if (real_peak[0] > channel[i].peak_l) {168channel[i].peak_l = real_peak[0];169} else {170channel[i].peak_l -= get_process_delta_time() * 60.0;171}172173if (real_peak[1] > channel[i].peak_r) {174channel[i].peak_r = real_peak[1];175} else {176channel[i].peak_r -= get_process_delta_time() * 60.0;177}178179channel[i].vu_l->set_value(channel[i].peak_l);180channel[i].vu_r->set_value(channel[i].peak_r);181182if (activity_found != channel[i].prev_active) {183if (activity_found) {184channel[i].vu_l->set_over_texture(Ref<Texture2D>());185channel[i].vu_r->set_over_texture(Ref<Texture2D>());186} else {187channel[i].vu_l->set_over_texture(disabled_vu);188channel[i].vu_r->set_over_texture(disabled_vu);189}190191channel[i].prev_active = activity_found;192}193}194} break;195196case NOTIFICATION_VISIBILITY_CHANGED: {197for (int i = 0; i < CHANNELS_MAX; i++) {198channel[i].peak_l = -100;199channel[i].peak_r = -100;200channel[i].prev_active = true;201}202203set_process(is_visible_in_tree());204} break;205206case NOTIFICATION_MOUSE_EXIT:207case NOTIFICATION_DRAG_END: {208if (hovering_drop) {209hovering_drop = false;210queue_redraw();211}212} break;213}214}215216void EditorAudioBus::update_send() {217send->clear();218if (is_master) {219send->set_disabled(true);220send->set_text(TTR("Speakers"));221} else {222send->set_disabled(false);223StringName current_send = AudioServer::get_singleton()->get_bus_send(get_index());224int current_send_index = 0; //by default to master225226for (int i = 0; i < get_index(); i++) {227StringName send_name = AudioServer::get_singleton()->get_bus_name(i);228send->add_item(send_name);229if (send_name == current_send) {230current_send_index = i;231}232}233234send->select(current_send_index);235}236}237238void EditorAudioBus::update_bus() {239if (updating_bus) {240return;241}242243updating_bus = true;244245int index = get_index();246247float db_value = AudioServer::get_singleton()->get_bus_volume_db(index);248slider->set_value(_scaled_db_to_normalized_volume(db_value));249track_name->set_text(AudioServer::get_singleton()->get_bus_name(index));250if (is_master) {251track_name->set_editable(false);252}253254solo->set_pressed(AudioServer::get_singleton()->is_bus_solo(index));255mute->set_pressed(AudioServer::get_singleton()->is_bus_mute(index));256bypass->set_pressed(AudioServer::get_singleton()->is_bus_bypassing_effects(index));257// effects..258effects->clear();259260TreeItem *root = effects->create_item();261for (int i = 0; i < AudioServer::get_singleton()->get_bus_effect_count(index); i++) {262Ref<AudioEffect> afx = AudioServer::get_singleton()->get_bus_effect(index, i);263264TreeItem *fx = effects->create_item(root);265fx->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);266fx->set_editable(0, true);267fx->set_checked(0, AudioServer::get_singleton()->is_bus_effect_enabled(index, i));268fx->set_text(0, afx->get_name());269fx->set_metadata(0, i);270}271272TreeItem *add = effects->create_item(root);273add->set_cell_mode(0, TreeItem::CELL_MODE_CUSTOM);274add->set_editable(0, true);275add->set_selectable(0, false);276add->set_text(0, TTR("Add Effect"));277278update_send();279280updating_bus = false;281}282283void EditorAudioBus::_name_changed(const String &p_new_name) {284if (updating_bus) {285return;286}287updating_bus = true;288track_name->release_focus();289290if (p_new_name == AudioServer::get_singleton()->get_bus_name(get_index())) {291updating_bus = false;292return;293}294295String attempt = p_new_name;296int attempts = 1;297298while (true) {299bool name_free = true;300for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {301if (AudioServer::get_singleton()->get_bus_name(i) == attempt) {302name_free = false;303break;304}305}306307if (name_free) {308break;309}310311attempts++;312attempt = p_new_name + " " + itos(attempts);313}314315EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();316317StringName current = AudioServer::get_singleton()->get_bus_name(get_index());318319ur->create_action(TTR("Rename Audio Bus"));320321ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", get_index(), attempt);322ur->add_undo_method(AudioServer::get_singleton(), "set_bus_name", get_index(), current);323324for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {325if (AudioServer::get_singleton()->get_bus_send(i) == current) {326ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", i, attempt);327ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", i, current);328}329}330331ur->add_do_method(buses, "_update_bus", get_index());332ur->add_undo_method(buses, "_update_bus", get_index());333334ur->add_do_method(buses, "_update_sends");335ur->add_undo_method(buses, "_update_sends");336337ur->commit_action();338339updating_bus = false;340}341342void EditorAudioBus::_volume_changed(float p_normalized) {343if (updating_bus) {344return;345}346347updating_bus = true;348349const float p_db = _normalized_volume_to_scaled_db(p_normalized);350351if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {352// Snap the value when holding Ctrl for easier editing.353// To do so, it needs to be converted back to normalized volume (as the slider uses that unit).354slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db)));355}356357EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();358ur->create_action(TTR("Change Audio Bus Volume"), UndoRedo::MERGE_ENDS);359ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), p_db);360ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), AudioServer::get_singleton()->get_bus_volume_db(get_index()));361ur->add_do_method(buses, "_update_bus", get_index());362ur->add_undo_method(buses, "_update_bus", get_index());363ur->commit_action();364365updating_bus = false;366}367368float EditorAudioBus::_normalized_volume_to_scaled_db(float normalized) {369/* There are three different formulas for the conversion from normalized370* values to relative decibal values.371* One formula is an exponential graph which intends to counteract372* the logarithmic nature of human hearing. This is an approximation373* of the behavior of a 'logarithmic potentiometer' found on most374* musical instruments and also emulated in popular software.375* The other two equations are hand-tuned linear tapers that intend to376* try to ease the exponential equation in areas where it makes sense.*/377378if (normalized > 0.6f) {379return 22.22f * normalized - 16.2f;380} else if (normalized < 0.05f) {381return 830.72 * normalized - 80.0f;382} else {383return 45.0f * Math::pow(normalized - 1.0, 3);384}385}386387float EditorAudioBus::_scaled_db_to_normalized_volume(float db) {388/* Inversion of equations found in _normalized_volume_to_scaled_db.389* IMPORTANT: If one function changes, the other much change to reflect it. */390if (db > -2.88) {391return (db + 16.2f) / 22.22f;392} else if (db < -38.602f) {393return (db + 80.00f) / 830.72f;394} else {395if (db < 0.0) {396/* To accommodate for NaN on negative numbers for root, we will mirror the397* results of the positive db range in order to get the desired numerical398* value on the negative side. */399float positive_x = Math::pow(Math::abs(db) / 45.0f, 1.0f / 3.0f) + 1.0f;400Vector2 translation = Vector2(1.0f, 0.0f) - Vector2(positive_x, Math::abs(db));401Vector2 reflected_position = Vector2(1.0, 0.0f) + translation;402return reflected_position.x;403} else {404return Math::pow(db / 45.0f, 1.0f / 3.0f) + 1.0f;405}406}407}408409void EditorAudioBus::_show_value(float slider_value) {410float db;411if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {412// Display the correct (snapped) value when holding Ctrl413db = Math::round(_normalized_volume_to_scaled_db(slider_value));414} else {415db = _normalized_volume_to_scaled_db(slider_value);416}417418String text;419if (Math::is_zero_approx(Math::snapped(db, 0.1))) {420// Prevent displaying `-0.0 dB` and show ` 0.0 dB` instead.421// The leading space makes the text visually line up with its positive/negative counterparts.422text = " 0.0 dB";423} else {424// Show an explicit `+` sign if positive.425text = vformat("%+.1f dB", db);426}427428// Also set the preview text as a standard Control tooltip.429// This way, it can be seen when the slider is merely hovered (instead of dragged).430slider->set_tooltip_text(text);431audio_value_preview_label->set_text(text);432const Vector2 slider_size = slider->get_size();433const Vector2 slider_position = slider->get_global_position();434const float vert_padding = 10.0f;435const Vector2 box_position = Vector2(slider_size.x, (slider_size.y - vert_padding) * (1.0f - slider->get_value()) - vert_padding);436audio_value_preview_box->set_position(slider_position + box_position);437audio_value_preview_box->set_size(audio_value_preview_label->get_size());438if (slider->has_focus() && !audio_value_preview_box->is_visible()) {439audio_value_preview_box->show();440}441preview_timer->start();442}443444void EditorAudioBus::_hide_value_preview() {445audio_value_preview_box->hide();446}447448void EditorAudioBus::_solo_toggled() {449updating_bus = true;450451EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();452ur->create_action(TTR("Toggle Audio Bus Solo"));453ur->add_do_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), solo->is_pressed());454ur->add_undo_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), AudioServer::get_singleton()->is_bus_solo(get_index()));455ur->add_do_method(buses, "_update_bus", get_index());456ur->add_undo_method(buses, "_update_bus", get_index());457ur->commit_action();458459updating_bus = false;460}461462void EditorAudioBus::_mute_toggled() {463updating_bus = true;464465EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();466ur->create_action(TTR("Toggle Audio Bus Mute"));467ur->add_do_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), mute->is_pressed());468ur->add_undo_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), AudioServer::get_singleton()->is_bus_mute(get_index()));469ur->add_do_method(buses, "_update_bus", get_index());470ur->add_undo_method(buses, "_update_bus", get_index());471ur->commit_action();472473updating_bus = false;474}475476void EditorAudioBus::_bypass_toggled() {477updating_bus = true;478479EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();480ur->create_action(TTR("Toggle Audio Bus Bypass Effects"));481ur->add_do_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), bypass->is_pressed());482ur->add_undo_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), AudioServer::get_singleton()->is_bus_bypassing_effects(get_index()));483ur->add_do_method(buses, "_update_bus", get_index());484ur->add_undo_method(buses, "_update_bus", get_index());485ur->commit_action();486487updating_bus = false;488}489490void EditorAudioBus::_send_selected(int p_which) {491updating_bus = true;492493EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();494ur->create_action(TTR("Select Audio Bus Send"));495ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", get_index(), send->get_item_text(p_which));496ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", get_index(), AudioServer::get_singleton()->get_bus_send(get_index()));497ur->add_do_method(buses, "_update_bus", get_index());498ur->add_undo_method(buses, "_update_bus", get_index());499ur->commit_action();500501updating_bus = false;502}503504void EditorAudioBus::_effect_selected() {505TreeItem *effect = effects->get_selected();506if (!effect) {507return;508}509updating_bus = true;510511if (effect->get_metadata(0) != Variant()) {512int index = effect->get_metadata(0);513Ref<AudioEffect> effect2 = AudioServer::get_singleton()->get_bus_effect(get_index(), index);514if (effect2.is_valid()) {515EditorNode::get_singleton()->push_item(effect2.ptr());516}517}518519updating_bus = false;520}521522void EditorAudioBus::_effect_edited() {523if (updating_bus) {524return;525}526527TreeItem *effect = effects->get_edited();528if (!effect) {529return;530}531532if (effect->get_metadata(0) == Variant()) {533Rect2 area = effects->get_item_rect(effect);534535effect_options->set_position(effects->get_screen_position() + area.position + Vector2(0, area.size.y));536effect_options->reset_size();537effect_options->popup();538//add effect539} else {540int index = effect->get_metadata(0);541updating_bus = true;542543EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();544ur->create_action(TTR("Select Audio Bus Send"));545ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, effect->is_checked(0));546ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, AudioServer::get_singleton()->is_bus_effect_enabled(get_index(), index));547ur->add_do_method(buses, "_update_bus", get_index());548ur->add_undo_method(buses, "_update_bus", get_index());549ur->commit_action();550551updating_bus = false;552}553}554555void EditorAudioBus::_effect_add(int p_which) {556if (updating_bus) {557return;558}559560StringName name = effect_options->get_item_metadata(p_which);561562Object *fx = ClassDB::instantiate(name);563ERR_FAIL_NULL(fx);564AudioEffect *afx = Object::cast_to<AudioEffect>(fx);565ERR_FAIL_NULL(afx);566Ref<AudioEffect> afxr = Ref<AudioEffect>(afx);567568afxr->set_name(effect_options->get_item_text(p_which));569570EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();571ur->create_action(TTR("Add Audio Bus Effect"));572ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), afxr, -1);573ur->add_undo_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect_count(get_index()));574ur->add_do_method(buses, "_update_bus", get_index());575ur->add_undo_method(buses, "_update_bus", get_index());576ur->commit_action();577}578579void EditorAudioBus::gui_input(const Ref<InputEvent> &p_event) {580ERR_FAIL_COND(p_event.is_null());581582Ref<InputEventMouseButton> mb = p_event;583if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {584bus_popup->set_position(get_screen_position() + mb->get_position());585bus_popup->reset_size();586bus_popup->popup();587}588589Ref<InputEventKey> k = p_event;590if (k.is_valid() && k->is_pressed() && k->is_action("ui_menu", true)) {591bus_popup->set_position(get_screen_position());592bus_popup->reset_size();593bus_popup->popup();594595accept_event();596}597}598599void EditorAudioBus::_effects_gui_input(Ref<InputEvent> p_event) {600Ref<InputEventKey> k = p_event;601if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == Key::KEY_DELETE) {602TreeItem *current_effect = effects->get_selected();603if (current_effect && current_effect->get_metadata(0).get_type() == Variant::INT) {604_delete_effect_pressed(0);605accept_event();606}607}608}609610void EditorAudioBus::_bus_popup_pressed(int p_option) {611if (p_option == 2) {612// Reset volume613emit_signal(SNAME("vol_reset_request"));614} else if (p_option == 1) {615emit_signal(SNAME("delete_request"));616} else if (p_option == 0) {617//duplicate618emit_signal(SNAME("duplicate_request"), get_index());619}620}621622Variant EditorAudioBus::get_drag_data(const Point2 &p_point) {623if (get_index() == 0) {624return Variant();625}626627Control *c = memnew(Control);628Panel *p = memnew(Panel);629c->add_child(p);630p->set_modulate(Color(1, 1, 1, 0.7));631p->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("focus"), SNAME("Button")));632p->set_size(get_size());633p->set_position((p_point == Vector2(Math::INF, Math::INF)) ? Vector2() : -p_point);634set_drag_preview(c);635Dictionary d;636d["type"] = "move_audio_bus";637d["index"] = get_index();638639if (get_index() < AudioServer::get_singleton()->get_bus_count() - 1) {640emit_signal(SNAME("drop_end_request"));641}642643return d;644}645646bool EditorAudioBus::can_drop_data(const Point2 &p_point, const Variant &p_data) const {647if (get_index() == 0) {648return false;649}650651Dictionary d = p_data;652if (d.has("type") && String(d["type"]) == "move_audio_bus" && (int)d["index"] != get_index()) {653hovering_drop = true;654return true;655}656657return false;658}659660void EditorAudioBus::drop_data(const Point2 &p_point, const Variant &p_data) {661Dictionary d = p_data;662emit_signal(SNAME("dropped"), d["index"], get_index());663}664665Variant EditorAudioBus::get_drag_data_fw(const Point2 &p_point, Control *p_from) {666TreeItem *item = (p_point == Vector2(Math::INF, Math::INF)) ? effects->get_selected() : effects->get_item_at_position(p_point);667if (!item) {668return Variant();669}670671Variant md = item->get_metadata(0);672if (md.get_type() == Variant::INT) {673Dictionary fxd;674fxd["type"] = "audio_bus_effect";675fxd["bus"] = get_index();676fxd["effect"] = md;677678Label *l = memnew(Label);679l->set_focus_mode(FOCUS_ACCESSIBILITY);680l->set_text(item->get_text(0));681l->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);682effects->set_drag_preview(l);683684return fxd;685}686687return Variant();688}689690bool EditorAudioBus::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {691Dictionary d = p_data;692if (!d.has("type") || String(d["type"]) != "audio_bus_effect") {693return false;694}695696TreeItem *item = (p_point == Vector2(Math::INF, Math::INF)) ? effects->get_selected() : effects->get_item_at_position(p_point);697if (!item) {698return false;699}700701effects->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);702703return true;704}705706void EditorAudioBus::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {707Dictionary d = p_data;708709TreeItem *item = (p_point == Vector2(Math::INF, Math::INF)) ? effects->get_selected() : effects->get_item_at_position(p_point);710if (!item) {711return;712}713int 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);714Variant md = item->get_metadata(0);715716int paste_at;717int bus = d["bus"];718int effect = d["effect"];719720if (md.get_type() == Variant::INT) {721paste_at = md;722if (pos > 0) {723paste_at++;724}725726if (bus == get_index() && paste_at > effect) {727paste_at--;728}729} else {730paste_at = -1;731}732733bool enabled = AudioServer::get_singleton()->is_bus_effect_enabled(bus, effect);734735EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();736ur->create_action(TTR("Move Bus Effect"));737ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", bus, effect);738ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(bus, effect), paste_at);739740if (paste_at == -1) {741paste_at = AudioServer::get_singleton()->get_bus_effect_count(get_index());742if (bus == get_index()) {743paste_at--;744}745}746if (!enabled) {747ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), paste_at, false);748}749750ur->add_undo_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), paste_at);751ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", bus, AudioServer::get_singleton()->get_bus_effect(bus, effect), effect);752if (!enabled) {753ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", bus, effect, false);754}755756ur->add_do_method(buses, "_update_bus", get_index());757ur->add_undo_method(buses, "_update_bus", get_index());758if (get_index() != bus) {759ur->add_do_method(buses, "_update_bus", bus);760ur->add_undo_method(buses, "_update_bus", bus);761}762ur->commit_action();763}764765void EditorAudioBus::_delete_effect_pressed(int p_option) {766TreeItem *item = effects->get_selected();767if (!item) {768return;769}770771if (item->get_metadata(0).get_type() != Variant::INT) {772return;773}774775int index = item->get_metadata(0);776777EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();778ur->create_action(TTR("Delete Bus Effect"));779ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), index);780ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(get_index(), index), index);781ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, AudioServer::get_singleton()->is_bus_effect_enabled(get_index(), index));782ur->add_do_method(buses, "_update_bus", get_index());783ur->add_undo_method(buses, "_update_bus", get_index());784ur->commit_action();785}786787void EditorAudioBus::_effect_rmb(const Vector2 &p_pos, MouseButton p_button) {788if (p_button != MouseButton::RIGHT) {789return;790}791792TreeItem *item = effects->get_selected();793if (!item) {794return;795}796797if (item->get_metadata(0).get_type() != Variant::INT) {798return;799}800801delete_effect_popup->set_position(get_screen_position() + get_local_mouse_position());802delete_effect_popup->reset_size();803delete_effect_popup->popup();804}805806void EditorAudioBus::_bind_methods() {807ClassDB::bind_method("update_bus", &EditorAudioBus::update_bus);808ClassDB::bind_method("update_send", &EditorAudioBus::update_send);809810ADD_SIGNAL(MethodInfo("duplicate_request"));811ADD_SIGNAL(MethodInfo("delete_request"));812ADD_SIGNAL(MethodInfo("vol_reset_request"));813ADD_SIGNAL(MethodInfo("drop_end_request"));814ADD_SIGNAL(MethodInfo("dropped"));815}816817EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {818buses = p_buses;819is_master = p_is_master;820821set_tooltip_text(TTR("Drag & drop to rearrange."));822823VBoxContainer *vb = memnew(VBoxContainer);824vb->add_theme_constant_override("separation", 4 * EDSCALE);825add_child(vb);826827set_v_size_flags(SIZE_EXPAND_FILL);828829track_name = memnew(LineEdit);830track_name->set_accessibility_name(TTRC("Track Name"));831track_name->connect(SceneStringName(text_submitted), callable_mp(this, &EditorAudioBus::_name_changed));832track_name->connect(SceneStringName(focus_exited), callable_mp(this, &EditorAudioBus::_name_focus_exit));833vb->add_child(track_name);834835HBoxContainer *hbc = memnew(HBoxContainer);836vb->add_child(hbc);837solo = memnew(Button);838solo->set_theme_type_variation(SceneStringName(FlatButton));839solo->set_toggle_mode(true);840solo->set_tooltip_text(TTR("Solo"));841solo->set_focus_mode(FOCUS_ACCESSIBILITY);842solo->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBus::_solo_toggled));843hbc->add_child(solo);844mute = memnew(Button);845mute->set_theme_type_variation(SceneStringName(FlatButton));846mute->set_toggle_mode(true);847mute->set_tooltip_text(TTR("Mute"));848mute->set_focus_mode(FOCUS_ACCESSIBILITY);849mute->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBus::_mute_toggled));850hbc->add_child(mute);851bypass = memnew(Button);852bypass->set_theme_type_variation(SceneStringName(FlatButton));853bypass->set_toggle_mode(true);854bypass->set_tooltip_text(TTR("Bypass"));855bypass->set_focus_mode(FOCUS_ACCESSIBILITY);856bypass->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBus::_bypass_toggled));857hbc->add_child(bypass);858hbc->add_spacer();859860Ref<StyleBoxEmpty> sbempty = memnew(StyleBoxEmpty);861for (int i = 0; i < hbc->get_child_count(); i++) {862Control *child = Object::cast_to<Control>(hbc->get_child(i));863child->begin_bulk_theme_override();864child->add_theme_style_override(CoreStringName(normal), sbempty);865child->add_theme_style_override(SceneStringName(hover), sbempty);866child->add_theme_style_override("hover_mirrored", sbempty);867child->add_theme_style_override("focus", sbempty);868child->add_theme_style_override("focus_mirrored", sbempty);869870Ref<StyleBoxFlat> sbflat = memnew(StyleBoxFlat);871sbflat->set_content_margin_all(0);872sbflat->set_bg_color(Color(1, 1, 1, 0));873sbflat->set_border_width(Side::SIDE_BOTTOM, Math::round(3 * EDSCALE));874child->add_theme_style_override(SceneStringName(pressed), sbflat);875child->add_theme_style_override("pressed_mirrored", sbflat);876child->add_theme_style_override("hover_pressed", sbflat);877child->add_theme_style_override("hover_pressed_mirrored", sbflat);878879child->end_bulk_theme_override();880}881882HSeparator *separator = memnew(HSeparator);883separator->set_mouse_filter(MOUSE_FILTER_PASS);884vb->add_child(separator);885886Control *spacer_top = memnew(Control);887spacer_top->set_custom_minimum_size(Size2(0, 6 * EDSCALE));888vb->add_child(spacer_top);889890HBoxContainer *hb = memnew(HBoxContainer);891vb->add_child(hb);892893Control *spacer_bottom = memnew(Control);894spacer_bottom->set_custom_minimum_size(Size2(0, 2 * EDSCALE));895vb->add_child(spacer_bottom);896897slider = memnew(VSlider);898slider->set_min(0.0);899slider->set_max(1.0);900slider->set_step(0.0001);901slider->set_clip_contents(false);902slider->set_accessibility_name(TTRC("Volume"));903904audio_value_preview_box = memnew(Panel);905slider->add_child(audio_value_preview_box);906audio_value_preview_box->set_as_top_level(true);907audio_value_preview_box->set_mouse_filter(MOUSE_FILTER_PASS);908audio_value_preview_box->hide();909910HBoxContainer *audioprev_hbc = memnew(HBoxContainer);911audioprev_hbc->set_v_size_flags(SIZE_EXPAND_FILL);912audioprev_hbc->set_h_size_flags(SIZE_EXPAND_FILL);913audio_value_preview_box->add_child(audioprev_hbc);914915audio_value_preview_label = memnew(Label);916audio_value_preview_label->set_focus_mode(FOCUS_ACCESSIBILITY);917audio_value_preview_label->set_v_size_flags(SIZE_EXPAND_FILL);918audio_value_preview_label->set_h_size_flags(SIZE_EXPAND_FILL);919audio_value_preview_label->set_mouse_filter(MOUSE_FILTER_PASS);920audioprev_hbc->add_child(audio_value_preview_label);921922preview_timer = memnew(Timer);923preview_timer->set_wait_time(0.8f);924preview_timer->set_one_shot(true);925add_child(preview_timer);926927slider->connect(SceneStringName(value_changed), callable_mp(this, &EditorAudioBus::_volume_changed));928slider->connect(SceneStringName(value_changed), callable_mp(this, &EditorAudioBus::_show_value));929preview_timer->connect("timeout", callable_mp(this, &EditorAudioBus::_hide_value_preview));930hb->add_child(slider);931932cc = 0;933for (int i = 0; i < CHANNELS_MAX; i++) {934channel[i].vu_l = memnew(TextureProgressBar);935channel[i].vu_l->set_fill_mode(TextureProgressBar::FILL_BOTTOM_TO_TOP);936hb->add_child(channel[i].vu_l);937channel[i].vu_l->set_min(-80);938channel[i].vu_l->set_max(24);939channel[i].vu_l->set_step(0.1);940channel[i].vu_l->set_accessibility_name(vformat(TTR("Channel %d, Left VU"), i));941942channel[i].vu_r = memnew(TextureProgressBar);943channel[i].vu_r->set_fill_mode(TextureProgressBar::FILL_BOTTOM_TO_TOP);944hb->add_child(channel[i].vu_r);945channel[i].vu_r->set_min(-80);946channel[i].vu_r->set_max(24);947channel[i].vu_r->set_step(0.1);948channel[i].vu_r->set_accessibility_name(vformat(TTR("Channel %d, Right VU"), i));949950channel[i].peak_l = 0.0f;951channel[i].peak_r = 0.0f;952}953954EditorAudioMeterNotches *scale = memnew(EditorAudioMeterNotches);955956for (float db = 6.0f; db >= -80.0f; db -= 6.0f) {957bool renderNotch = (db >= -6.0f || db == -24.0f || db == -72.0f);958scale->add_notch(_scaled_db_to_normalized_volume(db), db, renderNotch);959}960scale->set_mouse_filter(MOUSE_FILTER_PASS);961hb->add_child(scale);962963effects = memnew(Tree);964effects->set_accessibility_name(TTRC("Effects"));965effects->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);966effects->set_hide_root(true);967effects->set_custom_minimum_size(Size2(0, 80) * EDSCALE);968effects->set_hide_folding(true);969effects->set_v_size_flags(SIZE_EXPAND_FILL);970vb->add_child(effects);971effects->connect("item_edited", callable_mp(this, &EditorAudioBus::_effect_edited));972effects->connect("cell_selected", callable_mp(this, &EditorAudioBus::_effect_selected));973effects->connect(SceneStringName(focus_exited), callable_mp(effects, &Tree::deselect_all));974effects->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);975SET_DRAG_FORWARDING_GCD(effects, EditorAudioBus);976effects->connect("item_mouse_selected", callable_mp(this, &EditorAudioBus::_effect_rmb));977effects->set_allow_rmb_select(true);978effects->set_focus_mode(FOCUS_CLICK);979effects->set_allow_reselect(true);980effects->set_theme_type_variation("EditorAudioBusEffectsTree");981effects->connect(SceneStringName(gui_input), callable_mp(this, &EditorAudioBus::_effects_gui_input));982983send = memnew(OptionButton);984send->set_accessibility_name(TTRC("Send"));985send->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);986send->set_clip_text(true);987send->connect(SceneStringName(item_selected), callable_mp(this, &EditorAudioBus::_send_selected));988vb->add_child(send);989990set_focus_mode(FOCUS_CLICK);991992effect_options = memnew(PopupMenu);993effect_options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // Don't translate class names.994effect_options->connect("index_pressed", callable_mp(this, &EditorAudioBus::_effect_add));995add_child(effect_options);996LocalVector<StringName> effect_list;997ClassDB::get_inheriters_from_class("AudioEffect", effect_list);998effect_list.sort_custom<StringName::AlphCompare>();999for (const StringName &E : effect_list) {1000if (!ClassDB::can_instantiate(E) || ClassDB::is_virtual(E)) {1001continue;1002}10031004String name = E.operator String().replace("AudioEffect", "");1005effect_options->add_item(name);1006effect_options->set_item_metadata(-1, E);1007}10081009bus_options = memnew(MenuButton);1010bus_options->set_shortcut_context(this);1011bus_options->set_h_size_flags(SIZE_SHRINK_END);1012bus_options->set_anchor(SIDE_RIGHT, 0.0);1013bus_options->set_tooltip_text(TTR("Bus Options"));1014hbc->add_child(bus_options);10151016bus_popup = bus_options->get_popup();1017bus_popup->add_shortcut(ED_SHORTCUT("audio_bus_editor/duplicate_selected_bus", TTRC("Duplicate Bus"), KeyModifierMask::CMD_OR_CTRL | Key::D));1018bus_popup->add_shortcut(ED_SHORTCUT("audio_bus_editor/delete_selected_bus", TTRC("Delete Bus"), Key::KEY_DELETE));1019bus_popup->set_item_disabled(1, is_master);1020bus_popup->add_item(TTR("Reset Volume"));1021bus_popup->connect("index_pressed", callable_mp(this, &EditorAudioBus::_bus_popup_pressed));10221023delete_effect_popup = memnew(PopupMenu);1024delete_effect_popup->add_item(TTR("Delete Effect"));1025add_child(delete_effect_popup);1026delete_effect_popup->connect("index_pressed", callable_mp(this, &EditorAudioBus::_delete_effect_pressed));1027}10281029void EditorAudioBusDrop::_notification(int p_what) {1030switch (p_what) {1031case NOTIFICATION_DRAW: {1032draw_style_box(get_theme_stylebox(CoreStringName(normal), SNAME("Button")), Rect2(Vector2(), get_size()));10331034if (hovering_drop) {1035Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));1036accent.a *= 0.7;1037draw_rect(Rect2(Point2(), get_size()), accent, false);1038}1039} break;10401041case NOTIFICATION_MOUSE_ENTER: {1042if (!hovering_drop) {1043hovering_drop = true;1044queue_redraw();1045}1046} break;10471048case NOTIFICATION_MOUSE_EXIT:1049case NOTIFICATION_DRAG_END: {1050if (hovering_drop) {1051hovering_drop = false;1052queue_redraw();1053}1054} break;1055}1056}10571058bool EditorAudioBusDrop::can_drop_data(const Point2 &p_point, const Variant &p_data) const {1059Dictionary d = p_data;1060return (d.has("type") && String(d["type"]) == "move_audio_bus");1061}10621063void EditorAudioBusDrop::drop_data(const Point2 &p_point, const Variant &p_data) {1064Dictionary d = p_data;1065emit_signal(SNAME("dropped"), d["index"], AudioServer::get_singleton()->get_bus_count());1066}10671068void EditorAudioBusDrop::_bind_methods() {1069ADD_SIGNAL(MethodInfo("dropped"));1070}10711072void EditorAudioBuses::_update_file_label() {1073const String filename = ResourceUID::ensure_path(edited_path).get_file();1074file->set_text(filename);1075file->set_tooltip_text(filename);10761077if (is_visible_in_tree()) {1078_update_file_label_size();1079}1080}10811082void EditorAudioBuses::_update_file_label_size() {1083int label_min_width = file->get_minimum_size().x + file->get_character_bounds(0).size.x;1084file->set_custom_minimum_size(Size2(label_min_width, 0));1085}10861087void EditorAudioBuses::_rebuild_buses() {1088for (int i = bus_hb->get_child_count() - 1; i >= 0; i--) {1089EditorAudioBus *audio_bus = Object::cast_to<EditorAudioBus>(bus_hb->get_child(i));1090if (audio_bus) {1091bus_hb->remove_child(audio_bus);1092audio_bus->queue_free();1093}1094}10951096if (drop_end) {1097bus_hb->remove_child(drop_end);1098drop_end->queue_free();1099drop_end = nullptr;1100}11011102for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {1103bool is_master = (i == 0);1104EditorAudioBus *audio_bus = memnew(EditorAudioBus(this, is_master));1105bus_hb->add_child(audio_bus);1106audio_bus->connect("delete_request", callable_mp(this, &EditorAudioBuses::_delete_bus).bind(audio_bus), CONNECT_DEFERRED);1107audio_bus->connect("duplicate_request", callable_mp(this, &EditorAudioBuses::_duplicate_bus), CONNECT_DEFERRED);1108audio_bus->connect("vol_reset_request", callable_mp(this, &EditorAudioBuses::_reset_bus_volume).bind(audio_bus), CONNECT_DEFERRED);1109audio_bus->connect("drop_end_request", callable_mp(this, &EditorAudioBuses::_request_drop_end));1110audio_bus->connect("dropped", callable_mp(this, &EditorAudioBuses::_drop_at_index), CONNECT_DEFERRED);1111}1112}11131114EditorAudioBuses *EditorAudioBuses::register_editor() {1115EditorAudioBuses *audio_buses = memnew(EditorAudioBuses);1116EditorDockManager::get_singleton()->add_dock(audio_buses);1117return audio_buses;1118}11191120void EditorAudioBuses::_notification(int p_what) {1121switch (p_what) {1122case NOTIFICATION_THEME_CHANGED: {1123bus_scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));1124if (is_visible_in_tree()) {1125_update_file_label_size();1126}1127} break;11281129case NOTIFICATION_READY: {1130_rebuild_buses();1131} break;11321133case NOTIFICATION_DRAG_END: {1134if (drop_end) {1135bus_hb->remove_child(drop_end);1136drop_end->queue_free();1137drop_end = nullptr;1138}1139} break;11401141case NOTIFICATION_PROCESS: {1142// Check if anything was edited.1143bool edited = AudioServer::get_singleton()->is_edited();1144for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {1145for (int j = 0; j < AudioServer::get_singleton()->get_bus_effect_count(i); j++) {1146Ref<AudioEffect> effect = AudioServer::get_singleton()->get_bus_effect(i, j);1147if (effect->is_edited()) {1148edited = true;1149effect->set_edited(false);1150}1151}1152}11531154if (edited) {1155AudioServer::get_singleton()->set_edited(false);1156save_timer->start();1157}1158} break;1159case NOTIFICATION_VISIBILITY_CHANGED: {1160if (is_visible_in_tree()) {1161_update_file_label();1162}1163} break;1164}1165}11661167void EditorAudioBuses::_add_bus() {1168EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();11691170ur->create_action(TTR("Add Audio Bus"));1171ur->add_do_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count() + 1);1172ur->add_undo_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count());1173ur->commit_action();1174}11751176void EditorAudioBuses::_update_bus(int p_index) {1177if (p_index >= bus_hb->get_child_count()) {1178return;1179}11801181bus_hb->get_child(p_index)->call("update_bus");1182}11831184void EditorAudioBuses::_update_sends() {1185for (int i = 0; i < bus_hb->get_child_count(); i++) {1186bus_hb->get_child(i)->call("update_send");1187}1188}11891190void EditorAudioBuses::_delete_bus(Object *p_which) {1191EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which);1192int index = bus->get_index();1193if (index == 0) {1194EditorNode::get_singleton()->show_warning(TTR("Master bus can't be deleted!"));1195return;1196}11971198EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();11991200ur->create_action(TTR("Delete Audio Bus"));1201ur->add_do_method(AudioServer::get_singleton(), "remove_bus", index);1202ur->add_undo_method(AudioServer::get_singleton(), "add_bus", index);1203ur->add_undo_method(AudioServer::get_singleton(), "set_bus_name", index, AudioServer::get_singleton()->get_bus_name(index));1204ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", index, AudioServer::get_singleton()->get_bus_volume_db(index));1205ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", index, AudioServer::get_singleton()->get_bus_send(index));1206ur->add_undo_method(AudioServer::get_singleton(), "set_bus_solo", index, AudioServer::get_singleton()->is_bus_solo(index));1207ur->add_undo_method(AudioServer::get_singleton(), "set_bus_mute", index, AudioServer::get_singleton()->is_bus_mute(index));1208ur->add_undo_method(AudioServer::get_singleton(), "set_bus_bypass_effects", index, AudioServer::get_singleton()->is_bus_bypassing_effects(index));1209for (int i = 0; i < AudioServer::get_singleton()->get_bus_effect_count(index); i++) {1210ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", index, AudioServer::get_singleton()->get_bus_effect(index, i));1211ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", index, i, AudioServer::get_singleton()->is_bus_effect_enabled(index, i));1212}1213ur->commit_action();1214}12151216void EditorAudioBuses::_duplicate_bus(int p_which) {1217int add_at_pos = p_which + 1;1218EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1219ur->create_action(TTR("Duplicate Audio Bus"));1220ur->add_do_method(AudioServer::get_singleton(), "add_bus", add_at_pos);1221ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", add_at_pos, AudioServer::get_singleton()->get_bus_name(p_which) + " Copy");1222ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", add_at_pos, AudioServer::get_singleton()->get_bus_volume_db(p_which));1223ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", add_at_pos, AudioServer::get_singleton()->get_bus_send(p_which));1224ur->add_do_method(AudioServer::get_singleton(), "set_bus_solo", add_at_pos, AudioServer::get_singleton()->is_bus_solo(p_which));1225ur->add_do_method(AudioServer::get_singleton(), "set_bus_mute", add_at_pos, AudioServer::get_singleton()->is_bus_mute(p_which));1226ur->add_do_method(AudioServer::get_singleton(), "set_bus_bypass_effects", add_at_pos, AudioServer::get_singleton()->is_bus_bypassing_effects(p_which));1227for (int i = 0; i < AudioServer::get_singleton()->get_bus_effect_count(p_which); i++) {1228ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", add_at_pos, AudioServer::get_singleton()->get_bus_effect(p_which, i));1229ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", add_at_pos, i, AudioServer::get_singleton()->is_bus_effect_enabled(p_which, i));1230}1231ur->add_do_method(this, "_update_bus", add_at_pos);1232ur->add_undo_method(AudioServer::get_singleton(), "remove_bus", add_at_pos);1233ur->commit_action();1234}12351236void EditorAudioBuses::_reset_bus_volume(Object *p_which) {1237EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which);1238int index = bus->get_index();12391240EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1241ur->create_action(TTR("Reset Bus Volume"));1242ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", index, 0.f);1243ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", index, AudioServer::get_singleton()->get_bus_volume_db(index));1244ur->add_do_method(this, "_update_bus", index);1245ur->add_undo_method(this, "_update_bus", index);1246ur->commit_action();1247}12481249void EditorAudioBuses::_request_drop_end() {1250if (!drop_end && bus_hb->get_child_count()) {1251drop_end = memnew(EditorAudioBusDrop);12521253bus_hb->add_child(drop_end);1254drop_end->set_custom_minimum_size(Object::cast_to<Control>(bus_hb->get_child(0))->get_size());1255drop_end->connect("dropped", callable_mp(this, &EditorAudioBuses::_drop_at_index), CONNECT_DEFERRED);1256}1257}12581259void EditorAudioBuses::_drop_at_index(int p_bus, int p_index) {1260EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1261ur->create_action(TTR("Move Audio Bus"));12621263ur->add_do_method(AudioServer::get_singleton(), "move_bus", p_bus, p_index);1264int real_bus = p_index > p_bus ? p_bus : p_bus + 1;1265int real_index = p_index > p_bus ? p_index - 1 : p_index;1266ur->add_undo_method(AudioServer::get_singleton(), "move_bus", real_index, real_bus);12671268ur->commit_action();1269}12701271void EditorAudioBuses::_server_save() {1272Ref<AudioBusLayout> state = AudioServer::get_singleton()->generate_bus_layout();1273if (edited_path.is_empty()) {1274ResourceSaver::save(state, "res://default_bus_layout.tres");1275edited_path = ResourceUID::path_to_uid("res://default_bus_layout.tres");1276ProjectSettings::get_singleton()->set_setting("audio/buses/default_bus_layout", edited_path);1277_update_file_label();1278} else if (!edited_path.begins_with("uid://")) {1279ResourceSaver::save(state, edited_path);1280edited_path = ResourceUID::path_to_uid(edited_path);1281ProjectSettings::get_singleton()->set_setting("audio/buses/default_bus_layout", edited_path);1282} else {1283ResourceSaver::save(state, ResourceUID::ensure_path(edited_path));1284}1285}12861287void EditorAudioBuses::_file_moved(const String &p_old_path, const String &p_new_path) {1288if (is_visible_in_tree() && !edited_path.is_empty()) {1289callable_mp(this, &EditorAudioBuses::_update_file_label).call_deferred();1290}1291}12921293void EditorAudioBuses::_select_layout() {1294FileSystemDock::get_singleton()->navigate_to_path(ResourceUID::ensure_path(edited_path));1295}12961297void EditorAudioBuses::_save_as_layout() {1298file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);1299file_dialog->set_title(TTR("Save Audio Bus Layout As..."));1300file_dialog->set_current_path(ResourceUID::ensure_path(edited_path));1301file_dialog->popup_file_dialog();1302new_layout = false;1303}13041305void EditorAudioBuses::_new_layout() {1306file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);1307file_dialog->set_title(TTR("Location for New Layout..."));1308file_dialog->set_current_path("new_bus_layout.tres");1309file_dialog->popup_file_dialog();1310new_layout = true;1311}13121313void EditorAudioBuses::_load_layout() {1314file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);1315file_dialog->set_title(TTR("Open Audio Bus Layout"));1316file_dialog->set_current_path(ResourceUID::ensure_path(edited_path));1317file_dialog->popup_file_dialog();1318new_layout = false;1319}13201321void EditorAudioBuses::_load_default_layout() {1322open_layout(GLOBAL_GET("audio/buses/default_bus_layout"));1323}13241325void EditorAudioBuses::_file_dialog_callback(const String &p_string) {1326if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {1327if (new_layout) {1328Ref<AudioBusLayout> empty_state;1329empty_state.instantiate();1330AudioServer::get_singleton()->set_bus_layout(empty_state);1331}13321333Error err = ResourceSaver::save(AudioServer::get_singleton()->generate_bus_layout(), p_string);1334if (err != OK) {1335EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file: %s"), p_string));1336return;1337}1338}1339open_layout(ResourceUID::path_to_uid(p_string));1340}13411342void EditorAudioBuses::update_layout(EditorDock::DockLayout p_layout) {1343bool new_floating = (p_layout == EditorDock::DOCK_LAYOUT_FLOATING);1344if (floating == new_floating) {1345return;1346}1347floating = new_floating;13481349if (floating) {1350bus_mc->set_theme_type_variation("NoBorderHorizontalBottom");1351bus_scroll->set_scroll_hint_mode(ScrollContainer::SCROLL_HINT_MODE_TOP_AND_LEFT);1352} else {1353bus_mc->set_theme_type_variation("NoBorderBottomPanel");1354bus_scroll->set_scroll_hint_mode(ScrollContainer::SCROLL_HINT_MODE_ALL);1355}1356}13571358void EditorAudioBuses::_bind_methods() {1359ClassDB::bind_method("_update_bus", &EditorAudioBuses::_update_bus);1360ClassDB::bind_method("_update_sends", &EditorAudioBuses::_update_sends);1361}13621363EditorAudioBuses::EditorAudioBuses() {1364set_name(TTRC("Audio"));1365set_icon_name("AudioStreamPlayer");1366set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_audio_bottom_panel", TTRC("Toggle Audio Dock"), KeyModifierMask::ALT | Key::A));1367set_default_slot(EditorDock::DOCK_SLOT_BOTTOM);1368set_available_layouts(EditorDock::DOCK_LAYOUT_HORIZONTAL | EditorDock::DOCK_LAYOUT_FLOATING);13691370VBoxContainer *main_vb = memnew(VBoxContainer);1371add_child(main_vb);13721373top_hb = memnew(HBoxContainer);1374main_vb->add_child(top_hb);13751376edited_path = GLOBAL_GET("audio/buses/default_bus_layout");13771378Label *layout_label = memnew(Label(TTRC("Layout:")));1379top_hb->add_child(layout_label);13801381file = memnew(Label);1382file->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);1383file->set_mouse_filter(MOUSE_FILTER_PASS);1384file->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);1385file->set_h_size_flags(SIZE_EXPAND_FILL);1386top_hb->add_child(file);13871388add = memnew(Button);1389top_hb->add_child(add);1390add->set_text(TTR("Add Bus"));1391add->set_tooltip_text(TTR("Add a new Audio Bus to this layout."));1392add->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBuses::_add_bus));13931394VSeparator *separator = memnew(VSeparator);1395top_hb->add_child(separator);13961397load = memnew(Button);1398load->set_text(TTR("Load"));1399load->set_tooltip_text(TTR("Load an existing Bus Layout."));1400top_hb->add_child(load);1401load->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBuses::_load_layout));14021403save_as = memnew(Button);1404save_as->set_text(TTR("Save As"));1405save_as->set_tooltip_text(TTR("Save this Bus Layout to a file."));1406top_hb->add_child(save_as);1407save_as->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBuses::_save_as_layout));14081409_default = memnew(Button);1410_default->set_text(TTR("Load Default"));1411_default->set_tooltip_text(TTR("Load the default Bus Layout."));1412top_hb->add_child(_default);1413_default->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBuses::_load_default_layout));14141415_new = memnew(Button);1416_new->set_text(TTR("Create"));1417_new->set_tooltip_text(TTR("Create a new Bus Layout."));1418top_hb->add_child(_new);1419_new->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBuses::_new_layout));14201421bus_mc = memnew(MarginContainer);1422bus_mc->set_theme_type_variation("NoBorderBottomPanel");1423bus_mc->set_v_size_flags(SIZE_EXPAND_FILL);1424main_vb->add_child(bus_mc);14251426bus_scroll = memnew(ScrollContainer);1427bus_scroll->set_scroll_hint_mode(ScrollContainer::SCROLL_HINT_MODE_ALL);1428bus_scroll->set_custom_minimum_size(Size2(0, 40 * EDSCALE));1429bus_mc->add_child(bus_scroll);14301431bus_hb = memnew(HBoxContainer);1432bus_hb->set_v_size_flags(SIZE_EXPAND_FILL);1433bus_scroll->add_child(bus_hb);14341435save_timer = memnew(Timer);1436save_timer->set_wait_time(0.8);1437save_timer->set_one_shot(true);1438main_vb->add_child(save_timer);1439save_timer->connect("timeout", callable_mp(this, &EditorAudioBuses::_server_save));14401441set_v_size_flags(SIZE_EXPAND_FILL);14421443file_dialog = memnew(EditorFileDialog);1444List<String> ext;1445ResourceLoader::get_recognized_extensions_for_type("AudioBusLayout", &ext);1446for (const String &E : ext) {1447file_dialog->add_filter("*." + E, TTR("Audio Bus Layout"));1448}1449add_child(file_dialog);1450file_dialog->connect("file_selected", callable_mp(this, &EditorAudioBuses::_file_dialog_callback));14511452AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &EditorAudioBuses::_rebuild_buses));1453FileSystemDock::get_singleton()->connect("files_moved", callable_mp(this, &EditorAudioBuses::_file_moved));14541455set_process(true);1456}14571458void EditorAudioBuses::open_layout(const String &p_path) {1459make_visible();14601461const String path = ResourceUID::ensure_path(p_path);1462if (!ResourceLoader::exists(path)) {1463EditorNode::get_singleton()->show_warning(vformat(TTR(R"(Can't open audio bus layout: "%s" doesn't exist.)"), path));1464return;1465}14661467Ref<AudioBusLayout> state = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);1468if (state.is_null()) {1469EditorNode::get_singleton()->show_warning(vformat(TTR(R"(Can't open audio bus layout: "%s" is not a valid audio bus layout.)"), path));1470return;1471}14721473edited_path = p_path; // Use UID when available.1474_update_file_label();14751476AudioServer::get_singleton()->set_bus_layout(state);1477_rebuild_buses();1478EditorUndoRedoManager::get_singleton()->clear_history(EditorUndoRedoManager::GLOBAL_HISTORY);1479callable_mp(this, &EditorAudioBuses::_select_layout).call_deferred();1480}14811482void AudioBusesEditorPlugin::edit(Object *p_node) {1483Ref<AudioBusLayout> bus_layout(p_node);1484if (bus_layout.is_null()) {1485return;1486}1487const String path = bus_layout->get_path();1488if (path.is_resource_file()) {1489audio_bus_editor->open_layout(ResourceUID::path_to_uid(path));1490}1491}14921493bool AudioBusesEditorPlugin::handles(Object *p_node) const {1494return (Object::cast_to<AudioBusLayout>(p_node) != nullptr);1495}14961497void AudioBusesEditorPlugin::make_visible(bool p_visible) {1498}14991500AudioBusesEditorPlugin::AudioBusesEditorPlugin(EditorAudioBuses *p_node) {1501audio_bus_editor = p_node;1502}15031504void EditorAudioMeterNotches::add_notch(float p_normalized_offset, float p_db_value, bool p_render_value) {1505notches.push_back(AudioNotch(p_normalized_offset, p_db_value, p_render_value));1506}15071508Size2 EditorAudioMeterNotches::get_minimum_size() const {1509Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));1510int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));1511float font_height = font->get_height(font_size);15121513float width = 0;1514float height = top_padding + btm_padding;15151516for (const EditorAudioMeterNotches::AudioNotch ¬ch : notches) {1517if (notch.render_db_value) {1518width = MAX(width, font->get_string_size(String::num(Math::abs(notch.db_value)) + "dB", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x);1519height += font_height;1520}1521}1522width += line_length + label_space;15231524return Size2(width, height);1525}15261527void EditorAudioMeterNotches::_update_theme_item_cache() {1528Control::_update_theme_item_cache();15291530theme_cache.notch_color = get_theme_color(SceneStringName(font_color), EditorStringName(Editor));15311532theme_cache.font = get_theme_font(SceneStringName(font), SNAME("Label"));1533theme_cache.font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));1534}15351536void EditorAudioMeterNotches::_bind_methods() {1537ClassDB::bind_method("add_notch", &EditorAudioMeterNotches::add_notch);1538ClassDB::bind_method("_draw_audio_notches", &EditorAudioMeterNotches::_draw_audio_notches);1539}15401541void EditorAudioMeterNotches::_notification(int p_what) {1542switch (p_what) {1543case NOTIFICATION_DRAW: {1544_draw_audio_notches();1545} break;1546}1547}15481549void EditorAudioMeterNotches::_draw_audio_notches() {1550float font_height = theme_cache.font->get_height(theme_cache.font_size);15511552for (const AudioNotch &n : notches) {1553draw_line(Vector2(0, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding),1554Vector2(line_length * EDSCALE, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding),1555theme_cache.notch_color,1556Math::round(EDSCALE));15571558if (n.render_db_value) {1559draw_string(theme_cache.font,1560Vector2((line_length + label_space) * EDSCALE,1561(1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + (font_height / 4) + top_padding),1562String::num(Math::abs(n.db_value)) + "dB",1563HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size,1564theme_cache.notch_color);1565}1566}1567}156815691570