using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using NVorbis.Ogg; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")] [assembly: AssemblyCompany("Andrew Ward")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © Andrew Ward 2019")] [assembly: AssemblyDescription("A fully managed implementation of a Xiph.org Foundation Ogg Vorbis decoder.")] [assembly: AssemblyFileVersion("0.9.0.0")] [assembly: AssemblyInformationalVersion("0.9.0.0")] [assembly: AssemblyProduct("NVorbis")] [assembly: AssemblyTitle("NVorbis")] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("0.9.0.0")] namespace NVorbis { public abstract class DataPacket { [Flags] protected enum PacketFlags : byte { IsResync = 1, IsEndOfStream = 2, IsShort = 4, HasGranuleCount = 8, User1 = 0x10, User2 = 0x20, User3 = 0x40, User4 = 0x80 } private ulong _bitBucket; private int _bitCount; private int _readBits; private byte _overflowBits; private PacketFlags _packetFlags; private long _granulePosition; private long _pageGranulePosition; private int _length; private int _granuleCount; private int _pageSequenceNumber; public bool IsResync { get { return GetFlag(PacketFlags.IsResync); } internal set { SetFlag(PacketFlags.IsResync, value); } } public long GranulePosition { get { return _granulePosition; } set { _granulePosition = value; } } public long PageGranulePosition { get { return _pageGranulePosition; } internal set { _pageGranulePosition = value; } } public int Length { get { return _length; } protected set { _length = value; } } public bool IsEndOfStream { get { return GetFlag(PacketFlags.IsEndOfStream); } internal set { SetFlag(PacketFlags.IsEndOfStream, value); } } public long BitsRead => _readBits; public int? GranuleCount { get { if (GetFlag(PacketFlags.HasGranuleCount)) { return _granuleCount; } return null; } set { if (value.HasValue) { _granuleCount = value.Value; SetFlag(PacketFlags.HasGranuleCount, value: true); } else { SetFlag(PacketFlags.HasGranuleCount, value: false); } } } internal int PageSequenceNumber { get { return _pageSequenceNumber; } set { _pageSequenceNumber = value; } } internal bool IsShort { get { return GetFlag(PacketFlags.IsShort); } private set { SetFlag(PacketFlags.IsShort, value); } } protected bool GetFlag(PacketFlags flag) { return (_packetFlags & flag) == flag; } protected void SetFlag(PacketFlags flag, bool value) { if (value) { _packetFlags |= flag; } else { _packetFlags &= (PacketFlags)(byte)(~(int)flag); } } protected DataPacket(int length) { Length = length; } protected abstract int ReadNextByte(); public virtual void Done() { } public ulong TryPeekBits(int count, out int bitsRead) { ulong num = 0uL; switch (count) { default: throw new ArgumentOutOfRangeException("count"); case 0: bitsRead = 0; return 0uL; case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: break; } while (_bitCount < count) { int num2 = ReadNextByte(); if (num2 == -1) { bitsRead = _bitCount; num = _bitBucket; _bitBucket = 0uL; _bitCount = 0; IsShort = true; return num; } _bitBucket = (ulong)((long)(num2 & 0xFF) << _bitCount) | _bitBucket; _bitCount += 8; if (_bitCount > 64) { _overflowBits = (byte)(num2 >> 72 - _bitCount); } } num = _bitBucket; if (count < 64) { num &= (ulong)((1L << count) - 1); } bitsRead = count; return num; } public void SkipBits(int count) { if (count == 0) { return; } if (_bitCount > count) { if (count > 63) { _bitBucket = 0uL; } else { _bitBucket >>= count; } if (_bitCount > 64) { int num = _bitCount - 64; _bitBucket |= (ulong)_overflowBits << _bitCount - count - num; if (num > count) { _overflowBits = (byte)(_overflowBits >> count); } } _bitCount -= count; _readBits += count; return; } if (_bitCount == count) { _bitBucket = 0uL; _bitCount = 0; _readBits += count; return; } count -= _bitCount; _readBits += _bitCount; _bitCount = 0; _bitBucket = 0uL; while (count > 8) { if (ReadNextByte() == -1) { count = 0; IsShort = true; break; } count -= 8; _readBits += 8; } if (count > 0) { int num2 = ReadNextByte(); if (num2 == -1) { IsShort = true; return; } _bitBucket = (ulong)(num2 >> count); _bitCount = 8 - count; _readBits += count; } } protected void ResetBitReader() { _bitBucket = 0uL; _bitCount = 0; _readBits = 0; IsShort = false; } public ulong ReadBits(int count) { if (count == 0) { return 0uL; } int bitsRead; ulong result = TryPeekBits(count, out bitsRead); SkipBits(count); return result; } public byte PeekByte() { int bitsRead; return (byte)TryPeekBits(8, out bitsRead); } public byte ReadByte() { return (byte)ReadBits(8); } public byte[] ReadBytes(int count) { byte[] array = new byte[count]; for (int i = 0; i < count; i++) { array[i] = ReadByte(); } return array; } public int Read(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)TryPeekBits(8, out bitsRead); if (bitsRead == 0) { return i; } buffer[index++] = b; SkipBits(8); } return count; } public bool ReadBit() { return ReadBits(1) == 1; } public short ReadInt16() { return (short)ReadBits(16); } public int ReadInt32() { return (int)ReadBits(32); } public long ReadInt64() { return (long)ReadBits(64); } public ushort ReadUInt16() { return (ushort)ReadBits(16); } public uint ReadUInt32() { return (uint)ReadBits(32); } public ulong ReadUInt64() { return ReadBits(64); } public void SkipBytes(int count) { SkipBits(count * 8); } } internal static class Huffman { private const int MAX_TABLE_BITS = 10; internal static List BuildPrefixedLinkedList(IReadOnlyList values, int[] lengthList, int[] codeList, out int tableBits, out HuffmanListNode firstOverflowNode) { HuffmanListNode[] array = new HuffmanListNode[lengthList.Length]; int num = 0; for (int i = 0; i < array.Length; i++) { array[i] = new HuffmanListNode { Value = values[i], Length = ((lengthList[i] <= 0) ? 99999 : lengthList[i]), Bits = codeList[i], Mask = (1 << lengthList[i]) - 1 }; if (lengthList[i] > 0 && num < lengthList[i]) { num = lengthList[i]; } } Array.Sort(array, 0, array.Length); tableBits = ((num > 10) ? 10 : num); List list = new List(1 << tableBits); firstOverflowNode = null; for (int j = 0; j < array.Length && array[j].Length < 99999; j++) { if (firstOverflowNode == null) { int length = array[j].Length; if (length > tableBits) { firstOverflowNode = array[j]; continue; } int num2 = 1 << tableBits - length; HuffmanListNode huffmanListNode = array[j]; for (int k = 0; k < num2; k++) { int num3 = (k << length) | huffmanListNode.Bits; while (list.Count <= num3) { list.Add(null); } list[num3] = huffmanListNode; } } else { array[j - 1].Next = array[j]; } } while (list.Count < 1 << tableBits) { list.Add(null); } return list; } } internal class HuffmanListNode : IComparable { internal int Value; internal int Length; internal int Bits; internal int Mask; internal HuffmanListNode Next; int IComparable.CompareTo(HuffmanListNode other) { int num = Length - other.Length; if (num == 0) { return Bits - other.Bits; } return num; } } public interface IContainerReader : IDisposable { int[] StreamSerials { get; } bool CanSeek { get; } long WasteBits { get; } int PagesRead { get; } event EventHandler NewStream; bool Init(); bool FindNextStream(); int GetTotalPageCount(); } public interface IPacketProvider : IDisposable { int StreamSerial { get; } bool CanSeek { get; } long ContainerBits { get; } event EventHandler ParameterChange; int GetTotalPageCount(); DataPacket GetNextPacket(); DataPacket PeekNextPacket(); DataPacket GetPacket(int packetIndex); long GetGranuleCount(); DataPacket FindPacket(long granulePos, Func packetGranuleCountCallback); void SeekToPacket(DataPacket packet, int preRoll); } public interface IVorbisStreamStatus { int EffectiveBitRate { get; } int InstantBitRate { get; } TimeSpan PageLatency { get; } TimeSpan PacketLatency { get; } TimeSpan SecondLatency { get; } long OverheadBits { get; } long AudioBits { get; } int PagesRead { get; } int TotalPages { get; } bool Clipped { get; } void ResetStats(); } internal class Mdct { private const float M_PI = (float)Math.PI; private static Dictionary _setupCache = new Dictionary(2); private int _n; private int _n2; private int _n4; private int _n8; private int _ld; private float[] _A; private float[] _B; private float[] _C; private ushort[] _bitrev; private Dictionary _threadLocalBuffers = new Dictionary(1); public static void Reverse(float[] samples, int sampleCount) { GetSetup(sampleCount).CalcReverse(samples); } private static Mdct GetSetup(int n) { lock (_setupCache) { if (!_setupCache.ContainsKey(n)) { _setupCache[n] = new Mdct(n); } return _setupCache[n]; } } private Mdct(int n) { _n = n; _n2 = n >> 1; _n4 = _n2 >> 1; _n8 = _n4 >> 1; _ld = Utils.ilog(n) - 1; _A = new float[_n2]; _B = new float[_n2]; _C = new float[_n4]; int num2; int num = (num2 = 0); while (num < _n4) { _A[num2] = (float)Math.Cos((float)(4 * num) * (float)Math.PI / (float)n); _A[num2 + 1] = (float)(0.0 - Math.Sin((float)(4 * num) * (float)Math.PI / (float)n)); _B[num2] = (float)Math.Cos((float)(num2 + 1) * (float)Math.PI / (float)n / 2f) * 0.5f; _B[num2 + 1] = (float)Math.Sin((float)(num2 + 1) * (float)Math.PI / (float)n / 2f) * 0.5f; num++; num2 += 2; } num = (num2 = 0); while (num < _n8) { _C[num2] = (float)Math.Cos((float)(2 * (num2 + 1)) * (float)Math.PI / (float)n); _C[num2 + 1] = (float)(0.0 - Math.Sin((float)(2 * (num2 + 1)) * (float)Math.PI / (float)n)); num++; num2 += 2; } _bitrev = new ushort[_n8]; for (int i = 0; i < _n8; i++) { _bitrev[i] = (ushort)(Utils.BitReverse((uint)i, _ld - 3) << 2); } } private float[] GetBuffer() { lock (_threadLocalBuffers) { if (!_threadLocalBuffers.TryGetValue(Thread.CurrentThread.ManagedThreadId, out var value)) { value = (_threadLocalBuffers[Thread.CurrentThread.ManagedThreadId] = new float[_n2]); } return value; } } private void CalcReverse(float[] buffer) { float[] buffer2 = GetBuffer(); int num = _n2 - 2; int num2 = 0; int i = 0; for (int n = _n2; i != n; i += 4) { buffer2[num + 1] = buffer[i] * _A[num2] - buffer[i + 2] * _A[num2 + 1]; buffer2[num] = buffer[i] * _A[num2 + 1] + buffer[i + 2] * _A[num2]; num -= 2; num2 += 2; } i = _n2 - 3; while (num >= 0) { buffer2[num + 1] = (0f - buffer[i + 2]) * _A[num2] - (0f - buffer[i]) * _A[num2 + 1]; buffer2[num] = (0f - buffer[i + 2]) * _A[num2 + 1] + (0f - buffer[i]) * _A[num2]; num -= 2; num2 += 2; i -= 4; } float[] array = buffer2; int num3 = _n2 - 8; int num4 = _n4; int num5 = 0; int num6 = _n4; int num7 = 0; while (num3 >= 0) { float num8 = array[num4 + 1] - array[num5 + 1]; float num9 = array[num4] - array[num5]; buffer[num6 + 1] = array[num4 + 1] + array[num5 + 1]; buffer[num6] = array[num4] + array[num5]; buffer[num7 + 1] = num8 * _A[num3 + 4] - num9 * _A[num3 + 5]; buffer[num7] = num9 * _A[num3 + 4] + num8 * _A[num3 + 5]; num8 = array[num4 + 3] - array[num5 + 3]; num9 = array[num4 + 2] - array[num5 + 2]; buffer[num6 + 3] = array[num4 + 3] + array[num5 + 3]; buffer[num6 + 2] = array[num4 + 2] + array[num5 + 2]; buffer[num7 + 3] = num8 * _A[num3] - num9 * _A[num3 + 1]; buffer[num7 + 2] = num9 * _A[num3] + num8 * _A[num3 + 1]; num3 -= 8; num6 += 4; num7 += 4; num4 += 4; num5 += 4; } int n2 = _n >> 4; int num10 = _n2 - 1; _ = _n4; step3_iter0_loop(n2, buffer, num10 - 0, -_n8); step3_iter0_loop(_n >> 4, buffer, _n2 - 1 - _n4, -_n8); int lim = _n >> 5; int num11 = _n2 - 1; _ = _n8; step3_inner_r_loop(lim, buffer, num11 - 0, -(_n >> 4), 16); step3_inner_r_loop(_n >> 5, buffer, _n2 - 1 - _n8, -(_n >> 4), 16); step3_inner_r_loop(_n >> 5, buffer, _n2 - 1 - _n8 * 2, -(_n >> 4), 16); step3_inner_r_loop(_n >> 5, buffer, _n2 - 1 - _n8 * 3, -(_n >> 4), 16); int j; for (j = 2; j < _ld - 3 >> 1; j++) { int num12 = _n >> j + 2; int num13 = num12 >> 1; int num14 = 1 << j + 1; for (int k = 0; k < num14; k++) { step3_inner_r_loop(_n >> j + 4, buffer, _n2 - 1 - num12 * k, -num13, 1 << j + 3); } } for (; j < _ld - 6; j++) { int num15 = _n >> j + 2; int num16 = 1 << j + 3; int num17 = num15 >> 1; int num18 = _n >> j + 6; int n3 = 1 << j + 1; int num19 = _n2 - 1; int num20 = 0; for (int num21 = num18; num21 > 0; num21--) { step3_inner_s_loop(n3, buffer, num19, -num17, num20, num16, num15); num20 += num16 * 4; num19 -= 8; } } step3_inner_s_loop_ld654(_n >> 5, buffer, _n2 - 1, _n); int num22 = 0; int num23 = _n4 - 4; int num24 = _n2 - 4; while (num23 >= 0) { int num25 = _bitrev[num22]; array[num24 + 3] = buffer[num25]; array[num24 + 2] = buffer[num25 + 1]; array[num23 + 3] = buffer[num25 + 2]; array[num23 + 2] = buffer[num25 + 3]; num25 = _bitrev[num22 + 1]; array[num24 + 1] = buffer[num25]; array[num24] = buffer[num25 + 1]; array[num23 + 1] = buffer[num25 + 2]; array[num23] = buffer[num25 + 3]; num23 -= 4; num24 -= 4; num22 += 2; } int num26 = 0; int num27 = 0; int num28 = _n2 - 4; while (num27 < num28) { float num29 = array[num27] - array[num28 + 2]; float num30 = array[num27 + 1] + array[num28 + 3]; float num31 = _C[num26 + 1] * num29 + _C[num26] * num30; float num32 = _C[num26 + 1] * num30 - _C[num26] * num29; float num33 = array[num27] + array[num28 + 2]; float num34 = array[num27 + 1] - array[num28 + 3]; array[num27] = num33 + num31; array[num27 + 1] = num34 + num32; array[num28 + 2] = num33 - num31; array[num28 + 3] = num32 - num34; num29 = array[num27 + 2] - array[num28]; num30 = array[num27 + 3] + array[num28 + 1]; num31 = _C[num26 + 3] * num29 + _C[num26 + 2] * num30; num32 = _C[num26 + 3] * num30 - _C[num26 + 2] * num29; num33 = array[num27 + 2] + array[num28]; num34 = array[num27 + 3] - array[num28 + 1]; array[num27 + 2] = num33 + num31; array[num27 + 3] = num34 + num32; array[num28] = num33 - num31; array[num28 + 1] = num32 - num34; num26 += 4; num27 += 4; num28 -= 4; } int num35 = _n2 - 8; int num36 = _n2 - 8; int num37 = 0; int num38 = _n2 - 4; int num39 = _n2; int num40 = _n - 4; while (num36 >= 0) { float num41 = buffer2[num36 + 6] * _B[num35 + 7] - buffer2[num36 + 7] * _B[num35 + 6]; float num42 = (0f - buffer2[num36 + 6]) * _B[num35 + 6] - buffer2[num36 + 7] * _B[num35 + 7]; buffer[num37] = num41; buffer[num38 + 3] = 0f - num41; buffer[num39] = num42; buffer[num40 + 3] = num42; float num43 = buffer2[num36 + 4] * _B[num35 + 5] - buffer2[num36 + 5] * _B[num35 + 4]; float num44 = (0f - buffer2[num36 + 4]) * _B[num35 + 4] - buffer2[num36 + 5] * _B[num35 + 5]; buffer[num37 + 1] = num43; buffer[num38 + 2] = 0f - num43; buffer[num39 + 1] = num44; buffer[num40 + 2] = num44; num41 = buffer2[num36 + 2] * _B[num35 + 3] - buffer2[num36 + 3] * _B[num35 + 2]; num42 = (0f - buffer2[num36 + 2]) * _B[num35 + 2] - buffer2[num36 + 3] * _B[num35 + 3]; buffer[num37 + 2] = num41; buffer[num38 + 1] = 0f - num41; buffer[num39 + 2] = num42; buffer[num40 + 1] = num42; num43 = buffer2[num36] * _B[num35 + 1] - buffer2[num36 + 1] * _B[num35]; num44 = (0f - buffer2[num36]) * _B[num35] - buffer2[num36 + 1] * _B[num35 + 1]; buffer[num37 + 3] = num43; buffer[num38] = 0f - num43; buffer[num39 + 3] = num44; buffer[num40] = num44; num35 -= 8; num36 -= 8; num37 += 4; num39 += 4; num38 -= 4; num40 -= 4; } } private void step3_iter0_loop(int n, float[] e, int i_off, int k_off) { int num = i_off; int num2 = num + k_off; int num3 = 0; for (int num4 = n >> 2; num4 > 0; num4--) { float num5 = e[num] - e[num2]; float num6 = e[num - 1] - e[num2 - 1]; e[num] += e[num2]; e[num - 1] += e[num2 - 1]; e[num2] = num5 * _A[num3] - num6 * _A[num3 + 1]; e[num2 - 1] = num6 * _A[num3] + num5 * _A[num3 + 1]; num3 += 8; num5 = e[num - 2] - e[num2 - 2]; num6 = e[num - 3] - e[num2 - 3]; e[num - 2] += e[num2 - 2]; e[num - 3] += e[num2 - 3]; e[num2 - 2] = num5 * _A[num3] - num6 * _A[num3 + 1]; e[num2 - 3] = num6 * _A[num3] + num5 * _A[num3 + 1]; num3 += 8; num5 = e[num - 4] - e[num2 - 4]; num6 = e[num - 5] - e[num2 - 5]; e[num - 4] += e[num2 - 4]; e[num - 5] += e[num2 - 5]; e[num2 - 4] = num5 * _A[num3] - num6 * _A[num3 + 1]; e[num2 - 5] = num6 * _A[num3] + num5 * _A[num3 + 1]; num3 += 8; num5 = e[num - 6] - e[num2 - 6]; num6 = e[num - 7] - e[num2 - 7]; e[num - 6] += e[num2 - 6]; e[num - 7] += e[num2 - 7]; e[num2 - 6] = num5 * _A[num3] - num6 * _A[num3 + 1]; e[num2 - 7] = num6 * _A[num3] + num5 * _A[num3 + 1]; num3 += 8; num -= 8; num2 -= 8; } } private void step3_inner_r_loop(int lim, float[] e, int d0, int k_off, int k1) { int num = d0; int num2 = num + k_off; int num3 = 0; for (int num4 = lim >> 2; num4 > 0; num4--) { float num5 = e[num] - e[num2]; float num6 = e[num - 1] - e[num2 - 1]; e[num] += e[num2]; e[num - 1] += e[num2 - 1]; e[num2] = num5 * _A[num3] - num6 * _A[num3 + 1]; e[num2 - 1] = num6 * _A[num3] + num5 * _A[num3 + 1]; num3 += k1; num5 = e[num - 2] - e[num2 - 2]; num6 = e[num - 3] - e[num2 - 3]; e[num - 2] += e[num2 - 2]; e[num - 3] += e[num2 - 3]; e[num2 - 2] = num5 * _A[num3] - num6 * _A[num3 + 1]; e[num2 - 3] = num6 * _A[num3] + num5 * _A[num3 + 1]; num3 += k1; num5 = e[num - 4] - e[num2 - 4]; num6 = e[num - 5] - e[num2 - 5]; e[num - 4] += e[num2 - 4]; e[num - 5] += e[num2 - 5]; e[num2 - 4] = num5 * _A[num3] - num6 * _A[num3 + 1]; e[num2 - 5] = num6 * _A[num3] + num5 * _A[num3 + 1]; num3 += k1; num5 = e[num - 6] - e[num2 - 6]; num6 = e[num - 7] - e[num2 - 7]; e[num - 6] += e[num2 - 6]; e[num - 7] += e[num2 - 7]; e[num2 - 6] = num5 * _A[num3] - num6 * _A[num3 + 1]; e[num2 - 7] = num6 * _A[num3] + num5 * _A[num3 + 1]; num3 += k1; num -= 8; num2 -= 8; } } private void step3_inner_s_loop(int n, float[] e, int i_off, int k_off, int a, int a_off, int k0) { float num = _A[a]; float num2 = _A[a + 1]; float num3 = _A[a + a_off]; float num4 = _A[a + a_off + 1]; float num5 = _A[a + a_off * 2]; float num6 = _A[a + a_off * 2 + 1]; float num7 = _A[a + a_off * 3]; float num8 = _A[a + a_off * 3 + 1]; int num9 = i_off; int num10 = num9 + k_off; for (int num11 = n; num11 > 0; num11--) { float num12 = e[num9] - e[num10]; float num13 = e[num9 - 1] - e[num10 - 1]; e[num9] += e[num10]; e[num9 - 1] += e[num10 - 1]; e[num10] = num12 * num - num13 * num2; e[num10 - 1] = num13 * num + num12 * num2; num12 = e[num9 - 2] - e[num10 - 2]; num13 = e[num9 - 3] - e[num10 - 3]; e[num9 - 2] += e[num10 - 2]; e[num9 - 3] += e[num10 - 3]; e[num10 - 2] = num12 * num3 - num13 * num4; e[num10 - 3] = num13 * num3 + num12 * num4; num12 = e[num9 - 4] - e[num10 - 4]; num13 = e[num9 - 5] - e[num10 - 5]; e[num9 - 4] += e[num10 - 4]; e[num9 - 5] += e[num10 - 5]; e[num10 - 4] = num12 * num5 - num13 * num6; e[num10 - 5] = num13 * num5 + num12 * num6; num12 = e[num9 - 6] - e[num10 - 6]; num13 = e[num9 - 7] - e[num10 - 7]; e[num9 - 6] += e[num10 - 6]; e[num9 - 7] += e[num10 - 7]; e[num10 - 6] = num12 * num7 - num13 * num8; e[num10 - 7] = num13 * num7 + num12 * num8; num9 -= k0; num10 -= k0; } } private void step3_inner_s_loop_ld654(int n, float[] e, int i_off, int base_n) { int num = base_n >> 3; float num2 = _A[num]; int num3 = i_off; int num4 = num3 - 16 * n; while (num3 > num4) { float num5 = e[num3] - e[num3 - 8]; float num6 = e[num3 - 1] - e[num3 - 9]; e[num3] += e[num3 - 8]; e[num3 - 1] += e[num3 - 9]; e[num3 - 8] = num5; e[num3 - 9] = num6; num5 = e[num3 - 2] - e[num3 - 10]; num6 = e[num3 - 3] - e[num3 - 11]; e[num3 - 2] += e[num3 - 10]; e[num3 - 3] += e[num3 - 11]; e[num3 - 10] = (num5 + num6) * num2; e[num3 - 11] = (num6 - num5) * num2; num5 = e[num3 - 12] - e[num3 - 4]; num6 = e[num3 - 5] - e[num3 - 13]; e[num3 - 4] += e[num3 - 12]; e[num3 - 5] += e[num3 - 13]; e[num3 - 12] = num6; e[num3 - 13] = num5; num5 = e[num3 - 14] - e[num3 - 6]; num6 = e[num3 - 7] - e[num3 - 15]; e[num3 - 6] += e[num3 - 14]; e[num3 - 7] += e[num3 - 15]; e[num3 - 14] = (num5 + num6) * num2; e[num3 - 15] = (num5 - num6) * num2; iter_54(e, num3); iter_54(e, num3 - 8); num3 -= 16; } } private void iter_54(float[] e, int z) { float num = e[z] - e[z - 4]; float num2 = e[z] + e[z - 4]; float num3 = e[z - 2] + e[z - 6]; float num4 = e[z - 2] - e[z - 6]; e[z] = num2 + num3; e[z - 2] = num2 - num3; float num5 = e[z - 3] - e[z - 7]; e[z - 4] = num + num5; e[z - 6] = num - num5; float num6 = e[z - 1] - e[z - 5]; float num7 = e[z - 1] + e[z - 5]; float num8 = e[z - 3] + e[z - 7]; e[z - 1] = num7 + num8; e[z - 3] = num7 - num8; e[z - 5] = num6 - num4; e[z - 7] = num6 + num4; } } [Serializable] public class NewStreamEventArgs : EventArgs { public IPacketProvider PacketProvider { get; private set; } public bool IgnoreStream { get; set; } public NewStreamEventArgs(IPacketProvider packetProvider) { if (packetProvider == null) { throw new ArgumentNullException("packetProvider"); } PacketProvider = packetProvider; } } [Serializable] public class ParameterChangeEventArgs : EventArgs { public DataPacket FirstPacket { get; private set; } public ParameterChangeEventArgs(DataPacket firstPacket) { FirstPacket = firstPacket; } } internal class RingBuffer { private float[] _buffer; private int _start; private int _end; private int _bufLen; internal int Channels; internal int Length { get { int num = _end - _start; if (num < 0) { num += _bufLen; } return num; } } internal RingBuffer(int size) { _buffer = new float[size]; _start = (_end = 0); _bufLen = size; } internal void EnsureSize(int size) { size += Channels; if (_bufLen < size) { float[] array = new float[size]; Array.Copy(_buffer, _start, array, 0, _bufLen - _start); if (_end < _start) { Array.Copy(_buffer, 0, array, _bufLen - _start, _end); } int length = Length; _start = 0; _end = length; _buffer = array; _bufLen = size; } } internal void CopyTo(float[] buffer, int index, int count) { if (index < 0 || index + count > buffer.Length) { throw new ArgumentOutOfRangeException("index"); } int start = _start; RemoveItems(count); int num = (_end - start + _bufLen) % _bufLen; if (count > num) { throw new ArgumentOutOfRangeException("count"); } int num2 = Math.Min(count, _bufLen - start); Buffer.BlockCopy(_buffer, start * 4, buffer, index * 4, num2 * 4); if (num2 < count) { Buffer.BlockCopy(_buffer, 0, buffer, (index + num2) * 4, (count - num2) * 4); } } internal void RemoveItems(int count) { int num = (count + _start) % _bufLen; if (_end > _start) { if (num > _end || num < _start) { throw new ArgumentOutOfRangeException(); } } else if (num < _start && num > _end) { throw new ArgumentOutOfRangeException(); } _start = num; } internal void Clear() { _start = (_end = 0); } internal void Write(int channel, int index, int start, int switchPoint, int end, float[] pcm, float[] window) { int num; for (num = (index + start) * Channels + channel + _start; num >= _bufLen; num -= _bufLen) { } if (num < 0) { start -= index; num = channel; } while (num < _bufLen && start < switchPoint) { _buffer[num] += pcm[start] * window[start]; num += Channels; start++; } if (num >= _bufLen) { num -= _bufLen; while (start < switchPoint) { _buffer[num] += pcm[start] * window[start]; num += Channels; start++; } } while (num < _bufLen && start < end) { _buffer[num] = pcm[start] * window[start]; num += Channels; start++; } if (num >= _bufLen) { num -= _bufLen; while (start < end) { _buffer[num] = pcm[start] * window[start]; num += Channels; start++; } } _end = num; } } internal static class Utils { [StructLayout(LayoutKind.Explicit)] private struct FloatBits { [FieldOffset(0)] public float Float; [FieldOffset(0)] public uint Bits; } internal static int ilog(int x) { int num = 0; while (x > 0) { num++; x >>= 1; } return num; } internal static uint BitReverse(uint n) { return BitReverse(n, 32); } internal static uint BitReverse(uint n, int bits) { n = ((n & 0xAAAAAAAAu) >> 1) | ((n & 0x55555555) << 1); n = ((n & 0xCCCCCCCCu) >> 2) | ((n & 0x33333333) << 2); n = ((n & 0xF0F0F0F0u) >> 4) | ((n & 0xF0F0F0F) << 4); n = ((n & 0xFF00FF00u) >> 8) | ((n & 0xFF00FF) << 8); return ((n >> 16) | (n << 16)) >> 32 - bits; } internal static float ClipValue(float value, ref bool clipped) { FloatBits floatBits = default(FloatBits); floatBits.Bits = 0u; floatBits.Float = value; if ((floatBits.Bits & 0x7FFFFFFF) > 1065353215) { clipped = true; floatBits.Bits = 0x3F7FFFFF | (floatBits.Bits & 0x80000000u); } return floatBits.Float; } internal static float ConvertFromVorbisFloat32(uint bits) { int num = (int)bits >> 31; double y = (int)(((bits & 0x7FE00000) >> 21) - 788); return (float)(((bits & 0x1FFFFF) ^ num) + (num & 1)) * (float)Math.Pow(2.0, y); } internal static int Sum(Queue queue) { int num = 0; for (int i = 0; i < queue.Count; i++) { int num2 = queue.Dequeue(); num += num2; queue.Enqueue(num2); } return num; } } internal class VorbisCodebook { private class FastRange : IReadOnlyList, IReadOnlyCollection, IEnumerable, IEnumerable { [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 GetEnumerator() { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } internal int BookNum; internal int Dimensions; internal int Entries; private int[] Lengths; private float[] LookupTable; internal int MapType; private HuffmanListNode PrefixOverflowTree; private List PrefixList; private int PrefixBitLength; private int MaxBits; internal float this[int entry, int dim] => LookupTable[entry * Dimensions + dim]; internal static VorbisCodebook Init(VorbisStreamDecoder vorbis, DataPacket packet, int number) { return new VorbisCodebook(packet, number); } private VorbisCodebook(DataPacket packet, int number) { BookNum = number; if (packet.ReadBits(24) != 5653314) { throw new InvalidDataException(); } Dimensions = (int)packet.ReadBits(16); Entries = (int)packet.ReadBits(24); Lengths = new int[Entries]; InitTree(packet); InitLookupTable(packet); } private void InitTree(DataPacket packet) { int num = 0; bool flag; if (packet.ReadBit()) { int num2 = (int)packet.ReadBits(5) + 1; int num3 = 0; while (num3 < Entries) { int num4 = (int)packet.ReadBits(Utils.ilog(Entries - num3)); while (--num4 >= 0) { Lengths[num3++] = num2; } num2++; } num = 0; flag = false; } else { flag = packet.ReadBit(); for (int i = 0; i < Entries; i++) { if (!flag || packet.ReadBit()) { Lengths[i] = (int)packet.ReadBits(5) + 1; num++; } else { Lengths[i] = -1; } } } if ((MaxBits = Lengths.Max()) > -1) { int num5 = 0; int[] array = null; if (flag && num >= Entries >> 2) { array = new int[Entries]; Array.Copy(Lengths, array, Entries); flag = false; } num5 = (flag ? num : 0); int num6 = num5; int[] array2 = null; int[] array3 = null; if (!flag) { array3 = new int[Entries]; } else if (num6 != 0) { array = new int[num6]; array3 = new int[num6]; array2 = new int[num6]; } if (!ComputeCodewords(flag, num6, array3, array, Lengths, Entries, array2)) { throw new InvalidDataException(); } IReadOnlyList readOnlyList = array2; IReadOnlyList values = readOnlyList ?? FastRange.Get(0, array3.Length); PrefixList = Huffman.BuildPrefixedLinkedList(values, array ?? Lengths, array3, out PrefixBitLength, out PrefixOverflowTree); } } private bool ComputeCodewords(bool sparse, int sortedEntries, int[] codewords, int[] codewordLengths, int[] len, int n, int[] values) { int num = 0; uint[] array = new uint[32]; int i; for (i = 0; i < n && len[i] <= 0; i++) { } if (i == n) { return true; } AddEntry(sparse, codewords, codewordLengths, 0u, i, num++, len[i], values); for (int j = 1; j <= len[i]; j++) { array[j] = (uint)(1 << 32 - j); } for (int j = i + 1; j < n; j++) { int num2 = len[j]; if (num2 <= 0) { continue; } while (num2 > 0 && array[num2] == 0) { num2--; } if (num2 == 0) { return false; } uint num3 = array[num2]; array[num2] = 0u; AddEntry(sparse, codewords, codewordLengths, Utils.BitReverse(num3), j, num++, len[j], values); if (num2 != len[j]) { for (int num4 = len[j]; num4 > num2; num4--) { array[num4] = num3 + (uint)(1 << 32 - num4); } } } return true; } private void AddEntry(bool sparse, int[] codewords, int[] codewordLengths, uint huffCode, int symbol, int count, int len, int[] values) { if (sparse) { codewords[count] = (int)huffCode; codewordLengths[count] = len; values[count] = symbol; } else { codewords[symbol] = (int)huffCode; } } private void InitLookupTable(DataPacket packet) { MapType = (int)packet.ReadBits(4); if (MapType == 0) { return; } float num = Utils.ConvertFromVorbisFloat32(packet.ReadUInt32()); float num2 = Utils.ConvertFromVorbisFloat32(packet.ReadUInt32()); int count = (int)packet.ReadBits(4) + 1; bool flag = packet.ReadBit(); int num3 = Entries * Dimensions; float[] array = new float[num3]; if (MapType == 1) { num3 = lookup1_values(); } uint[] array2 = new uint[num3]; for (int i = 0; i < num3; i++) { array2[i] = (uint)packet.ReadBits(count); } if (MapType == 1) { for (int j = 0; j < Entries; j++) { double num4 = 0.0; int num5 = 1; for (int k = 0; k < Dimensions; k++) { int num6 = j / num5 % num3; double num7 = (double)((float)array2[num6] * num2 + num) + num4; array[j * Dimensions + k] = (float)num7; if (flag) { num4 = num7; } num5 *= num3; } } } else { for (int l = 0; l < Entries; l++) { double num8 = 0.0; int num9 = l * Dimensions; for (int m = 0; m < Dimensions; m++) { double num10 = (double)((float)array2[num9] * num2 + num) + num8; array[l * Dimensions + m] = (float)num10; if (flag) { num8 = num10; } num9++; } } } LookupTable = array; } private int lookup1_values() { int num = (int)Math.Floor(Math.Exp(Math.Log(Entries) / (double)Dimensions)); if (Math.Floor(Math.Pow(num + 1, Dimensions)) <= (double)Entries) { num++; } return num; } internal int DecodeScalar(DataPacket packet) { int index = (int)packet.TryPeekBits(PrefixBitLength, out var bitsRead); if (bitsRead == 0) { return -1; } HuffmanListNode huffmanListNode = PrefixList[index]; if (huffmanListNode != null) { packet.SkipBits(huffmanListNode.Length); return huffmanListNode.Value; } index = (int)packet.TryPeekBits(MaxBits, out bitsRead); huffmanListNode = PrefixOverflowTree; do { if (huffmanListNode.Bits == (index & huffmanListNode.Mask)) { packet.SkipBits(huffmanListNode.Length); return huffmanListNode.Value; } } while ((huffmanListNode = huffmanListNode.Next) != null); return -1; } } internal abstract class VorbisFloor { internal abstract class PacketData { internal int BlockSize; protected abstract bool HasEnergy { get; } internal bool ForceEnergy { get; set; } internal bool ForceNoEnergy { get; set; } internal bool ExecuteChannel => (ForceEnergy | HasEnergy) & !ForceNoEnergy; } private class Floor0 : VorbisFloor { private class PacketData0 : PacketData { internal float[] Coeff; internal float Amp; protected override bool HasEnergy => Amp > 0f; } private int _order; private int _rate; private int _bark_map_size; private int _ampBits; private int _ampOfs; private int _ampDiv; private VorbisCodebook[] _books; private int _bookBits; private Dictionary _wMap; private Dictionary _barkMaps; private PacketData0[] _reusablePacketData; internal Floor0(VorbisStreamDecoder vorbis) : base(vorbis) { } protected override void Init(DataPacket packet) { _order = (int)packet.ReadBits(8); _rate = (int)packet.ReadBits(16); _bark_map_size = (int)packet.ReadBits(16); _ampBits = (int)packet.ReadBits(6); _ampOfs = (int)packet.ReadBits(8); _books = new VorbisCodebook[(int)packet.ReadBits(4) + 1]; if (_order < 1 || _rate < 1 || _bark_map_size < 1 || _books.Length == 0) { throw new InvalidDataException(); } _ampDiv = (1 << _ampBits) - 1; for (int i = 0; i < _books.Length; i++) { int num = (int)packet.ReadBits(8); if (num < 0 || num >= _vorbis.Books.Length) { throw new InvalidDataException(); } VorbisCodebook vorbisCodebook = _vorbis.Books[num]; if (vorbisCodebook.MapType == 0 || vorbisCodebook.Dimensions < 1) { throw new InvalidDataException(); } _books[i] = vorbisCodebook; } _bookBits = Utils.ilog(_books.Length); _barkMaps = new Dictionary(); _barkMaps[_vorbis.Block0Size] = SynthesizeBarkCurve(_vorbis.Block0Size / 2); _barkMaps[_vorbis.Block1Size] = SynthesizeBarkCurve(_vorbis.Block1Size / 2); _wMap = new Dictionary(); _wMap[_vorbis.Block0Size] = SynthesizeWDelMap(_vorbis.Block0Size / 2); _wMap[_vorbis.Block1Size] = SynthesizeWDelMap(_vorbis.Block1Size / 2); _reusablePacketData = new PacketData0[_vorbis._channels]; for (int j = 0; j < _reusablePacketData.Length; j++) { _reusablePacketData[j] = new PacketData0 { Coeff = new float[_order + 1] }; } } private int[] SynthesizeBarkCurve(int n) { float num = (float)_bark_map_size / toBARK(_rate / 2); int[] array = new int[n + 1]; for (int i = 0; i < n - 1; i++) { array[i] = Math.Min(_bark_map_size - 1, (int)Math.Floor(toBARK((float)_rate / 2f / (float)n * (float)i) * num)); } array[n] = -1; return array; } private static float toBARK(double lsp) { return (float)(13.1 * Math.Atan(0.00074 * lsp) + 2.24 * Math.Atan(1.85E-08 * lsp * lsp) + 0.0001 * lsp); } private float[] SynthesizeWDelMap(int n) { float num = (float)(Math.PI / (double)_bark_map_size); float[] array = new float[n]; for (int i = 0; i < n; i++) { array[i] = 2f * (float)Math.Cos(num * (float)i); } return array; } internal override PacketData UnpackPacket(DataPacket packet, int blockSize, int channel) { PacketData0 packetData = _reusablePacketData[channel]; packetData.BlockSize = blockSize; packetData.ForceEnergy = false; packetData.ForceNoEnergy = false; packetData.Amp = packet.ReadBits(_ampBits); if (packetData.Amp > 0f) { Array.Clear(packetData.Coeff, 0, packetData.Coeff.Length); packetData.Amp = packetData.Amp / (float)_ampDiv * (float)_ampOfs; uint num = (uint)packet.ReadBits(_bookBits); if (num >= _books.Length) { packetData.Amp = 0f; return packetData; } VorbisCodebook vorbisCodebook = _books[num]; int i = 0; while (i < _order) { int num2 = vorbisCodebook.DecodeScalar(packet); if (num2 == -1) { packetData.Amp = 0f; return packetData; } int num3 = 0; for (; i < _order; i++) { if (num3 >= vorbisCodebook.Dimensions) { break; } packetData.Coeff[i] = vorbisCodebook[num2, num3]; num3++; } } float num4 = 0f; int num5 = 0; while (num5 < _order) { int num6 = 0; while (num5 < _order && num6 < vorbisCodebook.Dimensions) { packetData.Coeff[num5] += num4; num5++; num6++; } num4 = packetData.Coeff[num5 - 1]; } } return packetData; } internal override void Apply(PacketData packetData, float[] residue) { if (!(packetData is PacketData0 packetData2)) { throw new ArgumentException("Incorrect packet data!"); } int num = packetData2.BlockSize / 2; if (packetData2.Amp > 0f) { int[] array = _barkMaps[packetData2.BlockSize]; float[] array2 = _wMap[packetData2.BlockSize]; int num2 = 0; for (num2 = 0; num2 < _order; num2++) { packetData2.Coeff[num2] = 2f * (float)Math.Cos(packetData2.Coeff[num2]); } num2 = 0; while (num2 < num) { int num3 = array[num2]; float num4 = 0.5f; float num5 = 0.5f; float num6 = array2[num3]; int i; for (i = 1; i < _order; i += 2) { num5 *= num6 - packetData2.Coeff[i - 1]; num4 *= num6 - packetData2.Coeff[i]; } if (i == _order) { num5 *= num6 - packetData2.Coeff[i - 1]; num4 *= num4 * (4f - num6 * num6); num5 *= num5; } else { num4 *= num4 * (2f - num6); num5 *= num5 * (2f + num6); } num5 = packetData2.Amp / (float)Math.Sqrt(num4 + num5) - (float)_ampOfs; num5 = (float)Math.Exp(num5 * 0.11512925f); residue[num2] *= num5; while (array[++num2] == num3) { residue[num2] *= num5; } } } else { Array.Clear(residue, 0, num); } } } private class Floor1 : VorbisFloor { private class PacketData1 : PacketData { public int[] Posts = new int[64]; public int PostCount; protected override bool HasEnergy => PostCount > 0; } private int[] _partitionClass; private int[] _classDimensions; private int[] _classSubclasses; private int[] _xList; private int[] _classMasterBookIndex; private int[] _hNeigh; private int[] _lNeigh; private int[] _sortIdx; private int _multiplier; private int _range; private int _yBits; private VorbisCodebook[] _classMasterbooks; private VorbisCodebook[][] _subclassBooks; private int[][] _subclassBookIndex; private static int[] _rangeLookup = new int[4] { 256, 128, 86, 64 }; private static int[] _yBitsLookup = new int[4] { 8, 7, 7, 6 }; private PacketData1[] _reusablePacketData; private bool[] _stepFlags = new bool[64]; private int[] _finalY = new int[64]; private static readonly float[] inverse_dB_table = new float[256] { 1.0649863E-07f, 1.1341951E-07f, 1.2079015E-07f, 1.2863978E-07f, 1.369995E-07f, 1.459025E-07f, 1.5538409E-07f, 1.6548181E-07f, 1.7623574E-07f, 1.8768856E-07f, 1.998856E-07f, 2.128753E-07f, 2.2670913E-07f, 2.4144197E-07f, 2.5713223E-07f, 2.7384212E-07f, 2.9163792E-07f, 3.1059022E-07f, 3.307741E-07f, 3.5226967E-07f, 3.7516213E-07f, 3.995423E-07f, 4.255068E-07f, 4.5315863E-07f, 4.8260745E-07f, 5.1397E-07f, 5.4737063E-07f, 5.829419E-07f, 6.208247E-07f, 6.611694E-07f, 7.041359E-07f, 7.4989464E-07f, 7.98627E-07f, 8.505263E-07f, 9.057983E-07f, 9.646621E-07f, 1.0273513E-06f, 1.0941144E-06f, 1.1652161E-06f, 1.2409384E-06f, 1.3215816E-06f, 1.4074654E-06f, 1.4989305E-06f, 1.5963394E-06f, 1.7000785E-06f, 1.8105592E-06f, 1.9282195E-06f, 2.053526E-06f, 2.1869757E-06f, 2.3290977E-06f, 2.4804558E-06f, 2.6416496E-06f, 2.813319E-06f, 2.9961443E-06f, 3.1908505E-06f, 3.39821E-06f, 3.619045E-06f, 3.8542307E-06f, 4.1047006E-06f, 4.371447E-06f, 4.6555283E-06f, 4.958071E-06f, 5.280274E-06f, 5.623416E-06f, 5.988857E-06f, 6.3780467E-06f, 6.7925284E-06f, 7.2339453E-06f, 7.704048E-06f, 8.2047E-06f, 8.737888E-06f, 9.305725E-06f, 9.910464E-06f, 1.0554501E-05f, 1.1240392E-05f, 1.1970856E-05f, 1.2748789E-05f, 1.3577278E-05f, 1.4459606E-05f, 1.5399271E-05f, 1.6400005E-05f, 1.7465769E-05f, 1.8600793E-05f, 1.9809577E-05f, 2.1096914E-05f, 2.2467912E-05f, 2.3928002E-05f, 2.5482977E-05f, 2.7139005E-05f, 2.890265E-05f, 3.078091E-05f, 3.2781227E-05f, 3.4911533E-05f, 3.718028E-05f, 3.9596467E-05f, 4.2169668E-05f, 4.491009E-05f, 4.7828602E-05f, 5.0936775E-05f, 5.424693E-05f, 5.7772202E-05f, 6.152657E-05f, 6.552491E-05f, 6.9783084E-05f, 7.4317984E-05f, 7.914758E-05f, 8.429104E-05f, 8.976875E-05f, 9.560242E-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f, 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f, 0.00015820454f, 0.00016848555f, 0.00017943469f, 0.00019109536f, 0.00020351382f, 0.0002167393f, 0.00023082423f, 0.00024582449f, 0.00026179955f, 0.00027881275f, 0.00029693157f, 0.00031622787f, 0.00033677815f, 0.00035866388f, 0.00038197188f, 0.00040679457f, 0.00043323037f, 0.0004613841f, 0.0004913675f, 0.00052329927f, 0.0005573062f, 0.0005935231f, 0.0006320936f, 0.0006731706f, 0.000716917f, 0.0007635063f, 0.00081312325f, 0.00086596457f, 0.00092223985f, 0.0009821722f, 0.0010459992f, 0.0011139743f, 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f, 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f, 0.0019632196f, 0.0020908006f, 0.0022266726f, 0.0023713743f, 0.0025254795f, 0.0026895993f, 0.0028643848f, 0.0030505287f, 0.003248769f, 0.0034598925f, 0.0036847359f, 0.0039241905f, 0.0041792067f, 0.004450795f, 0.004740033f, 0.005048067f, 0.0053761187f, 0.005725489f, 0.0060975635f, 0.0064938175f, 0.0069158226f, 0.0073652514f, 0.007843887f, 0.008353627f, 0.008896492f, 0.009474637f, 0.010090352f, 0.01074608f, 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f, 0.014722068f, 0.015678791f, 0.016697686f, 0.017782796f, 0.018938422f, 0.020169148f, 0.021479854f, 0.022875736f, 0.02436233f, 0.025945531f, 0.027631618f, 0.029427277f, 0.031339627f, 0.03337625f, 0.035545226f, 0.037855156f, 0.0403152f, 0.042935107f, 0.045725275f, 0.048696756f, 0.05186135f, 0.05523159f, 0.05882085f, 0.062643364f, 0.06671428f, 0.07104975f, 0.075666964f, 0.08058423f, 0.08582105f, 0.09139818f, 0.097337745f, 0.1036633f, 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f, 0.14201812f, 0.15124726f, 0.16107617f, 0.1715438f, 0.18269168f, 0.19456401f, 0.20720787f, 0.22067343f, 0.23501402f, 0.25028655f, 0.26655158f, 0.28387362f, 0.3023213f, 0.32196787f, 0.34289113f, 0.36517414f, 0.3889052f, 0.41417846f, 0.44109413f, 0.4697589f, 0.50028646f, 0.53279793f, 0.5674221f, 0.6042964f, 0.64356697f, 0.6853896f, 0.72993004f, 0.777365f, 0.8278826f, 0.88168305f, 0.9389798f, 1f }; internal Floor1(VorbisStreamDecoder vorbis) : base(vorbis) { } protected override void Init(DataPacket packet) { _partitionClass = new int[(uint)packet.ReadBits(5)]; for (int i = 0; i < _partitionClass.Length; i++) { _partitionClass[i] = (int)packet.ReadBits(4); } int num = _partitionClass.Max(); _classDimensions = new int[num + 1]; _classSubclasses = new int[num + 1]; _classMasterbooks = new VorbisCodebook[num + 1]; _classMasterBookIndex = new int[num + 1]; _subclassBooks = new VorbisCodebook[num + 1][]; _subclassBookIndex = new int[num + 1][]; for (int j = 0; j <= num; j++) { _classDimensions[j] = (int)packet.ReadBits(3) + 1; _classSubclasses[j] = (int)packet.ReadBits(2); if (_classSubclasses[j] > 0) { _classMasterBookIndex[j] = (int)packet.ReadBits(8); _classMasterbooks[j] = _vorbis.Books[_classMasterBookIndex[j]]; } _subclassBooks[j] = new VorbisCodebook[1 << _classSubclasses[j]]; _subclassBookIndex[j] = new int[_subclassBooks[j].Length]; for (int k = 0; k < _subclassBooks[j].Length; k++) { int num2 = (int)packet.ReadBits(8) - 1; if (num2 >= 0) { _subclassBooks[j][k] = _vorbis.Books[num2]; } _subclassBookIndex[j][k] = num2; } } _multiplier = (int)packet.ReadBits(2); _range = _rangeLookup[_multiplier]; _yBits = _yBitsLookup[_multiplier]; _multiplier++; int num3 = (int)packet.ReadBits(4); List list = new List(); list.Add(0); list.Add(1 << num3); for (int l = 0; l < _partitionClass.Length; l++) { int num4 = _partitionClass[l]; for (int m = 0; m < _classDimensions[num4]; m++) { list.Add((int)packet.ReadBits(num3)); } } _xList = list.ToArray(); _lNeigh = new int[list.Count]; _hNeigh = new int[list.Count]; _sortIdx = new int[list.Count]; _sortIdx[0] = 0; _sortIdx[1] = 1; for (int n = 2; n < _lNeigh.Length; n++) { _lNeigh[n] = 0; _hNeigh[n] = 1; _sortIdx[n] = n; for (int num5 = 2; num5 < n; num5++) { int num6 = _xList[num5]; if (num6 < _xList[n]) { if (num6 > _xList[_lNeigh[n]]) { _lNeigh[n] = num5; } } else if (num6 < _xList[_hNeigh[n]]) { _hNeigh[n] = num5; } } } for (int num7 = 0; num7 < _sortIdx.Length - 1; num7++) { for (int num8 = num7 + 1; num8 < _sortIdx.Length; num8++) { if (_xList[num7] == _xList[num8]) { throw new InvalidDataException(); } if (_xList[_sortIdx[num7]] > _xList[_sortIdx[num8]]) { int num9 = _sortIdx[num7]; _sortIdx[num7] = _sortIdx[num8]; _sortIdx[num8] = num9; } } } _reusablePacketData = new PacketData1[_vorbis._channels]; for (int num10 = 0; num10 < _reusablePacketData.Length; num10++) { _reusablePacketData[num10] = new PacketData1(); } } internal override PacketData UnpackPacket(DataPacket packet, int blockSize, int channel) { PacketData1 packetData = _reusablePacketData[channel]; packetData.BlockSize = blockSize; packetData.ForceEnergy = false; packetData.ForceNoEnergy = false; packetData.PostCount = 0; Array.Clear(packetData.Posts, 0, 64); if (packet.ReadBit()) { int num = 2; packetData.Posts[0] = (int)packet.ReadBits(_yBits); packetData.Posts[1] = (int)packet.ReadBits(_yBits); for (int i = 0; i < _partitionClass.Length; i++) { int num2 = _partitionClass[i]; int num3 = _classDimensions[num2]; int num4 = _classSubclasses[num2]; int num5 = (1 << num4) - 1; uint num6 = 0u; if (num4 > 0 && (num6 = (uint)_classMasterbooks[num2].DecodeScalar(packet)) == uint.MaxValue) { num = 0; break; } for (int j = 0; j < num3; j++) { VorbisCodebook vorbisCodebook = _subclassBooks[num2][num6 & num5]; num6 >>= num4; if (vorbisCodebook != null && (packetData.Posts[num] = vorbisCodebook.DecodeScalar(packet)) == -1) { num = 0; i = _partitionClass.Length; break; } num++; } } packetData.PostCount = num; } return packetData; } internal override void Apply(PacketData packetData, float[] residue) { if (!(packetData is PacketData1 packetData2)) { throw new ArgumentException("Incorrect packet data!", "packetData"); } int num = packetData2.BlockSize / 2; if (packetData2.PostCount > 0) { bool[] array = UnwrapPosts(packetData2); int num2 = 0; int num3 = packetData2.Posts[0] * _multiplier; for (int i = 1; i < packetData2.PostCount; i++) { int num4 = _sortIdx[i]; if (array[num4]) { int num5 = _xList[num4]; int num6 = packetData2.Posts[num4] * _multiplier; if (num2 < num) { RenderLineMulti(num2, num3, Math.Min(num5, num), num6, residue); } num2 = num5; num3 = num6; } if (num2 >= num) { break; } } if (num2 < num) { RenderLineMulti(num2, num3, num, num3, residue); } } else { Array.Clear(residue, 0, num); } } private bool[] UnwrapPosts(PacketData1 data) { Array.Clear(_stepFlags, 2, 62); _stepFlags[0] = true; _stepFlags[1] = true; Array.Clear(_finalY, 2, 62); _finalY[0] = data.Posts[0]; _finalY[1] = data.Posts[1]; for (int i = 2; i < data.PostCount; i++) { int num = _lNeigh[i]; int num2 = _hNeigh[i]; int num3 = RenderPoint(_xList[num], _finalY[num], _xList[num2], _finalY[num2], _xList[i]); int num4 = data.Posts[i]; int num5 = _range - num3; int num6 = num3; int num7 = ((num5 >= num6) ? (num6 * 2) : (num5 * 2)); if (num4 != 0) { _stepFlags[num] = true; _stepFlags[num2] = true; _stepFlags[i] = true; if (num4 >= num7) { if (num5 > num6) { _finalY[i] = num4 - num6 + num3; } else { _finalY[i] = num3 - num4 + num5 - 1; } } else if (num4 % 2 == 1) { _finalY[i] = num3 - (num4 + 1) / 2; } else { _finalY[i] = num3 + num4 / 2; } } else { _stepFlags[i] = false; _finalY[i] = num3; } } for (int j = 0; j < data.PostCount; j++) { data.Posts[j] = _finalY[j]; } return _stepFlags; } private int RenderPoint(int x0, int y0, int x1, int y1, int X) { int num = y1 - y0; int num2 = x1 - x0; int num3 = Math.Abs(num) * (X - x0) / num2; if (num < 0) { return y0 - num3; } return y0 + num3; } private void RenderLineMulti(int x0, int y0, int x1, int y1, float[] v) { int num = y1 - y0; int num2 = x1 - x0; int num3 = Math.Abs(num); int num4 = 1 - ((num >> 31) & 1) * 2; int num5 = num / num2; int num6 = x0; int num7 = y0; int num8 = -num2; v[x0] *= inverse_dB_table[y0]; num3 -= Math.Abs(num5) * num2; while (++num6 < x1) { num7 += num5; num8 += num3; if (num8 >= 0) { num8 -= num2; num7 += num4; } v[num6] *= inverse_dB_table[num7]; } } } private VorbisStreamDecoder _vorbis; internal static VorbisFloor Init(VorbisStreamDecoder vorbis, DataPacket packet) { int num = (int)packet.ReadBits(16); VorbisFloor vorbisFloor = null; switch (num) { case 0: vorbisFloor = new Floor0(vorbis); break; case 1: vorbisFloor = new Floor1(vorbis); break; } if (vorbisFloor == null) { throw new InvalidDataException(); } vorbisFloor.Init(packet); return vorbisFloor; } protected VorbisFloor(VorbisStreamDecoder vorbis) { _vorbis = vorbis; } protected abstract void Init(DataPacket packet); internal abstract PacketData UnpackPacket(DataPacket packet, int blockSize, int channel); internal abstract void Apply(PacketData packetData, float[] residue); } internal abstract class VorbisMapping { private class Mapping0 : VorbisMapping { internal Mapping0(VorbisStreamDecoder vorbis) : base(vorbis) { } protected override void Init(DataPacket packet) { int num = 1; if (packet.ReadBit()) { num += (int)packet.ReadBits(4); } int num2 = 0; if (packet.ReadBit()) { num2 = (int)packet.ReadBits(8) + 1; } int count = Utils.ilog(_vorbis._channels - 1); CouplingSteps = new CouplingStep[num2]; for (int i = 0; i < num2; i++) { int num3 = (int)packet.ReadBits(count); int num4 = (int)packet.ReadBits(count); if (num3 == num4 || num3 > _vorbis._channels - 1 || num4 > _vorbis._channels - 1) { throw new InvalidDataException(); } CouplingSteps[i] = new CouplingStep { Angle = num4, Magnitude = num3 }; } if (packet.ReadBits(2) != 0L) { throw new InvalidDataException(); } int[] array = new int[_vorbis._channels]; if (num > 1) { for (int j = 0; j < ChannelSubmap.Length; j++) { array[j] = (int)packet.ReadBits(4); if (array[j] >= num) { throw new InvalidDataException(); } } } Submaps = new Submap[num]; for (int k = 0; k < num; k++) { packet.ReadBits(8); int num5 = (int)packet.ReadBits(8); if (num5 >= _vorbis.Floors.Length) { throw new InvalidDataException(); } if ((int)packet.ReadBits(8) >= _vorbis.Residues.Length) { throw new InvalidDataException(); } Submaps[k] = new Submap { Floor = _vorbis.Floors[num5], Residue = _vorbis.Residues[num5] }; } ChannelSubmap = new Submap[_vorbis._channels]; for (int l = 0; l < ChannelSubmap.Length; l++) { ChannelSubmap[l] = Submaps[array[l]]; } } } internal class Submap { internal VorbisFloor Floor; internal VorbisResidue Residue; internal Submap() { } } internal class CouplingStep { internal int Magnitude; internal int Angle; internal CouplingStep() { } } private VorbisStreamDecoder _vorbis; internal Submap[] Submaps; internal Submap[] ChannelSubmap; internal CouplingStep[] CouplingSteps; internal static VorbisMapping Init(VorbisStreamDecoder vorbis, DataPacket packet) { int num = (int)packet.ReadBits(16); VorbisMapping vorbisMapping = null; if (num == 0) { vorbisMapping = new Mapping0(vorbis); } if (vorbisMapping == null) { throw new InvalidDataException(); } vorbisMapping.Init(packet); return vorbisMapping; } protected VorbisMapping(VorbisStreamDecoder vorbis) { _vorbis = vorbis; } protected abstract void Init(DataPacket packet); } internal class VorbisMode { private const float M_PI = (float)Math.PI; private const float M_PI2 = (float)Math.PI / 2f; private VorbisStreamDecoder _vorbis; private float[][] _windows; internal bool BlockFlag; internal int WindowType; internal int TransformType; internal VorbisMapping Mapping; internal int BlockSize; internal static VorbisMode Init(VorbisStreamDecoder vorbis, DataPacket packet) { VorbisMode vorbisMode = new VorbisMode(vorbis); vorbisMode.BlockFlag = packet.ReadBit(); vorbisMode.WindowType = (int)packet.ReadBits(16); vorbisMode.TransformType = (int)packet.ReadBits(16); int num = (int)packet.ReadBits(8); if (vorbisMode.WindowType != 0 || vorbisMode.TransformType != 0 || num >= vorbis.Maps.Length) { throw new InvalidDataException(); } vorbisMode.Mapping = vorbis.Maps[num]; vorbisMode.BlockSize = (vorbisMode.BlockFlag ? vorbis.Block1Size : vorbis.Block0Size); if (vorbisMode.BlockFlag) { vorbisMode._windows = new float[4][]; vorbisMode._windows[0] = new float[vorbis.Block1Size]; vorbisMode._windows[1] = new float[vorbis.Block1Size]; vorbisMode._windows[2] = new float[vorbis.Block1Size]; vorbisMode._windows[3] = new float[vorbis.Block1Size]; } else { vorbisMode._windows = new float[1][]; vorbisMode._windows[0] = new float[vorbis.Block0Size]; } vorbisMode.CalcWindows(); return vorbisMode; } private VorbisMode(VorbisStreamDecoder vorbis) { _vorbis = vorbis; } private void CalcWindows() { for (int i = 0; i < _windows.Length; i++) { float[] array = _windows[i]; int num = (((i & 1) == 0) ? _vorbis.Block0Size : _vorbis.Block1Size) / 2; int blockSize = BlockSize; int num2 = (((i & 2) == 0) ? _vorbis.Block0Size : _vorbis.Block1Size) / 2; int num3 = blockSize / 4 - num / 2; int num4 = blockSize - blockSize / 4 - num2 / 2; for (int j = 0; j < num; j++) { float num5 = (float)Math.Sin(((double)j + 0.5) / (double)num * 1.5707963705062866); num5 *= num5; array[num3 + j] = (float)Math.Sin(num5 * ((float)Math.PI / 2f)); } for (int k = num3 + num; k < num4; k++) { array[k] = 1f; } for (int l = 0; l < num2; l++) { float num6 = (float)Math.Sin(((double)(num2 - l) - 0.5) / (double)num2 * 1.5707963705062866); num6 *= num6; array[num4 + l] = (float)Math.Sin(num6 * ((float)Math.PI / 2f)); } } } internal float[] GetWindow(bool prev, bool next) { if (BlockFlag) { if (next) { if (prev) { return _windows[3]; } return _windows[2]; } if (prev) { return _windows[1]; } } return _windows[0]; } } public class VorbisReader : IDisposable { private int _streamIdx; private IContainerReader _containerReader; private List _decoders; private List _serials; private VorbisStreamDecoder ActiveDecoder { get { if (_decoders == null) { throw new ObjectDisposedException("VorbisReader"); } return _decoders[_streamIdx]; } } public int Channels => ActiveDecoder._channels; public int SampleRate => ActiveDecoder._sampleRate; public int UpperBitrate => ActiveDecoder._upperBitrate; public int NominalBitrate => ActiveDecoder._nominalBitrate; public int LowerBitrate => ActiveDecoder._lowerBitrate; public string Vendor => ActiveDecoder._vendor; public string[] Comments => ActiveDecoder._comments; public bool IsParameterChange => ActiveDecoder.IsParameterChange; public long ContainerOverheadBits => ActiveDecoder.ContainerBits; public bool ClipSamples { get; set; } public IVorbisStreamStatus[] Stats => _decoders.Select((VorbisStreamDecoder d) => d).Cast().ToArray(); public int StreamIndex => _streamIdx; public int StreamCount => _decoders.Count; public TimeSpan DecodedTime { get { return TimeSpan.FromSeconds((double)ActiveDecoder.CurrentPosition / (double)SampleRate); } set { ActiveDecoder.SeekTo((long)(value.TotalSeconds * (double)SampleRate)); } } public long DecodedPosition { get { return ActiveDecoder.CurrentPosition; } set { ActiveDecoder.SeekTo(value); } } public TimeSpan TotalTime { get { VorbisStreamDecoder activeDecoder = ActiveDecoder; if (activeDecoder.CanSeek) { return TimeSpan.FromSeconds((double)activeDecoder.GetLastGranulePos() / (double)activeDecoder._sampleRate); } return TimeSpan.MaxValue; } } public long TotalSamples { get { VorbisStreamDecoder activeDecoder = ActiveDecoder; if (activeDecoder.CanSeek) { return activeDecoder.GetLastGranulePos(); } return long.MaxValue; } } private VorbisReader() { ClipSamples = true; _decoders = new List(); _serials = new List(); } public VorbisReader(string fileName) : this(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read), closeStreamOnDispose: true) { } public VorbisReader(Stream stream, bool closeStreamOnDispose) : this() { ContainerReader containerReader = new ContainerReader(stream, closeStreamOnDispose); if (!LoadContainer(containerReader)) { if (closeStreamOnDispose) { stream.Close(); } throw new InvalidDataException("Could not determine container type!"); } _containerReader = containerReader; if (_decoders.Count == 0) { throw new InvalidDataException("No Vorbis data found!"); } } public VorbisReader(IContainerReader containerReader) : this() { if (!LoadContainer(containerReader)) { throw new InvalidDataException("Container did not initialize!"); } _containerReader = containerReader; if (_decoders.Count == 0) { throw new InvalidDataException("No Vorbis data found!"); } } public VorbisReader(IPacketProvider packetProvider) : this() { NewStreamEventArgs e = new NewStreamEventArgs(packetProvider); NewStream(this, e); if (e.IgnoreStream) { throw new InvalidDataException("No Vorbis data found!"); } } private bool LoadContainer(IContainerReader containerReader) { containerReader.NewStream += NewStream; if (!containerReader.Init()) { containerReader.NewStream -= NewStream; return false; } return true; } private void NewStream(object sender, NewStreamEventArgs ea) { IPacketProvider packetProvider = ea.PacketProvider; VorbisStreamDecoder vorbisStreamDecoder = new VorbisStreamDecoder(packetProvider); if (vorbisStreamDecoder.TryInit()) { _decoders.Add(vorbisStreamDecoder); _serials.Add(packetProvider.StreamSerial); } else { ea.IgnoreStream = true; } } public void Dispose() { if (_decoders != null) { foreach (VorbisStreamDecoder decoder in _decoders) { decoder.Dispose(); } _decoders.Clear(); _decoders = null; } if (_containerReader != null) { _containerReader.NewStream -= NewStream; _containerReader.Dispose(); _containerReader = null; } } public int ReadSamples(float[] buffer, int offset, int count) { if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0 || offset + count > buffer.Length) { throw new ArgumentOutOfRangeException("count"); } count = ActiveDecoder.ReadSamples(buffer, offset, count); if (ClipSamples) { VorbisStreamDecoder vorbisStreamDecoder = _decoders[_streamIdx]; int num = 0; while (num < count) { buffer[offset] = Utils.ClipValue(buffer[offset], ref vorbisStreamDecoder._clipped); num++; offset++; } } return count; } public void ClearParameterChange() { ActiveDecoder.IsParameterChange = false; } public bool FindNextStream() { if (_containerReader == null) { return false; } return _containerReader.FindNextStream(); } public bool SwitchStreams(int index) { if (index < 0 || index >= StreamCount) { throw new ArgumentOutOfRangeException("index"); } if (_decoders == null) { throw new ObjectDisposedException("VorbisReader"); } if (_streamIdx == index) { return false; } VorbisStreamDecoder vorbisStreamDecoder = _decoders[_streamIdx]; _streamIdx = index; VorbisStreamDecoder vorbisStreamDecoder2 = _decoders[_streamIdx]; if (vorbisStreamDecoder._channels == vorbisStreamDecoder2._channels) { return vorbisStreamDecoder._sampleRate != vorbisStreamDecoder2._sampleRate; } return true; } } internal abstract class VorbisResidue { private class Residue0 : VorbisResidue { private int _begin; private int _end; private int _partitionSize; private int _classifications; private int _maxStages; private VorbisCodebook[][] _books; private VorbisCodebook _classBook; private int[] _cascade; private int[] _entryCache; private int[][] _decodeMap; private int[][][] _partWordCache; internal Residue0(VorbisStreamDecoder vorbis) : base(vorbis) { } protected override void Init(DataPacket packet) { _begin = (int)packet.ReadBits(24); _end = (int)packet.ReadBits(24); _partitionSize = (int)packet.ReadBits(24) + 1; _classifications = (int)packet.ReadBits(6) + 1; _classBook = _vorbis.Books[(uint)packet.ReadBits(8)]; _cascade = new int[_classifications]; int num = 0; for (int i = 0; i < _classifications; i++) { int num2 = (int)packet.ReadBits(3); if (packet.ReadBit()) { _cascade[i] = ((int)packet.ReadBits(5) << 3) | num2; } else { _cascade[i] = num2; } num += icount(_cascade[i]); } int[] array = new int[num]; for (int j = 0; j < num; j++) { array[j] = (int)packet.ReadBits(8); if (_vorbis.Books[array[j]].MapType == 0) { throw new InvalidDataException(); } } int entries = _classBook.Entries; int num3 = _classBook.Dimensions; int num4 = 1; while (num3 > 0) { num4 *= _classifications; if (num4 > entries) { throw new InvalidDataException(); } num3--; } num3 = _classBook.Dimensions; _books = new VorbisCodebook[_classifications][]; num = 0; int num5 = 0; for (int k = 0; k < _classifications; k++) { int num6 = Utils.ilog(_cascade[k]); _books[k] = new VorbisCodebook[num6]; if (num6 <= 0) { continue; } num5 = Math.Max(num5, num6); for (int l = 0; l < num6; l++) { if ((_cascade[k] & (1 << l)) > 0) { _books[k][l] = _vorbis.Books[array[num++]]; } } } _maxStages = num5; _decodeMap = new int[num4][]; for (int m = 0; m < num4; m++) { int num7 = m; int num8 = num4 / _classifications; _decodeMap[m] = new int[_classBook.Dimensions]; for (int n = 0; n < _classBook.Dimensions; n++) { int num9 = num7 / num8; num7 -= num9 * num8; num8 /= _classifications; _decodeMap[m][n] = num9; } } _entryCache = new int[_partitionSize]; _partWordCache = new int[_vorbis._channels][][]; int num10 = ((_end - _begin) / _partitionSize + _classBook.Dimensions - 1) / _classBook.Dimensions; for (int num11 = 0; num11 < _vorbis._channels; num11++) { _partWordCache[num11] = new int[num10][]; } } internal override float[][] Decode(DataPacket packet, bool[] doNotDecode, int channels, int blockSize) { float[][] residueBuffer = GetResidueBuffer(doNotDecode.Length); int num = ((_end < blockSize / 2) ? _end : (blockSize / 2)) - _begin; if (num > 0 && doNotDecode.Contains(value: false)) { int num2 = num / _partitionSize; int length = (num2 + _classBook.Dimensions - 1) / _classBook.Dimensions; for (int i = 0; i < channels; i++) { Array.Clear(_partWordCache[i], 0, length); } for (int j = 0; j < _maxStages; j++) { int k = 0; int num3 = 0; while (k < num2) { if (j == 0) { for (int l = 0; l < channels; l++) { int num4 = _classBook.DecodeScalar(packet); if (num4 >= 0 && num4 < _decodeMap.Length) { _partWordCache[l][num3] = _decodeMap[num4]; continue; } k = num2; j = _maxStages; break; } } int num5 = 0; for (; k < num2; k++) { if (num5 >= _classBook.Dimensions) { break; } int offset = _begin + k * _partitionSize; for (int m = 0; m < channels; m++) { int num6 = _partWordCache[m][num3][num5]; if ((_cascade[num6] & (1 << j)) != 0) { VorbisCodebook vorbisCodebook = _books[num6][j]; if (vorbisCodebook != null && WriteVectors(vorbisCodebook, packet, residueBuffer, m, offset, _partitionSize)) { k = num2; j = _maxStages; break; } } } num5++; } num3++; } } } return residueBuffer; } protected virtual bool WriteVectors(VorbisCodebook codebook, DataPacket packet, float[][] residue, int channel, int offset, int partitionSize) { float[] array = residue[channel]; int num = partitionSize / codebook.Dimensions; for (int i = 0; i < num; i++) { if ((_entryCache[i] = codebook.DecodeScalar(packet)) == -1) { return true; } } for (int j = 0; j < codebook.Dimensions; j++) { int num2 = 0; while (num2 < num) { array[offset] += codebook[_entryCache[num2], j]; num2++; offset++; } } return false; } } private class Residue1 : Residue0 { internal Residue1(VorbisStreamDecoder vorbis) : base(vorbis) { } protected override bool WriteVectors(VorbisCodebook codebook, DataPacket packet, float[][] residue, int channel, int offset, int partitionSize) { float[] array = residue[channel]; int num = 0; while (num < partitionSize) { int num2 = codebook.DecodeScalar(packet); if (num2 == -1) { return true; } for (int i = 0; i < codebook.Dimensions; i++) { array[offset + num] += codebook[num2, i]; num++; } } return false; } } private class Residue2 : Residue0 { private int _channels; internal Residue2(VorbisStreamDecoder vorbis) : base(vorbis) { } internal override float[][] Decode(DataPacket packet, bool[] doNotDecode, int channels, int blockSize) { _channels = channels; return base.Decode(packet, doNotDecode, 1, blockSize * channels); } protected override bool WriteVectors(VorbisCodebook codebook, DataPacket packet, float[][] residue, int channel, int offset, int partitionSize) { int num = 0; offset /= _channels; int num2 = 0; while (num2 < partitionSize) { int num3 = codebook.DecodeScalar(packet); if (num3 == -1) { return true; } int num4 = 0; while (num4 < codebook.Dimensions) { residue[num][offset] += codebook[num3, num4]; if (++num == _channels) { num = 0; offset++; } num4++; num2++; } } return false; } } private VorbisStreamDecoder _vorbis; private float[][] _residue; internal static VorbisResidue Init(VorbisStreamDecoder vorbis, DataPacket packet) { int num = (int)packet.ReadBits(16); VorbisResidue vorbisResidue = null; switch (num) { case 0: vorbisResidue = new Residue0(vorbis); break; case 1: vorbisResidue = new Residue1(vorbis); break; case 2: vorbisResidue = new Residue2(vorbis); break; } if (vorbisResidue == null) { throw new InvalidDataException(); } vorbisResidue.Init(packet); return vorbisResidue; } private static int icount(int v) { int num = 0; while (v != 0) { num += v & 1; v >>= 1; } return num; } protected VorbisResidue(VorbisStreamDecoder vorbis) { _vorbis = vorbis; _residue = new float[_vorbis._channels][]; for (int i = 0; i < _vorbis._channels; i++) { _residue[i] = new float[_vorbis.Block1Size]; } } protected float[][] GetResidueBuffer(int channels) { float[][] array = _residue; if (channels < _vorbis._channels) { array = new float[channels][]; Array.Copy(_residue, array, channels); } for (int i = 0; i < channels; i++) { Array.Clear(array[i], 0, array[i].Length); } return array; } internal abstract float[][] Decode(DataPacket packet, bool[] doNotDecode, int channels, int blockSize); protected abstract void Init(DataPacket packet); } internal class VorbisStreamDecoder : IVorbisStreamStatus, IDisposable { internal int _upperBitrate; internal int _nominalBitrate; internal int _lowerBitrate; internal string _vendor; internal string[] _comments; internal int _channels; internal int _sampleRate; internal int Block0Size; internal int Block1Size; internal VorbisCodebook[] Books; internal VorbisTime[] Times; internal VorbisFloor[] Floors; internal VorbisResidue[] Residues; internal VorbisMapping[] Maps; internal VorbisMode[] Modes; private int _modeFieldBits; internal long _glueBits; internal long _metaBits; internal long _bookBits; internal long _timeHdrBits; internal long _floorHdrBits; internal long _resHdrBits; internal long _mapHdrBits; internal long _modeHdrBits; internal long _wasteHdrBits; internal long _modeBits; internal long _floorBits; internal long _resBits; internal long _wasteBits; internal long _samples; internal int _packetCount; internal Stopwatch _sw = new Stopwatch(); private IPacketProvider _packetProvider; private DataPacket _parameterChangePacket; private List _pagesSeen; private int _lastPageSeen; private bool _eosFound; private object _seekLock = new object(); private static readonly byte[] PacketSignatureStream = new byte[7] { 1, 118, 111, 114, 98, 105, 115 }; 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 }; private float[] _prevBuffer; private RingBuffer _outputBuffer; private Queue _bitsPerPacketHistory; private Queue _sampleCountHistory; private int _preparedLength; internal bool _clipped; private Stack _resyncQueue; private long _currentPosition; private long _reportedPosition; private VorbisMode _mode; private bool _prevFlag; private bool _nextFlag; private bool[] _noExecuteChannel; private VorbisFloor.PacketData[] _floorData; private float[][] _residue; private bool _isParameterChange; internal bool IsParameterChange { get { return _isParameterChange; } set { if (value) { throw new InvalidOperationException("Only clearing is supported!"); } _isParameterChange = value; } } internal bool CanSeek => _packetProvider.CanSeek; internal long CurrentPosition { get { return _reportedPosition; } private set { _reportedPosition = value; _currentPosition = value; _preparedLength = 0; _eosFound = false; ResetDecoder(isFullReset: false); _prevBuffer = null; } } internal long ContainerBits => _packetProvider.ContainerBits; public int EffectiveBitRate { get { if (_samples == 0L) { return 0; } double num = (double)(_currentPosition - _preparedLength) / (double)_sampleRate; return (int)((double)AudioBits / num); } } public int InstantBitRate { get { int num = _sampleCountHistory.Sum(); if (num > 0) { return (int)((long)_bitsPerPacketHistory.Sum() * (long)_sampleRate / num); } return -1; } } public TimeSpan PageLatency => TimeSpan.FromTicks(_sw.ElapsedTicks / PagesRead); public TimeSpan PacketLatency => TimeSpan.FromTicks(_sw.ElapsedTicks / _packetCount); public TimeSpan SecondLatency => TimeSpan.FromTicks(_sw.ElapsedTicks / _samples * _sampleRate); public long OverheadBits => _glueBits + _metaBits + _timeHdrBits + _wasteHdrBits + _wasteBits + _packetProvider.ContainerBits; public long AudioBits => _bookBits + _floorHdrBits + _resHdrBits + _mapHdrBits + _modeHdrBits + _modeBits + _floorBits + _resBits; public int PagesRead => _pagesSeen.IndexOf(_lastPageSeen) + 1; public int TotalPages => _packetProvider.GetTotalPageCount(); public bool Clipped => _clipped; internal VorbisStreamDecoder(IPacketProvider packetProvider) { _packetProvider = packetProvider; _packetProvider.ParameterChange += SetParametersChanging; _pagesSeen = new List(); _lastPageSeen = -1; } internal bool TryInit() { if (!ProcessStreamHeader(_packetProvider.PeekNextPacket())) { return false; } _packetProvider.GetNextPacket().Done(); DataPacket nextPacket = _packetProvider.GetNextPacket(); if (!LoadComments(nextPacket)) { throw new InvalidDataException("Comment header was not readable!"); } nextPacket.Done(); nextPacket = _packetProvider.GetNextPacket(); if (!LoadBooks(nextPacket)) { throw new InvalidDataException("Book header was not readable!"); } nextPacket.Done(); InitDecoder(); return true; } private void SetParametersChanging(object sender, ParameterChangeEventArgs e) { _parameterChangePacket = e.FirstPacket; } public void Dispose() { if (_packetProvider != null) { IPacketProvider packetProvider = _packetProvider; _packetProvider = null; packetProvider.ParameterChange -= SetParametersChanging; packetProvider.Dispose(); } } private void ProcessParameterChange(DataPacket packet) { _parameterChangePacket = null; bool flag = false; bool isFullReset = false; if (ProcessStreamHeader(packet)) { packet.Done(); flag = true; isFullReset = true; packet = _packetProvider.PeekNextPacket(); if (packet == null) { throw new InvalidDataException("Couldn't get next packet!"); } } if (LoadComments(packet)) { if (flag) { _packetProvider.GetNextPacket().Done(); } else { packet.Done(); } flag = true; packet = _packetProvider.PeekNextPacket(); if (packet == null) { throw new InvalidDataException("Couldn't get next packet!"); } } if (LoadBooks(packet)) { if (flag) { _packetProvider.GetNextPacket().Done(); } else { packet.Done(); } } ResetDecoder(isFullReset); } private static bool ValidateHeader(DataPacket packet, byte[] expected) { for (int i = 0; i < expected.Length; i++) { if (expected[i] != packet.ReadByte()) { return false; } } return true; } private bool ProcessStreamHeader(DataPacket packet) { if (!ValidateHeader(packet, PacketSignatureStream)) { _glueBits += packet.Length * 8; return false; } if (!_pagesSeen.Contains(_lastPageSeen = packet.PageSequenceNumber)) { _pagesSeen.Add(_lastPageSeen); } _glueBits += 56L; long bitsRead = packet.BitsRead; if (packet.ReadInt32() != 0) { throw new InvalidDataException("Only Vorbis stream version 0 is supported."); } _channels = packet.ReadByte(); _sampleRate = packet.ReadInt32(); _upperBitrate = packet.ReadInt32(); _nominalBitrate = packet.ReadInt32(); _lowerBitrate = packet.ReadInt32(); Block0Size = 1 << (int)packet.ReadBits(4); Block1Size = 1 << (int)packet.ReadBits(4); if (_nominalBitrate == 0 && _upperBitrate > 0 && _lowerBitrate > 0) { _nominalBitrate = (_upperBitrate + _lowerBitrate) / 2; } _metaBits += packet.BitsRead - bitsRead + 8; _wasteHdrBits += 8 * packet.Length - packet.BitsRead; return true; } private bool LoadComments(DataPacket packet) { if (!ValidateHeader(packet, PacketSignatureComments)) { _glueBits += packet.Length * 8; return false; } if (!_pagesSeen.Contains(_lastPageSeen = packet.PageSequenceNumber)) { _pagesSeen.Add(_lastPageSeen); } _glueBits += 56L; _vendor = Encoding.UTF8.GetString(packet.ReadBytes(packet.ReadInt32())); _comments = new string[packet.ReadInt32()]; for (int i = 0; i < _comments.Length; i++) { _comments[i] = Encoding.UTF8.GetString(packet.ReadBytes(packet.ReadInt32())); } _metaBits += packet.BitsRead - 56; _wasteHdrBits += 8 * packet.Length - packet.BitsRead; return true; } private bool LoadBooks(DataPacket packet) { if (!ValidateHeader(packet, PacketSignatureBooks)) { _glueBits += packet.Length * 8; return false; } if (!_pagesSeen.Contains(_lastPageSeen = packet.PageSequenceNumber)) { _pagesSeen.Add(_lastPageSeen); } long bitsRead = packet.BitsRead; _glueBits += packet.BitsRead; Books = new VorbisCodebook[packet.ReadByte() + 1]; for (int i = 0; i < Books.Length; i++) { Books[i] = VorbisCodebook.Init(this, packet, i); } _bookBits += packet.BitsRead - bitsRead; bitsRead = packet.BitsRead; Times = new VorbisTime[(int)packet.ReadBits(6) + 1]; for (int j = 0; j < Times.Length; j++) { Times[j] = VorbisTime.Init(this, packet); } _timeHdrBits += packet.BitsRead - bitsRead; bitsRead = packet.BitsRead; Floors = new VorbisFloor[(int)packet.ReadBits(6) + 1]; for (int k = 0; k < Floors.Length; k++) { Floors[k] = VorbisFloor.Init(this, packet); } _floorHdrBits += packet.BitsRead - bitsRead; bitsRead = packet.BitsRead; Residues = new VorbisResidue[(int)packet.ReadBits(6) + 1]; for (int l = 0; l < Residues.Length; l++) { Residues[l] = VorbisResidue.Init(this, packet); } _resHdrBits += packet.BitsRead - bitsRead; bitsRead = packet.BitsRead; Maps = new VorbisMapping[(int)packet.ReadBits(6) + 1]; for (int m = 0; m < Maps.Length; m++) { Maps[m] = VorbisMapping.Init(this, packet); } _mapHdrBits += packet.BitsRead - bitsRead; bitsRead = packet.BitsRead; Modes = new VorbisMode[(int)packet.ReadBits(6) + 1]; for (int n = 0; n < Modes.Length; n++) { Modes[n] = VorbisMode.Init(this, packet); } _modeHdrBits += packet.BitsRead - bitsRead; if (!packet.ReadBit()) { throw new InvalidDataException(); } _glueBits++; _wasteHdrBits += 8 * packet.Length - packet.BitsRead; _modeFieldBits = Utils.ilog(Modes.Length - 1); return true; } private void InitDecoder() { _currentPosition = 0L; _resyncQueue = new Stack(); _bitsPerPacketHistory = new Queue(); _sampleCountHistory = new Queue(); ResetDecoder(isFullReset: true); } private void ResetDecoder(bool isFullReset) { if (_preparedLength > 0) { SaveBuffer(); } if (isFullReset) { _noExecuteChannel = new bool[_channels]; _floorData = new VorbisFloor.PacketData[_channels]; _residue = new float[_channels][]; for (int i = 0; i < _channels; i++) { _residue[i] = new float[Block1Size]; } _outputBuffer = new RingBuffer(Block1Size * 2 * _channels); _outputBuffer.Channels = _channels; } else { _outputBuffer.Clear(); } _preparedLength = 0; } private void SaveBuffer() { float[] array = new float[_preparedLength * _channels]; ReadSamples(array, 0, array.Length); _prevBuffer = array; } private bool UnpackPacket(DataPacket packet) { if (packet.ReadBit()) { return false; } int num = _modeFieldBits; _mode = Modes[(uint)packet.ReadBits(_modeFieldBits)]; if (_mode.BlockFlag) { _prevFlag = packet.ReadBit(); _nextFlag = packet.ReadBit(); num += 2; } else { _prevFlag = (_nextFlag = false); } if (packet.IsShort) { return false; } long bitsRead = packet.BitsRead; int num2 = _mode.BlockSize / 2; for (int i = 0; i < _channels; i++) { _floorData[i] = _mode.Mapping.ChannelSubmap[i].Floor.UnpackPacket(packet, _mode.BlockSize, i); _noExecuteChannel[i] = !_floorData[i].ExecuteChannel; Array.Clear(_residue[i], 0, num2); } VorbisMapping.CouplingStep[] couplingSteps = _mode.Mapping.CouplingSteps; foreach (VorbisMapping.CouplingStep couplingStep in couplingSteps) { if (_floorData[couplingStep.Angle].ExecuteChannel || _floorData[couplingStep.Magnitude].ExecuteChannel) { _floorData[couplingStep.Angle].ForceEnergy = true; _floorData[couplingStep.Magnitude].ForceEnergy = true; } } long num3 = packet.BitsRead - bitsRead; bitsRead = packet.BitsRead; VorbisMapping.Submap[] submaps = _mode.Mapping.Submaps; foreach (VorbisMapping.Submap submap in submaps) { for (int k = 0; k < _channels; k++) { if (_mode.Mapping.ChannelSubmap[k] != submap) { _floorData[k].ForceNoEnergy = true; } } float[][] array = submap.Residue.Decode(packet, _noExecuteChannel, _channels, _mode.BlockSize); for (int l = 0; l < _channels; l++) { float[] array2 = _residue[l]; float[] array3 = array[l]; for (int m = 0; m < num2; m++) { array2[m] += array3[m]; } } } _glueBits++; _modeBits += num; _floorBits += num3; _resBits += packet.BitsRead - bitsRead; _wasteBits += 8 * packet.Length - packet.BitsRead; _packetCount++; return true; } private void DecodePacket() { VorbisMapping.CouplingStep[] couplingSteps = _mode.Mapping.CouplingSteps; int num = _mode.BlockSize / 2; for (int num2 = couplingSteps.Length - 1; num2 >= 0; num2--) { if (_floorData[couplingSteps[num2].Angle].ExecuteChannel || _floorData[couplingSteps[num2].Magnitude].ExecuteChannel) { float[] array = _residue[couplingSteps[num2].Magnitude]; float[] array2 = _residue[couplingSteps[num2].Angle]; for (int i = 0; i < num; i++) { float num3; float num4; if (array[i] > 0f) { if (array2[i] > 0f) { num3 = array[i]; num4 = array[i] - array2[i]; } else { num4 = array[i]; num3 = array[i] + array2[i]; } } else if (array2[i] > 0f) { num3 = array[i]; num4 = array[i] + array2[i]; } else { num4 = array[i]; num3 = array[i] - array2[i]; } array[i] = num3; array2[i] = num4; } } } for (int j = 0; j < _channels; j++) { VorbisFloor.PacketData packetData = _floorData[j]; float[] array3 = _residue[j]; if (packetData.ExecuteChannel) { _mode.Mapping.ChannelSubmap[j].Floor.Apply(packetData, array3); Mdct.Reverse(array3, _mode.BlockSize); } else { Array.Clear(array3, num, num); } } } private int OverlapSamples() { float[] window = _mode.GetWindow(_prevFlag, _nextFlag); int blockSize = _mode.BlockSize; int num = blockSize; int num2 = num >> 1; int num3 = 0; int num4 = -num2; int num5 = num2; if (_mode.BlockFlag) { if (!_prevFlag) { num3 = Block1Size / 4 - Block0Size / 4; num2 = num3 + Block0Size / 2; num4 = Block0Size / -2 - num3; } if (!_nextFlag) { num -= blockSize / 4 - Block0Size / 4; num5 = blockSize / 4 + Block0Size / 4; } } int index = _outputBuffer.Length / _channels + num4; for (int i = 0; i < _channels; i++) { _outputBuffer.Write(i, index, num3, num2, num, _residue[i], window); } int num6 = _outputBuffer.Length / _channels - num5; int result = num6 - _preparedLength; _preparedLength = num6; return result; } private void UpdatePosition(int samplesDecoded, DataPacket packet) { _samples += samplesDecoded; if (packet.IsResync) { _currentPosition = -packet.PageGranulePosition; _resyncQueue.Push(packet); } else { if (samplesDecoded <= 0) { return; } _currentPosition += samplesDecoded; packet.GranulePosition = _currentPosition; if (_currentPosition < 0) { if (packet.PageGranulePosition > -_currentPosition) { long num = _currentPosition - samplesDecoded; while (_resyncQueue.Count > 0) { DataPacket dataPacket = _resyncQueue.Pop(); long num2 = dataPacket.GranulePosition + num; dataPacket.GranulePosition = num; num = num2; } } else { packet.GranulePosition = -samplesDecoded; _resyncQueue.Push(packet); } } else if (packet.IsEndOfStream && _currentPosition > packet.PageGranulePosition) { int num3 = (int)(_currentPosition - packet.PageGranulePosition); if (num3 >= 0) { _preparedLength -= num3; _currentPosition -= num3; } else { _preparedLength = 0; } packet.GranulePosition = packet.PageGranulePosition; _eosFound = true; } } } private void DecodeNextPacket() { _sw.Start(); DataPacket dataPacket = null; try { IPacketProvider packetProvider = _packetProvider; if (packetProvider != null) { dataPacket = packetProvider.GetNextPacket(); } if (dataPacket == null) { _eosFound = true; return; } if (!_pagesSeen.Contains(_lastPageSeen = dataPacket.PageSequenceNumber)) { _pagesSeen.Add(_lastPageSeen); } if (dataPacket.IsResync) { ResetDecoder(isFullReset: false); } if (dataPacket == _parameterChangePacket) { _isParameterChange = true; ProcessParameterChange(dataPacket); return; } if (!UnpackPacket(dataPacket)) { dataPacket.Done(); _wasteBits += 8 * dataPacket.Length; return; } dataPacket.Done(); DecodePacket(); int num = OverlapSamples(); if (!dataPacket.GranuleCount.HasValue) { dataPacket.GranuleCount = num; } UpdatePosition(num, dataPacket); int num2 = Utils.Sum(_sampleCountHistory) + num; _bitsPerPacketHistory.Enqueue((int)dataPacket.BitsRead); _sampleCountHistory.Enqueue(num); while (num2 > _sampleRate) { _bitsPerPacketHistory.Dequeue(); num2 -= _sampleCountHistory.Dequeue(); } } catch { dataPacket?.Done(); throw; } finally { _sw.Stop(); } } internal int GetPacketLength(DataPacket curPacket, DataPacket lastPacket) { if (lastPacket == null || curPacket.IsResync) { return 0; } if (curPacket.ReadBit()) { return 0; } if (lastPacket.ReadBit()) { return 0; } int num = (int)curPacket.ReadBits(_modeFieldBits); if (num < 0 || num >= Modes.Length) { return 0; } VorbisMode vorbisMode = Modes[num]; num = (int)lastPacket.ReadBits(_modeFieldBits); if (num < 0 || num >= Modes.Length) { return 0; } VorbisMode vorbisMode2 = Modes[num]; return vorbisMode.BlockSize / 4 + vorbisMode2.BlockSize / 4; } internal int ReadSamples(float[] buffer, int offset, int count) { int num = 0; lock (_seekLock) { if (_prevBuffer != null) { int num2 = Math.Min(count, _prevBuffer.Length); Buffer.BlockCopy(_prevBuffer, 0, buffer, offset, num2 * 4); if (num2 < _prevBuffer.Length) { float[] array = new float[_prevBuffer.Length - num2]; Buffer.BlockCopy(_prevBuffer, num2 * 4, array, 0, (_prevBuffer.Length - num2) * 4); _prevBuffer = array; } else { _prevBuffer = null; } count -= num2; offset += num2; num = num2; } else if (_isParameterChange) { throw new InvalidOperationException("Currently pending a parameter change. Read new parameters before requesting further samples!"); } int size = count + Block1Size * _channels; _outputBuffer.EnsureSize(size); while (_preparedLength * _channels < count && !_eosFound && !_isParameterChange) { DecodeNextPacket(); if (_prevBuffer != null) { return ReadSamples(buffer, offset, _prevBuffer.Length); } } if (_preparedLength * _channels < count) { count = _preparedLength * _channels; } _outputBuffer.CopyTo(buffer, offset, count); _preparedLength -= count / _channels; _reportedPosition = _currentPosition - _preparedLength; } return num + count; } internal void SeekTo(long granulePos) { if (!_packetProvider.CanSeek) { throw new NotSupportedException(); } if (granulePos < 0) { throw new ArgumentOutOfRangeException("granulePos"); } DataPacket dataPacket; if (granulePos > 0) { dataPacket = _packetProvider.FindPacket(granulePos, GetPacketLength); if (dataPacket == null) { throw new ArgumentOutOfRangeException("granulePos"); } } else { dataPacket = _packetProvider.GetPacket(4); } lock (_seekLock) { _packetProvider.SeekToPacket(dataPacket, 1); DataPacket dataPacket2 = _packetProvider.PeekNextPacket(); CurrentPosition = dataPacket2.GranulePosition; int num = (int)((granulePos - CurrentPosition) * _channels); if (num <= 0) { return; } float[] buffer = new float[num]; while (num > 0) { int num2 = ReadSamples(buffer, 0, num); if (num2 == 0) { break; } num -= num2; } } } internal long GetLastGranulePos() { return _packetProvider.GetGranuleCount(); } public void ResetStats() { _clipped = false; _packetCount = 0; _floorBits = 0L; _glueBits = 0L; _modeBits = 0L; _resBits = 0L; _wasteBits = 0L; _samples = 0L; _sw.Reset(); } } internal abstract class VorbisTime { private class Time0 : VorbisTime { internal Time0(VorbisStreamDecoder vorbis) : base(vorbis) { } protected override void Init(DataPacket packet) { } } private VorbisStreamDecoder _vorbis; internal static VorbisTime Init(VorbisStreamDecoder vorbis, DataPacket packet) { int num = (int)packet.ReadBits(16); VorbisTime vorbisTime = null; if (num == 0) { vorbisTime = new Time0(vorbis); } if (vorbisTime == null) { throw new InvalidDataException(); } vorbisTime.Init(packet); return vorbisTime; } protected VorbisTime(VorbisStreamDecoder vorbis) { _vorbis = vorbis; } protected abstract void Init(DataPacket packet); } } namespace NVorbis.Ogg { public class ContainerReader : IContainerReader, IDisposable { private class PageHeader { public int StreamSerial { get; set; } public PageFlags Flags { get; set; } public long GranulePosition { get; set; } public int SequenceNumber { get; set; } public long DataOffset { get; set; } public int[] PacketSizes { get; set; } public bool LastPacketContinues { get; set; } public bool IsResync { get; set; } } private Crc _crc = new Crc(); private Stream _stream; private bool _closeOnDispose; private Dictionary _packetReaders; private List _disposedStreamSerials; private long _nextPageOffset; private int _pageCount; private byte[] _readBuffer = new byte[65025]; private long _containerBits; private long _wasteBits; public int[] StreamSerials => _packetReaders.Keys.ToArray(); public int PagesRead => _pageCount; public bool CanSeek => true; public long WasteBits => _wasteBits; public event EventHandler NewStream; public ContainerReader(string path) : this(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read), closeOnDispose: true) { } public ContainerReader(Stream stream, bool closeOnDispose) { _packetReaders = new Dictionary(); _disposedStreamSerials = new List(); _stream = stream ?? throw new ArgumentNullException("stream"); _closeOnDispose = closeOnDispose; if (!_stream.CanSeek) { throw new ArgumentException("The specified stream must be seek-able!", "stream"); } } public bool Init() { return GatherNextPage() != -1; } public void Dispose() { int[] streamSerials = StreamSerials; foreach (int key in streamSerials) { _packetReaders[key].Dispose(); } _nextPageOffset = 0L; _containerBits = 0L; _wasteBits = 0L; _stream.Dispose(); } public IPacketProvider GetStream(int streamSerial) { if (!_packetReaders.TryGetValue(streamSerial, out var value)) { throw new ArgumentOutOfRangeException("streamSerial"); } return value; } public bool FindNextStream() { int count = _packetReaders.Count; while (_packetReaders.Count == count && GatherNextPage() != -1) { } return count > _packetReaders.Count; } public int GetTotalPageCount() { while (GatherNextPage() != -1) { } return _pageCount; } private PageHeader ReadPageHeader(long position) { _stream.Seek(position, SeekOrigin.Begin); if (_stream.Read(_readBuffer, 0, 27) != 27) { return null; } if (_readBuffer[0] != 79 || _readBuffer[1] != 103 || _readBuffer[2] != 103 || _readBuffer[3] != 83) { return null; } if (_readBuffer[4] != 0) { return null; } PageHeader pageHeader = new PageHeader(); pageHeader.Flags = (PageFlags)_readBuffer[5]; pageHeader.GranulePosition = BitConverter.ToInt64(_readBuffer, 6); pageHeader.StreamSerial = BitConverter.ToInt32(_readBuffer, 14); pageHeader.SequenceNumber = BitConverter.ToInt32(_readBuffer, 18); uint checkCrc = BitConverter.ToUInt32(_readBuffer, 22); _crc.Reset(); for (int i = 0; i < 22; i++) { _crc.Update(_readBuffer[i]); } _crc.Update(0); _crc.Update(0); _crc.Update(0); _crc.Update(0); _crc.Update(_readBuffer[26]); int num = _readBuffer[26]; if (_stream.Read(_readBuffer, 0, num) != num) { return null; } List list = new List(num); int num2 = 0; int num3 = 0; for (int j = 0; j < num; j++) { byte b = _readBuffer[j]; _crc.Update(b); if (num3 == list.Count) { list.Add(0); } list[num3] += b; if (b < byte.MaxValue) { num3++; pageHeader.LastPacketContinues = false; } else { pageHeader.LastPacketContinues = true; } num2 += b; } pageHeader.PacketSizes = list.ToArray(); pageHeader.DataOffset = position + 27 + num; if (_stream.Read(_readBuffer, 0, num2) != num2) { return null; } for (int k = 0; k < num2; k++) { _crc.Update(_readBuffer[k]); } if (_crc.Test(checkCrc)) { _containerBits += 8 * (27 + num); _pageCount++; return pageHeader; } return null; } private PageHeader FindNextPageHeader() { long num = _nextPageOffset; bool isResync = false; PageHeader pageHeader; while ((pageHeader = ReadPageHeader(num)) == null) { isResync = true; _wasteBits += 8L; num = (_stream.Position = num + 1); int num3 = 0; do { switch (_stream.ReadByte()) { case 79: if (_stream.ReadByte() == 103) { if (_stream.ReadByte() == 103) { if (_stream.ReadByte() == 83) { num += num3; goto end_IL_0032; } _stream.Seek(-1L, SeekOrigin.Current); } _stream.Seek(-1L, SeekOrigin.Current); } _stream.Seek(-1L, SeekOrigin.Current); break; case -1: return null; } _wasteBits += 8L; continue; end_IL_0032: break; } while (++num3 < 65536); if (num3 == 65536) { return null; } } pageHeader.IsResync = isResync; _nextPageOffset = pageHeader.DataOffset; for (int i = 0; i < pageHeader.PacketSizes.Length; i++) { _nextPageOffset += pageHeader.PacketSizes[i]; } return pageHeader; } private bool AddPage(PageHeader hdr) { if (!_packetReaders.TryGetValue(hdr.StreamSerial, out var value)) { value = new PacketReader(this, hdr.StreamSerial); } value.ContainerBits += _containerBits; _containerBits = 0L; bool isContinued = hdr.PacketSizes.Length == 1 && hdr.LastPacketContinues; bool isContinuation = (hdr.Flags & PageFlags.ContinuesPacket) == PageFlags.ContinuesPacket; bool isEndOfStream = false; bool isResync = hdr.IsResync; long num = hdr.DataOffset; int num2 = hdr.PacketSizes.Length; int[] packetSizes = hdr.PacketSizes; foreach (int num3 in packetSizes) { Packet packet = new Packet(this, num, num3) { PageGranulePosition = hdr.GranulePosition, IsEndOfStream = isEndOfStream, PageSequenceNumber = hdr.SequenceNumber, IsContinued = isContinued, IsContinuation = isContinuation, IsResync = isResync }; value.AddPacket(packet); num += num3; isContinuation = false; isResync = false; if (--num2 == 1) { isContinued = hdr.LastPacketContinues; isEndOfStream = (hdr.Flags & PageFlags.EndOfStream) == PageFlags.EndOfStream; } } if (!_packetReaders.ContainsKey(hdr.StreamSerial)) { _packetReaders.Add(hdr.StreamSerial, value); return true; } return false; } private int GatherNextPage() { PageHeader pageHeader; while (true) { pageHeader = FindNextPageHeader(); if (pageHeader == null) { return -1; } if (!_disposedStreamSerials.Contains(pageHeader.StreamSerial)) { if (!AddPage(pageHeader)) { break; } EventHandler eventHandler = this.NewStream; if (eventHandler == null) { break; } NewStreamEventArgs e = new NewStreamEventArgs(_packetReaders[pageHeader.StreamSerial]); eventHandler(this, e); if (!e.IgnoreStream) { break; } _packetReaders[pageHeader.StreamSerial].Dispose(); } } return pageHeader.StreamSerial; } internal void DisposePacketReader(PacketReader packetReader) { _disposedStreamSerials.Add(packetReader.StreamSerial); _packetReaders.Remove(packetReader.StreamSerial); } internal int PacketReadByte(long offset) { _stream.Position = offset; return _stream.ReadByte(); } internal void GatherNextPage(int streamSerial) { if (!_packetReaders.ContainsKey(streamSerial)) { throw new ArgumentOutOfRangeException("streamSerial"); } while (!_packetReaders[streamSerial].HasEndOfStream) { int num = GatherNextPage(); if (num == -1) { foreach (KeyValuePair packetReader in _packetReaders) { if (!packetReader.Value.HasEndOfStream) { packetReader.Value.SetEndOfStream(); } } break; } if (num == streamSerial) { break; } } } } internal class Crc { private const uint CRC32_POLY = 79764919u; private static uint[] crcTable; private uint _crc; static Crc() { 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) ^ (uint)((num2 >= 2147483648u) ? 79764919 : 0); } crcTable[num] = num2; } } public Crc() { Reset(); } public void Reset() { _crc = 0u; } public void Update(int nextVal) { _crc = (_crc << 8) ^ crcTable[nextVal ^ (_crc >> 24)]; } public bool Test(uint checkCrc) { return _crc == checkCrc; } } internal class Packet : DataPacket { private long _offset; private int _length; private int _curOfs; private Packet _mergedPacket; private Packet _next; private Packet _prev; private ContainerReader _containerReader; internal Packet Next { get { return _next; } set { _next = value; } } internal Packet Prev { get { return _prev; } set { _prev = value; } } internal bool IsContinued { get { return GetFlag(PacketFlags.User1); } set { SetFlag(PacketFlags.User1, value); } } internal bool IsContinuation { get { return GetFlag(PacketFlags.User2); } set { SetFlag(PacketFlags.User2, value); } } internal Packet(ContainerReader containerReader, long streamOffset, int length) : base(length) { _containerReader = containerReader; _offset = streamOffset; _length = length; _curOfs = 0; } internal void MergeWith(DataPacket continuation) { if (!(continuation is Packet mergedPacket)) { throw new ArgumentException("Incorrect packet type!"); } base.Length += continuation.Length; if (_mergedPacket == null) { _mergedPacket = mergedPacket; } else { _mergedPacket.MergeWith(continuation); } base.PageGranulePosition = continuation.PageGranulePosition; base.PageSequenceNumber = continuation.PageSequenceNumber; } internal void Reset() { _curOfs = 0; ResetBitReader(); if (_mergedPacket != null) { _mergedPacket.Reset(); } } protected override int ReadNextByte() { if (_curOfs == _length) { if (_mergedPacket == null) { return -1; } return _mergedPacket.ReadNextByte(); } int num = _containerReader.PacketReadByte(_offset + _curOfs); if (num != -1) { _curOfs++; } return num; } } [DebuggerTypeProxy(typeof(DebugView))] internal class PacketReader : IPacketProvider, IDisposable { private class DebugView { private PacketReader _reader; private Packet _last; private Packet _first; private Packet[] _packetList = new Packet[0]; public ContainerReader Container => _reader._container; public int StreamSerial => _reader._streamSerial; public bool EndOfStreamFound => _reader._eosFound; public int CurrentPacketIndex { get { if (_reader._current == null) { return -1; } return Array.IndexOf(Packets, _reader._current); } } public Packet[] Packets { get { if (_reader._last == _last && _reader._first == _first) { return _packetList; } _last = _reader._last; _first = _reader._first; List list = new List(); for (Packet packet = _first; packet != null; packet = packet.Next) { list.Add(packet); } _packetList = list.ToArray(); return _packetList; } } public DebugView(PacketReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } _reader = reader; } } private ContainerReader _container; private int _streamSerial; private bool _eosFound; private Packet _first; private Packet _current; private Packet _last; private object _packetLock = new object(); internal bool HasEndOfStream => _eosFound; public int StreamSerial => _streamSerial; public long ContainerBits { get; set; } public bool CanSeek => true; public event EventHandler ParameterChange; internal PacketReader(ContainerReader container, int streamSerial) { _container = container; _streamSerial = streamSerial; } public void Dispose() { _eosFound = true; if (_container != null) { _container.DisposePacketReader(this); } _container = null; _current = null; if (_first != null) { Packet packet = _first; _first = null; while (packet.Next != null) { Packet next = packet.Next; packet.Next = null; packet = next; packet.Prev = null; } packet = null; } _last = null; } internal void AddPacket(Packet packet) { lock (_packetLock) { if (_eosFound) { return; } if (packet.IsResync) { packet.IsContinuation = false; if (_last != null) { _last.IsContinued = false; } } if (packet.IsContinuation) { if (_last == null) { throw new InvalidDataException(); } if (!_last.IsContinued) { throw new InvalidDataException(); } _last.MergeWith(packet); _last.IsContinued = packet.IsContinued; } else { if (packet == null) { throw new ArgumentException("Wrong packet datatype", "packet"); } if (_first == null) { _first = packet; _last = packet; } else { Packet packet2 = (packet.Prev = _last); Packet last2 = (packet2.Next = packet); _last = last2; } } if (packet.IsEndOfStream) { SetEndOfStream(); } } } internal void SetEndOfStream() { lock (_packetLock) { _eosFound = true; if (_last.IsContinued) { _last = _last.Prev; _last.Next.Prev = null; _last.Next = null; } } } public DataPacket GetNextPacket() { return _current = PeekNextPacketInternal(); } public DataPacket PeekNextPacket() { return PeekNextPacketInternal(); } private Packet PeekNextPacketInternal() { Packet packet; if (_current == null) { packet = _first; } else { while (true) { lock (_packetLock) { packet = _current.Next; if ((packet != null && !packet.IsContinued) || _eosFound) { break; } goto IL_004f; } IL_004f: _container.GatherNextPage(_streamSerial); } } if (packet != null) { if (packet.IsContinued) { throw new InvalidDataException("Packet is incomplete!"); } packet.Reset(); } return packet; } internal void ReadAllPages() { while (!_eosFound) { _container.GatherNextPage(_streamSerial); } } internal DataPacket GetLastPacket() { ReadAllPages(); return _last; } public int GetTotalPageCount() { ReadAllPages(); int num = 0; int num2 = 0; for (Packet packet = _first; packet != null; packet = packet.Next) { if (packet.PageSequenceNumber != num2) { num++; num2 = packet.PageSequenceNumber; } } return num; } public DataPacket GetPacket(int packetIndex) { if (packetIndex < 0) { throw new ArgumentOutOfRangeException("index"); } if (_first == null) { throw new InvalidOperationException("Packet reader has no packets!"); } Packet packet = _first; while (--packetIndex >= 0) { while (packet.Next == null) { if (_eosFound) { throw new ArgumentOutOfRangeException("index"); } _container.GatherNextPage(_streamSerial); } packet = packet.Next; } packet.Reset(); return packet; } private Packet GetLastPacketInPage(Packet packet) { if (packet != null) { int pageSequenceNumber = packet.PageSequenceNumber; while (packet.Next != null && packet.Next.PageSequenceNumber == pageSequenceNumber) { packet = packet.Next; } if (packet != null && packet.IsContinued) { packet = packet.Prev; } } return packet; } private Packet FindPacketInPage(Packet pagePacket, long targetGranulePos, Func packetGranuleCountCallback) { Packet lastPacketInPage = GetLastPacketInPage(pagePacket); if (lastPacketInPage == null) { return null; } Packet packet = lastPacketInPage; do { if (!packet.GranuleCount.HasValue) { if (packet == lastPacketInPage) { packet.GranulePosition = packet.PageGranulePosition; } else { packet.GranulePosition = packet.Next.GranulePosition - packet.Next.GranuleCount.Value; } if (packet == _last && _eosFound && packet.Prev.PageSequenceNumber < packet.PageSequenceNumber) { packet.GranuleCount = (int)(packet.GranulePosition - packet.Prev.PageGranulePosition); } else if (packet.Prev != null) { packet.Prev.Reset(); packet.Reset(); packet.GranuleCount = packetGranuleCountCallback(packet, packet.Prev); } else { if (packet.GranulePosition > packet.Next.GranulePosition - packet.Next.GranuleCount) { throw new InvalidOperationException("First data packet size mismatch"); } packet.GranuleCount = (int)packet.GranulePosition; } } if (targetGranulePos <= packet.GranulePosition && targetGranulePos > packet.GranulePosition - packet.GranuleCount) { if (packet.Prev != null && !packet.Prev.GranuleCount.HasValue) { packet.Prev.GranulePosition = packet.GranulePosition - packet.GranuleCount.Value; } return packet; } packet = packet.Prev; } while (packet != null && packet.PageSequenceNumber == lastPacketInPage.PageSequenceNumber); if (packet != null && packet.PageGranulePosition < targetGranulePos) { packet.GranulePosition = packet.PageGranulePosition; return packet.Next; } return null; } public DataPacket FindPacket(long granulePos, Func packetGranuleCountCallback) { if (granulePos < 0) { throw new ArgumentOutOfRangeException("granulePos"); } Packet packet = null; Packet packet2 = _current ?? _first; if (granulePos > packet2.PageGranulePosition) { while (granulePos > packet2.PageGranulePosition) { if ((packet2.Next == null || packet2.IsContinued) && !_eosFound) { _container.GatherNextPage(_streamSerial); if (_eosFound) { packet2 = null; break; } } packet2 = packet2.Next; } return FindPacketInPage(packet2, granulePos, packetGranuleCountCallback); } while (packet2.Prev != null && (granulePos <= packet2.Prev.PageGranulePosition || packet2.Prev.PageGranulePosition == -1)) { packet2 = packet2.Prev; } return FindPacketInPage(packet2, granulePos, packetGranuleCountCallback); } public void SeekToPacket(DataPacket packet, int preRoll) { if (preRoll < 0) { throw new ArgumentOutOfRangeException("preRoll"); } if (packet == null) { throw new ArgumentNullException("granulePos"); } Packet packet2 = packet as Packet; if (packet2 == null) { throw new ArgumentException("Incorrect packet type!", "packet"); } while (--preRoll >= 0) { packet2 = packet2.Prev; if (packet2 == null) { throw new ArgumentOutOfRangeException("preRoll"); } } _current = packet2.Prev; } public long GetGranuleCount() { return GetLastPacket().PageGranulePosition; } } [Flags] internal enum PageFlags { None = 0, ContinuesPacket = 1, BeginningOfStream = 2, EndOfStream = 4 } }