Decompiled source of MoreOSTsModPlus v1.4.0

NAudio.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.Win32;
using NAudio.CoreAudioApi;
using NAudio.CoreAudioApi.Interfaces;
using NAudio.Dmo;
using NAudio.Dmo.Effect;
using NAudio.Dsp;
using NAudio.FileFormats.Wav;
using NAudio.MediaFoundation;
using NAudio.Mixer;
using NAudio.Utils;
using NAudio.Wave;
using NAudio.Wave.Asio;
using NAudio.Wave.Compression;
using NAudio.Wave.SampleProviders;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("NAudioTests")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Mark Heath & Contributors")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("© Mark Heath 2020")]
[assembly: AssemblyDescription("NAudio, an audio library for .NET")]
[assembly: AssemblyFileVersion("1.10.0.0")]
[assembly: AssemblyInformationalVersion("1.10.0")]
[assembly: AssemblyProduct("NAudio")]
[assembly: AssemblyTitle("NAudio")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.10.0.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
	{
		private MmResult result;

		private string function;

		public MmResult Result => result;

		public MmException(MmResult result, string function)
			: base(ErrorMessage(result, function))
		{
			this.result = result;
			this.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.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 MarshalHelpers
	{
		public static int SizeOf<T>()
		{
			return Marshal.SizeOf<T>();
		}

		public static IntPtr OffsetOf<T>(string fieldName)
		{
			return Marshal.OffsetOf<T>(fieldName);
		}

		public static T PtrToStructure<T>(IntPtr pointer)
		{
			return Marshal.PtrToStructure<T>(pointer);
		}
	}
	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);
		}
	}
	internal 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.Mixer
{
	public class BooleanMixerControl : MixerControl
	{
		private MixerInterop.MIXERCONTROLDETAILS_BOOLEAN boolDetails;

		public bool Value
		{
			get
			{
				GetControlDetails();
				return boolDetails.fValue == 1;
			}
			set
			{
				boolDetails.fValue = (value ? 1 : 0);
				mixerControlDetails.paDetails = Marshal.AllocHGlobal(Marshal.SizeOf(boolDetails));
				Marshal.StructureToPtr(boolDetails, mixerControlDetails.paDetails, fDeleteOld: false);
				MmException.Try(MixerInterop.mixerSetControlDetails(mixerHandle, ref mixerControlDetails, MixerFlags.Mixer | mixerHandleType), "mixerSetControlDetails");
				Marshal.FreeHGlobal(mixerControlDetails.paDetails);
			}
		}

		internal BooleanMixerControl(MixerInterop.MIXERCONTROL mixerControl, IntPtr mixerHandle, MixerFlags mixerHandleType, int nChannels)
		{
			base.mixerControl = mixerControl;
			base.mixerHandle = mixerHandle;
			base.mixerHandleType = mixerHandleType;
			base.nChannels = nChannels;
			mixerControlDetails = default(MixerInterop.MIXERCONTROLDETAILS);
			GetControlDetails();
		}

		protected override void GetDetails(IntPtr pDetails)
		{
			boolDetails = MarshalHelpers.PtrToStructure<MixerInterop.MIXERCONTROLDETAILS_BOOLEAN>(pDetails);
		}
	}
	public class CustomMixerControl : MixerControl
	{
		internal CustomMixerControl(MixerInterop.MIXERCONTROL mixerControl, IntPtr mixerHandle, MixerFlags mixerHandleType, int nChannels)
		{
			base.mixerControl = mixerControl;
			base.mixerHandle = mixerHandle;
			base.mixerHandleType = mixerHandleType;
			base.nChannels = nChannels;
			mixerControlDetails = default(MixerInterop.MIXERCONTROLDETAILS);
			GetControlDetails();
		}

		protected override void GetDetails(IntPtr pDetails)
		{
		}
	}
	public class ListTextMixerControl : MixerControl
	{
		internal ListTextMixerControl(MixerInterop.MIXERCONTROL mixerControl, IntPtr mixerHandle, MixerFlags mixerHandleType, int nChannels)
		{
			base.mixerControl = mixerControl;
			base.mixerHandle = mixerHandle;
			base.mixerHandleType = mixerHandleType;
			base.nChannels = nChannels;
			mixerControlDetails = default(MixerInterop.MIXERCONTROLDETAILS);
			GetControlDetails();
		}

		protected override void GetDetails(IntPtr pDetails)
		{
		}
	}
	public class Mixer
	{
		private MixerInterop.MIXERCAPS caps;

		private IntPtr mixerHandle;

		private MixerFlags mixerHandleType;

		public static int NumberOfDevices => MixerInterop.mixerGetNumDevs();

		public int DestinationCount => (int)caps.cDestinations;

		public string Name => caps.szPname;

		public Manufacturers Manufacturer => (Manufacturers)caps.wMid;

		public int ProductID => caps.wPid;

		public IEnumerable<MixerLine> Destinations
		{
			get
			{
				for (int destination = 0; destination < DestinationCount; destination++)
				{
					yield return GetDestination(destination);
				}
			}
		}

		public static IEnumerable<Mixer> Mixers
		{
			get
			{
				for (int device = 0; device < NumberOfDevices; device++)
				{
					yield return new Mixer(device);
				}
			}
		}

		public Mixer(int mixerIndex)
		{
			if (mixerIndex < 0 || mixerIndex >= NumberOfDevices)
			{
				throw new ArgumentOutOfRangeException("mixerID");
			}
			caps = default(MixerInterop.MIXERCAPS);
			MmException.Try(MixerInterop.mixerGetDevCaps((IntPtr)mixerIndex, ref caps, Marshal.SizeOf(caps)), "mixerGetDevCaps");
			mixerHandle = (IntPtr)mixerIndex;
			mixerHandleType = MixerFlags.Mixer;
		}

		public MixerLine GetDestination(int destinationIndex)
		{
			if (destinationIndex < 0 || destinationIndex >= DestinationCount)
			{
				throw new ArgumentOutOfRangeException("destinationIndex");
			}
			return new MixerLine(mixerHandle, destinationIndex, mixerHandleType);
		}
	}
	public abstract class MixerControl
	{
		internal MixerInterop.MIXERCONTROL mixerControl;

		internal MixerInterop.MIXERCONTROLDETAILS mixerControlDetails;

		protected IntPtr mixerHandle;

		protected int nChannels;

		protected MixerFlags mixerHandleType;

		public string Name => mixerControl.szName;

		public MixerControlType ControlType => mixerControl.dwControlType;

		public bool IsBoolean => IsControlBoolean(mixerControl.dwControlType);

		public bool IsListText => IsControlListText(mixerControl.dwControlType);

		public bool IsSigned => IsControlSigned(mixerControl.dwControlType);

		public bool IsUnsigned => IsControlUnsigned(mixerControl.dwControlType);

		public bool IsCustom => IsControlCustom(mixerControl.dwControlType);

		public static IList<MixerControl> GetMixerControls(IntPtr mixerHandle, MixerLine mixerLine, MixerFlags mixerHandleType)
		{
			List<MixerControl> list = new List<MixerControl>();
			if (mixerLine.ControlsCount > 0)
			{
				int num = MarshalHelpers.SizeOf<MixerInterop.MIXERCONTROL>();
				MixerInterop.MIXERLINECONTROLS mixerLineControls = default(MixerInterop.MIXERLINECONTROLS);
				IntPtr intPtr = Marshal.AllocHGlobal(num * mixerLine.ControlsCount);
				mixerLineControls.cbStruct = Marshal.SizeOf(mixerLineControls);
				mixerLineControls.dwLineID = mixerLine.LineId;
				mixerLineControls.cControls = mixerLine.ControlsCount;
				mixerLineControls.pamxctrl = intPtr;
				mixerLineControls.cbmxctrl = MarshalHelpers.SizeOf<MixerInterop.MIXERCONTROL>();
				try
				{
					MmResult mmResult = MixerInterop.mixerGetLineControls(mixerHandle, ref mixerLineControls, MixerFlags.Mixer | mixerHandleType);
					if (mmResult != 0)
					{
						throw new MmException(mmResult, "mixerGetLineControls");
					}
					for (int i = 0; i < mixerLineControls.cControls; i++)
					{
						MixerInterop.MIXERCONTROL mIXERCONTROL = MarshalHelpers.PtrToStructure<MixerInterop.MIXERCONTROL>((IntPtr)(intPtr.ToInt64() + num * i));
						MixerControl item = GetMixerControl(mixerHandle, mixerLine.LineId, mIXERCONTROL.dwControlID, mixerLine.Channels, mixerHandleType);
						list.Add(item);
					}
				}
				finally
				{
					Marshal.FreeHGlobal(intPtr);
				}
			}
			return list;
		}

		public static MixerControl GetMixerControl(IntPtr mixerHandle, int nLineId, int controlId, int nChannels, MixerFlags mixerFlags)
		{
			MixerInterop.MIXERLINECONTROLS mixerLineControls = default(MixerInterop.MIXERLINECONTROLS);
			MixerInterop.MIXERCONTROL structure = default(MixerInterop.MIXERCONTROL);
			IntPtr intPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(structure));
			mixerLineControls.cbStruct = Marshal.SizeOf(mixerLineControls);
			mixerLineControls.cControls = 1;
			mixerLineControls.dwControlID = controlId;
			mixerLineControls.cbmxctrl = Marshal.SizeOf(structure);
			mixerLineControls.pamxctrl = intPtr;
			mixerLineControls.dwLineID = nLineId;
			MmResult mmResult = MixerInterop.mixerGetLineControls(mixerHandle, ref mixerLineControls, MixerFlags.ListText | mixerFlags);
			if (mmResult != 0)
			{
				Marshal.FreeCoTaskMem(intPtr);
				throw new MmException(mmResult, "mixerGetLineControls");
			}
			structure = MarshalHelpers.PtrToStructure<MixerInterop.MIXERCONTROL>(mixerLineControls.pamxctrl);
			Marshal.FreeCoTaskMem(intPtr);
			if (IsControlBoolean(structure.dwControlType))
			{
				return new BooleanMixerControl(structure, mixerHandle, mixerFlags, nChannels);
			}
			if (IsControlSigned(structure.dwControlType))
			{
				return new SignedMixerControl(structure, mixerHandle, mixerFlags, nChannels);
			}
			if (IsControlUnsigned(structure.dwControlType))
			{
				return new UnsignedMixerControl(structure, mixerHandle, mixerFlags, nChannels);
			}
			if (IsControlListText(structure.dwControlType))
			{
				return new ListTextMixerControl(structure, mixerHandle, mixerFlags, nChannels);
			}
			if (IsControlCustom(structure.dwControlType))
			{
				return new CustomMixerControl(structure, mixerHandle, mixerFlags, nChannels);
			}
			throw new InvalidOperationException($"Unknown mixer control type {structure.dwControlType}");
		}

		protected void GetControlDetails()
		{
			mixerControlDetails.cbStruct = Marshal.SizeOf(mixerControlDetails);
			mixerControlDetails.dwControlID = mixerControl.dwControlID;
			if (IsCustom)
			{
				mixerControlDetails.cChannels = 0;
			}
			else if ((mixerControl.fdwControl & (true ? 1u : 0u)) != 0)
			{
				mixerControlDetails.cChannels = 1;
			}
			else
			{
				mixerControlDetails.cChannels = nChannels;
			}
			if ((mixerControl.fdwControl & 2u) != 0)
			{
				mixerControlDetails.hwndOwner = (IntPtr)mixerControl.cMultipleItems;
			}
			else if (IsCustom)
			{
				mixerControlDetails.hwndOwner = IntPtr.Zero;
			}
			else
			{
				mixerControlDetails.hwndOwner = IntPtr.Zero;
			}
			if (IsBoolean)
			{
				mixerControlDetails.cbDetails = MarshalHelpers.SizeOf<MixerInterop.MIXERCONTROLDETAILS_BOOLEAN>();
			}
			else if (IsListText)
			{
				mixerControlDetails.cbDetails = MarshalHelpers.SizeOf<MixerInterop.MIXERCONTROLDETAILS_LISTTEXT>();
			}
			else if (IsSigned)
			{
				mixerControlDetails.cbDetails = MarshalHelpers.SizeOf<MixerInterop.MIXERCONTROLDETAILS_SIGNED>();
			}
			else if (IsUnsigned)
			{
				mixerControlDetails.cbDetails = MarshalHelpers.SizeOf<MixerInterop.MIXERCONTROLDETAILS_UNSIGNED>();
			}
			else
			{
				mixerControlDetails.cbDetails = mixerControl.Metrics.customData;
			}
			int num = mixerControlDetails.cbDetails * mixerControlDetails.cChannels;
			if ((mixerControl.fdwControl & 2u) != 0)
			{
				num *= (int)mixerControl.cMultipleItems;
			}
			IntPtr intPtr = Marshal.AllocCoTaskMem(num);
			mixerControlDetails.paDetails = intPtr;
			MmResult mmResult = MixerInterop.mixerGetControlDetails(mixerHandle, ref mixerControlDetails, MixerFlags.Mixer | mixerHandleType);
			if (mmResult == MmResult.NoError)
			{
				GetDetails(mixerControlDetails.paDetails);
			}
			Marshal.FreeCoTaskMem(intPtr);
			if (mmResult != 0)
			{
				throw new MmException(mmResult, "mixerGetControlDetails");
			}
		}

		protected abstract void GetDetails(IntPtr pDetails);

		private static bool IsControlBoolean(MixerControlType controlType)
		{
			switch (controlType)
			{
			case MixerControlType.BooleanMeter:
			case MixerControlType.Boolean:
			case MixerControlType.OnOff:
			case MixerControlType.Mute:
			case MixerControlType.Mono:
			case MixerControlType.Loudness:
			case MixerControlType.StereoEnhance:
			case MixerControlType.Button:
			case MixerControlType.SingleSelect:
			case MixerControlType.Mux:
			case MixerControlType.MultipleSelect:
			case MixerControlType.Mixer:
				return true;
			default:
				return false;
			}
		}

		private static bool IsControlListText(MixerControlType controlType)
		{
			if (controlType == MixerControlType.Equalizer || (uint)(controlType - 1879113728) <= 1u || (uint)(controlType - 1895890944) <= 1u)
			{
				return true;
			}
			return false;
		}

		private static bool IsControlSigned(MixerControlType controlType)
		{
			switch (controlType)
			{
			case MixerControlType.SignedMeter:
			case MixerControlType.PeakMeter:
			case MixerControlType.Signed:
			case MixerControlType.Decibels:
			case MixerControlType.Slider:
			case MixerControlType.Pan:
			case MixerControlType.QSoundPan:
				return true;
			default:
				return false;
			}
		}

		private static bool IsControlUnsigned(MixerControlType controlType)
		{
			switch (controlType)
			{
			case MixerControlType.UnsignedMeter:
			case MixerControlType.Unsigned:
			case MixerControlType.Percent:
			case MixerControlType.Fader:
			case MixerControlType.Volume:
			case MixerControlType.Bass:
			case MixerControlType.Treble:
			case MixerControlType.Equalizer:
			case MixerControlType.MicroTime:
			case MixerControlType.MilliTime:
				return true;
			default:
				return false;
			}
		}

		private static bool IsControlCustom(MixerControlType controlType)
		{
			return controlType == MixerControlType.Custom;
		}

		public override string ToString()
		{
			return $"{Name} {ControlType}";
		}
	}
	[Flags]
	internal enum MixerControlClass
	{
		Custom = 0,
		Meter = 0x10000000,
		Switch = 0x20000000,
		Number = 0x30000000,
		Slider = 0x40000000,
		Fader = 0x50000000,
		Time = 0x60000000,
		List = 0x70000000,
		Mask = 0x70000000
	}
	[Flags]
	internal enum MixerControlSubclass
	{
		SwitchBoolean = 0,
		SwitchButton = 0x1000000,
		MeterPolled = 0,
		TimeMicrosecs = 0,
		TimeMillisecs = 0x1000000,
		ListSingle = 0,
		ListMultiple = 0x1000000,
		Mask = 0xF000000
	}
	[Flags]
	internal enum MixerControlUnits
	{
		Custom = 0,
		Boolean = 0x10000,
		Signed = 0x20000,
		Unsigned = 0x30000,
		Decibels = 0x40000,
		Percent = 0x50000,
		Mask = 0xFF0000
	}
	public enum MixerControlType
	{
		Custom = 0,
		BooleanMeter = 268500992,
		SignedMeter = 268566528,
		PeakMeter = 268566529,
		UnsignedMeter = 268632064,
		Boolean = 536936448,
		OnOff = 536936449,
		Mute = 536936450,
		Mono = 536936451,
		Loudness = 536936452,
		StereoEnhance = 536936453,
		Button = 553713664,
		Decibels = 805568512,
		Signed = 805437440,
		Unsigned = 805502976,
		Percent = 805634048,
		Slider = 1073872896,
		Pan = 1073872897,
		QSoundPan = 1073872898,
		Fader = 1342373888,
		Volume = 1342373889,
		Bass = 1342373890,
		Treble = 1342373891,
		Equalizer = 1342373892,
		SingleSelect = 1879113728,
		Mux = 1879113729,
		MultipleSelect = 1895890944,
		Mixer = 1895890945,
		MicroTime = 1610809344,
		MilliTime = 1627586560
	}
	[Flags]
	public enum MixerFlags
	{
		Handle = int.MinValue,
		Mixer = 0,
		MixerHandle = int.MinValue,
		WaveOut = 0x10000000,
		WaveOutHandle = -1879048192,
		WaveIn = 0x20000000,
		WaveInHandle = -1610612736,
		MidiOut = 0x30000000,
		MidiOutHandle = -1342177280,
		MidiIn = 0x40000000,
		MidiInHandle = -1073741824,
		Aux = 0x50000000,
		Value = 0,
		ListText = 1,
		QueryMask = 0xF,
		All = 0,
		OneById = 1,
		OneByType = 2,
		GetLineInfoOfDestination = 0,
		GetLineInfoOfSource = 1,
		GetLineInfoOfLineId = 2,
		GetLineInfoOfComponentType = 3,
		GetLineInfoOfTargetType = 4,
		GetLineInfoOfQueryMask = 0xF
	}
	internal class MixerInterop
	{
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
		public struct MIXERCONTROLDETAILS
		{
			public int cbStruct;

			public int dwControlID;

			public int cChannels;

			public IntPtr hwndOwner;

			public int cbDetails;

			public IntPtr paDetails;
		}

		[StructLayout(LayoutKind.Sequential, Pack = 1)]
		public struct MIXERCAPS
		{
			public ushort wMid;

			public ushort wPid;

			public uint vDriverVersion;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
			public string szPname;

			public uint fdwSupport;

			public uint cDestinations;
		}

		[StructLayout(LayoutKind.Sequential, Pack = 1)]
		public struct MIXERLINECONTROLS
		{
			public int cbStruct;

			public int dwLineID;

			public int dwControlID;

			public int cControls;

			public int cbmxctrl;

			public IntPtr pamxctrl;
		}

		[Flags]
		public enum MIXERLINE_LINEF
		{
			MIXERLINE_LINEF_ACTIVE = 1,
			MIXERLINE_LINEF_DISCONNECTED = 0x8000,
			MIXERLINE_LINEF_SOURCE = int.MinValue
		}

		[StructLayout(LayoutKind.Sequential, Pack = 1)]
		public struct MIXERLINE
		{
			public int cbStruct;

			public int dwDestination;

			public int dwSource;

			public int dwLineID;

			public MIXERLINE_LINEF fdwLine;

			public IntPtr dwUser;

			public MixerLineComponentType dwComponentType;

			public int cChannels;

			public int cConnections;

			public int cControls;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
			public string szShortName;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
			public string szName;

			public uint dwType;

			public uint dwDeviceID;

			public ushort wMid;

			public ushort wPid;

			public uint vDriverVersion;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
			public string szPname;
		}

		[StructLayout(LayoutKind.Sequential, Pack = 1)]
		public struct Bounds
		{
			public int minimum;

			public int maximum;

			public int reserved2;

			public int reserved3;

			public int reserved4;

			public int reserved5;
		}

		[StructLayout(LayoutKind.Sequential, Pack = 1)]
		public struct Metrics
		{
			public int step;

			public int customData;

			public int reserved2;

			public int reserved3;

			public int reserved4;

			public int reserved5;
		}

		[StructLayout(LayoutKind.Sequential, Pack = 1)]
		public struct MIXERCONTROL
		{
			public uint cbStruct;

			public int dwControlID;

			public MixerControlType dwControlType;

			public uint fdwControl;

			public uint cMultipleItems;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
			public string szShortName;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
			public string szName;

			public Bounds Bounds;

			public Metrics Metrics;
		}

		public struct MIXERCONTROLDETAILS_BOOLEAN
		{
			public int fValue;
		}

		public struct MIXERCONTROLDETAILS_SIGNED
		{
			public int lValue;
		}

		[StructLayout(LayoutKind.Sequential, Pack = 1)]
		public struct MIXERCONTROLDETAILS_LISTTEXT
		{
			public uint dwParam1;

			public uint dwParam2;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
			public string szName;
		}

		public struct MIXERCONTROLDETAILS_UNSIGNED
		{
			public uint dwValue;
		}

		public const uint MIXERCONTROL_CONTROLF_UNIFORM = 1u;

		public const uint MIXERCONTROL_CONTROLF_MULTIPLE = 2u;

		public const uint MIXERCONTROL_CONTROLF_DISABLED = 2147483648u;

		public const int MAXPNAMELEN = 32;

		public const int MIXER_SHORT_NAME_CHARS = 16;

		public const int MIXER_LONG_NAME_CHARS = 64;

		[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
		public static extern int mixerGetNumDevs();

		[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
		public static extern MmResult mixerOpen(out IntPtr hMixer, int uMxId, IntPtr dwCallback, IntPtr dwInstance, MixerFlags dwOpenFlags);

		[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
		public static extern MmResult mixerClose(IntPtr hMixer);

		[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
		public static extern MmResult mixerGetControlDetails(IntPtr hMixer, ref MIXERCONTROLDETAILS mixerControlDetails, MixerFlags dwDetailsFlags);

		[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
		public static extern MmResult mixerGetDevCaps(IntPtr nMixerID, ref MIXERCAPS mixerCaps, int mixerCapsSize);

		[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
		public static extern MmResult mixerGetID(IntPtr hMixer, out int mixerID, MixerFlags dwMixerIDFlags);

		[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
		public static extern MmResult mixerGetLineControls(IntPtr hMixer, ref MIXERLINECONTROLS mixerLineControls, MixerFlags dwControlFlags);

		[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
		public static extern MmResult mixerGetLineInfo(IntPtr hMixer, ref MIXERLINE mixerLine, MixerFlags dwInfoFlags);

		[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
		public static extern MmResult mixerMessage(IntPtr hMixer, uint nMessage, IntPtr dwParam1, IntPtr dwParam2);

		[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
		public static extern MmResult mixerSetControlDetails(IntPtr hMixer, ref MIXERCONTROLDETAILS mixerControlDetails, MixerFlags dwDetailsFlags);
	}
	public class MixerLine
	{
		private MixerInterop.MIXERLINE mixerLine;

		private IntPtr mixerHandle;

		private MixerFlags mixerHandleType;

		public string Name => mixerLine.szName;

		public string ShortName => mixerLine.szShortName;

		public int LineId => mixerLine.dwLineID;

		public MixerLineComponentType ComponentType => mixerLine.dwComponentType;

		public string TypeDescription => mixerLine.dwComponentType switch
		{
			MixerLineComponentType.DestinationUndefined => "Undefined Destination", 
			MixerLineComponentType.DestinationDigital => "Digital Destination", 
			MixerLineComponentType.DestinationLine => "Line Level Destination", 
			MixerLineComponentType.DestinationMonitor => "Monitor Destination", 
			MixerLineComponentType.DestinationSpeakers => "Speakers Destination", 
			MixerLineComponentType.DestinationHeadphones => "Headphones Destination", 
			MixerLineComponentType.DestinationTelephone => "Telephone Destination", 
			MixerLineComponentType.DestinationWaveIn => "Wave Input Destination", 
			MixerLineComponentType.DestinationVoiceIn => "Voice Recognition Destination", 
			MixerLineComponentType.SourceUndefined => "Undefined Source", 
			MixerLineComponentType.SourceDigital => "Digital Source", 
			MixerLineComponentType.SourceLine => "Line Level Source", 
			MixerLineComponentType.SourceMicrophone => "Microphone Source", 
			MixerLineComponentType.SourceSynthesizer => "Synthesizer Source", 
			MixerLineComponentType.SourceCompactDisc => "Compact Disk Source", 
			MixerLineComponentType.SourceTelephone => "Telephone Source", 
			MixerLineComponentType.SourcePcSpeaker => "PC Speaker Source", 
			MixerLineComponentType.SourceWaveOut => "Wave Out Source", 
			MixerLineComponentType.SourceAuxiliary => "Auxiliary Source", 
			MixerLineComponentType.SourceAnalog => "Analog Source", 
			_ => "Invalid Component Type", 
		};

		public int Channels => mixerLine.cChannels;

		public int SourceCount => mixerLine.cConnections;

		public int ControlsCount => mixerLine.cControls;

		public bool IsActive => (mixerLine.fdwLine & MixerInterop.MIXERLINE_LINEF.MIXERLINE_LINEF_ACTIVE) != 0;

		public bool IsDisconnected => (mixerLine.fdwLine & MixerInterop.MIXERLINE_LINEF.MIXERLINE_LINEF_DISCONNECTED) != 0;

		public bool IsSource => (mixerLine.fdwLine & MixerInterop.MIXERLINE_LINEF.MIXERLINE_LINEF_SOURCE) != 0;

		public IEnumerable<MixerControl> Controls => MixerControl.GetMixerControls(mixerHandle, this, mixerHandleType);

		public IEnumerable<MixerLine> Sources
		{
			get
			{
				for (int source = 0; source < SourceCount; source++)
				{
					yield return GetSource(source);
				}
			}
		}

		public string TargetName => mixerLine.szPname;

		public MixerLine(IntPtr mixerHandle, int destinationIndex, MixerFlags mixerHandleType)
		{
			this.mixerHandle = mixerHandle;
			this.mixerHandleType = mixerHandleType;
			mixerLine = default(MixerInterop.MIXERLINE);
			mixerLine.cbStruct = Marshal.SizeOf(mixerLine);
			mixerLine.dwDestination = destinationIndex;
			MmException.Try(MixerInterop.mixerGetLineInfo(mixerHandle, ref mixerLine, mixerHandleType | MixerFlags.Mixer), "mixerGetLineInfo");
		}

		public MixerLine(IntPtr mixerHandle, int destinationIndex, int sourceIndex, MixerFlags mixerHandleType)
		{
			this.mixerHandle = mixerHandle;
			this.mixerHandleType = mixerHandleType;
			mixerLine = default(MixerInterop.MIXERLINE);
			mixerLine.cbStruct = Marshal.SizeOf(mixerLine);
			mixerLine.dwDestination = destinationIndex;
			mixerLine.dwSource = sourceIndex;
			MmException.Try(MixerInterop.mixerGetLineInfo(mixerHandle, ref mixerLine, mixerHandleType | MixerFlags.ListText), "mixerGetLineInfo");
		}

		public static int GetMixerIdForWaveIn(int waveInDevice)
		{
			int mixerID = -1;
			MmException.Try(MixerInterop.mixerGetID((IntPtr)waveInDevice, out mixerID, MixerFlags.WaveIn), "mixerGetID");
			return mixerID;
		}

		public MixerLine GetSource(int sourceIndex)
		{
			if (sourceIndex < 0 || sourceIndex >= SourceCount)
			{
				throw new ArgumentOutOfRangeException("sourceIndex");
			}
			return new MixerLine(mixerHandle, mixerLine.dwDestination, sourceIndex, mixerHandleType);
		}

		public override string ToString()
		{
			return $"{Name} {TypeDescription} ({ControlsCount} controls, ID={mixerLine.dwLineID})";
		}
	}
	public enum MixerLineComponentType
	{
		DestinationUndefined = 0,
		DestinationDigital = 1,
		DestinationLine = 2,
		DestinationMonitor = 3,
		DestinationSpeakers = 4,
		DestinationHeadphones = 5,
		DestinationTelephone = 6,
		DestinationWaveIn = 7,
		DestinationVoiceIn = 8,
		SourceUndefined = 4096,
		SourceDigital = 4097,
		SourceLine = 4098,
		SourceMicrophone = 4099,
		SourceSynthesizer = 4100,
		SourceCompactDisc = 4101,
		SourceTelephone = 4102,
		SourcePcSpeaker = 4103,
		SourceWaveOut = 4104,
		SourceAuxiliary = 4105,
		SourceAnalog = 4106
	}
	public class SignedMixerControl : MixerControl
	{
		private MixerInterop.MIXERCONTROLDETAILS_SIGNED signedDetails;

		public int Value
		{
			get
			{
				GetControlDetails();
				return signedDetails.lValue;
			}
			set
			{
				signedDetails.lValue = value;
				mixerControlDetails.paDetails = Marshal.AllocHGlobal(Marshal.SizeOf(signedDetails));
				Marshal.StructureToPtr(signedDetails, mixerControlDetails.paDetails, fDeleteOld: false);
				MmException.Try(MixerInterop.mixerSetControlDetails(mixerHandle, ref mixerControlDetails, MixerFlags.Mixer | mixerHandleType), "mixerSetControlDetails");
				Marshal.FreeHGlobal(mixerControlDetails.paDetails);
			}
		}

		public int MinValue => mixerControl.Bounds.minimum;

		public int MaxValue => mixerControl.Bounds.maximum;

		public double Percent
		{
			get
			{
				return 100.0 * (double)(Value - MinValue) / (double)(MaxValue - MinValue);
			}
			set
			{
				Value = (int)((double)MinValue + value / 100.0 * (double)(MaxValue - MinValue));
			}
		}

		internal SignedMixerControl(MixerInterop.MIXERCONTROL mixerControl, IntPtr mixerHandle, MixerFlags mixerHandleType, int nChannels)
		{
			base.mixerControl = mixerControl;
			base.mixerHandle = mixerHandle;
			base.mixerHandleType = mixerHandleType;
			base.nChannels = nChannels;
			mixerControlDetails = default(MixerInterop.MIXERCONTROLDETAILS);
			GetControlDetails();
		}

		protected override void GetDetails(IntPtr pDetails)
		{
			signedDetails = MarshalHelpers.PtrToStructure<MixerInterop.MIXERCONTROLDETAILS_SIGNED>(mixerControlDetails.paDetails);
		}

		public override string ToString()
		{
			return $"{base.ToString()} {Percent}%";
		}
	}
	public class UnsignedMixerControl : MixerControl
	{
		private MixerInterop.MIXERCONTROLDETAILS_UNSIGNED[] unsignedDetails;

		public uint Value
		{
			get
			{
				GetControlDetails();
				return unsignedDetails[0].dwValue;
			}
			set
			{
				int num = Marshal.SizeOf(unsignedDetails[0]);
				mixerControlDetails.paDetails = Marshal.AllocHGlobal(num * nChannels);
				for (int i = 0; i < nChannels; i++)
				{
					unsignedDetails[i].dwValue = value;
					long num2 = mixerControlDetails.paDetails.ToInt64() + num * i;
					Marshal.StructureToPtr(unsignedDetails[i], (IntPtr)num2, fDeleteOld: false);
				}
				MmException.Try(MixerInterop.mixerSetControlDetails(mixerHandle, ref mixerControlDetails, MixerFlags.Mixer | mixerHandleType), "mixerSetControlDetails");
				Marshal.FreeHGlobal(mixerControlDetails.paDetails);
			}
		}

		public uint MinValue => (uint)mixerControl.Bounds.minimum;

		public uint MaxValue => (uint)mixerControl.Bounds.maximum;

		public double Percent
		{
			get
			{
				return 100.0 * (double)(Value - MinValue) / (double)(MaxValue - MinValue);
			}
			set
			{
				Value = (uint)((double)MinValue + value / 100.0 * (double)(MaxValue - MinValue));
			}
		}

		internal UnsignedMixerControl(MixerInterop.MIXERCONTROL mixerControl, IntPtr mixerHandle, MixerFlags mixerHandleType, int nChannels)
		{
			base.mixerControl = mixerControl;
			base.mixerHandle = mixerHandle;
			base.mixerHandleType = mixerHandleType;
			base.nChannels = nChannels;
			mixerControlDetails = default(MixerInterop.MIXERCONTROLDETAILS);
			GetControlDetails();
		}

		protected override void GetDetails(IntPtr pDetails)
		{
			unsignedDetails = new MixerInterop.MIXERCONTROLDETAILS_UNSIGNED[nChannels];
			for (int i = 0; i < nChannels; i++)
			{
				unsignedDetails[i] = MarshalHelpers.PtrToStructure<MixerInterop.MIXERCONTROLDETAILS_UNSIGNED>(mixerControlDetails.paDetails);
			}
		}

		public override string ToString()
		{
			return $"{base.ToString()} {Percent}%";
		}
	}
}
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 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 disposed;

		private MidiInterop.MidiInCallback callback;

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

		public event EventHandler<MidiInMessageEventArgs> MessageReceived;

		public event EventHandler<MidiInMessageEventArgs> ErrorReceived;

		public MidiIn(int deviceNo)
		{
			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()
		{
			MmException.Try(MidiInterop.midiInStart(hMidiIn), "midiInStart");
		}

		public void Stop()
		{
			MmException.Try(MidiInterop.midiInStop(hMidiIn), "midiInStop");
		}

		public void Reset()
		{
			MmException.Try(MidiInterop.midiInReset(hMidiIn), "midiInReset");
		}

		private void Callback(IntPtr midiInHandle, MidiInterop.MidiInMessage message, IntPtr userData, IntPtr messageParameter1, IntPtr messageParameter2)
		{
			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.Open:
			case MidiInterop.MidiInMessage.Close:
			case MidiInterop.MidiInMessage.LongData:
			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)
		{
			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)
		{
			if (!disposed)
			{
				MidiInterop.midiInClose(hMidiIn);
			}
			disposed = true;
		}

		~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)
			{
			}
		}
	}
	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, ref MIDIHDR 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, ref MIDIHDR 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, ref MIDIHDR 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
			{
				int lpdwVolume = 0;
				MmException.Try(MidiInterop.midiOutGetVolume(hMidiOut, ref lpdwVolume), "midiOutGetVolume");
				return lpdwVolume;
			}
			set
			{
				MmException.Try(MidiInterop.midiOutSetVolume(hMidiOut, value), "midiOutSetVolume");
			}
		}

		public static MidiOutCapabilities DeviceInfo(int midiOutDeviceNumber)
		{
			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)
		{
			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()
		{
			MmException.Try(MidiInterop.midiOutReset(hMidiOut), "midiOutReset");
		}

		public void SendDriverMessage(int message, int param1, int param2)
		{
			MmException.Try(MidiInterop.midiOutMessage(hMidiOut, message, (IntPtr)param1, (IntPtr)param2), "midiOutMessage");
		}

		public void Send(int message)
		{
			MmException.Try(MidiInterop.midiOutShortMsg(hMidiOut, message), "midiOutShortMsg");
		}

		protected virtual void Dispose(bool disposing)
		{
			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)
		{
			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 (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 FormatExcept

OriginalSoundTrack.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Xml;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using EnemiesReturns.ModdedEntityStates.Judgement.Arraign.Phase1;
using EnemiesReturns.ModdedEntityStates.Judgement.WaveInteractable;
using EntityStates.ArtifactShell;
using EntityStates.FalseSonBoss;
using EntityStates.Missions.BrotherEncounter;
using EntityStates.Missions.ChampRush;
using EntityStates.Missions.ProvidenceBossEncounter;
using EntityStates.SolusHeart;
using EntityStates.SolusHeart.Death;
using EntityStates.SolusWing;
using EntityStates.TeleporterCatastrophe.DLC4.Teleporter;
using EntityStates.VoidRaidCrab;
using FathomlessVoidling.EntityStates;
using HarmonyLib;
using NAudio.Wave;
using NAudio.Wave.SampleProviders;
using On.EntityStates.ArtifactShell;
using On.EntityStates.FalseSonBoss;
using On.EntityStates.Missions.BrotherEncounter;
using On.EntityStates.Missions.ChampRush;
using On.EntityStates.Missions.ProvidenceBossEncounter;
using On.EntityStates.SolusHeart;
using On.EntityStates.SolusHeart.Death;
using On.EntityStates.SolusWing;
using On.EntityStates.TeleporterCatastrophe.DLC4.Teleporter;
using On.EntityStates.VoidRaidCrab;
using On.RoR2;
using On.RoR2.Quests.TrialQuests;
using On.RoR2.UI;
using R2API.Utils;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using RoR2.ConVar;
using RoR2.Quests.TrialQuests;
using RoR2.UI;
using TagLib;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("OriginalSoundTrack")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+47d450bfc45073eb8a69c71cdec477c83a625cd8")]
[assembly: AssemblyProduct("OriginalSoundTrack")]
[assembly: AssemblyTitle("OriginalSoundTrack")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace OriginalSoundTrack;

internal static class enemiesreturnswrapper
{
	private static OriginalSoundTrack ostplugin;

	private static bool? _Present;

	public static bool Present
	{
		get
		{
			if (!_Present.HasValue)
			{
				_Present = Chainloader.PluginInfos.ContainsKey("com.Viliger.EnemiesReturns");
			}
			return _Present.Value;
		}
	}

	[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
	public static void Init(OriginalSoundTrack instance)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		Debug.Log((object)"hey i loaded correctly");
		ostplugin = instance;
		Harmony val = new Harmony("com.jasoncreatesblep.moreostsmodplus");
		val.PatchAll(typeof(enemiesreturnswrapper));
	}

	[HarmonyPatch(typeof(Spawn), "OnEnter")]
	[HarmonyPostfix]
	private static void PatchOnEnter()
	{
		Debug.Log((object)"====================== JUDGEMENT BOSS FIGHT START ======================");
		ostplugin.extratracksfrfr = false;
		ostplugin.bossActive = false;
		ostplugin.afterBossPhase = true;
		ostplugin.hasshuffled = false;
		ostplugin.listtracker = 0;
		ostplugin.JudgementWaveCounter = 0;
		ostplugin.PickOutMusic();
	}

	[HarmonyPatch(typeof(StartingUp), "OnEnter")]
	[HarmonyPostfix]
	private static void PatchOnEnter2()
	{
		ostplugin.JudgementWaveCounter++;
		if (!ostplugin.bossActive)
		{
			Debug.Log((object)"====================== JUDGEMENT TRIAl START ======================");
			ostplugin.bossActive = true;
			ostplugin.hasshuffled = false;
			ostplugin.listtracker = 0;
			ostplugin.PickOutMusic(isForTeleporter: true);
		}
		if (ostplugin.JudgementWaveCounter == 5 && ostplugin.judgementfinalwavesenabled)
		{
			Debug.Log((object)"====================== LAST 2 WAVES REMAINING ======================");
			ostplugin.extratracksfrfr = true;
			ostplugin.bossActive = true;
			ostplugin.hasshuffled = false;
			ostplugin.listtracker = 0;
			ostplugin.PickOutMusic(isForTeleporter: true);
		}
	}
}
internal static class fathomlesswrapper
{
	private static OriginalSoundTrack ostpluginfathomless;

	private static bool? _Present2;

	public static bool Present2
	{
		get
		{
			if (!_Present2.HasValue)
			{
				_Present2 = Chainloader.PluginInfos.ContainsKey("Nuxlar.FathomlessVoidling");
			}
			return _Present2.Value;
		}
	}

	[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
	public static void Init2(OriginalSoundTrack instance2)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		Debug.Log((object)"hey i loaded correctly as well uwu");
		ostpluginfathomless = instance2;
		Harmony val = new Harmony("com.jasoncreatesblep.moreostsmodplus");
		val.PatchAll(typeof(fathomlesswrapper));
	}

	[HarmonyPatch(typeof(BetterSpawnState), "OnEnter")]
	[HarmonyPostfix]
	private static void PatchOnEnter()
	{
		Debug.Log((object)"====================== FATHOMLESS VOIDLING BOSS START ======================");
		ostpluginfathomless.extratracksfrfr = false;
		ostpluginfathomless.bossActive = true;
		ostpluginfathomless.afterBossPhase = false;
		ostpluginfathomless.hasshuffled = false;
		ostpluginfathomless.listtracker = 0;
		ostpluginfathomless.PickOutMusic(isForTeleporter: true);
	}
}
internal class NetworkCompatibilityAttribute : Attribute
{
	private CompatibilityLevel noNeedForSync;

	private VersionStrictness differentModVersionsAreOk;

	public NetworkCompatibilityAttribute(CompatibilityLevel noNeedForSync, VersionStrictness differentModVersionsAreOk)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		this.noNeedForSync = noNeedForSync;
		this.differentModVersionsAreOk = differentModVersionsAreOk;
	}
}
[BepInPlugin("com.jasoncreatesblep.moreostsmodplus", "MoreOSTsModPlus", "2.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
public class OriginalSoundTrack : BaseUnityPlugin
{
	private enum postbossmusicmode
	{
		silence,
		alttrack,
		normaltrack
	}

	private enum randomizationmodelist
	{
		off,
		shuffle,
		shuffleonce
	}

	public class Music
	{
		public string name;

		public string fullName;

		public string[] scenes;

		public bool boss = false;

		public float volume = 1f;

		public bool loop = false;

		public bool afterboss = false;

		public bool simulacrum = false;

		public bool postloopvariant = false;

		public bool isextratrack = false;

		public bool soulboundboss = false;
	}

	public class LoopStream : WaveStream
	{
		private WaveStream sourceStream;

		private bool EnableLooping = true;

		public override WaveFormat WaveFormat => sourceStream.WaveFormat;

		public override long Position
		{
			get
			{
				return ((Stream)(object)sourceStream).Position;
			}
			set
			{
				((Stream)(object)sourceStream).Position = value;
			}
		}

		public override long Length => ((Stream)(object)sourceStream).Length;

		public LoopStream(WaveStream sourceStream, bool shouldLoop)
		{
			this.sourceStream = sourceStream;
			EnableLooping = shouldLoop;
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			int i;
			int num2;
			for (i = 0; i < count; i += num2)
			{
				int num = count - i;
				num2 = ((Stream)(object)sourceStream).Read(buffer, offset + i, num);
				if (num2 < num || ((Stream)(object)sourceStream).Position >= ((Stream)(object)sourceStream).Length)
				{
					if (!EnableLooping)
					{
						break;
					}
					((Stream)(object)sourceStream).Position = 0L;
				}
			}
			return i;
		}
	}

	private FadeInOutSampleProvider fader;

	private WaveOutEvent outputDevice;

	private FileInfo[] soundFiles;

	private List<Music> musics = new List<Music>();

	private AudioFileReader currentSong;

	private string currentSongFullName = "";

	private bool songPaused = false;

	private float currentMusicVolume;

	private ConfigEntry<float> globalMusicVolume;

	private ConfigEntry<bool> EnableMetaData;

	private bool shouldLoop = true;

	public bool hasshuffled = false;

	private string oldMusicVolume = "";

	private string currentScene = "";

	private Random rnd = new Random();

	private postbossmusicmode postbossmusic = postbossmusicmode.silence;

	private randomizationmodelist randomizationmode = randomizationmodelist.off;

	private XmlElement settings;

	private Texture2D modIconTexture;

	private SceneIndex lastStageIndex = (SceneIndex)(-1);

	public bool bossActive = false;

	public bool afterBossPhase = false;

	public bool simulacrumactive = false;

	public bool playanimamusic = false;

	public bool playerhaslooped = false;

	private string[] storedloopstages = null;

	private int postloopamount = 0;

	public bool extratracksfrfr = false;

	public int JudgementWaveCounter = 0;

	public bool artifactmusicenabled = false;

	public bool judgementfinalwavesenabled = false;

	public bool soultrialstrackenabled = false;

	public bool karmicmithrixtrackenabled = false;

	public bool winnowingreckoningenabled = false;

	public bool mithrixaltoutro = false;

	public int listtracker = 0;

	private string lasttitle = "";

	public void Awake()
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Expected O, but got Unknown
		//IL_0063: Expected O, but got Unknown
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Expected O, but got Unknown
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Expected O, but got Unknown
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Expected O, but got Unknown
		//IL_00f4: Expected O, but got Unknown
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Expected O, but got Unknown
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Expected O, but got Unknown
		//IL_0194: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0777: Unknown result type (might be due to invalid IL or missing references)
		//IL_0781: Expected O, but got Unknown
		//IL_0789: Unknown result type (might be due to invalid IL or missing references)
		//IL_0793: Expected O, but got Unknown
		//IL_079b: Unknown result type (might be due to invalid IL or missing references)
		//IL_07a5: Expected O, but got Unknown
		//IL_07ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_07b7: Expected O, but got Unknown
		//IL_07bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_07c9: Expected O, but got Unknown
		//IL_07d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_07db: Expected O, but got Unknown
		//IL_07e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_07ed: Expected O, but got Unknown
		//IL_07f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_07ff: Expected O, but got Unknown
		//IL_0807: Unknown result type (might be due to invalid IL or missing references)
		//IL_0811: Expected O, but got Unknown
		//IL_0819: Unknown result type (might be due to invalid IL or missing references)
		//IL_0823: Expected O, but got Unknown
		//IL_082b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0835: Expected O, but got Unknown
		//IL_083d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0847: Expected O, but got Unknown
		//IL_084f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0859: Expected O, but got Unknown
		//IL_0861: Unknown result type (might be due to invalid IL or missing references)
		//IL_086b: Expected O, but got Unknown
		//IL_0873: Unknown result type (might be due to invalid IL or missing references)
		//IL_087d: Expected O, but got Unknown
		//IL_0885: Unknown result type (might be due to invalid IL or missing references)
		//IL_088f: Expected O, but got Unknown
		//IL_0897: Unknown result type (might be due to invalid IL or missing references)
		//IL_08a1: Expected O, but got Unknown
		//IL_08a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_08b3: Expected O, but got Unknown
		//IL_08bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_08c5: Expected O, but got Unknown
		//IL_08cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_08d7: Expected O, but got Unknown
		//IL_08df: Unknown result type (might be due to invalid IL or missing references)
		//IL_08e9: Expected O, but got Unknown
		//IL_08f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_08fb: Expected O, but got Unknown
		//IL_0903: Unknown result type (might be due to invalid IL or missing references)
		//IL_090d: Expected O, but got Unknown
		//IL_0915: Unknown result type (might be due to invalid IL or missing references)
		//IL_091f: Expected O, but got Unknown
		//IL_0927: Unknown result type (might be due to invalid IL or missing references)
		//IL_0931: Expected O, but got Unknown
		//IL_0939: Unknown result type (might be due to invalid IL or missing references)
		//IL_0943: Expected O, but got Unknown
		//IL_0765: Unknown result type (might be due to invalid IL or missing references)
		//IL_076f: Expected O, but got Unknown
		TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterFinished;
		string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
		string text = directoryName;
		globalMusicVolume = ((BaseUnityPlugin)this).Config.Bind<float>(new ConfigDefinition("General", "Volume"), 40f, new ConfigDescription("The volume of the More OSTs Mod music. KEEP THE GAME'S MUSIC VOLUME AT 0!!!", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
		ModSettingsManager.AddOption((BaseOption)new StepSliderOption(globalMusicVolume, new StepSliderConfig
		{
			min = 0f,
			max = 100f,
			increment = 1f,
			formatString = "{0:0}%"
		}));
		globalMusicVolume.SettingChanged += delegate
		{
			UpdateVolume();
		};
		EnableMetaData = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("General", "Display Metadata"), true, new ConfigDescription("toggles whether the current song's title and artist will display in chat", (AcceptableValueBase)(object)new AcceptableValueRange<bool>(false, true), Array.Empty<object>()));
		ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(EnableMetaData));
		modIconTexture = new Texture2D(0, 0);
		using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("OriginalSoundTrack.ror2_more_osts_mod_clean.png"))
		{
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			byte[] array = memoryStream.ToArray();
			ImageConversion.LoadImage(modIconTexture, array);
		}
		Sprite modIcon = Sprite.Create(modIconTexture, new Rect(0f, 0f, (float)((Texture)modIconTexture).width, (float)((Texture)modIconTexture).height), new Vector2(0f, 0f));
		ModSettingsManager.SetModIcon(modIcon);
		try
		{
			XmlDocument xmlDocument = new XmlDocument();
			xmlDocument.Load(directoryName + "/settings.xml");
			settings = xmlDocument["settings"];
			shouldLoop = settings["loop"].InnerText.ToLower() == "true";
			if (Enum.TryParse<postbossmusicmode>(settings["aftertptracks"].InnerText, ignoreCase: true, out var result))
			{
				postbossmusic = result;
			}
			if (Enum.TryParse<randomizationmodelist>(settings["randomization"].InnerText, ignoreCase: true, out var result2))
			{
				randomizationmode = result2;
			}
			if (settings["music-path"] != null)
			{
				text = settings["music-path"].InnerText;
			}
			soundFiles = SearchForAudioFiles(text);
			foreach (XmlNode setting in settings)
			{
				if (setting.Name == "postloopstagetracksettings")
				{
					storedloopstages = (from str in settings["postloopstagetracksettings"].GetAttribute("loopscenes").Split(',')
						select str.Trim()).ToArray();
					if (int.TryParse(settings["postloopstagetracksettings"].GetAttribute("enableatloop"), out var result3))
					{
						postloopamount = result3;
					}
				}
				if (setting.Name == "extratracksettings")
				{
					if (bool.TryParse(settings["extratracksettings"].GetAttribute("artifacttrialmusic"), out var result4))
					{
						artifactmusicenabled = result4;
					}
					if (bool.TryParse(settings["extratracksettings"].GetAttribute("judgementwave5track"), out var result5))
					{
						judgementfinalwavesenabled = result5;
					}
					if (bool.TryParse(settings["extratracksettings"].GetAttribute("soultrialtptrack"), out var result6))
					{
						soultrialstrackenabled = result6;
					}
					if (bool.TryParse(settings["extratracksettings"].GetAttribute("karma8mithrixtrack"), out var result7))
					{
						karmicmithrixtrackenabled = result7;
					}
					if (bool.TryParse(settings["extratracksettings"].GetAttribute("winnowingreckoning"), out var result8))
					{
						winnowingreckoningenabled = result8;
					}
				}
			}
			foreach (XmlNode childNode in settings["music"].ChildNodes)
			{
				if (childNode.NodeType == XmlNodeType.Comment)
				{
					continue;
				}
				Music music = new Music();
				music.name = GetAttribute(childNode, "name");
				music.scenes = (from str in GetAttribute(childNode, "scenes").Split(',')
					select str.Trim()).ToArray();
				music.boss = GetAttribute(childNode, "boss").ToLower() == "true";
				music.afterboss = GetAttribute(childNode, "afterboss").ToLower() == "true";
				music.simulacrum = GetAttribute(childNode, "simulacrum").ToLower() == "true";
				music.postloopvariant = GetAttribute(childNode, "postloopvariant").ToLower() == "true";
				music.isextratrack = GetAttribute(childNode, "isextratrack").ToLower() == "true";
				music.soulboundboss = GetAttribute(childNode, "soulboundboss").ToLower().Equals("true");
				if (float.TryParse(GetAttribute(childNode, "volume"), NumberStyles.Any, CultureInfo.InvariantCulture, out var result9))
				{
					music.volume = result9;
				}
				music.loop = GetAttribute(childNode, "loop").ToLower() == "true";
				FileInfo[] array2 = soundFiles;
				foreach (FileInfo fileInfo in array2)
				{
					if (fileInfo.Name == music.name)
					{
						music.fullName = fileInfo.FullName;
						break;
					}
				}
				musics.Add(music);
			}
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)"!!!!! OriginalSoundTrack Mod: Failed to parse settings.xml !!!!!");
			Debug.Log((object)"OriginalSoundTrack Mod: Music will be randomly selected from what is found in the plugin dir.");
			Debug.Log((object)ex);
		}
		if (soundFiles == null)
		{
			text = directoryName;
			soundFiles = SearchForAudioFiles(text);
		}
		if (soundFiles.Length == 0)
		{
			Debug.LogError((object)"!!!!! OriginalSoundTrack Mod: No audio files found. Exiting. !!!!!");
			Debug.LogError((object)("OriginalSoundTrack Mod: Looked for .mp3 and .wav files in: " + text));
			return;
		}
		if (outputDevice == null)
		{
			outputDevice = new WaveOutEvent();
		}
		TeleporterInteraction.OnInteractionBegin += (hook_OnInteractionBegin)delegate(orig_OnInteractionBegin orig, TeleporterInteraction self, Interactor activator)
		{
			orig.Invoke(self, activator);
			if (!bossActive)
			{
				bossActive = true;
				hasshuffled = false;
				listtracker = 0;
				PickOutMusic(isForTeleporter: true);
			}
		};
		TeleporterInteraction.RpcClientOnActivated += (hook_RpcClientOnActivated)delegate(orig_RpcClientOnActivated orig, TeleporterInteraction self, GameObject activator)
		{
			orig.Invoke(self, activator);
			if (!bossActive)
			{
				bossActive = true;
				hasshuffled = false;
				listtracker = 0;
				PickOutMusic(isForTeleporter: true);
			}
		};
		OverchargingInterludeState.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, OverchargingInterludeState self)
		{
			orig.Invoke(self);
			if (bossActive && soultrialstrackenabled)
			{
				Debug.Log((object)"====================== OVERCHARGING THE TELEPORTER!!! ======================");
				bossActive = true;
				extratracksfrfr = true;
				hasshuffled = false;
				listtracker = 0;
				PickOutMusic(isForTeleporter: true);
			}
		};
		PauseScreenController.OnEnable += (hook_OnEnable)delegate(orig_OnEnable orig, PauseScreenController self)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			orig.Invoke(self);
			if (outputDevice != null && (int)outputDevice.PlaybackState == 1)
			{
				outputDevice.Pause();
				songPaused = true;
			}
		};
		PauseScreenController.OnDisable += (hook_OnDisable)delegate(orig_OnDisable orig, PauseScreenController self)
		{
			orig.Invoke(self);
			if (outputDevice != null && songPaused)
			{
				outputDevice.Play();
				songPaused = false;
			}
		};
		InfiniteTowerRun.Start += (hook_Start)delegate(orig_Start orig, InfiniteTowerRun self)
		{
			orig.Invoke(self);
			simulacrumactive = true;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic();
		};
		InfiniteTowerRun.OnDestroy += (hook_OnDestroy)delegate(orig_OnDestroy orig, InfiniteTowerRun self)
		{
			orig.Invoke(self);
			simulacrumactive = false;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic();
		};
		Phase1.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, Phase1 self)
		{
			orig.Invoke(self);
			if (KarmaManager.instance.GetEffectiveKarma() == 8 && karmicmithrixtrackenabled)
			{
				Debug.Log((object)"====================== KARMIC MITHRIX START ======================");
				bossActive = true;
				extratracksfrfr = true;
				mithrixaltoutro = true;
				hasshuffled = false;
				listtracker = 0;
				PickOutMusic(isForTeleporter: true);
			}
			else
			{
				Debug.Log((object)"====================== MITHRIX BOSS FIGHT START ======================");
				bossActive = true;
				hasshuffled = false;
				listtracker = 0;
				PickOutMusic(isForTeleporter: true);
			}
		};
		EncounterFinished.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, EncounterFinished self)
		{
			orig.Invoke(self);
			Debug.Log((object)"====================== MITHRIX BOSS FIGHT DONE ======================");
			bossActive = false;
			afterBossPhase = true;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic();
		};
		HeartSpawnState.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, HeartSpawnState self)
		{
			orig.Invoke(self);
			Debug.Log((object)"====================== FALSE SON BOSS FIGHT START ======================");
			bossActive = true;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic(isForTeleporter: true);
		};
		SkyJumpDeathState.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, SkyJumpDeathState self)
		{
			orig.Invoke(self);
			Debug.Log((object)"====================== FALSE SON BOSS FIGHT DONE ======================");
			bossActive = false;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic();
		};
		CutsceneTransformation.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, CutsceneTransformation self)
		{
			orig.Invoke(self);
			Debug.Log((object)"====================== SOLUS HEART BOSS FIGHT START ======================");
			bossActive = true;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic(isForTeleporter: true);
		};
		Offering.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, Offering self)
		{
			orig.Invoke(self);
			Debug.Log((object)"====================== SOLUS HEART BOSS FIGHT DONE ======================");
			bossActive = false;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic();
		};
		SpawnState.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, SpawnState self)
		{
			orig.Invoke(self);
			Debug.Log((object)"====================== SOLUS WING BOSS FIGHT START ======================");
			bossActive = true;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic(isForTeleporter: true);
		};
		DeathState.OnExit += (hook_OnExit)delegate(orig_OnExit orig, DeathState self)
		{
			orig.Invoke(self);
			Debug.Log((object)"====================== SOLUS WING BOSS FIGHT DONE ======================");
			bossActive = false;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic();
		};
		SpawnState.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, SpawnState self)
		{
			if (!bossActive)
			{
				orig.Invoke(self);
				Debug.Log((object)"====================== VOIDLING BOSS FIGHT START ======================");
				bossActive = true;
				hasshuffled = false;
				listtracker = 0;
				PickOutMusic(isForTeleporter: true);
			}
		};
		DeathState.OnExit += (hook_OnExit)delegate(orig_OnExit orig, DeathState self)
		{
			orig.Invoke(self);
			Debug.Log((object)"====================== VOIDLING BOSS FIGHT DONE ======================");
			bossActive = false;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic();
		};
		StartHurt.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, StartHurt self)
		{
			if (artifactmusicenabled)
			{
				orig.Invoke(self);
				Debug.Log((object)"====================== ARTIFACT TRIAL START ======================");
				extratracksfrfr = true;
				bossActive = false;
				hasshuffled = false;
				listtracker = 0;
				PickOutMusic();
			}
		};
		Death.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, Death self)
		{
			if (artifactmusicenabled)
			{
				orig.Invoke(self);
				Debug.Log((object)"====================== ARTIFACT TRIAL END ======================");
				extratracksfrfr = false;
				bossActive = false;
				hasshuffled = false;
				listtracker = 0;
				PickOutMusic();
			}
		};
		StartChampRush.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, StartChampRush self)
		{
			orig.Invoke(self);
			Debug.Log((object)"====================== SOULBOUND TRIAL START ======================");
			bossActive = true;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic(isForTeleporter: true);
		};
		ReaperFight.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, ReaperFight self)
		{
			if (!playanimamusic)
			{
				orig.Invoke(self);
				Debug.Log((object)"====================== ANIMA HARVESTER BOSS START ======================");
				bossActive = true;
				playanimamusic = true;
				hasshuffled = false;
				listtracker = 0;
				PickOutMusic(isForTeleporter: true);
			}
		};
		Aftermath.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, Aftermath self)
		{
			orig.Invoke(self);
			Debug.Log((object)"====================== SOULBOUND TRIAL END ======================");
			bossActive = false;
			hasshuffled = false;
			listtracker = 0;
			playanimamusic = false;
			PickOutMusic();
		};
		Phase1.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, Phase1 self)
		{
			orig.Invoke(self);
			Debug.Log((object)"====================== PROVIDENCE BOSS FIGHT START ======================");
			bossActive = true;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic(isForTeleporter: true);
		};
		BossDeath.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, BossDeath self)
		{
			orig.Invoke(self);
			Debug.Log((object)"====================== PROVIDENCE BOSS FIGHT END ======================");
			bossActive = false;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic();
		};
		BaseTrialQuest.OnEnter += (hook_OnEnter)delegate(orig_OnEnter orig, BaseTrialQuest self)
		{
			orig.Invoke(self);
			if (winnowingreckoningenabled)
			{
				Debug.Log((object)"====================== WINNOWING TRIAL START ======================");
				bossActive = true;
				hasshuffled = false;
				listtracker = 0;
				PickOutMusic(isForTeleporter: true);
			}
		};
		BaseTrialQuest.OnExit += (hook_OnExit)delegate(orig_OnExit orig, BaseTrialQuest self)
		{
			orig.Invoke(self);
			if (winnowingreckoningenabled)
			{
				Debug.Log((object)"====================== WINNOWING TRIAL END ======================");
				bossActive = false;
				hasshuffled = false;
				listtracker = 0;
				PickOutMusic();
			}
		};
		if (enemiesreturnswrapper.Present)
		{
			enemiesreturnswrapper.Init(this);
		}
		if (fathomlesswrapper.Present2)
		{
			fathomlesswrapper.Init2(this);
		}
		SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode mode)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			Debug.Log((object)"====================== CHANGE SCENE ========================");
			Debug.Log((object)((Scene)(ref scene)).name);
			currentScene = ((Scene)(ref scene)).name;
			SceneIndex sceneDefIndex = SceneCatalog.mostRecentSceneDef.sceneDefIndex;
			if (currentScene == "enemiesreturns_judgementoutro")
			{
				extratracksfrfr = false;
				lastStageIndex = sceneDefIndex;
				afterBossPhase = true;
				bossActive = false;
				hasshuffled = false;
				playanimamusic = false;
				listtracker = 0;
				JudgementWaveCounter = 0;
				mithrixaltoutro = false;
				PickOutMusic();
			}
			else if (currentScene == "outro" && mithrixaltoutro)
			{
				extratracksfrfr = true;
				lastStageIndex = sceneDefIndex;
				afterBossPhase = false;
				bossActive = false;
				hasshuffled = false;
				playanimamusic = false;
				listtracker = 0;
				JudgementWaveCounter = 0;
				mithrixaltoutro = false;
				PickOutMusic();
			}
			else if (sceneDefIndex != lastStageIndex)
			{
				if ((Object)(object)Run.instance != (Object)null)
				{
					playerhaslooped = Run.instance.loopClearCount >= postloopamount;
				}
				lastStageIndex = sceneDefIndex;
				playanimamusic = false;
				afterBossPhase = false;
				extratracksfrfr = false;
				bossActive = false;
				hasshuffled = false;
				listtracker = 0;
				JudgementWaveCounter = 0;
				mithrixaltoutro = false;
				PickOutMusic();
			}
			else if (!bossActive)
			{
				extratracksfrfr = false;
				hasshuffled = false;
				playanimamusic = false;
				listtracker = 0;
				JudgementWaveCounter = 0;
				mithrixaltoutro = false;
				PickOutMusic();
			}
		};
	}

	private void OnTeleporterFinished(TeleporterInteraction tp)
	{
		switch (postbossmusic)
		{
		case postbossmusicmode.silence:
			Debug.Log((object)"==================== Play Nothing Once This Song Finishes? COMING RIGHT UP!! ====================");
			break;
		case postbossmusicmode.alttrack:
			Debug.Log((object)"==================== Alt Stage Track Post-Tp ENABLED!!!!!!!!!!!! ====================");
			bossActive = false;
			extratracksfrfr = false;
			afterBossPhase = true;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic();
			break;
		case postbossmusicmode.normaltrack:
			Debug.Log((object)"==================== Normal Stage Track Post-Tp ENABLED!!!!!!!!!!!! ====================");
			bossActive = false;
			extratracksfrfr = false;
			hasshuffled = false;
			listtracker = 0;
			PickOutMusic();
			break;
		}
	}

	private void UpdateVolume()
	{
		currentSong.Volume = currentMusicVolume * globalMusicVolume.Value / 100f;
	}

	private FileInfo[] SearchForAudioFiles(string path)
	{
		DirectoryInfo directoryInfo = new DirectoryInfo(path);
		if (directoryInfo.Exists)
		{
			return (from f in directoryInfo.GetFiles()
				where Path.GetExtension(f.Name) == ".mp3" || Path.GetExtension(f.Name) == ".wav"
				select f).ToArray();
		}
		return new FileInfo[0];
	}

	private string GetAttribute(XmlNode node, string attribute)
	{
		if (node.Attributes != null)
		{
			XmlNode namedItem = node.Attributes.GetNamedItem(attribute);
			if (namedItem != null)
			{
				return namedItem.Value;
			}
		}
		return "";
	}

	private bool sceneMostlyMatches(string[] scenes)
	{
		foreach (string value in scenes)
		{
			if (currentScene.Contains(value))
			{
				return true;
			}
		}
		return false;
	}

	public void PickOutMusic(bool isForTeleporter = false)
	{
		Music[] array = musics.Where(delegate(Music music3)
		{
			bool flag = sceneMostlyMatches(music3.scenes);
			bool flag2 = playanimamusic;
			bool flag3 = isForTeleporter == music3.boss;
			bool flag4 = playerhaslooped && storedloopstages != null && storedloopstages.Contains(currentScene);
			bool flag5 = extratracksfrfr;
			bool flag6 = extratracksfrfr && !currentScene.Contains("enemiesreturns_judgementoutro");
			if (simulacrumactive)
			{
				return music3.simulacrum == simulacrumactive && flag && music3.fullName != null;
			}
			return afterBossPhase ? (music3.afterboss && flag && music3.postloopvariant == flag4 && music3.isextratrack == flag6 && music3.fullName != null) : (music3.fullName != null && flag3 && flag && music3.postloopvariant == flag4 && music3.isextratrack == flag5 && music3.soulboundboss == flag2 && !music3.afterboss && !music3.simulacrum);
		}).ToArray();
		Debug.Log((object)"====== Selecting Music ======");
		Debug.Log((object)("Current Scene: " + currentScene));
		Debug.Log((object)("Is For Teleporter: " + isForTeleporter));
		Debug.Log((object)"Choices: ");
		Music[] array2 = array;
		foreach (Music music in array2)
		{
			Debug.Log((object)music.name);
		}
		Debug.Log((object)"");
		string fullName = currentSongFullName;
		Music music2 = null;
		int num2 = 0;
		if (array.Length != 0)
		{
			while (fullName == currentSongFullName && num2 < 10)
			{
				switch (randomizationmode)
				{
				case randomizationmodelist.off:
					music2 = array[listtracker % array.Length];
					fullName = music2.fullName;
					num2++;
					listtracker++;
					break;
				case randomizationmodelist.shuffle:
					music2 = array[rnd.Next(array.Length)];
					fullName = music2.fullName;
					num2++;
					hasshuffled = true;
					break;
				case randomizationmodelist.shuffleonce:
					if (!hasshuffled)
					{
						listtracker = rnd.Next(array.Length);
						music2 = array[listtracker % array.Length];
						fullName = music2.fullName;
						num2++;
						hasshuffled = true;
					}
					else
					{
						music2 = array[listtracker % array.Length];
						fullName = music2.fullName;
						num2++;
						listtracker++;
					}
					break;
				}
			}
			((MonoBehaviour)this).StartCoroutine((IEnumerator)PlayMusic(fullName, music2.volume));
		}
		else
		{
			Debug.Log((object)"======= MUSIC PICK FAILED! =======");
			Debug.Log((object)"choosing random song...");
			num2 = 0;
			while (fullName == currentSongFullName && num2 < 10)
			{
				fullName = soundFiles[rnd.Next(soundFiles.Length)].FullName;
				num2++;
			}
			((MonoBehaviour)this).StartCoroutine((IEnumerator)PlayMusic(fullName));
		}
	}

	private IEnumerator<WaitForSeconds> PlayMusic(string file, float volume = 1f)
	{
		currentMusicVolume = volume;
		if (file != currentSongFullName)
		{
			currentSongFullName = file;
			if ((int)outputDevice.PlaybackState == 1)
			{
				fader.BeginFadeOut(1500.0);
				yield return new WaitForSeconds(1.5f);
				outputDevice.Stop();
				currentSong = null;
			}
			currentSong = new AudioFileReader(file);
			UpdateVolume();
			LoopStream looper = new LoopStream(shouldLoop: musics.First((Music m) => m.fullName == file).loop, sourceStream: (WaveStream)(object)currentSong);
			fader = new FadeInOutSampleProvider((ISampleProvider)new WaveToSampleProvider((IWaveProvider)(object)looper), false);
			WaveExtensionMethods.Init((IWavePlayer)(object)outputDevice, (ISampleProvider)(object)fader, false);
			Debug.Log((object)("====== Now Playing: " + file));
			if (EnableMetaData.Value && (Object)(object)Run.instance != (Object)null)
			{
				DisplayMetaData(file);
			}
			outputDevice.Play();
			songPaused = false;
		}
		else
		{
			Debug.Log((object)("PlayMusic: Already playing: " + file));
		}
	}

	private void DisplayMetaData(string file)
	{
		try
		{
			File val = File.Create(file);
			try
			{
				string text = string.Join(", ", val.Tag.Performers);
				string text2 = val.Tag.Title;
				if (!(text2 == lasttitle))
				{
					if (string.IsNullOrEmpty(text))
					{
						text = "???";
					}
					if (string.IsNullOrEmpty(text2))
					{
						text2 = "unknown song";
					}
					Chat.AddMessage("<style=cWorldEvent>♬ Currently Playing: " + text + " - " + text2 + " ♬</style>");
					lasttitle = text2;
				}
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
		}
		catch (Exception ex)
		{
			Debug.Log((object)"OSTMODPLUS failed to display song metadata oopsie doopsie");
			Debug.Log((object)ex);
		}
	}

	public void Update()
	{
		if (oldMusicVolume == "" && (Object)(object)Console.instance != (Object)null)
		{
			BaseConVar val = Console.instance.FindConVar("volume_music");
			if (val != null)
			{
				oldMusicVolume = val.GetString();
				val.SetString("0");
			}
		}
	}

	private void FixedUpdate()
	{
		if (currentSong != null && ((Stream)(object)currentSong).Position >= ((Stream)(object)currentSong).Length && !shouldLoop)
		{
			outputDevice.Stop();
			((Stream)(object)currentSong).Position = ((Stream)(object)currentSong).Length - 1;
			PickOutMusic(bossActive);
		}
	}

	private void OnDestroy()
	{
		BaseConVar val = Console.instance.FindConVar("volume_music");
		if (val != null)
		{
			val.SetString(oldMusicVolume);
		}
	}
}

TagLibSharp.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using System.Xml;
using Microsoft.CodeAnalysis;
using TagLib.Aac;
using TagLib.Aiff;
using TagLib.Ape;
using TagLib.Asf;
using TagLib.Audible;
using TagLib.Dsf;
using TagLib.Flac;
using TagLib.Gif;
using TagLib.IFD;
using TagLib.IFD.Entries;
using TagLib.IFD.Makernotes;
using TagLib.IFD.Tags;
using TagLib.IIM;
using TagLib.Id3v1;
using TagLib.Id3v2;
using TagLib.Image;
using TagLib.Image.NoMetadata;
using TagLib.Jpeg;
using TagLib.Matroska;
using TagLib.Mpeg;
using TagLib.Mpeg4;
using TagLib.MusePack;
using TagLib.NonContainer;
using TagLib.Ogg;
using TagLib.Ogg.Codecs;
using TagLib.Png;
using TagLib.Riff;
using TagLib.Tiff;
using TagLib.Tiff.Arw;
using TagLib.Tiff.Cr2;
using TagLib.Tiff.Dng;
using TagLib.Tiff.Nef;
using TagLib.Tiff.Pef;
using TagLib.Tiff.Rw2;
using TagLib.WavPack;
using TagLib.Xmp;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Brian Nickel, Gabriel Burt, Stephen Shaw, etc")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2006-2007 Brian Nickel.  Copyright (c) 2009-2020 Other contributors")]
[assembly: AssemblyDescription("A library for for reading and writing metadata in media files, including video, audio, and photo formats.")]
[assembly: AssemblyFileVersion("2.3.0.0")]
[assembly: AssemblyInformationalVersion("2.3.0.0")]
[assembly: AssemblyProduct("TagLib#")]
[assembly: AssemblyTitle("TagLibSharp")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/mono/taglib-sharp")]
[assembly: AssemblyVersion("2.3.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
}
namespace TagLib
{
	public enum StringType
	{
		Latin1,
		UTF16,
		UTF16BE,
		UTF8,
		UTF16LE
	}
	public class ByteVector : IList<byte>, ICollection<byte>, IEnumerable<byte>, IEnumerable, IComparable<ByteVector>
	{
		private static readonly uint[] crc_table = new uint[256]
		{
			0u, 79764919u, 159529838u, 222504665u, 319059676u, 398814059u, 445009330u, 507990021u, 638119352u, 583659535u,
			797628118u, 726387553u, 890018660u, 835552979u, 1015980042u, 944750013u, 1276238704u, 1221641927u, 1167319070u, 1095957929u,
			1595256236u, 1540665371u, 1452775106u, 1381403509u, 1780037320u, 1859660671u, 1671105958u, 1733955601u, 2031960084u, 2111593891u,
			1889500026u, 1952343757u, 2552477408u, 2632100695u, 2443283854u, 2506133561u, 2334638140u, 2414271883u, 2191915858u, 2254759653u,
			3190512472u, 3135915759u, 3081330742u, 3009969537u, 2905550212u, 2850959411u, 2762807018u, 2691435357u, 3560074640u, 3505614887u,
			3719321342u, 3648080713u, 3342211916u, 3287746299u, 3467911202u, 3396681109u, 4063920168u, 4143685023u, 4223187782u, 4286162673u,
			3779000052u, 3858754371u, 3904687514u, 3967668269u, 881225847u, 809987520u, 1023691545u, 969234094u, 662832811u, 591600412u,
			771767749u, 717299826u, 311336399u, 374308984u, 453813921u, 533576470u, 25881363u, 88864420u, 134795389u, 214552010u,
			2023205639u, 2086057648u, 1897238633u, 1976864222u, 1804852699u, 1867694188u, 1645340341u, 1724971778u, 1587496639u, 1516133128u,
			1461550545u, 1406951526u, 1302016099u, 1230646740u, 1142491917u, 1087903418u, 2896545431u, 2825181984u, 2770861561u, 2716262478u,
			3215044683u, 3143675388u, 3055782693u, 3001194130u, 2326604591u, 2389456536u, 2200899649u, 2280525302u, 2578013683u, 2640855108u,
			2418763421u, 2498394922u, 3769900519u, 3832873040u, 3912640137u, 3992402750u, 4088425275u, 4151408268u, 4197601365u, 4277358050u,
			3334271071u, 3263032808u, 3476998961u, 3422541446u, 3585640067u, 3514407732u, 3694837229u, 3640369242u, 1762451694u, 1842216281u,
			1619975040u, 1682949687u, 2047383090u, 2127137669u, 1938468188u, 2001449195u, 1325665622u, 1271206113u, 1183200824u, 1111960463u,
			1543535498u, 1489069629u, 1434599652u, 1363369299u, 622672798u, 568075817u, 748617968u, 677256519u, 907627842u, 853037301u,
			1067152940u, 995781531u, 51762726u, 131386257u, 177728840u, 240578815u, 269590778u, 349224269u, 429104020u, 491947555u,
			4046411278u, 4126034873u, 4172115296u, 4234965207u, 3794477266u, 3874110821u, 3953728444u, 4016571915u, 3609705398u, 3555108353u,
			3735388376u, 3664026991u, 3290680682u, 3236090077u, 3449943556u, 3378572211u, 3174993278u, 3120533705u, 3032266256u, 2961025959u,
			2923101090u, 2868635157u, 2813903052u, 2742672763u, 2604032198u, 2683796849u, 2461293480u, 2524268063u, 2284983834u, 2364738477u,
			2175806836u, 2238787779u, 1569362073u, 1498123566u, 1409854455u, 1355396672u, 1317987909u, 1246755826u, 1192025387u, 1137557660u,
			2072149281u, 2135122070u, 1912620623u, 1992383480u, 1753615357u, 1816598090u, 1627664531u, 1707420964u, 295390185u, 358241886u,
			404320391u, 483945776u, 43990325u, 106832002u, 186451547u, 266083308u, 932423249u, 861060070u, 1041341759u, 986742920u,
			613929101u, 542559546u, 756411363u, 701822548u, 3316196985u, 3244833742u, 3425377559u, 3370778784u, 3601682597u, 3530312978u,
			3744426955u, 3689838204u, 3819031489u, 3881883254u, 3928223919u, 4007849240u, 4037393693u, 4100235434u, 4180117107u, 4259748804u,
			2310601993u, 2373574846u, 2151335527u, 2231098320u, 2596047829u, 2659030626u, 2470359227u, 2550115596u, 2947551409u, 2876312838u,
			2788305887u, 2733848168u, 3165939309u, 3094707162u, 3040238851u, 2985771188u
		};

		private static bool use_broken_latin1;

		private static readonly ReadOnlyByteVector td1 = new ReadOnlyByteVector(1);

		private static readonly ReadOnlyByteVector td2 = new ReadOnlyByteVector(2);

		private static Encoding last_utf16_encoding = Encoding.Unicode;

		private readonly List<byte> data = new List<byte>();

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

		public bool IsEmpty => data.Count == 0;

		public uint Checksum
		{
			get
			{
				uint num = 0u;
				foreach (byte datum in data)
				{
					num = (num << 8) ^ crc_table[((num >> 24) & 0xFF) ^ datum];
				}
				return num;
			}
		}

		public static bool UseBrokenLatin1Behavior
		{
			get
			{
				return use_broken_latin1;
			}
			set
			{
				use_broken_latin1 = value;
			}
		}

		public int Count => data.Count;

		public bool IsSynchronized => false;

		public object SyncRoot => this;

		public virtual bool IsReadOnly => false;

		public virtual bool IsFixedSize => false;

		public byte this[int index]
		{
			get
			{
				return data[index];
			}
			set
			{
				if (IsReadOnly)
				{
					throw new NotSupportedException("Cannot edit readonly objects.");
				}
				data[index] = value;
			}
		}

		public ByteVector()
		{
		}

		public ByteVector(ByteVector vector)
		{
			if (vector != null)
			{
				data.AddRange(vector);
			}
		}

		public ByteVector(params byte[] data)
		{
			if (data != null)
			{
				this.data.AddRange(data);
			}
		}

		public ByteVector(byte[] data, int length)
		{
			if (length > data.Length)
			{
				throw new ArgumentOutOfRangeException("length", "Length exceeds size of data.");
			}
			if (length < 0)
			{
				throw new ArgumentOutOfRangeException("length", "Length is less than zero.");
			}
			if (length == data.Length)
			{
				this.data.AddRange(data);
				return;
			}
			byte[] array = new byte[length];
			Array.Copy(data, 0, array, 0, length);
			this.data.AddRange(array);
		}

		public ByteVector(int size)
			: this(size, 0)
		{
		}

		public ByteVector(int size, byte value)
		{
			if (size < 0)
			{
				throw new ArgumentOutOfRangeException("size", "Size is less than zero.");
			}
			if (size != 0)
			{
				byte[] array = new byte[size];
				for (int i = 0; i < size; i++)
				{
					array[i] = value;
				}
				data.AddRange(array);
			}
		}

		public ByteVector Mid(int startIndex, int length)
		{
			if (startIndex < 0 || startIndex > Count)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (length < 0 || startIndex + length > Count)
			{
				throw new ArgumentOutOfRangeException("length");
			}
			if (length == 0)
			{
				return new ByteVector();
			}
			if (startIndex + length > data.Count)
			{
				length = data.Count - startIndex;
			}
			byte[] array = new byte[length];
			data.CopyTo(startIndex, array, 0, length);
			return array;
		}

		public ByteVector Mid(int index)
		{
			return Mid(index, Count - index);
		}

		public int Find(ByteVector pattern, int offset, int byteAlign)
		{
			if (pattern == null)
			{
				throw new ArgumentNullException("pattern");
			}
			if (offset < 0)
			{
				throw new ArgumentOutOfRangeException("offset", "offset must be at least 0.");
			}
			if (byteAlign < 1)
			{
				throw new ArgumentOutOfRangeException("byteAlign", "byteAlign must be at least 1.");
			}
			if (pattern.Count > Count - offset)
			{
				return -1;
			}
			if (pattern.Count == 1)
			{
				byte b = pattern[0];
				for (int i = offset; i < data.Count; i += byteAlign)
				{
					if (data[i] == b)
					{
						return i;
					}
				}
				return -1;
			}
			int[] array = new int[256];
			for (int j = 0; j < 256; j++)
			{
				array[j] = pattern.Count;
			}
			for (int k = 0; k < pattern.Count - 1; k++)
			{
				array[pattern[k]] = pattern.Count - k - 1;
			}
			for (int l = pattern.Count - 1 + offset; l < data.Count; l += array[data[l]])
			{
				int num = l;
				int num2 = pattern.Count - 1;
				while (num2 >= 0 && data[num] == pattern[num2])
				{
					num--;
					num2--;
				}
				if (-1 == num2 && (num + 1 - offset) % byteAlign == 0)
				{
					return num + 1;
				}
			}
			return -1;
		}

		public int Find(ByteVector pattern, int offset)
		{
			return Find(pattern, offset, 1);
		}

		public int Find(ByteVector pattern)
		{
			return Find(pattern, 0, 1);
		}

		public int RFind(ByteVector pattern, int offset, int byteAlign)
		{
			if (pattern == null)
			{
				throw new ArgumentNullException("pattern");
			}
			if (offset < 0)
			{
				throw new ArgumentOutOfRangeException("offset");
			}
			if (pattern.Count == 0 || pattern.Count > Count - offset)
			{
				return -1;
			}
			if (pattern.Count == 1)
			{
				byte b = pattern[0];
				for (int num = Count - offset - 1; num >= 0; num -= byteAlign)
				{
					if (data[num] == b)
					{
						return num;
					}
				}
				return -1;
			}
			int[] array = new int[256];
			for (int i = 0; i < 256; i++)
			{
				array[i] = pattern.Count;
			}
			for (int num2 = pattern.Count - 1; num2 > 0; num2--)
			{
				array[pattern[num2]] = num2;
			}
			for (int num3 = Count - offset - pattern.Count; num3 >= 0; num3 -= array[data[num3]])
			{
				if ((offset - num3) % byteAlign == 0 && ContainsAt(pattern, num3))
				{
					return num3;
				}
			}
			return -1;
		}

		public int RFind(ByteVector pattern, int offset)
		{
			return RFind(pattern, offset, 1);
		}

		public int RFind(ByteVector pattern)
		{
			return RFind(pattern, 0, 1);
		}

		public bool ContainsAt(ByteVector pattern, int offset, int patternOffset, int patternLength)
		{
			if (pattern == null)
			{
				throw new ArgumentNullException("pattern");
			}
			if (pattern.Count < patternLength)
			{
				patternLength = pattern.Count;
			}
			if (patternLength > data.Count || offset >= data.Count || patternOffset >= pattern.Count || patternLength <= 0 || offset < 0)
			{
				return false;
			}
			for (int i = 0; i < patternLength - patternOffset; i++)
			{
				if (data[i + offset] != pattern[i + patternOffset])
				{
					return false;
				}
			}
			return true;
		}

		public bool ContainsAt(ByteVector pattern, int offset, int patternOffset)
		{
			return ContainsAt(pattern, offset, patternOffset, int.MaxValue);
		}

		public bool ContainsAt(ByteVector pattern, int offset)
		{
			return ContainsAt(pattern, offset, 0);
		}

		public bool StartsWith(ByteVector pattern)
		{
			return ContainsAt(pattern, 0);
		}

		public bool EndsWith(ByteVector pattern)
		{
			if (pattern == null)
			{
				throw new ArgumentNullException("pattern");
			}
			return ContainsAt(pattern, data.Count - pattern.Count);
		}

		public int EndsWithPartialMatch(ByteVector pattern)
		{
			if (pattern == null)
			{
				throw new ArgumentNullException("pattern");
			}
			if (pattern.Count > data.Count)
			{
				return -1;
			}
			int num = data.Count - pattern.Count;
			for (int i = 1; i < pattern.Count; i++)
			{
				if (ContainsAt(pattern, num + i, 0, pattern.Count - i))
				{
					return num + i;
				}
			}
			return -1;
		}

		public void Add(ByteVector data)
		{
			if (IsReadOnly)
			{
				throw new NotSupportedException("Cannot edit readonly objects.");
			}
			if (data != null)
			{
				this.data.AddRange(data);
			}
		}

		public void Add(byte[] data)
		{
			if (IsReadOnly)
			{
				throw new NotSupportedException("Cannot edit readonly objects.");
			}
			if (data != null)
			{
				this.data.AddRange(data);
			}
		}

		public void Insert(int index, ByteVector data)
		{
			if (IsReadOnly)
			{
				throw new NotSupportedException("Cannot edit readonly objects.");
			}
			if (data != null)
			{
				this.data.InsertRange(index, data);
			}
		}

		public void Insert(int index, byte[] data)
		{
			if (IsReadOnly)
			{
				throw new NotSupportedException("Cannot edit readonly objects.");
			}
			if (data != null)
			{
				this.data.InsertRange(index, data);
			}
		}

		public ByteVector Resize(int size, byte padding)
		{
			if (IsReadOnly)
			{
				throw new NotSupportedException("Cannot edit readonly objects.");
			}
			if (data.Count > size)
			{
				data.RemoveRange(size, data.Count - size);
			}
			while (data.Count < size)
			{
				data.Add(padding);
			}
			return this;
		}

		public ByteVector Resize(int size)
		{
			return Resize(size, 0);
		}

		public void RemoveRange(int index, int count)
		{
			if (IsReadOnly)
			{
				throw new NotSupportedException("Cannot edit readonly objects.");
			}
			data.RemoveRange(index, count);
		}

		public int ToInt(bool mostSignificantByteFirst)
		{
			int num = 0;
			int num2 = ((Count > 4) ? 3 : (Count - 1));
			for (int i = 0; i <= num2; i++)
			{
				int num3 = (mostSignificantByteFirst ? (num2 - i) : i);
				num |= this[i] << num3 * 8;
			}
			return num;
		}

		public int ToInt()
		{
			return ToInt(mostSignificantByteFirst: true);
		}

		public uint ToUInt(bool mostSignificantByteFirst)
		{
			uint num = 0u;
			int num2 = ((Count > 4) ? 3 : (Count - 1));
			for (int i = 0; i <= num2; i++)
			{
				int num3 = (mostSignificantByteFirst ? (num2 - i) : i);
				num |= (uint)(this[i] << num3 * 8);
			}
			return num;
		}

		public uint ToUInt()
		{
			return ToUInt(mostSignificantByteFirst: true);
		}

		public short ToShort(bool mostSignificantByteFirst)
		{
			short num = 0;
			int num2 = ((Count > 2) ? 1 : (Count - 1));
			for (int i = 0; i <= num2; i++)
			{
				int num3 = (mostSignificantByteFirst ? (num2 - i) : i);
				num |= (short)(this[i] << num3 * 8);
			}
			return num;
		}

		public short ToShort()
		{
			return ToShort(mostSignificantByteFirst: true);
		}

		public ushort ToUShort(bool mostSignificantByteFirst)
		{
			ushort num = 0;
			int num2 = ((Count > 2) ? 1 : (Count - 1));
			for (int i = 0; i <= num2; i++)
			{
				int num3 = (mostSignificantByteFirst ? (num2 - i) : i);
				num |= (ushort)(this[i] << num3 * 8);
			}
			return num;
		}

		public ushort ToUShort()
		{
			return ToUShort(mostSignificantByteFirst: true);
		}

		public long ToLong(bool mostSignificantByteFirst)
		{
			long num = 0L;
			int num2 = ((Count > 8) ? 7 : (Count - 1));
			for (int i = 0; i <= num2; i++)
			{
				int num3 = (mostSignificantByteFirst ? (num2 - i) : i);
				num |= (long)((ulong)this[i] << num3 * 8);
			}
			return num;
		}

		public long ToLong()
		{
			return ToLong(mostSignificantByteFirst: true);
		}

		public ulong ToULong(bool mostSignificantByteFirst)
		{
			ulong num = 0uL;
			int num2 = ((Count > 8) ? 7 : (Count - 1));
			for (int i = 0; i <= num2; i++)
			{
				int num3 = (mostSignificantByteFirst ? (num2 - i) : i);
				num |= (ulong)this[i] << num3 * 8;
			}
			return num;
		}

		public ulong ToULong()
		{
			return ToULong(mostSignificantByteFirst: true);
		}

		public float ToFloat(bool mostSignificantByteFirst)
		{
			byte[] array = (byte[])Data.Clone();
			if (mostSignificantByteFirst)
			{
				Array.Reverse((Array)array);
			}
			return BitConverter.ToSingle(array, 0);
		}

		public float ToFloat()
		{
			return ToFloat(mostSignificantByteFirst: true);
		}

		public double ToDouble(bool mostSignificantByteFirst)
		{
			byte[] array = (byte[])Data.Clone();
			if (mostSignificantByteFirst)
			{
				Array.Reverse((Array)array);
			}
			return BitConverter.ToDouble(array, 0);
		}

		public double ToDouble()
		{
			return ToDouble(mostSignificantByteFirst: true);
		}

		public double ToExtendedPrecision()
		{
			int num = ((this[0] & 0x7F) << 8) | this[1];
			ulong num2 = ((ulong)this[2] << 24) | ((ulong)this[3] << 16) | ((ulong)this[4] << 8) | this[5];
			ulong num3 = ((ulong)this[6] << 24) | ((ulong)this[7] << 16) | ((ulong)this[8] << 8) | this[9];
			double num4;
			if (num == 0 && num2 == 0L && num3 == 0L)
			{
				num4 = 0.0;
			}
			else if (num == 32767)
			{
				num4 = double.PositiveInfinity;
			}
			else
			{
				num -= 16383;
				num4 = (double)num2 * Math.Pow(2.0, num -= 31);
				num4 += (double)num3 * Math.Pow(2.0, num -= 32);
			}
			if ((this[0] & 0x80) == 0)
			{
				return num4;
			}
			return 0.0 - num4;
		}

		public string ToString(StringType type, int offset, int count)
		{
			if (offset < 0 || offset > Count)
			{
				throw new ArgumentOutOfRangeException("offset");
			}
			if (count < 0 || count + offset > Count)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			ByteVector bom = ((type == StringType.UTF16 && data.Count - offset > 1) ? Mid(offset, 2) : null);
			string @string = StringTypeToEncoding(type, bom).GetString(Data, offset, count);
			if (@string.Length != 0 && (@string[0] == '\ufffe' || @string[0] == '\ufeff'))
			{
				return @string.Substring(1);
			}
			return @string;
		}

		[Obsolete("Use ToString(StringType,int,int)")]
		public string ToString(StringType type, int offset)
		{
			return ToString(type, offset, Count - offset);
		}

		public string ToString(StringType type)
		{
			return ToString(type, 0, Count);
		}

		public override string ToString()
		{
			return ToString(StringType.UTF8, 0, Count);
		}

		public string[] ToStrings(StringType type, int offset)
		{
			return ToStrings(type, offset, int.MaxValue);
		}

		public string[] ToStrings(StringType type, int offset, int count)
		{
			int num = 0;
			int num2 = offset;
			List<string> list = new List<string>();
			ByteVector byteVector = TextDelimiter(type);
			int count2 = byteVector.Count;
			while (num < count && num2 < Count)
			{
				int num3 = num2;
				if (num + 1 == count)
				{
					num2 = offset + count;
				}
				else
				{
					num2 = Find(byteVector, num3, count2);
					if (num2 < 0)
					{
						num2 = Count;
					}
				}
				int num4 = num2 - num3;
				if (num4 == 0)
				{
					list.Add(string.Empty);
				}
				else
				{
					string text = ToString(type, num3, num4);
					if (text.Length != 0 && (text[0] == '\ufffe' || text[0] == '\ufeff'))
					{
						text = text.Substring(1);
					}
					list.Add(text);
				}
				num2 += count2;
			}
			return list.ToArray();
		}

		public static bool operator ==(ByteVector first, ByteVector second)
		{
			bool flag = (object)first == null;
			bool flag2 = (object)second == null;
			if (flag && flag2)
			{
				return true;
			}
			if (flag || flag2)
			{
				return false;
			}
			return first.Equals(second);
		}

		public static bool operator !=(ByteVector first, ByteVector second)
		{
			return !(first == second);
		}

		public static bool operator <(ByteVector first, ByteVector second)
		{
			if (first == null)
			{
				throw new ArgumentNullException("first");
			}
			if (second == null)
			{
				throw new ArgumentNullException("second");
			}
			return first.CompareTo(second) < 0;
		}

		public static bool operator <=(ByteVector first, ByteVector second)
		{
			if (first == null)
			{
				throw new ArgumentNullException("first");
			}
			if (second == null)
			{
				throw new ArgumentNullException("second");
			}
			return first.CompareTo(second) <= 0;
		}

		public static bool operator >(ByteVector first, ByteVector second)
		{
			if (first == null)
			{
				throw new ArgumentNullException("first");
			}
			if (second == null)
			{
				throw new ArgumentNullException("second");
			}
			return first.CompareTo(second) > 0;
		}

		public static bool operator >=(ByteVector first, ByteVector second)
		{
			if (first == null)
			{
				throw new ArgumentNullException("first");
			}
			if (second == null)
			{
				throw new ArgumentNullException("second");
			}
			return first.CompareTo(second) >= 0;
		}

		public static ByteVector operator +(ByteVector first, ByteVector second)
		{
			return new ByteVector(first) { second };
		}

		public static implicit operator ByteVector(byte value)
		{
			return new ByteVector(value);
		}

		public static implicit operator ByteVector(byte[] value)
		{
			return new ByteVector(value);
		}

		public static implicit operator ByteVector(string value)
		{
			return FromString(value, StringType.UTF8);
		}

		public static ByteVector FromInt(int value, bool mostSignificantByteFirst)
		{
			ByteVector byteVector = new ByteVector();
			for (int i = 0; i < 4; i++)
			{
				int num = (mostSignificantByteFirst ? (3 - i) : i);
				byteVector.Add((byte)((uint)(value >> num * 8) & 0xFFu));
			}
			return byteVector;
		}

		public static ByteVector FromInt(int value)
		{
			return FromInt(value, mostSignificantByteFirst: true);
		}

		public static ByteVector FromUInt(uint value, bool mostSignificantByteFirst)
		{
			ByteVector byteVector = new ByteVector();
			for (int i = 0; i < 4; i++)
			{
				int num = (mostSignificantByteFirst ? (3 - i) : i);
				byteVector.Add((byte)((value >> num * 8) & 0xFFu));
			}
			return byteVector;
		}

		public static ByteVector FromUInt(uint value)
		{
			return FromUInt(value, mostSignificantByteFirst: true);
		}

		public static ByteVector FromShort(short value, bool mostSignificantByteFirst)
		{
			ByteVector byteVector = new ByteVector();
			for (int i = 0; i < 2; i++)
			{
				int num = (mostSignificantByteFirst ? (1 - i) : i);
				byteVector.Add((byte)((uint)(value >> num * 8) & 0xFFu));
			}
			return byteVector;
		}

		public static ByteVector FromShort(short value)
		{
			return FromShort(value, mostSignificantByteFirst: true);
		}

		public static ByteVector FromUShort(ushort value, bool mostSignificantByteFirst)
		{
			ByteVector byteVector = new ByteVector();
			for (int i = 0; i < 2; i++)
			{
				int num = (mostSignificantByteFirst ? (1 - i) : i);
				byteVector.Add((byte)((uint)(value >> num * 8) & 0xFFu));
			}
			return byteVector;
		}

		public static ByteVector FromUShort(ushort value)
		{
			return FromUShort(value, mostSignificantByteFirst: true);
		}

		public static ByteVector FromLong(long value, bool mostSignificantByteFirst)
		{
			ByteVector byteVector = new ByteVector();
			for (int i = 0; i < 8; i++)
			{
				int num = (mostSignificantByteFirst ? (7 - i) : i);
				byteVector.Add((byte)((value >> num * 8) & 0xFF));
			}
			return byteVector;
		}

		public static ByteVector FromLong(long value)
		{
			return FromLong(value, mostSignificantByteFirst: true);
		}

		public static ByteVector FromULong(ulong value, bool mostSignificantByteFirst)
		{
			ByteVector byteVector = new ByteVector();
			for (int i = 0; i < 8; i++)
			{
				int num = (mostSignificantByteFirst ? (7 - i) : i);
				byteVector.Add((byte)((value >> num * 8) & 0xFF));
			}
			return byteVector;
		}

		public static ByteVector FromULong(ulong value)
		{
			return FromULong(value, mostSignificantByteFirst: true);
		}

		public static ByteVector FromString(string text, StringType type, int length)
		{
			ByteVector byteVector = new ByteVector();
			if (type == StringType.UTF16)
			{
				byteVector.Add(new byte[2] { 255, 254 });
			}
			if (text == null || text.Length == 0)
			{
				return byteVector;
			}
			if (text.Length > length)
			{
				text = text.Substring(0, length);
			}
			byteVector.Add(StringTypeToEncoding(type, byteVector).GetBytes(text));
			return byteVector;
		}

		public static ByteVector FromString(string text, StringType type)
		{
			return FromString(text, type, int.MaxValue);
		}

		public static ByteVector FromString(string text, int length)
		{
			return FromString(text, StringType.UTF8, length);
		}

		[Obsolete("Use FromString(string,StringType)")]
		public static ByteVector FromString(string text)
		{
			return FromString(text, StringType.UTF8);
		}

		public static ByteVector FromPath(string path)
		{
			byte[] firstChunk;
			return FromPath(path, out firstChunk, copyFirstChunk: false);
		}

		internal static ByteVector FromPath(string path, out byte[] firstChunk, bool copyFirstChunk)
		{
			if (path == null)
			{
				throw new ArgumentNullException("path");
			}
			return FromFile(new File.LocalFileAbstraction(path), out firstChunk, copyFirstChunk);
		}

		public static ByteVector FromFile(File.IFileAbstraction abstraction)
		{
			byte[] firstChunk;
			return FromFile(abstraction, out firstChunk, copyFirstChunk: false);
		}

		internal static ByteVector FromFile(File.IFileAbstraction abstraction, out byte[] firstChunk, bool copyFirstChunk)
		{
			if (abstraction == null)
			{
				throw new ArgumentNullException("abstraction");
			}
			Stream readStream = abstraction.ReadStream;
			ByteVector result = FromStream(readStream, out firstChunk, copyFirstChunk);
			abstraction.CloseStream(readStream);
			return result;
		}

		public static ByteVector FromStream(Stream stream)
		{
			byte[] firstChunk;
			return FromStream(stream, out firstChunk, copyFirstChunk: false);
		}

		internal static ByteVector FromStream(Stream stream, out byte[] firstChunk, bool copyFirstChunk)
		{
			ByteVector byteVector = new ByteVector();
			byte[] array = new byte[4096];
			int num = array.Length;
			int num2 = 0;
			bool flag = false;
			firstChunk = null;
			int num3;
			do
			{
				Array.Clear(array, 0, array.Length);
				num3 = stream.Read(array, 0, num);
				byteVector.Add(array);
				num2 += num3;
				if (flag)
				{
					continue;
				}
				if (copyFirstChunk)
				{
					if (firstChunk == null || firstChunk.Length != num)
					{
						firstChunk = new byte[num];
					}
					Array.Copy(array, 0, firstChunk, 0, num3);
				}
				flag = true;
			}
			while ((num2 != stream.Length || stream.Length <= 0) && (num3 >= num || stream.Length > 0));
			if (stream.Length > 0 && byteVector.Count != stream.Length)
			{
				byteVector.Resize((int)stream.Length);
			}
			return byteVector;
		}

		public static ByteVector TextDelimiter(StringType type)
		{
			if (type != StringType.UTF16 && type != StringType.UTF16BE && type != StringType.UTF16LE)
			{
				return td1;
			}
			return td2;
		}

		private static Encoding StringTypeToEncoding(StringType type, ByteVector bom)
		{
			switch (type)
			{
			case StringType.UTF16:
				if (bom == null)
				{
					return last_utf16_encoding;
				}
				if (bom[0] == byte.MaxValue && bom[1] == 254)
				{
					return last_utf16_encoding = Encoding.Unicode;
				}
				if (bom[1] == byte.MaxValue && bom[0] == 254)
				{
					return last_utf16_encoding = Encoding.BigEndianUnicode;
				}
				return last_utf16_encoding;
			case StringType.UTF16BE:
				return Encoding.BigEndianUnicode;
			case StringType.UTF8:
				return Encoding.UTF8;
			case StringType.UTF16LE:
				return Encoding.Unicode;
			default:
				if (use_broken_latin1)
				{
					return Encoding.Default;
				}
				try
				{
					return Encoding.GetEncoding("latin1");
				}
				catch (ArgumentException)
				{
					return Encoding.UTF8;
				}
			}
		}

		public override bool Equals(object other)
		{
			if (!(other is ByteVector))
			{
				return false;
			}
			return Equals((ByteVector)other);
		}

		public bool Equals(ByteVector other)
		{
			return CompareTo(other) == 0;
		}

		public override int GetHashCode()
		{
			return (int)Checksum;
		}

		public int CompareTo(ByteVector other)
		{
			if ((object)other == null)
			{
				throw new ArgumentNullException("other");
			}
			int num = Count - other.Count;
			int num2 = 0;
			while (num == 0 && num2 < Count)
			{
				num = this[num2] - other[num2];
				num2++;
			}
			return num;
		}

		public IEnumerator<byte> GetEnumerator()
		{
			return data.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return data.GetEnumerator();
		}

		public void Clear()
		{
			if (IsReadOnly)
			{
				throw new NotSupportedException("Cannot edit readonly objects.");
			}
			data.Clear();
		}

		public void Add(byte item)
		{
			if (IsReadOnly)
			{
				throw new NotSupportedException("Cannot edit readonly objects.");
			}
			data.Add(item);
		}

		public bool Remove(byte item)
		{
			if (IsReadOnly)
			{
				throw new NotSupportedException("Cannot edit readonly objects.");
			}
			return data.Remove(item);
		}

		public void CopyTo(byte[] array, int arrayIndex)
		{
			data.CopyTo(array, arrayIndex);
		}

		public bool Contains(byte item)
		{
			return data.Contains(item);
		}

		public void RemoveAt(int index)
		{
			if (IsReadOnly)
			{
				throw new NotSupportedException("Cannot edit readonly objects.");
			}
			data.RemoveAt(index);
		}

		public void Insert(int index, byte item)
		{
			if (IsReadOnly)
			{
				throw new NotSupportedException("Cannot edit readonly objects.");
			}
			data.Insert(index, item);
		}

		public int IndexOf(byte item)
		{
			return data.IndexOf(item);
		}
	}
	[ComVisible(false)]
	public class ByteVectorCollection : ListBase<ByteVector>
	{
		public ByteVectorCollection()
		{
		}

		public ByteVectorCollection(IEnumerable<ByteVector> list)
		{
			if (list != null)
			{
				Add(list);
			}
		}

		public ByteVectorCollection(params ByteVector[] list)
		{
			if (list != null)
			{
				Add(list);
			}
		}

		public override void SortedInsert(ByteVector item, bool unique)
		{
			if (item == null)
			{
				throw new ArgumentNullException("item");
			}
			int i;
			for (i = 0; i < base.Count; i++)
			{
				if (item == base[i] && unique)
				{
					return;
				}
				if (item >= base[i])
				{
					break;
				}
			}
			Insert(i + 1, item);
		}

		public ByteVector ToByteVector(ByteVector separator)
		{
			if (separator == null)
			{
				throw new ArgumentNullException("separator");
			}
			ByteVector byteVector = new ByteVector();
			for (int i = 0; i < base.Count; i++)
			{
				if (i != 0 && separator.Count > 0)
				{
					byteVector.Add(separator);
				}
				byteVector.Add(base[i]);
			}
			return byteVector;
		}

		public static ByteVectorCollection Split(ByteVector vector, ByteVector pattern, int byteAlign, int max)
		{
			if (vector == null)
			{
				throw new ArgumentNullException("vector");
			}
			if (pattern == null)
			{
				throw new ArgumentNullException("pattern");
			}
			if (byteAlign < 1)
			{
				throw new ArgumentOutOfRangeException("byteAlign", "byteAlign must be at least 1.");
			}
			ByteVectorCollection byteVectorCollection = new ByteVectorCollection();
			int num = 0;
			int num2 = vector.Find(pattern, 0, byteAlign);
			while (num2 != -1 && (max < 1 || max > byteVectorCollection.Count + 1))
			{
				byteVectorCollection.Add(vector.Mid(num, num2 - num));
				num = num2 + pattern.Count;
				num2 = vector.Find(pattern, num2 + pattern.Count, byteAlign);
			}
			if (num < vector.Count)
			{
				byteVectorCollection.Add(vector.Mid(num, vector.Count - num));
			}
			return byteVectorCollection;
		}

		public static ByteVectorCollection Split(ByteVector vector, ByteVector pattern, int byteAlign)
		{
			return Split(vector, pattern, byteAlign, 0);
		}

		public static ByteVectorCollection Split(ByteVector vector, ByteVector pattern)
		{
			return Split(vector, pattern, 1);
		}
	}
	public class CombinedTag : Tag
	{
		private readonly List<Tag> tags;

		public virtual Tag[] Tags => tags.ToArray();

		public override TagTypes TagTypes
		{
			get
			{
				TagTypes tagTypes = TagTypes.None;
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tagTypes |= tag.TagTypes;
					}
				}
				return tagTypes;
			}
		}

		public override string Title
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string title = tag.Title;
						if (title != null)
						{
							return title;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Title = value;
					}
				}
			}
		}

		public override string Subtitle
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string subtitle = tag.Subtitle;
						if (subtitle != null)
						{
							return subtitle;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Subtitle = value;
					}
				}
			}
		}

		public override string Description
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string description = tag.Description;
						if (description != null)
						{
							return description;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Description = value;
					}
				}
			}
		}

		public override string[] Performers
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string[] performers = tag.Performers;
						if (performers != null && performers.Length != 0)
						{
							return performers;
						}
					}
				}
				return new string[0];
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Performers = value;
					}
				}
			}
		}

		public override string[] PerformersSort
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string[] performersSort = tag.PerformersSort;
						if (performersSort != null && performersSort.Length != 0)
						{
							return performersSort;
						}
					}
				}
				return new string[0];
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.PerformersSort = value;
					}
				}
			}
		}

		public override string[] PerformersRole
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string[] performersRole = tag.PerformersRole;
						if (performersRole != null && performersRole.Length != 0)
						{
							return performersRole;
						}
					}
				}
				return new string[0];
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.PerformersRole = value;
					}
				}
			}
		}

		public override string[] AlbumArtistsSort
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string[] albumArtistsSort = tag.AlbumArtistsSort;
						if (albumArtistsSort != null && albumArtistsSort.Length != 0)
						{
							return albumArtistsSort;
						}
					}
				}
				return new string[0];
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.AlbumArtistsSort = value;
					}
				}
			}
		}

		public override string[] AlbumArtists
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string[] albumArtists = tag.AlbumArtists;
						if (albumArtists != null && albumArtists.Length != 0)
						{
							return albumArtists;
						}
					}
				}
				return new string[0];
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.AlbumArtists = value;
					}
				}
			}
		}

		public override string[] Composers
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string[] composers = tag.Composers;
						if (composers != null && composers.Length != 0)
						{
							return composers;
						}
					}
				}
				return new string[0];
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Composers = value;
					}
				}
			}
		}

		public override string[] ComposersSort
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string[] composersSort = tag.ComposersSort;
						if (composersSort != null && composersSort.Length != 0)
						{
							return composersSort;
						}
					}
				}
				return new string[0];
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.ComposersSort = value;
					}
				}
			}
		}

		public override string TitleSort
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string titleSort = tag.TitleSort;
						if (titleSort != null && titleSort.Length > 0)
						{
							return titleSort;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.TitleSort = value;
					}
				}
			}
		}

		public override string AlbumSort
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string albumSort = tag.AlbumSort;
						if (albumSort != null && albumSort.Length > 0)
						{
							return albumSort;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.AlbumSort = value;
					}
				}
			}
		}

		public override string Album
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string album = tag.Album;
						if (album != null)
						{
							return album;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Album = value;
					}
				}
			}
		}

		public override string Comment
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string comment = tag.Comment;
						if (comment != null)
						{
							return comment;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Comment = value;
					}
				}
			}
		}

		public override string[] Genres
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string[] genres = tag.Genres;
						if (genres != null && genres.Length != 0)
						{
							return genres;
						}
					}
				}
				return new string[0];
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Genres = value;
					}
				}
			}
		}

		public override uint Year
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						uint year = tag.Year;
						if (year != 0)
						{
							return year;
						}
					}
				}
				return 0u;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Year = value;
					}
				}
			}
		}

		public override uint Track
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						uint track = tag.Track;
						if (track != 0)
						{
							return track;
						}
					}
				}
				return 0u;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Track = value;
					}
				}
			}
		}

		public override uint TrackCount
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						uint trackCount = tag.TrackCount;
						if (trackCount != 0)
						{
							return trackCount;
						}
					}
				}
				return 0u;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.TrackCount = value;
					}
				}
			}
		}

		public override uint Disc
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						uint disc = tag.Disc;
						if (disc != 0)
						{
							return disc;
						}
					}
				}
				return 0u;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Disc = value;
					}
				}
			}
		}

		public override uint DiscCount
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						uint discCount = tag.DiscCount;
						if (discCount != 0)
						{
							return discCount;
						}
					}
				}
				return 0u;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.DiscCount = value;
					}
				}
			}
		}

		public override string Lyrics
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string lyrics = tag.Lyrics;
						if (lyrics != null)
						{
							return lyrics;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Lyrics = value;
					}
				}
			}
		}

		public override string Grouping
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string grouping = tag.Grouping;
						if (grouping != null)
						{
							return grouping;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Grouping = value;
					}
				}
			}
		}

		public override uint BeatsPerMinute
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						uint beatsPerMinute = tag.BeatsPerMinute;
						if (beatsPerMinute != 0)
						{
							return beatsPerMinute;
						}
					}
				}
				return 0u;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.BeatsPerMinute = value;
					}
				}
			}
		}

		public override string Conductor
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string conductor = tag.Conductor;
						if (conductor != null)
						{
							return conductor;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Conductor = value;
					}
				}
			}
		}

		public override string Copyright
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string copyright = tag.Copyright;
						if (copyright != null)
						{
							return copyright;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Copyright = value;
					}
				}
			}
		}

		public override DateTime? DateTagged
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						DateTime? dateTagged = tag.DateTagged;
						if (dateTagged.HasValue)
						{
							return dateTagged;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.DateTagged = value;
					}
				}
			}
		}

		public override string MusicBrainzArtistId
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string musicBrainzArtistId = tag.MusicBrainzArtistId;
						if (musicBrainzArtistId != null)
						{
							return musicBrainzArtistId;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.MusicBrainzArtistId = value;
					}
				}
			}
		}

		public override string MusicBrainzReleaseGroupId
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string musicBrainzReleaseGroupId = tag.MusicBrainzReleaseGroupId;
						if (musicBrainzReleaseGroupId != null)
						{
							return musicBrainzReleaseGroupId;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.MusicBrainzReleaseGroupId = value;
					}
				}
			}
		}

		public override string MusicBrainzReleaseId
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string musicBrainzReleaseId = tag.MusicBrainzReleaseId;
						if (musicBrainzReleaseId != null)
						{
							return musicBrainzReleaseId;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.MusicBrainzReleaseId = value;
					}
				}
			}
		}

		public override string MusicBrainzReleaseArtistId
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string musicBrainzReleaseArtistId = tag.MusicBrainzReleaseArtistId;
						if (musicBrainzReleaseArtistId != null)
						{
							return musicBrainzReleaseArtistId;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.MusicBrainzReleaseArtistId = value;
					}
				}
			}
		}

		public override string MusicBrainzTrackId
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string musicBrainzTrackId = tag.MusicBrainzTrackId;
						if (musicBrainzTrackId != null)
						{
							return musicBrainzTrackId;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.MusicBrainzTrackId = value;
					}
				}
			}
		}

		public override string MusicBrainzDiscId
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string musicBrainzDiscId = tag.MusicBrainzDiscId;
						if (musicBrainzDiscId != null)
						{
							return musicBrainzDiscId;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.MusicBrainzDiscId = value;
					}
				}
			}
		}

		public override string MusicIpId
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string musicIpId = tag.MusicIpId;
						if (musicIpId != null)
						{
							return musicIpId;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.MusicIpId = value;
					}
				}
			}
		}

		public override string AmazonId
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string amazonId = tag.AmazonId;
						if (amazonId != null)
						{
							return amazonId;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.AmazonId = value;
					}
				}
			}
		}

		public override string MusicBrainzReleaseStatus
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string musicBrainzReleaseStatus = tag.MusicBrainzReleaseStatus;
						if (musicBrainzReleaseStatus != null)
						{
							return musicBrainzReleaseStatus;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.MusicBrainzReleaseStatus = value;
					}
				}
			}
		}

		public override string MusicBrainzReleaseType
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string musicBrainzReleaseType = tag.MusicBrainzReleaseType;
						if (musicBrainzReleaseType != null)
						{
							return musicBrainzReleaseType;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.MusicBrainzReleaseType = value;
					}
				}
			}
		}

		public override string MusicBrainzReleaseCountry
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string musicBrainzReleaseCountry = tag.MusicBrainzReleaseCountry;
						if (musicBrainzReleaseCountry != null)
						{
							return musicBrainzReleaseCountry;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.MusicBrainzReleaseCountry = value;
					}
				}
			}
		}

		public override IPicture[] Pictures
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						IPicture[] pictures = tag.Pictures;
						if (pictures != null && pictures.Length != 0)
						{
							return pictures;
						}
					}
				}
				return base.Pictures;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Pictures = value;
					}
				}
			}
		}

		public override double ReplayGainTrackGain
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						double replayGainTrackGain = tag.ReplayGainTrackGain;
						if (!double.IsNaN(replayGainTrackGain))
						{
							return replayGainTrackGain;
						}
					}
				}
				return double.NaN;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.ReplayGainTrackGain = value;
					}
				}
			}
		}

		public override double ReplayGainTrackPeak
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						double replayGainTrackPeak = tag.ReplayGainTrackPeak;
						if (!double.IsNaN(replayGainTrackPeak))
						{
							return replayGainTrackPeak;
						}
					}
				}
				return double.NaN;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.ReplayGainTrackPeak = value;
					}
				}
			}
		}

		public override double ReplayGainAlbumGain
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						double replayGainAlbumGain = tag.ReplayGainAlbumGain;
						if (!double.IsNaN(replayGainAlbumGain))
						{
							return replayGainAlbumGain;
						}
					}
				}
				return double.NaN;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.ReplayGainAlbumGain = value;
					}
				}
			}
		}

		public override double ReplayGainAlbumPeak
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						double replayGainAlbumPeak = tag.ReplayGainAlbumPeak;
						if (!double.IsNaN(replayGainAlbumPeak))
						{
							return replayGainAlbumPeak;
						}
					}
				}
				return double.NaN;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.ReplayGainAlbumPeak = value;
					}
				}
			}
		}

		public override string InitialKey
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string initialKey = tag.InitialKey;
						if (initialKey != null)
						{
							return initialKey;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.InitialKey = value;
					}
				}
			}
		}

		public override string RemixedBy
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string remixedBy = tag.RemixedBy;
						if (remixedBy != null)
						{
							return remixedBy;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.RemixedBy = value;
					}
				}
			}
		}

		public override string Publisher
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string publisher = tag.Publisher;
						if (publisher != null)
						{
							return publisher;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Publisher = value;
					}
				}
			}
		}

		public override string ISRC
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string iSRC = tag.ISRC;
						if (iSRC != null)
						{
							return iSRC;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.ISRC = value;
					}
				}
			}
		}

		public override string Length
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						string length = tag.Length;
						if (length != null)
						{
							return length;
						}
					}
				}
				return null;
			}
			set
			{
				foreach (Tag tag in tags)
				{
					if (tag != null)
					{
						tag.Length = value;
					}
				}
			}
		}

		public override bool IsEmpty
		{
			get
			{
				foreach (Tag tag in tags)
				{
					if (tag.IsEmpty)
					{
						return true;
					}
				}
				return false;
			}
		}

		public CombinedTag()
		{
			tags = new List<Tag>();
		}

		public CombinedTag(params Tag[] tags)
		{
			this.tags = new List<Tag>(tags);
		}

		public void SetTags(params Tag[] tags)
		{
			this.tags.Clear();
			this.tags.AddRange(tags);
		}

		protected void InsertTag(int index, Tag tag)
		{
			tags.Insert(index, tag);
		}

		protected void AddTag(Tag tag)
		{
			tags.Add(tag);
		}

		protected void RemoveTag(Tag tag)
		{
			tags.Remove(tag);
		}

		protected void ClearTags()
		{
			tags.Clear();
		}

		public override void Clear()
		{
			foreach (Tag tag in tags)
			{
				tag.Clear();
			}
		}
	}
	[Serializable]
	public class CorruptFileException : Exception
	{
		public CorruptFileException(string message)
			: base(message)
		{
		}

		public CorruptFileException()
		{
		}

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

		protected CorruptFileException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	internal static class Debugger
	{
		public delegate void DebugMessageSentHandler(string message);

		private struct DebugTimeData
		{
			public TimeSpan time;

			public long occurances;

			public DebugTimeData(TimeSpan time, int occurances)
			{
				this.time = time;
				this.occurances = occurances;
			}
		}

		private static readonly string allowed = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()_+-={}[];:'\",.<>?/\\|";

		private static readonly Dictionary<object, Dictionary<object, DebugTimeData>> debug_times = new Dictionary<object, Dictionary<object, DebugTimeData>>();

		public static event DebugMessageSentHandler DebugMessageSent;

		public static void Debug(string message)
		{
			Debugger.DebugMessageSent?.Invoke(message);
		}

		public static void DumpHex(ByteVector data)
		{
			DumpHex(data.Data);
		}

		public static void DumpHex(byte[] data)
		{
			int num = 16;
			int num2 = data.Length / num + ((data.Length % num != 0) ? 1 : 0);
			for (int i = 0; i < num2; i++)
			{
				for (int j = 0; j < num; j++)
				{
					if (i == num2 - 1 && data.Length % num != 0 && j >= data.Length % num)
					{
						Console.Write("   ");
					}
					else
					{
						Console.Write(" {0:x2}", data[i * num + j]);
					}
				}
				Console.Write(" | ");
				for (int k = 0; k < num; k++)
				{
					if (i == num2 - 1 && data.Length % num != 0 && k >= data.Length % num)
					{
						Console.Write(" ");
					}
					else
					{
						WriteByte2(data[i * num + k]);
					}
				}
				Console.WriteLine();
			}
			Console.WriteLine();
		}

		private static void WriteByte2(byte data)
		{
			string text = allowed;
			foreach (char c in text)
			{
				if (c == data)
				{
					Console.Write(c);
					return;
				}
			}
			Console.Write(".");
		}

		public static void AddDebugTime(object o1, object o2, DateTime start)
		{
			DebugTimeData value = new DebugTimeData(DateTime.Now - start, 1);
			if (debug_times.ContainsKey(o1) && debug_times[o1].ContainsKey(o2))
			{
				value.time += debug_times[o1][o2].time;
				value.occurances += debug_times[o1][o2].occurances;
			}
			if (!debug_times.ContainsKey(o1))
			{
				debug_times.Add(o1, new Dictionary<object, DebugTimeData>());
			}
			if (!debug_times[o1].ContainsKey(o2))
			{
				debug_times[o1].Add(o2, value);
			}
			else
			{
				debug_times[o1][o2] = value;
			}
		}

		public static void DumpDebugTime(object o1)
		{
			Console.WriteLine(o1.ToString());
			if (!debug_times.ContainsKey(o1))
			{
				return;
			}
			foreach (KeyValuePair<object, DebugTimeData> item in debug_times[o1])
			{
				Console.WriteLine("  {0}", item.Key);
				Console.WriteLine("    Objects: {0}", item.Value.time);
				Console.WriteLine("    Total:   {0}", item.Value.occurances);
				Console.WriteLine("    Average: {0}", new TimeSpan(item.Value.time.Ticks / item.Value.occurances));
				Console.WriteLine();
			}
			debug_times.Remove(o1);
		}
	}
	[Flags]
	public enum ReadStyle
	{
		None = 0,
		Average = 2,
		PictureLazy = 4
	}
	public abstract class File : IDisposable
	{
		public enum AccessMode
		{
			Read,
			Write,
			Closed
		}

		public delegate File FileTypeResolver(IFileAbstraction abstraction, string mimetype, ReadStyle style);

		public class LocalFileAbstraction : IFileAbstraction
		{
			private readonly string name;

			public string Name => name;

			public Stream ReadStream => System.IO.File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read);

			public Stream WriteStream => System.IO.File.Open(Name, FileMode.Open, FileAccess.ReadWrite);

			public LocalFileAbstraction(string path)
			{
				if (path == null)
				{
					throw new ArgumentNullException("path");
				}
				name = path;
			}

			public void CloseStream(Stream stream)
			{
				if (stream == null)
				{
					throw new ArgumentNullException("stream");
				}
				stream.Close();
			}
		}

		public interface IFileAbstraction
		{
			string Name { get; }

			Stream ReadStream { get; }

			Stream WriteStream { get; }

			void CloseStream(Stream stream);
		}

		private Stream file_stream;

		protected IFileAbstraction file_abstraction;

		private static readonly int buffer_size = 1024;

		private static readonly List<FileTypeResolver> file_type_resolvers = new List<FileTypeResolver>();

		private List<string> corruption_reasons;

		public static uint BufferSize => (uint)buffer_size;

		public abstract Tag Tag { get; }

		public abstract Properties Properties { get; }

		public TagTypes TagTypesOnDisk { get; protected set; }

		public TagTypes TagTypes => Tag?.TagTypes ?? TagTypes.None;

		public string Name => file_abstraction.Name;

		public string MimeType { get; internal set; }

		public long Tell
		{
			get
			{
				if (Mode != AccessMode.Closed)
				{
					return file_stream.Position;
				}
				return 0L;
			}
		}

		public long Length
		{
			get
			{
				if (Mode != AccessMode.Closed)
				{
					return file_stream.Length;
				}
				return 0L;
			}
		}

		public long InvariantStartPosition { get; protected set; } = -1L;


		public long InvariantEndPosition { get; protected set; } = -1L;


		public AccessMode Mode
		{
			get
			{
				if (file_stream == null)
				{
					return AccessMode.Closed;
				}
				if (file_stream.CanWrite)
				{
					return AccessMode.Write;
				}
				return AccessMode.Read;
			}
			set
			{
				if (Mode != value && (Mode != AccessMode.Write || value != 0))
				{
					if (file_stream != null)
					{
						file_abstraction.CloseStream(file_stream);
					}
					file_stream = null;
					switch (value)
					{
					case AccessMode.Read:
						file_stream = file_abstraction.ReadStream;
						break;
					case AccessMode.Write:
						file_stream = file_abstraction.WriteStream;
						break;
					}
					Mode = value;
				}
			}
		}

		public IFileAbstraction FileAbstraction => file_abstraction;

		public virtual bool Writeable => !PossiblyCorrupt;

		public bool PossiblyCorrupt => corruption_reasons != null;

		public IEnumerable<string> CorruptionReasons => corruption_reasons;

		protected File(string path)
		{
			if (path == null)
			{
				throw new ArgumentNullException("path");
			}
			file_abstraction = new LocalFileAbstraction(path);
		}

		protected File(IFileAbstraction abstraction)
		{
			if (abstraction == null)
			{
				throw new ArgumentNullException("abstraction");
			}
			file_abstraction = abstraction;
		}

		internal void MarkAsCorrupt(string reason)
		{
			if (corruption_reasons == null)
			{
				corruption_reasons = new List<string>();
			}
			corruption_reasons.Add(reason);
		}

		public void Dispose()
		{
			Mode = AccessMode.Closed;
		}

		public abstract void Save();

		public abstract void RemoveTags(TagTypes types);

		public abstract Tag GetTag(TagTypes type, bool create);

		public Tag GetTag(TagTypes type)
		{
			return GetTag(type, create: false);
		}

		public ByteVector ReadBlock(int length)
		{
			if (length < 0)
			{
				throw new ArgumentException("Length must be non-negative", "length");
			}
			if (length == 0)
			{
				return new ByteVector();
			}
			Mode = AccessMode.Read;
			byte[] array = new byte[length];
			int num = 0;
			int num2 = 0;
			int num3 = length;
			do
			{
				num = file_stream.Read(array, num2, num3);
				num2 += num;
				num3 -= num;
			}
			while (num3 > 0 && num != 0);
			return new ByteVector(array, num2);
		}

		public void WriteBlock(ByteVector data)
		{
			if (data == null)
			{
				throw new ArgumentNullException("data");
			}
			Mode = AccessMode.Write;
			file_stream.Write(data.Data, 0, data.Count);
		}

		public long Find(ByteVector pattern, long startPosition, ByteVector before)
		{
			if (pattern == null)
			{
				throw new ArgumentNullException("pattern");
			}
			Mode = AccessMode.Read;
			if (pattern.Count > buffer_size)
			{
				return -1L;
			}
			long num = startPosition;
			long position = file_stream.Position;
			try
			{
				file_stream.Position = startPosition;
				ByteVector byteVector = ReadBlock(buffer_size);
				while (byteVector.Count > 0)
				{
					int num2 = byteVector.Find(pattern);
					if (before != null && byteVector.Find(before) < num2)
					{
						return -1L;
					}
					if (num2 >= 0)
					{
						return num + num2;
					}
					num += buffer_size - pattern.Count;
					if (before != null && before.Count > pattern.Count)
					{
						num -= before.Count - pattern.Count;
					}
					file_stream.Position = num;
					byteVector = ReadBlock(buffer_size);
				}
				return -1L;
			}
			finally
			{
				file_stream.Position = position;
			}
		}

		public long Find(ByteVector pattern, long startPosition)
		{
			return Find(pattern, startPosition, null);
		}

		public long Find(ByteVector pattern)
		{
			return Find(pattern, 0L);
		}

		private long RFind(ByteVector pattern, long startPosition, ByteVector after)
		{
			if (pattern == null)
			{
				throw new ArgumentNullException("pattern");
			}
			Mode = AccessMode.Read;
			if (pattern.Count > buffer_size)
			{
				return -1L;
			}
			long position = file_stream.Position;
			long num = Length - startPosition;
			int num2 = buffer_size;
			num2 = (int)Math.Min(num, buffer_size);
			num -= num2;
			file_stream.Position = num;
			ByteVector byteVector = ReadBlock(num2);
			while (byteVector.Count > 0)
			{
				long num3 = byteVector.RFind(pattern);
				if (num3 >= 0)
				{
					file_stream.Position = position;
					return num + num3;
				}
				if (after != null && byteVector.RFind(after) >= 0)
				{
					file_stream.Position = position;
					return -1L;
				}
				num2 = (int)Math.Min(num, buffer_size);
				num -= num2;
				if (num2 + pattern.Count > buffer_size)
				{
					num += pattern.Count;
				}
				file_stream.Position = num;
				byteVector = ReadBlock(num2);
			}
			file_stream.Position = position;
			return -1L;
		}

		public long RFind(ByteVector pattern, long startPosition)
		{
			return RFind(pattern, startPosition, null);
		}

		public long RFind(ByteVector pattern)
		{
			return RFind(pattern, 0L);
		}

		public void Insert(ByteVector data, long start, long replace)
		{
			if (data == null)
			{
				throw new ArgumentNullException("data");
			}
			Insert(data, data.Count, start, replace);
		}

		public void Insert(ByteVector data, long start)
		{
			Insert(data, start, 0L);
		}

		public void Insert(long size, long start)
		{
			Insert(null, size, start, 0L);
		}

		public void RemoveBlock(long start, long length)
		{
			if (length > 0)
			{
				Mode = AccessMode.Write;
				int length2 = buffer_size;
				long num = start + length;
				long num2 = start;
				ByteVector byteVector = (byte)1;
				while (byteVector.Count != 0)
				{
					file_stream.Position = num;
					byteVector = ReadBlock(length2);
					num += byteVector.Count;
					file_stream.Position = num2;
					WriteBlock(byteVector);
					num2 += byteVector.Count;
				}
				Truncate(num2);
			}
		}

		public void Seek(long offset, SeekOrigin origin)
		{
			if (Mode != AccessMode.Closed)
			{
				file_stream.Seek(offset, origin);
			}
		}

		public void Seek(long offset)
		{
			Seek(offset, SeekOrigin.Begin);
		}

		public static File Create(string path)
		{
			return Create(path, null, ReadStyle.Average);
		}

		public static File Create(IFileAbstraction abstraction)
		{
			return Create(abstraction, null, ReadStyle.Average);
		}

		public static File Create(string path, ReadStyle propertiesStyle)
		{
			return Create(path, null, propertiesStyle);
		}

		public static File Create(IFileAbstraction abstraction, ReadStyle propertiesStyle)
		{
			return Create(abstraction, null, propertiesStyle);
		}

		public static File Create(string path, string mimetype, ReadStyle propertiesStyle)
		{
			return Create(new LocalFileAbstraction(path), mimetype, propertiesStyle);
		}

		public static File Create(IFileAbstraction abstraction, string mimetype, ReadStyle propertiesStyle)
		{
			if (mimetype == null)
			{
				string text = string.Empty;
				int num = abstraction.Name.LastIndexOf(".") + 1;
				if (num >= 1 && num < abstraction.Name.Length)
				{
					text = abstraction.Name.Substring(num, abstraction.Name.Length - num);
				}
				mimetype = "taglib/" + text.ToLower(CultureInfo.InvariantCulture);
			}
			foreach (FileTypeResolver file_type_resolver in file_type_resolvers)
			{
				File file = file_type_resolver(abstraction, mimetype, propertiesStyle);
				if (file != null)
				{
					return file;
				}
			}
			if (!FileTypes.AvailableTypes.ContainsKey(mimetype))
			{
				throw new UnsupportedFormatException(string.Format(CultureInfo.InvariantCulture, "{0} ({1})", abstraction.Name, mimetype));
			}
			Type type = FileTypes.AvailableTypes[mimetype];
			try
			{
				File obj = (File)Activator.CreateInstance(type, abstraction, propertiesStyle);
				obj.MimeType = mimetype;
				return obj;
			}
			catch (TargetInvocationException ex)
			{
				PrepareExceptionForRethrow(ex.InnerException);
				throw ex.InnerException;
			}
		}

		public static void AddFileTypeResolver(FileTypeResolver resolver)
		{
			if (resolver != null)
			{
				file_type_resolvers.Insert(0, resolver);
			}
		}

		protected void PreSave()
		{
			if (!Writeable)
			{
				throw new InvalidOperationException("File not writeable.");
			}
			if (PossiblyCorrupt)
			{
				throw new CorruptFileException("Corrupted file cannot be saved.");
			}
			if (Tag?.Pictures == null)
			{
				return;
			}
			IPicture[] pictures = Tag.Pictures;
			for (int i = 0; i < pictures.Length; i++)
			{
				if (pictures[i] is ILazy lazy)
				{
					lazy.Load();
				}
			}
		}

		private void Insert(ByteVector data, long size, long start, long replace)
		{
			Mode = AccessMode.Write;
			if (size == replace)
			{
				if (data != null)
				{
					file_stream.Position = start;
					WriteBlock(data);
				}
				return;
			}
			if (size < replace)
			{
				if (data != null)
				{
					file_stream.Position = start;
					WriteBlock(data);
				}
				RemoveBlock(start + size, replace - size);
				return;
			}
			int num = (int)(size - replace);
			int num2 = num % buffer_size;
			if (num2 != 0)
			{
				num += buffer_size - num2;
			}
			long num3 = start + replace;
			long num4 = start;
			file_stream.Position = num3;
			byte[] data2 = ReadBlock(num).Data;
			num3 += num;
			if (data != null)
			{
				file_stream.Position = num4;
				WriteBlock(data);
			}
			else if (start + size > Length)
			{
				file_stream.SetLength(start + size);
			}
			num4 += size;
			byte[] array = new byte[data2.Length];
			Array.Copy(data2, 0, array, 0, data2.Length);
			while (num != 0)
			{
				file_stream.Position = num3;
				int num5 = file_stream.Read(data2, 0, (num < data2.Length) ? num : data2.Length);
				num3 += num;
				file_stream.Position = num4;
				file_stream.Write(array, 0, (num < array.Length) ? num : array.Length);
				num4 += num;
				Array.Copy(data2, 0, array, 0, num5);
				num = num5;
			}
		}

		protected void Truncate(long length)
		{
			AccessMode mode = Mode;
			Mode = AccessMode.Write;
			file_stream.SetLength(length);
			Mode = mode;
		}

		private static void PrepareExceptionForRethrow(Exception ex)
		{
			StreamingContext context = new StreamingContext(StreamingContextStates.CrossAppDomain);
			ObjectManager objectManager = new ObjectManager(null, context);
			SerializationInfo info = new SerializationInfo(ex.GetType(), new FormatterConverter());
			ex.GetObjectData(info, context);
			objectManager.RegisterObject(ex, 1L, info);
			objectManager.DoFixups();
		}
	}
	public static class FileTypes
	{
		private static Dictionary<string, Type> file_types;

		private static readonly Type[] static_file_types;

		public static IDictionary<string, Type> AvailableTypes => file_types;

		static FileTypes()
		{
			static_file_types = new Type[26]
			{
				typeof(TagLib.Aac.File),
				typeof(TagLib.Aiff.File),
				typeof(TagLib.Ape.File),
				typeof(TagLib.Asf.File),
				typeof(TagLib.Audible.File),
				typeof(TagLib.Dsf.File),
				typeof(TagLib.Flac.File),
				typeof(TagLib.Matroska.File),
				typeof(TagLib.Gif.File),
				typeof(TagLib.Image.NoMetadata.File),
				typeof(TagLib.Jpeg.File),
				typeof(TagLib.Mpeg4.File),
				typeof(AudioFile),
				typeof(TagLib.Mpeg.File),
				typeof(TagLib.MusePack.File),
				typeof(TagLib.Ogg.File),
				typeof(TagLib.Png.File),
				typeof(TagLib.Riff.File),
				typeof(TagLib.Tiff.Arw.File),
				typeof(TagLib.Tiff.Cr2.File),
				typeof(TagLib.Tiff.Dng.File),
				typeof(TagLib.Tiff.File),
				typeof(TagLib.Tiff.Nef.File),
				typeof(TagLib.Tiff.Pef.File),
				typeof(TagLib.Tiff.Rw2.File),
				typeof(TagLib.WavPack.File)
			};
			Init();
		}

		internal static void Init()
		{
			if (file_types == null)
			{
				file_types = new Dictionary<string, Type>();
				Type[] array = static_file_types;
				for (int i = 0; i < array.Length; i++)
				{
					Register(array[i]);
				}
			}
		}

		public static void Register(Type type)
		{
			Attribute[] customAttributes = Attribute.GetCustomAttributes(type, typeof(SupportedMimeType), inherit: false);
			if (customAttributes.Length != 0)
			{
				Attribute[] array = customAttributes;
				for (int i = 0; i < array.Length; i++)
				{
					SupportedMimeType supportedMimeType = (SupportedMimeType)array[i];
					file_types.Add(supportedMimeType.MimeType, type);
				}
			}
		}
	}
	public static class Genres
	{
		private static readonly string[] audio = new string[148]
		{
			"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal",
			"New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial",
			"Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
			"Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
			"Alternative Rock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
			"Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
			"Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychedelic", "Rave", "Showtunes",
			"Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
			"Folk", "Folk/Rock", "National Folk", "Swing", "Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass",
			"Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic",
			"Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove",
			"Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
			"Duet", "Punk Rock", "Drum Solo", "A Cappella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore",
			"Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap", "Heavy Metal", "Black Metal", "Crossover",
			"Contemporary Christian", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "Jpop", "Synthpop"
		};

		private static readonly string[] video = new string[40]
		{
			"Action", "Action/Adventure", "Adult", "Adventure", "Catastrophe", "Child's", "Claymation", "Comedy", "Concert", "Documentary",
			"Drama", "Eastern", "Entertaining", "Erotic", "Extremal Sport", "Fantasy", "Fashion", "Historical", "Horror", "Horror/Mystic",
			"Humor", "Indian", "Informercial", "Melodrama", "Military & War", "Music Video", "Musical", "Mystery", "Nature", "Political Satire",
			"Popular Science", "Psychological Thriller", "Religion", "Science Fiction", "Scifi Action", "Slapstick", "Splatter", "Sports", "Thriller", "Western"
		};

		public static string[] Audio => (string[])audio.Clone();

		public static string[] Video => (string[])video.Clone();

		public static byte AudioToIndex(string name)
		{
			for (byte b = 0; b < audio.Length; b++)
			{
				if (name == audio[b])
				{
					return b;
				}
			}
			return byte.MaxValue;
		}

		public static byte VideoToIndex(string name)
		{
			for (byte b = 0; b < video.Length; b++)
			{
				if (name == video[b])
				{
					return b;
				}
			}
			return byte.MaxValue;
		}

		public static string IndexToAudio(byte index)
		{
			if (index >= audio.Length)
			{
				return null;
			}
			return audio[index];
		}

		public static string IndexToVideo(byte index)
		{
			if (index >= video.Length)
			{
				return null;
			}
			return video[index];
		}

		public static string IndexToAudio(string text)
		{
			return IndexToAudio(StringToByte(text));
		}

		public static string IndexToVideo(string text)
		{
			return IndexToVideo(StringToByte(text));
		}

		private static byte StringToByte(string text)
		{
			int num;
			if (text != null && text.Length > 2 && text[0] == '(' && (num = text.IndexOf(')')) != -1 && byte.TryParse(text.Substring(1, num - 1), out var result))
			{
				return result;
			}
			if (text != null && byte.TryParse(text, out result))
			{
				return result;
			}
			return byte.MaxValue;
		}
	}
	[Flags]
	public enum MediaTypes
	{
		None = 0,
		Audio = 1,
		Video = 2,
		Photo = 4,
		Text = 8
	}
	public interface ICodec
	{
		TimeSpan Duration { get; }

		MediaTypes MediaTypes { get; }

		string Description { get; }
	}
	public interface IAudioCodec : ICodec
	{
		int AudioBitrate { get; }

		int AudioSampleRate { get; }

		int AudioChannels { get; }
	}
	public interface ILosslessAudioCodec
	{
		int BitsPerSample { get; }
	}
	public interface IVideoCodec : ICodec
	{
		int VideoWidth { get; }

		int VideoHeight { get; }
	}
	public interface IPhotoCodec : ICodec
	{
		int PhotoWidth { get; }

		int PhotoHeight { get; }

		int PhotoQuality { get; }
	}
	public interface ILazy
	{
		bool IsLoaded { get; }

		void Load();
	}
	public class ListBase<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable where T : IComparable<T>
	{
		private readonly List<T> data = new List<T>();

		public bool IsEmpty => Count == 0;

		public bool IsReadOnly => false;

		public bool IsFixedSize => false;

		public T this[int index]
		{
			get
			{
				return data[index];
			}
			set
			{
				data[index] = value;
			}
		}

		public int Count => data.Count;

		public bool IsSynchronized => false;

		public object SyncRoot => this;

		public ListBase()
		{
		}

		public ListBase(ListBase<T> list)
		{
			if (list != null)
			{
				Add(list);
			}
		}

		public ListBase(params T[] list)
		{
			if (list != null)
			{
				Add(list);
			}
		}

		public void Add(ListBase<T> list)
		{
			if (list != null)
			{
				data.AddRange(list);
			}
		}

		public void Add(IEnumerable<T> list)
		{
			if (list != null)
			{
				data.AddRange(list);
			}
		}

		public void Add(T[] list)
		{
			if (list != null)
			{
				data.AddRange(list);
			}
		}

		public virtual void SortedInsert(T item, bool unique)
		{
			if (item == null)
			{
				throw new ArgumentNullException("item");
			}
			int i;
			for (i = 0; i < data.Count; i++)
			{
				if (item.CompareTo(data[i]) == 0 && unique)
				{
					return;
				}
				if (item.CompareTo(data[i]) <= 0)
				{
					break;
				}
			}
			Insert(i, item);
		}

		public void SortedInsert(T item)
		{
			if (item == null)
			{
				throw new ArgumentNullException("item");
			}
			SortedInsert(item, unique: false);
		}

		public T[] ToArray()
		{
			return data.ToArray();
		}

		public void Add(T item)
		{
			data.Add(item);
		}

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

		public bool Contains(T item)
		{
			return data.Contains(item);
		}

		public int IndexOf(T item)
		{
			return data.IndexOf(item);
		}

		public void Insert(int index, T item)
		{
			data.Insert(index, item);
		}

		public bool Remove(T item)
		{
			return data.Remove(item);
		}

		public void RemoveAt(int index)
		{
			data.RemoveAt(index);
		}

		public string ToString(string separator)
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < Count; i++)
			{
				if (i != 0)
				{
					stringBuilder.Append(separator);
				}
				stringBuilder.Append(this[i]);
			}
			return stringBuilder.ToString();
		}

		public override string ToString()
		{
			return ToString(", ");
		}

		public void CopyTo(T[] array, int arrayIndex)
		{
			data.CopyTo(array, arrayIndex);
		}

		public IEnumerator<T> GetEnumerator()
		{
			return data.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return data.GetEnumerator();
		}
	}
	public class TextBox : Box
	{
		private ByteVector data;

		public override ByteVector Data
		{
			get
			{
				return data;
			}
			set
			{
				data = value;
			}
		}

		public TextBox(BoxHeader header, File file, IsoHandlerBox handler)
			: base(header, handler)
		{
			if (file == null)
			{
				throw new ArgumentNullException("file");
			}
			data = LoadData(file);
		}
	}
	public class UrlBox : Box
	{
		private ByteVector data;

		public override ByteVector Data
		{
			get
			{
				return data;
			}
			set
			{
				data = value;
			}
		}

		public UrlBox(BoxHeader header, File file, IsoHandlerBox handler)
			: base(header, handler)
		{
			if (file == null)
			{
				throw new ArgumentNullException("file");
			}
			data = LoadData(file);
		}
	}
	public enum PictureType
	{
		Other = 0,
		FileIcon = 1,
		OtherFileIcon = 2,
		FrontCover = 3,
		BackCover = 4,
		LeafletPage = 5,
		Media = 6,
		LeadArtist = 7,
		Artist = 8,
		Conductor = 9,
		Band = 10,
		Composer = 11,
		Lyricist = 12,
		RecordingLocation = 13,
		DuringRecording = 14,
		DuringPerformance = 15,
		MovieScreenCapture = 16,
		ColoredFish = 17,
		Illustration = 18,
		BandLogo = 19,
		PublisherLogo = 20,
		NotAPicture = 255
	}
	public interface IPicture
	{
		string MimeType { get; set; }

		PictureType Type { get; set; }

		string Filename { get; set; }

		string Description { get; set; }

		ByteVector Data { get; set; }
	}
	public class Picture : IPicture
	{
		private static readonly string[] lutExtensionMime = new string[150]
		{
			"aac", "audio/aac", "abw", "application/x-abiword", "arc", "application/octet-stream", "avi", "video/x-msvideo", "azw", "application/vnd.amazon.ebook",
			"bin", "application/octet-stream", "bmp", "image/bmp", "bmp", "image/x-windows-bmp", "bm", "image/bmp", "bz", "application/x-bzip",
			"bz2", "application/x-bzip2", "csh", "application/x-csh", "css", "text/css", "csv", "text/csv", "doc", "application/msword",
			"eot", "application/vnd.ms-fontobject", "epub", "application/epub+zip", "gif", "image/gif", "htm", "text/html", "html", "text/html",
			"ico", "image/x-icon", "ics", "text/calendar", "jar", "application/java-archive", "jpg", "image/jpeg", "jpeg", "image/jpeg",
			"js", "application/javascript", "json", "application/json", "mid", "audio/midi", "midi", "audio/midi", "mp3", "audio/mpeg",
			"mp1", "audio/mpeg", "mp2", "audio/mpeg", "mpg", "video/mpeg", "mpeg", "video/mpeg", "m4a", "audio/mp4",
			"mp4", "video/mp4", "m4v", "video/mp4", "mpkg", "application/vnd.apple.installer+xml", "odp", "application/vnd.oasis.opendocument.presentation", "ods", "application/vnd.oasis.opendocument.spreadsheet",
			"odt", "application/vnd.oasis.opendocument.text", "oga", "audio/ogg", "ogg", "audio/ogg", "ogx", "application/ogg", "ogv", "video/ogg",
			"otf", "font/otf", "png", "image/png", "pdf", "application/pdf", "ppt", "application/vnd.ms-powerpoint", "rar", "application/x-rar-compressed",
			"rtf", "application/rtf", "sh", "application/x-sh", "svg", "image/svg+xml", "swf", "application/x-shockwave-flash", "tar", "application/x-tar",
			"tif", "image/tiff", "tiff", "image/tiff", "ts", "video/vnd.dlna.mpeg-tts", "ttf", "font/ttf", "vsd", "application/vnd.visio",
			"wav", "audio/x-wav", "weba", "audio/webm", "webm", "video/webm", "webp", "image/webp", "woff", "font/woff",
			"woff2", "font/woff2", "xhtml", "application/xhtml+xml", "xls", "application/vnd.ms", "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xml", "application/xml",
			"xul", "application/vnd.mozilla.xul+xml", "zip", "application/zip", "3gp", "video/3gpp", "3g2", "video/3gpp2", "7z", "application/x-7z-compressed"
		};

		public string MimeType { get; set; }

		public PictureType Type { get; set; }

		public string Filename { get; set; }

		public string Description { get; set; }

		public ByteVector Data { get; set; }

		public Picture()
		{
		}

		public Picture(string path)
		{
			if (path == null)
			{
				throw new ArgumentNullException("path");
			}
			Data = ByteVector.FromPath(path);
			Filename = Path.GetFileName(path);
			Description = Filename;
			MimeType = GetMimeFromExtension(Filename);
			Type = (MimeType.StartsWith("image/") ? PictureType.FrontCover : PictureType.NotAPicture);
		}

		public Picture(File.IFileAbstraction abstraction)
		{
			if (abstraction == null)
			{
				throw new ArgumentNullException("abstraction");
			}
			Data = ByteVector.FromFile(abstraction);
			Filename = abstraction.Name;
			Description = abstraction.Name;
			if (!string.IsNullOrEmpty(Filename) && Filename.Contains("."))
			{
				MimeType = GetMimeFromExtension(Filename);
				Type = (MimeType.StartsWith("image/") ? PictureType.FrontCover : PictureType.NotAPicture);
				return;
			}
			string extensionFromData = GetExtensionFromData(Data);
			MimeType = GetMimeFromExtension(extensionFromData);
			if (extensionFromData != null)
			{
				Type = PictureType.FrontCover;
				Filename = (Description = "cover" + extensionFromData);
			}
			else
			{
				Type = PictureType.NotAPicture;
				Filename = "UnknownType";
			}
		}

		public Picture(ByteVector data)
		{
			if (data == null)
			{
				throw new ArgumentNullException("data");
			}
			Data = new ByteVector(data);
			string extensionFromData = GetExtensionFromData(data);
			MimeType = GetMimeFromExtension(extensionFromData);
			if (extensionFromData != null)
			{
				Type = PictureType.FrontCover;
				Filename = (Description = "cover" + extensionFromData);
			}
			else
			{
				Type = PictureType.NotAPicture;
				Filename = "UnknownType";
			}
		}

		public Picture(IPicture picture)
		{
			MimeType = picture.MimeType;
			Type = picture.Type;
			Filename = picture.Filename;
			Description = picture.Description;
			Data = picture.Data;
		}

		[Obsolete("Use Picture(string filename) constructor instead.")]
		public static Picture CreateFromPath(string filename)
		{
			return new Picture(filename);
		}

		[Obsolete("Use Picture(File.IFileAbstraction abstraction) constructor instead.")]
		public static Picture CreateFromFile(File.IFileAbstraction abstraction)
		{
			return new Picture(abstraction);
		}

		public static string GetExtensionFromData(ByteVector data)
		{
			string result = null;
			if (data.Count >= 4)
			{
				if (data[1] == 80 && data[2] == 78 && data[3] == 71)
				{
					result = ".png";
				}
				else if (data[0] == 71 && data[1] == 73 && data[2] == 70)
				{
					result = ".gif";
				}
				else if (data[0] == 66 && data[1] == 77)
				{
					result = ".bmp";
				}
				else if (data[0] == byte.MaxValue && data[1] == 216 && data[data.Count - 2] == byte.MaxValue && data[data.Count - 1] == 217)
				{
					result = ".jpg";
				}
			}
			return result;
		}

		public static string GetExtensionFromMime(string mime)
		{
			string result = null;
			for (int i = 1; i < lutExtensionMime.Length; i += 2)
			{
				if (lutExtensionMime[i] == mime)
				{
					result = lutExtensionMime[i - 1];
					break;
				}
			}
			return result;
		}

		public static string GetMimeFromExtension(string name)
		{
			string result = "application/octet-stream";
			if (string.IsNullOrEmpty(name))
			{
				return result;
			}
			string extension = Path.GetExtension(name);
			extension = ((!string.IsNullOrEmpty(extension)) ? extension.Substring(1) : name);
			extension = extension.ToLower();
			for (int i = 0; i < lutExtensionMime.Length; i += 2)
			{
				if (lutExtensionMime[i] == extension)
				{
					result = lutExtensionMime[i + 1];
					break;
				}
			}
			return result;
		}
	}
	public class PictureLazy : IPicture, ILazy
	{
		private string mime_type;

		private PictureType type;

		private string filename;

		private ByteVector data;

		private File.IFileAbstraction file;

		private readonly long stream_offset;

		private readonly long stream_size = -1L;

		public string MimeType
		{
			get
			{
				if (mime_type == null)
				{
					Load();
				}
				return mime_type;
			}
			set
			{
				mime_type = value;
			}
		}

		public PictureType Type
		{
			get
			{
				if (type == PictureType.Other && mime_type == null)
				{
					Load();
				}
				return type;
			}
			set
			{
				type = value;
			}
		}

		public string Filename
		{
			get
			{
				if (filename == null)
				{
					Load();
				}
				return filename;
			}
			set
			{
				filename = value;
			}
		}

		public string Description { get; set; }

		public ByteVector Data
		{
			get
			{
				if (data == null)
				{
					Load();
				}
				return data;
			}
			set
			{
				data = value;
			}
		}

		public bool IsLoaded => data != null;

		public PictureLazy()
		{
		}

		public PictureLazy(string path)
		{
			if (path == null)
			{
				throw new ArgumentNullException("path");
			}
			file = new File.LocalFileAbstraction(path);
			filename = Path.GetFileName(path);
			Description = filename;
			mime_type = Picture.GetMimeFromExtension(filename);
			type = (mime_type.StartsWith("image/") ? PictureType.FrontCover : PictureType.NotAPicture);
		}

		public PictureLazy(File.IFileAbstraction abstraction, long offset = 0L, long size = -1L)
		{
			if (abstraction == null)
			{
				throw new ArgumentNullException("abstraction");
			}
			file = abstraction;
			stream_offset = offset;
			stream_size = size;
			filename = abstraction.Name;
			Description = abstraction.Name;
			if (!string.IsNullOrEmpty(filename) && filename.Contains("."))
			{
				mime_type = Picture.GetMimeFromExtension(filename);
				type = (mime_type.StartsWith("image/") ? PictureType.FrontCover : PictureType.NotAPicture);
			}
		}

		public PictureLazy(ByteVector data)
		{
			if (data == null)
			{
				throw new ArgumentNullException("data");
			}
			Data = new ByteVector(data);
			string extensionFromData = Picture.GetExtensionFromData(data);
			MimeType = Picture.GetMimeFromExtension(extensionFromData);
			if (extensionFromData != null)
			{
				type = PictureType.FrontCover;
				filename = (Description = "cover" + extensionFromData);
			}
			else
			{
				type = PictureType.NotAPicture;
				filename = "UnknownType";
			}
		}

		public PictureLazy(IPicture picture)
		{
			mime_type = picture.MimeType;
			type = picture.Type;
			filename = picture.Filename;
			Description = picture.Description;
			data = picture.Data;
		}

		public void Load()
		{
			if (data != null)
			{
				return;
			}
			Stream stream = null;
			try
			{
				if (stream_size == 0L)
				{
					data = new ByteVector();
				}
				else if (stream_size > 0)
				{
					stream = file.ReadStream;
					stream.Seek(stream_offset, SeekOrigin.Begin);
					int num = 0;
					int num2 = 0;
					int num3 = (int)stream_size;
					byte[] buffer = new byte[num3];
					do
					{
						num = stream.Read(buffer, num2, num3);
						num2 += num;
						num3 -= num;
					}
					while (num3 > 0 && num != 0);
					data = new ByteVector(buffer, num2);
				}
				else
				{
					stream = file.ReadStream;
					stream.Seek(stream_offset, SeekOrigin.Begin);
					data = ByteVector.FromStream(stream);
				}
			}
			finally
			{
				if (stream != null && file != null)
				{
					file.CloseStream(stream);
				}
				file = null;
			}
			if (mime_type != null)
			{
				return;
			}
			string extensionFromData = Picture.GetExtensionFromData(data);
			MimeType = Picture.GetMimeFromExtension(extensionFromData);
			if (extensionFromData != null)
			{
				type = PictureType.FrontCover;
				if (filename == null)
				{
					string text2 = (Description = "cover" + extensionFromData);
					filename = text2;
				}
			}
			else
			{
				type = PictureType.NotAPicture;
				if (filename == null)
				{
					filename = "UnknownType";
				}
			}
		}
	}
	public class Properties : IAudioCodec, ICodec, IVideoCodec, IPhotoCodec
	{
		private readonly ICodec[] codecs = new ICodec[0];

		private TimeSpan duration = TimeSpan.Zero;

		public IEnumerable<ICodec> Codecs => codecs;

		public TimeSpan Duration
		{
			get
			{
				TimeSpan timeSpan = duration;
				if (timeSpan != TimeSpan.Zero)
				{
					return timeSpan;
				}
				ICodec[] array = codecs;
				foreach (ICodec codec in array)
				{
					if (codec != null && codec.Duration > timeSpan)
					{
						timeSpan = codec.Duration;
					}
				}
				return timeSpan;
			}
		}

		public MediaTypes MediaTypes
		{
			get
			{
				MediaTypes mediaTypes = MediaTypes.None;
				ICodec[] array = codecs;
				foreach (ICodec codec in array)
				{
					if (codec != null)
					{
						mediaTypes |= codec.MediaTypes;
					}
				}
				return mediaTypes;
			}
		}

		public string Description
		{
			get
			{
				StringBuilder stringBuilder = new StringBuilder();
				ICodec[] array = codecs;
				foreach (ICodec codec in array)
				{
					if (codec != null)
					{
						if (stringBuilder.Length != 0)
						{
							stringBuilder.Append("; ");
						}
						stringBuilder.Append(codec.Description);
					}
				}
				return stringBuilder.ToString();
			}
		}

		public int AudioBitrate
		{
			get
			{
				ICodec[] array = codecs;
				foreach (ICodec codec in array)
				{
					if (codec != null && (codec.MediaTypes & MediaTypes.Audio) != 0 && codec is IAudioCodec audioCodec && audioCodec.AudioBitrate != 0)
					{
						return audioCodec.AudioBitrate;
					}
				}
				return 0;
			}
		}

		public int AudioSampleRate
		{
			get
			{
				ICodec[] array = codecs;
				foreach (ICodec codec in array)
				{
					if (codec != null && (codec.MediaTypes & MediaTypes.Audio) != 0 && codec is IAudioCodec audioCodec && audioCodec.AudioSampleRate != 0)
					{
						return audioCodec.AudioSampleRate;
					}
				}
				return 0;
			}
		}

		public int BitsPerSample
		{
			get
			{
				ICodec[] array = codecs;
				foreach (ICodec codec in array)
				{
					if (codec != null && (codec.MediaTypes & MediaTypes.Audio) != 0 && codec is ILosslessAudioCodec losslessAudioCodec && losslessAudioCodec.BitsPerSample != 0)
					{
						return losslessAudioCodec.BitsPerSample;
					}
				}
				return 0;
			}
		}

		public int AudioChannels
		{
			get
			{
				ICodec[] array = codecs;
				foreach (ICodec codec in array)
				{
					if (codec != null && (codec.MediaTypes & MediaTypes.Audio) != 0 && codec is IAudioCodec audioCodec && audioCodec.AudioChannels != 0)
					{
						return audioCodec.AudioChannels;
					}
				}
				return 0;
			}
		}

		public int VideoWidth
		{
			get
			{
				ICodec[] array = codecs;
				foreach (ICodec codec in array)
				{
					if (codec != null && (codec.MediaTypes & MediaTypes.Video) != 0 && codec is IVideoCodec videoCodec && videoCodec.VideoWidth != 0)
					{
						return videoCodec.VideoWidth;
					}
				}
				return 0;
			}
		}

		public int VideoHeight
		{
			get
			{
				ICodec[] array = codecs;
				foreach (ICodec codec in array)
				{
					if (codec != null && (codec.MediaTypes & MediaTypes.Video) != 0 && codec is IVideoCodec videoCodec && videoCodec.VideoHeight != 0)
					{
						return videoCodec.VideoHeight;
					}
				}
				return 0;
			}
		}

		public int PhotoWidth
		{
			get
			{
				ICodec[] array = codecs;
				foreach (ICodec codec in array)
				{
					if (codec != null && (codec.MediaTypes & MediaTypes.Photo) != 0 && codec is IPhotoCodec photoCodec && photoCodec.PhotoWidth != 0)
					{
						return photoCodec.PhotoWidth;
					}
				}
				return 0;
			}
		}

		public int PhotoHeight
		{
			get
			{
				ICodec[] array = codecs;
				foreach (ICodec codec in array)
				{
					if (codec != null && (codec.MediaTypes & MediaTypes.Photo) != 0 && codec is IPhotoCodec photoCodec && photoCodec.PhotoHeight != 0)
					{
						return photoCodec.PhotoHeight;
					}
				}
				return 0;
			}
		}

		public int PhotoQuality
		{
			get
			{
				ICodec[] array = codecs;
				foreach (ICodec codec in array)
				{
					if (codec != null && (codec.MediaTypes & MediaTypes.Photo) != 0 && codec is IPhotoCodec photoCodec && photoCodec.PhotoQuality != 0)
					{
						return photoCodec.PhotoQuality;
					}
				}
				return 0;
			}
		}

		public Properties()
		{
		}

		public Properties(TimeSpan duration, params ICodec[] codecs)
		{
			this.duration = duration;
			if (codecs != null)
			{
				this.codecs = codecs;
			}
		}

		public Properties(TimeSpan duration, IEnumerable<ICodec> codecs)
		{
			this.duration = duration;
			if (codecs != null)
			{
				this.codecs = new List<ICodec>(codecs).ToArray();
			}
		}
	}
	public sealed class ReadOnlyByteVector : ByteVector
	{
		public override bool IsReadOnly => true;

		public override bool IsFixedSize => true;

		public ReadOnlyByteVector()
		{
		}

		public ReadOnlyByteVector(int size, byte value)
			: base(size, value)
		{
		}

		public ReadOnlyByteVector(int size)
			: this(size, 0)
		{
		}

		public ReadOnlyByteVector(ByteVector vector)
			: base(vector)
		{
		}

		public ReadOnlyByteVector(byte[] data, int length)
			: base(data, length)
		{
		}

		public ReadOnlyByteVector(params byte[] data)
			: base(data)
		{
		}

		public static implicit operator ReadOnlyByteVector(byte value)
		{
			return new ReadOnlyByteVector(value);
		}

		public static implicit operator ReadOnlyByteVector(byte[] value)
		{
			return new ReadOnlyByteVector(value);
		}

		public static implicit operator ReadOnlyByteVector(string value)
		{
			return new ReadOnlyByteVector(ByteVector.FromString(value, StringType.UTF8));
		}
	}
	[ComVisible(false)]
	public class StringCollection : ListBase<string>
	{
		public StringCollection()
		{
		}

		public StringCollection(StringCollection values)
		{
			Add(values);
		}

		public StringCollection(params string[] values)
		{
			Add(values);
		}

		public StringCollection(ByteVectorCollection vectorList, StringType type)
		{
			foreach (ByteVector vector in vectorList)
			{
				Add(vector.ToString(type));
			}
		}

		public StringCollection(ByteVectorCollection vectorList)
			: this(vectorList, StringType.UTF8)
		{
		}

		public static StringCollection Split(string value, string pattern)
		{
			if (value == null)
			{
				throw new ArgumentNullException("value");
			}
			if (pattern == null)
			{
				throw new ArgumentNullException("pattern");
			}
			StringCollection stringCollection = new StringCollection();
			int num = 0;
			int num2 = value.IndexOf(pattern, 0);
			int length = pattern.Length;
			while (num2 != -1)
			{
				stringCollection.Add(value.Substring(num, num2 - num));
				num = num2 + length;
				num2 = value.IndexOf(pattern, num);
			}
			stringCollection.Add(value.Substring(num));
			return stringCollection;
		}
	}
	[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
	public sealed class SupportedMimeType : Attribute
	{
		private static readonly List<SupportedMimeType> mimetypes;

		public string MimeType { get; private set; }

		public string Extension { get; private set; }

		public static IEnumerable<string> AllMimeTypes
		{
			get
			{
				foreach (SupportedMimeType mimetype in mimetypes)
				{
					yield return mimetype.MimeType;
				}
			}
		}

		public static IEnumerable<string> AllExtensions
		{
			get
			{
				foreach (SupportedMimeType mimetype in mimetypes)
				{
					if (mimetype.Extension != null)
					{
						yield return mimetype.Extension;
					}
				}
			}
		}

		static SupportedMimeType()
		{
			mimetypes = new List<SupportedMimeType>();
			FileTypes.Init();
		}

		public SupportedMimeType(string mimetype)
		{
			MimeType = mimetype;
			mimetypes.Add(this);
		}

		public SupportedMimeType(string mimetype, string extension)
			: this(mimetype)
		{
			Extension = extension;
		}
	}
	[Flags]
	public enum TagTypes : uint
	{
		None = 0u,
		Xiph = 1u,
		Id3v1 = 2u,
		Id3v2 = 4u,
		Ape = 8u,
		Apple = 0x10u,
		Asf = 0x20u,
		RiffInfo = 0x40u,
		MovieId = 0x80u,
		DivX = 0x100u,
		FlacMetadata = 0x200u,
		TiffIFD = 0x400u,
		XMP = 0x800u,
		JpegComment = 0x1000u,
		GifComment = 0x2000u,
		Png = 0x4000u,
		IPTCIIM = 0x8000u,
		AudibleMetadata = 0x10000u,
		Matroska = 0x20000u,
		AllTags = uint.MaxValue
	}
	public abstract class Tag
	{
		public abstract TagTypes TagTypes { get; }

		public virtual string Title
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string TitleSort
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string Subtitle
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string Description
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string[] Performers
		{
			get
			{
				return new string[0];
			}
			set
			{
			}
		}

		public virtual string[] PerformersSort
		{
			get
			{
				return new string[0];
			}
			set
			{
			}
		}

		public virtual string[] PerformersRole
		{
			get
			{
				return new string[0];
			}
			set
			{
			}
		}

		public virtual string[] AlbumArtists
		{
			get
			{
				return new string[0];
			}
			set
			{
			}
		}

		public virtual string[] AlbumArtistsSort
		{
			get
			{
				return new string[0];
			}
			set
			{
			}
		}

		public virtual string[] Composers
		{
			get
			{
				return new string[0];
			}
			set
			{
			}
		}

		public virtual string[] ComposersSort
		{
			get
			{
				return new string[0];
			}
			set
			{
			}
		}

		public virtual string Album
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string AlbumSort
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string Comment
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string[] Genres
		{
			get
			{
				return new string[0];
			}
			set
			{
			}
		}

		public virtual uint Year
		{
			get
			{
				return 0u;
			}
			set
			{
			}
		}

		public virtual uint Track
		{
			get
			{
				return 0u;
			}
			set
			{
			}
		}

		public virtual uint TrackCount
		{
			get
			{
				return 0u;
			}
			set
			{
			}
		}

		public virtual uint Disc
		{
			get
			{
				return 0u;
			}
			set
			{
			}
		}

		public virtual uint DiscCount
		{
			get
			{
				return 0u;
			}
			set
			{
			}
		}

		public virtual string Lyrics
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string Grouping
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual uint BeatsPerMinute
		{
			get
			{
				return 0u;
			}
			set
			{
			}
		}

		public virtual string Conductor
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string Copyright
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual DateTime? DateTagged
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string MusicBrainzArtistId
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string MusicBrainzReleaseGroupId
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string MusicBrainzReleaseId
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string MusicBrainzReleaseArtistId
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string MusicBrainzTrackId
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string MusicBrainzDiscId
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string MusicIpId
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string AmazonId
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string MusicBrainzReleaseStatus
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string MusicBrainzReleaseType
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string MusicBrainzReleaseCountry
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual double ReplayGainTrackGain
		{
			get
			{
				return double.NaN;
			}
			set
			{
			}
		}

		public virtual double ReplayGainTrackPeak
		{
			get
			{
				return double.NaN;
			}
			set
			{
			}
		}

		public virtual double ReplayGainAlbumGain
		{
			get
			{
				return double.NaN;
			}
			set
			{
			}
		}

		public virtual double ReplayGainAlbumPeak
		{
			get
			{
				return double.NaN;
			}
			set
			{
			}
		}

		public virtual string InitialKey
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string RemixedBy
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string Publisher
		{
			get
			{
				return null;
			}