Decompiled source of RadioLib v1.1.0

NLayer.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using NLayer.Decoder;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Mark Heath, Andrew Ward")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Fully Managed MPEG 1 & 2 Decoder for Layers 1, 2, & 3")]
[assembly: AssemblyFileVersion("1.16.0.0")]
[assembly: AssemblyInformationalVersion("1.16.0+c88b0d8abfa15c1e506106931ea8410170dc6326")]
[assembly: AssemblyProduct("NLayer")]
[assembly: AssemblyTitle("NLayer")]
[assembly: AssemblyVersion("1.16.0.0")]
namespace NLayer
{
	public enum MpegVersion
	{
		Unknown = 0,
		Version1 = 10,
		Version2 = 20,
		Version25 = 25
	}
	public enum MpegLayer
	{
		Unknown,
		LayerI,
		LayerII,
		LayerIII
	}
	public enum MpegChannelMode
	{
		Stereo,
		JointStereo,
		DualChannel,
		Mono
	}
	public enum StereoMode
	{
		Both,
		LeftOnly,
		RightOnly,
		DownmixToMono
	}
	public interface IMpegFrame
	{
		int SampleRate { get; }

		int SampleRateIndex { get; }

		int FrameLength { get; }

		int BitRate { get; }

		MpegVersion Version { get; }

		MpegLayer Layer { get; }

		MpegChannelMode ChannelMode { get; }

		int ChannelModeExtension { get; }

		int SampleCount { get; }

		int BitRateIndex { get; }

		bool IsCopyrighted { get; }

		bool HasCrc { get; }

		bool IsCorrupted { get; }

		void Reset();

		int ReadBits(int bitCount);
	}
	public class MpegFile : IDisposable
	{
		private Stream _stream;

		private bool _closeStream;

		private bool _eofFound;

		private MpegStreamReader _reader;

		private MpegFrameDecoder _decoder;

		private object _seekLock = new object();

		private long _position;

		private float[] _readBuf = new float[2304];

		private int _readBufLen;

		private int _readBufOfs;

		public int SampleRate => _reader.SampleRate;

		public int Channels => _reader.Channels;

		public bool CanSeek => _reader.CanSeek;

		public long Length => _reader.SampleCount * _reader.Channels * 4;

		public TimeSpan Duration
		{
			get
			{
				long sampleCount = _reader.SampleCount;
				if (sampleCount == -1)
				{
					return TimeSpan.Zero;
				}
				return TimeSpan.FromSeconds((double)sampleCount / (double)_reader.SampleRate);
			}
		}

		public long Position
		{
			get
			{
				return _position;
			}
			set
			{
				if (!_reader.CanSeek)
				{
					throw new InvalidOperationException("Cannot Seek!");
				}
				if (value < 0)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				long num = value / 4 / _reader.Channels;
				int num2 = 0;
				if (num >= _reader.FirstFrameSampleCount)
				{
					num2 = _reader.FirstFrameSampleCount;
					num -= num2;
				}
				lock (_seekLock)
				{
					long num3 = _reader.SeekTo(num);
					if (num3 == -1)
					{
						throw new ArgumentOutOfRangeException("value");
					}
					_decoder.Reset();
					if (num2 != 0)
					{
						_decoder.DecodeFrame(_reader.NextFrame(), _readBuf, 0);
						num3 += num2;
					}
					_position = num3 * 4 * _reader.Channels;
					_eofFound = false;
					_readBufOfs = (_readBufLen = 0);
				}
			}
		}

		public TimeSpan Time
		{
			get
			{
				return TimeSpan.FromSeconds((double)_position / 4.0 / (double)_reader.Channels / (double)_reader.SampleRate);
			}
			set
			{
				Position = (long)(value.TotalSeconds * (double)_reader.SampleRate * (double)_reader.Channels * 4.0);
			}
		}

		public StereoMode StereoMode
		{
			get
			{
				return _decoder.StereoMode;
			}
			set
			{
				_decoder.StereoMode = value;
			}
		}

		public MpegFile(string fileName)
		{
			Init(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read), closeStream: true);
		}

		public MpegFile(Stream stream)
		{
			Init(stream, closeStream: false);
		}

		private void Init(Stream stream, bool closeStream)
		{
			_stream = stream;
			_closeStream = closeStream;
			_reader = new MpegStreamReader(_stream);
			_decoder = new MpegFrameDecoder();
		}

		public void Dispose()
		{
			if (_closeStream)
			{
				_stream.Dispose();
				_closeStream = false;
			}
		}

		public void SetEQ(float[] eq)
		{
			_decoder.SetEQ(eq);
		}

		public int ReadSamples(byte[] buffer, int index, int count)
		{
			if (index < 0 || index + count > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			count -= count % 4;
			return ReadSamplesImpl(buffer, index, count, 32);
		}

		public int ReadSamples(float[] buffer, int index, int count)
		{
			if (index < 0 || index + count > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			return ReadSamplesImpl(buffer, index * 4, count * 4, 32) / 4;
		}

		public int ReadSamplesInt16(byte[] buffer, int index, int count)
		{
			if (index < 0 || index + count > buffer.Length * 2)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			return ReadSamplesImpl(buffer, index, count, 16) * 2 / 4;
		}

		public int ReadSamplesInt8(byte[] buffer, int index, int count)
		{
			if (index < 0 || index + count > buffer.Length * 4)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			return ReadSamplesImpl(buffer, index, count, 8) / 4;
		}

		private int ReadSamplesImpl(Array buffer, int index, int count, int bitDepth)
		{
			int num = 0;
			lock (_seekLock)
			{
				while (count > 0)
				{
					if (_readBufLen > _readBufOfs)
					{
						int num2 = _readBufLen - _readBufOfs;
						if (num2 > count)
						{
							num2 = count;
						}
						if (bitDepth == 32)
						{
							Buffer.BlockCopy(_readBuf, _readBufOfs, buffer, index, num2);
						}
						else
						{
							for (int i = 0; i < num2 / 4; i++)
							{
								switch (bitDepth)
								{
								case 8:
									buffer.SetValue((byte)Math.Round(127.5f * _readBuf[_readBufOfs / 4 + i] + 127.5f), index / 4 + i);
									break;
								case 16:
								{
									int num3 = (int)Math.Round(32767.5f * _readBuf[_readBufOfs / 4 + i] - 0.5f);
									if (num3 < 0)
									{
										num3 += 65536;
									}
									buffer.SetValue((byte)(num3 % 256), 2 * (index / 4 + i));
									buffer.SetValue((byte)(num3 / 256), 2 * (index / 4 + i) + 1);
									break;
								}
								}
							}
						}
						num += num2;
						count -= num2;
						index += num2;
						_position += num2;
						_readBufOfs += num2;
						if (_readBufOfs == _readBufLen)
						{
							_readBufLen = 0;
						}
					}
					if (_readBufLen != 0)
					{
						continue;
					}
					if (_eofFound)
					{
						break;
					}
					MpegFrame mpegFrame = _reader.NextFrame();
					if (mpegFrame == null)
					{
						_eofFound = true;
						break;
					}
					try
					{
						_readBufLen = _decoder.DecodeFrame(mpegFrame, _readBuf, 0) * 4;
						_readBufOfs = 0;
					}
					catch (InvalidDataException)
					{
						_decoder.Reset();
						_readBufOfs = (_readBufLen = 0);
					}
					catch (EndOfStreamException)
					{
						_eofFound = true;
						break;
					}
					finally
					{
						mpegFrame.ClearBuffer();
					}
				}
			}
			return num;
		}
	}
	public class MpegFrameDecoder
	{
		private LayerIDecoder _layerIDecoder;

		private LayerIIDecoder _layerIIDecoder;

		private LayerIIIDecoder _layerIIIDecoder;

		private float[] _eqFactors;

		private float[] _ch0;

		private float[] _ch1;

		public StereoMode StereoMode { get; set; }

		public MpegFrameDecoder()
		{
			_ch0 = new float[1152];
			_ch1 = new float[1152];
		}

		public void SetEQ(float[] eq)
		{
			if (eq != null)
			{
				float[] array = new float[32];
				for (int i = 0; i < eq.Length; i++)
				{
					array[i] = (float)Math.Pow(2.0, eq[i] / 6f);
				}
				_eqFactors = array;
			}
			else
			{
				_eqFactors = null;
			}
		}

		public int DecodeFrame(IMpegFrame frame, byte[] dest, int destOffset)
		{
			if (frame == null)
			{
				throw new ArgumentNullException("frame");
			}
			if (dest == null)
			{
				throw new ArgumentNullException("dest");
			}
			if (destOffset % 4 != 0)
			{
				throw new ArgumentException("Must be an even multiple of 4", "destOffset");
			}
			if ((dest.Length - destOffset) / 4 < ((frame.ChannelMode == MpegChannelMode.Mono) ? 1 : 2) * frame.SampleCount)
			{
				throw new ArgumentException("Buffer not large enough!  Must be big enough to hold the frame's entire output.  This is up to 9,216 bytes.", "dest");
			}
			return DecodeFrameImpl(frame, dest, destOffset / 4) * 4;
		}

		public int DecodeFrame(IMpegFrame frame, float[] dest, int destOffset)
		{
			if (frame == null)
			{
				throw new ArgumentNullException("frame");
			}
			if (dest == null)
			{
				throw new ArgumentNullException("dest");
			}
			if (dest.Length - destOffset < ((frame.ChannelMode == MpegChannelMode.Mono) ? 1 : 2) * frame.SampleCount)
			{
				throw new ArgumentException("Buffer not large enough!  Must be big enough to hold the frame's entire output.  This is up to 2,304 elements.", "dest");
			}
			return DecodeFrameImpl(frame, dest, destOffset);
		}

		private int DecodeFrameImpl(IMpegFrame frame, Array dest, int destOffset)
		{
			frame.Reset();
			LayerDecoderBase layerDecoderBase = null;
			switch (frame.Layer)
			{
			case MpegLayer.LayerI:
				if (_layerIDecoder == null)
				{
					_layerIDecoder = new LayerIDecoder();
				}
				layerDecoderBase = _layerIDecoder;
				break;
			case MpegLayer.LayerII:
				if (_layerIIDecoder == null)
				{
					_layerIIDecoder = new LayerIIDecoder();
				}
				layerDecoderBase = _layerIIDecoder;
				break;
			case MpegLayer.LayerIII:
				if (_layerIIIDecoder == null)
				{
					_layerIIIDecoder = new LayerIIIDecoder();
				}
				layerDecoderBase = _layerIIIDecoder;
				break;
			}
			if (layerDecoderBase != null)
			{
				layerDecoderBase.SetEQ(_eqFactors);
				layerDecoderBase.StereoMode = StereoMode;
				int num = layerDecoderBase.DecodeFrame(frame, _ch0, _ch1);
				if (frame.ChannelMode == MpegChannelMode.Mono)
				{
					Buffer.BlockCopy(_ch0, 0, dest, destOffset * 4, num * 4);
				}
				else
				{
					for (int i = 0; i < num; i++)
					{
						Buffer.BlockCopy(_ch0, i * 4, dest, destOffset * 4, 4);
						destOffset++;
						Buffer.BlockCopy(_ch1, i * 4, dest, destOffset * 4, 4);
						destOffset++;
					}
					num *= 2;
				}
				return num;
			}
			return 0;
		}

		public void Reset()
		{
			if (_layerIDecoder != null)
			{
				_layerIDecoder.ResetForSeek();
			}
			if (_layerIIDecoder != null)
			{
				_layerIIDecoder.ResetForSeek();
			}
			if (_layerIIIDecoder != null)
			{
				_layerIIIDecoder.ResetForSeek();
			}
		}
	}
}
namespace NLayer.Decoder
{
	internal class BitReservoir
	{
		private byte[] _buf = new byte[8192];

		private int _start;

		private int _end = -1;

		private int _bitsLeft;

		private long _bitsRead;

		public int BitsAvailable
		{
			get
			{
				if (_bitsLeft > 0)
				{
					return (_end + _buf.Length - _start) % _buf.Length * 8 + _bitsLeft;
				}
				return 0;
			}
		}

		public long BitsRead => _bitsRead;

		private static int GetSlots(IMpegFrame frame)
		{
			int num = frame.FrameLength - 4;
			if (frame.HasCrc)
			{
				num -= 2;
			}
			if (frame.Version == MpegVersion.Version1 && frame.ChannelMode != MpegChannelMode.Mono)
			{
				return num - 32;
			}
			if (frame.Version > MpegVersion.Version1 && frame.ChannelMode == MpegChannelMode.Mono)
			{
				return num - 9;
			}
			return num - 17;
		}

		public bool AddBits(IMpegFrame frame, int overlap)
		{
			int end = _end;
			int num = GetSlots(frame);
			while (--num >= 0)
			{
				int num2 = frame.ReadBits(8);
				if (num2 == -1)
				{
					throw new InvalidDataException("Frame did not have enough bytes!");
				}
				_buf[++_end] = (byte)num2;
				if (_end == _buf.Length - 1)
				{
					_end = -1;
				}
			}
			_bitsLeft = 8;
			if (end == -1)
			{
				return overlap == 0;
			}
			if ((end + 1 - _start + _buf.Length) % _buf.Length >= overlap)
			{
				_start = (end + 1 - overlap + _buf.Length) % _buf.Length;
				return true;
			}
			_start = end + overlap;
			return false;
		}

		public int GetBits(int count)
		{
			int readCount;
			int result = TryPeekBits(count, out readCount);
			if (readCount < count)
			{
				throw new InvalidDataException("Reservoir did not have enough bytes!");
			}
			SkipBits(count);
			return result;
		}

		public int Get1Bit()
		{
			if (_bitsLeft == 0)
			{
				throw new InvalidDataException("Reservoir did not have enough bytes!");
			}
			_bitsLeft--;
			_bitsRead++;
			int result = (_buf[_start] >> _bitsLeft) & 1;
			if (_bitsLeft == 0 && (_start = (_start + 1) % _buf.Length) != _end + 1)
			{
				_bitsLeft = 8;
			}
			return result;
		}

		public int TryPeekBits(int count, out int readCount)
		{
			if (count < 0 || count > 32)
			{
				throw new ArgumentOutOfRangeException("count", "Must return between 0 and 32 bits!");
			}
			if (_bitsLeft == 0 || count == 0)
			{
				readCount = 0;
				return 0;
			}
			int num = _buf[_start];
			if (count < _bitsLeft)
			{
				num >>= _bitsLeft - count;
				num &= (1 << count) - 1;
				readCount = count;
				return num;
			}
			num &= (1 << _bitsLeft) - 1;
			count -= _bitsLeft;
			readCount = _bitsLeft;
			int num2 = _start;
			while (count > 0 && (num2 = (num2 + 1) % _buf.Length) != _end + 1)
			{
				int num3 = Math.Min(count, 8);
				num <<= num3;
				num |= _buf[num2] >> (8 - num3) % 8;
				count -= num3;
				readCount += num3;
			}
			return num;
		}

		public void SkipBits(int count)
		{
			if (count > 0)
			{
				if (count > BitsAvailable)
				{
					throw new ArgumentOutOfRangeException("count");
				}
				int num = 8 - _bitsLeft + count;
				_start = (num / 8 + _start) % _buf.Length;
				_bitsLeft = 8 - num % 8;
				_bitsRead += count;
			}
		}

		public void RewindBits(int count)
		{
			_bitsLeft += count;
			_bitsRead -= count;
			while (_bitsLeft > 8)
			{
				_start--;
				_bitsLeft -= 8;
			}
			while (_start < 0)
			{
				_start += _buf.Length;
			}
		}

		public void FlushBits()
		{
			if (_bitsLeft < 8)
			{
				SkipBits(_bitsLeft);
			}
		}

		public void Reset()
		{
			_start = 0;
			_end = -1;
			_bitsLeft = 0;
		}
	}
	internal abstract class FrameBase
	{
		private static int _totalAllocation;

		private MpegStreamReader _reader;

		private byte[] _savedBuffer;

		internal static int TotalAllocation => Interlocked.CompareExchange(ref _totalAllocation, 0, 0);

		internal long Offset { get; private set; }

		internal int Length { get; set; }

		internal bool Validate(long offset, MpegStreamReader reader)
		{
			Offset = offset;
			_reader = reader;
			int num = Validate();
			if (num > 0)
			{
				Length = num;
				return true;
			}
			return false;
		}

		protected int Read(int offset, byte[] buffer)
		{
			return Read(offset, buffer, 0, buffer.Length);
		}

		protected int Read(int offset, byte[] buffer, int index, int count)
		{
			if (_savedBuffer != null)
			{
				if (index < 0 || index + count > buffer.Length)
				{
					return 0;
				}
				if (offset < 0 || offset >= _savedBuffer.Length)
				{
					return 0;
				}
				if (offset + count > _savedBuffer.Length)
				{
					count = _savedBuffer.Length - index;
				}
				Array.Copy(_savedBuffer, offset, buffer, index, count);
				return count;
			}
			return _reader.Read(Offset + offset, buffer, index, count);
		}

		protected int ReadByte(int offset)
		{
			if (_savedBuffer != null)
			{
				if (offset < 0)
				{
					throw new ArgumentOutOfRangeException();
				}
				if (offset >= _savedBuffer.Length)
				{
					return -1;
				}
				return _savedBuffer[offset];
			}
			return _reader.ReadByte(Offset + offset);
		}

		protected abstract int Validate();

		internal void SaveBuffer()
		{
			_savedBuffer = new byte[Length];
			_reader.Read(Offset, _savedBuffer, 0, Length);
			Interlocked.Add(ref _totalAllocation, Length);
		}

		internal void ClearBuffer()
		{
			Interlocked.Add(ref _totalAllocation, -Length);
			_savedBuffer = null;
		}

		internal virtual void Parse()
		{
		}
	}
	internal class Huffman
	{
		private class HuffmanListNode
		{
			internal byte Value;

			internal int Length;

			internal int Bits;

			internal int Mask;

			internal HuffmanListNode Next;
		}

		private static readonly byte[][,] _codeTables;

		private static readonly float[] _floatLookup;

		private static HuffmanListNode[] _llCache;

		private static int[] _llCacheMaxBits;

		private static readonly int[] LIN_BITS;

		static Huffman()
		{
			_codeTables = new byte[17][,]
			{
				new byte[7, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 2, 1 },
					{ 0, 16 },
					{ 2, 1 },
					{ 0, 1 },
					{ 0, 17 }
				},
				new byte[17, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 33 },
					{ 2, 1 },
					{ 0, 18 },
					{ 2, 1 },
					{ 0, 2 },
					{ 0, 34 }
				},
				new byte[17, 2]
				{
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 2, 1 },
					{ 0, 16 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 33 },
					{ 2, 1 },
					{ 0, 18 },
					{ 2, 1 },
					{ 0, 2 },
					{ 0, 34 }
				},
				new byte[31, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 34 },
					{ 0, 48 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 19 },
					{ 2, 1 },
					{ 0, 49 },
					{ 2, 1 },
					{ 0, 50 },
					{ 2, 1 },
					{ 0, 35 },
					{ 0, 51 }
				},
				new byte[31, 2]
				{
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 0, 16 },
					{ 0, 17 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 33 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 18 },
					{ 2, 1 },
					{ 0, 2 },
					{ 0, 34 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 50 },
					{ 2, 1 },
					{ 0, 35 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 51 }
				},
				new byte[71, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 0, 33 },
					{ 18, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 18 },
					{ 2, 1 },
					{ 0, 34 },
					{ 0, 48 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 50 },
					{ 2, 1 },
					{ 0, 35 },
					{ 0, 4 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 65 },
					{ 2, 1 },
					{ 0, 20 },
					{ 2, 1 },
					{ 0, 66 },
					{ 0, 36 },
					{ 12, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 51 },
					{ 0, 67 },
					{ 0, 80 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 52 },
					{ 0, 5 },
					{ 0, 81 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 21 },
					{ 2, 1 },
					{ 0, 82 },
					{ 0, 37 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 53 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 83 },
					{ 0, 84 },
					{ 2, 1 },
					{ 0, 69 },
					{ 0, 85 }
				},
				new byte[71, 2]
				{
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 14, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 2, 1 },
					{ 0, 34 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 3 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 4 },
					{ 2, 1 },
					{ 0, 65 },
					{ 2, 1 },
					{ 0, 20 },
					{ 0, 66 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 36 },
					{ 2, 1 },
					{ 0, 51 },
					{ 0, 80 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 67 },
					{ 0, 52 },
					{ 0, 81 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 21 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 82 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 37 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 53 },
					{ 2, 1 },
					{ 0, 83 },
					{ 2, 1 },
					{ 0, 69 },
					{ 2, 1 },
					{ 0, 84 },
					{ 0, 85 }
				},
				new byte[71, 2]
				{
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 0, 16 },
					{ 2, 1 },
					{ 0, 1 },
					{ 0, 17 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 33 },
					{ 2, 1 },
					{ 0, 18 },
					{ 2, 1 },
					{ 0, 2 },
					{ 0, 34 },
					{ 12, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 3 },
					{ 0, 49 },
					{ 2, 1 },
					{ 0, 19 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 65 },
					{ 0, 20 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 51 },
					{ 2, 1 },
					{ 0, 66 },
					{ 0, 36 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 4 },
					{ 0, 80 },
					{ 0, 67 },
					{ 2, 1 },
					{ 0, 52 },
					{ 0, 81 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 21 },
					{ 0, 82 },
					{ 2, 1 },
					{ 0, 37 },
					{ 0, 68 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 84 },
					{ 0, 83 },
					{ 2, 1 },
					{ 0, 53 },
					{ 2, 1 },
					{ 0, 69 },
					{ 0, 85 }
				},
				new byte[127, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 10, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 28, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 34 },
					{ 0, 48 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 50 },
					{ 2, 1 },
					{ 0, 35 },
					{ 0, 64 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 65 },
					{ 0, 20 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 4 },
					{ 0, 51 },
					{ 2, 1 },
					{ 0, 66 },
					{ 0, 36 },
					{ 28, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 80 },
					{ 0, 5 },
					{ 0, 96 },
					{ 2, 1 },
					{ 0, 97 },
					{ 0, 22 },
					{ 12, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 67 },
					{ 0, 52 },
					{ 0, 81 },
					{ 2, 1 },
					{ 0, 21 },
					{ 2, 1 },
					{ 0, 82 },
					{ 0, 37 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 38 },
					{ 0, 54 },
					{ 0, 113 },
					{ 20, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 23 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 83 },
					{ 0, 6 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 53 },
					{ 0, 69 },
					{ 0, 98 },
					{ 2, 1 },
					{ 0, 112 },
					{ 2, 1 },
					{ 0, 7 },
					{ 0, 100 },
					{ 14, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 114 },
					{ 0, 39 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 99 },
					{ 2, 1 },
					{ 0, 84 },
					{ 0, 85 },
					{ 2, 1 },
					{ 0, 70 },
					{ 0, 115 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 55 },
					{ 0, 101 },
					{ 2, 1 },
					{ 0, 86 },
					{ 0, 116 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 71 },
					{ 2, 1 },
					{ 0, 102 },
					{ 0, 117 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 87 },
					{ 0, 118 },
					{ 2, 1 },
					{ 0, 103 },
					{ 0, 119 }
				},
				new byte[127, 2]
				{
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 0, 18 },
					{ 24, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 33 },
					{ 2, 1 },
					{ 0, 34 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 3 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 4 },
					{ 2, 1 },
					{ 0, 65 },
					{ 0, 20 },
					{ 30, 1 },
					{ 16, 1 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 66 },
					{ 0, 36 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 51 },
					{ 0, 67 },
					{ 0, 80 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 52 },
					{ 0, 81 },
					{ 0, 97 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 22 },
					{ 2, 1 },
					{ 0, 6 },
					{ 0, 38 },
					{ 2, 1 },
					{ 0, 98 },
					{ 2, 1 },
					{ 0, 21 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 82 },
					{ 16, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 37 },
					{ 0, 68 },
					{ 0, 96 },
					{ 2, 1 },
					{ 0, 99 },
					{ 0, 54 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 112 },
					{ 0, 23 },
					{ 0, 113 },
					{ 16, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 7 },
					{ 0, 100 },
					{ 0, 114 },
					{ 2, 1 },
					{ 0, 39 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 83 },
					{ 0, 53 },
					{ 2, 1 },
					{ 0, 84 },
					{ 0, 69 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 70 },
					{ 0, 115 },
					{ 2, 1 },
					{ 0, 55 },
					{ 2, 1 },
					{ 0, 101 },
					{ 0, 86 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 85 },
					{ 0, 87 },
					{ 0, 116 },
					{ 2, 1 },
					{ 0, 71 },
					{ 0, 102 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 117 },
					{ 0, 118 },
					{ 2, 1 },
					{ 0, 103 },
					{ 0, 119 }
				},
				new byte[127, 2]
				{
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 2, 1 },
					{ 0, 0 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 16, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 34 },
					{ 0, 49 },
					{ 2, 1 },
					{ 0, 19 },
					{ 2, 1 },
					{ 0, 48 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 64 },
					{ 26, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 2, 1 },
					{ 0, 65 },
					{ 0, 51 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 20 },
					{ 0, 66 },
					{ 2, 1 },
					{ 0, 36 },
					{ 2, 1 },
					{ 0, 4 },
					{ 0, 80 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 67 },
					{ 0, 52 },
					{ 2, 1 },
					{ 0, 81 },
					{ 0, 21 },
					{ 28, 1 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 82 },
					{ 0, 37 },
					{ 2, 1 },
					{ 0, 83 },
					{ 0, 53 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 96 },
					{ 0, 22 },
					{ 0, 97 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 98 },
					{ 0, 38 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 6 },
					{ 0, 68 },
					{ 2, 1 },
					{ 0, 84 },
					{ 0, 69 },
					{ 18, 1 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 99 },
					{ 0, 54 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 112 },
					{ 0, 7 },
					{ 0, 113 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 23 },
					{ 0, 100 },
					{ 2, 1 },
					{ 0, 70 },
					{ 0, 114 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 39 },
					{ 2, 1 },
					{ 0, 85 },
					{ 0, 115 },
					{ 2, 1 },
					{ 0, 55 },
					{ 0, 86 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 101 },
					{ 0, 116 },
					{ 2, 1 },
					{ 0, 71 },
					{ 0, 102 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 117 },
					{ 0, 87 },
					{ 2, 1 },
					{ 0, 118 },
					{ 2, 1 },
					{ 0, 103 },
					{ 0, 119 }
				},
				new byte[511, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 2, 1 },
					{ 0, 1 },
					{ 0, 17 },
					{ 28, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 34 },
					{ 0, 48 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 49 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 19 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 4 },
					{ 0, 65 },
					{ 70, 1 },
					{ 28, 1 },
					{ 14, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 20 },
					{ 2, 1 },
					{ 0, 51 },
					{ 0, 66 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 36 },
					{ 0, 80 },
					{ 2, 1 },
					{ 0, 67 },
					{ 0, 52 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 81 },
					{ 0, 21 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 82 },
					{ 2, 1 },
					{ 0, 37 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 83 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 96 },
					{ 0, 6 },
					{ 2, 1 },
					{ 0, 97 },
					{ 0, 22 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 128 },
					{ 0, 8 },
					{ 0, 129 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 53 },
					{ 0, 98 },
					{ 2, 1 },
					{ 0, 38 },
					{ 0, 84 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 69 },
					{ 0, 99 },
					{ 2, 1 },
					{ 0, 54 },
					{ 0, 112 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 7 },
					{ 0, 85 },
					{ 0, 113 },
					{ 2, 1 },
					{ 0, 23 },
					{ 2, 1 },
					{ 0, 39 },
					{ 0, 55 },
					{ 72, 1 },
					{ 24, 1 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 24 },
					{ 0, 130 },
					{ 2, 1 },
					{ 0, 40 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 100 },
					{ 0, 70 },
					{ 0, 114 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 132 },
					{ 0, 72 },
					{ 2, 1 },
					{ 0, 144 },
					{ 0, 9 },
					{ 2, 1 },
					{ 0, 145 },
					{ 0, 25 },
					{ 24, 1 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 115 },
					{ 0, 101 },
					{ 2, 1 },
					{ 0, 86 },
					{ 0, 116 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 71 },
					{ 0, 102 },
					{ 0, 131 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 56 },
					{ 2, 1 },
					{ 0, 117 },
					{ 0, 87 },
					{ 2, 1 },
					{ 0, 146 },
					{ 0, 41 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 103 },
					{ 0, 133 },
					{ 2, 1 },
					{ 0, 88 },
					{ 0, 57 },
					{ 2, 1 },
					{ 0, 147 },
					{ 2, 1 },
					{ 0, 73 },
					{ 0, 134 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 160 },
					{ 2, 1 },
					{ 0, 104 },
					{ 0, 10 },
					{ 2, 1 },
					{ 0, 161 },
					{ 0, 26 },
					{ 68, 1 },
					{ 24, 1 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 162 },
					{ 0, 42 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 149 },
					{ 0, 89 },
					{ 2, 1 },
					{ 0, 163 },
					{ 0, 58 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 74 },
					{ 0, 150 },
					{ 2, 1 },
					{ 0, 176 },
					{ 0, 11 },
					{ 2, 1 },
					{ 0, 177 },
					{ 0, 27 },
					{ 20, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 178 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 118 },
					{ 0, 119 },
					{ 0, 148 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 135 },
					{ 0, 120 },
					{ 0, 164 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 105 },
					{ 0, 165 },
					{ 0, 43 },
					{ 12, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 90 },
					{ 0, 136 },
					{ 0, 179 },
					{ 2, 1 },
					{ 0, 59 },
					{ 2, 1 },
					{ 0, 121 },
					{ 0, 166 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 106 },
					{ 0, 180 },
					{ 0, 192 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 12 },
					{ 0, 152 },
					{ 0, 193 },
					{ 60, 1 },
					{ 22, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 28 },
					{ 2, 1 },
					{ 0, 137 },
					{ 0, 181 },
					{ 2, 1 },
					{ 0, 91 },
					{ 0, 194 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 44 },
					{ 0, 60 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 182 },
					{ 0, 107 },
					{ 2, 1 },
					{ 0, 196 },
					{ 0, 76 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 168 },
					{ 0, 138 },
					{ 2, 1 },
					{ 0, 208 },
					{ 0, 13 },
					{ 2, 1 },
					{ 0, 209 },
					{ 2, 1 },
					{ 0, 75 },
					{ 2, 1 },
					{ 0, 151 },
					{ 0, 167 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 195 },
					{ 2, 1 },
					{ 0, 122 },
					{ 0, 153 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 197 },
					{ 0, 92 },
					{ 0, 183 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 29 },
					{ 0, 210 },
					{ 2, 1 },
					{ 0, 45 },
					{ 2, 1 },
					{ 0, 123 },
					{ 0, 211 },
					{ 52, 1 },
					{ 28, 1 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 61 },
					{ 0, 198 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 108 },
					{ 0, 169 },
					{ 2, 1 },
					{ 0, 154 },
					{ 0, 212 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 184 },
					{ 0, 139 },
					{ 2, 1 },
					{ 0, 77 },
					{ 0, 199 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 124 },
					{ 0, 213 },
					{ 2, 1 },
					{ 0, 93 },
					{ 0, 224 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 225 },
					{ 0, 30 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 14 },
					{ 0, 46 },
					{ 0, 226 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 227 },
					{ 0, 109 },
					{ 2, 1 },
					{ 0, 140 },
					{ 0, 228 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 229 },
					{ 0, 186 },
					{ 0, 240 },
					{ 38, 1 },
					{ 16, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 241 },
					{ 0, 31 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 170 },
					{ 0, 155 },
					{ 0, 185 },
					{ 2, 1 },
					{ 0, 62 },
					{ 2, 1 },
					{ 0, 214 },
					{ 0, 200 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 78 },
					{ 2, 1 },
					{ 0, 215 },
					{ 0, 125 },
					{ 2, 1 },
					{ 0, 171 },
					{ 2, 1 },
					{ 0, 94 },
					{ 0, 201 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 15 },
					{ 2, 1 },
					{ 0, 156 },
					{ 0, 110 },
					{ 2, 1 },
					{ 0, 242 },
					{ 0, 47 },
					{ 32, 1 },
					{ 16, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 216 },
					{ 0, 141 },
					{ 0, 63 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 243 },
					{ 2, 1 },
					{ 0, 230 },
					{ 0, 202 },
					{ 2, 1 },
					{ 0, 244 },
					{ 0, 79 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 187 },
					{ 0, 172 },
					{ 2, 1 },
					{ 0, 231 },
					{ 0, 245 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 217 },
					{ 0, 157 },
					{ 2, 1 },
					{ 0, 95 },
					{ 0, 232 },
					{ 30, 1 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 111 },
					{ 2, 1 },
					{ 0, 246 },
					{ 0, 203 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 188 },
					{ 0, 173 },
					{ 0, 218 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 247 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 126 },
					{ 0, 127 },
					{ 0, 142 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 158 },
					{ 0, 174 },
					{ 0, 204 },
					{ 2, 1 },
					{ 0, 248 },
					{ 0, 143 },
					{ 18, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 219 },
					{ 0, 189 },
					{ 2, 1 },
					{ 0, 234 },
					{ 0, 249 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 159 },
					{ 0, 235 },
					{ 2, 1 },
					{ 0, 190 },
					{ 2, 1 },
					{ 0, 205 },
					{ 0, 250 },
					{ 14, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 221 },
					{ 0, 236 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 233 },
					{ 0, 175 },
					{ 0, 220 },
					{ 2, 1 },
					{ 0, 206 },
					{ 0, 251 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 191 },
					{ 0, 222 },
					{ 2, 1 },
					{ 0, 207 },
					{ 0, 238 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 223 },
					{ 0, 239 },
					{ 2, 1 },
					{ 0, 255 },
					{ 2, 1 },
					{ 0, 237 },
					{ 2, 1 },
					{ 0, 253 },
					{ 2, 1 },
					{ 0, 252 },
					{ 0, 254 }
				},
				new byte[511, 2]
				{
					{ 16, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 50, 1 },
					{ 16, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 34 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 49 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 19 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 64 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 14, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 4 },
					{ 0, 20 },
					{ 0, 65 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 51 },
					{ 0, 66 },
					{ 2, 1 },
					{ 0, 36 },
					{ 0, 67 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 52 },
					{ 2, 1 },
					{ 0, 80 },
					{ 0, 5 },
					{ 2, 1 },
					{ 0, 81 },
					{ 0, 21 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 82 },
					{ 0, 37 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 83 },
					{ 0, 97 },
					{ 90, 1 },
					{ 36, 1 },
					{ 18, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 53 },
					{ 2, 1 },
					{ 0, 96 },
					{ 0, 6 },
					{ 2, 1 },
					{ 0, 22 },
					{ 0, 98 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 38 },
					{ 0, 84 },
					{ 2, 1 },
					{ 0, 69 },
					{ 0, 99 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 54 },
					{ 2, 1 },
					{ 0, 112 },
					{ 0, 7 },
					{ 2, 1 },
					{ 0, 113 },
					{ 0, 85 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 23 },
					{ 0, 100 },
					{ 2, 1 },
					{ 0, 114 },
					{ 0, 39 },
					{ 24, 1 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 70 },
					{ 0, 115 },
					{ 2, 1 },
					{ 0, 55 },
					{ 0, 101 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 86 },
					{ 0, 128 },
					{ 2, 1 },
					{ 0, 8 },
					{ 0, 116 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 129 },
					{ 0, 24 },
					{ 2, 1 },
					{ 0, 130 },
					{ 0, 40 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 71 },
					{ 0, 102 },
					{ 2, 1 },
					{ 0, 131 },
					{ 0, 56 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 117 },
					{ 0, 87 },
					{ 2, 1 },
					{ 0, 132 },
					{ 0, 72 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 144 },
					{ 0, 25 },
					{ 0, 145 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 146 },
					{ 0, 118 },
					{ 2, 1 },
					{ 0, 103 },
					{ 0, 41 },
					{ 92, 1 },
					{ 36, 1 },
					{ 18, 1 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 133 },
					{ 0, 88 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 9 },
					{ 0, 119 },
					{ 0, 147 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 57 },
					{ 0, 148 },
					{ 2, 1 },
					{ 0, 73 },
					{ 0, 134 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 104 },
					{ 2, 1 },
					{ 0, 160 },
					{ 0, 10 },
					{ 2, 1 },
					{ 0, 161 },
					{ 0, 26 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 162 },
					{ 0, 42 },
					{ 2, 1 },
					{ 0, 149 },
					{ 0, 89 },
					{ 26, 1 },
					{ 14, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 163 },
					{ 2, 1 },
					{ 0, 58 },
					{ 0, 135 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 120 },
					{ 0, 164 },
					{ 2, 1 },
					{ 0, 74 },
					{ 0, 150 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 105 },
					{ 0, 176 },
					{ 0, 177 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 27 },
					{ 0, 165 },
					{ 0, 178 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 90 },
					{ 0, 43 },
					{ 2, 1 },
					{ 0, 136 },
					{ 0, 151 },
					{ 2, 1 },
					{ 0, 179 },
					{ 2, 1 },
					{ 0, 121 },
					{ 0, 59 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 106 },
					{ 0, 180 },
					{ 2, 1 },
					{ 0, 75 },
					{ 0, 193 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 152 },
					{ 0, 137 },
					{ 2, 1 },
					{ 0, 28 },
					{ 0, 181 },
					{ 80, 1 },
					{ 34, 1 },
					{ 16, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 91 },
					{ 0, 44 },
					{ 0, 194 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 11 },
					{ 0, 192 },
					{ 0, 166 },
					{ 2, 1 },
					{ 0, 167 },
					{ 0, 122 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 195 },
					{ 0, 60 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 12 },
					{ 0, 153 },
					{ 0, 182 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 107 },
					{ 0, 196 },
					{ 2, 1 },
					{ 0, 76 },
					{ 0, 168 },
					{ 20, 1 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 138 },
					{ 0, 197 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 208 },
					{ 0, 92 },
					{ 0, 209 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 183 },
					{ 0, 123 },
					{ 2, 1 },
					{ 0, 29 },
					{ 2, 1 },
					{ 0, 13 },
					{ 0, 45 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 210 },
					{ 0, 211 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 61 },
					{ 0, 198 },
					{ 2, 1 },
					{ 0, 108 },
					{ 0, 169 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 154 },
					{ 0, 184 },
					{ 0, 212 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 139 },
					{ 0, 77 },
					{ 2, 1 },
					{ 0, 199 },
					{ 0, 124 },
					{ 68, 1 },
					{ 34, 1 },
					{ 18, 1 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 213 },
					{ 0, 93 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 224 },
					{ 0, 14 },
					{ 0, 225 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 30 },
					{ 0, 226 },
					{ 2, 1 },
					{ 0, 170 },
					{ 0, 46 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 185 },
					{ 0, 155 },
					{ 2, 1 },
					{ 0, 227 },
					{ 0, 214 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 109 },
					{ 0, 62 },
					{ 2, 1 },
					{ 0, 200 },
					{ 0, 140 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 228 },
					{ 0, 78 },
					{ 2, 1 },
					{ 0, 215 },
					{ 0, 125 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 229 },
					{ 0, 186 },
					{ 2, 1 },
					{ 0, 171 },
					{ 0, 94 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 201 },
					{ 0, 156 },
					{ 2, 1 },
					{ 0, 241 },
					{ 0, 31 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 240 },
					{ 0, 110 },
					{ 0, 242 },
					{ 2, 1 },
					{ 0, 47 },
					{ 0, 230 },
					{ 38, 1 },
					{ 18, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 216 },
					{ 0, 243 },
					{ 2, 1 },
					{ 0, 63 },
					{ 0, 244 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 79 },
					{ 2, 1 },
					{ 0, 141 },
					{ 0, 217 },
					{ 2, 1 },
					{ 0, 187 },
					{ 0, 202 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 172 },
					{ 0, 231 },
					{ 2, 1 },
					{ 0, 126 },
					{ 0, 245 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 157 },
					{ 0, 95 },
					{ 2, 1 },
					{ 0, 232 },
					{ 0, 142 },
					{ 2, 1 },
					{ 0, 246 },
					{ 0, 203 },
					{ 34, 1 },
					{ 18, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 15 },
					{ 0, 174 },
					{ 0, 111 },
					{ 2, 1 },
					{ 0, 188 },
					{ 0, 218 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 173 },
					{ 0, 247 },
					{ 2, 1 },
					{ 0, 127 },
					{ 0, 233 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 158 },
					{ 0, 204 },
					{ 2, 1 },
					{ 0, 248 },
					{ 0, 143 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 219 },
					{ 0, 189 },
					{ 2, 1 },
					{ 0, 234 },
					{ 0, 249 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 159 },
					{ 0, 220 },
					{ 2, 1 },
					{ 0, 205 },
					{ 0, 235 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 190 },
					{ 0, 250 },
					{ 2, 1 },
					{ 0, 175 },
					{ 0, 221 },
					{ 14, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 236 },
					{ 0, 206 },
					{ 0, 251 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 191 },
					{ 0, 237 },
					{ 2, 1 },
					{ 0, 222 },
					{ 0, 252 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 207 },
					{ 0, 253 },
					{ 0, 238 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 223 },
					{ 0, 254 },
					{ 2, 1 },
					{ 0, 239 },
					{ 0, 255 }
				},
				new byte[511, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 2, 1 },
					{ 0, 1 },
					{ 0, 17 },
					{ 42, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 34 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 3 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 4 },
					{ 0, 65 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 20 },
					{ 2, 1 },
					{ 0, 51 },
					{ 0, 66 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 36 },
					{ 0, 80 },
					{ 2, 1 },
					{ 0, 67 },
					{ 0, 52 },
					{ 138, 1 },
					{ 40, 1 },
					{ 16, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 21 },
					{ 0, 81 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 82 },
					{ 0, 37 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 53 },
					{ 0, 83 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 96 },
					{ 0, 6 },
					{ 0, 97 },
					{ 2, 1 },
					{ 0, 22 },
					{ 0, 98 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 38 },
					{ 0, 84 },
					{ 2, 1 },
					{ 0, 69 },
					{ 0, 99 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 54 },
					{ 0, 112 },
					{ 0, 113 },
					{ 40, 1 },
					{ 18, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 23 },
					{ 2, 1 },
					{ 0, 7 },
					{ 2, 1 },
					{ 0, 85 },
					{ 0, 100 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 114 },
					{ 0, 39 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 70 },
					{ 0, 101 },
					{ 0, 115 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 55 },
					{ 2, 1 },
					{ 0, 86 },
					{ 0, 8 },
					{ 2, 1 },
					{ 0, 128 },
					{ 0, 129 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 24 },
					{ 2, 1 },
					{ 0, 116 },
					{ 0, 71 },
					{ 2, 1 },
					{ 0, 130 },
					{ 2, 1 },
					{ 0, 40 },
					{ 0, 102 },
					{ 24, 1 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 131 },
					{ 0, 56 },
					{ 2, 1 },
					{ 0, 117 },
					{ 0, 132 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 72 },
					{ 0, 144 },
					{ 0, 145 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 25 },
					{ 2, 1 },
					{ 0, 9 },
					{ 0, 118 },
					{ 2, 1 },
					{ 0, 146 },
					{ 0, 41 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 133 },
					{ 0, 88 },
					{ 2, 1 },
					{ 0, 147 },
					{ 0, 57 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 160 },
					{ 0, 10 },
					{ 0, 26 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 162 },
					{ 2, 1 },
					{ 0, 103 },
					{ 2, 1 },
					{ 0, 87 },
					{ 0, 73 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 148 },
					{ 2, 1 },
					{ 0, 119 },
					{ 0, 134 },
					{ 2, 1 },
					{ 0, 161 },
					{ 2, 1 },
					{ 0, 104 },
					{ 0, 149 },
					{ 220, 1 },
					{ 126, 1 },
					{ 50, 1 },
					{ 26, 1 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 42 },
					{ 2, 1 },
					{ 0, 89 },
					{ 0, 58 },
					{ 2, 1 },
					{ 0, 163 },
					{ 2, 1 },
					{ 0, 135 },
					{ 0, 120 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 164 },
					{ 0, 74 },
					{ 2, 1 },
					{ 0, 150 },
					{ 0, 105 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 176 },
					{ 0, 11 },
					{ 0, 177 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 27 },
					{ 0, 178 },
					{ 2, 1 },
					{ 0, 43 },
					{ 2, 1 },
					{ 0, 165 },
					{ 0, 90 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 179 },
					{ 2, 1 },
					{ 0, 166 },
					{ 0, 106 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 180 },
					{ 0, 75 },
					{ 2, 1 },
					{ 0, 12 },
					{ 0, 193 },
					{ 30, 1 },
					{ 14, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 181 },
					{ 0, 194 },
					{ 0, 44 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 167 },
					{ 0, 195 },
					{ 2, 1 },
					{ 0, 107 },
					{ 0, 196 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 29 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 136 },
					{ 0, 151 },
					{ 0, 59 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 209 },
					{ 0, 210 },
					{ 2, 1 },
					{ 0, 45 },
					{ 0, 211 },
					{ 18, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 30 },
					{ 0, 46 },
					{ 0, 226 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 121 },
					{ 0, 152 },
					{ 0, 192 },
					{ 2, 1 },
					{ 0, 28 },
					{ 2, 1 },
					{ 0, 137 },
					{ 0, 91 },
					{ 14, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 60 },
					{ 2, 1 },
					{ 0, 122 },
					{ 0, 182 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 76 },
					{ 0, 153 },
					{ 2, 1 },
					{ 0, 168 },
					{ 0, 138 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 13 },
					{ 2, 1 },
					{ 0, 197 },
					{ 0, 92 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 61 },
					{ 0, 198 },
					{ 2, 1 },
					{ 0, 108 },
					{ 0, 154 },
					{ 88, 1 },
					{ 86, 1 },
					{ 36, 1 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 139 },
					{ 0, 77 },
					{ 2, 1 },
					{ 0, 199 },
					{ 0, 124 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 213 },
					{ 0, 93 },
					{ 2, 1 },
					{ 0, 224 },
					{ 0, 14 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 227 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 208 },
					{ 0, 183 },
					{ 0, 123 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 169 },
					{ 0, 184 },
					{ 0, 212 },
					{ 2, 1 },
					{ 0, 225 },
					{ 2, 1 },
					{ 0, 170 },
					{ 0, 185 },
					{ 24, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 155 },
					{ 0, 214 },
					{ 0, 109 },
					{ 2, 1 },
					{ 0, 62 },
					{ 0, 200 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 140 },
					{ 0, 228 },
					{ 0, 78 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 215 },
					{ 0, 229 },
					{ 2, 1 },
					{ 0, 186 },
					{ 0, 171 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 156 },
					{ 0, 230 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 110 },
					{ 0, 216 },
					{ 2, 1 },
					{ 0, 141 },
					{ 0, 187 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 231 },
					{ 0, 157 },
					{ 2, 1 },
					{ 0, 232 },
					{ 0, 142 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 203 },
					{ 0, 188 },
					{ 0, 158 },
					{ 0, 241 },
					{ 2, 1 },
					{ 0, 31 },
					{ 2, 1 },
					{ 0, 15 },
					{ 0, 47 },
					{ 66, 1 },
					{ 56, 1 },
					{ 2, 1 },
					{ 0, 242 },
					{ 52, 1 },
					{ 50, 1 },
					{ 20, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 189 },
					{ 2, 1 },
					{ 0, 94 },
					{ 2, 1 },
					{ 0, 125 },
					{ 0, 201 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 202 },
					{ 2, 1 },
					{ 0, 172 },
					{ 0, 126 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 218 },
					{ 0, 173 },
					{ 0, 204 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 174 },
					{ 2, 1 },
					{ 0, 219 },
					{ 0, 220 },
					{ 2, 1 },
					{ 0, 205 },
					{ 0, 190 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 235 },
					{ 0, 237 },
					{ 0, 238 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 217 },
					{ 0, 234 },
					{ 0, 233 },
					{ 2, 1 },
					{ 0, 222 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 221 },
					{ 0, 236 },
					{ 0, 206 },
					{ 0, 63 },
					{ 0, 240 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 243 },
					{ 0, 244 },
					{ 2, 1 },
					{ 0, 79 },
					{ 2, 1 },
					{ 0, 245 },
					{ 0, 95 },
					{ 10, 1 },
					{ 2, 1 },
					{ 0, 255 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 246 },
					{ 0, 111 },
					{ 2, 1 },
					{ 0, 247 },
					{ 0, 127 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 143 },
					{ 2, 1 },
					{ 0, 248 },
					{ 0, 249 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 159 },
					{ 0, 250 },
					{ 0, 175 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 251 },
					{ 0, 191 },
					{ 2, 1 },
					{ 0, 252 },
					{ 0, 207 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 253 },
					{ 0, 223 },
					{ 2, 1 },
					{ 0, 254 },
					{ 0, 239 }
				},
				new byte[512, 2]
				{
					{ 60, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 0, 16 },
					{ 2, 1 },
					{ 0, 1 },
					{ 0, 17 },
					{ 14, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 0, 33 },
					{ 2, 1 },
					{ 0, 18 },
					{ 2, 1 },
					{ 0, 34 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 3 },
					{ 14, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 4 },
					{ 0, 65 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 20 },
					{ 0, 51 },
					{ 2, 1 },
					{ 0, 66 },
					{ 0, 36 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 67 },
					{ 0, 52 },
					{ 0, 81 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 80 },
					{ 0, 5 },
					{ 0, 21 },
					{ 2, 1 },
					{ 0, 82 },
					{ 0, 37 },
					{ 250, 1 },
					{ 98, 1 },
					{ 34, 1 },
					{ 18, 1 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 83 },
					{ 2, 1 },
					{ 0, 53 },
					{ 2, 1 },
					{ 0, 96 },
					{ 0, 6 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 97 },
					{ 0, 22 },
					{ 2, 1 },
					{ 0, 98 },
					{ 0, 38 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 84 },
					{ 0, 69 },
					{ 2, 1 },
					{ 0, 99 },
					{ 0, 54 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 113 },
					{ 0, 85 },
					{ 2, 1 },
					{ 0, 100 },
					{ 0, 70 },
					{ 32, 1 },
					{ 14, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 114 },
					{ 2, 1 },
					{ 0, 39 },
					{ 0, 55 },
					{ 2, 1 },
					{ 0, 115 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 112 },
					{ 0, 7 },
					{ 0, 23 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 101 },
					{ 0, 86 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 128 },
					{ 0, 8 },
					{ 0, 129 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 116 },
					{ 0, 71 },
					{ 2, 1 },
					{ 0, 24 },
					{ 0, 130 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 40 },
					{ 0, 102 },
					{ 2, 1 },
					{ 0, 131 },
					{ 0, 56 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 117 },
					{ 0, 87 },
					{ 2, 1 },
					{ 0, 132 },
					{ 0, 72 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 145 },
					{ 0, 25 },
					{ 2, 1 },
					{ 0, 146 },
					{ 0, 118 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 103 },
					{ 0, 41 },
					{ 2, 1 },
					{ 0, 133 },
					{ 0, 88 },
					{ 92, 1 },
					{ 34, 1 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 147 },
					{ 0, 57 },
					{ 2, 1 },
					{ 0, 148 },
					{ 0, 73 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 119 },
					{ 0, 134 },
					{ 2, 1 },
					{ 0, 104 },
					{ 0, 161 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 162 },
					{ 0, 42 },
					{ 2, 1 },
					{ 0, 149 },
					{ 0, 89 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 163 },
					{ 0, 58 },
					{ 2, 1 },
					{ 0, 135 },
					{ 2, 1 },
					{ 0, 120 },
					{ 0, 74 },
					{ 22, 1 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 164 },
					{ 0, 150 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 105 },
					{ 0, 177 },
					{ 2, 1 },
					{ 0, 27 },
					{ 0, 165 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 178 },
					{ 2, 1 },
					{ 0, 90 },
					{ 0, 43 },
					{ 2, 1 },
					{ 0, 136 },
					{ 0, 179 },
					{ 16, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 144 },
					{ 2, 1 },
					{ 0, 9 },
					{ 0, 160 },
					{ 2, 1 },
					{ 0, 151 },
					{ 0, 121 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 166 },
					{ 0, 106 },
					{ 0, 180 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 26 },
					{ 2, 1 },
					{ 0, 10 },
					{ 0, 176 },
					{ 2, 1 },
					{ 0, 59 },
					{ 2, 1 },
					{ 0, 11 },
					{ 0, 192 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 75 },
					{ 0, 193 },
					{ 2, 1 },
					{ 0, 152 },
					{ 0, 137 },
					{ 67, 1 },
					{ 34, 1 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 28 },
					{ 0, 181 },
					{ 2, 1 },
					{ 0, 91 },
					{ 0, 194 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 44 },
					{ 0, 167 },
					{ 2, 1 },
					{ 0, 122 },
					{ 0, 195 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 60 },
					{ 2, 1 },
					{ 0, 12 },
					{ 0, 208 },
					{ 2, 1 },
					{ 0, 182 },
					{ 0, 107 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 196 },
					{ 0, 76 },
					{ 2, 1 },
					{ 0, 153 },
					{ 0, 168 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 138 },
					{ 0, 197 },
					{ 2, 1 },
					{ 0, 92 },
					{ 0, 209 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 183 },
					{ 0, 123 },
					{ 2, 1 },
					{ 0, 29 },
					{ 0, 210 },
					{ 9, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 45 },
					{ 0, 211 },
					{ 2, 1 },
					{ 0, 61 },
					{ 0, 198 },
					{ 85, 250 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 108 },
					{ 0, 169 },
					{ 2, 1 },
					{ 0, 154 },
					{ 0, 212 },
					{ 32, 1 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 184 },
					{ 0, 139 },
					{ 2, 1 },
					{ 0, 77 },
					{ 0, 199 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 124 },
					{ 0, 213 },
					{ 2, 1 },
					{ 0, 93 },
					{ 0, 225 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 30 },
					{ 0, 226 },
					{ 2, 1 },
					{ 0, 170 },
					{ 0, 185 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 155 },
					{ 0, 227 },
					{ 2, 1 },
					{ 0, 214 },
					{ 0, 109 },
					{ 20, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 62 },
					{ 2, 1 },
					{ 0, 46 },
					{ 0, 78 },
					{ 2, 1 },
					{ 0, 200 },
					{ 0, 140 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 228 },
					{ 0, 215 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 125 },
					{ 0, 171 },
					{ 0, 229 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 186 },
					{ 0, 94 },
					{ 2, 1 },
					{ 0, 201 },
					{ 2, 1 },
					{ 0, 156 },
					{ 0, 110 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 230 },
					{ 2, 1 },
					{ 0, 13 },
					{ 2, 1 },
					{ 0, 224 },
					{ 0, 14 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 216 },
					{ 0, 141 },
					{ 2, 1 },
					{ 0, 187 },
					{ 0, 202 },
					{ 74, 1 },
					{ 2, 1 },
					{ 0, 255 },
					{ 64, 1 },
					{ 58, 1 },
					{ 32, 1 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 172 },
					{ 0, 231 },
					{ 2, 1 },
					{ 0, 126 },
					{ 0, 217 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 157 },
					{ 0, 232 },
					{ 2, 1 },
					{ 0, 142 },
					{ 0, 203 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 188 },
					{ 0, 218 },
					{ 2, 1 },
					{ 0, 173 },
					{ 0, 233 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 158 },
					{ 0, 204 },
					{ 2, 1 },
					{ 0, 219 },
					{ 0, 189 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 234 },
					{ 0, 174 },
					{ 2, 1 },
					{ 0, 220 },
					{ 0, 205 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 235 },
					{ 0, 190 },
					{ 2, 1 },
					{ 0, 221 },
					{ 0, 236 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 206 },
					{ 0, 237 },
					{ 2, 1 },
					{ 0, 222 },
					{ 0, 238 },
					{ 0, 15 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 240 },
					{ 0, 31 },
					{ 0, 241 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 242 },
					{ 0, 47 },
					{ 2, 1 },
					{ 0, 243 },
					{ 0, 63 },
					{ 18, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 244 },
					{ 0, 79 },
					{ 2, 1 },
					{ 0, 245 },
					{ 0, 95 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 246 },
					{ 0, 111 },
					{ 2, 1 },
					{ 0, 247 },
					{ 2, 1 },
					{ 0, 127 },
					{ 0, 143 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 248 },
					{ 0, 249 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 159 },
					{ 0, 175 },
					{ 0, 250 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 251 },
					{ 0, 191 },
					{ 2, 1 },
					{ 0, 252 },
					{ 0, 207 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 253 },
					{ 0, 223 },
					{ 2, 1 },
					{ 0, 254 },
					{ 0, 239 }
				},
				new byte[31, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 8 },
					{ 0, 4 },
					{ 2, 1 },
					{ 0, 1 },
					{ 0, 2 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 12 },
					{ 0, 10 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 6 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 9 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 7 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 14 },
					{ 0, 13 },
					{ 2, 1 },
					{ 0, 15 },
					{ 0, 11 }
				},
				new byte[31, 2]
				{
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 2 },
					{ 0, 3 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 4 },
					{ 0, 5 },
					{ 2, 1 },
					{ 0, 6 },
					{ 0, 7 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 8 },
					{ 0, 9 },
					{ 2, 1 },
					{ 0, 10 },
					{ 0, 11 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 12 },
					{ 0, 13 },
					{ 2, 1 },
					{ 0, 14 },
					{ 0, 15 }
				}
			};
			_llCache = new HuffmanListNode[_codeTables.Length];
			_llCacheMaxBits = new int[_codeTables.Length];
			LIN_BITS = new int[32]
			{
				0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
				0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
				6, 8, 10, 13, 4, 5, 6, 7, 8, 9,
				11, 13
			};
			_floatLookup = new float[8207];
			for (int i = 0; i < 8207; i++)
			{
				_floatLookup[i] = (float)Math.Pow(i, 1.3333333333333333);
			}
		}

		internal static void Decode(BitReservoir br, int table, out float x, out float y)
		{
			if (table == 0 || table == 4 || table == 14)
			{
				x = (y = 0f);
				return;
			}
			byte num = DecodeSymbol(br, table);
			int num2 = num >> 4;
			int num3 = num & 0xF;
			int num4 = LIN_BITS[table];
			if (num4 > 0 && num2 == 15)
			{
				num2 += br.GetBits(num4);
			}
			if (num2 != 0 && br.Get1Bit() != 0)
			{
				x = 0f - _floatLookup[num2];
			}
			else
			{
				x = _floatLookup[num2];
			}
			if (num4 > 0 && num3 == 15)
			{
				num3 += br.GetBits(num4);
			}
			if (num3 != 0 && br.Get1Bit() != 0)
			{
				y = 0f - _floatLookup[num3];
			}
			else
			{
				y = _floatLookup[num3];
			}
		}

		internal static void Decode(BitReservoir br, int table, out float x, out float y, out float v, out float w)
		{
			byte num = DecodeSymbol(br, table);
			v = (w = (x = (y = 0f)));
			if ((num & 8u) != 0)
			{
				if (br.Get1Bit() == 1)
				{
					v = 0f - _floatLookup[1];
				}
				else
				{
					v = _floatLookup[1];
				}
			}
			if ((num & 4u) != 0)
			{
				if (br.Get1Bit() == 1)
				{
					w = 0f - _floatLookup[1];
				}
				else
				{
					w = _floatLookup[1];
				}
			}
			if ((num & 2u) != 0)
			{
				if (br.Get1Bit() == 1)
				{
					x = 0f - _floatLookup[1];
				}
				else
				{
					x = _floatLookup[1];
				}
			}
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				if (br.Get1Bit() == 1)
				{
					y = 0f - _floatLookup[1];
				}
				else
				{
					y = _floatLookup[1];
				}
			}
		}

		private static byte DecodeSymbol(BitReservoir br, int table)
		{
			int maxBits;
			HuffmanListNode huffmanListNode = GetNode(table, out maxBits);
			int readCount;
			int num = br.TryPeekBits(maxBits, out readCount);
			if (readCount < maxBits)
			{
				num <<= maxBits - readCount;
			}
			while (huffmanListNode != null && huffmanListNode.Length <= readCount)
			{
				if ((num & huffmanListNode.Mask) == huffmanListNode.Bits)
				{
					br.SkipBits(huffmanListNode.Length);
					break;
				}
				huffmanListNode = huffmanListNode.Next;
			}
			if (huffmanListNode != null && huffmanListNode.Length <= readCount)
			{
				return huffmanListNode.Value;
			}
			return 0;
		}

		private static HuffmanListNode GetNode(int table, out int maxBits)
		{
			int num = table;
			if (num > 16)
			{
				num = ((num > 31) ? (num - 17) : ((num < 24) ? 13 : 14));
			}
			else
			{
				if (num > 13)
				{
					num--;
				}
				if (num > 3)
				{
					num--;
				}
				num--;
			}
			if (_llCache[num] == null)
			{
				_llCache[num] = InitTable(_codeTables[num], out maxBits);
				_llCacheMaxBits[num] = maxBits;
			}
			else
			{
				maxBits = _llCacheMaxBits[num];
			}
			return _llCache[num];
		}

		private static HuffmanListNode InitTable(byte[,] tree, out int maxBits)
		{
			List<byte> list = new List<byte>();
			List<int> list2 = new List<int>();
			List<int> list3 = new List<int>();
			int length = tree.GetLength(0);
			for (int i = 0; i < length; i++)
			{
				if (tree[i, 0] == 0)
				{
					int num = 0;
					int item = 0;
					int num2 = i;
					do
					{
						num2 = FindPreviousNode(tree, num2, out var bit);
						num |= bit << item++;
					}
					while (num2 > 0);
					list.Add(tree[i, 1]);
					list2.Add(item);
					list3.Add(num);
				}
			}
			return BuildLinkedList(list, list2, list3, out maxBits);
		}

		private static int FindPreviousNode(byte[,] tree, int idx, out int bit)
		{
			for (int num = idx - 1; num >= 0; num--)
			{
				if (tree[num, 0] != 0)
				{
					for (int i = 0; i < 2; i++)
					{
						if (num + tree[num, i] != idx)
						{
							continue;
						}
						if (tree[num, i] >= 250)
						{
							int result = FindPreviousNode(tree, num, out bit);
							if (bit != i)
							{
								throw new InvalidOperationException();
							}
							return result;
						}
						bit = i;
						return num;
					}
				}
			}
			throw new InvalidOperationException();
		}

		private static HuffmanListNode BuildLinkedList(List<byte> values, List<int> lengthList, List<int> codeList, out int maxBits)
		{
			HuffmanListNode[] array = new HuffmanListNode[lengthList.Count];
			maxBits = lengthList.Max();
			for (int j = 0; j < array.Length; j++)
			{
				int num = maxBits - lengthList[j];
				array[j] = new HuffmanListNode
				{
					Value = values[j],
					Length = lengthList[j],
					Bits = codeList[j] << num,
					Mask = (1 << lengthList[j]) - 1 << num
				};
			}
			Array.Sort(array, (HuffmanListNode i1, HuffmanListNode i2) => i1.Length - i2.Length);
			for (int k = 1; k < array.Length && array[k].Length < 99999; k++)
			{
				array[k - 1].Next = array[k];
			}
			return array[0];
		}
	}
	internal class ID3Frame : FrameBase
	{
		private int _version;

		internal int Version
		{
			get
			{
				if (_version == 0)
				{
					return 1;
				}
				return _version;
			}
		}

		internal static ID3Frame TrySync(uint syncMark)
		{
			if ((syncMark & 0xFFFFFF00u) == 1229206272)
			{
				return new ID3Frame
				{
					_version = 2
				};
			}
			if ((syncMark & 0xFFFFFF00u) == 1413564160)
			{
				if ((syncMark & 0xFF) == 43)
				{
					return new ID3Frame
					{
						_version = 1
					};
				}
				return new ID3Frame
				{
					_version = 0
				};
			}
			return null;
		}

		private ID3Frame()
		{
		}

		protected override int Validate()
		{
			switch (_version)
			{
			case 2:
			{
				byte[] array = new byte[7];
				if (Read(3, array) == 7)
				{
					byte b;
					switch (array[0])
					{
					case 2:
						b = 63;
						break;
					case 3:
						b = 31;
						break;
					case 4:
						b = 15;
						break;
					default:
						return -1;
					}
					int num = (array[3] << 21) | (array[4] << 14) | (array[5] << 7) | array[6];
					if (((array[2] & b) | (array[3] & 0x80) | (array[4] & 0x80) | (array[5] & 0x80) | (array[6] & 0x80)) == 0 && array[1] != byte.MaxValue)
					{
						return num + 10;
					}
				}
				break;
			}
			case 1:
				return 355;
			case 0:
				return 128;
			}
			return -1;
		}

		internal override void Parse()
		{
			switch (_version)
			{
			case 2:
				ParseV2();
				break;
			case 1:
				ParseV1Enh();
				break;
			case 0:
				ParseV1(3);
				break;
			}
		}

		private void ParseV1(int offset)
		{
		}

		private void ParseV1Enh()
		{
			ParseV1(230);
		}

		private void ParseV2()
		{
		}

		internal void Merge(ID3Frame newFrame)
		{
		}
	}
	internal abstract class LayerDecoderBase
	{
		protected const int SBLIMIT = 32;

		private const float INV_SQRT_2 = 0.70710677f;

		private static float[] DEWINDOW_TABLE = new float[512]
		{
			0f, -1.5259E-05f, -1.5259E-05f, -1.5259E-05f, -1.5259E-05f, -1.5259E-05f, -1.5259E-05f, -3.0518E-05f, -3.0518E-05f, -3.0518E-05f,
			-3.0518E-05f, -4.5776E-05f, -4.5776E-05f, -6.1035E-05f, -6.1035E-05f, -7.6294E-05f, -7.6294E-05f, -9.1553E-05f, -0.000106812f, -0.000106812f,
			-0.00012207f, -0.000137329f, -0.000152588f, -0.000167847f, -0.000198364f, -0.000213623f, -0.000244141f, -0.000259399f, -0.000289917f, -0.000320435f,
			-0.000366211f, -0.000396729f, -0.000442505f, -0.000473022f, -0.000534058f, -0.000579834f, -0.00062561f, -0.000686646f, -0.000747681f, -0.000808716f,
			-0.00088501f, -0.000961304f, -0.001037598f, -0.001113892f, -0.001205444f, -0.001296997f, -0.00138855f, -0.001480103f, -0.001586914f, -0.001693726f,
			-0.001785278f, -0.001907349f, -0.00201416f, -0.002120972f, -0.002243042f, -0.002349854f, -0.002456665f, -0.002578735f, -0.002685547f, -0.002792358f,
			-0.00289917f, -0.002990723f, -0.003082275f, -0.003173828f, 0.003250122f, 0.003326416f, 0.003387451f, 0.003433228f, 0.003463745f, 0.003479004f,
			0.003479004f, 0.003463745f, 0.003417969f, 0.003372192f, 0.00328064f, 0.003173828f, 0.003051758f, 0.002883911f, 0.002700806f, 0.002487183f,
			0.002227783f, 0.001937866f, 0.001617432f, 0.001266479f, 0.000869751f, 0.000442505f, -3.0518E-05f, -0.000549316f, -0.001098633f, -0.001693726f,
			-0.002334595f, -0.003005981f, -0.003723145f, -0.004486084f, -0.0052948f, -0.006118774f, -0.007003784f, -0.007919312f, -0.008865356f, -0.009841919f,
			-0.010848999f, -0.011886597f, -0.012939453f, -0.014022827f, -0.01512146f, -0.016235352f, -0.017349243f, -0.018463135f, -0.019577026f, -0.020690918f,
			-0.02178955f, -0.022857666f, -0.023910522f, -0.024932861f, -0.025909424f, -0.02684021f, -0.02772522f, -0.028533936f, -0.029281616f, -0.029937744f,
			-0.030532837f, -0.03100586f, -0.03138733f, -0.031661987f, -0.031814575f, -0.031845093f, -0.03173828f, -0.03147888f, 0.031082153f, 0.030517578f,
			0.029785156f, 0.028884888f, 0.027801514f, 0.026535034f, 0.02508545f, 0.023422241f, 0.021575928f, 0.01953125f, 0.01725769f, 0.014801025f,
			0.012115479f, 0.009231567f, 0.006134033f, 0.002822876f, -0.000686646f, -0.004394531f, -0.00831604f, -0.012420654f, -0.016708374f, -0.0211792f,
			-0.025817871f, -0.03060913f, -0.03555298f, -0.040634155f, -0.045837402f, -0.051132202f, -0.056533813f, -0.06199646f, -0.06752014f, -0.07305908f,
			-0.07862854f, -0.08418274f, -0.08970642f, -0.09516907f, -0.10054016f, -0.1058197f, -0.110946655f, -0.11592102f, -0.12069702f, -0.1252594f,
			-0.12956238f, -0.1335907f, -0.13729858f, -0.14067078f, -0.14367676f, -0.1462555f, -0.14842224f, -0.15011597f, -0.15130615f, -0.15196228f,
			-0.15206909f, -0.15159607f, -0.15049744f, -0.1487732f, -0.1463623f, -0.14326477f, -0.13945007f, -0.1348877f, -0.12957764f, -0.12347412f,
			-0.11657715f, -0.1088562f, 0.10031128f, 0.090927124f, 0.08068848f, 0.06959534f, 0.057617188f, 0.044784546f, 0.031082153f, 0.01651001f,
			0.001068115f, -0.015228271f, -0.03237915f, -0.050354004f, -0.06916809f, -0.088775635f, -0.10916138f, -0.13031006f, -0.15220642f, -0.17478943f,
			-0.19805908f, -0.22198486f, -0.24650574f, -0.2715912f, -0.2972107f, -0.32331848f, -0.34986877f, -0.37680054f, -0.40408325f, -0.43165588f,
			-0.45947266f, -0.48747253f, -0.51560974f, -0.54382324f, -0.57203674f, -0.6002197f, -0.6282959f, -0.6562195f, -0.6839142f, -0.71131897f,
			-0.7383728f, -0.7650299f, -0.791214f, -0.816864f, -0.84194946f, -0.8663635f, -0.89009094f, -0.9130554f, -0.9351959f, -0.95648193f,
			-0.9768524f, -0.99624634f, -1.0146179f, -1.0319366f, -1.0481567f, -1.0632172f, -1.0771179f, -1.0897827f, -1.1012115f, -1.1113739f,
			-1.120224f, -1.1277466f, -1.1339264f, -1.1387634f, -1.1422119f, -1.1442871f, 1.144989f, 1.1442871f, 1.1422119f, 1.1387634f,
			1.1339264f, 1.1277466f, 1.120224f, 1.1113739f, 1.1012115f, 1.0897827f, 1.0771179f, 1.0632172f, 1.0481567f, 1.0319366f,
			1.0146179f, 0.99624634f, 0.9768524f, 0.95648193f, 0.9351959f, 0.9130554f, 0.89009094f, 0.8663635f, 0.84194946f, 0.816864f,
			0.791214f, 0.7650299f, 0.7383728f, 0.71131897f, 0.6839142f, 0.6562195f, 0.6282959f, 0.6002197f, 0.57203674f, 0.54382324f,
			0.51560974f, 0.48747253f, 0.45947266f, 0.43165588f, 0.40408325f, 0.37680054f, 0.34986877f, 0.32331848f, 0.2972107f, 0.2715912f,
			0.24650574f, 0.22198486f, 0.19805908f, 0.17478943f, 0.15220642f, 0.13031006f, 0.10916138f, 0.088775635f, 0.06916809f, 0.050354004f,
			0.03237915f, 0.015228271f, -0.001068115f, -0.01651001f, -0.031082153f, -0.044784546f, -0.057617188f, -0.06959534f, -0.08068848f, -0.090927124f,
			0.10031128f, 0.1088562f, 0.11657715f, 0.12347412f, 0.12957764f, 0.1348877f, 0.13945007f, 0.14326477f, 0.1463623f, 0.1487732f,
			0.15049744f, 0.15159607f, 0.15206909f, 0.15196228f, 0.15130615f, 0.15011597f, 0.14842224f, 0.1462555f, 0.14367676f, 0.14067078f,
			0.13729858f, 0.1335907f, 0.12956238f, 0.1252594f, 0.12069702f, 0.11592102f, 0.110946655f, 0.1058197f, 0.10054016f, 0.09516907f,
			0.08970642f, 0.08418274f, 0.07862854f, 0.07305908f, 0.06752014f, 0.06199646f, 0.056533813f, 0.051132202f, 0.045837402f, 0.040634155f,
			0.03555298f, 0.03060913f, 0.025817871f, 0.0211792f, 0.016708374f, 0.012420654f, 0.00831604f, 0.004394531f, 0.000686646f, -0.002822876f,
			-0.006134033f, -0.009231567f, -0.012115479f, -0.014801025f, -0.01725769f, -0.01953125f, -0.021575928f, -0.023422241f, -0.02508545f, -0.026535034f,
			-0.027801514f, -0.028884888f, -0.029785156f, -0.030517578f, 0.031082153f, 0.03147888f, 0.03173828f, 0.031845093f, 0.031814575f, 0.031661987f,
			0.03138733f, 0.03100586f, 0.030532837f, 0.029937744f, 0.029281616f, 0.028533936f, 0.02772522f, 0.02684021f, 0.025909424f, 0.024932861f,
			0.023910522f, 0.022857666f, 0.02178955f, 0.020690918f, 0.019577026f, 0.018463135f, 0.017349243f, 0.016235352f, 0.01512146f, 0.014022827f,
			0.012939453f, 0.011886597f, 0.010848999f, 0.009841919f, 0.008865356f, 0.007919312f, 0.007003784f, 0.006118774f, 0.0052948f, 0.004486084f,
			0.003723145f, 0.003005981f, 0.002334595f, 0.001693726f, 0.001098633f, 0.000549316f, 3.0518E-05f, -0.000442505f, -0.000869751f, -0.001266479f,
			-0.001617432f, -0.001937866f, -0.002227783f, -0.002487183f, -0.002700806f, -0.002883911f, -0.003051758f, -0.003173828f, -0.00328064f, -0.003372192f,
			-0.003417969f, -0.003463745f, -0.003479004f, -0.003479004f, -0.003463745f, -0.003433228f, -0.003387451f, -0.003326416f, 0.003250122f, 0.003173828f,
			0.003082275f, 0.002990723f, 0.00289917f, 0.002792358f, 0.002685547f, 0.002578735f, 0.002456665f, 0.002349854f, 0.002243042f, 0.002120972f,
			0.00201416f, 0.001907349f, 0.001785278f, 0.001693726f, 0.001586914f, 0.001480103f, 0.00138855f, 0.001296997f, 0.001205444f, 0.001113892f,
			0.001037598f, 0.000961304f, 0.00088501f, 0.000808716f, 0.000747681f, 0.000686646f, 0.00062561f, 0.000579834f, 0.000534058f, 0.000473022f,
			0.000442505f, 0.000396729f, 0.000366211f, 0.000320435f, 0.000289917f, 0.000259399f, 0.000244141f, 0.000213623f, 0.000198364f, 0.000167847f,
			0.000152588f, 0.000137329f, 0.00012207f, 0.000106812f, 0.000106812f, 9.1553E-05f, 7.6294E-05f, 7.6294E-05f, 6.1035E-05f, 6.1035E-05f,
			4.5776E-05f, 4.5776E-05f, 3.0518E-05f, 3.0518E-05f, 3.0518E-05f, 3.0518E-05f, 1.5259E-05f, 1.5259E-05f, 1.5259E-05f, 1.5259E-05f,
			1.5259E-05f, 1.5259E-05f
		};

		private static float[] SYNTH_COS64_TABLE = new float[31]
		{
			0.500603f, 0.5024193f, 0.50547093f, 0.5097956f, 0.5154473f, 0.5224986f, 0.5310426f, 0.5411961f, 0.5531039f, 0.56694406f,
			0.582935f, 0.6013449f, 0.6225041f, 0.6468218f, 0.6748083f, 0.70710677f, 0.7445363f, 0.7881546f, 0.8393496f, 0.8999762f,
			0.9725682f, 1.0606776f, 1.1694399f, 1.306563f, 1.4841646f, 1.7224472f, 2.057781f, 2.5629156f, 3.4076085f, 5.1011486f,
			10.190008f
		};

		private List<float[]> _synBuf = new List<float[]>(2);

		private List<int> _bufOffset = new List<int>(2);

		private float[] _eq;

		private float[] ippuv = new float[512];

		private float[] ei32 = new float[16];

		private float[] eo32 = new float[16];

		private float[] oi32 = new float[16];

		private float[] oo32 = new float[16];

		private float[] ei16 = new float[8];

		private float[] eo16 = new float[8];

		private float[] oi16 = new float[8];

		private float[] oo16 = new float[8];

		private float[] ei8 = new float[4];

		private float[] tmp8 = new float[6];

		private float[] oi8 = new float[4];

		private float[] oo8 = new float[4];

		internal StereoMode StereoMode { get; set; }

		internal LayerDecoderBase()
		{
			StereoMode = StereoMode.Both;
		}

		internal abstract int DecodeFrame(IMpegFrame frame, float[] ch0, float[] ch1);

		internal void SetEQ(float[] eq)
		{
			if (eq == null || eq.Length == 32)
			{
				_eq = eq;
			}
		}

		internal virtual void ResetForSeek()
		{
			_synBuf.Clear();
			_bufOffset.Clear();
		}

		protected void InversePolyPhase(int channel, float[] data)
		{
			GetBufAndOffset(channel, out var synBuf, out var k);
			if (_eq != null)
			{
				for (int i = 0; i < 32; i++)
				{
					data[i] *= _eq[i];
				}
			}
			DCT32(data, synBuf, k);
			BuildUVec(ippuv, synBuf, k);
			DewindowOutput(ippuv, data);
		}

		private void GetBufAndOffset(int channel, out float[] synBuf, out int k)
		{
			while (_synBuf.Count <= channel)
			{
				_synBuf.Add(new float[1024]);
			}
			while (_bufOffset.Count <= channel)
			{
				_bufOffset.Add(0);
			}
			synBuf = _synBuf[channel];
			k = _bufOffset[channel];
			k = (k - 32) & 0x1FF;
			_bufOffset[channel] = k;
		}

		private void DCT32(float[] _in, float[] _out, int k)
		{
			for (int i = 0; i < 16; i++)
			{
				ei32[i] = _in[i] + _in[31 - i];
				oi32[i] = (_in[i] - _in[31 - i]) * SYNTH_COS64_TABLE[2 * i];
			}
			DCT16(ei32, eo32);
			DCT16(oi32, oo32);
			for (int i = 0; i < 15; i++)
			{
				_out[2 * i + k] = eo32[i];
				_out[2 * i + 1 + k] = oo32[i] + oo32[i + 1];
			}
			_out[30 + k] = eo32[15];
			_out[31 + k] = oo32[15];
		}

		private void DCT16(float[] _in, float[] _out)
		{
			float num = _in[0];
			float num2 = _in[15];
			ei16[0] = num + num2;
			oi16[0] = (num - num2) * SYNTH_COS64_TABLE[1];
			num = _in[1];
			num2 = _in[14];
			ei16[1] = num + num2;
			oi16[1] = (num - num2) * SYNTH_COS64_TABLE[5];
			num = _in[2];
			num2 = _in[13];
			ei16[2] = num + num2;
			oi16[2] = (num - num2) * SYNTH_COS64_TABLE[9];
			num = _in[3];
			num2 = _in[12];
			ei16[3] = num + num2;
			oi16[3] = (num - num2) * SYNTH_COS64_TABLE[13];
			num = _in[4];
			num2 = _in[11];
			ei16[4] = num + num2;
			oi16[4] = (num - num2) * SYNTH_COS64_TABLE[17];
			num = _in[5];
			num2 = _in[10];
			ei16[5] = num + num2;
			oi16[5] = (num - num2) * SYNTH_COS64_TABLE[21];
			num = _in[6];
			num2 = _in[9];
			ei16[6] = num + num2;
			oi16[6] = (num - num2) * SYNTH_COS64_TABLE[25];
			num = _in[7];
			num2 = _in[8];
			ei16[7] = num + num2;
			oi16[7] = (num - num2) * SYNTH_COS64_TABLE[29];
			DCT8(ei16, eo16);
			DCT8(oi16, oo16);
			_out[0] = eo16[0];
			_out[1] = oo16[0] + oo16[1];
			_out[2] = eo16[1];
			_out[3] = oo16[1] + oo16[2];
			_out[4] = eo16[2];
			_out[5] = oo16[2] + oo16[3];
			_out[6] = eo16[3];
			_out[7] = oo16[3] + oo16[4];
			_out[8] = eo16[4];
			_out[9] = oo16[4] + oo16[5];
			_out[10] = eo16[5];
			_out[11] = oo16[5] + oo16[6];
			_out[12] = eo16[6];
			_out[13] = oo16[6] + oo16[7];
			_out[14] = eo16[7];
			_out[15] = oo16[7];
		}

		private void DCT8(float[] _in, float[] _out)
		{
			ei8[0] = _in[0] + _in[7];
			ei8[1] = _in[3] + _in[4];
			ei8[2] = _in[1] + _in[6];
			ei8[3] = _in[2] + _in[5];
			tmp8[0] = ei8[0] + ei8[1];
			tmp8[1] = ei8[2] + ei8[3];
			tmp8[2] = (ei8[0] - ei8[1]) * SYNTH_COS64_TABLE[7];
			tmp8[3] = (ei8[2] - ei8[3]) * SYNTH_COS64_TABLE[23];
			tmp8[4] = (tmp8[2] - tmp8[3]) * 0.70710677f;
			_out[0] = tmp8[0] + tmp8[1];
			_out[2] = tmp8[2] + tmp8[3] + tmp8[4];
			_out[4] = (tmp8[0] - tmp8[1]) * 0.70710677f;
			_out[6] = tmp8[4];
			oi8[0] = (_in[0] - _in[7]) * SYNTH_COS64_TABLE[3];
			oi8[1] = (_in[1] - _in[6]) * SYNTH_COS64_TABLE[11];
			oi8[2] = (_in[2] - _in[5]) * SYNTH_COS64_TABLE[19];
			oi8[3] = (_in[3] - _in[4]) * SYNTH_COS64_TABLE[27];
			tmp8[0] = oi8[0] + oi8[3];
			tmp8[1] = oi8[1] + oi8[2];
			tmp8[2] = (oi8[0] - oi8[3]) * SYNTH_COS64_TABLE[7];
			tmp8[3] = (oi8[1] - oi8[2]) * SYNTH_COS64_TABLE[23];
			tmp8[4] = tmp8[2] + tmp8[3];
			tmp8[5] = (tmp8[2] - tmp8[3]) * 0.70710677f;
			oo8[0] = tmp8[0] + tmp8[1];
			oo8[1] = tmp8[4] + tmp8[5];
			oo8[2] = (tmp8[0] - tmp8[1]) * 0.70710677f;
			oo8[3] = tmp8[5];
			_out[1] = oo8[0] + oo8[1];
			_out[3] = oo8[1] + oo8[2];
			_out[5] = oo8[2] + oo8[3];
			_out[7] = oo8[3];
		}

		private void BuildUVec(float[] u_vec, float[] cur_synbuf, int k)
		{
			int num = 0;
			for (int i = 0; i < 8; i++)
			{
				for (int j = 0; j < 16; j++)
				{
					u_vec[num + j] = cur_synbuf[k + j + 16];
					u_vec[num + j + 17] = 0f - cur_synbuf[k + 31 - j];
				}
				k = (k + 32) & 0x1FF;
				for (int j = 0; j < 16; j++)
				{
					u_vec[num + j + 32] = 0f - cur_synbuf[k + 16 - j];
					u_vec[num + j + 48] = 0f - cur_synbuf[k + j];
				}
				u_vec[num + 16] = 0f;
				k = (k + 32) & 0x1FF;
				num += 64;
			}
		}

		private void DewindowOutput(float[] u_vec, float[] samples)
		{
			for (int i = 0; i < 512; i++)
			{
				u_vec[i] *= DEWINDOW_TABLE[i];
			}
			for (int j = 0; j < 32; j++)
			{
				float num = u_vec[j];
				num += u_vec[j + 32];
				num += u_vec[j + 64];
				num += u_vec[j + 96];
				num += u_vec[j + 128];
				num += u_vec[j + 160];
				num += u_vec[j + 192];
				num += u_vec[j + 224];
				num += u_vec[j + 256];
				num += u_vec[j + 288];
				num += u_vec[j + 320];
				num += u_vec[j + 352];
				num += u_vec[j + 384];
				num += u_vec[j + 416];
				num += u_vec[j + 448];
				num += u_vec[j + 480];
				u_vec[j] = num;
			}
			for (int k = 0; k < 32; k++)
			{
				samples[k] = u_vec[k];
			}
		}
	}
	internal class LayerIDecoder : LayerIIDecoderBase
	{
		private static readonly int[] _rateTable = new int[32];

		private static readonly int[][] _allocLookupTable = new int[1][] { new int[17]
		{
			4, 0, 2, 3, 4, 5, 6, 7, 8, 9,
			10, 11, 12, 13, 14, 15, 16
		} };

		internal static bool GetCRC(MpegFrame frame, ref uint crc)
		{
			return LayerIIDecoderBase.GetCRC(frame, _rateTable, _allocLookupTable, readScfsiBits: false, ref crc);
		}

		internal LayerIDecoder()
			: base(_allocLookupTable, 1)
		{
		}

		protected override int[] GetRateTable(IMpegFrame frame)
		{
			return _rateTable;
		}

		protected override void ReadScaleFactorSelection(IMpegFrame frame, int[][] scfsi, int channels)
		{
		}
	}
	internal class LayerIIDecoder : LayerIIDecoderBase
	{
		private static readonly int[][] _rateLookupTable = new int[5][]
		{
			new int[27]
			{
				3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
				2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 0, 0, 0, 0
			},
			new int[30]
			{
				3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
				2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 0, 0, 0, 0, 0, 0, 0
			},
			new int[8] { 4, 4, 5, 5, 5, 5, 5, 5 },
			new int[12]
			{
				4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
				5, 5
			},
			new int[30]
			{
				6, 6, 6, 6, 5, 5, 5, 5, 5, 5,
				5, 7, 7, 7, 7, 7, 7, 7, 7, 7,
				7, 7, 7, 7, 7, 7, 7, 7, 7, 7
			}
		};

		private static readonly int[][] _allocLookupTable = new int[8][]
		{
			new int[5] { 2, 0, -5, -7, 16 },
			new int[9] { 3, 0, -5, -7, 3, -10, 4, 5, 16 },
			new int[17]
			{
				4, 0, -5, -7, 3, -10, 4, 5, 6, 7,
				8, 9, 10, 11, 12, 13, 16
			},
			new int[17]
			{
				4, 0, -5, 3, 4, 5, 6, 7, 8, 9,
				10, 11, 12, 13, 14, 15, 16
			},
			new int[17]
			{
				4, 0, -5, -7, -10, 4, 5, 6, 7, 8,
				9, 10, 11, 12, 13, 14, 15
			},
			new int[9] { 3, 0, -5, -7, -10, 4, 5, 6, 9 },
			new int[17]
			{
				4, 0, -5, -7, 3, -10, 4, 5, 6, 7,
				8, 9, 10, 11, 12, 13, 14
			},
			new int[5] { 2, 0, -5, -7, 3 }
		};

		internal static bool GetCRC(MpegFrame frame, ref uint crc)
		{
			return LayerIIDecoderBase.GetCRC(frame, SelectTable(frame), _allocLookupTable, readScfsiBits: true, ref crc);
		}

		private static int[] SelectTable(IMpegFrame frame)
		{
			int num = frame.BitRate / ((frame.ChannelMode == MpegChannelMode.Mono) ? 1 : 2) / 1000;
			if (frame.Version == MpegVersion.Version1)
			{
				if ((num >= 56 && num <= 80) || (frame.SampleRate == 48000 && num >= 56))
				{
					return _rateLookupTable[0];
				}
				if (frame.SampleRate != 48000 && num >= 96)
				{
					return _rateLookupTable[1];
				}
				if (frame.SampleRate != 32000 && num <= 48)
				{
					return _rateLookupTable[2];
				}
				return _rateLookupTable[3];
			}
			return _rateLookupTable[4];
		}

		internal LayerIIDecoder()
			: base(_allocLookupTable, 3)
		{
		}

		protected override int[] GetRateTable(IMpegFrame frame)
		{
			return SelectTable(frame);
		}

		protected override void ReadScaleFactorSelection(IMpegFrame frame, int[][] scfsi, int channels)
		{
			for (int i = 0; i < 30; i++)
			{
				for (int j = 0; j < channels; j++)
				{
					if (scfsi[j][i] == 2)
					{
						scfsi[j][i] = frame.ReadBits(2);
					}
				}
			}
		}
	}
	internal abstract class LayerIIDecoderBase : LayerDecoderBase
	{
		protected const int SSLIMIT = 12;

		private static readonly float[] _groupedC = new float[5] { 0f, 0f, 1.3333334f, 1.6f, 1.7777778f };

		private static readonly float[] _groupedD = new float[5] { 0f, 0f, -0.5f, -0.5f, -0.5f };

		private static readonly float[] _C = new float[17]
		{
			0f, 0f, 1.3333334f, 1.1428572f, 1.0666667f, 1.032258f, 1.0158731f, 1.007874f, 1.0039216f, 1.0019569f,
			1.0009775f, 1.0004885f, 1.0002443f, 1.0001221f, 1.000061f, 1.0000305f, 1.0000153f
		};

		private static readonly float[] _D = new float[17]
		{
			0f,
			0f,
			-0.5f,
			-0.75f,
			-0.875f,
			-0.9375f,
			-31f / 32f,
			-63f / 64f,
			-127f / 128f,
			-0.99609375f,
			-0.9980469f,
			-0.99902344f,
			-0.9995117f,
			-0.99975586f,
			-0.9998779f,
			-0.99993896f,
			-0.9999695f
		};

		private static readonly float[] _denormalMultiplier = new float[64]
		{
			2f,
			1.587401f,
			1.2599211f,
			1f,
			0.7937005f,
			0.62996054f,
			0.5f,
			0.39685026f,
			0.31498027f,
			0.25f,
			0.19842513f,
			0.15749013f,
			0.125f,
			0.099212565f,
			0.07874507f,
			0.0625f,
			0.049606282f,
			0.039372534f,
			1f / 32f,
			0.024803141f,
			0.019686267f,
			1f / 64f,
			0.012401571f,
			0.009843133f,
			1f / 128f,
			0.0062007853f,
			0.0049215667f,
			0.00390625f,
			0.0031003926f,
			0.0024607833f,
			0.001953125f,
			0.0015501963f,
			0.0012303917f,
			0.0009765625f,
			0.00077509816f,
			0.00061519584f,
			0.00048828125f,
			0.00038754908f,
			0.00030759792f,
			0.00024414062f,
			0.00019377454f,
			0.00015379896f,
			0.00012207031f,
			9.688727E-05f,
			7.689948E-05f,
			6.1035156E-05f,
			4.8443635E-05f,
			3.844974E-05f,
			3.0517578E-05f,
			2.4221818E-05f,
			1.922487E-05f,
			1.5258789E-05f,
			1.2110909E-05f,
			9.612435E-06f,
			7.6293945E-06f,
			6.0554544E-06f,
			4.8062175E-06f,
			3.8146973E-06f,
			3.0277272E-06f,
			2.4031087E-06f,
			1.9073486E-06f,
			1.5138636E-06f,
			1.2015544E-06f,
			9.536743E-07f
		};

		private int _channels;

		private int _jsbound;

		private int _granuleCount;

		private int[][] _allocLookupTable;

		private int[][] _scfsi;

		private int[][] _samples;

		private int[][][] _scalefac;

		private float[] _polyPhaseBuf;

		private int[][] _allocation;

		protected static bool GetCRC(MpegFrame frame, int[] rateTable, int[][] allocLookupTable, bool readScfsiBits, ref uint crc)
		{
			int num = 0;
			int num2 = rateTable.Length;
			int num3 = num2;
			if (frame.ChannelMode == MpegChannelMode.JointStereo)
			{
				num3 = frame.ChannelModeExtension * 4 + 4;
			}
			int num4 = ((frame.ChannelMode == MpegChannelMode.Mono) ? 1 : 2);
			int i;
			for (i = 0; i < num3; i++)
			{
				int num5 = allocLookupTable[rateTable[i]][0];
				for (int j = 0; j < num4; j++)
				{
					int num6 = frame.ReadBits(num5);
					if (num6 > 0)
					{
						num += 2;
					}
					MpegFrame.UpdateCRC(num6, num5, ref crc);
				}
			}
			for (; i < num2; i++)
			{
				int num7 = allocLookupTable[rateTable[i]][0];
				int num8 = frame.ReadBits(num7);
				if (num8 > 0)
				{
					num += num4 * 2;
				}
				MpegFrame.UpdateCRC(num8, num7, ref crc);
			}
			if (readScfsiBits)
			{
				while (num >= 2)
				{
					MpegFrame.UpdateCRC(frame.ReadBits(2), 2, ref crc);
					num -= 2;
				}
			}
			return true;
		}

		protected LayerIIDecoderBase(int[][] allocLookupTable, int granuleCount)
		{
			_allocLookupTable = allocLookupTable;
			_granuleCount = granuleCount;
			_allocation = new int[2][]
			{
				new int[32],
				new int[32]
			};
			_scfsi = new int[2][]
			{
				new int[32],
				new int[32]
			};
			_samples = new int[2][]
			{
				new int[384 * _granuleCount],
				new int[384 * _granuleCount]
			};
			_scalefac = new int[2][][]
			{
				new int[3][],
				new int[3][]
			};
			for (int i = 0; i < 3; i++)
			{
				_scalefac[0][i] = new int[32];
				_scalefac[1][i] = new int[32];
			}
			_polyPhaseBuf = new float[32];
		}

		internal override int DecodeFrame(IMpegFrame frame, float[] ch0, float[] ch1)
		{
			InitFrame(frame);
			int[] rateTable = GetRateTable(frame);
			ReadAllocation(frame, rateTable);
			for (int i = 0; i < _scfsi[0].Length; i++)
			{
				_scfsi[0][i] = ((_allocation[0][i] != 0) ? 2 : (-1));
				_scfsi[1][i] = ((_allocation[1][i] != 0) ? 2 : (-1));
			}
			ReadScaleFactorSelection(frame, _scfsi, _channels);
			ReadScaleFactors(frame);
			ReadSamples(frame);
			return DecodeSamples(ch0, ch1);
		}

		private void InitFrame(IMpegFrame frame)
		{
			switch (frame.ChannelMode)
			{
			case MpegChannelMode.Mono:
				_channels = 1;
				_jsbound = 32;
				break;
			case MpegChannelMode.JointStereo:
				_channels = 2;
				_jsbound = frame.ChannelModeExtension * 4 + 4;
				break;
			default:
				_channels = 2;
				_jsbound = 32;
				break;
			}
		}

		protected abstract int[] GetRateTable(IMpegFrame frame);

		private void ReadAllocation(IMpegFrame frame, int[] rateTable)
		{
			int num = rateTable.Length;
			if (_jsbound > num)
			{
				_jsbound = num;
			}
			Array.Clear(_allocation[0], 0, 32);
			Array.Clear(_allocation[1], 0, 32);
			int i;
			for (i = 0; i < _jsbound; i++)
			{
				int[] array = _allocLookupTable[rateTable[i]];
				int bitCount = array[0];
				for (int j = 0; j < _channels; j++)
				{
					_allocation[j][i] = array[frame.ReadBits(bitCount) + 1];
				}
			}
			for (; i < num; i++)
			{
				int[] array2 = _allocLookupTable[rateTable[i]];
				_allocation[0][i] = (_allocation[1][i] = array2[frame.ReadBits(array2[0]) + 1]);
			}
		}

		protected abstract void ReadScaleFactorSelection(IMpegFrame frame, int[][] scfsi, int channels);

		private void ReadScaleFactors(IMpegFrame frame)
		{
			for (int i = 0; i < 32; i++)
			{
				for (int j = 0; j < _channels; j++)
				{
					switch (_scfsi[j][i])
					{
					case 0:
						_scalefac[j][0][i] = frame.ReadBits(6);
						_scalefac[j][1][i] = frame.ReadBits(6);
						_scalefac[j][2][i] = frame.ReadBits(6);
						break;
					case 1:
						_scalefac[j][0][i] = (_scalefac[j][1][i] = frame.ReadBits(6));
						_scalefac[j][2][i] = frame.ReadBits(6);
						break;
					case 2:
						_scalefac[j][0][i] = (_scalefac[j][1][i] = (_scalefac[j][2][i] = frame.ReadBits(6)));
						break;
					case 3:
						_scalefac[j][0][i] = frame.ReadBits(6);
						_scalefac[j][1][i] = (_scalefac[j][2][i] = frame.ReadBits(6));
						break;
					default:
						_scalefac[j][0][i] = 63;
						_scalefac[j][1][i] = 63;
						_scalefac[j][2][i] = 63;
						break;
					}
				}
			}
		}

		private void ReadSamples(IMpegFrame frame)
		{
			int num = 0;
			int num2 = 0;
			while (num < 12)
			{
				int num3 = 0;
				while (num3 < 32)
				{
					for (int i = 0; i < _channels; i++)
					{
						if (i == 0 || num3 < _jsbound)
						{
							int num4 = _allocation[i][num3];
							if (num4 != 0)
							{
								if (num4 < 0)
								{
									int num5 = frame.ReadBits(-num4);
									int num6 = (1 << -num4 / 2 + -num4 % 2 - 1) + 1;
									_samples[i][num2] = num5 % num6;
									num5 /= num6;
									_samples[i][num2 + 32] = num5 % num6;
									_samples[i][num2 + 64] = num5 / num6;
								}
								else
								{
									for (int j = 0; j < _granuleCount; j++)
									{
										_samples[i][num2 + 32 * j] = frame.ReadBits(num4);
									}
								}
							}
							else
							{
								for (int k = 0; k < _granuleCount; k++)
								{
									_samples[i][num2 + 32 * k] = 0;
								}
							}
						}
						else
						{
							for (int l = 0; l < _granuleCount; l++)
							{
								_samples[1][num2 + 32 * l] = _samples[0][num2 + 32 * l];
							}
						}
					}
					num3++;
					num2++;
				}
				num++;
				num2 += 32 * (_granuleCount - 1);
			}
		}

		private int DecodeSamples(float[] ch0, float[] ch1)
		{
			float[][] array = new float[2][];
			int num = 0;
			int num2 = _channels - 1;
			if (_channels == 1 || base.StereoMode == StereoMode.LeftOnly)
			{
				array[0] = ch0;
				num2 = 0;
			}
			else if (base.StereoMode == StereoMode.RightOnly)
			{
				array[1] = ch0;
				num = 1;
			}
			else
			{
				array[0] = ch0;
				array[1] = ch1;
			}
			int num3 = 0;
			for (int i = num; i <= num2; i++)
			{
				num3 = 0;
				for (int j = 0; j < _granuleCount; j++)
				{
					for (int k = 0; k < 12; k++)
					{
						int num4 = 0;
						while (num4 < 32)
						{
							int num5 = _allocation[i][num4];
							if (num5 != 0)
							{
								float[] array2;
								float[] array3;
								if (num5 < 0)
								{
									num5 = -num5 / 2 + -num5 % 2 - 1;
									array2 = _groupedC;
									array3 = _groupedD;
								}
								else
								{
									array2 = _C;
									array3 = _D;
								}
								_polyPhaseBuf[num4] = array2[num5] * ((float)(_samples[i][num3] << 16 - num5) / 32768f + array3[num5]) * _denormalMultiplier[_scalefac[i][j][num4]];
							}
							else
							{
								_polyPhaseBuf[num4] = 0f;
							}
							num4++;
							num3++;
						}
						InversePolyPhase(i, _polyPhaseBuf);
						Array.Copy(_polyPhaseBuf, 0, array[i], num3 - 32, 32);
					}
				}
			}
			if (_channels == 2 && base.StereoMode == StereoMode.DownmixToMono)
			{
				for (int l = 0; l < num3; l++)
				{
					ch0[l] = (ch0[l] + ch1[l]) / 2f;
				}
			}
			return num3;
		}
	}
	internal sealed class LayerIIIDecoder : LayerDecoderBase
	{
		private class HybridMDCT
		{
			private const float PI = MathF.PI;

			private static float[][] _swin;

			private static float[] icos72_table;

			private List<float[]> _prevBlock;

			private List<float[]> _nextBlock;

			private float[] _imdctTemp = new float[18];

			private float[] _imdctResult = new float[36];

			private const float sqrt32 = 0.8660254f;

			static HybridMDCT()
			{
				icos72_table = new float[35]
				{
					0.50047636f, 0.5019099f, 0.5043145f, 0.5077133f, 0.51213974f, 0.5176381f, 0.5242646f, 0.5320889f, 0.5411961f, 0.55168897f,
					0.56369096f, 0.57735026f, 0.59284455f, 0.61038727f, 0.6302362f, 0.65270364f, 0.67817086f, 0.70710677f, 0.7400936f, 0.7778619f,
					0.8213398f, 0.8717234f, 0.9305795f, 1f, 1.0828403f, 1.1831008f, 1.306563f, 1.4619021f, 1.6627548f, 1.9318516f,
					2.3101132f, 2.8793852f, 3.830649f, 5.7368565f, 11.462792f
				};
				_swin = new float[4][]
				{
					new float[36],
					new float[36],
					new float[36],
					new float[36]
				};
				for (int i = 0; i < 36; i++)
				{
					_swin[0][i] = (float)Math.Sin(0.0872664675116539 * ((double)i + 0.5));
				}
				for (int i = 0; i < 18; i++)
				{
					_swin[1][i] = (float)Math.Sin(0.0872664675116539 * ((double)i + 0.5));
				}
				for (int i = 18; i < 24; i++)
				{
					_swin[1][i] = 1f;
				}
				for (int i = 24; i < 30; i++)
				{
					_swin[1][i] = (float)Math.Sin(0.2617993950843811 * ((double)i + 0.5 - 18.0));
				}
				for (int i = 30; i < 36; i++)
				{
					_swin[1][i] = 0f;
				}
				for (int i = 0; i < 6; i++)
				{
					_swin[3][i] = 0f;
				}
				for (int i = 6; i < 12; i++)
				{
					_swin[3][i] = (float)Math.Sin(0.2617993950843811 * ((double)i + 0.5 - 6.0));
				}
				for (int i = 12; i < 18; i++)
				{
					_swin[3][i] = 1f;
				}
				for (int i = 18; i < 36; i++)
				{
					_swin[3][i] = (float)Math.Sin(0.0872664675116539 * ((double)i + 0.5));
				}
				for (int i = 0; i < 12; i++)
				{
					_swin[2][i] = (float)Math.Sin(0.2617993950843811 * ((double)i + 0.5));
				}
				for (int i = 12; i < 36; i++)
				{
					_swin[2][i] = 0f;
				}
			}

			internal HybridMDCT()
			{
				_prevBlock = new List<float[]>();
				_nextBlock = new List<float[]>();
			}

			internal void Reset()
			{
				_prevBlock.Clear();
				_nextBlock.Clear();
			}

			private void GetPrevBlock(int channel, out float[] prevBlock, out float[] nextBlock)
			{
				while (_prevBlock.Count <= channel)
				{
					_prevBlock.Add(new float[576]);
				}
				while (_nextBlock.Count <= channel)
				{
					_nextBlock.Add(new float[576]);
				}
				prevBlock = _prevBlock[channel];
				nextBlock = _nextBlock[channel];
				_nextBlock[channel] = prevBlock;
				_prevBlock[channel] = nextBlock;
			}

			internal void Apply(float[] fsIn, int channel, int blockType, bool doMixed)
			{
				GetPrevBlock(channel, out var prevBlock, out var nextBlock);
				int sbStart = 0;
				if (doMixed)
				{
					LongImpl(fsIn, 0, 2, nextBlock, 0);
					sbStart = 2;
				}
				if (blockType == 2)
				{
					ShortImpl(fsIn, sbStart, nextBlock);
				}
				else
				{
					LongImpl(fsIn, sbStart, 32, nextBlock, blockType);
				}
				for (int i = 0; i < 576; i++)
				{
					fsIn[i] += prevBlock[i];
				}
			}

			private void LongImpl(float[] fsIn, int sbStart, int sbLimit, float[] nextblck, int blockType)
			{
				int i = sbStart;
				int num = sbStart * 18;
				for (; i < sbLimit; i++)
				{
					Array.Copy(fsIn, num, _imdctTemp, 0, 18);
					LongIMDCT(_imdctTemp, _imdctResult);
					float[] array = _swin[blockType];
					int j;
					for (j = 0; j < 18; j++)
					{
						fsIn[num++] = _imdctResult[j] * array[j];
					}
					num -= 18;
					for (; j < 36; j++)
					{
						nextblck[num++] = _imdctResult[j] * array[j];
					}
				}
			}

			private static void LongIMDCT(float[] invec, float[] outvec)
			{
				float[] array = new float[17];
				float[] array2 = new float[18];
				float[] array3 = new float[9];
				float[] array4 = new float[9];
				float[] array5 = new float[9];
				float[] array6 = new float[9];
				int i;
				for (i = 0; i < 17; i++)
				{
					array[i] = invec[i] + invec[i + 1];
				}
				array3[0] = invec[0];
				array4[0] = array[0];
				int num = 0;
				i = 1;
				while (i < 9)
				{
					array3[i] = array[num + 1];
					array4[i] = array[num] + array[num + 2];
					i++;
					num += 2;
				}
				imdct_9pt(array3, array5);
				imdct_9pt(array4, array6);
				for (i = 0; i < 9; i++)
				{
					array6[i] *= ICOS36_A(i);
					array2[i] = (array5[i] + array6[i]) * ICOS72_A(i);
				}
				for (; i < 18; i++)
				{
					array2[i] = (array5[17 - i] - array6[17 - i]) * ICOS72_A(i);
				}
				outvec[0] = array2[9];
				outvec[1] = array2[10];
				outvec[2] = array2[11];
				outvec[3] = array2[12];
				outvec[4] = array2[13];
				outvec[5] = array2[14];
				outvec[6] = array2[15];
				outvec[7] = array2[16];
				outvec[8] = array2[17];
				outvec[9] = 0f - array2[17];
				outvec[10] = 0f - array2[16];
				outvec[11] = 0f - array2[15];
				outvec[12] = 0f - array2[14];
				outvec[13] = 0f - array2[13];
				outvec[14] = 0f - array2[12];
				outvec[15] = 0f - array2[11];
				outvec[16] = 0f - array2[10];
				outvec[17] = 0f - array2[9];
				outvec[35] = (outvec[18] = 0f - array2[8]);
				outvec[34] = (outvec[19] = 0f - array2[7]);
				outvec[33] = (outvec[20] = 0f - array2[6]);
				outvec[32] = (outvec[21] = 0f - array2[5]);
				outvec[31] = (outvec[22] = 0f - array2[4]);
				outvec[30] = (outvec[23] = 0f - array2[3]);
				outvec[29] = (outvec[24] = 0f - array2[2]);
				outvec[28] = (outvec[25] = 0f - array2[1]);
				outvec[27] = (outvec[26] = 0f - array2[0]);
			}

			private static float ICOS72_A(int i)
			{
				return icos72_table[2 * i];
			}

			private static float ICOS36_A(int i)
			{
				return icos72_table[4 * i + 1];
			}

			private static void imdct_9pt(float[] invec, float[] outvec)
			{
				float[] array = new float[5];
				float[] array2 = new float[4];
				float num = invec[6] / 2f + invec[0];
				float num2 = invec[0] - invec[6];
				float num3 = invec[2] - invec[4] - invec[8];
				array[0] = num + invec[2] * 0.9396926f + invec[4] * 0.76604444f + invec[8] * 0.17364818f;
				array[1] = num3 / 2f + num2;
				array[2] = num - invec[2] * 0.17364818f - invec[4] * 0.9396926f + invec[8] * 0.76604444f;
				array[3] = num - invec[2] * 0.76604444f + invec[4] * 0.17364818f - invec[8] * 0.9396926f;
				array[4] = num2 - num3;
				float num4 = invec[1] + invec[3];
				float num5 = invec[3] + invec[5];
				num = (invec[5] + invec[7]) * 0.5f + invec[1];
				array2[0] = num + num4 * 0.9396926f + num5 * 0.76604444f;
				array2[1] = (invec[1] - invec[5]) * 1.5f - invec[7];
				array2[2] = num - num4 * 0.17364818f - num5 * 0.9396926f;
				array2[3] = num - num4 * 0.76604444f + num5 * 0.17364818f;
				array2[0] += invec[7] * 0.17364818f;
				array2[1] -= invec[7] * 0.5f;
				array2[2] += invec[7] * 0.76604444f;
				array2[3] -= invec[7] * 0.9396926f;
				array2[0] *= 0.5077133f;
				array2[1] *= 0.57735026f;
				array2[2] *= 0.7778619f;
				array2[3] *= 1.4619021f;
				for (int i = 0; i < 4; i++)
				{
					outvec[i] = array[i] + array2[i];
				}
				outvec[4] = array[4];
				for (int i = 5; i < 9; i++)
				{
					outvec[i] = array[8 - i] - array2[8 - i];
				}
			}

			private void ShortImpl(float[] fsIn, int sbStart, float[] nextblck)
			{
				_ = _swin[2];
				int num = sbStart;
				int num2 = sbStart * 18;
				while (num < 32)
				{
					int i = 0;
					int num3 = 0;
					for (; i < 3; i++)
					{
						int num4 = num2 + i;
						for (int j = 0; j < 6; j++)
						{
							_imdctTemp[num3 + j] = fsIn[num4];
							num4 += 3;
						}
						num3 += 6;
					}
					Array.Clear(fsIn, num2, 6);
					ShortIMDCT(_imdctTemp, 0, _imdctResult);
					Array.Copy(_imdctResult, 0, fsIn, num2 + 6, 12);
					ShortIMDCT(_imdct

NVorbis.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using NVorbis.Contracts;
using NVorbis.Contracts.Ogg;
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 2021")]
[assembly: AssemblyDescription("A fully managed implementation of a Xiph.org Foundation Ogg Vorbis decoder.")]
[assembly: AssemblyFileVersion("0.10.5.0")]
[assembly: AssemblyInformationalVersion("0.10.5")]
[assembly: AssemblyProduct("NVorbis")]
[assembly: AssemblyTitle("NVorbis")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/NVorbis/NVorbis")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: AssemblyVersion("0.10.5.0")]
namespace NVorbis
{
	internal class Codebook : ICodebook
	{
		private class FastRange : IReadOnlyList<int>, IEnumerable<int>, IEnumerable, IReadOnlyCollection<int>
		{
			[ThreadStatic]
			private static FastRange _cachedRange;

			private int _start;

			private int _count;

			public int this[int index]
			{
				get
				{
					if (index > _count)
					{
						throw new ArgumentOutOfRangeException();
					}
					return _start + index;
				}
			}

			public int Count => _count;

			internal static FastRange Get(int start, int count)
			{
				FastRange obj = _cachedRange ?? (_cachedRange = new FastRange());
				obj._start = start;
				obj._count = count;
				return obj;
			}

			private FastRange()
			{
			}

			public IEnumerator<int> GetEnumerator()
			{
				throw new NotSupportedException();
			}

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

		private int[] _lengths;

		private float[] _lookupTable;

		private IReadOnlyList<HuffmanListNode> _overflowList;

		private IReadOnlyList<HuffmanListNode> _prefixList;

		private int _prefixBitLength;

		private int _maxBits;

		public float this[int entry, int dim] => _lookupTable[entry * Dimensions + dim];

		public int Dimensions { get; private set; }

		public int Entries { get; private set; }

		public int MapType { get; private set; }

		public void Init(IPacket packet, IHuffman huffman)
		{
			if (packet.ReadBits(24) != 5653314)
			{
				throw new InvalidDataException("Book header had invalid signature!");
			}
			Dimensions = (int)packet.ReadBits(16);
			Entries = (int)packet.ReadBits(24);
			_lengths = new int[Entries];
			InitTree(packet, huffman);
			InitLookupTable(packet);
		}

		private void InitTree(IPacket packet, IHuffman huffman)
		{
			int num = 0;
			bool flag;
			int num5;
			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;
				num5 = num2;
			}
			else
			{
				num5 = -1;
				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 (_lengths[i] > num5)
					{
						num5 = _lengths[i];
					}
				}
			}
			if ((_maxBits = num5) > -1)
			{
				int[] array = null;
				if (flag && num >= Entries >> 2)
				{
					array = new int[Entries];
					Array.Copy(_lengths, array, Entries);
					flag = false;
				}
				int num6 = (flag ? num : 0);
				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, array3, array, _lengths, Entries, array2))
				{
					throw new InvalidDataException();
				}
				IReadOnlyList<int> readOnlyList = array2;
				IReadOnlyList<int> value = readOnlyList ?? FastRange.Get(0, array3.Length);
				huffman.GenerateTable(value, array ?? _lengths, array3);
				_prefixList = huffman.PrefixTree;
				_prefixBitLength = huffman.TableBits;
				_overflowList = huffman.OverflowList;
			}
		}

		private bool ComputeCodewords(bool sparse, 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(IPacket packet)
		{
			MapType = (int)packet.ReadBits(4);
			if (MapType == 0)
			{
				return;
			}
			float num = Utils.ConvertFromVorbisFloat32((uint)packet.ReadBits(32));
			float num2 = Utils.ConvertFromVorbisFloat32((uint)packet.ReadBits(32));
			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;
		}

		public int DecodeScalar(IPacket 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 var _);
			for (int i = 0; i < _overflowList.Count; i++)
			{
				huffmanListNode = _overflowList[i];
				if (huffmanListNode.Bits == (index & huffmanListNode.Mask))
				{
					packet.SkipBits(huffmanListNode.Length);
					return huffmanListNode.Value;
				}
			}
			return -1;
		}
	}
	public abstract class DataPacket : IPacket
	{
		[Flags]
		protected enum PacketFlags : byte
		{
			IsResync = 1,
			IsEndOfStream = 2,
			IsShort = 4,
			User0 = 8,
			User1 = 0x10,
			User2 = 0x20,
			User3 = 0x40,
			User4 = 0x80
		}

		private ulong _bitBucket;

		private int _bitCount;

		private byte _overflowBits;

		private PacketFlags _packetFlags;

		private int _readBits;

		public int ContainerOverheadBits { get; set; }

		public long? GranulePosition { get; set; }

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

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

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

		public int BitsRead => _readBits;

		public int BitsRemaining => TotalBits - _readBits;

		protected abstract int TotalBits { get; }

		private bool GetFlag(PacketFlags flag)
		{
			return _packetFlags.HasFlag(flag);
		}

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

		protected abstract int ReadNextByte();

		public virtual void Done()
		{
		}

		public virtual void Reset()
		{
			_bitBucket = 0uL;
			_bitCount = 0;
			_overflowBits = 0;
			_readBits = 0;
		}

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

		public ulong TryPeekBits(int count, out int bitsRead)
		{
			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 num = ReadNextByte();
				if (num == -1)
				{
					bitsRead = _bitCount;
					return _bitBucket;
				}
				_bitBucket = (ulong)((long)(num & 0xFF) << _bitCount) | _bitBucket;
				_bitCount += 8;
				if (_bitCount > 64)
				{
					_overflowBits = (byte)(num >> 72 - _bitCount);
				}
			}
			ulong num2 = _bitBucket;
			if (count < 64)
			{
				num2 &= (ulong)((1L << count) - 1);
			}
			bitsRead = count;
			return num2;
		}

		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;
			}
		}
	}
	public static class Extensions
	{
		public static int Read(this IPacket packet, byte[] buffer, int index, int count)
		{
			if (index < 0 || index >= buffer.Length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			if (count < 0 || index + count > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			for (int i = 0; i < count; i++)
			{
				int bitsRead;
				byte b = (byte)packet.TryPeekBits(8, out bitsRead);
				if (bitsRead == 0)
				{
					return i;
				}
				buffer[index++] = b;
				packet.SkipBits(8);
			}
			return count;
		}

		public static byte[] ReadBytes(this IPacket packet, int count)
		{
			byte[] array = new byte[count];
			int num = packet.Read(array, 0, count);
			if (num < count)
			{
				byte[] array2 = new byte[num];
				Buffer.BlockCopy(array, 0, array2, 0, num);
				return array2;
			}
			return array;
		}

		public static bool ReadBit(this IPacket packet)
		{
			return packet.ReadBits(1) == 1;
		}

		public static byte PeekByte(this IPacket packet)
		{
			int bitsRead;
			return (byte)packet.TryPeekBits(8, out bitsRead);
		}

		public static byte ReadByte(this IPacket packet)
		{
			return (byte)packet.ReadBits(8);
		}

		public static short ReadInt16(this IPacket packet)
		{
			return (short)packet.ReadBits(16);
		}

		public static int ReadInt32(this IPacket packet)
		{
			return (int)packet.ReadBits(32);
		}

		public static long ReadInt64(this IPacket packet)
		{
			return (long)packet.ReadBits(64);
		}

		public static ushort ReadUInt16(this IPacket packet)
		{
			return (ushort)packet.ReadBits(16);
		}

		public static uint ReadUInt32(this IPacket packet)
		{
			return (uint)packet.ReadBits(32);
		}

		public static ulong ReadUInt64(this IPacket packet)
		{
			return packet.ReadBits(64);
		}

		public static void SkipBytes(this IPacket packet, int count)
		{
			packet.SkipBits(count * 8);
		}
	}
	internal class Factory : IFactory
	{
		public IHuffman CreateHuffman()
		{
			return new Huffman();
		}

		public IMdct CreateMdct()
		{
			return new Mdct();
		}

		public ICodebook CreateCodebook()
		{
			return new Codebook();
		}

		public IFloor CreateFloor(IPacket packet)
		{
			return (int)packet.ReadBits(16) switch
			{
				0 => new Floor0(), 
				1 => new Floor1(), 
				_ => throw new InvalidDataException("Invalid floor type!"), 
			};
		}

		public IMapping CreateMapping(IPacket packet)
		{
			if (packet.ReadBits(16) != 0L)
			{
				throw new InvalidDataException("Invalid mapping type!");
			}
			return new Mapping();
		}

		public IMode CreateMode()
		{
			return new Mode();
		}

		public IResidue CreateResidue(IPacket packet)
		{
			return (int)packet.ReadBits(16) switch
			{
				0 => new Residue0(), 
				1 => new Residue1(), 
				2 => new Residue2(), 
				_ => throw new InvalidDataException("Invalid residue type!"), 
			};
		}
	}
	internal class Floor0 : IFloor
	{
		private class Data : IFloorData
		{
			internal float[] Coeff;

			internal float Amp;

			public bool ExecuteChannel
			{
				get
				{
					if (ForceEnergy || Amp > 0f)
					{
						return !ForceNoEnergy;
					}
					return false;
				}
			}

			public bool ForceEnergy { get; set; }

			public bool ForceNoEnergy { get; set; }
		}

		private int _order;

		private int _rate;

		private int _bark_map_size;

		private int _ampBits;

		private int _ampOfs;

		private int _ampDiv;

		private ICodebook[] _books;

		private int _bookBits;

		private Dictionary<int, float[]> _wMap;

		private Dictionary<int, int[]> _barkMaps;

		public void Init(IPacket packet, int channels, int block0Size, int block1Size, ICodebook[] codebooks)
		{
			_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 ICodebook[(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 >= codebooks.Length)
				{
					throw new InvalidDataException();
				}
				ICodebook codebook = codebooks[num];
				if (codebook.MapType == 0 || codebook.Dimensions < 1)
				{
					throw new InvalidDataException();
				}
				_books[i] = codebook;
			}
			_bookBits = Utils.ilog(_books.Length);
			_barkMaps = new Dictionary<int, int[]>
			{
				[block0Size] = SynthesizeBarkCurve(block0Size / 2),
				[block1Size] = SynthesizeBarkCurve(block1Size / 2)
			};
			_wMap = new Dictionary<int, float[]>
			{
				[block0Size] = SynthesizeWDelMap(block0Size / 2),
				[block1Size] = SynthesizeWDelMap(block1Size / 2)
			};
		}

		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;
		}

		public IFloorData Unpack(IPacket packet, int blockSize, int channel)
		{
			Data data = new Data
			{
				Coeff = new float[_order + 1]
			};
			data.Amp = packet.ReadBits(_ampBits);
			if (data.Amp > 0f)
			{
				Array.Clear(data.Coeff, 0, data.Coeff.Length);
				data.Amp = data.Amp / (float)_ampDiv * (float)_ampOfs;
				uint num = (uint)packet.ReadBits(_bookBits);
				if (num >= _books.Length)
				{
					data.Amp = 0f;
					return data;
				}
				ICodebook codebook = _books[num];
				int i = 0;
				while (i < _order)
				{
					int num2 = codebook.DecodeScalar(packet);
					if (num2 == -1)
					{
						data.Amp = 0f;
						return data;
					}
					int num3 = 0;
					for (; i < _order; i++)
					{
						if (num3 >= codebook.Dimensions)
						{
							break;
						}
						data.Coeff[i] = codebook[num2, num3];
						num3++;
					}
				}
				float num4 = 0f;
				int num5 = 0;
				while (num5 < _order)
				{
					int num6 = 0;
					while (num5 < _order && num6 < codebook.Dimensions)
					{
						data.Coeff[num5] += num4;
						num5++;
						num6++;
					}
					num4 = data.Coeff[num5 - 1];
				}
			}
			return data;
		}

		public void Apply(IFloorData floorData, int blockSize, float[] residue)
		{
			if (!(floorData is Data data))
			{
				throw new ArgumentException("Incorrect packet data!");
			}
			int num = blockSize / 2;
			if (data.Amp > 0f)
			{
				int[] array = _barkMaps[blockSize];
				float[] array2 = _wMap[blockSize];
				int num2 = 0;
				for (num2 = 0; num2 < _order; num2++)
				{
					data.Coeff[num2] = 2f * (float)Math.Cos(data.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 - data.Coeff[i - 1];
						num4 *= num6 - data.Coeff[i];
					}
					if (i == _order)
					{
						num5 *= num6 - data.Coeff[i - 1];
						num4 *= num4 * (4f - num6 * num6);
						num5 *= num5;
					}
					else
					{
						num4 *= num4 * (2f - num6);
						num5 *= num5 * (2f + num6);
					}
					num5 = data.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);
			}
		}
	}
	internal class Floor1 : IFloor
	{
		private class Data : IFloorData
		{
			internal int[] Posts = new int[64];

			internal int PostCount;

			public bool ExecuteChannel
			{
				get
				{
					if (ForceEnergy || PostCount > 0)
					{
						return !ForceNoEnergy;
					}
					return false;
				}
			}

			public bool ForceEnergy { get; set; }

			public bool ForceNoEnergy { get; set; }
		}

		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 ICodebook[] _classMasterbooks;

		private ICodebook[][] _subclassBooks;

		private int[][] _subclassBookIndex;

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

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

		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
		};

		public void Init(IPacket packet, int channels, int block0Size, int block1Size, ICodebook[] codebooks)
		{
			int num = -1;
			_partitionClass = new int[(uint)packet.ReadBits(5)];
			for (int i = 0; i < _partitionClass.Length; i++)
			{
				_partitionClass[i] = (int)packet.ReadBits(4);
				if (_partitionClass[i] > num)
				{
					num = _partitionClass[i];
				}
			}
			_classDimensions = new int[++num];
			_classSubclasses = new int[num];
			_classMasterbooks = new ICodebook[num];
			_classMasterBookIndex = new int[num];
			_subclassBooks = new ICodebook[num][];
			_subclassBookIndex = new int[num][];
			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] = codebooks[_classMasterBookIndex[j]];
				}
				_subclassBooks[j] = new ICodebook[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] = codebooks[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;
					}
				}
			}
		}

		public IFloorData Unpack(IPacket packet, int blockSize, int channel)
		{
			Data data = new Data();
			if (packet.ReadBit())
			{
				int num = 2;
				data.Posts[0] = (int)packet.ReadBits(_yBits);
				data.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++)
					{
						ICodebook codebook = _subclassBooks[num2][num6 & num5];
						num6 >>= num4;
						if (codebook != null && (data.Posts[num] = codebook.DecodeScalar(packet)) == -1)
						{
							num = 0;
							i = _partitionClass.Length;
							break;
						}
						num++;
					}
				}
				data.PostCount = num;
			}
			return data;
		}

		public void Apply(IFloorData floorData, int blockSize, float[] residue)
		{
			if (!(floorData is Data data))
			{
				throw new ArgumentException("Incorrect packet data!", "packetData");
			}
			int num = blockSize / 2;
			if (data.PostCount > 0)
			{
				bool[] array = UnwrapPosts(data);
				int num2 = 0;
				int num3 = data.Posts[0] * _multiplier;
				for (int i = 1; i < data.PostCount; i++)
				{
					int num4 = _sortIdx[i];
					if (array[num4])
					{
						int num5 = _xList[num4];
						int num6 = data.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(Data data)
		{
			bool[] array = new bool[64];
			array[0] = true;
			array[1] = true;
			int[] array2 = new int[64];
			array2[0] = data.Posts[0];
			array2[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], array2[num], _xList[num2], array2[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)
				{
					array[num] = true;
					array[num2] = true;
					array[i] = true;
					if (num4 >= num7)
					{
						if (num5 > num6)
						{
							array2[i] = num4 - num6 + num3;
						}
						else
						{
							array2[i] = num3 - num4 + num5 - 1;
						}
					}
					else if (num4 % 2 == 1)
					{
						array2[i] = num3 - (num4 + 1) / 2;
					}
					else
					{
						array2[i] = num3 + num4 / 2;
					}
				}
				else
				{
					array[i] = false;
					array2[i] = num3;
				}
			}
			for (int j = 0; j < data.PostCount; j++)
			{
				data.Posts[j] = array2[j];
			}
			return array;
		}

		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];
			}
		}
	}
	internal class Huffman : IHuffman, IComparer<HuffmanListNode>
	{
		private const int MAX_TABLE_BITS = 10;

		public int TableBits { get; private set; }

		public IReadOnlyList<HuffmanListNode> PrefixTree { get; private set; }

		public IReadOnlyList<HuffmanListNode> OverflowList { get; private set; }

		public void GenerateTable(IReadOnlyList<int> values, int[] lengthList, int[] codeList)
		{
			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, 0, array.Length, this);
			int num2 = ((num > 10) ? 10 : num);
			List<HuffmanListNode> list = new List<HuffmanListNode>(1 << num2);
			List<HuffmanListNode> list2 = null;
			for (int j = 0; j < array.Length && array[j].Length < 99999; j++)
			{
				int length = array[j].Length;
				if (length > num2)
				{
					list2 = new List<HuffmanListNode>(array.Length - j);
					for (; j < array.Length && array[j].Length < 99999; j++)
					{
						list2.Add(array[j]);
					}
					continue;
				}
				int num3 = 1 << num2 - length;
				HuffmanListNode huffmanListNode = array[j];
				for (int k = 0; k < num3; k++)
				{
					int num4 = (k << length) | huffmanListNode.Bits;
					while (list.Count <= num4)
					{
						list.Add(null);
					}
					list[num4] = huffmanListNode;
				}
			}
			while (list.Count < 1 << num2)
			{
				list.Add(null);
			}
			TableBits = num2;
			PrefixTree = list;
			OverflowList = list2;
		}

		int IComparer<HuffmanListNode>.Compare(HuffmanListNode x, HuffmanListNode y)
		{
			int num = x.Length - y.Length;
			if (num == 0)
			{
				return x.Bits - y.Bits;
			}
			return num;
		}
	}
	[Obsolete("Moved to NVorbis.Contracts.IContainerReader", true)]
	public interface IContainerReader : NVorbis.Contracts.IContainerReader, IDisposable
	{
		[Obsolete("Use Streams.Select(s => s.StreamSerial).ToArray() instead.", true)]
		int[] StreamSerials { get; }

		[Obsolete("No longer supported.", true)]
		int PagesRead { get; }

		[Obsolete("Moved to NewStreamCallback.", true)]
		event EventHandler<NewStreamEventArgs> NewStream;

		[Obsolete("Renamed to TryInit().", true)]
		bool Init();

		[Obsolete("No longer supported.", true)]
		int GetTotalPageCount();
	}
	[Obsolete("Moved to NVorbis.Contracts.IPacketProvider", true)]
	public interface IPacketProvider : NVorbis.Contracts.IPacketProvider
	{
		[Obsolete("Moved to per-stream IStreamStats instance on IStreamDecoder.Stats or VorbisReader.Stats.", true)]
		long ContainerBits { get; }

		[Obsolete("No longer supported.", true)]
		event EventHandler ParameterChange;

		[Obsolete("No longer supported.", true)]
		int GetTotalPageCount();

		[Obsolete("Getting a packet by index is no longer supported.", true)]
		DataPacket GetPacket(int packetIndex);

		[Obsolete("Moved to long SeekTo(long, int, GetPacketGranuleCount)", true)]
		DataPacket FindPacket(long granulePos, Func<DataPacket, DataPacket, int> packetGranuleCountCallback);

		[Obsolete("Seeking to a specified packet is no longer supported.  See SeekTo(...) instead.", true)]
		void SeekToPacket(DataPacket packet, int preRoll);
	}
	[Obsolete("Moved to NVorbis.Contracts.IStreamStats", true)]
	public interface IVorbisStreamStatus : IStreamStats
	{
		[Obsolete("No longer supported.", true)]
		TimeSpan PageLatency { get; }

		[Obsolete("No longer supported.", true)]
		TimeSpan PacketLatency { get; }

		[Obsolete("No longer supported.", true)]
		TimeSpan SecondLatency { get; }

		[Obsolete("No longer supported.", true)]
		int PagesRead { get; }

		[Obsolete("No longer supported.", true)]
		int TotalPages { get; }

		[Obsolete("Use IStreamDecoder.HasClipped instead.  VorbisReader.HasClipped will return the same value for the stream it is handling.", true)]
		bool Clipped { get; }
	}
	internal class Mapping : IMapping
	{
		private IMdct _mdct;

		private int[] _couplingAngle;

		private int[] _couplingMangitude;

		private IFloor[] _submapFloor;

		private IResidue[] _submapResidue;

		private IFloor[] _channelFloor;

		private IResidue[] _channelResidue;

		public void Init(IPacket packet, int channels, IFloor[] floors, IResidue[] residues, IMdct mdct)
		{
			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(channels - 1);
			_couplingAngle = new int[num2];
			_couplingMangitude = new int[num2];
			for (int i = 0; i < num2; i++)
			{
				int num3 = (int)packet.ReadBits(count);
				int num4 = (int)packet.ReadBits(count);
				if (num3 == num4 || num3 > channels - 1 || num4 > channels - 1)
				{
					throw new InvalidDataException("Invalid magnitude or angle in mapping header!");
				}
				_couplingAngle[i] = num4;
				_couplingMangitude[i] = num3;
			}
			if (packet.ReadBits(2) != 0L)
			{
				throw new InvalidDataException("Reserved bits not 0 in mapping header.");
			}
			int[] array = new int[channels];
			if (num > 1)
			{
				for (int j = 0; j < channels; j++)
				{
					array[j] = (int)packet.ReadBits(4);
					if (array[j] > num)
					{
						throw new InvalidDataException("Invalid channel mux submap index in mapping header!");
					}
				}
			}
			_submapFloor = new IFloor[num];
			_submapResidue = new IResidue[num];
			for (int k = 0; k < num; k++)
			{
				packet.SkipBits(8);
				int num5 = (int)packet.ReadBits(8);
				if (num5 >= floors.Length)
				{
					throw new InvalidDataException("Invalid floor number in mapping header!");
				}
				int num6 = (int)packet.ReadBits(8);
				if (num6 >= residues.Length)
				{
					throw new InvalidDataException("Invalid residue number in mapping header!");
				}
				_submapFloor[k] = floors[num5];
				_submapResidue[k] = residues[num6];
			}
			_channelFloor = new IFloor[channels];
			_channelResidue = new IResidue[channels];
			for (int l = 0; l < channels; l++)
			{
				_channelFloor[l] = _submapFloor[array[l]];
				_channelResidue[l] = _submapResidue[array[l]];
			}
			_mdct = mdct;
		}

		public void DecodePacket(IPacket packet, int blockSize, int channels, float[][] buffer)
		{
			int num = blockSize >> 1;
			IFloorData[] array = new IFloorData[_channelFloor.Length];
			bool[] array2 = new bool[_channelFloor.Length];
			for (int i = 0; i < _channelFloor.Length; i++)
			{
				array[i] = _channelFloor[i].Unpack(packet, blockSize, i);
				array2[i] = !array[i].ExecuteChannel;
				Array.Clear(buffer[i], 0, num);
			}
			for (int j = 0; j < _couplingAngle.Length; j++)
			{
				if (array[_couplingAngle[j]].ExecuteChannel || array[_couplingMangitude[j]].ExecuteChannel)
				{
					array[_couplingAngle[j]].ForceEnergy = true;
					array[_couplingMangitude[j]].ForceEnergy = true;
				}
			}
			for (int k = 0; k < _submapFloor.Length; k++)
			{
				for (int l = 0; l < _channelFloor.Length; l++)
				{
					if (_submapFloor[k] != _channelFloor[l] || _submapResidue[k] != _channelResidue[l])
					{
						array[l].ForceNoEnergy = true;
					}
				}
				_submapResidue[k].Decode(packet, array2, blockSize, buffer);
			}
			for (int num2 = _couplingAngle.Length - 1; num2 >= 0; num2--)
			{
				if (array[_couplingAngle[num2]].ExecuteChannel || array[_couplingMangitude[num2]].ExecuteChannel)
				{
					float[] array3 = buffer[_couplingMangitude[num2]];
					float[] array4 = buffer[_couplingAngle[num2]];
					for (int m = 0; m < num; m++)
					{
						float num3 = array3[m];
						float num4 = array4[m];
						float num5;
						float num6;
						if (num3 > 0f)
						{
							if (num4 > 0f)
							{
								num5 = num3;
								num6 = num3 - num4;
							}
							else
							{
								num6 = num3;
								num5 = num3 + num4;
							}
						}
						else if (num4 > 0f)
						{
							num5 = num3;
							num6 = num3 + num4;
						}
						else
						{
							num6 = num3;
							num5 = num3 - num4;
						}
						array3[m] = num5;
						array4[m] = num6;
					}
				}
			}
			for (int n = 0; n < _channelFloor.Length; n++)
			{
				if (array[n].ExecuteChannel)
				{
					_channelFloor[n].Apply(array[n], blockSize, buffer[n]);
					_mdct.Reverse(buffer[n], blockSize);
				}
				else
				{
					Array.Clear(buffer[n], num, num);
				}
			}
		}
	}
	internal class Mdct : IMdct
	{
		private class MdctImpl
		{
			private readonly int _n;

			private readonly int _n2;

			private readonly int _n4;

			private readonly int _n8;

			private readonly int _ld;

			private readonly float[] _a;

			private readonly float[] _b;

			private readonly float[] _c;

			private readonly ushort[] _bitrev;

			public MdctImpl(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 num;
				int num2 = (num = 0);
				while (num2 < _n4)
				{
					_a[num] = (float)Math.Cos((float)(4 * num2) * MathF.PI / (float)n);
					_a[num + 1] = (float)(0.0 - Math.Sin((float)(4 * num2) * MathF.PI / (float)n));
					_b[num] = (float)Math.Cos((float)(num + 1) * MathF.PI / (float)n / 2f) * 0.5f;
					_b[num + 1] = (float)Math.Sin((float)(num + 1) * MathF.PI / (float)n / 2f) * 0.5f;
					num2++;
					num += 2;
				}
				num2 = (num = 0);
				while (num2 < _n8)
				{
					_c[num] = (float)Math.Cos((float)(2 * (num + 1)) * MathF.PI / (float)n);
					_c[num + 1] = (float)(0.0 - Math.Sin((float)(2 * (num + 1)) * MathF.PI / (float)n));
					num2++;
					num += 2;
				}
				_bitrev = new ushort[_n8];
				for (int i = 0; i < _n8; i++)
				{
					_bitrev[i] = (ushort)(Utils.BitReverse((uint)i, _ld - 3) << 2);
				}
			}

			internal void CalcReverse(float[] buffer)
			{
				float[] array = new float[_n2];
				int num = _n2 - 2;
				int num2 = 0;
				int i = 0;
				for (int n = _n2; i != n; i += 4)
				{
					array[num + 1] = buffer[i] * _a[num2] - buffer[i + 2] * _a[num2 + 1];
					array[num] = buffer[i] * _a[num2 + 1] + buffer[i + 2] * _a[num2];
					num -= 2;
					num2 += 2;
				}
				i = _n2 - 3;
				while (num >= 0)
				{
					array[num + 1] = (0f - buffer[i + 2]) * _a[num2] - (0f - buffer[i]) * _a[num2 + 1];
					array[num] = (0f - buffer[i + 2]) * _a[num2 + 1] + (0f - buffer[i]) * _a[num2];
					num -= 2;
					num2 += 2;
					i -= 4;
				}
				float[] array2 = array;
				int num3 = _n2 - 8;
				int num4 = _n4;
				int num5 = 0;
				int num6 = _n4;
				int num7 = 0;
				while (num3 >= 0)
				{
					float num8 = array2[num4 + 1] - array2[num5 + 1];
					float num9 = array2[num4] - array2[num5];
					buffer[num6 + 1] = array2[num4 + 1] + array2[num5 + 1];
					buffer[num6] = array2[num4] + array2[num5];
					buffer[num7 + 1] = num8 * _a[num3 + 4] - num9 * _a[num3 + 5];
					buffer[num7] = num9 * _a[num3 + 4] + num8 * _a[num3 + 5];
					num8 = array2[num4 + 3] - array2[num5 + 3];
					num9 = array2[num4 + 2] - array2[num5 + 2];
					buffer[num6 + 3] = array2[num4 + 3] + array2[num5 + 3];
					buffer[num6 + 2] = array2[num4 + 2] + array2[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];
					array2[num24 + 3] = buffer[num25];
					array2[num24 + 2] = buffer[num25 + 1];
					array2[num23 + 3] = buffer[num25 + 2];
					array2[num23 + 2] = buffer[num25 + 3];
					num25 = _bitrev[num22 + 1];
					array2[num24 + 1] = buffer[num25];
					array2[num24] = buffer[num25 + 1];
					array2[num23 + 1] = buffer[num25 + 2];
					array2[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 = array2[num27] - array2[num28 + 2];
					float num30 = array2[num27 + 1] + array2[num28 + 3];
					float num31 = _c[num26 + 1] * num29 + _c[num26] * num30;
					float num32 = _c[num26 + 1] * num30 - _c[num26] * num29;
					float num33 = array2[num27] + array2[num28 + 2];
					float num34 = array2[num27 + 1] - array2[num28 + 3];
					array2[num27] = num33 + num31;
					array2[num27 + 1] = num34 + num32;
					array2[num28 + 2] = num33 - num31;
					array2[num28 + 3] = num32 - num34;
					num29 = array2[num27 + 2] - array2[num28];
					num30 = array2[num27 + 3] + array2[num28 + 1];
					num31 = _c[num26 + 3] * num29 + _c[num26 + 2] * num30;
					num32 = _c[num26 + 3] * num30 - _c[num26 + 2] * num29;
					num33 = array2[num27 + 2] + array2[num28];
					num34 = array2[num27 + 3] - array2[num28 + 1];
					array2[num27 + 2] = num33 + num31;
					array2[num27 + 3] = num34 + num32;
					array2[num28] = num33 - num31;
					array2[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 = array[num36 + 6] * _b[num35 + 7] - array[num36 + 7] * _b[num35 + 6];
					float num42 = (0f - array[num36 + 6]) * _b[num35 + 6] - array[num36 + 7] * _b[num35 + 7];
					buffer[num37] = num41;
					buffer[num38 + 3] = 0f - num41;
					buffer[num39] = num42;
					buffer[num40 + 3] = num42;
					float num43 = array[num36 + 4] * _b[num35 + 5] - array[num36 + 5] * _b[num35 + 4];
					float num44 = (0f - array[num36 + 4]) * _b[num35 + 4] - array[num36 + 5] * _b[num35 + 5];
					buffer[num37 + 1] = num43;
					buffer[num38 + 2] = 0f - num43;
					buffer[num39 + 1] = num44;
					buffer[num40 + 2] = num44;
					num41 = array[num36 + 2] * _b[num35 + 3] - array[num36 + 3] * _b[num35 + 2];
					num42 = (0f - array[num36 + 2]) * _b[num35 + 2] - array[num36 + 3] * _b[num35 + 3];
					buffer[num37 + 2] = num41;
					buffer[num38 + 1] = 0f - num41;
					buffer[num39 + 2] = num42;
					buffer[num40 + 1] = num42;
					num43 = array[num36] * _b[num35 + 1] - array[num36 + 1] * _b[num35];
					num44 = (0f - array[num36]) * _b[num35] - array[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;
			}
		}

		private const float M_PI = MathF.PI;

		private Dictionary<int, MdctImpl> _setupCache = new Dictionary<int, MdctImpl>();

		public void Reverse(float[] samples, int sampleCount)
		{
			if (!_setupCache.TryGetValue(sampleCount, out var value))
			{
				value = new MdctImpl(sampleCount);
				_setupCache[sampleCount] = value;
			}
			value.CalcReverse(samples);
		}
	}
	internal class Mode : IMode
	{
		private struct OverlapInfo
		{
			public int PacketStartIndex;

			public int PacketTotalLength;

			public int PacketValidLength;
		}

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

		private int _channels;

		private bool _blockFlag;

		private int _blockSize;

		private IMapping _mapping;

		private float[][] _windows;

		private OverlapInfo[] _overlapInfo;

		public void Init(IPacket packet, int channels, int block0Size, int block1Size, IMapping[] mappings)
		{
			_channels = channels;
			_blockFlag = packet.ReadBit();
			if (packet.ReadBits(32) != 0L)
			{
				throw new InvalidDataException("Mode header had invalid window or transform type!");
			}
			int num = (int)packet.ReadBits(8);
			if (num >= mappings.Length)
			{
				throw new InvalidDataException("Mode header had invalid mapping index!");
			}
			_mapping = mappings[num];
			if (_blockFlag)
			{
				_blockSize = block1Size;
				_windows = new float[4][]
				{
					CalcWindow(block0Size, block1Size, block0Size),
					CalcWindow(block1Size, block1Size, block0Size),
					CalcWindow(block0Size, block1Size, block1Size),
					CalcWindow(block1Size, block1Size, block1Size)
				};
				_overlapInfo = new OverlapInfo[4]
				{
					CalcOverlap(block0Size, block1Size, block0Size),
					CalcOverlap(block1Size, block1Size, block0Size),
					CalcOverlap(block0Size, block1Size, block1Size),
					CalcOverlap(block1Size, block1Size, block1Size)
				};
			}
			else
			{
				_blockSize = block0Size;
				_windows = new float[1][] { CalcWindow(block0Size, block0Size, block0Size) };
			}
		}

		private static float[] CalcWindow(int prevBlockSize, int blockSize, int nextBlockSize)
		{
			float[] array = new float[blockSize];
			int num = prevBlockSize / 2;
			int num2 = nextBlockSize / 2;
			int num3 = blockSize / 4 - num / 2;
			int num4 = blockSize - blockSize / 4 - num2 / 2;
			for (int i = 0; i < num; i++)
			{
				float num5 = (float)Math.Sin(((double)i + 0.5) / (double)num * 1.5707963705062866);
				num5 *= num5;
				array[num3 + i] = (float)Math.Sin(num5 * (MathF.PI / 2f));
			}
			for (int j = num3 + num; j < num4; j++)
			{
				array[j] = 1f;
			}
			for (int k = 0; k < num2; k++)
			{
				float num6 = (float)Math.Sin(((double)(num2 - k) - 0.5) / (double)num2 * 1.5707963705062866);
				num6 *= num6;
				array[num4 + k] = (float)Math.Sin(num6 * (MathF.PI / 2f));
			}
			return array;
		}

		private static OverlapInfo CalcOverlap(int prevBlockSize, int blockSize, int nextBlockSize)
		{
			int num = prevBlockSize / 4;
			int num2 = nextBlockSize / 4;
			int packetStartIndex = blockSize / 4 - num;
			int num3 = blockSize / 4 * 3 + num2;
			int packetValidLength = num3 - num2 * 2;
			OverlapInfo result = default(OverlapInfo);
			result.PacketStartIndex = packetStartIndex;
			result.PacketValidLength = packetValidLength;
			result.PacketTotalLength = num3;
			return result;
		}

		private bool GetPacketInfo(IPacket packet, out int windowIndex, out int packetStartIndex, out int packetValidLength, out int packetTotalLength)
		{
			if (packet.IsShort)
			{
				windowIndex = 0;
				packetStartIndex = 0;
				packetValidLength = 0;
				packetTotalLength = 0;
				return false;
			}
			if (_blockFlag)
			{
				bool flag = packet.ReadBit();
				bool flag2 = packet.ReadBit();
				windowIndex = (flag ? 1 : 0) + (flag2 ? 2 : 0);
				OverlapInfo overlapInfo = _overlapInfo[windowIndex];
				packetStartIndex = overlapInfo.PacketStartIndex;
				packetValidLength = overlapInfo.PacketValidLength;
				packetTotalLength = overlapInfo.PacketTotalLength;
			}
			else
			{
				windowIndex = 0;
				packetStartIndex = 0;
				packetValidLength = _blockSize / 2;
				packetTotalLength = _blockSize;
			}
			return true;
		}

		public bool Decode(IPacket packet, float[][] buffer, out int packetStartindex, out int packetValidLength, out int packetTotalLength)
		{
			if (GetPacketInfo(packet, out var windowIndex, out packetStartindex, out packetValidLength, out packetTotalLength))
			{
				_mapping.DecodePacket(packet, _blockSize, _channels, buffer);
				float[] array = _windows[windowIndex];
				for (int i = 0; i < _blockSize; i++)
				{
					for (int j = 0; j < _channels; j++)
					{
						buffer[j][i] *= array[i];
					}
				}
				return true;
			}
			return false;
		}

		public int GetPacketSampleCount(IPacket packet)
		{
			GetPacketInfo(packet, out var _, out var packetStartIndex, out var packetValidLength, out var _);
			return packetValidLength - packetStartIndex;
		}
	}
	[Serializable]
	public class NewStreamEventArgs : EventArgs
	{
		public IStreamDecoder StreamDecoder { get; }

		public bool IgnoreStream { get; set; }

		public NewStreamEventArgs(IStreamDecoder streamDecoder)
		{
			StreamDecoder = streamDecoder ?? throw new ArgumentNullException("streamDecoder");
		}
	}
	internal class Residue0 : IResidue
	{
		private int _channels;

		private int _begin;

		private int _end;

		private int _partitionSize;

		private int _classifications;

		private int _maxStages;

		private ICodebook[][] _books;

		private ICodebook _classBook;

		private int[] _cascade;

		private int[][] _decodeMap;

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

		public virtual void Init(IPacket packet, int channels, ICodebook[] codebooks)
		{
			_begin = (int)packet.ReadBits(24);
			_end = (int)packet.ReadBits(24);
			_partitionSize = (int)packet.ReadBits(24) + 1;
			_classifications = (int)packet.ReadBits(6) + 1;
			_classBook = codebooks[(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 (codebooks[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--;
			}
			_books = new ICodebook[_classifications][];
			num = 0;
			int num5 = 0;
			for (int k = 0; k < _classifications; k++)
			{
				int num6 = Utils.ilog(_cascade[k]);
				_books[k] = new ICodebook[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] = codebooks[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;
				}
			}
			_channels = channels;
		}

		public virtual void Decode(IPacket packet, bool[] doNotDecodeChannel, int blockSize, float[][] buffer)
		{
			int num = ((_end < blockSize / 2) ? _end : (blockSize / 2)) - _begin;
			if (num <= 0 || Array.IndexOf(doNotDecodeChannel, value: false) == -1)
			{
				return;
			}
			int num2 = num / _partitionSize;
			int num3 = (num2 + _classBook.Dimensions - 1) / _classBook.Dimensions;
			int[,][] array = new int[_channels, num3][];
			for (int i = 0; i < _maxStages; i++)
			{
				int j = 0;
				int num4 = 0;
				while (j < num2)
				{
					if (i == 0)
					{
						for (int k = 0; k < _channels; k++)
						{
							int num5 = _classBook.DecodeScalar(packet);
							if (num5 >= 0 && num5 < _decodeMap.Length)
							{
								array[k, num4] = _decodeMap[num5];
								continue;
							}
							j = num2;
							i = _maxStages;
							break;
						}
					}
					int num6 = 0;
					for (; j < num2; j++)
					{
						if (num6 >= _classBook.Dimensions)
						{
							break;
						}
						int offset = _begin + j * _partitionSize;
						for (int l = 0; l < _channels; l++)
						{
							int num7 = array[l, num4][num6];
							if ((_cascade[num7] & (1 << i)) != 0)
							{
								ICodebook codebook = _books[num7][i];
								if (codebook != null && WriteVectors(codebook, packet, buffer, l, offset, _partitionSize))
								{
									j = num2;
									i = _maxStages;
									break;
								}
							}
						}
						num6++;
					}
					num4++;
				}
			}
		}

		protected virtual bool WriteVectors(ICodebook codebook, IPacket packet, float[][] residue, int channel, int offset, int partitionSize)
		{
			float[] array = residue[channel];
			int num = partitionSize / codebook.Dimensions;
			int[] array2 = new int[num];
			for (int i = 0; i < num; i++)
			{
				if ((array2[i] = codebook.DecodeScalar(packet)) == -1)
				{
					return true;
				}
			}
			for (int j = 0; j < codebook.Dimensions; j++)
			{
				int num2 = 0;
				while (num2 < num)
				{
					array[offset] += codebook[array2[num2], j];
					num2++;
					offset++;
				}
			}
			return false;
		}
	}
	internal class Residue1 : Residue0
	{
		protected override bool WriteVectors(ICodebook codebook, IPacket 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;
		}
	}
	internal class Residue2 : Residue0
	{
		private int _channels;

		public override void Init(IPacket packet, int channels, ICodebook[] codebooks)
		{
			_channels = channels;
			base.Init(packet, 1, codebooks);
		}

		public override void Decode(IPacket packet, bool[] doNotDecodeChannel, int blockSize, float[][] buffer)
		{
			base.Decode(packet, doNotDecodeChannel, blockSize * _channels, buffer);
		}

		protected override bool WriteVectors(ICodebook codebook, IPacket 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;
		}
	}
	public sealed class StreamDecoder : IStreamDecoder, IDisposable
	{
		private NVorbis.Contracts.IPacketProvider _packetProvider;

		private IFactory _factory;

		private StreamStats _stats;

		private byte _channels;

		private int _sampleRate;

		private int _block0Size;

		private int _block1Size;

		private IMode[] _modes;

		private int _modeFieldBits;

		private string _vendor;

		private string[] _comments;

		private ITagData _tags;

		private long _currentPosition;

		private bool _hasClipped;

		private bool _hasPosition;

		private bool _eosFound;

		private float[][] _nextPacketBuf;

		private float[][] _prevPacketBuf;

		private int _prevPacketStart;

		private int _prevPacketEnd;

		private int _prevPacketStop;

		private static readonly byte[] PacketSignatureStream = new byte[11]
		{
			1, 118, 111, 114, 98, 105, 115, 0, 0, 0,
			0
		};

		private static readonly byte[] PacketSignatureComments = new byte[7] { 3, 118, 111, 114, 98, 105, 115 };

		private static readonly byte[] PacketSignatureBooks = new byte[7] { 5, 118, 111, 114, 98, 105, 115 };

		internal static Func<IFactory> CreateFactory { get; set; } = () => new Factory();


		public int Channels => _channels;

		public int SampleRate => _sampleRate;

		public int UpperBitrate { get; private set; }

		public int NominalBitrate { get; private set; }

		public int LowerBitrate { get; private set; }

		public ITagData Tags => _tags ?? (_tags = new TagData(_vendor, _comments));

		public TimeSpan TotalTime => TimeSpan.FromSeconds((double)TotalSamples / (double)_sampleRate);

		public long TotalSamples => (_packetProvider ?? throw new ObjectDisposedException("StreamDecoder")).GetGranuleCount();

		public TimeSpan TimePosition
		{
			get
			{
				return TimeSpan.FromSeconds((double)_currentPosition / (double)_sampleRate);
			}
			set
			{
				SeekTo(value);
			}
		}

		public long SamplePosition
		{
			get
			{
				return _currentPosition;
			}
			set
			{
				SeekTo(value);
			}
		}

		public bool ClipSamples { get; set; }

		public bool HasClipped => _hasClipped;

		public bool IsEndOfStream
		{
			get
			{
				if (_eosFound)
				{
					return _prevPacketBuf == null;
				}
				return false;
			}
		}

		public IStreamStats Stats => _stats;

		public StreamDecoder(NVorbis.Contracts.IPacketProvider packetProvider)
			: this(packetProvider, new Factory())
		{
		}

		internal StreamDecoder(NVorbis.Contracts.IPacketProvider packetProvider, IFactory factory)
		{
			_packetProvider = packetProvider ?? throw new ArgumentNullException("packetProvider");
			_factory = factory ?? throw new ArgumentNullException("factory");
			_stats = new StreamStats();
			_currentPosition = 0L;
			ClipSamples = true;
			IPacket packet = _packetProvider.PeekNextPacket();
			if (!ProcessHeaderPackets(packet))
			{
				_packetProvider = null;
				packet.Reset();
				throw GetInvalidStreamException(packet);
			}
		}

		private static Exception GetInvalidStreamException(IPacket packet)
		{
			try
			{
				ulong num = packet.ReadBits(64);
				if (num == 7233173838382854223L)
				{
					return new ArgumentException("Found OPUS bitstream.");
				}
				if ((num & 0xFF) == 127)
				{
					return new ArgumentException("Found FLAC bitstream.");
				}
				switch (num)
				{
				case 2314885909937746003uL:
					return new ArgumentException("Found Speex bitstream.");
				case 28254585843050854uL:
					return new ArgumentException("Found Skeleton metadata bitstream.");
				default:
					if ((num & 0xFFFFFFFFFFFF00L) == 27428895509214208L)
					{
						return new ArgumentException("Found Theora bitsream.");
					}
					return new ArgumentException("Could not find Vorbis data to decode.");
				}
			}
			finally
			{
				packet.Reset();
			}
		}

		private bool ProcessHeaderPackets(IPacket packet)
		{
			if (!ProcessHeaderPacket(packet, LoadStreamHeader, delegate
			{
				_packetProvider.GetNextPacket().Done();
			}))
			{
				return false;
			}
			if (!ProcessHeaderPacket(_packetProvider.GetNextPacket(), LoadComments, delegate(IPacket pkt)
			{
				pkt.Done();
			}))
			{
				return false;
			}
			if (!ProcessHeaderPacket(_packetProvider.GetNextPacket(), LoadBooks, delegate(IPacket pkt)
			{
				pkt.Done();
			}))
			{
				return false;
			}
			_currentPosition = 0L;
			ResetDecoder();
			return true;
		}

		private static bool ProcessHeaderPacket(IPacket packet, Func<IPacket, bool> processAction, Action<IPacket> doneAction)
		{
			if (packet != null)
			{
				try
				{
					return processAction(packet);
				}
				finally
				{
					doneAction(packet);
				}
			}
			return false;
		}

		private static bool ValidateHeader(IPacket packet, byte[] expected)
		{
			for (int i = 0; i < expected.Length; i++)
			{
				if (expected[i] != packet.ReadBits(8))
				{
					return false;
				}
			}
			return true;
		}

		private static string ReadString(IPacket packet)
		{
			int num = (int)packet.ReadBits(32);
			if (num == 0)
			{
				return string.Empty;
			}
			byte[] array = new byte[num];
			if (packet.Read(array, 0, num) < num)
			{
				throw new InvalidDataException("Could not read full string!");
			}
			return Encoding.UTF8.GetString(array);
		}

		private bool LoadStreamHeader(IPacket packet)
		{
			if (!ValidateHeader(packet, PacketSignatureStream))
			{
				return false;
			}
			_channels = (byte)packet.ReadBits(8);
			_sampleRate = (int)packet.ReadBits(32);
			UpperBitrate = (int)packet.ReadBits(32);
			NominalBitrate = (int)packet.ReadBits(32);
			LowerBitrate = (int)packet.ReadBits(32);
			_block0Size = 1 << (int)packet.ReadBits(4);
			_block1Size = 1 << (int)packet.ReadBits(4);
			if (NominalBitrate == 0 && UpperBitrate > 0 && LowerBitrate > 0)
			{
				NominalBitrate = (UpperBitrate + LowerBitrate) / 2;
			}
			_stats.SetSampleRate(_sampleRate);
			_stats.AddPacket(-1, packet.BitsRead, packet.BitsRemaining, packet.ContainerOverheadBits);
			return true;
		}

		private bool LoadComments(IPacket packet)
		{
			if (!ValidateHeader(packet, PacketSignatureComments))
			{
				return false;
			}
			_vendor = ReadString(packet);
			_comments = new string[packet.ReadBits(32)];
			for (int i = 0; i < _comments.Length; i++)
			{
				_comments[i] = ReadString(packet);
			}
			_stats.AddPacket(-1, packet.BitsRead, packet.BitsRemaining, packet.ContainerOverheadBits);
			return true;
		}

		private bool LoadBooks(IPacket packet)
		{
			if (!ValidateHeader(packet, PacketSignatureBooks))
			{
				return false;
			}
			IMdct mdct = _factory.CreateMdct();
			IHuffman huffman = _factory.CreateHuffman();
			ICodebook[] array = new ICodebook[packet.ReadBits(8) + 1];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = _factory.CreateCodebook();
				array[i].Init(packet, huffman);
			}
			int num = (int)packet.ReadBits(6) + 1;
			packet.SkipBits(16 * num);
			IFloor[] array2 = new IFloor[packet.ReadBits(6) + 1];
			for (int j = 0; j < array2.Length; j++)
			{
				array2[j] = _factory.CreateFloor(packet);
				array2[j].Init(packet, _channels, _block0Size, _block1Size, array);
			}
			IResidue[] array3 = new IResidue[packet.ReadBits(6) + 1];
			for (int k = 0; k < array3.Length; k++)
			{
				array3[k] = _factory.CreateResidue(packet);
				array3[k].Init(packet, _channels, array);
			}
			IMapping[] array4 = new IMapping[packet.ReadBits(6) + 1];
			for (int l = 0; l < array4.Length; l++)
			{
				array4[l] = _factory.CreateMapping(packet);
				array4[l].Init(packet, _channels, array2, array3, mdct);
			}
			_modes = new IMode[packet.ReadBits(6) + 1];
			for (int m = 0; m < _modes.Length; m++)
			{
				_modes[m] = _factory.CreateMode();
				_modes[m].Init(packet, _channels, _block0Size, _block1Size, array4);
			}
			if (!packet.ReadBit())
			{
				throw new InvalidDataException("Book packet did not end on correct bit!");
			}
			_modeFieldBits = Utils.ilog(_modes.Length - 1);
			_stats.AddPacket(-1, packet.BitsRead, packet.BitsRemaining, packet.ContainerOverheadBits);
			return true;
		}

		private void ResetDecoder()
		{
			_prevPacketBuf = null;
			_prevPacketStart = 0;
			_prevPacketEnd = 0;
			_prevPacketStop = 0;
			_nextPacketBuf = null;
			_eosFound = false;
			_hasClipped = false;
			_hasPosition = false;
		}

		public int Read(Span<float> buffer, int offset, int count)
		{
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			if (offset < 0 || offset + count > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("offset");
			}
			if (count % _channels != 0)
			{
				throw new ArgumentOutOfRangeException("count", "Must be a multiple of Channels!");
			}
			if (_packetProvider == null)
			{
				throw new ObjectDisposedException("StreamDecoder");
			}
			if (count == 0)
			{
				return 0;
			}
			int num = offset;
			int num2 = offset + count;
			while (num < num2)
			{
				if (_prevPacketStart == _prevPacketEnd)
				{
					if (_eosFound)
					{
						_nextPacketBuf = null;
						_prevPacketBuf = null;
						break;
					}
					if (!ReadNextPacket((num - offset) / _channels, out var samplePosition))
					{
						_prevPacketEnd = _prevPacketStop;
					}
					if (samplePosition.HasValue && !_hasPosition)
					{
						_hasPosition = true;
						_currentPosition = samplePosition.Value - (_prevPacketEnd - _prevPacketStart) - (num - offset) / _channels;
					}
				}
				int num3 = Math.Min((num2 - num) / _channels, _prevPacketEnd - _prevPacketStart);
				if (num3 > 0)
				{
					num = ((!ClipSamples) ? (num + CopyBuffer(buffer, num, num3)) : (num + ClippingCopyBuffer(buffer, num, num3)));
				}
			}
			count = num - offset;
			_currentPosition += count / _channels;
			return count;
		}

		private int ClippingCopyBuffer(Span<float> target, int targetIndex, int count)
		{
			int num = targetIndex;
			while (count > 0)
			{
				for (int i = 0; i < _channels; i++)
				{
					target[num++] = Utils.ClipValue(_prevPacketBuf[i][_prevPacketStart], ref _hasClipped);
				}
				_prevPacketStart++;
				count--;
			}
			return num - targetIndex;
		}

		private int CopyBuffer(Span<float> target, int targetIndex, int count)
		{
			int num = targetIndex;
			while (count > 0)
			{
				for (int i = 0; i < _channels; i++)
				{
					target[num++] = _prevPacketBuf[i][_prevPacketStart];
				}
				_prevPacketStart++;
				count--;
			}
			return num - targetIndex;
		}

		private bool ReadNextPacket(int bufferedSamples, out long? samplePosition)
		{
			int packetStartindex;
			int packetValidLength;
			int packetTotalLength;
			bool isEndOfStream;
			int bitsRead;
			int bitsRemaining;
			int containerOverheadBits;
			float[][] array = DecodeNextPacket(out packetStartindex, out packetValidLength, out packetTotalLength, out isEndOfStream, out samplePosition, out bitsRead, out bitsRemaining, out containerOverheadBits);
			_eosFound |= isEndOfStream;
			if (array == null)
			{
				_stats.AddPacket(0, bitsRead, bitsRemaining, containerOverheadBits);
				return false;
			}
			if (samplePosition.HasValue && isEndOfStream)
			{
				long num = _currentPosition + bufferedSamples + packetValidLength - packetStartindex;
				int num2 = (int)(samplePosition.Value - num);
				if (num2 < 0)
				{
					packetValidLength += num2;
				}
			}
			if (_prevPacketEnd > 0)
			{
				OverlapBuffers(_prevPacketBuf, array, _prevPacketStart, _prevPacketStop, packetStartindex, _channels);
				_prevPacketStart = packetStartindex;
			}
			else if (_prevPacketBuf == null)
			{
				_prevPacketStart = packetValidLength;
			}
			_stats.AddPacket(packetValidLength - _prevPacketStart, bitsRead, bitsRemaining, containerOverheadBits);
			_nextPacketBuf = _prevPacketBuf;
			_prevPacketEnd = packetValidLength;
			_prevPacketStop = packetTotalLength;
			_prevPacketBuf = array;
			return true;
		}

		private float[][] DecodeNextPacket(out int packetStartindex, out int packetValidLength, out int packetTotalLength, out bool isEndOfStream, out long? samplePosition, out int bitsRead, out int bitsRemaining, out int containerOverheadBits)
		{
			IPacket packet = null;
			try
			{
				if ((packet = _packetProvider.GetNextPacket()) == null)
				{
					isEndOfStream = true;
				}
				else
				{
					isEndOfStream = packet.IsEndOfStream;
					if (packet.IsResync)
					{
						_hasPosition = false;
					}
					containerOverheadBits = packet.ContainerOverheadBits;
					if (packet.ReadBit())
					{
						bitsRemaining = packet.BitsRemaining + 1;
					}
					else
					{
						IMode mode = _modes[(uint)packet.ReadBits(_modeFieldBits)];
						if (_nextPacketBuf == null)
						{
							_nextPacketBuf = new float[_channels][];
							for (int i = 0; i < _channels; i++)
							{
								_nextPacketBuf[i] = new float[_block1Size];
							}
						}
						if (mode.Decode(packet, _nextPacketBuf, out packetStartindex, out packetValidLength, out packetTotalLength))
						{
							samplePosition = packet.GranulePosition;
							bitsRead = packet.BitsRead;
							bitsRemaining = packet.BitsRemaining;
							return _nextPacketBuf;
						}
						bitsRemaining = packet.BitsRead + packet.BitsRemaining;
					}
				}
				packetStartindex = 0;
				packetValidLength = 0;
				packetTotalLength = 0;
				samplePosition = null;
				bitsRead = 0;
				bitsRemaining = 0;
				containerOverheadBits = 0;
				return null;
			}
			finally
			{
				packet?.Done();
			}
		}

		private static void OverlapBuffers(float[][] previous, float[][] next, int prevStart, int prevLen, int nextStart, int channels)
		{
			while (prevStart < prevLen)
			{
				for (int i = 0; i < channels; i++)
				{
					next[i][nextStart] += previous[i][prevStart];
				}
				prevStart++;
				nextStart++;
			}
		}

		public void SeekTo(TimeSpan timePosition, SeekOrigin seekOrigin = SeekOrigin.Begin)
		{
			SeekTo((long)((double)SampleRate * timePosition.TotalSeconds), seekOrigin);
		}

		public void SeekTo(long samplePosition, SeekOrigin seekOrigin = SeekOrigin.Begin)
		{
			if (_packetProvider == null)
			{
				throw new ObjectDisposedException("StreamDecoder");
			}
			if (!_packetProvider.CanSeek)
			{
				throw new InvalidOperationException("Seek is not supported by the Contracts.IPacketProvider instance.");
			}
			switch (seekOrigin)
			{
			case SeekOrigin.Current:
				samplePosition = SamplePosition - samplePosition;
				break;
			case SeekOrigin.End:
				samplePosition = TotalSamples - samplePosition;
				break;
			default:
				throw new ArgumentOutOfRangeException("seekOrigin");
			case SeekOrigin.Begin:
				break;
			}
			if (samplePosition < 0)
			{
				throw new ArgumentOutOfRangeException("samplePosition");
			}
			int num;
			if (samplePosition == 0L)
			{
				_packetProvider.SeekTo(0L, 0, GetPacketGranules);
				num = 0;
			}
			else
			{
				long num2 = _packetProvider.SeekTo(samplePosition, 1, GetPacketGranules);
				num = (int)(samplePosition - num2);
			}
			ResetDecoder();
			_hasPosition = true;
			if (!ReadNextPacket(0, out var samplePosition2))
			{
				_eosFound = true;
				if (_packetProvider.GetGranuleCount() != samplePosition)
				{
					throw new InvalidOperationException("Could not read pre-roll packet!  Try seeking again prior to reading more samples.");
				}
				_prevPacketStart = _prevPacketStop;
				_currentPosition = samplePosition;
				return;
			}
			if (!ReadNextPacket(0, out samplePosition2))
			{
				ResetDecoder();
				_eosFound = true;
				throw new InvalidOperationException("Could not read pre-roll packet!  Try seeking again prior to reading more samples.");
			}
			_prevPacketStart += num;
			_currentPosition = samplePosition;
		}

		private int GetPacketGranules(IPacket curPacket)
		{
			if (curPacket.IsResync)
			{
				return 0;
			}
			if (curPacket.ReadBit())
			{
				return 0;
			}
			int num = (int)curPacket.ReadBits(_modeFieldBits);
			if (num < 0 || num >= _modes.Length)
			{
				return 0;
			}
			return _modes[num].GetPacketSampleCount(curPacket);
		}

		public void Dispose()
		{
			(_packetProvider as IDisposable)?.Dispose();
			_packetProvider = null;
		}
	}
	internal class StreamStats : IStreamStats
	{
		private int _sampleRate;

		private readonly int[] _packetBits = new int[2];

		private readonly int[] _packetSamples = new int[2];

		private int _packetIndex;

		private long _totalSamples;

		private long _audioBits;

		private long _headerBits;

		private long _containerBits;

		private long _wasteBits;

		private object _lock = new object();

		private int _packetCount;

		public int EffectiveBitRate
		{
			get
			{
				long totalSamples;
				long num;
				lock (_lock)
				{
					totalSamples = _totalSamples;
					num = _audioBits + _headerBits + _containerBits + _wasteBits;
				}
				if (totalSamples > 0)
				{
					return (int)((double)num / (double)totalSamples * (double)_sampleRate);
				}
				return 0;
			}
		}

		public int InstantBitRate
		{
			get
			{
				int num;
				int num2;
				lock (_lock)
				{
					num = _packetBits[0] + _packetBits[1];
					num2 = _packetSamples[0] + _packetSamples[1];
				}
				if (num2 > 0)
				{
					return (int)((double)num / (double)num2 * (double)_sampleRate);
				}
				return 0;
			}
		}

		public long ContainerBits => _containerBits;

		public long OverheadBits => _headerBits;

		public long AudioBits => _audioBits;

		public long WasteBits => _wasteBits;

		public int PacketCount => _packetCount;

		public void ResetStats()
		{
			lock (_lock)
			{
				_packetBits[0] = (_packetBits[1] = 0);
				_packetSamples[0] = (_packetSamples[1] = 0);
				_packetIndex = 0;
				_packetCount = 0;
				_audioBits = 0L;
				_totalSamples = 0L;
				_headerBits = 0L;
				_containerBits = 0L;
				_wasteBits = 0L;
			}
		}

		internal void SetSampleRate(int sampleRate)
		{
			lock (_lock)
			{
				_sampleRate = sampleRate;
				ResetStats();
			}
		}

		internal void AddPacket(int samples, int bits, int waste, int container)
		{
			lock (_lock)
			{
				if (samples >= 0)
				{
					_audioBits += bits;
					_wasteBits += waste;
					_containerBits += container;
					_totalSamples += samples;
					_packetBits[_packetIndex] = bits + waste;
					_packetSamples[_packetIndex] = samples;
					if (++_packetIndex == 2)
					{
						_packetIndex = 0;
					}
				}
				else
				{
					_headerBits += bits;
					_wasteBits += waste;
					_containerBits += container;
				}
			}
		}
	}
	internal class TagData : ITagData
	{
		private static IReadOnlyList<string> s_emptyList = new List<string>();

		private Dictionary<string, IReadOnlyList<string>> _tags;

		public IReadOnlyDictionary<string, IReadOnlyList<string>> All => _tags;

		public string EncoderVendor { get; }

		public string Title => GetTagSingle("TITLE");

		public string Version => GetTagSingle("VERSION");

		public string Album => GetTagSingle("ALBUM");

		public string TrackNumber => GetTagSingle("TRACKNUMBER");

		public string Artist => GetTagSingle("ARTIST");

		public IReadOnlyList<string> Performers => GetTagMulti("PERFORMER");

		public string Copyright => GetTagSingle("COPYRIGHT");

		public string License => GetTagSingle("LICENSE");

		public string Organization => GetTagSingle("ORGANIZATION");

		public string Description => GetTagSingle("DESCRIPTION");

		public IReadOnlyList<string> Genres => GetTagMulti("GENRE");

		public IReadOnlyList<string> Dates => GetTagMulti("DATE");

		public IReadOnlyList<string> Locations => GetTagMulti("LOCATION");

		public string Contact => GetTagSingle("CONTACT");

		public string Isrc => GetTagSingle("ISRC");

		public TagData(string vendor, string[] comments)
		{
			EncoderVendor = vendor;
			Dictionary<string, IReadOnlyList<string>> dictionary = new Dictionary<string, IReadOnlyList<string>>();
			for (int i = 0; i < comments.Length; i++)
			{
				string[] array = comments[i].Split(new char[1] { '=' });
				if (array.Length == 1)
				{
					array = new string[2]
					{
						array[0],
						string.Empty
					};
				}
				int num = array[0].IndexOf('[');
				if (num > -1)
				{
					array[1] = array[0].Substring(num + 1, array[0].Length - num - 2).ToUpper(CultureInfo.CurrentCulture) + ": " + array[1];
					array[0] = array[0].Substring(0, num);
				}
				if (dictionary.TryGetValue(array[0].ToUpperInvariant(), out var value))
				{
					((List<string>)value).Add(array[1]);
					continue;
				}
				dictionary.Add(array[0].ToUpperInvariant(), new List<string> { array[1] });
			}
			_tags = dictionary;
		}

		public string GetTagSingle(string key, bool concatenate = false)
		{
			IReadOnlyList<string> tagMulti = GetTagMulti(key);
			if (tagMulti.Count > 0)
			{
				if (concatenate)
				{
					return string.Join(Environment.NewLine, tagMulti.ToArray());
				}
				return tagMulti[tagMulti.Count - 1];
			}
			return string.Empty;
		}

		public IReadOnlyList<string> GetTagMulti(string key)
		{
			if (_tags.TryGetValue(key.ToUpperInvariant(), out var value))
			{
				return value;
			}
			return s_emptyList;
		}
	}
	internal static class Utils
	{
		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)
		{
			if (value > MathF.PI * 113f / 355f)
			{
				clipped = true;
				return MathF.PI * 113f / 355f;
			}
			if (value < MathF.PI * -113f / 355f)
			{
				clipped = true;
				return MathF.PI * -113f / 355f;
			}
			return value;
		}

		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);
		}
	}
	public sealed class VorbisReader : IVorbisReader, IDisposable
	{
		private readonly List<IStreamDecoder> _decoders;

		private readonly NVorbis.Contracts.IContainerReader _containerReader;

		private readonly bool _closeOnDispose;

		private IStreamDecoder _streamDecoder;

		internal static Func<Stream, bool, NVorbis.Contracts.IContainerReader> CreateContainerReader { get; set; } = (Stream s, bool cod) => new ContainerReader(s, cod);


		internal static Func<NVorbis.Contracts.IPacketProvider, IStreamDecoder> CreateStreamDecoder { get; set; } = (NVorbis.Contracts.IPacketProvider pp) => new StreamDecoder(pp, new Factory());


		public IReadOnlyList<IStreamDecoder> Streams => _decoders;

		public int Channels => _streamDecoder.Channels;

		public int SampleRate => _streamDecoder.SampleRate;

		public int UpperBitrate => _streamDecoder.UpperBitrate;

		public int NominalBitrate => _streamDecoder.NominalBitrate;

		public int LowerBitrate => _streamDecoder.LowerBitrate;

		public ITagData Tags => _streamDecoder.Tags;

		[Obsolete("Use .Tags.EncoderVendor instead.")]
		public string Vendor => _streamDecoder.Tags.EncoderVendor;

		[Obsolete("Use .Tags.All instead.")]
		public string[] Comments => _streamDecoder.Tags.All.SelectMany((KeyValuePair<string, IReadOnlyList<string>> k) => k.Value, (KeyValuePair<string, IReadOnlyList<string>> kvp, string Item) => kvp.Key + "=" + Item).ToArray();

		[Obsolete("No longer supported.  Will receive a new stream when parameters change.", true)]
		public bool IsParameterChange
		{
			get
			{
				throw new NotSupportedException();
			}
		}

		public long ContainerOverheadBits => _containerReader?.ContainerBits ?? 0;

		public long ContainerWasteBits => _containerReader?.WasteBits ?? 0;

		public int StreamIndex => _decoders.IndexOf(_streamDecoder);

		[Obsolete("Use .Streams.Count instead.")]
		public int StreamCount => _decoders.Count;

		[Obsolete("Use VorbisReader.TimePosition instead.")]
		public TimeSpan DecodedTime
		{
			get
			{
				return _streamDecoder.TimePosition;
			}
			set
			{
				TimePosition = value;
			}
		}

		[Obsolete("Use VorbisReader.SamplePosition instead.")]
		public long DecodedPosition
		{
			get
			{
				return _streamDecoder.SamplePosition;
			}
			set
			{
				SamplePosition = value;
			}
		}

		public TimeSpan TotalTime => _streamDecoder.TotalTime;

		public long TotalSamples => _streamDecoder.TotalSamples;

		public TimeSpan TimePosition
		{
			get
			{
				return _streamDecoder.TimePosition;
			}
			set
			{
				_streamDecoder.TimePosition = value;
			}
		}

		public long SamplePosition
		{
			get
			{
				return _streamDecoder.SamplePosition;
			}
			set
			{
				_streamDecoder.SamplePosition = value;
			}
		}

		public bool IsEndOfStream => _streamDecoder.IsEndOfStream;

		public bool ClipSamples
		{
			get
			{
				return _streamDecoder.ClipSamples;
			}
			set
			{
				_streamDecoder.ClipSamples = value;
			}
		}

		public bool HasClipped => _streamDecoder.HasClipped;

		public IStreamStats StreamStats => _streamDecoder.Stats;

		[Obsolete("Use Streams[*].Stats instead.", true)]
		public IVorbisStreamStatus[] Stats
		{
			get
			{
				throw new NotSupportedException();
			}
		}

		public event EventHandler<NewStreamEventArgs> NewStream;

		public VorbisReader(string fileName)
			: this(File.OpenRead(fileName))
		{
		}

		public VorbisReader(Stream stream, bool closeOnDispose = true)
		{
			_decoders = new List<IStreamDecoder>();
			NVorbis.Contracts.IContainerReader containerReader = CreateContainerReader(stream, closeOnDispose);
			containerReader.NewStreamCallback = ProcessNewStream;
			if (!containerReader.TryInit() || _decoders.Count == 0)
			{
				containerReader.NewStreamCallback = null;
				containerReader.Dispose();
				if (closeOnDispose)
				{
					stream.Dispose();
				}
				throw new ArgumentException("Could not load the specified container!", "containerReader");
			}
			_closeOnDispose = closeOnDispose;
			_containerReader = containerReader;
			_streamDecoder = _decoders[0];
		}

		[Obsolete("Use \"new StreamDecoder(Contracts.IPacketProvider)\" and the container's NewStreamCallback or Streams property instead.", true)]
		public VorbisReader(NVorbis.Contracts.IContainerReader containerReader)
		{
			throw new NotSupportedException();
		}

		[Obsolete("Use \"new StreamDecoder(Contracts.IPacketProvider)\" instead.", true)]
		public VorbisReader(NVorbis.Contracts.IPacketProvider packetProvider)
		{
			throw new NotSupportedException();
		}

		private bool ProcessNewStream(NVorbis.Contracts.IPacketProvider packetProvider)
		{
			IStreamDecoder streamDecoder = CreateStreamDecoder(packetProvider);
			streamDecoder.ClipSamples = true;
			NewStreamEventArgs newStreamEventArgs = new NewStreamEventArgs(streamDecoder);
			this.NewStream?.Invoke(this, newStreamEventArgs);
			if (!newStreamEventArgs.IgnoreStream)
			{
				_decoders.Add(streamDecoder);
				return true;
			}
			return false;
		}

		public void Dispose()
		{
			if (_decoders != null)
			{
				foreach (IStreamDecoder decoder in _decoders)
				{
					decoder.Dispose();
				}
				_decoders.Clear();
			}
			if (_containerReader != null)
			{
				_containerReader.NewStreamCallback = null;
				if (_closeOnDispose)
				{
					_containerReader.Dispose();
				}
			}
		}

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

		public bool SwitchStreams(int index)
		{
			if (index < 0 || index >= _decoders.Count)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			IStreamDecoder streamDecoder = _decoders[index];
			IStreamDecoder streamDecoder2 = _streamDecoder;
			if (streamDecoder == streamDecoder2)
			{
				return false;
			}
			streamDecoder.ClipSamples = streamDecoder2.ClipSamples;
			_streamDecoder = streamDecoder;
			if (streamDecoder.Channels == streamDecoder2.Channels)
			{
				return streamDecoder.SampleRate != streamDecoder2.SampleRate;
			}
			return true;
		}

		public void SeekTo(TimeSpan timePosition, SeekOrigin seekOrigin = SeekOrigin.Begin)
		{
			_streamDecoder.SeekTo(timePosition, seekOrigin);
		}

		public void SeekTo(long samplePosition, SeekOrigin seekOrigin = SeekOrigin.Begin)
		{
			_streamDecoder.SeekTo(samplePosition, seekOrigin);
		}

		public int ReadSamples(float[] buffer, int offset, int count)
		{
			count -= count % _streamDecoder.Channels;
			if (count > 0)
			{
				return _streamDecoder.Read(buffer, offset, count);
			}
			return 0;
		}

		public int ReadSamples(Span<float> buffer)
		{
			int count = buffer.Length - buffer.Length % _streamDecoder.Channels;
			if (!buffer.IsEmpty)
			{
				return _streamDecoder.Read(buffer, 0, count);
			}
			return 0;
		}

		[Obsolete("No longer needed.", true)]
		public void ClearParameterChange()
		{
			throw new NotSupportedException();
		}
	}
}
namespace NVorbis.Ogg
{
	public sealed class ContainerReader : NVorbis.Contracts.IContainerReader, IDisposable
	{
		private IPageReader _reader;

		private List<WeakReference<NVorbis.Contracts.IPacketProvider>> _packetProviders;

		private bool _foundStream;

		internal static Func<Stream, bool, Func<NVorbis.Contracts.IPacketProvider, bool>, IPageReader> CreatePageReader { get; set; } = (Stream s, bool cod, Func<NVorbis.Contracts.IPacketProvider, bool> cb) => new PageReader(s, cod, cb);


		internal static Func<Stream, bool, Func<NVorbis.Contracts.IPacketProvider, bool>, IPageReader> CreateForwardOnlyPageReader { get; set; } = (Stream s, bool cod, Func<NVorbis.Contracts.IPacketProvider, bool> cb) => new ForwardOnlyPageReader(s, cod, cb);


		public NewStreamHandler NewStreamCallback { get; set; }

		public bool CanSeek { get; }

		public long WasteBits => _reader.WasteBits;

		public long ContainerBits => _reader.ContainerBits;

		public IReadOnlyList<NVorbis.Contracts.IPacketProvider> GetStreams()
		{
			List<NVorbis.Contracts.IPacketProvider> list = new List<NVorbis.Contracts.IPacketProvider>(_packetProviders.Count);
			for (int i = 0; i < _packetProviders.Count; i++)
			{
				if (_packetProviders[i].TryGetTarget(out var target))
				{
					list.Add(target);
					continue;
				}
				list.RemoveAt(i);
				i--;
			}
			return list;
		}

		public ContainerReader(Stream stream, bool closeOnDispose)
		{
			if (stream == null)
			{
				throw new ArgumentNullException("stream");
			}
			_packetProviders = new List<WeakReference<NVorbis.Contracts.IPacketProvider>>();
			if (stream.CanSeek)
			{
				_reader = CreatePageReader(stream, closeOnDispose, ProcessNewStream);
				CanSeek = true;
			}
			else
			{
				_reader = CreateForwardOnlyPageReader(stream, closeOnDispose, ProcessNewStream);
			}
		}

		public bool TryInit()
		{
			return FindNextStream();
		}

		public bool FindNextStream()
		{
			_reader.Lock();
			try
			{
				_foundStream = false;
				while (_reader.ReadNextPage())
				{
					if (_foundStream)
					{
						return true;
					}
				}
				return false;
			}
			finally
			{
				_reader.Release();
			}
		}

		private bool ProcessNewStream(NVorbis.Contracts.IPacketProvider packetProvider)
		{
			bool flag = _reader.Release();
			try
			{
				NewStreamHandler newStreamCallback = NewStreamCallback;
				if (newStreamCallback == null || newStreamCallback(packetProvider))
				{
					_packetProviders.Add(new WeakReference<NVorbis.Contracts.IPacketProvider>(packetProvider));
					_foundStream = true;
					return true;
				}
				return false;
			}
			finally
			{
				if (flag)
				{
					_reader.Lock();
				}
			}
		}

		public void Dispose()
		{
			_reader?.Dispose();
			_reader = null;
		}
	}
	internal class Crc : ICrc
	{
		private const uint CRC32_POLY = 79764919u;

		private static readonly uint[] s_crcTable;

		private uint _crc;

		static Crc()
		{
			s_crcTable = new uint[256];
			for (uint num = 0u; num < 256; num++)
			{
				uint num2 = num << 24;
				for (int i = 0; i < 8; i++)
				{
					num2 = (num2 << 1) ^ ((num2 >= 2147483648u) ? 79764919u : 0u);
				}
				s_crcTable[num] = num2;
			}
		}

		public Crc()
		{
			Reset();
		}

		public void Reset()
		{
			_crc = 0u;
		}

		public void Update(int nextVal)
		{
			_crc = (_crc << 8) ^ s_crcTable[nextVal ^ (_crc >> 24)];
		}

		public bool Test(uint checkCrc)
		{
			return _crc == checkCrc;
		}
	}
	internal class ForwardOnlyPacketProvider : DataPacket, IForwardOnlyPacketProvider, NVorbis.Contracts.IPacketProvider
	{
		private int _lastSeqNo;

		private readonly Queue<(byte[] buf, bool isResync)> _pageQueue = new Queue<(byte[], bool)>();

		private readonly IPageReader _reader;

		private byte[] _pageBuf;

		private int _packetIndex;

		private bool _isEndOfStream;

		private int _dataStart;

		private bool _lastWasPeek;

		private Memory<byte> _packetBuf;

		private int _dataIndex;

		public bool CanSeek => false;

		public int StreamSerial { get; }

		protected override int TotalBits => _packetBuf.Length * 8;

		public ForwardOnlyPacketProvider(IPageReader reader, int streamSerial)
		{
			_reader = reader;
			StreamSerial = streamSerial;
			_packetIndex = int.MaxValue;
		}

		public bool AddPage(byte[] buf, bool isResync)
		{
			if ((buf[5] & 2u) != 0)
			{
				if (_isEndOfStream)
				{
					return false;
				}
				isResync = true;
				_lastSeqNo = BitConverter.ToInt32(buf, 18);
			}
			else
			{
				int num = BitConverter.ToInt32(buf, 18);
				isResync |= num != _lastSeqNo + 1;
				_lastSeqNo = num;
			}
			int num2 = 0;
			for (int i = 0; i < buf[26]; i++)
			{
				num2 += buf[27 + i];
			}
			if (num2 == 0)
			{
				return false;
			}
			_pageQueue.Enqueue((buf, isResync));
			return true;
		}

		public void SetEndOfStream()
		{
			_isEndOfStream = true;
		}

		public IPacket GetNextPacket()
		{
			if (_packetBuf.Length > 0)
			{
				if (!_lastWasPeek)
				{
					throw new InvalidOperationException("Must call Done() on previous packet first.");
				}
				_lastWasPeek = false;
				return this;
			}
			_lastWasPeek = false;
			if (GetPacket())
			{
				return this;
			}
			return null;
		}

		public IPacket PeekNextPacket()
		{
			if (_packetBuf.Length > 0)
			{
				if (!_lastWasPeek)
				{
					throw new InvalidOperationException("Must call Done() on previous packet first.");
				}
				return this;
			}
			_lastWasPeek = true;
			if (GetPacket())
			{
				return this;
			}
			return null;
		}

		private bool GetPacket()
		{
			byte[] pageBuf;
			bool isResync;
			int packetIndex;
			bool isContinuation;
			bool isContinued;
			int dataStart;
			if (_pageBuf != null && _packetIndex < 27 + _pageBuf[26])
			{
				pageBuf = _pageBuf;
				isResync = false;
				dataStart = _dataStart;
				packetIndex = _packetIndex;
				isContinuation = false;
				isContinued = pageBuf[26 + pageBuf[26]] == byte.MaxValue;
			}
			else if (!ReadNextPage(out pageBuf, out isResync, out dataStart, out packetIndex, out isContinuation, out isContinued))
			{
				return false;
			}
			int num = dataStart;
			bool flag = packetIndex == 27;
			if (isContinuation && flag)
			{
				isResync = true;
				num += GetPacketLength(pageBuf, ref packetIndex);
				if (packetIndex == 27 + pageBuf[26])
				{
					return GetPacket();
				}
			}
			if (!flag)
			{
				num = 0;
			}
			int packetLength = GetPacketLength(pageBuf, ref packetIndex);
			Memory<byte> memory = new Memory<byte>(pageBuf, dataStart, packetLength);
			dataStart += packetLength;
			bool flag2 = packetIndex == 27 + pageBuf[26];
			if (isContinued)
			{
				if (flag2)
				{
					flag2 = false;
				}
				else
				{
					int packetIndex2 = packetIndex;
					GetPacketLength(pageBuf, ref packetIndex2);
					flag2 = packetIndex2 == 27 + pageBuf[26];
				}
			}
			bool flag3 = false;
			long? granulePosition = null;
			if (flag2)
			{
				granulePosition = BitConverter.ToInt64(pageBuf, 6);
				if ((pageBuf[5] & 4u) != 0 || (_isEndOfStream && _pageQueue.Count == 0))
				{
					flag3 = true;
				}
			}
			else
			{
				while (isContinued && packetIndex == 27 + pageBuf[26] && ReadNextPage(out pageBuf, out isResync, out dataStart, out packetIndex, out isContinuation, out isContinued) && !isResync && isContinuation)
				{
					num += 27 + pageBuf[26];
					Memory<byte> memory2 = memory;
					int packetLength2 = GetPacketLength(pageBuf, ref packetIndex);
					memory = new Memory<byte>(new byte[memory2.Length + packetLength2]);
					memory2.CopyTo(memory);
					new Memory<byte>(pageBuf, dataStart, packetLength2).CopyTo(memory.Slice(memory2.Length));
					dataStart += packetLength2;
				}
			}
			base.IsResync = isResync;
			base.GranulePosition = granulePosition;
			base.IsEndOfStream = flag3;
			base.ContainerOverheadBits = num * 8;
			_pageBuf = pageBuf;
			_dataStart = dataStart;
			_packetIndex = packetIndex;
			_packetBuf = memory;
			_isEndOfStream |= flag3;
			Reset();
			return true;
		}

		private bool ReadNextPage(out byte[] pageBuf, out bool isResync, out int dataStart, out int packetIndex, out bool isContinuation, out bool isContinued)
		{
			while (_pageQueue.Count == 0)
			{
				if (_isEndOfStream || !_reader.ReadNextPage())
				{
					pageBuf = null;
					isResync = false;
					dataStart = 0;
					packetIndex = 0;
					isContinuation = false;
					isContinued = false;
					return false;
				}
			}
			(byte[], bool) tuple = _pageQueue.Dequeue();
			pageBuf = tuple.Item1;
			isResync = tuple.Item2;
			dataStart = pageBuf[26] + 27;
			packetIndex = 27;
			isContinuation = (pageBuf[5] & 1) != 0;
			isContinued = pageBuf[26 + pageBuf[26]] == byte.MaxValue;
			return true;
		}

		private int GetPacketLength(byte[] pageBuf, ref int packetIndex)
		{
			int num = 0;
		

RadioLib.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Audio;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using FMOD;
using FMOD.Studio;
using FMODUnity;
using Fusion;
using Fusion.Sockets;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Microsoft.CodeAnalysis;
using NLayer;
using NVorbis;
using Networking;
using RadioLib.Net;
using RoadsideResearch;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("RadioLib")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RadioLib")]
[assembly: AssemblyTitle("RadioLib")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NativeIntegerAttribute : Attribute
	{
		public readonly bool[] TransformFlags;

		public NativeIntegerAttribute()
		{
			TransformFlags = new bool[1] { true };
		}

		public NativeIntegerAttribute(bool[] P_0)
		{
			TransformFlags = P_0;
		}
	}
}
namespace RadioLib
{
	public static class AudioClipFactory
	{
		private struct ManagedSpanWrapper
		{
			public IntPtr begin;

			public int length;
		}

		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		private unsafe delegate void CreateUserSoundInjectedFn(IntPtr nativePtr, ManagedSpanWrapper* name, int lengthSamples, int channels, int frequency, bool stream);

		private static readonly List<nint> _gcHandles = new List<IntPtr>();

		private static readonly List<AudioClip> _clips = new List<AudioClip>();

		private static IntPtr _icallPtr = IntPtr.Zero;

		private static bool _resolved = false;

		internal static string InitStatus = "not yet initialized";

		public static AudioClip CreateClip(TrackInfo track)
		{
			//IL_0424: Unknown result type (might be due to invalid IL or missing references)
			//IL_042a: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Expected O, but got Unknown
			//IL_03ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f4: Expected O, but got Unknown
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Expected O, but got Unknown
			bool flag = default(bool);
			if (track.PcmData == null || track.PcmData.Length == 0)
			{
				ManualLogSource log = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(24, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No PCM data for track '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(track.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
				}
				log.LogError(val);
				return null;
			}
			if (!_resolved)
			{
				ResolveIcall();
			}
			try
			{
				AudioClip val2 = AudioClip.Construct_Internal();
				if ((Object)(object)val2 == (Object)null)
				{
					InitStatus += " | Construct_Internal=null";
					Plugin.Log.LogError((object)"Construct_Internal returned null");
					return null;
				}
				IntPtr intPtr = Marshal.ReadIntPtr(((Il2CppObjectBase)val2).Pointer + 16);
				InitStatus += $" | native=0x{intPtr:X}";
				if (_icallPtr != IntPtr.Zero && intPtr != IntPtr.Zero)
				{
					CallInjected(intPtr, track.Name, track.LengthSamples, track.Channels, track.SampleRate);
					InitStatus += $" | after_icall_samples={val2.samples}";
				}
				if (val2.samples == 0)
				{
					try
					{
						val2.CreateUserSound(track.Name, track.LengthSamples, track.Channels, track.SampleRate, false);
						InitStatus += $" | after_interop_samples={val2.samples}";
					}
					catch (Exception ex)
					{
						InitStatus = InitStatus + " | interop_err=" + ex.GetType().Name;
					}
				}
				if (val2.samples == 0)
				{
					try
					{
						val2 = AudioClip.Create(track.Name, track.LengthSamples, track.Channels, track.SampleRate, false);
						if ((Object)(object)val2 != (Object)null)
						{
							InitStatus += $" | after_Create_samples={val2.samples}";
						}
						else
						{
							InitStatus += " | Create=null";
						}
					}
					catch (Exception ex2)
					{
						InitStatus = InitStatus + " | Create_err=" + ex2.GetType().Name;
					}
				}
				if ((Object)(object)val2 != (Object)null)
				{
					Il2CppStructArray<float> val3 = new Il2CppStructArray<float>((long)track.PcmData.Length);
					for (int i = 0; i < track.PcmData.Length; i++)
					{
						((Il2CppArrayBase<float>)(object)val3)[i] = track.PcmData[i];
					}
					bool flag2 = val2.SetData(val3, 0);
					InitStatus += $" | SetData={flag2}";
					if (flag2)
					{
						PinClip(val2);
						ManualLogSource log2 = Plugin.Log;
						BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(34, 4, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("AudioClip ready: '");
							((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(track.Name);
							((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("' ");
							((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(track.Channels);
							((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("ch ");
							((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(track.SampleRate);
							((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Hz ");
							((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(track.LengthSamples);
							((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" samples");
						}
						log2.LogInfo(val4);
						return val2;
					}
				}
				ManualLogSource log3 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(44, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("All AudioClip creation methods failed for '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(track.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
				}
				log3.LogError(val);
				ManualLogSource log4 = Plugin.Log;
				val = new BepInExErrorLogInterpolatedStringHandler(12, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Diagnostic: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(InitStatus);
				}
				log4.LogError(val);
				return null;
			}
			catch (Exception ex3)
			{
				ManualLogSource log5 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(35, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to create AudioClip for '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(track.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex3);
				}
				log5.LogError(val);
				return null;
			}
		}

		private unsafe static void CallInjected(IntPtr nativePtr, string name, int lengthSamples, int channels, int frequency)
		{
			try
			{
				IntPtr intPtr = IL2CPP.ManagedStringToIl2Cpp(name);
				IntPtr begin = intPtr + 20;
				int length = Marshal.ReadInt32(intPtr + 16);
				ManagedSpanWrapper managedSpanWrapper = default(ManagedSpanWrapper);
				managedSpanWrapper.begin = begin;
				managedSpanWrapper.length = length;
				ManagedSpanWrapper managedSpanWrapper2 = managedSpanWrapper;
				Marshal.GetDelegateForFunctionPointer<CreateUserSoundInjectedFn>(_icallPtr)(nativePtr, &managedSpanWrapper2, lengthSamples, channels, frequency, stream: false);
			}
			catch (Exception ex)
			{
				InitStatus = InitStatus + " | icall_ex=" + ex.GetType().Name + ":" + ex.Message;
			}
		}

		private static void ResolveIcall()
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			_resolved = true;
			string[] array = new string[3] { "UnityEngine.AudioClip::CreateUserSound_Injected", "UnityEngine.AudioClip::CreateUserSound(System.String,System.Int32,System.Int32,System.Int32,System.Boolean)", "UnityEngine.AudioClip::CreateUserSound" };
			bool flag = default(bool);
			foreach (string text in array)
			{
				_icallPtr = IL2CPP.il2cpp_resolve_icall(text);
				if (_icallPtr != IntPtr.Zero)
				{
					InitStatus = $"icall=0x{_icallPtr:X} ({text})";
					ManualLogSource log = Plugin.Log;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(16, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Resolved: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" -> 0x");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted(_icallPtr, "X");
					}
					log.LogInfo(val);
					return;
				}
			}
			InitStatus = "no icall found";
			Plugin.Log.LogError((object)"Could not resolve any CreateUserSound icall");
		}

		private static void PinClip(AudioClip clip)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			IntPtr item = IL2CPP.il2cpp_gchandle_new(((Il2CppObjectBase)clip).Pointer, false);
			_gcHandles.Add(item);
			((Object)clip).hideFlags = (HideFlags)(((Object)clip).hideFlags | 0x20);
			_clips.Add(clip);
		}
	}
	internal enum DecodePriority
	{
		Background,
		Prefetch,
		Immediate
	}
	internal static class DecodeService
	{
		private struct DecodeRequest
		{
			public TrackInfo Track;

			public string FilePath;

			public DecodePriority Priority;

			public CancellationTokenSource Cts;

			public long Sequence;
		}

		private static readonly object _lock = new object();

		private static readonly List<DecodeRequest> _queue = new List<DecodeRequest>();

		private static readonly ConcurrentDictionary<string, CancellationTokenSource> _active = new ConcurrentDictionary<string, CancellationTokenSource>(StringComparer.OrdinalIgnoreCase);

		private static readonly ManualResetEventSlim _signal = new ManualResetEventSlim(initialState: false);

		private static long _sequence;

		private static volatile bool _shutdown;

		private static Thread _worker;

		internal static void Start()
		{
			if (_worker == null)
			{
				_worker = new Thread(WorkerLoop)
				{
					Name = "RadioLib.Decode",
					IsBackground = true
				};
				_worker.Start();
			}
		}

		public static CancellationTokenSource Request(TrackInfo track, string filePath, DecodePriority priority)
		{
			if (track == null || string.IsNullOrEmpty(filePath))
			{
				return null;
			}
			string hash = track.Hash;
			if (string.IsNullOrEmpty(hash))
			{
				return null;
			}
			Start();
			if (_active.TryGetValue(hash, out var value) && !value.IsCancellationRequested)
			{
				return value;
			}
			CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
			_active[hash] = cancellationTokenSource;
			lock (_lock)
			{
				_queue.Add(new DecodeRequest
				{
					Track = track,
					FilePath = filePath,
					Priority = priority,
					Cts = cancellationTokenSource,
					Sequence = Interlocked.Increment(ref _sequence)
				});
			}
			_signal.Set();
			return cancellationTokenSource;
		}

		public static void Cancel(string hash)
		{
			if (!string.IsNullOrEmpty(hash) && _active.TryRemove(hash, out var value))
			{
				value.Cancel();
			}
		}

		public static void CancelAll()
		{
			foreach (KeyValuePair<string, CancellationTokenSource> item in _active)
			{
				item.Value.Cancel();
			}
			_active.Clear();
			lock (_lock)
			{
				_queue.Clear();
			}
		}

		internal static void Shutdown()
		{
			_shutdown = true;
			_signal.Set();
		}

		private static void WorkerLoop()
		{
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Expected O, but got Unknown
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Expected O, but got Unknown
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			bool flag = default(bool);
			while (!_shutdown)
			{
				_signal.Wait();
				if (_shutdown)
				{
					break;
				}
				_signal.Reset();
				DecodeRequest result;
				while (TryDequeueHighest(out result))
				{
					if (result.Cts.IsCancellationRequested)
					{
						continue;
					}
					TrackInfo track = result.Track;
					CancellationToken token = result.Cts.Token;
					string extension = track.Extension;
					string filePath = result.FilePath;
					ManualLogSource log = Plugin.Log;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(17, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Decoding '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(track.Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' (");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<DecodePriority>(result.Priority);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")...");
					}
					log.LogInfo(val);
					WavData wavData = null;
					try
					{
						wavData = extension switch
						{
							".wav" => WavLoader.Load(filePath, Plugin.Log, token), 
							".mp3" => Mp3Loader.Load(filePath, Plugin.Log, token), 
							".ogg" => OggLoader.Load(filePath, Plugin.Log, token), 
							_ => null, 
						};
					}
					catch (Exception ex)
					{
						ManualLogSource log2 = Plugin.Log;
						BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(25, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("DecodeService: '");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(track.Name);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' threw: ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
						}
						log2.LogError(val2);
					}
					if (token.IsCancellationRequested)
					{
						ManualLogSource log3 = Plugin.Log;
						val = new BepInExInfoLogInterpolatedStringHandler(27, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Decode of '");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(track.Name);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' was cancelled.");
						}
						log3.LogInfo(val);
						continue;
					}
					_active.TryRemove(track.Hash, out var _);
					if (wavData == null)
					{
						ManualLogSource log4 = Plugin.Log;
						BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(27, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Decode of '");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(track.Name);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' returned null.");
						}
						log4.LogWarning(val3);
					}
					else
					{
						float[] samples = wavData.Samples;
						int sr = wavData.SampleRate;
						int ch = wavData.Channels;
						string hash = track.Hash;
						MainThread.Enqueue(delegate
						{
							RadioAPI.MarkTrackReady(hash, samples, sr, ch);
						});
					}
				}
			}
		}

		private static bool TryDequeueHighest(out DecodeRequest result)
		{
			lock (_lock)
			{
				if (_queue.Count == 0)
				{
					result = default(DecodeRequest);
					return false;
				}
				int index = 0;
				for (int i = 1; i < _queue.Count; i++)
				{
					DecodeRequest decodeRequest = _queue[index];
					DecodeRequest decodeRequest2 = _queue[i];
					if (decodeRequest2.Priority > decodeRequest.Priority || (decodeRequest2.Priority == decodeRequest.Priority && decodeRequest2.Sequence < decodeRequest.Sequence))
					{
						index = i;
					}
				}
				result = _queue[index];
				_queue.RemoveAt(index);
				return true;
			}
		}
	}
	public static class FmodSoundFactory
	{
		internal static string InitStatus = "not yet initialized";

		public static Sound CreateSound(TrackInfo track)
		{
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			bool flag = default(bool);
			if (track.PcmData == null || track.PcmData.Length == 0)
			{
				ManualLogSource log = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(24, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No PCM data for track '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(track.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
				}
				log.LogError(val);
				return default(Sound);
			}
			try
			{
				System coreSystem = RuntimeManager.CoreSystem;
				int num = track.PcmData.Length * 4;
				IntPtr intPtr = Marshal.AllocHGlobal(num);
				Marshal.Copy(track.PcmData, 0, intPtr, track.PcmData.Length);
				CREATESOUNDEXINFO val2 = default(CREATESOUNDEXINFO);
				val2.cbsize = Marshal.SizeOf<CREATESOUNDEXINFO>();
				val2.length = (uint)num;
				val2.numchannels = track.Channels;
				val2.defaultfrequency = track.SampleRate;
				val2.format = (SOUND_FORMAT)5;
				CREATESOUNDEXINFO val3 = val2;
				MODE val4 = (MODE)530705;
				Sound result = default(Sound);
				RESULT val5 = ((System)(ref coreSystem)).createSound(intPtr, val4, ref val3, ref result);
				if ((int)val5 != 0)
				{
					Marshal.FreeHGlobal(intPtr);
					InitStatus = $"createSound failed: {val5}";
					ManualLogSource log2 = Plugin.Log;
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(32, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("FMOD createSound failed for '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(track.Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<RESULT>(val5);
					}
					log2.LogError(val);
					return default(Sound);
				}
				((Sound)(ref result)).set3DMinMaxDistance(1f, 20f);
				track.NativePcmPtr = intPtr;
				InitStatus = "OK";
				ManualLogSource log3 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val6 = new BepInExInfoLogInterpolatedStringHandler(32, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("FMOD Sound created: '");
					((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<string>(track.Name);
					((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("' ");
					((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<int>(track.Channels);
					((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("ch ");
					((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<int>(track.SampleRate);
					((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("Hz ");
					((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<int>(track.LengthSamples);
					((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("smp");
				}
				log3.LogInfo(val6);
				return result;
			}
			catch (Exception ex)
			{
				InitStatus = "exception: " + ex.GetType().Name + ": " + ex.Message;
				ManualLogSource log4 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(36, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to create FMOD Sound for '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(track.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log4.LogError(val);
				return default(Sound);
			}
		}
	}
	public static class FolderScanner
	{
		private static readonly string[] SupportedExtensions = new string[3] { "*.wav", "*.mp3", "*.ogg" };

		private const long MaxFileBytes = 20971520L;

		public static string PluginDirectory => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		public static void ScanAndRegister()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			string text = Plugin.MusicFolderName?.Value;
			if (string.IsNullOrWhiteSpace(text))
			{
				text = "Music";
			}
			string text2 = Path.Combine(PluginDirectory, text);
			if (!Directory.Exists(text2))
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(49, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No Music folder found at ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" — skipping folder scan.");
				}
				log.LogInfo(val);
				return;
			}
			string[] directories = Directory.GetDirectories(text2);
			if (directories.Length != 0)
			{
				string[] array = directories;
				foreach (string obj in array)
				{
					string fileName = Path.GetFileName(obj);
					ScanFolder(obj, "radiolib.folder." + fileName, fileName);
				}
			}
			if (GetAudioFiles(text2).Length != 0)
			{
				ScanFolder(text2, "radiolib.folder.custom", "Custom Music");
			}
		}

		private static string[] GetAudioFiles(string folderPath)
		{
			List<string> list = new List<string>();
			string[] supportedExtensions = SupportedExtensions;
			foreach (string searchPattern in supportedExtensions)
			{
				list.AddRange(Directory.GetFiles(folderPath, searchPattern));
			}
			string[] array = list.ToArray();
			Array.Sort(array, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
			return array;
		}

		private static void ScanFolder(string folderPath, string stationId, string stationName)
		{
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Expected O, but got Unknown
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Expected O, but got Unknown
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			string[] audioFiles = GetAudioFiles(folderPath);
			bool flag = default(bool);
			if (audioFiles.Length == 0)
			{
				ManualLogSource log = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(31, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No audio files in '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(folderPath);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("', skipping.");
				}
				log.LogInfo(val);
				return;
			}
			StationDefinition stationDefinition = new StationDefinition
			{
				Id = stationId,
				Name = stationName,
				Shuffle = false,
				Loop = true
			};
			int num = 0;
			string[] array = audioFiles;
			foreach (string text in array)
			{
				FileInfo fileInfo = new FileInfo(text);
				if (fileInfo.Length > 20971520)
				{
					ManualLogSource log2 = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(32, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Skipped '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(fileInfo.Name);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("': ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<long>(fileInfo.Length / 1024 / 1024);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" MB exceeds ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<long>(20L);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" MB cap.");
					}
					log2.LogWarning(val2);
					continue;
				}
				ProbeResult probeResult = ProbeAudioFile(text);
				if (probeResult == null)
				{
					ManualLogSource log3 = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(54, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Skipped '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(Path.GetFileName(text));
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' in station '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(stationName);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' — probe returned no metadata.");
					}
					log3.LogWarning(val2);
					continue;
				}
				string hash;
				try
				{
					hash = ComputeSha256(text);
				}
				catch (Exception ex)
				{
					ManualLogSource log4 = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(26, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Skipped '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(Path.GetFileName(text));
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' — hash failed: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					log4.LogWarning(val2);
					continue;
				}
				TrackInfo item = new TrackInfo
				{
					Name = Path.GetFileNameWithoutExtension(text),
					PcmData = null,
					SampleRate = probeResult.SampleRate,
					Channels = probeResult.Channels,
					LengthSamples = probeResult.LengthSamples,
					Hash = hash,
					Extension = Path.GetExtension(text).ToLowerInvariant(),
					SourcePath = text
				};
				stationDefinition.Tracks.Add(item);
				num++;
			}
			if (num > 0)
			{
				RadioAPI.RegisterStation(stationDefinition);
				ManualLogSource log5 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(42, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Folder station '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(stationName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(audioFiles.Length);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" track(s) loaded from ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(folderPath);
				}
				log5.LogInfo(val);
			}
			else
			{
				ManualLogSource log6 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(96, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Station '");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(stationName);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' skipped: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(audioFiles.Length);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" file(s) found but none decoded. Station will NOT appear in the radio wheel.");
				}
				log6.LogError(val3);
			}
		}

		private static ProbeResult ProbeAudioFile(string filePath)
		{
			return Path.GetExtension(filePath).ToLowerInvariant() switch
			{
				".wav" => WavLoader.Probe(filePath, Plugin.Log), 
				".mp3" => Mp3Loader.Probe(filePath, Plugin.Log), 
				".ogg" => OggLoader.Probe(filePath, Plugin.Log), 
				_ => null, 
			};
		}

		internal static string ComputeSha256(string filePath)
		{
			using SHA256 sHA = SHA256.Create();
			using FileStream inputStream = File.OpenRead(filePath);
			return BytesToHex(sHA.ComputeHash(inputStream));
		}

		internal static string ComputeSha256(byte[] data)
		{
			using SHA256 sHA = SHA256.Create();
			return BytesToHex(sHA.ComputeHash(data));
		}

		internal static string BytesToHex(byte[] bytes)
		{
			char[] array = new char[bytes.Length * 2];
			for (int i = 0; i < bytes.Length; i++)
			{
				array[i * 2] = "0123456789abcdef"[bytes[i] >> 4];
				array[i * 2 + 1] = "0123456789abcdef"[bytes[i] & 0xF];
			}
			return new string(array);
		}
	}
	internal static class MainThread
	{
		private static readonly ConcurrentQueue<Action> _queue = new ConcurrentQueue<Action>();

		private const int MaxPerFrame = 16;

		public static void Enqueue(Action action)
		{
			if (action != null)
			{
				_queue.Enqueue(action);
			}
		}

		internal static void ProcessQueue()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			bool flag = default(bool);
			for (int i = 0; i < 16; i++)
			{
				if (!_queue.TryDequeue(out var result))
				{
					break;
				}
				try
				{
					result();
				}
				catch (Exception ex)
				{
					ManualLogSource log = Plugin.Log;
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(21, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("MainThread dispatch: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogError(val);
				}
			}
		}
	}
	internal static class MemoryBudget
	{
		private static long _maxBytes = 209715200L;

		private static long _totalBytes;

		private static readonly LinkedList<string> _lruOrder = new LinkedList<string>();

		private static readonly Dictionary<string, LinkedListNode<string>> _lruNodes = new Dictionary<string, LinkedListNode<string>>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, long> _bytesPerTrack = new Dictionary<string, long>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> _pinned = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		public static void Configure(long maxBytes)
		{
			_maxBytes = maxBytes;
		}

		public static void RecordDecode(string hash, long pcmBytes)
		{
			if (string.IsNullOrEmpty(hash))
			{
				return;
			}
			if (_lruNodes.TryGetValue(hash, out var value))
			{
				if (_bytesPerTrack.TryGetValue(hash, out var value2))
				{
					_totalBytes -= value2;
				}
				_lruOrder.Remove(value);
				_lruNodes.Remove(hash);
			}
			LinkedListNode<string> value3 = _lruOrder.AddLast(hash);
			_lruNodes[hash] = value3;
			_bytesPerTrack[hash] = pcmBytes;
			_totalBytes += pcmBytes;
			EvictIfNeeded();
		}

		public static void RecordAccess(string hash)
		{
			if (!string.IsNullOrEmpty(hash) && _lruNodes.TryGetValue(hash, out var value))
			{
				_lruOrder.Remove(value);
				_lruNodes[hash] = _lruOrder.AddLast(hash);
			}
		}

		public static void Pin(string hash)
		{
			if (!string.IsNullOrEmpty(hash))
			{
				_pinned.Add(hash);
			}
		}

		public static void Unpin(string hash)
		{
			if (!string.IsNullOrEmpty(hash))
			{
				_pinned.Remove(hash);
			}
		}

		private static void EvictIfNeeded()
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			if (_totalBytes <= _maxBytes)
			{
				return;
			}
			LinkedListNode<string> linkedListNode = _lruOrder.First;
			bool flag = default(bool);
			while (linkedListNode != null && _totalBytes > _maxBytes)
			{
				LinkedListNode<string> next = linkedListNode.Next;
				string value = linkedListNode.Value;
				if (_pinned.Contains(value))
				{
					linkedListNode = next;
					continue;
				}
				TrackInfo trackInfo = RadioAPI.TryGetTrackByHash(value);
				if (trackInfo != null)
				{
					trackInfo.Unload();
					if (_bytesPerTrack.TryGetValue(value, out var value2))
					{
						_totalBytes -= value2;
						_bytesPerTrack.Remove(value);
						ManualLogSource log = Plugin.Log;
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(31, 4, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Evicted '");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(trackInfo.Name);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' (");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(value2 / 1024 / 1024);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" MB) — budget: ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(_totalBytes / 1024 / 1024);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(_maxBytes / 1024 / 1024);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" MB");
						}
						log.LogInfo(val);
					}
				}
				_lruOrder.Remove(linkedListNode);
				_lruNodes.Remove(value);
				linkedListNode = next;
			}
		}
	}
	public static class Mp3Loader
	{
		public static ProbeResult Probe(string filePath, ManualLogSource log = null)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			try
			{
				using FileStream fileStream = File.OpenRead(filePath);
				MpegFile val = new MpegFile((Stream)fileStream);
				int sampleRate = val.SampleRate;
				int channels = val.Channels;
				int lengthSamples = (int)(val.Duration.TotalSeconds * (double)sampleRate);
				return new ProbeResult
				{
					SampleRate = sampleRate,
					Channels = channels,
					LengthSamples = lengthSamples
				};
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(25, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("MP3 probe failed for '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(filePath);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("': ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					log.LogWarning(val2);
				}
				return null;
			}
		}

		public static WavData Load(string filePath, ManualLogSource log = null, CancellationToken ct = default(CancellationToken))
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				using FileStream fileStream = File.OpenRead(filePath);
				MpegFile val = new MpegFile((Stream)fileStream);
				int sampleRate = val.SampleRate;
				int channels = val.Channels;
				List<float> list = new List<float>();
				float[] array = new float[4096];
				int num = 0;
				int num2;
				while ((num2 = val.ReadSamples(array, 0, array.Length)) > 0)
				{
					for (int i = 0; i < num2; i++)
					{
						list.Add(array[i]);
					}
					if (++num % 4 == 0 && ct.IsCancellationRequested)
					{
						return null;
					}
				}
				float[] array2 = list.ToArray();
				int num3 = array2.Length / channels;
				ManualLogSource val2 = log;
				if (val2 != null)
				{
					BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(24, 4, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Loaded MP3: ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(Path.GetFileName(filePath));
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" — ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(channels);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("ch, ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(sampleRate);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Hz, ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>((float)num3 / (float)sampleRate, "F1");
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("s");
					}
					val2.LogInfo(val3);
				}
				return new WavData(array2, sampleRate, channels, num3);
			}
			catch (Exception ex)
			{
				ManualLogSource val2 = log;
				if (val2 != null)
				{
					BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(25, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Failed to decode MP3 '");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(filePath);
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("': ");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(ex.Message);
					}
					val2.LogError(val4);
				}
				return null;
			}
		}
	}
	public static class OggLoader
	{
		public static ProbeResult Probe(string filePath, ManualLogSource log = null)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			try
			{
				VorbisReader val = new VorbisReader(filePath);
				try
				{
					int sampleRate = val.SampleRate;
					int channels = val.Channels;
					int lengthSamples = (int)val.TotalSamples;
					return new ProbeResult
					{
						SampleRate = sampleRate,
						Channels = channels,
						LengthSamples = lengthSamples
					};
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(25, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("OGG probe failed for '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(filePath);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("': ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					log.LogWarning(val2);
				}
				return null;
			}
		}

		public static WavData Load(string filePath, ManualLogSource log = null, CancellationToken ct = default(CancellationToken))
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				VorbisReader val = new VorbisReader(filePath);
				try
				{
					int sampleRate = val.SampleRate;
					int channels = val.Channels;
					List<float> list = new List<float>();
					float[] array = new float[4096];
					int num = 0;
					int num2;
					while ((num2 = val.ReadSamples(array, 0, array.Length)) > 0)
					{
						for (int i = 0; i < num2; i++)
						{
							list.Add(array[i]);
						}
						if (++num % 4 == 0 && ct.IsCancellationRequested)
						{
							return null;
						}
					}
					float[] array2 = list.ToArray();
					int num3 = array2.Length / channels;
					ManualLogSource val2 = log;
					if (val2 != null)
					{
						BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(24, 4, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Loaded OGG: ");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(Path.GetFileName(filePath));
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" — ");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(channels);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("ch, ");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(sampleRate);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Hz, ");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>((float)num3 / (float)sampleRate, "F1");
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("s");
						}
						val2.LogInfo(val3);
					}
					return new WavData(array2, sampleRate, channels, num3);
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource val2 = log;
				if (val2 != null)
				{
					BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(25, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Failed to decode OGG '");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(filePath);
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("': ");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(ex.Message);
					}
					val2.LogError(val4);
				}
				return null;
			}
		}
	}
	[BepInPlugin("com.radiolib.roadsideresearch", "RadioLib", "1.1.0")]
	public class Plugin : BasePlugin
	{
		public const string GUID = "com.radiolib.roadsideresearch";

		public const string Name = "RadioLib";

		public const string Version = "1.1.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<string> MusicFolderName;

		internal static ConfigEntry<bool> VerboseLogging;

		internal static ConfigEntry<int> MemoryBudgetMB;

		internal static ConfigEntry<int> CacheLimitMB;

		public override void Load()
		{
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			Log = ((BasePlugin)this).Log;
			Enabled = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master toggle. When off, no local stations are scanned and no sync patches are applied.");
			MusicFolderName = ((BasePlugin)this).Config.Bind<string>("General", "MusicFolderName", "Music", "Folder name (relative to this plugin's directory) where custom music is loaded from. Subfolders become separate stations; files placed directly in this folder are grouped under the \"Custom Music\" station.");
			VerboseLogging = ((BasePlugin)this).Config.Bind<bool>("General", "VerboseLogging", false, "Emit extra log lines during folder scanning and network transfer. Leave off unless troubleshooting.");
			MemoryBudgetMB = ((BasePlugin)this).Config.Bind<int>("Performance", "MemoryBudgetMB", 200, "Maximum megabytes of decoded PCM audio to keep in RAM. Tracks beyond this limit are evicted (least recently used first) and re-decoded on demand.");
			CacheLimitMB = ((BasePlugin)this).Config.Bind<int>("Performance", "CacheLimitMB", 500, "Maximum megabytes of cached audio files on disk. Oldest files are deleted when the limit is exceeded.");
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val;
			if (!Enabled.Value)
			{
				ManualLogSource log = Log;
				val = new BepInExInfoLogInterpolatedStringHandler(48, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("RadioLib");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" disabled via config; skipping scan and patches.");
				}
				log.LogInfo(val);
				return;
			}
			MemoryBudget.Configure((long)MemoryBudgetMB.Value * 1024L * 1024);
			AudioCache.EvictOldEntries((long)CacheLimitMB.Value * 1024L * 1024);
			FolderScanner.ScanAndRegister();
			Harmony val2 = new Harmony("com.radiolib.roadsideresearch");
			val2.PatchAll(typeof(RadioPatches));
			val2.PatchAll(typeof(RadioLibNet));
			ManualLogSource log2 = Log;
			val = new BepInExInfoLogInterpolatedStringHandler(47, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("RadioLib");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.1.0");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded! ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(RadioAPI.GetStations().Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" local custom station(s) registered.");
			}
			log2.LogInfo(val);
		}
	}
	public static class RadioAPI
	{
		private static readonly List<StationDefinition> _stations = new List<StationDefinition>();

		private static readonly Dictionary<string, TrackInfo> _tracksByHash = new Dictionary<string, TrackInfo>(StringComparer.OrdinalIgnoreCase);

		internal static int _vanillaStationCount = -1;

		public static int TotalStationCount => ((_vanillaStationCount >= 0) ? _vanillaStationCount : 0) + _stations.Count;

		public static int VanillaStationCount
		{
			get
			{
				if (_vanillaStationCount >= 0)
				{
					return _vanillaStationCount;
				}
				return 0;
			}
		}

		public static event Action<TrackInfo> TrackReady;

		public static void RegisterStation(StationDefinition station)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			if (station == null || string.IsNullOrEmpty(station.Id))
			{
				return;
			}
			bool flag = default(bool);
			foreach (StationDefinition station2 in _stations)
			{
				if (station2.Id == station.Id)
				{
					ManualLogSource log = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(40, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Station '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(station.Id);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' already registered, skipping.");
					}
					log.LogWarning(val);
					return;
				}
			}
			_stations.Add(station);
			foreach (TrackInfo track in station.Tracks)
			{
				if (!string.IsNullOrEmpty(track.Hash))
				{
					_tracksByHash[track.Hash] = track;
				}
			}
			ManualLogSource log2 = Plugin.Log;
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(77, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Registered station '");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(station.Name);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' with ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(station.Tracks.Count);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" track(s). FMOD sounds deferred to first playback.");
			}
			log2.LogInfo(val2);
		}

		public static void RegisterStation(string id, string name, float[] pcmData, int sampleRate, int channels)
		{
			int lengthSamples = pcmData.Length / channels;
			TrackInfo item = new TrackInfo
			{
				Name = name,
				PcmData = pcmData,
				SampleRate = sampleRate,
				Channels = channels,
				LengthSamples = lengthSamples
			};
			RegisterStation(new StationDefinition
			{
				Id = id,
				Name = name,
				Tracks = { item }
			});
		}

		public static IReadOnlyList<StationDefinition> GetStations()
		{
			return _stations;
		}

		public static bool IsCustomStation(int stationIndex)
		{
			if (_vanillaStationCount >= 0)
			{
				return stationIndex >= _vanillaStationCount;
			}
			return false;
		}

		public static StationDefinition GetCustomStation(int stationIndex)
		{
			if (!IsCustomStation(stationIndex))
			{
				return null;
			}
			int num = stationIndex - _vanillaStationCount;
			if (num < 0 || num >= _stations.Count)
			{
				return null;
			}
			return _stations[num];
		}

		public static int IndexOfStation(StationDefinition station)
		{
			int num = _stations.IndexOf(station);
			if (num < 0)
			{
				return -1;
			}
			return ((_vanillaStationCount >= 0) ? _vanillaStationCount : 0) + num;
		}

		internal static void ReplaceStationsFromManifest(IList<StationDefinition> newStations)
		{
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			foreach (StationDefinition station in _stations)
			{
				foreach (TrackInfo track in station.Tracks)
				{
					track.ReleaseNativeData();
				}
			}
			_stations.Clear();
			_tracksByHash.Clear();
			foreach (StationDefinition newStation in newStations)
			{
				_stations.Add(newStation);
				foreach (TrackInfo track2 in newStation.Tracks)
				{
					if (!string.IsNullOrEmpty(track2.Hash))
					{
						_tracksByHash[track2.Hash] = track2;
					}
				}
			}
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(30, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Manifest applied: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_stations.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" station(s).");
			}
			log.LogInfo(val);
		}

		internal static TrackInfo TryGetTrackByHash(string hash)
		{
			if (string.IsNullOrEmpty(hash))
			{
				return null;
			}
			_tracksByHash.TryGetValue(hash, out var value);
			return value;
		}

		internal static void MarkTrackReady(string hash, float[] pcm, int sampleRate, int channels)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			TrackInfo trackInfo = TryGetTrackByHash(hash);
			if (trackInfo == null)
			{
				return;
			}
			trackInfo.PcmData = pcm;
			trackInfo.SampleRate = sampleRate;
			trackInfo.Channels = channels;
			trackInfo.LengthSamples = pcm.Length / Math.Max(1, channels);
			MemoryBudget.RecordDecode(hash, (long)pcm.Length * 4L);
			try
			{
				RadioAPI.TrackReady?.Invoke(trackInfo);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(26, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("TrackReady handler threw: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		internal static IEnumerable<StationDefinition> AllStations()
		{
			return _stations;
		}
	}
	public class RadioController
	{
		public struct PlaybackSnapshot
		{
			public uint RadioId;

			public int StationIndex;

			public int TrackIndex;

			public float ElapsedSeconds;
		}

		private static readonly Dictionary<IntPtr, RadioController> _controllers = new Dictionary<IntPtr, RadioController>();

		private static readonly Dictionary<uint, RadioController> _byNetworkId = new Dictionary<uint, RadioController>();

		private static bool _trackReadySubscribed;

		private Channel _channel;

		private Transform _transform;

		private Radio _radio;

		private uint _radioId;

		private int _currentCustomIndex = -1;

		private int _currentTrackIndex;

		private bool _isPlaying;

		private StationDefinition _currentStation;

		private Random _rng = new Random();

		private float _volume = 0.5f;

		private CancellationTokenSource _decodeCts;

		private int _nextTrackIndex = -1;

		private bool _prefetchSent;

		private int _pendingTrackIndex = -1;

		private float _seekAfterReady;

		private static bool IsFollower(StationDefinition station)
		{
			if (station != null && station.RemoteStation)
			{
				return !RadioLibNet.IsHost;
			}
			return false;
		}

		public static RadioController Create(GameObject radioObject)
		{
			EnsureTrackReadyHook();
			RadioController radioController = new RadioController();
			radioController._transform = radioObject.transform;
			radioController._radio = radioObject.GetComponent<Radio>();
			radioController._radioId = TryReadNetworkIdRaw(radioController._radio);
			_controllers[((Il2CppObjectBase)radioObject).Pointer] = radioController;
			if (radioController._radioId != 0)
			{
				_byNetworkId[radioController._radioId] = radioController;
			}
			return radioController;
		}

		public static RadioController Get(GameObject radioObject)
		{
			_controllers.TryGetValue(((Il2CppObjectBase)radioObject).Pointer, out var value);
			return value;
		}

		public static void Remove(GameObject radioObject)
		{
			if (_controllers.TryGetValue(((Il2CppObjectBase)radioObject).Pointer, out var value))
			{
				if (value._radioId != 0)
				{
					_byNetworkId.Remove(value._radioId);
				}
				value.Cleanup();
				_controllers.Remove(((Il2CppObjectBase)radioObject).Pointer);
			}
		}

		private static uint TryReadNetworkIdRaw(Radio radio)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)radio == (Object)null)
			{
				return 0u;
			}
			try
			{
				NetworkObject @object = ((SimulationBehaviour)radio).Object;
				if ((Object)(object)@object == (Object)null)
				{
					return 0u;
				}
				return @object.Id.Raw;
			}
			catch
			{
				return 0u;
			}
		}

		public void PlayStation(int customIndex)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			StationDefinition customStation = RadioAPI.GetCustomStation(customIndex);
			bool flag = default(bool);
			if (customStation == null || customStation.Tracks.Count == 0)
			{
				ManualLogSource log = Plugin.Log;
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(47, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PlayStation(");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(customIndex);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("): station is null or has no tracks");
				}
				log.LogWarning(val);
				Stop();
				return;
			}
			if (IsFollower(customStation))
			{
				_currentCustomIndex = customIndex;
				_currentStation = customStation;
				return;
			}
			ManualLogSource log2 = Plugin.Log;
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(40, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("PlayStation(");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(customIndex);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("): playing '");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(customStation.Name);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' with ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(customStation.Tracks.Count);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" track(s)");
			}
			log2.LogInfo(val2);
			_decodeCts?.Cancel();
			_decodeCts = null;
			_nextTrackIndex = -1;
			_prefetchSent = false;
			_currentCustomIndex = customIndex;
			_currentStation = customStation;
			_currentTrackIndex = (customStation.Shuffle ? _rng.Next(customStation.Tracks.Count) : 0);
			PlayCurrentTrack();
			BroadcastTrackSelect();
		}

		public void Stop()
		{
			_decodeCts?.Cancel();
			_decodeCts = null;
			_isPlaying = false;
			_currentCustomIndex = -1;
			_currentStation = null;
			_pendingTrackIndex = -1;
			_nextTrackIndex = -1;
			_prefetchSent = false;
			StopChannel();
		}

		public void SetVolume(float volume)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			_volume = volume;
			if (((Channel)(ref _channel)).hasHandle())
			{
				((Channel)(ref _channel)).setVolume(volume);
			}
		}

		public void CheckTrackAdvance()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (!_isPlaying || _currentStation == null)
			{
				return;
			}
			Update3DPosition();
			if (!((Channel)(ref _channel)).hasHandle())
			{
				return;
			}
			bool flag = default(bool);
			((Channel)(ref _channel)).isPlaying(ref flag);
			if (flag)
			{
				if (!IsFollower(_currentStation) && !_prefetchSent)
				{
					TryPrefetchNext();
				}
			}
			else if (!IsFollower(_currentStation))
			{
				_prefetchSent = false;
				_nextTrackIndex = -1;
				AdvanceTrack();
			}
		}

		private void TryPrefetchNext()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (_currentStation == null || _currentStation.Tracks.Count <= 1)
			{
				return;
			}
			uint num = default(uint);
			((Channel)(ref _channel)).getPosition(ref num, (TIMEUNIT)1);
			TrackInfo trackInfo = _currentStation.Tracks[_currentTrackIndex];
			if ((float)trackInfo.LengthSamples / (float)Math.Max(1, trackInfo.SampleRate) * 1000f - (float)num > 30000f)
			{
				return;
			}
			int num2 = PeekNextTrack();
			if (num2 >= 0 && num2 < _currentStation.Tracks.Count)
			{
				TrackInfo trackInfo2 = _currentStation.Tracks[num2];
				if (!trackInfo2.Ready && !string.IsNullOrEmpty(trackInfo2.SourcePath))
				{
					DecodeService.Request(trackInfo2, trackInfo2.SourcePath, DecodePriority.Prefetch);
				}
				if (RadioLibNet.IsHost && !string.IsNullOrEmpty(trackInfo2.Hash))
				{
					RadioLibNet.BroadcastToClients(MessageCodec.BuildPrefetchHint(trackInfo2.Hash));
				}
				_prefetchSent = true;
			}
		}

		private int PeekNextTrack()
		{
			if (_nextTrackIndex >= 0)
			{
				return _nextTrackIndex;
			}
			if (_currentStation == null || _currentStation.Tracks.Count == 0)
			{
				return -1;
			}
			if (_currentStation.Shuffle && _currentStation.Tracks.Count > 1)
			{
				do
				{
					_nextTrackIndex = _rng.Next(_currentStation.Tracks.Count);
				}
				while (_nextTrackIndex == _currentTrackIndex);
			}
			else
			{
				_nextTrackIndex = _currentTrackIndex + 1;
				if (_nextTrackIndex >= _currentStation.Tracks.Count)
				{
					_nextTrackIndex = ((!_currentStation.Loop) ? (-1) : 0);
				}
			}
			return _nextTrackIndex;
		}

		private void Update3DPosition()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (((Channel)(ref _channel)).hasHandle() && !((Object)(object)_transform == (Object)null))
			{
				Vector3 position = _transform.position;
				VECTOR val = default(VECTOR);
				val.x = position.x;
				val.y = position.y;
				val.z = position.z;
				VECTOR val2 = val;
				val = default(VECTOR);
				val.x = 0f;
				val.y = 0f;
				val.z = 0f;
				VECTOR val3 = val;
				((Channel)(ref _channel)).set3DAttributes(ref val2, ref val3);
			}
		}

		private void PlayCurrentTrack()
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Expected O, but got Unknown
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Expected O, but got Unknown
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			if (_currentStation == null)
			{
				return;
			}
			List<TrackInfo> tracks = _currentStation.Tracks;
			if (_currentTrackIndex < 0 || _currentTrackIndex >= tracks.Count)
			{
				Stop();
				return;
			}
			TrackInfo trackInfo = tracks[_currentTrackIndex];
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val;
			if (!trackInfo.Ready)
			{
				_pendingTrackIndex = _currentTrackIndex;
				if (!string.IsNullOrEmpty(trackInfo.SourcePath))
				{
					_decodeCts?.Cancel();
					_decodeCts = DecodeService.Request(trackInfo, trackInfo.SourcePath, DecodePriority.Immediate);
				}
				ManualLogSource log = Plugin.Log;
				val = new BepInExInfoLogInterpolatedStringHandler(35, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Deferring play of '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(trackInfo.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' until decoded.");
				}
				log.LogInfo(val);
				return;
			}
			Sound fmodSound = trackInfo.FmodSound;
			if (!((Sound)(ref fmodSound)).hasHandle())
			{
				ManualLogSource log2 = Plugin.Log;
				val = new BepInExInfoLogInterpolatedStringHandler(34, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Lazy-creating FMOD sound for '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(trackInfo.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'...");
				}
				log2.LogInfo(val);
				trackInfo.FmodSound = FmodSoundFactory.CreateSound(trackInfo);
				fmodSound = trackInfo.FmodSound;
				if (!((Sound)(ref fmodSound)).hasHandle())
				{
					ManualLogSource log3 = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(34, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Track '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(trackInfo.Name);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' has no FMOD sound. DIAG: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(FmodSoundFactory.InitStatus);
					}
					log3.LogWarning(val2);
					Stop();
					return;
				}
			}
			StopChannel();
			System coreSystem = RuntimeManager.CoreSystem;
			RESULT val3 = ((System)(ref coreSystem)).playSound(trackInfo.FmodSound, default(ChannelGroup), false, ref _channel);
			if ((int)val3 != 0)
			{
				ManualLogSource log4 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(30, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("FMOD playSound failed for '");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(trackInfo.Name);
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("': ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<RESULT>(val3);
				}
				log4.LogError(val4);
				Stop();
				return;
			}
			((Channel)(ref _channel)).setVolume(_volume);
			((Channel)(ref _channel)).set3DMinMaxDistance(1f, 20f);
			Update3DPosition();
			_isPlaying = true;
			_pendingTrackIndex = -1;
			MemoryBudget.RecordAccess(trackInfo.Hash);
			MemoryBudget.Pin(trackInfo.Hash);
			ManualLogSource log5 = Plugin.Log;
			val = new BepInExInfoLogInterpolatedStringHandler(20, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Now playing track '");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(trackInfo.Name);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
			}
			log5.LogInfo(val);
		}

		private void AdvanceTrack()
		{
			if (_currentStation == null)
			{
				return;
			}
			List<TrackInfo> tracks = _currentStation.Tracks;
			if (tracks.Count == 0)
			{
				Stop();
				return;
			}
			if (_nextTrackIndex >= 0 && _nextTrackIndex < tracks.Count)
			{
				_currentTrackIndex = _nextTrackIndex;
			}
			else if (_currentStation.Shuffle && tracks.Count > 1)
			{
				int num;
				do
				{
					num = _rng.Next(tracks.Count);
				}
				while (num == _currentTrackIndex);
				_currentTrackIndex = num;
			}
			else if (!_currentStation.Shuffle)
			{
				_currentTrackIndex++;
			}
			_nextTrackIndex = -1;
			_prefetchSent = false;
			if (_currentTrackIndex >= tracks.Count)
			{
				if (!_currentStation.Loop)
				{
					Stop();
					return;
				}
				_currentTrackIndex = 0;
			}
			_decodeCts?.Cancel();
			_decodeCts = null;
			PlayCurrentTrack();
			BroadcastTrackSelect();
		}

		private float GetCurrentTrackElapsed()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Channel)(ref _channel)).hasHandle())
			{
				return 0f;
			}
			uint num = default(uint);
			((Channel)(ref _channel)).getPosition(ref num, (TIMEUNIT)1);
			return (float)num / 1000f;
		}

		private void BroadcastTrackSelect()
		{
			if (RadioLibNet.IsHost && _currentStation != null && _radioId != 0)
			{
				int num = RadioAPI.IndexOfStation(_currentStation);
				if (num >= 0)
				{
					float currentTrackElapsed = GetCurrentTrackElapsed();
					RadioLibNet.BroadcastToClients(MessageCodec.BuildTrackSelect(_radioId, num, _currentTrackIndex, currentTrackElapsed));
				}
			}
		}

		public static void ApplyRemoteTrackSelect(uint radioId, int stationIndex, int trackIndex, float elapsedSeconds = 0f)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			if (!_byNetworkId.TryGetValue(radioId, out var value))
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(61, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ApplyRemoteTrackSelect: no radio with id=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<uint>(radioId);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" registered locally.");
				}
				log.LogWarning(val);
			}
			else
			{
				value.ApplyRemoteTrackSelectInternal(stationIndex, trackIndex, elapsedSeconds);
			}
		}

		private void ApplyRemoteTrackSelectInternal(int stationIndex, int trackIndex, float elapsedSeconds)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			StationDefinition customStation = RadioAPI.GetCustomStation(stationIndex);
			if (customStation == null)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(49, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ApplyRemoteTrackSelect: station ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(stationIndex);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" missing locally.");
				}
				log.LogWarning(val);
				return;
			}
			_decodeCts?.Cancel();
			_decodeCts = null;
			_currentStation = customStation;
			_currentCustomIndex = stationIndex;
			_currentTrackIndex = Math.Max(0, Math.Min(trackIndex, customStation.Tracks.Count - 1));
			_seekAfterReady = elapsedSeconds;
			PlayCurrentTrack();
			if (elapsedSeconds > 0f && ((Channel)(ref _channel)).hasHandle())
			{
				((Channel)(ref _channel)).setPosition((uint)(elapsedSeconds * 1000f), (TIMEUNIT)1);
				_seekAfterReady = 0f;
			}
		}

		public static void RefreshAllRadios()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			int vanillaStationCount = RadioAPI.VanillaStationCount;
			int count = RadioAPI.GetStations().Count;
			int count2 = vanillaStationCount + count;
			bool flag = default(bool);
			foreach (KeyValuePair<IntPtr, RadioController> controller in _controllers)
			{
				Radio radio = controller.Value._radio;
				if ((Object)(object)radio == (Object)null)
				{
					continue;
				}
				try
				{
					RadioPatches.WriteStationCountExternal(radio, count2);
				}
				catch (Exception ex)
				{
					ManualLogSource log = Plugin.Log;
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(18, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("RefreshAllRadios: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogError(val);
				}
			}
		}

		public static IEnumerable<PlaybackSnapshot> SnapshotActiveCustomPlayback()
		{
			foreach (KeyValuePair<IntPtr, RadioController> controller in _controllers)
			{
				RadioController value = controller.Value;
				if (value._isPlaying && value._currentStation != null)
				{
					int num = RadioAPI.IndexOfStation(value._currentStation);
					if (num >= 0 && value._radioId != 0)
					{
						yield return new PlaybackSnapshot
						{
							RadioId = value._radioId,
							StationIndex = num,
							TrackIndex = value._currentTrackIndex,
							ElapsedSeconds = value.GetCurrentTrackElapsed()
						};
					}
				}
			}
		}

		private void StopChannel()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if (((Channel)(ref _channel)).hasHandle())
			{
				if (_currentStation != null && _currentTrackIndex >= 0 && _currentTrackIndex < _currentStation.Tracks.Count)
				{
					MemoryBudget.Unpin(_currentStation.Tracks[_currentTrackIndex].Hash);
				}
				((Channel)(ref _channel)).stop();
				((Channel)(ref _channel)).clearHandle();
			}
		}

		private void Cleanup()
		{
			StopChannel();
		}

		private static void EnsureTrackReadyHook()
		{
			if (!_trackReadySubscribed)
			{
				RadioAPI.TrackReady += OnTrackReady;
				_trackReadySubscribed = true;
			}
		}

		private static void OnTrackReady(TrackInfo track)
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<IntPtr, RadioController> controller in _controllers)
			{
				RadioController value = controller.Value;
				if (value._pendingTrackIndex >= 0 && value._currentStation != null && value._pendingTrackIndex < value._currentStation.Tracks.Count && value._currentStation.Tracks[value._pendingTrackIndex] == track)
				{
					value.PlayCurrentTrack();
					if (value._seekAfterReady > 0f && ((Channel)(ref value._channel)).hasHandle())
					{
						((Channel)(ref value._channel)).setPosition((uint)(value._seekAfterReady * 1000f), (TIMEUNIT)1);
						value._seekAfterReady = 0f;
					}
				}
			}
		}
	}
	[HarmonyPatch]
	public static class RadioPatches
	{
		private static int _lastDispatchFrame = -1;

		private const int OFFSET_AMOUNT_OF_STATIONS = 128;

		private const int OFFSET_EVENT_INSTANCE = 216;

		private const int OFFSET_IS_RADIO_ON_LOCAL = 228;

		private const int OFFSET_RADIO_STATION_LOCAL = 236;

		private const int OFFSET_VOLUME_LOCAL = 244;

		private static int ReadStationCount(Radio radio)
		{
			return Marshal.ReadInt32(((Il2CppObjectBase)radio).Pointer + 128);
		}

		private static void WriteStationCount(Radio radio, int count)
		{
			Marshal.WriteInt32(((Il2CppObjectBase)radio).Pointer + 128, count);
		}

		internal static void WriteStationCountExternal(Radio radio, int count)
		{
			WriteStationCount(radio, count);
		}

		private static int ReadCurrentStation(Radio radio)
		{
			return Marshal.ReadInt32(((Il2CppObjectBase)radio).Pointer + 236);
		}

		private static float ReadVolume(Radio radio)
		{
			return BitConverter.Int32BitsToSingle(Marshal.ReadInt32(((Il2CppObjectBase)radio).Pointer + 244));
		}

		private static bool ReadIsRadioOn(Radio radio)
		{
			return Marshal.ReadByte(((Il2CppObjectBase)radio).Pointer + 228) != 0;
		}

		[HarmonyPatch(typeof(Radio), "Spawned")]
		[HarmonyPostfix]
		public static void SpawnedPostfix(Radio __instance)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				int num = ReadStationCount(__instance);
				if (RadioAPI._vanillaStationCount < 0)
				{
					RadioAPI._vanillaStationCount = num;
					ManualLogSource log = Plugin.Log;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(29, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Vanilla radio station count: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					}
					log.LogInfo(val);
				}
				int count = RadioAPI.GetStations().Count;
				if (count > 0)
				{
					int count2 = num + count;
					WriteStationCount(__instance, count2);
					int num2 = ReadStationCount(__instance);
					ManualLogSource log2 = Plugin.Log;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(40, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Expanded radio stations: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" -> ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num2);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (+");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(count);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" custom)");
					}
					log2.LogInfo(val);
				}
				if (RadioController.Get(((Component)__instance).gameObject) == null)
				{
					RadioController.Create(((Component)__instance).gameObject);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(29, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("RadioPatches.SpawnedPostfix: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log3.LogError(val2);
			}
		}

		[HarmonyPatch(typeof(Radio), "Despawned")]
		[HarmonyPrefix]
		public static void DespawnedPrefix(Radio __instance)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			try
			{
				RadioController.Remove(((Component)__instance).gameObject);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(30, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("RadioPatches.DespawnedPrefix: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		[HarmonyPatch(typeof(Radio), "OnChangedRadioStation")]
		[HarmonyPostfix]
		public static void OnChangedRadioStationPostfix(Radio __instance)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Expected O, but got Unknown
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			bool flag = default(bool);
			try
			{
				int num = ReadCurrentStation(__instance);
				ManualLogSource log = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(42, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("OnChangedRadioStation: station=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", isCustom=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(RadioAPI.IsCustomStation(num));
				}
				log.LogInfo(val);
				RadioController radioController = RadioController.Get(((Component)__instance).gameObject);
				if (radioController == null)
				{
					return;
				}
				if (RadioAPI.IsCustomStation(num))
				{
					EventInstance value = Traverse.Create((object)__instance).Field("_eventInstance").GetValue<EventInstance>();
					if (((EventInstance)(ref value)).isValid())
					{
						((EventInstance)(ref value)).stop((STOP_MODE)1);
					}
					float volume = ReadVolume(__instance);
					radioController.SetVolume(volume);
					radioController.PlayStation(num);
				}
				else
				{
					radioController.Stop();
					EventInstance value2 = Traverse.Create((object)__instance).Field("_eventInstance").GetValue<EventInstance>();
					if (((EventInstance)(ref value2)).isValid())
					{
						((EventInstance)(ref value2)).setPaused(false);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(43, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("RadioPatches.OnChangedRadioStationPostfix: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log2.LogError(val2);
			}
		}

		[HarmonyPatch(typeof(Radio), "OnChangedVolume")]
		[HarmonyPostfix]
		public static void OnChangedVolumePostfix(Radio __instance)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			try
			{
				RadioController radioController = RadioController.Get(((Component)__instance).gameObject);
				if (radioController != null)
				{
					float volume = ReadVolume(__instance);
					radioController.SetVolume(volume);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(37, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("RadioPatches.OnChangedVolumePostfix: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		[HarmonyPatch(typeof(Radio), "OnChangedRadioOn")]
		[HarmonyPostfix]
		public static void OnChangedRadioOnPostfix(Radio __instance)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_0043: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				RadioController radioController = RadioController.Get(((Component)__instance).gameObject);
				if (radioController == null)
				{
					return;
				}
				bool num = ReadIsRadioOn(__instance);
				int num2 = ReadCurrentStation(__instance);
				if (!num)
				{
					radioController.Stop();
				}
				else if (RadioAPI.IsCustomStation(num2))
				{
					EventInstance value = Traverse.Create((object)__instance).Field("_eventInstance").GetValue<EventInstance>();
					if (((EventInstance)(ref value)).isValid())
					{
						((EventInstance)(ref value)).stop((STOP_MODE)1);
					}
					float volume = ReadVolume(__instance);
					radioController.SetVolume(volume);
					radioController.PlayStation(num2);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(38, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("RadioPatches.OnChangedRadioOnPostfix: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		[HarmonyPatch(typeof(Radio), "Update")]
		[HarmonyPostfix]
		public static void UpdatePostfix(Radio __instance)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Invalid comparison between Unknown and I4
			try
			{
				int frameCount = Time.frameCount;
				if (frameCount != _lastDispatchFrame)
				{
					_lastDispatchFrame = frameCount;
					MainThread.ProcessQueue();
				}
				RadioController.Get(((Component)__instance).gameObject)?.CheckTrackAdvance();
				if (!ReadIsRadioOn(__instance) || !RadioAPI.IsCustomStation(ReadCurrentStation(__instance)))
				{
					return;
				}
				EventInstance value = Traverse.Create((object)__instance).Field("_eventInstance").GetValue<EventInstance>();
				if (((EventInstance)(ref value)).isValid())
				{
					PLAYBACK_STATE val = default(PLAYBACK_STATE);
					((EventInstance)(ref value)).getPlaybackState(ref val);
					if ((int)val == 0 || (int)val == 3)
					{
						((EventInstance)(ref value)).stop((STOP_MODE)1);
					}
				}
			}
			catch
			{
			}
		}
	}
	public class TrackInfo
	{
		public string Name { get; set; }

		public float[] PcmData { get; set; }

		public int SampleRate { get; set; }

		public int Channels { get; set; }

		public int LengthSamples { get; set; }

		public Sound FmodSound { get; internal set; }

		public string Hash { get; set; }

		public string Extension { get; set; }

		public string SourcePath { get; set; }

		public bool Ready
		{
			get
			{
				if (PcmData != null)
				{
					return PcmData.Length != 0;
				}
				return false;
			}
		}

		internal IntPtr NativePcmPtr { get; set; }

		public void Unload()
		{
			ReleaseNativeData();
			PcmData = null;
		}

		internal void ReleaseNativeData()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if (NativePcmPtr != IntPtr.Zero)
			{
				Marshal.FreeHGlobal(NativePcmPtr);
				NativePcmPtr = IntPtr.Zero;
			}
			Sound fmodSound = FmodSound;
			if (((Sound)(ref fmodSound)).hasHandle())
			{
				fmodSound = FmodSound;
				((Sound)(ref fmodSound)).release();
				fmodSound = FmodSound;
				((Sound)(ref fmodSound)).clearHandle();
			}
		}
	}
	public class StationDefinition
	{
		public string Id { get; set; }

		public string Name { get; set; }

		public List<TrackInfo> Tracks { get; set; } = new List<TrackInfo>();


		public bool Shuffle { get; set; }

		public bool Loop { get; set; } = true;


		public bool RemoteStation { get; set; }
	}
	public class WavData
	{
		public float[] Samples;

		public int SampleRate;

		public int Channels;

		public int LengthSamples;

		public WavData(float[] samples, int sampleRate, int channels, int lengthSamples)
		{
			Samples = samples;
			SampleRate = sampleRate;
			Channels = channels;
			LengthSamples = lengthSamples;
		}
	}
	public class ProbeResult
	{
		public int SampleRate;

		public int Channels;

		public int LengthSamples;
	}
	public static class WavLoader
	{
		public static WavData Load(string filePath, ManualLogSource log = null, CancellationToken ct = default(CancellationToken))
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Expected O, but got Unknown
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Expected O, but got Unknown
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Expected O, but got Unknown
			//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Expected O, but got Unknown
			byte[] array;
			bool flag = default(bool);
			ManualLogSource val;
			try
			{
				array = File.ReadAllBytes(filePath);
			}
			catch (Exception ex)
			{
				val = log;
				if (val != null)
				{
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(28, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Failed to read WAV file '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(filePath);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("': ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					val.LogError(val2);
				}
				return null;
			}
			if (ct.IsCancellationRequested)
			{
				return null;
			}
			if (array.Length < 44)
			{
				val = log;
				if (val != null)
				{
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(20, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("WAV file too small: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(filePath);
					}
					val.LogError(val2);
				}
				return null;
			}
			string @string = Encoding.ASCII.GetString(array, 0, 4);
			string string2 = Encoding.ASCII.GetString(array, 8, 4);
			if (@string != "RIFF" || string2 != "WAVE")
			{
				val = log;
				if (val != null)
				{
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(22, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Not a valid WAV file: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(filePath);
					}
					val.LogError(val2);
				}
				return null;
			}
			int num = FindChunk(array, "fmt ", 12);
			if (num < 0)
			{
				val = log;
				if (val != null)
				{
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(23, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("No fmt chunk found in: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(filePath);
					}
					val.LogError(val2);
				}
				return null;
			}
			BitConverter.ToInt32(array, num + 4);
			int num2 = num + 8;
			ushort num3 = BitConverter.ToUInt16(array, num2);
			ushort num4 = BitConverter.ToUInt16(array, num2 + 2);
			int num5 = BitConverter.ToInt32(array, num2 + 4);
			ushort num6 = BitConverter.ToUInt16(array, num2 + 14);
			if (num3 != 1 && num3 != 3)
			{
				val = log;
				if (val != null)
				{
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(68, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Unsupported WAV format ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<ushort>(num3);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" in: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(filePath);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" (only PCM=1 and IEEE float=3 supported)");
					}
					val.LogError(val2);
				}
				return null;
			}
			int num7 = FindChunk(array, "data", 12);
			if (num7 < 0)
			{
				val = log;
				if (val != null)
				{
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(24, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("No data chunk found in: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(filePath);
					}
					val.LogError(val2);
				}
				return null;
			}
			int num8 = BitConverter.ToInt32(array, num7 + 4);
			int num9 = num7 + 8;
			if (num9 + num8 > array.Length)
			{
				num8 = array.Length - num9;
			}
			float[] array2;
			if (num3 == 1 && num6 == 16)
			{
				int num10 = num8 / 2;
				array2 = new float[num10];
				for (int i = 0; i < num10; i++)
				{
					short num11 = BitConverter.ToInt16(array, num9 + i * 2);
					array2[i] = (float)num11 / 32768f;
				}
			}
			else if (num3 == 1 && num6 == 24)
			{
				int num12 = num8 / 3;
				array2 = new float[num12];
				for (int j = 0; j < num12; j++)
				{
					int num13 = num9 + j * 3;
					int num14 = array[num13] | (array[num13 + 1] << 8) | (array[num13 + 2] << 16);
					if (num14 >= 8388608)
					{
						num14 -= 16777216;
					}
					array2[j] = (float)num14 / 8388608f;
				}
			}
			else
			{
				if (num3 != 3 || num6 != 32)
				{
					val = log;
					if (val != null)
					{
						BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(39, 3, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Unsupported bit depth ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<ushort>(num6);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" for format ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<ushort>(num3);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" in: ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(filePath);
						}
						val.LogError(val2);
					}
					return null;
				}
				int num15 = num8 / 4;
				array2 = new float[num15];
				Buffer.BlockCopy(array, num9, array2, 0, num15 * 4);
			}
			int num16 = array2.Length / num4;
			val = log;
			if (val != null)
			{
				BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(29, 5, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Loaded WAV: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(Path.GetFileName(filePath));
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" — ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<ushort>(num4);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("ch, ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num5);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Hz, ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<ushort>(num6);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("bit, ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>((float)num16 / (float)num5, "F1");
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("s");
				}
				val.LogInfo(val3);
			}
			return new WavData(array2, num5, num4, num16);
		}

		public static ProbeResult Probe(string filePath, ManualLogSource log = null)
		{
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Expected O, but got Unknown
			try
			{
				long length;
				byte[] array;
				using (FileStream fileStream = File.OpenRead(filePath))
				{
					length = fileStream.Length;
					int num = (int)Math.Min(length, 512L);
					array = new byte[num];
					int num2;
					for (int i = 0; i < num; i += num2)
					{
						num2 = fileStream.Read(array, i, num - i);
						if (num2 == 0)
						{
							break;
						}
					}
				}
				if (array.Length < 44)
				{
					return null;
				}
				string @string = Encoding.ASCII.GetString(array, 0, 4);
				string string2 = Encoding.ASCII.GetString(array, 8, 4);
				if (@string != "RIFF" || string2 != "WAVE")
				{
					return null;
				}
				int num3 = FindChunk(array, "fmt ", 12);
				if (num3 < 0)
				{
					return null;
				}
				int num4 = num3 + 8;
				if (num4 + 16 > array.Length)
				{
					return null;
				}
				ushort num5 = BitConverter.ToUInt16(array, num4 + 2);
				int sampleRate = BitConverter.ToInt32(array, num4 + 4);
				ushort num6 = BitConverter.ToUInt16(array, num4 + 14);
				int num7 = FindChunk(array, "data", 12);
				int num8 = (int)((num7 < 0 || num7 + 8 > array.Length) ? (length - 44) : BitConverter.ToInt32(array, num7 + 4));
				if (num6 == 0 || num5 == 0)
				{
					return null;
				}
				int num9 = num6 / 8;
				int lengthSamples = num8 / num9 / num5;
				return new ProbeResult
				{
					SampleRate = sampleRate,
					Channels = num5,
					LengthSamples = lengthSamples
				};
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					bool flag = default(bool);