CatStation/Content.Client/Audio/ContentAudioSystem.cs
Morb0 1e0bee212f Merge remote-tracking branch 'upstream/master' into upstream-sync
# Conflicts:
#	.github/workflows/publish.yml
#	Content.Server/GameTicking/GameTicker.RoundFlow.cs
#	Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs
#	Resources/Prototypes/Datasets/tips.yml
#	Resources/Prototypes/Maps/barratry.yml
#	Resources/ServerInfo/Gameplay.txt
#	Resources/ServerInfo/Guidebook/Antagonist/MinorAntagonists.xml
#	Resources/ServerInfo/Guidebook/Engineering/Power.xml
#	Resources/ServerInfo/Guidebook/Engineering/Singularity.xml
#	Resources/ServerInfo/Guidebook/Jobs.xml
#	Resources/ServerInfo/Guidebook/Science/MachineUpgrading.xml
#	Resources/Textures/Clothing/Mask/bat.rsi/meta.json
#	Resources/Textures/Clothing/Mask/bear.rsi/meta.json
#	Resources/Textures/Clothing/Mask/bee.rsi/meta.json
#	Resources/Textures/Clothing/Mask/breath.rsi/meta.json
#	Resources/Textures/Clothing/Mask/clown.rsi/meta.json
#	Resources/Textures/Clothing/Mask/cluwne.rsi/meta.json
#	Resources/Textures/Clothing/Mask/ert.rsi/meta.json
#	Resources/Textures/Clothing/Mask/fox.rsi/meta.json
#	Resources/Textures/Clothing/Mask/gas.rsi/meta.json
#	Resources/Textures/Clothing/Mask/gascaptain.rsi/meta.json
#	Resources/Textures/Clothing/Mask/gascentcom.rsi/meta.json
#	Resources/Textures/Clothing/Mask/gasexplorer.rsi/meta.json
#	Resources/Textures/Clothing/Mask/gassecurity.rsi/meta.json
#	Resources/Textures/Clothing/Mask/gassyndicate.rsi/meta.json
#	Resources/Textures/Clothing/Mask/jackal.rsi/meta.json
#	Resources/Textures/Clothing/Mask/joy.rsi/meta.json
#	Resources/Textures/Clothing/Mask/medical.rsi/meta.json
#	Resources/Textures/Clothing/Mask/medicalsecurity.rsi/meta.json
#	Resources/Textures/Clothing/Mask/merc.rsi/meta.json
#	Resources/Textures/Clothing/Mask/mime.rsi/meta.json
#	Resources/Textures/Clothing/Mask/muzzle.rsi/meta.json
#	Resources/Textures/Clothing/Mask/rat.rsi/meta.json
#	Resources/Textures/Clothing/Mask/raven.rsi/meta.json
#	Resources/Textures/Clothing/Mask/sadmime.rsi/meta.json
#	Resources/Textures/Clothing/Mask/scaredmime.rsi/meta.json
#	Resources/Textures/Clothing/Mask/sexyclown.rsi/meta.json
#	Resources/Textures/Clothing/Mask/sexymime.rsi/meta.json
#	Resources/Textures/Clothing/Mask/squadron.rsi/meta.json
#	Resources/Textures/Clothing/Mask/sterile.rsi/meta.json
#	Resources/Textures/Clothing/Mask/swat.rsi/meta.json
2024-01-10 00:23:02 +03:00

171 lines
5.2 KiB
C#

using Content.Shared.Audio;
using Content.Shared.GameTicking;
using Robust.Client.Audio;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using AudioComponent = Robust.Shared.Audio.Components.AudioComponent;
namespace Content.Client.Audio;
public sealed partial class ContentAudioSystem : SharedContentAudioSystem
{
[Dependency] private readonly IAudioManager _audioManager = default!;
[Dependency] private readonly IResourceCache _cache = default!;
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
// Need how much volume to change per tick and just remove it when it drops below "0"
private readonly Dictionary<EntityUid, float> _fadingOut = new();
// Need volume change per tick + target volume.
private readonly Dictionary<EntityUid, (float VolumeChange, float TargetVolume)> _fadingIn = new();
private readonly List<EntityUid> _fadeToRemove = new();
private const float MinVolume = -32f;
private const float DefaultDuration = 2f;
/*
* Gain multipliers for specific audio sliders.
* The float value will get multiplied by this when setting
* i.e. a gain of 0.5f x 3 will equal 1.5f which is supported in OpenAL.
*/
public const float MasterVolumeMultiplier = 3f;
public const float MidiVolumeMultiplier = 0.25f;
public const float AmbienceMultiplier = 3f;
public const float AmbientMusicMultiplier = 3f;
public const float LobbyMultiplier = 3f;
public const float InterfaceMultiplier = 2f;
public const float TtsMultiplier = 3f; // Corvax-TTS
public override void Initialize()
{
base.Initialize();
UpdatesOutsidePrediction = true;
InitializeAmbientMusic();
SubscribeNetworkEvent<RoundRestartCleanupEvent>(OnRoundCleanup);
}
private void OnRoundCleanup(RoundRestartCleanupEvent ev)
{
_fadingOut.Clear();
// Preserve lobby music but everything else should get dumped.
var lobbyStream = EntityManager.System<BackgroundAudioSystem>().LobbyStream;
TryComp(lobbyStream, out AudioComponent? audioComp);
var oldGain = audioComp?.Gain;
SilenceAudio();
if (oldGain != null)
{
Audio.SetGain(lobbyStream, oldGain.Value, audioComp);
}
}
public override void Shutdown()
{
base.Shutdown();
ShutdownAmbientMusic();
}
public override void Update(float frameTime)
{
base.Update(frameTime);
if (!_timing.IsFirstTimePredicted)
return;
UpdateAmbientMusic();
UpdateFades(frameTime);
}
#region Fades
public void FadeOut(EntityUid? stream, AudioComponent? component = null, float duration = DefaultDuration)
{
if (stream == null || duration <= 0f || !Resolve(stream.Value, ref component))
return;
// Just in case
// TODO: Maybe handle the removals by making it seamless?
_fadingIn.Remove(stream.Value);
var diff = component.Volume - MinVolume;
_fadingOut.Add(stream.Value, diff / duration);
}
public void FadeIn(EntityUid? stream, AudioComponent? component = null, float duration = DefaultDuration)
{
if (stream == null || duration <= 0f || !Resolve(stream.Value, ref component) || component.Volume < MinVolume)
return;
_fadingOut.Remove(stream.Value);
var curVolume = component.Volume;
var change = (curVolume - MinVolume) / duration;
_fadingIn.Add(stream.Value, (change, component.Volume));
component.Volume = MinVolume;
}
private void UpdateFades(float frameTime)
{
_fadeToRemove.Clear();
foreach (var (stream, change) in _fadingOut)
{
if (!TryComp(stream, out AudioComponent? component))
{
_fadeToRemove.Add(stream);
continue;
}
var volume = component.Volume - change * frameTime;
volume = MathF.Max(MinVolume, volume);
_audio.SetVolume(stream, volume, component);
if (component.Volume.Equals(MinVolume))
{
_audio.Stop(stream);
_fadeToRemove.Add(stream);
}
}
foreach (var stream in _fadeToRemove)
{
_fadingOut.Remove(stream);
}
_fadeToRemove.Clear();
foreach (var (stream, (change, target)) in _fadingIn)
{
// Cancelled elsewhere
if (!TryComp(stream, out AudioComponent? component))
{
_fadeToRemove.Add(stream);
continue;
}
var volume = component.Volume + change * frameTime;
volume = MathF.Max(target, volume);
_audio.SetVolume(stream, volume, component);
if (component.Volume.Equals(target))
{
_fadeToRemove.Add(stream);
}
}
foreach (var stream in _fadeToRemove)
{
_fadingIn.Remove(stream);
}
}
#endregion
}
/// <summary>
/// Raised whenever ambient music tries to play.
/// </summary>
[ByRefEvent]
public record struct PlayAmbientMusicEvent(bool Cancelled = false);