Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions C7/Audio/AudioLoader.cs.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://d3ppdw6qcpc4k
143 changes: 143 additions & 0 deletions C7/Audio/AudioManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@

using System;
using C7Engine;
using Godot;
using Serilog;

[GlobalClass]
public partial class AudioManager : Node {
private ILogger log;

[Export] AudioStreamPlayer musicPlayer;
[Export] AudioStreamPlayer sfxAudioPlayer;
[Export] AudioStreamPlayer uiAudioPlayer;
[Export] AudioStreamPlayer ambienceAudioPlayer;

private PolyphonicAudioPlayer _polyMusicPlayer;
private PolyphonicAudioPlayer _polySfxAudioPlayer;
private PolyphonicAudioPlayer _polyUiAudioPlayer;
private PolyphonicAudioPlayer _polyAmbienceAudioPlayer;

private static string AudioSettingsSection = "audio";

public static string MusicBus = "Music";
public static string SfxAudioBus = "Sfx";
public static string UIAudioBus = "UI";
public static string AmbienceAudioBus = "Ambience";

private bool musicEnabled = true;
private bool sfxAudioEnabled = true;
private bool uiAudioEnabled = true;
private bool ambienceAudioEnabled = true;

public override void _Ready() {
log = LogManager.ForContext<AudioManager>();

musicEnabled = ConfigureVolume("musicVolume", MusicBus);
_polyMusicPlayer = new PolyphonicAudioPlayer(musicPlayer, 2);

sfxAudioEnabled = ConfigureVolume("sfxAudioVolume", SfxAudioBus);
_polySfxAudioPlayer = new PolyphonicAudioPlayer(sfxAudioPlayer, 32);

uiAudioEnabled = ConfigureVolume("uiAudioVolume", UIAudioBus);
_polyUiAudioPlayer = new PolyphonicAudioPlayer(uiAudioPlayer, 8);

ambienceAudioEnabled = ConfigureVolume("ambienceAudioVolume", AmbienceAudioBus);
_polyAmbienceAudioPlayer = new PolyphonicAudioPlayer(ambienceAudioPlayer, 8);
}

private bool ConfigureVolume(string volumeKey, string audioBus) {
try {
string volume = C7Settings.GetSettingValue(AudioSettingsSection, volumeKey);
float volumeDb = LogicalVolumeAsDecibel(volume, volumeKey);

if (volumeDb == float.MinValue) {
return false;
}

log.Debug("setting {volumeKey} to {volume}, which is {offset} decibel (offset)",
volumeKey, volume, volumeDb);

int busIndex = AudioServer.GetBusIndex(audioBus);
AudioServer.SetBusVolumeDb(busIndex, volumeDb);

return true;
} catch (ApplicationException ex) {
log.Error(ex, "could not configure {volumeKey}", volumeKey);
return false;
}
}

/**
* Godot uses a decibel offset volume system, described at https://docs.godotengine.org/en/stable/tutorials/audio/audio_buses.html
* This is what audio professionals would use, but is not intuitive to end users.
* In this system, a 6db difference halves or doubles the volume.
* Our users are probably more used to a 0% to 100% system.
* So this method converts between them.
*/
private float LogicalVolumeAsDecibel(string volume, string volumeKey) {
if (volume == null) {
//First run. Save the setting.
C7Settings.SetValue(AudioSettingsSection, volumeKey, "100");
C7Settings.SaveSettings();
return 0;
}
int userVolumeSetting = int.Parse(volume);
if (userVolumeSetting == 100) {
return 0;
} else if (userVolumeSetting == 0) {
return float.MinValue;
} else {
//Conversion math based on https://stackoverflow.com/a/37810295/3534605
return 20.0f * (float)(Math.Log10(userVolumeSetting / 100.0f));
}
}

// TODO: playlists, mixing, transitions
// See: https://www.youtube.com/watch?app=desktop&v=07Kyqqg31FI&t=346s

// TODO: polyphony via AudioStreamPolyphonic + AudioStreamPlaybackPolyphonic
// https://docs.godotengine.org/en/4.0/classes/class_audiostreampolyphonic.html

private long currentMusicId = AudioStreamPlaybackPolyphonic.InvalidId;

public void PlayMusic(string configKey) {
AudioStream stream = AudioLoader.Load(configKey);

if (stream == null)
return;

if (currentMusicId != AudioStreamPlaybackPolyphonic.InvalidId) {
_polyMusicPlayer.Stop(currentMusicId);
currentMusicId = AudioStreamPlaybackPolyphonic.InvalidId;
}

currentMusicId = _polyMusicPlayer.Play(stream);
}


public void StopMusic() {
if (currentMusicId != AudioStreamPlaybackPolyphonic.InvalidId) {
_polyMusicPlayer.Stop(currentMusicId);
currentMusicId = AudioStreamPlaybackPolyphonic.InvalidId;
}
}

public void PlaySfxAudio(string configKey) {
var stream = AudioLoader.Load(configKey);
if (stream != null)
_polySfxAudioPlayer.Play(stream);
}

public void PlayUIAudio(string configKey) {
var stream = AudioLoader.Load(configKey);
if (stream != null)
_polyUiAudioPlayer.Play(stream);
}

public void PlayAmbienceAudio(string configKey) {
var stream = AudioLoader.Load(configKey);
if (stream != null)
_polyAmbienceAudioPlayer.Play(stream);
}
}
1 change: 1 addition & 0 deletions C7/Audio/AudioManager.cs.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://eyk3k7dd7tcy
22 changes: 22 additions & 0 deletions C7/Audio/AudioManager.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[gd_scene load_steps=2 format=3 uid="uid://4hh28tdyqvfg"]

[ext_resource type="Script" uid="uid://eyk3k7dd7tcy" path="res://Audio/AudioManager.cs" id="1_l0aok"]

[node name="AudioManager" type="Node" node_paths=PackedStringArray("musicPlayer", "sfxAudioPlayer", "uiAudioPlayer", "ambienceAudioPlayer")]
script = ExtResource("1_l0aok")
musicPlayer = NodePath("MusicPlayer")
sfxAudioPlayer = NodePath("SfxAudioPlayer")
uiAudioPlayer = NodePath("UIAudioPlayer")
ambienceAudioPlayer = NodePath("AmbienceAudioPlayer")

[node name="MusicPlayer" type="AudioStreamPlayer" parent="."]
bus = &"Music"

[node name="SfxAudioPlayer" type="AudioStreamPlayer" parent="."]
bus = &"Sfx"

[node name="UIAudioPlayer" type="AudioStreamPlayer" parent="."]
bus = &"UI"

[node name="AmbienceAudioPlayer" type="AudioStreamPlayer" parent="."]
bus = &"Ambience"
35 changes: 35 additions & 0 deletions C7/Audio/PolyphonicAudioPlayer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Godot;

public class PolyphonicAudioPlayer {
private readonly AudioStreamPlayer player;
private AudioStreamPlaybackPolyphonic playback;

public PolyphonicAudioPlayer(AudioStreamPlayer player, int polyphony = 32) {
this.player = player;

player.Stream = new AudioStreamPolyphonic {
Polyphony = polyphony
};

player.Play();

playback = player.GetStreamPlayback()
as AudioStreamPlaybackPolyphonic;
}

public long Play(AudioStream stream) {
return playback.PlayStream(stream);
}

public void Stop(long id) {
playback.StopStream(id);
}

public void StopAll() {
player.Stop();
player.Play();

playback = player.GetStreamPlayback()
as AudioStreamPlaybackPolyphonic;
}
}
7 changes: 7 additions & 0 deletions C7/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,13 @@ private async Task InitializeGame() {
}

InitializeMapView();
InitializeAudio();
}

private void InitializeAudio() {
AudioManager audio = GetNode<AudioManager>("/root/GlobalAudioManager");
audio.StopMusic();
// TODO: switch to in-game playlist / music logic
}

private async Task StartGame() {
Expand Down
24 changes: 12 additions & 12 deletions C7/UIElements/MainMenu/MainMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ public partial class MainMenu : Node {
Civ3FileDialog LoadScenarioDialog;
[Export]
MenuButtonContainer ButtonContainer;
[Export]
AudioStreamPlayer player;

GlobalSingleton Global;
AudioManager AudioManager;

public override void _Ready() {
log = LogManager.ForContext<MainMenu>();
Expand All @@ -29,6 +28,9 @@ public override void _Ready() {

try {
DisplayTitleScreen();

AudioManager = GetNode<AudioManager>("/root/GlobalAudioManager");
PlayMusic();
} catch (Exception ex) {
log.Error(ex, "Could not set up the main menu");
}
Expand Down Expand Up @@ -148,16 +150,6 @@ public void _on_Exit_pressed() {
GetTree().Quit(); // no need to notify the scene tree
}

private void PlayButtonPressedSound() {
AudioStream stream = AudioLoader.Load("buttons.button_1");

if (stream == null)
return;

player.Stream = stream;
player.Play();
}

private void _on_SetCiv3Home_pressed() {
SetCiv3HomeDialog.Popup();
}
Expand All @@ -174,4 +166,12 @@ private void UseStandaloneModePressed() {
Global.ActivateGameMode(GamePaths.standalone);
DisplayTitleScreen();
}

private void PlayMusic() {
AudioManager.PlayMusic("menu.main_menu_1");
}

private void PlayButtonPressedSound() {
AudioManager.PlayUIAudio("buttons.button_1");
}
}
62 changes: 0 additions & 62 deletions C7/UIElements/MainMenu/MainMenuMusicPlayer.cs

This file was deleted.

1 change: 0 additions & 1 deletion C7/UIElements/MainMenu/MainMenuMusicPlayer.cs.uid

This file was deleted.

8 changes: 2 additions & 6 deletions C7/UIElements/MainMenu/main_menu.tscn
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
[gd_scene load_steps=13 format=3 uid="uid://gnt0y3og7nk6"]
[gd_scene load_steps=12 format=3 uid="uid://gnt0y3og7nk6"]

[ext_resource type="Script" uid="uid://dgpuse88jc2hc" path="res://UIElements/MainMenu/MainMenu.cs" id="1_akneh"]
[ext_resource type="Texture2D" uid="uid://s55xvcaini8h" path="res://title-screen.png" id="2_erxyj"]
[ext_resource type="Script" uid="uid://ca14gkdccjfcg" path="res://UIElements/MainMenu/MenuButtonContainer.cs" id="3_t1nuq"]
[ext_resource type="FontFile" uid="uid://b1xkj8g82jbx5" path="res://Fonts/NotoSans-BoldItalic.ttf" id="3_x68dx"]
[ext_resource type="Texture2D" uid="uid://ovwv08a53d7k" path="res://title.png" id="4_brea7"]
[ext_resource type="Script" uid="uid://dauceqein40wj" path="res://UIElements/MainMenu/MainMenuMusicPlayer.cs" id="4_tqr50"]
[ext_resource type="PackedScene" uid="uid://bvncm1bgcii5e" path="res://UIElements/civ3_file_dialog.tscn" id="5_rw2g7"]

[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_vbij8"]
Expand Down Expand Up @@ -204,17 +203,14 @@ offset_top = -48.0
grow_horizontal = 2
grow_vertical = 0
text = "OpenCiv3 0.3 \"Dutch 2\" © OpenCiv3 contributors
OpenCiv3 is not affiliated with civfanatics.com, Firaxis Games, BreakAway Games,
OpenCiv3 is not affiliated with civfanatics.com, Firaxis Games, BreakAway Games,
Hasbro Interactive, Infogrames Interactive, Atari Interactive, or Take-Two Interactive Software.
All trademarks are property of their respective owners."
label_settings = SubResource("LabelSettings_brea7")
horizontal_alignment = 1
vertical_alignment = 2
autowrap_mode = 3

[node name="MainMenuMusicPlayer" type="AudioStreamPlayer" parent="."]
script = ExtResource("4_tqr50")

[node name="SoundEffectPlayer" type="AudioStreamPlayer" parent="."]

[node name="SetCiv3HomeDialog" type="FileDialog" parent="."]
Expand Down
27 changes: 27 additions & 0 deletions C7/default_bus_layout.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[gd_resource type="AudioBusLayout" format=3 uid="uid://cw11tyqth76rn"]

[resource]
bus/1/name = &"Music"
bus/1/solo = false
bus/1/mute = false
bus/1/bypass_fx = false
bus/1/volume_db = 0.0
bus/1/send = &"Master"
bus/2/name = &"Sfx"
bus/2/solo = false
bus/2/mute = false
bus/2/bypass_fx = false
bus/2/volume_db = 0.0
bus/2/send = &"Master"
bus/3/name = &"UI"
bus/3/solo = false
bus/3/mute = false
bus/3/bypass_fx = false
bus/3/volume_db = 0.0
bus/3/send = &"Master"
bus/4/name = &"Ambience"
bus/4/solo = false
bus/4/mute = false
bus/4/bypass_fx = false
bus/4/volume_db = 0.0
bus/4/send = &"Master"
Loading
Loading