Decompiled source of BugleHero v0.2.0

NAudio.Core.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using NAudio.Dmo;
using NAudio.Dsp;
using NAudio.FileFormats.Wav;
using NAudio.Utils;
using NAudio.Wave;
using NAudio.Wave.SampleProviders;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Mark Heath")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("© Mark Heath 2023")]
[assembly: AssemblyFileVersion("2.2.1.0")]
[assembly: AssemblyInformationalVersion("2.2.1")]
[assembly: AssemblyProduct("NAudio.Core")]
[assembly: AssemblyTitle("NAudio.Core")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/naudio/NAudio")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.2.1.0")]
[module: UnverifiableCode]
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,
		KeyNumberToVolumeEnvelopeHold,
		KeyNumberToVolumeEnvelopeDecay,
		Instrument,
		Reserved1,
		KeyRange,
		VelocityRange,
		StartLoopAddressCoarseOffset,
		KeyNumber,
		Velocity,
		InitialAttenuation,
		Reserved2,
		EndLoopAddressCoarseOffset,
		CoarseTune,
		FineTune,
		SampleID,
		SampleModes,
		Reserved3,
		ScaleTuning,
		ExclusiveClass,
		OverridingRootKey,
		Unused5,
		UnusedEnd
	}
	public class InfoChunk
	{
		public SFVersion SoundFontVersion { get; }

		public string WaveTableSoundEngine { get; set; }

		public string BankName { get; set; }

		public string DataROM { get; set; }

		public string CreationDate { get; set; }

		public string Author { get; set; }

		public string TargetProduct { get; set; }

		public string Copyright { get; set; }

		public string Comments { get; set; }

		public string Tools { get; set; }

		public SFVersion ROMVersion { get; set; }

		internal InfoChunk(RiffChunk chunk)
		{
			bool flag = false;
			bool flag2 = false;
			if (chunk.ReadChunkID() != "INFO")
			{
				throw new InvalidDataException("Not an INFO chunk");
			}
			RiffChunk nextSubChunk;
			while ((nextSubChunk = chunk.GetNextSubChunk()) != null)
			{
				switch (nextSubChunk.ChunkID)
				{
				case "ifil":
					flag = true;
					SoundFontVersion = nextSubChunk.GetDataAsStructure(new SFVersionBuilder());
					break;
				case "isng":
					WaveTableSoundEngine = nextSubChunk.GetDataAsString();
					break;
				case "INAM":
					flag2 = true;
					BankName = nextSubChunk.GetDataAsString();
					break;
				case "irom":
					DataROM = nextSubChunk.GetDataAsString();
					break;
				case "iver":
					ROMVersion = nextSubChunk.GetDataAsStructure(new SFVersionBuilder());
					break;
				case "ICRD":
					CreationDate = nextSubChunk.GetDataAsString();
					break;
				case "IENG":
					Author = nextSubChunk.GetDataAsString();
					break;
				case "IPRD":
					TargetProduct = nextSubChunk.GetDataAsString();
					break;
				case "ICOP":
					Copyright = nextSubChunk.GetDataAsString();
					break;
				case "ICMT":
					Comments = nextSubChunk.GetDataAsString();
					break;
				case "ISFT":
					Tools = nextSubChunk.GetDataAsString();
					break;
				default:
					throw new InvalidDataException("Unknown chunk type " + nextSubChunk.ChunkID);
				}
			}
			if (!flag)
			{
				throw new InvalidDataException("Missing SoundFont version information");
			}
			if (!flag2)
			{
				throw new InvalidDataException("Missing SoundFont name information");
			}
		}

		public override string ToString()
		{
			return string.Format("Bank Name: {0}\r\nAuthor: {1}\r\nCopyright: {2}\r\nCreation Date: {3}\r\nTools: {4}\r\nComments: {5}\r\nSound Engine: {6}\r\nSoundFont Version: {7}\r\nTarget Product: {8}\r\nData ROM: {9}\r\nROM Version: {10}", BankName, Author, Copyright, CreationDate, Tools, "TODO-fix comments", WaveTableSoundEngine, SoundFontVersion, TargetProduct, DataROM, ROMVersion);
		}
	}
	public class Instrument
	{
		internal ushort startInstrumentZoneIndex;

		internal ushort endInstrumentZoneIndex;

		public string Name { get; set; }

		public Zone[] Zones { get; set; }

		public override string ToString()
		{
			return Name;
		}
	}
	internal class InstrumentBuilder : StructureBuilder<Instrument>
	{
		private Instrument lastInstrument;

		public override int Length => 22;

		public Instrument[] Instruments => data.ToArray();

		public override Instrument Read(BinaryReader br)
		{
			Instrument instrument = new Instrument();
			string text = Encoding.UTF8.GetString(br.ReadBytes(20), 0, 20);
			if (text.IndexOf('\0') >= 0)
			{
				text = text.Substring(0, text.IndexOf('\0'));
			}
			instrument.Name = text;
			instrument.startInstrumentZoneIndex = br.ReadUInt16();
			if (lastInstrument != null)
			{
				lastInstrument.endInstrumentZoneIndex = (ushort)(instrument.startInstrumentZoneIndex - 1);
			}
			data.Add(instrument);
			lastInstrument = instrument;
			return instrument;
		}

		public override void Write(BinaryWriter bw, Instrument instrument)
		{
		}

		public void LoadZones(Zone[] zones)
		{
			for (int i = 0; i < data.Count - 1; i++)
			{
				Instrument instrument = data[i];
				instrument.Zones = new Zone[instrument.endInstrumentZoneIndex - instrument.startInstrumentZoneIndex + 1];
				Array.Copy(zones, instrument.startInstrumentZoneIndex, instrument.Zones, 0, instrument.Zones.Length);
			}
			data.RemoveAt(data.Count - 1);
		}
	}
	public enum TransformEnum
	{
		Linear
	}
	public class Modulator
	{
		public ModulatorType SourceModulationData { get; set; }

		public GeneratorEnum DestinationGenerator { get; set; }

		public short Amount { get; set; }

		public ModulatorType SourceModulationAmount { get; set; }

		public TransformEnum SourceTransform { get; set; }

		public override string ToString()
		{
			return $"Modulator {SourceModulationData} {DestinationGenerator} {Amount} {SourceModulationAmount} {SourceTransform}";
		}
	}
	internal class ModulatorBuilder : StructureBuilder<Modulator>
	{
		public override int Length => 10;

		public Modulator[] Modulators => data.ToArray();

		public override Modulator Read(BinaryReader br)
		{
			Modulator modulator = new Modulator();
			modulator.SourceModulationData = new ModulatorType(br.ReadUInt16());
			modulator.DestinationGenerator = (GeneratorEnum)br.ReadUInt16();
			modulator.Amount = br.ReadInt16();
			modulator.SourceModulationAmount = new ModulatorType(br.ReadUInt16());
			modulator.SourceTransform = (TransformEnum)br.ReadUInt16();
			data.Add(modulator);
			return modulator;
		}

		public override void Write(BinaryWriter bw, Modulator o)
		{
		}
	}
	public enum ControllerSourceEnum
	{
		NoController = 0,
		NoteOnVelocity = 2,
		NoteOnKeyNumber = 3,
		PolyPressure = 10,
		ChannelPressure = 13,
		PitchWheel = 14,
		PitchWheelSensitivity = 16
	}
	public enum SourceTypeEnum
	{
		Linear,
		Concave,
		Convex,
		Switch
	}
	public class ModulatorType
	{
		private bool polarity;

		private bool direction;

		private bool midiContinuousController;

		private ControllerSourceEnum controllerSource;

		private SourceTypeEnum sourceType;

		private ushort midiContinuousControllerNumber;

		internal ModulatorType(ushort raw)
		{
			polarity = (raw & 0x200) == 512;
			direction = (raw & 0x100) == 256;
			midiContinuousController = (raw & 0x80) == 128;
			sourceType = (SourceTypeEnum)((raw & 0xFC00) >> 10);
			controllerSource = (ControllerSourceEnum)(raw & 0x7F);
			midiContinuousControllerNumber = (ushort)(raw & 0x7Fu);
		}

		public override string ToString()
		{
			if (midiContinuousController)
			{
				return $"{sourceType} CC{midiContinuousControllerNumber}";
			}
			return $"{sourceType} {controllerSource}";
		}
	}
	public class Preset
	{
		internal ushort startPresetZoneIndex;

		internal ushort endPresetZoneIndex;

		internal uint library;

		internal uint genre;

		internal uint morphology;

		public string Name { get; set; }

		public ushort PatchNumber { get; set; }

		public ushort Bank { get; set; }

		public Zone[] Zones { get; set; }

		public override string ToString()
		{
			return $"{Bank}-{PatchNumber} {Name}";
		}
	}
	internal class PresetBuilder : StructureBuilder<Preset>
	{
		private Preset lastPreset;

		public override int Length => 38;

		public Preset[] Presets => data.ToArray();

		public override Preset Read(BinaryReader br)
		{
			Preset preset = new Preset();
			string text = Encoding.UTF8.GetString(br.ReadBytes(20), 0, 20);
			if (text.IndexOf('\0') >= 0)
			{
				text = text.Substring(0, text.IndexOf('\0'));
			}
			preset.Name = text;
			preset.PatchNumber = br.ReadUInt16();
			preset.Bank = br.ReadUInt16();
			preset.startPresetZoneIndex = br.ReadUInt16();
			preset.library = br.ReadUInt32();
			preset.genre = br.ReadUInt32();
			preset.morphology = br.ReadUInt32();
			if (lastPreset != null)
			{
				lastPreset.endPresetZoneIndex = (ushort)(preset.startPresetZoneIndex - 1);
			}
			data.Add(preset);
			lastPreset = preset;
			return preset;
		}

		public override void Write(BinaryWriter bw, Preset preset)
		{
		}

		public void LoadZones(Zone[] presetZones)
		{
			for (int i = 0; i < data.Count - 1; i++)
			{
				Preset preset = data[i];
				preset.Zones = new Zone[preset.endPresetZoneIndex - preset.startPresetZoneIndex + 1];
				Array.Copy(presetZones, preset.startPresetZoneIndex, preset.Zones, 0, preset.Zones.Length);
			}
			data.RemoveAt(data.Count - 1);
		}
	}
	public class PresetsChunk
	{
		private PresetBuilder presetHeaders = new PresetBuilder();

		private ZoneBuilder presetZones = new ZoneBuilder();

		private ModulatorBuilder presetZoneModulators = new ModulatorBuilder();

		private GeneratorBuilder presetZoneGenerators = new GeneratorBuilder();

		private InstrumentBuilder instruments = new InstrumentBuilder();

		private ZoneBuilder instrumentZones = new ZoneBuilder();

		private ModulatorBuilder instrumentZoneModulators = new ModulatorBuilder();

		private GeneratorBuilder instrumentZoneGenerators = new GeneratorBuilder();

		private SampleHeaderBuilder sampleHeaders = new SampleHeaderBuilder();

		public Preset[] Presets => presetHeaders.Presets;

		public Instrument[] Instruments => instruments.Instruments;

		public SampleHeader[] SampleHeaders => sampleHeaders.SampleHeaders;

		internal PresetsChunk(RiffChunk chunk)
		{
			string text = chunk.ReadChunkID();
			if (text != "pdta")
			{
				throw new InvalidDataException($"Not a presets data chunk ({text})");
			}
			RiffChunk nextSubChunk;
			while ((nextSubChunk = chunk.GetNextSubChunk()) != null)
			{
				switch (nextSubChunk.ChunkID)
				{
				case "phdr":
				case "PHDR":
					nextSubChunk.GetDataAsStructureArray(presetHeaders);
					break;
				case "pbag":
				case "PBAG":
					nextSubChunk.GetDataAsStructureArray(presetZones);
					break;
				case "pmod":
				case "PMOD":
					nextSubChunk.GetDataAsStructureArray(presetZoneModulators);
					break;
				case "pgen":
				case "PGEN":
					nextSubChunk.GetDataAsStructureArray(presetZoneGenerators);
					break;
				case "inst":
				case "INST":
					nextSubChunk.GetDataAsStructureArray(instruments);
					break;
				case "ibag":
				case "IBAG":
					nextSubChunk.GetDataAsStructureArray(instrumentZones);
					break;
				case "imod":
				case "IMOD":
					nextSubChunk.GetDataAsStructureArray(instrumentZoneModulators);
					break;
				case "igen":
				case "IGEN":
					nextSubChunk.GetDataAsStructureArray(instrumentZoneGenerators);
					break;
				case "shdr":
				case "SHDR":
					nextSubChunk.GetDataAsStructureArray(sampleHeaders);
					break;
				default:
					throw new InvalidDataException($"Unknown chunk type {nextSubChunk.ChunkID}");
				}
			}
			instrumentZoneGenerators.Load(sampleHeaders.SampleHeaders);
			instrumentZones.Load(instrumentZoneModulators.Modulators, instrumentZoneGenerators.Generators);
			instruments.LoadZones(instrumentZones.Zones);
			presetZoneGenerators.Load(instruments.Instruments);
			presetZones.Load(presetZoneModulators.Modulators, presetZoneGenerators.Generators);
			presetHeaders.LoadZones(presetZones.Zones);
			sampleHeaders.RemoveEOS();
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("Preset Headers:\r\n");
			Preset[] presets = presetHeaders.Presets;
			foreach (Preset arg in presets)
			{
				stringBuilder.AppendFormat("{0}\r\n", arg);
			}
			stringBuilder.Append("Instruments:\r\n");
			Instrument[] array = instruments.Instruments;
			foreach (Instrument arg2 in array)
			{
				stringBuilder.AppendFormat("{0}\r\n", arg2);
			}
			return stringBuilder.ToString();
		}
	}
	internal class RiffChunk
	{
		private string chunkID;

		private BinaryReader riffFile;

		public string ChunkID
		{
			get
			{
				return chunkID;
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("ChunkID may not be null");
				}
				if (value.Length != 4)
				{
					throw new ArgumentException("ChunkID must be four characters");
				}
				chunkID = value;
			}
		}

		public uint ChunkSize { get; private set; }

		public long DataOffset { get; private set; }

		public static RiffChunk GetTopLevelChunk(BinaryReader file)
		{
			RiffChunk riffChunk = new RiffChunk(file);
			riffChunk.ReadChunk();
			return riffChunk;
		}

		private RiffChunk(BinaryReader file)
		{
			riffFile = file;
			chunkID = "????";
			ChunkSize = 0u;
			DataOffset = 0L;
		}

		public string ReadChunkID()
		{
			byte[] array = riffFile.ReadBytes(4);
			if (array.Length != 4)
			{
				throw new InvalidDataException("Couldn't read Chunk ID");
			}
			return ByteEncoding.Instance.GetString(array, 0, array.Length);
		}

		private void ReadChunk()
		{
			chunkID = ReadChunkID();
			ChunkSize = riffFile.ReadUInt32();
			DataOffset = riffFile.BaseStream.Position;
		}

		public RiffChunk GetNextSubChunk()
		{
			if (riffFile.BaseStream.Position + 8 < DataOffset + ChunkSize)
			{
				RiffChunk riffChunk = new RiffChunk(riffFile);
				riffChunk.ReadChunk();
				return riffChunk;
			}
			return null;
		}

		public byte[] GetData()
		{
			riffFile.BaseStream.Position = DataOffset;
			byte[] array = riffFile.ReadBytes((int)ChunkSize);
			if (array.Length != ChunkSize)
			{
				throw new InvalidDataException($"Couldn't read chunk's data Chunk: {this}, read {array.Length} bytes");
			}
			return array;
		}

		public string GetDataAsString()
		{
			byte[] data = GetData();
			if (data == null)
			{
				return null;
			}
			return ByteEncoding.Instance.GetString(data, 0, data.Length);
		}

		public T GetDataAsStructure<T>(StructureBuilder<T> s)
		{
			riffFile.BaseStream.Position = DataOffset;
			if (s.Length != ChunkSize)
			{
				throw new InvalidDataException($"Chunk size is: {ChunkSize} so can't read structure of: {s.Length}");
			}
			return s.Read(riffFile);
		}

		public T[] GetDataAsStructureArray<T>(StructureBuilder<T> s)
		{
			riffFile.BaseStream.Position = DataOffset;
			if (ChunkSize % s.Length != 0L)
			{
				throw new InvalidDataException($"Chunk size is: {ChunkSize} not a multiple of structure size: {s.Length}");
			}
			int num = (int)(ChunkSize / s.Length);
			T[] array = new T[num];
			for (int i = 0; i < num; i++)
			{
				array[i] = s.Read(riffFile);
			}
			return array;
		}

		public override string ToString()
		{
			return $"RiffChunk ID: {ChunkID} Size: {ChunkSize} Data Offset: {DataOffset}";
		}
	}
	internal class SampleDataChunk
	{
		public byte[] SampleData { get; private set; }

		public SampleDataChunk(RiffChunk chunk)
		{
			string text = chunk.ReadChunkID();
			if (text != "sdta")
			{
				throw new InvalidDataException("Not a sample data chunk (" + text + ")");
			}
			SampleData = chunk.GetData();
		}
	}
	public class SampleHeader
	{
		public string SampleName;

		public uint Start;

		public uint End;

		public uint StartLoop;

		public uint EndLoop;

		public uint SampleRate;

		public byte OriginalPitch;

		public sbyte PitchCorrection;

		public ushort SampleLink;

		public SFSampleLink SFSampleLink;

		public override string ToString()
		{
			return SampleName;
		}
	}
	internal class SampleHeaderBuilder : StructureBuilder<SampleHeader>
	{
		public override int Length => 46;

		public SampleHeader[] SampleHeaders => data.ToArray();

		public override SampleHeader Read(BinaryReader br)
		{
			SampleHeader sampleHeader = new SampleHeader();
			byte[] array = br.ReadBytes(20);
			sampleHeader.SampleName = ByteEncoding.Instance.GetString(array, 0, array.Length);
			sampleHeader.Start = br.ReadUInt32();
			sampleHeader.End = br.ReadUInt32();
			sampleHeader.StartLoop = br.ReadUInt32();
			sampleHeader.EndLoop = br.ReadUInt32();
			sampleHeader.SampleRate = br.ReadUInt32();
			sampleHeader.OriginalPitch = br.ReadByte();
			sampleHeader.PitchCorrection = br.ReadSByte();
			sampleHeader.SampleLink = br.ReadUInt16();
			sampleHeader.SFSampleLink = (SFSampleLink)br.ReadUInt16();
			data.Add(sampleHeader);
			return sampleHeader;
		}

		public override void Write(BinaryWriter bw, SampleHeader sampleHeader)
		{
		}

		internal void RemoveEOS()
		{
			data.RemoveAt(data.Count - 1);
		}
	}
	public enum SampleMode
	{
		NoLoop,
		LoopContinuously,
		ReservedNoLoop,
		LoopAndContinue
	}
	public enum SFSampleLink : ushort
	{
		MonoSample = 1,
		RightSample = 2,
		LeftSample = 4,
		LinkedSample = 8,
		RomMonoSample = 32769,
		RomRightSample = 32770,
		RomLeftSample = 32772,
		RomLinkedSample = 32776
	}
	public class SFVersion
	{
		public short Major { get; set; }

		public short Minor { get; set; }
	}
	internal class SFVersionBuilder : StructureBuilder<SFVersion>
	{
		public override int Length => 4;

		public override SFVersion Read(BinaryReader br)
		{
			SFVersion sFVersion = new SFVersion();
			sFVersion.Major = br.ReadInt16();
			sFVersion.Minor = br.ReadInt16();
			data.Add(sFVersion);
			return sFVersion;
		}

		public override void Write(BinaryWriter bw, SFVersion v)
		{
			bw.Write(v.Major);
			bw.Write(v.Minor);
		}
	}
	public class SoundFont
	{
		private InfoChunk info;

		private PresetsChunk presetsChunk;

		private SampleDataChunk sampleData;

		public InfoChunk FileInfo => info;

		public Preset[] Presets => presetsChunk.Presets;

		public Instrument[] Instruments => presetsChunk.Instruments;

		public SampleHeader[] SampleHeaders => presetsChunk.SampleHeaders;

		public byte[] SampleData => sampleData.SampleData;

		public SoundFont(string fileName)
			: this(new FileStream(fileName, FileMode.Open, FileAccess.Read))
		{
		}

		public SoundFont(Stream sfFile)
		{
			using (sfFile)
			{
				RiffChunk topLevelChunk = RiffChunk.GetTopLevelChunk(new BinaryReader(sfFile));
				if (topLevelChunk.ChunkID == "RIFF")
				{
					string text = topLevelChunk.ReadChunkID();
					if (text != "sfbk")
					{
						throw new InvalidDataException($"Not a SoundFont ({text})");
					}
					RiffChunk nextSubChunk = topLevelChunk.GetNextSubChunk();
					if (nextSubChunk.ChunkID == "LIST")
					{
						info = new InfoChunk(nextSubChunk);
						RiffChunk nextSubChunk2 = topLevelChunk.GetNextSubChunk();
						sampleData = new SampleDataChunk(nextSubChunk2);
						nextSubChunk2 = topLevelChunk.GetNextSubChunk();
						presetsChunk = new PresetsChunk(nextSubChunk2);
						return;
					}
					throw new InvalidDataException($"Not info list found ({nextSubChunk.ChunkID})");
				}
				throw new InvalidDataException("Not a RIFF file");
			}
		}

		public override string ToString()
		{
			return $"Info Chunk:\r\n{info}\r\nPresets Chunk:\r\n{presetsChunk}";
		}
	}
	internal abstract class StructureBuilder<T>
	{
		protected List<T> data;

		public abstract int Length { get; }

		public T[] Data => data.ToArray();

		public StructureBuilder()
		{
			Reset();
		}

		public abstract T Read(BinaryReader br);

		public abstract void Write(BinaryWriter bw, T o);

		public void Reset()
		{
			data = new List<T>();
		}
	}
	public class Zone
	{
		internal ushort generatorIndex;

		internal ushort modulatorIndex;

		internal ushort generatorCount;

		internal ushort modulatorCount;

		public Modulator[] Modulators { get; set; }

		public Generator[] Generators { get; set; }

		public override string ToString()
		{
			return $"Zone {generatorCount} Gens:{generatorIndex} {modulatorCount} Mods:{modulatorIndex}";
		}
	}
	internal class ZoneBuilder : StructureBuilder<Zone>
	{
		private Zone lastZone;

		public Zone[] Zones => data.ToArray();

		public override int Length => 4;

		public override Zone Read(BinaryReader br)
		{
			Zone zone = new Zone();
			zone.generatorIndex = br.ReadUInt16();
			zone.modulatorIndex = br.ReadUInt16();
			if (lastZone != null)
			{
				lastZone.generatorCount = (ushort)(zone.generatorIndex - lastZone.generatorIndex);
				lastZone.modulatorCount = (ushort)(zone.modulatorIndex - lastZone.modulatorIndex);
			}
			data.Add(zone);
			lastZone = zone;
			return zone;
		}

		public override void Write(BinaryWriter bw, Zone zone)
		{
		}

		public void Load(Modulator[] modulators, Generator[] generators)
		{
			for (int i = 0; i < data.Count - 1; i++)
			{
				Zone zone = data[i];
				zone.Generators = new Generator[zone.generatorCount];
				Array.Copy(generators, zone.generatorIndex, zone.Generators, 0, zone.generatorCount);
				zone.Modulators = new Modulator[zone.modulatorCount];
				Array.Copy(modulators, zone.modulatorIndex, zone.Modulators, 0, zone.modulatorCount);
			}
			data.RemoveAt(data.Count - 1);
		}
	}
}
namespace NAudio.Wave
{
	public enum ChannelMode
	{
		Stereo,
		JointStereo,
		DualChannel,
		Mono
	}
	public class Id3v2Tag
	{
		private long tagStartPosition;

		private long tagEndPosition;

		private byte[] rawData;

		public byte[] RawData => rawData;

		public static Id3v2Tag ReadTag(Stream input)
		{
			try
			{
				return new Id3v2Tag(input);
			}
			catch (FormatException)
			{
				return null;
			}
		}

		public static Id3v2Tag Create(IEnumerable<KeyValuePair<string, string>> tags)
		{
			return ReadTag(CreateId3v2TagStream(tags));
		}

		private static byte[] FrameSizeToBytes(int n)
		{
			byte[] bytes = BitConverter.GetBytes(n);
			Array.Reverse((Array)bytes);
			return bytes;
		}

		private static byte[] CreateId3v2Frame(string key, string value)
		{
			if (string.IsNullOrEmpty(key))
			{
				throw new ArgumentNullException("key");
			}
			if (string.IsNullOrEmpty(value))
			{
				throw new ArgumentNullException("value");
			}
			if (key.Length != 4)
			{
				throw new ArgumentOutOfRangeException("key", "key " + key + " must be 4 characters long");
			}
			byte[] array = new byte[2] { 255, 254 };
			byte[] array2 = new byte[3];
			byte[] array3 = new byte[2];
			byte[] array4 = ((!(key == "COMM")) ? ByteArrayExtensions.Concat(new byte[1] { 1 }, array, Encoding.Unicode.GetBytes(value)) : ByteArrayExtensions.Concat(new byte[1] { 1 }, array2, array3, array, Encoding.Unicode.GetBytes(value)));
			return ByteArrayExtensions.Concat(Encoding.UTF8.GetBytes(key), FrameSizeToBytes(array4.Length), new byte[2], array4);
		}

		private static byte[] GetId3TagHeaderSize(int size)
		{
			byte[] array = new byte[4];
			for (int num = array.Length - 1; num >= 0; num--)
			{
				array[num] = (byte)(size % 128);
				size /= 128;
			}
			return array;
		}

		private static byte[] CreateId3v2TagHeader(IEnumerable<byte[]> frames)
		{
			int num = 0;
			foreach (byte[] frame in frames)
			{
				num += frame.Length;
			}
			return ByteArrayExtensions.Concat(Encoding.UTF8.GetBytes("ID3"), new byte[2] { 3, 0 }, new byte[1], GetId3TagHeaderSize(num));
		}

		private static Stream CreateId3v2TagStream(IEnumerable<KeyValuePair<string, string>> tags)
		{
			List<byte[]> list = new List<byte[]>();
			foreach (KeyValuePair<string, string> tag in tags)
			{
				list.Add(CreateId3v2Frame(tag.Key, tag.Value));
			}
			byte[] array = CreateId3v2TagHeader(list);
			MemoryStream memoryStream = new MemoryStream();
			memoryStream.Write(array, 0, array.Length);
			foreach (byte[] item in list)
			{
				memoryStream.Write(item, 0, item.Length);
			}
			memoryStream.Position = 0L;
			return memoryStream;
		}

		private Id3v2Tag(Stream input)
		{
			tagStartPosition = input.Position;
			BinaryReader binaryReader = new BinaryReader(input);
			byte[] array = binaryReader.ReadBytes(10);
			if (array.Length >= 3 && array[0] == 73 && array[1] == 68 && array[2] == 51)
			{
				if ((array[5] & 0x40) == 64)
				{
					byte[] array2 = binaryReader.ReadBytes(4);
					_ = array2[0] * 2097152 + array2[1] * 16384 + array2[2] * 128;
					_ = array2[3];
				}
				int num = array[6] * 2097152;
				num += array[7] * 16384;
				num += array[8] * 128;
				num += array[9];
				binaryReader.ReadBytes(num);
				if ((array[5] & 0x10) == 16)
				{
					binaryReader.ReadBytes(10);
				}
				tagEndPosition = input.Position;
				input.Position = tagStartPosition;
				rawData = binaryReader.ReadBytes((int)(tagEndPosition - tagStartPosition));
				return;
			}
			input.Position = tagStartPosition;
			throw new FormatException("Not an ID3v2 tag");
		}
	}
	public interface IMp3FrameDecompressor : IDisposable
	{
		WaveFormat OutputFormat { get; }

		int DecompressFrame(Mp3Frame frame, byte[] dest, int destOffset);

		void Reset();
	}
	public class Mp3Frame
	{
		private static readonly int[,,] bitRates = new int[2, 3, 15]
		{
			{
				{
					0, 32, 64, 96, 128, 160, 192, 224, 256, 288,
					320, 352, 384, 416, 448
				},
				{
					0, 32, 48, 56, 64, 80, 96, 112, 128, 160,
					192, 224, 256, 320, 384
				},
				{
					0, 32, 40, 48, 56, 64, 80, 96, 112, 128,
					160, 192, 224, 256, 320
				}
			},
			{
				{
					0, 32, 48, 56, 64, 80, 96, 112, 128, 144,
					160, 176, 192, 224, 256
				},
				{
					0, 8, 16, 24, 32, 40, 48, 56, 64, 80,
					96, 112, 128, 144, 160
				},
				{
					0, 8, 16, 24, 32, 40, 48, 56, 64, 80,
					96, 112, 128, 144, 160
				}
			}
		};

		private static readonly int[,] samplesPerFrame = new int[2, 3]
		{
			{ 384, 1152, 1152 },
			{ 384, 1152, 576 }
		};

		private static readonly int[] sampleRatesVersion1 = new int[3] { 44100, 48000, 32000 };

		private static readonly int[] sampleRatesVersion2 = new int[3] { 22050, 24000, 16000 };

		private static readonly int[] sampleRatesVersion25 = new int[3] { 11025, 12000, 8000 };

		private const int MaxFrameLength = 16384;

		public int SampleRate { get; private set; }

		public int FrameLength { get; private set; }

		public int BitRate { get; private set; }

		public byte[] RawData { get; private set; }

		public MpegVersion MpegVersion { get; private set; }

		public MpegLayer MpegLayer { get; private set; }

		public ChannelMode ChannelMode { get; private set; }

		public int SampleCount { get; private set; }

		public int ChannelExtension { get; private set; }

		public int BitRateIndex { get; private set; }

		public bool Copyright { get; private set; }

		public bool CrcPresent { get; private set; }

		public long FileOffset { get; private set; }

		public static Mp3Frame LoadFromStream(Stream input)
		{
			return LoadFromStream(input, readData: true);
		}

		public static Mp3Frame LoadFromStream(Stream input, bool readData)
		{
			Mp3Frame mp3Frame = new Mp3Frame();
			mp3Frame.FileOffset = input.Position;
			byte[] array = new byte[4];
			if (input.Read(array, 0, array.Length) < array.Length)
			{
				return null;
			}
			while (!IsValidHeader(array, mp3Frame))
			{
				array[0] = array[1];
				array[1] = array[2];
				array[2] = array[3];
				if (input.Read(array, 3, 1) < 1)
				{
					return null;
				}
				mp3Frame.FileOffset++;
			}
			int num = mp3Frame.FrameLength - 4;
			if (readData)
			{
				mp3Frame.RawData = new byte[mp3Frame.FrameLength];
				Array.Copy(array, mp3Frame.RawData, 4);
				if (input.Read(mp3Frame.RawData, 4, num) < num)
				{
					throw new EndOfStreamException("Unexpected end of stream before frame complete");
				}
			}
			else
			{
				input.Position += num;
			}
			return mp3Frame;
		}

		private Mp3Frame()
		{
		}

		private static bool IsValidHeader(byte[] headerBytes, Mp3Frame frame)
		{
			if (headerBytes[0] == byte.MaxValue && (headerBytes[1] & 0xE0) == 224)
			{
				frame.MpegVersion = (MpegVersion)((headerBytes[1] & 0x18) >> 3);
				if (frame.MpegVersion == MpegVersion.Reserved)
				{
					return false;
				}
				frame.MpegLayer = (MpegLayer)((headerBytes[1] & 6) >> 1);
				if (frame.MpegLayer == MpegLayer.Reserved)
				{
					return false;
				}
				int num = ((frame.MpegLayer != MpegLayer.Layer1) ? ((frame.MpegLayer == MpegLayer.Layer2) ? 1 : 2) : 0);
				frame.CrcPresent = (headerBytes[1] & 1) == 0;
				frame.BitRateIndex = (headerBytes[2] & 0xF0) >> 4;
				if (frame.BitRateIndex == 15)
				{
					return false;
				}
				int num2 = ((frame.MpegVersion != MpegVersion.Version1) ? 1 : 0);
				frame.BitRate = bitRates[num2, num, frame.BitRateIndex] * 1000;
				if (frame.BitRate == 0)
				{
					return false;
				}
				int num3 = (headerBytes[2] & 0xC) >> 2;
				if (num3 == 3)
				{
					return false;
				}
				if (frame.MpegVersion == MpegVersion.Version1)
				{
					frame.SampleRate = sampleRatesVersion1[num3];
				}
				else if (frame.MpegVersion == MpegVersion.Version2)
				{
					frame.SampleRate = sampleRatesVersion2[num3];
				}
				else
				{
					frame.SampleRate = sampleRatesVersion25[num3];
				}
				bool flag = (headerBytes[2] & 2) == 2;
				_ = headerBytes[2];
				frame.ChannelMode = (ChannelMode)((headerBytes[3] & 0xC0) >> 6);
				frame.ChannelExtension = (headerBytes[3] & 0x30) >> 4;
				if (frame.ChannelExtension != 0 && frame.ChannelMode != ChannelMode.JointStereo)
				{
					return false;
				}
				frame.Copyright = (headerBytes[3] & 8) == 8;
				_ = headerBytes[3];
				_ = headerBytes[3];
				int num4 = (flag ? 1 : 0);
				frame.SampleCount = samplesPerFrame[num2, num];
				int num5 = frame.SampleCount / 8;
				if (frame.MpegLayer == MpegLayer.Layer1)
				{
					frame.FrameLength = (num5 * frame.BitRate / frame.SampleRate + num4) * 4;
				}
				else
				{
					frame.FrameLength = num5 * frame.BitRate / frame.SampleRate + num4;
				}
				if (frame.FrameLength > 16384)
				{
					return false;
				}
				return true;
			}
			return false;
		}
	}
	public enum MpegLayer
	{
		Reserved,
		Layer3,
		Layer2,
		Layer1
	}
	public enum MpegVersion
	{
		Version25,
		Reserved,
		Version2,
		Version1
	}
	public class XingHeader
	{
		[Flags]
		private enum XingHeaderOptions
		{
			Frames = 1,
			Bytes = 2,
			Toc = 4,
			VbrScale = 8
		}

		private static int[] sr_table = new int[4] { 44100, 48000, 32000, 99999 };

		private int vbrScale = -1;

		private int startOffset;

		private int endOffset;

		private int tocOffset = -1;

		private int framesOffset = -1;

		private int bytesOffset = -1;

		private Mp3Frame frame;

		public int Frames
		{
			get
			{
				if (framesOffset == -1)
				{
					return -1;
				}
				return ReadBigEndian(frame.RawData, framesOffset);
			}
			set
			{
				if (framesOffset == -1)
				{
					throw new InvalidOperationException("Frames flag is not set");
				}
				WriteBigEndian(frame.RawData, framesOffset, value);
			}
		}

		public int Bytes
		{
			get
			{
				if (bytesOffset == -1)
				{
					return -1;
				}
				return ReadBigEndian(frame.RawData, bytesOffset);
			}
			set
			{
				if (framesOffset == -1)
				{
					throw new InvalidOperationException("Bytes flag is not set");
				}
				WriteBigEndian(frame.RawData, bytesOffset, value);
			}
		}

		public int VbrScale => vbrScale;

		public Mp3Frame Mp3Frame => frame;

		private static int ReadBigEndian(byte[] buffer, int offset)
		{
			return (((((buffer[offset] << 8) | buffer[offset + 1]) << 8) | buffer[offset + 2]) << 8) | buffer[offset + 3];
		}

		private void WriteBigEndian(byte[] buffer, int offset, int value)
		{
			byte[] bytes = BitConverter.GetBytes(value);
			for (int i = 0; i < 4; i++)
			{
				buffer[offset + 3 - i] = bytes[i];
			}
		}

		public static XingHeader LoadXingHeader(Mp3Frame frame)
		{
			XingHeader xingHeader = new XingHeader();
			xingHeader.frame = frame;
			int num = 0;
			if (frame.MpegVersion == MpegVersion.Version1)
			{
				num = ((frame.ChannelMode == ChannelMode.Mono) ? 21 : 36);
			}
			else
			{
				if (frame.MpegVersion != MpegVersion.Version2)
				{
					return null;
				}
				num = ((frame.ChannelMode == ChannelMode.Mono) ? 13 : 21);
			}
			if (frame.RawData[num] == 88 && frame.RawData[num + 1] == 105 && frame.RawData[num + 2] == 110 && frame.RawData[num + 3] == 103)
			{
				xingHeader.startOffset = num;
				num += 4;
			}
			else
			{
				if (frame.RawData[num] != 73 || frame.RawData[num + 1] != 110 || frame.RawData[num + 2] != 102 || frame.RawData[num + 3] != 111)
				{
					return null;
				}
				xingHeader.startOffset = num;
				num += 4;
			}
			int num2 = ReadBigEndian(frame.RawData, num);
			num += 4;
			if (((uint)num2 & (true ? 1u : 0u)) != 0)
			{
				xingHeader.framesOffset = num;
				num += 4;
			}
			if (((uint)num2 & 2u) != 0)
			{
				xingHeader.bytesOffset = num;
				num += 4;
			}
			if (((uint)num2 & 4u) != 0)
			{
				xingHeader.tocOffset = num;
				num += 100;
			}
			if (((uint)num2 & 8u) != 0)
			{
				xingHeader.vbrScale = ReadBigEndian(frame.RawData, num);
				num += 4;
			}
			xingHeader.endOffset = num;
			return xingHeader;
		}

		private XingHeader()
		{
		}
	}
	public static class WaveExtensionMethods
	{
		public static ISampleProvider ToSampleProvider(this IWaveProvider waveProvider)
		{
			return SampleProviderConverters.ConvertWaveProviderIntoSampleProvider(waveProvider);
		}

		public static void Init(this IWavePlayer wavePlayer, ISampleProvider sampleProvider, bool convertTo16Bit = false)
		{
			IWaveProvider waveProvider2;
			if (!convertTo16Bit)
			{
				IWaveProvider waveProvider = new SampleToWaveProvider(sampleProvider);
				waveProvider2 = waveProvider;
			}
			else
			{
				IWaveProvider waveProvider = new SampleToWaveProvider16(sampleProvider);
				waveProvider2 = waveProvider;
			}
			IWaveProvider waveProvider3 = waveProvider2;
			wavePlayer.Init(waveProvider3);
		}

		public static WaveFormat AsStandardWaveFormat(this WaveFormat waveFormat)
		{
			if (!(waveFormat is WaveFormatExtensible waveFormatExtensible))
			{
				return waveFormat;
			}
			return waveFormatExtensible.ToStandardWaveFormat();
		}

		public static IWaveProvider ToWaveProvider(this ISampleProvider sampleProvider)
		{
			return new SampleToWaveProvider(sampleProvider);
		}

		public static IWaveProvider ToWaveProvider16(this ISampleProvider sampleProvider)
		{
			return new SampleToWaveProvider16(sampleProvider);
		}

		public static ISampleProvider FollowedBy(this ISampleProvider sampleProvider, ISampleProvider next)
		{
			return new ConcatenatingSampleProvider(new ISampleProvider[2] { sampleProvider, next });
		}

		public static ISampleProvider FollowedBy(this ISampleProvider sampleProvider, TimeSpan silenceDuration, ISampleProvider next)
		{
			OffsetSampleProvider offsetSampleProvider = new OffsetSampleProvider(sampleProvider)
			{
				LeadOut = silenceDuration
			};
			return new ConcatenatingSampleProvider(new ISampleProvider[2] { offsetSampleProvider, next });
		}

		public static ISampleProvider Skip(this ISampleProvider sampleProvider, TimeSpan skipDuration)
		{
			return new OffsetSampleProvider(sampleProvider)
			{
				SkipOver = skipDuration
			};
		}

		public static ISampleProvider Take(this ISampleProvider sampleProvider, TimeSpan takeDuration)
		{
			return new OffsetSampleProvider(sampleProvider)
			{
				Take = takeDuration
			};
		}

		public static ISampleProvider ToMono(this ISampleProvider sourceProvider, float leftVol = 0.5f, float rightVol = 0.5f)
		{
			if (sourceProvider.WaveFormat.Channels == 1)
			{
				return sourceProvider;
			}
			return new StereoToMonoSampleProvider(sourceProvider)
			{
				LeftVolume = leftVol,
				RightVolume = rightVol
			};
		}

		public static ISampleProvider ToStereo(this ISampleProvider sourceProvider, float leftVol = 1f, float rightVol = 1f)
		{
			if (sourceProvider.WaveFormat.Channels == 2)
			{
				return sourceProvider;
			}
			return new MonoToStereoSampleProvider(sourceProvider)
			{
				LeftVolume = leftVol,
				RightVolume = rightVol
			};
		}
	}
	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	public class AdpcmWaveFormat : WaveFormat
	{
		private short samplesPerBlock;

		private short numCoeff;

		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
		private short[] coefficients;

		public int SamplesPerBlock => samplesPerBlock;

		public int NumCoefficients => numCoeff;

		public short[] Coefficients => coefficients;

		private AdpcmWaveFormat()
			: this(8000, 1)
		{
		}

		public AdpcmWaveFormat(int sampleRate, int channels)
			: base(sampleRate, 0, channels)
		{
			waveFormatTag = WaveFormatEncoding.Adpcm;
			extraSize = 32;
			switch (base.sampleRate)
			{
			case 8000:
			case 11025:
				blockAlign = 256;
				break;
			case 22050:
				blockAlign = 512;
				break;
			default:
				blockAlign = 1024;
				break;
			}
			bitsPerSample = 4;
			samplesPerBlock = (short)((blockAlign - 7 * channels) * 8 / (bitsPerSample * channels) + 2);
			averageBytesPerSecond = base.SampleRate * blockAlign / samplesPerBlock;
			numCoeff = 7;
			coefficients = new short[14]
			{
				256, 0, 512, -256, 0, 0, 192, 64, 240, 0,
				460, -208, 392, -232
			};
		}

		public override void Serialize(BinaryWriter writer)
		{
			base.Serialize(writer);
			writer.Write(samplesPerBlock);
			writer.Write(numCoeff);
			short[] array = coefficients;
			foreach (short value in array)
			{
				writer.Write(value);
			}
		}

		public override string ToString()
		{
			return $"Microsoft ADPCM {base.SampleRate} Hz {channels} channels {bitsPerSample} bits per sample {samplesPerBlock} samples per block";
		}
	}
	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	public class Gsm610WaveFormat : WaveFormat
	{
		private readonly short samplesPerBlock;

		public short SamplesPerBlock => samplesPerBlock;

		public Gsm610WaveFormat()
		{
			waveFormatTag = WaveFormatEncoding.Gsm610;
			channels = 1;
			averageBytesPerSecond = 1625;
			bitsPerSample = 0;
			blockAlign = 65;
			sampleRate = 8000;
			extraSize = 2;
			samplesPerBlock = 320;
		}

		public override void Serialize(BinaryWriter writer)
		{
			base.Serialize(writer);
			writer.Write(samplesPerBlock);
		}
	}
	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	public class ImaAdpcmWaveFormat : WaveFormat
	{
		private short samplesPerBlock;

		private ImaAdpcmWaveFormat()
		{
		}

		public ImaAdpcmWaveFormat(int sampleRate, int channels, int bitsPerSample)
		{
			waveFormatTag = WaveFormatEncoding.DviAdpcm;
			base.sampleRate = sampleRate;
			base.channels = (short)channels;
			base.bitsPerSample = (short)bitsPerSample;
			extraSize = 2;
			blockAlign = 0;
			averageBytesPerSecond = 0;
			samplesPerBlock = 0;
		}
	}
	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	public class Mp3WaveFormat : WaveFormat
	{
		public Mp3WaveFormatId id;

		public Mp3WaveFormatFlags flags;

		public ushort blockSize;

		public ushort framesPerBlock;

		public ushort codecDelay;

		private const short Mp3WaveFormatExtraBytes = 12;

		public Mp3WaveFormat(int sampleRate, int channels, int blockSize, int bitRate)
		{
			waveFormatTag = WaveFormatEncoding.MpegLayer3;
			base.channels = (short)channels;
			averageBytesPerSecond = bitRate / 8;
			bitsPerSample = 0;
			blockAlign = 1;
			base.sampleRate = sampleRate;
			extraSize = 12;
			id = Mp3WaveFormatId.Mpeg;
			flags = Mp3WaveFormatFlags.PaddingIso;
			this.blockSize = (ushort)blockSize;
			framesPerBlock = 1;
			codecDelay = 0;
		}
	}
	[Flags]
	public enum Mp3WaveFormatFlags
	{
		PaddingIso = 0,
		PaddingOn = 1,
		PaddingOff = 2
	}
	public enum Mp3WaveFormatId : ushort
	{
		Unknown,
		Mpeg,
		ConstantFrameSize
	}
	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	internal class OggWaveFormat : WaveFormat
	{
		public uint dwVorbisACMVersion;

		public uint dwLibVorbisVersion;
	}
	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	public class TrueSpeechWaveFormat : WaveFormat
	{
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
		private short[] unknown;

		public TrueSpeechWaveFormat()
		{
			waveFormatTag = WaveFormatEncoding.DspGroupTrueSpeech;
			channels = 1;
			averageBytesPerSecond = 1067;
			bitsPerSample = 1;
			blockAlign = 32;
			sampleRate = 8000;
			extraSize = 32;
			unknown = new short[16];
			unknown[0] = 1;
			unknown[1] = 240;
		}

		public override void Serialize(BinaryWriter writer)
		{
			base.Serialize(writer);
			short[] array = unknown;
			foreach (short value in array)
			{
				writer.Write(value);
			}
		}
	}
	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	public class WaveFormat
	{
		protected WaveFormatEncoding waveFormatTag;

		protected short channels;

		protected int sampleRate;

		protected int averageBytesPerSecond;

		protected short blockAlign;

		protected short bitsPerSample;

		protected short extraSize;

		public WaveFormatEncoding Encoding => waveFormatTag;

		public int Channels => channels;

		public int SampleRate => sampleRate;

		public int AverageBytesPerSecond => averageBytesPerSecond;

		public virtual int BlockAlign => blockAlign;

		public int BitsPerSample => bitsPerSample;

		public int ExtraSize => extraSize;

		public WaveFormat()
			: this(44100, 16, 2)
		{
		}

		public WaveFormat(int sampleRate, int channels)
			: this(sampleRate, 16, channels)
		{
		}

		public int ConvertLatencyToByteSize(int milliseconds)
		{
			int num = (int)((double)AverageBytesPerSecond / 1000.0 * (double)milliseconds);
			if (num % BlockAlign != 0)
			{
				num = num + BlockAlign - num % BlockAlign;
			}
			return num;
		}

		public static WaveFormat CreateCustomFormat(WaveFormatEncoding tag, int sampleRate, int channels, int averageBytesPerSecond, int blockAlign, int bitsPerSample)
		{
			return new WaveFormat
			{
				waveFormatTag = tag,
				channels = (short)channels,
				sampleRate = sampleRate,
				averageBytesPerSecond = averageBytesPerSecond,
				blockAlign = (short)blockAlign,
				bitsPerSample = (short)bitsPerSample,
				extraSize = 0
			};
		}

		public static WaveFormat CreateALawFormat(int sampleRate, int channels)
		{
			return CreateCustomFormat(WaveFormatEncoding.ALaw, sampleRate, channels, sampleRate * channels, channels, 8);
		}

		public static WaveFormat CreateMuLawFormat(int sampleRate, int channels)
		{
			return CreateCustomFormat(WaveFormatEncoding.MuLaw, sampleRate, channels, sampleRate * channels, channels, 8);
		}

		public WaveFormat(int rate, int bits, int channels)
		{
			if (channels < 1)
			{
				throw new ArgumentOutOfRangeException("channels", "Channels must be 1 or greater");
			}
			waveFormatTag = WaveFormatEncoding.Pcm;
			this.channels = (short)channels;
			sampleRate = rate;
			bitsPerSample = (short)bits;
			extraSize = 0;
			blockAlign = (short)(channels * (bits / 8));
			averageBytesPerSecond = sampleRate * blockAlign;
		}

		public static WaveFormat CreateIeeeFloatWaveFormat(int sampleRate, int channels)
		{
			WaveFormat waveFormat = new WaveFormat();
			waveFormat.waveFormatTag = WaveFormatEncoding.IeeeFloat;
			waveFormat.channels = (short)channels;
			waveFormat.bitsPerSample = 32;
			waveFormat.sampleRate = sampleRate;
			waveFormat.blockAlign = (short)(4 * channels);
			waveFormat.averageBytesPerSecond = sampleRate * waveFormat.blockAlign;
			waveFormat.extraSize = 0;
			return waveFormat;
		}

		public static WaveFormat MarshalFromPtr(IntPtr pointer)
		{
			WaveFormat waveFormat = Marshal.PtrToStructure<WaveFormat>(pointer);
			switch (waveFormat.Encoding)
			{
			case WaveFormatEncoding.Pcm:
				waveFormat.extraSize = 0;
				break;
			case WaveFormatEncoding.Extensible:
				waveFormat = Marshal.PtrToStructure<WaveFormatExtensible>(pointer);
				break;
			case WaveFormatEncoding.Adpcm:
				waveFormat = Marshal.PtrToStructure<AdpcmWaveFormat>(pointer);
				break;
			case WaveFormatEncoding.Gsm610:
				waveFormat = Marshal.PtrToStructure<Gsm610WaveFormat>(pointer);
				break;
			default:
				if (waveFormat.ExtraSize > 0)
				{
					waveFormat = Marshal.PtrToStructure<WaveFormatExtraData>(pointer);
				}
				break;
			}
			return waveFormat;
		}

		public static IntPtr MarshalToPtr(WaveFormat format)
		{
			IntPtr intPtr = Marshal.AllocHGlobal(Marshal.SizeOf(format));
			Marshal.StructureToPtr(format, intPtr, fDeleteOld: false);
			return intPtr;
		}

		public static WaveFormat FromFormatChunk(BinaryReader br, int formatChunkLength)
		{
			WaveFormatExtraData waveFormatExtraData = new WaveFormatExtraData();
			waveFormatExtraData.ReadWaveFormat(br, formatChunkLength);
			waveFormatExtraData.ReadExtraData(br);
			return waveFormatExtraData;
		}

		private void ReadWaveFormat(BinaryReader br, int formatChunkLength)
		{
			if (formatChunkLength < 16)
			{
				throw new InvalidDataException("Invalid WaveFormat Structure");
			}
			waveFormatTag = (WaveFormatEncoding)br.ReadUInt16();
			channels = br.ReadInt16();
			sampleRate = br.ReadInt32();
			averageBytesPerSecond = br.ReadInt32();
			blockAlign = br.ReadInt16();
			bitsPerSample = br.ReadInt16();
			if (formatChunkLength > 16)
			{
				extraSize = br.ReadInt16();
				if (extraSize != formatChunkLength - 18)
				{
					extraSize = (short)(formatChunkLength - 18);
				}
			}
		}

		public WaveFormat(BinaryReader br)
		{
			int formatChunkLength = br.ReadInt32();
			ReadWaveFormat(br, formatChunkLength);
		}

		public override string ToString()
		{
			switch (waveFormatTag)
			{
			case WaveFormatEncoding.Pcm:
			case WaveFormatEncoding.Extensible:
				return $"{bitsPerSample} bit PCM: {sampleRate}Hz {channels} channels";
			case WaveFormatEncoding.IeeeFloat:
				return $"{bitsPerSample} bit IEEFloat: {sampleRate}Hz {channels} channels";
			default:
				return waveFormatTag.ToString();
			}
		}

		public override bool Equals(object obj)
		{
			if (obj is WaveFormat waveFormat)
			{
				if (waveFormatTag == waveFormat.waveFormatTag && channels == waveFormat.channels && sampleRate == waveFormat.sampleRate && averageBytesPerSecond == waveFormat.averageBytesPerSecond && blockAlign == waveFormat.blockAlign)
				{
					return bitsPerSample == waveFormat.bitsPerSample;
				}
				return false;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (int)waveFormatTag ^ (int)channels ^ sampleRate ^ averageBytesPerSecond ^ blockAlign ^ bitsPerSample;
		}

		public virtual void Serialize(BinaryWriter writer)
		{
			writer.Write(18 + extraSize);
			writer.Write((short)Encoding);
			writer.Write((short)Channels);
			writer.Write(SampleRate);
			writer.Write(AverageBytesPerSecond);
			writer.Write((short)BlockAlign);
			writer.Write((short)BitsPerSample);
			writer.Write(extraSize);
		}
	}
	public sealed class WaveFormatCustomMarshaler : ICustomMarshaler
	{
		private static WaveFormatCustomMarshaler marshaler;

		public static ICustomMarshaler GetInstance(string cookie)
		{
			if (marshaler == null)
			{
				marshaler = new WaveFormatCustomMarshaler();
			}
			return marshaler;
		}

		public void CleanUpManagedData(object ManagedObj)
		{
		}

		public void CleanUpNativeData(IntPtr pNativeData)
		{
			Marshal.FreeHGlobal(pNativeData);
		}

		public int GetNativeDataSize()
		{
			throw new NotImplementedException();
		}

		public IntPtr MarshalManagedToNative(object ManagedObj)
		{
			return WaveFormat.MarshalToPtr((WaveFormat)ManagedObj);
		}

		public object MarshalNativeToManaged(IntPtr pNativeData)
		{
			return WaveFormat.MarshalFromPtr(pNativeData);
		}
	}
	public enum WaveFormatEncoding : ushort
	{
		Unknown = 0,
		Pcm = 1,
		Adpcm = 2,
		IeeeFloat = 3,
		Vselp = 4,
		IbmCvsd = 5,
		ALaw = 6,
		MuLaw = 7,
		Dts = 8,
		Drm = 9,
		WmaVoice9 = 10,
		OkiAdpcm = 16,
		DviAdpcm = 17,
		ImaAdpcm = 17,
		MediaspaceAdpcm = 18,
		SierraAdpcm = 19,
		G723Adpcm = 20,
		DigiStd = 21,
		DigiFix = 22,
		DialogicOkiAdpcm = 23,
		MediaVisionAdpcm = 24,
		CUCodec = 25,
		YamahaAdpcm = 32,
		SonarC = 33,
		DspGroupTrueSpeech = 34,
		EchoSpeechCorporation1 = 35,
		AudioFileAf36 = 36,
		Aptx = 37,
		AudioFileAf10 = 38,
		Prosody1612 = 39,
		Lrc = 40,
		DolbyAc2 = 48,
		Gsm610 = 49,
		MsnAudio = 50,
		AntexAdpcme = 51,
		ControlResVqlpc = 52,
		DigiReal = 53,
		DigiAdpcm = 54,
		ControlResCr10 = 55,
		WAVE_FORMAT_NMS_VBXADPCM = 56,
		WAVE_FORMAT_CS_IMAADPCM = 57,
		WAVE_FORMAT_ECHOSC3 = 58,
		WAVE_FORMAT_ROCKWELL_ADPCM = 59,
		WAVE_FORMAT_ROCKWELL_DIGITALK = 60,
		WAVE_FORMAT_XEBEC = 61,
		WAVE_FORMAT_G721_ADPCM = 64,
		WAVE_FORMAT_G728_CELP = 65,
		WAVE_FORMAT_MSG723 = 66,
		Mpeg = 80,
		WAVE_FORMAT_RT24 = 82,
		WAVE_FORMAT_PAC = 83,
		MpegLayer3 = 85,
		WAVE_FORMAT_LUCENT_G723 = 89,
		WAVE_FORMAT_CIRRUS = 96,
		WAVE_FORMAT_ESPCM = 97,
		WAVE_FORMAT_VOXWARE = 98,
		WAVE_FORMAT_CANOPUS_ATRAC = 99,
		WAVE_FORMAT_G726_ADPCM = 100,
		WAVE_FORMAT_G722_ADPCM = 101,
		WAVE_FORMAT_DSAT_DISPLAY = 103,
		WAVE_FORMAT_VOXWARE_BYTE_ALIGNED = 105,
		WAVE_FORMAT_VOXWARE_AC8 = 112,
		WAVE_FORMAT_VOXWARE_AC10 = 113,
		WAVE_FORMAT_VOXWARE_AC16 = 114,
		WAVE_FORMAT_VOXWARE_AC20 = 115,
		WAVE_FORMAT_VOXWARE_RT24 = 116,
		WAVE_FORMAT_VOXWARE_RT29 = 117,
		WAVE_FORMAT_VOXWARE_RT29HW = 118,
		WAVE_FORMAT_VOXWARE_VR12 = 119,
		WAVE_FORMAT_VOXWARE_VR18 = 120,
		WAVE_FORMAT_VOXWARE_TQ40 = 121,
		WAVE_FORMAT_SOFTSOUND = 128,
		WAVE_FORMAT_VOXWARE_TQ60 = 129,
		WAVE_FORMAT_MSRT24 = 130,
		WAVE_FORMAT_G729A = 131,
		WAVE_FORMAT_MVI_MVI2 = 132,
		WAVE_FORMAT_DF_G726 = 133,
		WAVE_FORMAT_DF_GSM610 = 134,
		WAVE_FORMAT_ISIAUDIO = 136,
		WAVE_FORMAT_ONLIVE = 137,
		WAVE_FORMAT_SBC24 = 145,
		WAVE_FORMAT_DOLBY_AC3_SPDIF = 146,
		WAVE_FORMAT_MEDIASONIC_G723 = 147,
		WAVE_FORMAT_PROSODY_8KBPS = 148,
		WAVE_FORMAT_ZYXEL_ADPCM = 151,
		WAVE_FORMAT_PHILIPS_LPCBB = 152,
		WAVE_FORMAT_PACKED = 153,
		WAVE_FORMAT_MALDEN_PHONYTALK = 160,
		Gsm = 161,
		G729 = 162,
		G723 = 163,
		Acelp = 164,
		RawAac = 255,
		WAVE_FORMAT_RHETOREX_ADPCM = 256,
		WAVE_FORMAT_IRAT = 257,
		WAVE_FORMAT_VIVO_G723 = 273,
		WAVE_FORMAT_VIVO_SIREN = 274,
		WAVE_FORMAT_DIGITAL_G723 = 291,
		WAVE_FORMAT_SANYO_LD_ADPCM = 293,
		WAVE_FORMAT_SIPROLAB_ACEPLNET = 304,
		WAVE_FORMAT_SIPROLAB_ACELP4800 = 305,
		WAVE_FORMAT_SIPROLAB_ACELP8V3 = 306,
		WAVE_FORMAT_SIPROLAB_G729 = 307,
		WAVE_FORMAT_SIPROLAB_G729A = 308,
		WAVE_FORMAT_SIPROLAB_KELVIN = 309,
		WAVE_FORMAT_G726ADPCM = 320,
		WAVE_FORMAT_QUALCOMM_PUREVOICE = 336,
		WAVE_FORMAT_QUALCOMM_HALFRATE = 337,
		WAVE_FORMAT_TUBGSM = 341,
		WAVE_FORMAT_MSAUDIO1 = 352,
		WindowsMediaAudio = 353,
		WindowsMediaAudioProfessional = 354,
		WindowsMediaAudioLosseless = 355,
		WindowsMediaAudioSpdif = 356,
		WAVE_FORMAT_UNISYS_NAP_ADPCM = 368,
		WAVE_FORMAT_UNISYS_NAP_ULAW = 369,
		WAVE_FORMAT_UNISYS_NAP_ALAW = 370,
		WAVE_FORMAT_UNISYS_NAP_16K = 371,
		WAVE_FORMAT_CREATIVE_ADPCM = 512,
		WAVE_FORMAT_CREATIVE_FASTSPEECH8 = 514,
		WAVE_FORMAT_CREATIVE_FASTSPEECH10 = 515,
		WAVE_FORMAT_UHER_ADPCM = 528,
		WAVE_FORMAT_QUARTERDECK = 544,
		WAVE_FORMAT_ILINK_VC = 560,
		WAVE_FORMAT_RAW_SPORT = 576,
		WAVE_FORMAT_ESST_AC3 = 577,
		WAVE_FORMAT_IPI_HSX = 592,
		WAVE_FORMAT_IPI_RPELP = 593,
		WAVE_FORMAT_CS2 = 608,
		WAVE_FORMAT_SONY_SCX = 624,
		WAVE_FORMAT_FM_TOWNS_SND = 768,
		WAVE_FORMAT_BTV_DIGITAL = 1024,
		WAVE_FORMAT_QDESIGN_MUSIC = 1104,
		WAVE_FORMAT_VME_VMPCM = 1664,
		WAVE_FORMAT_TPC = 1665,
		WAVE_FORMAT_OLIGSM = 4096,
		WAVE_FORMAT_OLIADPCM = 4097,
		WAVE_FORMAT_OLICELP = 4098,
		WAVE_FORMAT_OLISBC = 4099,
		WAVE_FORMAT_OLIOPR = 4100,
		WAVE_FORMAT_LH_CODEC = 4352,
		WAVE_FORMAT_NORRIS = 5120,
		WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS = 5376,
		MPEG_ADTS_AAC = 5632,
		MPEG_RAW_AAC = 5633,
		MPEG_LOAS = 5634,
		NOKIA_MPEG_ADTS_AAC = 5640,
		NOKIA_MPEG_RAW_AAC = 5641,
		VODAFONE_MPEG_ADTS_AAC = 5642,
		VODAFONE_MPEG_RAW_AAC = 5643,
		MPEG_HEAAC = 5648,
		WAVE_FORMAT_DVM = 8192,
		Vorbis1 = 26447,
		Vorbis2 = 26448,
		Vorbis3 = 26449,
		Vorbis1P = 26479,
		Vorbis2P = 26480,
		Vorbis3P = 26481,
		Extensible = 65534,
		WAVE_FORMAT_DEVELOPMENT = ushort.MaxValue
	}
	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	public class WaveFormatExtensible : WaveFormat
	{
		private short wValidBitsPerSample;

		private int dwChannelMask;

		private Guid subFormat;

		public Guid SubFormat => subFormat;

		private WaveFormatExtensible()
		{
		}

		public WaveFormatExtensible(int rate, int bits, int channels)
			: base(rate, bits, channels)
		{
			waveFormatTag = WaveFormatEncoding.Extensible;
			extraSize = 22;
			wValidBitsPerSample = (short)bits;
			for (int i = 0; i < channels; i++)
			{
				dwChannelMask |= 1 << i;
			}
			if (bits == 32)
			{
				subFormat = AudioMediaSubtypes.MEDIASUBTYPE_IEEE_FLOAT;
			}
			else
			{
				subFormat = AudioMediaSubtypes.MEDIASUBTYPE_PCM;
			}
		}

		public WaveFormat ToStandardWaveFormat()
		{
			if (subFormat == AudioMediaSubtypes.MEDIASUBTYPE_IEEE_FLOAT && bitsPerSample == 32)
			{
				return WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels);
			}
			if (subFormat == AudioMediaSubtypes.MEDIASUBTYPE_PCM)
			{
				return new WaveFormat(sampleRate, bitsPerSample, channels);
			}
			return this;
		}

		public override void Serialize(BinaryWriter writer)
		{
			base.Serialize(writer);
			writer.Write(wValidBitsPerSample);
			writer.Write(dwChannelMask);
			byte[] array = subFormat.ToByteArray();
			writer.Write(array, 0, array.Length);
		}

		public override string ToString()
		{
			return "WAVE_FORMAT_EXTENSIBLE " + AudioMediaSubtypes.GetAudioSubtypeName(subFormat) + " " + $"{base.SampleRate}Hz {base.Channels} channels {base.BitsPerSample} bit";
		}
	}
	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	public class WaveFormatExtraData : WaveFormat
	{
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
		private byte[] extraData = new byte[100];

		public byte[] ExtraData => extraData;

		internal WaveFormatExtraData()
		{
		}

		public WaveFormatExtraData(BinaryReader reader)
			: base(reader)
		{
			ReadExtraData(reader);
		}

		internal void ReadExtraData(BinaryReader reader)
		{
			if (extraSize > 0)
			{
				reader.Read(extraData, 0, extraSize);
			}
		}

		public override void Serialize(BinaryWriter writer)
		{
			base.Serialize(writer);
			if (extraSize > 0)
			{
				writer.Write(extraData, 0, extraSize);
			}
		}
	}
	public interface IWaveIn : IDisposable
	{
		WaveFormat WaveFormat { get; set; }

		event EventHandler<WaveInEventArgs> DataAvailable;

		event EventHandler<StoppedEventArgs> RecordingStopped;

		void StartRecording();

		void StopRecording();
	}
	public class WaveInEventArgs : EventArgs
	{
		private byte[] buffer;

		private int bytes;

		public byte[] Buffer => buffer;

		public int BytesRecorded => bytes;

		public WaveInEventArgs(byte[] buffer, int bytes)
		{
			this.buffer = buffer;
			this.bytes = bytes;
		}
	}
	public class AiffFileWriter : Stream
	{
		private Stream outStream;

		private BinaryWriter writer;

		private long dataSizePos;

		private long commSampleCountPos;

		private long dataChunkSize = 8L;

		private WaveFormat format;

		private string filename;

		private byte[] value24 = new byte[3];

		public string Filename => filename;

		public override long Length => dataChunkSize;

		public WaveFormat WaveFormat => format;

		public override bool CanRead => false;

		public override bool CanWrite => true;

		public override bool CanSeek => false;

		public override long Position
		{
			get
			{
				return dataChunkSize;
			}
			set
			{
				throw new InvalidOperationException("Repositioning an AiffFileWriter is not supported");
			}
		}

		public static void CreateAiffFile(string filename, WaveStream sourceProvider)
		{
			using AiffFileWriter aiffFileWriter = new AiffFileWriter(filename, sourceProvider.WaveFormat);
			byte[] array = new byte[16384];
			while (sourceProvider.Position < sourceProvider.Length)
			{
				int count = Math.Min((int)(sourceProvider.Length - sourceProvider.Position), array.Length);
				int num = sourceProvider.Read(array, 0, count);
				if (num == 0)
				{
					break;
				}
				aiffFileWriter.Write(array, 0, num);
			}
		}

		public AiffFileWriter(Stream outStream, WaveFormat format)
		{
			this.outStream = outStream;
			this.format = format;
			writer = new BinaryWriter(outStream, Encoding.UTF8);
			writer.Write(Encoding.UTF8.GetBytes("FORM"));
			writer.Write(0);
			writer.Write(Encoding.UTF8.GetBytes("AIFF"));
			CreateCommChunk();
			WriteSsndChunkHeader();
		}

		public AiffFileWriter(string filename, WaveFormat format)
			: this(new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Read), format)
		{
			this.filename = filename;
		}

		private void WriteSsndChunkHeader()
		{
			writer.Write(Encoding.UTF8.GetBytes("SSND"));
			dataSizePos = outStream.Position;
			writer.Write(0);
			writer.Write(0);
			writer.Write(SwapEndian(format.BlockAlign));
		}

		private byte[] SwapEndian(short n)
		{
			return new byte[2]
			{
				(byte)(n >> 8),
				(byte)((uint)n & 0xFFu)
			};
		}

		private byte[] SwapEndian(int n)
		{
			return new byte[4]
			{
				(byte)((uint)(n >> 24) & 0xFFu),
				(byte)((uint)(n >> 16) & 0xFFu),
				(byte)((uint)(n >> 8) & 0xFFu),
				(byte)((uint)n & 0xFFu)
			};
		}

		private void CreateCommChunk()
		{
			writer.Write(Encoding.UTF8.GetBytes("COMM"));
			writer.Write(SwapEndian(18));
			writer.Write(SwapEndian((short)format.Channels));
			commSampleCountPos = outStream.Position;
			writer.Write(0);
			writer.Write(SwapEndian((short)format.BitsPerSample));
			writer.Write(IEEE.ConvertToIeeeExtended(format.SampleRate));
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			throw new InvalidOperationException("Cannot read from an AiffFileWriter");
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			throw new InvalidOperationException("Cannot seek within an AiffFileWriter");
		}

		public override void SetLength(long value)
		{
			throw new InvalidOperationException("Cannot set length of an AiffFileWriter");
		}

		public override void Write(byte[] data, int offset, int count)
		{
			byte[] array = new byte[data.Length];
			int num = format.BitsPerSample / 8;
			for (int i = 0; i < data.Length; i++)
			{
				int num2 = (int)Math.Floor((double)i / (double)num) * num + (num - i % num - 1);
				array[i] = data[num2];
			}
			outStream.Write(array, offset, count);
			dataChunkSize += count;
		}

		public void WriteSample(float sample)
		{
			if (WaveFormat.BitsPerSample == 16)
			{
				writer.Write(SwapEndian((short)(32767f * sample)));
				dataChunkSize += 2L;
			}
			else if (WaveFormat.BitsPerSample == 24)
			{
				byte[] bytes = BitConverter.GetBytes((int)(2.1474836E+09f * sample));
				value24[2] = bytes[1];
				value24[1] = bytes[2];
				value24[0] = bytes[3];
				writer.Write(value24);
				dataChunkSize += 3L;
			}
			else
			{
				if (WaveFormat.BitsPerSample != 32 || WaveFormat.Encoding != WaveFormatEncoding.Extensible)
				{
					throw new InvalidOperationException("Only 16, 24 or 32 bit PCM or IEEE float audio data supported");
				}
				writer.Write(SwapEndian(65535 * (int)sample));
				dataChunkSize += 4L;
			}
		}

		public void WriteSamples(float[] samples, int offset, int count)
		{
			for (int i = 0; i < count; i++)
			{
				WriteSample(samples[offset + i]);
			}
		}

		public void WriteSamples(short[] samples, int offset, int count)
		{
			if (WaveFormat.BitsPerSample == 16)
			{
				for (int i = 0; i < count; i++)
				{
					writer.Write(SwapEndian(samples[i + offset]));
				}
				dataChunkSize += count * 2;
			}
			else if (WaveFormat.BitsPerSample == 24)
			{
				for (int j = 0; j < count; j++)
				{
					byte[] bytes = BitConverter.GetBytes(65535 * samples[j + offset]);
					value24[2] = bytes[1];
					value24[1] = bytes[2];
					value24[0] = bytes[3];
					writer.Write(value24);
				}
				dataChunkSize += count * 3;
			}
			else
			{
				if (WaveFormat.BitsPerSample != 32 || WaveFormat.Encoding != WaveFormatEncoding.Extensible)
				{
					throw new InvalidOperationException("Only 16, 24 or 32 bit PCM audio data supported");
				}
				for (int k = 0; k < count; k++)
				{
					writer.Write(SwapEndian(65535 * samples[k + offset]));
				}
				dataChunkSize += count * 4;
			}
		}

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

		protected override void Dispose(bool disposing)
		{
			if (disposing && outStream != null)
			{
				try
				{
					UpdateHeader(writer);
				}
				finally
				{
					outStream.Dispose();
					outStream = null;
				}
			}
		}

		protected virtual void UpdateHeader(BinaryWriter writer)
		{
			Flush();
			writer.Seek(4, SeekOrigin.Begin);
			writer.Write(SwapEndian((int)(outStream.Length - 8)));
			UpdateCommChunk(writer);
			UpdateSsndChunk(writer);
		}

		private void UpdateCommChunk(BinaryWriter writer)
		{
			writer.Seek((int)commSampleCountPos, SeekOrigin.Begin);
			writer.Write(SwapEndian((int)(dataChunkSize * 8 / format.BitsPerSample / format.Channels)));
		}

		private void UpdateSsndChunk(BinaryWriter writer)
		{
			writer.Seek((int)dataSizePos, SeekOrigin.Begin);
			writer.Write(SwapEndian((int)dataChunkSize));
		}

		~AiffFileWriter()
		{
			Dispose(disposing: false);
		}
	}
	public class BextChunkInfo
	{
		public string Description { get; set; }

		public string Originator { get; set; }

		public string OriginatorReference { get; set; }

		public DateTime OriginationDateTime { get; set; }

		public string OriginationDate => OriginationDateTime.ToString("yyyy-MM-dd");

		public string OriginationTime => OriginationDateTime.ToString("HH:mm:ss");

		public long TimeReference { get; set; }

		public ushort Version => 1;

		public string UniqueMaterialIdentifier { get; set; }

		public byte[] Reserved { get; }

		public string CodingHistory { get; set; }

		public BextChunkInfo()
		{
			Reserved = new byte[190];
		}
	}
	public class BwfWriter : IDisposable
	{
		private readonly WaveFormat format;

		private readonly BinaryWriter writer;

		private readonly long dataChunkSizePosition;

		private long dataLength;

		private bool isDisposed;

		public BwfWriter(string filename, WaveFormat format, BextChunkInfo bextChunkInfo)
		{
			this.format = format;
			writer = new BinaryWriter(File.OpenWrite(filename));
			writer.Write(Encoding.UTF8.GetBytes("RIFF"));
			writer.Write(0);
			writer.Write(Encoding.UTF8.GetBytes("WAVE"));
			writer.Write(Encoding.UTF8.GetBytes("JUNK"));
			writer.Write(28);
			writer.Write(0L);
			writer.Write(0L);
			writer.Write(0L);
			writer.Write(0);
			writer.Write(Encoding.UTF8.GetBytes("bext"));
			byte[] bytes = Encoding.ASCII.GetBytes(bextChunkInfo.CodingHistory ?? "");
			int num = 602 + bytes.Length;
			if (num % 2 != 0)
			{
				num++;
			}
			writer.Write(num);
			_ = writer.BaseStream.Position;
			writer.Write(GetAsBytes(bextChunkInfo.Description, 256));
			writer.Write(GetAsBytes(bextChunkInfo.Originator, 32));
			writer.Write(GetAsBytes(bextChunkInfo.OriginatorReference, 32));
			writer.Write(GetAsBytes(bextChunkInfo.OriginationDate, 10));
			writer.Write(GetAsBytes(bextChunkInfo.OriginationTime, 8));
			writer.Write(bextChunkInfo.TimeReference);
			writer.Write(bextChunkInfo.Version);
			writer.Write(GetAsBytes(bextChunkInfo.UniqueMaterialIdentifier, 64));
			writer.Write(bextChunkInfo.Reserved);
			writer.Write(bytes);
			if (bytes.Length % 2 != 0)
			{
				writer.Write((byte)0);
			}
			writer.Write(Encoding.UTF8.GetBytes("fmt "));
			format.Serialize(writer);
			writer.Write(Encoding.UTF8.GetBytes("data"));
			dataChunkSizePosition = writer.BaseStream.Position;
			writer.Write(-1);
		}

		public void Write(byte[] buffer, int offset, int count)
		{
			if (isDisposed)
			{
				throw new ObjectDisposedException("This BWF Writer already disposed");
			}
			writer.Write(buffer, offset, count);
			dataLength += count;
		}

		public void Flush()
		{
			if (isDisposed)
			{
				throw new ObjectDisposedException("This BWF Writer already disposed");
			}
			writer.Flush();
			FixUpChunkSizes(restorePosition: true);
		}

		private void FixUpChunkSizes(bool restorePosition)
		{
			long position = writer.BaseStream.Position;
			bool num = dataLength > int.MaxValue;
			long num2 = writer.BaseStream.Length - 8;
			if (num)
			{
				int num3 = format.BitsPerSample / 8 * format.Channels;
				writer.BaseStream.Position = 0L;
				writer.Write(Encoding.UTF8.GetBytes("RF64"));
				writer.Write(-1);
				writer.BaseStream.Position += 4L;
				writer.Write(Encoding.UTF8.GetBytes("ds64"));
				writer.BaseStream.Position += 4L;
				writer.Write(num2);
				writer.Write(dataLength);
				writer.Write(dataLength / num3);
			}
			else
			{
				writer.BaseStream.Position = 4L;
				writer.Write((uint)num2);
				writer.BaseStream.Position = dataChunkSizePosition;
				writer.Write((uint)dataLength);
			}
			if (restorePosition)
			{
				writer.BaseStream.Position = position;
			}
		}

		public void Dispose()
		{
			if (!isDisposed)
			{
				FixUpChunkSizes(restorePosition: false);
				writer.Dispose();
				isDisposed = true;
			}
		}

		private static byte[] GetAsBytes(string message, int byteSize)
		{
			byte[] array = new byte[byteSize];
			byte[] bytes = Encoding.ASCII.GetBytes(message ?? "");
			Array.Copy(bytes, array, Math.Min(bytes.Length, byteSize));
			return array;
		}
	}
	public class CueWaveFileWriter : WaveFileWriter
	{
		private CueList cues;

		public CueWaveFileWriter(string fileName, WaveFormat waveFormat)
			: base(fileName, waveFormat)
		{
		}

		public void AddCue(int position, string label)
		{
			if (cues == null)
			{
				cues = new CueList();
			}
			cues.Add(new Cue(position, label));
		}

		private void WriteCues(BinaryWriter w)
		{
			if (cues != null)
			{
				int count = cues.GetRiffChunks().Length;
				w.Seek(0, SeekOrigin.End);
				if (w.BaseStream.Length % 2 == 1)
				{
					w.Write((byte)0);
				}
				w.Write(cues.GetRiffChunks(), 0, count);
				w.Seek(4, SeekOrigin.Begin);
				w.Write((int)(w.BaseStream.Length - 8));
			}
		}

		protected override void UpdateHeader(BinaryWriter writer)
		{
			base.UpdateHeader(writer);
			WriteCues(writer);
		}
	}
	public class DirectSoundOut : IWavePlayer, IDisposable
	{
		[StructLayout(LayoutKind.Sequential, Pack = 2)]
		internal class BufferDescription
		{
			public int dwSize;

			[MarshalAs(UnmanagedType.U4)]
			public DirectSoundBufferCaps dwFlags;

			public uint dwBufferBytes;

			public int dwReserved;

			public IntPtr lpwfxFormat;

			public Guid guidAlgo;
		}

		[StructLayout(LayoutKind.Sequential, Pack = 2)]
		internal class BufferCaps
		{
			public int dwSize;

			public int dwFlags;

			public int dwBufferBytes;

			public int dwUnlockTransferRate;

			public int dwPlayCpuOverhead;
		}

		internal enum DirectSoundCooperativeLevel : uint
		{
			DSSCL_NORMAL = 1u,
			DSSCL_PRIORITY,
			DSSCL_EXCLUSIVE,
			DSSCL_WRITEPRIMARY
		}

		[Flags]
		internal enum DirectSoundPlayFlags : uint
		{
			DSBPLAY_LOOPING = 1u,
			DSBPLAY_LOCHARDWARE = 2u,
			DSBPLAY_LOCSOFTWARE = 4u,
			DSBPLAY_TERMINATEBY_TIME = 8u,
			DSBPLAY_TERMINATEBY_DISTANCE = 0x10u,
			DSBPLAY_TERMINATEBY_PRIORITY = 0x20u
		}

		internal enum DirectSoundBufferLockFlag : uint
		{
			None,
			FromWriteCursor,
			EntireBuffer
		}

		[Flags]
		internal enum DirectSoundBufferStatus : uint
		{
			DSBSTATUS_PLAYING = 1u,
			DSBSTATUS_BUFFERLOST = 2u,
			DSBSTATUS_LOOPING = 4u,
			DSBSTATUS_LOCHARDWARE = 8u,
			DSBSTATUS_LOCSOFTWARE = 0x10u,
			DSBSTATUS_TERMINATED = 0x20u
		}

		[Flags]
		internal enum DirectSoundBufferCaps : uint
		{
			DSBCAPS_PRIMARYBUFFER = 1u,
			DSBCAPS_STATIC = 2u,
			DSBCAPS_LOCHARDWARE = 4u,
			DSBCAPS_LOCSOFTWARE = 8u,
			DSBCAPS_CTRL3D = 0x10u,
			DSBCAPS_CTRLFREQUENCY = 0x20u,
			DSBCAPS_CTRLPAN = 0x40u,
			DSBCAPS_CTRLVOLUME = 0x80u,
			DSBCAPS_CTRLPOSITIONNOTIFY = 0x100u,
			DSBCAPS_CTRLFX = 0x200u,
			DSBCAPS_STICKYFOCUS = 0x4000u,
			DSBCAPS_GLOBALFOCUS = 0x8000u,
			DSBCAPS_GETCURRENTPOSITION2 = 0x10000u,
			DSBCAPS_MUTE3DATMAXDISTANCE = 0x20000u,
			DSBCAPS_LOCDEFER = 0x40000u
		}

		internal struct DirectSoundBufferPositionNotify
		{
			public uint dwOffset;

			public IntPtr hEventNotify;
		}

		[ComImport]
		[Guid("279AFA83-4981-11CE-A521-0020AF0BE560")]
		[SuppressUnmanagedCodeSecurity]
		[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		internal interface IDirectSound
		{
			void CreateSoundBuffer([In] BufferDescription desc, [MarshalAs(UnmanagedType.Interface)] out object dsDSoundBuffer, IntPtr pUnkOuter);

			void GetCaps(IntPtr caps);

			void DuplicateSoundBuffer([In][MarshalAs(UnmanagedType.Interface)] IDirectSoundBuffer bufferOriginal, [In][MarshalAs(UnmanagedType.Interface)] IDirectSoundBuffer bufferDuplicate);

			void SetCooperativeLevel(IntPtr HWND, [In][MarshalAs(UnmanagedType.U4)] DirectSoundCooperativeLevel dwLevel);

			void Compact();

			void GetSpeakerConfig(IntPtr pdwSpeakerConfig);

			void SetSpeakerConfig(uint pdwSpeakerConfig);

			void Initialize([In][MarshalAs(UnmanagedType.LPStruct)] Guid guid);
		}

		[ComImport]
		[Guid("279AFA85-4981-11CE-A521-0020AF0BE560")]
		[SuppressUnmanagedCodeSecurity]
		[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		internal interface IDirectSoundBuffer
		{
			void GetCaps([MarshalAs(UnmanagedType.LPStruct)] BufferCaps pBufferCaps);

			void GetCurrentPosition(out uint currentPlayCursor, out uint currentWriteCursor);

			void GetFormat();

			[return: MarshalAs(UnmanagedType.I4)]
			int GetVolume();

			void GetPan(out uint pan);

			[return: MarshalAs(UnmanagedType.I4)]
			int GetFrequency();

			[return: MarshalAs(UnmanagedType.U4)]
			DirectSoundBufferStatus GetStatus();

			void Initialize([In][MarshalAs(UnmanagedType.Interface)] IDirectSound directSound, [In] BufferDescription desc);

			void Lock(int dwOffset, uint dwBytes, out IntPtr audioPtr1, out int audioBytes1, out IntPtr audioPtr2, out int audioBytes2, [MarshalAs(UnmanagedType.U4)] DirectSoundBufferLockFlag dwFlags);

			void Play(uint dwReserved1, uint dwPriority, [In][MarshalAs(UnmanagedType.U4)] DirectSoundPlayFlags dwFlags);

			void SetCurrentPosition(uint dwNewPosition);

			void SetFormat([In] WaveFormat pcfxFormat);

			void SetVolume(int volume);

			void SetPan(uint pan);

			void SetFrequency(uint frequency);

			void Stop();

			void Unlock(IntPtr pvAudioPtr1, int dwAudioBytes1, IntPtr pvAudioPtr2, int dwAudioBytes2);

			void Restore();
		}

		[ComImport]
		[Guid("b0210783-89cd-11d0-af08-00a0c925cd16")]
		[SuppressUnmanagedCodeSecurity]
		[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		internal interface IDirectSoundNotify
		{
			void SetNotificationPositions(uint dwPositionNotifies, [In][MarshalAs(UnmanagedType.LPArray)] DirectSoundBufferPositionNotify[] pcPositionNotifies);
		}

		private delegate bool DSEnumCallback(IntPtr lpGuid, IntPtr lpcstrDescription, IntPtr lpcstrModule, IntPtr lpContext);

		private PlaybackState playbackState;

		private WaveFormat waveFormat;

		private int samplesTotalSize;

		private int samplesFrameSize;

		private int nextSamplesWriteIndex;

		private int desiredLatency;

		private Guid device;

		private byte[] samples;

		private IWaveProvider waveStream;

		private IDirectSound directSound;

		private IDirectSoundBuffer primarySoundBuffer;

		private IDirectSoundBuffer sec

NAudio.Midi.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using NAudio.Utils;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Mark Heath")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("© Mark Heath 2023")]
[assembly: AssemblyFileVersion("2.2.1.0")]
[assembly: AssemblyInformationalVersion("2.2.1")]
[assembly: AssemblyProduct("NAudio.Midi")]
[assembly: AssemblyTitle("NAudio.Midi")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/naudio/NAudio")]
[assembly: AssemblyVersion("2.2.1.0")]
namespace NAudio.Midi
{
	public class ChannelAfterTouchEvent : MidiEvent
	{
		private byte afterTouchPressure;

		public int AfterTouchPressure
		{
			get
			{
				return afterTouchPressure;
			}
			set
			{
				if (value < 0 || value > 127)
				{
					throw new ArgumentOutOfRangeException("value", "After touch pressure must be in the range 0-127");
				}
				afterTouchPressure = (byte)value;
			}
		}

		public ChannelAfterTouchEvent(BinaryReader br)
		{
			afterTouchPressure = br.ReadByte();
			if ((afterTouchPressure & 0x80u) != 0)
			{
				throw new FormatException("Invalid afterTouchPressure");
			}
		}

		public ChannelAfterTouchEvent(long absoluteTime, int channel, int afterTouchPressure)
			: base(absoluteTime, channel, MidiCommandCode.ChannelAfterTouch)
		{
			AfterTouchPressure = afterTouchPressure;
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write(afterTouchPressure);
		}

		public override int GetAsShortMessage()
		{
			return base.GetAsShortMessage() + (afterTouchPressure << 8);
		}

		public override string ToString()
		{
			return $"{base.ToString()} {afterTouchPressure}";
		}
	}
	public class ControlChangeEvent : MidiEvent
	{
		private MidiController controller;

		private byte controllerValue;

		public MidiController Controller
		{
			get
			{
				return controller;
			}
			set
			{
				if ((int)value < 0 || (int)value > 127)
				{
					throw new ArgumentOutOfRangeException("value", "Controller number must be in the range 0-127");
				}
				controller = value;
			}
		}

		public int ControllerValue
		{
			get
			{
				return controllerValue;
			}
			set
			{
				if (value < 0 || value > 127)
				{
					throw new ArgumentOutOfRangeException("value", "Controller Value must be in the range 0-127");
				}
				controllerValue = (byte)value;
			}
		}

		public ControlChangeEvent(BinaryReader br)
		{
			byte b = br.ReadByte();
			controllerValue = br.ReadByte();
			if ((b & 0x80u) != 0)
			{
				throw new InvalidDataException("Invalid controller");
			}
			controller = (MidiController)b;
			if ((controllerValue & 0x80u) != 0)
			{
				throw new InvalidDataException($"Invalid controllerValue {controllerValue} for controller {controller}, Pos 0x{br.BaseStream.Position:X}");
			}
		}

		public ControlChangeEvent(long absoluteTime, int channel, MidiController controller, int controllerValue)
			: base(absoluteTime, channel, MidiCommandCode.ControlChange)
		{
			Controller = controller;
			ControllerValue = controllerValue;
		}

		public override string ToString()
		{
			return $"{base.ToString()} Controller {controller} Value {controllerValue}";
		}

		public override int GetAsShortMessage()
		{
			byte b = (byte)controller;
			return base.GetAsShortMessage() + (b << 8) + (controllerValue << 16);
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write((byte)controller);
			writer.Write(controllerValue);
		}
	}
	public class KeySignatureEvent : MetaEvent
	{
		private readonly byte sharpsFlats;

		private readonly byte majorMinor;

		public int SharpsFlats => (sbyte)sharpsFlats;

		public int MajorMinor => majorMinor;

		public KeySignatureEvent(BinaryReader br, int length)
		{
			if (length != 2)
			{
				throw new FormatException("Invalid key signature length");
			}
			sharpsFlats = br.ReadByte();
			majorMinor = br.ReadByte();
		}

		public KeySignatureEvent(int sharpsFlats, int majorMinor, long absoluteTime)
			: base(MetaEventType.KeySignature, 2, absoluteTime)
		{
			this.sharpsFlats = (byte)sharpsFlats;
			this.majorMinor = (byte)majorMinor;
		}

		public override MidiEvent Clone()
		{
			return (KeySignatureEvent)MemberwiseClone();
		}

		public override string ToString()
		{
			return $"{base.ToString()} {SharpsFlats} {majorMinor}";
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write(sharpsFlats);
			writer.Write(majorMinor);
		}
	}
	public class MetaEvent : MidiEvent
	{
		private MetaEventType metaEvent;

		internal int metaDataLength;

		public MetaEventType MetaEventType => metaEvent;

		protected MetaEvent()
		{
		}

		public MetaEvent(MetaEventType metaEventType, int metaDataLength, long absoluteTime)
			: base(absoluteTime, 1, MidiCommandCode.MetaEvent)
		{
			metaEvent = metaEventType;
			this.metaDataLength = metaDataLength;
		}

		public override MidiEvent Clone()
		{
			return new MetaEvent(metaEvent, metaDataLength, base.AbsoluteTime);
		}

		public static MetaEvent ReadMetaEvent(BinaryReader br)
		{
			MetaEventType metaEventType = (MetaEventType)br.ReadByte();
			int num = MidiEvent.ReadVarInt(br);
			MetaEvent metaEvent = new MetaEvent();
			if (metaEventType <= MetaEventType.SetTempo)
			{
				if (metaEventType <= MetaEventType.DeviceName)
				{
					if (metaEventType != 0)
					{
						if (metaEventType - 1 > MetaEventType.ProgramName)
						{
							goto IL_00a6;
						}
						metaEvent = new TextEvent(br, num);
					}
					else
					{
						metaEvent = new TrackSequenceNumberEvent(br, num);
					}
				}
				else if (metaEventType != MetaEventType.EndTrack)
				{
					if (metaEventType != MetaEventType.SetTempo)
					{
						goto IL_00a6;
					}
					metaEvent = new TempoEvent(br, num);
				}
				else if (num != 0)
				{
					throw new FormatException("End track length");
				}
			}
			else if (metaEventType <= MetaEventType.TimeSignature)
			{
				if (metaEventType != MetaEventType.SmpteOffset)
				{
					if (metaEventType != MetaEventType.TimeSignature)
					{
						goto IL_00a6;
					}
					metaEvent = new TimeSignatureEvent(br, num);
				}
				else
				{
					metaEvent = new SmpteOffsetEvent(br, num);
				}
			}
			else if (metaEventType != MetaEventType.KeySignature)
			{
				if (metaEventType != MetaEventType.SequencerSpecific)
				{
					goto IL_00a6;
				}
				metaEvent = new SequencerSpecificEvent(br, num);
			}
			else
			{
				metaEvent = new KeySignatureEvent(br, num);
			}
			metaEvent.metaEvent = metaEventType;
			metaEvent.metaDataLength = num;
			return metaEvent;
			IL_00a6:
			byte[] array = br.ReadBytes(num);
			if (array.Length != num)
			{
				throw new FormatException("Failed to read metaevent's data fully");
			}
			return new RawMetaEvent(metaEventType, 0L, array);
		}

		public override string ToString()
		{
			return $"{base.AbsoluteTime} {metaEvent}";
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write((byte)metaEvent);
			MidiEvent.WriteVarInt(writer, metaDataLength);
		}
	}
	public enum MetaEventType : byte
	{
		TrackSequenceNumber = 0,
		TextEvent = 1,
		Copyright = 2,
		SequenceTrackName = 3,
		TrackInstrumentName = 4,
		Lyric = 5,
		Marker = 6,
		CuePoint = 7,
		ProgramName = 8,
		DeviceName = 9,
		MidiChannel = 32,
		MidiPort = 33,
		EndTrack = 47,
		SetTempo = 81,
		SmpteOffset = 84,
		TimeSignature = 88,
		KeySignature = 89,
		SequencerSpecific = 127
	}
	public enum MidiCommandCode : byte
	{
		NoteOff = 128,
		NoteOn = 144,
		KeyAfterTouch = 160,
		ControlChange = 176,
		PatchChange = 192,
		ChannelAfterTouch = 208,
		PitchWheelChange = 224,
		Sysex = 240,
		Eox = 247,
		TimingClock = 248,
		StartSequence = 250,
		ContinueSequence = 251,
		StopSequence = 252,
		AutoSensing = 254,
		MetaEvent = byte.MaxValue
	}
	public enum MidiController : byte
	{
		BankSelect = 0,
		Modulation = 1,
		BreathController = 2,
		FootController = 4,
		MainVolume = 7,
		Pan = 10,
		Expression = 11,
		BankSelectLsb = 32,
		Sustain = 64,
		Portamento = 65,
		Sostenuto = 66,
		SoftPedal = 67,
		LegatoFootswitch = 68,
		ResetAllControllers = 121,
		AllNotesOff = 123
	}
	public class MidiEvent : ICloneable
	{
		private MidiCommandCode commandCode;

		private int channel;

		private int deltaTime;

		private long absoluteTime;

		public virtual int Channel
		{
			get
			{
				return channel;
			}
			set
			{
				if (value < 1 || value > 16)
				{
					throw new ArgumentOutOfRangeException("value", value, $"Channel must be 1-16 (Got {value})");
				}
				channel = value;
			}
		}

		public int DeltaTime => deltaTime;

		public long AbsoluteTime
		{
			get
			{
				return absoluteTime;
			}
			set
			{
				absoluteTime = value;
			}
		}

		public MidiCommandCode CommandCode => commandCode;

		public static MidiEvent FromRawMessage(int rawMessage)
		{
			long num = 0L;
			int num2 = rawMessage & 0xFF;
			int num3 = (rawMessage >> 8) & 0xFF;
			int num4 = (rawMessage >> 16) & 0xFF;
			int num5 = 1;
			MidiCommandCode midiCommandCode;
			if ((num2 & 0xF0) == 240)
			{
				midiCommandCode = (MidiCommandCode)num2;
			}
			else
			{
				midiCommandCode = (MidiCommandCode)((uint)num2 & 0xF0u);
				num5 = (num2 & 0xF) + 1;
			}
			switch (midiCommandCode)
			{
			case MidiCommandCode.NoteOff:
			case MidiCommandCode.NoteOn:
			case MidiCommandCode.KeyAfterTouch:
				if (num4 > 0 && midiCommandCode == MidiCommandCode.NoteOn)
				{
					return new NoteOnEvent(num, num5, num3, num4, 0);
				}
				return new NoteEvent(num, num5, midiCommandCode, num3, num4);
			case MidiCommandCode.ControlChange:
				return new ControlChangeEvent(num, num5, (MidiController)num3, num4);
			case MidiCommandCode.PatchChange:
				return new PatchChangeEvent(num, num5, num3);
			case MidiCommandCode.ChannelAfterTouch:
				return new ChannelAfterTouchEvent(num, num5, num3);
			case MidiCommandCode.PitchWheelChange:
				return new PitchWheelChangeEvent(num, num5, num3 + (num4 << 7));
			case MidiCommandCode.TimingClock:
			case MidiCommandCode.StartSequence:
			case MidiCommandCode.ContinueSequence:
			case MidiCommandCode.StopSequence:
			case MidiCommandCode.AutoSensing:
				return new MidiEvent(num, num5, midiCommandCode);
			default:
				throw new FormatException($"Unsupported MIDI Command Code for Raw Message {midiCommandCode}");
			}
		}

		public static MidiEvent ReadNextEvent(BinaryReader br, MidiEvent previous)
		{
			int num = ReadVarInt(br);
			int num2 = 1;
			byte b = br.ReadByte();
			MidiCommandCode midiCommandCode;
			if ((b & 0x80) == 0)
			{
				midiCommandCode = previous.CommandCode;
				num2 = previous.Channel;
				br.BaseStream.Position--;
			}
			else if ((b & 0xF0) == 240)
			{
				midiCommandCode = (MidiCommandCode)b;
			}
			else
			{
				midiCommandCode = (MidiCommandCode)(b & 0xF0u);
				num2 = (b & 0xF) + 1;
			}
			MidiEvent midiEvent;
			switch (midiCommandCode)
			{
			case MidiCommandCode.NoteOn:
				midiEvent = new NoteOnEvent(br);
				break;
			case MidiCommandCode.NoteOff:
			case MidiCommandCode.KeyAfterTouch:
				midiEvent = new NoteEvent(br);
				break;
			case MidiCommandCode.ControlChange:
				midiEvent = new ControlChangeEvent(br);
				break;
			case MidiCommandCode.PatchChange:
				midiEvent = new PatchChangeEvent(br);
				break;
			case MidiCommandCode.ChannelAfterTouch:
				midiEvent = new ChannelAfterTouchEvent(br);
				break;
			case MidiCommandCode.PitchWheelChange:
				midiEvent = new PitchWheelChangeEvent(br);
				break;
			case MidiCommandCode.TimingClock:
			case MidiCommandCode.StartSequence:
			case MidiCommandCode.ContinueSequence:
			case MidiCommandCode.StopSequence:
				midiEvent = new MidiEvent();
				break;
			case MidiCommandCode.Sysex:
				midiEvent = SysexEvent.ReadSysexEvent(br);
				break;
			case MidiCommandCode.MetaEvent:
				midiEvent = MetaEvent.ReadMetaEvent(br);
				break;
			default:
				throw new FormatException($"Unsupported MIDI Command Code {(byte)midiCommandCode:X2}");
			}
			midiEvent.channel = num2;
			midiEvent.deltaTime = num;
			midiEvent.commandCode = midiCommandCode;
			return midiEvent;
		}

		public virtual int GetAsShortMessage()
		{
			return channel - 1 + (int)commandCode;
		}

		protected MidiEvent()
		{
		}

		public MidiEvent(long absoluteTime, int channel, MidiCommandCode commandCode)
		{
			this.absoluteTime = absoluteTime;
			Channel = channel;
			this.commandCode = commandCode;
		}

		public virtual MidiEvent Clone()
		{
			return (MidiEvent)MemberwiseClone();
		}

		object ICloneable.Clone()
		{
			return Clone();
		}

		public static bool IsNoteOff(MidiEvent midiEvent)
		{
			if (midiEvent != null)
			{
				if (midiEvent.CommandCode == MidiCommandCode.NoteOn)
				{
					return ((NoteEvent)midiEvent).Velocity == 0;
				}
				return midiEvent.CommandCode == MidiCommandCode.NoteOff;
			}
			return false;
		}

		public static bool IsNoteOn(MidiEvent midiEvent)
		{
			if (midiEvent != null && midiEvent.CommandCode == MidiCommandCode.NoteOn)
			{
				return ((NoteEvent)midiEvent).Velocity > 0;
			}
			return false;
		}

		public static bool IsEndTrack(MidiEvent midiEvent)
		{
			if (midiEvent != null && midiEvent is MetaEvent metaEvent)
			{
				return metaEvent.MetaEventType == MetaEventType.EndTrack;
			}
			return false;
		}

		public override string ToString()
		{
			if ((int)commandCode >= 240)
			{
				return $"{absoluteTime} {commandCode}";
			}
			return $"{absoluteTime} {commandCode} Ch: {channel}";
		}

		public static int ReadVarInt(BinaryReader br)
		{
			int num = 0;
			for (int i = 0; i < 4; i++)
			{
				byte b = br.ReadByte();
				num <<= 7;
				num += b & 0x7F;
				if ((b & 0x80) == 0)
				{
					return num;
				}
			}
			throw new FormatException("Invalid Var Int");
		}

		public static void WriteVarInt(BinaryWriter writer, int value)
		{
			if (value < 0)
			{
				throw new ArgumentOutOfRangeException("value", value, "Cannot write a negative Var Int");
			}
			if (value > 268435455)
			{
				throw new ArgumentOutOfRangeException("value", value, "Maximum allowed Var Int is 0x0FFFFFFF");
			}
			int num = 0;
			byte[] array = new byte[4];
			do
			{
				array[num++] = (byte)((uint)value & 0x7Fu);
				value >>= 7;
			}
			while (value > 0);
			while (num > 0)
			{
				num--;
				if (num > 0)
				{
					writer.Write((byte)(array[num] | 0x80u));
				}
				else
				{
					writer.Write(array[num]);
				}
			}
		}

		public virtual void Export(ref long absoluteTime, BinaryWriter writer)
		{
			if (this.absoluteTime < absoluteTime)
			{
				throw new FormatException("Can't export unsorted MIDI events");
			}
			WriteVarInt(writer, (int)(this.absoluteTime - absoluteTime));
			absoluteTime = this.absoluteTime;
			int num = (int)commandCode;
			if (commandCode != MidiCommandCode.MetaEvent)
			{
				num += channel - 1;
			}
			writer.Write((byte)num);
		}
	}
	public class MidiEventCollection : IEnumerable<IList<MidiEvent>>, IEnumerable
	{
		private int midiFileType;

		private readonly List<IList<MidiEvent>> trackEvents;

		public int Tracks => trackEvents.Count;

		public long StartAbsoluteTime { get; set; }

		public int DeltaTicksPerQuarterNote { get; }

		public IList<MidiEvent> this[int trackNumber] => trackEvents[trackNumber];

		public int MidiFileType
		{
			get
			{
				return midiFileType;
			}
			set
			{
				if (midiFileType != value)
				{
					midiFileType = value;
					if (value == 0)
					{
						FlattenToOneTrack();
					}
					else
					{
						ExplodeToManyTracks();
					}
				}
			}
		}

		public MidiEventCollection(int midiFileType, int deltaTicksPerQuarterNote)
		{
			this.midiFileType = midiFileType;
			DeltaTicksPerQuarterNote = deltaTicksPerQuarterNote;
			StartAbsoluteTime = 0L;
			trackEvents = new List<IList<MidiEvent>>();
		}

		public IList<MidiEvent> GetTrackEvents(int trackNumber)
		{
			return trackEvents[trackNumber];
		}

		public IList<MidiEvent> AddTrack()
		{
			return AddTrack(null);
		}

		public IList<MidiEvent> AddTrack(IList<MidiEvent> initialEvents)
		{
			List<MidiEvent> list = new List<MidiEvent>();
			if (initialEvents != null)
			{
				list.AddRange(initialEvents);
			}
			trackEvents.Add(list);
			return list;
		}

		public void RemoveTrack(int track)
		{
			trackEvents.RemoveAt(track);
		}

		public void Clear()
		{
			trackEvents.Clear();
		}

		public void AddEvent(MidiEvent midiEvent, int originalTrack)
		{
			if (midiFileType == 0)
			{
				EnsureTracks(1);
				trackEvents[0].Add(midiEvent);
			}
			else if (originalTrack == 0)
			{
				switch (midiEvent.CommandCode)
				{
				case MidiCommandCode.NoteOff:
				case MidiCommandCode.NoteOn:
				case MidiCommandCode.KeyAfterTouch:
				case MidiCommandCode.ControlChange:
				case MidiCommandCode.PatchChange:
				case MidiCommandCode.ChannelAfterTouch:
				case MidiCommandCode.PitchWheelChange:
					EnsureTracks(midiEvent.Channel + 1);
					trackEvents[midiEvent.Channel].Add(midiEvent);
					break;
				default:
					EnsureTracks(1);
					trackEvents[0].Add(midiEvent);
					break;
				}
			}
			else
			{
				EnsureTracks(originalTrack + 1);
				trackEvents[originalTrack].Add(midiEvent);
			}
		}

		private void EnsureTracks(int count)
		{
			for (int i = trackEvents.Count; i < count; i++)
			{
				trackEvents.Add(new List<MidiEvent>());
			}
		}

		private void ExplodeToManyTracks()
		{
			IList<MidiEvent> list = trackEvents[0];
			Clear();
			foreach (MidiEvent item in list)
			{
				AddEvent(item, 0);
			}
			PrepareForExport();
		}

		private void FlattenToOneTrack()
		{
			bool flag = false;
			for (int i = 1; i < trackEvents.Count; i++)
			{
				foreach (MidiEvent item in trackEvents[i])
				{
					if (!MidiEvent.IsEndTrack(item))
					{
						trackEvents[0].Add(item);
						flag = true;
					}
				}
			}
			for (int num = trackEvents.Count - 1; num > 0; num--)
			{
				RemoveTrack(num);
			}
			if (flag)
			{
				PrepareForExport();
			}
		}

		public void PrepareForExport()
		{
			MidiEventComparer comparer = new MidiEventComparer();
			foreach (IList<MidiEvent> trackEvent in trackEvents)
			{
				MergeSort.Sort(trackEvent, comparer);
				int num = 0;
				while (num < trackEvent.Count - 1)
				{
					if (MidiEvent.IsEndTrack(trackEvent[num]))
					{
						trackEvent.RemoveAt(num);
					}
					else
					{
						num++;
					}
				}
			}
			int num2 = 0;
			while (num2 < trackEvents.Count)
			{
				IList<MidiEvent> list = trackEvents[num2];
				if (list.Count == 0)
				{
					RemoveTrack(num2);
					continue;
				}
				if (list.Count == 1 && MidiEvent.IsEndTrack(list[0]))
				{
					RemoveTrack(num2);
					continue;
				}
				if (!MidiEvent.IsEndTrack(list[list.Count - 1]))
				{
					list.Add(new MetaEvent(MetaEventType.EndTrack, 0, list[list.Count - 1].AbsoluteTime));
				}
				num2++;
			}
		}

		public IEnumerator<IList<MidiEvent>> GetEnumerator()
		{
			return trackEvents.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return trackEvents.GetEnumerator();
		}
	}
	public class MidiEventComparer : IComparer<MidiEvent>
	{
		public int Compare(MidiEvent x, MidiEvent y)
		{
			long num = x.AbsoluteTime;
			long num2 = y.AbsoluteTime;
			if (num == num2)
			{
				MetaEvent metaEvent = x as MetaEvent;
				MetaEvent metaEvent2 = y as MetaEvent;
				if (metaEvent != null)
				{
					num = ((metaEvent.MetaEventType != MetaEventType.EndTrack) ? long.MinValue : long.MaxValue);
				}
				if (metaEvent2 != null)
				{
					num2 = ((metaEvent2.MetaEventType != MetaEventType.EndTrack) ? long.MinValue : long.MaxValue);
				}
			}
			return num.CompareTo(num2);
		}
	}
	public class MidiFile
	{
		private readonly MidiEventCollection events;

		private readonly ushort fileFormat;

		private readonly ushort deltaTicksPerQuarterNote;

		private readonly bool strictChecking;

		public int FileFormat => fileFormat;

		public MidiEventCollection Events => events;

		public int Tracks => events.Tracks;

		public int DeltaTicksPerQuarterNote => deltaTicksPerQuarterNote;

		public MidiFile(string filename)
			: this(filename, strictChecking: true)
		{
		}

		public MidiFile(string filename, bool strictChecking)
			: this(File.OpenRead(filename), strictChecking, ownInputStream: true)
		{
		}

		public MidiFile(Stream inputStream, bool strictChecking)
			: this(inputStream, strictChecking, ownInputStream: false)
		{
		}

		private MidiFile(Stream inputStream, bool strictChecking, bool ownInputStream)
		{
			this.strictChecking = strictChecking;
			BinaryReader binaryReader = new BinaryReader(inputStream);
			try
			{
				if (Encoding.UTF8.GetString(binaryReader.ReadBytes(4)) != "MThd")
				{
					throw new FormatException("Not a MIDI file - header chunk missing");
				}
				uint num = SwapUInt32(binaryReader.ReadUInt32());
				if (num != 6)
				{
					throw new FormatException("Unexpected header chunk length");
				}
				fileFormat = SwapUInt16(binaryReader.ReadUInt16());
				int num2 = SwapUInt16(binaryReader.ReadUInt16());
				deltaTicksPerQuarterNote = SwapUInt16(binaryReader.ReadUInt16());
				events = new MidiEventCollection((fileFormat != 0) ? 1 : 0, deltaTicksPerQuarterNote);
				for (int i = 0; i < num2; i++)
				{
					events.AddTrack();
				}
				long num3 = 0L;
				for (int j = 0; j < num2; j++)
				{
					if (fileFormat == 1)
					{
						num3 = 0L;
					}
					if (Encoding.UTF8.GetString(binaryReader.ReadBytes(4)) != "MTrk")
					{
						throw new FormatException("Invalid chunk header");
					}
					num = SwapUInt32(binaryReader.ReadUInt32());
					long position = binaryReader.BaseStream.Position;
					MidiEvent midiEvent = null;
					List<NoteOnEvent> list = new List<NoteOnEvent>();
					while (binaryReader.BaseStream.Position < position + num)
					{
						try
						{
							midiEvent = MidiEvent.ReadNextEvent(binaryReader, midiEvent);
						}
						catch (InvalidDataException)
						{
							if (strictChecking)
							{
								throw;
							}
							continue;
						}
						catch (FormatException)
						{
							if (strictChecking)
							{
								throw;
							}
							continue;
						}
						num3 = (midiEvent.AbsoluteTime = num3 + midiEvent.DeltaTime);
						events[j].Add(midiEvent);
						if (midiEvent.CommandCode == MidiCommandCode.NoteOn)
						{
							NoteEvent noteEvent = (NoteEvent)midiEvent;
							if (noteEvent.Velocity > 0)
							{
								list.Add((NoteOnEvent)noteEvent);
							}
							else
							{
								FindNoteOn(noteEvent, list);
							}
						}
						else if (midiEvent.CommandCode == MidiCommandCode.NoteOff)
						{
							FindNoteOn((NoteEvent)midiEvent, list);
						}
						else if (midiEvent.CommandCode == MidiCommandCode.MetaEvent && ((MetaEvent)midiEvent).MetaEventType == MetaEventType.EndTrack && strictChecking && binaryReader.BaseStream.Position < position + num)
						{
							throw new FormatException($"End Track event was not the last MIDI event on track {j}");
						}
					}
					if (list.Count > 0 && strictChecking)
					{
						throw new FormatException($"Note ons without note offs {list.Count} (file format {fileFormat})");
					}
					if (binaryReader.BaseStream.Position != position + num)
					{
						throw new FormatException($"Read too far {num}+{position}!={binaryReader.BaseStream.Position}");
					}
				}
			}
			finally
			{
				if (ownInputStream)
				{
					binaryReader.Dispose();
				}
			}
		}

		private void FindNoteOn(NoteEvent offEvent, List<NoteOnEvent> outstandingNoteOns)
		{
			bool flag = false;
			foreach (NoteOnEvent outstandingNoteOn in outstandingNoteOns)
			{
				if (outstandingNoteOn.Channel == offEvent.Channel && outstandingNoteOn.NoteNumber == offEvent.NoteNumber)
				{
					outstandingNoteOn.OffEvent = offEvent;
					outstandingNoteOns.Remove(outstandingNoteOn);
					flag = true;
					break;
				}
			}
			if (!flag && strictChecking)
			{
				throw new FormatException($"Got an off without an on {offEvent}");
			}
		}

		private static uint SwapUInt32(uint i)
		{
			return ((i & 0xFF000000u) >> 24) | ((i & 0xFF0000) >> 8) | ((i & 0xFF00) << 8) | ((i & 0xFF) << 24);
		}

		private static ushort SwapUInt16(ushort i)
		{
			return (ushort)(((i & 0xFF00) >> 8) | ((i & 0xFF) << 8));
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendFormat("Format {0}, Tracks {1}, Delta Ticks Per Quarter Note {2}\r\n", fileFormat, Tracks, deltaTicksPerQuarterNote);
			for (int i = 0; i < Tracks; i++)
			{
				foreach (MidiEvent item in events[i])
				{
					stringBuilder.AppendFormat("{0}\r\n", item);
				}
			}
			return stringBuilder.ToString();
		}

		public static void Export(string filename, MidiEventCollection events)
		{
			if (events.MidiFileType == 0 && events.Tracks > 1)
			{
				throw new ArgumentException("Can't export more than one track to a type 0 file");
			}
			using BinaryWriter binaryWriter = new BinaryWriter(File.Create(filename));
			binaryWriter.Write(Encoding.UTF8.GetBytes("MThd"));
			binaryWriter.Write(SwapUInt32(6u));
			binaryWriter.Write(SwapUInt16((ushort)events.MidiFileType));
			binaryWriter.Write(SwapUInt16((ushort)events.Tracks));
			binaryWriter.Write(SwapUInt16((ushort)events.DeltaTicksPerQuarterNote));
			for (int i = 0; i < events.Tracks; i++)
			{
				IList<MidiEvent> list = events[i];
				binaryWriter.Write(Encoding.UTF8.GetBytes("MTrk"));
				long position = binaryWriter.BaseStream.Position;
				binaryWriter.Write(SwapUInt32(0u));
				long absoluteTime = events.StartAbsoluteTime;
				MergeSort.Sort(list, new MidiEventComparer());
				_ = list.Count;
				_ = 0;
				foreach (MidiEvent item in list)
				{
					item.Export(ref absoluteTime, binaryWriter);
				}
				uint num = (uint)((int)(binaryWriter.BaseStream.Position - position) - 4);
				binaryWriter.BaseStream.Position = position;
				binaryWriter.Write(SwapUInt32(num));
				binaryWriter.BaseStream.Position += num;
			}
		}
	}
	public class MidiIn : IDisposable
	{
		private IntPtr hMidiIn = IntPtr.Zero;

		private bool disposeIsRunning;

		private bool disposed;

		private MidiInterop.MidiInCallback callback;

		private IntPtr[] SysexBufferHeaders = new IntPtr[0];

		public static int NumberOfDevices => MidiInterop.midiInGetNumDevs();

		public event EventHandler<MidiInMessageEventArgs> MessageReceived;

		public event EventHandler<MidiInMessageEventArgs> ErrorReceived;

		public event EventHandler<MidiInSysexMessageEventArgs> SysexMessageReceived;

		public MidiIn(int deviceNo)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			callback = Callback;
			MmException.Try(MidiInterop.midiInOpen(out hMidiIn, (IntPtr)deviceNo, callback, IntPtr.Zero, 196608), "midiInOpen");
		}

		public void Close()
		{
			Dispose();
		}

		public void Dispose()
		{
			GC.KeepAlive(callback);
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		public void Start()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			MmException.Try(MidiInterop.midiInStart(hMidiIn), "midiInStart");
		}

		public void Stop()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			MmException.Try(MidiInterop.midiInStop(hMidiIn), "midiInStop");
		}

		public void Reset()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			MmException.Try(MidiInterop.midiInReset(hMidiIn), "midiInReset");
		}

		public void CreateSysexBuffers(int bufferSize, int numberOfBuffers)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			SysexBufferHeaders = new IntPtr[numberOfBuffers];
			int cb = Marshal.SizeOf(typeof(MidiInterop.MIDIHDR));
			for (int i = 0; i < numberOfBuffers; i++)
			{
				MidiInterop.MIDIHDR structure = default(MidiInterop.MIDIHDR);
				structure.dwBufferLength = bufferSize;
				structure.dwBytesRecorded = 0;
				structure.lpData = Marshal.AllocHGlobal(bufferSize);
				structure.dwFlags = 0;
				IntPtr intPtr = Marshal.AllocHGlobal(cb);
				Marshal.StructureToPtr(structure, intPtr, fDeleteOld: false);
				MmException.Try(MidiInterop.midiInPrepareHeader(hMidiIn, intPtr, Marshal.SizeOf(typeof(MidiInterop.MIDIHDR))), "midiInPrepareHeader");
				MmException.Try(MidiInterop.midiInAddBuffer(hMidiIn, intPtr, Marshal.SizeOf(typeof(MidiInterop.MIDIHDR))), "midiInAddBuffer");
				SysexBufferHeaders[i] = intPtr;
			}
		}

		private void Callback(IntPtr midiInHandle, MidiInterop.MidiInMessage message, IntPtr userData, IntPtr messageParameter1, IntPtr messageParameter2)
		{
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			switch (message)
			{
			case MidiInterop.MidiInMessage.Data:
				if (this.MessageReceived != null)
				{
					this.MessageReceived(this, new MidiInMessageEventArgs(messageParameter1.ToInt32(), messageParameter2.ToInt32()));
				}
				break;
			case MidiInterop.MidiInMessage.Error:
				if (this.ErrorReceived != null)
				{
					this.ErrorReceived(this, new MidiInMessageEventArgs(messageParameter1.ToInt32(), messageParameter2.ToInt32()));
				}
				break;
			case MidiInterop.MidiInMessage.LongData:
				if (this.SysexMessageReceived != null)
				{
					MidiInterop.MIDIHDR mIDIHDR = (MidiInterop.MIDIHDR)Marshal.PtrToStructure(messageParameter1, typeof(MidiInterop.MIDIHDR));
					byte[] array = new byte[mIDIHDR.dwBytesRecorded];
					Marshal.Copy(mIDIHDR.lpData, array, 0, mIDIHDR.dwBytesRecorded);
					if (array.Length != 0)
					{
						this.SysexMessageReceived(this, new MidiInSysexMessageEventArgs(array, messageParameter2.ToInt32()));
					}
					if (!disposeIsRunning)
					{
						MidiInterop.midiInAddBuffer(hMidiIn, messageParameter1, Marshal.SizeOf(typeof(MidiInterop.MIDIHDR)));
					}
				}
				break;
			case MidiInterop.MidiInMessage.Open:
			case MidiInterop.MidiInMessage.Close:
			case MidiInterop.MidiInMessage.LongError:
			case (MidiInterop.MidiInMessage)967:
			case (MidiInterop.MidiInMessage)968:
			case (MidiInterop.MidiInMessage)969:
			case (MidiInterop.MidiInMessage)970:
			case (MidiInterop.MidiInMessage)971:
			case MidiInterop.MidiInMessage.MoreData:
				break;
			}
		}

		public static MidiInCapabilities DeviceInfo(int midiInDeviceNumber)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			MidiInCapabilities capabilities = default(MidiInCapabilities);
			int size = Marshal.SizeOf(capabilities);
			MmException.Try(MidiInterop.midiInGetDevCaps((IntPtr)midiInDeviceNumber, out capabilities, size), "midiInGetDevCaps");
			return capabilities;
		}

		protected virtual void Dispose(bool disposing)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (!disposed)
			{
				disposeIsRunning = true;
				if (SysexBufferHeaders.Length != 0)
				{
					MmException.Try(MidiInterop.midiInReset(hMidiIn), "midiInReset");
					IntPtr[] sysexBufferHeaders = SysexBufferHeaders;
					foreach (IntPtr intPtr in sysexBufferHeaders)
					{
						MidiInterop.MIDIHDR obj = (MidiInterop.MIDIHDR)Marshal.PtrToStructure(intPtr, typeof(MidiInterop.MIDIHDR));
						MmException.Try(MidiInterop.midiInUnprepareHeader(hMidiIn, intPtr, Marshal.SizeOf(typeof(MidiInterop.MIDIHDR))), "midiInPrepareHeader");
						Marshal.FreeHGlobal(obj.lpData);
						Marshal.FreeHGlobal(intPtr);
					}
					SysexBufferHeaders = new IntPtr[0];
				}
				MidiInterop.midiInClose(hMidiIn);
			}
			disposed = true;
			disposeIsRunning = false;
		}

		~MidiIn()
		{
			Dispose(disposing: false);
		}
	}
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	public struct MidiInCapabilities
	{
		private ushort manufacturerId;

		private ushort productId;

		private uint driverVersion;

		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
		private string productName;

		private int support;

		private const int MaxProductNameLength = 32;

		public Manufacturers Manufacturer => (Manufacturers)manufacturerId;

		public int ProductId => productId;

		public string ProductName => productName;
	}
	public class MidiInMessageEventArgs : EventArgs
	{
		public int RawMessage { get; private set; }

		public MidiEvent MidiEvent { get; private set; }

		public int Timestamp { get; private set; }

		public MidiInMessageEventArgs(int message, int timestamp)
		{
			RawMessage = message;
			Timestamp = timestamp;
			try
			{
				MidiEvent = MidiEvent.FromRawMessage(message);
			}
			catch (Exception)
			{
			}
		}
	}
	public class MidiInSysexMessageEventArgs : EventArgs
	{
		public byte[] SysexBytes { get; private set; }

		public int Timestamp { get; private set; }

		public MidiInSysexMessageEventArgs(byte[] sysexBytes, int timestamp)
		{
			SysexBytes = sysexBytes;
			Timestamp = timestamp;
		}
	}
	internal class MidiInterop
	{
		public enum MidiInMessage
		{
			Open = 961,
			Close = 962,
			Data = 963,
			LongData = 964,
			Error = 965,
			LongError = 966,
			MoreData = 972
		}

		public enum MidiOutMessage
		{
			Open = 967,
			Close,
			Done
		}

		public delegate void MidiInCallback(IntPtr midiInHandle, MidiInMessage message, IntPtr userData, IntPtr messageParameter1, IntPtr messageParameter2);

		public delegate void MidiOutCallback(IntPtr midiInHandle, MidiOutMessage message, IntPtr userData, IntPtr messageParameter1, IntPtr messageParameter2);

		public struct MMTIME
		{
			public int wType;

			public int u;
		}

		public struct MIDIEVENT
		{
			public int dwDeltaTime;

			public int dwStreamID;

			public int dwEvent;

			[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
			public int dwParms;
		}

		public struct MIDIHDR
		{
			public IntPtr lpData;

			public int dwBufferLength;

			public int dwBytesRecorded;

			public IntPtr dwUser;

			public int dwFlags;

			public IntPtr lpNext;

			public IntPtr reserved;

			public int dwOffset;

			[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
			public IntPtr[] dwReserved;
		}

		public struct MIDIPROPTEMPO
		{
			public int cbStruct;

			public int dwTempo;
		}

		public const int CALLBACK_FUNCTION = 196608;

		public const int CALLBACK_NULL = 0;

		[DllImport("winmm.dll")]
		public static extern MmResult midiConnect(IntPtr hMidiIn, IntPtr hMidiOut, IntPtr pReserved);

		[DllImport("winmm.dll")]
		public static extern MmResult midiDisconnect(IntPtr hMidiIn, IntPtr hMidiOut, IntPtr pReserved);

		[DllImport("winmm.dll")]
		public static extern MmResult midiInAddBuffer(IntPtr hMidiIn, IntPtr lpMidiInHdr, int uSize);

		[DllImport("winmm.dll")]
		public static extern MmResult midiInClose(IntPtr hMidiIn);

		[DllImport("winmm.dll", CharSet = CharSet.Auto)]
		public static extern MmResult midiInGetDevCaps(IntPtr deviceId, out MidiInCapabilities capabilities, int size);

		[DllImport("winmm.dll")]
		public static extern MmResult midiInGetErrorText(int err, string lpText, int uSize);

		[DllImport("winmm.dll")]
		public static extern MmResult midiInGetID(IntPtr hMidiIn, out int lpuDeviceId);

		[DllImport("winmm.dll")]
		public static extern int midiInGetNumDevs();

		[DllImport("winmm.dll")]
		public static extern MmResult midiInMessage(IntPtr hMidiIn, int msg, IntPtr dw1, IntPtr dw2);

		[DllImport("winmm.dll")]
		public static extern MmResult midiInOpen(out IntPtr hMidiIn, IntPtr uDeviceID, MidiInCallback callback, IntPtr dwInstance, int dwFlags);

		[DllImport("winmm.dll", EntryPoint = "midiInOpen")]
		public static extern MmResult midiInOpenWindow(out IntPtr hMidiIn, IntPtr uDeviceID, IntPtr callbackWindowHandle, IntPtr dwInstance, int dwFlags);

		[DllImport("winmm.dll")]
		public static extern MmResult midiInPrepareHeader(IntPtr hMidiIn, IntPtr lpMidiInHdr, int uSize);

		[DllImport("winmm.dll")]
		public static extern MmResult midiInReset(IntPtr hMidiIn);

		[DllImport("winmm.dll")]
		public static extern MmResult midiInStart(IntPtr hMidiIn);

		[DllImport("winmm.dll")]
		public static extern MmResult midiInStop(IntPtr hMidiIn);

		[DllImport("winmm.dll")]
		public static extern MmResult midiInUnprepareHeader(IntPtr hMidiIn, IntPtr lpMidiInHdr, int uSize);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutCacheDrumPatches(IntPtr hMidiOut, int uPatch, IntPtr lpKeyArray, int uFlags);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutCachePatches(IntPtr hMidiOut, int uBank, IntPtr lpPatchArray, int uFlags);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutClose(IntPtr hMidiOut);

		[DllImport("winmm.dll", CharSet = CharSet.Auto)]
		public static extern MmResult midiOutGetDevCaps(IntPtr deviceNumber, out MidiOutCapabilities caps, int uSize);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutGetErrorText(IntPtr err, string lpText, int uSize);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutGetID(IntPtr hMidiOut, out int lpuDeviceID);

		[DllImport("winmm.dll")]
		public static extern int midiOutGetNumDevs();

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutGetVolume(IntPtr uDeviceID, ref int lpdwVolume);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutLongMsg(IntPtr hMidiOut, ref MIDIHDR lpMidiOutHdr, int uSize);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutMessage(IntPtr hMidiOut, int msg, IntPtr dw1, IntPtr dw2);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutOpen(out IntPtr lphMidiOut, IntPtr uDeviceID, MidiOutCallback dwCallback, IntPtr dwInstance, int dwFlags);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutPrepareHeader(IntPtr hMidiOut, ref MIDIHDR lpMidiOutHdr, int uSize);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutReset(IntPtr hMidiOut);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutSetVolume(IntPtr hMidiOut, int dwVolume);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutShortMsg(IntPtr hMidiOut, int dwMsg);

		[DllImport("winmm.dll")]
		public static extern MmResult midiOutUnprepareHeader(IntPtr hMidiOut, ref MIDIHDR lpMidiOutHdr, int uSize);

		[DllImport("winmm.dll")]
		public static extern MmResult midiStreamClose(IntPtr hMidiStream);

		[DllImport("winmm.dll")]
		public static extern MmResult midiStreamOpen(out IntPtr hMidiStream, IntPtr puDeviceID, int cMidi, IntPtr dwCallback, IntPtr dwInstance, int fdwOpen);

		[DllImport("winmm.dll")]
		public static extern MmResult midiStreamOut(IntPtr hMidiStream, ref MIDIHDR pmh, int cbmh);

		[DllImport("winmm.dll")]
		public static extern MmResult midiStreamPause(IntPtr hMidiStream);

		[DllImport("winmm.dll")]
		public static extern MmResult midiStreamPosition(IntPtr hMidiStream, ref MMTIME lpmmt, int cbmmt);

		[DllImport("winmm.dll")]
		public static extern MmResult midiStreamProperty(IntPtr hMidiStream, IntPtr lppropdata, int dwProperty);

		[DllImport("winmm.dll")]
		public static extern MmResult midiStreamRestart(IntPtr hMidiStream);

		[DllImport("winmm.dll")]
		public static extern MmResult midiStreamStop(IntPtr hMidiStream);
	}
	public class MidiMessage
	{
		private int rawData;

		public int RawData => rawData;

		public MidiMessage(int status, int data1, int data2)
		{
			rawData = status + (data1 << 8) + (data2 << 16);
		}

		public MidiMessage(int rawData)
		{
			this.rawData = rawData;
		}

		public static MidiMessage StartNote(int note, int volume, int channel)
		{
			ValidateNoteParameters(note, volume, channel);
			return new MidiMessage(144 + channel - 1, note, volume);
		}

		private static void ValidateNoteParameters(int note, int volume, int channel)
		{
			ValidateChannel(channel);
			if (note < 0 || note > 127)
			{
				throw new ArgumentOutOfRangeException("note", "Note number must be in the range 0-127");
			}
			if (volume < 0 || volume > 127)
			{
				throw new ArgumentOutOfRangeException("volume", "Velocity must be in the range 0-127");
			}
		}

		private static void ValidateChannel(int channel)
		{
			if (channel < 1 || channel > 16)
			{
				throw new ArgumentOutOfRangeException("channel", channel, $"Channel must be 1-16 (Got {channel})");
			}
		}

		public static MidiMessage StopNote(int note, int volume, int channel)
		{
			ValidateNoteParameters(note, volume, channel);
			return new MidiMessage(128 + channel - 1, note, volume);
		}

		public static MidiMessage ChangePatch(int patch, int channel)
		{
			ValidateChannel(channel);
			return new MidiMessage(192 + channel - 1, patch, 0);
		}

		public static MidiMessage ChangeControl(int controller, int value, int channel)
		{
			ValidateChannel(channel);
			return new MidiMessage(176 + channel - 1, controller, value);
		}
	}
	public class MidiOut : IDisposable
	{
		private IntPtr hMidiOut = IntPtr.Zero;

		private bool disposed;

		private MidiInterop.MidiOutCallback callback;

		public static int NumberOfDevices => MidiInterop.midiOutGetNumDevs();

		public int Volume
		{
			get
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				int lpdwVolume = 0;
				MmException.Try(MidiInterop.midiOutGetVolume(hMidiOut, ref lpdwVolume), "midiOutGetVolume");
				return lpdwVolume;
			}
			set
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				MmException.Try(MidiInterop.midiOutSetVolume(hMidiOut, value), "midiOutSetVolume");
			}
		}

		public static MidiOutCapabilities DeviceInfo(int midiOutDeviceNumber)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			MidiOutCapabilities caps = default(MidiOutCapabilities);
			int uSize = Marshal.SizeOf(caps);
			MmException.Try(MidiInterop.midiOutGetDevCaps((IntPtr)midiOutDeviceNumber, out caps, uSize), "midiOutGetDevCaps");
			return caps;
		}

		public MidiOut(int deviceNo)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			callback = Callback;
			MmException.Try(MidiInterop.midiOutOpen(out hMidiOut, (IntPtr)deviceNo, callback, IntPtr.Zero, 196608), "midiOutOpen");
		}

		public void Close()
		{
			Dispose();
		}

		public void Dispose()
		{
			GC.KeepAlive(callback);
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		public void Reset()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			MmException.Try(MidiInterop.midiOutReset(hMidiOut), "midiOutReset");
		}

		public void SendDriverMessage(int message, int param1, int param2)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			MmException.Try(MidiInterop.midiOutMessage(hMidiOut, message, (IntPtr)param1, (IntPtr)param2), "midiOutMessage");
		}

		public void Send(int message)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			MmException.Try(MidiInterop.midiOutShortMsg(hMidiOut, message), "midiOutShortMsg");
		}

		protected virtual void Dispose(bool disposing)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (!disposed)
			{
				MidiInterop.midiOutClose(hMidiOut);
			}
			disposed = true;
		}

		private void Callback(IntPtr midiInHandle, MidiInterop.MidiOutMessage message, IntPtr userData, IntPtr messageParameter1, IntPtr messageParameter2)
		{
		}

		public void SendBuffer(byte[] byteBuffer)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			MidiInterop.MIDIHDR lpMidiOutHdr = default(MidiInterop.MIDIHDR);
			lpMidiOutHdr.lpData = Marshal.AllocHGlobal(byteBuffer.Length);
			Marshal.Copy(byteBuffer, 0, lpMidiOutHdr.lpData, byteBuffer.Length);
			lpMidiOutHdr.dwBufferLength = byteBuffer.Length;
			lpMidiOutHdr.dwBytesRecorded = byteBuffer.Length;
			int uSize = Marshal.SizeOf(lpMidiOutHdr);
			MidiInterop.midiOutPrepareHeader(hMidiOut, ref lpMidiOutHdr, uSize);
			if ((int)MidiInterop.midiOutLongMsg(hMidiOut, ref lpMidiOutHdr, uSize) != 0)
			{
				MidiInterop.midiOutUnprepareHeader(hMidiOut, ref lpMidiOutHdr, uSize);
			}
			Marshal.FreeHGlobal(lpMidiOutHdr.lpData);
		}

		~MidiOut()
		{
			Dispose(disposing: false);
		}
	}
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	public struct MidiOutCapabilities
	{
		[Flags]
		private enum MidiOutCapabilityFlags
		{
			Volume = 1,
			LeftRightVolume = 2,
			PatchCaching = 4,
			Stream = 8
		}

		private short manufacturerId;

		private short productId;

		private int driverVersion;

		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
		private string productName;

		private short wTechnology;

		private short wVoices;

		private short wNotes;

		private ushort wChannelMask;

		private MidiOutCapabilityFlags dwSupport;

		private const int MaxProductNameLength = 32;

		public Manufacturers Manufacturer => (Manufacturers)manufacturerId;

		public short ProductId => productId;

		public string ProductName => productName;

		public int Voices => wVoices;

		public int Notes => wNotes;

		public bool SupportsAllChannels => wChannelMask == ushort.MaxValue;

		public bool SupportsPatchCaching => (dwSupport & MidiOutCapabilityFlags.PatchCaching) != 0;

		public bool SupportsSeparateLeftAndRightVolume => (dwSupport & MidiOutCapabilityFlags.LeftRightVolume) != 0;

		public bool SupportsMidiStreamOut => (dwSupport & MidiOutCapabilityFlags.Stream) != 0;

		public bool SupportsVolumeControl => (dwSupport & MidiOutCapabilityFlags.Volume) != 0;

		public MidiOutTechnology Technology => (MidiOutTechnology)wTechnology;

		public bool SupportsChannel(int channel)
		{
			return (wChannelMask & (1 << channel - 1)) > 0;
		}
	}
	public enum MidiOutTechnology
	{
		MidiPort = 1,
		Synth,
		SquareWaveSynth,
		FMSynth,
		MidiMapper,
		WaveTableSynth,
		SoftwareSynth
	}
	public class NoteEvent : MidiEvent
	{
		private int noteNumber;

		private int velocity;

		private static readonly string[] NoteNames = new string[12]
		{
			"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A",
			"A#", "B"
		};

		public virtual int NoteNumber
		{
			get
			{
				return noteNumber;
			}
			set
			{
				if (value < 0 || value > 127)
				{
					throw new ArgumentOutOfRangeException("value", "Note number must be in the range 0-127");
				}
				noteNumber = value;
			}
		}

		public int Velocity
		{
			get
			{
				return velocity;
			}
			set
			{
				if (value < 0 || value > 127)
				{
					throw new ArgumentOutOfRangeException("value", "Velocity must be in the range 0-127");
				}
				velocity = value;
			}
		}

		public string NoteName
		{
			get
			{
				if (Channel == 16 || Channel == 10)
				{
					return noteNumber switch
					{
						35 => "Acoustic Bass Drum", 
						36 => "Bass Drum 1", 
						37 => "Side Stick", 
						38 => "Acoustic Snare", 
						39 => "Hand Clap", 
						40 => "Electric Snare", 
						41 => "Low Floor Tom", 
						42 => "Closed Hi-Hat", 
						43 => "High Floor Tom", 
						44 => "Pedal Hi-Hat", 
						45 => "Low Tom", 
						46 => "Open Hi-Hat", 
						47 => "Low-Mid Tom", 
						48 => "Hi-Mid Tom", 
						49 => "Crash Cymbal 1", 
						50 => "High Tom", 
						51 => "Ride Cymbal 1", 
						52 => "Chinese Cymbal", 
						53 => "Ride Bell", 
						54 => "Tambourine", 
						55 => "Splash Cymbal", 
						56 => "Cowbell", 
						57 => "Crash Cymbal 2", 
						58 => "Vibraslap", 
						59 => "Ride Cymbal 2", 
						60 => "Hi Bongo", 
						61 => "Low Bongo", 
						62 => "Mute Hi Conga", 
						63 => "Open Hi Conga", 
						64 => "Low Conga", 
						65 => "High Timbale", 
						66 => "Low Timbale", 
						67 => "High Agogo", 
						68 => "Low Agogo", 
						69 => "Cabasa", 
						70 => "Maracas", 
						71 => "Short Whistle", 
						72 => "Long Whistle", 
						73 => "Short Guiro", 
						74 => "Long Guiro", 
						75 => "Claves", 
						76 => "Hi Wood Block", 
						77 => "Low Wood Block", 
						78 => "Mute Cuica", 
						79 => "Open Cuica", 
						80 => "Mute Triangle", 
						81 => "Open Triangle", 
						_ => $"Drum {noteNumber}", 
					};
				}
				int num = noteNumber / 12;
				return $"{NoteNames[noteNumber % 12]}{num}";
			}
		}

		public NoteEvent(BinaryReader br)
		{
			NoteNumber = br.ReadByte();
			velocity = br.ReadByte();
			if (velocity > 127)
			{
				velocity = 127;
			}
		}

		public NoteEvent(long absoluteTime, int channel, MidiCommandCode commandCode, int noteNumber, int velocity)
			: base(absoluteTime, channel, commandCode)
		{
			NoteNumber = noteNumber;
			Velocity = velocity;
		}

		public override int GetAsShortMessage()
		{
			return base.GetAsShortMessage() + (noteNumber << 8) + (velocity << 16);
		}

		public override string ToString()
		{
			return $"{base.ToString()} {NoteName} Vel:{Velocity}";
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write((byte)noteNumber);
			writer.Write((byte)velocity);
		}
	}
	public class NoteOnEvent : NoteEvent
	{
		private NoteEvent offEvent;

		public NoteEvent OffEvent
		{
			get
			{
				return offEvent;
			}
			set
			{
				if (!MidiEvent.IsNoteOff(value))
				{
					throw new ArgumentException("OffEvent must be a valid MIDI note off event");
				}
				if (value.NoteNumber != NoteNumber)
				{
					throw new ArgumentException("Note Off Event must be for the same note number");
				}
				if (value.Channel != Channel)
				{
					throw new ArgumentException("Note Off Event must be for the same channel");
				}
				offEvent = value;
			}
		}

		public override int NoteNumber
		{
			get
			{
				return base.NoteNumber;
			}
			set
			{
				base.NoteNumber = value;
				if (OffEvent != null)
				{
					OffEvent.NoteNumber = NoteNumber;
				}
			}
		}

		public override int Channel
		{
			get
			{
				return base.Channel;
			}
			set
			{
				base.Channel = value;
				if (OffEvent != null)
				{
					OffEvent.Channel = Channel;
				}
			}
		}

		public int NoteLength
		{
			get
			{
				return (int)(offEvent.AbsoluteTime - base.AbsoluteTime);
			}
			set
			{
				if (value < 0)
				{
					throw new ArgumentException("NoteLength must be 0 or greater");
				}
				offEvent.AbsoluteTime = base.AbsoluteTime + value;
			}
		}

		public NoteOnEvent(BinaryReader br)
			: base(br)
		{
		}

		public NoteOnEvent(long absoluteTime, int channel, int noteNumber, int velocity, int duration)
			: base(absoluteTime, channel, MidiCommandCode.NoteOn, noteNumber, velocity)
		{
			OffEvent = new NoteEvent(absoluteTime, channel, MidiCommandCode.NoteOff, noteNumber, 0);
			NoteLength = duration;
		}

		public override MidiEvent Clone()
		{
			return new NoteOnEvent(base.AbsoluteTime, Channel, NoteNumber, base.Velocity, NoteLength);
		}

		public override string ToString()
		{
			if (base.Velocity == 0 && OffEvent == null)
			{
				return $"{base.ToString()} (Note Off)";
			}
			return string.Format("{0} Len: {1}", base.ToString(), (OffEvent == null) ? "?" : NoteLength.ToString());
		}
	}
	public class PatchChangeEvent : MidiEvent
	{
		private byte patch;

		private static readonly string[] patchNames = new string[128]
		{
			"Acoustic Grand", "Bright Acoustic", "Electric Grand", "Honky-Tonk", "Electric Piano 1", "Electric Piano 2", "Harpsichord", "Clav", "Celesta", "Glockenspiel",
			"Music Box", "Vibraphone", "Marimba", "Xylophone", "Tubular Bells", "Dulcimer", "Drawbar Organ", "Percussive Organ", "Rock Organ", "Church Organ",
			"Reed Organ", "Accoridan", "Harmonica", "Tango Accordian", "Acoustic Guitar(nylon)", "Acoustic Guitar(steel)", "Electric Guitar(jazz)", "Electric Guitar(clean)", "Electric Guitar(muted)", "Overdriven Guitar",
			"Distortion Guitar", "Guitar Harmonics", "Acoustic Bass", "Electric Bass(finger)", "Electric Bass(pick)", "Fretless Bass", "Slap Bass 1", "Slap Bass 2", "Synth Bass 1", "Synth Bass 2",
			"Violin", "Viola", "Cello", "Contrabass", "Tremolo Strings", "Pizzicato Strings", "Orchestral Strings", "Timpani", "String Ensemble 1", "String Ensemble 2",
			"SynthStrings 1", "SynthStrings 2", "Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit", "Trumpet", "Trombone", "Tuba", "Muted Trumpet",
			"French Horn", "Brass Section", "SynthBrass 1", "SynthBrass 2", "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax", "Oboe", "English Horn",
			"Bassoon", "Clarinet", "Piccolo", "Flute", "Recorder", "Pan Flute", "Blown Bottle", "Skakuhachi", "Whistle", "Ocarina",
			"Lead 1 (square)", "Lead 2 (sawtooth)", "Lead 3 (calliope)", "Lead 4 (chiff)", "Lead 5 (charang)", "Lead 6 (voice)", "Lead 7 (fifths)", "Lead 8 (bass+lead)", "Pad 1 (new age)", "Pad 2 (warm)",
			"Pad 3 (polysynth)", "Pad 4 (choir)", "Pad 5 (bowed)", "Pad 6 (metallic)", "Pad 7 (halo)", "Pad 8 (sweep)", "FX 1 (rain)", "FX 2 (soundtrack)", "FX 3 (crystal)", "FX 4 (atmosphere)",
			"FX 5 (brightness)", "FX 6 (goblins)", "FX 7 (echoes)", "FX 8 (sci-fi)", "Sitar", "Banjo", "Shamisen", "Koto", "Kalimba", "Bagpipe",
			"Fiddle", "Shanai", "Tinkle Bell", "Agogo", "Steel Drums", "Woodblock", "Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse Cymbal",
			"Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet", "Telephone Ring", "Helicopter", "Applause", "Gunshot"
		};

		public int Patch
		{
			get
			{
				return patch;
			}
			set
			{
				if (value < 0 || value > 127)
				{
					throw new ArgumentOutOfRangeException("value", "Patch number must be in the range 0-127");
				}
				patch = (byte)value;
			}
		}

		public static string GetPatchName(int patchNumber)
		{
			return patchNames[patchNumber];
		}

		public PatchChangeEvent(BinaryReader br)
		{
			patch = br.ReadByte();
			if ((patch & 0x80u) != 0)
			{
				throw new FormatException("Invalid patch");
			}
		}

		public PatchChangeEvent(long absoluteTime, int channel, int patchNumber)
			: base(absoluteTime, channel, MidiCommandCode.PatchChange)
		{
			Patch = patchNumber;
		}

		public override string ToString()
		{
			return $"{base.ToString()} {GetPatchName(patch)}";
		}

		public override int GetAsShortMessage()
		{
			return base.GetAsShortMessage() + (patch << 8);
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write(patch);
		}
	}
	public class PitchWheelChangeEvent : MidiEvent
	{
		private int pitch;

		public int Pitch
		{
			get
			{
				return pitch;
			}
			set
			{
				if (value < 0 || value >= 16384)
				{
					throw new ArgumentOutOfRangeException("value", "Pitch value must be in the range 0 - 0x3FFF");
				}
				pitch = value;
			}
		}

		public PitchWheelChangeEvent(BinaryReader br)
		{
			byte b = br.ReadByte();
			byte b2 = br.ReadByte();
			if ((b & 0x80u) != 0)
			{
				throw new FormatException("Invalid pitchwheelchange byte 1");
			}
			if ((b2 & 0x80u) != 0)
			{
				throw new FormatException("Invalid pitchwheelchange byte 2");
			}
			pitch = b + (b2 << 7);
		}

		public PitchWheelChangeEvent(long absoluteTime, int channel, int pitchWheel)
			: base(absoluteTime, channel, MidiCommandCode.PitchWheelChange)
		{
			Pitch = pitchWheel;
		}

		public override string ToString()
		{
			return $"{base.ToString()} Pitch {pitch} ({pitch - 8192})";
		}

		public override int GetAsShortMessage()
		{
			return base.GetAsShortMessage() + ((pitch & 0x7F) << 8) + (((pitch >> 7) & 0x7F) << 16);
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write((byte)((uint)pitch & 0x7Fu));
			writer.Write((byte)((uint)(pitch >> 7) & 0x7Fu));
		}
	}
	public class RawMetaEvent : MetaEvent
	{
		public byte[] Data { get; set; }

		public RawMetaEvent(MetaEventType metaEventType, long absoluteTime, byte[] data)
			: base(metaEventType, (data != null) ? data.Length : 0, absoluteTime)
		{
			Data = data;
		}

		public override MidiEvent Clone()
		{
			return new RawMetaEvent(base.MetaEventType, base.AbsoluteTime, (byte[])Data?.Clone());
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder().Append(base.ToString());
			byte[] data = Data;
			foreach (byte b in data)
			{
				stringBuilder.AppendFormat(" {0:X2}", b);
			}
			return stringBuilder.ToString();
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			if (Data != null)
			{
				writer.Write(Data, 0, Data.Length);
			}
		}
	}
	public class SequencerSpecificEvent : MetaEvent
	{
		private byte[] data;

		public byte[] Data
		{
			get
			{
				return data;
			}
			set
			{
				data = value;
				metaDataLength = data.Length;
			}
		}

		public SequencerSpecificEvent(BinaryReader br, int length)
		{
			data = br.ReadBytes(length);
		}

		public SequencerSpecificEvent(byte[] data, long absoluteTime)
			: base(MetaEventType.SequencerSpecific, data.Length, absoluteTime)
		{
			this.data = data;
		}

		public override MidiEvent Clone()
		{
			return new SequencerSpecificEvent((byte[])data.Clone(), base.AbsoluteTime);
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(base.ToString());
			stringBuilder.Append(" ");
			byte[] array = data;
			foreach (byte b in array)
			{
				stringBuilder.AppendFormat("{0:X2} ", b);
			}
			stringBuilder.Length--;
			return stringBuilder.ToString();
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write(data);
		}
	}
	public class SmpteOffsetEvent : MetaEvent
	{
		private readonly byte hours;

		private readonly byte minutes;

		private readonly byte seconds;

		private readonly byte frames;

		private readonly byte subFrames;

		public int Hours => hours;

		public int Minutes => minutes;

		public int Seconds => seconds;

		public int Frames => frames;

		public int SubFrames => subFrames;

		public SmpteOffsetEvent(byte hours, byte minutes, byte seconds, byte frames, byte subFrames)
		{
			this.hours = hours;
			this.minutes = minutes;
			this.seconds = seconds;
			this.frames = frames;
			this.subFrames = subFrames;
		}

		public SmpteOffsetEvent(BinaryReader br, int length)
		{
			if (length != 5)
			{
				throw new FormatException($"Invalid SMPTE Offset length: Got {length}, expected 5");
			}
			hours = br.ReadByte();
			minutes = br.ReadByte();
			seconds = br.ReadByte();
			frames = br.ReadByte();
			subFrames = br.ReadByte();
		}

		public override MidiEvent Clone()
		{
			return (SmpteOffsetEvent)MemberwiseClone();
		}

		public override string ToString()
		{
			return $"{base.ToString()} {hours}:{minutes}:{seconds}:{frames}:{subFrames}";
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write(hours);
			writer.Write(minutes);
			writer.Write(seconds);
			writer.Write(frames);
			writer.Write(subFrames);
		}
	}
	public class SysexEvent : MidiEvent
	{
		private byte[] data;

		public static SysexEvent ReadSysexEvent(BinaryReader br)
		{
			SysexEvent sysexEvent = new SysexEvent();
			List<byte> list = new List<byte>();
			bool flag = true;
			while (flag)
			{
				byte b = br.ReadByte();
				if (b == 247)
				{
					flag = false;
				}
				else
				{
					list.Add(b);
				}
			}
			sysexEvent.data = list.ToArray();
			return sysexEvent;
		}

		public override MidiEvent Clone()
		{
			return new SysexEvent
			{
				data = (byte[])data?.Clone()
			};
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			byte[] array = data;
			foreach (byte b in array)
			{
				stringBuilder.AppendFormat("{0:X2} ", b);
			}
			return $"{base.AbsoluteTime} Sysex: {data.Length} bytes\r\n{stringBuilder.ToString()}";
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write(data, 0, data.Length);
			writer.Write((byte)247);
		}
	}
	public class TempoEvent : MetaEvent
	{
		private int microsecondsPerQuarterNote;

		public int MicrosecondsPerQuarterNote
		{
			get
			{
				return microsecondsPerQuarterNote;
			}
			set
			{
				microsecondsPerQuarterNote = value;
			}
		}

		public double Tempo
		{
			get
			{
				return 60000000.0 / (double)microsecondsPerQuarterNote;
			}
			set
			{
				microsecondsPerQuarterNote = (int)(60000000.0 / value);
			}
		}

		public TempoEvent(BinaryReader br, int length)
		{
			if (length != 3)
			{
				throw new FormatException("Invalid tempo length");
			}
			microsecondsPerQuarterNote = (br.ReadByte() << 16) + (br.ReadByte() << 8) + br.ReadByte();
		}

		public TempoEvent(int microsecondsPerQuarterNote, long absoluteTime)
			: base(MetaEventType.SetTempo, 3, absoluteTime)
		{
			this.microsecondsPerQuarterNote = microsecondsPerQuarterNote;
		}

		public override MidiEvent Clone()
		{
			return (TempoEvent)MemberwiseClone();
		}

		public override string ToString()
		{
			return string.Format("{0} {2}bpm ({1})", base.ToString(), microsecondsPerQuarterNote, 60000000 / microsecondsPerQuarterNote);
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write((byte)((uint)(microsecondsPerQuarterNote >> 16) & 0xFFu));
			writer.Write((byte)((uint)(microsecondsPerQuarterNote >> 8) & 0xFFu));
			writer.Write((byte)((uint)microsecondsPerQuarterNote & 0xFFu));
		}
	}
	public class TextEvent : MetaEvent
	{
		private byte[] data;

		public string Text
		{
			get
			{
				return ((Encoding)(object)ByteEncoding.Instance).GetString(data);
			}
			set
			{
				Encoding instance = (Encoding)(object)ByteEncoding.Instance;
				data = instance.GetBytes(value);
				metaDataLength = data.Length;
			}
		}

		public byte[] Data
		{
			get
			{
				return data;
			}
			set
			{
				data = value;
				metaDataLength = data.Length;
			}
		}

		public TextEvent(BinaryReader br, int length)
		{
			data = br.ReadBytes(length);
		}

		public TextEvent(string text, MetaEventType metaEventType, long absoluteTime)
			: base(metaEventType, text.Length, absoluteTime)
		{
			Text = text;
		}

		public override MidiEvent Clone()
		{
			return (TextEvent)MemberwiseClone();
		}

		public override string ToString()
		{
			return $"{base.ToString()} {Text}";
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write(data);
		}
	}
	public class TimeSignatureEvent : MetaEvent
	{
		private byte numerator;

		private byte denominator;

		private byte ticksInMetronomeClick;

		private byte no32ndNotesInQuarterNote;

		public int Numerator => numerator;

		public int Denominator => denominator;

		public int TicksInMetronomeClick => ticksInMetronomeClick;

		public int No32ndNotesInQuarterNote => no32ndNotesInQuarterNote;

		public string TimeSignature
		{
			get
			{
				string arg = $"Unknown ({denominator})";
				switch (denominator)
				{
				case 1:
					arg = "2";
					break;
				case 2:
					arg = "4";
					break;
				case 3:
					arg = "8";
					break;
				case 4:
					arg = "16";
					break;
				case 5:
					arg = "32";
					break;
				}
				return $"{numerator}/{arg}";
			}
		}

		public TimeSignatureEvent(BinaryReader br, int length)
		{
			if (length != 4)
			{
				throw new FormatException($"Invalid time signature length: Got {length}, expected 4");
			}
			numerator = br.ReadByte();
			denominator = br.ReadByte();
			ticksInMetronomeClick = br.ReadByte();
			no32ndNotesInQuarterNote = br.ReadByte();
		}

		public TimeSignatureEvent(long absoluteTime, int numerator, int denominator, int ticksInMetronomeClick, int no32ndNotesInQuarterNote)
			: base(MetaEventType.TimeSignature, 4, absoluteTime)
		{
			this.numerator = (byte)numerator;
			this.denominator = (byte)denominator;
			this.ticksInMetronomeClick = (byte)ticksInMetronomeClick;
			this.no32ndNotesInQuarterNote = (byte)no32ndNotesInQuarterNote;
		}

		public override MidiEvent Clone()
		{
			return (TimeSignatureEvent)MemberwiseClone();
		}

		public override string ToString()
		{
			return $"{base.ToString()} {TimeSignature} TicksInClick:{ticksInMetronomeClick} 32ndsInQuarterNote:{no32ndNotesInQuarterNote}";
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write(numerator);
			writer.Write(denominator);
			writer.Write(ticksInMetronomeClick);
			writer.Write(no32ndNotesInQuarterNote);
		}
	}
	public class TrackSequenceNumberEvent : MetaEvent
	{
		private ushort sequenceNumber;

		public TrackSequenceNumberEvent(ushort sequenceNumber)
		{
			this.sequenceNumber = sequenceNumber;
		}

		public TrackSequenceNumberEvent(BinaryReader br, int length)
		{
			if (length != 2)
			{
				throw new FormatException("Invalid sequence number length");
			}
			sequenceNumber = (ushort)((br.ReadByte() << 8) + br.ReadByte());
		}

		public override MidiEvent Clone()
		{
			return (TrackSequenceNumberEvent)MemberwiseClone();
		}

		public override string ToString()
		{
			return $"{base.ToString()} {sequenceNumber}";
		}

		public override void Export(ref long absoluteTime, BinaryWriter writer)
		{
			base.Export(ref absoluteTime, writer);
			writer.Write((byte)((uint)(sequenceNumber >> 8) & 0xFFu));
			writer.Write((byte)(sequenceNumber & 0xFFu));
		}
	}
}
namespace NAudio.Utils
{
	internal class MergeSort
	{
		private static void Sort<T>(IList<T> list, int lowIndex, int highIndex, IComparer<T> comparer)
		{
			if (lowIndex >= highIndex)
			{
				return;
			}
			int num = (lowIndex + highIndex) / 2;
			Sort(list, lowIndex, num, comparer);
			Sort(list, num + 1, highIndex, comparer);
			int num2 = num;
			int num3 = num + 1;
			while (lowIndex <= num2 && num3 <= highIndex)
			{
				if (comparer.Compare(list[lowIndex], list[num3]) <= 0)
				{
					lowIndex++;
					continue;
				}
				T value = list[num3];
				for (int num4 = num3 - 1; num4 >= lowIndex; num4--)
				{
					list[num4 + 1] = list[num4];
				}
				list[lowIndex] = value;
				lowIndex++;
				num2++;
				num3++;
			}
		}

		public static void Sort<T>(IList<T> list) where T : IComparable<T>
		{
			Sort(list, 0, list.Count - 1, Comparer<T>.Default);
		}

		public static void Sort<T>(IList<T> list, IComparer<T> comparer)
		{
			Sort(list, 0, list.Count - 1, comparer);
		}
	}
}

BugleHero.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BugleHero;
using BugleHero.Patches;
using HarmonyLib;
using NAudio.Midi;
using Photon.Pun;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("BugleHero")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BugleHero")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("5cdd586e-a0b6-485a-9f93-4b072f545200")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
public class MidiInputHandler
{
	private MidiIn midiIn;

	private ConfigEntry<string> midiDeviceName;

	private readonly ConcurrentQueue<Action> mainThreadQueue = new ConcurrentQueue<Action>();

	private readonly HashSet<int> expectedActiveNotes = new HashSet<int>();

	private float lastMidiActivity = 0f;

	private void EnqueueOnMainThread(Action a)
	{
		if (a != null)
		{
			mainThreadQueue.Enqueue(a);
		}
	}

	public void ProcessMainThreadQueue()
	{
		Action result;
		while (mainThreadQueue.TryDequeue(out result))
		{
			try
			{
				result();
			}
			catch (Exception ex)
			{
				Plugin.Instance.mls.LogWarning((object)("Exception processing MIDI action: " + ex));
			}
		}
		CheckForStuckNotes();
	}

	private void CheckForStuckNotes()
	{
		if (expectedActiveNotes.Count > 0 && Time.time - lastMidiActivity > 10f)
		{
			Plugin.Instance.mls.LogWarning((object)$"No MIDI activity for 10 seconds but {expectedActiveNotes.Count} notes expected active. Clearing expected notes.");
			expectedActiveNotes.Clear();
			BugleMIDIPatch.EmergencyStopAll();
		}
	}

	public void Initialize(ConfigFile config)
	{
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Expected O, but got Unknown
		List<string> list = Enumerable.Range(0, MidiIn.NumberOfDevices).Select(delegate(int i)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			MidiInCapabilities val = MidiIn.DeviceInfo(i);
			return ((MidiInCapabilities)(ref val)).ProductName;
		}).ToList();
		if (list.Count == 0)
		{
			Plugin.Instance.mls.LogInfo((object)"No MIDI devices detected.");
			return;
		}
		midiDeviceName = config.Bind<string>("MIDI", "DeviceName", list.First(), new ConfigDescription("Select MIDI input device", (AcceptableValueBase)null, new object[1]
		{
			new AcceptableValueList<string>(list.ToArray())
		}));
		midiDeviceName.SettingChanged += delegate
		{
			OpenMidiDeviceByName(midiDeviceName.Value);
		};
		OpenMidiDeviceByName(midiDeviceName.Value);
	}

	public void OpenMidiDeviceByName(string deviceName)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Expected O, but got Unknown
		int num = -1;
		for (int i = 0; i < MidiIn.NumberOfDevices; i++)
		{
			MidiInCapabilities val = MidiIn.DeviceInfo(i);
			if (((MidiInCapabilities)(ref val)).ProductName == deviceName)
			{
				num = i;
				break;
			}
		}
		if (num < 0)
		{
			Plugin.Instance.mls.LogWarning((object)("MIDI device '" + deviceName + "' not found."));
			return;
		}
		StopListening();
		midiIn = new MidiIn(num);
		midiIn.MessageReceived += MidiIn_MessageReceived;
		midiIn.ErrorReceived += MidiIn_ErrorReceived;
		midiIn.Start();
		Plugin.Instance.mls.LogInfo((object)$"Started listening to MIDI device #{num}: {deviceName}");
	}

	private void MidiIn_MessageReceived(object sender, MidiInMessageEventArgs e)
	{
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Invalid comparison between Unknown and I4
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Invalid comparison between Unknown and I4
		//IL_0144: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Invalid comparison between Unknown and I4
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Invalid comparison between Unknown and I4
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Expected I4, but got Unknown
		try
		{
			lastMidiActivity = Time.time;
			MidiEvent midiEvent = e.MidiEvent;
			NoteOnEvent val = (NoteOnEvent)(object)((midiEvent is NoteOnEvent) ? midiEvent : null);
			if (val != null)
			{
				int midiNote = ((NoteEvent)val).NoteNumber;
				if (((NoteEvent)val).Velocity > 0)
				{
					expectedActiveNotes.Add(midiNote);
					EnqueueOnMainThread(delegate
					{
						BugleSFX val5 = FindLocalBugleSFX();
						if ((Object)(object)val5 != (Object)null)
						{
							BugleMIDIPatch.OnMidiNoteOn(midiNote, val5);
						}
					});
					return;
				}
				expectedActiveNotes.Remove(midiNote);
				EnqueueOnMainThread(delegate
				{
					BugleSFX val4 = FindLocalBugleSFX();
					if ((Object)(object)val4 != (Object)null)
					{
						BugleMIDIPatch.OnMidiNoteOff(midiNote, val4);
					}
				});
				return;
			}
			MidiEvent midiEvent2 = e.MidiEvent;
			NoteEvent noteEvent = (NoteEvent)(object)((midiEvent2 is NoteEvent) ? midiEvent2 : null);
			if (noteEvent != null && (int)((MidiEvent)noteEvent).CommandCode == 128)
			{
				expectedActiveNotes.Remove(noteEvent.NoteNumber);
				EnqueueOnMainThread(delegate
				{
					BugleSFX val3 = FindLocalBugleSFX();
					if ((Object)(object)val3 != (Object)null)
					{
						BugleMIDIPatch.OnMidiNoteOff(noteEvent.NoteNumber, val3);
					}
				});
				return;
			}
			MidiEvent midiEvent3 = e.MidiEvent;
			ControlChangeEvent val2 = (ControlChangeEvent)(object)((midiEvent3 is ControlChangeEvent) ? midiEvent3 : null);
			if (val2 == null)
			{
				return;
			}
			if ((int)val2.Controller == 120 || (int)val2.Controller == 123)
			{
				Plugin.Instance.mls.LogInfo((object)$"Received All Notes/Sound Off MIDI message (CC {(int)val2.Controller})");
				expectedActiveNotes.Clear();
				EnqueueOnMainThread(delegate
				{
					BugleMIDIPatch.EmergencyStopAll();
				});
			}
			else if ((int)val2.Controller == 64)
			{
				Plugin.Instance.mls.LogInfo((object)$"Sustain pedal: {val2.ControllerValue}");
			}
		}
		catch (Exception ex)
		{
			Plugin.Instance.mls.LogWarning((object)("Exception in MIDI handler: " + ex));
		}
	}

	private void MidiIn_ErrorReceived(object sender, MidiInMessageEventArgs e)
	{
		Plugin.Instance.mls.LogWarning((object)("MIDI error: " + e.RawMessage));
		expectedActiveNotes.Clear();
	}

	public void StopListening()
	{
		expectedActiveNotes.Clear();
		BugleMIDIPatch.EmergencyStopAll();
		if (midiIn != null)
		{
			midiIn.Stop();
			midiIn.Dispose();
			midiIn = null;
		}
	}

	private BugleSFX FindLocalBugleSFX()
	{
		return ((IEnumerable<BugleSFX>)Object.FindObjectsOfType<BugleSFX>()).FirstOrDefault((Func<BugleSFX, bool>)((BugleSFX b) => ((MonoBehaviourPun)b).photonView.IsMine));
	}

	public void EmergencyStopAllNotes()
	{
		Plugin.Instance.mls.LogInfo((object)"Manual emergency stop triggered");
		expectedActiveNotes.Clear();
		BugleMIDIPatch.EmergencyStopAll();
	}
}
namespace BugleHero
{
	[BepInPlugin("Grin.BugleHero", "Bugle Hero", "0.0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string modGUID = "Grin.BugleHero";

		public const string modName = "Bugle Hero";

		public const string modVersion = "0.0.1.0";

		private readonly Harmony harmony = new Harmony("Grin.BugleHero");

		internal static Plugin Instance;

		internal ManualLogSource mls;

		private MidiInputHandler midiHandler;

		public ConfigEntry<string> MidiDeviceName { get; private set; }

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			mls = ((BaseUnityPlugin)this).Logger;
			mls.LogInfo((object)"Warming up the brass...");
			mls.LogInfo((object)"Toot toot! Ready for duty.");
			mls.LogInfo((object)"Calibrating toot pressure...");
			mls.LogInfo((object)"Now 400% more toot.");
			mls.LogInfo((object)"Tootware version 0.0.1.0 initialized.");
			mls.LogInfo((object)"Ready to bugle at a moment’s tootice.");
			mls.LogInfo((object)"Practice safe tooting.");
			InitConfig();
			InitMidi();
			harmony.PatchAll();
		}

		private void Update()
		{
			midiHandler?.ProcessMainThreadQueue();
		}

		private void InitConfig()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			List<string> list = new List<string>();
			for (int i = 0; i < MidiIn.NumberOfDevices; i++)
			{
				MidiInCapabilities val = MidiIn.DeviceInfo(i);
				list.Add(((MidiInCapabilities)(ref val)).ProductName);
			}
			if (list.Count == 0)
			{
				mls.LogWarning((object)"No MIDI devices found for config.");
				list.Add("No MIDI devices detected");
			}
			string[] array = list.ToArray();
			MidiDeviceName = ((BaseUnityPlugin)this).Config.Bind<string>("MIDI", "DeviceName", array[0], new ConfigDescription("Select MIDI input device", (AcceptableValueBase)null, new object[1]
			{
				new AcceptableValueList<string>(array)
			}));
		}

		private void InitMidi()
		{
			midiHandler = new MidiInputHandler();
			MidiDeviceName.SettingChanged += delegate
			{
				midiHandler.OpenMidiDeviceByName(MidiDeviceName.Value);
			};
			midiHandler.OpenMidiDeviceByName(MidiDeviceName.Value);
		}

		public void DisposeMidi()
		{
			midiHandler?.StopListening();
		}

		private void OnDestroy()
		{
			try
			{
				DisposeMidi();
			}
			catch
			{
			}
			try
			{
				harmony.UnpatchSelf();
			}
			catch
			{
			}
		}
	}
}
namespace BugleHero.Patches
{
	[HarmonyPatch(typeof(BugleSFX))]
	internal class BugleMIDIPatch
	{
		[CompilerGenerated]
		private sealed class <RemoteStartAfterDelay>d__27 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public BugleSFX instance;

			public float delay;

			public int clip;

			public float pitch;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RemoteStartAfterDelay>d__27(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(delay);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					((MonoBehaviourPun)instance).photonView.RPC("RPC_StartToot", (RpcTarget)1, new object[2] { clip, pitch });
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <RestartAfterDelay>d__26 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public BugleSFX instance;

			public float delay;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RestartAfterDelay>d__26(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(delay);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if (forceHold && currentPlayingNote.HasValue)
					{
						((MonoBehaviourPun)instance).photonView.RPC("RPC_StartToot", (RpcTarget)1, new object[2] { forcedClip, forcedPitch });
						PlayToot(instance, forcedClip, forcedPitch);
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static HashSet<int> activeNotes = new HashSet<int>();

		private static int? currentPlayingNote = null;

		private static int forcedClip = 0;

		private static float forcedPitch = 0f;

		private static bool forceHold = false;

		private static float loopStartTime = 0f;

		private static float loopClipLength = 0f;

		private static float lastActivityTime = 0f;

		private static readonly float inactivityTimeout = 5f;

		private const float loopRestartDelay = 0.05f;

		private const float clip0BaseFreqLow = 255f;

		private const float clip0BaseFreqHigh = 1025f;

		private static FieldInfo currentClipField = typeof(BugleSFX).GetField("currentClip", BindingFlags.Instance | BindingFlags.NonPublic);

		private static FieldInfo tField = typeof(BugleSFX).GetField("t", BindingFlags.Instance | BindingFlags.NonPublic);

		private static FieldInfo currentPitchField = typeof(BugleSFX).GetField("currentPitch", BindingFlags.Instance | BindingFlags.NonPublic);

		private static float MidiNoteToFreq(int midiNote)
		{
			return 440f * Mathf.Pow(2f, (float)(midiNote - 69) / 12f);
		}

		private static int MidiNoteToClip(int midiNote)
		{
			float num = MidiNoteToFreq(midiNote);
			if (num < 400f)
			{
				return 0;
			}
			if (num < 700f)
			{
				return 1;
			}
			if (num < 900f)
			{
				return 2;
			}
			return 3;
		}

		private static float MidiNoteToPitch(int midiNote)
		{
			float num;
			for (num = MidiNoteToFreq(midiNote); num < 255f; num *= 2f)
			{
			}
			while (num > 1025f)
			{
				num /= 2f;
			}
			return (num - 255f) / 770f;
		}

		private static float AdjustPitchForClip(float basePitch, int clipIndex)
		{
			float num = Mathf.Lerp(255f, 1025f, basePitch);
			float num2 = 1f;
			if (clipIndex == 1 || clipIndex == 2)
			{
				num2 = 1.0156f;
			}
			else if (clipIndex == 3)
			{
				num2 = 1.039f;
			}
			float num3;
			for (num3 = num * num2; num3 > 1025f; num3 /= 2f)
			{
			}
			while (num3 < 255f)
			{
				num3 *= 2f;
			}
			return (num3 - 255f) / 770f;
		}

		public static void OnMidiNoteOn(int midiNote, BugleSFX instance)
		{
			if (!((Object)(object)instance == (Object)null))
			{
				lastActivityTime = Time.time;
				activeNotes.Add(midiNote);
				if (currentPlayingNote.HasValue)
				{
					ForceStopCurrentNote(instance);
				}
				currentPlayingNote = midiNote;
				int clipIndex = MidiNoteToClip(midiNote);
				float basePitch = MidiNoteToPitch(midiNote);
				float pitch = AdjustPitchForClip(basePitch, clipIndex);
				PlayToot(instance, clipIndex, pitch);
			}
		}

		public static void OnMidiNoteOff(int midiNote, BugleSFX instance)
		{
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			lastActivityTime = Time.time;
			activeNotes.Remove(midiNote);
			if (currentPlayingNote == midiNote)
			{
				StopToot(instance);
				currentPlayingNote = null;
				if (activeNotes.Count > 0)
				{
					int midiNote2 = activeNotes.Last();
					OnMidiNoteOn(midiNote2, instance);
				}
			}
		}

		public static void ForceStopAllNotes(BugleSFX instance)
		{
			if (!((Object)(object)instance == (Object)null))
			{
				Plugin.Instance.mls.LogInfo((object)"Force stopping all stuck notes");
				activeNotes.Clear();
				currentPlayingNote = null;
				forceHold = false;
				instance.hold = false;
				tField?.SetValue(instance, false);
				((MonoBehaviourPun)instance).photonView.RPC("RPC_EndToot", (RpcTarget)0, Array.Empty<object>());
				if (instance.buglePlayer.isPlaying)
				{
					instance.buglePlayer.Stop();
				}
				if (Object.op_Implicit((Object)(object)instance.particle1) && instance.particle1.isPlaying)
				{
					instance.particle1.Stop();
				}
				if (Object.op_Implicit((Object)(object)instance.particle2) && instance.particle2.isPlaying)
				{
					instance.particle2.Stop();
				}
			}
		}

		private static void ForceStopCurrentNote(BugleSFX instance)
		{
			if (currentPlayingNote.HasValue)
			{
				forceHold = false;
				instance.hold = false;
				tField?.SetValue(instance, false);
				((MonoBehaviourPun)instance).photonView.RPC("RPC_EndToot", (RpcTarget)0, Array.Empty<object>());
				if (instance.buglePlayer.isPlaying)
				{
					instance.buglePlayer.Stop();
				}
			}
		}

		private static void PlayToot(BugleSFX instance, int clipIndex, float pitch)
		{
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			((MonoBehaviourPun)instance).photonView.RPC("RPC_EndToot", (RpcTarget)0, Array.Empty<object>());
			forcedClip = clipIndex;
			forcedPitch = pitch;
			forceHold = true;
			currentClipField?.SetValue(instance, clipIndex);
			currentPitchField?.SetValue(instance, pitch);
			tField?.SetValue(instance, true);
			instance.hold = true;
			instance.buglePlayer.clip = instance.bugle[clipIndex];
			instance.buglePlayer.pitch = Mathf.Lerp(instance.pitchMin, instance.pitchMax, pitch);
			instance.buglePlayer.volume = 0f;
			instance.buglePlayer.Play();
			loopClipLength = instance.bugle[clipIndex].length;
			loopStartTime = Time.time;
			if (Object.op_Implicit((Object)(object)instance.particle1) && Object.op_Implicit((Object)(object)instance.particle2))
			{
				if (!instance.particle1.isPlaying)
				{
					instance.particle1.Play();
				}
				if (!instance.particle2.isPlaying)
				{
					instance.particle2.Play();
				}
				EmissionModule emission = instance.particle1.emission;
				((EmissionModule)(ref emission)).enabled = true;
				EmissionModule emission2 = instance.particle2.emission;
				((EmissionModule)(ref emission2)).enabled = true;
			}
			((MonoBehaviour)instance).StartCoroutine(RemoteStartAfterDelay(instance, 0.05f, clipIndex, pitch));
		}

		public static void StopToot(BugleSFX instance)
		{
			forceHold = false;
			instance.hold = false;
			tField?.SetValue(instance, false);
			((MonoBehaviourPun)instance).photonView.RPC("RPC_EndToot", (RpcTarget)0, Array.Empty<object>());
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(BugleSFX), "UpdateTooting")]
		private static bool Prefix_UpdateTooting(BugleSFX __instance)
		{
			if (!((MonoBehaviourPun)__instance).photonView.IsMine)
			{
				return true;
			}
			if (forceHold && Time.time - lastActivityTime > inactivityTimeout)
			{
				Plugin.Instance.mls.LogWarning((object)"Detected potentially stuck note due to inactivity, forcing stop");
				ForceStopAllNotes(__instance);
				return false;
			}
			if (forceHold && !__instance.buglePlayer.isPlaying && Time.time - loopStartTime > loopClipLength + 1f)
			{
				Plugin.Instance.mls.LogWarning((object)"Detected stuck note (player not playing), forcing stop");
				ForceStopAllNotes(__instance);
				return false;
			}
			if (forceHold)
			{
				if (Time.time - loopStartTime >= loopClipLength)
				{
					((MonoBehaviourPun)__instance).photonView.RPC("RPC_EndToot", (RpcTarget)0, Array.Empty<object>());
					__instance.buglePlayer.Stop();
					((MonoBehaviour)__instance).StartCoroutine(RestartAfterDelay(__instance, 0.05f));
					loopStartTime = Time.time + 0.05f;
				}
				return false;
			}
			return true;
		}

		[IteratorStateMachine(typeof(<RestartAfterDelay>d__26))]
		private static IEnumerator RestartAfterDelay(BugleSFX instance, float delay)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RestartAfterDelay>d__26(0)
			{
				instance = instance,
				delay = delay
			};
		}

		[IteratorStateMachine(typeof(<RemoteStartAfterDelay>d__27))]
		private static IEnumerator RemoteStartAfterDelay(BugleSFX instance, float delay, int clip, float pitch)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RemoteStartAfterDelay>d__27(0)
			{
				instance = instance,
				delay = delay,
				clip = clip,
				pitch = pitch
			};
		}

		public static void EmergencyStopAll()
		{
			BugleSFX val = ((IEnumerable<BugleSFX>)Object.FindObjectsOfType<BugleSFX>()).FirstOrDefault((Func<BugleSFX, bool>)((BugleSFX b) => ((MonoBehaviourPun)b).photonView.IsMine));
			if ((Object)(object)val != (Object)null)
			{
				ForceStopAllNotes(val);
			}
		}
	}
}