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