From 60729af2f81770130adde6bcc2e4484ce32a374f Mon Sep 17 00:00:00 2001 From: inb40 <86928941+inb40@users.noreply.github.com> Date: Sat, 27 May 2023 19:25:50 +0200 Subject: [PATCH 1/2] Added MacTTSContext --- TSOClient/FSO.Windows/FSO.Windows.csproj | 1 + TSOClient/FSO.Windows/MacTTSContext.cs | 65 ++++++++++++++++++++++++ TSOClient/FSO.Windows/Program.cs | 36 ++++++++++++- 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 TSOClient/FSO.Windows/MacTTSContext.cs diff --git a/TSOClient/FSO.Windows/FSO.Windows.csproj b/TSOClient/FSO.Windows/FSO.Windows.csproj index 94df8a62f..4d8539a91 100644 --- a/TSOClient/FSO.Windows/FSO.Windows.csproj +++ b/TSOClient/FSO.Windows/FSO.Windows.csproj @@ -93,6 +93,7 @@ + diff --git a/TSOClient/FSO.Windows/MacTTSContext.cs b/TSOClient/FSO.Windows/MacTTSContext.cs new file mode 100644 index 000000000..177559eea --- /dev/null +++ b/TSOClient/FSO.Windows/MacTTSContext.cs @@ -0,0 +1,65 @@ +using FSO.Client.UI.Panels; +using FSO.Common.Utils; +using Microsoft.Xna.Framework.Audio; +using System; +using System.Diagnostics; +using System.Text.RegularExpressions; + +namespace FSO.Windows +{ + public class MacTTSContext : ITTSContext + { + public static MacTTSContext PlatformProvider() + { + return new MacTTSContext(); + } + + public MacTTSContext() + { + } + + public override void Dispose() + { + } + + public override void Speak(string text, bool gender, int ipitch) + { + if (string.IsNullOrEmpty(text)) return; + + // Remove double-quotes from text. + text = text.Replace("\"", string.Empty); + // Remove any 'say' command control sequences. + text = Regex.Replace(text, @"\[\[.*?\]\]", string.Empty); + + // Determine the voice to use based on the gender. + // Samantha and Alex are available on most systems. + // If not available, it falls back to the default voice. + string voice = gender ? "Samantha" : "Alex"; + + // Convert pitch from 0-100 scale to 0-127 scale used by 'pbas' command. + // Note: negative values are clamped to 0 on macOS, it doesn't allow lower pitch than 0 (the default pitch). + int pbas = (int)(ipitch * 1.27); + + // Construct the command to send to 'say'. + string command = $"[[pbas {pbas}]] {text}"; + + // Create a ProcessStartInfo to specify the 'say' command and arguments. + var psi = new ProcessStartInfo("say", $"-v {voice} \"{command}\"") + { + UseShellExecute = false, + CreateNoWindow = true + }; + + try + { + // Run the 'say' command. + Process.Start(psi); + } + catch (Exception ex) + { + // Handle exception silently to not disrupt the game if anything happens. + Console.WriteLine("Error running 'say' command: " + ex.Message); + } + } + } +} \ No newline at end of file diff --git a/TSOClient/FSO.Windows/Program.cs b/TSOClient/FSO.Windows/Program.cs index f6c658d51..82e92d03d 100644 --- a/TSOClient/FSO.Windows/Program.cs +++ b/TSOClient/FSO.Windows/Program.cs @@ -18,6 +18,7 @@ using FSO.Client.UI.Panels; using System.Windows.Forms; using System.Text.RegularExpressions; +using System.Diagnostics; namespace FSO.Windows { @@ -46,14 +47,45 @@ public static void InitWindows() OperatingSystem os = Environment.OSVersion; PlatformID pid = os.Platform; - bool linux = pid == PlatformID.MacOSX || pid == PlatformID.Unix; - if (!linux) ITTSContext.Provider = UITTSContext.PlatformProvider; + + if (IsRunningOnMac()) + { + ITTSContext.Provider = MacTTSContext.PlatformProvider; + } + else if (pid != PlatformID.Unix) + { + ITTSContext.Provider = UITTSContext.PlatformProvider; + } AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; FSOProgram.ShowDialog = ShowDialog; } + private static bool IsRunningOnMac() + { + // Check for Unix first because Mac is also Unix and would pass both checks + if (Environment.OSVersion.Platform != PlatformID.Unix) return false; + + // Distinguish Linux from MacOS + return GetKernelName().ToLower() == "darwin"; + } + + + private static string GetKernelName() + { + var startInfo = new ProcessStartInfo("uname", "-s") + { + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + }; + using (var process = Process.Start(startInfo)) + { + return process.StandardOutput.ReadLine().Trim(); + } + } + public static void ShowDialog(string text) { OperatingSystem os = Environment.OSVersion; From bf2d469beaf82bf712e63f4ffbe87eb201b63454 Mon Sep 17 00:00:00 2001 From: inb40 <86928941+inb40@users.noreply.github.com> Date: Sat, 27 May 2023 20:46:19 +0200 Subject: [PATCH 2/2] Start in a new thread to avoid command run overhead --- TSOClient/FSO.Windows/MacTTSContext.cs | 64 ++++++++++++++------------ 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/TSOClient/FSO.Windows/MacTTSContext.cs b/TSOClient/FSO.Windows/MacTTSContext.cs index 177559eea..901c02920 100644 --- a/TSOClient/FSO.Windows/MacTTSContext.cs +++ b/TSOClient/FSO.Windows/MacTTSContext.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace FSO.Windows { @@ -24,42 +25,45 @@ public override void Dispose() public override void Speak(string text, bool gender, int ipitch) { - if (string.IsNullOrEmpty(text)) return; + Task.Run(() => + { + if (string.IsNullOrEmpty(text)) return; - // Remove double-quotes from text. - text = text.Replace("\"", string.Empty); - // Remove any 'say' command control sequences. - text = Regex.Replace(text, @"\[\[.*?\]\]", string.Empty); + // Remove double-quotes from text. + text = text.Replace("\"", string.Empty); + // Remove any 'say' command control sequences. + text = Regex.Replace(text, @"\[\[.*?\]\]", string.Empty); - // Determine the voice to use based on the gender. - // Samantha and Alex are available on most systems. - // If not available, it falls back to the default voice. - string voice = gender ? "Samantha" : "Alex"; + // Determine the voice to use based on the gender. + // Samantha and Alex are available on most systems. + // If not available, it falls back to the default voice. + string voice = gender ? "Samantha" : "Alex"; - // Convert pitch from 0-100 scale to 0-127 scale used by 'pbas' command. - // Note: negative values are clamped to 0 on macOS, it doesn't allow lower pitch than 0 (the default pitch). - int pbas = (int)(ipitch * 1.27); + // Convert pitch from 0-100 scale to 0-127 scale used by 'pbas' command. + // Note: negative values are clamped to 0 on macOS, it doesn't allow lower pitch than 0 (the default pitch). + int pbas = (int)(ipitch * 1.27); - // Construct the command to send to 'say'. - string command = $"[[pbas {pbas}]] {text}"; + // Construct the command to send to 'say'. + string command = $"[[pbas {pbas}]] {text}"; - // Create a ProcessStartInfo to specify the 'say' command and arguments. - var psi = new ProcessStartInfo("say", $"-v {voice} \"{command}\"") - { - UseShellExecute = false, - CreateNoWindow = true - }; + // Create a ProcessStartInfo to specify the 'say' command and arguments. + var psi = new ProcessStartInfo("say", $"-v {voice} \"{command}\"") + { + UseShellExecute = false, + CreateNoWindow = true + }; - try - { - // Run the 'say' command. - Process.Start(psi); - } - catch (Exception ex) - { - // Handle exception silently to not disrupt the game if anything happens. - Console.WriteLine("Error running 'say' command: " + ex.Message); - } + try + { + // Run the 'say' command. + Process.Start(psi); + } + catch (Exception ex) + { + // Handle exception silently to not disrupt the game if anything happens. + Console.WriteLine("Error running 'say' command: " + ex.Message); + } + }); } } } \ No newline at end of file