Decompiled source of Terraria CalamityOST v1.2.0

NVorbis.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using NVorbis.Ogg;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Andrew Ward")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © Andrew Ward 2018")]
[assembly: AssemblyDescription("A fully managed implementation of a Xiph.org Foundation Ogg Vorbis decoder.")]
[assembly: AssemblyFileVersion("0.8.6.0")]
[assembly: AssemblyInformationalVersion("0.8.6.0")]
[assembly: AssemblyProduct("NVorbis")]
[assembly: AssemblyTitle("NVorbis")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: AssemblyVersion("0.8.6.0")]
namespace NVorbis
{
	internal class BufferedReadStream : Stream
	{
		private const int DEFAULT_INITIAL_SIZE = 32768;

		private const int DEFAULT_MAX_SIZE = 262144;

		private Stream _baseStream;

		private StreamReadBuffer _buffer;

		private long _readPosition;

		private object _localLock = new object();

		private Thread _owningThread;

		private int _lockCount;

		public bool CloseBaseStream { get; set; }

		public bool MinimalRead
		{
			get
			{
				return _buffer.MinimalRead;
			}
			set
			{
				_buffer.MinimalRead = value;
			}
		}

		public int MaxBufferSize
		{
			get
			{
				return _buffer.MaxSize;
			}
			set
			{
				CheckLock();
				_buffer.MaxSize = value;
			}
		}

		public long BufferBaseOffset => _buffer.BaseOffset;

		public int BufferBytesFilled => _buffer.BytesFilled;

		public override bool CanRead => true;

		public override bool CanSeek => true;

		public override bool CanWrite => false;

		public override long Length => _baseStream.Length;

		public override long Position
		{
			get
			{
				return _readPosition;
			}
			set
			{
				Seek(value, SeekOrigin.Begin);
			}
		}

		public BufferedReadStream(Stream baseStream)
			: this(baseStream, 32768, 262144, minimalRead: false)
		{
		}

		public BufferedReadStream(Stream baseStream, bool minimalRead)
			: this(baseStream, 32768, 262144, minimalRead)
		{
		}

		public BufferedReadStream(Stream baseStream, int initialSize, int maxSize)
			: this(baseStream, initialSize, maxSize, minimalRead: false)
		{
		}

		public BufferedReadStream(Stream baseStream, int initialSize, int maxBufferSize, bool minimalRead)
		{
			if (baseStream == null)
			{
				throw new ArgumentNullException("baseStream");
			}
			if (!baseStream.CanRead)
			{
				throw new ArgumentException("baseStream");
			}
			if (maxBufferSize < 1)
			{
				maxBufferSize = 1;
			}
			if (initialSize < 1)
			{
				initialSize = 1;
			}
			if (initialSize > maxBufferSize)
			{
				initialSize = maxBufferSize;
			}
			_baseStream = baseStream;
			_buffer = new StreamReadBuffer(baseStream, initialSize, maxBufferSize, minimalRead);
			_buffer.MaxSize = maxBufferSize;
			_buffer.MinimalRead = minimalRead;
		}

		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);
			if (disposing)
			{
				if (_buffer != null)
				{
					_buffer.Dispose();
					_buffer = null;
				}
				if (CloseBaseStream)
				{
					_baseStream.Close();
				}
			}
		}

		public void TakeLock()
		{
			Monitor.Enter(_localLock);
			if (++_lockCount == 1)
			{
				_owningThread = Thread.CurrentThread;
			}
		}

		private void CheckLock()
		{
			if (_owningThread != Thread.CurrentThread)
			{
				throw new SynchronizationLockException();
			}
		}

		public void ReleaseLock()
		{
			CheckLock();
			if (--_lockCount == 0)
			{
				_owningThread = null;
			}
			Monitor.Exit(_localLock);
		}

		public void Discard(int bytes)
		{
			CheckLock();
			_buffer.DiscardThrough(_buffer.BaseOffset + bytes);
		}

		public void DiscardThrough(long offset)
		{
			CheckLock();
			_buffer.DiscardThrough(offset);
		}

		public override void Flush()
		{
		}

		public override int ReadByte()
		{
			CheckLock();
			int num = _buffer.ReadByte(Position);
			if (num > -1)
			{
				Seek(1L, SeekOrigin.Current);
			}
			return num;
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			CheckLock();
			int num = _buffer.Read(Position, buffer, offset, count);
			Seek(num, SeekOrigin.Current);
			return num;
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			CheckLock();
			switch (origin)
			{
			case SeekOrigin.Current:
				offset += Position;
				break;
			case SeekOrigin.End:
				offset += _baseStream.Length;
				break;
			}
			if (!_baseStream.CanSeek)
			{
				if (offset < _buffer.BaseOffset)
				{
					throw new InvalidOperationException("Cannot seek to before the start of the buffer!");
				}
				if (offset >= _buffer.BufferEndOffset)
				{
					throw new InvalidOperationException("Cannot seek to beyond the end of the buffer!  Discard some bytes.");
				}
			}
			return _readPosition = offset;
		}

		public override void SetLength(long value)
		{
			throw new NotSupportedException();
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			throw new NotSupportedException();
		}
	}
	public abstract class DataPacket
	{
		[Flags]
		protected enum PacketFlags : byte
		{
			IsResync = 1,
			IsEndOfStream = 2,
			IsShort = 4,
			HasGranuleCount = 8,
			User1 = 0x10,
			User2 = 0x20,
			User3 = 0x40,
			User4 = 0x80
		}

		private ulong _bitBucket;

		private int _bitCount;

		private int _readBits;

		private byte _overflowBits;

		private PacketFlags _packetFlags;

		private long _granulePosition;

		private long _pageGranulePosition;

		private int _length;

		private int _granuleCount;

		private int _pageSequenceNumber;

		public bool IsResync
		{
			get
			{
				return GetFlag(PacketFlags.IsResync);
			}
			internal set
			{
				SetFlag(PacketFlags.IsResync, value);
			}
		}

		public long GranulePosition
		{
			get
			{
				return _granulePosition;
			}
			set
			{
				_granulePosition = value;
			}
		}

		public long PageGranulePosition
		{
			get
			{
				return _pageGranulePosition;
			}
			internal set
			{
				_pageGranulePosition = value;
			}
		}

		public int Length
		{
			get
			{
				return _length;
			}
			protected set
			{
				_length = value;
			}
		}

		public bool IsEndOfStream
		{
			get
			{
				return GetFlag(PacketFlags.IsEndOfStream);
			}
			internal set
			{
				SetFlag(PacketFlags.IsEndOfStream, value);
			}
		}

		public long BitsRead => _readBits;

		public int? GranuleCount
		{
			get
			{
				if (GetFlag(PacketFlags.HasGranuleCount))
				{
					return _granuleCount;
				}
				return null;
			}
			set
			{
				if (value.HasValue)
				{
					_granuleCount = value.Value;
					SetFlag(PacketFlags.HasGranuleCount, value: true);
				}
				else
				{
					SetFlag(PacketFlags.HasGranuleCount, value: false);
				}
			}
		}

		internal int PageSequenceNumber
		{
			get
			{
				return _pageSequenceNumber;
			}
			set
			{
				_pageSequenceNumber = value;
			}
		}

		internal bool IsShort
		{
			get
			{
				return GetFlag(PacketFlags.IsShort);
			}
			private set
			{
				SetFlag(PacketFlags.IsShort, value);
			}
		}

		protected bool GetFlag(PacketFlags flag)
		{
			return (_packetFlags & flag) == flag;
		}

		protected void SetFlag(PacketFlags flag, bool value)
		{
			if (value)
			{
				_packetFlags |= flag;
			}
			else
			{
				_packetFlags &= (PacketFlags)(byte)(~(int)flag);
			}
		}

		protected DataPacket(int length)
		{
			Length = length;
		}

		protected abstract int ReadNextByte();

		public virtual void Done()
		{
		}

		public ulong TryPeekBits(int count, out int bitsRead)
		{
			ulong num = 0uL;
			switch (count)
			{
			default:
				throw new ArgumentOutOfRangeException("count");
			case 0:
				bitsRead = 0;
				return 0uL;
			case 1:
			case 2:
			case 3:
			case 4:
			case 5:
			case 6:
			case 7:
			case 8:
			case 9:
			case 10:
			case 11:
			case 12:
			case 13:
			case 14:
			case 15:
			case 16:
			case 17:
			case 18:
			case 19:
			case 20:
			case 21:
			case 22:
			case 23:
			case 24:
			case 25:
			case 26:
			case 27:
			case 28:
			case 29:
			case 30:
			case 31:
			case 32:
			case 33:
			case 34:
			case 35:
			case 36:
			case 37:
			case 38:
			case 39:
			case 40:
			case 41:
			case 42:
			case 43:
			case 44:
			case 45:
			case 46:
			case 47:
			case 48:
			case 49:
			case 50:
			case 51:
			case 52:
			case 53:
			case 54:
			case 55:
			case 56:
			case 57:
			case 58:
			case 59:
			case 60:
			case 61:
			case 62:
			case 63:
			case 64:
				break;
			}
			while (_bitCount < count)
			{
				int num2 = ReadNextByte();
				if (num2 == -1)
				{
					bitsRead = _bitCount;
					num = _bitBucket;
					_bitBucket = 0uL;
					_bitCount = 0;
					IsShort = true;
					return num;
				}
				_bitBucket = (ulong)((long)(num2 & 0xFF) << _bitCount) | _bitBucket;
				_bitCount += 8;
				if (_bitCount > 64)
				{
					_overflowBits = (byte)(num2 >> 72 - _bitCount);
				}
			}
			num = _bitBucket;
			if (count < 64)
			{
				num &= (ulong)((1L << count) - 1);
			}
			bitsRead = count;
			return num;
		}

		public void SkipBits(int count)
		{
			if (count == 0)
			{
				return;
			}
			if (_bitCount > count)
			{
				if (count > 63)
				{
					_bitBucket = 0uL;
				}
				else
				{
					_bitBucket >>= count;
				}
				if (_bitCount > 64)
				{
					int num = _bitCount - 64;
					_bitBucket |= (ulong)_overflowBits << _bitCount - count - num;
					if (num > count)
					{
						_overflowBits = (byte)(_overflowBits >> count);
					}
				}
				_bitCount -= count;
				_readBits += count;
				return;
			}
			if (_bitCount == count)
			{
				_bitBucket = 0uL;
				_bitCount = 0;
				_readBits += count;
				return;
			}
			count -= _bitCount;
			_readBits += _bitCount;
			_bitCount = 0;
			_bitBucket = 0uL;
			while (count > 8)
			{
				if (ReadNextByte() == -1)
				{
					count = 0;
					IsShort = true;
					break;
				}
				count -= 8;
				_readBits += 8;
			}
			if (count > 0)
			{
				int num2 = ReadNextByte();
				if (num2 == -1)
				{
					IsShort = true;
					return;
				}
				_bitBucket = (ulong)(num2 >> count);
				_bitCount = 8 - count;
				_readBits += count;
			}
		}

		protected void ResetBitReader()
		{
			_bitBucket = 0uL;
			_bitCount = 0;
			_readBits = 0;
			IsShort = false;
		}

		public ulong ReadBits(int count)
		{
			if (count == 0)
			{
				return 0uL;
			}
			int bitsRead;
			ulong result = TryPeekBits(count, out bitsRead);
			SkipBits(count);
			return result;
		}

		public byte PeekByte()
		{
			int bitsRead;
			return (byte)TryPeekBits(8, out bitsRead);
		}

		public byte ReadByte()
		{
			return (byte)ReadBits(8);
		}

		public byte[] ReadBytes(int count)
		{
			List<byte> list = new List<byte>(count);
			while (list.Count < count)
			{
				list.Add(ReadByte());
			}
			return list.ToArray();
		}

		public int Read(byte[] buffer, int index, int count)
		{
			if (index < 0 || index + count > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			for (int i = 0; i < count; i++)
			{
				int bitsRead;
				byte b = (byte)TryPeekBits(8, out bitsRead);
				if (bitsRead == 0)
				{
					return i;
				}
				buffer[index++] = b;
				SkipBits(8);
			}
			return count;
		}

		public bool ReadBit()
		{
			return ReadBits(1) == 1;
		}

		public short ReadInt16()
		{
			return (short)ReadBits(16);
		}

		public int ReadInt32()
		{
			return (int)ReadBits(32);
		}

		public long ReadInt64()
		{
			return (long)ReadBits(64);
		}

		public ushort ReadUInt16()
		{
			return (ushort)ReadBits(16);
		}

		public uint ReadUInt32()
		{
			return (uint)ReadBits(32);
		}

		public ulong ReadUInt64()
		{
			return ReadBits(64);
		}

		public void SkipBytes(int count)
		{
			SkipBits(count * 8);
		}
	}
	internal static class Huffman
	{
		private const int MAX_TABLE_BITS = 10;

		internal static List<HuffmanListNode> BuildPrefixedLinkedList(int[] values, int[] lengthList, int[] codeList, out int tableBits, out HuffmanListNode firstOverflowNode)
		{
			HuffmanListNode[] array = new HuffmanListNode[lengthList.Length];
			int num = 0;
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = new HuffmanListNode
				{
					Value = values[i],
					Length = ((lengthList[i] <= 0) ? 99999 : lengthList[i]),
					Bits = codeList[i],
					Mask = (1 << lengthList[i]) - 1
				};
				if (lengthList[i] > 0 && num < lengthList[i])
				{
					num = lengthList[i];
				}
			}
			Array.Sort(array, SortCallback);
			tableBits = ((num > 10) ? 10 : num);
			List<HuffmanListNode> list = new List<HuffmanListNode>(1 << tableBits);
			firstOverflowNode = null;
			for (int j = 0; j < array.Length && array[j].Length < 99999; j++)
			{
				if (firstOverflowNode == null)
				{
					int length = array[j].Length;
					if (length > tableBits)
					{
						firstOverflowNode = array[j];
						continue;
					}
					int num2 = 1 << tableBits - length;
					HuffmanListNode huffmanListNode = array[j];
					for (int k = 0; k < num2; k++)
					{
						int num3 = (k << length) | huffmanListNode.Bits;
						while (list.Count <= num3)
						{
							list.Add(null);
						}
						list[num3] = huffmanListNode;
					}
				}
				else
				{
					array[j - 1].Next = array[j];
				}
			}
			while (list.Count < 1 << tableBits)
			{
				list.Add(null);
			}
			return list;
		}

		private static int SortCallback(HuffmanListNode i1, HuffmanListNode i2)
		{
			int num = i1.Length - i2.Length;
			if (num == 0)
			{
				return i1.Bits - i2.Bits;
			}
			return num;
		}
	}
	internal class HuffmanListNode
	{
		internal int Value;

		internal int Length;

		internal int Bits;

		internal int Mask;

		internal HuffmanListNode Next;
	}
	public interface IContainerReader : IDisposable
	{
		int[] StreamSerials { get; }

		bool CanSeek { get; }

		long WasteBits { get; }

		int PagesRead { get; }

		event EventHandler<NewStreamEventArgs> NewStream;

		bool Init();

		bool FindNextStream();

		int GetTotalPageCount();
	}
	public interface IPacketProvider : IDisposable
	{
		int StreamSerial { get; }

		bool CanSeek { get; }

		long ContainerBits { get; }

		event EventHandler<ParameterChangeEventArgs> ParameterChange;

		int GetTotalPageCount();

		DataPacket GetNextPacket();

		DataPacket PeekNextPacket();

		DataPacket GetPacket(int packetIndex);

		long GetGranuleCount();

		DataPacket FindPacket(long granulePos, Func<DataPacket, DataPacket, int> packetGranuleCountCallback);

		void SeekToPacket(DataPacket packet, int preRoll);
	}
	public interface IVorbisStreamStatus
	{
		int EffectiveBitRate { get; }

		int InstantBitRate { get; }

		TimeSpan PageLatency { get; }

		TimeSpan PacketLatency { get; }

		TimeSpan SecondLatency { get; }

		long OverheadBits { get; }

		long AudioBits { get; }

		int PagesRead { get; }

		int TotalPages { get; }

		bool Clipped { get; }

		void ResetStats();
	}
	internal class Mdct
	{
		private const float M_PI = MathF.PI;

		private static Dictionary<int, Mdct> _setupCache = new Dictionary<int, Mdct>(2);

		private int _n;

		private int _n2;

		private int _n4;

		private int _n8;

		private int _ld;

		private float[] _A;

		private float[] _B;

		private float[] _C;

		private ushort[] _bitrev;

		private Dictionary<int, float[]> _threadLocalBuffers = new Dictionary<int, float[]>(1);

		public static void Reverse(float[] samples, int sampleCount)
		{
			GetSetup(sampleCount).CalcReverse(samples);
		}

		private static Mdct GetSetup(int n)
		{
			lock (_setupCache)
			{
				if (!_setupCache.ContainsKey(n))
				{
					_setupCache[n] = new Mdct(n);
				}
				return _setupCache[n];
			}
		}

		private Mdct(int n)
		{
			_n = n;
			_n2 = n >> 1;
			_n4 = _n2 >> 1;
			_n8 = _n4 >> 1;
			_ld = Utils.ilog(n) - 1;
			_A = new float[_n2];
			_B = new float[_n2];
			_C = new float[_n4];
			int num2;
			int num = (num2 = 0);
			while (num < _n4)
			{
				_A[num2] = (float)Math.Cos((float)(4 * num) * MathF.PI / (float)n);
				_A[num2 + 1] = (float)(0.0 - Math.Sin((float)(4 * num) * MathF.PI / (float)n));
				_B[num2] = (float)Math.Cos((float)(num2 + 1) * MathF.PI / (float)n / 2f) * 0.5f;
				_B[num2 + 1] = (float)Math.Sin((float)(num2 + 1) * MathF.PI / (float)n / 2f) * 0.5f;
				num++;
				num2 += 2;
			}
			num = (num2 = 0);
			while (num < _n8)
			{
				_C[num2] = (float)Math.Cos((float)(2 * (num2 + 1)) * MathF.PI / (float)n);
				_C[num2 + 1] = (float)(0.0 - Math.Sin((float)(2 * (num2 + 1)) * MathF.PI / (float)n));
				num++;
				num2 += 2;
			}
			_bitrev = new ushort[_n8];
			for (int i = 0; i < _n8; i++)
			{
				_bitrev[i] = (ushort)(Utils.BitReverse((uint)i, _ld - 3) << 2);
			}
		}

		private float[] GetBuffer()
		{
			lock (_threadLocalBuffers)
			{
				if (!_threadLocalBuffers.TryGetValue(Thread.CurrentThread.ManagedThreadId, out var value))
				{
					value = (_threadLocalBuffers[Thread.CurrentThread.ManagedThreadId] = new float[_n2]);
				}
				return value;
			}
		}

		private void CalcReverse(float[] buffer)
		{
			float[] buffer2 = GetBuffer();
			int num = _n2 - 2;
			int num2 = 0;
			int i = 0;
			for (int n = _n2; i != n; i += 4)
			{
				buffer2[num + 1] = buffer[i] * _A[num2] - buffer[i + 2] * _A[num2 + 1];
				buffer2[num] = buffer[i] * _A[num2 + 1] + buffer[i + 2] * _A[num2];
				num -= 2;
				num2 += 2;
			}
			i = _n2 - 3;
			while (num >= 0)
			{
				buffer2[num + 1] = (0f - buffer[i + 2]) * _A[num2] - (0f - buffer[i]) * _A[num2 + 1];
				buffer2[num] = (0f - buffer[i + 2]) * _A[num2 + 1] + (0f - buffer[i]) * _A[num2];
				num -= 2;
				num2 += 2;
				i -= 4;
			}
			float[] array = buffer2;
			int num3 = _n2 - 8;
			int num4 = _n4;
			int num5 = 0;
			int num6 = _n4;
			int num7 = 0;
			while (num3 >= 0)
			{
				float num8 = array[num4 + 1] - array[num5 + 1];
				float num9 = array[num4] - array[num5];
				buffer[num6 + 1] = array[num4 + 1] + array[num5 + 1];
				buffer[num6] = array[num4] + array[num5];
				buffer[num7 + 1] = num8 * _A[num3 + 4] - num9 * _A[num3 + 5];
				buffer[num7] = num9 * _A[num3 + 4] + num8 * _A[num3 + 5];
				num8 = array[num4 + 3] - array[num5 + 3];
				num9 = array[num4 + 2] - array[num5 + 2];
				buffer[num6 + 3] = array[num4 + 3] + array[num5 + 3];
				buffer[num6 + 2] = array[num4 + 2] + array[num5 + 2];
				buffer[num7 + 3] = num8 * _A[num3] - num9 * _A[num3 + 1];
				buffer[num7 + 2] = num9 * _A[num3] + num8 * _A[num3 + 1];
				num3 -= 8;
				num6 += 4;
				num7 += 4;
				num4 += 4;
				num5 += 4;
			}
			int n2 = _n >> 4;
			int num10 = _n2 - 1;
			_ = _n4;
			step3_iter0_loop(n2, buffer, num10 - 0, -_n8);
			step3_iter0_loop(_n >> 4, buffer, _n2 - 1 - _n4, -_n8);
			int lim = _n >> 5;
			int num11 = _n2 - 1;
			_ = _n8;
			step3_inner_r_loop(lim, buffer, num11 - 0, -(_n >> 4), 16);
			step3_inner_r_loop(_n >> 5, buffer, _n2 - 1 - _n8, -(_n >> 4), 16);
			step3_inner_r_loop(_n >> 5, buffer, _n2 - 1 - _n8 * 2, -(_n >> 4), 16);
			step3_inner_r_loop(_n >> 5, buffer, _n2 - 1 - _n8 * 3, -(_n >> 4), 16);
			int j;
			for (j = 2; j < _ld - 3 >> 1; j++)
			{
				int num12 = _n >> j + 2;
				int num13 = num12 >> 1;
				int num14 = 1 << j + 1;
				for (int k = 0; k < num14; k++)
				{
					step3_inner_r_loop(_n >> j + 4, buffer, _n2 - 1 - num12 * k, -num13, 1 << j + 3);
				}
			}
			for (; j < _ld - 6; j++)
			{
				int num15 = _n >> j + 2;
				int num16 = 1 << j + 3;
				int num17 = num15 >> 1;
				int num18 = _n >> j + 6;
				int n3 = 1 << j + 1;
				int num19 = _n2 - 1;
				int num20 = 0;
				for (int num21 = num18; num21 > 0; num21--)
				{
					step3_inner_s_loop(n3, buffer, num19, -num17, num20, num16, num15);
					num20 += num16 * 4;
					num19 -= 8;
				}
			}
			step3_inner_s_loop_ld654(_n >> 5, buffer, _n2 - 1, _n);
			int num22 = 0;
			int num23 = _n4 - 4;
			int num24 = _n2 - 4;
			while (num23 >= 0)
			{
				int num25 = _bitrev[num22];
				array[num24 + 3] = buffer[num25];
				array[num24 + 2] = buffer[num25 + 1];
				array[num23 + 3] = buffer[num25 + 2];
				array[num23 + 2] = buffer[num25 + 3];
				num25 = _bitrev[num22 + 1];
				array[num24 + 1] = buffer[num25];
				array[num24] = buffer[num25 + 1];
				array[num23 + 1] = buffer[num25 + 2];
				array[num23] = buffer[num25 + 3];
				num23 -= 4;
				num24 -= 4;
				num22 += 2;
			}
			int num26 = 0;
			int num27 = 0;
			int num28 = _n2 - 4;
			while (num27 < num28)
			{
				float num29 = array[num27] - array[num28 + 2];
				float num30 = array[num27 + 1] + array[num28 + 3];
				float num31 = _C[num26 + 1] * num29 + _C[num26] * num30;
				float num32 = _C[num26 + 1] * num30 - _C[num26] * num29;
				float num33 = array[num27] + array[num28 + 2];
				float num34 = array[num27 + 1] - array[num28 + 3];
				array[num27] = num33 + num31;
				array[num27 + 1] = num34 + num32;
				array[num28 + 2] = num33 - num31;
				array[num28 + 3] = num32 - num34;
				num29 = array[num27 + 2] - array[num28];
				num30 = array[num27 + 3] + array[num28 + 1];
				num31 = _C[num26 + 3] * num29 + _C[num26 + 2] * num30;
				num32 = _C[num26 + 3] * num30 - _C[num26 + 2] * num29;
				num33 = array[num27 + 2] + array[num28];
				num34 = array[num27 + 3] - array[num28 + 1];
				array[num27 + 2] = num33 + num31;
				array[num27 + 3] = num34 + num32;
				array[num28] = num33 - num31;
				array[num28 + 1] = num32 - num34;
				num26 += 4;
				num27 += 4;
				num28 -= 4;
			}
			int num35 = _n2 - 8;
			int num36 = _n2 - 8;
			int num37 = 0;
			int num38 = _n2 - 4;
			int num39 = _n2;
			int num40 = _n - 4;
			while (num36 >= 0)
			{
				float num41 = buffer2[num36 + 6] * _B[num35 + 7] - buffer2[num36 + 7] * _B[num35 + 6];
				float num42 = (0f - buffer2[num36 + 6]) * _B[num35 + 6] - buffer2[num36 + 7] * _B[num35 + 7];
				buffer[num37] = num41;
				buffer[num38 + 3] = 0f - num41;
				buffer[num39] = num42;
				buffer[num40 + 3] = num42;
				float num43 = buffer2[num36 + 4] * _B[num35 + 5] - buffer2[num36 + 5] * _B[num35 + 4];
				float num44 = (0f - buffer2[num36 + 4]) * _B[num35 + 4] - buffer2[num36 + 5] * _B[num35 + 5];
				buffer[num37 + 1] = num43;
				buffer[num38 + 2] = 0f - num43;
				buffer[num39 + 1] = num44;
				buffer[num40 + 2] = num44;
				num41 = buffer2[num36 + 2] * _B[num35 + 3] - buffer2[num36 + 3] * _B[num35 + 2];
				num42 = (0f - buffer2[num36 + 2]) * _B[num35 + 2] - buffer2[num36 + 3] * _B[num35 + 3];
				buffer[num37 + 2] = num41;
				buffer[num38 + 1] = 0f - num41;
				buffer[num39 + 2] = num42;
				buffer[num40 + 1] = num42;
				num43 = buffer2[num36] * _B[num35 + 1] - buffer2[num36 + 1] * _B[num35];
				num44 = (0f - buffer2[num36]) * _B[num35] - buffer2[num36 + 1] * _B[num35 + 1];
				buffer[num37 + 3] = num43;
				buffer[num38] = 0f - num43;
				buffer[num39 + 3] = num44;
				buffer[num40] = num44;
				num35 -= 8;
				num36 -= 8;
				num37 += 4;
				num39 += 4;
				num38 -= 4;
				num40 -= 4;
			}
		}

		private void step3_iter0_loop(int n, float[] e, int i_off, int k_off)
		{
			int num = i_off;
			int num2 = num + k_off;
			int num3 = 0;
			for (int num4 = n >> 2; num4 > 0; num4--)
			{
				float num5 = e[num] - e[num2];
				float num6 = e[num - 1] - e[num2 - 1];
				e[num] += e[num2];
				e[num - 1] += e[num2 - 1];
				e[num2] = num5 * _A[num3] - num6 * _A[num3 + 1];
				e[num2 - 1] = num6 * _A[num3] + num5 * _A[num3 + 1];
				num3 += 8;
				num5 = e[num - 2] - e[num2 - 2];
				num6 = e[num - 3] - e[num2 - 3];
				e[num - 2] += e[num2 - 2];
				e[num - 3] += e[num2 - 3];
				e[num2 - 2] = num5 * _A[num3] - num6 * _A[num3 + 1];
				e[num2 - 3] = num6 * _A[num3] + num5 * _A[num3 + 1];
				num3 += 8;
				num5 = e[num - 4] - e[num2 - 4];
				num6 = e[num - 5] - e[num2 - 5];
				e[num - 4] += e[num2 - 4];
				e[num - 5] += e[num2 - 5];
				e[num2 - 4] = num5 * _A[num3] - num6 * _A[num3 + 1];
				e[num2 - 5] = num6 * _A[num3] + num5 * _A[num3 + 1];
				num3 += 8;
				num5 = e[num - 6] - e[num2 - 6];
				num6 = e[num - 7] - e[num2 - 7];
				e[num - 6] += e[num2 - 6];
				e[num - 7] += e[num2 - 7];
				e[num2 - 6] = num5 * _A[num3] - num6 * _A[num3 + 1];
				e[num2 - 7] = num6 * _A[num3] + num5 * _A[num3 + 1];
				num3 += 8;
				num -= 8;
				num2 -= 8;
			}
		}

		private void step3_inner_r_loop(int lim, float[] e, int d0, int k_off, int k1)
		{
			int num = d0;
			int num2 = num + k_off;
			int num3 = 0;
			for (int num4 = lim >> 2; num4 > 0; num4--)
			{
				float num5 = e[num] - e[num2];
				float num6 = e[num - 1] - e[num2 - 1];
				e[num] += e[num2];
				e[num - 1] += e[num2 - 1];
				e[num2] = num5 * _A[num3] - num6 * _A[num3 + 1];
				e[num2 - 1] = num6 * _A[num3] + num5 * _A[num3 + 1];
				num3 += k1;
				num5 = e[num - 2] - e[num2 - 2];
				num6 = e[num - 3] - e[num2 - 3];
				e[num - 2] += e[num2 - 2];
				e[num - 3] += e[num2 - 3];
				e[num2 - 2] = num5 * _A[num3] - num6 * _A[num3 + 1];
				e[num2 - 3] = num6 * _A[num3] + num5 * _A[num3 + 1];
				num3 += k1;
				num5 = e[num - 4] - e[num2 - 4];
				num6 = e[num - 5] - e[num2 - 5];
				e[num - 4] += e[num2 - 4];
				e[num - 5] += e[num2 - 5];
				e[num2 - 4] = num5 * _A[num3] - num6 * _A[num3 + 1];
				e[num2 - 5] = num6 * _A[num3] + num5 * _A[num3 + 1];
				num3 += k1;
				num5 = e[num - 6] - e[num2 - 6];
				num6 = e[num - 7] - e[num2 - 7];
				e[num - 6] += e[num2 - 6];
				e[num - 7] += e[num2 - 7];
				e[num2 - 6] = num5 * _A[num3] - num6 * _A[num3 + 1];
				e[num2 - 7] = num6 * _A[num3] + num5 * _A[num3 + 1];
				num3 += k1;
				num -= 8;
				num2 -= 8;
			}
		}

		private void step3_inner_s_loop(int n, float[] e, int i_off, int k_off, int a, int a_off, int k0)
		{
			float num = _A[a];
			float num2 = _A[a + 1];
			float num3 = _A[a + a_off];
			float num4 = _A[a + a_off + 1];
			float num5 = _A[a + a_off * 2];
			float num6 = _A[a + a_off * 2 + 1];
			float num7 = _A[a + a_off * 3];
			float num8 = _A[a + a_off * 3 + 1];
			int num9 = i_off;
			int num10 = num9 + k_off;
			for (int num11 = n; num11 > 0; num11--)
			{
				float num12 = e[num9] - e[num10];
				float num13 = e[num9 - 1] - e[num10 - 1];
				e[num9] += e[num10];
				e[num9 - 1] += e[num10 - 1];
				e[num10] = num12 * num - num13 * num2;
				e[num10 - 1] = num13 * num + num12 * num2;
				num12 = e[num9 - 2] - e[num10 - 2];
				num13 = e[num9 - 3] - e[num10 - 3];
				e[num9 - 2] += e[num10 - 2];
				e[num9 - 3] += e[num10 - 3];
				e[num10 - 2] = num12 * num3 - num13 * num4;
				e[num10 - 3] = num13 * num3 + num12 * num4;
				num12 = e[num9 - 4] - e[num10 - 4];
				num13 = e[num9 - 5] - e[num10 - 5];
				e[num9 - 4] += e[num10 - 4];
				e[num9 - 5] += e[num10 - 5];
				e[num10 - 4] = num12 * num5 - num13 * num6;
				e[num10 - 5] = num13 * num5 + num12 * num6;
				num12 = e[num9 - 6] - e[num10 - 6];
				num13 = e[num9 - 7] - e[num10 - 7];
				e[num9 - 6] += e[num10 - 6];
				e[num9 - 7] += e[num10 - 7];
				e[num10 - 6] = num12 * num7 - num13 * num8;
				e[num10 - 7] = num13 * num7 + num12 * num8;
				num9 -= k0;
				num10 -= k0;
			}
		}

		private void step3_inner_s_loop_ld654(int n, float[] e, int i_off, int base_n)
		{
			int num = base_n >> 3;
			float num2 = _A[num];
			int num3 = i_off;
			int num4 = num3 - 16 * n;
			while (num3 > num4)
			{
				float num5 = e[num3] - e[num3 - 8];
				float num6 = e[num3 - 1] - e[num3 - 9];
				e[num3] += e[num3 - 8];
				e[num3 - 1] += e[num3 - 9];
				e[num3 - 8] = num5;
				e[num3 - 9] = num6;
				num5 = e[num3 - 2] - e[num3 - 10];
				num6 = e[num3 - 3] - e[num3 - 11];
				e[num3 - 2] += e[num3 - 10];
				e[num3 - 3] += e[num3 - 11];
				e[num3 - 10] = (num5 + num6) * num2;
				e[num3 - 11] = (num6 - num5) * num2;
				num5 = e[num3 - 12] - e[num3 - 4];
				num6 = e[num3 - 5] - e[num3 - 13];
				e[num3 - 4] += e[num3 - 12];
				e[num3 - 5] += e[num3 - 13];
				e[num3 - 12] = num6;
				e[num3 - 13] = num5;
				num5 = e[num3 - 14] - e[num3 - 6];
				num6 = e[num3 - 7] - e[num3 - 15];
				e[num3 - 6] += e[num3 - 14];
				e[num3 - 7] += e[num3 - 15];
				e[num3 - 14] = (num5 + num6) * num2;
				e[num3 - 15] = (num5 - num6) * num2;
				iter_54(e, num3);
				iter_54(e, num3 - 8);
				num3 -= 16;
			}
		}

		private void iter_54(float[] e, int z)
		{
			float num = e[z] - e[z - 4];
			float num2 = e[z] + e[z - 4];
			float num3 = e[z - 2] + e[z - 6];
			float num4 = e[z - 2] - e[z - 6];
			e[z] = num2 + num3;
			e[z - 2] = num2 - num3;
			float num5 = e[z - 3] - e[z - 7];
			e[z - 4] = num + num5;
			e[z - 6] = num - num5;
			float num6 = e[z - 1] - e[z - 5];
			float num7 = e[z - 1] + e[z - 5];
			float num8 = e[z - 3] + e[z - 7];
			e[z - 1] = num7 + num8;
			e[z - 3] = num7 - num8;
			e[z - 5] = num6 - num4;
			e[z - 7] = num6 + num4;
		}
	}
	[Serializable]
	public class NewStreamEventArgs : EventArgs
	{
		public IPacketProvider PacketProvider { get; private set; }

		public bool IgnoreStream { get; set; }

		public NewStreamEventArgs(IPacketProvider packetProvider)
		{
			if (packetProvider == null)
			{
				throw new ArgumentNullException("packetProvider");
			}
			PacketProvider = packetProvider;
		}
	}
	[Serializable]
	public class ParameterChangeEventArgs : EventArgs
	{
		public DataPacket FirstPacket { get; private set; }

		public ParameterChangeEventArgs(DataPacket firstPacket)
		{
			FirstPacket = firstPacket;
		}
	}
	internal class RingBuffer
	{
		private float[] _buffer;

		private int _start;

		private int _end;

		private int _bufLen;

		internal int Channels;

		internal int Length
		{
			get
			{
				int num = _end - _start;
				if (num < 0)
				{
					num += _bufLen;
				}
				return num;
			}
		}

		internal RingBuffer(int size)
		{
			_buffer = new float[size];
			_start = (_end = 0);
			_bufLen = size;
		}

		internal void EnsureSize(int size)
		{
			size += Channels;
			if (_bufLen < size)
			{
				float[] array = new float[size];
				Array.Copy(_buffer, _start, array, 0, _bufLen - _start);
				if (_end < _start)
				{
					Array.Copy(_buffer, 0, array, _bufLen - _start, _end);
				}
				int length = Length;
				_start = 0;
				_end = length;
				_buffer = array;
				_bufLen = size;
			}
		}

		internal void CopyTo(float[] buffer, int index, int count)
		{
			if (index < 0 || index + count > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			int start = _start;
			RemoveItems(count);
			int num = (_end - start + _bufLen) % _bufLen;
			if (count > num)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			int num2 = Math.Min(count, _bufLen - start);
			Buffer.BlockCopy(_buffer, start * 4, buffer, index * 4, num2 * 4);
			if (num2 < count)
			{
				Buffer.BlockCopy(_buffer, 0, buffer, (index + num2) * 4, (count - num2) * 4);
			}
		}

		internal void RemoveItems(int count)
		{
			int num = (count + _start) % _bufLen;
			if (_end > _start)
			{
				if (num > _end || num < _start)
				{
					throw new ArgumentOutOfRangeException();
				}
			}
			else if (num < _start && num > _end)
			{
				throw new ArgumentOutOfRangeException();
			}
			_start = num;
		}

		internal void Clear()
		{
			_start = (_end = 0);
		}

		internal void Write(int channel, int index, int start, int switchPoint, int end, float[] pcm, float[] window)
		{
			int num;
			for (num = (index + start) * Channels + channel + _start; num >= _bufLen; num -= _bufLen)
			{
			}
			if (num < 0)
			{
				start -= index;
				num = channel;
			}
			while (num < _bufLen && start < switchPoint)
			{
				_buffer[num] += pcm[start] * window[start];
				num += Channels;
				start++;
			}
			if (num >= _bufLen)
			{
				num -= _bufLen;
				while (start < switchPoint)
				{
					_buffer[num] += pcm[start] * window[start];
					num += Channels;
					start++;
				}
			}
			while (num < _bufLen && start < end)
			{
				_buffer[num] = pcm[start] * window[start];
				num += Channels;
				start++;
			}
			if (num >= _bufLen)
			{
				num -= _bufLen;
				while (start < end)
				{
					_buffer[num] = pcm[start] * window[start];
					num += Channels;
					start++;
				}
			}
			_end = num;
		}
	}
	internal class StreamReadBuffer : IDisposable
	{
		private class StreamWrapper
		{
			internal Stream Source;

			internal object LockObject = new object();

			internal long EofOffset = long.MaxValue;

			internal int RefCount = 1;
		}

		private class SavedBuffer
		{
			public byte[] Buffer;

			public long BaseOffset;

			public int End;

			public int DiscardCount;

			public long VersionSaved;
		}

		private static Dictionary<Stream, StreamWrapper> _lockObjects = new Dictionary<Stream, StreamWrapper>();

		private StreamWrapper _wrapper;

		private int _maxSize;

		private byte[] _data;

		private long _baseOffset;

		private int _end;

		private int _discardCount;

		private bool _minimalRead;

		private long _versionCounter;

		private List<SavedBuffer> _savedBuffers;

		public bool MinimalRead
		{
			get
			{
				return _minimalRead;
			}
			set
			{
				_minimalRead = value;
			}
		}

		public int MaxSize
		{
			get
			{
				return _maxSize;
			}
			set
			{
				if (value < 1)
				{
					throw new ArgumentOutOfRangeException("Must be greater than zero.");
				}
				int num = 1 << (int)Math.Ceiling(Math.Log(value, 2.0));
				if (num < _end)
				{
					if (num < _end - _discardCount)
					{
						throw new ArgumentOutOfRangeException("Must be greater than or equal to the number of bytes currently buffered.");
					}
					CommitDiscard();
					byte[] array = new byte[num];
					Buffer.BlockCopy(_data, 0, array, 0, _end);
					_data = array;
				}
				_maxSize = num;
			}
		}

		public long BaseOffset => _baseOffset + _discardCount;

		public int BytesFilled => _end - _discardCount;

		public int Length => _data.Length;

		internal long BufferEndOffset
		{
			get
			{
				if (_end - _discardCount > 0)
				{
					return _baseOffset + _discardCount + _maxSize;
				}
				return _wrapper.Source.Length;
			}
		}

		internal StreamReadBuffer(Stream source, int initialSize, int maxSize, bool minimalRead)
		{
			StreamWrapper value;
			lock (_lockObjects)
			{
				if (!_lockObjects.TryGetValue(source, out value))
				{
					_lockObjects.Add(source, new StreamWrapper
					{
						Source = source
					});
					value = _lockObjects[source];
					if (source.CanSeek)
					{
						value.EofOffset = source.Length;
					}
				}
				else
				{
					value.RefCount++;
				}
			}
			initialSize = 2 << (int)Math.Log(initialSize - 1, 2.0);
			maxSize = 1 << (int)Math.Log(maxSize, 2.0);
			_wrapper = value;
			_data = new byte[initialSize];
			_maxSize = maxSize;
			_minimalRead = minimalRead;
			_savedBuffers = new List<SavedBuffer>();
		}

		public void Dispose()
		{
			lock (_lockObjects)
			{
				if (--_wrapper.RefCount == 0)
				{
					_lockObjects.Remove(_wrapper.Source);
				}
			}
		}

		public int Read(long offset, byte[] buffer, int index, int count)
		{
			if (offset < 0)
			{
				throw new ArgumentOutOfRangeException("offset");
			}
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			if (index < 0 || index + count > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			if (count < 0)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			if (offset >= _wrapper.EofOffset)
			{
				return 0;
			}
			int srcOffset = EnsureAvailable(offset, ref count, isRecursion: false);
			Buffer.BlockCopy(_data, srcOffset, buffer, index, count);
			return count;
		}

		internal int ReadByte(long offset)
		{
			if (offset < 0)
			{
				throw new ArgumentOutOfRangeException("offset");
			}
			if (offset >= _wrapper.EofOffset)
			{
				return -1;
			}
			int count = 1;
			int num = EnsureAvailable(offset, ref count, isRecursion: false);
			if (count == 1)
			{
				return _data[num];
			}
			return -1;
		}

		private int EnsureAvailable(long offset, ref int count, bool isRecursion)
		{
			if (offset >= _baseOffset && offset + count < _baseOffset + _end)
			{
				return (int)(offset - _baseOffset);
			}
			if (count > _maxSize)
			{
				throw new InvalidOperationException("Not enough room in the buffer!  Increase the maximum size and try again.");
			}
			_versionCounter++;
			if (!isRecursion)
			{
				for (int i = 0; i < _savedBuffers.Count; i++)
				{
					long num = _savedBuffers[i].BaseOffset - offset;
					if ((num < 0 && _savedBuffers[i].End + num > 0) || (num > 0 && count - num > 0))
					{
						SwapBuffers(_savedBuffers[i]);
						return EnsureAvailable(offset, ref count, isRecursion: true);
					}
				}
			}
			while (_savedBuffers.Count > 0 && _savedBuffers[0].VersionSaved + 25 < _versionCounter)
			{
				_savedBuffers[0].Buffer = null;
				_savedBuffers.RemoveAt(0);
			}
			if (offset < _baseOffset && !_wrapper.Source.CanSeek)
			{
				throw new InvalidOperationException("Cannot seek before buffer on forward-only streams!");
			}
			CalcBuffer(offset, count, out var readStart, out var readEnd);
			count = FillBuffer(offset, count, readStart, readEnd);
			return (int)(offset - _baseOffset);
		}

		private void SaveBuffer()
		{
			_savedBuffers.Add(new SavedBuffer
			{
				Buffer = _data,
				BaseOffset = _baseOffset,
				End = _end,
				DiscardCount = _discardCount,
				VersionSaved = _versionCounter
			});
			_data = null;
			_end = 0;
			_discardCount = 0;
		}

		private void CreateNewBuffer(long offset, int count)
		{
			SaveBuffer();
			_data = new byte[Math.Min(2 << (int)Math.Log(count - 1, 2.0), _maxSize)];
			_baseOffset = offset;
		}

		private void SwapBuffers(SavedBuffer savedBuffer)
		{
			_savedBuffers.Remove(savedBuffer);
			SaveBuffer();
			_data = savedBuffer.Buffer;
			_baseOffset = savedBuffer.BaseOffset;
			_end = savedBuffer.End;
			_discardCount = savedBuffer.DiscardCount;
		}

		private void CalcBuffer(long offset, int count, out int readStart, out int readEnd)
		{
			readStart = 0;
			readEnd = 0;
			if (offset < _baseOffset)
			{
				if (offset + _maxSize <= _baseOffset)
				{
					if (_baseOffset - (offset + _maxSize) > _maxSize)
					{
						CreateNewBuffer(offset, count);
					}
					else
					{
						EnsureBufferSize(count, copyContents: false, 0);
					}
					_baseOffset = offset;
					readEnd = count;
				}
				else
				{
					readEnd = (int)(offset - _baseOffset);
					EnsureBufferSize(Math.Min((int)(offset + _maxSize - _baseOffset), _end) - readEnd, copyContents: true, readEnd);
					readEnd = (int)(offset - _baseOffset) - readEnd;
				}
			}
			else if (offset >= _baseOffset + _maxSize)
			{
				if (offset - (_baseOffset + _maxSize) > _maxSize)
				{
					CreateNewBuffer(offset, count);
				}
				else
				{
					EnsureBufferSize(count, copyContents: false, 0);
				}
				_baseOffset = offset;
				readEnd = count;
			}
			else
			{
				readEnd = (int)(offset + count - _baseOffset);
				int num = Math.Max(readEnd - _maxSize, 0);
				EnsureBufferSize(readEnd - num, copyContents: true, num);
				readStart = _end;
				readEnd = (int)(offset + count - _baseOffset);
			}
		}

		private void EnsureBufferSize(int reqSize, bool copyContents, int copyOffset)
		{
			byte[] array = _data;
			if (reqSize > _data.Length)
			{
				if (reqSize > _maxSize)
				{
					if (!_wrapper.Source.CanSeek && reqSize - _discardCount > _maxSize)
					{
						throw new InvalidOperationException("Not enough room in the buffer!  Increase the maximum size and try again.");
					}
					int num = reqSize - _maxSize;
					copyOffset += num;
					reqSize = _maxSize;
				}
				else
				{
					int num2;
					for (num2 = _data.Length; num2 < reqSize; num2 *= 2)
					{
					}
					reqSize = num2;
				}
				if (reqSize > _data.Length)
				{
					array = new byte[reqSize];
				}
			}
			if (copyContents)
			{
				if ((copyOffset > 0 && copyOffset < _end) || (copyOffset == 0 && array != _data))
				{
					Buffer.BlockCopy(_data, copyOffset, array, 0, _end - copyOffset);
					if ((_discardCount -= copyOffset) < 0)
					{
						_discardCount = 0;
					}
				}
				else if (copyOffset < 0 && -copyOffset < _end)
				{
					if (array != _data || _end <= -copyOffset)
					{
						Buffer.BlockCopy(_data, 0, array, -copyOffset, Math.Max(_end, Math.Min(_end, _data.Length + copyOffset)));
					}
					else
					{
						_end = copyOffset;
					}
					_discardCount = 0;
				}
				else
				{
					_end = copyOffset;
					_discardCount = 0;
				}
				_baseOffset += copyOffset;
				_end -= copyOffset;
				if (_end > array.Length)
				{
					_end = array.Length;
				}
			}
			else
			{
				_discardCount = 0;
				_end = 0;
			}
			_data = array;
		}

		private int FillBuffer(long offset, int count, int readStart, int readEnd)
		{
			long readOffset = _baseOffset + readStart;
			int readCount = readEnd - readStart;
			lock (_wrapper.LockObject)
			{
				readCount = PrepareStreamForRead(readCount, readOffset);
				ReadStream(readStart, readCount, readOffset);
				if (_end < readStart + readCount)
				{
					count = Math.Max(0, (int)(_baseOffset + _end - offset));
				}
				else if (!_minimalRead && _end < _data.Length)
				{
					readCount = _data.Length - _end;
					readCount = PrepareStreamForRead(readCount, _baseOffset + _end);
					_end += _wrapper.Source.Read(_data, _end, readCount);
				}
			}
			return count;
		}

		private int PrepareStreamForRead(int readCount, long readOffset)
		{
			if (readCount > 0 && _wrapper.Source.Position != readOffset)
			{
				if (readOffset < _wrapper.EofOffset)
				{
					if (_wrapper.Source.CanSeek)
					{
						_wrapper.Source.Position = readOffset;
					}
					else
					{
						long num = readOffset - _wrapper.Source.Position;
						if (num < 0)
						{
							readCount = 0;
						}
						else
						{
							while (--num >= 0)
							{
								if (_wrapper.Source.ReadByte() == -1)
								{
									_wrapper.EofOffset = _wrapper.Source.Position;
									readCount = 0;
									break;
								}
							}
						}
					}
				}
				else
				{
					readCount = 0;
				}
			}
			return readCount;
		}

		private void ReadStream(int readStart, int readCount, long readOffset)
		{
			while (readCount > 0 && readOffset < _wrapper.EofOffset)
			{
				int num = _wrapper.Source.Read(_data, readStart, readCount);
				if (num == 0)
				{
					break;
				}
				readStart += num;
				readOffset += num;
				readCount -= num;
			}
			if (readStart > _end)
			{
				_end = readStart;
			}
		}

		public void DiscardThrough(long offset)
		{
			int val = (int)(offset - _baseOffset);
			_discardCount = Math.Max(val, _discardCount);
			if (_discardCount >= _data.Length)
			{
				CommitDiscard();
			}
		}

		private void CommitDiscard()
		{
			if (_discardCount >= _data.Length || _discardCount >= _end)
			{
				_baseOffset += _discardCount;
				_end = 0;
			}
			else
			{
				Buffer.BlockCopy(_data, _discardCount, _data, 0, _end - _discardCount);
				_baseOffset += _discardCount;
				_end -= _discardCount;
			}
			_discardCount = 0;
		}
	}
	internal static class Utils
	{
		[StructLayout(LayoutKind.Explicit)]
		private struct FloatBits
		{
			[FieldOffset(0)]
			public float Float;

			[FieldOffset(0)]
			public uint Bits;
		}

		internal static int ilog(int x)
		{
			int num = 0;
			while (x > 0)
			{
				num++;
				x >>= 1;
			}
			return num;
		}

		internal static uint BitReverse(uint n)
		{
			return BitReverse(n, 32);
		}

		internal static uint BitReverse(uint n, int bits)
		{
			n = ((n & 0xAAAAAAAAu) >> 1) | ((n & 0x55555555) << 1);
			n = ((n & 0xCCCCCCCCu) >> 2) | ((n & 0x33333333) << 2);
			n = ((n & 0xF0F0F0F0u) >> 4) | ((n & 0xF0F0F0F) << 4);
			n = ((n & 0xFF00FF00u) >> 8) | ((n & 0xFF00FF) << 8);
			return ((n >> 16) | (n << 16)) >> 32 - bits;
		}

		internal static float ClipValue(float value, ref bool clipped)
		{
			FloatBits floatBits = default(FloatBits);
			floatBits.Bits = 0u;
			floatBits.Float = value;
			if ((floatBits.Bits & 0x7FFFFFFF) > 1065353215)
			{
				clipped = true;
				floatBits.Bits = 0x3F7FFFFF | (floatBits.Bits & 0x80000000u);
			}
			return floatBits.Float;
		}

		internal static float ConvertFromVorbisFloat32(uint bits)
		{
			int num = (int)bits >> 31;
			double y = (int)(((bits & 0x7FE00000) >> 21) - 788);
			return (float)(((bits & 0x1FFFFF) ^ num) + (num & 1)) * (float)Math.Pow(2.0, y);
		}

		internal static int Sum(Queue<int> queue)
		{
			int num = 0;
			for (int i = 0; i < queue.Count; i++)
			{
				int num2 = queue.Dequeue();
				num += num2;
				queue.Enqueue(num2);
			}
			return num;
		}
	}
	internal class VorbisCodebook
	{
		internal int BookNum;

		internal int Dimensions;

		internal int Entries;

		private int[] Lengths;

		private float[] LookupTable;

		internal int MapType;

		private HuffmanListNode PrefixOverflowTree;

		private List<HuffmanListNode> PrefixList;

		private int PrefixBitLength;

		private int MaxBits;

		internal float this[int entry, int dim] => LookupTable[entry * Dimensions + dim];

		internal static VorbisCodebook Init(VorbisStreamDecoder vorbis, DataPacket packet, int number)
		{
			VorbisCodebook vorbisCodebook = new VorbisCodebook();
			vorbisCodebook.BookNum = number;
			vorbisCodebook.Init(packet);
			return vorbisCodebook;
		}

		private VorbisCodebook()
		{
		}

		internal void Init(DataPacket packet)
		{
			if (packet.ReadBits(24) != 5653314)
			{
				throw new InvalidDataException();
			}
			Dimensions = (int)packet.ReadBits(16);
			Entries = (int)packet.ReadBits(24);
			Lengths = new int[Entries];
			InitTree(packet);
			InitLookupTable(packet);
		}

		private void InitTree(DataPacket packet)
		{
			int num = 0;
			bool flag;
			if (packet.ReadBit())
			{
				int num2 = (int)packet.ReadBits(5) + 1;
				int num3 = 0;
				while (num3 < Entries)
				{
					int num4 = (int)packet.ReadBits(Utils.ilog(Entries - num3));
					while (--num4 >= 0)
					{
						Lengths[num3++] = num2;
					}
					num2++;
				}
				num = 0;
				flag = false;
			}
			else
			{
				flag = packet.ReadBit();
				for (int i = 0; i < Entries; i++)
				{
					if (!flag || packet.ReadBit())
					{
						Lengths[i] = (int)packet.ReadBits(5) + 1;
						num++;
					}
					else
					{
						Lengths[i] = -1;
					}
				}
			}
			if ((MaxBits = Lengths.Max()) > -1)
			{
				int num5 = 0;
				int[] array = null;
				if (flag && num >= Entries >> 2)
				{
					array = new int[Entries];
					Array.Copy(Lengths, array, Entries);
					flag = false;
				}
				num5 = (flag ? num : 0);
				int num6 = num5;
				int[] array2 = null;
				int[] array3 = null;
				if (!flag)
				{
					array3 = new int[Entries];
				}
				else if (num6 != 0)
				{
					array = new int[num6];
					array3 = new int[num6];
					array2 = new int[num6];
				}
				if (!ComputeCodewords(flag, num6, array3, array, Lengths, Entries, array2))
				{
					throw new InvalidDataException();
				}
				PrefixList = Huffman.BuildPrefixedLinkedList(array2 ?? Enumerable.Range(0, array3.Length).ToArray(), array ?? Lengths, array3, out PrefixBitLength, out PrefixOverflowTree);
			}
		}

		private bool ComputeCodewords(bool sparse, int sortedEntries, int[] codewords, int[] codewordLengths, int[] len, int n, int[] values)
		{
			int num = 0;
			uint[] array = new uint[32];
			int i;
			for (i = 0; i < n && len[i] <= 0; i++)
			{
			}
			if (i == n)
			{
				return true;
			}
			AddEntry(sparse, codewords, codewordLengths, 0u, i, num++, len[i], values);
			for (int j = 1; j <= len[i]; j++)
			{
				array[j] = (uint)(1 << 32 - j);
			}
			for (int j = i + 1; j < n; j++)
			{
				int num2 = len[j];
				if (num2 <= 0)
				{
					continue;
				}
				while (num2 > 0 && array[num2] == 0)
				{
					num2--;
				}
				if (num2 == 0)
				{
					return false;
				}
				uint num3 = array[num2];
				array[num2] = 0u;
				AddEntry(sparse, codewords, codewordLengths, Utils.BitReverse(num3), j, num++, len[j], values);
				if (num2 != len[j])
				{
					for (int num4 = len[j]; num4 > num2; num4--)
					{
						array[num4] = num3 + (uint)(1 << 32 - num4);
					}
				}
			}
			return true;
		}

		private void AddEntry(bool sparse, int[] codewords, int[] codewordLengths, uint huffCode, int symbol, int count, int len, int[] values)
		{
			if (sparse)
			{
				codewords[count] = (int)huffCode;
				codewordLengths[count] = len;
				values[count] = symbol;
			}
			else
			{
				codewords[symbol] = (int)huffCode;
			}
		}

		private void InitLookupTable(DataPacket packet)
		{
			MapType = (int)packet.ReadBits(4);
			if (MapType == 0)
			{
				return;
			}
			float num = Utils.ConvertFromVorbisFloat32(packet.ReadUInt32());
			float num2 = Utils.ConvertFromVorbisFloat32(packet.ReadUInt32());
			int count = (int)packet.ReadBits(4) + 1;
			bool flag = packet.ReadBit();
			int num3 = Entries * Dimensions;
			float[] array = new float[num3];
			if (MapType == 1)
			{
				num3 = lookup1_values();
			}
			uint[] array2 = new uint[num3];
			for (int i = 0; i < num3; i++)
			{
				array2[i] = (uint)packet.ReadBits(count);
			}
			if (MapType == 1)
			{
				for (int j = 0; j < Entries; j++)
				{
					double num4 = 0.0;
					int num5 = 1;
					for (int k = 0; k < Dimensions; k++)
					{
						int num6 = j / num5 % num3;
						double num7 = (double)((float)array2[num6] * num2 + num) + num4;
						array[j * Dimensions + k] = (float)num7;
						if (flag)
						{
							num4 = num7;
						}
						num5 *= num3;
					}
				}
			}
			else
			{
				for (int l = 0; l < Entries; l++)
				{
					double num8 = 0.0;
					int num9 = l * Dimensions;
					for (int m = 0; m < Dimensions; m++)
					{
						double num10 = (double)((float)array2[num9] * num2 + num) + num8;
						array[l * Dimensions + m] = (float)num10;
						if (flag)
						{
							num8 = num10;
						}
						num9++;
					}
				}
			}
			LookupTable = array;
		}

		private int lookup1_values()
		{
			int num = (int)Math.Floor(Math.Exp(Math.Log(Entries) / (double)Dimensions));
			if (Math.Floor(Math.Pow(num + 1, Dimensions)) <= (double)Entries)
			{
				num++;
			}
			return num;
		}

		internal int DecodeScalar(DataPacket packet)
		{
			int index = (int)packet.TryPeekBits(PrefixBitLength, out var bitsRead);
			if (bitsRead == 0)
			{
				return -1;
			}
			HuffmanListNode huffmanListNode = PrefixList[index];
			if (huffmanListNode != null)
			{
				packet.SkipBits(huffmanListNode.Length);
				return huffmanListNode.Value;
			}
			index = (int)packet.TryPeekBits(MaxBits, out bitsRead);
			huffmanListNode = PrefixOverflowTree;
			do
			{
				if (huffmanListNode.Bits == (index & huffmanListNode.Mask))
				{
					packet.SkipBits(huffmanListNode.Length);
					return huffmanListNode.Value;
				}
			}
			while ((huffmanListNode = huffmanListNode.Next) != null);
			return -1;
		}
	}
	internal abstract class VorbisFloor
	{
		internal abstract class PacketData
		{
			internal int BlockSize;

			protected abstract bool HasEnergy { get; }

			internal bool ForceEnergy { get; set; }

			internal bool ForceNoEnergy { get; set; }

			internal bool ExecuteChannel => (ForceEnergy | HasEnergy) & !ForceNoEnergy;
		}

		private class Floor0 : VorbisFloor
		{
			private class PacketData0 : PacketData
			{
				internal float[] Coeff;

				internal float Amp;

				protected override bool HasEnergy => Amp > 0f;
			}

			private int _order;

			private int _rate;

			private int _bark_map_size;

			private int _ampBits;

			private int _ampOfs;

			private int _ampDiv;

			private VorbisCodebook[] _books;

			private int _bookBits;

			private Dictionary<int, float[]> _wMap;

			private Dictionary<int, int[]> _barkMaps;

			private PacketData0[] _reusablePacketData;

			internal Floor0(VorbisStreamDecoder vorbis)
				: base(vorbis)
			{
			}

			protected override void Init(DataPacket packet)
			{
				_order = (int)packet.ReadBits(8);
				_rate = (int)packet.ReadBits(16);
				_bark_map_size = (int)packet.ReadBits(16);
				_ampBits = (int)packet.ReadBits(6);
				_ampOfs = (int)packet.ReadBits(8);
				_books = new VorbisCodebook[(int)packet.ReadBits(4) + 1];
				if (_order < 1 || _rate < 1 || _bark_map_size < 1 || _books.Length == 0)
				{
					throw new InvalidDataException();
				}
				_ampDiv = (1 << _ampBits) - 1;
				for (int i = 0; i < _books.Length; i++)
				{
					int num = (int)packet.ReadBits(8);
					if (num < 0 || num >= _vorbis.Books.Length)
					{
						throw new InvalidDataException();
					}
					VorbisCodebook vorbisCodebook = _vorbis.Books[num];
					if (vorbisCodebook.MapType == 0 || vorbisCodebook.Dimensions < 1)
					{
						throw new InvalidDataException();
					}
					_books[i] = vorbisCodebook;
				}
				_bookBits = Utils.ilog(_books.Length);
				_barkMaps = new Dictionary<int, int[]>();
				_barkMaps[_vorbis.Block0Size] = SynthesizeBarkCurve(_vorbis.Block0Size / 2);
				_barkMaps[_vorbis.Block1Size] = SynthesizeBarkCurve(_vorbis.Block1Size / 2);
				_wMap = new Dictionary<int, float[]>();
				_wMap[_vorbis.Block0Size] = SynthesizeWDelMap(_vorbis.Block0Size / 2);
				_wMap[_vorbis.Block1Size] = SynthesizeWDelMap(_vorbis.Block1Size / 2);
				_reusablePacketData = new PacketData0[_vorbis._channels];
				for (int j = 0; j < _reusablePacketData.Length; j++)
				{
					_reusablePacketData[j] = new PacketData0
					{
						Coeff = new float[_order + 1]
					};
				}
			}

			private int[] SynthesizeBarkCurve(int n)
			{
				float num = (float)_bark_map_size / toBARK(_rate / 2);
				int[] array = new int[n + 1];
				for (int i = 0; i < n - 1; i++)
				{
					array[i] = Math.Min(_bark_map_size - 1, (int)Math.Floor(toBARK((float)_rate / 2f / (float)n * (float)i) * num));
				}
				array[n] = -1;
				return array;
			}

			private static float toBARK(double lsp)
			{
				return (float)(13.1 * Math.Atan(0.00074 * lsp) + 2.24 * Math.Atan(1.85E-08 * lsp * lsp) + 0.0001 * lsp);
			}

			private float[] SynthesizeWDelMap(int n)
			{
				float num = (float)(Math.PI / (double)_bark_map_size);
				float[] array = new float[n];
				for (int i = 0; i < n; i++)
				{
					array[i] = 2f * (float)Math.Cos(num * (float)i);
				}
				return array;
			}

			internal override PacketData UnpackPacket(DataPacket packet, int blockSize, int channel)
			{
				PacketData0 packetData = _reusablePacketData[channel];
				packetData.BlockSize = blockSize;
				packetData.ForceEnergy = false;
				packetData.ForceNoEnergy = false;
				packetData.Amp = packet.ReadBits(_ampBits);
				if (packetData.Amp > 0f)
				{
					Array.Clear(packetData.Coeff, 0, packetData.Coeff.Length);
					packetData.Amp = packetData.Amp / (float)_ampDiv * (float)_ampOfs;
					uint num = (uint)packet.ReadBits(_bookBits);
					if (num >= _books.Length)
					{
						packetData.Amp = 0f;
						return packetData;
					}
					VorbisCodebook vorbisCodebook = _books[num];
					int i = 0;
					while (i < _order)
					{
						int num2 = vorbisCodebook.DecodeScalar(packet);
						if (num2 == -1)
						{
							packetData.Amp = 0f;
							return packetData;
						}
						int num3 = 0;
						for (; i < _order; i++)
						{
							if (num3 >= vorbisCodebook.Dimensions)
							{
								break;
							}
							packetData.Coeff[i] = vorbisCodebook[num2, num3];
							num3++;
						}
					}
					float num4 = 0f;
					int num5 = 0;
					while (num5 < _order)
					{
						int num6 = 0;
						while (num5 < _order && num6 < vorbisCodebook.Dimensions)
						{
							packetData.Coeff[num5] += num4;
							num5++;
							num6++;
						}
						num4 = packetData.Coeff[num5 - 1];
					}
				}
				return packetData;
			}

			internal override void Apply(PacketData packetData, float[] residue)
			{
				if (!(packetData is PacketData0 packetData2))
				{
					throw new ArgumentException("Incorrect packet data!");
				}
				int num = packetData2.BlockSize / 2;
				if (packetData2.Amp > 0f)
				{
					int[] array = _barkMaps[packetData2.BlockSize];
					float[] array2 = _wMap[packetData2.BlockSize];
					int num2 = 0;
					for (num2 = 0; num2 < _order; num2++)
					{
						packetData2.Coeff[num2] = 2f * (float)Math.Cos(packetData2.Coeff[num2]);
					}
					num2 = 0;
					while (num2 < num)
					{
						int num3 = array[num2];
						float num4 = 0.5f;
						float num5 = 0.5f;
						float num6 = array2[num3];
						int i;
						for (i = 1; i < _order; i += 2)
						{
							num5 *= num6 - packetData2.Coeff[i - 1];
							num4 *= num6 - packetData2.Coeff[i];
						}
						if (i == _order)
						{
							num5 *= num6 - packetData2.Coeff[i - 1];
							num4 *= num4 * (4f - num6 * num6);
							num5 *= num5;
						}
						else
						{
							num4 *= num4 * (2f - num6);
							num5 *= num5 * (2f + num6);
						}
						num5 = packetData2.Amp / (float)Math.Sqrt(num4 + num5) - (float)_ampOfs;
						num5 = (float)Math.Exp(num5 * 0.11512925f);
						residue[num2] *= num5;
						while (array[++num2] == num3)
						{
							residue[num2] *= num5;
						}
					}
				}
				else
				{
					Array.Clear(residue, 0, num);
				}
			}
		}

		private class Floor1 : VorbisFloor
		{
			private class PacketData1 : PacketData
			{
				public int[] Posts = new int[64];

				public int PostCount;

				protected override bool HasEnergy => PostCount > 0;
			}

			private int[] _partitionClass;

			private int[] _classDimensions;

			private int[] _classSubclasses;

			private int[] _xList;

			private int[] _classMasterBookIndex;

			private int[] _hNeigh;

			private int[] _lNeigh;

			private int[] _sortIdx;

			private int _multiplier;

			private int _range;

			private int _yBits;

			private VorbisCodebook[] _classMasterbooks;

			private VorbisCodebook[][] _subclassBooks;

			private int[][] _subclassBookIndex;

			private static int[] _rangeLookup = new int[4] { 256, 128, 86, 64 };

			private static int[] _yBitsLookup = new int[4] { 8, 7, 7, 6 };

			private PacketData1[] _reusablePacketData;

			private bool[] _stepFlags = new bool[64];

			private int[] _finalY = new int[64];

			private static readonly float[] inverse_dB_table = new float[256]
			{
				1.0649863E-07f, 1.1341951E-07f, 1.2079015E-07f, 1.2863978E-07f, 1.369995E-07f, 1.459025E-07f, 1.5538409E-07f, 1.6548181E-07f, 1.7623574E-07f, 1.8768856E-07f,
				1.998856E-07f, 2.128753E-07f, 2.2670913E-07f, 2.4144197E-07f, 2.5713223E-07f, 2.7384212E-07f, 2.9163792E-07f, 3.1059022E-07f, 3.307741E-07f, 3.5226967E-07f,
				3.7516213E-07f, 3.995423E-07f, 4.255068E-07f, 4.5315863E-07f, 4.8260745E-07f, 5.1397E-07f, 5.4737063E-07f, 5.829419E-07f, 6.208247E-07f, 6.611694E-07f,
				7.041359E-07f, 7.4989464E-07f, 7.98627E-07f, 8.505263E-07f, 9.057983E-07f, 9.646621E-07f, 1.0273513E-06f, 1.0941144E-06f, 1.1652161E-06f, 1.2409384E-06f,
				1.3215816E-06f, 1.4074654E-06f, 1.4989305E-06f, 1.5963394E-06f, 1.7000785E-06f, 1.8105592E-06f, 1.9282195E-06f, 2.053526E-06f, 2.1869757E-06f, 2.3290977E-06f,
				2.4804558E-06f, 2.6416496E-06f, 2.813319E-06f, 2.9961443E-06f, 3.1908505E-06f, 3.39821E-06f, 3.619045E-06f, 3.8542307E-06f, 4.1047006E-06f, 4.371447E-06f,
				4.6555283E-06f, 4.958071E-06f, 5.280274E-06f, 5.623416E-06f, 5.988857E-06f, 6.3780467E-06f, 6.7925284E-06f, 7.2339453E-06f, 7.704048E-06f, 8.2047E-06f,
				8.737888E-06f, 9.305725E-06f, 9.910464E-06f, 1.0554501E-05f, 1.1240392E-05f, 1.1970856E-05f, 1.2748789E-05f, 1.3577278E-05f, 1.4459606E-05f, 1.5399271E-05f,
				1.6400005E-05f, 1.7465769E-05f, 1.8600793E-05f, 1.9809577E-05f, 2.1096914E-05f, 2.2467912E-05f, 2.3928002E-05f, 2.5482977E-05f, 2.7139005E-05f, 2.890265E-05f,
				3.078091E-05f, 3.2781227E-05f, 3.4911533E-05f, 3.718028E-05f, 3.9596467E-05f, 4.2169668E-05f, 4.491009E-05f, 4.7828602E-05f, 5.0936775E-05f, 5.424693E-05f,
				5.7772202E-05f, 6.152657E-05f, 6.552491E-05f, 6.9783084E-05f, 7.4317984E-05f, 7.914758E-05f, 8.429104E-05f, 8.976875E-05f, 9.560242E-05f, 0.00010181521f,
				0.00010843174f, 0.00011547824f, 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f, 0.00015820454f, 0.00016848555f, 0.00017943469f, 0.00019109536f,
				0.00020351382f, 0.0002167393f, 0.00023082423f, 0.00024582449f, 0.00026179955f, 0.00027881275f, 0.00029693157f, 0.00031622787f, 0.00033677815f, 0.00035866388f,
				0.00038197188f, 0.00040679457f, 0.00043323037f, 0.0004613841f, 0.0004913675f, 0.00052329927f, 0.0005573062f, 0.0005935231f, 0.0006320936f, 0.0006731706f,
				0.000716917f, 0.0007635063f, 0.00081312325f, 0.00086596457f, 0.00092223985f, 0.0009821722f, 0.0010459992f, 0.0011139743f, 0.0011863665f, 0.0012634633f,
				0.0013455702f, 0.0014330129f, 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f, 0.0019632196f, 0.0020908006f, 0.0022266726f, 0.0023713743f,
				0.0025254795f, 0.0026895993f, 0.0028643848f, 0.0030505287f, 0.003248769f, 0.0034598925f, 0.0036847359f, 0.0039241905f, 0.0041792067f, 0.004450795f,
				0.004740033f, 0.005048067f, 0.0053761187f, 0.005725489f, 0.0060975635f, 0.0064938175f, 0.0069158226f, 0.0073652514f, 0.007843887f, 0.008353627f,
				0.008896492f, 0.009474637f, 0.010090352f, 0.01074608f, 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f, 0.014722068f, 0.015678791f,
				0.016697686f, 0.017782796f, 0.018938422f, 0.020169148f, 0.021479854f, 0.022875736f, 0.02436233f, 0.025945531f, 0.027631618f, 0.029427277f,
				0.031339627f, 0.03337625f, 0.035545226f, 0.037855156f, 0.0403152f, 0.042935107f, 0.045725275f, 0.048696756f, 0.05186135f, 0.05523159f,
				0.05882085f, 0.062643364f, 0.06671428f, 0.07104975f, 0.075666964f, 0.08058423f, 0.08582105f, 0.09139818f, 0.097337745f, 0.1036633f,
				0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f, 0.14201812f, 0.15124726f, 0.16107617f, 0.1715438f, 0.18269168f, 0.19456401f,
				0.20720787f, 0.22067343f, 0.23501402f, 0.25028655f, 0.26655158f, 0.28387362f, 0.3023213f, 0.32196787f, 0.34289113f, 0.36517414f,
				0.3889052f, 0.41417846f, 0.44109413f, 0.4697589f, 0.50028646f, 0.53279793f, 0.5674221f, 0.6042964f, 0.64356697f, 0.6853896f,
				0.72993004f, 0.777365f, 0.8278826f, 0.88168305f, 0.9389798f, 1f
			};

			internal Floor1(VorbisStreamDecoder vorbis)
				: base(vorbis)
			{
			}

			protected override void Init(DataPacket packet)
			{
				_partitionClass = new int[(uint)packet.ReadBits(5)];
				for (int i = 0; i < _partitionClass.Length; i++)
				{
					_partitionClass[i] = (int)packet.ReadBits(4);
				}
				int num = _partitionClass.Max();
				_classDimensions = new int[num + 1];
				_classSubclasses = new int[num + 1];
				_classMasterbooks = new VorbisCodebook[num + 1];
				_classMasterBookIndex = new int[num + 1];
				_subclassBooks = new VorbisCodebook[num + 1][];
				_subclassBookIndex = new int[num + 1][];
				for (int j = 0; j <= num; j++)
				{
					_classDimensions[j] = (int)packet.ReadBits(3) + 1;
					_classSubclasses[j] = (int)packet.ReadBits(2);
					if (_classSubclasses[j] > 0)
					{
						_classMasterBookIndex[j] = (int)packet.ReadBits(8);
						_classMasterbooks[j] = _vorbis.Books[_classMasterBookIndex[j]];
					}
					_subclassBooks[j] = new VorbisCodebook[1 << _classSubclasses[j]];
					_subclassBookIndex[j] = new int[_subclassBooks[j].Length];
					for (int k = 0; k < _subclassBooks[j].Length; k++)
					{
						int num2 = (int)packet.ReadBits(8) - 1;
						if (num2 >= 0)
						{
							_subclassBooks[j][k] = _vorbis.Books[num2];
						}
						_subclassBookIndex[j][k] = num2;
					}
				}
				_multiplier = (int)packet.ReadBits(2);
				_range = _rangeLookup[_multiplier];
				_yBits = _yBitsLookup[_multiplier];
				_multiplier++;
				int num3 = (int)packet.ReadBits(4);
				List<int> list = new List<int>();
				list.Add(0);
				list.Add(1 << num3);
				for (int l = 0; l < _partitionClass.Length; l++)
				{
					int num4 = _partitionClass[l];
					for (int m = 0; m < _classDimensions[num4]; m++)
					{
						list.Add((int)packet.ReadBits(num3));
					}
				}
				_xList = list.ToArray();
				_lNeigh = new int[list.Count];
				_hNeigh = new int[list.Count];
				_sortIdx = new int[list.Count];
				_sortIdx[0] = 0;
				_sortIdx[1] = 1;
				for (int n = 2; n < _lNeigh.Length; n++)
				{
					_lNeigh[n] = 0;
					_hNeigh[n] = 1;
					_sortIdx[n] = n;
					for (int num5 = 2; num5 < n; num5++)
					{
						int num6 = _xList[num5];
						if (num6 < _xList[n])
						{
							if (num6 > _xList[_lNeigh[n]])
							{
								_lNeigh[n] = num5;
							}
						}
						else if (num6 < _xList[_hNeigh[n]])
						{
							_hNeigh[n] = num5;
						}
					}
				}
				for (int num7 = 0; num7 < _sortIdx.Length - 1; num7++)
				{
					for (int num8 = num7 + 1; num8 < _sortIdx.Length; num8++)
					{
						if (_xList[num7] == _xList[num8])
						{
							throw new InvalidDataException();
						}
						if (_xList[_sortIdx[num7]] > _xList[_sortIdx[num8]])
						{
							int num9 = _sortIdx[num7];
							_sortIdx[num7] = _sortIdx[num8];
							_sortIdx[num8] = num9;
						}
					}
				}
				_reusablePacketData = new PacketData1[_vorbis._channels];
				for (int num10 = 0; num10 < _reusablePacketData.Length; num10++)
				{
					_reusablePacketData[num10] = new PacketData1();
				}
			}

			internal override PacketData UnpackPacket(DataPacket packet, int blockSize, int channel)
			{
				PacketData1 packetData = _reusablePacketData[channel];
				packetData.BlockSize = blockSize;
				packetData.ForceEnergy = false;
				packetData.ForceNoEnergy = false;
				packetData.PostCount = 0;
				Array.Clear(packetData.Posts, 0, 64);
				if (packet.ReadBit())
				{
					int num = 2;
					packetData.Posts[0] = (int)packet.ReadBits(_yBits);
					packetData.Posts[1] = (int)packet.ReadBits(_yBits);
					for (int i = 0; i < _partitionClass.Length; i++)
					{
						int num2 = _partitionClass[i];
						int num3 = _classDimensions[num2];
						int num4 = _classSubclasses[num2];
						int num5 = (1 << num4) - 1;
						uint num6 = 0u;
						if (num4 > 0 && (num6 = (uint)_classMasterbooks[num2].DecodeScalar(packet)) == uint.MaxValue)
						{
							num = 0;
							break;
						}
						for (int j = 0; j < num3; j++)
						{
							VorbisCodebook vorbisCodebook = _subclassBooks[num2][num6 & num5];
							num6 >>= num4;
							if (vorbisCodebook != null && (packetData.Posts[num] = vorbisCodebook.DecodeScalar(packet)) == -1)
							{
								num = 0;
								i = _partitionClass.Length;
								break;
							}
							num++;
						}
					}
					packetData.PostCount = num;
				}
				return packetData;
			}

			internal override void Apply(PacketData packetData, float[] residue)
			{
				if (!(packetData is PacketData1 packetData2))
				{
					throw new ArgumentException("Incorrect packet data!", "packetData");
				}
				int num = packetData2.BlockSize / 2;
				if (packetData2.PostCount > 0)
				{
					bool[] array = UnwrapPosts(packetData2);
					int num2 = 0;
					int num3 = packetData2.Posts[0] * _multiplier;
					for (int i = 1; i < packetData2.PostCount; i++)
					{
						int num4 = _sortIdx[i];
						if (array[num4])
						{
							int num5 = _xList[num4];
							int num6 = packetData2.Posts[num4] * _multiplier;
							if (num2 < num)
							{
								RenderLineMulti(num2, num3, Math.Min(num5, num), num6, residue);
							}
							num2 = num5;
							num3 = num6;
						}
						if (num2 >= num)
						{
							break;
						}
					}
					if (num2 < num)
					{
						RenderLineMulti(num2, num3, num, num3, residue);
					}
				}
				else
				{
					Array.Clear(residue, 0, num);
				}
			}

			private bool[] UnwrapPosts(PacketData1 data)
			{
				Array.Clear(_stepFlags, 2, 62);
				_stepFlags[0] = true;
				_stepFlags[1] = true;
				Array.Clear(_finalY, 2, 62);
				_finalY[0] = data.Posts[0];
				_finalY[1] = data.Posts[1];
				for (int i = 2; i < data.PostCount; i++)
				{
					int num = _lNeigh[i];
					int num2 = _hNeigh[i];
					int num3 = RenderPoint(_xList[num], _finalY[num], _xList[num2], _finalY[num2], _xList[i]);
					int num4 = data.Posts[i];
					int num5 = _range - num3;
					int num6 = num3;
					int num7 = ((num5 >= num6) ? (num6 * 2) : (num5 * 2));
					if (num4 != 0)
					{
						_stepFlags[num] = true;
						_stepFlags[num2] = true;
						_stepFlags[i] = true;
						if (num4 >= num7)
						{
							if (num5 > num6)
							{
								_finalY[i] = num4 - num6 + num3;
							}
							else
							{
								_finalY[i] = num3 - num4 + num5 - 1;
							}
						}
						else if (num4 % 2 == 1)
						{
							_finalY[i] = num3 - (num4 + 1) / 2;
						}
						else
						{
							_finalY[i] = num3 + num4 / 2;
						}
					}
					else
					{
						_stepFlags[i] = false;
						_finalY[i] = num3;
					}
				}
				for (int j = 0; j < data.PostCount; j++)
				{
					data.Posts[j] = _finalY[j];
				}
				return _stepFlags;
			}

			private int RenderPoint(int x0, int y0, int x1, int y1, int X)
			{
				int num = y1 - y0;
				int num2 = x1 - x0;
				int num3 = Math.Abs(num) * (X - x0) / num2;
				if (num < 0)
				{
					return y0 - num3;
				}
				return y0 + num3;
			}

			private void RenderLineMulti(int x0, int y0, int x1, int y1, float[] v)
			{
				int num = y1 - y0;
				int num2 = x1 - x0;
				int num3 = Math.Abs(num);
				int num4 = 1 - ((num >> 31) & 1) * 2;
				int num5 = num / num2;
				int num6 = x0;
				int num7 = y0;
				int num8 = -num2;
				v[x0] *= inverse_dB_table[y0];
				num3 -= Math.Abs(num5) * num2;
				while (++num6 < x1)
				{
					num7 += num5;
					num8 += num3;
					if (num8 >= 0)
					{
						num8 -= num2;
						num7 += num4;
					}
					v[num6] *= inverse_dB_table[num7];
				}
			}
		}

		private VorbisStreamDecoder _vorbis;

		internal static VorbisFloor Init(VorbisStreamDecoder vorbis, DataPacket packet)
		{
			int num = (int)packet.ReadBits(16);
			VorbisFloor vorbisFloor = null;
			switch (num)
			{
			case 0:
				vorbisFloor = new Floor0(vorbis);
				break;
			case 1:
				vorbisFloor = new Floor1(vorbis);
				break;
			}
			if (vorbisFloor == null)
			{
				throw new InvalidDataException();
			}
			vorbisFloor.Init(packet);
			return vorbisFloor;
		}

		protected VorbisFloor(VorbisStreamDecoder vorbis)
		{
			_vorbis = vorbis;
		}

		protected abstract void Init(DataPacket packet);

		internal abstract PacketData UnpackPacket(DataPacket packet, int blockSize, int channel);

		internal abstract void Apply(PacketData packetData, float[] residue);
	}
	internal abstract class VorbisMapping
	{
		private class Mapping0 : VorbisMapping
		{
			internal Mapping0(VorbisStreamDecoder vorbis)
				: base(vorbis)
			{
			}

			protected override void Init(DataPacket packet)
			{
				int num = 1;
				if (packet.ReadBit())
				{
					num += (int)packet.ReadBits(4);
				}
				int num2 = 0;
				if (packet.ReadBit())
				{
					num2 = (int)packet.ReadBits(8) + 1;
				}
				int count = Utils.ilog(_vorbis._channels - 1);
				CouplingSteps = new CouplingStep[num2];
				for (int i = 0; i < num2; i++)
				{
					int num3 = (int)packet.ReadBits(count);
					int num4 = (int)packet.ReadBits(count);
					if (num3 == num4 || num3 > _vorbis._channels - 1 || num4 > _vorbis._channels - 1)
					{
						throw new InvalidDataException();
					}
					CouplingSteps[i] = new CouplingStep
					{
						Angle = num4,
						Magnitude = num3
					};
				}
				if (packet.ReadBits(2) != 0L)
				{
					throw new InvalidDataException();
				}
				int[] array = new int[_vorbis._channels];
				if (num > 1)
				{
					for (int j = 0; j < ChannelSubmap.Length; j++)
					{
						array[j] = (int)packet.ReadBits(4);
						if (array[j] >= num)
						{
							throw new InvalidDataException();
						}
					}
				}
				Submaps = new Submap[num];
				for (int k = 0; k < num; k++)
				{
					packet.ReadBits(8);
					int num5 = (int)packet.ReadBits(8);
					if (num5 >= _vorbis.Floors.Length)
					{
						throw new InvalidDataException();
					}
					if ((int)packet.ReadBits(8) >= _vorbis.Residues.Length)
					{
						throw new InvalidDataException();
					}
					Submaps[k] = new Submap
					{
						Floor = _vorbis.Floors[num5],
						Residue = _vorbis.Residues[num5]
					};
				}
				ChannelSubmap = new Submap[_vorbis._channels];
				for (int l = 0; l < ChannelSubmap.Length; l++)
				{
					ChannelSubmap[l] = Submaps[array[l]];
				}
			}
		}

		internal class Submap
		{
			internal VorbisFloor Floor;

			internal VorbisResidue Residue;

			internal Submap()
			{
			}
		}

		internal class CouplingStep
		{
			internal int Magnitude;

			internal int Angle;

			internal CouplingStep()
			{
			}
		}

		private VorbisStreamDecoder _vorbis;

		internal Submap[] Submaps;

		internal Submap[] ChannelSubmap;

		internal CouplingStep[] CouplingSteps;

		internal static VorbisMapping Init(VorbisStreamDecoder vorbis, DataPacket packet)
		{
			int num = (int)packet.ReadBits(16);
			VorbisMapping vorbisMapping = null;
			if (num == 0)
			{
				vorbisMapping = new Mapping0(vorbis);
			}
			if (vorbisMapping == null)
			{
				throw new InvalidDataException();
			}
			vorbisMapping.Init(packet);
			return vorbisMapping;
		}

		protected VorbisMapping(VorbisStreamDecoder vorbis)
		{
			_vorbis = vorbis;
		}

		protected abstract void Init(DataPacket packet);
	}
	internal class VorbisMode
	{
		private const float M_PI = MathF.PI;

		private const float M_PI2 = MathF.PI / 2f;

		private VorbisStreamDecoder _vorbis;

		private float[][] _windows;

		internal bool BlockFlag;

		internal int WindowType;

		internal int TransformType;

		internal VorbisMapping Mapping;

		internal int BlockSize;

		internal static VorbisMode Init(VorbisStreamDecoder vorbis, DataPacket packet)
		{
			VorbisMode vorbisMode = new VorbisMode(vorbis);
			vorbisMode.BlockFlag = packet.ReadBit();
			vorbisMode.WindowType = (int)packet.ReadBits(16);
			vorbisMode.TransformType = (int)packet.ReadBits(16);
			int num = (int)packet.ReadBits(8);
			if (vorbisMode.WindowType != 0 || vorbisMode.TransformType != 0 || num >= vorbis.Maps.Length)
			{
				throw new InvalidDataException();
			}
			vorbisMode.Mapping = vorbis.Maps[num];
			vorbisMode.BlockSize = (vorbisMode.BlockFlag ? vorbis.Block1Size : vorbis.Block0Size);
			if (vorbisMode.BlockFlag)
			{
				vorbisMode._windows = new float[4][];
				vorbisMode._windows[0] = new float[vorbis.Block1Size];
				vorbisMode._windows[1] = new float[vorbis.Block1Size];
				vorbisMode._windows[2] = new float[vorbis.Block1Size];
				vorbisMode._windows[3] = new float[vorbis.Block1Size];
			}
			else
			{
				vorbisMode._windows = new float[1][];
				vorbisMode._windows[0] = new float[vorbis.Block0Size];
			}
			vorbisMode.CalcWindows();
			return vorbisMode;
		}

		private VorbisMode(VorbisStreamDecoder vorbis)
		{
			_vorbis = vorbis;
		}

		private void CalcWindows()
		{
			for (int i = 0; i < _windows.Length; i++)
			{
				float[] array = _windows[i];
				int num = (((i & 1) == 0) ? _vorbis.Block0Size : _vorbis.Block1Size) / 2;
				int blockSize = BlockSize;
				int num2 = (((i & 2) == 0) ? _vorbis.Block0Size : _vorbis.Block1Size) / 2;
				int num3 = blockSize / 4 - num / 2;
				int num4 = blockSize - blockSize / 4 - num2 / 2;
				for (int j = 0; j < num; j++)
				{
					float num5 = (float)Math.Sin(((double)j + 0.5) / (double)num * 1.5707963705062866);
					num5 *= num5;
					array[num3 + j] = (float)Math.Sin(num5 * (MathF.PI / 2f));
				}
				for (int k = num3 + num; k < num4; k++)
				{
					array[k] = 1f;
				}
				for (int l = 0; l < num2; l++)
				{
					float num6 = (float)Math.Sin(((double)(num2 - l) - 0.5) / (double)num2 * 1.5707963705062866);
					num6 *= num6;
					array[num4 + l] = (float)Math.Sin(num6 * (MathF.PI / 2f));
				}
			}
		}

		internal float[] GetWindow(bool prev, bool next)
		{
			if (BlockFlag)
			{
				if (next)
				{
					if (prev)
					{
						return _windows[3];
					}
					return _windows[2];
				}
				if (prev)
				{
					return _windows[1];
				}
			}
			return _windows[0];
		}
	}
	public class VorbisReader : IDisposable
	{
		private int _streamIdx;

		private IContainerReader _containerReader;

		private List<VorbisStreamDecoder> _decoders;

		private List<int> _serials;

		private VorbisStreamDecoder ActiveDecoder
		{
			get
			{
				if (_decoders == null)
				{
					throw new ObjectDisposedException("VorbisReader");
				}
				return _decoders[_streamIdx];
			}
		}

		public int Channels => ActiveDecoder._channels;

		public int SampleRate => ActiveDecoder._sampleRate;

		public int UpperBitrate => ActiveDecoder._upperBitrate;

		public int NominalBitrate => ActiveDecoder._nominalBitrate;

		public int LowerBitrate => ActiveDecoder._lowerBitrate;

		public string Vendor => ActiveDecoder._vendor;

		public string[] Comments => ActiveDecoder._comments;

		public bool IsParameterChange => ActiveDecoder.IsParameterChange;

		public long ContainerOverheadBits => ActiveDecoder.ContainerBits;

		public bool ClipSamples { get; set; }

		public IVorbisStreamStatus[] Stats => _decoders.Select((VorbisStreamDecoder d) => d).Cast<IVorbisStreamStatus>().ToArray();

		public int StreamIndex => _streamIdx;

		public int StreamCount => _decoders.Count;

		public TimeSpan DecodedTime
		{
			get
			{
				return TimeSpan.FromSeconds((double)ActiveDecoder.CurrentPosition / (double)SampleRate);
			}
			set
			{
				ActiveDecoder.SeekTo((long)(value.TotalSeconds * (double)SampleRate));
			}
		}

		public long DecodedPosition
		{
			get
			{
				return ActiveDecoder.CurrentPosition;
			}
			set
			{
				ActiveDecoder.SeekTo(value);
			}
		}

		public TimeSpan TotalTime
		{
			get
			{
				VorbisStreamDecoder activeDecoder = ActiveDecoder;
				if (activeDecoder.CanSeek)
				{
					return TimeSpan.FromSeconds((double)activeDecoder.GetLastGranulePos() / (double)activeDecoder._sampleRate);
				}
				return TimeSpan.MaxValue;
			}
		}

		public long TotalSamples
		{
			get
			{
				VorbisStreamDecoder activeDecoder = ActiveDecoder;
				if (activeDecoder.CanSeek)
				{
					return activeDecoder.GetLastGranulePos();
				}
				return long.MaxValue;
			}
		}

		private VorbisReader()
		{
			ClipSamples = true;
			_decoders = new List<VorbisStreamDecoder>();
			_serials = new List<int>();
		}

		public VorbisReader(string fileName)
			: this(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read), closeStreamOnDispose: true)
		{
		}

		public VorbisReader(Stream stream, bool closeStreamOnDispose)
			: this()
		{
			BufferedReadStream bufferedReadStream = new BufferedReadStream(stream)
			{
				CloseBaseStream = closeStreamOnDispose
			};
			ContainerReader containerReader = new ContainerReader(bufferedReadStream, closeStreamOnDispose);
			if (!LoadContainer(containerReader))
			{
				bufferedReadStream.Close();
				throw new InvalidDataException("Could not determine container type!");
			}
			_containerReader = containerReader;
			if (_decoders.Count == 0)
			{
				throw new InvalidDataException("No Vorbis data found!");
			}
		}

		public VorbisReader(IContainerReader containerReader)
			: this()
		{
			if (!LoadContainer(containerReader))
			{
				throw new InvalidDataException("Container did not initialize!");
			}
			_containerReader = containerReader;
			if (_decoders.Count == 0)
			{
				throw new InvalidDataException("No Vorbis data found!");
			}
		}

		public VorbisReader(IPacketProvider packetProvider)
			: this()
		{
			NewStreamEventArgs e = new NewStreamEventArgs(packetProvider);
			NewStream(this, e);
			if (e.IgnoreStream)
			{
				throw new InvalidDataException("No Vorbis data found!");
			}
		}

		private bool LoadContainer(IContainerReader containerReader)
		{
			containerReader.NewStream += NewStream;
			if (!containerReader.Init())
			{
				containerReader.NewStream -= NewStream;
				return false;
			}
			return true;
		}

		private void NewStream(object sender, NewStreamEventArgs ea)
		{
			IPacketProvider packetProvider = ea.PacketProvider;
			VorbisStreamDecoder vorbisStreamDecoder = new VorbisStreamDecoder(packetProvider);
			if (vorbisStreamDecoder.TryInit())
			{
				_decoders.Add(vorbisStreamDecoder);
				_serials.Add(packetProvider.StreamSerial);
			}
			else
			{
				ea.IgnoreStream = true;
			}
		}

		public void Dispose()
		{
			if (_decoders != null)
			{
				foreach (VorbisStreamDecoder decoder in _decoders)
				{
					decoder.Dispose();
				}
				_decoders.Clear();
				_decoders = null;
			}
			if (_containerReader != null)
			{
				_containerReader.NewStream -= NewStream;
				_containerReader.Dispose();
				_containerReader = null;
			}
		}

		public int ReadSamples(float[] buffer, int offset, int count)
		{
			if (offset < 0)
			{
				throw new ArgumentOutOfRangeException("offset");
			}
			if (count < 0 || offset + count > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			count = ActiveDecoder.ReadSamples(buffer, offset, count);
			if (ClipSamples)
			{
				VorbisStreamDecoder vorbisStreamDecoder = _decoders[_streamIdx];
				int num = 0;
				while (num < count)
				{
					buffer[offset] = Utils.ClipValue(buffer[offset], ref vorbisStreamDecoder._clipped);
					num++;
					offset++;
				}
			}
			return count;
		}

		public void ClearParameterChange()
		{
			ActiveDecoder.IsParameterChange = false;
		}

		public bool FindNextStream()
		{
			if (_containerReader == null)
			{
				return false;
			}
			return _containerReader.FindNextStream();
		}

		public bool SwitchStreams(int index)
		{
			if (index < 0 || index >= StreamCount)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			if (_decoders == null)
			{
				throw new ObjectDisposedException("VorbisReader");
			}
			if (_streamIdx == index)
			{
				return false;
			}
			VorbisStreamDecoder vorbisStreamDecoder = _decoders[_streamIdx];
			_streamIdx = index;
			VorbisStreamDecoder vorbisStreamDecoder2 = _decoders[_streamIdx];
			if (vorbisStreamDecoder._channels == vorbisStreamDecoder2._channels)
			{
				return vorbisStreamDecoder._sampleRate != vorbisStreamDecoder2._sampleRate;
			}
			return true;
		}
	}
	internal abstract class VorbisResidue
	{
		private class Residue0 : VorbisResidue
		{
			private int _begin;

			private int _end;

			private int _partitionSize;

			private int _classifications;

			private int _maxStages;

			private VorbisCodebook[][] _books;

			private VorbisCodebook _classBook;

			private int[] _cascade;

			private int[] _entryCache;

			private int[][] _decodeMap;

			private int[][][] _partWordCache;

			internal Residue0(VorbisStreamDecoder vorbis)
				: base(vorbis)
			{
			}

			protected override void Init(DataPacket packet)
			{
				_begin = (int)packet.ReadBits(24);
				_end = (int)packet.ReadBits(24);
				_partitionSize = (int)packet.ReadBits(24) + 1;
				_classifications = (int)packet.ReadBits(6) + 1;
				_classBook = _vorbis.Books[(uint)packet.ReadBits(8)];
				_cascade = new int[_classifications];
				int num = 0;
				for (int i = 0; i < _classifications; i++)
				{
					int num2 = (int)packet.ReadBits(3);
					if (packet.ReadBit())
					{
						_cascade[i] = ((int)packet.ReadBits(5) << 3) | num2;
					}
					else
					{
						_cascade[i] = num2;
					}
					num += icount(_cascade[i]);
				}
				int[] array = new int[num];
				for (int j = 0; j < num; j++)
				{
					array[j] = (int)packet.ReadBits(8);
					if (_vorbis.Books[array[j]].MapType == 0)
					{
						throw new InvalidDataException();
					}
				}
				int entries = _classBook.Entries;
				int num3 = _classBook.Dimensions;
				int num4 = 1;
				while (num3 > 0)
				{
					num4 *= _classifications;
					if (num4 > entries)
					{
						throw new InvalidDataException();
					}
					num3--;
				}
				num3 = _classBook.Dimensions;
				_books = new VorbisCodebook[_classifications][];
				num = 0;
				int num5 = 0;
				for (int k = 0; k < _classifications; k++)
				{
					int num6 = Utils.ilog(_cascade[k]);
					_books[k] = new VorbisCodebook[num6];
					if (num6 <= 0)
					{
						continue;
					}
					num5 = Math.Max(num5, num6);
					for (int l = 0; l < num6; l++)
					{
						if ((_cascade[k] & (1 << l)) > 0)
						{
							_books[k][l] = _vorbis.Books[array[num++]];
						}
					}
				}
				_maxStages = num5;
				_decodeMap = new int[num4][];
				for (int m = 0; m < num4; m++)
				{
					int num7 = m;
					int num8 = num4 / _classifications;
					_decodeMap[m] = new int[_classBook.Dimensions];
					for (int n = 0; n < _classBook.Dimensions; n++)
					{
						int num9 = num7 / num8;
						num7 -= num9 * num8;
						num8 /= _classifications;
						_decodeMap[m][n] = num9;
					}
				}
				_entryCache = new int[_partitionSize];
				_partWordCache = new int[_vorbis._channels][][];
				int num10 = ((_end - _begin) / _partitionSize + _classBook.Dimensions - 1) / _classBook.Dimensions;
				for (int num11 = 0; num11 < _vorbis._channels; num11++)
				{
					_partWordCache[num11] = new int[num10][];
				}
			}

			internal override float[][] Decode(DataPacket packet, bool[] doNotDecode, int channels, int blockSize)
			{
				float[][] residueBuffer = GetResidueBuffer(doNotDecode.Length);
				int num = ((_end < blockSize / 2) ? _end : (blockSize / 2)) - _begin;
				if (num > 0 && doNotDecode.Contains(value: false))
				{
					int num2 = num / _partitionSize;
					int length = (num2 + _classBook.Dimensions - 1) / _classBook.Dimensions;
					for (int i = 0; i < channels; i++)
					{
						Array.Clear(_partWordCache[i], 0, length);
					}
					for (int j = 0; j < _maxStages; j++)
					{
						int k = 0;
						int num3 = 0;
						while (k < num2)
						{
							if (j == 0)
							{
								for (int l = 0; l < channels; l++)
								{
									int num4 = _classBook.DecodeScalar(packet);
									if (num4 >= 0 && num4 < _decodeMap.Length)
									{
										_partWordCache[l][num3] = _decodeMap[num4];
										continue;
									}
									k = num2;
									j = _maxStages;
									break;
								}
							}
							int num5 = 0;
							for (; k < num2; k++)
							{
								if (num5 >= _classBook.Dimensions)
								{
									break;
								}
								int offset = _begin + k * _partitionSize;
								for (int m = 0; m < channels; m++)
								{
									int num6 = _partWordCache[m][num3][num5];
									if ((_cascade[num6] & (1 << j)) != 0)
									{
										VorbisCodebook vorbisCodebook = _books[num6][j];
										if (vorbisCodebook != null && WriteVectors(vorbisCodebook, packet, residueBuffer, m, offset, _partitionSize))
										{
											k = num2;
											j = _maxStages;
											break;
										}
									}
								}
								num5++;
							}
							num3++;
						}
					}
				}
				return residueBuffer;
			}

			protected virtual bool WriteVectors(VorbisCodebook codebook, DataPacket packet, float[][] residue, int channel, int offset, int partitionSize)
			{
				float[] array = residue[channel];
				int num = partitionSize / codebook.Dimensions;
				for (int i = 0; i < num; i++)
				{
					if ((_entryCache[i] = codebook.DecodeScalar(packet)) == -1)
					{
						return true;
					}
				}
				for (int j = 0; j < codebook.Dimensions; j++)
				{
					int num2 = 0;
					while (num2 < num)
					{
						array[offset] += codebook[_entryCache[num2], j];
						num2++;
						offset++;
					}
				}
				return false;
			}
		}

		private class Residue1 : Residue0
		{
			internal Residue1(VorbisStreamDecoder vorbis)
				: base(vorbis)
			{
			}

			protected override bool WriteVectors(VorbisCodebook codebook, DataPacket packet, float[][] residue, int channel, int offset, int partitionSize)
			{
				float[] array = residue[channel];
				int num = 0;
				while (num < partitionSize)
				{
					int num2 = codebook.DecodeScalar(packet);
					if (num2 == -1)
					{
						return true;
					}
					for (int i = 0; i < codebook.Dimensions; i++)
					{
						array[offset + num] += codebook[num2, i];
						num++;
					}
				}
				return false;
			}
		}

		private class Residue2 : Residue0
		{
			private int _channels;

			internal Residue2(VorbisStreamDecoder vorbis)
				: base(vorbis)
			{
			}

			internal override float[][] Decode(DataPacket packet, bool[] doNotDecode, int channels, int blockSize)
			{
				_channels = channels;
				return base.Decode(packet, doNotDecode, 1, blockSize * channels);
			}

			protected override bool WriteVectors(VorbisCodebook codebook, DataPacket packet, float[][] residue, int channel, int offset, int partitionSize)
			{
				int num = 0;
				offset /= _channels;
				int num2 = 0;
				while (num2 < partitionSize)
				{
					int num3 = codebook.DecodeScalar(packet);
					if (num3 == -1)
					{
						return true;
					}
					int num4 = 0;
					while (num4 < codebook.Dimensions)
					{
						residue[num][offset] += codebook[num3, num4];
						if (++num == _channels)
						{
							num = 0;
							offset++;
						}
						num4++;
						num2++;
					}
				}
				return false;
			}
		}

		private VorbisStreamDecoder _vorbis;

		private float[][] _residue;

		internal static VorbisResidue Init(VorbisStreamDecoder vorbis, DataPacket packet)
		{
			int num = (int)packet.ReadBits(16);
			VorbisResidue vorbisResidue = null;
			switch (num)
			{
			case 0:
				vorbisResidue = new Residue0(vorbis);
				break;
			case 1:
				vorbisResidue = new Residue1(vorbis);
				break;
			case 2:
				vorbisResidue = new Residue2(vorbis);
				break;
			}
			if (vorbisResidue == null)
			{
				throw new InvalidDataException();
			}
			vorbisResidue.Init(packet);
			return vorbisResidue;
		}

		private static int icount(int v)
		{
			int num = 0;
			while (v != 0)
			{
				num += v & 1;
				v >>= 1;
			}
			return num;
		}

		protected VorbisResidue(VorbisStreamDecoder vorbis)
		{
			_vorbis = vorbis;
			_residue = new float[_vorbis._channels][];
			for (int i = 0; i < _vorbis._channels; i++)
			{
				_residue[i] = new float[_vorbis.Block1Size];
			}
		}

		protected float[][] GetResidueBuffer(int channels)
		{
			float[][] array = _residue;
			if (channels < _vorbis._channels)
			{
				array = new float[channels][];
				Array.Copy(_residue, array, channels);
			}
			for (int i = 0; i < channels; i++)
			{
				Array.Clear(array[i], 0, array[i].Length);
			}
			return array;
		}

		internal abstract float[][] Decode(DataPacket packet, bool[] doNotDecode, int channels, int blockSize);

		protected abstract void Init(DataPacket packet);
	}
	internal class VorbisStreamDecoder : IVorbisStreamStatus, IDisposable
	{
		internal int _upperBitrate;

		internal int _nominalBitrate;

		internal int _lowerBitrate;

		internal string _vendor;

		internal string[] _comments;

		internal int _channels;

		internal int _sampleRate;

		internal int Block0Size;

		internal int Block1Size;

		internal VorbisCodebook[] Books;

		internal VorbisTime[] Times;

		internal VorbisFloor[] Floors;

		internal VorbisResidue[] Residues;

		internal VorbisMapping[] Maps;

		internal VorbisMode[] Modes;

		private int _modeFieldBits;

		internal long _glueBits;

		internal long _metaBits;

		internal long _bookBits;

		internal long _timeHdrBits;

		internal long _floorHdrBits;

		internal long _resHdrBits;

		internal long _mapHdrBits;

		internal long _modeHdrBits;

		internal long _wasteHdrBits;

		internal long _modeBits;

		internal long _floorBits;

		internal long _resBits;

		internal long _wasteBits;

		internal long _samples;

		internal int _packetCount;

		internal Stopwatch _sw = new Stopwatch();

		private IPacketProvider _packetProvider;

		private DataPacket _parameterChangePacket;

		private List<int> _pagesSeen;

		private int _lastPageSeen;

		private bool _eosFound;

		private object _seekLock = new object();

		private float[] _prevBuffer;

		private RingBuffer _outputBuffer;

		private Queue<int> _bitsPerPacketHistory;

		private Queue<int> _sampleCountHistory;

		private int _preparedLength;

		internal bool _clipped;

		private Stack<DataPacket> _resyncQueue;

		private long _currentPosition;

		private long _reportedPosition;

		private VorbisMode _mode;

		private bool _prevFlag;

		private bool _nextFlag;

		private bool[] _noExecuteChannel;

		private VorbisFloor.PacketData[] _floorData;

		private float[][] _residue;

		private bool _isParameterChange;

		internal bool IsParameterChange
		{
			get
			{
				return _isParameterChange;
			}
			set
			{
				if (value)
				{
					throw new InvalidOperationException("Only clearing is supported!");
				}
				_isParameterChange = value;
			}
		}

		internal bool CanSeek => _packetProvider.CanSeek;

		internal long CurrentPosition
		{
			get
			{
				return _reportedPosition;
			}
			private set
			{
				_reportedPosition = value;
				_currentPosition = value;
				_preparedLength = 0;
				_eosFound = false;
				ResetDecoder(isFullReset: false);
				_prevBuffer = null;
			}
		}

		internal long ContainerBits => _packetProvider.ContainerBits;

		public int EffectiveBitRate
		{
			get
			{
				if (_samples == 0L)
				{
					return 0;
				}
				double num = (double)(_currentPosition - _preparedLength) / (double)_sampleRate;
				return (int)((double)AudioBits / num);
			}
		}

		public int InstantBitRate
		{
			get
			{
				int num = _sampleCountHistory.Sum();
				if (num > 0)
				{
					return (int)((long)_bitsPerPacketHistory.Sum() * (long)_sampleRate / num);
				}
				return -1;
			}
		}

		public TimeSpan PageLatency => TimeSpan.FromTicks(_sw.ElapsedTicks / PagesRead);

		public TimeSpan PacketLatency => TimeSpan.FromTicks(_sw.ElapsedTicks / _packetCount);

		public TimeSpan SecondLatency => TimeSpan.FromTicks(_sw.ElapsedTicks / _samples * _sampleRate);

		public long OverheadBits => _glueBits + _metaBits + _timeHdrBits + _wasteHdrBits + _wasteBits + _packetProvider.ContainerBits;

		public long AudioBits => _bookBits + _floorHdrBits + _resHdrBits + _mapHdrBits + _modeHdrBits + _modeBits + _floorBits + _resBits;

		public int PagesRead => _pagesSeen.IndexOf(_lastPageSeen) + 1;

		public int TotalPages => _packetProvider.GetTotalPageCount();

		public bool Clipped => _clipped;

		internal VorbisStreamDecoder(IPacketProvider packetProvider)
		{
			_packetProvider = packetProvider;
			_packetProvider.ParameterChange += SetParametersChanging;
			_pagesSeen = new List<int>();
			_lastPageSeen = -1;
		}

		internal bool TryInit()
		{
			if (!ProcessStreamHeader(_packetProvider.PeekNextPacket()))
			{
				return false;
			}
			_packetProvider.GetNextPacket().Done();
			DataPacket nextPacket = _packetProvider.GetNextPacket();
			if (!LoadComments(nextPacket))
			{
				throw new InvalidDataException("Comment header was not readable!");
			}
			nextPacket.Done();
			nextPacket = _packetProvider.GetNextPacket();
			if (!LoadBooks(nextPacket))
			{
				throw new InvalidDataException("Book header was not readable!");
			}
			nextPacket.Done();
			InitDecoder();
			return true;
		}

		private void SetParametersChanging(object sender, ParameterChangeEventArgs e)
		{
			_parameterChangePacket = e.FirstPacket;
		}

		public void Dispose()
		{
			if (_packetProvider != null)
			{
				IPacketProvider packetProvider = _packetProvider;
				_packetProvider = null;
				packetProvider.ParameterChange -= SetParametersChanging;
				packetProvider.Dispose();
			}
		}

		private void ProcessParameterChange(DataPacket packet)
		{
			_parameterChangePacket = null;
			bool flag = false;
			bool isFullReset = false;
			if (ProcessStreamHeader(packet))
			{
				packet.Done();
				flag = true;
				isFullReset = true;
				packet = _packetProvider.PeekNextPacket();
				if (packet == null)
				{
					throw new InvalidDataException("Couldn't get next packet!");
				}
			}
			if (LoadComments(packet))
			{
				if (flag)
				{
					_packetProvider.GetNextPacket().Done();
				}
				else
				{
					packet.Done();
				}
				flag = true;
				packet = _packetProvider.PeekNextPacket();
				if (packet == null)
				{
					throw new InvalidDataException("Couldn't get next packet!");
				}
			}
			if (LoadBooks(packet))
			{
				if (flag)
				{
					_packetProvider.GetNextPacket().Done();
				}
				else
				{
					packet.Done();
				}
			}
			ResetDecoder(isFullReset);
		}

		private bool ProcessStreamHeader(DataPacket packet)
		{
			if (!packet.ReadBytes(7).SequenceEqual(new byte[7] { 1, 118, 111, 114, 98, 105, 115 }))
			{
				_glueBits += packet.Length * 8;
				return false;
			}
			if (!_pagesSeen.Contains(_lastPageSeen = packet.PageSequenceNumber))
			{
				_pagesSeen.Add(_lastPageSeen);
			}
			_glueBits += 56L;
			long bitsRead = packet.BitsRead;
			if (packet.ReadInt32() != 0)
			{
				throw new InvalidDataException("Only Vorbis stream version 0 is supported.");
			}
			_channels = packet.ReadByte();
			_sampleRate = packet.ReadInt32();
			_upperBitrate = packet.ReadInt32();
			_nominalBitrate = packet.ReadInt32();
			_lowerBitrate = packet.ReadInt32();
			Block0Size = 1 << (int)packet.ReadBits(4);
			Block1Size = 1 << (int)packet.ReadBits(4);
			if (_nominalBitrate == 0 && _upperBitrate > 0 && _lowerBitrate > 0)
			{
				_nominalBitrate = (_upperBitrate + _lowerBitrate) / 2;
			}
			_metaBits += packet.BitsRead - bitsRead + 8;
			_wasteHdrBits += 8 * packet.Length - packet.BitsRead;
			return true;
		}

		private bool LoadComments(DataPacket packet)
		{
			if (!packet.ReadBytes(7).SequenceEqual(new byte[7] { 3, 118, 111, 114, 98, 105, 115 }))
			{
				return false;
			}
			if (!_pagesSeen.Contains(_lastPageSeen = packet.PageSequenceNumber))
			{
				_pagesSeen.Add(_lastPageSeen);
			}
			_glueBits += 56L;
			_vendor = Encoding.UTF8.GetString(packet.ReadBytes(packet.ReadInt32()));
			_comments = new string[packet.ReadInt32()];
			for (int i = 0; i < _comments.Length; i++)
			{
				_comments[i] = Encoding.UTF8.GetString(packet.ReadBytes(packet.ReadInt32()));
			}
			_metaBits += packet.BitsRead - 56;
			_wasteHdrBits += 8 * packet.Length - packet.BitsRead;
			return true;
		}

		private bool LoadBooks(DataPacket packet)
		{
			if (!packet.ReadBytes(7).SequenceEqual(new byte[7] { 5, 118, 111, 114, 98, 105, 115 }))
			{
				return false;
			}
			if (!_pagesSeen.Contains(_lastPageSeen = packet.PageSequenceNumber))
			{
				_pagesSeen.Add(_lastPageSeen);
			}
			long bitsRead = packet.BitsRead;
			_glueBits += packet.BitsRead;
			Books = new VorbisCodebook[packet.ReadByte() + 1];
			for (int i = 0; i < Books.Length; i++)
			{
				Books[i] = VorbisCodebook.Init(this, packet, i);
			}
			_bookBits += packet.BitsRead - bitsRead;
			bitsRead = packet.BitsRead;
			Times = new VorbisTime[(int)packet.ReadBits(6) + 1];
			for (int j = 0; j < Times.Length; j++)
			{
				Times[j] = VorbisTime.Init(this, packet);
			}
			_timeHdrBits += packet.BitsRead - bitsRead;
			bitsRead = packet.BitsRead;
			Floors = new VorbisFloor[(int)packet.ReadBits(6) + 1];
			for (int k = 0; k < Floors.Length; k++)
			{
				Floors[k] = VorbisFloor.Init(this, packet);
			}
			_floorHdrBits += packet.BitsRead - bitsRead;
			bitsRead = packet.BitsRead;
			Residues = new VorbisResidue[(int)packet.ReadBits(6) + 1];
			for (int l = 0; l < Residues.Length; l++)
			{
				Residues[l] = VorbisResidue.Init(this, packet);
			}
			_resHdrBits += packet.BitsRead - bitsRead;
			bitsRead = packet.BitsRead;
			Maps = new VorbisMapping[(int)packet.ReadBits(6) + 1];
			for (int m = 0; m < Maps.Length; m++)
			{
				Maps[m] = VorbisMapping.Init(this, packet);
			}
			_mapHdrBits += packet.BitsRead - bitsRead;
			bitsRead = packet.BitsRead;
			Modes = new VorbisMode[(int)packet.ReadBits(6) + 1];
			for (int n = 0; n < Modes.Length; n++)
			{
				Modes[n] = VorbisMode.Init(this, packet);
			}
			_modeHdrBits += packet.BitsRead - bitsRead;
			if (!packet.ReadBit())
			{
				throw new InvalidDataException();
			}
			_glueBits++;
			_wasteHdrBits += 8 * packet.Length - packet.BitsRead;
			_modeFieldBits = Utils.ilog(Modes.Length - 1);
			return true;
		}

		private void InitDecoder()
		{
			_currentPosition = 0L;
			_resyncQueue = new Stack<DataPacket>();
			_bitsPerPacketHistory = new Queue<int>();
			_sampleCountHistory = new Queue<int>();
			ResetDecoder(isFullReset: true);
		}

		private void ResetDecoder(bool isFullReset)
		{
			if (_preparedLength > 0)
			{
				SaveBuffer();
			}
			if (isFullReset)
			{
				_noExecuteChannel = new bool[_channels];
				_floorData = new VorbisFloor.PacketData[_channels];
				_residue = new float[_channels][];
				for (int i = 0; i < _channels; i++)
				{
					_residue[i] = new float[Block1Size];
				}
				_outputBuffer = new RingBuffer(Block1Size * 2 * _channels);
				_outputBuffer.Channels = _channels;
			}
			else
			{
				_outputBuffer.Clear();
			}
			_preparedLength = 0;
		}

		private void SaveBuffer()
		{
			float[] array = new float[_preparedLength * _channels];
			ReadSamples(array, 0, array.Length);
			_prevBuffer = array;
		}

		private bool UnpackPacket(DataPacket packet)
		{
			if (packet.ReadBit())
			{
				return false;
			}
			int num = _modeFieldBits;
			_mode = Modes[(uint)packet.ReadBits(_modeFieldBits)];
			if (_mode.BlockFlag)
			{
				_prevFlag = packet.ReadBit();
				_nextFlag = packet.ReadBit();
				num += 2;
			}
			else
			{
				_prevFlag = (_nextFlag = false);
			}
			if (packet.IsShort)
			{
				return false;
			}
			long bitsRead = packet.BitsRead;
			int num2 = _mode.BlockSize / 2;
			for (int i = 0; i < _channels; i++)
			{
				_floorData[i] = _mode.Mapping.ChannelSubmap[i].Floor.UnpackPacket(packet, _mode.BlockSize, i);
				_noExecuteChannel[i] = !_floorData[i].ExecuteChannel;
				Array.Clear(_residue[i], 0, num2);
			}
			VorbisMapping.CouplingStep[] couplingSteps = _mode.Mapping.CouplingSteps;
			foreach (VorbisMapping.CouplingStep couplingStep in couplingSteps)
			{
				if (_floorData[couplingStep.Angle].ExecuteChannel || _floorData[couplingStep.Magnitude].ExecuteChannel)
				{
					_floorData[couplingStep.Angle].ForceEnergy = true;
					_floorData[couplingStep.Magnitude].ForceEnergy = true;
				}
			}
			long num3 = packet.BitsRead - bitsRead;
			bitsRead = packet.BitsRead;
			VorbisMapping.Submap[] submaps = _mode.Mapping.Submaps;
			foreach (VorbisMapping.Submap submap in submaps)
			{
				for (int k = 0; k < _channels; k++)
				{
					if (_mode.Mapping.ChannelSubmap[k] != submap)
					{
						_floorData[k].ForceNoEnergy = true;
					}
				}
				float[][] array = submap.Residue.Decode(packet, _noExecuteChannel, _channels, _mode.BlockSize);
				for (int l = 0; l < _channels; l++)
				{
					float[] array2 = _residue[l];
					float[] array3 = array[l];
					for (int m = 0; m < num2; m++)
					{
						array2[m] += array3[m];
					}
				}
			}
			_glueBits++;
			_modeBits += num;
			_floorBits += num3;
			_resBits += packet.BitsRead - bitsRead;
			_wasteBits += 8 * packet.Length - packet.BitsRead;
			_packetCount++;
			return true;
		}

		private void DecodePacket()
		{
			VorbisMapping.CouplingStep[] couplingSteps = _mode.Mapping.CouplingSteps;
			int num = _mode.BlockSize / 2;
			for (int num2 = couplingSteps.Length - 1; num2 >= 0; num2--)
			{
				if (_floorData[couplingSteps[num2].Angle].ExecuteChannel || _floorData[couplingSteps[num2].Magnitude].ExecuteChannel)
				{
					float[] array = _residue[couplingSteps[num2].Magnitude];
					float[] array

NAudio.dll

Decompiled 2 hours 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

CustomTextMusicMod.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using NAudio.Wave;
using NVorbis;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CustomTextMusicMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CustomTextMusicMod")]
[assembly: AssemblyTitle("CustomTextMusicMod")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TerraCalamityOST
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.terra.calamityost", "Terra Calamity OST", "2.5.0")]
	public class CustomTextMusicPlugin : BaseUnityPlugin
	{
		public class MusicRule
		{
			public string SceneKey;

			public bool IsBoss;

			public string FilePath;

			public float VolumeMultiplier;
		}

		private sealed class VorbisWaveProvider : WaveStream
		{
			private readonly VorbisReader _reader;

			private readonly WaveFormat _waveFormat;

			public override WaveFormat WaveFormat => _waveFormat;

			public override long Length => (long)(_reader.TotalTime.TotalSeconds * (double)_waveFormat.AverageBytesPerSecond);

			public override long Position
			{
				get
				{
					return (long)(_reader.DecodedTime.TotalSeconds * (double)_waveFormat.AverageBytesPerSecond);
				}
				set
				{
					_reader.DecodedTime = TimeSpan.FromSeconds((double)value / (double)_waveFormat.AverageBytesPerSecond);
				}
			}

			public VorbisWaveProvider(string fileName)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Expected O, but got Unknown
				_reader = new VorbisReader(fileName);
				_waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(_reader.SampleRate, _reader.Channels);
			}

			public override int Read(byte[] buffer, int offset, int count)
			{
				int num = count / 4;
				float[] array = new float[num];
				int num2 = _reader.ReadSamples(array, 0, num);
				Buffer.BlockCopy(array, 0, buffer, offset, num2 * 4);
				return num2 * 4;
			}

			protected override void Dispose(bool disposing)
			{
				if (disposing)
				{
					VorbisReader reader = _reader;
					if (reader != null)
					{
						reader.Dispose();
					}
				}
				((Stream)this).Dispose(disposing);
			}
		}

		private sealed class LoopingFadeSampleProvider : ISampleProvider
		{
			private readonly WaveStream _sourceStream;

			private readonly ISampleProvider _sampleProvider;

			private readonly object _lock = new object();

			public float TargetVolume { get; set; } = 1f;

			public float CurrentFade { get; private set; }

			public float TargetFade { get; private set; } = 1f;

			public float FadeStepPerSample { get; private set; }

			public WaveFormat WaveFormat => _sampleProvider.WaveFormat;

			public LoopingFadeSampleProvider(WaveStream sourceStream)
			{
				_sourceStream = sourceStream;
				_sampleProvider = WaveExtensionMethods.ToSampleProvider((IWaveProvider)(object)sourceStream);
			}

			public void SetFade(float startFade, float targetFade, float durationSeconds)
			{
				lock (_lock)
				{
					CurrentFade = Mathf.Clamp01(startFade);
					TargetFade = Mathf.Clamp01(targetFade);
					int num = Mathf.Max(1, (int)(durationSeconds * (float)WaveFormat.SampleRate * (float)WaveFormat.Channels));
					FadeStepPerSample = Mathf.Abs(TargetFade - CurrentFade) / (float)num;
				}
			}

			public int Read(float[] buffer, int offset, int count)
			{
				int i;
				int num;
				for (i = 0; i < count; i += num)
				{
					num = _sampleProvider.Read(buffer, offset + i, count - i);
					if (num == 0)
					{
						((Stream)(object)_sourceStream).Position = 0L;
						num = _sampleProvider.Read(buffer, offset + i, count - i);
						if (num == 0)
						{
							break;
						}
					}
				}
				lock (_lock)
				{
					float targetVolume = TargetVolume;
					for (int j = 0; j < i; j++)
					{
						if (CurrentFade < TargetFade)
						{
							CurrentFade = Mathf.Min(TargetFade, CurrentFade + FadeStepPerSample);
						}
						else if (CurrentFade > TargetFade)
						{
							CurrentFade = Mathf.Max(TargetFade, CurrentFade - FadeStepPerSample);
						}
						buffer[offset + j] *= targetVolume * CurrentFade;
					}
					return i;
				}
			}
		}

		private sealed class ActiveTrackStream : IDisposable
		{
			public string FilePath { get; }

			public float RuleVolumeMultiplier { get; set; }

			public WaveStream Reader { get; private set; }

			public LoopingFadeSampleProvider SampleProvider { get; private set; }

			public WaveOutEvent OutputDevice { get; private set; }

			public bool IsFadingOut { get; private set; }

			public bool IsDisposed { get; private set; }

			public ActiveTrackStream(string filePath, float ruleVolumeMultiplier)
			{
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Expected O, but got Unknown
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Expected O, but got Unknown
				FilePath = filePath;
				RuleVolumeMultiplier = ruleVolumeMultiplier;
				if (filePath.EndsWith(".ogg", StringComparison.OrdinalIgnoreCase))
				{
					Reader = (WaveStream)(object)new VorbisWaveProvider(filePath);
				}
				else
				{
					Reader = (WaveStream)new AudioFileReader(filePath);
				}
				SampleProvider = new LoopingFadeSampleProvider(Reader);
				OutputDevice = new WaveOutEvent();
				WaveExtensionMethods.Init((IWavePlayer)(object)OutputDevice, (ISampleProvider)(object)SampleProvider, false);
			}

			public void FadeIn(float durationSeconds, float targetVolume)
			{
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0068: Invalid comparison between Unknown and I4
				if (!IsDisposed)
				{
					IsFadingOut = false;
					SampleProvider.TargetVolume = targetVolume;
					if (durationSeconds <= 0.05f)
					{
						SampleProvider.SetFade(1f, 1f, 0.01f);
					}
					else
					{
						SampleProvider.SetFade(SampleProvider.CurrentFade, 1f, durationSeconds);
					}
					if ((int)OutputDevice.PlaybackState != 1)
					{
						OutputDevice.Play();
					}
				}
			}

			public void FadeOutAndPause(float durationSeconds)
			{
				if (!IsDisposed)
				{
					if (durationSeconds <= 0.05f)
					{
						SampleProvider.SetFade(0f, 0f, 0.01f);
						OutputDevice.Pause();
						IsFadingOut = false;
					}
					else
					{
						IsFadingOut = true;
						SampleProvider.SetFade(SampleProvider.CurrentFade, 0f, durationSeconds);
					}
				}
			}

			public void TickFadeCheck()
			{
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Invalid comparison between Unknown and I4
				if (!IsDisposed && IsFadingOut && SampleProvider.CurrentFade <= 0.001f)
				{
					IsFadingOut = false;
					if ((int)OutputDevice.PlaybackState == 1)
					{
						OutputDevice.Pause();
					}
				}
			}

			public void Dispose()
			{
				if (IsDisposed)
				{
					return;
				}
				IsDisposed = true;
				try
				{
					WaveOutEvent outputDevice = OutputDevice;
					if (outputDevice != null)
					{
						outputDevice.Stop();
					}
				}
				catch
				{
				}
				try
				{
					WaveOutEvent outputDevice2 = OutputDevice;
					if (outputDevice2 != null)
					{
						outputDevice2.Dispose();
					}
				}
				catch
				{
				}
				try
				{
					((Stream)(object)Reader)?.Dispose();
				}
				catch
				{
				}
			}
		}

		[HarmonyPatch(typeof(MusicController), "UpdateState")]
		private static class MusicControllerMutePatch
		{
			private static void Postfix(MusicController __instance)
			{
				if ((Object)(object)Instance != (Object)null && Instance._enableMod.Value && Instance._currentStream != null)
				{
					AkSoundEngine.PostEvent("Pause_Music", ((Component)__instance).gameObject);
				}
			}
		}

		[HarmonyPatch(typeof(TeleporterInteraction), "OnInteractionBegin")]
		private static class TeleporterPatch
		{
			private static void Postfix()
			{
				if (!((Object)(object)Instance == (Object)null) && Instance._enableMod.Value)
				{
					Instance._isBossFight = true;
					Instance._bossGraceTimer = Mathf.Max(0f, Instance._bossGraceSecondsConfig.Value);
					Instance.CheckAndUpdateMusic();
				}
			}
		}

		[HarmonyPatch(typeof(Interactor), "PerformInteraction")]
		private static class InteractorPerformInteractionPatch
		{
			private static void Postfix(GameObject interactableObject)
			{
				if (!((Object)(object)Instance == (Object)null) && Instance._enableMod.Value)
				{
					Instance.OnInteractableTriggered(interactableObject);
				}
			}
		}

		[HarmonyPatch(typeof(PurchaseInteraction), "OnInteractionBegin")]
		private static class PurchaseInteractionPatch
		{
			private static void Postfix(PurchaseInteraction __instance)
			{
				if (!((Object)(object)Instance == (Object)null) && Instance._enableMod.Value && !((Object)(object)__instance == (Object)null))
				{
					Instance.OnInteractableTriggered(((Component)__instance).gameObject);
				}
			}
		}

		private readonly Dictionary<string, List<MusicRule>> _musicRules = new Dictionary<string, List<MusicRule>>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, ActiveTrackStream> _cachedStreams = new Dictionary<string, ActiveTrackStream>(StringComparer.OrdinalIgnoreCase);

		private ActiveTrackStream _currentStream;

		private string _currentSceneName = "";

		private bool _isBossFight;

		private bool _arenaBossLocked;

		private float _bossGraceTimer;

		private bool _champRushRitualStarted;

		private bool _champRushFinalBossSpawned;

		private ConfigEntry<bool> _enableMod;

		private ConfigEntry<float> _masterVolumeConfig;

		private ConfigEntry<float> _stageVolumeConfig;

		private ConfigEntry<float> _bossVolumeConfig;

		private ConfigEntry<float> _crossfadeSecondsConfig;

		private ConfigEntry<float> _bossGraceSecondsConfig;

		private string _pluginFolderPath;

		private string _musicTxtFilePath;

		private readonly Random _rng = new Random();

		public static CustomTextMusicPlugin Instance { get; private set; }

		public void Awake()
		{
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			_pluginFolderPath = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Paths.PluginPath;
			_musicTxtFilePath = Path.Combine(_pluginFolderPath, "music_list.txt");
			_enableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMod", true, "Включить замену музыки.");
			_masterVolumeConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Volume", "MasterVolume", 100f, "Общая громкость музыки (%).");
			_stageVolumeConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Volume", "StageVolume", 100f, "Громкость музыки локаций (%).");
			_bossVolumeConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Volume", "BossVolume", 100f, "Громкость музыки боссов (%).");
			_crossfadeSecondsConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Transitions", "CrossfadeSeconds", 2.5f, "Длительность плавного перехода между треками (сек).");
			_bossGraceSecondsConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Transitions", "BossGraceSeconds", 15f, "Время удержания музыки босса после исчезновения полоски ХП (сек).");
			_enableMod.SettingChanged += delegate
			{
				if (!_enableMod.Value)
				{
					StopAllStreams(disposeAll: true);
				}
				else
				{
					CheckAndUpdateMusic();
				}
			};
			CreateDefaultConfigIfNotExists();
			LoadMusicList();
			new Harmony("com.terra.calamityost").PatchAll();
			SceneManager.sceneLoaded += OnSceneLoaded;
			SetupRiskOfOptions();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Terra Calamity OST 2.5.0 initialized.");
		}

		public void OnDestroy()
		{
			StopAllStreams(disposeAll: true);
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			string text = ((Scene)(ref scene)).name.ToLowerInvariant();
			bool num = !string.Equals(_currentSceneName, text, StringComparison.OrdinalIgnoreCase);
			_currentSceneName = text;
			_isBossFight = false;
			_arenaBossLocked = false;
			_bossGraceTimer = 0f;
			_champRushRitualStarted = false;
			_champRushFinalBossSpawned = false;
			if (num)
			{
				CleanupUnusedStreams();
			}
			CheckAndUpdateMusic();
		}

		private void Update()
		{
			foreach (KeyValuePair<string, ActiveTrackStream> cachedStream in _cachedStreams)
			{
				cachedStream.Value.TickFadeCheck();
			}
			if (!_enableMod.Value)
			{
				return;
			}
			if (IsChampRushScene(_currentSceneName))
			{
				if (!_champRushRitualStarted && IsStandardBossGroupOrTeleporterActive())
				{
					_champRushRitualStarted = true;
					CheckAndUpdateMusic();
				}
				if (!_champRushFinalBossSpawned && IsChampRushFinalBossActive())
				{
					_champRushFinalBossSpawned = true;
					_champRushRitualStarted = true;
					_arenaBossLocked = true;
				}
			}
			bool num = IsBossCurrentlyActive();
			if (num)
			{
				_bossGraceTimer = Mathf.Max(0f, _bossGraceSecondsConfig.Value);
				if (IsMultiPhaseBossScene(_currentSceneName))
				{
					_arenaBossLocked = true;
				}
			}
			else if (_bossGraceTimer > 0f)
			{
				_bossGraceTimer -= Time.unscaledDeltaTime;
			}
			bool flag = num || _bossGraceTimer > 0f || _arenaBossLocked;
			if (flag != _isBossFight)
			{
				_isBossFight = flag;
				CheckAndUpdateMusic();
			}
			UpdateActiveStreamVolume();
		}

		private static bool IsChampRushScene(string sceneName)
		{
			return string.Equals(sceneName, "champrush", StringComparison.OrdinalIgnoreCase);
		}

		private static bool IsMultiPhaseBossScene(string sceneName)
		{
			if (string.IsNullOrEmpty(sceneName))
			{
				return false;
			}
			if (!sceneName.Contains("moon") && !sceneName.Contains("meridian") && !sceneName.Contains("voidraid") && !sceneName.Contains("solusweb") && !sceneName.Contains("solutionalhaunt"))
			{
				return sceneName.Contains("champrush");
			}
			return true;
		}

		private bool IsBossCurrentlyActive()
		{
			if (IsChampRushScene(_currentSceneName))
			{
				if (!_champRushFinalBossSpawned)
				{
					return IsChampRushFinalBossActive();
				}
				return true;
			}
			return IsStandardBossGroupOrTeleporterActive();
		}

		private static bool IsStandardBossGroupOrTeleporterActive()
		{
			if ((Object)(object)TeleporterInteraction.instance != (Object)null && TeleporterInteraction.instance.isCharging && !TeleporterInteraction.instance.isCharged)
			{
				return true;
			}
			List<BossGroup> instancesList = InstanceTracker.GetInstancesList<BossGroup>();
			if (instancesList != null)
			{
				for (int i = 0; i < instancesList.Count; i++)
				{
					BossGroup val = instancesList[i];
					if ((Object)(object)val != (Object)null && (Object)(object)val.combatSquad != (Object)null && val.combatSquad.memberCount > 0)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool IsChampRushFinalBossActive()
		{
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			if (readOnlyInstancesList == null)
			{
				return false;
			}
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				CharacterBody val = readOnlyInstancesList[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string text = ((Object)val).name ?? "";
				if (text.IndexOf("ChampRushReaper", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("AnimaHarvester", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("AnimaExtractor", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
				EntityStateMachine[] components = ((Component)val).GetComponents<EntityStateMachine>();
				if (components == null)
				{
					continue;
				}
				foreach (EntityStateMachine val2 in components)
				{
					if ((Object)(object)val2 != (Object)null && val2.state != null && (((object)val2.state).GetType().FullName ?? "").IndexOf("ChampRushReaper", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return true;
					}
				}
			}
			return false;
		}

		public void OnInteractableTriggered(GameObject interactableObject)
		{
			if (IsChampRushScene(_currentSceneName) && !_champRushRitualStarted && !((Object)(object)interactableObject == (Object)null) && !((Object)(object)interactableObject.GetComponent<GenericPickupController>() != (Object)null) && !((Object)(object)interactableObject.GetComponent<PickupPickerController>() != (Object)null) && !((Object)(object)interactableObject.GetComponent<CharacterBody>() != (Object)null))
			{
				_champRushRitualStarted = true;
				CheckAndUpdateMusic();
			}
		}

		private void CreateDefaultConfigIfNotExists()
		{
			if (!File.Exists(_musicTxtFilePath))
			{
				string contents = "# Код_Сцены | Тип (Stage/Boss) | Имя_файла | Громкость_%\nany | Stage | default_stage.mp3 | 100\nany | Boss  | default_boss.mp3  | 100\n";
				File.WriteAllText(_musicTxtFilePath, contents);
			}
		}

		private string ResolveAudioFilePath(string rawFileName)
		{
			if (string.IsNullOrWhiteSpace(rawFileName))
			{
				return null;
			}
			string text = rawFileName.Trim().Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
			string fileName = Path.GetFileName(text);
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text);
			string[] array = new string[2]
			{
				_pluginFolderPath,
				Path.Combine(_pluginFolderPath, "Tracks")
			};
			if (Path.IsPathRooted(text) && File.Exists(text))
			{
				return text;
			}
			string text2 = Path.Combine(_pluginFolderPath, text);
			if (File.Exists(text2))
			{
				return text2;
			}
			string[] array2 = new string[3] { ".mp3", ".ogg", ".wav" };
			string[] array3 = array;
			foreach (string text3 in array3)
			{
				if (!Directory.Exists(text3))
				{
					continue;
				}
				string text4 = Path.Combine(text3, fileName);
				if (File.Exists(text4))
				{
					return text4;
				}
				string[] array4 = array2;
				foreach (string text5 in array4)
				{
					string text6 = Path.Combine(text3, fileNameWithoutExtension + text5);
					if (File.Exists(text6))
					{
						return text6;
					}
				}
			}
			return null;
		}

		public void LoadMusicList()
		{
			_musicRules.Clear();
			if (!File.Exists(_musicTxtFilePath))
			{
				return;
			}
			string[] array = File.ReadAllLines(_musicTxtFilePath);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (string.IsNullOrEmpty(text) || text.StartsWith("#") || text.StartsWith("//"))
				{
					continue;
				}
				string[] array2 = text.Split('|');
				if (array2.Length < 3)
				{
					continue;
				}
				string text2 = array2[0].Trim().ToLowerInvariant();
				string text3 = array2[1].Trim();
				string rawFileName = array2[2].Trim();
				float result = 100f;
				if (array2.Length >= 4 && !float.TryParse(array2[3].Trim().Replace("%", "").Replace(",", "."), NumberStyles.Float, CultureInfo.InvariantCulture, out result))
				{
					result = 100f;
				}
				string text4 = ResolveAudioFilePath(rawFileName);
				if (!string.IsNullOrEmpty(text4))
				{
					bool flag = text3.Equals("Boss", StringComparison.OrdinalIgnoreCase);
					string key = text2 + "_" + (flag ? "Boss" : "Stage");
					if (!_musicRules.TryGetValue(key, out var value))
					{
						value = new List<MusicRule>();
						_musicRules[key] = value;
					}
					value.Add(new MusicRule
					{
						SceneKey = text2,
						IsBoss = flag,
						FilePath = text4,
						VolumeMultiplier = Mathf.Clamp(result / 100f, 0f, 3f)
					});
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Loaded {_musicRules.Count} music rule groups from music_list.txt.");
		}

		public void CheckAndUpdateMusic()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!_enableMod.Value)
			{
				return;
			}
			if (string.IsNullOrEmpty(_currentSceneName))
			{
				Scene activeScene = SceneManager.GetActiveScene();
				if (!((Scene)(ref activeScene)).IsValid() || string.IsNullOrEmpty(((Scene)(ref activeScene)).name))
				{
					return;
				}
				_currentSceneName = ((Scene)(ref activeScene)).name.ToLowerInvariant();
			}
			if (IsChampRushScene(_currentSceneName) && !_champRushRitualStarted && !_champRushFinalBossSpawned)
			{
				if (_currentStream != null)
				{
					_currentStream.FadeOutAndPause(_crossfadeSecondsConfig.Value);
					_currentStream = null;
				}
				return;
			}
			MusicRule musicRule = FindRuleForState(_currentSceneName, _isBossFight);
			if (musicRule == null && _isBossFight)
			{
				musicRule = FindRuleForState(_currentSceneName, isBoss: false);
			}
			if (musicRule == null)
			{
				if (_currentStream != null && !_isBossFight)
				{
					_currentStream.FadeOutAndPause(_crossfadeSecondsConfig.Value);
					_currentStream = null;
				}
			}
			else if (_currentStream != null && string.Equals(_currentStream.FilePath, musicRule.FilePath, StringComparison.OrdinalIgnoreCase))
			{
				_currentStream.RuleVolumeMultiplier = musicRule.VolumeMultiplier;
				_currentStream.FadeIn(_crossfadeSecondsConfig.Value, CalculateTargetVolume(musicRule.VolumeMultiplier));
			}
			else
			{
				SwitchToTrack(musicRule);
			}
		}

		private MusicRule FindRuleForState(string sceneName, bool isBoss)
		{
			string text = (isBoss ? "_Boss" : "_Stage");
			string key = sceneName + text;
			if (_musicRules.TryGetValue(key, out var value) && value.Count > 0)
			{
				return value[_rng.Next(value.Count)];
			}
			string key2 = "any" + text;
			if (_musicRules.TryGetValue(key2, out var value2) && value2.Count > 0)
			{
				return value2[_rng.Next(value2.Count)];
			}
			return null;
		}

		private float CalculateTargetVolume(float ruleVolumeMultiplier)
		{
			float num = _masterVolumeConfig.Value / 100f;
			float num2 = (_isBossFight ? _bossVolumeConfig.Value : _stageVolumeConfig.Value) / 100f;
			return Mathf.Clamp(num * num2 * ruleVolumeMultiplier, 0f, 1f);
		}

		private void UpdateActiveStreamVolume()
		{
			if (_currentStream != null && !_currentStream.IsDisposed)
			{
				_currentStream.SampleProvider.TargetVolume = CalculateTargetVolume(_currentStream.RuleVolumeMultiplier);
			}
		}

		private void SwitchToTrack(MusicRule rule)
		{
			float durationSeconds = Mathf.Max(0f, _crossfadeSecondsConfig.Value);
			if (_currentStream != null && !_currentStream.IsDisposed)
			{
				_currentStream.FadeOutAndPause(durationSeconds);
			}
			try
			{
				if (!_cachedStreams.TryGetValue(rule.FilePath, out var value) || value.IsDisposed)
				{
					value = new ActiveTrackStream(rule.FilePath, rule.VolumeMultiplier);
					_cachedStreams[rule.FilePath] = value;
				}
				else
				{
					value.RuleVolumeMultiplier = rule.VolumeMultiplier;
				}
				_currentStream = value;
				float targetVolume = CalculateTargetVolume(rule.VolumeMultiplier);
				_currentStream.FadeIn(durationSeconds, targetVolume);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Failed to play track '" + Path.GetFileName(rule.FilePath) + "': " + ex.Message));
			}
		}

		private void CleanupUnusedStreams()
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, ActiveTrackStream> cachedStream in _cachedStreams)
			{
				if (cachedStream.Value != _currentStream && !cachedStream.Value.IsFadingOut)
				{
					cachedStream.Value.Dispose();
					list.Add(cachedStream.Key);
				}
			}
			foreach (string item in list)
			{
				_cachedStreams.Remove(item);
			}
		}

		private void StopAllStreams(bool disposeAll)
		{
			foreach (KeyValuePair<string, ActiveTrackStream> cachedStream in _cachedStreams)
			{
				if (disposeAll)
				{
					cachedStream.Value.Dispose();
				}
				else
				{
					cachedStream.Value.FadeOutAndPause(0f);
				}
			}
			if (disposeAll)
			{
				_cachedStreams.Clear();
			}
			_currentStream = null;
		}

		private void SetupRiskOfOptions()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0099: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: 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_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Expected O, but got Unknown
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Expected O, but got Unknown
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Expected O, but got Unknown
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Expected O, but got Unknown
			if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"))
			{
				ModSettingsManager.SetModDescription("Custom Text Music Loader v2.5.0 — настройка громкости и переходов.");
				TrySetModIcon();
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(_enableMod));
				ModSettingsManager.AddOption((BaseOption)new SliderOption(_masterVolumeConfig, new SliderConfig
				{
					min = 0f,
					max = 100f,
					FormatString = "{0:0}%"
				}));
				ModSettingsManager.AddOption((BaseOption)new SliderOption(_stageVolumeConfig, new SliderConfig
				{
					min = 0f,
					max = 100f,
					FormatString = "{0:0}%"
				}));
				ModSettingsManager.AddOption((BaseOption)new SliderOption(_bossVolumeConfig, new SliderConfig
				{
					min = 0f,
					max = 100f,
					FormatString = "{0:0}%"
				}));
				ModSettingsManager.AddOption((BaseOption)new SliderOption(_crossfadeSecondsConfig, new SliderConfig
				{
					min = 0f,
					max = 10f,
					FormatString = "{0:0.0} с"
				}));
				ModSettingsManager.AddOption((BaseOption)new SliderOption(_bossGraceSecondsConfig, new SliderConfig
				{
					min = 0f,
					max = 60f,
					FormatString = "{0:0} с"
				}));
				ModSettingsManager.AddOption((BaseOption)new GenericButtonOption("Перезагрузить music_list.txt", "General", "Перечитывает файл конфигурации без перезапуска игры.", "Обновить", (UnityAction)delegate
				{
					LoadMusicList();
					CheckAndUpdateMusic();
				}));
			}
		}

		private void TrySetModIcon()
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string path = Path.Combine(_pluginFolderPath, "icon.png");
				if (!File.Exists(path))
				{
					DirectoryInfo parent = Directory.GetParent(_pluginFolderPath);
					if (parent != null)
					{
						string text = Path.Combine(parent.FullName, "icon.png");
						if (File.Exists(text))
						{
							path = text;
						}
					}
				}
				if (File.Exists(path))
				{
					byte[] array = File.ReadAllBytes(path);
					Texture2D val = new Texture2D(256, 256, (TextureFormat)4, false);
					if (ImageConversion.LoadImage(val, array))
					{
						((Object)val).name = "TerraCalamityOST_Icon";
						ModSettingsManager.SetModIcon(Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)));
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to load icon.png for RiskOfOptions: " + ex.Message));
			}
		}
	}
}