Skip to content
2 changes: 1 addition & 1 deletion scripts/Rhythia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ public override void _Notification(int what)
else if (what == NotificationApplicationFocusIn)
{
var settings = SettingsManager.Instance.Settings;
Engine.MaxFps = settings.UnlockFPS ? 0 : settings.FPS;
Engine.MaxFps = settings.LockFPS ? settings.FPS : 0;
}
}
}
277 changes: 267 additions & 10 deletions scripts/SoundManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@

public partial class SoundManager : Node, ISkinnable
{
public enum PlaybackScope
{
Silent,
Preview,
GameplayResults,
}

public static SoundManager Instance;

public static AudioStreamPlayer HitSound;
public static AudioStreamPlayer MissSound;
public static AudioStreamPlayer FailSound;
public static AudioStreamPlayer Song;
public static AudioStreamPlayer MenuMusic;

public Action<Map> JukeboxPlayed;

Expand All @@ -22,9 +30,12 @@ public partial class SoundManager : Node, ISkinnable
public static bool JukeboxPaused = false;
public static ulong LastRewind = 0;
public static Map Map;
public static PlaybackScope Scope = PlaybackScope.Silent;

private static bool volumePopupShown = false;
private static ulong lastVolumeChange = 0;
private static bool? jeeping = null; // we're jeeping (last state of a song)
private static bool menuMusicPausedByUser = false;

public override void _Ready()
{
Expand All @@ -34,20 +45,29 @@ public override void _Ready()
MissSound = new();
FailSound = new();
Song = new();
MenuMusic = new();

HitSound.MaxPolyphony = 16;
MissSound.MaxPolyphony = 16;

AddChild(HitSound);
AddChild(MissSound);
AddChild(FailSound);
AddChild(Song);
AddChild(MenuMusic);

SkinManager.Instance.Loaded += UpdateSkin;

UpdateSkin(SkinManager.Instance.Skin);

Song.Finished += () =>
{
if (isScopedPlayback())
{
StopScopedSession();
return;
}

switch (SceneManager.Scene.Name)
{
case "SceneMenu":
Expand All @@ -67,15 +87,7 @@ public override void _Ready()

SettingsManager.Instance.Loaded += UpdateVolume;
Lobby.Instance.SpeedChanged += (speed) => { SoundManager.Song.PitchScale = (float)speed; };
MapManager.Selected.ValueChanged += (_, selected) =>
{
var map = selected.Value;

if (Map == null || Map.Name != map.Name)
{
PlayJukebox(map);
}
};
MapManager.Selected.ValueChanged += (_, _) => RefreshMenuMusicPlayback();

MapManager.MapDeleted += (map) =>
{
Expand All @@ -86,6 +98,12 @@ public override void _Ready()
return;
}

if (isScopedPlayback())
{
StopScopedSession();
return;
}

if (JukeboxQueue.Length == 0)
{
Song.Stop();
Expand All @@ -108,19 +126,30 @@ static void start()
{
PlayJukebox(new Random().Next(0, JukeboxQueue.Length));
}
else
{
StopScopedSession();
}
}

if (MapManager.Initialized)
{
start();
printSongPlaybackState();
return;
}

MapManager.MapsInitialized += _ => start();

RefreshMenuMusicPlayback();
printSongPlaybackState();
}

public override void _Process(double delta)
{
RefreshMenuMusicPlayback();
printSongPlaybackState();

if (volumePopupShown && Time.GetTicksMsec() - lastVolumeChange >= 1000)
{
volumePopupShown = false;
Expand Down Expand Up @@ -167,6 +196,20 @@ public override void _UnhandledInput(InputEvent @event)

public static void PlayJukebox(Map map, bool setRichPresence = true)
{
if (map == null)
{
return;
}

if (isScopedPlayback())
{
StartMapSelectionPlayback(map, setRichPresence);
return;
}

MenuMusic?.Stop();
menuMusicPausedByUser = false;

Map = map;

if (map.AudioBuffer == null)
Expand Down Expand Up @@ -212,6 +255,117 @@ public static void PlayJukebox(int index = -1, bool setRichPresence = true)
PlayJukebox(map, setRichPresence);
}

public static void StartMapSelectionPlayback(Map map, bool setRichPresence = true)
{
if (map == null)
{
return;
}

Song.Stop();
Song.StreamPaused = false;
Song.PitchScale = (float)Lobby.Speed;
MenuMusic?.Stop();
menuMusicPausedByUser = false;

Map = map;
Scope = PlaybackScope.Preview;

if (MapManager.Maps != null)
{
int mapIndex = MapManager.Maps.FindIndex(x => x.Id == map.Id);
if (mapIndex >= 0)
{
JukeboxIndex = mapIndex;
}
}

Song.Stream = Util.Audio.LoadFromFile($"{MapUtil.MapsCacheFolder}/{map.Name}/audio.{map.AudioExt}");
Song.Play(0);

Instance.JukeboxPlayed?.Invoke(map);

if (setRichPresence)
{
Discord.Client.UpdateState($"Listening to {map.PrettyTitle}");
}
}

public static void BeginGameplayScope(Map map)
{
if (!isScopedPlayback())
{
return;
}

Map = map;
Scope = PlaybackScope.GameplayResults;
MenuMusic?.Stop();
}

public static void StopScopedSession()
{
Song.Stop();
Song.StreamPaused = false;
Map = null;
Scope = PlaybackScope.Silent;
Instance.JukeboxEmpty?.Invoke();

RefreshMenuMusicPlayback();
}

public static bool IsJukeboxPaused()
{
if (Song != null && Song.StreamPaused)
{
return true;
}

return menuMusicPausedByUser;
}

public static bool ToggleJukeboxPause()
{
if (Song != null && (Song.Playing || Song.StreamPaused))
{
Song.StreamPaused = !Song.StreamPaused;
return Song.StreamPaused;
}

if (MenuMusic == null || MenuMusic.Stream == null)
{
return false;
}

if (!shouldPlayMenuMusic() && !menuMusicPausedByUser)
{
return false;
}

menuMusicPausedByUser = !menuMusicPausedByUser;

if (menuMusicPausedByUser)
{
MenuMusic.StreamPaused = true;
}
else
{
if (!MenuMusic.Playing)
{
MenuMusic.Play();
}

MenuMusic.StreamPaused = false;
}

return menuMusicPausedByUser;
}

private static bool isScopedPlayback()
{
return !SettingsManager.Instance.Settings.AutoplayJukebox.Value;
}

public static float ComputeVolumeDb(float volume, float master, float range)
{
if (volume <= 0 || master <= 0) return float.NegativeInfinity;
Expand All @@ -223,10 +377,32 @@ public static void UpdateVolume()
var settings = SettingsManager.Instance.Settings;

Song.VolumeDb = ComputeVolumeDb(settings.VolumeMusic.Value, settings.VolumeMaster.Value, 70);
HitSound.VolumeDb = ComputeVolumeDb(settings.VolumeSFX.Value, settings.VolumeMaster.Value, 80);
MenuMusic.VolumeDb = ComputeVolumeDb(settings.VolumeMenuMusic.Value, settings.VolumeMaster.Value, 70);
HitSound.VolumeDb = ComputeVolumeDb(settings.VolumeHitSound.Value, settings.VolumeMaster.Value, 80);
MissSound.VolumeDb = ComputeVolumeDb(settings.VolumeMissSound.Value, settings.VolumeMaster.Value, 80);
FailSound.VolumeDb = ComputeVolumeDb(settings.VolumeSFX.Value, settings.VolumeMaster.Value, 80);
}

public static void PlayHitSound()
{
if (!isSoundEffectEnabled(SettingsManager.Instance?.Settings.EnableHitSound, HitSound))
{
return;
}

HitSound.Play();
}

public static void PlayMissSound()
{
if (!isSoundEffectEnabled(SettingsManager.Instance?.Settings.EnableMissSound, MissSound))
{
return;
}

MissSound.Play();
}

public static void UpdateJukeboxQueue()
{
JukeboxQueue = [.. MapManager.Maps.Select(x => x.Id)];
Expand All @@ -235,6 +411,87 @@ public static void UpdateJukeboxQueue()
public void UpdateSkin(SkinProfile skin)
{
HitSound.Stream = Util.Audio.LoadStream(skin.HitSoundBuffer);
MissSound.Stream = Util.Audio.LoadStream(skin.MissSoundBuffer);
FailSound.Stream = Util.Audio.LoadStream(skin.FailSoundBuffer);
MenuMusic.Stream = Util.Audio.LoadStream(skin.MenuMusicBuffer);

RefreshMenuMusicPlayback();
}

public static void RefreshMenuMusicPlayback()
{
if (MenuMusic == null)
{
return;
}

if (menuMusicPausedByUser)
{
if (MenuMusic.Playing && !MenuMusic.StreamPaused)
{
MenuMusic.StreamPaused = true;
}

return;
}

if (shouldPlayMenuMusic())
{
if (!MenuMusic.Playing)
{
MenuMusic.Play();
}

if (MenuMusic.StreamPaused)
{
MenuMusic.StreamPaused = false;
}
}
else if (MenuMusic.Playing)
{
MenuMusic.Stop();
}
}

private static bool shouldPlayMenuMusic()
{
if (!SettingsManager.Instance.Settings.EnableMenuMusic.Value)
{
return false;
}

if (MenuMusic.Stream == null)
{
return false;
}

if (SceneManager.Scene is not MainMenu)
{
return false;
}

if (Song != null && Song.Playing)
{
return false;
}

return true;
}

private static bool isSoundEffectEnabled(SettingsItem<bool> setting, AudioStreamPlayer player)
{
return setting != null && setting.Value && player?.Stream != null;
}

private static void printSongPlaybackState()
{
bool isSongPlaying = Song != null && Song.Playing;

if (jeeping == isSongPlaying) // vroom vroom jeep
{
return;
}

jeeping = isSongPlaying; //jeeps go beep beep
}
}
Loading