using Content.Shared.Corvax.TTS;
using Robust.Shared.Audio.Components;
using Robust.Shared.Audio.Effects;
namespace Content.Client.Corvax.TTS;
public sealed partial class TTSSystem
{
private EntityUid? _radioAuxiliaryEntity;
private EntityUid? _voiceAuxiliaryEntity;
private EntityUid? _cachedVoiceEffectEntity;
private EntityUid? _cachedRadioEffectEntity;
private readonly object _voiceEffectLock = new();
private readonly object _radioEffectLock = new();
///
/// It frees up only the vocal effect and its auxiliary.
///
private void ShutdownVoiceEffect()
{
if (_cachedVoiceEffectEntity != null && !TerminatingOrDeleted(_cachedVoiceEffectEntity.Value))
{
_audio.Stop(_cachedVoiceEffectEntity);
Del(_cachedVoiceEffectEntity);
}
_cachedVoiceEffectEntity = null;
if (_voiceAuxiliaryEntity != null && !TerminatingOrDeleted(_voiceAuxiliaryEntity.Value))
{
if (TryComp(_voiceAuxiliaryEntity.Value, out var auxComp))
{
auxComp.Auxiliary?.SetEffect(null);
auxComp.Auxiliary?.Dispose();
}
Del(_voiceAuxiliaryEntity);
}
_voiceAuxiliaryEntity = null;
}
///
/// It frees up only the radio effect and its auxiliary.
///
private void ShutdownRadioEffect()
{
if (_cachedRadioEffectEntity != null && !TerminatingOrDeleted(_cachedRadioEffectEntity.Value))
{
_audio.Stop(_cachedRadioEffectEntity);
Del(_cachedRadioEffectEntity);
}
_cachedRadioEffectEntity = null;
if (_radioAuxiliaryEntity != null && !TerminatingOrDeleted(_radioAuxiliaryEntity.Value))
{
if (TryComp(_radioAuxiliaryEntity.Value, out var auxComp))
{
auxComp.Auxiliary?.SetEffect(null);
auxComp.Auxiliary?.Dispose();
}
Del(_radioAuxiliaryEntity);
}
_radioAuxiliaryEntity = null;
}
///
/// Clears all EFX-effects.
///
private void ShutdownEffects()
{
ShutdownVoiceEffect();
ShutdownRadioEffect();
}
private void ApplyVoiceEffect(Entity ent, TTSVoiceEffectPreset effect)
{
if (!_ttsEnabled)
return;
if (effect == TTSVoiceEffectPreset.None)
return;
if (!EnsureVoiceEffectInitialized())
return;
if (_voiceAuxiliaryEntity == null)
return;
try
{
_audio.SetAuxiliary(ent.Owner, ent.Comp, _voiceAuxiliaryEntity.Value);
}
catch (Exception ex)
{
_sawmill.Debug($"Failed to apply voice effect: {ex.Message}");
}
}
private void ApplyRadioEffect((EntityUid Entity, AudioComponent Component) audio)
{
if (!_ttsEnabled)
return;
if (!EnsureRadioEffectInitialized())
return;
if (_radioAuxiliaryEntity == null)
return;
try
{
var (entity, comp) = audio;
_audio.SetAuxiliary(entity, comp, _radioAuxiliaryEntity.Value);
}
catch (Exception ex)
{
_sawmill.Debug($"Failed to apply radio EFX effect: {ex.Message}");
}
}
///
/// Creates an effect and an auxiliary, configures the preset, and links them.
/// Rolls back everything created and returns null if any error occurs.
///
private (EntityUid Effect, EntityUid Auxiliary)? TryCreateEffectWithAuxiliary(ReverbProperties preset, string debugName)
{
EntityUid? effectUid = null;
EntityUid? auxUid = null;
try
{
var (effect, effectComp) = _audio.CreateEffect();
effectUid = effect;
_audio.SetEffectPreset(effect, effectComp, preset);
var (aux, auxComp) = _audio.CreateAuxiliary();
auxUid = aux;
_audio.SetEffect(aux, auxComp, effect);
return (effect, aux);
}
catch (Exception ex)
{
_sawmill.Warning($"Failed to initialize {debugName} effect: {ex.Message}");
if (auxUid != null && !TerminatingOrDeleted(auxUid.Value))
{
if (TryComp(auxUid.Value, out var auxComp))
{
auxComp.Auxiliary?.SetEffect(null);
auxComp.Auxiliary?.Dispose();
}
Del(auxUid.Value);
}
if (effectUid != null && !TerminatingOrDeleted(effectUid.Value))
{
_audio.Stop(effectUid.Value);
Del(effectUid.Value);
}
return null;
}
}
///
/// Initializes voice effect upon first use, if necessary.
///
private bool EnsureVoiceEffectInitialized()
{
if (!_ttsEnabled)
return false;
if (_voiceEffectPreset == TTSVoiceEffectPreset.None)
{
_cachedVoiceEffectEntity = null;
return false;
}
if (_cachedVoiceEffectEntity != null)
return true;
lock (_voiceEffectLock)
{
if (_cachedVoiceEffectEntity != null)
return true;
if (_voiceEffectPreset == TTSVoiceEffectPreset.None)
{
_cachedVoiceEffectEntity = null;
return false;
}
var result = TryCreateEffectWithAuxiliary(GetVoicePreset(_voiceEffectPreset), $"voice ({_voiceEffectPreset})");
if (result == null)
return false;
_cachedVoiceEffectEntity = result.Value.Effect;
_voiceAuxiliaryEntity = result.Value.Auxiliary;
_sawmill.Info($"Voice effect initialized: {_voiceEffectPreset}");
return true;
}
}
///
/// Initializes radio effect on first use.
///
private bool EnsureRadioEffectInitialized()
{
if (!_ttsEnabled)
return false;
if (_cachedRadioEffectEntity != null)
return true;
lock (_radioEffectLock)
{
if (_cachedRadioEffectEntity != null)
return true;
var result = TryCreateEffectWithAuxiliary(CreateRadioPreset(), "radio");
if (result == null)
return false;
_cachedRadioEffectEntity = result.Value.Effect;
_radioAuxiliaryEntity = result.Value.Auxiliary;
return true;
}
}
}