Skip to content

Commit

Permalink
add: TTS
Browse files Browse the repository at this point in the history
  • Loading branch information
Spatison committed Nov 5, 2024
1 parent 7c4566f commit bed0bbb
Show file tree
Hide file tree
Showing 43 changed files with 4,878 additions and 3 deletions.
1 change: 1 addition & 0 deletions Content.Client/Audio/ContentAudioSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
public const float LobbyMultiplier = 3f;
public const float InterfaceMultiplier = 2f;
public const float AnnouncerMultiplier = 3f;
public const float TTSMultiplier = 1f; // WD EDIT

public override void Initialize()
{
Expand Down
3 changes: 3 additions & 0 deletions Content.Client/Entry/EntryPoint.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Content.Client._White.TTS;
using Content.Client.Administration.Managers;
using Content.Client.Changelog;
using Content.Client.Chat.Managers;
Expand Down Expand Up @@ -74,6 +75,7 @@ public sealed class EntryPoint : GameClient
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly JoinQueueManager _joinQueue = default!;
[Dependency] private readonly DiscordAuthManager _discordAuth = default!;
[Dependency] private readonly TTSManager _ttsManager = default!; // WD EDIT

public override void Init()
{
Expand Down Expand Up @@ -169,6 +171,7 @@ public override void PostInit()
_documentParsingManager.Initialize();
_joinQueue.Initialize();
_discordAuth.Initialize();
_ttsManager.Initialize(); // WD EDIT

_baseClient.RunLevelChanged += (_, args) =>
{
Expand Down
2 changes: 2 additions & 0 deletions Content.Client/IoC/ClientContentIoC.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Content.Client._White.TTS;
using Content.Client.Administration.Managers;
using Content.Client.Changelog;
using Content.Client.Chat.Managers;
Expand Down Expand Up @@ -54,6 +55,7 @@ public static void Register()
collection.Register<ISharedPlaytimeManager, JobRequirementsManager>();
IoCManager.Register<JoinQueueManager>();
IoCManager.Register<DiscordAuthManager>();
IoCManager.Register<TTSManager>(); // WD EDIT
}
}
}
9 changes: 9 additions & 0 deletions Content.Client/Lobby/UI/HumanoidProfileEditor.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@
<Control HorizontalExpand="True"/>
<OptionButton Name="SexButton" HorizontalAlignment="Right" />
</BoxContainer>
<!--WD EDIT START-->
<!--TTS-->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-voice-label'}" />
<Control HorizontalExpand="True"/>
<OptionButton Name="VoiceButton" HorizontalAlignment="Right" />
<Button Name="VoicePlayButton" Text="" MaxWidth="80" />
</BoxContainer>
<!--WD EDIT END-->
<!-- Pronouns -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-pronouns-label'}" />
Expand Down
20 changes: 19 additions & 1 deletion Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ public HumanoidProfileEditor(

#endregion Sex

// WD EDIT START
#region Voice

InitializeVoice();

#endregion
// WD EDIT END

#region Age

AgeEdit.OnTextChanged += args =>
Expand Down Expand Up @@ -636,6 +644,7 @@ public void SetProfile(HumanoidCharacterProfile? profile, int? slot)

UpdateNameEdit();
UpdateSexControls();
UpdateTTSVoicesControls(); // WD EDIT
UpdateGenderControls();
UpdateSkinColor();
UpdateSpawnPriorityControls();
Expand Down Expand Up @@ -1122,10 +1131,19 @@ private void SetSex(Sex newSex)
}
UpdateGenderControls();
Markings.SetSex(newSex);
UpdateTTSVoicesControls(); // WD EDIT
ReloadProfilePreview();
SetDirty();
}

// WD EDIT START
private void SetVoice(string newVoice)
{
Profile = Profile?.WithVoice(newVoice);
IsDirty = true;
}
// WD EDIT END

private void SetGender(Gender newGender)
{
Profile = Profile?.WithGender(newGender);
Expand Down Expand Up @@ -1437,7 +1455,7 @@ private void UpdateWeight()
var avg = (Profile.Width + Profile.Height) / 2;
var weight = MathF.Round(MathF.PI * MathF.Pow(radius * avg, 2) * density);
WeightLabel.Text = Loc.GetString("humanoid-profile-editor-weight-label", ("weight", (int) weight));
}
}
else // Whelp, the fixture doesn't exist, guesstimate it instead
WeightLabel.Text = Loc.GetString("humanoid-profile-editor-weight-label", ("weight", (int) 71));

Expand Down
15 changes: 15 additions & 0 deletions Content.Client/Options/UI/Tabs/AudioTab.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@
<Label Name="AmbientMusicVolumeLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0"/>
</BoxContainer>
<!--WD EDIT START-->
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-tts-volume'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
<Slider Name="TtsVolumeSlider"
MinValue="0"
MaxValue="200"
HorizontalExpand="True"
MinSize="80 0"
Rounded="True" />
<Control MinSize="8 0" />
<Label Name="TtsVolumeLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0" />
</BoxContainer>
<!--WD EDIT END-->
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-ambience-volume'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
Expand Down
4 changes: 4 additions & 0 deletions Content.Client/Options/UI/Tabs/AudioTab.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Content.Client.Audio;
using Content.Shared._White;
using Content.Shared.CCVar;
using Robust.Client.Audio;
using Robust.Client.AutoGenerated;
Expand Down Expand Up @@ -40,6 +41,7 @@ public AudioTab()
LobbyVolumeSlider,
InterfaceVolumeSlider,
AnnouncerVolumeSlider,
TtsVolumeSlider, // WD EDIT

LobbyMusicCheckBox,
RestartSoundsCheckBox,
Expand Down Expand Up @@ -125,6 +127,7 @@ private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
_cfg.SetCVar(CCVars.LobbyMusicVolume, LobbyVolumeSlider.Value / 100f * ContentAudioSystem.LobbyMultiplier);
_cfg.SetCVar(CCVars.InterfaceVolume, InterfaceVolumeSlider.Value / 100f * ContentAudioSystem.InterfaceMultiplier);
_cfg.SetCVar(CCVars.AnnouncerVolume, AnnouncerVolumeSlider.Value / 100f * ContentAudioSystem.AnnouncerMultiplier);
_cfg.SetCVar(WhiteCVars.TtsVolume, TtsVolumeSlider.Value / 100f * ContentAudioSystem.TTSMultiplier); // WD EDIT

_cfg.SetCVar(CCVars.MaxAmbientSources, (int)AmbienceSoundsSlider.Value);

Expand All @@ -151,6 +154,7 @@ private void Reset()
LobbyVolumeSlider.Value = _cfg.GetCVar(CCVars.LobbyMusicVolume) * 100f / ContentAudioSystem.LobbyMultiplier;
InterfaceVolumeSlider.Value = _cfg.GetCVar(CCVars.InterfaceVolume) * 100f / ContentAudioSystem.InterfaceMultiplier;
AnnouncerVolumeSlider.Value = _cfg.GetCVar(CCVars.AnnouncerVolume) * 100f / ContentAudioSystem.AnnouncerMultiplier;
TtsVolumeSlider.Value = _cfg.GetCVar(WhiteCVars.TtsVolume) * 100f / ContentAudioSystem.TTSMultiplier; // WD EDIT

AmbienceSoundsSlider.Value = _cfg.GetCVar(CCVars.MaxAmbientSources);

Expand Down
77 changes: 77 additions & 0 deletions Content.Client/_White/TTS/HumanoidProfileEditor.TTS.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Linq;
using Content.Client._White.TTS;
using Content.Shared.Preferences;
using Content.Shared._White.TTS;
using Robust.Shared.Random;

// ReSharper disable InconsistentNaming
// ReSharper disable once CheckNamespace
namespace Content.Client.Lobby.UI;

public sealed partial class HumanoidProfileEditor
{
private TTSSystem _ttsSystem = default!;
private TTSManager _ttsManager = default!;
private IRobustRandom _random = default!;

private List<TTSVoicePrototype> _voiceList = default!;

private readonly string[] _sampleText =
[
"Помогите, клоун насилует в технических тоннелях!",
"ХоС, ваши сотрудники украли у меня собаку и засунули ее в стиральную машину!",
"Агент синдиката украл пиво из бара и взорвался!",
"Врача! Позовите врача!"
];

private void InitializeVoice()
{
_random = IoCManager.Resolve<IRobustRandom>();
_ttsManager = IoCManager.Resolve<TTSManager>();
_ttsSystem = IoCManager.Resolve<IEntityManager>().System<TTSSystem>();
_voiceList = _prototypeManager.EnumeratePrototypes<TTSVoicePrototype>().Where(o => o.RoundStart).ToList();

VoiceButton.OnItemSelected += args =>
{
VoiceButton.SelectId(args.Id);
SetVoice(_voiceList[args.Id].ID);
};

VoicePlayButton.OnPressed += _ => { PlayTTS(); };
}

private void UpdateTTSVoicesControls()
{
if (Profile is null)
return;

VoiceButton.Clear();

var firstVoiceChoiceId = 1;
for (var i = 0; i < _voiceList.Count; i++)
{
var voice = _voiceList[i];
if (!HumanoidCharacterProfile.CanHaveVoice(voice, Profile.Sex))
continue;

var name = Loc.GetString(voice.Name);
VoiceButton.AddItem(name, i);

if (firstVoiceChoiceId == 1)
firstVoiceChoiceId = i;
}

var voiceChoiceId = _voiceList.FindIndex(x => x.ID == Profile.Voice);
if (!VoiceButton.TrySelectId(voiceChoiceId) && VoiceButton.TrySelectId(firstVoiceChoiceId))
SetVoice(_voiceList[firstVoiceChoiceId].ID);
}

private void PlayTTS()
{
if (Profile is null)
return;

_ttsSystem.StopCurrentTTS(PreviewDummy);
_ttsManager.RequestTTS(PreviewDummy, _random.Pick(_sampleText), Profile.Voice);
}
}
24 changes: 24 additions & 0 deletions Content.Client/_White/TTS/TTSManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Content.Shared._White.TTS;
using Robust.Shared.Network;

namespace Content.Client._White.TTS;

// ReSharper disable once InconsistentNaming
public sealed class TTSManager
{
[Dependency] private readonly IClientNetManager _netMgr = default!;
[Dependency] private readonly EntityManager _entityManager = default!;

public void Initialize()
{
_netMgr.RegisterNetMessage<MsgRequestTTS>();
}

// ReSharper disable once InconsistentNaming
public void RequestTTS(EntityUid uid, string text, string voiceId)
{
var netEntity = _entityManager.GetNetEntity(uid);
var msg = new MsgRequestTTS { Text = text, Uid = netEntity, VoiceId = voiceId };
_netMgr.ClientSendMessage(msg);
}
}
130 changes: 130 additions & 0 deletions Content.Client/_White/TTS/TTSSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
using System.IO;
using Content.Shared._White;
using Content.Shared._White.TTS.Events;
using Robust.Client.Audio;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Components;
using Robust.Shared.Configuration;

namespace Content.Client._White.TTS;

// ReSharper disable InconsistentNaming
public sealed class TTSSystem : EntitySystem
{
[Dependency] private readonly IAudioManager _audioManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly AudioSystem _audioSystem = default!;

private float _volume;
private readonly Dictionary<EntityUid, AudioComponent> _currentlyPlaying = new();

private readonly Dictionary<EntityUid, Queue<AudioStreamWithParams>> _enquedStreams = new();

// Same as Server.ChatSystem.VoiceRange
private const float VoiceRange = 10;

public override void Initialize()
{
_cfg.OnValueChanged(WhiteCVars.TtsVolume, OnTtsVolumeChanged, true);

SubscribeNetworkEvent<PlayTTSEvent>(OnPlayTTS);
}

public override void Shutdown()
{
base.Shutdown();
_cfg.UnsubValueChanged(WhiteCVars.TtsVolume, OnTtsVolumeChanged);
ClearQueues();
}

public override void FrameUpdate(float frameTime)
{
foreach (var (uid, audioComponent) in _currentlyPlaying)
{
if (!Deleted(uid) && audioComponent is { Running: true, Playing: true }
|| !_enquedStreams.TryGetValue(uid, out var queue)
|| !queue.TryDequeue(out var toPlay))
continue;

var audio = _audioSystem.PlayEntity(toPlay.Stream, uid, toPlay.Params);
if (!audio.HasValue)
continue;

_currentlyPlaying[uid] = audio.Value.Component;
}
}

private void OnTtsVolumeChanged(float volume)
{
_volume = volume;
}

private void OnPlayTTS(PlayTTSEvent ev)
{
PlayTTS(GetEntity(ev.Uid), ev.Data, ev.BoostVolume ? _volume + 5 : _volume);
}

public void PlayTTS(EntityUid uid, byte[] data, float volume)
{
if (_volume <= -20f)
return;

var stream = CreateAudioStream(data);

var audioParams = new AudioParams
{
Volume = volume,
MaxDistance = VoiceRange
};

var audioStream = new AudioStreamWithParams(stream, audioParams);
EnqueueAudio(uid, audioStream);
}

public void StopCurrentTTS(EntityUid uid)
{
if (!_currentlyPlaying.TryGetValue(uid, out var audio))
return;

_audioSystem.Stop(audio.Owner);
}

private void EnqueueAudio(EntityUid uid, AudioStreamWithParams audioStream)
{
if (!_currentlyPlaying.ContainsKey(uid))
{
var audio = _audioSystem.PlayEntity(audioStream.Stream, uid, audioStream.Params);
if (!audio.HasValue)
return;

_currentlyPlaying[uid] = audio.Value.Component;
return;
}

if (_enquedStreams.TryGetValue(uid, out var queue))
{
queue.Enqueue(audioStream);
return;
}

queue = new Queue<AudioStreamWithParams>();
queue.Enqueue(audioStream);
_enquedStreams[uid] = queue;
}

private void ClearQueues()
{
foreach (var (_, queue) in _enquedStreams)
{
queue.Clear();
}
}

private AudioStream CreateAudioStream(byte[] data)
{
var dataStream = new MemoryStream(data) { Position = 0 };
return _audioManager.LoadAudioOggVorbis(dataStream);
}

private record AudioStreamWithParams(AudioStream Stream, AudioParams Params);
}
Loading

0 comments on commit bed0bbb

Please sign in to comment.