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