using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
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;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("TextToSpeech")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Azumatt")]
[assembly: AssemblyProduct("TextToSpeech")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace TextToSpeech
{
[HarmonyPatch(typeof(TextViewer), "ShowText")]
public static class TextViewerShowTextPatch
{
private static void Postfix(TextViewer __instance, Style style, string topic, string textId, bool autoHide)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected I4, but got Unknown
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)Player.m_localPlayer == (Object)null)
{
return;
}
UtilityMethods.GetPlayerAudioSource(out AudioSource playerSource);
if (!((Object)(object)playerSource == (Object)null))
{
string text;
string text2;
switch ((int)style)
{
case 0:
text = __instance.m_topic.text;
text2 = __instance.m_text.text;
break;
case 1:
text = __instance.m_introTopic.text;
text2 = __instance.m_introText.text;
break;
case 2:
text = __instance.m_ravenTopic.text;
text2 = __instance.m_ravenText.text;
break;
default:
text = Localization.instance.Localize(topic);
text2 = Localization.instance.Localize(textId);
break;
}
UtilityMethods.FireAndForget(TextToSpeechPlugin.Speak(UtilityMethods.StripRichText((topic.Length > 0) ? (text + " " + text2) : text2), playerSource));
}
}
}
[HarmonyPatch(typeof(Chat), "SetNpcText")]
public static class ShowRavenMessagesChatSetNpcTextPatch
{
private static void Postfix(Chat __instance, GameObject talker, Vector3 offset, float cullDistance, float ttl, string topic, string text, bool large)
{
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)Player.m_localPlayer == (Object)null))
{
UtilityMethods.GetPlayerAudioSource(out AudioSource playerSource);
if (!((Object)(object)playerSource == (Object)null))
{
UtilityMethods.FireAndForget(TextToSpeechPlugin.Speak((topic.Length > 0) ? UtilityMethods.StripRichText(Localization.instance.Localize(topic) + Localization.instance.Localize(text)) : UtilityMethods.StripRichText(Localization.instance.Localize(text)), playerSource, playAtPoint: true, talker.transform.position));
}
}
}
}
[HarmonyPatch(typeof(MessageHud), "ShowMessage")]
public static class MessageHudShowMessagePatch
{
private static void Postfix(MessageHud __instance, MessageType type, string text)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Invalid comparison between Unknown and I4
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)Player.m_localPlayer == (Object)null) && (int)type == 2)
{
UtilityMethods.GetPlayerAudioSource(out AudioSource playerSource);
if (!((Object)(object)playerSource == (Object)null))
{
UtilityMethods.FireAndForget(TextToSpeechPlugin.Speak(UtilityMethods.StripRichText(Localization.instance.Localize(text)), playerSource));
}
}
}
}
[HarmonyPatch(typeof(Terminal), "AddString", new Type[]
{
typeof(string),
typeof(string),
typeof(Type),
typeof(bool)
})]
public static class TerminalAddStringPatch
{
private static void Postfix(string user, string text, Type type, bool timestamp)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Expected I4, but got Unknown
//IL_009d: 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)
UtilityMethods.GetPlayerAudioSource(out AudioSource playerSource);
if (!((Object)(object)playerSource == (Object)null))
{
string text2 = (int)type switch
{
3 => "pinged",
2 => "shouted",
0 => "whispered",
_ => "said",
};
if (!(user == Player.m_localPlayer.GetPlayerName()) || !TextToSpeechPlugin.SkipSelf.Value.IsOn())
{
UtilityMethods.FireAndForget(TextToSpeechPlugin.Speak(UtilityMethods.StripRichText(user + " " + text2 + " in chat: " + text), playerSource));
}
}
}
}
[HarmonyPatch(typeof(DreamTexts), "GetRandomDreamText")]
public static class DreamTextsGetRandomDreamTextPatch
{
private static void Postfix(DreamTexts __instance, ref DreamText? __result)
{
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
if (__result != null && !((Object)(object)Player.m_localPlayer == (Object)null))
{
UtilityMethods.GetPlayerAudioSource(out AudioSource playerSource);
if (!((Object)(object)playerSource == (Object)null))
{
UtilityMethods.FireAndForget(TextToSpeechPlugin.Speak(UtilityMethods.StripRichText(Localization.instance.Localize(__result.m_text)), playerSource));
}
}
}
}
[HarmonyPatch(typeof(Player), "SetLocalPlayer")]
public static class PlayerSetLocalPlayerPatch
{
private static void Postfix(Player __instance)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)((Component)__instance).transform.Find("PiperTTS") != (Object)null))
{
GameObject val = new GameObject("PiperTTS");
AudioSource obj = val.AddComponent<AudioSource>();
obj.spatialBlend = 0f;
obj.dopplerLevel = 0f;
obj.rolloffMode = (AudioRolloffMode)1;
obj.minDistance = 1f;
obj.maxDistance = 100f;
obj.ignoreListenerVolume = true;
obj.ignoreListenerPause = true;
obj.bypassEffects = true;
obj.bypassReverbZones = true;
val.transform.SetParent(((Component)__instance).transform);
}
}
}
[BepInPlugin("Azumatt.TextToSpeech", "TextToSpeech", "1.0.0")]
public class TextToSpeechPlugin : BaseUnityPlugin
{
public enum Toggle
{
On = 1,
Off = 0
}
internal const string ModName = "TextToSpeech";
internal const string ModVersion = "1.0.0";
internal const string Author = "Azumatt";
private const string ModGUID = "Azumatt.TextToSpeech";
private static string ConfigFileName = "Azumatt.TextToSpeech.cfg";
private static string ConfigFileFullPath;
internal static string ConnectionError;
private readonly Harmony _harmony = new Harmony("Azumatt.TextToSpeech");
public static readonly ManualLogSource TextToSpeechLogger;
private FileSystemWatcher _watcher;
private readonly object _reloadLock = new object();
private DateTime _lastConfigReloadTime;
private const long RELOAD_DELAY = 10000000L;
private static readonly HttpClient httpClient;
private const string PiperZipUrl = "https://github.com/rhasspy/piper/releases/download/2023.11.14-2/piper_windows_amd64.zip";
private string _voiceModelConfigUrl = string.Empty;
private static string _voiceModelConfigPath;
private string _modDirectory = string.Empty;
private string _piperFolder = string.Empty;
private string _piperZipPath = string.Empty;
private static string _piperExePath;
private static string _voiceModelPath;
internal static ConfigEntry<string> VoiceModelUrl;
internal static ConfigEntry<Toggle> SkipSelf;
public async void Awake()
{
bool saveOnSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
VoiceModelUrl = config("1 - General", "Voice Model URL", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/alba/medium/en_GB-alba-medium.onnx", "URL for the voice model file.");
SkipSelf = config("1 - Preferences", "Skip Self In Chat", Toggle.On, "Do not TTS your own messages in chat.");
_voiceModelConfigUrl = VoiceModelUrl.Value.Replace("?download=true", string.Empty) + ".json";
_modDirectory = ((!string.IsNullOrEmpty(((BaseUnityPlugin)this).Info.Location)) ? Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) : Environment.CurrentDirectory);
_piperFolder = Path.Combine(_modDirectory, "Piper");
Directory.CreateDirectory(_piperFolder);
UpdateVoiceModelPaths();
VoiceModelUrl.SettingChanged += delegate
{
UpdateVoiceModelPaths();
EnsureVoiceModel();
EnsureVoiceModelConfig();
};
_piperZipPath = Path.Combine(_piperFolder, "piper_windows_amd64.zip");
_piperExePath = Path.Combine(_piperFolder, "piper", "piper.exe");
await EnsurePiperFiles();
await EnsureVoiceModel();
await EnsureVoiceModelConfig();
Assembly executingAssembly = Assembly.GetExecutingAssembly();
_harmony.PatchAll(executingAssembly);
SetupWatcher();
((BaseUnityPlugin)this).Config.Save();
if (saveOnSet)
{
((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnSet;
}
}
private async Task EnsurePiperFiles()
{
if (!File.Exists(_piperExePath))
{
TextToSpeechLogger.LogInfo((object)"Piper executable not found. Downloading Piper zip...");
await DownloadFile("https://github.com/rhasspy/piper/releases/download/2023.11.14-2/piper_windows_amd64.zip", _piperZipPath);
TextToSpeechLogger.LogInfo((object)"Extracting Piper zip...");
try
{
ZipFile.ExtractToDirectory(_piperZipPath, _piperFolder);
TextToSpeechLogger.LogInfo((object)"Piper extracted successfully.");
File.Delete(_piperZipPath);
return;
}
catch (Exception ex)
{
TextToSpeechLogger.LogError((object)("Failed to extract Piper: " + ex.Message));
return;
}
}
TextToSpeechLogger.LogInfo((object)"Piper already exists.");
}
private async Task EnsureVoiceModel()
{
if (!File.Exists(_voiceModelPath))
{
TextToSpeechLogger.LogInfo((object)"Voice model not found. Downloading voice model...");
await DownloadFile(VoiceModelUrl.Value, _voiceModelPath);
}
else
{
TextToSpeechLogger.LogInfo((object)"Voice model already exists.");
}
}
private async Task EnsureVoiceModelConfig()
{
if (!File.Exists(_voiceModelConfigPath))
{
TextToSpeechLogger.LogInfo((object)"Voice model config not found. Downloading voice model config...");
await DownloadFile(_voiceModelConfigUrl, _voiceModelConfigPath);
}
else
{
TextToSpeechLogger.LogInfo((object)"Voice model config already exists.");
}
}
private async Task DownloadFile(string url, string destinationPath)
{
try
{
File.WriteAllBytes(destinationPath, await httpClient.GetByteArrayAsync(url));
TextToSpeechLogger.LogInfo((object)("Downloaded file from " + url + " to " + destinationPath));
}
catch (Exception ex)
{
TextToSpeechLogger.LogError((object)("Failed to download file from " + url + ": " + ex.Message));
}
}
private void UpdateVoiceModelPaths()
{
if (Uri.TryCreate(VoiceModelUrl.Value, UriKind.Absolute, out Uri result))
{
string fileName = Path.GetFileName(result.LocalPath);
if (string.IsNullOrEmpty(fileName))
{
TextToSpeechLogger.LogError((object)("Failed to extract file name from URL: " + VoiceModelUrl.Value));
return;
}
_voiceModelPath = Path.Combine(_piperFolder, fileName);
_voiceModelConfigPath = Path.Combine(_piperFolder, fileName + ".json");
_voiceModelConfigUrl = VoiceModelUrl.Value.Replace("?download=true", string.Empty) + ".json";
TextToSpeechLogger.LogDebug((object)("Updated voice model path to: " + _voiceModelPath + " and config path to: " + _voiceModelConfigPath));
}
else
{
TextToSpeechLogger.LogError((object)("Invalid voice model URL: " + VoiceModelUrl.Value));
}
}
public static async Task Speak(string text, AudioSource? targetSource = null, bool playAtPoint = false, Vector3 position = default(Vector3))
{
//IL_0026: 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)
_ = 1;
try
{
string tempWavPath = Path.Combine(Path.GetTempPath(), $"piper_tts_{Guid.NewGuid()}.wav");
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = _piperExePath;
processStartInfo.Arguments = "--model \"" + _voiceModelPath + "\" --model_config \"" + _voiceModelConfigPath + "\" --output_file \"" + tempWavPath + "\"";
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.UseShellExecute = false;
processStartInfo.CreateNoWindow = true;
ProcessStartInfo startInfo = processStartInfo;
using (Process p = new Process
{
StartInfo = startInfo
})
{
p.Start();
await p.StandardInput.WriteLineAsync(text);
p.StandardInput.Close();
string text2 = await p.StandardError.ReadToEndAsync();
p.WaitForExit();
if (!string.IsNullOrEmpty(text2))
{
if (!text2.Contains("[info]"))
{
TextToSpeechLogger.LogError((object)("Piper error: " + text2));
}
else
{
TextToSpeechLogger.LogDebug((object)("Piper info: " + text2));
}
}
}
if (File.Exists(tempWavPath))
{
PlayAudio(File.ReadAllBytes(tempWavPath), targetSource, playAtPoint, position);
File.Delete(tempWavPath);
}
else
{
TextToSpeechLogger.LogError((object)"Temporary WAV file was not created.");
}
}
catch (Exception ex)
{
TextToSpeechLogger.LogError((object)("Error in Piper TTS: " + ex.Message));
}
}
private static void PlayAudio(byte[] audioData, AudioSource? targetSource = null, bool playAtPoint = false, Vector3 position = default(Vector3))
{
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Expected O, but got Unknown
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
AudioClip val = WavUtility.ToAudioClip(audioData);
if ((Object)(object)val == (Object)null)
{
return;
}
if ((Object)(object)targetSource != (Object)null)
{
targetSource.clip = val;
if (playAtPoint)
{
UtilityMethods.PlayOneShotAtPointWithBypass(targetSource.clip, (position == default(Vector3)) ? ((Component)targetSource).transform.position : position, targetSource);
}
else
{
targetSource.Play();
}
}
else
{
GameObject val2 = new GameObject("PiperTTS");
AudioSource obj = val2.AddComponent<AudioSource>();
obj.clip = val;
obj.Play();
Object.Destroy((Object)val2, val.length);
}
}
private static void PlayRawAudio(byte[] rawData)
{
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Expected O, but got Unknown
int num = rawData.Length / 2;
float[] array = new float[num];
for (int i = 0; i < num; i++)
{
short num2 = BitConverter.ToInt16(rawData, i * 2);
array[i] = (float)num2 / 32768f;
}
AudioClip val = AudioClip.Create("PiperTTS", num, 1, 22050, false);
val.SetData(array, 0);
GameObject val2 = new GameObject("PiperTTS");
AudioSource obj = val2.AddComponent<AudioSource>();
obj.clip = val;
obj.Play();
Object.Destroy((Object)val2, val.length);
}
private static void PlayAudio(byte[] audioData)
{
//IL_001c: 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)
//IL_003e: Expected O, but got Unknown
AudioClip val = WavUtility.ToAudioClip(audioData);
if (!((Object)(object)val == (Object)null))
{
GameObject val2 = new GameObject("PiperTTS");
AudioSource obj = val2.AddComponent<AudioSource>();
obj.clip = val;
obj.Play();
Object.Destroy((Object)val2, val.length);
}
}
private void OnDestroy()
{
SaveWithRespectToConfigSet();
_watcher?.Dispose();
}
private void SetupWatcher()
{
_watcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
_watcher.Changed += ReadConfigValues;
_watcher.Created += ReadConfigValues;
_watcher.Renamed += ReadConfigValues;
_watcher.IncludeSubdirectories = true;
_watcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
_watcher.EnableRaisingEvents = true;
}
private void ReadConfigValues(object sender, FileSystemEventArgs e)
{
DateTime now = DateTime.Now;
if (now.Ticks - _lastConfigReloadTime.Ticks < 10000000)
{
return;
}
lock (_reloadLock)
{
if (!File.Exists(ConfigFileFullPath))
{
TextToSpeechLogger.LogWarning((object)"Config file does not exist. Skipping reload.");
return;
}
try
{
TextToSpeechLogger.LogDebug((object)"Reloading configuration...");
SaveWithRespectToConfigSet(reload: true);
TextToSpeechLogger.LogInfo((object)"Configuration reload complete.");
}
catch (Exception ex)
{
TextToSpeechLogger.LogError((object)("Error reloading configuration: " + ex.Message));
}
}
_lastConfigReloadTime = now;
}
private void SaveWithRespectToConfigSet(bool reload = false)
{
bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
if (reload)
{
((BaseUnityPlugin)this).Config.Reload();
}
((BaseUnityPlugin)this).Config.Save();
if (saveOnConfigSet)
{
((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
}
}
private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description)
{
return ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, description);
}
private ConfigEntry<T> config<T>(string group, string name, T value, string description)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
}
static TextToSpeechPlugin()
{
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Expected O, but got Unknown
string configPath = Paths.ConfigPath;
char directorySeparatorChar = Path.DirectorySeparatorChar;
ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
ConnectionError = "";
TextToSpeechLogger = Logger.CreateLogSource("TextToSpeech");
httpClient = new HttpClient();
_voiceModelConfigPath = string.Empty;
_piperExePath = string.Empty;
_voiceModelPath = string.Empty;
VoiceModelUrl = null;
SkipSelf = null;
}
}
public static class ToggleExtensions
{
public static bool IsOn(this TextToSpeechPlugin.Toggle toggle)
{
return toggle == TextToSpeechPlugin.Toggle.On;
}
public static bool IsOff(this TextToSpeechPlugin.Toggle toggle)
{
return toggle == TextToSpeechPlugin.Toggle.Off;
}
}
public abstract class UtilityMethods
{
public static void GetPlayerAudioSource(out AudioSource? playerSource)
{
Player localPlayer = Player.m_localPlayer;
object obj;
if (localPlayer == null)
{
obj = null;
}
else
{
Transform obj2 = ((Component)localPlayer).transform.Find("PiperTTS");
obj = ((obj2 != null) ? ((Component)obj2).GetComponent<AudioSource>() : null);
}
playerSource = (AudioSource?)obj;
if ((Object)(object)playerSource == (Object)null)
{
TextToSpeechPlugin.TextToSpeechLogger.LogError((object)"Player AudioSource not found.");
}
}
public static string StripRichText(string input)
{
if (!string.IsNullOrEmpty(input))
{
return Regex.Replace(input, "<[^>]+>", string.Empty, RegexOptions.IgnoreCase | RegexOptions.Compiled);
}
return input;
}
public static void FireAndForget(Task task)
{
task.ContinueWith(delegate(Task t)
{
if (t.Exception != null)
{
TextToSpeechPlugin.TextToSpeechLogger.LogError((object)t.Exception);
}
}, TaskContinuationOptions.OnlyOnFaulted);
}
public static void PlayOneShotAtPointWithBypass(AudioClip clip, Vector3 position, AudioSource? targetSource = null)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Expected O, but got Unknown
if (!((Object)(object)clip == (Object)null) && !((Object)(object)targetSource == (Object)null))
{
GameObject val = new GameObject("TTSOneShotAudioAtPoint");
val.transform.position = ((position == default(Vector3)) ? ((Component)targetSource).transform.position : position);
AudioSource obj = val.AddComponent<AudioSource>();
obj.clip = clip;
obj.spatialBlend = 1f;
obj.bypassReverbZones = true;
obj.bypassListenerEffects = true;
obj.bypassEffects = true;
obj.volume = 1f;
obj.Play();
Object.Destroy((Object)val, clip.length * (((double)Time.timeScale < 0.009999999776482582) ? 0.01f : Time.timeScale));
}
}
}
public static class WavUtility
{
public static AudioClip? ToAudioClip(byte[] wavFile, string clipName = "wavClip", bool streaming = false)
{
if (wavFile == null || wavFile.Length < 44)
{
Debug.LogError((object)"Invalid or empty WAV file provided.");
return null;
}
int num = BitConverter.ToInt16(wavFile, 22);
int num2 = BitConverter.ToInt32(wavFile, 24);
int num3 = BitConverter.ToInt16(wavFile, 34);
int i;
int num4;
for (i = 12; i + 8 < wavFile.Length; i += 8 + num4)
{
string @string = Encoding.ASCII.GetString(wavFile, i, 4);
num4 = BitConverter.ToInt32(wavFile, i + 4);
if (@string == "data")
{
i += 8;
break;
}
}
if (i >= wavFile.Length)
{
Debug.LogError((object)"Data chunk not found in WAV file.");
return null;
}
int num5 = (wavFile.Length - i) / (num3 / 8);
int num6 = num5 / num;
float[] array = new float[num5];
switch (num3)
{
case 16:
{
for (int k = 0; k < num5; k++)
{
short num7 = BitConverter.ToInt16(wavFile, i + k * 2);
array[k] = (float)num7 / 32768f;
}
break;
}
case 8:
{
for (int j = 0; j < num5; j++)
{
byte b = wavFile[i + j];
array[j] = (float)(b - 128) / 128f;
}
break;
}
default:
Debug.LogError((object)"WavUtility supports only 8-bit and 16-bit audio formats.");
return null;
}
AudioClip obj = AudioClip.Create(clipName, num6, num, num2, streaming);
obj.SetData(array, 0);
return obj;
}
}
}