Decompiled source of SemiBoombox v1.2.0

SemiBoombox.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Microsoft.Win32;
using NAudio.CoreAudioApi;
using NAudio.CoreAudioApi.Interfaces;
using NAudio.Dmo;
using NAudio.Dmo.Effect;
using NAudio.Dsp;
using NAudio.FileFormats.Wav;
using NAudio.MediaFoundation;
using NAudio.Mixer;
using NAudio.Utils;
using NAudio.Wasapi.CoreAudioApi;
using NAudio.Wasapi.CoreAudioApi.Interfaces;
using NAudio.Wave;
using NAudio.Wave.Asio;
using NAudio.Wave.Compression;
using NAudio.Wave.SampleProviders;
using Photon.Pun;
using Photon.Realtime;
using SemiBoombox.Utils;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("SemiBoombox")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0+4baf32f067d47e44bc937b32bdd9d13ee3aa6988")]
[assembly: AssemblyProduct("Semi Boombox")]
[assembly: AssemblyTitle("SemiBoombox")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SemiBoombox
{
	public class Boombox : MonoBehaviour
	{
		public PhotonView photonView;

		public AudioSource audioSource;

		private static Dictionary<string, AudioClip> downloadedClips = new Dictionary<string, AudioClip>();

		private static Dictionary<string, HashSet<int>> downloadsReady = new Dictionary<string, HashSet<int>>();

		public static Dictionary<string, string> downloadedSongs = new Dictionary<string, string>();

		private bool isDownloading;

		private static Dictionary<int, Boombox> _boomboxCache = new Dictionary<int, Boombox>();

		public static Dictionary<int, Boombox> BoomboxCache
		{
			get
			{
				if (IsCacheInvalid())
				{
					RefreshBoomboxCache();
				}
				return _boomboxCache;
			}
		}

		private void Awake()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
			audioSource.spatialBlend = 1f;
			audioSource.playOnAwake = false;
			audioSource.minDistance = 1f;
			audioSource.maxDistance = 30f;
			audioSource.rolloffMode = (AudioRolloffMode)2;
			AnimationCurve val = new AnimationCurve();
			val.AddKey(1f, 1f);
			val.AddKey(30f, 0f);
			audioSource.SetCustomCurve((AudioSourceCurveType)0, val);
			photonView = ((Component)this).GetComponent<PhotonView>();
			if ((Object)(object)photonView == (Object)null)
			{
				Debug.LogError((object)"PhotonView not found on Boombox object.");
			}
			else if (photonView.IsMine)
			{
				audioSource.volume = 0.1f;
				((Component)this).gameObject.AddComponent<BoomboxUI>();
			}
			else
			{
				audioSource.volume = 0.2f;
			}
		}

		[PunRPC]
		public async void RequestSong(string url, int requesterId)
		{
			Debug.Log((object)$"RequestSong RPC received: url={url}, requesterId={requesterId}");
			if (photonView.IsMine && isDownloading)
			{
				Debug.Log((object)"Already downloading a song. Please wait for the current download to finish.");
				return;
			}
			if (photonView.IsMine)
			{
				isDownloading = true;
			}
			if (!downloadedClips.ContainsKey(url))
			{
				try
				{
					string filePath = await Task.Run(() => YoutubeDL.DownloadAudioAsync(url));
					AudioClip val = await Task.Run(() => AudioConverter.GetAudioClipAsync(filePath));
					downloadedClips[url] = val;
					Debug.Log((object)("Downloaded and cached clip for url: " + url));
					AddDownloadedSong(((Object)val).name, url);
				}
				catch (Exception ex)
				{
					Debug.LogError((object)("Failed to download audio: " + ex.Message));
					isDownloading = false;
					return;
				}
			}
			else
			{
				Debug.Log((object)("Clip already cached for url: " + url));
			}
			photonView.RPC("ReportDownloadComplete", (RpcTarget)0, new object[2]
			{
				PhotonNetwork.LocalPlayer.ActorNumber,
				url
			});
			await WaitForAllPlayersReady(url);
			photonView.RPC("SyncPlayback", (RpcTarget)0, new object[2] { url, requesterId });
			if (photonView.IsMine)
			{
				isDownloading = false;
			}
		}

		[PunRPC]
		public void ReportDownloadComplete(int actorNumber, string url)
		{
			if (!downloadsReady.ContainsKey(url))
			{
				downloadsReady[url] = new HashSet<int>();
			}
			downloadsReady[url].Add(actorNumber);
			Debug.Log((object)$"Player {actorNumber} reported ready for url: {url}. Total ready: {downloadsReady[url].Count}");
		}

		private async Task WaitForAllPlayersReady(string url)
		{
			int totalPlayers = PhotonNetwork.PlayerList.Length;
			while (!downloadsReady.ContainsKey(url) || downloadsReady[url].Count < totalPlayers)
			{
				await Task.Delay(100);
			}
		}

		[PunRPC]
		public void SyncPlayback(string url, int requesterId)
		{
			if (photonView.Owner != null && photonView.Owner.ActorNumber == requesterId)
			{
				if (!downloadedClips.ContainsKey(url))
				{
					Debug.LogError((object)("Clip not found for url: " + url));
					return;
				}
				audioSource.clip = downloadedClips[url];
				audioSource.Play();
				Debug.Log((object)$"SyncPlayback RPC executed: url={url}, requesterId={requesterId}");
			}
		}

		[PunRPC]
		public void StopPlayback(int requesterId)
		{
			if (photonView.Owner != null && photonView.Owner.ActorNumber == requesterId)
			{
				Debug.Log((object)$"Stopping playback on Boombox owned by player {requesterId}");
				if (audioSource.isPlaying)
				{
					audioSource.Stop();
				}
			}
		}

		[PunRPC]
		public void SyncTime(float time, int requesterId)
		{
			if (photonView.Owner != null && photonView.Owner.ActorNumber == requesterId)
			{
				if (audioSource.isPlaying)
				{
					audioSource.time = time;
				}
				Debug.Log((object)$"Syncing time to {time} seconds, requesterId={requesterId}");
			}
		}

		private static bool IsCacheInvalid()
		{
			if (_boomboxCache == null || _boomboxCache.Count == 0)
			{
				return true;
			}
			foreach (KeyValuePair<int, Boombox> item in _boomboxCache)
			{
				if ((Object)(object)item.Value == (Object)null || (Object)(object)((Component)item.Value).gameObject == (Object)null)
				{
					return true;
				}
			}
			return false;
		}

		private static void RefreshBoomboxCache()
		{
			_boomboxCache.Clear();
			Boombox[] array = Object.FindObjectsOfType<Boombox>();
			foreach (Boombox boombox in array)
			{
				if (boombox.photonView.Owner != null)
				{
					int actorNumber = boombox.photonView.Owner.ActorNumber;
					_boomboxCache[actorNumber] = boombox;
				}
			}
		}

		private void AddDownloadedSong(string songName, string url)
		{
			if (!downloadedSongs.ContainsKey(songName))
			{
				downloadedSongs.Add(songName, url);
			}
		}
	}
	public class BoomboxUI : MonoBehaviour
	{
		public PhotonView photonView;

		private bool showUI;

		private string urlInput = "";

		private string urlFeedback = "";

		private float volume = 0.15f;

		private float currentPlaybackTime;

		private float totalPlaybackTime;

		private float lastSyncTime;

		private const float SYNC_COOLDOWN = 0.15f;

		private bool sliderLocked;

		private Rect windowRect = new Rect(100f, 100f, 400f, 500f);

		private Vector2 scrollPosition = Vector2.zero;

		private Boombox boombox;

		private void Awake()
		{
			boombox = ((Component)this).GetComponent<Boombox>();
			photonView = boombox.photonView;
		}

		private void Update()
		{
			if (Input.GetKeyDown((KeyCode)120))
			{
				showUI = !showUI;
				Cursor.visible = showUI;
				Cursor.lockState = (CursorLockMode)((!showUI) ? 1 : 0);
			}
			if ((Object)(object)boombox.audioSource != (Object)null && (Object)(object)boombox.audioSource.clip != (Object)null)
			{
				if (boombox.audioSource.isPlaying)
				{
					currentPlaybackTime = boombox.audioSource.time;
					totalPlaybackTime = boombox.audioSource.clip.length;
				}
				else
				{
					currentPlaybackTime = boombox.audioSource.time;
					totalPlaybackTime = boombox.audioSource.clip.length;
				}
			}
			else
			{
				currentPlaybackTime = 0f;
				totalPlaybackTime = 0f;
			}
		}

		private void OnGUI()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0021: 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)
			if (showUI)
			{
				windowRect = GUI.Window(0, windowRect, new WindowFunction(DrawUI), "Boombox Controller");
			}
		}

		private void DrawUI(int windowID)
		{
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.Label("Enter YouTube URL:", Array.Empty<GUILayoutOption>());
			urlInput = GUILayout.TextField(urlInput, 200, Array.Empty<GUILayoutOption>());
			GUILayout.Label(urlFeedback, Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			GUILayout.Label($"Volume: {Mathf.Round(volume * 100f)}%", Array.Empty<GUILayoutOption>());
			float num = GUILayout.HorizontalSlider(volume, 0f, 1f, Array.Empty<GUILayoutOption>());
			if (num != volume)
			{
				volume = num;
				foreach (Boombox value in Boombox.BoomboxCache.Values)
				{
					if ((Object)(object)value.audioSource != (Object)null)
					{
						value.audioSource.volume = volume;
					}
				}
			}
			GUILayout.Space(10f);
			GUILayout.Label("Current Time: " + FormatTime(currentPlaybackTime) + " / " + FormatTime(totalPlaybackTime), Array.Empty<GUILayoutOption>());
			sliderLocked = Time.time - lastSyncTime < 0.15f;
			if ((Object)(object)boombox.audioSource != (Object)null && boombox.audioSource.isPlaying)
			{
				GUI.enabled = !sliderLocked;
				float num2 = GUILayout.HorizontalSlider(currentPlaybackTime, 0f, totalPlaybackTime, Array.Empty<GUILayoutOption>());
				GUI.enabled = true;
				if (!sliderLocked && Mathf.Abs(num2 - currentPlaybackTime) > 0.1f)
				{
					lastSyncTime = Time.time;
					currentPlaybackTime = num2;
					photonView.RPC("SyncTime", (RpcTarget)0, new object[2]
					{
						currentPlaybackTime,
						PhotonNetwork.LocalPlayer.ActorNumber
					});
				}
			}
			GUILayout.Space(10f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Play", Array.Empty<GUILayoutOption>()))
			{
				if (IsValidUrl(urlInput, out var correctedUrl))
				{
					photonView.RPC("RequestSong", (RpcTarget)0, new object[2]
					{
						correctedUrl,
						PhotonNetwork.LocalPlayer.ActorNumber
					});
				}
				else
				{
					urlFeedback = "Invalid URL!";
					Debug.LogError((object)"Invalid URL!");
				}
			}
			if (GUILayout.Button("Stop", Array.Empty<GUILayoutOption>()))
			{
				photonView.RPC("StopPlayback", (RpcTarget)0, new object[1] { PhotonNetwork.LocalPlayer.ActorNumber });
			}
			if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>()))
			{
				showUI = false;
				Cursor.lockState = (CursorLockMode)1;
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(10f);
			GUILayout.Label("Downloaded Songs:", Array.Empty<GUILayoutOption>());
			scrollPosition = GUILayout.BeginScrollView(scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(200f) });
			foreach (KeyValuePair<string, string> downloadedSong in Boombox.downloadedSongs)
			{
				if (GUILayout.Button(downloadedSong.Key, Array.Empty<GUILayoutOption>()))
				{
					urlInput = downloadedSong.Value;
				}
			}
			GUILayout.EndScrollView();
			GUI.DragWindow();
		}

		private bool IsValidUrl(string url, out string correctedUrl)
		{
			string pattern = "^https?:\\/\\/(www\\.)?youtube\\.com\\/watch\\?v=[a-zA-Z0-9_-]+$";
			correctedUrl = url;
			if (Regex.IsMatch(url, pattern))
			{
				return true;
			}
			if (url.Contains("youtube") && url.Contains("watch?v="))
			{
				correctedUrl = "https://www.youtube.com/watch?v=" + url.Split(new string[1] { "watch?v=" }, StringSplitOptions.None)[1].Split(new char[1] { '&' })[0];
				urlFeedback = "URL fixed to: " + correctedUrl;
				return true;
			}
			return false;
		}

		private string FormatTime(float seconds)
		{
			TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
			return $"{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}";
		}
	}
	[BepInPlugin("SemiBoombox", "Semi Boombox", "1.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		private static Harmony _harmony;

		private void Awake()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"Plugin SemiBoombox is loaded!");
			Task.Run(delegate
			{
				YoutubeDL.InitializeAsync().Wait();
			});
			_harmony = new Harmony("SemiBoombox");
			_harmony.PatchAll();
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "SemiBoombox";

		public const string PLUGIN_NAME = "Semi Boombox";

		public const string PLUGIN_VERSION = "1.2.0";
	}
}
namespace SemiBoombox.Utils
{
	public static class AudioConverter
	{
		public static string ConvertM4AToWav(string inputFile)
		{
			string text = Path.ChangeExtension(inputFile, ".wav");
			using MediaFoundationReader mediaFoundationReader = new MediaFoundationReader(inputFile);
			using WaveFileWriter destination = new WaveFileWriter(text, mediaFoundationReader.WaveFormat);
			mediaFoundationReader.CopyTo(destination);
			return text;
		}

		public static async Task<AudioClip> WavToAudioClipAsync(string filePath)
		{
			byte[] wavBytes;
			using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
			{
				wavBytes = new byte[fileStream.Length];
				await fileStream.ReadAsync(wavBytes, 0, wavBytes.Length);
			}
			int num = 44;
			short num2 = BitConverter.ToInt16(wavBytes, 22);
			int num3 = BitConverter.ToInt32(wavBytes, 24);
			short num4 = BitConverter.ToInt16(wavBytes, 34);
			int num5 = wavBytes.Length - num;
			int num6 = num4 / 8;
			int num7 = num5 / num6;
			float[] array = new float[num7];
			if (num4 == 16)
			{
				for (int i = 0; i < num7; i++)
				{
					short num8 = BitConverter.ToInt16(wavBytes, num + i * num6);
					array[i] = (float)num8 / 32768f;
				}
				int num9 = num7 / num2;
				AudioClip obj = AudioClip.Create(Path.GetFileNameWithoutExtension(filePath), num9, (int)num2, num3, false);
				obj.SetData(array, 0);
				return obj;
			}
			throw new NotSupportedException("Only 16-bit PCM WAV files are supported in this example.");
		}

		public static async Task<AudioClip> GetAudioClipAsync(string filePath)
		{
			string wavFile = ConvertM4AToWav(filePath);
			AudioClip result = await WavToAudioClipAsync(wavFile);
			string directoryName = Path.GetDirectoryName(filePath);
			if (File.Exists(filePath))
			{
				File.Delete(filePath);
			}
			if (File.Exists(wavFile))
			{
				File.Delete(wavFile);
			}
			if (Directory.Exists(directoryName) && Directory.GetFileSystemEntries(directoryName).Length == 0)
			{
				Directory.Delete(directoryName);
			}
			return result;
		}
	}
	public static class YoutubeDL
	{
		private static readonly string baseFolder = Path.Combine(Directory.GetCurrentDirectory(), "SemiBoombox");

		private const string YTDLP_URL = "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe";

		private static readonly string ytDlpPath = Path.Combine(baseFolder, "yt-dlp.exe");

		private static bool _updateCheckDone = false;

		public static async Task InitializeAsync()
		{
			if (!Directory.Exists(baseFolder))
			{
				Directory.CreateDirectory(baseFolder);
			}
			if (_updateCheckDone)
			{
				return;
			}
			if (File.Exists(ytDlpPath))
			{
				try
				{
					Console.WriteLine("Updating yt-dlp using the --update command...");
					await RunUpdateCommandAsync();
				}
				catch (Exception ex)
				{
					Console.WriteLine("Error during yt-dlp self-update: " + ex.Message);
					File.Delete(ytDlpPath);
					await DownloadFileAsync("https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe", ytDlpPath);
				}
			}
			else
			{
				Console.WriteLine("yt-dlp not found. Downloading latest version...");
				await DownloadFileAsync("https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe", ytDlpPath);
			}
			_updateCheckDone = true;
			Console.WriteLine("yt-dlp is up to date.");
		}

		private static async Task RunUpdateCommandAsync()
		{
			ProcessStartInfo startInfo = new ProcessStartInfo
			{
				FileName = ytDlpPath,
				Arguments = "--update",
				RedirectStandardOutput = true,
				RedirectStandardError = true,
				UseShellExecute = false,
				CreateNoWindow = true
			};
			using Process updateProcess = Process.Start(startInfo) ?? throw new Exception("Failed to start yt-dlp update process.");
			await WaitForProcessExit(updateProcess);
		}

		private static Task WaitForProcessExit(Process process)
		{
			TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
			process.EnableRaisingEvents = true;
			process.Exited += delegate
			{
				tcs.TrySetResult(null);
			};
			if (process.HasExited)
			{
				tcs.TrySetResult(null);
			}
			return tcs.Task;
		}

		private static async Task DownloadFileAsync(string url, string destinationPath)
		{
			HttpClient client = new HttpClient();
			try
			{
				File.WriteAllBytes(destinationPath, await client.GetByteArrayAsync(url));
			}
			finally
			{
				((IDisposable)client)?.Dispose();
			}
		}

		public static async Task<string> DownloadAudioAsync(string videoUrl)
		{
			await InitializeAsync();
			string tempFolder = Path.Combine(baseFolder, Guid.NewGuid().ToString());
			Directory.CreateDirectory(tempFolder);
			Console.WriteLine("Downloading audio...");
			return await Task.Run(delegate
			{
				try
				{
					string arguments = "-f \"bestaudio[ext=m4a]\" -o \"" + Path.Combine(tempFolder, "%(title)s.%(ext)s") + "\" " + videoUrl;
					using (Process process = Process.Start(new ProcessStartInfo
					{
						FileName = ytDlpPath,
						Arguments = arguments,
						RedirectStandardOutput = true,
						RedirectStandardError = true,
						UseShellExecute = false,
						CreateNoWindow = true
					}))
					{
						if (process == null)
						{
							throw new Exception("Failed to start yt-dlp process.");
						}
						process.WaitForExit();
						if (process.ExitCode != 0)
						{
							string text = process.StandardError.ReadToEnd();
							throw new Exception("yt-dlp error: " + text);
						}
					}
					return Directory.GetFiles(tempFolder, "*.m4a").FirstOrDefault() ?? throw new Exception("Audio download failed.");
				}
				catch (Exception ex)
				{
					Directory.Delete(tempFolder, recursive: true);
					throw new Exception("Error downloading audio: " + ex.Message);
				}
			});
		}
	}
}
namespace SemiBoombox.Patches
{
	[HarmonyPatch(typeof(PlayerAvatar), "Awake")]
	public class PlayerAvatarPatch
	{
		private static void Postfix(PlayerAvatar __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<Boombox>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<Boombox>();
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatarTalkAnimation), "Update")]
	public class PlayerAvatarTalkAnimationPatch
	{
		private static Dictionary<int, Boombox> _boomboxCache = new Dictionary<int, Boombox>();

		private static void Postfix(PlayerAvatarTalkAnimation __instance)
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.objectToRotate == (Object)null || (Object)(object)__instance.playerAvatar == (Object)null)
			{
				return;
			}
			PhotonView photonView = __instance.playerAvatar.photonView;
			if (((photonView != null) ? photonView.Owner : null) == null)
			{
				return;
			}
			Boombox boombox = FindBoomboxForPlayer(__instance.playerAvatar.photonView.Owner.ActorNumber);
			if (!((Object)(object)boombox == (Object)null) && !((Object)(object)boombox.audioSource == (Object)null) && boombox.audioSource.isPlaying)
			{
				float audioLoudness = GetAudioLoudness(boombox.audioSource);
				if (!(audioLoudness < 0.005f))
				{
					float num = Mathf.Lerp(0f, 0f - __instance.rotationMaxAngle, audioLoudness * 4f);
					__instance.objectToRotate.transform.localRotation = Quaternion.Slerp(__instance.objectToRotate.transform.localRotation, Quaternion.Euler(num, 0f, 0f), 100f * Time.deltaTime);
				}
			}
		}

		private static Boombox FindBoomboxForPlayer(int actorNumber)
		{
			if (_boomboxCache.TryGetValue(actorNumber, out var value) && (Object)(object)value != (Object)null && (Object)(object)((Component)value).gameObject != (Object)null)
			{
				return value;
			}
			Boombox[] array = Object.FindObjectsOfType<Boombox>();
			foreach (Boombox boombox in array)
			{
				if (boombox != null)
				{
					PhotonView photonView = boombox.photonView;
					int? obj;
					if (photonView == null)
					{
						obj = null;
					}
					else
					{
						Player owner = photonView.Owner;
						obj = ((owner != null) ? new int?(owner.ActorNumber) : null);
					}
					if (obj == actorNumber)
					{
						_boomboxCache[actorNumber] = boombox;
						return boombox;
					}
				}
			}
			return null;
		}

		private static float GetAudioLoudness(AudioSource source)
		{
			float[] array = new float[1024];
			source.GetOutputData(array, 0);
			float num = 0f;
			float[] array2 = array;
			foreach (float num2 in array2)
			{
				num += Mathf.Abs(num2);
			}
			return num / (float)array.Length;
		}
	}
}
namespace NAudio.Wave
{
	public class AudioFileReader : WaveStream, ISampleProvider
	{
		private WaveStream readerStream;

		private readonly SampleChannel sampleChannel;

		private readonly int destBytesPerSample;

		private readonly int sourceBytesPerSample;

		private readonly long length;

		private readonly object lockObject;

		public string FileName { get; }

		public override WaveFormat WaveFormat => sampleChannel.WaveFormat;

		public override long Length => length;

		public override long Position
		{
			get
			{
				return SourceToDest(readerStream.Position);
			}
			set
			{
				lock (lockObject)
				{
					readerStream.Position = DestToSource(value);
				}
			}
		}

		public float Volume
		{
			get
			{
				return sampleChannel.Volume;
			}
			set
			{
				sampleChannel.Volume = value;
			}
		}

		public AudioFileReader(string fileName)
		{
			lockObject = new object();
			FileName = fileName;
			CreateReaderStream(fileName);
			sourceBytesPerSample = readerStream.WaveFormat.BitsPerSample / 8 * readerStream.WaveFormat.Channels;
			sampleChannel = new SampleChannel(readerStream, forceStereo: false);
			destBytesPerSample = 4 * sampleChannel.WaveFormat.Channels;
			length = SourceToDest(readerStream.Length);
		}

		private void CreateReaderStream(string fileName)
		{
			if (fileName.EndsWith(".wav", StringComparison.OrdinalIgnoreCase))
			{
				readerStream = new WaveFileReader(fileName);
				if (readerStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm && readerStream.WaveFormat.Encoding != WaveFormatEncoding.IeeeFloat)
				{
					readerStream = WaveFormatConversionStream.CreatePcmStream(readerStream);
					readerStream = new BlockAlignReductionStream(readerStream);
				}
			}
			else if (fileName.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase))
			{
				if (Environment.OSVersion.Version.Major < 6)
				{
					readerStream = new Mp3FileReader(fileName);
				}
				else
				{
					readerStream = new MediaFoundationReader(fileName);
				}
			}
			else if (fileName.EndsWith(".aiff", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".aif", StringComparison.OrdinalIgnoreCase))
			{
				readerStream = new AiffFileReader(fileName);
			}
			else
			{
				readerStream = new MediaFoundationReader(fileName);
			}
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			WaveBuffer waveBuffer = new WaveBuffer(buffer);
			int count2 = count / 4;
			return Read(waveBuffer.FloatBuffer, offset / 4, count2) * 4;
		}

		public int Read(float[] buffer, int offset, int count)
		{
			lock (lockObject)
			{
				return sampleChannel.Read(buffer, offset, count);
			}
		}

		private long SourceToDest(long sourceBytes)
		{
			return destBytesPerSample * (sourceBytes / sourceBytesPerSample);
		}

		private long DestToSource(long destBytes)
		{
			return sourceBytesPerSample * (destBytes / destBytesPerSample);
		}

		protected override void Dispose(bool disposing)
		{
			if (disposing && readerStream != null)
			{
				readerStream.Dispose();
				readerStream = null;
			}
			base.Dispose(disposing);
		}
	}
	public class Mp3FileReader : Mp3FileReaderBase
	{
		public Mp3FileReader(string mp3FileName)
			: base(File.OpenRead(mp3FileName), CreateAcmFrameDecompressor, ownInputStream: true)
		{
		}

		public Mp3FileReader(Stream inputStream)
			: base(inputStream, CreateAcmFrameDecompressor, ownInputStream: false)
		{
		}

		public static IMp3FrameDecompressor CreateAcmFrameDecompressor(WaveFormat mp3Format)
		{
			return new AcmMp3FrameDecompressor(mp3Format);
		}
	}
	public class AsioAudioAvailableEventArgs : EventArgs
	{
		public IntPtr[] InputBuffers { get; private set; }

		public IntPtr[] OutputBuffers { get; private set; }

		public bool WrittenToOutputBuffers { get; set; }

		public int SamplesPerBuffer { get; private set; }

		public AsioSampleType AsioSampleType { get; private set; }

		public AsioAudioAvailableEventArgs(IntPtr[] inputBuffers, IntPtr[] outputBuffers, int samplesPerBuffer, AsioSampleType asioSampleType)
		{
			InputBuffers = inputBuffers;
			OutputBuffers = outputBuffers;
			SamplesPerBuffer = samplesPerBuffer;
			AsioSampleType = asioSampleType;
		}

		public unsafe int GetAsInterleavedSamples(float[] samples)
		{
			int num = InputBuffers.Length;
			if (samples.Length < SamplesPerBuffer * num)
			{
				throw new ArgumentException("Buffer not big enough");
			}
			int num2 = 0;
			if (AsioSampleType == AsioSampleType.Int32LSB)
			{
				for (int i = 0; i < SamplesPerBuffer; i++)
				{
					for (int j = 0; j < num; j++)
					{
						samples[num2++] = (float)(*(int*)((byte*)(void*)InputBuffers[j] + (nint)i * (nint)4)) / 2.1474836E+09f;
					}
				}
			}
			else if (AsioSampleType == AsioSampleType.Int16LSB)
			{
				for (int k = 0; k < SamplesPerBuffer; k++)
				{
					for (int l = 0; l < num; l++)
					{
						samples[num2++] = (float)(*(short*)((byte*)(void*)InputBuffers[l] + (nint)k * (nint)2)) / 32767f;
					}
				}
			}
			else if (AsioSampleType == AsioSampleType.Int24LSB)
			{
				for (int m = 0; m < SamplesPerBuffer; m++)
				{
					for (int n = 0; n < num; n++)
					{
						byte* ptr = (byte*)(void*)InputBuffers[n] + m * 3;
						int num3 = *ptr | (ptr[1] << 8) | ((sbyte)ptr[2] << 16);
						samples[num2++] = (float)num3 / 8388608f;
					}
				}
			}
			else
			{
				if (AsioSampleType != AsioSampleType.Float32LSB)
				{
					throw new NotImplementedException($"ASIO Sample Type {AsioSampleType} not supported");
				}
				for (int num4 = 0; num4 < SamplesPerBuffer; num4++)
				{
					for (int num5 = 0; num5 < num; num5++)
					{
						samples[num2++] = *(float*)((byte*)(void*)InputBuffers[num5] + (nint)num4 * (nint)4);
					}
				}
			}
			return SamplesPerBuffer * num;
		}

		[Obsolete("Better performance if you use the overload that takes an array, and reuse the same one")]
		public float[] GetAsInterleavedSamples()
		{
			int num = InputBuffers.Length;
			float[] array = new float[SamplesPerBuffer * num];
			GetAsInterleavedSamples(array);
			return array;
		}
	}
	public class AsioOut : IWavePlayer, IDisposable
	{
		private AsioDriverExt driver;

		private IWaveProvider sourceStream;

		private PlaybackState playbackState;

		private int nbSamples;

		private byte[] waveBuffer;

		private AsioSampleConvertor.SampleConvertor convertor;

		private string driverName;

		private readonly SynchronizationContext syncContext;

		private bool isInitialized;

		public int PlaybackLatency
		{
			get
			{
				driver.Driver.GetLatencies(out var _, out var outputLatency);
				return outputLatency;
			}
		}

		public bool AutoStop { get; set; }

		public bool HasReachedEnd { get; private set; }

		public PlaybackState PlaybackState => playbackState;

		public string DriverName => driverName;

		public int NumberOfOutputChannels { get; private set; }

		public int NumberOfInputChannels { get; private set; }

		public int DriverInputChannelCount => driver.Capabilities.NbInputChannels;

		public int DriverOutputChannelCount => driver.Capabilities.NbOutputChannels;

		public int FramesPerBuffer
		{
			get
			{
				if (!isInitialized)
				{
					throw new Exception("Not initialized yet. Call this after calling Init");
				}
				return nbSamples;
			}
		}

		public int ChannelOffset { get; set; }

		public int InputChannelOffset { get; set; }

		[Obsolete("this function will be removed in a future NAudio as ASIO does not support setting the volume on the device")]
		public float Volume
		{
			get
			{
				return 1f;
			}
			set
			{
				if (value != 1f)
				{
					throw new InvalidOperationException("AsioOut does not support setting the device volume");
				}
			}
		}

		public WaveFormat OutputWaveFormat { get; private set; }

		public event EventHandler<StoppedEventArgs> PlaybackStopped;

		public event EventHandler<AsioAudioAvailableEventArgs> AudioAvailable;

		public event EventHandler DriverResetRequest;

		public AsioOut()
			: this(0)
		{
		}

		public AsioOut(string driverName)
		{
			syncContext = SynchronizationContext.Current;
			InitFromName(driverName);
		}

		public AsioOut(int driverIndex)
		{
			syncContext = SynchronizationContext.Current;
			string[] driverNames = GetDriverNames();
			if (driverNames.Length == 0)
			{
				throw new ArgumentException("There is no ASIO Driver installed on your system");
			}
			if (driverIndex < 0 || driverIndex > driverNames.Length)
			{
				throw new ArgumentException($"Invalid device number. Must be in the range [0,{driverNames.Length}]");
			}
			InitFromName(driverNames[driverIndex]);
		}

		~AsioOut()
		{
			Dispose();
		}

		public void Dispose()
		{
			if (driver != null)
			{
				if (playbackState != 0)
				{
					driver.Stop();
				}
				driver.ResetRequestCallback = null;
				driver.ReleaseDriver();
				driver = null;
			}
		}

		public static string[] GetDriverNames()
		{
			return AsioDriver.GetAsioDriverNames();
		}

		public static bool isSupported()
		{
			return GetDriverNames().Length != 0;
		}

		public bool IsSampleRateSupported(int sampleRate)
		{
			return driver.IsSampleRateSupported(sampleRate);
		}

		private void InitFromName(string driverName)
		{
			this.driverName = driverName;
			AsioDriver asioDriverByName = AsioDriver.GetAsioDriverByName(driverName);
			try
			{
				driver = new AsioDriverExt(asioDriverByName);
			}
			catch
			{
				ReleaseDriver(asioDriverByName);
				throw;
			}
			driver.ResetRequestCallback = OnDriverResetRequest;
			ChannelOffset = 0;
		}

		private void OnDriverResetRequest()
		{
			this.DriverResetRequest?.Invoke(this, EventArgs.Empty);
		}

		private void ReleaseDriver(AsioDriver driver)
		{
			driver.DisposeBuffers();
			driver.ReleaseComAsioDriver();
		}

		public void ShowControlPanel()
		{
			driver.ShowControlPanel();
		}

		public void Play()
		{
			if (playbackState != PlaybackState.Playing)
			{
				playbackState = PlaybackState.Playing;
				HasReachedEnd = false;
				driver.Start();
			}
		}

		public void Stop()
		{
			playbackState = PlaybackState.Stopped;
			driver.Stop();
			HasReachedEnd = false;
			RaisePlaybackStopped(null);
		}

		public void Pause()
		{
			playbackState = PlaybackState.Paused;
			driver.Stop();
		}

		public void Init(IWaveProvider waveProvider)
		{
			InitRecordAndPlayback(waveProvider, 0, -1);
		}

		public void InitRecordAndPlayback(IWaveProvider waveProvider, int recordChannels, int recordOnlySampleRate)
		{
			if (isInitialized)
			{
				throw new InvalidOperationException("Already initialised this instance of AsioOut - dispose and create a new one");
			}
			isInitialized = true;
			int num = waveProvider?.WaveFormat.SampleRate ?? recordOnlySampleRate;
			if (waveProvider != null)
			{
				sourceStream = waveProvider;
				NumberOfOutputChannels = waveProvider.WaveFormat.Channels;
				AsioSampleType type = driver.Capabilities.OutputChannelInfos[0].type;
				convertor = AsioSampleConvertor.SelectSampleConvertor(waveProvider.WaveFormat, type);
				switch (type)
				{
				case AsioSampleType.Float32LSB:
					OutputWaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(waveProvider.WaveFormat.SampleRate, waveProvider.WaveFormat.Channels);
					break;
				case AsioSampleType.Int32LSB:
					OutputWaveFormat = new WaveFormat(waveProvider.WaveFormat.SampleRate, 32, waveProvider.WaveFormat.Channels);
					break;
				case AsioSampleType.Int16LSB:
					OutputWaveFormat = new WaveFormat(waveProvider.WaveFormat.SampleRate, 16, waveProvider.WaveFormat.Channels);
					break;
				case AsioSampleType.Int24LSB:
					OutputWaveFormat = new WaveFormat(waveProvider.WaveFormat.SampleRate, 24, waveProvider.WaveFormat.Channels);
					break;
				default:
					throw new NotSupportedException($"{type} not currently supported");
				}
			}
			else
			{
				NumberOfOutputChannels = 0;
			}
			if (!driver.IsSampleRateSupported(num))
			{
				throw new ArgumentException("SampleRate is not supported");
			}
			if (driver.Capabilities.SampleRate != (double)num)
			{
				driver.SetSampleRate(num);
			}
			driver.FillBufferCallback = driver_BufferUpdate;
			NumberOfInputChannels = recordChannels;
			nbSamples = driver.CreateBuffers(NumberOfOutputChannels, NumberOfInputChannels, useMaxBufferSize: false);
			driver.SetChannelOffset(ChannelOffset, InputChannelOffset);
			if (waveProvider != null)
			{
				waveBuffer = new byte[nbSamples * NumberOfOutputChannels * waveProvider.WaveFormat.BitsPerSample / 8];
			}
		}

		private unsafe void driver_BufferUpdate(IntPtr[] inputChannels, IntPtr[] outputChannels)
		{
			if (NumberOfInputChannels > 0)
			{
				EventHandler<AsioAudioAvailableEventArgs> audioAvailable = this.AudioAvailable;
				if (audioAvailable != null)
				{
					AsioAudioAvailableEventArgs asioAudioAvailableEventArgs = new AsioAudioAvailableEventArgs(inputChannels, outputChannels, nbSamples, driver.Capabilities.InputChannelInfos[0].type);
					audioAvailable(this, asioAudioAvailableEventArgs);
					if (asioAudioAvailableEventArgs.WrittenToOutputBuffers)
					{
						return;
					}
				}
			}
			if (NumberOfOutputChannels <= 0)
			{
				return;
			}
			int num = sourceStream.Read(waveBuffer, 0, waveBuffer.Length);
			if (num < waveBuffer.Length)
			{
				Array.Clear(waveBuffer, num, waveBuffer.Length - num);
			}
			fixed (byte* ptr = &waveBuffer[0])
			{
				void* value = ptr;
				convertor(new IntPtr(value), outputChannels, NumberOfOutputChannels, nbSamples);
			}
			if (num == 0)
			{
				if (AutoStop)
				{
					Stop();
				}
				HasReachedEnd = true;
			}
		}

		private void RaisePlaybackStopped(Exception e)
		{
			EventHandler<StoppedEventArgs> handler = this.PlaybackStopped;
			if (handler == null)
			{
				return;
			}
			if (syncContext == null)
			{
				handler(this, new StoppedEventArgs(e));
				return;
			}
			syncContext.Post(delegate
			{
				handler(this, new StoppedEventArgs(e));
			}, null);
		}

		public string AsioInputChannelName(int channel)
		{
			if (channel <= DriverInputChannelCount)
			{
				return driver.Capabilities.InputChannelInfos[channel].name;
			}
			return "";
		}

		public string AsioOutputChannelName(int channel)
		{
			if (channel <= DriverOutputChannelCount)
			{
				return driver.Capabilities.OutputChannelInfos[channel].name;
			}
			return "";
		}
	}
}
namespace NAudio.Wave.Asio
{
	[StructLayout(LayoutKind.Sequential, Pack = 4)]
	public struct Asio64Bit
	{
		public uint hi;

		public uint lo;
	}
	[StructLayout(LayoutKind.Sequential, Pack = 4)]
	public struct AsioCallbacks
	{
		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		public delegate void AsioBufferSwitchCallBack(int doubleBufferIndex, bool directProcess);

		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		public delegate void AsioSampleRateDidChangeCallBack(double sRate);

		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		public delegate int AsioAsioMessageCallBack(AsioMessageSelector selector, int value, IntPtr message, IntPtr opt);

		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		public delegate IntPtr AsioBufferSwitchTimeInfoCallBack(IntPtr asioTimeParam, int doubleBufferIndex, bool directProcess);

		public AsioBufferSwitchCallBack pbufferSwitch;

		public AsioSampleRateDidChangeCallBack psampleRateDidChange;

		public AsioAsioMessageCallBack pasioMessage;

		public AsioBufferSwitchTimeInfoCallBack pbufferSwitchTimeInfo;
	}
	[StructLayout(LayoutKind.Sequential, Pack = 4)]
	public struct AsioChannelInfo
	{
		public int channel;

		public bool isInput;

		public bool isActive;

		public int channelGroup;

		[MarshalAs(UnmanagedType.U4)]
		public AsioSampleType type;

		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
		public string name;
	}
	public class AsioDriver
	{
		[StructLayout(LayoutKind.Sequential, Pack = 2)]
		private class AsioDriverVTable
		{
			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate int ASIOInit(IntPtr _pUnknown, IntPtr sysHandle);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate void ASIOgetDriverName(IntPtr _pUnknown, StringBuilder name);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate int ASIOgetDriverVersion(IntPtr _pUnknown);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate void ASIOgetErrorMessage(IntPtr _pUnknown, StringBuilder errorMessage);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOstart(IntPtr _pUnknown);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOstop(IntPtr _pUnknown);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOgetChannels(IntPtr _pUnknown, out int numInputChannels, out int numOutputChannels);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOgetLatencies(IntPtr _pUnknown, out int inputLatency, out int outputLatency);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOgetBufferSize(IntPtr _pUnknown, out int minSize, out int maxSize, out int preferredSize, out int granularity);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOcanSampleRate(IntPtr _pUnknown, double sampleRate);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOgetSampleRate(IntPtr _pUnknown, out double sampleRate);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOsetSampleRate(IntPtr _pUnknown, double sampleRate);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOgetClockSources(IntPtr _pUnknown, out long clocks, int numSources);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOsetClockSource(IntPtr _pUnknown, int reference);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOgetSamplePosition(IntPtr _pUnknown, out long samplePos, ref Asio64Bit timeStamp);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOgetChannelInfo(IntPtr _pUnknown, ref AsioChannelInfo info);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOcreateBuffers(IntPtr _pUnknown, IntPtr bufferInfos, int numChannels, int bufferSize, IntPtr callbacks);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOdisposeBuffers(IntPtr _pUnknown);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOcontrolPanel(IntPtr _pUnknown);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOfuture(IntPtr _pUnknown, int selector, IntPtr opt);

			[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
			public delegate AsioError ASIOoutputReady(IntPtr _pUnknown);

			public ASIOInit init;

			public ASIOgetDriverName getDriverName;

			public ASIOgetDriverVersion getDriverVersion;

			public ASIOgetErrorMessage getErrorMessage;

			public ASIOstart start;

			public ASIOstop stop;

			public ASIOgetChannels getChannels;

			public ASIOgetLatencies getLatencies;

			public ASIOgetBufferSize getBufferSize;

			public ASIOcanSampleRate canSampleRate;

			public ASIOgetSampleRate getSampleRate;

			public ASIOsetSampleRate setSampleRate;

			public ASIOgetClockSources getClockSources;

			public ASIOsetClockSource setClockSource;

			public ASIOgetSamplePosition getSamplePosition;

			public ASIOgetChannelInfo getChannelInfo;

			public ASIOcreateBuffers createBuffers;

			public ASIOdisposeBuffers disposeBuffers;

			public ASIOcontrolPanel controlPanel;

			public ASIOfuture future;

			public ASIOoutputReady outputReady;
		}

		private IntPtr pAsioComObject;

		private IntPtr pinnedcallbacks;

		private AsioDriverVTable asioDriverVTable;

		private AsioDriver()
		{
		}

		public static string[] GetAsioDriverNames()
		{
			RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\ASIO");
			string[] result = new string[0];
			if (registryKey != null)
			{
				result = registryKey.GetSubKeyNames();
				registryKey.Close();
			}
			return result;
		}

		public static AsioDriver GetAsioDriverByName(string name)
		{
			return GetAsioDriverByGuid(new Guid((Registry.LocalMachine.OpenSubKey("SOFTWARE\\ASIO\\" + name) ?? throw new ArgumentException("Driver Name " + name + " doesn't exist")).GetValue("CLSID").ToString()));
		}

		public static AsioDriver GetAsioDriverByGuid(Guid guid)
		{
			AsioDriver asioDriver = new AsioDriver();
			asioDriver.InitFromGuid(guid);
			return asioDriver;
		}

		public bool Init(IntPtr sysHandle)
		{
			return asioDriverVTable.init(pAsioComObject, sysHandle) == 1;
		}

		public string GetDriverName()
		{
			StringBuilder stringBuilder = new StringBuilder(256);
			asioDriverVTable.getDriverName(pAsioComObject, stringBuilder);
			return stringBuilder.ToString();
		}

		public int GetDriverVersion()
		{
			return asioDriverVTable.getDriverVersion(pAsioComObject);
		}

		public string GetErrorMessage()
		{
			StringBuilder stringBuilder = new StringBuilder(256);
			asioDriverVTable.getErrorMessage(pAsioComObject, stringBuilder);
			return stringBuilder.ToString();
		}

		public void Start()
		{
			HandleException(asioDriverVTable.start(pAsioComObject), "start");
		}

		public AsioError Stop()
		{
			return asioDriverVTable.stop(pAsioComObject);
		}

		public void GetChannels(out int numInputChannels, out int numOutputChannels)
		{
			HandleException(asioDriverVTable.getChannels(pAsioComObject, out numInputChannels, out numOutputChannels), "getChannels");
		}

		public AsioError GetLatencies(out int inputLatency, out int outputLatency)
		{
			return asioDriverVTable.getLatencies(pAsioComObject, out inputLatency, out outputLatency);
		}

		public void GetBufferSize(out int minSize, out int maxSize, out int preferredSize, out int granularity)
		{
			HandleException(asioDriverVTable.getBufferSize(pAsioComObject, out minSize, out maxSize, out preferredSize, out granularity), "getBufferSize");
		}

		public bool CanSampleRate(double sampleRate)
		{
			AsioError asioError = asioDriverVTable.canSampleRate(pAsioComObject, sampleRate);
			switch (asioError)
			{
			case AsioError.ASE_NoClock:
				return false;
			case AsioError.ASE_OK:
				return true;
			default:
				HandleException(asioError, "canSampleRate");
				return false;
			}
		}

		public double GetSampleRate()
		{
			HandleException(asioDriverVTable.getSampleRate(pAsioComObject, out var sampleRate), "getSampleRate");
			return sampleRate;
		}

		public void SetSampleRate(double sampleRate)
		{
			HandleException(asioDriverVTable.setSampleRate(pAsioComObject, sampleRate), "setSampleRate");
		}

		public void GetClockSources(out long clocks, int numSources)
		{
			HandleException(asioDriverVTable.getClockSources(pAsioComObject, out clocks, numSources), "getClockSources");
		}

		public void SetClockSource(int reference)
		{
			HandleException(asioDriverVTable.setClockSource(pAsioComObject, reference), "setClockSources");
		}

		public void GetSamplePosition(out long samplePos, ref Asio64Bit timeStamp)
		{
			HandleException(asioDriverVTable.getSamplePosition(pAsioComObject, out samplePos, ref timeStamp), "getSamplePosition");
		}

		public AsioChannelInfo GetChannelInfo(int channelNumber, bool trueForInputInfo)
		{
			AsioChannelInfo asioChannelInfo = default(AsioChannelInfo);
			asioChannelInfo.channel = channelNumber;
			asioChannelInfo.isInput = trueForInputInfo;
			AsioChannelInfo info = asioChannelInfo;
			HandleException(asioDriverVTable.getChannelInfo(pAsioComObject, ref info), "getChannelInfo");
			return info;
		}

		public void CreateBuffers(IntPtr bufferInfos, int numChannels, int bufferSize, ref AsioCallbacks callbacks)
		{
			pinnedcallbacks = Marshal.AllocHGlobal(Marshal.SizeOf(callbacks));
			Marshal.StructureToPtr(callbacks, pinnedcallbacks, fDeleteOld: false);
			HandleException(asioDriverVTable.createBuffers(pAsioComObject, bufferInfos, numChannels, bufferSize, pinnedcallbacks), "createBuffers");
		}

		public AsioError DisposeBuffers()
		{
			AsioError result = asioDriverVTable.disposeBuffers(pAsioComObject);
			Marshal.FreeHGlobal(pinnedcallbacks);
			return result;
		}

		public void ControlPanel()
		{
			HandleException(asioDriverVTable.controlPanel(pAsioComObject), "controlPanel");
		}

		public void Future(int selector, IntPtr opt)
		{
			HandleException(asioDriverVTable.future(pAsioComObject, selector, opt), "future");
		}

		public AsioError OutputReady()
		{
			return asioDriverVTable.outputReady(pAsioComObject);
		}

		public void ReleaseComAsioDriver()
		{
			Marshal.Release(pAsioComObject);
		}

		private void HandleException(AsioError error, string methodName)
		{
			if (error != 0 && error != AsioError.ASE_SUCCESS)
			{
				throw new AsioException("Error code [" + AsioException.getErrorName(error) + "] while calling ASIO method <" + methodName + ">, " + GetErrorMessage())
				{
					Error = error
				};
			}
		}

		private void InitFromGuid(Guid asioGuid)
		{
			int num = CoCreateInstance(ref asioGuid, IntPtr.Zero, 1u, ref asioGuid, out pAsioComObject);
			if (num != 0)
			{
				throw new COMException("Unable to instantiate ASIO. Check if STAThread is set", num);
			}
			IntPtr ptr = Marshal.ReadIntPtr(pAsioComObject);
			asioDriverVTable = new AsioDriverVTable();
			FieldInfo[] fields = typeof(AsioDriverVTable).GetFields();
			for (int i = 0; i < fields.Length; i++)
			{
				FieldInfo fieldInfo = fields[i];
				object delegateForFunctionPointer = Marshal.GetDelegateForFunctionPointer(Marshal.ReadIntPtr(ptr, (i + 3) * IntPtr.Size), fieldInfo.FieldType);
				fieldInfo.SetValue(asioDriverVTable, delegateForFunctionPointer);
			}
		}

		[DllImport("ole32.Dll")]
		private static extern int CoCreateInstance(ref Guid clsid, IntPtr inner, uint context, ref Guid uuid, out IntPtr rReturnedComObject);
	}
	public class AsioDriverCapability
	{
		public string DriverName;

		public int NbInputChannels;

		public int NbOutputChannels;

		public int InputLatency;

		public int OutputLatency;

		public int BufferMinSize;

		public int BufferMaxSize;

		public int BufferPreferredSize;

		public int BufferGranularity;

		public double SampleRate;

		public AsioChannelInfo[] InputChannelInfos;

		public AsioChannelInfo[] OutputChannelInfos;
	}
	public delegate void AsioFillBufferCallback(IntPtr[] inputChannels, IntPtr[] outputChannels);
	public class AsioDriverExt
	{
		private readonly AsioDriver driver;

		private AsioCallbacks callbacks;

		private AsioDriverCapability capability;

		private AsioBufferInfo[] bufferInfos;

		private bool isOutputReadySupported;

		private IntPtr[] currentOutputBuffers;

		private IntPtr[] currentInputBuffers;

		private int numberOfOutputChannels;

		private int numberOfInputChannels;

		private AsioFillBufferCallback fillBufferCallback;

		private int bufferSize;

		private int outputChannelOffset;

		private int inputChannelOffset;

		public Action ResetRequestCallback;

		public AsioDriver Driver => driver;

		public AsioFillBufferCallback FillBufferCallback
		{
			get
			{
				return fillBufferCallback;
			}
			set
			{
				fillBufferCallback = value;
			}
		}

		public AsioDriverCapability Capabilities => capability;

		public AsioDriverExt(AsioDriver driver)
		{
			this.driver = driver;
			if (!driver.Init(IntPtr.Zero))
			{
				throw new InvalidOperationException(driver.GetErrorMessage());
			}
			callbacks = default(AsioCallbacks);
			callbacks.pasioMessage = AsioMessageCallBack;
			callbacks.pbufferSwitch = BufferSwitchCallBack;
			callbacks.pbufferSwitchTimeInfo = BufferSwitchTimeInfoCallBack;
			callbacks.psampleRateDidChange = SampleRateDidChangeCallBack;
			BuildCapabilities();
		}

		public void SetChannelOffset(int outputChannelOffset, int inputChannelOffset)
		{
			if (outputChannelOffset + numberOfOutputChannels <= Capabilities.NbOutputChannels)
			{
				this.outputChannelOffset = outputChannelOffset;
				if (inputChannelOffset + numberOfInputChannels <= Capabilities.NbInputChannels)
				{
					this.inputChannelOffset = inputChannelOffset;
					return;
				}
				throw new ArgumentException("Invalid channel offset");
			}
			throw new ArgumentException("Invalid channel offset");
		}

		public void Start()
		{
			driver.Start();
		}

		public void Stop()
		{
			driver.Stop();
		}

		public void ShowControlPanel()
		{
			driver.ControlPanel();
		}

		public void ReleaseDriver()
		{
			try
			{
				driver.DisposeBuffers();
			}
			catch (Exception ex)
			{
				Console.Out.WriteLine(ex.ToString());
			}
			driver.ReleaseComAsioDriver();
		}

		public bool IsSampleRateSupported(double sampleRate)
		{
			return driver.CanSampleRate(sampleRate);
		}

		public void SetSampleRate(double sampleRate)
		{
			driver.SetSampleRate(sampleRate);
			BuildCapabilities();
		}

		public unsafe int CreateBuffers(int numberOfOutputChannels, int numberOfInputChannels, bool useMaxBufferSize)
		{
			if (numberOfOutputChannels < 0 || numberOfOutputChannels > capability.NbOutputChannels)
			{
				throw new ArgumentException($"Invalid number of channels {numberOfOutputChannels}, must be in the range [0,{capability.NbOutputChannels}]");
			}
			if (numberOfInputChannels < 0 || numberOfInputChannels > capability.NbInputChannels)
			{
				throw new ArgumentException("numberOfInputChannels", $"Invalid number of input channels {numberOfInputChannels}, must be in the range [0,{capability.NbInputChannels}]");
			}
			this.numberOfOutputChannels = numberOfOutputChannels;
			this.numberOfInputChannels = numberOfInputChannels;
			int num = capability.NbInputChannels + capability.NbOutputChannels;
			bufferInfos = new AsioBufferInfo[num];
			currentOutputBuffers = new IntPtr[numberOfOutputChannels];
			currentInputBuffers = new IntPtr[numberOfInputChannels];
			int num2 = 0;
			int num3 = 0;
			while (num3 < capability.NbInputChannels)
			{
				bufferInfos[num2].isInput = true;
				bufferInfos[num2].channelNum = num3;
				bufferInfos[num2].pBuffer0 = IntPtr.Zero;
				bufferInfos[num2].pBuffer1 = IntPtr.Zero;
				num3++;
				num2++;
			}
			int num4 = 0;
			while (num4 < capability.NbOutputChannels)
			{
				bufferInfos[num2].isInput = false;
				bufferInfos[num2].channelNum = num4;
				bufferInfos[num2].pBuffer0 = IntPtr.Zero;
				bufferInfos[num2].pBuffer1 = IntPtr.Zero;
				num4++;
				num2++;
			}
			if (useMaxBufferSize)
			{
				bufferSize = capability.BufferMaxSize;
			}
			else
			{
				bufferSize = capability.BufferPreferredSize;
			}
			fixed (AsioBufferInfo* value = &bufferInfos[0])
			{
				IntPtr intPtr = new IntPtr(value);
				driver.CreateBuffers(intPtr, num, bufferSize, ref callbacks);
			}
			isOutputReadySupported = driver.OutputReady() == AsioError.ASE_OK;
			return bufferSize;
		}

		private void BuildCapabilities()
		{
			capability = new AsioDriverCapability();
			capability.DriverName = driver.GetDriverName();
			driver.GetChannels(out capability.NbInputChannels, out capability.NbOutputChannels);
			capability.InputChannelInfos = new AsioChannelInfo[capability.NbInputChannels];
			capability.OutputChannelInfos = new AsioChannelInfo[capability.NbOutputChannels];
			for (int i = 0; i < capability.NbInputChannels; i++)
			{
				capability.InputChannelInfos[i] = driver.GetChannelInfo(i, trueForInputInfo: true);
			}
			for (int j = 0; j < capability.NbOutputChannels; j++)
			{
				capability.OutputChannelInfos[j] = driver.GetChannelInfo(j, trueForInputInfo: false);
			}
			capability.SampleRate = driver.GetSampleRate();
			AsioError latencies = driver.GetLatencies(out capability.InputLatency, out capability.OutputLatency);
			if (latencies != 0 && latencies != AsioError.ASE_NotPresent)
			{
				throw new AsioException("ASIOgetLatencies")
				{
					Error = latencies
				};
			}
			driver.GetBufferSize(out capability.BufferMinSize, out capability.BufferMaxSize, out capability.BufferPreferredSize, out capability.BufferGranularity);
		}

		private void BufferSwitchCallBack(int doubleBufferIndex, bool directProcess)
		{
			for (int i = 0; i < numberOfInputChannels; i++)
			{
				currentInputBuffers[i] = bufferInfos[i + inputChannelOffset].Buffer(doubleBufferIndex);
			}
			for (int j = 0; j < numberOfOutputChannels; j++)
			{
				currentOutputBuffers[j] = bufferInfos[j + outputChannelOffset + capability.NbInputChannels].Buffer(doubleBufferIndex);
			}
			fillBufferCallback?.Invoke(currentInputBuffers, currentOutputBuffers);
			if (isOutputReadySupported)
			{
				driver.OutputReady();
			}
		}

		private void SampleRateDidChangeCallBack(double sRate)
		{
			capability.SampleRate = sRate;
		}

		private int AsioMessageCallBack(AsioMessageSelector selector, int value, IntPtr message, IntPtr opt)
		{
			switch (selector)
			{
			case AsioMessageSelector.kAsioSelectorSupported:
				switch ((AsioMessageSelector)Enum.ToObject(typeof(AsioMessageSelector), value))
				{
				case AsioMessageSelector.kAsioEngineVersion:
					return 1;
				case AsioMessageSelector.kAsioResetRequest:
					ResetRequestCallback?.Invoke();
					return 0;
				case AsioMessageSelector.kAsioBufferSizeChange:
					return 0;
				case AsioMessageSelector.kAsioResyncRequest:
					return 0;
				case AsioMessageSelector.kAsioLatenciesChanged:
					return 0;
				case AsioMessageSelector.kAsioSupportsTimeInfo:
					return 0;
				case AsioMessageSelector.kAsioSupportsTimeCode:
					return 0;
				}
				break;
			case AsioMessageSelector.kAsioEngineVersion:
				return 2;
			case AsioMessageSelector.kAsioResetRequest:
				ResetRequestCallback?.Invoke();
				return 1;
			case AsioMessageSelector.kAsioBufferSizeChange:
				return 0;
			case AsioMessageSelector.kAsioResyncRequest:
				return 0;
			case AsioMessageSelector.kAsioLatenciesChanged:
				return 0;
			case AsioMessageSelector.kAsioSupportsTimeInfo:
				return 0;
			case AsioMessageSelector.kAsioSupportsTimeCode:
				return 0;
			}
			return 0;
		}

		private IntPtr BufferSwitchTimeInfoCallBack(IntPtr asioTimeParam, int doubleBufferIndex, bool directProcess)
		{
			return IntPtr.Zero;
		}
	}
	public enum AsioError
	{
		ASE_OK = 0,
		ASE_SUCCESS = 1061701536,
		ASE_NotPresent = -1000,
		ASE_HWMalfunction = -999,
		ASE_InvalidParameter = -998,
		ASE_InvalidMode = -997,
		ASE_SPNotAdvancing = -996,
		ASE_NoClock = -995,
		ASE_NoMemory = -994
	}
	public enum AsioMessageSelector
	{
		kAsioSelectorSupported = 1,
		kAsioEngineVersion,
		kAsioResetRequest,
		kAsioBufferSizeChange,
		kAsioResyncRequest,
		kAsioLatenciesChanged,
		kAsioSupportsTimeInfo,
		kAsioSupportsTimeCode,
		kAsioMMCCommand,
		kAsioSupportsInputMonitor,
		kAsioSupportsInputGain,
		kAsioSupportsInputMeter,
		kAsioSupportsOutputGain,
		kAsioSupportsOutputMeter,
		kAsioOverload
	}
	internal class AsioSampleConvertor
	{
		public delegate void SampleConvertor(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples);

		public static SampleConvertor SelectSampleConvertor(WaveFormat waveFormat, AsioSampleType asioType)
		{
			SampleConvertor result = null;
			bool flag = waveFormat.Channels == 2;
			switch (asioType)
			{
			case AsioSampleType.Int32LSB:
				switch (waveFormat.BitsPerSample)
				{
				case 16:
					result = (flag ? new SampleConvertor(ConvertorShortToInt2Channels) : new SampleConvertor(ConvertorShortToIntGeneric));
					break;
				case 32:
					result = ((waveFormat.Encoding != WaveFormatEncoding.IeeeFloat) ? (flag ? new SampleConvertor(ConvertorIntToInt2Channels) : new SampleConvertor(ConvertorIntToIntGeneric)) : (flag ? new SampleConvertor(ConvertorFloatToInt2Channels) : new SampleConvertor(ConvertorFloatToIntGeneric)));
					break;
				}
				break;
			case AsioSampleType.Int16LSB:
				switch (waveFormat.BitsPerSample)
				{
				case 16:
					result = (flag ? new SampleConvertor(ConvertorShortToShort2Channels) : new SampleConvertor(ConvertorShortToShortGeneric));
					break;
				case 32:
					result = ((waveFormat.Encoding != WaveFormatEncoding.IeeeFloat) ? (flag ? new SampleConvertor(ConvertorIntToShort2Channels) : new SampleConvertor(ConvertorIntToShortGeneric)) : (flag ? new SampleConvertor(ConvertorFloatToShort2Channels) : new SampleConvertor(ConvertorFloatToShortGeneric)));
					break;
				}
				break;
			case AsioSampleType.Int24LSB:
				switch (waveFormat.BitsPerSample)
				{
				case 16:
					throw new ArgumentException("Not a supported conversion");
				case 32:
					if (waveFormat.Encoding == WaveFormatEncoding.IeeeFloat)
					{
						result = ConverterFloatTo24LSBGeneric;
						break;
					}
					throw new ArgumentException("Not a supported conversion");
				}
				break;
			case AsioSampleType.Float32LSB:
				switch (waveFormat.BitsPerSample)
				{
				case 16:
					throw new ArgumentException("Not a supported conversion");
				case 32:
					result = ((waveFormat.Encoding != WaveFormatEncoding.IeeeFloat) ? new SampleConvertor(ConvertorIntToFloatGeneric) : new SampleConvertor(ConverterFloatToFloatGeneric));
					break;
				}
				break;
			default:
				throw new ArgumentException($"ASIO Buffer Type {Enum.GetName(typeof(AsioSampleType), asioType)} is not yet supported.");
			}
			return result;
		}

		public unsafe static void ConvertorShortToInt2Channels(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			short* ptr = (short*)(void*)inputInterleavedBuffer;
			short* ptr2 = (short*)(void*)asioOutputBuffers[0];
			short* ptr3 = (short*)(void*)asioOutputBuffers[1];
			ptr2++;
			ptr3++;
			for (int i = 0; i < nbSamples; i++)
			{
				*ptr2 = *ptr;
				*ptr3 = ptr[1];
				ptr += 2;
				ptr2 += 2;
				ptr3 += 2;
			}
		}

		public unsafe static void ConvertorShortToIntGeneric(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			short* ptr = (short*)(void*)inputInterleavedBuffer;
			short*[] array = new short*[nbChannels];
			for (int i = 0; i < nbChannels; i++)
			{
				array[i] = (short*)(void*)asioOutputBuffers[i];
				int num = i;
				short* ptr2 = array[num];
				array[num] = ptr2 + 1;
			}
			for (int j = 0; j < nbSamples; j++)
			{
				for (int k = 0; k < nbChannels; k++)
				{
					*array[k] = *(ptr++);
					short*[] array2 = array;
					int num = k;
					array2[num] += 2;
				}
			}
		}

		public unsafe static void ConvertorFloatToInt2Channels(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			float* ptr = (float*)(void*)inputInterleavedBuffer;
			int* ptr2 = (int*)(void*)asioOutputBuffers[0];
			int* ptr3 = (int*)(void*)asioOutputBuffers[1];
			for (int i = 0; i < nbSamples; i++)
			{
				*(ptr2++) = clampToInt(*ptr);
				*(ptr3++) = clampToInt(ptr[1]);
				ptr += 2;
			}
		}

		public unsafe static void ConvertorFloatToIntGeneric(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			float* ptr = (float*)(void*)inputInterleavedBuffer;
			int*[] array = new int*[nbChannels];
			for (int i = 0; i < nbChannels; i++)
			{
				array[i] = (int*)(void*)asioOutputBuffers[i];
			}
			for (int j = 0; j < nbSamples; j++)
			{
				for (int k = 0; k < nbChannels; k++)
				{
					int num = k;
					int* ptr2 = array[num];
					array[num] = ptr2 + 1;
					*ptr2 = clampToInt(*(ptr++));
				}
			}
		}

		public unsafe static void ConvertorIntToInt2Channels(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			int* ptr = (int*)(void*)inputInterleavedBuffer;
			int* ptr2 = (int*)(void*)asioOutputBuffers[0];
			int* ptr3 = (int*)(void*)asioOutputBuffers[1];
			for (int i = 0; i < nbSamples; i++)
			{
				*(ptr2++) = *ptr;
				*(ptr3++) = ptr[1];
				ptr += 2;
			}
		}

		public unsafe static void ConvertorIntToIntGeneric(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			int* ptr = (int*)(void*)inputInterleavedBuffer;
			int*[] array = new int*[nbChannels];
			for (int i = 0; i < nbChannels; i++)
			{
				array[i] = (int*)(void*)asioOutputBuffers[i];
			}
			for (int j = 0; j < nbSamples; j++)
			{
				for (int k = 0; k < nbChannels; k++)
				{
					int num = k;
					int* ptr2 = array[num];
					array[num] = ptr2 + 1;
					*ptr2 = *(ptr++);
				}
			}
		}

		public unsafe static void ConvertorIntToShort2Channels(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			int* ptr = (int*)(void*)inputInterleavedBuffer;
			short* ptr2 = (short*)(void*)asioOutputBuffers[0];
			short* ptr3 = (short*)(void*)asioOutputBuffers[1];
			for (int i = 0; i < nbSamples; i++)
			{
				*(ptr2++) = (short)(*ptr / 65536);
				*(ptr3++) = (short)(ptr[1] / 65536);
				ptr += 2;
			}
		}

		public unsafe static void ConvertorIntToShortGeneric(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			int* ptr = (int*)(void*)inputInterleavedBuffer;
			int*[] array = new int*[nbChannels];
			for (int i = 0; i < nbChannels; i++)
			{
				array[i] = (int*)(void*)asioOutputBuffers[i];
			}
			for (int j = 0; j < nbSamples; j++)
			{
				for (int k = 0; k < nbChannels; k++)
				{
					int num = k;
					int* ptr2 = array[num];
					array[num] = ptr2 + 1;
					*ptr2 = (short)(*(ptr++) / 65536);
				}
			}
		}

		public unsafe static void ConvertorIntToFloatGeneric(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			int* ptr = (int*)(void*)inputInterleavedBuffer;
			float*[] array = new float*[nbChannels];
			for (int i = 0; i < nbChannels; i++)
			{
				array[i] = (float*)(void*)asioOutputBuffers[i];
			}
			for (int j = 0; j < nbSamples; j++)
			{
				for (int k = 0; k < nbChannels; k++)
				{
					int num = k;
					float* ptr2 = array[num];
					array[num] = ptr2 + 1;
					*ptr2 = *(ptr++) / int.MinValue;
				}
			}
		}

		public unsafe static void ConvertorShortToShort2Channels(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			short* ptr = (short*)(void*)inputInterleavedBuffer;
			short* ptr2 = (short*)(void*)asioOutputBuffers[0];
			short* ptr3 = (short*)(void*)asioOutputBuffers[1];
			for (int i = 0; i < nbSamples; i++)
			{
				*(ptr2++) = *ptr;
				*(ptr3++) = ptr[1];
				ptr += 2;
			}
		}

		public unsafe static void ConvertorShortToShortGeneric(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			short* ptr = (short*)(void*)inputInterleavedBuffer;
			short*[] array = new short*[nbChannels];
			for (int i = 0; i < nbChannels; i++)
			{
				array[i] = (short*)(void*)asioOutputBuffers[i];
			}
			for (int j = 0; j < nbSamples; j++)
			{
				for (int k = 0; k < nbChannels; k++)
				{
					int num = k;
					short* ptr2 = array[num];
					array[num] = ptr2 + 1;
					*ptr2 = *(ptr++);
				}
			}
		}

		public unsafe static void ConvertorFloatToShort2Channels(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			float* ptr = (float*)(void*)inputInterleavedBuffer;
			short* ptr2 = (short*)(void*)asioOutputBuffers[0];
			short* ptr3 = (short*)(void*)asioOutputBuffers[1];
			for (int i = 0; i < nbSamples; i++)
			{
				*(ptr2++) = clampToShort(*ptr);
				*(ptr3++) = clampToShort(ptr[1]);
				ptr += 2;
			}
		}

		public unsafe static void ConvertorFloatToShortGeneric(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			float* ptr = (float*)(void*)inputInterleavedBuffer;
			short*[] array = new short*[nbChannels];
			for (int i = 0; i < nbChannels; i++)
			{
				array[i] = (short*)(void*)asioOutputBuffers[i];
			}
			for (int j = 0; j < nbSamples; j++)
			{
				for (int k = 0; k < nbChannels; k++)
				{
					int num = k;
					short* ptr2 = array[num];
					array[num] = ptr2 + 1;
					*ptr2 = clampToShort(*(ptr++));
				}
			}
		}

		public unsafe static void ConverterFloatTo24LSBGeneric(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			float* ptr = (float*)(void*)inputInterleavedBuffer;
			byte*[] array = new byte*[nbChannels];
			for (int i = 0; i < nbChannels; i++)
			{
				array[i] = (byte*)(void*)asioOutputBuffers[i];
			}
			for (int j = 0; j < nbSamples; j++)
			{
				for (int k = 0; k < nbChannels; k++)
				{
					int num = clampTo24Bit(*(ptr++));
					int num2 = k;
					*(array[num2]++) = (byte)num;
					num2 = k;
					*(array[num2]++) = (byte)(num >> 8);
					num2 = k;
					*(array[num2]++) = (byte)(num >> 16);
				}
			}
		}

		public unsafe static void ConverterFloatToFloatGeneric(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
		{
			float* ptr = (float*)(void*)inputInterleavedBuffer;
			float*[] array = new float*[nbChannels];
			for (int i = 0; i < nbChannels; i++)
			{
				array[i] = (float*)(void*)asioOutputBuffers[i];
			}
			for (int j = 0; j < nbSamples; j++)
			{
				for (int k = 0; k < nbChannels; k++)
				{
					int num = k;
					float* ptr2 = array[num];
					array[num] = ptr2 + 1;
					*ptr2 = *(ptr++);
				}
			}
		}

		private static int clampTo24Bit(double sampleValue)
		{
			sampleValue = ((sampleValue < -1.0) ? (-1.0) : ((sampleValue > 1.0) ? 1.0 : sampleValue));
			return (int)(sampleValue * 8388607.0);
		}

		private static int clampToInt(double sampleValue)
		{
			sampleValue = ((sampleValue < -1.0) ? (-1.0) : ((sampleValue > 1.0) ? 1.0 : sampleValue));
			return (int)(sampleValue * 2147483647.0);
		}

		private static short clampToShort(double sampleValue)
		{
			sampleValue = ((sampleValue < -1.0) ? (-1.0) : ((sampleValue > 1.0) ? 1.0 : sampleValue));
			return (short)(sampleValue * 32767.0);
		}
	}
	public enum AsioSampleType
	{
		Int16MSB = 0,
		Int24MSB = 1,
		Int32MSB = 2,
		Float32MSB = 3,
		Float64MSB = 4,
		Int32MSB16 = 8,
		Int32MSB18 = 9,
		Int32MSB20 = 10,
		Int32MSB24 = 11,
		Int16LSB = 16,
		Int24LSB = 17,
		Int32LSB = 18,
		Float32LSB = 19,
		Float64LSB = 20,
		Int32LSB16 = 24,
		Int32LSB18 = 25,
		Int32LSB20 = 26,
		Int32LSB24 = 27,
		DSDInt8LSB1 = 32,
		DSDInt8MSB1 = 33,
		DSDInt8NER8 = 40
	}
	internal class AsioException : Exception
	{
		private AsioError error;

		public AsioError Error
		{
			get
			{
				return error;
			}
			set
			{
				error = value;
				Data["ASIOError"] = error;
			}
		}

		public AsioException()
		{
		}

		public AsioException(string message)
			: base(message)
		{
		}

		public AsioException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public static string getErrorName(AsioError error)
		{
			return Enum.GetName(typeof(AsioError), error);
		}
	}
	[StructLayout(LayoutKind.Sequential, Pack = 4)]
	internal struct AsioBufferInfo
	{
		public bool isInput;

		public int channelNum;

		public IntPtr pBuffer0;

		public IntPtr pBuffer1;

		public IntPtr Buffer(int bufferIndex)
		{
			if (bufferIndex != 0)
			{
				return pBuffer1;
			}
			return pBuffer0;
		}
	}
	[StructLayout(LayoutKind.Sequential, Pack = 4)]
	internal struct AsioTimeCode
	{
		public double speed;

		public Asio64Bit timeCodeSamples;

		public AsioTimeCodeFlags flags;

		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
		public string future;
	}
	[Flags]
	internal enum AsioTimeCodeFlags
	{
		kTcValid = 1,
		kTcRunning = 2,
		kTcReverse = 4,
		kTcOnspeed = 8,
		kTcStill = 0x10,
		kTcSpeedValid = 0x100
	}
	[StructLayout(LayoutKind.Sequential, Pack = 4)]
	internal struct AsioTimeInfo
	{
		public double speed;

		public Asio64Bit systemTime;

		public Asio64Bit samplePosition;

		public double sampleRate;

		public AsioTimeInfoFlags flags;

		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)]
		public string reserved;
	}
	[Flags]
	internal enum AsioTimeInfoFlags
	{
		kSystemTimeValid = 1,
		kSamplePositionValid = 2,
		kSampleRateValid = 4,
		kSpeedValid = 8,
		kSampleRateChanged = 0x10,
		kClockSourceChanged = 0x20
	}
	[StructLayout(LayoutKind.Sequential, Pack = 4)]
	internal struct AsioTime
	{
		public int reserved1;

		public int reserved2;

		public int reserved3;

		public int reserved4;

		public AsioTimeInfo timeInfo;

		public AsioTimeCode timeCode;
	}
}
namespace NAudio
{
	public enum Manufacturers
	{
		Microsoft = 1,
		Creative = 2,
		Mediavision = 3,
		Fujitsu = 4,
		Artisoft = 20,
		TurtleBeach = 21,
		Ibm = 22,
		Vocaltec = 23,
		Roland = 24,
		DspSolutions = 25,
		Nec = 26,
		Ati = 27,
		Wanglabs = 28,
		Tandy = 29,
		Voyetra = 30,
		Antex = 31,
		IclPS = 32,
		Intel = 33,
		Gravis = 34,
		Val = 35,
		Interactive = 36,
		Yamaha = 37,
		Everex = 38,
		Echo = 39,
		Sierra = 40,
		Cat = 41,
		Apps = 42,
		DspGroup = 43,
		Melabs = 44,
		ComputerFriends = 45,
		Ess = 46,
		Audiofile = 47,
		Motorola = 48,
		Canopus = 49,
		Epson = 50,
		Truevision = 51,
		Aztech = 52,
		Videologic = 53,
		Scalacs = 54,
		Korg = 55,
		Apt = 56,
		Ics = 57,
		Iteratedsys = 58,
		Metheus = 59,
		Logitech = 60,
		Winnov = 61,
		Ncr = 62,
		Exan = 63,
		Ast = 64,
		Willowpond = 65,
		Sonicfoundry = 66,
		Vitec = 67,
		Moscom = 68,
		Siliconsoft = 69,
		Supermac = 73,
		Audiopt = 74,
		Speechcomp = 76,
		Ahead = 77,
		Dolby = 78,
		Oki = 79,
		Auravision = 80,
		Olivetti = 81,
		Iomagic = 82,
		Matsushita = 83,
		Controlres = 84,
		Xebec = 85,
		Newmedia = 86,
		Nms = 87,
		Lyrrus = 88,
		Compusic = 89,
		Opti = 90,
		Adlacc = 91,
		Compaq = 92,
		Dialogic = 93,
		Insoft = 94,
		Mptus = 95,
		Weitek = 96,
		LernoutAndHauspie = 97,
		Qciar = 98,
		Apple = 99,
		Digital = 100,
		Motu = 101,
		Workbit = 102,
		Ositech = 103,
		Miro = 104,
		Cirruslogic = 105,
		Isolution = 106,
		Horizons = 107,
		Concepts = 108,
		Vtg = 109,
		Radius = 110,
		Rockwell = 111,
		Xyz = 112,
		Opcode = 113,
		Voxware = 114,
		NorthernTelecom = 115,
		Apicom = 116,
		Grande = 117,
		Addx = 118,
		Wildcat = 119,
		Rhetorex = 120,
		Brooktree = 121,
		Ensoniq = 125,
		Fast = 126,
		Nvidia = 127,
		Oksori = 128,
		Diacoustics = 129,
		Gulbransen = 130,
		KayElemetrics = 131,
		Crystal = 132,
		SplashStudios = 133,
		Quarterdeck = 134,
		Tdk = 135,
		DigitalAudioLabs = 136,
		Seersys = 137,
		Picturetel = 138,
		AttMicroelectronics = 139,
		Osprey = 140,
		Mediatrix = 141,
		Soundesigns = 142,
		Aldigital = 143,
		SpectrumSignalProcessing = 144,
		Ecs = 145,
		Amd = 146,
		Coredynamics = 147,
		Canam = 148,
		Softsound = 149,
		Norris = 150,
		Ddd = 151,
		Euphonics = 152,
		Precept = 153,
		CrystalNet = 154,
		Chromatic = 155,
		Voiceinfo = 156,
		Viennasys = 157,
		Connectix = 158,
		Gadgetlabs = 159,
		Frontier = 160,
		Viona = 161,
		Casio = 162,
		Diamondmm = 163,
		S3 = 164,
		FraunhoferIis = 172
	}
	public class MmException : Exception
	{
		public MmResult Result { get; }

		public string Function { get; }

		public MmException(MmResult result, string function)
			: base(ErrorMessage(result, function))
		{
			Result = result;
			Function = function;
		}

		private static string ErrorMessage(MmResult result, string function)
		{
			return $"{result} calling {function}";
		}

		public static void Try(MmResult result, string function)
		{
			if (result != 0)
			{
				throw new MmException(result, function);
			}
		}
	}
	public enum MmResult
	{
		NoError = 0,
		UnspecifiedError = 1,
		BadDeviceId = 2,
		NotEnabled = 3,
		AlreadyAllocated = 4,
		InvalidHandle = 5,
		NoDriver = 6,
		MemoryAllocationError = 7,
		NotSupported = 8,
		BadErrorNumber = 9,
		InvalidFlag = 10,
		InvalidParameter = 11,
		HandleBusy = 12,
		InvalidAlias = 13,
		BadRegistryDatabase = 14,
		RegistryKeyNotFound = 15,
		RegistryReadError = 16,
		RegistryWriteError = 17,
		RegistryDeleteError = 18,
		RegistryValueNotFound = 19,
		NoDriverCallback = 20,
		MoreData = 21,
		WaveBadFormat = 32,
		WaveStillPlaying = 33,
		WaveHeaderUnprepared = 34,
		WaveSync = 35,
		AcmNotPossible = 512,
		AcmBusy = 513,
		AcmHeaderUnprepared = 514,
		AcmCancelled = 515,
		MixerInvalidLine = 1024,
		MixerInvalidControl = 1025,
		MixerInvalidValue = 1026
	}
}
namespace NAudio.CoreAudioApi
{
	public enum CaptureState
	{
		Stopped,
		Starting,
		Capturing,
		Stopping
	}
}
namespace NAudio.Dmo
{
	public class AudioMediaSubtypes
	{
		public static readonly Guid MEDIASUBTYPE_PCM = new Guid("00000001-0000-0010-8000-00AA00389B71");

		public static readonly Guid MEDIASUBTYPE_PCMAudioObsolete = new Guid("e436eb8a-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid MEDIASUBTYPE_MPEG1Packet = new Guid("e436eb80-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid MEDIASUBTYPE_MPEG1Payload = new Guid("e436eb81-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid MEDIASUBTYPE_MPEG2_AUDIO = new Guid("e06d802b-db46-11cf-b4d1-00805f6cbbea");

		public static readonly Guid MEDIASUBTYPE_DVD_LPCM_AUDIO = new Guid("e06d8032-db46-11cf-b4d1-00805f6cbbea");

		public static readonly Guid MEDIASUBTYPE_DRM_Audio = new Guid("00000009-0000-0010-8000-00aa00389b71");

		public static readonly Guid MEDIASUBTYPE_IEEE_FLOAT = new Guid("00000003-0000-0010-8000-00aa00389b71");

		public static readonly Guid MEDIASUBTYPE_DOLBY_AC3 = new Guid("e06d802c-db46-11cf-b4d1-00805f6cbbea");

		public static readonly Guid MEDIASUBTYPE_DOLBY_AC3_SPDIF = new Guid("00000092-0000-0010-8000-00aa00389b71");

		public static readonly Guid MEDIASUBTYPE_RAW_SPORT = new Guid("00000240-0000-0010-8000-00aa00389b71");

		public static readonly Guid MEDIASUBTYPE_SPDIF_TAG_241h = new Guid("00000241-0000-0010-8000-00aa00389b71");

		public static readonly Guid MEDIASUBTYPE_I420 = new Guid("30323449-0000-0010-8000-00AA00389B71");

		public static readonly Guid MEDIASUBTYPE_IYUV = new Guid("56555949-0000-0010-8000-00AA00389B71");

		public static readonly Guid MEDIASUBTYPE_RGB1 = new Guid("e436eb78-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid MEDIASUBTYPE_RGB24 = new Guid("e436eb7d-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid MEDIASUBTYPE_RGB32 = new Guid("e436eb7e-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid MEDIASUBTYPE_RGB4 = new Guid("e436eb79-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid MEDIASUBTYPE_RGB555 = new Guid("e436eb7c-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid MEDIASUBTYPE_RGB565 = new Guid("e436eb7b-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid MEDIASUBTYPE_RGB8 = new Guid("e436eb7a-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid MEDIASUBTYPE_UYVY = new Guid("59565955-0000-0010-8000-00AA00389B71");

		public static readonly Guid MEDIASUBTYPE_VIDEOIMAGE = new Guid("1d4a45f2-e5f6-4b44-8388-f0ae5c0e0c37");

		public static readonly Guid MEDIASUBTYPE_YUY2 = new Guid("32595559-0000-0010-8000-00AA00389B71");

		public static readonly Guid MEDIASUBTYPE_YV12 = new Guid("31313259-0000-0010-8000-00AA00389B71");

		public static readonly Guid MEDIASUBTYPE_YVU9 = new Guid("39555659-0000-0010-8000-00AA00389B71");

		public static readonly Guid MEDIASUBTYPE_YVYU = new Guid("55595659-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMFORMAT_MPEG2Video = new Guid("e06d80e3-db46-11cf-b4d1-00805f6cbbea");

		public static readonly Guid WMFORMAT_Script = new Guid("5C8510F2-DEBE-4ca7-BBA5-F07A104F8DFF");

		public static readonly Guid WMFORMAT_VideoInfo = new Guid("05589f80-c356-11ce-bf01-00aa0055595a");

		public static readonly Guid WMFORMAT_WaveFormatEx = new Guid("05589f81-c356-11ce-bf01-00aa0055595a");

		public static readonly Guid WMFORMAT_WebStream = new Guid("da1e6b13-8359-4050-b398-388e965bf00c");

		public static readonly Guid WMMEDIASUBTYPE_ACELPnet = new Guid("00000130-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_Base = new Guid("00000000-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_DRM = new Guid("00000009-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_MP3 = new Guid("00000055-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_MP43 = new Guid("3334504D-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_MP4S = new Guid("5334504D-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_M4S2 = new Guid("3253344D-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_P422 = new Guid("32323450-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_MPEG2_VIDEO = new Guid("e06d8026-db46-11cf-b4d1-00805f6cbbea");

		public static readonly Guid WMMEDIASUBTYPE_MSS1 = new Guid("3153534D-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_MSS2 = new Guid("3253534D-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_PCM = new Guid("00000001-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_WebStream = new Guid("776257d4-c627-41cb-8f81-7ac7ff1c40cc");

		public static readonly Guid WMMEDIASUBTYPE_WMAudio_Lossless = new Guid("00000163-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_WMAudioV2 = new Guid("00000161-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_WMAudioV7 = new Guid("00000161-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_WMAudioV8 = new Guid("00000161-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_WMAudioV9 = new Guid("00000162-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_WMSP1 = new Guid("0000000A-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_WMV1 = new Guid("31564D57-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_WMV2 = new Guid("32564D57-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_WMV3 = new Guid("33564D57-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_WMVA = new Guid("41564D57-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_WMVP = new Guid("50564D57-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIASUBTYPE_WVP2 = new Guid("32505657-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIATYPE_Audio = new Guid("73647561-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIATYPE_FileTransfer = new Guid("D9E47579-930E-4427-ADFC-AD80F290E470");

		public static readonly Guid WMMEDIATYPE_Image = new Guid("34A50FD8-8AA5-4386-81FE-A0EFE0488E31");

		public static readonly Guid WMMEDIATYPE_Script = new Guid("73636d64-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMMEDIATYPE_Text = new Guid("9BBA1EA7-5AB2-4829-BA57-0940209BCF3E");

		public static readonly Guid WMMEDIATYPE_Video = new Guid("73646976-0000-0010-8000-00AA00389B71");

		public static readonly Guid WMSCRIPTTYPE_TwoStrings = new Guid("82f38a70-c29f-11d1-97ad-00a0c95ea850");

		public static readonly Guid MEDIASUBTYPE_WAVE = new Guid("e436eb8b-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid MEDIASUBTYPE_AU = new Guid("e436eb8c-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid MEDIASUBTYPE_AIFF = new Guid("e436eb8d-524f-11ce-9f53-0020af0ba770");

		public static readonly Guid[] AudioSubTypes = new Guid[13]
		{
			MEDIASUBTYPE_PCM, MEDIASUBTYPE_PCMAudioObsolete, MEDIASUBTYPE_MPEG1Packet, MEDIASUBTYPE_MPEG1Payload, MEDIASUBTYPE_MPEG2_AUDIO, MEDIASUBTYPE_DVD_LPCM_AUDIO, MEDIASUBTYPE_DRM_Audio, MEDIASUBTYPE_IEEE_FLOAT, MEDIASUBTYPE_DOLBY_AC3, MEDIASUBTYPE_DOLBY_AC3_SPDIF,
			MEDIASUBTYPE_RAW_SPORT, MEDIASUBTYPE_SPDIF_TAG_241h, WMMEDIASUBTYPE_MP3
		};

		public static readonly string[] AudioSubTypeNames = new string[13]
		{
			"PCM", "PCM Obsolete", "MPEG1Packet", "MPEG1Payload", "MPEG2_AUDIO", "DVD_LPCM_AUDIO", "DRM_Audio", "IEEE_FLOAT", "DOLBY_AC3", "DOLBY_AC3_SPDIF",
			"RAW_SPORT", "SPDIF_TAG_241h", "MP3"
		};

		public static string GetAudioSubtypeName(Guid subType)
		{
			for (int i = 0; i < AudioSubTypes.Length; i++)
			{
				if (subType == AudioSubTypes[i])
				{
					return AudioSubTypeNames[i];
				}
			}
			return subType.ToString();
		}
	}
}
namespace NAudio.Utils
{
	public static class BufferHelpers
	{
		public static byte[] Ensure(byte[] buffer, int bytesRequired)
		{
			if (buffer == null || buffer.Length < bytesRequired)
			{
				buffer = new byte[bytesRequired];
			}
			return buffer;
		}

		public static float[] Ensure(float[] buffer, int samplesRequired)
		{
			if (buffer == null || buffer.Length < samplesRequired)
			{
				buffer = new float[samplesRequired];
			}
			return buffer;
		}
	}
	public static class ByteArrayExtensions
	{
		public static bool IsEntirelyNull(byte[] buffer)
		{
			for (int i = 0; i < buffer.Length; i++)
			{
				if (buffer[i] != 0)
				{
					return false;
				}
			}
			return true;
		}

		public static string DescribeAsHex(byte[] buffer, string separator, int bytesPerLine)
		{
			StringBuilder stringBuilder = new StringBuilder();
			int num = 0;
			foreach (byte b in buffer)
			{
				stringBuilder.AppendFormat("{0:X2}{1}", b, separator);
				if (++num % bytesPerLine == 0)
				{
					stringBuilder.Append("\r\n");
				}
			}
			stringBuilder.Append("\r\n");
			return stringBuilder.ToString();
		}

		public static string DecodeAsString(byte[] buffer, int offset, int length, Encoding encoding)
		{
			for (int i = 0; i < length; i++)
			{
				if (buffer[offset + i] == 0)
				{
					length = i;
				}
			}
			return encoding.GetString(buffer, offset, length);
		}

		public static byte[] Concat(params byte[][] byteArrays)
		{
			int num = 0;
			byte[][] array = byteArrays;
			foreach (byte[] array2 in array)
			{
				num += array2.Length;
			}
			if (num <= 0)
			{
				return new byte[0];
			}
			byte[] array3 = new byte[num];
			int num2 = 0;
			array = byteArrays;
			foreach (byte[] array4 in array)
			{
				Array.Copy(array4, 0, array3, num2, array4.Length);
				num2 += array4.Length;
			}
			return array3;
		}
	}
	public class ByteEncoding : Encoding
	{
		public static readonly ByteEncoding Instance = new ByteEncoding();

		private ByteEncoding()
		{
		}

		public override int GetByteCount(char[] chars, int index, int count)
		{
			return count;
		}

		public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
		{
			for (int i = 0; i < charCount; i++)
			{
				bytes[byteIndex + i] = (byte)chars[charIndex + i];
			}
			return charCount;
		}

		public override int GetCharCount(byte[] bytes, int index, int count)
		{
			for (int i = 0; i < count; i++)
			{
				if (bytes[index + i] == 0)
				{
					return i;
				}
			}
			return count;
		}

		public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
		{
			for (int i = 0; i < byteCount; i++)
			{
				byte b = bytes[byteIndex + i];
				if (b == 0)
				{
					return i;
				}
				chars[charIndex + i] = (char)b;
			}
			return byteCount;
		}

		public override int GetMaxCharCount(int byteCount)
		{
			return byteCount;
		}

		public override int GetMaxByteCount(int charCount)
		{
			return charCount;
		}
	}
	public class ChunkIdentifier
	{
		public static int ChunkIdentifierToInt32(string s)
		{
			if (s.Length != 4)
			{
				throw new ArgumentException("Must be a four character string");
			}
			byte[] bytes = Encoding.UTF8.GetBytes(s);
			if (bytes.Length != 4)
			{
				throw new ArgumentException("Must encode to exactly four bytes");
			}
			return BitConverter.ToInt32(bytes, 0);
		}
	}
	public class CircularBuffer
	{
		private readonly byte[] buffer;

		private readonly object lockObject;

		private int writePosition;

		private int readPosition;

		private int byteCount;

		public int MaxLength => buffer.Length;

		public int Count
		{
			get
			{
				lock (lockObject)
				{
					return byteCount;
				}
			}
		}

		public CircularBuffer(int size)
		{
			buffer = new byte[size];
			lockObject = new object();
		}

		public int Write(byte[] data, int offset, int count)
		{
			lock (lockObject)
			{
				int num = 0;
				if (count > buffer.Length - byteCount)
				{
					count = buffer.Length - byteCount;
				}
				int num2 = Math.Min(buffer.Length - writePosition, count);
				Array.Copy(data, offset, buffer, writePosition, num2);
				writePosition += num2;
				writePosition %= buffer.Length;
				num += num2;
				if (num < count)
				{
					Array.Copy(data, offset + num, buffer, writePosition, count - num);
					writePosition += count - num;
					num = count;
				}
				byteCount += num;
				return num;
			}
		}

		public int Read(byte[] data, int offset, int count)
		{
			lock (lockObject)
			{
				if (count > byteCount)
				{
					count = byteCount;
				}
				int num = 0;
				int num2 = Math.Min(buffer.Length - readPosition, count);
				Array.Copy(buffer, readPosition, data, offset, num2);
				num += num2;
				readPosition += num2;
				readPosition %= buffer.Length;
				if (num < count)
				{
					Array.Copy(buffer, readPosition, data, offset + num, count - num);
					readPosition += count - num;
					num = count;
				}
				byteCount -= num;
				return num;
			}
		}

		public void Reset()
		{
			lock (lockObject)
			{
				ResetInner();
			}
		}

		private void ResetInner()
		{
			byteCount = 0;
			readPosition = 0;
			writePosition = 0;
		}

		public void Advance(int count)
		{
			lock (lockObject)
			{
				if (count >= byteCount)
				{
					ResetInner();
					return;
				}
				byteCount -= count;
				readPosition += count;
				readPosition %= MaxLength;
			}
		}
	}
	public class Decibels
	{
		private const double LOG_2_DB = 8.685889638065037;

		private const double DB_2_LOG = 0.11512925464970228;

		public static double LinearToDecibels(double lin)
		{
			return Math.Log(lin) * 8.685889638065037;
		}

		public static double DecibelsToLinear(double dB)
		{
			return Math.Exp(dB * 0.11512925464970228);
		}
	}
	[AttributeUsage(AttributeTargets.Field)]
	public class FieldDescriptionAttribute : Attribute
	{
		public string Description { get; }

		public FieldDescriptionAttribute(string description)
		{
			Description = description;
		}

		public override string ToString()
		{
			return Description;
		}
	}
	public static class FieldDescriptionHelper
	{
		public static string Describe(Type t, Guid guid)
		{
			FieldInfo[] fields = t.GetFields(BindingFlags.Static | BindingFlags.Public);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!fieldInfo.IsPublic || !fieldInfo.IsStatic || !(fieldInfo.FieldType == typeof(Guid)) || !((Guid)fieldInfo.GetValue(null) == guid))
				{
					continue;
				}
				object[] customAttributes = fieldInfo.GetCustomAttributes(inherit: false);
				for (int j = 0; j < customAttributes.Length; j++)
				{
					if (customAttributes[j] is FieldDescriptionAttribute fieldDescriptionAttribute)
					{
						return fieldDescriptionAttribute.Description;
					}
				}
				return fieldInfo.Name;
			}
			return guid.ToString();
		}
	}
	public static class HResult
	{
		public const int S_OK = 0;

		public const int S_FALSE = 1;

		public const int E_INVALIDARG = -2147483645;

		private const int FACILITY_AAF = 18;

		private const int FACILITY_ACS = 20;

		private const int FACILITY_BACKGROUNDCOPY = 32;

		private const int FACILITY_CERT = 11;

		private const int FACILITY_COMPLUS = 17;

		private const int FACILITY_CONFIGURATION = 33;

		private const int FACILITY_CONTROL = 10;

		private const int FACILITY_DISPATCH = 2;

		private const int FACILITY_DPLAY = 21;

		private const int FACILITY_HTTP = 25;

		private const int FACILITY_INTERNET = 12;

		private const int FACILITY_ITF = 4;

		private const int FACILITY_MEDIASERVER = 13;

		private const int FACILITY_MSMQ = 14;

		private const int FACILITY_NULL = 0;

		private const int FACILITY_RPC = 1;

		private const int FACILITY_SCARD = 16;

		private const int FACILITY_SECURITY = 9;

		private const int FACILITY_SETUPAPI = 15;

		private const int FACILITY_SSPI = 9;

		private const int FACILITY_STORAGE = 3;

		private const int FACILITY_SXS = 23;

		private const int FACILITY_UMI = 22;

		private const int FACILITY_URT = 19;

		private const int FACILITY_WIN32 = 7;

		private const int FACILITY_WINDOWS = 8;

		private const int FACILITY_WINDOWS_CE = 24;

		public static int MAKE_HRESULT(int sev, int fac, int code)
		{
			return (sev << 31) | (fac << 16) | code;
		}

		public static int GetHResult(this COMException exception)
		{
			return exception.ErrorCode;
		}
	}
	public static class IEEE
	{
		private static double UnsignedToFloat(ulong u)
		{
			return (double)(long)(u - int.MaxValue - 1) + 2147483648.0;
		}

		private static double ldexp(double x, int exp)
		{
			return x * Math.Pow(2.0, exp);
		}

		private static double frexp(double x, out int exp)
		{
			exp = (int)Math.Floor(Math.Log(x) / Math.Log(2.0)) + 1;
			return 1.0 - (Math.Pow(2.0, exp) - x) / Math.Pow(2.0, exp);
		}

		private static ulong FloatToUnsigned(double f)
		{
			return (ulong)((long)(f - 2147483648.0) + int.MaxValue + 1);
		}

		public static byte[] ConvertToIeeeExtended(double num)
		{
			int num2;
			if (num < 0.0)
			{
				num2 = 32768;
				num *= -1.0;
			}
			else
			{
				num2 = 0;
			}
			ulong num4;
			ulong num5;
			int num3;
			if (num == 0.0)
			{
				num3 = 0;
				num4 = 0uL;
				num5 = 0uL;
			}
			else
			{
				double num6 = frexp(num, out num3);
				if (num3 > 16384 || !(num6 < 1.0))
				{
					num3 = num2 | 0x7FFF;
					num4 = 0uL;
					num5 = 0uL;
				}
				else
				{
					num3 += 16382;
					if (num3 < 0)
					{
						num6 = ldexp(num6, num3);
						num3 = 0;
					}
					num3 |= num2;
					num6 = ldexp(num6, 32);
					double num7 = Math.Floor(num6);
					num4 = FloatToUnsigned(num7);
					num6 = ldexp(num6 - num7, 32);
					num7 = Math.Floor(num6);
					num5 = FloatToUnsigned(num7);
				}
			}
			return new byte[10]
			{
				(byte)(num3 >> 8),
				(byte)num3,
				(byte)(num4 >> 24),
				(byte)(num4 >> 16),
				(byte)(num4 >> 8),
				(byte)num4,
				(byte)(num5 >> 24),
				(byte)(num5 >> 16),
				(byte)(num5 >> 8),
				(byte)num5
			};
		}

		public static double ConvertFromIeeeExtended(byte[] bytes)
		{
			if (bytes.Length != 10)
			{
				throw new Exception("Incorrect length for IEEE extended.");
			}
			int num = ((bytes[0] & 0x7F) << 8) | bytes[1];
			uint num2 = (uint)((bytes[2] << 24) | (bytes[3] << 16) | (bytes[4] << 8) | bytes[5]);
			uint num3 = (uint)((bytes[6] << 24) | (bytes[7] << 16) | (bytes[8] << 8) | bytes[9]);
			double num4;
			if (num == 0 && num2 == 0 && num3 == 0)
			{
				num4 = 0.0;
			}
			else if (num == 32767)
			{
				num4 = double.NaN;
			}
			else
			{
				num -= 16383;
				num4 = ldexp(UnsignedToFloat(num2), num -= 31);
				num4 += ldexp(UnsignedToFloat(num3), num -= 32);
			}
			if ((bytes[0] & 0x80) == 128)
			{
				return 0.0 - num4;
			}
			return num4;
		}
	}
	public class IgnoreDisposeStream : Stream
	{
		public Stream SourceStream { get; private set; }

		public bool IgnoreDispose { get; set; }

		public override bool CanRead => SourceStream.CanRead;

		public override bool CanSeek => SourceStream.CanSeek;

		public override bool CanWrite => SourceStream.CanWrite;

		public override long Length => SourceStream.Length;

		public override long Position
		{
			get
			{
				return SourceStream.Position;
			}
			set
			{
				SourceStream.Position = value;
			}
		}

		public IgnoreDisposeStream(Stream sourceStream)
		{
			SourceStream = sourceStream;
			IgnoreDispose = true;
		}

		public override void Flush()
		{
			SourceStream.Flush();
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			return SourceStream.Read(buffer, offset, count);
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			return SourceStream.Seek(offset, origin);
		}

		public override void SetLength(long value)
		{
			SourceStream.SetLength(value);
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			SourceStream.Write(buffer, offset, count);
		}

		protected override void Dispose(bool disposing)
		{
			if (!IgnoreDispose)
			{
				SourceStream.Dispose();
				SourceStream = null;
			}
		}
	}
	public static class NativeMethods
	{
		[DllImport("kernel32.dll")]
		public static extern IntPtr LoadLibrary(string dllToLoad);

		[DllImport("kernel32.dll")]
		public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

		[DllImport("kernel32.dll")]
		public static extern bool FreeLibrary(IntPtr hModule);
	}
	public static class WavePositionExtensions
	{
		public static TimeSpan GetPositionTimeSpan(this IWavePosition @this)
		{
			return TimeSpan.FromMilliseconds((double)(@this.GetPosition() / (@this.OutputWaveFormat.Channels * @this.OutputWaveFormat.BitsPerSample / 8)) * 1000.0 / (double)@this.OutputWaveFormat.SampleRate);
		}
	}
}
namespace NAudio.FileFormats.Wav
{
	public class WaveFileChunkReader
	{
		private WaveFormat waveFormat;

		private long dataChunkPosition;

		private long dataChunkLength;

		private List<RiffChunk> riffChunks;

		private readonly bool strictMode;

		private bool isRf64;

		private readonly bool storeAllChunks;

		private long riffSize;

		public WaveFormat WaveFormat => waveFormat;

		public long DataChunkPosition => dataChunkPosition;

		public long DataChunkLength => dataChunkLength;

		public List<RiffChunk> RiffChunks => riffChunks;

		public WaveFileChunkReader()
		{
			storeAllChunks = true;
			strictMode = false;
		}

		public void ReadWaveHeader(Stream stream)
		{
			dataChunkPosition = -1L;
			waveFormat = null;
			riffChunks = new List<RiffChunk>();
			dataChunkLength = 0L;
			BinaryReader binaryReader = new BinaryReader(stream);
			ReadRiffHeader(binaryReader);
			riffSize = binaryReader.ReadUInt32();
			if (binaryReader.ReadInt32() != ChunkIdentifier.ChunkIdentifierToInt32("WAVE"))
			{
				throw new FormatException("Not a WAVE file - no WAVE header");
			}
			if (isRf64)
			{
				ReadDs64Chunk(binaryReader);
			}
			int num = ChunkIdentifier.ChunkIdentifierToInt32("data");
			int num2 = ChunkIdentifier.ChunkIdentifierToInt32("fmt ");
			long num3 = Math.Min(riffSize + 8, stream.Length);
			while (stream.Position <= num3 - 8)
			{
				int num4 = binaryReader.ReadInt32();
				uint num5 = binaryReader.ReadUInt32();
				if (num4 == num)
				{
					dataChunkPosition = stream.Position;
					if (!isRf64)
					{
						dataChunkLength = num5;
					}
					stream.Position += num5;
				}
				else if (num4 == num2)
				{
					if (num5 > int.MaxValue)
					{
						throw new InvalidDataException($"Format chunk length must be between 0 and {int.MaxValue}.");
					}
					waveFormat = WaveFormat.FromFormatChunk(binaryReader, (int)num5);
				}
				else
				{
					if (num5 > stream.Length - stream.Position)
					{
						if (!strictMode)
						{
						}
						break;
					}
					if (storeAllChunks)
					{
						if (num5 > int.MaxValue)
						{
							throw new InvalidDataException($"RiffChunk chunk length must be between 0 and {int.MaxValue}.");
						}
						riffChunks.Add(GetRiffChunk(stream, num4, (int)num5));
					}
					stream.Position += num5;
				}
				if (num5 % 2 != 0 && binaryReader.PeekChar() == 0)
				{
					stream.Position++;
				}
			}
			if (waveFormat == null)
			{
				throw new FormatException("Invalid WAV file - No fmt chunk found");
			}
			if (dataChunkPosition == -1)
			{
				throw new FormatException("Invalid WAV file - No data chunk found");
			}
		}

		private void ReadDs64Chunk(BinaryReader reader)
		{
			int num = ChunkIdentifier.ChunkIdentifierToInt32("ds64");
			if (reader.ReadInt32() != num)
			{
				throw new FormatException("Invalid RF64 WAV file - No ds64 chunk found");
			}
			int num2 = reader.ReadInt32();
			riffSize = reader.ReadInt64();
			dataChunkLength = reader.ReadInt64();
			reader.ReadInt64();
			reader.ReadBytes(num2 - 24);
		}

		private static RiffChunk GetRiffChunk(Stream stream, int chunkIdentifier, int chunkLength)
		{
			return new RiffChunk(chunkIdentifier, chunkLength, stream.Position);
		}

		private void ReadRiffHeader(BinaryReader br)
		{
			int num = br.ReadInt32();
			if (num == ChunkIdentifier.ChunkIdentifierToInt32("RF64"))
			{
				isRf64 = true;
			}
			else if (num != ChunkIdentifier.ChunkIdentifierToInt32("RIFF"))
			{
				throw new FormatException("Not a WAVE file - no RIFF header");
			}
		}
	}
}
namespace NAudio.SoundFont
{
	public class Generator
	{
		public GeneratorEnum GeneratorType { get; set; }

		public ushort UInt16Amount { get; set; }

		public short Int16Amount
		{
			get
			{
				return (short)UInt16Amount;
			}
			set
			{
				UInt16Amount = (ushort)value;
			}
		}

		public byte LowByteAmount
		{
			get
			{
				return (byte)(UInt16Amount & 0xFFu);
			}
			set
			{
				UInt16Amount &= 65280;
				UInt16Amount += value;
			}
		}

		public byte HighByteAmount
		{
			get
			{
				return (byte)((UInt16Amount & 0xFF00) >> 8);
			}
			set
			{
				UInt16Amount &= 255;
				UInt16Amount += (ushort)(value << 8);
			}
		}

		public Instrument Instrument { get; set; }

		public SampleHeader SampleHeader { get; set; }

		public override string ToString()
		{
			if (GeneratorType == GeneratorEnum.Instrument)
			{
				return "Generator Instrument " + Instrument.Name;
			}
			if (GeneratorType == GeneratorEnum.SampleID)
			{
				return $"Generator SampleID {SampleHeader}";
			}
			return $"Generator {GeneratorType} {UInt16Amount}";
		}
	}
	internal class GeneratorBuilder : StructureBuilder<Generator>
	{
		public override int Length => 4;

		public Generator[] Generators => data.ToArray();

		public override Generator Read(BinaryReader br)
		{
			Generator generator = new Generator();
			generator.GeneratorType = (GeneratorEnum)br.ReadUInt16();
			generator.UInt16Amount = br.ReadUInt16();
			data.Add(generator);
			return generator;
		}

		public override void Write(BinaryWriter bw, Generator o)
		{
		}

		public void Load(Instrument[] instruments)
		{
			Generator[] generators = Generators;
			foreach (Generator generator in generators)
			{
				if (generator.GeneratorType == GeneratorEnum.Instrument)
				{
					generator.Instrument = instruments[generator.UInt16Amount];
				}
			}
		}

		public void Load(SampleHeader[] sampleHeaders)
		{
			Generator[] generators = Generators;
			foreach (Generator generator in generators)
			{
				if (generator.GeneratorType == GeneratorEnum.SampleID)
				{
					generator.SampleHeader = sampleHeaders[generator.UInt16Amount];
				}
			}
		}
	}
	public enum GeneratorEnum
	{
		StartAddressOffset,
		EndAddressOffset,
		StartLoopAddressOffset,
		EndLoopAddressOffset,
		StartAddressCoarseOffset,
		ModulationLFOToPitch,
		VibratoLFOToPitch,
		ModulationEnvelopeToPitch,
		InitialFilterCutoffFrequency,
		InitialFilterQ,
		ModulationLFOToFilterCutoffFrequency,
		ModulationEnvelopeToFilterCutoffFrequency,
		EndAddressCoarseOffset,
		ModulationLFOToVolume,
		Unused1,
		ChorusEffectsSend,
		ReverbEffectsSend,
		Pan,
		Unused2,
		Unused3,
		Unused4,
		DelayModulationLFO,
		FrequencyModulationLFO,
		DelayVibratoLFO,
		FrequencyVibratoLFO,
		DelayModulationEnvelope,
		AttackModulationEnvelope,
		HoldModulationEnvelope,
		DecayModulationEnvelope,
		SustainModulationEnvelope,
		ReleaseModulationEnvelope,
		KeyNumberToModulationEnvelopeHold,
		KeyNumberToModulationEnvelopeDecay,
		DelayVolumeEnvelope,
		AttackVolumeEnvelope,
		HoldVolumeEnvelope,
		DecayVolumeEnvelope,
		SustainVolumeEnvelope,
		ReleaseVolumeEnvelope,
		KeyNumberToVolum