1/**************************************************************************/
2/* editor_audio_buses.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "editor_audio_buses.h"
32
33#include "core/config/project_settings.h"
34#include "core/input/input.h"
35#include "core/io/resource_saver.h"
36#include "core/os/keyboard.h"
37#include "editor/editor_node.h"
38#include "editor/editor_scale.h"
39#include "editor/editor_settings.h"
40#include "editor/editor_string_names.h"
41#include "editor/editor_undo_redo_manager.h"
42#include "editor/filesystem_dock.h"
43#include "editor/gui/editor_file_dialog.h"
44#include "scene/gui/separator.h"
45#include "scene/resources/font.h"
46#include "servers/audio_server.h"
47
48void EditorAudioBus::_update_visible_channels() {
49 int i = 0;
50 for (; i < cc; i++) {
51 if (!channel[i].vu_l->is_visible()) {
52 channel[i].vu_l->show();
53 }
54 if (!channel[i].vu_r->is_visible()) {
55 channel[i].vu_r->show();
56 }
57 }
58
59 for (; i < CHANNELS_MAX; i++) {
60 if (channel[i].vu_l->is_visible()) {
61 channel[i].vu_l->hide();
62 }
63 if (channel[i].vu_r->is_visible()) {
64 channel[i].vu_r->hide();
65 }
66 }
67}
68
69void EditorAudioBus::_notification(int p_what) {
70 switch (p_what) {
71 case NOTIFICATION_ENTER_TREE:
72 case NOTIFICATION_THEME_CHANGED: {
73 Ref<Texture2D> active_bus_texture = get_editor_theme_icon(SNAME("BusVuActive"));
74 for (int i = 0; i < CHANNELS_MAX; i++) {
75 channel[i].vu_l->set_under_texture(active_bus_texture);
76 channel[i].vu_l->set_tint_under(Color(0.75, 0.75, 0.75));
77 channel[i].vu_l->set_progress_texture(active_bus_texture);
78
79 channel[i].vu_r->set_under_texture(active_bus_texture);
80 channel[i].vu_r->set_tint_under(Color(0.75, 0.75, 0.75));
81 channel[i].vu_r->set_progress_texture(active_bus_texture);
82 channel[i].prev_active = true;
83 }
84
85 disabled_vu = get_editor_theme_icon(SNAME("BusVuFrozen"));
86
87 Color solo_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1.0, 0.89, 0.22) : Color(1.0, 0.92, 0.44);
88 Color mute_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1.0, 0.16, 0.16) : Color(1.0, 0.44, 0.44);
89 Color bypass_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(0.13, 0.8, 1.0) : Color(0.44, 0.87, 1.0);
90
91 solo->set_icon(get_editor_theme_icon(SNAME("AudioBusSolo")));
92 solo->add_theme_color_override("icon_pressed_color", solo_color);
93 mute->set_icon(get_editor_theme_icon(SNAME("AudioBusMute")));
94 mute->add_theme_color_override("icon_pressed_color", mute_color);
95 bypass->set_icon(get_editor_theme_icon(SNAME("AudioBusBypass")));
96 bypass->add_theme_color_override("icon_pressed_color", bypass_color);
97
98 bus_options->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
99
100 audio_value_preview_label->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("TooltipLabel")));
101 audio_value_preview_label->add_theme_color_override("font_shadow_color", get_theme_color(SNAME("font_shadow_color"), SNAME("TooltipLabel")));
102 audio_value_preview_box->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TooltipPanel")));
103
104 for (int i = 0; i < effect_options->get_item_count(); i++) {
105 String class_name = effect_options->get_item_metadata(i);
106 Ref<Texture> icon = EditorNode::get_singleton()->get_class_icon(class_name);
107 effect_options->set_item_icon(i, icon);
108 }
109 } break;
110
111 case NOTIFICATION_READY: {
112 update_bus();
113 set_process(true);
114 } break;
115
116 case NOTIFICATION_DRAW: {
117 if (is_master) {
118 draw_style_box(get_theme_stylebox(SNAME("disabled"), SNAME("Button")), Rect2(Vector2(), get_size()));
119 } else if (has_focus()) {
120 draw_style_box(get_theme_stylebox(SNAME("focus"), SNAME("Button")), Rect2(Vector2(), get_size()));
121 } else {
122 draw_style_box(get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")), Rect2(Vector2(), get_size()));
123 }
124
125 if (get_index() != 0 && hovering_drop) {
126 Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
127 accent.a *= 0.7;
128 draw_rect(Rect2(Point2(), get_size()), accent, false);
129 }
130 } break;
131
132 case NOTIFICATION_PROCESS: {
133 if (cc != AudioServer::get_singleton()->get_bus_channels(get_index())) {
134 cc = AudioServer::get_singleton()->get_bus_channels(get_index());
135 _update_visible_channels();
136 }
137
138 for (int i = 0; i < cc; i++) {
139 float real_peak[2] = { -100, -100 };
140 bool activity_found = false;
141
142 if (AudioServer::get_singleton()->is_bus_channel_active(get_index(), i)) {
143 activity_found = true;
144 real_peak[0] = MAX(real_peak[0], AudioServer::get_singleton()->get_bus_peak_volume_left_db(get_index(), i));
145 real_peak[1] = MAX(real_peak[1], AudioServer::get_singleton()->get_bus_peak_volume_right_db(get_index(), i));
146 }
147
148 if (real_peak[0] > channel[i].peak_l) {
149 channel[i].peak_l = real_peak[0];
150 } else {
151 channel[i].peak_l -= get_process_delta_time() * 60.0;
152 }
153
154 if (real_peak[1] > channel[i].peak_r) {
155 channel[i].peak_r = real_peak[1];
156 } else {
157 channel[i].peak_r -= get_process_delta_time() * 60.0;
158 }
159
160 channel[i].vu_l->set_value(channel[i].peak_l);
161 channel[i].vu_r->set_value(channel[i].peak_r);
162
163 if (activity_found != channel[i].prev_active) {
164 if (activity_found) {
165 channel[i].vu_l->set_over_texture(Ref<Texture2D>());
166 channel[i].vu_r->set_over_texture(Ref<Texture2D>());
167 } else {
168 channel[i].vu_l->set_over_texture(disabled_vu);
169 channel[i].vu_r->set_over_texture(disabled_vu);
170 }
171
172 channel[i].prev_active = activity_found;
173 }
174 }
175 } break;
176
177 case NOTIFICATION_VISIBILITY_CHANGED: {
178 for (int i = 0; i < CHANNELS_MAX; i++) {
179 channel[i].peak_l = -100;
180 channel[i].peak_r = -100;
181 channel[i].prev_active = true;
182 }
183
184 set_process(is_visible_in_tree());
185 } break;
186
187 case NOTIFICATION_MOUSE_EXIT:
188 case NOTIFICATION_DRAG_END: {
189 if (hovering_drop) {
190 hovering_drop = false;
191 queue_redraw();
192 }
193 } break;
194 }
195}
196
197void EditorAudioBus::update_send() {
198 send->clear();
199 if (is_master) {
200 send->set_disabled(true);
201 send->set_text(TTR("Speakers"));
202 } else {
203 send->set_disabled(false);
204 StringName current_send = AudioServer::get_singleton()->get_bus_send(get_index());
205 int current_send_index = 0; //by default to master
206
207 for (int i = 0; i < get_index(); i++) {
208 StringName send_name = AudioServer::get_singleton()->get_bus_name(i);
209 send->add_item(send_name);
210 if (send_name == current_send) {
211 current_send_index = i;
212 }
213 }
214
215 send->select(current_send_index);
216 }
217}
218
219void EditorAudioBus::update_bus() {
220 if (updating_bus) {
221 return;
222 }
223
224 updating_bus = true;
225
226 int index = get_index();
227
228 float db_value = AudioServer::get_singleton()->get_bus_volume_db(index);
229 slider->set_value(_scaled_db_to_normalized_volume(db_value));
230 track_name->set_text(AudioServer::get_singleton()->get_bus_name(index));
231 if (is_master) {
232 track_name->set_editable(false);
233 }
234
235 solo->set_pressed(AudioServer::get_singleton()->is_bus_solo(index));
236 mute->set_pressed(AudioServer::get_singleton()->is_bus_mute(index));
237 bypass->set_pressed(AudioServer::get_singleton()->is_bus_bypassing_effects(index));
238 // effects..
239 effects->clear();
240
241 TreeItem *root = effects->create_item();
242 for (int i = 0; i < AudioServer::get_singleton()->get_bus_effect_count(index); i++) {
243 Ref<AudioEffect> afx = AudioServer::get_singleton()->get_bus_effect(index, i);
244
245 TreeItem *fx = effects->create_item(root);
246 fx->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
247 fx->set_editable(0, true);
248 fx->set_checked(0, AudioServer::get_singleton()->is_bus_effect_enabled(index, i));
249 fx->set_text(0, afx->get_name());
250 fx->set_metadata(0, i);
251 }
252
253 TreeItem *add = effects->create_item(root);
254 add->set_cell_mode(0, TreeItem::CELL_MODE_CUSTOM);
255 add->set_editable(0, true);
256 add->set_selectable(0, false);
257 add->set_text(0, TTR("Add Effect"));
258
259 update_send();
260
261 updating_bus = false;
262}
263
264void EditorAudioBus::_name_changed(const String &p_new_name) {
265 if (updating_bus) {
266 return;
267 }
268 updating_bus = true;
269 track_name->release_focus();
270
271 if (p_new_name == AudioServer::get_singleton()->get_bus_name(get_index())) {
272 updating_bus = false;
273 return;
274 }
275
276 String attempt = p_new_name;
277 int attempts = 1;
278
279 while (true) {
280 bool name_free = true;
281 for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
282 if (AudioServer::get_singleton()->get_bus_name(i) == attempt) {
283 name_free = false;
284 break;
285 }
286 }
287
288 if (name_free) {
289 break;
290 }
291
292 attempts++;
293 attempt = p_new_name + " " + itos(attempts);
294 }
295
296 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
297
298 StringName current = AudioServer::get_singleton()->get_bus_name(get_index());
299
300 ur->create_action(TTR("Rename Audio Bus"));
301 ur->add_do_method(buses, "_set_renaming_buses", true);
302 ur->add_undo_method(buses, "_set_renaming_buses", true);
303
304 ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", get_index(), attempt);
305 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_name", get_index(), current);
306
307 for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
308 if (AudioServer::get_singleton()->get_bus_send(i) == current) {
309 ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", i, attempt);
310 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", i, current);
311 }
312 }
313
314 ur->add_do_method(buses, "_update_bus", get_index());
315 ur->add_undo_method(buses, "_update_bus", get_index());
316
317 ur->add_do_method(buses, "_update_sends");
318 ur->add_undo_method(buses, "_update_sends");
319
320 ur->add_do_method(buses, "_set_renaming_buses", false);
321 ur->add_undo_method(buses, "_set_renaming_buses", false);
322 ur->commit_action();
323
324 updating_bus = false;
325}
326
327void EditorAudioBus::_volume_changed(float p_normalized) {
328 if (updating_bus) {
329 return;
330 }
331
332 updating_bus = true;
333
334 const float p_db = this->_normalized_volume_to_scaled_db(p_normalized);
335
336 if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
337 // Snap the value when holding Ctrl for easier editing.
338 // To do so, it needs to be converted back to normalized volume (as the slider uses that unit).
339 slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db)));
340 }
341
342 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
343 ur->create_action(TTR("Change Audio Bus Volume"), UndoRedo::MERGE_ENDS);
344 ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), p_db);
345 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), AudioServer::get_singleton()->get_bus_volume_db(get_index()));
346 ur->add_do_method(buses, "_update_bus", get_index());
347 ur->add_undo_method(buses, "_update_bus", get_index());
348 ur->commit_action();
349
350 updating_bus = false;
351}
352
353float EditorAudioBus::_normalized_volume_to_scaled_db(float normalized) {
354 /* There are three different formulas for the conversion from normalized
355 * values to relative decibal values.
356 * One formula is an exponential graph which intends to counteract
357 * the logarithmic nature of human hearing. This is an approximation
358 * of the behavior of a 'logarithmic potentiometer' found on most
359 * musical instruments and also emulated in popular software.
360 * The other two equations are hand-tuned linear tapers that intend to
361 * try to ease the exponential equation in areas where it makes sense.*/
362
363 if (normalized > 0.6f) {
364 return 22.22f * normalized - 16.2f;
365 } else if (normalized < 0.05f) {
366 return 830.72 * normalized - 80.0f;
367 } else {
368 return 45.0f * Math::pow(normalized - 1.0, 3);
369 }
370}
371
372float EditorAudioBus::_scaled_db_to_normalized_volume(float db) {
373 /* Inversion of equations found in _normalized_volume_to_scaled_db.
374 * IMPORTANT: If one function changes, the other much change to reflect it. */
375 if (db > -2.88) {
376 return (db + 16.2f) / 22.22f;
377 } else if (db < -38.602f) {
378 return (db + 80.00f) / 830.72f;
379 } else {
380 if (db < 0.0) {
381 /* To accommodate for NaN on negative numbers for root, we will mirror the
382 * results of the positive db range in order to get the desired numerical
383 * value on the negative side. */
384 float positive_x = Math::pow(Math::abs(db) / 45.0f, 1.0f / 3.0f) + 1.0f;
385 Vector2 translation = Vector2(1.0f, 0.0f) - Vector2(positive_x, Math::abs(db));
386 Vector2 reflected_position = Vector2(1.0, 0.0f) + translation;
387 return reflected_position.x;
388 } else {
389 return Math::pow(db / 45.0f, 1.0f / 3.0f) + 1.0f;
390 }
391 }
392}
393
394void EditorAudioBus::_show_value(float slider_value) {
395 float db;
396 if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
397 // Display the correct (snapped) value when holding Ctrl
398 db = Math::round(_normalized_volume_to_scaled_db(slider_value));
399 } else {
400 db = _normalized_volume_to_scaled_db(slider_value);
401 }
402
403 String text;
404 if (Math::is_zero_approx(Math::snapped(db, 0.1))) {
405 // Prevent displaying `-0.0 dB` and show ` 0.0 dB` instead.
406 // The leading space makes the text visually line up with its positive/negative counterparts.
407 text = " 0.0 dB";
408 } else {
409 // Show an explicit `+` sign if positive.
410 text = vformat("%+.1f dB", db);
411 }
412
413 // Also set the preview text as a standard Control tooltip.
414 // This way, it can be seen when the slider is merely hovered (instead of dragged).
415 slider->set_tooltip_text(text);
416 audio_value_preview_label->set_text(text);
417 const Vector2 slider_size = slider->get_size();
418 const Vector2 slider_position = slider->get_global_position();
419 const float vert_padding = 10.0f;
420 const Vector2 box_position = Vector2(slider_size.x, (slider_size.y - vert_padding) * (1.0f - slider->get_value()) - vert_padding);
421 audio_value_preview_box->set_position(slider_position + box_position);
422 audio_value_preview_box->set_size(audio_value_preview_label->get_size());
423 if (slider->has_focus() && !audio_value_preview_box->is_visible()) {
424 audio_value_preview_box->show();
425 }
426 preview_timer->start();
427}
428
429void EditorAudioBus::_hide_value_preview() {
430 audio_value_preview_box->hide();
431}
432
433void EditorAudioBus::_solo_toggled() {
434 updating_bus = true;
435
436 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
437 ur->create_action(TTR("Toggle Audio Bus Solo"));
438 ur->add_do_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), solo->is_pressed());
439 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), AudioServer::get_singleton()->is_bus_solo(get_index()));
440 ur->add_do_method(buses, "_update_bus", get_index());
441 ur->add_undo_method(buses, "_update_bus", get_index());
442 ur->commit_action();
443
444 updating_bus = false;
445}
446
447void EditorAudioBus::_mute_toggled() {
448 updating_bus = true;
449
450 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
451 ur->create_action(TTR("Toggle Audio Bus Mute"));
452 ur->add_do_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), mute->is_pressed());
453 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), AudioServer::get_singleton()->is_bus_mute(get_index()));
454 ur->add_do_method(buses, "_update_bus", get_index());
455 ur->add_undo_method(buses, "_update_bus", get_index());
456 ur->commit_action();
457
458 updating_bus = false;
459}
460
461void EditorAudioBus::_bypass_toggled() {
462 updating_bus = true;
463
464 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
465 ur->create_action(TTR("Toggle Audio Bus Bypass Effects"));
466 ur->add_do_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), bypass->is_pressed());
467 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), AudioServer::get_singleton()->is_bus_bypassing_effects(get_index()));
468 ur->add_do_method(buses, "_update_bus", get_index());
469 ur->add_undo_method(buses, "_update_bus", get_index());
470 ur->commit_action();
471
472 updating_bus = false;
473}
474
475void EditorAudioBus::_send_selected(int p_which) {
476 updating_bus = true;
477
478 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
479 ur->create_action(TTR("Select Audio Bus Send"));
480 ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", get_index(), send->get_item_text(p_which));
481 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", get_index(), AudioServer::get_singleton()->get_bus_send(get_index()));
482 ur->add_do_method(buses, "_update_bus", get_index());
483 ur->add_undo_method(buses, "_update_bus", get_index());
484 ur->commit_action();
485
486 updating_bus = false;
487}
488
489void EditorAudioBus::_effect_selected() {
490 TreeItem *effect = effects->get_selected();
491 if (!effect) {
492 return;
493 }
494 updating_bus = true;
495
496 if (effect->get_metadata(0) != Variant()) {
497 int index = effect->get_metadata(0);
498 Ref<AudioEffect> effect2 = AudioServer::get_singleton()->get_bus_effect(get_index(), index);
499 if (effect2.is_valid()) {
500 EditorNode::get_singleton()->push_item(effect2.ptr());
501 }
502 }
503
504 updating_bus = false;
505}
506
507void EditorAudioBus::_effect_edited() {
508 if (updating_bus) {
509 return;
510 }
511
512 TreeItem *effect = effects->get_edited();
513 if (!effect) {
514 return;
515 }
516
517 if (effect->get_metadata(0) == Variant()) {
518 Rect2 area = effects->get_item_rect(effect);
519
520 effect_options->set_position(effects->get_screen_position() + area.position + Vector2(0, area.size.y));
521 effect_options->reset_size();
522 effect_options->popup();
523 //add effect
524 } else {
525 int index = effect->get_metadata(0);
526 updating_bus = true;
527
528 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
529 ur->create_action(TTR("Select Audio Bus Send"));
530 ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, effect->is_checked(0));
531 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, AudioServer::get_singleton()->is_bus_effect_enabled(get_index(), index));
532 ur->add_do_method(buses, "_update_bus", get_index());
533 ur->add_undo_method(buses, "_update_bus", get_index());
534 ur->commit_action();
535
536 updating_bus = false;
537 }
538}
539
540void EditorAudioBus::_effect_add(int p_which) {
541 if (updating_bus) {
542 return;
543 }
544
545 StringName name = effect_options->get_item_metadata(p_which);
546
547 Object *fx = ClassDB::instantiate(name);
548 ERR_FAIL_NULL(fx);
549 AudioEffect *afx = Object::cast_to<AudioEffect>(fx);
550 ERR_FAIL_NULL(afx);
551 Ref<AudioEffect> afxr = Ref<AudioEffect>(afx);
552
553 afxr->set_name(effect_options->get_item_text(p_which));
554
555 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
556 ur->create_action(TTR("Add Audio Bus Effect"));
557 ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), afxr, -1);
558 ur->add_undo_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect_count(get_index()));
559 ur->add_do_method(buses, "_update_bus", get_index());
560 ur->add_undo_method(buses, "_update_bus", get_index());
561 ur->commit_action();
562}
563
564void EditorAudioBus::gui_input(const Ref<InputEvent> &p_event) {
565 ERR_FAIL_COND(p_event.is_null());
566
567 Ref<InputEventMouseButton> mb = p_event;
568 if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
569 bus_popup->set_position(get_screen_position() + mb->get_position());
570 bus_popup->reset_size();
571 bus_popup->popup();
572 }
573}
574
575void EditorAudioBus::_effects_gui_input(Ref<InputEvent> p_event) {
576 Ref<InputEventKey> k = p_event;
577 if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == Key::KEY_DELETE) {
578 TreeItem *current_effect = effects->get_selected();
579 if (current_effect && current_effect->get_metadata(0).get_type() == Variant::INT) {
580 _delete_effect_pressed(0);
581 accept_event();
582 }
583 }
584}
585
586void EditorAudioBus::_bus_popup_pressed(int p_option) {
587 if (p_option == 2) {
588 // Reset volume
589 emit_signal(SNAME("vol_reset_request"));
590 } else if (p_option == 1) {
591 emit_signal(SNAME("delete_request"));
592 } else if (p_option == 0) {
593 //duplicate
594 emit_signal(SNAME("duplicate_request"), get_index());
595 }
596}
597
598Variant EditorAudioBus::get_drag_data(const Point2 &p_point) {
599 if (get_index() == 0) {
600 return Variant();
601 }
602
603 Control *c = memnew(Control);
604 Panel *p = memnew(Panel);
605 c->add_child(p);
606 p->set_modulate(Color(1, 1, 1, 0.7));
607 p->add_theme_style_override("panel", get_theme_stylebox(SNAME("focus"), SNAME("Button")));
608 p->set_size(get_size());
609 p->set_position(-p_point);
610 set_drag_preview(c);
611 Dictionary d;
612 d["type"] = "move_audio_bus";
613 d["index"] = get_index();
614
615 if (get_index() < AudioServer::get_singleton()->get_bus_count() - 1) {
616 emit_signal(SNAME("drop_end_request"));
617 }
618
619 return d;
620}
621
622bool EditorAudioBus::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
623 if (get_index() == 0) {
624 return false;
625 }
626
627 Dictionary d = p_data;
628 if (d.has("type") && String(d["type"]) == "move_audio_bus" && (int)d["index"] != get_index()) {
629 hovering_drop = true;
630 return true;
631 }
632
633 return false;
634}
635
636void EditorAudioBus::drop_data(const Point2 &p_point, const Variant &p_data) {
637 Dictionary d = p_data;
638 emit_signal(SNAME("dropped"), d["index"], get_index());
639}
640
641Variant EditorAudioBus::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
642 TreeItem *item = effects->get_item_at_position(p_point);
643 if (!item) {
644 return Variant();
645 }
646
647 Variant md = item->get_metadata(0);
648 if (md.get_type() == Variant::INT) {
649 Dictionary fxd;
650 fxd["type"] = "audio_bus_effect";
651 fxd["bus"] = get_index();
652 fxd["effect"] = md;
653
654 Label *l = memnew(Label);
655 l->set_text(item->get_text(0));
656 effects->set_drag_preview(l);
657
658 return fxd;
659 }
660
661 return Variant();
662}
663
664bool EditorAudioBus::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
665 Dictionary d = p_data;
666 if (!d.has("type") || String(d["type"]) != "audio_bus_effect") {
667 return false;
668 }
669
670 TreeItem *item = effects->get_item_at_position(p_point);
671 if (!item) {
672 return false;
673 }
674
675 effects->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);
676
677 return true;
678}
679
680void EditorAudioBus::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
681 Dictionary d = p_data;
682
683 TreeItem *item = effects->get_item_at_position(p_point);
684 if (!item) {
685 return;
686 }
687 int pos = effects->get_drop_section_at_position(p_point);
688 Variant md = item->get_metadata(0);
689
690 int paste_at;
691 int bus = d["bus"];
692 int effect = d["effect"];
693
694 if (md.get_type() == Variant::INT) {
695 paste_at = md;
696 if (pos > 0) {
697 paste_at++;
698 }
699
700 if (bus == get_index() && paste_at > effect) {
701 paste_at--;
702 }
703 } else {
704 paste_at = -1;
705 }
706
707 bool enabled = AudioServer::get_singleton()->is_bus_effect_enabled(bus, effect);
708
709 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
710 ur->create_action(TTR("Move Bus Effect"));
711 ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", bus, effect);
712 ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(bus, effect), paste_at);
713
714 if (paste_at == -1) {
715 paste_at = AudioServer::get_singleton()->get_bus_effect_count(get_index());
716 if (bus == get_index()) {
717 paste_at--;
718 }
719 }
720 if (!enabled) {
721 ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), paste_at, false);
722 }
723
724 ur->add_undo_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), paste_at);
725 ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", bus, AudioServer::get_singleton()->get_bus_effect(bus, effect), effect);
726 if (!enabled) {
727 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", bus, effect, false);
728 }
729
730 ur->add_do_method(buses, "_update_bus", get_index());
731 ur->add_undo_method(buses, "_update_bus", get_index());
732 if (get_index() != bus) {
733 ur->add_do_method(buses, "_update_bus", bus);
734 ur->add_undo_method(buses, "_update_bus", bus);
735 }
736 ur->commit_action();
737}
738
739void EditorAudioBus::_delete_effect_pressed(int p_option) {
740 TreeItem *item = effects->get_selected();
741 if (!item) {
742 return;
743 }
744
745 if (item->get_metadata(0).get_type() != Variant::INT) {
746 return;
747 }
748
749 int index = item->get_metadata(0);
750
751 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
752 ur->create_action(TTR("Delete Bus Effect"));
753 ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), index);
754 ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(get_index(), index), index);
755 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, AudioServer::get_singleton()->is_bus_effect_enabled(get_index(), index));
756 ur->add_do_method(buses, "_update_bus", get_index());
757 ur->add_undo_method(buses, "_update_bus", get_index());
758 ur->commit_action();
759}
760
761void EditorAudioBus::_effect_rmb(const Vector2 &p_pos, MouseButton p_button) {
762 if (p_button != MouseButton::RIGHT) {
763 return;
764 }
765
766 TreeItem *item = effects->get_selected();
767 if (!item) {
768 return;
769 }
770
771 if (item->get_metadata(0).get_type() != Variant::INT) {
772 return;
773 }
774
775 delete_effect_popup->set_position(get_screen_position() + get_local_mouse_position());
776 delete_effect_popup->reset_size();
777 delete_effect_popup->popup();
778}
779
780void EditorAudioBus::_bind_methods() {
781 ClassDB::bind_method("update_bus", &EditorAudioBus::update_bus);
782 ClassDB::bind_method("update_send", &EditorAudioBus::update_send);
783
784 ADD_SIGNAL(MethodInfo("duplicate_request"));
785 ADD_SIGNAL(MethodInfo("delete_request"));
786 ADD_SIGNAL(MethodInfo("vol_reset_request"));
787 ADD_SIGNAL(MethodInfo("drop_end_request"));
788 ADD_SIGNAL(MethodInfo("dropped"));
789}
790
791EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
792 buses = p_buses;
793 is_master = p_is_master;
794
795 set_tooltip_text(TTR("Drag & drop to rearrange."));
796
797 VBoxContainer *vb = memnew(VBoxContainer);
798 add_child(vb);
799
800 set_v_size_flags(SIZE_EXPAND_FILL);
801
802 track_name = memnew(LineEdit);
803 track_name->connect("text_submitted", callable_mp(this, &EditorAudioBus::_name_changed));
804 track_name->connect("focus_exited", callable_mp(this, &EditorAudioBus::_name_focus_exit));
805 vb->add_child(track_name);
806
807 HBoxContainer *hbc = memnew(HBoxContainer);
808 vb->add_child(hbc);
809 solo = memnew(Button);
810 solo->set_flat(true);
811 solo->set_toggle_mode(true);
812 solo->set_tooltip_text(TTR("Solo"));
813 solo->set_focus_mode(FOCUS_NONE);
814 solo->connect("pressed", callable_mp(this, &EditorAudioBus::_solo_toggled));
815 hbc->add_child(solo);
816 mute = memnew(Button);
817 mute->set_flat(true);
818 mute->set_toggle_mode(true);
819 mute->set_tooltip_text(TTR("Mute"));
820 mute->set_focus_mode(FOCUS_NONE);
821 mute->connect("pressed", callable_mp(this, &EditorAudioBus::_mute_toggled));
822 hbc->add_child(mute);
823 bypass = memnew(Button);
824 bypass->set_flat(true);
825 bypass->set_toggle_mode(true);
826 bypass->set_tooltip_text(TTR("Bypass"));
827 bypass->set_focus_mode(FOCUS_NONE);
828 bypass->connect("pressed", callable_mp(this, &EditorAudioBus::_bypass_toggled));
829 hbc->add_child(bypass);
830 hbc->add_spacer();
831
832 Ref<StyleBoxEmpty> sbempty = memnew(StyleBoxEmpty);
833 for (int i = 0; i < hbc->get_child_count(); i++) {
834 Control *child = Object::cast_to<Control>(hbc->get_child(i));
835 child->add_theme_style_override("normal", sbempty);
836 child->add_theme_style_override("hover", sbempty);
837 child->add_theme_style_override("focus", sbempty);
838 child->add_theme_style_override("pressed", sbempty);
839 }
840
841 HSeparator *separator = memnew(HSeparator);
842 separator->set_mouse_filter(MOUSE_FILTER_PASS);
843 vb->add_child(separator);
844
845 HBoxContainer *hb = memnew(HBoxContainer);
846 vb->add_child(hb);
847 slider = memnew(VSlider);
848 slider->set_min(0.0);
849 slider->set_max(1.0);
850 slider->set_step(0.0001);
851 slider->set_clip_contents(false);
852
853 audio_value_preview_box = memnew(Panel);
854 slider->add_child(audio_value_preview_box);
855 audio_value_preview_box->set_as_top_level(true);
856 audio_value_preview_box->set_mouse_filter(MOUSE_FILTER_PASS);
857 audio_value_preview_box->hide();
858
859 HBoxContainer *audioprev_hbc = memnew(HBoxContainer);
860 audioprev_hbc->set_v_size_flags(SIZE_EXPAND_FILL);
861 audioprev_hbc->set_h_size_flags(SIZE_EXPAND_FILL);
862 audio_value_preview_box->add_child(audioprev_hbc);
863
864 audio_value_preview_label = memnew(Label);
865 audio_value_preview_label->set_v_size_flags(SIZE_EXPAND_FILL);
866 audio_value_preview_label->set_h_size_flags(SIZE_EXPAND_FILL);
867 audio_value_preview_label->set_mouse_filter(MOUSE_FILTER_PASS);
868 audioprev_hbc->add_child(audio_value_preview_label);
869
870 preview_timer = memnew(Timer);
871 preview_timer->set_wait_time(0.8f);
872 preview_timer->set_one_shot(true);
873 add_child(preview_timer);
874
875 slider->connect("value_changed", callable_mp(this, &EditorAudioBus::_volume_changed));
876 slider->connect("value_changed", callable_mp(this, &EditorAudioBus::_show_value));
877 preview_timer->connect("timeout", callable_mp(this, &EditorAudioBus::_hide_value_preview));
878 hb->add_child(slider);
879
880 cc = 0;
881 for (int i = 0; i < CHANNELS_MAX; i++) {
882 channel[i].vu_l = memnew(TextureProgressBar);
883 channel[i].vu_l->set_fill_mode(TextureProgressBar::FILL_BOTTOM_TO_TOP);
884 hb->add_child(channel[i].vu_l);
885 channel[i].vu_l->set_min(-80);
886 channel[i].vu_l->set_max(24);
887 channel[i].vu_l->set_step(0.1);
888
889 channel[i].vu_r = memnew(TextureProgressBar);
890 channel[i].vu_r->set_fill_mode(TextureProgressBar::FILL_BOTTOM_TO_TOP);
891 hb->add_child(channel[i].vu_r);
892 channel[i].vu_r->set_min(-80);
893 channel[i].vu_r->set_max(24);
894 channel[i].vu_r->set_step(0.1);
895
896 channel[i].peak_l = 0.0f;
897 channel[i].peak_r = 0.0f;
898 }
899
900 EditorAudioMeterNotches *scale = memnew(EditorAudioMeterNotches);
901
902 for (float db = 6.0f; db >= -80.0f; db -= 6.0f) {
903 bool renderNotch = (db >= -6.0f || db == -24.0f || db == -72.0f);
904 scale->add_notch(_scaled_db_to_normalized_volume(db), db, renderNotch);
905 }
906 scale->set_mouse_filter(MOUSE_FILTER_PASS);
907 hb->add_child(scale);
908
909 effects = memnew(Tree);
910 effects->set_hide_root(true);
911 effects->set_custom_minimum_size(Size2(0, 80) * EDSCALE);
912 effects->set_hide_folding(true);
913 effects->set_v_size_flags(SIZE_EXPAND_FILL);
914 vb->add_child(effects);
915 effects->connect("item_edited", callable_mp(this, &EditorAudioBus::_effect_edited));
916 effects->connect("cell_selected", callable_mp(this, &EditorAudioBus::_effect_selected));
917 effects->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
918 SET_DRAG_FORWARDING_GCD(effects, EditorAudioBus);
919 effects->connect("item_mouse_selected", callable_mp(this, &EditorAudioBus::_effect_rmb));
920 effects->set_allow_rmb_select(true);
921 effects->set_focus_mode(FOCUS_CLICK);
922 effects->set_allow_reselect(true);
923 effects->connect("gui_input", callable_mp(this, &EditorAudioBus::_effects_gui_input));
924
925 send = memnew(OptionButton);
926 send->set_clip_text(true);
927 send->connect("item_selected", callable_mp(this, &EditorAudioBus::_send_selected));
928 vb->add_child(send);
929
930 set_focus_mode(FOCUS_CLICK);
931
932 effect_options = memnew(PopupMenu);
933 effect_options->connect("index_pressed", callable_mp(this, &EditorAudioBus::_effect_add));
934 add_child(effect_options);
935 List<StringName> effect_list;
936 ClassDB::get_inheriters_from_class("AudioEffect", &effect_list);
937 effect_list.sort_custom<StringName::AlphCompare>();
938 for (const StringName &E : effect_list) {
939 if (!ClassDB::can_instantiate(E) || ClassDB::is_virtual(E)) {
940 continue;
941 }
942
943 String name = E.operator String().replace("AudioEffect", "");
944 effect_options->add_item(name);
945 effect_options->set_item_metadata(-1, E);
946 }
947
948 bus_options = memnew(MenuButton);
949 bus_options->set_shortcut_context(this);
950 bus_options->set_h_size_flags(SIZE_SHRINK_END);
951 bus_options->set_anchor(SIDE_RIGHT, 0.0);
952 bus_options->set_tooltip_text(TTR("Bus Options"));
953 hbc->add_child(bus_options);
954
955 bus_popup = bus_options->get_popup();
956 bus_popup->add_shortcut(ED_SHORTCUT("audio_bus_editor/duplicate_selected_bus", TTR("Duplicate Bus"), KeyModifierMask::CMD_OR_CTRL | Key::D));
957 bus_popup->add_shortcut(ED_SHORTCUT("audio_bus_editor/delete_selected_bus", TTR("Delete Bus"), Key::KEY_DELETE));
958 bus_popup->set_item_disabled(1, is_master);
959 bus_popup->add_item(TTR("Reset Volume"));
960 bus_popup->connect("index_pressed", callable_mp(this, &EditorAudioBus::_bus_popup_pressed));
961
962 delete_effect_popup = memnew(PopupMenu);
963 delete_effect_popup->add_item(TTR("Delete Effect"));
964 add_child(delete_effect_popup);
965 delete_effect_popup->connect("index_pressed", callable_mp(this, &EditorAudioBus::_delete_effect_pressed));
966}
967
968void EditorAudioBusDrop::_notification(int p_what) {
969 switch (p_what) {
970 case NOTIFICATION_DRAW: {
971 draw_style_box(get_theme_stylebox(SNAME("normal"), SNAME("Button")), Rect2(Vector2(), get_size()));
972
973 if (hovering_drop) {
974 Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
975 accent.a *= 0.7;
976 draw_rect(Rect2(Point2(), get_size()), accent, false);
977 }
978 } break;
979
980 case NOTIFICATION_MOUSE_ENTER: {
981 if (!hovering_drop) {
982 hovering_drop = true;
983 queue_redraw();
984 }
985 } break;
986
987 case NOTIFICATION_MOUSE_EXIT:
988 case NOTIFICATION_DRAG_END: {
989 if (hovering_drop) {
990 hovering_drop = false;
991 queue_redraw();
992 }
993 } break;
994 }
995}
996
997bool EditorAudioBusDrop::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
998 Dictionary d = p_data;
999 return (d.has("type") && String(d["type"]) == "move_audio_bus");
1000}
1001
1002void EditorAudioBusDrop::drop_data(const Point2 &p_point, const Variant &p_data) {
1003 Dictionary d = p_data;
1004 emit_signal(SNAME("dropped"), d["index"], AudioServer::get_singleton()->get_bus_count());
1005}
1006
1007void EditorAudioBusDrop::_bind_methods() {
1008 ADD_SIGNAL(MethodInfo("dropped"));
1009}
1010
1011EditorAudioBusDrop::EditorAudioBusDrop() {
1012}
1013
1014void EditorAudioBuses::_set_renaming_buses(bool p_renaming) {
1015 renaming_buses = p_renaming;
1016}
1017
1018void EditorAudioBuses::_update_buses() {
1019 if (renaming_buses) {
1020 // This case will be handled more gracefully, no need to trigger a full rebuild.
1021 // This is possibly a mistake in the AudioServer, which fires bus_layout_changed
1022 // on a rename. This may not be intended, but no way to tell at the moment.
1023 return;
1024 }
1025
1026 for (int i = bus_hb->get_child_count() - 1; i >= 0; i--) {
1027 EditorAudioBus *audio_bus = Object::cast_to<EditorAudioBus>(bus_hb->get_child(i));
1028 if (audio_bus) {
1029 bus_hb->remove_child(audio_bus);
1030 audio_bus->queue_free();
1031 }
1032 }
1033
1034 if (drop_end) {
1035 bus_hb->remove_child(drop_end);
1036 drop_end->queue_free();
1037 drop_end = nullptr;
1038 }
1039
1040 for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
1041 bool is_master = (i == 0);
1042 EditorAudioBus *audio_bus = memnew(EditorAudioBus(this, is_master));
1043 bus_hb->add_child(audio_bus);
1044 audio_bus->connect("delete_request", callable_mp(this, &EditorAudioBuses::_delete_bus).bind(audio_bus), CONNECT_DEFERRED);
1045 audio_bus->connect("duplicate_request", callable_mp(this, &EditorAudioBuses::_duplicate_bus), CONNECT_DEFERRED);
1046 audio_bus->connect("vol_reset_request", callable_mp(this, &EditorAudioBuses::_reset_bus_volume).bind(audio_bus), CONNECT_DEFERRED);
1047 audio_bus->connect("drop_end_request", callable_mp(this, &EditorAudioBuses::_request_drop_end));
1048 audio_bus->connect("dropped", callable_mp(this, &EditorAudioBuses::_drop_at_index), CONNECT_DEFERRED);
1049 }
1050}
1051
1052EditorAudioBuses *EditorAudioBuses::register_editor() {
1053 EditorAudioBuses *audio_buses = memnew(EditorAudioBuses);
1054 EditorNode::get_singleton()->add_bottom_panel_item(TTR("Audio"), audio_buses);
1055 return audio_buses;
1056}
1057
1058void EditorAudioBuses::_notification(int p_what) {
1059 switch (p_what) {
1060 case NOTIFICATION_ENTER_TREE:
1061 case NOTIFICATION_THEME_CHANGED: {
1062 bus_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
1063 } break;
1064
1065 case NOTIFICATION_READY: {
1066 _update_buses();
1067 } break;
1068
1069 case NOTIFICATION_DRAG_END: {
1070 if (drop_end) {
1071 bus_hb->remove_child(drop_end);
1072 drop_end->queue_free();
1073 drop_end = nullptr;
1074 }
1075 } break;
1076
1077 case NOTIFICATION_PROCESS: {
1078 // Check if anything was edited.
1079 bool edited = AudioServer::get_singleton()->is_edited();
1080 for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
1081 for (int j = 0; j < AudioServer::get_singleton()->get_bus_effect_count(i); j++) {
1082 Ref<AudioEffect> effect = AudioServer::get_singleton()->get_bus_effect(i, j);
1083 if (effect->is_edited()) {
1084 edited = true;
1085 effect->set_edited(false);
1086 }
1087 }
1088 }
1089
1090 AudioServer::get_singleton()->set_edited(false);
1091
1092 if (edited) {
1093 save_timer->start();
1094 }
1095 } break;
1096 }
1097}
1098
1099void EditorAudioBuses::_add_bus() {
1100 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
1101
1102 ur->create_action(TTR("Add Audio Bus"));
1103 ur->add_do_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count() + 1);
1104 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count());
1105 ur->add_do_method(this, "_update_buses");
1106 ur->add_undo_method(this, "_update_buses");
1107 ur->commit_action();
1108}
1109
1110void EditorAudioBuses::_update_bus(int p_index) {
1111 if (p_index >= bus_hb->get_child_count()) {
1112 return;
1113 }
1114
1115 bus_hb->get_child(p_index)->call("update_bus");
1116}
1117
1118void EditorAudioBuses::_update_sends() {
1119 for (int i = 0; i < bus_hb->get_child_count(); i++) {
1120 bus_hb->get_child(i)->call("update_send");
1121 }
1122}
1123
1124void EditorAudioBuses::_delete_bus(Object *p_which) {
1125 EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which);
1126 int index = bus->get_index();
1127 if (index == 0) {
1128 EditorNode::get_singleton()->show_warning(TTR("Master bus can't be deleted!"));
1129 return;
1130 }
1131
1132 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
1133
1134 ur->create_action(TTR("Delete Audio Bus"));
1135 ur->add_do_method(AudioServer::get_singleton(), "remove_bus", index);
1136 ur->add_undo_method(AudioServer::get_singleton(), "add_bus", index);
1137 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_name", index, AudioServer::get_singleton()->get_bus_name(index));
1138 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", index, AudioServer::get_singleton()->get_bus_volume_db(index));
1139 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", index, AudioServer::get_singleton()->get_bus_send(index));
1140 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_solo", index, AudioServer::get_singleton()->is_bus_solo(index));
1141 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_mute", index, AudioServer::get_singleton()->is_bus_mute(index));
1142 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_bypass_effects", index, AudioServer::get_singleton()->is_bus_bypassing_effects(index));
1143 for (int i = 0; i < AudioServer::get_singleton()->get_bus_effect_count(index); i++) {
1144 ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", index, AudioServer::get_singleton()->get_bus_effect(index, i));
1145 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", index, i, AudioServer::get_singleton()->is_bus_effect_enabled(index, i));
1146 }
1147 ur->add_do_method(this, "_update_buses");
1148 ur->add_undo_method(this, "_update_buses");
1149 ur->commit_action();
1150}
1151
1152void EditorAudioBuses::_duplicate_bus(int p_which) {
1153 int add_at_pos = p_which + 1;
1154 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
1155 ur->create_action(TTR("Duplicate Audio Bus"));
1156 ur->add_do_method(AudioServer::get_singleton(), "add_bus", add_at_pos);
1157 ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", add_at_pos, AudioServer::get_singleton()->get_bus_name(p_which) + " Copy");
1158 ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", add_at_pos, AudioServer::get_singleton()->get_bus_volume_db(p_which));
1159 ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", add_at_pos, AudioServer::get_singleton()->get_bus_send(p_which));
1160 ur->add_do_method(AudioServer::get_singleton(), "set_bus_solo", add_at_pos, AudioServer::get_singleton()->is_bus_solo(p_which));
1161 ur->add_do_method(AudioServer::get_singleton(), "set_bus_mute", add_at_pos, AudioServer::get_singleton()->is_bus_mute(p_which));
1162 ur->add_do_method(AudioServer::get_singleton(), "set_bus_bypass_effects", add_at_pos, AudioServer::get_singleton()->is_bus_bypassing_effects(p_which));
1163 for (int i = 0; i < AudioServer::get_singleton()->get_bus_effect_count(p_which); i++) {
1164 ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", add_at_pos, AudioServer::get_singleton()->get_bus_effect(p_which, i));
1165 ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", add_at_pos, i, AudioServer::get_singleton()->is_bus_effect_enabled(p_which, i));
1166 }
1167 ur->add_undo_method(AudioServer::get_singleton(), "remove_bus", add_at_pos);
1168 ur->add_do_method(this, "_update_buses");
1169 ur->add_undo_method(this, "_update_buses");
1170 ur->commit_action();
1171}
1172
1173void EditorAudioBuses::_reset_bus_volume(Object *p_which) {
1174 EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which);
1175 int index = bus->get_index();
1176
1177 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
1178 ur->create_action(TTR("Reset Bus Volume"));
1179 ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", index, 0.f);
1180 ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", index, AudioServer::get_singleton()->get_bus_volume_db(index));
1181 ur->add_do_method(this, "_update_buses");
1182 ur->add_undo_method(this, "_update_buses");
1183 ur->commit_action();
1184}
1185
1186void EditorAudioBuses::_request_drop_end() {
1187 if (!drop_end && bus_hb->get_child_count()) {
1188 drop_end = memnew(EditorAudioBusDrop);
1189
1190 bus_hb->add_child(drop_end);
1191 drop_end->set_custom_minimum_size(Object::cast_to<Control>(bus_hb->get_child(0))->get_size());
1192 drop_end->connect("dropped", callable_mp(this, &EditorAudioBuses::_drop_at_index), CONNECT_DEFERRED);
1193 }
1194}
1195
1196void EditorAudioBuses::_drop_at_index(int p_bus, int p_index) {
1197 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
1198 ur->create_action(TTR("Move Audio Bus"));
1199
1200 ur->add_do_method(AudioServer::get_singleton(), "move_bus", p_bus, p_index);
1201 int real_bus = p_index > p_bus ? p_bus : p_bus + 1;
1202 int real_index = p_index > p_bus ? p_index - 1 : p_index;
1203 ur->add_undo_method(AudioServer::get_singleton(), "move_bus", real_index, real_bus);
1204
1205 ur->add_do_method(this, "_update_buses");
1206 ur->add_undo_method(this, "_update_buses");
1207 ur->commit_action();
1208}
1209
1210void EditorAudioBuses::_server_save() {
1211 Ref<AudioBusLayout> state = AudioServer::get_singleton()->generate_bus_layout();
1212 ResourceSaver::save(state, edited_path);
1213}
1214
1215void EditorAudioBuses::_select_layout() {
1216 FileSystemDock::get_singleton()->select_file(edited_path);
1217}
1218
1219void EditorAudioBuses::_save_as_layout() {
1220 file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
1221 file_dialog->set_title(TTR("Save Audio Bus Layout As..."));
1222 file_dialog->set_current_path(edited_path);
1223 file_dialog->popup_file_dialog();
1224 new_layout = false;
1225}
1226
1227void EditorAudioBuses::_new_layout() {
1228 file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
1229 file_dialog->set_title(TTR("Location for New Layout..."));
1230 file_dialog->set_current_path(edited_path);
1231 file_dialog->popup_file_dialog();
1232 new_layout = true;
1233}
1234
1235void EditorAudioBuses::_load_layout() {
1236 file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
1237 file_dialog->set_title(TTR("Open Audio Bus Layout"));
1238 file_dialog->set_current_path(edited_path);
1239 file_dialog->popup_file_dialog();
1240 new_layout = false;
1241}
1242
1243void EditorAudioBuses::_load_default_layout() {
1244 String layout_path = GLOBAL_GET("audio/buses/default_bus_layout");
1245
1246 Ref<AudioBusLayout> state = ResourceLoader::load(layout_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
1247 if (state.is_null()) {
1248 EditorNode::get_singleton()->show_warning(vformat(TTR("There is no '%s' file."), layout_path));
1249 return;
1250 }
1251
1252 edited_path = layout_path;
1253 file->set_text(String(TTR("Layout:")) + " " + layout_path.get_file());
1254 AudioServer::get_singleton()->set_bus_layout(state);
1255 _update_buses();
1256 EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
1257 call_deferred(SNAME("_select_layout"));
1258}
1259
1260void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
1261 if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_OPEN_FILE) {
1262 Ref<AudioBusLayout> state = ResourceLoader::load(p_string, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
1263 if (state.is_null()) {
1264 EditorNode::get_singleton()->show_warning(TTR("Invalid file, not an audio bus layout."));
1265 return;
1266 }
1267
1268 edited_path = p_string;
1269 file->set_text(String(TTR("Layout:")) + " " + p_string.get_file());
1270 AudioServer::get_singleton()->set_bus_layout(state);
1271 _update_buses();
1272 EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
1273 call_deferred(SNAME("_select_layout"));
1274
1275 } else if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
1276 if (new_layout) {
1277 Ref<AudioBusLayout> empty_state;
1278 empty_state.instantiate();
1279 AudioServer::get_singleton()->set_bus_layout(empty_state);
1280 }
1281
1282 Error err = ResourceSaver::save(AudioServer::get_singleton()->generate_bus_layout(), p_string);
1283
1284 if (err != OK) {
1285 EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file: %s"), p_string));
1286 return;
1287 }
1288
1289 edited_path = p_string;
1290 file->set_text(String(TTR("Layout:")) + " " + p_string.get_file());
1291 _update_buses();
1292 EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
1293 call_deferred(SNAME("_select_layout"));
1294 }
1295}
1296
1297void EditorAudioBuses::_bind_methods() {
1298 ClassDB::bind_method("_set_renaming_buses", &EditorAudioBuses::_set_renaming_buses);
1299 ClassDB::bind_method("_update_buses", &EditorAudioBuses::_update_buses);
1300 ClassDB::bind_method("_update_bus", &EditorAudioBuses::_update_bus);
1301 ClassDB::bind_method("_update_sends", &EditorAudioBuses::_update_sends);
1302 ClassDB::bind_method("_select_layout", &EditorAudioBuses::_select_layout);
1303}
1304
1305EditorAudioBuses::EditorAudioBuses() {
1306 top_hb = memnew(HBoxContainer);
1307 add_child(top_hb);
1308
1309 file = memnew(Label);
1310 String layout_path = GLOBAL_GET("audio/buses/default_bus_layout");
1311 file->set_text(String(TTR("Layout:")) + " " + layout_path.get_file());
1312 file->set_clip_text(true);
1313 file->set_h_size_flags(SIZE_EXPAND_FILL);
1314 top_hb->add_child(file);
1315
1316 add = memnew(Button);
1317 top_hb->add_child(add);
1318 add->set_text(TTR("Add Bus"));
1319 add->set_tooltip_text(TTR("Add a new Audio Bus to this layout."));
1320 add->connect("pressed", callable_mp(this, &EditorAudioBuses::_add_bus));
1321
1322 VSeparator *separator = memnew(VSeparator);
1323 top_hb->add_child(separator);
1324
1325 load = memnew(Button);
1326 load->set_text(TTR("Load"));
1327 load->set_tooltip_text(TTR("Load an existing Bus Layout."));
1328 top_hb->add_child(load);
1329 load->connect("pressed", callable_mp(this, &EditorAudioBuses::_load_layout));
1330
1331 save_as = memnew(Button);
1332 save_as->set_text(TTR("Save As"));
1333 save_as->set_tooltip_text(TTR("Save this Bus Layout to a file."));
1334 top_hb->add_child(save_as);
1335 save_as->connect("pressed", callable_mp(this, &EditorAudioBuses::_save_as_layout));
1336
1337 _default = memnew(Button);
1338 _default->set_text(TTR("Load Default"));
1339 _default->set_tooltip_text(TTR("Load the default Bus Layout."));
1340 top_hb->add_child(_default);
1341 _default->connect("pressed", callable_mp(this, &EditorAudioBuses::_load_default_layout));
1342
1343 _new = memnew(Button);
1344 _new->set_text(TTR("Create"));
1345 _new->set_tooltip_text(TTR("Create a new Bus Layout."));
1346 top_hb->add_child(_new);
1347 _new->connect("pressed", callable_mp(this, &EditorAudioBuses::_new_layout));
1348
1349 bus_scroll = memnew(ScrollContainer);
1350 bus_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
1351 bus_scroll->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
1352 add_child(bus_scroll);
1353 bus_hb = memnew(HBoxContainer);
1354 bus_hb->set_v_size_flags(SIZE_EXPAND_FILL);
1355 bus_scroll->add_child(bus_hb);
1356
1357 save_timer = memnew(Timer);
1358 save_timer->set_wait_time(0.8);
1359 save_timer->set_one_shot(true);
1360 add_child(save_timer);
1361 save_timer->connect("timeout", callable_mp(this, &EditorAudioBuses::_server_save));
1362
1363 set_v_size_flags(SIZE_EXPAND_FILL);
1364
1365 edited_path = GLOBAL_GET("audio/buses/default_bus_layout");
1366
1367 file_dialog = memnew(EditorFileDialog);
1368 List<String> ext;
1369 ResourceLoader::get_recognized_extensions_for_type("AudioBusLayout", &ext);
1370 for (const String &E : ext) {
1371 file_dialog->add_filter("*." + E, TTR("Audio Bus Layout"));
1372 }
1373 add_child(file_dialog);
1374 file_dialog->connect("file_selected", callable_mp(this, &EditorAudioBuses::_file_dialog_callback));
1375
1376 AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &EditorAudioBuses::_update_buses));
1377
1378 set_process(true);
1379}
1380
1381void EditorAudioBuses::open_layout(const String &p_path) {
1382 EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
1383
1384 Ref<AudioBusLayout> state = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
1385 if (state.is_null()) {
1386 EditorNode::get_singleton()->show_warning(TTR("Invalid file, not an audio bus layout."));
1387 return;
1388 }
1389
1390 edited_path = p_path;
1391 file->set_text(p_path.get_file());
1392 AudioServer::get_singleton()->set_bus_layout(state);
1393 _update_buses();
1394 EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
1395 call_deferred(SNAME("_select_layout"));
1396}
1397
1398void AudioBusesEditorPlugin::edit(Object *p_node) {
1399 if (Object::cast_to<AudioBusLayout>(p_node)) {
1400 String path = Object::cast_to<AudioBusLayout>(p_node)->get_path();
1401 if (path.is_resource_file()) {
1402 audio_bus_editor->open_layout(path);
1403 }
1404 }
1405}
1406
1407bool AudioBusesEditorPlugin::handles(Object *p_node) const {
1408 return (Object::cast_to<AudioBusLayout>(p_node) != nullptr);
1409}
1410
1411void AudioBusesEditorPlugin::make_visible(bool p_visible) {
1412}
1413
1414AudioBusesEditorPlugin::AudioBusesEditorPlugin(EditorAudioBuses *p_node) {
1415 audio_bus_editor = p_node;
1416}
1417
1418AudioBusesEditorPlugin::~AudioBusesEditorPlugin() {
1419}
1420
1421void EditorAudioMeterNotches::add_notch(float p_normalized_offset, float p_db_value, bool p_render_value) {
1422 notches.push_back(AudioNotch(p_normalized_offset, p_db_value, p_render_value));
1423}
1424
1425Size2 EditorAudioMeterNotches::get_minimum_size() const {
1426 Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
1427 int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
1428 float font_height = font->get_height(font_size);
1429
1430 float width = 0;
1431 float height = top_padding + btm_padding;
1432
1433 for (int i = 0; i < notches.size(); i++) {
1434 if (notches[i].render_db_value) {
1435 width = MAX(width, font->get_string_size(String::num(Math::abs(notches[i].db_value)) + "dB", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x);
1436 height += font_height;
1437 }
1438 }
1439 width += line_length + label_space;
1440
1441 return Size2(width, height);
1442}
1443
1444void EditorAudioMeterNotches::_update_theme_item_cache() {
1445 Control::_update_theme_item_cache();
1446
1447 theme_cache.notch_color = get_theme_color(SNAME("font_color"), EditorStringName(Editor));
1448
1449 theme_cache.font = get_theme_font(SNAME("font"), SNAME("Label"));
1450 theme_cache.font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
1451}
1452
1453void EditorAudioMeterNotches::_bind_methods() {
1454 ClassDB::bind_method("add_notch", &EditorAudioMeterNotches::add_notch);
1455 ClassDB::bind_method("_draw_audio_notches", &EditorAudioMeterNotches::_draw_audio_notches);
1456}
1457
1458void EditorAudioMeterNotches::_notification(int p_what) {
1459 switch (p_what) {
1460 case NOTIFICATION_DRAW: {
1461 _draw_audio_notches();
1462 } break;
1463 }
1464}
1465
1466void EditorAudioMeterNotches::_draw_audio_notches() {
1467 float font_height = theme_cache.font->get_height(theme_cache.font_size);
1468
1469 for (int i = 0; i < notches.size(); i++) {
1470 AudioNotch n = notches[i];
1471 draw_line(Vector2(0, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding),
1472 Vector2(line_length * EDSCALE, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding),
1473 theme_cache.notch_color,
1474 Math::round(EDSCALE));
1475
1476 if (n.render_db_value) {
1477 draw_string(theme_cache.font,
1478 Vector2((line_length + label_space) * EDSCALE,
1479 (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + (font_height / 4) + top_padding),
1480 String::num(Math::abs(n.db_value)) + "dB",
1481 HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size,
1482 theme_cache.notch_color);
1483 }
1484 }
1485}
1486