Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of EmberWords v0.6.0
plugins/Magic.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using HatterWeaponsPack; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using Photon.Voice; using SherpaOnnx; using UnityEngine; using UnityEngine.Audio; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Magic")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Magic")] [assembly: AssemblyTitle("Magic")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 Magic { internal static class DoomFx { private static readonly Color Red = new Color(1f, 0.12f, 0.03f, 1f); private static readonly Color Fire = new Color(1f, 0.45f, 0.08f, 1f); private static Material material; private const int Rate = 44100; private static AudioClip drone; private static AudioClip rumble; private static AudioClip beat; internal static Material Glow { get { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown if ((Object)(object)material == (Object)null) { Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val != (Object)null) { material = new Material(val); } } return material; } } internal static AudioClip Drone { get { if (!((Object)(object)drone != (Object)null)) { return drone = Make("Ember Words doom drone", 8f, delegate(float t) { float num = 0.6f + 0.4f * Mathf.Sin(MathF.PI / 2f * t); return (Sine(55f, t) * 0.35f + Sine(58.25f, t) * 0.3f + Sine(77.75f, t) * 0.22f * num + Sine(110f, t) * 0.18f + Sine(116.5f, t) * 0.14f * (1f - num) + Sine(220.25f, t) * 0.05f) * (0.75f + 0.25f * Mathf.Sin(MathF.PI * 3f / 4f * t)); }); } return drone; } } internal static AudioClip Rumble { get { if (!((Object)(object)rumble != (Object)null)) { return rumble = MakeNoise("Ember Words doom rumble", 6f); } return rumble; } } internal static AudioClip Beat { get { if (!((Object)(object)beat != (Object)null)) { return beat = Make("Ember Words doom beat", 0.6f, (float t) => Thump(t, 0f, 1f) + Thump(t, 0.22f, 0.65f)); } return beat; } } public static void Charge(ChargedWand wand, float seconds) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) try { object? obj = R.Gun?.GetValue(wand); ItemGun val = (ItemGun)((obj is ItemGun) ? obj : null); Transform tip = (((Object)(object)val != (Object)null && (Object)(object)val.gunMuzzle != (Object)null) ? val.gunMuzzle : ((Component)wand).transform); new GameObject("Ember Words doom charge").AddComponent<DoomCharge>().Begin(wand, tip, seconds); } catch (Exception ex) { Plugin.Log.LogError((object)("doom charge effect failed: " + ex)); } } public static void Trail(Transform fireball) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = new GameObject("Ember Words doom glow"); val.transform.SetParent(fireball, false); Light obj = val.AddComponent<Light>(); obj.type = (LightType)2; obj.color = Red; obj.range = 15f; obj.intensity = 4f; obj.shadows = (LightShadows)0; } catch (Exception ex) { Plugin.Log.LogError((object)("doom glow failed: " + ex)); } } public static void Explode(Vector3 at, Spell s) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) float num = s[Stat.SplashRadius]; int num2 = Mathf.RoundToInt(s[Stat.SplashDamage]); try { R.SpawnSmall?.Invoke(null, new object[5] { at, 3f, 0.05f, 0, 0f }); R.Blast?.Invoke(null, new object[6] { at, num, num2, num2, s[Stat.Knockback], true }); } catch (Exception ex) { Plugin.Log.LogError((object)("doom blast failed: " + ex)); } try { new GameObject("Ember Words doom blast").AddComponent<DoomBlast>().Begin(at, num); GameDirector instance = GameDirector.instance; if (instance != null) { CameraShake cameraShake = instance.CameraShake; if (cameraShake != null) { cameraShake.ShakeDistance(10f, num * 0.3f, num * 1.5f, at, 2.5f); } } if (instance != null) { CameraShake cameraImpact = instance.CameraImpact; if (cameraImpact != null) { cameraImpact.ShakeDistance(10f, num * 0.3f, num * 1.5f, at, 0.5f); } } } catch (Exception ex2) { Plugin.Log.LogError((object)("doom blast effect failed: " + ex2)); } Plugin.Log.LogInfo((object)$"doom exploded: {num:0} m radius, {num2} damage"); } private static float Sine(float hz, float t) { return Mathf.Sin(MathF.PI * 2f * hz * t); } private static float Thump(float t, float at, float loud) { float num = t - at; if (num < 0f) { return 0f; } return loud * Mathf.Exp((0f - num) * 18f) * Mathf.Sin(MathF.PI * 2f * (48f + 40f * Mathf.Exp((0f - num) * 30f)) * num); } private static AudioClip Make(string name, float seconds, Func<float, float> wave) { int num = Mathf.RoundToInt(seconds * 44100f); float[] array = new float[num]; for (int i = 0; i < num; i++) { array[i] = Mathf.Clamp(wave((float)i / 44100f), -1f, 1f); } AudioClip obj = AudioClip.Create(name, num, 1, 44100, false); obj.SetData(array, 0); return obj; } private static AudioClip MakeNoise(string name, float seconds) { int num = Mathf.RoundToInt(seconds * 44100f); int num2 = 22050; float[] array = new float[num + num2]; Random random = new Random(666); float num3 = 0f; float num4 = 0f; for (int i = 0; i < array.Length; i++) { num3 += ((float)random.NextDouble() * 2f - 1f) * 0.02f; num3 *= 0.995f; num4 = (array[i] = num4 + (num3 - num4) * 0.05f); } float num5 = 0.0001f; float[] array2 = array; foreach (float num6 in array2) { num5 = Mathf.Max(num5, Mathf.Abs(num6)); } float[] array3 = new float[num]; for (int k = 0; k < num; k++) { float num7 = array[k]; if (k < num2) { num7 = Mathf.Lerp(array[num + k], num7, (float)k / (float)num2); } array3[k] = num7 / num5 * 0.9f; } AudioClip obj = AudioClip.Create(name, num, 1, 44100, false); obj.SetData(array3, 0); return obj; } internal static AudioSource MakeSource(GameObject go, AudioClip clip, bool loop, float spatial, float maxDistance) { AudioSource val = go.AddComponent<AudioSource>(); val.clip = clip; val.loop = loop; val.playOnAwake = false; val.spatialBlend = spatial; val.rolloffMode = (AudioRolloffMode)1; val.minDistance = 10f; val.maxDistance = maxDistance; val.dopplerLevel = 0f; val.volume = 0f; AudioMixerGroup val2 = (((Object)(object)AudioManager.instance != (Object)null) ? AudioManager.instance.SoundMasterGroup : null); if ((Object)(object)val2 != (Object)null) { val.outputAudioMixerGroup = val2; } return val; } internal static Light MakeLight(GameObject go, float range, float intensity) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) Light obj = go.AddComponent<Light>(); obj.type = (LightType)2; obj.color = Red; obj.range = range; obj.intensity = intensity; obj.shadows = (LightShadows)0; return obj; } } [HarmonyPatch(typeof(EmberWand), "ChargeTick")] internal static class DoomTipHook { private const float MaxSize = 6f; private static readonly FieldInfo Growing = AccessTools.Field(typeof(EmberWand), "growing"); private static readonly MethodInfo Tip = AccessTools.PropertyGetter(typeof(ChargedWand), "Tip"); private static void Postfix(EmberWand __instance, float __0) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) try { if (Casts.Current.TryGetValue(((Object)__instance).GetInstanceID(), out var value) && value.ShapeId == 8) { object? obj = Growing?.GetValue(__instance); Component val = (Component)((obj is Component) ? obj : null); object? obj2 = Tip?.Invoke(__instance, null); Transform val2 = (Transform)((obj2 is Transform) ? obj2 : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null) && !(R.FxSize == null)) { float num = Mathf.Lerp(0.04f, Mathf.Min(6f, value[Stat.Size]), __0); R.FxSize.SetValue(val, num); val.transform.SetPositionAndRotation(val2.position + val2.forward * (0.1f * num * 1.5f), val2.rotation); } } } catch (Exception ex) { Plugin.Log.LogError((object)("doom tip fireball failed: " + ex.Message)); } } } internal sealed class DoomCharge : MonoBehaviour { private ChargedWand wand; private Transform tip; private float seconds; private float started; private float nextShake; private Light light; private string warning; private GUIStyle style; private GUIStyle shadow; private AudioSource drone; private AudioSource rumble; private AudioSource beat; private float nextBeat; public const float QuakeReach = 150f; private const float Stretch = 2.5f; private static Font font; private static bool fontLooked; private const float TextSize = 0.175f; private int fittedFor; private string shown; public void Begin(ChargedWand wand, Transform tip, float seconds) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) this.wand = wand; this.tip = tip; ((Component)this).transform.position = tip.position; this.seconds = Mathf.Max(1f, seconds); started = Time.time; light = DoomFx.MakeLight(((Component)this).gameObject, 3f, 1f); PlayerAvatar val = R.HolderOf(wand); string text = (((Object)(object)val != (Object)null) ? SemiFunc.PlayerGetName(val) : null); warning = (string.IsNullOrWhiteSpace(text) ? "SOMEONE" : text.ToUpperInvariant()) + " DARES SPEAK DOOM"; drone = DoomFx.MakeSource(((Component)this).gameObject, DoomFx.Drone, loop: true, 0f, 500f); beat = DoomFx.MakeSource(((Component)this).gameObject, DoomFx.Beat, loop: false, 0f, 500f); rumble = DoomFx.MakeSource(((Component)this).gameObject, DoomFx.Rumble, loop: true, 1f, 150f); drone.Play(); rumble.Play(); } private static Font WarningFont() { if (!fontLooked) { fontLooked = true; Font[] array = Resources.FindObjectsOfTypeAll<Font>(); font = Array.Find(array, (Font f) => (Object)(object)f != (Object)null && ((Object)f).name.StartsWith("Teko")) ?? Array.Find(array, (Font f) => (Object)(object)f != (Object)null && ((Object)f).name.StartsWith("VCR")); } return font; } private void OnGUI() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) float num = Time.time - started; float num2 = Mathf.Clamp01(num / seconds); if (style == null || fittedFor != Screen.width * 10000 + Screen.height) { Fit(); } int fontSize = style.fontSize; float num3 = 0.75f + 0.25f * Mathf.Sin(num * Mathf.Lerp(2f, 10f, num2)); float num4 = Mathf.Clamp01(num / 0.6f) * num3; style.normal.textColor = new Color(0.85f, 0.04f, 0.02f, num4); shadow.normal.textColor = new Color(0f, 0f, 0f, num4 * 0.85f); float num5 = Mathf.Lerp(2f, 12f, num2); float num6 = (float)Screen.height * 0.5f; Matrix4x4 matrix = GUI.matrix; GUIUtility.ScaleAroundPivot(new Vector2(1f, 2.5f), new Vector2((float)Screen.width / 2f, num6)); float num7 = (float)Screen.height / 2.5f; Rect val = default(Rect); ((Rect)(ref val))..ctor(Random.Range(0f - num5, num5), num6 - num7 / 2f + Random.Range(0f - num5, num5) / 2.5f, (float)Screen.width, num7); float num8 = Mathf.Max(3f, (float)fontSize * 0.04f); GUI.Label(new Rect(((Rect)(ref val)).x + num8, ((Rect)(ref val)).y + num8 / 2.5f, ((Rect)(ref val)).width, ((Rect)(ref val)).height), shown, shadow); GUI.Label(val, shown, style); GUI.matrix = matrix; } private void Fit() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Expected O, but got Unknown fittedFor = Screen.width * 10000 + Screen.height; style = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, fontStyle = (FontStyle)1, wordWrap = false }; Font val = WarningFont(); if ((Object)(object)val != (Object)null) { style.font = val; style.fontStyle = (FontStyle)0; } int num = Mathf.Max(8, Mathf.RoundToInt((float)Screen.height * 0.175f)); style.fontSize = num; shown = warning; if (style.CalcSize(new GUIContent(shown)).x > (float)Screen.width * 0.95f) { shown = warning.Replace(" DARES ", "\nDARES "); } Vector2 val2 = style.CalcSize(new GUIContent(shown)); float num2 = Mathf.Min(new float[3] { 1f, (float)Screen.width * 0.95f / val2.x, (float)Screen.height * 0.95f / (val2.y * 2.5f) }); style.fontSize = Mathf.Max(8, Mathf.FloorToInt((float)num * num2)); shadow = new GUIStyle(style); } private void Update() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) float num = Time.time - started; if ((Object)(object)wand == (Object)null || num > seconds + 1f || (num > 0.5f && !R.IsCharging(wand))) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } if ((Object)(object)tip != (Object)null) { ((Component)this).transform.position = tip.position; } float num2 = Mathf.Clamp01(num / seconds); float num3 = 0.6f + 0.4f * Mathf.Sin(num * Mathf.Lerp(3f, 18f, num2)); light.range = Mathf.Lerp(3f, 40f, num2); light.intensity = Mathf.Lerp(1f, 7f, num2) * num3; if (Time.time >= nextShake) { nextShake = Time.time + 0.5f; GameDirector instance = GameDirector.instance; if (instance != null) { CameraShake cameraShake = instance.CameraShake; if (cameraShake != null) { cameraShake.ShakeDistance(Mathf.Lerp(0.5f, 5f, num2), 5f, 150f, ((Component)this).transform.position, 0.6f); } } } float num4 = Mathf.Clamp01(num / 1.5f); drone.volume = Mathf.Lerp(0.25f, 0.8f, num2) * num4; drone.pitch = Mathf.Lerp(0.85f, 1.25f, num2 * num2); rumble.volume = Mathf.Lerp(0.3f, 1f, num2) * num4; rumble.pitch = Mathf.Lerp(0.8f, 1.1f, num2); if (Time.time >= nextBeat) { nextBeat = Time.time + Mathf.Lerp(1.5f, 0.4f, num2); beat.volume = Mathf.Lerp(0.4f, 1f, num2); beat.Play(); } } } internal sealed class DoomBlast : MonoBehaviour { private const float Grow = 1.2f; private const float Life = 3f; private float radius; private float started; private Material mat; private Light flash; private Transform sphere; public void Begin(Vector3 at, float radius) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_0091: Expected O, but got Unknown this.radius = radius; started = Time.time; ((Component)this).transform.position = at; GameObject val = GameObject.CreatePrimitive((PrimitiveType)0); Object.Destroy((Object)(object)val.GetComponent<Collider>()); val.transform.SetParent(((Component)this).transform, false); val.transform.localScale = Vector3.one * 0.5f; MeshRenderer component = val.GetComponent<MeshRenderer>(); ((Renderer)component).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)component).receiveShadows = false; if ((Object)(object)DoomFx.Glow != (Object)null) { Material val2 = new Material(DoomFx.Glow); Material val3 = val2; ((Renderer)component).material = val2; mat = val3; } sphere = val.transform; flash = DoomFx.MakeLight(((Component)this).gameObject, radius, 12f); Object.Destroy((Object)(object)((Component)this).gameObject, 3f); } private void Update() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) float num = Time.time - started; float num2 = Mathf.Clamp01(num / 1.2f); sphere.localScale = Vector3.one * Mathf.Max(0.5f, radius * 2f * (1f - (1f - num2) * (1f - num2))); float num3 = 1f - Mathf.Clamp01(num / 3f); if ((Object)(object)mat != (Object)null) { mat.color = new Color(1f, Mathf.Lerp(0.12f, 0.45f, num3), 0.05f, 0.45f * num3); } flash.intensity = 12f * num3 * num3; } } internal sealed class KeywordEncoder { private const char WordStart = '▁'; private readonly Dictionary<string, double> scores = new Dictionary<string, double>(); private readonly int longest; public KeywordEncoder(string tokensPath, string modelPath) { HashSet<string> hashSet = new HashSet<string>(); string[] array = File.ReadAllLines(tokensPath, Encoding.UTF8); foreach (string text in array) { int num = text.LastIndexOf(' '); if (num > 0) { hashSet.Add(text.Substring(0, num)); } } foreach (var item in ReadPieces(File.ReadAllBytes(modelPath))) { var (text2, num2, _) = item; if (item.normal && hashSet.Contains(text2)) { scores[text2] = num2; longest = Math.Max(longest, text2.Length); } } if (scores.Count == 0) { throw new InvalidDataException("no usable pieces in " + modelPath); } } public string Encode(string phrase) { List<string> list = phrase.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(EncodeWord).ToList(); if (list.Count != 0 && !list.Contains(null)) { return string.Join(" ", list); } return null; } private string EncodeWord(string word) { string text = "▁" + word.ToUpperInvariant(); int length = text.Length; double[] array = new double[length + 1]; int[] array2 = new int[length + 1]; for (int i = 1; i <= length; i++) { array[i] = double.NegativeInfinity; } for (int j = 1; j <= length; j++) { for (int k = Math.Max(0, j - longest); k < j; k++) { if (!double.IsNegativeInfinity(array[k]) && scores.TryGetValue(text.Substring(k, j - k), out var value) && array[k] + value > array[j]) { array[j] = array[k] + value; array2[j] = k; } } } if (double.IsNegativeInfinity(array[length])) { return null; } List<string> list = new List<string>(); for (int num = length; num > 0; num = array2[num]) { list.Add(text.Substring(array2[num], num - array2[num])); } list.Reverse(); return string.Join(" ", list); } public static string Line(string tokens, string word, float boost, float threshold) { return string.Format(CultureInfo.InvariantCulture, "{0} :{1:0.###} #{2:0.###} @{3}", tokens, boost, threshold, word.Replace(' ', '_')); } private static IEnumerable<(string piece, float score, bool normal)> ReadPieces(byte[] data) { int pos = 0; while (pos < data.Length) { ulong num = Varint(data, ref pos); int num2 = (int)(num >> 3); int num3 = (int)(num & 7); if (num3 != 2) { Skip(data, ref pos, num3); continue; } int num4 = (int)Varint(data, ref pos); int end = pos + num4; if (num2 == 1) { yield return ReadPiece(data, pos, end); } pos = end; } } private static (string, float, bool) ReadPiece(byte[] data, int pos, int end) { string item = ""; float item2 = 0f; int num = 1; while (pos < end) { ulong num2 = Varint(data, ref pos); int num3 = (int)(num2 >> 3); int num4 = (int)(num2 & 7); if (num3 == 1 && num4 == 2) { int num5 = (int)Varint(data, ref pos); item = Encoding.UTF8.GetString(data, pos, num5); pos += num5; } else if (num3 == 2 && num4 == 5) { item2 = BitConverter.ToSingle(data, pos); pos += 4; } else if (num3 == 3 && num4 == 0) { num = (int)Varint(data, ref pos); } else { Skip(data, ref pos, num4); } } return (item, item2, num == 1); } private static ulong Varint(byte[] data, ref int pos) { ulong num = 0uL; int num2 = 0; while (true) { byte b = data[pos++]; num |= (ulong)((long)(b & 0x7F) << num2); if ((b & 0x80) == 0) { break; } num2 += 7; } return num; } private static void Skip(byte[] data, ref int pos, int wire) { switch (wire) { case 0: Varint(data, ref pos); break; case 1: pos += 8; break; case 2: pos += (int)Varint(data, ref pos); break; case 5: pos += 4; break; default: throw new InvalidDataException("bad protobuf wire type " + wire); } } } internal static class Lore { private const byte WhisperEvent = 177; public static ConfigEntry<bool> Enabled; public static ConfigEntry<string> MagicItems; public static ConfigEntry<int> RandomCarriers; public static ConfigEntry<int> MaxTimesSaid; public static ConfigEntry<float> WhisperVolume; public static ConfigEntry<float> DoomChance; private static readonly Dictionary<int, int> timesSaid = new Dictionary<int, int>(); private static readonly HashSet<int> carriers = new HashSet<int>(); private static string levelKey = ""; private static readonly Random rng = new Random(); public static void Bind(ConfigFile cfg) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown Enabled = cfg.Bind<bool>("Lore", "Enabled", true, "Valuables whisper this run's spell words when first picked up."); MagicItems = cfg.Bind<string>("Lore", "MagicItems", "Cube of Knowledge, Crystal Ball, Fortune Card, Chomp Book, Star Wand, Time Glass, Eye of Orpigox, Power Crystal, Ocarina, Music Box, Manor Map, Energy Crystal Chunk, Zero Grav Crystal, Snow Globe, Big Sample, Cool Brain", "Valuables that always carry a word, by name, separated by commas."); RandomCarriers = cfg.Bind<int>("Lore", "RandomCarriersPerLevel", 1, new ConfigDescription("Other valuables per level that also carry a word, picked at random.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>())); MaxTimesSaid = cfg.Bind<int>("Lore", "MaxTimesSaid", 5, new ConfigDescription("After a word has been whispered or cast this many times in a run, items stop whispering it.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>())); DoomChance = cfg.Bind<float>("Lore", "DoomChance", 0.05f, new ConfigDescription("Chance that a whisper is \"doom\" instead, until doom has been whispered once this run (0 to 1).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); WhisperVolume = cfg.Bind<float>("Lore", "WhisperVolume", 0.4f, new ConfigDescription("How loud a whisper is, compared with normal text-to-speech (each player's own setting).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>())); } public static void ResetRun() { timesSaid.Clear(); carriers.Clear(); levelKey = ""; } public static void NoteCast(Spell spell) { foreach (int item in spell.Roles.Distinct()) { Role role = SpellBook.RoleById(item); if (role != null && role.Rotates) { timesSaid[item] = Said(item) + 1; } } } private static int Said(int id) { if (!timesSaid.TryGetValue(id, out var value)) { return 0; } return value; } public static void OnGrab(ValuableObject valuable, PlayerAvatar who) { if (!Enabled.Value || (Object)(object)valuable == (Object)null || (Object)(object)who == (Object)null) { return; } RefreshLevel(); if (carriers.Remove(((Object)valuable).GetInstanceID())) { string text = PickWord(); Plugin.Log.LogInfo((object)((text != null) ? ("lore: " + Name(valuable) + " whispered \"" + text + "\" to " + SemiFunc.PlayerGetName(who)) : ("lore: " + Name(valuable) + " stayed silent: every word has been heard enough"))); if (text != null) { Send(who, text); } } } private static string PickWord() { Role role = SpellBook.RoleById(8); if (!SpellBook.DoomUnlocked && role != null && role.Words.Length != 0 && rng.NextDouble() < (double)DoomChance.Value) { SpellBook.UnlockDoom(); return role.Words[0]; } List<Role> list = SpellBook.Roles.Where((Role r) => r.Rotates && Said(r.Id) < MaxTimesSaid.Value).ToList(); if (list.Count == 0) { return null; } double num = list.Sum((Role r) => 1.0 / (double)(1 + Said(r.Id))); double num2 = rng.NextDouble() * num; foreach (Role item in list) { num2 -= 1.0 / (double)(1 + Said(item.Id)); if (!(num2 > 0.0)) { timesSaid[item.Id] = Said(item.Id) + 1; return SpellBook.ActiveWord(item); } } Role role2 = list[list.Count - 1]; timesSaid[role2.Id] = Said(role2.Id) + 1; return SpellBook.ActiveWord(role2); } private static void RefreshLevel() { RunManager instance = RunManager.instance; string text = (((Object)(object)instance == (Object)null) ? "" : ((((Object)(object)instance.levelCurrent != (Object)null) ? ((Object)instance.levelCurrent).name : "") + "#" + instance.levelsCompleted)); if (text == levelKey) { return; } levelKey = text; carriers.Clear(); string[] source = (from text2 in MagicItems.Value.Split(',').Select(Normalize) where text2.Length > 0 select text2).ToArray(); List<string> list = new List<string>(); List<ValuableObject> list2 = new List<ValuableObject>(); List<ValuableObject> list3 = (((Object)(object)ValuableDirector.instance != (Object)null && ValuableDirector.instance.valuableList.Count > 0) ? ValuableDirector.instance.valuableList.Where((ValuableObject v) => (Object)(object)v != (Object)null).ToList() : Object.FindObjectsByType<ValuableObject>((FindObjectsInactive)1, (FindObjectsSortMode)0).ToList()); foreach (ValuableObject item in list3) { string n = Normalize(((Object)((Component)item).gameObject).name); if (source.Any((string m) => n.Contains(m))) { carriers.Add(((Object)item).GetInstanceID()); list.Add(Name(item)); } else { list2.Add(item); } } List<ValuableObject> list4 = list2.OrderBy((ValuableObject _) => rng.Next()).Take(RandomCarriers.Value).ToList(); foreach (ValuableObject item2 in list4) { carriers.Add(((Object)item2).GetInstanceID()); } Plugin.Log.LogInfo((object)($"lore: level {text}: {list3.Count} valuables; magic items carrying a word: " + ((list.Count > 0) ? string.Join(", ", list) : "none in this level") + "; random carriers: " + ((list4.Count > 0) ? string.Join(", ", list4.Select(Name)) : "none"))); } private static string Name(ValuableObject v) { return ((Object)((Component)v).gameObject).name.Replace("(Clone)", "").Replace("Valuable ", "").Trim(); } private static string Normalize(string s) { return new string((s ?? "").ToLowerInvariant().Where(char.IsLetter).ToArray()); } private static void Send(PlayerAvatar who, string word) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) PhotonView photonView = who.photonView; if ((Object)(object)photonView == (Object)null || photonView.IsMine || !PhotonNetwork.InRoom) { Whisper.Speak(word); return; } RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { photonView.OwnerActorNr }; PhotonNetwork.RaiseEvent((byte)177, (object)word, val, SendOptions.SendReliable); } public static void Listen() { PhotonNetwork.NetworkingClient.EventReceived += delegate(EventData ev) { if (ev.Code == 177 && ev.CustomData is string word) { Whisper.Speak(word); } }; } } internal static class Whisper { private static readonly FieldInfo VoiceChatField = AccessTools.Field(typeof(PlayerAvatar), "voiceChat"); private static readonly FieldInfo TtsVoiceField = AccessTools.Field(typeof(PlayerVoiceChat), "ttsVoice"); private static readonly FieldInfo TtsSourceField = AccessTools.Field(typeof(PlayerVoiceChat), "ttsAudioSource"); private static readonly MethodInfo SpeakNow = AccessTools.Method(typeof(TTSVoice), "StartSpeakingWithHighlight", (Type[])null, (Type[])null); internal static AudioSource Source; private static float normalVolume; private static float started; public static void Speak(string word) { try { PlayerAvatar val = SemiFunc.PlayerAvatarLocal(); PlayerVoiceChat val2 = (PlayerVoiceChat)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); TTSVoice val3 = (TTSVoice)(((Object)(object)val2 != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); AudioSource val4 = (AudioSource)(((Object)(object)val2 != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || SpeakNow == null) { Plugin.Log.LogWarning((object)"whisper: no voice to speak with"); return; } Restore(); Source = val4; normalVolume = val4.volume; val4.volume = normalVolume * Lore.WhisperVolume.Value; started = Time.unscaledTime; SpeakNow.Invoke(val3, new object[3] { word, false, word }); } catch (Exception ex) { Plugin.Log.LogError((object)("whisper failed: " + ex)); Restore(); } } public static void Tick() { if (!((Object)(object)Source == (Object)null)) { float num = Time.unscaledTime - started; if ((num > 0.5f && !Source.isPlaying) || num > 8f) { Restore(); } } } private static void Restore() { if ((Object)(object)Source != (Object)null) { Source.volume = normalVolume; } Source = null; } internal static void Requiet(AudioSource source) { if (!((Object)(object)source == (Object)null) && !((Object)(object)source != (Object)(object)Source)) { normalVolume = source.volume; source.volume = normalVolume * Lore.WhisperVolume.Value; } } } [HarmonyPatch(typeof(AudioLowPassLogic), "LowPassValuesApply")] internal static class WhisperVolumeHook { private static readonly FieldInfo SourceField = AccessTools.Field(typeof(AudioLowPassLogic), "AudioSource"); private static void Postfix(AudioLowPassLogic __instance) { if (!((Object)(object)Whisper.Source == (Object)null)) { object? obj = SourceField?.GetValue(__instance); Whisper.Requiet((AudioSource)((obj is AudioSource) ? obj : null)); } } } [HarmonyPatch(typeof(PhysGrabObject), "GrabPlayerAddRPC")] internal static class GrabHook { private static void Postfix(PhysGrabObject __instance, int __0) { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } try { ValuableObject component = ((Component)__instance).GetComponent<ValuableObject>(); if (!((Object)(object)component == (Object)null)) { PhotonView obj = PhotonView.Find(__0); PhysGrabber val = ((obj != null) ? ((Component)obj).GetComponent<PhysGrabber>() : null); Lore.OnGrab(component, ((Object)(object)val != (Object)null) ? val.playerAvatar : null); } } catch (Exception ex) { Plugin.Log.LogError((object)("whisper failed: " + ex)); } } } [BepInPlugin("cam.magic", "Ember Words", "0.6.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "cam.magic"; internal static ManualLogSource Log; internal static ConfigEntry<bool> TriggerCasts; internal static ConfigEntry<bool> VoiceEnabled; internal static ConfigEntry<bool> LogVoice; internal static ConfigEntry<bool> VoiceTestWords; internal static ConfigEntry<float> TtsSpeed; internal static ConfigEntry<float> VoiceNoShapeSeconds; internal static ConfigEntry<float> VoiceMinLoudness; internal static ConfigEntry<float> VoiceMinSpeechSeconds; internal static ConfigEntry<float> VoiceThreshold; internal static ConfigEntry<float> VoiceBoost; private float nextHandCheck; private float nextWordSync; private EmberWand inHand; private bool rolledThisRun; private bool listening; private static ConfigDescription Range(string text, float min, float max) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown return new ConfigDescription(text, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>()); } private void Awake() { //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; TriggerCasts = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "TriggerCasts", false, "Let a normal trigger pull cast a plain fireball. Off = words only."); TtsSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("General", "TTSSpeed", 1.6f, Range("How fast characters speak spell phrases, in one line (1 = the game's normal speed). Each player's own setting.", 0.5f, 3f)); VoiceEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Voice", "Enabled", true, "Cast by speaking (each player's own setting). Typing in chat always works."); VoiceNoShapeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Voice", "NoShapeSeconds", 2.5f, Range("A shape word casts at once. Modifiers heard without one wait this long for a shape, then fizzle.", 0.2f, 5f)); VoiceMinLoudness = ((BaseUnityPlugin)this).Config.Bind<float>("Voice", "MinLoudness", 0.02f, Range("How loud audio must be to count as speech (0 to 1). Raise if background noise casts spells.", 0f, 1f)); VoiceMinSpeechSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Voice", "MinSpeechSeconds", 0.15f, Range("How much speech a phrase needs before it can cast.", 0f, 2f)); VoiceThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Voice", "Threshold", 0.06f, Range("How sure the recogniser must be before a word counts. Raise if words cast that you didn't say; lower if real words are missed.", 0.05f, 0.95f)); VoiceBoost = ((BaseUnityPlugin)this).Config.Bind<float>("Voice", "Boost", 1f, Range("How strongly the recogniser leans toward spell words.", 0f, 5f)); VoiceTestWords = ((BaseUnityPlugin)this).Config.Bind<bool>("Voice", "TestWords", false, "Testing only: while the Ember Wand is in hand, voice listens for every word in every pool, shows and logs each one it hears, and casts nothing. Turns itself off each time the game starts."); VoiceTestWords.Value = false; LogVoice = ((BaseUnityPlugin)this).Config.Bind<bool>("Voice", "Log", false, "Write every heard spell word, how loud it was and whether it was used, to the log. For tuning."); SpellBook.Bind(((BaseUnityPlugin)this).Config); Lore.Bind(((BaseUnityPlugin)this).Config); RemoveOldEntries(); ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { SpellBook.WordsVersion++; SpellBook.ListenVersion++; }; ((BaseUnityPlugin)this).Config.ConfigReloaded += delegate { SpellBook.WordsVersion++; SpellBook.ListenVersion++; }; Harmony val = new Harmony("cam.magic"); Type[] types = typeof(Plugin).Assembly.GetTypes(); foreach (Type type in types) { if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0) { try { val.CreateClassProcessor(type).Patch(); } catch (Exception ex) { Log.LogError((object)("hook " + type.Name + " failed: " + ex.Message)); } } } R.Check(); SpellBook.RollWords(); if (VoiceEnabled.Value) { string text = Speech.FindVoiceDir(((BaseUnityPlugin)this).Info.Location); if (text != null) { Speech.ResolveFrom(text); Speech.Load(text); } } } private void RemoveOldEntries() { if (AccessTools.Property(typeof(ConfigFile), "OrphanedEntries")?.GetValue(((BaseUnityPlugin)this).Config) is Dictionary<ConfigDefinition, string> { Count: not 0 } dictionary) { Log.LogInfo((object)$"removed {dictionary.Count} old settings from the config"); dictionary.Clear(); } } private void Update() { if (!listening) { listening = true; Lore.Listen(); } Whisper.Tick(); if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)RunManager.instance != (Object)null) { if (RunManager.instance.levelsCompleted > 0) { rolledThisRun = false; } else if (!rolledThisRun && SemiFunc.RunIsLevel()) { rolledThisRun = true; SpellBook.RollWords(); } } if (Time.unscaledTime >= nextWordSync) { nextWordSync = Time.unscaledTime + 0.5f; SpellBook.Sync(); } if (Time.unscaledTime >= nextHandCheck) { nextHandCheck = Time.unscaledTime + 0.1f; inHand = null; foreach (EmberWand wand in Casts.Wands) { if ((Object)(object)wand != (Object)null && R.IsInLocalHands((ChargedWand)(object)wand)) { inHand = wand; break; } } Speech.Listening = VoiceEnabled.Value && (Object)(object)inHand != (Object)null; } Speech.Tick(); string result; while (Speech.TestHeard.TryDequeue(out result)) { Ui.Show("word test heard: " + result, 3f); } string result2; while (Speech.Heard.TryDequeue(out result2)) { if (!((Object)(object)inHand == (Object)null) && !R.IsCharging((ChargedWand)(object)inHand)) { if (LogVoice.Value) { Log.LogInfo((object)("voice cast: \"" + result2 + "\"")); } R.SendChat(SemiFunc.PlayerAvatarLocal(), result2); } } } private void OnGUI() { Ui.Draw(); } } [HarmonyPatch(typeof(ChargedWand), "LateUpdate")] internal static class ReloadSparks { private static readonly FieldInfo State = AccessTools.Field(typeof(ItemGun), "stateCurrent"); private static readonly Dictionary<int, ParticleSystem> Sparks = new Dictionary<int, ParticleSystem>(); private static readonly Color Hot = new Color(1f, 0.85f, 0.4f, 1f); private static readonly Color Cool = new Color(1f, 0.3f, 0.05f, 1f); private static Material material; private static bool failed; private static void Postfix(ChargedWand __instance) { if (failed || !(__instance is EmberWand)) { return; } try { object? obj = R.Gun?.GetValue(__instance); ItemGun val = (ItemGun)((obj is ItemGun) ? obj : null); if ((Object)(object)val == (Object)null || (Object)(object)val.gunMuzzle == (Object)null || State == null) { return; } bool flag = Convert.ToInt32(State.GetValue(val)) != 0 && !R.IsCharging(__instance); int instanceID = ((Object)__instance).GetInstanceID(); Sparks.TryGetValue(instanceID, out var value); if ((Object)(object)value == (Object)null) { if (!flag) { return; } ParticleSystem val2 = (Sparks[instanceID] = Create(val.gunMuzzle)); value = val2; } if (flag && !value.isEmitting) { value.Play(); } else if (!flag && value.isEmitting) { value.Stop(true, (ParticleSystemStopBehavior)1); } } catch (Exception ex) { failed = true; Plugin.Log.LogError((object)("reload sparks failed, turned off: " + ex)); } } private static ParticleSystem Create(Transform tip) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown GameObject val = new GameObject("Ember Words reload sparks"); val.transform.SetParent(tip, false); ParticleSystem val2 = val.AddComponent<ParticleSystem>(); val2.Stop(true, (ParticleSystemStopBehavior)0); MainModule main = val2.main; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.2f, 0.45f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.6f, 1.6f); ((MainModule)(ref main)).startSize = new MinMaxCurve(0.008f, 0.02f); ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(Hot); ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).maxParticles = 40; ((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(0.4f); EmissionModule emission = val2.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(30f); ShapeModule shape = val2.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0; ((ShapeModule)(ref shape)).radius = 0.02f; ColorOverLifetimeModule colorOverLifetime = val2.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; Gradient val3 = new Gradient(); val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(Hot, 0f), new GradientColorKey(Cool, 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[2] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(0f, 1f) }); ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = MinMaxGradient.op_Implicit(val3); ParticleSystemRenderer component = val.GetComponent<ParticleSystemRenderer>(); if ((Object)(object)material == (Object)null) { Shader val4 = Shader.Find("Sprites/Default"); if ((Object)(object)val4 != (Object)null) { material = new Material(val4); } } if ((Object)(object)material != (Object)null) { ((Renderer)component).sharedMaterial = material; } ((Renderer)component).shadowCastingMode = (ShadowCastingMode)0; return val2; } } internal static class Speech { public static volatile bool Ready; public static volatile bool Listening; public static readonly ConcurrentQueue<string> Heard = new ConcurrentQueue<string>(); public static readonly ConcurrentQueue<string> TestHeard = new ConcurrentQueue<string>(); private const string Marker = "ember-words-voice.txt"; private static readonly FieldInfo LocalVoiceField = AccessTools.Field(typeof(PlayerVoiceChat), "localVoice"); private static readonly FieldInfo ViewField = AccessTools.Field(typeof(PlayerVoiceChat), "photonView"); private static PlayerVoiceChat localChat; private static float nextCheck; [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr LoadLibraryW(string path); [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] private static extern bool SetDllDirectoryW(string path); public static string FindVoiceDir(string pluginFile) { try { string directoryName = Path.GetDirectoryName(pluginFile); if (File.Exists(Path.Combine(directoryName, "model", "tokens.txt")) && File.Exists(Path.Combine(directoryName, "sherpa-onnx.dll"))) { Plugin.Log.LogInfo((object)("voice engine found in " + directoryName)); return directoryName; } string[] files = Directory.GetFiles(Paths.PluginPath, "ember-words-voice.txt", SearchOption.AllDirectories); if (files.Length != 0) { string directoryName2 = Path.GetDirectoryName(files[0]); Plugin.Log.LogInfo((object)("voice engine found in the separate EmberWordsVoice package at " + directoryName2)); return directoryName2; } } catch (Exception ex) { Plugin.Log.LogError((object)("voice engine search failed: " + ex.Message)); } Plugin.Log.LogError((object)"voice engine missing (reinstall Ember Words): voice casting off, typing still works"); return null; } public static void ResolveFrom(string dir) { AppDomain.CurrentDomain.AssemblyResolve += delegate(object _, ResolveEventArgs args) { if (new AssemblyName(args.Name).Name != "sherpa-onnx") { return (Assembly)null; } string text = Path.Combine(dir, "sherpa-onnx.dll"); return (!File.Exists(text)) ? null : Assembly.LoadFrom(text); }; } public static void Load(string dir) { Thread thread = new Thread((ThreadStart)delegate { try { SetDllDirectoryW(dir); string[] array = new string[2] { "onnxruntime.dll", "sherpa-onnx-c-api.dll" }; foreach (string text in array) { if (LoadLibraryW(Path.Combine(dir, text)) == IntPtr.Zero) { throw new Exception($"could not load {text} (Windows error {Marshal.GetLastWin32Error()})"); } } Engine.Start(Path.Combine(dir, "model")); Ready = true; Plugin.Log.LogInfo((object)"speech ready"); } catch (Exception ex) { Plugin.Log.LogError((object)("speech failed to load: " + ex)); } }); thread.IsBackground = true; thread.Name = "Ember Words speech load"; thread.Start(); } public static void Tick() { if (!Ready || Time.unscaledTime < nextCheck) { return; } nextCheck = Time.unscaledTime + 1f; try { if ((Object)(object)localChat == (Object)null) { PlayerVoiceChat[] array = Object.FindObjectsByType<PlayerVoiceChat>((FindObjectsSortMode)0); foreach (PlayerVoiceChat obj in array) { object? obj2 = ViewField?.GetValue(obj); PhotonView val = (PhotonView)((obj2 is PhotonView) ? obj2 : null); if (val != null && val.IsMine) { localChat = obj; break; } } } if ((Object)(object)localChat != (Object)null) { object? obj3 = LocalVoiceField?.GetValue(localChat); LocalVoice val2 = (LocalVoice)((obj3 is LocalVoice) ? obj3 : null); if (val2 != null) { VoiceHook.Tap(val2); } } } catch (Exception ex) { Plugin.Log.LogError((object)("voice check failed: " + ex)); nextCheck = Time.unscaledTime + 30f; } } internal static LocalVoice VoiceOf(PlayerVoiceChat chat) { object? obj = LocalVoiceField?.GetValue(chat); return (LocalVoice)((obj is LocalVoice) ? obj : null); } } internal static class Engine { public static KeywordSpotter Spotter; public static KeywordEncoder Encoder; private const string Placeholder = "Z Q Z Q Z Q Z Q @init"; [MethodImpl(MethodImplOptions.NoInlining)] public static void Start(string modelDir) { //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown string text = Path.Combine(modelDir, "tokens.txt"); KeywordSpotterConfig val = default(KeywordSpotterConfig); ((KeywordSpotterConfig)(ref val))..ctor(); val.FeatConfig.SampleRate = 16000; val.FeatConfig.FeatureDim = 80; val.ModelConfig.Transducer.Encoder = Path.Combine(modelDir, "encoder-epoch-12-avg-2-chunk-16-left-64.int8.onnx"); val.ModelConfig.Transducer.Decoder = Path.Combine(modelDir, "decoder-epoch-12-avg-2-chunk-16-left-64.onnx"); val.ModelConfig.Transducer.Joiner = Path.Combine(modelDir, "joiner-epoch-12-avg-2-chunk-16-left-64.int8.onnx"); val.ModelConfig.Tokens = text; val.ModelConfig.Provider = "cpu"; val.ModelConfig.NumThreads = 1; val.KeywordsScore = Plugin.VoiceBoost.Value; val.KeywordsThreshold = Plugin.VoiceThreshold.Value; val.KeywordsBuf = "Z Q Z Q Z Q Z Q @init"; val.KeywordsBufSize = "Z Q Z Q Z Q Z Q @init".Length; Encoder = new KeywordEncoder(text, Path.Combine(modelDir, "bpe.model")); Spotter = new KeywordSpotter(val); } } [HarmonyPatch(typeof(PlayerVoiceChat), "PhotonVoiceCreated")] internal static class VoiceHook { private static LocalVoice tapped; private static void Postfix(PlayerVoiceChat __instance) { try { LocalVoice val = Speech.VoiceOf(__instance); if (val != null) { Tap(val); } } catch (Exception ex) { Plugin.Log.LogError((object)("voice hook failed: " + ex)); } } internal static void Tap(LocalVoice voice) { if (voice != tapped && Speech.Ready && Plugin.VoiceEnabled.Value) { Connect(voice); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void Connect(LocalVoice voice) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) try { VoiceInfo info = voice.Info; int samplingRate = ((VoiceInfo)(ref info)).SamplingRate; info = voice.Info; Listener l = Listener.Create(samplingRate, Math.Max(1, ((VoiceInfo)(ref info)).Channels)); if (voice is LocalVoiceFramed<float> val) { val.AddPostProcessor(new IProcessor<float>[1] { new FloatTap(l) }); } else { if (!(voice is LocalVoiceFramed<short> val2)) { Plugin.Log.LogError((object)("unknown voice audio type " + ((object)voice).GetType().Name)); return; } val2.AddPostProcessor(new IProcessor<short>[1] { new ShortTap(l) }); } tapped = voice; ManualLogSource log = Plugin.Log; info = voice.Info; log.LogInfo((object)$"voice chat connected ({((VoiceInfo)(ref info)).SamplingRate} Hz)"); } catch (Exception ex) { Plugin.Log.LogError((object)("voice connect failed: " + ex)); } } } internal sealed class FloatTap : IProcessor<float>, IDisposable { private readonly Listener l; public FloatTap(Listener l) { this.l = l; } public float[] Process(float[] buf) { if (Speech.Listening) { l.Push(buf); } return buf; } public void Dispose() { } } internal sealed class ShortTap : IProcessor<short>, IDisposable { private readonly Listener l; public ShortTap(Listener l) { this.l = l; } public short[] Process(short[] buf) { if (Speech.Listening) { l.Push(buf); } return buf; } public void Dispose() { } } internal sealed class Listener { private const double LoudWindow = 1.5; private static Listener current; private readonly BlockingCollection<float[]> queue = new BlockingCollection<float[]>(200); private readonly int channels; private readonly int rate; private readonly HashSet<string> warned = new HashSet<string>(); private OnlineStream stream; private int builtVersion = -1; private float builtThreshold; private float builtBoost; private bool builtTest; private bool dirty; private readonly List<(double at, double seconds)> loud = new List<(double, double)>(); private readonly List<(int role, string word)> held = new List<(int, string)>(); private double lastHit; private double heldLoud; public static Listener Create(int rate, int channels) { current?.queue.CompleteAdding(); current = new Listener(rate, channels); return current; } private Listener(int rate, int channels) { this.rate = rate; this.channels = channels; Thread thread = new Thread(Run); thread.IsBackground = true; thread.Name = "Ember Words speech"; thread.Start(); } public void Push(float[] buf) { int num = buf.Length / channels; float[] array = new float[num]; for (int i = 0; i < num; i++) { array[i] = Mathf.Clamp(buf[i * channels], -1f, 1f); } queue.TryAdd(array); } public void Push(short[] buf) { int num = buf.Length / channels; float[] array = new float[num]; for (int i = 0; i < num; i++) { array[i] = (float)buf[i * channels] / 32768f; } queue.TryAdd(array); } private static float Loudness(float[] s) { double num = 0.0; for (int i = 0; i < s.Length; i++) { num += (double)s[i] * (double)s[i]; } if (s.Length != 0) { return (float)Math.Sqrt(num / (double)s.Length); } return 0f; } private void BuildStream() { builtVersion = SpellBook.ListenVersion; builtThreshold = Plugin.VoiceThreshold.Value; builtBoost = Plugin.VoiceBoost.Value; builtTest = Plugin.VoiceTestWords.Value; string[] array = (builtTest ? SpellBook.AllWords() : SpellBook.ListenWords()); List<string> list = new List<string>(); string[] array2 = array; foreach (string text in array2) { string text2 = Engine.Encoder.Encode(text); if (text2 != null) { list.Add(KeywordEncoder.Line(text2, text, builtBoost, builtThreshold)); } else if (warned.Add(text)) { Plugin.Log.LogWarning((object)("voice can't listen for \"" + text + "\": the recogniser has no way to write it")); } } OnlineStream obj = stream; if (obj != null) { obj.Dispose(); } stream = ((list.Count > 0) ? Engine.Spotter.CreateStream(string.Join("\n", list)) : null); ForgetHeard(); if (builtTest) { Plugin.Log.LogInfo((object)$"voice word test on: listening for all {list.Count} words, casting nothing"); } else if (Plugin.LogVoice.Value) { Plugin.Log.LogInfo((object)("voice listening for: " + string.Join(", ", array))); } } private void ForgetHeard() { held.Clear(); loud.Clear(); heldLoud = 0.0; dirty = false; } private void Run() { Stopwatch stopwatch = Stopwatch.StartNew(); try { while (!queue.IsCompleted) { double now = stopwatch.Elapsed.TotalSeconds; if (!Speech.Listening) { if (dirty) { if (stream != null) { Engine.Spotter.Reset(stream); } ForgetHeard(); } queue.TryTake(out var _, 100); continue; } if (builtVersion != SpellBook.ListenVersion || builtThreshold != Plugin.VoiceThreshold.Value || builtBoost != Plugin.VoiceBoost.Value || builtTest != Plugin.VoiceTestWords.Value) { BuildStream(); } if (queue.TryTake(out var item2, 50) && stream != null) { dirty = true; if (Loudness(item2) >= Plugin.VoiceMinLoudness.Value) { loud.Add((now, (double)item2.Length / (double)rate)); } loud.RemoveAll(((double at, double seconds) x) => now - x.at > 1.5); stream.AcceptWaveform(rate, item2); while (Engine.Spotter.IsReady(stream)) { Engine.Spotter.Decode(stream); string text = Word(Engine.Spotter.GetResult(stream).Keyword); if (text.Length != 0) { Engine.Spotter.Reset(stream); Hit(text, now); } } } if (held.Count > 0 && now - lastHit >= (double)Plugin.VoiceNoShapeSeconds.Value) { Finish(string.Join(" ", held.Select(((int role, string word) h) => h.word)), heldLoud, "no shape"); held.Clear(); } } } catch (Exception ex) { Plugin.Log.LogError((object)("speech recognition stopped: " + ex)); } finally { OnlineStream obj = stream; if (obj != null) { obj.Dispose(); } } } private static string Word(string keyword) { return (keyword ?? "").Replace(" ", "").Replace("▁", "").Replace("_", " ") .Trim() .ToLowerInvariant(); } private void Hit(string word, double now) { if (builtTest) { Plugin.Log.LogInfo((object)("word test heard \"" + word + "\"")); Speech.TestHeard.Enqueue(word); return; } Role role = SpellBook.ListenRole(word); double num = loud.Where(((double at, double seconds) x) => now - x.at <= 1.5).Sum(((double at, double seconds) x) => x.seconds); string arg; if (role == null) { arg = "ignored, not an active word"; } else if (num < (double)Plugin.VoiceMinSpeechSeconds.Value) { arg = "ignored, too quiet"; } else if (role.IsShape) { arg = "shape, cast"; List<string> list = held.Select(((int role, string word) h) => h.word).ToList(); list.Add(word); held.Clear(); Finish(string.Join(" ", list), num, "shape heard"); } else if (held.Any(((int role, string word) h) => h.role == role.Id)) { arg = "ignored, that modifier is already held"; } else if (held.Count >= Math.Max(0, SpellBook.MaxWords.Value - 1)) { arg = "ignored, no room for more modifiers"; } else { arg = "modifier, waiting for a shape"; held.Add((role.Id, word)); lastHit = now; heldLoud = num; } if (Plugin.LogVoice.Value) { Plugin.Log.LogInfo((object)$"heard word \"{word}\" ({num:0.00}s of speech) -> {arg}"); } } private static void Finish(string phrase, double loudSeconds, string why) { if (!string.IsNullOrEmpty(phrase)) { bool flag = loudSeconds >= (double)Plugin.VoiceMinSpeechSeconds.Value; if (Plugin.LogVoice.Value) { Plugin.Log.LogInfo((object)string.Format("heard \"{0}\" ({1}, {2:0.00}s of speech) -> {3}", phrase, why, loudSeconds, flag ? "cast" : "ignored, too quiet")); } if (flag) { Speech.Heard.Enqueue(phrase); } } } } public enum Stat { DirectDamage, SplashDamage, SplashRadius, Speed, Lifetime, Knockback, ChargeSeconds, ReloadSeconds, EnergyCost, Size } public enum Fizzle { None, TwoShapes, NoCharge, NoShape, UnknownWord } public sealed class Spell { public const int StatCount = 10; private const float Magic = 4242f; private const float Version = 4f; public int ShapeId; public Fizzle Fizzle; public int Detail; public readonly float[] Stats = new float[10]; public readonly List<int> Roles = new List<int>(); public float this[Stat s] { get { return Stats[(int)s]; } set { Stats[(int)s] = value; } } public float[] Encode() { List<float> list = new List<float> { 4242f, 4f, ShapeId, (float)Fizzle, Detail }; list.AddRange(Stats); list.Add(Roles.Count); foreach (int role in Roles) { list.Add(role); } return list.ToArray(); } public static Spell Decode(float[] f) { if (f == null || f.Length < 16 || f[0] != 4242f || f[1] != 4f) { return null; } Spell spell = new Spell { ShapeId = (int)f[2], Fizzle = (Fizzle)f[3], Detail = (int)f[4] }; for (int i = 0; i < 10; i++) { spell.Stats[i] = f[5 + i]; } int num = (int)f[15]; for (int j = 0; j < num && 16 + j < f.Length; j++) { spell.Roles.Add((int)f[16 + j]); } return spell; } } public sealed class Role { public int Id; public string Name; public bool IsShape; public ConfigEntry<string> WordsEntry; public readonly ConfigEntry<float>[] Values = new ConfigEntry<float>[10]; public readonly ConfigEntry<float>[] Adds = new ConfigEntry<float>[10]; public string[] Words => (from w in (WordsEntry?.Value ?? "").Split(',') select w.Trim().ToLowerInvariant() into w where w.Length > 0 select w).ToArray(); public bool Rotates => Words.Length > 1; public float Value(int stat) { ConfigEntry<float> obj = Values[stat]; if (obj == null) { if (!IsShape) { return 1f; } return 0f; } return obj.Value; } public float AddOf(int stat) { return Adds[stat]?.Value ?? 0f; } } public static class SpellBook { private sealed class ListenSet { public readonly string[] Words; public readonly Dictionary<string, Role> ByWord = new Dictionary<string, Role>(); public readonly string Key; public ListenSet(Dictionary<int, string> byRole) { foreach (Role role in Roles) { if (byRole.TryGetValue(role.Id, out var value) && value.Length > 0 && !ByWord.ContainsKey(value)) { ByWord[value] = role; } } Words = ByWord.Keys.ToArray(); Key = string.Join(",", ByWord.Select((KeyValuePair<string, Role> p) => p.Value.Id + ":" + p.Key)); } } public const int Fireball = 0; public const int Bolt = 1; public const int Nova = 2; public const int Speed = 3; public const int Power = 4; public const int Wide = 5; public const int Heavy = 6; public const int Rapid = 7; public const int Doom = 8; public const int FizzleShape = 99; public static readonly List<Role> Roles = new List<Role>(); public static volatile int WordsVersion; public static Role FizzleRole; public static ConfigEntry<int> MaxWords; public static ConfigEntry<float> SecondWordCostMult; public static ConfigEntry<float> MinCharge; public static ConfigEntry<float> MinReload; private static readonly bool[] HigherIsBetter = new bool[10] { true, true, true, true, true, true, false, false, false, true }; public const float MaxSplashRadius = 5f; private static readonly (float min, float max)[] StatRange = new(float, float)[10] { (0f, 1000f), (0f, 1000f), (0f, 5f), (0.1f, 100f), (0.05f, 30f), (0f, 200f), (0f, 10f), (0f, 20f), (1f, 30f), (0.1f, 10f) }; private static readonly (float min, float max)[] DoomRange = new(float, float)[10] { (0f, 1000f), (0f, 1000f), (5f, 150f), (0.1f, 100f), (0.05f, 30f), (0f, 200f), (0f, 30f), (0f, 30f), (1f, 30f), (0.1f, 10f) }; private static readonly (float min, float max) MultRange = (min: 0f, max: 10f); private static readonly Dictionary<int, string> active = new Dictionary<int, string>(); private static readonly Random rng = new Random(); private const string RoomKey = "ew.words"; public static volatile int ListenVersion; private static Dictionary<int, string> hostActive = new Dictionary<int, string>(); private static string lastHostString; private static string lastSent; private static float sentAt; private static bool wasHost; private static volatile ListenSet listenSet = new ListenSet(new Dictionary<int, string>()); public static bool DoomUnlocked { get; private set; } private static bool HasAdd(int stat) { if (stat != 6 && stat != 7) { return stat == 8; } return true; } private static (float min, float max) RangeOf(int shape, int stat) { if (shape != 8) { return StatRange[stat]; } return DoomRange[stat]; } private static (float min, float max) AddRange(int stat) { if (stat != 6) { return (min: -10f, max: 10f); } return (min: -5f, max: 5f); } private static ConfigDescription Range(string text, float min, float max) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown return new ConfigDescription(text, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>()); } public static void Bind(ConfigFile cfg) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown MaxWords = cfg.Bind<int>("Rules", "MaxWords", 3, new ConfigDescription("Most words counted in one phrase.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>())); SecondWordCostMult = cfg.Bind<float>("Rules", "SecondWordCostMult", 1.5f, Range("How much heavier the second modifier's costs are (1.5 = 50% more).", 1f, 5f)); MinCharge = cfg.Bind<float>("Rules", "MinChargeSeconds", 0.2f, Range("Shortest possible charge.", 0f, 5f)); MinReload = cfg.Bind<float>("Rules", "MinReloadSeconds", 0.3f, Range("Shortest possible reload.", 0f, 5f)); Roles.Clear(); Shape(cfg, 0, "Fireball", "fireball", 120f, 30f, 0.8f, 15f, 5f, 10f, 1.5f, 1.01f, 2f, 1f); Shape(cfg, 1, "Bolt", "bolt, spark, needle, arrow, sting", 90f, 0f, 0f, 40f, 3f, 0f, 0f, 1.5f, 1f, 0.2f); Shape(cfg, 2, "Nova", "supernova, sun, comet, meteor, eclipse", 250f, 120f, 4f, 12f, 12f, 50f, 4f, 6f, 6f, 5f); Shape(cfg, 8, "Doom", "doom", 1000f, 1000f, 60f, 8f, 15f, 100f, 30f, 10f, 1f, 10f); Modifier(cfg, 3, "Haste", "haste, swift, fleet", 0.8f, 0.8f, 1f, 2f, 0.8f, 0.7f, 0.5f, 1f, 1f, 0.8f, 0f, 0f, 0f); Modifier(cfg, 4, "Scorch", "scorch, blaze, burn, char, sizzle, ignite, singe", 1.6f, 1.6f, 1.1f, 1.1f, 1.2f, 1.1f, 1.1f, 1.1f, 1f, 1.2f, 0f, 0f, 1f); Modifier(cfg, 5, "Blast", "blast, boom, erupt, shatter, bloom, detonate", 1f, 1.7f, 1.7f, 1f, 1.3f, 1.1f, 1.1f, 1f, 1f, 1.5f, 0f, 1f, 1f); Modifier(cfg, 6, "Crush", "crush, smash, heavy", 1.3f, 1f, 1f, 1f, 1f, 3f, 1f, 1.1f, 1f, 1.2f, 1.5f, 0f, 0f); Modifier(cfg, 7, "Rapid", "rapid, flurry, frenzy, swarm, volley, barrage, torrent", 0.85f, 0.85f, 1f, 1f, 0.8f, 1f, 0.9f, 0.5f, 1f, 0.95f, 0f, 0f, 0f); FizzleRole = new Role { Id = 99, Name = "Fizzle", IsShape = true }; BindShapeStats(cfg, "Shape.Fizzle", FizzleRole, 10f, 20f, 5f, 2f, 0.05f, 30f, 0.2f, 1f, 1f, 2f); } private static void Shape(ConfigFile cfg, int id, string name, string words, params float[] stats) { string text = "Shape." + name; Role role = new Role { Id = id, Name = name, IsShape = true }; role.WordsEntry = cfg.Bind<string>(text, "Words", words, (id == 8) ? "The doom word. It only works after a valuable has whispered it this run. Drains the whole wand and ignores modifiers." : "Words for this shape, separated by commas. One is picked each run. A single word always works."); BindShapeStats(cfg, text, role, stats); Roles.Add(role); } private static void BindShapeStats(ConfigFile cfg, string sec, Role role, params float[] stats) { for (int i = 0; i < 10; i++) { string text = i switch { 8 => (role.Id == 8) ? "Not used: doom drains the whole wand." : "Battery bars this spell uses. The wand's total is Hatter's Ember Wand FireballsPerCharge setting.", 2 => (role.Id == 8) ? "Blast radius in metres. Hits everyone inside, the caster included." : "Blast radius in metres. Hits everyone inside, the caster included. Capped at the largest blast the explosion can show.", 9 => "Fireball size: 1 = normal. Changes both how big it looks and how big a target it hits.", _ => "", }; (float, float) tuple = RangeOf(role.Id, i); ConfigEntry<float>[] values = role.Values; int num = i; Stat stat = (Stat)i; values[num] = cfg.Bind<float>(sec, stat.ToString(), stats[i], Range(text, tuple.Item1, tuple.Item2)); } } private static void Modifier(ConfigFile cfg, int id, string name, string words, params float[] values) { string text = "Modifier." + name; Role role = new Role { Id = id, Name = name, IsShape = false }; role.WordsEntry = cfg.Bind<string>(text, "Words", words, "Words for this modifier, separated by commas. One is picked each run. Without a shape word in the phrase it fizzles."); int num = 10; for (int i = 0; i < 10; i++) { Stat stat = (Stat)i; role.Values[i] = cfg.Bind<float>(text, stat.ToString() + "Mult", values[i], Range("", MultRange.min, MultRange.max)); if (HasAdd(i)) { role.Adds[i] = cfg.Bind<float>(text, stat.ToString() + "Add", values[num++], Range("", AddRange(i).min, AddRange(i).max)); } } Roles.Add(role); } public static Role RoleById(int id) { if (id != 99) { return Roles.FirstOrDefault((Role r) => r.Id == id); } return FizzleRole; } public static string[] AllWords() { return Roles.SelectMany((Role r) => r.Words).Distinct().ToArray(); } public static List<string> SpellWords(string phrase, out bool allMatched) { string[] array = (phrase ?? "").ToLowerInvariant().Split(new char[6] { ' ', ',', '.', '!', '?', '-' }, StringSplitOptions.RemoveEmptyEntries); HashSet<string> hashSet = new HashSet<string>(AllWords()); int val = ((hashSet.Count == 0) ? 1 : hashSet.Max((string w) => w.Split(' ').Length)); List<string> list = new List<string>(); allMatched = array.Length != 0; int num = 0; while (num < array.Length) { int num2 = Math.Min(val, array.Length - num); while (num2 > 0 && !hashSet.Contains(string.Join(" ", array, num, num2))) { num2--; } if (num2 == 0) { allMatched = false; num++; } else { list.Add(string.Join(" ", array, num, num2)); num += num2; } } return list; } public static string[] ShapeWords() { return Roles.Where((Role r) => r.IsShape).SelectMany((Role r) => r.Words).Distinct() .ToArray(); } public static void UnlockDoom() { if (!DoomUnlocked) { DoomUnlocked = true; ListenVersion++; PublishActive(); Plugin.Log.LogInfo((object)"doom unlocked for this run"); } } private static bool Usable(int roleId) { if (roleId == 8) { return DoomUnlocked; } return true; } public static void RollWords() { DoomUnlocked = false; active.Clear(); foreach (Role role in Roles) { string[] words = role.Words; if (words.Length != 0) { active[role.Id] = words[rng.Next(words.Length)]; } } Lore.ResetRun(); ListenVersion++; PublishActive(); } public static string ActiveWord(Role r) { string[] words = r.Words; if (words.Length <= 1) { return words.FirstOrDefault() ?? ""; } if (!active.TryGetValue(r.Id, out var value) || Array.IndexOf(words, value) < 0) { value = (active[r.Id] = words[rng.Next(words.Length)]); ListenVersion++; PublishActive(); } return value; } public static void PublishActive() { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_00c8: Expected O, but got Unknown try { if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient) { string text = string.Join(",", from r in Roles where Usable(r.Id) && active.ContainsKey(r.Id) && active[r.Id].IndexOfAny(new char[2] { ',', ':' }) < 0 select r.Id + ":" + active[r.Id]); if (!(text == RoomText()) && (!(text == lastSent) || !(Time.unscaledTime < sentAt + 3f))) { lastSent = text; sentAt = Time.unscaledTime; Room currentRoom = PhotonNetwork.CurrentRoom; Hashtable val = new Hashtable(); ((Dictionary<object, object>)val).Add((object)"ew.words", (object)text); currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); } } } catch (Exception ex) { Plugin.Log.LogError((object)("could not share the active words: " + ex.Message)); } } public static void SetActiveFromHost(string text) { Dictionary<int, string> dictionary = new Dictionary<int, string>(); string[] array = (text ?? "").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { int num = text2.IndexOf(':'); if (num > 0 && int.TryParse(text2.Substring(0, num), out var result)) { dictionary[result] = text2.Substring(num + 1).Trim().ToLowerInvariant(); } } hostActive = dictionary; lastHostString = text; ListenVersion++; } private static string RoomText() { Room currentRoom = PhotonNetwork.CurrentRoom; Hashtable val = ((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties : null); if (val == null || !((Dictionary<object, object>)(object)val).TryGetValue((object)"ew.words", out object value)) { return null; } return value as string; } public static void Sync() { try { bool num = SemiFunc.IsMasterClientOrSingleplayer(); string text = (PhotonNetwork.InRoom ? RoomText() : null); if (num && !wasHost && text != null) { AdoptRoomWords(text); } wasHost = num; if (num) { PublishActive(); } else if (text == null) { if (hostActive.Count > 0) { hostActive = new Dictionary<int, string>(); lastHostString = null; ListenVersion++; } } else if (text != lastHostString) { SetActiveFromHost(text); } ListenSet listenSet = new ListenSet(num ? Roles.Where((Role r) => r.Words.Length != 0 && Usable(r.Id)).ToDictionary((Role r) => r.Id, ActiveWord) : ((hostActive.Count > 0) ? hostActive : Roles.Where((Role r) => r.Id == 0 && r.Words.Length != 0).ToDictionary((Role r) => r.Id, (Role r) => r.Words[0]))); if (listenSet.Key != SpellBook.listenSet.Key) { SpellBook.listenSet = listenSet; ListenVersion++; } } catch (Exception ex) { Plugin.Log.LogError((object)("word sync failed: " + ex.Message)); } } private static void AdoptRoomWords(string text) { SetActiveFromHost(text); foreach (KeyValuePair<int, string> item in hostActive) { Role role = RoleById(item.Key); if (role != null && Array.IndexOf(role.Words, item.Value) >= 0) { active[item.Key] = item.Value; } } hostActive = new Dictionary<int, string>(); lastHostString = null; } public static string[] ListenWords() { return listenSet.Words; } public static Role ListenRole(string word) { if (word == null || !listenSet.ByWord.TryGetValue(word, out var value)) { return null; } return value; } public static Spell Parse(string phrase) { List<(Role, string)> list = new List<(Role, string)>(); bool allMatched; foreach (string raw in SpellWords(phrase, out allMatched)) { Role role = Roles.FirstOrDefault((Role x) => x.Words.Contains(raw)); if (role != null) { list.Add((role, raw)); } if (list.Count >= MaxWords.Value) { break; } } if (list.Count == 0) { return null; } Spell spell = new Spell(); spell.Roles.AddRange(list.Select<(Role, string), int>(((Role role, string word) s) => s.role.Id)); (Role, string) tuple = list.FirstOrDefault<(Role, string)>(((Role role, string word) s) => s.word != ActiveWord(s.role) || !Usable(s.role.Id)); if (tuple.Item1 != null) { return MakeFizzle(spell, Fizzle.UnknownWord, tuple.Item1.Id * 100 + Array.IndexOf(tuple.Item1.Words, tuple.Item2)); } List<Role> list2 = (from s in list select s.role into r where r.IsShape select r).Distinct().ToList(); if (list2.Count == 0) { return MakeFizzle(spell, Fizzle.NoShape); } if (list2.Count > 1) { return MakeFizzle(spell, Fizzle.TwoShapes); } Role role2 = list2[0]; spell.ShapeId = role2.Id; for (int num = 0; num < 10; num++) { spell.Stats[num] = role2.Value(num); } List<Role> list3 = ((role2.Id == 8) ? new List<Role>() : (from s in list select s.role into r where !r.IsShape select r).Distinct().ToList()); for (int num2 = 0; num2 < list3.Count; num2++) { Apply(spell, list3[num2], (num2 == 0) ? 1f : SecondWordCostMult.Value); } Clamp(spell); return spell; } private static void Apply(Spell s, Role mod, float k) { for (int i = 0; i < 10; i++) { float num = mod.Value(i); float num2 = mod.AddOf(i); bool flag = HigherIsBetter[i]; bool num3 = i != 9 && (flag ? (num < 1f) : (num > 1f)); bool flag2 = i != 9 && (flag ? (num2 < 0f) : (num2 > 0f)); if (num3) { num = 1f + (num - 1f) * k; } if (flag2) { num2 *= k; } s.Stats[i] = s.Stats[i] * num + num2; } } private static void Clamp(Spell s) { for (int i = 0; i < 10; i++) { (float, float) tuple = RangeOf(s.ShapeId, i); s.Stats[i] = Math.Min(tuple.Item2, Math.Max(tuple.Item1, s.Stats[i])); } s[Stat.ChargeSeconds] = Math.Max(MinCharge.Value, s[Stat.ChargeSeconds]); s[Stat.ReloadSeconds] = Math.Max(MinReload.Value, s[Stat.ReloadSeconds]); s[Stat.EnergyCost] = Math.Min(StatRange[8].max, (float)Math.Ceiling(s[Stat.EnergyCost] - 0.001f)); } public static Spell MakeFizzle(Spell from, Fizzle why, int detail = 0) { Spell spell = new Spell { ShapeId = 99, Fizzle = why, Detail = detail }; spell.Roles.AddRange(from.Roles); for (int i = 0; i < 10; i++) { spell.Stats[i] = FizzleRole.Value(i); } Clamp(spell); return spell; } public static Spell PlainFireball() { Spell spell = new Spell { ShapeId = 0 }; Role role = RoleById(0); for (int i = 0; i < 10; i++) { spell.Stats[i] = role.Value(i); } Clamp(spell); return spell; } } [HarmonyPatch(typeof(TTSVoice), "StartSpeakingWithHighlight")] internal static class TtsHook { private static readonly MethodInfo StopAndClear = AccessTools.Method(typeof(TTSVoice), "StopAndClearVoice", (Type[])null, (Type[])null); private static readonly MethodInfo SetVoice = AccessTools.Method(typeof(TTSVoice), "setVoice", (Type[])null, (Type[])null); private static readonly MethodInfo Translate = AccessTools.Method(typeof(TTSVoice), "TranslateSpecialLetters", (Type[])null, (Type[])null); private static readonly FieldInfo VoicingSource = AccessTools.Field(typeof(TTSVoice), "voicingSource"); private static readonly FieldInfo ActiveVoice = AccessTools.Field(typeof(TTSVoice), "activeVoice"); private static MethodInfo schedule; private static FieldInfo frameMs; private static bool looked; private static bool Prefix(TTSVoice __instance, string __0, bool __1) { if (!IsSpellPhrase(__0)) { return true; } try { StopAndClear?.Invoke(__instance, null); VoicingSource?.SetValue(__instance, Enum.ToObject(VoicingSource.FieldType, __1 ? 1 : 0)); SetVoice?.Invoke(__instance, new object[1] { __1 ? 1 : 0 }); object obj = ActiveVoice?.GetValue(__instance); if (obj == null || !Find(obj.GetType())) { return true; } string text = ((Translate != null) ? ((string)Translate.Invoke(__instance, new object[1] { __0 })) : __0); object obj2 = frameMs?.GetValue(obj); if (obj2 is int num) { frameMs.SetValue(obj, Math.Max(1, (int)Math.Round((float)num / Plugin.TtsSpeed.Value))); } schedule.Invoke(obj, new object[3] { text, true, __0 }); if (obj2 != null) { frameMs.SetValue(obj, obj2); } return false; } catch (Exception ex) { Plugin.Log.LogWarning((object)("quick spell speech failed, using normal speech: " + ex.Message)); return true; } } private static bool IsSpellPhrase(string message) { if (string.IsNullOrWhiteSpace(message)) { return false; } SpellBook.SpellWords(message, out var allMatched); return allMatched; } private static bool Find(Type speechType) { if (!looked) { looked = true; schedule = AccessTools.Method(speechType, "schedule", new Type[3] { typeof(string), typeof(bool), typeof(string) }, (Type[])null); frameMs = AccessTools.Field(speechType, "msPerSpeechFrame"); if (frameMs == null) { Plugin.Log.LogWarning((object)("TTS speed setting not found; spell phrases play at normal speed. Speech fields: " + string.Join(", ", from f in speechType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) select f.Name))); } } return schedule != null; } } internal static class Ui { private static readonly List<(string text, float until)> lines = new List<(string, float)>(); private static GUIStyle style; private static GUIStyle shadow; public static void Show(string text, float seconds = 5f) { if (!string.IsNullOrWhiteSpace(text)) { lines.Add((text, Time.unscaledTime + seconds)); if (lines.Count > 3) { lines.RemoveAt(0); } } } public static void Draw() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) lines.RemoveAll(((string text, float until) l) => Time.unscaledTime > l.until); if (lines.Count == 0) { return; } if (style == null) { style = new GUIStyle(GUI.skin.label) { fontSize = 22, alignment = (TextAnchor)4, wordWrap = true }; style.normal.textColor = new Color(1f, 0.85f, 0.55f); shadow = new GUIStyle(style); shadow.normal.textColor = new Color(0f, 0f, 0f, 0.8f); } float num = Mathf.Min(900f, (float)Screen.width - 40f); float num2 = (float)Screen.height * 0.72f; Rect val = default(Rect); foreach (var line in lines) { string item = line.text; ((Rect)(ref val))..ctor(((float)Screen.width - num) / 2f, num2, num, 34f); GUI.Label(new Rect(((Rect)(ref val)).x + 2f, ((Rect)(ref val)).y + 2f, ((Rect)(ref val)).width, ((Rect)(ref val)).height), item, shadow); GUI.Label(val, item, style); num2 += 34f; } } } internal static class R { public static readonly MethodInfo HostTriggerPulled = AccessTools.Method(typeof(ChargedWand), "HostTriggerPulled", (Type[])null, (Type[])null); public static readonly MethodInfo Holder = AccessTools.PropertyGetter(typeof(ChargedWand), "Holder"); public static readonly MethodInfo HeldByLocal = AccessTools.PropertyGetter(typeof(ChargedWand), "HeldByLocal"); public static readonly FieldInfo Gun = AccessTools.Field(typeof(ChargedWand), "gun"); public static readonly FieldInfo ShootCooldown = AccessTools.Field(typeof(ItemGun), "shootCooldown"); public static readonly FieldInfo BatteryDrainBars = AccessTools.Field(typeof(ItemGun), "batteryDrainFullBars"); public static readonly FieldInfo BatteryInt = AccessTools.Field(typeof(ItemBattery), "batteryLifeInt"); public static readonly FieldInfo IsEquipped = AccessTools.Field(typeof(ItemEquippable), "isEquipped"); public static readonly MethodInfo SpawnSmall = AccessTools.Method(AccessTools.TypeByName("HatterWeaponsPack.RocketExplosion"), "SpawnSmall", (Type[])null, (Type[])null); public static readonly MethodInfo Blast = AccessTools.Method(AccessTools.TypeByName("HatterWeaponsPack.RocketExplosion"), "Blast", (Type[])null, (Type[])null); public static readonly Type FxType = AccessTools.TypeByName("HatterWeaponsPack.FireballFx"); public static readonly FieldInfo FxSize = ((FxType == null) ? null : AccessTools.Field(FxType, "size")); public static readonly MethodInfo ChatSend = AccessTools.Method(typeof(PlayerAvatar), "ChatMessageSend", (Type[])null, (Type[])null); private static readonly Func<ChargedWand, bool> HeldByLocalFast = ((HeldByLocal == null) ? null : ((Func<ChargedWand, bool>)Delegate.CreateDelegate(typeof(Func<ChargedWand, bool>), HeldByLocal))); private static readonly FieldRef<ChargedWand, bool> HostChargingRef = AccessTools.FieldRefAccess<ChargedWand, bool>("hostCharging"); private static readonly FieldRef<ChargedWand, bool> ChargingRef = AccessTools.FieldRefAccess<ChargedWand, bool>("charging"); public static PlayerAvatar HolderOf(ChargedWand w) { object? obj = Holder?.Invoke(w, null); return (PlayerAvatar)((obj is PlayerAvatar) ? obj : null); } public static bool IsHeldByLocal(ChargedWand w) { if (HeldByLocalFast != null) { return HeldByLocalFast(w); } return false; } public static bool IsHostCharging(ChargedWand w) { return HostChargingRef.Invoke(w); } public static bool IsCharging(ChargedWand w) { return ChargingRef.Invoke(w); } public static bool IsInLocalHands(ChargedWand w) { if (!IsHeldByLocal(w)) { return false; } ItemEquippable component = ((Component)w).GetComponent<ItemEquippable>(); if (!((Object)(object)component == (Object)null) && !(IsEquipped == null)) { return !(bool)IsEquipped.GetValue(component); } return true; } public static void SendChat(PlayerAvatar avatar, string text) { if (!((Object)(object)avatar == (Object)null) && !(ChatSend == null)) { object[] array = new object[ChatSend.GetParameters().Length]; array[0] = text; ChatSend.Invoke(avatar, array); } } public static void Check() { FieldInfo[] fields = typeof(R).GetFields(BindingFlags.Static | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.GetValue(null) == null) { Plugin.Log.LogError((object)("could not find game or Hatter member: " + fieldInfo.Name)); } } } } internal static class Casts { public static readonly Dictionary<int, Spell> Pending = new Dictionary<int, Spell>(); public static readonly Dictionary<int, Spell> Current = new Dictionary<int, Spell>(); public static readonly Dictionary<long, Spell> InFlight = new Dictionary<long, Spell>(); public static Spell Active; public static readonly List<EmberWand> Wands = new List<EmberWand>(); public static long Key(ChargedWand w, int id) { return ((long)((Object)w).GetInstanceID() << 32) | (uint)id; } public static void OnChat(PlayerAvatar sender, string message) { if (!SemiFunc.IsMasterClientOrSingleplayer() || (Object)(object)sender == (Object)null || string.IsNullOrWhiteSpace(message)) { return; } EmberWand val = null; foreach (EmberWand wand in Wands) { if ((Object)(object)wand != (Object)null && (Object)(object)R.HolderOf((ChargedWand)(object)wand) == (Object)(object)sender) { val = wand; break; } } if ((Object)(object)val == (Object)null || R.IsHostCharging((ChargedWand)(object)val)) { return; } Spell spell = SpellBook.Parse(message); if (spell == null) { return; } ItemBattery component = ((Component)val).GetComponent<ItemBattery>(); int num = (((Object)(object)component != (Object)null && R.BatteryInt != null) ? Convert.ToInt32(R.BatteryInt.GetValue(component)) : 99); if (num > 0) { if (spell.ShapeId == 8) { spell[Stat.EnergyCost] = Math.Min(30, num); } else if ((float)num < spell[Stat.EnergyCost]) { spell = SpellBook.MakeFizzle(spell, Fizzle.NoCharge); } if (spell.Fizzle == Fizzle.None) { Lore.NoteCast(spell); } int instanceID = ((Object)val).GetInstanceID(); Pending[instanceID] = spell; ApplyGunNumbers((ChargedWand)(object)val, spell); if (!(bool)R.HostTriggerPulled.Invoke(val, null) || !R.IsHostCharging((ChargedWand)(object)val)) { Pending.Remove(instanceID); } } } public static void ApplyGunNumbers(ChargedWand wand, Spell spell) { object? obj = R.Gun?.GetValue(wand); ItemGun val = (ItemGun)((obj is ItemGun) ? obj : null); if (!((Object)(object)val == (Object)null)) { R.ShootCooldown?.SetValue(val, spell[Stat.ReloadSeconds]); R.BatteryDrainBars?.SetValue(val, (int)spell[Stat.EnergyCost]); } } } [HarmonyPatch(typeof(ChargedWand), "Awake")] internal static class WandLifeHook { private static void Postfix(ChargedWand __instance) { EmberWand val = (EmberWand)(object)((__instance is EmberWand) ? __instance : null); if (val != null && !Casts.Wands.Contains(val)) { Casts.Wands.Add(val); } } } [HarmonyPatch(typeof(ChargedWand), "OnDestroy")] internal static class WandGoneHook { private static void Prefix(ChargedWand __instance) { EmberWand val = (EmberWand)(object)((__instance is EmberWand) ? __instance : null); if (val != null) { Casts.Wands.Remove(val); int instanceID = ((Object)val).GetInstanceID(); Casts.Pending.Remove(instanceID); Casts.Current.Remove(instanceID); } } } [HarmonyPatch(typeof(PlayerAvatar), "ChatMessageSendRPC")] internal static class ChatRpcHook { private static void Postfix(PlayerAvatar __instance, string __0) { try { Casts.OnChat(__instance, __0); } catch (Exception ex) { Plugin.Log.LogError((object)("chat cast failed: " + ex)); } } } [HarmonyPatch(typeof(ChargedWand), "HostTriggerPulled")] internal static class TriggerHook { private static bool Prefix(ChargedWand __instance, ref bool __result) { if (!(__instance is EmberWand)) { return true; } int instanceID = ((Object)__instance).GetInstanceID(); if (Casts.Pending.ContainsKey(instanceID)) { return true; } if (!Plugin.TriggerCasts.Value) { __result = true; return false; } Spell spell = SpellBook.PlainFireball(); Casts.Pending[instanceID] = spell; Casts.ApplyGunNumbers(__instance, spell); return true; } } [HarmonyPatch(typeof(ChargedWand), "HostChargeData")] internal static class ChargeDataHook { private static void Postfix(ChargedWand __instance, ref float[] __result) { if (__instance is EmberWand) { int instanceID = ((Object)__instance).GetInstanceID(); if (Casts.Pending.TryGetValue(instanceID, out var value)) { Casts.Pending.Remove(instanceID); Casts.Current[instanceID] = value; __result = value.Encode(); } } } } [HarmonyPatch(typeof(EmberWand), "ChargeBegin")] internal static class ChargeBeginHook { private static void Prefix(EmberWand __instance, float[] __0) { Spell spell = Spell.Decode(__0); int instanceID = ((Object)__instance).GetInstanceID(); if (spell == null) { Casts.Current.Remove(instanceID); return; } Casts.Current[instanceID] = spell; Casts.ApplyGunNumbers((ChargedWand)(object)__instance, spell); if (spell.ShapeId == 8) { DoomFx.Charge((ChargedWand)(object)__instance, spell[Stat.ChargeSeconds]); } } } [HarmonyPatch(typeof(EmberWand), "get_ChargeSeconds")] internal static class ChargeSecondsHook { private static void Postfix(EmberWand __instance, ref float __result) { if (Casts.Current.TryGetValue(((Object)__instance).GetInstanceID(), out var value)) { __result = value[Stat.ChargeSeconds]; } } } [HarmonyPatch(typeof(EmberWand), "get_ChargeLines")] internal static class ChargeLinesHook { private static void Postfix(EmberWand __instance, ref string __result) { if (Casts.Current.TryGetValue(((Object)__instance).GetInstanceID(), out var value)) { __result = ((value.Roles.Count > 0) ? "" : SpellBook.ActiveWord(SpellBook.RoleById(0))); } } } internal sealed class SpellTag : MonoBehaviour { public Spell Spell; } [HarmonyPatch(typeof(Fireball), "Spawn")] internal static class SpawnHook { private static void Postfix(ChargedWand __0, int __1, Fireball __result) { if (!((Object)(object)__result == (Object)null) && __0 is EmberWand && Casts.Current.TryGetValue(((Object)__0).GetInstanceID(), out var value)) { ((Component)__result).gameObject.AddComponent<SpellTag>().Spell = value; Casts.InFlight[Casts.Key(__0, __1)] = value; Component val = ((R.FxType == null) ? null : ((Component)__result).GetComponent(R.FxType)); if ((Object)(object)val != (Object)null && R.FxSize != null) { R.FxSize.SetValue(val, value[Stat.Size]); } if (value.ShapeId == 8) { DoomFx.Trail(((Component)__result).transform); } } } } [HarmonyPatch(typeof(Fireball), "FixedUpdate")] internal static class FireballUpdateHook { private static void Prefix(Fireball __instance) { SpellTag component = ((Component)__instance).GetComponent<SpellTag>(); Casts.Active = (((Object)(object)component != (Object)null) ? component.Spell : null); } private static void Postfix() { Casts.Active = null; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> code) { Dictionary<MethodBase, MethodInfo> swaps = new Dictionary<MethodBase, MethodInfo> { { AccessTools.Method(typeof(Fireball), "get_Speed", (Type[])null, (Type[])null), AccessTools.Method(typeof(FireballStats), "Speed", (Type[])null, (Type[])null) }, { AccessTools.Method(typeof(Fireball), "get_Lifetime", (Type[])null, (Type[])null), AccessTools.Method(typeof(FireballStats), "Lifetime", (Type[])null, (Type[])null) }, { AccessTools.Method(typeof(Fireball), "get_DirectDamage", (Type[])null, (Type[])null), AccessTools.Method(typeof(FireballStats), "DirectDamage", (Type[])null, (Type[])null) } }; MethodInfo radius = AccessTools.Method(typeof(FireballStats), "HitRadius", (Type[])null, (Type[])null); foreach (CodeInstruction item in code) { if (item.opcode == OpCodes.Call && item.operand is MethodBase key && swaps.TryGetValue(key, out var value)) { item.operand = value; } else if (item.opcode == OpCodes.Ldc_R4 && item.operand is float num && Mathf.Approximately(num, 0.08f)) { item.opcode = OpCodes.Call; item.operand = radius; } yield return item; } } } internal static class FireballStats { private static readonly Func<float> HatterSpeed = Getter<float>("get_Speed"); private static readonly Func<float> HatterLifetime = Getter<float>("get_Lifetime"); private static readonly Func<int> HatterDamage = Getter<int>("get_DirectDamage"); private static Func<T> Getter<T>(string name) { MethodInfo methodInfo = AccessTools.Method(typeof(Fireball), name, (Type[])null, (Type[])null); if (!(methodInfo == null)) { return (Func<T>)Delegate.CreateDelegate(typeof(Func<T>), methodInfo); } return () => default(T); } public static float Speed() { if (Casts.Active == null) { return HatterSpeed(); } return Casts.Active[Stat.Speed]; } public static float Lifetime() { if (Casts.Active == null) { return HatterLifetime(); } return Casts.Active[Stat.Lifetime]; } public static int DirectDamage() { if (Casts.Active == null) { return HatterDamage(); } return Mathf.RoundToInt(Casts.Active[Stat.DirectDamage]); } public static float HitRadius() { return 0.08f * ((Casts.Active != null) ? Casts.Active[Stat.Size] : 1f); } } [HarmonyPatch(typeof(ChargedWand), "Impact")] internal static class ImpactHook { private static void Prefix(ChargedWand __instance, int __0) { if (__instance is EmberWand && Casts.InFlight.TryGetValue(Casts.Key(__instance, __0), out var value)) { Casts.Active = value; } } private static void Postfix(ChargedWand __instance, int __0) { if (__instance is EmberWand) { Casts.InFlight.Remove(Casts.Key(__instance, __0)); Casts.Active = null; } } } [HarmonyPatch(typeof(Fireball), "Explode")] internal static class ExplodeHook { private static bool Prefix(Vector3 __0) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) Spell active = Casts.Active; if (active == null || R.SpawnSmall ==
plugins/sherpa-onnx.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Xiaomi Corporation")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright 2019-2023 Xiaomi Corporation")] [assembly: AssemblyDescription("sherpa-onnx is an open-source real-time speech recognition toolkit developed\n by the Next-gen Kaldi team. It supports streaming recognition on a variety of\n platforms such as Android, iOS, Raspberry, Linux, Windows, macOS, etc.\n\n It does not require Internet connection during recognition.\n\n See the documentation https://k2-fsa.github.io/sherpa/onnx/index.html\n for details.\n ")] [assembly: AssemblyFileVersion("2.0.1.0")] [assembly: AssemblyInformationalVersion("2.0.1+af2d8d81dbfa61c4cea4c568da78f3982edca005")] [assembly: AssemblyProduct("sherpa-onnx")] [assembly: AssemblyTitle("sherpa-onnx")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/k2-fsa/sherpa-onnx")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.1.0")] [module: UnverifiableCode] namespace SherpaOnnx; public class AudioEvent { private struct Impl { public IntPtr Name; public int Index; public float Prob; } private string _name; private int _index; private float _prob; public string Name => _name; public int Index => _index; public float Prob => _prob; public unsafe AudioEvent(IntPtr handle) { Impl impl = (Impl)Marshal.PtrToStructure(handle, typeof(Impl)); int num = 0; byte* ptr = (byte*)(void*)impl.Name; while (*ptr != 0) { ptr++; num++; } byte[] array = new byte[num]; Marshal.Copy(impl.Name, array, 0, num); _name = Encoding.UTF8.GetString(array); _index = impl.Index; _prob = impl.Prob; } } public class AudioTagging : IDisposable { private HandleRef _handle; public AudioTagging(AudioTaggingConfig config) { IntPtr handle = SherpaOnnxCreateAudioTagging(ref config); _handle = new HandleRef(this, handle); } public OfflineStream CreateStream() { return new OfflineStream(SherpaOnnxAudioTaggingCreateOfflineStream(_handle.Handle)); } public AudioEvent[] Compute(OfflineStream stream, int topK = -1) { IntPtr intPtr = SherpaOnnxAudioTaggingCompute(_handle.Handle, stream.Handle, topK); List<AudioEvent> list = new List<AudioEvent>(); if (intPtr == IntPtr.Zero) { return list.ToArray(); } int num = 0; while (true) { IntPtr intPtr2 = Marshal.ReadIntPtr(intPtr, num * IntPtr.Size); if (intPtr2 == IntPtr.Zero) { break; } AudioEvent item = new AudioEvent(intPtr2); list.Add(item); num++; } SherpaOnnxAudioTaggingFreeResults(intPtr); return list.ToArray(); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~AudioTagging() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyAudioTagging(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateAudioTagging(ref AudioTaggingConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyAudioTagging(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxAudioTaggingCreateOfflineStream(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxAudioTaggingCompute(IntPtr handle, IntPtr stream, int topK); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxAudioTaggingFreeResults(IntPtr p); } public struct AudioTaggingConfig { public AudioTaggingModelConfig Model; [MarshalAs(UnmanagedType.LPStr)] public string Labels; public int TopK; public AudioTaggingConfig() { Model = new AudioTaggingModelConfig(); Labels = ""; TopK = 5; } } public struct AudioTaggingModelConfig { public OfflineZipformerAudioTaggingModelConfig Zipformer; [MarshalAs(UnmanagedType.LPStr)] public string CED; public int NumThreads; public int Debug; [MarshalAs(UnmanagedType.LPStr)] public string Provider; public AudioTaggingModelConfig() { Zipformer = new OfflineZipformerAudioTaggingModelConfig(); CED = ""; NumThreads = 1; Debug = 0; Provider = "cpu"; } } public class CircularBuffer : IDisposable { private HandleRef _handle; public int Size => SherpaOnnxCircularBufferSize(_handle.Handle); public long Head => SherpaOnnxCircularBufferHead(_handle.Handle); public CircularBuffer(int capacity) { IntPtr handle = SherpaOnnxCreateCircularBuffer(capacity); _handle = new HandleRef(this, handle); } public void Push(float[] data) { SherpaOnnxCircularBufferPush(_handle.Handle, data, data.Length); } public float[] Get(long startIndex, int n) { IntPtr intPtr = SherpaOnnxCircularBufferGet(_handle.Handle, startIndex, n); float[] array = new float[n]; Marshal.Copy(intPtr, array, 0, n); SherpaOnnxCircularBufferFree(intPtr); return array; } public void Pop(int n) { SherpaOnnxCircularBufferPop(_handle.Handle, n); } public void Reset() { SherpaOnnxCircularBufferReset(_handle.Handle); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~CircularBuffer() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyCircularBuffer(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateCircularBuffer(int capacity); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyCircularBuffer(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxCircularBufferPush(IntPtr handle, float[] p, int n); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCircularBufferGet(IntPtr handle, long startIndex, int n); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxCircularBufferFree(IntPtr p); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxCircularBufferPop(IntPtr handle, int n); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxCircularBufferSize(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern long SherpaOnnxCircularBufferHead(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxCircularBufferReset(IntPtr handle); } public class DenoisedAudio { private struct Impl { public IntPtr Samples; public int NumSamples; public int SampleRate; } private HandleRef _handle; public IntPtr Handle => _handle.Handle; public int NumSamples { get { if (Handle == IntPtr.Zero) { return 0; } return ((Impl)Marshal.PtrToStructure(Handle, typeof(Impl))).NumSamples; } } public int SampleRate { get { if (Handle == IntPtr.Zero) { return 0; } return ((Impl)Marshal.PtrToStructure(Handle, typeof(Impl))).SampleRate; } } public float[] Samples { get { if (Handle == IntPtr.Zero) { return new float[0]; } Impl impl = (Impl)Marshal.PtrToStructure(Handle, typeof(Impl)); float[] array = new float[impl.NumSamples]; if (impl.NumSamples > 0 && impl.Samples != IntPtr.Zero) { Marshal.Copy(impl.Samples, array, 0, impl.NumSamples); } return array; } } public DenoisedAudio(IntPtr p) { _handle = new HandleRef(this, p); } public bool SaveToWaveFile(string filename) { if (Handle == IntPtr.Zero) { return false; } Impl impl = (Impl)Marshal.PtrToStructure(Handle, typeof(Impl)); return WriteWave(impl.Samples, impl.NumSamples, impl.SampleRate, filename); } public static bool SaveToWaveFile(float[] samples, int sampleRate, string filename) { if (samples == null || samples.Length == 0) { return false; } IntPtr intPtr = Marshal.AllocHGlobal(samples.Length * 4); Marshal.Copy(samples, 0, intPtr, samples.Length); bool result = WriteWave(intPtr, samples.Length, sampleRate, filename); Marshal.FreeHGlobal(intPtr); return result; } private static bool WriteWave(IntPtr samples, int numSamples, int sampleRate, string filename) { byte[] bytes = Encoding.UTF8.GetBytes(filename); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; return SherpaOnnxWriteWave(samples, numSamples, sampleRate, array) == 1; } ~DenoisedAudio() { Cleanup(); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } private void Cleanup() { if (Handle != IntPtr.Zero) { SherpaOnnxDestroyDenoisedAudio(Handle); } _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyDenoisedAudio(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxWriteWave(IntPtr samples, int n, int sample_rate, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Filename); } internal static class Dll { public const string Filename = "sherpa-onnx-c-api"; } public struct FastClusteringConfig { public int NumClusters; public float Threshold; public int ComputeConfidence; public FastClusteringConfig() { NumClusters = -1; Threshold = 0.5f; ComputeConfidence = 0; } } public struct FeatureConfig { public int SampleRate; public int FeatureDim; public FeatureConfig() { SampleRate = 16000; FeatureDim = 80; } } public struct HomophoneReplacerConfig { [MarshalAs(UnmanagedType.LPStr)] public string DictDir; [MarshalAs(UnmanagedType.LPStr)] public string Lexicon; [MarshalAs(UnmanagedType.LPStr)] public string RuleFsts; public HomophoneReplacerConfig() { DictDir = ""; Lexicon = ""; RuleFsts = ""; } } public class KeywordResult { private struct Impl { public IntPtr Keyword; } private string _keyword; public string Keyword => _keyword; public unsafe KeywordResult(IntPtr handle) { Impl impl = (Impl)Marshal.PtrToStructure(handle, typeof(Impl)); int num = 0; byte* ptr = (byte*)(void*)impl.Keyword; while (*ptr != 0) { ptr++; num++; } byte[] array = new byte[num]; Marshal.Copy(impl.Keyword, array, 0, num); _keyword = Encoding.UTF8.GetString(array); } } public class KeywordSpotter : IDisposable { private HandleRef _handle; public KeywordSpotter(KeywordSpotterConfig config) { IntPtr handle = SherpaOnnxCreateKeywordSpotter(ref config); _handle = new HandleRef(this, handle); } public OnlineStream CreateStream() { return new OnlineStream(SherpaOnnxCreateKeywordStream(_handle.Handle)); } public OnlineStream CreateStream(string keywords) { byte[] bytes = Encoding.UTF8.GetBytes(keywords); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; return new OnlineStream(SherpaOnnxCreateKeywordStreamWithKeywords(_handle.Handle, array)); } public bool IsReady(OnlineStream stream) { return IsReady(_handle.Handle, stream.Handle) != 0; } public void Decode(OnlineStream stream) { Decode(_handle.Handle, stream.Handle); } public void Reset(OnlineStream stream) { Reset(_handle.Handle, stream.Handle); } public void Decode(IEnumerable<OnlineStream> streams) { List<IntPtr> list = new List<IntPtr>(); foreach (OnlineStream stream in streams) { list.Add(stream.Handle); } IntPtr[] array = list.ToArray(); Decode(_handle.Handle, array, array.Length); } public KeywordResult GetResult(OnlineStream stream) { IntPtr result = GetResult(_handle.Handle, stream.Handle); KeywordResult result2 = new KeywordResult(result); DestroyResult(result); return result2; } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~KeywordSpotter() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyKeywordSpotter(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateKeywordSpotter(ref KeywordSpotterConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyKeywordSpotter(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateKeywordStream(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateKeywordStreamWithKeywords(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Keywords); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxIsKeywordStreamReady")] private static extern int IsReady(IntPtr handle, IntPtr stream); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxDecodeKeywordStream")] private static extern void Decode(IntPtr handle, IntPtr stream); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxResetKeywordStream")] private static extern void Reset(IntPtr handle, IntPtr stream); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxDecodeMultipleKeywordStreams")] private static extern void Decode(IntPtr handle, IntPtr[] streams, int n); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxGetKeywordResult")] private static extern IntPtr GetResult(IntPtr handle, IntPtr stream); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxDestroyKeywordResult")] private static extern void DestroyResult(IntPtr result); } public struct KeywordSpotterConfig { public FeatureConfig FeatConfig; public OnlineModelConfig ModelConfig; public int MaxActivePaths; public int NumTrailingBlanks; public float KeywordsScore; public float KeywordsThreshold; [MarshalAs(UnmanagedType.LPStr)] public string KeywordsFile; [MarshalAs(UnmanagedType.LPStr)] public string KeywordsBuf; public int KeywordsBufSize; public KeywordSpotterConfig() { FeatConfig = new FeatureConfig(); ModelConfig = new OnlineModelConfig(); MaxActivePaths = 4; NumTrailingBlanks = 1; KeywordsScore = 1f; KeywordsThreshold = 0.25f; KeywordsFile = ""; KeywordsBuf = ""; KeywordsBufSize = 0; } } internal sealed class NativeResources : IDisposable { internal GCHandle? AudioHandle; internal GCHandle CodepointsHandle; internal GCHandle CodepointsLensHandle; internal GCHandle TokensHandle; internal GCHandle TokensLensHandle; internal readonly List<IntPtr> TokenStrings = new List<IntPtr>(); public void Dispose() { if (AudioHandle.HasValue) { AudioHandle.Value.Free(); AudioHandle = null; } if (CodepointsHandle.IsAllocated) { CodepointsHandle.Free(); } if (CodepointsLensHandle.IsAllocated) { CodepointsLensHandle.Free(); } if (TokensHandle.IsAllocated) { TokensHandle.Free(); } if (TokensLensHandle.IsAllocated) { TokensLensHandle.Free(); } foreach (IntPtr tokenString in TokenStrings) { if (tokenString != IntPtr.Zero) { Marshal.FreeHGlobal(tokenString); } } TokenStrings.Clear(); } } public struct OfflineCanaryModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Encoder; [MarshalAs(UnmanagedType.LPStr)] public string Decoder; [MarshalAs(UnmanagedType.LPStr)] public string SrcLang; [MarshalAs(UnmanagedType.LPStr)] public string TgtLang; public int UsePnc; public OfflineCanaryModelConfig() { Encoder = ""; Decoder = ""; SrcLang = "en"; TgtLang = "en"; UsePnc = 1; } } public struct OfflineCohereTranscribeModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Encoder; [MarshalAs(UnmanagedType.LPStr)] public string Decoder; [MarshalAs(UnmanagedType.LPStr)] public string Language; public int UsePunct; public int UseItn; public OfflineCohereTranscribeModelConfig() { Encoder = ""; Decoder = ""; Language = ""; UsePunct = 1; UseItn = 1; } } public struct OfflineCtcFstDecoderConfig { [MarshalAs(UnmanagedType.LPStr)] public string Graph; public int MaxActive; public OfflineCtcFstDecoderConfig() { Graph = ""; MaxActive = 3000; } } public struct OfflineDolphinModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OfflineDolphinModelConfig() { Model = ""; } } public struct OfflineFireRedAsrCtcModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OfflineFireRedAsrCtcModelConfig() { Model = ""; } } public struct OfflineFireRedAsrModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Encoder; [MarshalAs(UnmanagedType.LPStr)] public string Decoder; public OfflineFireRedAsrModelConfig() { Encoder = ""; Decoder = ""; } } public struct OfflineFunAsrNanoModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string EncoderAdaptor; [MarshalAs(UnmanagedType.LPStr)] public string LLM; [MarshalAs(UnmanagedType.LPStr)] public string Embedding; [MarshalAs(UnmanagedType.LPStr)] public string Tokenizer; [MarshalAs(UnmanagedType.LPStr)] public string SystemPrompt; [MarshalAs(UnmanagedType.LPStr)] public string UserPrompt; public int MaxNewTokens; public float Temperature; public float TopP; public int Seed; [MarshalAs(UnmanagedType.LPStr)] public string Language; public int Itn; [MarshalAs(UnmanagedType.LPStr)] public string Hotwords; public OfflineFunAsrNanoModelConfig() { EncoderAdaptor = ""; LLM = ""; Embedding = ""; Tokenizer = ""; SystemPrompt = "You are a helpful assistant."; UserPrompt = "语音转写:"; MaxNewTokens = 512; Temperature = 1E-06f; TopP = 0.8f; Seed = 42; Language = ""; Itn = 0; Hotwords = ""; } } public struct OfflineLMConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public float Scale; public OfflineLMConfig() { Model = ""; Scale = 0.5f; } } public struct OfflineMedAsrCtcModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OfflineMedAsrCtcModelConfig() { Model = ""; } } public struct OfflineModelConfig { public OfflineTransducerModelConfig Transducer; public OfflineParaformerModelConfig Paraformer; public OfflineNemoEncDecCtcModelConfig NeMoCtc; public OfflineWhisperModelConfig Whisper; public OfflineTdnnModelConfig Tdnn; [MarshalAs(UnmanagedType.LPStr)] public string Tokens; public int NumThreads; public int Debug; [MarshalAs(UnmanagedType.LPStr)] public string Provider; [MarshalAs(UnmanagedType.LPStr)] public string ModelType; [MarshalAs(UnmanagedType.LPStr)] public string ModelingUnit; [MarshalAs(UnmanagedType.LPStr)] public string BpeVocab; [MarshalAs(UnmanagedType.LPStr)] public string TeleSpeechCtc; public OfflineSenseVoiceModelConfig SenseVoice; public OfflineMoonshineModelConfig Moonshine; public OfflineFireRedAsrModelConfig FireRedAsr; public OfflineDolphinModelConfig Dolphin; public OfflineZipformerCtcModelConfig ZipformerCtc; public OfflineCanaryModelConfig Canary; public OfflineWenetCtcModelConfig WenetCtc; public OfflineOmnilingualAsrCtcModelConfig Omnilingual; public OfflineMedAsrCtcModelConfig MedAsr; public OfflineFunAsrNanoModelConfig FunAsrNano; public OfflineFireRedAsrCtcModelConfig FireRedAsrCtc; public OfflineQwen3AsrModelConfig Qwen3Asr; public OfflineCohereTranscribeModelConfig CohereTranscribe; public OfflineModelConfig() { Transducer = new OfflineTransducerModelConfig(); Paraformer = new OfflineParaformerModelConfig(); NeMoCtc = new OfflineNemoEncDecCtcModelConfig(); Whisper = new OfflineWhisperModelConfig(); Tdnn = new OfflineTdnnModelConfig(); Tokens = ""; NumThreads = 1; Debug = 0; Provider = "cpu"; ModelType = ""; ModelingUnit = "cjkchar"; BpeVocab = ""; TeleSpeechCtc = ""; SenseVoice = new OfflineSenseVoiceModelConfig(); Moonshine = new OfflineMoonshineModelConfig(); FireRedAsr = new OfflineFireRedAsrModelConfig(); Dolphin = new OfflineDolphinModelConfig(); ZipformerCtc = new OfflineZipformerCtcModelConfig(); Canary = new OfflineCanaryModelConfig(); WenetCtc = new OfflineWenetCtcModelConfig(); Omnilingual = new OfflineOmnilingualAsrCtcModelConfig(); MedAsr = new OfflineMedAsrCtcModelConfig(); FunAsrNano = new OfflineFunAsrNanoModelConfig(); FireRedAsrCtc = new OfflineFireRedAsrCtcModelConfig(); Qwen3Asr = new OfflineQwen3AsrModelConfig(); CohereTranscribe = new OfflineCohereTranscribeModelConfig(); } } public struct OfflineMoonshineModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Preprocessor; [MarshalAs(UnmanagedType.LPStr)] public string Encoder; [MarshalAs(UnmanagedType.LPStr)] public string UncachedDecoder; [MarshalAs(UnmanagedType.LPStr)] public string CachedDecoder; [MarshalAs(UnmanagedType.LPStr)] public string MergedDecoder; public OfflineMoonshineModelConfig() { Preprocessor = ""; Encoder = ""; UncachedDecoder = ""; CachedDecoder = ""; MergedDecoder = ""; } } public struct OfflineNemoEncDecCtcModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OfflineNemoEncDecCtcModelConfig() { Model = ""; } } public struct OfflineOmnilingualAsrCtcModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OfflineOmnilingualAsrCtcModelConfig() { Model = ""; } } public struct OfflineParaformerModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OfflineParaformerModelConfig() { Model = ""; } } public class OfflinePunctuation : IDisposable { private HandleRef _handle; public OfflinePunctuation(OfflinePunctuationConfig config) { IntPtr handle = SherpaOnnxCreateOfflinePunctuation(ref config); _handle = new HandleRef(this, handle); } public unsafe string AddPunct(string text) { byte[] bytes = Encoding.UTF8.GetBytes(text); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; IntPtr intPtr = SherpaOfflinePunctuationAddPunct(_handle.Handle, array); string result = ""; int num = 0; byte* ptr = (byte*)(void*)intPtr; if (ptr != null) { while (*ptr != 0) { ptr++; num++; } } if (num > 0) { byte[] array2 = new byte[num]; Marshal.Copy(intPtr, array2, 0, num); result = Encoding.UTF8.GetString(array2); } SherpaOfflinePunctuationFreeText(intPtr); return result; } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~OfflinePunctuation() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyOfflinePunctuation(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateOfflinePunctuation(ref OfflinePunctuationConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOfflinePunctuation(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOfflinePunctuationAddPunct(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Text); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOfflinePunctuationFreeText(IntPtr p); } public struct OfflinePunctuationConfig { public OfflinePunctuationModelConfig Model; public OfflinePunctuationConfig() { Model = new OfflinePunctuationModelConfig(); } } public struct OfflinePunctuationModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string CtTransformer; public int NumThreads; public int Debug; [MarshalAs(UnmanagedType.LPStr)] public string Provider; public OfflinePunctuationModelConfig() { CtTransformer = ""; NumThreads = 1; Debug = 0; Provider = "cpu"; } } public struct OfflineQwen3AsrModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string ConvFrontend; [MarshalAs(UnmanagedType.LPStr)] public string Encoder; [MarshalAs(UnmanagedType.LPStr)] public string Decoder; [MarshalAs(UnmanagedType.LPStr)] public string Tokenizer; public int MaxTotalLen; public int MaxNewTokens; public float Temperature; public float TopP; public int Seed; [MarshalAs(UnmanagedType.LPStr)] public string Hotwords; public OfflineQwen3AsrModelConfig() { ConvFrontend = ""; Encoder = ""; Decoder = ""; Tokenizer = ""; MaxTotalLen = 512; MaxNewTokens = 128; Temperature = 1E-06f; TopP = 0.8f; Seed = 42; Hotwords = ""; } } public class OfflineRecognizer : IDisposable { private HandleRef _handle; public OfflineRecognizer(OfflineRecognizerConfig config) { IntPtr handle = SherpaOnnxCreateOfflineRecognizer(ref config); _handle = new HandleRef(this, handle); } public void SetConfig(OfflineRecognizerConfig config) { SherpaOnnxOfflineRecognizerSetConfig(_handle.Handle, ref config); } public OfflineStream CreateStream() { return new OfflineStream(SherpaOnnxCreateOfflineStream(_handle.Handle)); } public void Decode(OfflineStream stream) { Decode(_handle.Handle, stream.Handle); } public void Decode(IEnumerable<OfflineStream> streams) { List<IntPtr> list = new List<IntPtr>(); foreach (OfflineStream stream in streams) { list.Add(stream.Handle); } IntPtr[] array = list.ToArray(); Decode(_handle.Handle, array, array.Length); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~OfflineRecognizer() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyOfflineRecognizer(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateOfflineRecognizer(ref OfflineRecognizerConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxOfflineRecognizerSetConfig(IntPtr handle, ref OfflineRecognizerConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOfflineRecognizer(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateOfflineStream(IntPtr handle); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxDecodeOfflineStream")] private static extern void Decode(IntPtr handle, IntPtr stream); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxDecodeMultipleOfflineStreams")] private static extern void Decode(IntPtr handle, IntPtr[] streams, int n); } public struct OfflineRecognizerConfig { public FeatureConfig FeatConfig; public OfflineModelConfig ModelConfig; public OfflineLMConfig LmConfig; [MarshalAs(UnmanagedType.LPStr)] public string DecodingMethod; public int MaxActivePaths; [MarshalAs(UnmanagedType.LPStr)] public string HotwordsFile; public float HotwordsScore; [MarshalAs(UnmanagedType.LPStr)] public string RuleFsts; [MarshalAs(UnmanagedType.LPStr)] public string RuleFars; public float BlankPenalty; public HomophoneReplacerConfig Hr; public OfflineCtcFstDecoderConfig CtcFstDecoderConfig; public OfflineRecognizerConfig() { FeatConfig = new FeatureConfig(); ModelConfig = new OfflineModelConfig(); LmConfig = new OfflineLMConfig(); DecodingMethod = "greedy_search"; MaxActivePaths = 4; HotwordsFile = ""; HotwordsScore = 1.5f; RuleFsts = ""; RuleFars = ""; BlankPenalty = 0f; Hr = new HomophoneReplacerConfig(); CtcFstDecoderConfig = new OfflineCtcFstDecoderConfig(); } } public class OfflineRecognizerResult { private struct Impl { public IntPtr Text; public IntPtr Timestamps; public int Count; public IntPtr Tokens; public IntPtr TokensArr; public IntPtr Json; public IntPtr Lang; public IntPtr Emotion; public IntPtr Event; public IntPtr Durations; public IntPtr YsLogProbs; public IntPtr SegmentTimestamps; public IntPtr SegmentDurations; public IntPtr SegmentTexts; public IntPtr SegmentTextsArr; public int SegmentCount; } private string _text; private string[] _tokens; private float[] _timestamps; private float[] _durations; public string Text => _text; public string[] Tokens => _tokens; public float[] Timestamps => _timestamps; public float[] Durations => _durations; public unsafe OfflineRecognizerResult(IntPtr handle) { Impl impl = (Impl)Marshal.PtrToStructure(handle, typeof(Impl)); int num = 0; byte* ptr = (byte*)(void*)impl.Text; while (*ptr != 0) { ptr++; num++; } byte[] array = new byte[num]; Marshal.Copy(impl.Text, array, 0, num); _text = Encoding.UTF8.GetString(array); _tokens = new string[impl.Count]; byte* ptr2 = (byte*)(void*)impl.Tokens; for (int i = 0; i < impl.Count; i++) { num = 0; byte* ptr3 = ptr2; while (*ptr2 != 0) { ptr2++; num++; } ptr2++; array = new byte[num]; fixed (byte* ptr4 = array) { for (int j = 0; j < num; j++) { ptr4[j] = ptr3[j]; } } _tokens[i] = Encoding.UTF8.GetString(array); } if (impl.Timestamps != IntPtr.Zero) { float* ptr5 = (float*)(void*)impl.Timestamps; _timestamps = new float[impl.Count]; fixed (float* timestamps = _timestamps) { for (int k = 0; k < impl.Count; k++) { timestamps[k] = ptr5[k]; } } } if (!(impl.Durations != IntPtr.Zero)) { return; } float* ptr6 = (float*)(void*)impl.Durations; _durations = new float[impl.Count]; fixed (float* durations = _durations) { for (int l = 0; l < impl.Count; l++) { durations[l] = ptr6[l]; } } } } public struct OfflineSenseVoiceModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; [MarshalAs(UnmanagedType.LPStr)] public string Language; public int UseInverseTextNormalization; public OfflineSenseVoiceModelConfig() { Model = ""; Language = ""; UseInverseTextNormalization = 0; } } public class OfflineSourceSeparation : IDisposable { private HandleRef _handle; public int OutputSampleRate => SherpaOnnxOfflineSourceSeparationGetOutputSampleRate(_handle.Handle); public int NumberOfStems => SherpaOnnxOfflineSourceSeparationGetNumberOfStems(_handle.Handle); public OfflineSourceSeparation(OfflineSourceSeparationConfig config) { IntPtr handle = SherpaOnnxCreateOfflineSourceSeparation(ref config); _handle = new HandleRef(this, handle); } public SourceSeparationOutput Process(float[][] channels, int sampleRate) { int num = channels.Length; if (num == 0) { return new SourceSeparationOutput(IntPtr.Zero); } int num_samples = channels[0].Length; IntPtr intPtr = Marshal.AllocHGlobal(num * IntPtr.Size); GCHandle[] array = new GCHandle[num]; try { for (int i = 0; i < num; i++) { array[i] = GCHandle.Alloc(channels[i], GCHandleType.Pinned); Marshal.WriteIntPtr(intPtr, i * IntPtr.Size, array[i].AddrOfPinnedObject()); } return new SourceSeparationOutput(SherpaOnnxOfflineSourceSeparationProcess(_handle.Handle, intPtr, num, num_samples, sampleRate)); } finally { for (int j = 0; j < num; j++) { if (array[j].IsAllocated) { array[j].Free(); } } Marshal.FreeHGlobal(intPtr); } } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~OfflineSourceSeparation() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyOfflineSourceSeparation(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } public static MultiChannelWaveData ReadWaveMultiChannel(string filename) { byte[] bytes = Encoding.UTF8.GetBytes(filename); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; IntPtr intPtr = SherpaOnnxReadWaveMultiChannel(array); if (intPtr == IntPtr.Zero) { return null; } return new MultiChannelWaveData(intPtr); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateOfflineSourceSeparation(ref OfflineSourceSeparationConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOfflineSourceSeparation(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxOfflineSourceSeparationGetOutputSampleRate(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxOfflineSourceSeparationGetNumberOfStems(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxOfflineSourceSeparationProcess(IntPtr handle, IntPtr samples, int num_channels, int num_samples, int sample_rate); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxReadWaveMultiChannel([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Filename); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxFreeMultiChannelWave(IntPtr wave); } public class MultiChannelWaveData : IDisposable { private struct Impl { public IntPtr Samples; public int NumChannels; public int NumSamples; public int SampleRate; } private HandleRef _handle; public int NumChannels { get { if (_handle.Handle == IntPtr.Zero) { return 0; } return ((Impl)Marshal.PtrToStructure(_handle.Handle, typeof(Impl))).NumChannels; } } public int NumSamples { get { if (_handle.Handle == IntPtr.Zero) { return 0; } return ((Impl)Marshal.PtrToStructure(_handle.Handle, typeof(Impl))).NumSamples; } } public int SampleRate { get { if (_handle.Handle == IntPtr.Zero) { return 0; } return ((Impl)Marshal.PtrToStructure(_handle.Handle, typeof(Impl))).SampleRate; } } internal MultiChannelWaveData(IntPtr handle) { _handle = new HandleRef(this, handle); } public float[][] GetChannels() { if (_handle.Handle == IntPtr.Zero) { return new float[0][]; } Impl obj = (Impl)Marshal.PtrToStructure(_handle.Handle, typeof(Impl)); int numChannels = obj.NumChannels; int numSamples = obj.NumSamples; float[][] array = new float[numChannels][]; IntPtr[] array2 = new IntPtr[numChannels]; Marshal.Copy(obj.Samples, array2, 0, numChannels); for (int i = 0; i < numChannels; i++) { array[i] = new float[numSamples]; Marshal.Copy(array2[i], array[i], 0, numSamples); } return array; } public void Dispose() { if (_handle.Handle != IntPtr.Zero) { SherpaOnnxFreeMultiChannelWave(_handle.Handle); } _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxFreeMultiChannelWave(IntPtr wave); } public struct OfflineSourceSeparationConfig { public OfflineSourceSeparationModelConfig Model; public OfflineSourceSeparationConfig() { Model = new OfflineSourceSeparationModelConfig(); } } public struct OfflineSourceSeparationModelConfig { public OfflineSourceSeparationSpleeterModelConfig Spleeter; public OfflineSourceSeparationUvrModelConfig Uvr; public int NumThreads; public int Debug; [MarshalAs(UnmanagedType.LPStr)] public string Provider; public OfflineSourceSeparationModelConfig() { Spleeter = new OfflineSourceSeparationSpleeterModelConfig(); Uvr = new OfflineSourceSeparationUvrModelConfig(); NumThreads = 1; Debug = 0; Provider = "cpu"; } } public struct OfflineSourceSeparationSpleeterModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Vocals; [MarshalAs(UnmanagedType.LPStr)] public string Accompaniment; public OfflineSourceSeparationSpleeterModelConfig() { Vocals = ""; Accompaniment = ""; } } public struct OfflineSourceSeparationUvrModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OfflineSourceSeparationUvrModelConfig() { Model = ""; } } public delegate int OfflineSpeakerDiarizationProgressCallback(int numProcessedChunks, int numTotalChunks, IntPtr arg); public class OfflineSpeakerDiarization : IDisposable { private HandleRef _handle; public int SampleRate => SherpaOnnxOfflineSpeakerDiarizationGetSampleRate(_handle.Handle); public OfflineSpeakerDiarization(OfflineSpeakerDiarizationConfig config) { IntPtr handle = SherpaOnnxCreateOfflineSpeakerDiarization(ref config); _handle = new HandleRef(this, handle); } public void SetConfig(OfflineSpeakerDiarizationConfig config) { SherpaOnnxOfflineSpeakerDiarizationSetConfig(_handle.Handle, ref config); } public OfflineSpeakerDiarizationSegment[] Process(float[] samples) { IntPtr result = SherpaOnnxOfflineSpeakerDiarizationProcess(_handle.Handle, samples, samples.Length); return ProcessImpl(result); } public OfflineSpeakerDiarizationSegment[] ProcessWithCallback(float[] samples, OfflineSpeakerDiarizationProgressCallback callback, IntPtr arg) { IntPtr result = SherpaOnnxOfflineSpeakerDiarizationProcessWithCallback(_handle.Handle, samples, samples.Length, callback, arg); return ProcessImpl(result); } private unsafe OfflineSpeakerDiarizationSegment[] ProcessImpl(IntPtr result) { if (result == IntPtr.Zero) { return new OfflineSpeakerDiarizationSegment[0]; } int num = SherpaOnnxOfflineSpeakerDiarizationResultGetNumSegments(result); IntPtr intPtr = SherpaOnnxOfflineSpeakerDiarizationResultSortByStartTime(result); OfflineSpeakerDiarizationSegment[] array = new OfflineSpeakerDiarizationSegment[num]; int num2 = 16; for (int i = 0; i != num; i++) { IntPtr handle = new IntPtr((byte*)(void*)intPtr + i * num2); array[i] = new OfflineSpeakerDiarizationSegment(handle); } SherpaOnnxOfflineSpeakerDiarizationDestroySegment(intPtr); SherpaOnnxOfflineSpeakerDiarizationDestroyResult(result); return array; } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~OfflineSpeakerDiarization() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyOfflineSpeakerDiarization(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateOfflineSpeakerDiarization(ref OfflineSpeakerDiarizationConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOfflineSpeakerDiarization(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxOfflineSpeakerDiarizationGetSampleRate(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxOfflineSpeakerDiarizationResultGetNumSegments(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxOfflineSpeakerDiarizationProcess(IntPtr handle, float[] samples, int n); [DllImport("sherpa-onnx-c-api", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr SherpaOnnxOfflineSpeakerDiarizationProcessWithCallback(IntPtr handle, float[] samples, int n, OfflineSpeakerDiarizationProgressCallback callback, IntPtr arg); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxOfflineSpeakerDiarizationDestroyResult(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxOfflineSpeakerDiarizationResultSortByStartTime(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxOfflineSpeakerDiarizationDestroySegment(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxOfflineSpeakerDiarizationSetConfig(IntPtr handle, ref OfflineSpeakerDiarizationConfig config); } public struct OfflineSpeakerDiarizationConfig { public OfflineSpeakerSegmentationModelConfig Segmentation; public SpeakerEmbeddingExtractorConfig Embedding; public FastClusteringConfig Clustering; public float MinDurationOn; public float MinDurationOff; public OfflineSpeakerDiarizationConfig() { Segmentation = new OfflineSpeakerSegmentationModelConfig(); Embedding = new SpeakerEmbeddingExtractorConfig(); Clustering = new FastClusteringConfig(); MinDurationOn = 0.3f; MinDurationOff = 0.5f; } } public class OfflineSpeakerDiarizationSegment { private struct Impl { public float Start; public float End; public int Speaker; public float Confidence; } public float Start; public float End; public int Speaker; public float Confidence; public OfflineSpeakerDiarizationSegment(IntPtr handle) { Impl impl = (Impl)Marshal.PtrToStructure(handle, typeof(Impl)); Start = impl.Start; End = impl.End; Speaker = impl.Speaker; Confidence = impl.Confidence; } } public struct OfflineSpeakerSegmentationModelConfig { public OfflineSpeakerSegmentationPyannoteModelConfig Pyannote; public int NumThreads; public int Debug; [MarshalAs(UnmanagedType.LPStr)] public string Provider; public OfflineSpeakerSegmentationModelConfig() { Pyannote = new OfflineSpeakerSegmentationPyannoteModelConfig(); NumThreads = 1; Debug = 0; Provider = "cpu"; } } public struct OfflineSpeakerSegmentationPyannoteModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public float WindowShiftRatio; public OfflineSpeakerSegmentationPyannoteModelConfig() { Model = ""; WindowShiftRatio = 0.1f; } } public class OfflineSpeechDenoiser : IDisposable { private HandleRef _handle; public int SampleRate => SherpaOnnxOfflineSpeechDenoiserGetSampleRate(_handle.Handle); public OfflineSpeechDenoiser(OfflineSpeechDenoiserConfig config) { IntPtr handle = SherpaOnnxCreateOfflineSpeechDenoiser(ref config); _handle = new HandleRef(this, handle); } public DenoisedAudio Run(float[] samples, int sampleRate) { return new DenoisedAudio(SherpaOnnxOfflineSpeechDenoiserRun(_handle.Handle, samples, samples.Length, sampleRate)); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~OfflineSpeechDenoiser() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyOfflineSpeechDenoiser(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateOfflineSpeechDenoiser(ref OfflineSpeechDenoiserConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOfflineSpeechDenoiser(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxOfflineSpeechDenoiserGetSampleRate(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxOfflineSpeechDenoiserRun(IntPtr handle, float[] samples, int n, int sampleRate); } public struct OfflineSpeechDenoiserConfig { public OfflineSpeechDenoiserModelConfig Model; public OfflineSpeechDenoiserConfig() { Model = new OfflineSpeechDenoiserModelConfig(); } } public struct OfflineSpeechDenoiserDpdfNetModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public float AttenuationLimitDb; public OfflineSpeechDenoiserDpdfNetModelConfig() { Model = ""; AttenuationLimitDb = 0f; } } public struct OfflineSpeechDenoiserGtcrnModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OfflineSpeechDenoiserGtcrnModelConfig() { Model = ""; } } public struct OfflineSpeechDenoiserModelConfig { public OfflineSpeechDenoiserGtcrnModelConfig Gtcrn; public int NumThreads; public int Debug; [MarshalAs(UnmanagedType.LPStr)] public string Provider; public OfflineSpeechDenoiserDpdfNetModelConfig Dpdfnet; public OfflineSpeechDenoiserVoxLockModelConfig Voxlock; public OfflineSpeechDenoiserModelConfig() { Gtcrn = new OfflineSpeechDenoiserGtcrnModelConfig(); Dpdfnet = new OfflineSpeechDenoiserDpdfNetModelConfig(); Voxlock = new OfflineSpeechDenoiserVoxLockModelConfig(); NumThreads = 1; Debug = 0; Provider = "cpu"; } } public struct OfflineSpeechDenoiserVoxLockModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string EnrollModel; [MarshalAs(UnmanagedType.LPStr)] public string ChunkModel; [MarshalAs(UnmanagedType.LPStr)] public string VoiceSample; public OfflineSpeechDenoiserVoxLockModelConfig() { EnrollModel = ""; ChunkModel = ""; VoiceSample = ""; } } public class OfflineStream : IDisposable { private HandleRef _handle; public OfflineRecognizerResult Result { get { IntPtr result = GetResult(_handle.Handle); OfflineRecognizerResult result2 = new OfflineRecognizerResult(result); DestroyResult(result); return result2; } } public IntPtr Handle => _handle.Handle; public OfflineStream(IntPtr p) { _handle = new HandleRef(this, p); } public void AcceptWaveform(int sampleRate, float[] samples) { AcceptWaveform(Handle, sampleRate, samples, samples.Length); } public void SetOption(string key, string value) { SherpaOnnxOfflineStreamSetOption(Handle, key, value); } public string GetOption(string key) { return Marshal.PtrToStringAnsi(SherpaOnnxOfflineStreamGetOption(Handle, key)) ?? ""; } public bool HasOption(string key) { return SherpaOnnxOfflineStreamHasOption(Handle, key) == 1; } ~OfflineStream() { Cleanup(); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } private void Cleanup() { SherpaOnnxDestroyOfflineStream(Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOfflineStream(IntPtr handle); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxAcceptWaveformOffline")] private static extern void AcceptWaveform(IntPtr handle, int sampleRate, float[] samples, int n); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxOfflineStreamSetOption(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string key, [MarshalAs(UnmanagedType.LPStr)] string value); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxOfflineStreamGetOption(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string key); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxOfflineStreamHasOption(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string key); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxGetOfflineStreamResult")] private static extern IntPtr GetResult(IntPtr handle); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxDestroyOfflineRecognizerResult")] private static extern void DestroyResult(IntPtr handle); } public struct OfflineTdnnModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OfflineTdnnModelConfig() { Model = ""; } } public struct OfflineTransducerModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Encoder; [MarshalAs(UnmanagedType.LPStr)] public string Decoder; [MarshalAs(UnmanagedType.LPStr)] public string Joiner; public OfflineTransducerModelConfig() { Encoder = ""; Decoder = ""; Joiner = ""; } } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int OfflineTtsCallback(IntPtr samples, int n); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int OfflineTtsCallbackProgress(IntPtr samples, int n, float progress); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int OfflineTtsCallbackProgressWithArg(IntPtr samples, int n, float progress, IntPtr arg); public class OfflineTts : IDisposable { private HandleRef _handle; public int SampleRate => SherpaOnnxOfflineTtsSampleRate(_handle.Handle); public int NumSpeakers => SherpaOnnxOfflineTtsNumSpeakers(_handle.Handle); public string Lang { get { IntPtr intPtr = SherpaOnnxOfflineTtsLang(_handle.Handle); string result = Marshal.PtrToStringAnsi(intPtr) ?? ""; SherpaOnnxDestroyOfflineTtsLang(intPtr); return result; } } public OfflineTts(OfflineTtsConfig config) { IntPtr handle = SherpaOnnxCreateOfflineTts(ref config); _handle = new HandleRef(this, handle); } public OfflineTtsGeneratedAudio Generate(string text, float speed, int speakerId) { byte[] bytes = Encoding.UTF8.GetBytes(text); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; NativeResources resources; OfflineTtsGenerationConfig.NativeStruct config = new OfflineTtsGenerationConfig { Speed = speed, Sid = speakerId }.ToNative(out resources); try { return new OfflineTtsGeneratedAudio(SherpaOnnxOfflineTtsGenerateWithConfig(_handle.Handle, array, ref config, null, IntPtr.Zero)); } finally { resources.Dispose(); } } public OfflineTtsGeneratedAudio GenerateWithCallback(string text, float speed, int speakerId, OfflineTtsCallback callback) { byte[] bytes = Encoding.UTF8.GetBytes(text); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; OfflineTtsGenerationConfig obj = new OfflineTtsGenerationConfig { Speed = speed, Sid = speakerId }; OfflineTtsCallbackProgressWithArg offlineTtsCallbackProgressWithArg = null; if (callback != null) { offlineTtsCallbackProgressWithArg = (IntPtr samples, int n, float progress, IntPtr arg) => callback(samples, n); } NativeResources resources; OfflineTtsGenerationConfig.NativeStruct config = obj.ToNative(out resources); GCHandle gCHandle = default(GCHandle); try { if (offlineTtsCallbackProgressWithArg != null) { gCHandle = GCHandle.Alloc(offlineTtsCallbackProgressWithArg); } return new OfflineTtsGeneratedAudio(SherpaOnnxOfflineTtsGenerateWithConfig(_handle.Handle, array, ref config, offlineTtsCallbackProgressWithArg, IntPtr.Zero)); } finally { if (gCHandle.IsAllocated) { gCHandle.Free(); } resources.Dispose(); } } public OfflineTtsGeneratedAudio GenerateWithCallbackProgress(string text, float speed, int speakerId, OfflineTtsCallbackProgress callback) { byte[] bytes = Encoding.UTF8.GetBytes(text); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; OfflineTtsGenerationConfig obj = new OfflineTtsGenerationConfig { Speed = speed, Sid = speakerId }; OfflineTtsCallbackProgressWithArg offlineTtsCallbackProgressWithArg = null; if (callback != null) { offlineTtsCallbackProgressWithArg = (IntPtr samples, int n, float progress, IntPtr arg) => callback(samples, n, progress); } NativeResources resources; OfflineTtsGenerationConfig.NativeStruct config = obj.ToNative(out resources); GCHandle gCHandle = default(GCHandle); try { if (offlineTtsCallbackProgressWithArg != null) { gCHandle = GCHandle.Alloc(offlineTtsCallbackProgressWithArg); } return new OfflineTtsGeneratedAudio(SherpaOnnxOfflineTtsGenerateWithConfig(_handle.Handle, array, ref config, offlineTtsCallbackProgressWithArg, IntPtr.Zero)); } finally { if (gCHandle.IsAllocated) { gCHandle.Free(); } resources.Dispose(); } } public OfflineTtsGeneratedAudio GenerateWithConfig(string text, OfflineTtsGenerationConfig config, OfflineTtsCallbackProgressWithArg callback) { byte[] bytes = Encoding.UTF8.GetBytes(text); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; GCHandle gCHandle = default(GCHandle); NativeResources resources; OfflineTtsGenerationConfig.NativeStruct config2 = config.ToNative(out resources); try { gCHandle = GCHandle.Alloc(callback); return new OfflineTtsGeneratedAudio(SherpaOnnxOfflineTtsGenerateWithConfig(_handle.Handle, array, ref config2, callback, IntPtr.Zero)); } finally { if (gCHandle.IsAllocated) { gCHandle.Free(); } resources.Dispose(); } } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~OfflineTts() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyOfflineTts(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateOfflineTts(ref OfflineTtsConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOfflineTts(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxOfflineTtsSampleRate(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxOfflineTtsNumSpeakers(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxOfflineTtsLang(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOfflineTtsLang(IntPtr s); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxOfflineTtsGenerate(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Text, int sid, float speed); [DllImport("sherpa-onnx-c-api", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr SherpaOnnxOfflineTtsGenerateWithCallback(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Text, int sid, float speed, OfflineTtsCallback callback); [DllImport("sherpa-onnx-c-api", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr SherpaOnnxOfflineTtsGenerateWithProgressCallback(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Text, int sid, float speed, OfflineTtsCallbackProgress callback); [DllImport("sherpa-onnx-c-api", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr SherpaOnnxOfflineTtsGenerateWithConfig(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Text, ref OfflineTtsGenerationConfig.NativeStruct config, OfflineTtsCallbackProgressWithArg callback, IntPtr arg); } public struct OfflineTtsConfig { public OfflineTtsModelConfig Model; [MarshalAs(UnmanagedType.LPStr)] public string RuleFsts; public int MaxNumSentences; [MarshalAs(UnmanagedType.LPStr)] public string RuleFars; public float SilenceScale; public OfflineTtsConfig() { Model = new OfflineTtsModelConfig(); RuleFsts = ""; MaxNumSentences = 1; RuleFars = ""; SilenceScale = 0.2f; } } public class OfflineTtsGeneratedAudio { private struct Impl { public IntPtr Samples; public int NumSamples; public int SampleRate; } private HandleRef _handle; public IntPtr Handle => _handle.Handle; public int NumSamples { get { if (Handle == IntPtr.Zero) { return 0; } return ((Impl)Marshal.PtrToStructure(Handle, typeof(Impl))).NumSamples; } } public int SampleRate { get { if (Handle == IntPtr.Zero) { return 0; } return ((Impl)Marshal.PtrToStructure(Handle, typeof(Impl))).SampleRate; } } public float[] Samples { get { if (Handle == IntPtr.Zero) { return new float[0]; } Impl impl = (Impl)Marshal.PtrToStructure(Handle, typeof(Impl)); float[] array = new float[impl.NumSamples]; Marshal.Copy(impl.Samples, array, 0, impl.NumSamples); return array; } } public OfflineTtsGeneratedAudio(IntPtr p) { _handle = new HandleRef(this, p); } public bool SaveToWaveFile(string filename) { if (Handle == IntPtr.Zero) { return false; } Impl impl = (Impl)Marshal.PtrToStructure(Handle, typeof(Impl)); byte[] bytes = Encoding.UTF8.GetBytes(filename); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; return SherpaOnnxWriteWave(impl.Samples, impl.NumSamples, impl.SampleRate, array) == 1; } ~OfflineTtsGeneratedAudio() { Cleanup(); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } private void Cleanup() { if (Handle != IntPtr.Zero) { SherpaOnnxDestroyOfflineTtsGeneratedAudio(Handle); } _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOfflineTtsGeneratedAudio(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxWriteWave(IntPtr samples, int n, int sample_rate, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Filename); } public class OfflineTtsGenerationConfig { internal struct NativeStruct { public float SilenceScale; public float Speed; public int Sid; public IntPtr ReferenceAudio; public int ReferenceAudioLen; public int ReferenceSampleRate; [MarshalAs(UnmanagedType.LPStr)] public string ReferenceText; public int NumSteps; [MarshalAs(UnmanagedType.LPStr)] public string Extra; public IntPtr PhonemeCodepoints; public IntPtr PhonemeCodepointsLens; public int PhonemeCodepointsNumSentences; public IntPtr Tokens; public IntPtr TokensLens; public int TokensNumSentences; } public float SilenceScale; public float Speed; public int Sid; public float[] ReferenceAudio; public int ReferenceSampleRate; public string ReferenceText; public int NumSteps; public Hashtable Extra; public int[][] PhonemeCodepoints; public string[][] Tokens; public OfflineTtsGenerationConfig() { SilenceScale = 0.2f; Speed = 1f; Sid = 0; ReferenceAudio = null; ReferenceSampleRate = 0; ReferenceText = ""; NumSteps = 5; Extra = new Hashtable(); PhonemeCodepoints = null; Tokens = null; } internal NativeStruct ToNative(out NativeResources resources) { resources = new NativeResources(); NativeStruct result = new NativeStruct { SilenceScale = SilenceScale, Speed = Speed, Sid = Sid }; if (ReferenceAudio != null && ReferenceAudio.Length != 0) { resources.AudioHandle = GCHandle.Alloc(ReferenceAudio, GCHandleType.Pinned); result.ReferenceAudio = resources.AudioHandle.Value.AddrOfPinnedObject(); result.ReferenceAudioLen = ReferenceAudio.Length; } else { result.ReferenceAudio = IntPtr.Zero; result.ReferenceAudioLen = 0; } result.ReferenceSampleRate = ReferenceSampleRate; result.ReferenceText = ReferenceText ?? ""; result.NumSteps = NumSteps; result.Extra = "{}"; if (Extra != null && Extra.Count > 0) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{"); bool flag = true; foreach (DictionaryEntry item in Extra) { if (!flag) { stringBuilder.Append(","); } flag = false; string arg = JsonEscape(item.Key.ToString()); string arg2 = ((!(item.Value is string)) ? ((!(item.Value is float) && !(item.Value is double)) ? ((!(item.Value is bool)) ? item.Value.ToString() : (((bool)item.Value) ? "true" : "false")) : ((IFormattable)item.Value).ToString(null, CultureInfo.InvariantCulture)) : JsonEscape((string)item.Value)); stringBuilder.AppendFormat("{0}:{1}", arg, arg2); } stringBuilder.Append("}"); result.Extra = stringBuilder.ToString(); } if (PhonemeCodepoints != null && PhonemeCodepoints.Length != 0) { int num = 0; int[][] phonemeCodepoints = PhonemeCodepoints; foreach (int[] array in phonemeCodepoints) { if (array != null) { num += array.Length; } } if (num > 0) { int[] array2 = new int[num]; int[] array3 = new int[PhonemeCodepoints.Length]; int num2 = 0; for (int j = 0; j < PhonemeCodepoints.Length; j++) { int[] array4 = PhonemeCodepoints[j]; if (array4 != null) { array3[j] = array4.Length; Array.Copy(array4, 0, array2, num2, array4.Length); num2 += array4.Length; } } resources.CodepointsHandle = GCHandle.Alloc(array2, GCHandleType.Pinned); resources.CodepointsLensHandle = GCHandle.Alloc(array3, GCHandleType.Pinned); result.PhonemeCodepoints = resources.CodepointsHandle.AddrOfPinnedObject(); result.PhonemeCodepointsLens = resources.CodepointsLensHandle.AddrOfPinnedObject(); result.PhonemeCodepointsNumSentences = PhonemeCodepoints.Length; } } if (Tokens != null && Tokens.Length != 0) { int num3 = 0; string[][] tokens = Tokens; foreach (string[] array5 in tokens) { if (array5 != null) { num3 += array5.Length; } } if (num3 > 0) { IntPtr[] array6 = new IntPtr[num3]; int[] array7 = new int[Tokens.Length]; int num4 = 0; for (int k = 0; k < Tokens.Length; k++) { string[] array8 = Tokens[k]; if (array8 != null) { array7[k] = array8.Length; for (int l = 0; l < array8.Length; l++) { IntPtr intPtr = Marshal.StringToHGlobalAnsi(array8[l] ?? ""); resources.TokenStrings.Add(intPtr); array6[num4++] = intPtr; } } } resources.TokensHandle = GCHandle.Alloc(array6, GCHandleType.Pinned); resources.TokensLensHandle = GCHandle.Alloc(array7, GCHandleType.Pinned); result.Tokens = resources.TokensHandle.AddrOfPinnedObject(); result.TokensLens = resources.TokensLensHandle.AddrOfPinnedObject(); result.TokensNumSentences = Tokens.Length; } } return result; } private static string JsonEscape(string s) { if (s == null) { return "\"\""; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append('"'); foreach (char c in s) { switch (c) { case '"': stringBuilder.Append("\\\""); continue; case '\\': stringBuilder.Append("\\\\"); continue; case '\b': stringBuilder.Append("\\b"); continue; case '\f': stringBuilder.Append("\\f"); continue; case '\n': stringBuilder.Append("\\n"); continue; case '\r': stringBuilder.Append("\\r"); continue; case '\t': stringBuilder.Append("\\t"); continue; } if (c < ' ' || c > '~') { stringBuilder.AppendFormat("\\u{0:X4}", (int)c); } else { stringBuilder.Append(c); } } stringBuilder.Append('"'); return stringBuilder.ToString(); } } public struct OfflineTtsKittenModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; [MarshalAs(UnmanagedType.LPStr)] public string Voices; [MarshalAs(UnmanagedType.LPStr)] public string Tokens; [MarshalAs(UnmanagedType.LPStr)] public string DataDir; public float LengthScale; [MarshalAs(UnmanagedType.LPStr)] public string Lexicon; public OfflineTtsKittenModelConfig() { Model = ""; Voices = ""; Tokens = ""; DataDir = ""; Lexicon = ""; LengthScale = 1f; } } public struct OfflineTtsKokoroModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; [MarshalAs(UnmanagedType.LPStr)] public string Voices; [MarshalAs(UnmanagedType.LPStr)] public string Tokens; [MarshalAs(UnmanagedType.LPStr)] public string DataDir; public float LengthScale; [MarshalAs(UnmanagedType.LPStr)] public string DictDir; [MarshalAs(UnmanagedType.LPStr)] public string Lexicon; [MarshalAs(UnmanagedType.LPStr)] public string Lang; public OfflineTtsKokoroModelConfig() { Model = ""; Voices = ""; Tokens = ""; DataDir = ""; LengthScale = 1f; DictDir = ""; Lexicon = ""; Lang = ""; } } public struct OfflineTtsMatchaModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string AcousticModel; [MarshalAs(UnmanagedType.LPStr)] public string Vocoder; [MarshalAs(UnmanagedType.LPStr)] public string Lexicon; [MarshalAs(UnmanagedType.LPStr)] public string Tokens; [MarshalAs(UnmanagedType.LPStr)] public string DataDir; public float NoiseScale; public float LengthScale; [MarshalAs(UnmanagedType.LPStr)] public string DictDir; public OfflineTtsMatchaModelConfig() { AcousticModel = ""; Vocoder = ""; Lexicon = ""; Tokens = ""; DataDir = ""; NoiseScale = 0.667f; LengthScale = 1f; DictDir = ""; } } public struct OfflineTtsModelConfig { public OfflineTtsVitsModelConfig Vits; public int NumThreads; public int Debug; [MarshalAs(UnmanagedType.LPStr)] public string Provider; public OfflineTtsMatchaModelConfig Matcha; public OfflineTtsKokoroModelConfig Kokoro; public OfflineTtsKittenModelConfig Kitten; public OfflineTtsZipVoiceModelConfig ZipVoice; public OfflineTtsPocketModelConfig Pocket; public OfflineTtsSupertonicModelConfig Supertonic; public OfflineTtsModelConfig() { Vits = new OfflineTtsVitsModelConfig(); Matcha = new OfflineTtsMatchaModelConfig(); Kokoro = new OfflineTtsKokoroModelConfig(); Kitten = new OfflineTtsKittenModelConfig(); ZipVoice = new OfflineTtsZipVoiceModelConfig(); Pocket = new OfflineTtsPocketModelConfig(); Supertonic = new OfflineTtsSupertonicModelConfig(); NumThreads = 1; Debug = 0; Provider = "cpu"; } } public struct OfflineTtsPocketModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string LmFlow; [MarshalAs(UnmanagedType.LPStr)] public string LmMain; [MarshalAs(UnmanagedType.LPStr)] public string Encoder; [MarshalAs(UnmanagedType.LPStr)] public string Decoder; [MarshalAs(UnmanagedType.LPStr)] public string TextConditioner; [MarshalAs(UnmanagedType.LPStr)] public string VocabJson; [MarshalAs(UnmanagedType.LPStr)] public string TokenScoresJson; public int VoiceEmbeddingCacheCapacity; public OfflineTtsPocketModelConfig() { LmFlow = ""; LmMain = ""; Encoder = ""; Decoder = ""; TextConditioner = ""; VocabJson = ""; TokenScoresJson = ""; VoiceEmbeddingCacheCapacity = 50; } } public struct OfflineTtsSupertonicModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string DurationPredictor; [MarshalAs(UnmanagedType.LPStr)] public string TextEncoder; [MarshalAs(UnmanagedType.LPStr)] public string VectorEstimator; [MarshalAs(UnmanagedType.LPStr)] public string Vocoder; [MarshalAs(UnmanagedType.LPStr)] public string TtsJson; [MarshalAs(UnmanagedType.LPStr)] public string UnicodeIndexer; [MarshalAs(UnmanagedType.LPStr)] public string VoiceStyle; public OfflineTtsSupertonicModelConfig() { DurationPredictor = ""; TextEncoder = ""; VectorEstimator = ""; Vocoder = ""; TtsJson = ""; UnicodeIndexer = ""; VoiceStyle = ""; } } public struct OfflineTtsVitsModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; [MarshalAs(UnmanagedType.LPStr)] public string Lexicon; [MarshalAs(UnmanagedType.LPStr)] public string Tokens; [MarshalAs(UnmanagedType.LPStr)] public string DataDir; public float NoiseScale; public float NoiseScaleW; public float LengthScale; [MarshalAs(UnmanagedType.LPStr)] public string DictDir; public OfflineTtsVitsModelConfig() { Model = ""; Lexicon = ""; Tokens = ""; DataDir = ""; NoiseScale = 0.667f; NoiseScaleW = 0.8f; LengthScale = 1f; DictDir = ""; } } public struct OfflineTtsZipVoiceModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Tokens; [MarshalAs(UnmanagedType.LPStr)] public string Encoder; [MarshalAs(UnmanagedType.LPStr)] public string Decoder; [MarshalAs(UnmanagedType.LPStr)] public string Vocoder; [MarshalAs(UnmanagedType.LPStr)] public string DataDir; [MarshalAs(UnmanagedType.LPStr)] public string Lexicon; public float FeatScale; public float Tshift; public float TargetRms; public float GuidanceScale; public OfflineTtsZipVoiceModelConfig() { Tokens = ""; Encoder = ""; Decoder = ""; Vocoder = ""; DataDir = ""; Lexicon = ""; FeatScale = 0.1f; Tshift = 0.5f; TargetRms = 0.1f; GuidanceScale = 1f; } } public struct OfflineWenetCtcModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OfflineWenetCtcModelConfig() { Model = ""; } } public struct OfflineWhisperModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Encoder; [MarshalAs(UnmanagedType.LPStr)] public string Decoder; [MarshalAs(UnmanagedType.LPStr)] public string Language; [MarshalAs(UnmanagedType.LPStr)] public string Task; public int TailPaddings; public int EnableTokenTimestamps; public int EnableSegmentTimestamps; public OfflineWhisperModelConfig() { Encoder = ""; Decoder = ""; Language = ""; Task = "transcribe"; TailPaddings = -1; EnableTokenTimestamps = 0; EnableSegmentTimestamps = 0; } } public struct OfflineZipformerAudioTaggingModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OfflineZipformerAudioTaggingModelConfig() { Model = ""; } } public struct OfflineZipformerCtcModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OfflineZipformerCtcModelConfig() { Model = ""; } } public struct OnlineCtcFstDecoderConfig { [MarshalAs(UnmanagedType.LPStr)] public string Graph; public int MaxActive; public OnlineCtcFstDecoderConfig() { Graph = ""; MaxActive = 3000; } } public struct OnlineModelConfig { public OnlineTransducerModelConfig Transducer; public OnlineParaformerModelConfig Paraformer; public OnlineZipformer2CtcModelConfig Zipformer2Ctc; [MarshalAs(UnmanagedType.LPStr)] public string Tokens; public int NumThreads; [MarshalAs(UnmanagedType.LPStr)] public string Provider; public int Debug; [MarshalAs(UnmanagedType.LPStr)] public string ModelType; [MarshalAs(UnmanagedType.LPStr)] public string ModelingUnit; [MarshalAs(UnmanagedType.LPStr)] public string BpeVocab; [MarshalAs(UnmanagedType.LPStr)] public string TokensBuf; public int TokensBufSize; public OnlineNemoCtcModelConfig NemoCtc; public OnlineToneCtcModelConfig ToneCtc; public OnlineModelConfig() { Transducer = new OnlineTransducerModelConfig(); Paraformer = new OnlineParaformerModelConfig(); Zipformer2Ctc = new OnlineZipformer2CtcModelConfig(); Tokens = ""; NumThreads = 1; Provider = "cpu"; Debug = 0; ModelType = ""; ModelingUnit = "cjkchar"; BpeVocab = ""; TokensBuf = ""; TokensBufSize = 0; NemoCtc = new OnlineNemoCtcModelConfig(); ToneCtc = new OnlineToneCtcModelConfig(); } } public struct OnlineNemoCtcModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OnlineNemoCtcModelConfig() { Model = ""; } } public struct OnlineParaformerModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Encoder; [MarshalAs(UnmanagedType.LPStr)] public string Decoder; public OnlineParaformerModelConfig() { Encoder = ""; Decoder = ""; } } public class OnlinePunctuation : IDisposable { private HandleRef _handle; public OnlinePunctuation(OnlinePunctuationConfig config) { IntPtr handle = SherpaOnnxCreateOnlinePunctuation(ref config); _handle = new HandleRef(this, handle); } public unsafe string AddPunct(string text) { byte[] bytes = Encoding.UTF8.GetBytes(text); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; IntPtr intPtr = SherpaOnnxOnlinePunctuationAddPunct(_handle.Handle, array); string result = ""; int num = 0; byte* ptr = (byte*)(void*)intPtr; if (ptr != null) { while (*ptr != 0) { ptr++; num++; } } if (num > 0) { byte[] array2 = new byte[num]; Marshal.Copy(intPtr, array2, 0, num); result = Encoding.UTF8.GetString(array2); } SherpaOnnxOnlinePunctuationFreeText(intPtr); return result; } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~OnlinePunctuation() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyOnlinePunctuation(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateOnlinePunctuation(ref OnlinePunctuationConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOnlinePunctuation(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxOnlinePunctuationAddPunct(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Text); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxOnlinePunctuationFreeText(IntPtr p); } public struct OnlinePunctuationConfig { public OnlinePunctuationModelConfig Model; public OnlinePunctuationConfig() { Model = new OnlinePunctuationModelConfig(); } } public struct OnlinePunctuationModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string CnnBiLstm; [MarshalAs(UnmanagedType.LPStr)] public string BpeVocab; public int NumThreads; public int Debug; [MarshalAs(UnmanagedType.LPStr)] public string Provider; public OnlinePunctuationModelConfig() { CnnBiLstm = ""; BpeVocab = ""; NumThreads = 1; Debug = 0; Provider = "cpu"; } } public class OnlineRecognizer : IDisposable { private HandleRef _handle; public OnlineRecognizer(OnlineRecognizerConfig config) { IntPtr handle = SherpaOnnxCreateOnlineRecognizer(ref config); _handle = new HandleRef(this, handle); } public OnlineStream CreateStream() { return new OnlineStream(SherpaOnnxCreateOnlineStream(_handle.Handle)); } public bool IsReady(OnlineStream stream) { return IsReady(_handle.Handle, stream.Handle) != 0; } public bool IsEndpoint(OnlineStream stream) { return SherpaOnnxOnlineStreamIsEndpoint(_handle.Handle, stream.Handle) != 0; } public void Decode(OnlineStream stream) { Decode(_handle.Handle, stream.Handle); } public void Decode(IEnumerable<OnlineStream> streams) { List<IntPtr> list = new List<IntPtr>(); foreach (OnlineStream stream in streams) { list.Add(stream.Handle); } IntPtr[] array = list.ToArray(); Decode(_handle.Handle, array, array.Length); } public OnlineRecognizerResult GetResult(OnlineStream stream) { IntPtr result = GetResult(_handle.Handle, stream.Handle); OnlineRecognizerResult result2 = new OnlineRecognizerResult(result); DestroyResult(result); return result2; } public void Reset(OnlineStream stream) { SherpaOnnxOnlineStreamReset(_handle.Handle, stream.Handle); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~OnlineRecognizer() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyOnlineRecognizer(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateOnlineRecognizer(ref OnlineRecognizerConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOnlineRecognizer(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateOnlineStream(IntPtr handle); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxIsOnlineStreamReady")] private static extern int IsReady(IntPtr handle, IntPtr stream); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxDecodeOnlineStream")] private static extern void Decode(IntPtr handle, IntPtr stream); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxDecodeMultipleOnlineStreams")] private static extern void Decode(IntPtr handle, IntPtr[] streams, int n); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxGetOnlineStreamResult")] private static extern IntPtr GetResult(IntPtr handle, IntPtr stream); [DllImport("sherpa-onnx-c-api", EntryPoint = "SherpaOnnxDestroyOnlineRecognizerResult")] private static extern void DestroyResult(IntPtr result); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxOnlineStreamReset(IntPtr handle, IntPtr stream); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxOnlineStreamIsEndpoint(IntPtr handle, IntPtr stream); } public struct OnlineRecognizerConfig { public FeatureConfig FeatConfig; public OnlineModelConfig ModelConfig; [MarshalAs(UnmanagedType.LPStr)] public string DecodingMethod; public int MaxActivePaths; public int EnableEndpoint; public float Rule1MinTrailingSilence; public float Rule2MinTrailingSilence; public float Rule3MinUtteranceLength; [MarshalAs(UnmanagedType.LPStr)] public string HotwordsFile; public float HotwordsScore; public OnlineCtcFstDecoderConfig CtcFstDecoderConfig; [MarshalAs(UnmanagedType.LPStr)] public string RuleFsts; [MarshalAs(UnmanagedType.LPStr)] public string RuleFars; public float BlankPenalty; [MarshalAs(UnmanagedType.LPStr)] public string HotwordsBuf; public int HotwordsBufSize; public HomophoneReplacerConfig Hr; public OnlineRecognizerConfig() { FeatConfig = new FeatureConfig(); ModelConfig = new OnlineModelConfig(); DecodingMethod = "greedy_search"; MaxActivePaths = 4; EnableEndpoint = 0; Rule1MinTrailingSilence = 1.2f; Rule2MinTrailingSilence = 2.4f; Rule3MinUtteranceLength = 20f; HotwordsFile = ""; HotwordsScore = 1.5f; CtcFstDecoderConfig = new OnlineCtcFstDecoderConfig(); RuleFsts = ""; RuleFars = ""; BlankPenalty = 0f; HotwordsBuf = ""; HotwordsBufSize = 0; Hr = new HomophoneReplacerConfig(); } } public class OnlineRecognizerResult { private struct Impl { public IntPtr Text; public IntPtr Tokens; public IntPtr TokensArr; public IntPtr Timestamps; public int Count; } private string _text; private string[] _tokens; private float[] _timestamps; public string Text => _text; public string[] Tokens => _tokens; public float[] Timestamps => _timestamps; public unsafe OnlineRecognizerResult(IntPtr handle) { Impl impl = (Impl)Marshal.PtrToStructure(handle, typeof(Impl)); int num = 0; byte* ptr = (byte*)(void*)impl.Text; while (*ptr != 0) { ptr++; num++; } byte[] array = new byte[num]; Marshal.Copy(impl.Text, array, 0, num); _text = Encoding.UTF8.GetString(array); _tokens = new string[impl.Count]; byte* ptr2 = (byte*)(void*)impl.Tokens; for (int i = 0; i < impl.Count; i++) { num = 0; byte* ptr3 = ptr2; while (*ptr2 != 0) { ptr2++; num++; } ptr2++; array = new byte[num]; fixed (byte* ptr4 = array) { for (int j = 0; j < num; j++) { ptr4[j] = ptr3[j]; } } _tokens[i] = Encoding.UTF8.GetString(array); } float* ptr5 = (float*)(void*)impl.Timestamps; if (ptr5 != null) { _timestamps = new float[impl.Count]; fixed (float* timestamps = _timestamps) { for (int k = 0; k < impl.Count; k++) { timestamps[k] = ptr5[k]; } } } else { _timestamps = new float[0]; } } } public class OnlineSpeechDenoiser : IDisposable { private HandleRef _handle; public int SampleRate => SherpaOnnxOnlineSpeechDenoiserGetSampleRate(_handle.Handle); public int FrameShiftInSamples => SherpaOnnxOnlineSpeechDenoiserGetFrameShiftInSamples(_handle.Handle); public OnlineSpeechDenoiser(OnlineSpeechDenoiserConfig config) { IntPtr handle = SherpaOnnxCreateOnlineSpeechDenoiser(ref config); _handle = new HandleRef(this, handle); } public DenoisedAudio Run(float[] samples, int sampleRate) { return new DenoisedAudio(SherpaOnnxOnlineSpeechDenoiserRun(_handle.Handle, samples, samples.Length, sampleRate)); } public DenoisedAudio Flush() { return new DenoisedAudio(SherpaOnnxOnlineSpeechDenoiserFlush(_handle.Handle)); } public void Reset() { SherpaOnnxOnlineSpeechDenoiserReset(_handle.Handle); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~OnlineSpeechDenoiser() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyOnlineSpeechDenoiser(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateOnlineSpeechDenoiser(ref OnlineSpeechDenoiserConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOnlineSpeechDenoiser(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxOnlineSpeechDenoiserGetSampleRate(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxOnlineSpeechDenoiserGetFrameShiftInSamples(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxOnlineSpeechDenoiserRun(IntPtr handle, float[] samples, int n, int sampleRate); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxOnlineSpeechDenoiserFlush(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxOnlineSpeechDenoiserReset(IntPtr handle); } public struct OnlineSpeechDenoiserConfig { public OfflineSpeechDenoiserModelConfig Model; public OnlineSpeechDenoiserConfig() { Model = new OfflineSpeechDenoiserModelConfig(); } } public class OnlineStream : IDisposable { private HandleRef _handle; public IntPtr Handle => _handle.Handle; public OnlineStream(IntPtr p) { _handle = new HandleRef(this, p); } public void AcceptWaveform(int sampleRate, float[] samples) { SherpaOnnxOnlineStreamAcceptWaveform(Handle, sampleRate, samples, samples.Length); } public void InputFinished() { SherpaOnnxOnlineStreamInputFinished(Handle); } public void SetOption(string key, string value) { SherpaOnnxOnlineStreamSetOption(Handle, key, value); } public string GetOption(string key) { return Marshal.PtrToStringAnsi(SherpaOnnxOnlineStreamGetOption(Handle, key)) ?? ""; } public bool HasOption(string key) { return SherpaOnnxOnlineStreamHasOption(Handle, key) == 1; } ~OnlineStream() { Cleanup(); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } private void Cleanup() { SherpaOnnxDestroyOnlineStream(Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyOnlineStream(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxOnlineStreamAcceptWaveform(IntPtr handle, int sampleRate, float[] samples, int n); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxOnlineStreamInputFinished(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxOnlineStreamSetOption(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string key, [MarshalAs(UnmanagedType.LPStr)] string value); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxOnlineStreamGetOption(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string key); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxOnlineStreamHasOption(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string key); } public struct OnlineToneCtcModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OnlineToneCtcModelConfig() { Model = ""; } } public struct OnlineTransducerModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Encoder; [MarshalAs(UnmanagedType.LPStr)] public string Decoder; [MarshalAs(UnmanagedType.LPStr)] public string Joiner; public OnlineTransducerModelConfig() { Encoder = ""; Decoder = ""; Joiner = ""; } } public struct OnlineZipformer2CtcModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public OnlineZipformer2CtcModelConfig() { Model = ""; } } public struct SileroVadModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public float Threshold; public float MinSilenceDuration; public float MinSpeechDuration; public int WindowSize; public float MaxSpeechDuration; public SileroVadModelConfig() { Model = ""; Threshold = 0.5f; MinSilenceDuration = 0.5f; MinSpeechDuration = 0.25f; WindowSize = 512; MaxSpeechDuration = 5f; } } public class SourceSeparationOutput : IDisposable { private struct StemImpl { public IntPtr Samples; public int NumChannels; public int N; } private struct Impl { public IntPtr Stems; public int NumStems; public int SampleRate; } private HandleRef _handle; public int SampleRate { get { if (Handle == IntPtr.Zero) { return 0; } return ((Impl)Marshal.PtrToStructure(Handle, typeof(Impl))).SampleRate; } } public int NumStems { get { if (Handle == IntPtr.Zero) { return 0; } return ((Impl)Marshal.PtrToStructure(Handle, typeof(Impl))).NumStems; } } public IntPtr Handle => _handle.Handle; public SourceSeparationOutput(IntPtr p) { _handle = new HandleRef(this, p); } public float[][] GetStemSamples(int stemIndex) { if (Handle == IntPtr.Zero) { return new float[0][]; } Impl impl = (Impl)Marshal.PtrToStructure(Handle, typeof(Impl)); if (stemIndex < 0 || stemIndex >= impl.NumStems) { return new float[0][]; } int num = Marshal.SizeOf(typeof(StemImpl)); StemImpl obj = (StemImpl)Marshal.PtrToStructure(new IntPtr(impl.Stems.ToInt64() + stemIndex * num), typeof(StemImpl)); int numChannels = obj.NumChannels; int n = obj.N; float[][] array = new float[numChannels][]; IntPtr[] array2 = new IntPtr[numChannels]; Marshal.Copy(obj.Samples, array2, 0, numChannels); for (int i = 0; i < numChannels; i++) { array[i] = new float[n]; Marshal.Copy(array2[i], array[i], 0, n); } return array; } public bool SaveStemToWaveFile(int stemIndex, string filename) { if (Handle == IntPtr.Zero) { return false; } Impl impl = (Impl)Marshal.PtrToStructure(Handle, typeof(Impl)); if (stemIndex < 0 || stemIndex >= impl.NumStems) { return false; } int num = Marshal.SizeOf(typeof(StemImpl)); StemImpl stemImpl = (StemImpl)Marshal.PtrToStructure(new IntPtr(impl.Stems.ToInt64() + stemIndex * num), typeof(StemImpl)); byte[] bytes = Encoding.UTF8.GetBytes(filename); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; return SherpaOnnxWriteWaveMultiChannel(stemImpl.Samples, stemImpl.N, impl.SampleRate, stemImpl.NumChannels, array) == 1; } ~SourceSeparationOutput() { Cleanup(); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } private void Cleanup() { if (Handle != IntPtr.Zero) { SherpaOnnxDestroySourceSeparationOutput(Handle); } _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroySourceSeparationOutput(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxWriteWaveMultiChannel(IntPtr samples, int n, int sample_rate, int num_channels, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Filename); } public class SpeakerEmbeddingExtractor : IDisposable { private HandleRef _handle; public int Dim => SherpaOnnxSpeakerEmbeddingExtractorDim(_handle.Handle); public SpeakerEmbeddingExtractor(SpeakerEmbeddingExtractorConfig config) { IntPtr handle = SherpaOnnxCreateSpeakerEmbeddingExtractor(ref config); _handle = new HandleRef(this, handle); } public OnlineStream CreateStream() { return new OnlineStream(SherpaOnnxSpeakerEmbeddingExtractorCreateStream(_handle.Handle)); } public bool IsReady(OnlineStream stream) { return SherpaOnnxSpeakerEmbeddingExtractorIsReady(_handle.Handle, stream.Handle) != 0; } public float[] Compute(OnlineStream stream) { IntPtr intPtr = SherpaOnnxSpeakerEmbeddingExtractorComputeEmbedding(_handle.Handle, stream.Handle); int dim = Dim; float[] array = new float[dim]; Marshal.Copy(intPtr, array, 0, dim); SherpaOnnxSpeakerEmbeddingExtractorDestroyEmbedding(intPtr); return array; } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~SpeakerEmbeddingExtractor() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroySpeakerEmbeddingExtractor(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateSpeakerEmbeddingExtractor(ref SpeakerEmbeddingExtractorConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroySpeakerEmbeddingExtractor(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxSpeakerEmbeddingExtractorDim(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxSpeakerEmbeddingExtractorCreateStream(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxSpeakerEmbeddingExtractorIsReady(IntPtr handle, IntPtr stream); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxSpeakerEmbeddingExtractorComputeEmbedding(IntPtr handle, IntPtr stream); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxSpeakerEmbeddingExtractorDestroyEmbedding(IntPtr p); } public struct SpeakerEmbeddingExtractorConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public int NumThreads; public int Debug; [MarshalAs(UnmanagedType.LPStr)] public string Provider; public SpeakerEmbeddingExtractorConfig() { Model = ""; NumThreads = 1; Debug = 0; Provider = "cpu"; } } public class SpeakerEmbeddingManager : IDisposable { private HandleRef _handle; private int _dim; public int NumSpeakers => SherpaOnnxSpeakerEmbeddingManagerNumSpeakers(_handle.Handle); public SpeakerEmbeddingManager(int dim) { IntPtr handle = SherpaOnnxCreateSpeakerEmbeddingManager(dim); _handle = new HandleRef(this, handle); _dim = dim; } public bool Add(string name, float[] v) { byte[] bytes = Encoding.UTF8.GetBytes(name); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; return SherpaOnnxSpeakerEmbeddingManagerAdd(_handle.Handle, array, v) == 1; } public bool Add(string name, ICollection<float[]> v_list) { int count = v_list.Count; float[] array = new float[count * _dim]; int num = 0; foreach (float[] item in v_list) { item.CopyTo(array, num); num += _dim; } byte[] bytes = Encoding.UTF8.GetBytes(name); byte[] array2 = new byte[bytes.Length + 1]; Array.Copy(bytes, array2, bytes.Length); array2[bytes.Length] = 0; return SherpaOnnxSpeakerEmbeddingManagerAddListFlattened(_handle.Handle, array2, array, count) == 1; } public bool Remove(string name) { byte[] bytes = Encoding.UTF8.GetBytes(name); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; return SherpaOnnxSpeakerEmbeddingManagerRemove(_handle.Handle, array) == 1; } public unsafe string Search(float[] v, float threshold) { IntPtr intPtr = SherpaOnnxSpeakerEmbeddingManagerSearch(_handle.Handle, v, threshold); string result = ""; int num = 0; byte* ptr = (byte*)(void*)intPtr; if (ptr != null) { while (*ptr != 0) { ptr++; num++; } } if (num > 0) { byte[] array = new byte[num]; Marshal.Copy(intPtr, array, 0, num); result = Encoding.UTF8.GetString(array); } SherpaOnnxSpeakerEmbeddingManagerFreeSearch(intPtr); return result; } public bool Verify(string name, float[] v, float threshold) { byte[] bytes = Encoding.UTF8.GetBytes(name); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; return SherpaOnnxSpeakerEmbeddingManagerVerify(_handle.Handle, array, v, threshold) == 1; } public bool Contains(string name) { byte[] bytes = Encoding.UTF8.GetBytes(name); byte[] array = new byte[bytes.Length + 1]; Array.Copy(bytes, array, bytes.Length); array[bytes.Length] = 0; return SherpaOnnxSpeakerEmbeddingManagerContains(_handle.Handle, array) == 1; } public unsafe string[] GetAllSpeakers() { if (NumSpeakers == 0) { return new string[0]; } IntPtr intPtr = SherpaOnnxSpeakerEmbeddingManagerGetAllSpeakers(_handle.Handle); string[] array = new string[NumSpeakers]; byte** ptr = (byte**)(void*)intPtr; for (int i = 0; i != NumSpeakers; i++) { int num = 0; byte* ptr2 = ptr[i]; while (*ptr2 != 0) { ptr2++; num++; } byte[] array2 = new byte[num]; Marshal.Copy((IntPtr)ptr[i], array2, 0, num); array[i] = Encoding.UTF8.GetString(array2); } SherpaOnnxSpeakerEmbeddingManagerFreeAllSpeakers(intPtr); return array; } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~SpeakerEmbeddingManager() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroySpeakerEmbeddingManager(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateSpeakerEmbeddingManager(int dim); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroySpeakerEmbeddingManager(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxSpeakerEmbeddingManagerAdd(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Name, float[] v); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxSpeakerEmbeddingManagerAddListFlattened(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Name, float[] v, int n); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxSpeakerEmbeddingManagerRemove(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Name); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxSpeakerEmbeddingManagerSearch(IntPtr handle, float[] v, float threshold); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxSpeakerEmbeddingManagerFreeSearch(IntPtr p); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxSpeakerEmbeddingManagerVerify(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Name, float[] v, float threshold); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxSpeakerEmbeddingManagerContains(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Name); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxSpeakerEmbeddingManagerNumSpeakers(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxSpeakerEmbeddingManagerGetAllSpeakers(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxSpeakerEmbeddingManagerFreeAllSpeakers(IntPtr names); } public class SpeechSegment { private struct Impl { public long Start; public IntPtr Samples; public int Count; } public long _start; private float[] _samples; public long Start => _start; public float[] Samples => _samples; public unsafe SpeechSegment(IntPtr handle) { Impl impl = (Impl)Marshal.PtrToStructure(handle, typeof(Impl)); _start = impl.Start; float* ptr = (float*)(void*)impl.Samples; _samples = new float[impl.Count]; fixed (float* samples = _samples) { for (int i = 0; i < impl.Count; i++) { samples[i] = ptr[i]; } } } } public class SpokenLanguageIdentification : IDisposable { private HandleRef _handle; public SpokenLanguageIdentification(SpokenLanguageIdentificationConfig config) { IntPtr handle = SherpaOnnxCreateSpokenLanguageIdentification(ref config); _handle = new HandleRef(this, handle); } public OfflineStream CreateStream() { return new OfflineStream(SherpaOnnxSpokenLanguageIdentificationCreateOfflineStream(_handle.Handle)); } public SpokenLanguageIdentificationResult Compute(OfflineStream stream) { IntPtr handle = SherpaOnnxSpokenLanguageIdentificationCompute(_handle.Handle, stream.Handle); SpokenLanguageIdentificationResult result = new SpokenLanguageIdentificationResult(handle); SherpaOnnxDestroySpokenLanguageIdentificationResult(handle); return result; } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~SpokenLanguageIdentification() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroySpokenLanguageIdentification(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateSpokenLanguageIdentification(ref SpokenLanguageIdentificationConfig config); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroySpokenLanguageIdentification(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxSpokenLanguageIdentificationCreateOfflineStream(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxSpokenLanguageIdentificationCompute(IntPtr handle, IntPtr stream); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroySpokenLanguageIdentificationResult(IntPtr handle); } public struct SpokenLanguageIdentificationConfig { public SpokenLanguageIdentificationWhisperConfig Whisper; public int NumThreads; public int Debug; [MarshalAs(UnmanagedType.LPStr)] public string Provider; public SpokenLanguageIdentificationConfig() { Whisper = new SpokenLanguageIdentificationWhisperConfig(); NumThreads = 1; Debug = 0; Provider = "cpu"; } } public class SpokenLanguageIdentificationResult { private struct Impl { public IntPtr Lang; } private string _lang; public string Lang => _lang; public unsafe SpokenLanguageIdentificationResult(IntPtr handle) { Impl impl = (Impl)Marshal.PtrToStructure(handle, typeof(Impl)); int num = 0; byte* ptr = (byte*)(void*)impl.Lang; while (*ptr != 0) { ptr++; num++; } byte[] array = new byte[num]; Marshal.Copy(impl.Lang, array, 0, num); _lang = Encoding.UTF8.GetString(array); } } public struct SpokenLanguageIdentificationWhisperConfig { [MarshalAs(UnmanagedType.LPStr)] public string Encoder; [MarshalAs(UnmanagedType.LPStr)] public string Decoder; public int TailPaddings; public SpokenLanguageIdentificationWhisperConfig() { Encoder = ""; Decoder = ""; TailPaddings = -1; } } public struct TenVadModelConfig { [MarshalAs(UnmanagedType.LPStr)] public string Model; public float Threshold; public float MinSilenceDuration; public float MinSpeechDuration; public int WindowSize; public float MaxSpeechDuration; public TenVadModelConfig() { Model = ""; Threshold = 0.5f; MinSilenceDuration = 0.5f; MinSpeechDuration = 0.25f; WindowSize = 256; MaxSpeechDuration = 5f; } } public struct VadModelConfig { public SileroVadModelConfig SileroVad; public int SampleRate; public int NumThreads; [MarshalAs(UnmanagedType.LPStr)] public string Provider; public int Debug; public TenVadModelConfig TenVad; public VadModelConfig() { SileroVad = new SileroVadModelConfig(); SampleRate = 16000; NumThreads = 1; Provider = "cpu"; Debug = 0; TenVad = new TenVadModelConfig(); } } public class VersionInfo { public unsafe static string Version { get { IntPtr intPtr = SherpaOnnxGetVersionStr(); string result = ""; int num = 0; byte* ptr = (byte*)(void*)intPtr; if (ptr != null) { while (*ptr != 0) { ptr++; num++; } } if (num > 0) { byte[] array = new byte[num]; Marshal.Copy(intPtr, array, 0, num); result = Encoding.UTF8.GetString(array); } return result; } } public unsafe static string GitSha1 { get { IntPtr intPtr = SherpaOnnxGetGitSha1(); string result = ""; int num = 0; byte* ptr = (byte*)(void*)intPtr; if (ptr != null) { while (*ptr != 0) { ptr++; num++; } } if (num > 0) { byte[] array = new byte[num]; Marshal.Copy(intPtr, array, 0, num); result = Encoding.UTF8.GetString(array); } return result; } } public unsafe static string GitDate { get { IntPtr intPtr = SherpaOnnxGetGitDate(); string result = ""; int num = 0; byte* ptr = (byte*)(void*)intPtr; if (ptr != null) { while (*ptr != 0) { ptr++; num++; } } if (num > 0) { byte[] array = new byte[num]; Marshal.Copy(intPtr, array, 0, num); result = Encoding.UTF8.GetString(array); } return result; } } public unsafe static string OnnxruntimeVersion { get { IntPtr intPtr = SherpaOnnxGetOnnxruntimeVersionStr(); string result = ""; int num = 0; byte* ptr = (byte*)(void*)intPtr; if (ptr != null) { while (*ptr != 0) { ptr++; num++; } } if (num > 0) { byte[] array = new byte[num]; Marshal.Copy(intPtr, array, 0, num); result = Encoding.UTF8.GetString(array); } return result; } } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxGetVersionStr(); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxGetGitSha1(); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxGetGitDate(); [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxGetOnnxruntimeVersionStr(); } public class VoiceActivityDetector : IDisposable { private HandleRef _handle; public VoiceActivityDetector(VadModelConfig config, float bufferSizeInSeconds) { IntPtr handle = SherpaOnnxCreateVoiceActivityDetector(ref config, bufferSizeInSeconds); _handle = new HandleRef(this, handle); } public void AcceptWaveform(float[] samples) { SherpaOnnxVoiceActivityDetectorAcceptWaveform(_handle.Handle, samples, samples.Length); } public bool IsEmpty() { return SherpaOnnxVoiceActivityDetectorEmpty(_handle.Handle) == 1; } public bool IsSpeechDetected() { return SherpaOnnxVoiceActivityDetectorDetected(_handle.Handle) == 1; } public void Pop() { SherpaOnnxVoiceActivityDetectorPop(_handle.Handle); } public SpeechSegment Front() { IntPtr intPtr = SherpaOnnxVoiceActivityDetectorFront(_handle.Handle); SpeechSegment result = new SpeechSegment(intPtr); SherpaOnnxDestroySpeechSegment(intPtr); return result; } public void Clear() { SherpaOnnxVoiceActivityDetectorClear(_handle.Handle); } public void Reset() { SherpaOnnxVoiceActivityDetectorReset(_handle.Handle); } public void Flush() { SherpaOnnxVoiceActivityDetectorFlush(_handle.Handle); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } ~VoiceActivityDetector() { Cleanup(); } private void Cleanup() { SherpaOnnxDestroyVoiceActivityDetector(_handle.Handle); _handle = new HandleRef(this, IntPtr.Zero); } [DllImport("sherpa-onnx-c-api")] private static extern IntPtr SherpaOnnxCreateVoiceActivityDetector(ref VadModelConfig config, float bufferSizeInSeconds); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxDestroyVoiceActivityDetector(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern void SherpaOnnxVoiceActivityDetectorAcceptWaveform(IntPtr handle, float[] samples, int n); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxVoiceActivityDetectorEmpty(IntPtr handle); [DllImport("sherpa-onnx-c-api")] private static extern int SherpaOnnxVoiceActivityDetector