Skip to content

Instantly share code, notes, and snippets.

@Shilo
Last active February 21, 2024 02:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Shilo/0fc572849fa0143a55e7c5e524a745a4 to your computer and use it in GitHub Desktop.
Save Shilo/0fc572849fa0143a55e7c5e524a745a4 to your computer and use it in GitHub Desktop.
Audio manager singleton that pools audio players.
using Godot;
using System.Collections.Generic;
public partial class SoundManager : Node
{
private const int MaxSimultaneousSounds = 32;
private const int SuppressSoundTimeMs = 100;
private readonly List<AudioStreamPlayer2D> _inactiveAudioPlayers = new();
private readonly List<AudioStreamPlayer2D> _activeAudioPlayers = new();
private readonly Dictionary<string, float> _lastPlayed = new();
public static SoundManager Instance;
public static float Volume { get; set; } = 1.0f;
public override void _EnterTree()
{
Instance = this;
}
public override void _Ready()
{
for (int i = 0; i < MaxSimultaneousSounds; i++)
{
var audioPlayer = new AudioStreamPlayer2D();
audioPlayer.Finished += () =>
{
_activeAudioPlayers.Remove(audioPlayer);
_inactiveAudioPlayers.Add(audioPlayer);
};
_inactiveAudioPlayers.Add(audioPlayer);
AddChild(audioPlayer);
}
}
public bool PlaySound(string path, bool nonPausable = false)
{
if (MaxSimultaneousSounds <= 0 || !CanPlaySound(path))
return false;
var audioPlayerPool = _inactiveAudioPlayers.Count > 0 ? _inactiveAudioPlayers : _activeAudioPlayers;
var audioPlayer = audioPlayerPool[0];
audioPlayerPool.RemoveAt(0);
_activeAudioPlayers.Add(audioPlayer);
audioPlayer.ProcessMode = nonPausable ? ProcessModeEnum.Always : ProcessModeEnum.Inherit;
audioPlayer.Stream = GD.Load<AudioStream>(path);
audioPlayer.VolumeDb = Mathf.LinearToDb(Volume);
audioPlayer.Play();
if (SuppressSoundTimeMs > 0)
_lastPlayed[path] = Time.GetTicksMsec();
return true;
}
private bool CanPlaySound(string path)
{
if (SuppressSoundTimeMs <= 0)
return true;
if (!_lastPlayed.TryGetValue(path, out float lastPlayed))
return true;
return Time.GetTicksMsec() - lastPlayed > SuppressSoundTimeMs;
}
private bool IsPlayingSound(string path)
{
path = path.ToLower();
return _activeAudioPlayers.Exists(audioPlayer => audioPlayer.Stream.ResourcePath.ToLower() == path);
}
public static bool Play(string path, bool nonPausable = false)
{
return Instance?.PlaySound(path, nonPausable) ?? false;
}
public override void _ExitTree()
{
if (Instance == this)
Instance = null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment