Skip to content

Commit

Permalink
Further stability to edge voice
Browse files Browse the repository at this point in the history
  • Loading branch information
Osmodium committed Feb 20, 2024
1 parent e86f465 commit 13d15c7
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 94 deletions.
4 changes: 4 additions & 0 deletions SpeechMod/Configuration/SettingEntries/PlaybackStop.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using HarmonyLib;
using Kingmaker;
using Kingmaker.Blueprints.Root;
using Kingmaker.Code.UI.MVVM.View.Common.PC;
using Kingmaker.Code.UI.MVVM.VM.WarningNotification;
using Kingmaker.Localization;
using Kingmaker.UI.Pointer;
using SpeechMod.Configuration.Settings;
#if DEBUG
using UnityEngine;
#endif

namespace SpeechMod.Configuration.SettingEntries;

Expand Down
2 changes: 1 addition & 1 deletion SpeechMod/Info.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"AssemblyName": "W40KRTSpeechMod.dll",
"EntryMethod": "SpeechMod.Main.Load",
"HomePage": "https://www.nexusmods.com/warhammer40kroguetrader/mods/75",
"Version": "0.9.3"
"Version": "0.9.4"
}
2 changes: 1 addition & 1 deletion SpeechMod/Main.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using HarmonyLib;
using SpeechMod.Configuration;
using SpeechMod.Configuration.Settings;
using SpeechMod.Unity;
using SpeechMod.Unity.Extensions;
using SpeechMod.Voice;
using System;
Expand All @@ -14,6 +13,7 @@
using UnityEngine;
using UnityModManagerNet;
using SpeechMod.Unity.GUIs;
using SpeechMod.Unity.Voices;

namespace SpeechMod;

Expand Down
20 changes: 14 additions & 6 deletions SpeechMod/Patches/SurfaceStaticPartPCView_Patch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ namespace SpeechMod.Patches;
[HarmonyPatch]
public static class SurfaceStaticPartPCView_Patch
{
private const string SPEECHMOD_DIALOGBUTTON_NAME = "SpeechMod_DialogButton";
private const string SURFACE_SCROLL_VIEW_PATH = "/SurfacePCView(Clone)/SurfaceStaticPartPCView/StaticCanvas/SurfaceDialogPCView/LeftSide/CueAndHistoryPlace/ScrollView";
private const string SPACE_SCROLL_VIEW_PATH = "/SpacePCView(Clone)/SpaceStaticPartPCView/StaticCanvas/SurfaceDialogPCView/LeftSide/CueAndHistoryPlace/ScrollView";

[HarmonyPatch(typeof(SurfaceStaticPartPCView), "Initialize")]
[HarmonyPatch(typeof(SurfaceStaticPartPCView), nameof(SurfaceStaticPartPCView.BindViewImplementation))]
[HarmonyPostfix]
public static void AddSurfaceDialogButton()
{
Expand All @@ -23,13 +24,13 @@ public static void AddSurfaceDialogButton()

#if DEBUG
var sceneName = Game.Instance!.CurrentlyLoadedArea!.ActiveUIScene!.SceneName;
Debug.Log($"{nameof(SurfaceStaticPartPCView)}_Initialize_Postfix @ {sceneName}");
Debug.Log($"{nameof(SurfaceStaticPartPCView)}_BindViewImplementation_Postfix @ {sceneName}");
#endif

AddDialogSpeechButton(SURFACE_SCROLL_VIEW_PATH);
}

[HarmonyPatch(typeof(SpaceStaticPartPCView), "Initialize")]
[HarmonyPatch(typeof(SpaceStaticPartPCView), nameof(SpaceStaticPartPCView.BindViewImplementation))]
[HarmonyPostfix]
public static void AddSpaceDialogButton()
{
Expand All @@ -38,7 +39,7 @@ public static void AddSpaceDialogButton()

#if DEBUG
var sceneName = Game.Instance!.CurrentlyLoadedArea!.ActiveUIScene!.SceneName;
Debug.Log($"{nameof(SpaceStaticPartPCView)}_Initialize_Postfix @ {sceneName}");
Debug.Log($"{nameof(SpaceStaticPartPCView)}_BindViewImplementation_Postfix @ {sceneName}");
#endif

AddDialogSpeechButton(SPACE_SCROLL_VIEW_PATH);
Expand All @@ -59,17 +60,24 @@ private static void AddDialogSpeechButton(string path)
return;
}


if (parent.TryFind(SPEECHMOD_DIALOGBUTTON_NAME) != null)
{
Debug.LogWarning("Button already exists!");
return;
}

var buttonGameObject = ButtonFactory.TryCreatePlayButton(parent, () =>
{
Main.Speech.SpeakDialog(Game.Instance?.DialogController?.CurrentCue?.DisplayText);
Main.Speech?.SpeakDialog(Game.Instance?.DialogController?.CurrentCue?.DisplayText);
});

if (buttonGameObject == null)
{
return;
}

buttonGameObject.name = "SpeechMod_DialogButton";
buttonGameObject.name = SPEECHMOD_DIALOGBUTTON_NAME;
buttonGameObject.RectAlignTopLeft(new Vector2(40, 10));
buttonGameObject.transform.localRotation = Quaternion.Euler(0, 0, 270);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using SpeechMod.Unity.Extensions;
using UnityEngine;

namespace SpeechMod.Unity;
namespace SpeechMod.Unity.Voices;

public class AppleVoiceUnity : MonoBehaviour
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
using System.Threading.Tasks;
using UnityEngine;

namespace SpeechMod.Unity;
namespace SpeechMod.Unity.Voices;

public class EdgeVoiceUnity : MonoBehaviour
{
private const string TOKEN = "6A5AA1D4EAFF4E9FB37E23D68491D6F4";
private int _playIndex;
private List<Task<EdgeVoiceClient>> _voiceTasks = new();
private static EdgeVoiceUnity s_Instance;
public int PlayIndex;
public List<Task<EdgeVoiceClient>> VoiceTasks = new();
public CancellationToken CancellationToken;

private EdgeVoiceUnity()
{
Expand All @@ -41,57 +42,56 @@ public static string[] SetAvailableVoices()

public static bool IsSpeaking()
{
if (s_Instance?._voiceTasks == null || s_Instance._voiceTasks.Count == 0)
if (s_Instance?.VoiceTasks == null || s_Instance.VoiceTasks.Count == 0)
return false;

if (s_Instance._playIndex < 0 || s_Instance._playIndex >= s_Instance._voiceTasks.Count)
if (s_Instance.PlayIndex < 0 || s_Instance.PlayIndex >= s_Instance.VoiceTasks.Count)
return false;

if (s_Instance._playIndex + 1 < s_Instance._voiceTasks.Count)
if (s_Instance.PlayIndex + 1 < s_Instance.VoiceTasks.Count)
return true;

var edgeVoiceClient = s_Instance._voiceTasks[s_Instance._playIndex]?.Result;
var edgeVoiceClient = s_Instance.VoiceTasks[s_Instance.PlayIndex]?.Result;
return edgeVoiceClient is { IsSpeaking: true };
}

public static string GetStatusMessage()
{
if (s_Instance?._voiceTasks == null)
return "Idle";
if (s_Instance?.VoiceTasks == null)
return EdgeVoiceClient.EdgeVoiceClientState.Ready.ToString();

if (s_Instance._playIndex < 0 || s_Instance._playIndex >= s_Instance._voiceTasks.Count)
{
s_Instance._playIndex = 0;
return "Idle";
}
if (s_Instance.PlayIndex < 0 || s_Instance.PlayIndex >= s_Instance.VoiceTasks.Count)
return EdgeVoiceClient.EdgeVoiceClientState.Ready.ToString();

var edgeVoiceClient = s_Instance._voiceTasks[s_Instance._playIndex]?.Result;
var edgeVoiceClient = s_Instance.VoiceTasks[s_Instance.PlayIndex]?.Result;
if (edgeVoiceClient != null)
return edgeVoiceClient.CurrentState.ToString();

return "Error";
return EdgeVoiceClient.EdgeVoiceClientState.Error.ToString();
}

public static void Speak(EdgeVoiceDto edgeVoiceDTO)
{
var cancellationToken = new CancellationToken();
SpeakInternal(edgeVoiceDTO, cancellationToken);
s_Instance.CancellationToken = new CancellationToken();
SpeakInternal(edgeVoiceDTO);
}

public static void SpeakMulti(EdgeVoiceDto[] edgeVoiceDTOs)
{
var cancellationToken = new CancellationToken();
SpeakMultiInternal(edgeVoiceDTOs, cancellationToken);
s_Instance.CancellationToken = new CancellationToken();
SpeakMultiInternal(edgeVoiceDTOs);
}

public static void Stop()
{
if (!IsSpeaking())
return;

var edgeVoiceClient = s_Instance?._voiceTasks?[s_Instance._playIndex]?.Result;
s_Instance?.StopCoroutine(PlayMultipleCoroutine());

var edgeVoiceClient = s_Instance?.VoiceTasks?[s_Instance.PlayIndex]?.Result;
edgeVoiceClient?.Stop();
s_Instance._playIndex = 0;
s_Instance.PlayIndex = 0;
}

void OnDestroy()
Expand Down Expand Up @@ -124,39 +124,40 @@ private static async Task<string[]> SetAvailableVoicesInternal()
return Main.EdgeAvailableVoices?.Select(x => x.ShortName).ToArray();
}

private static async Task SpeakInternal(EdgeVoiceDto edgeVoiceDTO, CancellationToken cancellationToken)
private static async Task SpeakInternal(EdgeVoiceDto edgeVoiceDTO)
{
Debug.Log($"SpeakInternal: '{edgeVoiceDTO.Voice}' - R: {edgeVoiceDTO.Rate}, P: {edgeVoiceDTO.Pitch}, V: {edgeVoiceDTO.Volume} ");
#if DEBUG
Debug.Log($"SpeakInternal: {edgeVoiceDTO.Text}");
#endif

Stop();
Reset();

s_Instance._voiceTasks.Add(new Task<EdgeVoiceClient>(() =>
s_Instance.VoiceTasks.Add(new Task<EdgeVoiceClient>(() =>
{
var edgeVoice = new EdgeVoiceClient();
edgeVoice.Load(edgeVoiceDTO, TOKEN);
return edgeVoice;
}));

var single = s_Instance._voiceTasks.First();
var single = s_Instance.VoiceTasks.First();

//s_Instance.StartCoroutine(SpeakingCoroutine());

single.Start();
await single;

if (cancellationToken.IsCancellationRequested)
if (s_Instance.CancellationToken.IsCancellationRequested)
return;

Debug.Log("Play");
single.Result?.Play();
}

private static async Task SpeakMultiInternal(EdgeVoiceDto[] edgeVoiceDTOs, CancellationToken cancellationToken)
private static async Task SpeakMultiInternal(EdgeVoiceDto[] edgeVoiceDTOs)
{
foreach (var edgeVoiceDto in edgeVoiceDTOs)
{
Debug.Log($"Speak: '{edgeVoiceDto.Text}' '{edgeVoiceDto.Voice}'");
}

#if DEBUG
Debug.Log($"SpeakMultiInternal: {edgeVoiceDTOs.Length}");
#endif
Stop();
Reset();

Expand All @@ -165,60 +166,67 @@ private static async Task SpeakMultiInternal(EdgeVoiceDto[] edgeVoiceDTOs, Cance
if (string.IsNullOrWhiteSpace(edgeVoiceDTO.Text))
continue;

s_Instance._voiceTasks?.Add(new Task<EdgeVoiceClient>(() =>
s_Instance.VoiceTasks?.Add(new Task<EdgeVoiceClient>(() =>
{
var edgeVoice = new EdgeVoiceClient();
edgeVoice.Load(edgeVoiceDTO, TOKEN);
return edgeVoice;
}));
}

foreach (var task in s_Instance._voiceTasks)
//s_Instance.StartCoroutine(SpeakingCoroutine());

foreach (var task in s_Instance.VoiceTasks)
{
task.Start();
}

await s_Instance._voiceTasks.First();
await s_Instance.VoiceTasks.First();

if (cancellationToken.IsCancellationRequested)
if (s_Instance.CancellationToken.IsCancellationRequested)
return;

var voiceClient = s_Instance._voiceTasks[s_Instance._playIndex]?.Result;
var voiceClient = s_Instance.VoiceTasks[s_Instance.PlayIndex]?.Result;
if (voiceClient != null)
{
Debug.Log("Play first");
voiceClient.Play();

Debug.Log("Starting Coroutine");
s_Instance.StartCoroutine(PlayMultipleCoroutine(cancellationToken));
s_Instance.StartCoroutine(PlayMultipleCoroutine());
}
}

private static IEnumerator PlayMultipleCoroutine(CancellationToken cancellationToken)
private static IEnumerator PlayMultipleCoroutine()
{
Debug.Log("Play Multiple Coroutine");
while (s_Instance._playIndex < s_Instance._voiceTasks.Count)
while (s_Instance.PlayIndex < s_Instance.VoiceTasks.Count)
{
if (cancellationToken.IsCancellationRequested)
if (s_Instance.CancellationToken.IsCancellationRequested)
break;

var edgeVoiceClient = s_Instance._voiceTasks[s_Instance._playIndex].Result;
var edgeVoiceClient = s_Instance.VoiceTasks[s_Instance.PlayIndex].Result;
if (edgeVoiceClient is { IsSpeaking: true })
yield return new WaitForSeconds(0.1f);
else
{
if (++s_Instance._playIndex >= s_Instance._voiceTasks.Count)
if (++s_Instance.PlayIndex >= s_Instance.VoiceTasks.Count)
break;
Debug.Log("Play next");
s_Instance._voiceTasks[s_Instance._playIndex]?.Result?.Play();

s_Instance.VoiceTasks[s_Instance.PlayIndex]?.Result?.Play();
}
}
}

private static IEnumerator SpeakingCoroutine()
{
while (IsSpeaking())
{
yield return new WaitForEndOfFrame();
}
}

private static void Reset()
{
s_Instance?.StopAllCoroutines();
s_Instance._playIndex = 0;
s_Instance._voiceTasks = new List<Task<EdgeVoiceClient>>();
s_Instance?.StopCoroutine(PlayMultipleCoroutine());
s_Instance.PlayIndex = 0;
s_Instance.VoiceTasks = new List<Task<EdgeVoiceClient>>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using SpeechMod.Unity.Extensions;
using UnityEngine;

namespace SpeechMod.Unity;
namespace SpeechMod.Unity.Voices;

public class WindowsVoiceUnity : MonoBehaviour
{
Expand Down Expand Up @@ -104,7 +104,7 @@ public static string GetStatusMessage()

public static float GetNormalizedProgress()
{
return 1-(float)(m_CurrentWordCount - getWordPosition()) / m_CurrentWordCount;
return 1 - (float)(m_CurrentWordCount - getWordPosition()) / m_CurrentWordCount;
}

public static void Stop()
Expand Down
2 changes: 1 addition & 1 deletion SpeechMod/Voice/AppleSpeech.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using SpeechMod.Unity;
using SpeechMod.Unity.Voices;
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;
Expand Down
11 changes: 7 additions & 4 deletions SpeechMod/Voice/Edge/EdgeSpeech.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System.Text.RegularExpressions;
using Kingmaker.Blueprints.Base;
using UnityEngine;
using SpeechMod.Unity;
using SpeechMod.Unity.Voices;

namespace SpeechMod.Voice.Edge;

Expand Down Expand Up @@ -70,9 +70,12 @@ private static EdgeVoiceDto[] ExtractOrderedStrings(string text)
if (string.IsNullOrWhiteSpace(text))
return null;

if (Game.Instance.DialogController.CurrentSpeaker.Gender == Gender.Female)
return new EdgeVoiceDto(text, Main.Settings.FemaleVoice, Main.Settings.FemalePitch, Main.Settings.FemaleRate, Main.Settings.FemaleVolume);
return new EdgeVoiceDto(text, Main.Settings.MaleVoice, Main.Settings.MalePitch, Main.Settings.MaleRate, Main.Settings.MaleVolume);
return Game.Instance?.DialogController?.CurrentSpeaker?.Gender switch
{
Gender.Female => new EdgeVoiceDto(text, Main.Settings.FemaleVoice, Main.Settings.FemalePitch, Main.Settings.FemaleRate, Main.Settings.FemaleVolume),
Gender.Male => new EdgeVoiceDto(text, Main.Settings.MaleVoice, Main.Settings.MalePitch, Main.Settings.MaleRate, Main.Settings.MaleVolume),
_ => new EdgeVoiceDto(text, Main.Settings.NarratorVoice, Main.Settings.NarratorPitch, Main.Settings.NarratorRate, Main.Settings.NarratorVolume)
};
}

public string GetStatusMessage()
Expand Down
Loading

0 comments on commit 13d15c7

Please sign in to comment.