generated from krampus/template-godot4
Volume mixer settings with persistence to disk
This commit is contained in:
parent
f75af2196d
commit
12fbbb82bc
|
@ -1,6 +1,7 @@
|
||||||
[gd_resource type="AudioBusLayout" format=3 uid="uid://cwxndi28bii8d"]
|
[gd_resource type="AudioBusLayout" format=3 uid="uid://cwxndi28bii8d"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
|
bus/0/volume_db = 0.0
|
||||||
bus/1/name = &"SFX"
|
bus/1/name = &"SFX"
|
||||||
bus/1/solo = false
|
bus/1/solo = false
|
||||||
bus/1/mute = false
|
bus/1/mute = false
|
||||||
|
|
|
@ -61,6 +61,7 @@ config/controls/camera/y_axis_acceleration=30.0
|
||||||
config/controls/camera/invert_pitch=false
|
config/controls/camera/invert_pitch=false
|
||||||
config/accessibility/enable_screen_shake=true
|
config/accessibility/enable_screen_shake=true
|
||||||
config/accessibility/enable_hit_lag=true
|
config/accessibility/enable_hit_lag=true
|
||||||
|
audio/buses/override_bus_layout="user://audio_bus_layout.tres"
|
||||||
|
|
||||||
[global_group]
|
[global_group]
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ class_name GameSettingsType extends Node
|
||||||
## Container for project settings, for quick runtime access.
|
## Container for project settings, for quick runtime access.
|
||||||
|
|
||||||
var settings_file: String
|
var settings_file: String
|
||||||
|
var audio_bus_file: String
|
||||||
|
|
||||||
var free_camera_speed: float
|
var free_camera_speed: float
|
||||||
var x_sensitivity: float
|
var x_sensitivity: float
|
||||||
|
@ -15,10 +16,13 @@ var enable_hit_lag: bool
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
ProjectSettings.settings_changed.connect(_read_settings)
|
ProjectSettings.settings_changed.connect(_read_settings)
|
||||||
|
_read_settings()
|
||||||
|
_load_audio_bus_override()
|
||||||
|
|
||||||
|
|
||||||
func _read_settings() -> void:
|
func _read_settings() -> void:
|
||||||
settings_file = ProjectSettings.get_setting("application/config/project_settings_override")
|
settings_file = ProjectSettings.get_setting("application/config/project_settings_override")
|
||||||
|
audio_bus_file = ProjectSettings.get_setting("game/audio/buses/override_bus_layout")
|
||||||
|
|
||||||
free_camera_speed = ProjectSettings.get_setting("game/config/controls/camera/free_camera_speed")
|
free_camera_speed = ProjectSettings.get_setting("game/config/controls/camera/free_camera_speed")
|
||||||
x_sensitivity = ProjectSettings.get_setting("game/config/controls/camera/x_axis_sensitivity")
|
x_sensitivity = ProjectSettings.get_setting("game/config/controls/camera/x_axis_sensitivity")
|
||||||
|
@ -31,3 +35,18 @@ func _read_settings() -> void:
|
||||||
"game/config/accessibility/enable_screen_shake"
|
"game/config/accessibility/enable_screen_shake"
|
||||||
)
|
)
|
||||||
enable_hit_lag = ProjectSettings.get_setting("game/config/accessibility/enable_hit_lag")
|
enable_hit_lag = ProjectSettings.get_setting("game/config/accessibility/enable_hit_lag")
|
||||||
|
|
||||||
|
|
||||||
|
func _load_audio_bus_override() -> void:
|
||||||
|
# Load override audio bus file
|
||||||
|
if FileAccess.file_exists(audio_bus_file):
|
||||||
|
print_debug("Loading audio bus override from ", audio_bus_file)
|
||||||
|
var bus_layout: AudioBusLayout = load(audio_bus_file)
|
||||||
|
AudioServer.set_bus_layout(bus_layout)
|
||||||
|
|
||||||
|
|
||||||
|
func write() -> void:
|
||||||
|
print_debug("Writing settings to ", settings_file)
|
||||||
|
ProjectSettings.save_custom(settings_file)
|
||||||
|
print_debug("Writing audio bus levels to ", audio_bus_file)
|
||||||
|
ResourceSaver.save(AudioServer.generate_bus_layout(), audio_bus_file)
|
||||||
|
|
|
@ -56,6 +56,12 @@ CancelButton/colors/font_outline_color = Color(0, 0, 0, 1)
|
||||||
CancelButton/constants/outline_size = 6
|
CancelButton/constants/outline_size = 6
|
||||||
CancelButton/font_sizes/font_size = 24
|
CancelButton/font_sizes/font_size = 24
|
||||||
CancelButton/fonts/font = ExtResource("2_5ty6u")
|
CancelButton/fonts/font = ExtResource("2_5ty6u")
|
||||||
|
ChannelMixerIcon/base_type = &"Label"
|
||||||
|
ChannelMixerIcon/colors/font_color = Color(1, 1, 0.870588, 1)
|
||||||
|
ChannelMixerIcon/colors/font_outline_color = Color(0, 0, 0, 1)
|
||||||
|
ChannelMixerIcon/constants/outline_size = 5
|
||||||
|
ChannelMixerIcon/font_sizes/font_size = 24
|
||||||
|
ChannelMixerIcon/fonts/font = ExtResource("2_8kux8")
|
||||||
CheckerContainerEven/base_type = &"PanelContainer"
|
CheckerContainerEven/base_type = &"PanelContainer"
|
||||||
CheckerContainerEven/styles/panel = SubResource("StyleBoxFlat_rq1no")
|
CheckerContainerEven/styles/panel = SubResource("StyleBoxFlat_rq1no")
|
||||||
CheckerContainerOdd/base_type = &"PanelContainer"
|
CheckerContainerOdd/base_type = &"PanelContainer"
|
||||||
|
@ -75,10 +81,13 @@ ClubSelectLabelDisabled/colors/font_outline_color = Color(0.2, 0.2, 0.2, 1)
|
||||||
ClubSelectLabelDisabled/colors/font_shadow_color = Color(0.2, 0.2, 0.2, 1)
|
ClubSelectLabelDisabled/colors/font_shadow_color = Color(0.2, 0.2, 0.2, 1)
|
||||||
ClubSelectLabelDisabled/font_sizes/font_size = 84
|
ClubSelectLabelDisabled/font_sizes/font_size = 84
|
||||||
ClubSelectLabelDisabled/fonts/font = ExtResource("1_3rv2b")
|
ClubSelectLabelDisabled/fonts/font = ExtResource("1_3rv2b")
|
||||||
|
HeaderLarge/constants/outline_size = 8
|
||||||
HeaderLarge/font_sizes/font_size = 28
|
HeaderLarge/font_sizes/font_size = 28
|
||||||
|
HeaderMedium/constants/outline_size = 6
|
||||||
HeaderMedium/font_sizes/font_size = 24
|
HeaderMedium/font_sizes/font_size = 24
|
||||||
HeaderSmall/font_sizes/font_size = 20
|
HeaderSmall/font_sizes/font_size = 20
|
||||||
HeaderXLarge/base_type = &"Label"
|
HeaderXLarge/base_type = &"Label"
|
||||||
|
HeaderXLarge/constants/outline_size = 10
|
||||||
HeaderXLarge/font_sizes/font_size = 36
|
HeaderXLarge/font_sizes/font_size = 36
|
||||||
InputBindButton/base_type = &"UIButton"
|
InputBindButton/base_type = &"UIButton"
|
||||||
InputBindButton/colors/font_color = Color(1, 1, 0.870588, 1)
|
InputBindButton/colors/font_color = Color(1, 1, 0.870588, 1)
|
||||||
|
|
|
@ -2,11 +2,14 @@ extends MarginContainer
|
||||||
## Menu allowing the user to adjust game configuration.
|
## Menu allowing the user to adjust game configuration.
|
||||||
|
|
||||||
const SETTINGS_GROUP := "Settings"
|
const SETTINGS_GROUP := "Settings"
|
||||||
|
const VOLUME_GROUP := "VolumeSliders"
|
||||||
|
|
||||||
|
@onready var bus_mixer_list: HBoxContainer = %BusMixerList
|
||||||
@onready var control_binding_list: VBoxContainer = %ControlBindingList
|
@onready var control_binding_list: VBoxContainer = %ControlBindingList
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
populate_volume_mixers()
|
||||||
populate_control_bindings()
|
populate_control_bindings()
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,12 +19,23 @@ func _get_settings_elements() -> Array[Setting]:
|
||||||
return elements
|
return elements
|
||||||
|
|
||||||
|
|
||||||
|
func _get_volume_sliders() -> Array[VolumeSlider]:
|
||||||
|
var elements: Array[VolumeSlider] = []
|
||||||
|
elements.assign(get_tree().get_nodes_in_group(VOLUME_GROUP))
|
||||||
|
return elements
|
||||||
|
|
||||||
|
|
||||||
func populate_control_bindings() -> void:
|
func populate_control_bindings() -> void:
|
||||||
for action: StringName in InputMap.get_actions():
|
for action: StringName in InputMap.get_actions():
|
||||||
if not action.begins_with("ui_"):
|
if not action.begins_with("ui_"):
|
||||||
control_binding_list.add_child(ControlBinding.create(action))
|
control_binding_list.add_child(ControlBinding.create(action))
|
||||||
|
|
||||||
|
|
||||||
|
func populate_volume_mixers() -> void:
|
||||||
|
for idx: int in range(AudioServer.bus_count):
|
||||||
|
bus_mixer_list.add_child(VolumeSlider.create(idx))
|
||||||
|
|
||||||
|
|
||||||
## Close menu without applying settings.
|
## Close menu without applying settings.
|
||||||
func cancel() -> void:
|
func cancel() -> void:
|
||||||
queue_free()
|
queue_free()
|
||||||
|
@ -31,12 +45,13 @@ func cancel() -> void:
|
||||||
func apply() -> void:
|
func apply() -> void:
|
||||||
for setting: Setting in _get_settings_elements():
|
for setting: Setting in _get_settings_elements():
|
||||||
setting.apply()
|
setting.apply()
|
||||||
|
for mixer: VolumeSlider in _get_volume_sliders():
|
||||||
|
mixer.apply()
|
||||||
|
|
||||||
|
|
||||||
## Write all applied settings to disk.
|
## Write all applied settings to disk.
|
||||||
func save_settings() -> void:
|
func save_settings() -> void:
|
||||||
print_debug("Writing settings to ", Game.settings.settings_file)
|
Game.settings.write()
|
||||||
ProjectSettings.save_custom(Game.settings.settings_file)
|
|
||||||
BindingLoader.write()
|
BindingLoader.write()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ script = ExtResource("1_lbcn7")
|
||||||
|
|
||||||
[node name="TabContainer" type="TabContainer" parent="."]
|
[node name="TabContainer" type="TabContainer" parent="."]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
current_tab = 3
|
current_tab = 2
|
||||||
|
|
||||||
[node name="Game" type="MarginContainer" parent="TabContainer"]
|
[node name="Game" type="MarginContainer" parent="TabContainer"]
|
||||||
visible = false
|
visible = false
|
||||||
|
@ -196,7 +196,6 @@ theme_type_variation = &"SettingsListMargin"
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
||||||
[node name="Audio" type="MarginContainer" parent="TabContainer"]
|
[node name="Audio" type="MarginContainer" parent="TabContainer"]
|
||||||
visible = false
|
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_type_variation = &"SettingsPageContainer"
|
theme_type_variation = &"SettingsPageContainer"
|
||||||
metadata/_tab_index = 2
|
metadata/_tab_index = 2
|
||||||
|
@ -229,10 +228,13 @@ size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_type_variation = &"SettingsListMargin"
|
theme_type_variation = &"SettingsListMargin"
|
||||||
|
|
||||||
[node name="SettingsList" type="VBoxContainer" parent="TabContainer/Audio/VBoxContainer/ScrollContainer/MarginContainer"]
|
[node name="BusMixerList" type="HBoxContainer" parent="TabContainer/Audio/VBoxContainer/ScrollContainer/MarginContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 16
|
||||||
|
|
||||||
[node name="Controls" type="MarginContainer" parent="TabContainer"]
|
[node name="Controls" type="MarginContainer" parent="TabContainer"]
|
||||||
|
visible = false
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_type_variation = &"SettingsPageContainer"
|
theme_type_variation = &"SettingsPageContainer"
|
||||||
metadata/_tab_index = 3
|
metadata/_tab_index = 3
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
class_name VolumeSlider extends VBoxContainer
|
||||||
|
## Input element for adjusting the volume of a single bus.
|
||||||
|
|
||||||
|
const SCENE := preload("res://src/ui/menus/settings_menu/volume_slider/volume_slider.tscn")
|
||||||
|
const VOLUME_FACTOR := 50.0
|
||||||
|
|
||||||
|
@export var bus_idx: int
|
||||||
|
|
||||||
|
var value: float:
|
||||||
|
get:
|
||||||
|
return slider.value
|
||||||
|
set(v):
|
||||||
|
slider.set_value_no_signal(v)
|
||||||
|
spin_box.set_value_no_signal(v)
|
||||||
|
_set_bus_volume(v)
|
||||||
|
|
||||||
|
var _applied_value: float
|
||||||
|
|
||||||
|
@onready var bus_name: Label = %BusName
|
||||||
|
@onready var slider: VSlider = %Slider
|
||||||
|
@onready var spin_box: SpinBox = %SpinBox
|
||||||
|
@onready var audio_demo: AudioStreamPlayer = %AudioDemo
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
bus_name.text = AudioServer.get_bus_name(bus_idx)
|
||||||
|
audio_demo.bus = bus_name.text
|
||||||
|
_applied_value = _db_to_volume(AudioServer.get_bus_volume_db(bus_idx))
|
||||||
|
value = _applied_value
|
||||||
|
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
# Revert volume to the value from the last time `apply` was called
|
||||||
|
_set_bus_volume(_applied_value)
|
||||||
|
|
||||||
|
|
||||||
|
func _db_to_volume(db: float) -> float:
|
||||||
|
return db_to_linear(db) * VOLUME_FACTOR
|
||||||
|
|
||||||
|
|
||||||
|
func _volume_to_db(volume: float) -> float:
|
||||||
|
return linear_to_db(volume / VOLUME_FACTOR)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_component_value_changed(new_value: float) -> void:
|
||||||
|
value = new_value
|
||||||
|
|
||||||
|
|
||||||
|
func _set_bus_volume(new_value: float) -> void:
|
||||||
|
AudioServer.set_bus_volume_db(bus_idx, _volume_to_db(new_value))
|
||||||
|
|
||||||
|
|
||||||
|
func apply() -> void:
|
||||||
|
# Prevent value from being reverted during destructor.
|
||||||
|
_applied_value = value
|
||||||
|
|
||||||
|
|
||||||
|
func _on_slider_drag_ended(value_changed: bool) -> void:
|
||||||
|
if value_changed:
|
||||||
|
audio_demo.play()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_spin_box_value_changed(_new_value: float) -> void:
|
||||||
|
audio_demo.play()
|
||||||
|
|
||||||
|
|
||||||
|
static func create(_bus_idx: int) -> VolumeSlider:
|
||||||
|
var instance: VolumeSlider = SCENE.instantiate()
|
||||||
|
instance.bus_idx = _bus_idx
|
||||||
|
return instance
|
|
@ -0,0 +1,51 @@
|
||||||
|
[gd_scene load_steps=3 format=3 uid="uid://d2ya6ly01724l"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://src/ui/menus/settings_menu/volume_slider/volume_slider.gd" id="1_rfe0k"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://cllhgumv1fkju" path="res://assets/sound/sfx/player/drive1.wav" id="2_822gu"]
|
||||||
|
|
||||||
|
[node name="VolumeSlider" type="VBoxContainer" groups=["VolumeSliders"]]
|
||||||
|
custom_minimum_size = Vector2(300, 0)
|
||||||
|
script = ExtResource("1_rfe0k")
|
||||||
|
|
||||||
|
[node name="NameContainer" type="HBoxContainer" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="Icon" type="Label" parent="NameContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_type_variation = &"ChannelMixerIcon"
|
||||||
|
text = "🎧"
|
||||||
|
|
||||||
|
[node name="BusName" type="Label" parent="NameContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 8
|
||||||
|
theme_type_variation = &"HeaderMedium"
|
||||||
|
text = "Channel"
|
||||||
|
|
||||||
|
[node name="Slider" type="VSlider" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 3
|
||||||
|
step = 0.1
|
||||||
|
|
||||||
|
[node name="DigitalDisplay" type="HBoxContainer" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 4
|
||||||
|
|
||||||
|
[node name="SpinBox" type="SpinBox" parent="DigitalDisplay"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
step = 0.1
|
||||||
|
alignment = 2
|
||||||
|
suffix = "%"
|
||||||
|
|
||||||
|
[node name="AudioDemo" type="AudioStreamPlayer" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
stream = ExtResource("2_822gu")
|
||||||
|
|
||||||
|
[connection signal="drag_ended" from="Slider" to="." method="_on_slider_drag_ended"]
|
||||||
|
[connection signal="value_changed" from="Slider" to="." method="_on_component_value_changed"]
|
||||||
|
[connection signal="value_changed" from="DigitalDisplay/SpinBox" to="." method="_on_component_value_changed"]
|
||||||
|
[connection signal="value_changed" from="DigitalDisplay/SpinBox" to="." method="_on_spin_box_value_changed"]
|
Loading…
Reference in New Issue