Decompiled source of SimlishTTS v1.1.2

OmniSimsTTS.dll

Decompiled 6 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Strobotnik.Klattersynth;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("Omniscye")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("OmniSimsTTS")]
[assembly: AssemblyTitle("OmniSimsTTS")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace OmniSimsTTS
{
	[BepInPlugin("Omniscye.OmniSimsTTS", "OmniSimsTTS", "1.0")]
	public class OmniSimsTTS : BaseUnityPlugin
	{
		internal static OmniSimsTTS Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		private void Awake()
		{
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Patch();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
		}

		internal void Patch()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0026: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
		}

		internal void Unpatch()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
		}
	}
}
namespace SimlishTTS
{
	[HarmonyPatch(typeof(Speech))]
	internal static class SimlishSpeechPatch
	{
		private static readonly Dictionary<string, string> simlishDict = new Dictionary<string, string>
		{
			{ "hello", "sul sul" },
			{ "hi", "zoola" },
			{ "hey", "heya" },
			{ "goodbye", "dag dag" },
			{ "bye", "froda" },
			{ "yes", "yibs" },
			{ "no", "neib" },
			{ "okay", "oka" },
			{ "ok", "yabo" },
			{ "alright", "alri" },
			{ "thanks", "tankyu" },
			{ "thank", "bando" },
			{ "please", "pleese" },
			{ "sorry", "sorri" },
			{ "wow", "woohoo" },
			{ "cool", "koolo" },
			{ "morning", "morno" },
			{ "evening", "evino" },
			{ "happy", "freng" },
			{ "sad", "groble" },
			{ "angry", "grawl" },
			{ "excited", "woohooz" },
			{ "tired", "sneyb" },
			{ "hungry", "hungrig" },
			{ "love", "luvva" },
			{ "hate", "blorf" },
			{ "scared", "fribbi" },
			{ "surprised", "majah" },
			{ "calm", "planka" },
			{ "confused", "nogg" },
			{ "nervous", "shibly" },
			{ "bored", "drowzy" },
			{ "go", "gonk" },
			{ "come", "kome" },
			{ "eat", "nom" },
			{ "sleep", "zzub" },
			{ "work", "werkz" },
			{ "play", "pley" },
			{ "dance", "dansi" },
			{ "sing", "singz" },
			{ "run", "skrrt" },
			{ "walk", "plak" },
			{ "talk", "chatz" },
			{ "see", "blicka" },
			{ "look", "blik" },
			{ "hear", "zib" },
			{ "listen", "zibba" },
			{ "think", "noggla" },
			{ "know", "knarb" },
			{ "want", "wanna" },
			{ "need", "needa" },
			{ "like", "likka" },
			{ "give", "giva" },
			{ "take", "taka" },
			{ "ask", "aska" },
			{ "help", "helpa" },
			{ "buy", "buyee" },
			{ "find", "finda" },
			{ "make", "makka" },
			{ "use", "uzo" },
			{ "open", "oppa" },
			{ "close", "closa" },
			{ "wait", "weita" },
			{ "stop", "stopp" },
			{ "start", "starta" },
			{ "call", "kal" },
			{ "watch", "wach" },
			{ "move", "mova" },
			{ "turn", "turna" },
			{ "fall", "faloo" },
			{ "sit", "sita" },
			{ "stand", "stando" },
			{ "drive", "vrooom" },
			{ "read", "reado" },
			{ "write", "writo" },
			{ "smile", "smilo" },
			{ "cry", "criyo" },
			{ "laugh", "lafa" },
			{ "break", "braka" },
			{ "house", "homeez" },
			{ "car", "vroom" },
			{ "money", "simoleons" },
			{ "food", "nooboo" },
			{ "water", "glippa" },
			{ "friend", "palsie" },
			{ "family", "famza" },
			{ "child", "kiddi" },
			{ "dog", "woofy" },
			{ "cat", "meewa" },
			{ "phone", "blingo" },
			{ "computer", "diggo" },
			{ "game", "playz" },
			{ "music", "tuno" },
			{ "song", "singzo" },
			{ "movie", "flika" },
			{ "school", "eduka" },
			{ "job", "jobba" },
			{ "city", "citka" },
			{ "country", "landoo" },
			{ "road", "radda" },
			{ "day", "dai" },
			{ "time", "tima" },
			{ "weather", "weatha" },
			{ "rain", "plipa" },
			{ "sun", "sola" },
			{ "moon", "luno" },
			{ "star", "stara" },
			{ "sky", "skyy" },
			{ "tree", "treelo" },
			{ "flower", "floora" },
			{ "bird", "chirpa" },
			{ "fish", "swima" },
			{ "mountain", "montee" },
			{ "river", "rivo" },
			{ "sea", "seeya" },
			{ "wind", "blowa" },
			{ "fire", "fira" },
			{ "earth", "erthee" },
			{ "air", "aira" },
			{ "light", "luma" },
			{ "dark", "duska" },
			{ "big", "gurb" },
			{ "small", "litzee" },
			{ "hot", "firby" },
			{ "cold", "freezy" },
			{ "fast", "skrrt" },
			{ "slow", "drow" },
			{ "new", "novu" },
			{ "old", "antik" },
			{ "good", "gud" },
			{ "bad", "blarfy" },
			{ "easy", "ezza" },
			{ "hard", "harz" },
			{ "beautiful", "bluma" },
			{ "ugly", "uggo" },
			{ "strong", "stronka" },
			{ "weak", "weaka" },
			{ "clean", "clena" },
			{ "dirty", "dirta" },
			{ "bright", "brila" },
			{ "soft", "soffa" },
			{ "loud", "luda" },
			{ "quiet", "queta" },
			{ "quickly", "skrrtly" },
			{ "slowly", "drowly" },
			{ "very", "veroo" },
			{ "really", "reelo" },
			{ "just", "jusso" },
			{ "never", "nope" },
			{ "always", "alwaza" },
			{ "sometimes", "sumbra" },
			{ "here", "hirro" },
			{ "there", "therro" },
			{ "everywhere", "evrywheree" },
			{ "soon", "soonoo" },
			{ "late", "lata" },
			{ "early", "erly" },
			{ "i", "meh" },
			{ "you", "yu" },
			{ "he", "heh" },
			{ "she", "sheh" },
			{ "we", "wee" },
			{ "they", "dey" },
			{ "me", "meh" },
			{ "my", "mai" },
			{ "your", "yur" },
			{ "his", "hiz" },
			{ "her", "hir" },
			{ "our", "owr" },
			{ "their", "deyr" },
			{ "who", "hoo" },
			{ "what", "wha" },
			{ "when", "wen" },
			{ "where", "wher" },
			{ "why", "whai" },
			{ "how", "hau" },
			{ "in", "inno" },
			{ "on", "onno" },
			{ "at", "atta" },
			{ "by", "bai" },
			{ "with", "wif" },
			{ "about", "aboo" },
			{ "under", "undro" },
			{ "over", "ovro" },
			{ "between", "bwetin" },
			{ "through", "throo" },
			{ "around", "arouda" },
			{ "before", "befora" },
			{ "after", "aftera" },
			{ "and", "en" },
			{ "or", "ohr" },
			{ "but", "boh" },
			{ "so", "soso" },
			{ "because", "becuz" },
			{ "although", "altho" },
			{ "while", "wila" },
			{ "if", "iffa" },
			{ "unless", "unlesa" },
			{ "fuck", "fraka" },
			{ "fucking", "frakoo" },
			{ "shit", "shizz" },
			{ "bitch", "bircha" },
			{ "asshole", "asoola" },
			{ "damn", "damba" },
			{ "crap", "krappa" },
			{ "dick", "dikzo" },
			{ "piss", "pisso" },
			{ "bollocks", "bolka" },
			{ "bugger", "buggo" },
			{ "bloody", "bluda" },
			{ "arse", "arso" },
			{ "twat", "twata" },
			{ "wanker", "wanko" }
		};

		private static readonly string[] simlishSyllables = new string[22]
		{
			"blar", "flor", "grib", "plerg", "wab", "zib", "freng", "gleb", "narf", "blicka",
			"meshka", "zurb", "firby", "nooboo", "pleerg", "wabadeb", "majah", "degoba", "ooboo", "firby",
			"blarf", "neib"
		};

		private static readonly string[] simlishExclamations = new string[10] { "wabadebadoo", "plerg majah", "nooboo", "meshaloob", "firby nurbs", "degoba", "woobox", "sul sul", "yibs yibs", "blarfy grawl" };

		private static readonly Random random = new Random();

		private static readonly HashSet<string> alreadyConverted = new HashSet<string>();

		private static string ConvertToSimlish(string englishText)
		{
			if (string.IsNullOrEmpty(englishText))
			{
				return englishText;
			}
			if (alreadyConverted.Contains(englishText.ToLower()) || IsAlreadySimlish(englishText))
			{
				return englishText;
			}
			StringBuilder stringBuilder = new StringBuilder();
			string[] array = englishText.ToLower().Split(new char[4] { ' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string input = array[i];
				string punctuation = "";
				string text = Regex.Replace(input, "[^\\w]", delegate(Match match)
				{
					punctuation += match.Value;
					return "";
				});
				string text2 = ((!simlishDict.ContainsKey(text)) ? GenerateSimlishWord(text) : simlishDict[text]);
				if (random.NextDouble() < 0.1)
				{
					text2 = AddVoiceEffect(text2);
				}
				stringBuilder.Append(text2 + punctuation);
				if (i < array.Length - 1)
				{
					stringBuilder.Append(" ");
				}
				if (random.NextDouble() < 0.05 && i < array.Length - 1)
				{
					stringBuilder.Append(" " + simlishExclamations[random.Next(simlishExclamations.Length)] + " ");
				}
			}
			string text3 = stringBuilder.ToString();
			alreadyConverted.Add(text3.ToLower());
			return text3;
		}

		private static bool IsAlreadySimlish(string text)
		{
			string text2 = text.ToLower();
			string[] array = new string[12]
			{
				"sul sul", "dag dag", "yibs", "neib", "blarf", "freng", "plerg", "nooboo", "meshka", "degoba",
				"wabadeb", "firby"
			};
			string[] array2 = array;
			foreach (string value in array2)
			{
				if (text2.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		private static string GenerateSimlishWord(string englishWord)
		{
			if (englishWord.Length <= 2)
			{
				return simlishSyllables[random.Next(simlishSyllables.Length / 2)];
			}
			if (englishWord.Length <= 5)
			{
				return simlishSyllables[random.Next(simlishSyllables.Length)];
			}
			int num = Math.Min(3, (englishWord.Length + 2) / 3);
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < num; i++)
			{
				stringBuilder.Append(simlishSyllables[random.Next(simlishSyllables.Length)]);
			}
			return stringBuilder.ToString();
		}

		private static string AddVoiceEffect(string word)
		{
			return random.Next(4) switch
			{
				0 => word.Replace("a", "aaa").Replace("e", "eee").Replace("i", "iii")
					.Replace("o", "ooo")
					.Replace("u", "uuu"), 
				1 => word[0] + "-" + word, 
				2 => word.ToUpper() + "!", 
				3 => word + "?", 
				_ => word, 
			};
		}

		[HarmonyPrefix]
		[HarmonyPatch("speak", new Type[]
		{
			typeof(int),
			typeof(VoicingSource),
			typeof(StringBuilder),
			typeof(bool)
		})]
		private static void Speak_StringBuilder_ONLY_Prefix(int voiceBaseFrequency, VoicingSource voicingSource, StringBuilder text, bool bracketsAsPhonemes)
		{
			if (text == null || text.Length <= 0)
			{
				return;
			}
			string text2 = text.ToString();
			if (!IsAlreadySimlish(text2))
			{
				string text3 = ConvertToSimlish(text2);
				if (text2 != text3)
				{
					text.Clear();
					text.Append(text3);
					Debug.Log((object)("[SimlishTTS] FINAL CONVERSION: '" + text2 + "' -> '" + text3 + "'"));
				}
			}
		}
	}
	[HarmonyPatch(typeof(Speech))]
	internal static class HumanVoicePatch
	{
		private static readonly Random voiceRandom = new Random();

		[HarmonyPostfix]
		[HarmonyPatch("Awake")]
		private static void Awake_Postfix(Speech __instance)
		{
			__instance.voiceBaseFrequency = 160;
			__instance.flutter = 1;
			__instance.flutterSpeed = 0.3f;
			__instance.msPerSpeechFrame = 20;
			Debug.Log((object)"[SimlishTTS] Voice HEAVILY humanized! Should sound much more natural now!");
		}

		[HarmonyPrefix]
		[HarmonyPatch("speak", new Type[]
		{
			typeof(int),
			typeof(VoicingSource),
			typeof(StringBuilder),
			typeof(bool)
		})]
		private static void Speak_StringBuilder_Humanize_Prefix(ref int voiceBaseFrequency, VoicingSource voicingSource, StringBuilder text, bool bracketsAsPhonemes)
		{
			string text2 = text.ToString().ToLower();
			if (text2.Contains("?"))
			{
				voiceBaseFrequency += voiceRandom.Next(20, 40);
			}
			else if (text2.Contains("!"))
			{
				voiceBaseFrequency += voiceRandom.Next(-15, 30);
			}
			else
			{
				voiceBaseFrequency += voiceRandom.Next(-10, 15);
			}
			voiceBaseFrequency = Mathf.Clamp(voiceBaseFrequency, 120, 280);
		}

		[HarmonyPrefix]
		[HarmonyPatch("schedule", new Type[]
		{
			typeof(int),
			typeof(VoicingSource),
			typeof(string),
			typeof(bool)
		})]
		private static void Schedule_AddNaturalPauses_Prefix(ref string text)
		{
			if (!string.IsNullOrEmpty(text))
			{
				text = text.Replace(", ", ", ... ");
				text = text.Replace(". ", ". ... ... ");
				text = text.Replace("! ", "! ... ");
				text = text.Replace("? ", "? ... ");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("getCurrentLoudness")]
		private static void GetCurrentLoudness_Humanize_Postfix(ref float __result)
		{
			float num = 0.8f + (float)voiceRandom.NextDouble() * 0.4f;
			__result *= num;
			if (voiceRandom.NextDouble() < 0.05)
			{
				__result *= 1.3f;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		private static void Update_HumanTiming_Postfix(Speech __instance)
		{
			if (voiceRandom.NextDouble() < 0.02)
			{
				__instance.flutter = Mathf.Clamp(__instance.flutter + voiceRandom.Next(-2, 3), 1, 8);
				__instance.flutterSpeed = Mathf.Clamp(__instance.flutterSpeed + ((float)voiceRandom.NextDouble() - 0.5f) * 0.2f, 0.3f, 1.2f);
			}
		}
	}
	[HarmonyPatch(typeof(Speech))]
	internal static class AdvancedHumanizationPatch
	{
		private static readonly Dictionary<string, float> emotionalPitchModifiers = new Dictionary<string, float>
		{
			{ "happy", 1.15f },
			{ "excited", 1.25f },
			{ "surprised", 1.3f },
			{ "sad", 0.85f },
			{ "tired", 0.8f },
			{ "angry", 0.9f },
			{ "calm", 1f },
			{ "confused", 1.1f }
		};

		[HarmonyPrefix]
		[HarmonyPatch("speak", new Type[]
		{
			typeof(string),
			typeof(bool)
		})]
		private static void Speak_EmotionalIntelligence_Prefix(Speech __instance, string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			string text2 = text.ToLower();
			foreach (KeyValuePair<string, float> emotionalPitchModifier in emotionalPitchModifiers)
			{
				if (text2.Contains(emotionalPitchModifier.Key))
				{
					__instance.voiceBaseFrequency = Mathf.RoundToInt((float)__instance.voiceBaseFrequency * emotionalPitchModifier.Value);
					if (emotionalPitchModifier.Key == "excited" || emotionalPitchModifier.Key == "happy")
					{
						__instance.flutterSpeed *= 1.2f;
					}
					else if (emotionalPitchModifier.Key == "sad" || emotionalPitchModifier.Key == "tired")
					{
						__instance.flutterSpeed *= 0.7f;
						__instance.msPerSpeechFrame += 3;
					}
					break;
				}
			}
		}
	}
}